本节着重介绍CRC校验部分的内容
一:总思路
当前思路是把bin的内容和CRC合并成新的文件流
二:具体如何合并
crcArray = getByteArray();
byte[] allData = mergeArrays(bytesInputStream1, crcArray);
inputStream = new ByteArrayInputStream(allData);
三:详解二中参数
二中的合并是通过两个实参(均为byte数组)完成的,bin和CRC,三中介绍bin,四中捋好CRC
3.1:bin文件,先拿到文件流
下面的是YModem的构造方法,当升级的bin存在手机内部,实际路径在创建YModem对象时,作为实参传入并初始化
public YModem(Context context, String filePath,
String fileNameString, String fileMd5String,
YModemListener listener) {
this.filePath = filePath;
this.fileNameString = fileNameString;
this.fileMd5String = fileMd5String;
this.mContext = context;
this.listener = listener;
}
如果升级的bin文件放在APP的外部通过手机进行数据存储,则通过下面的方法拿到bin文件的文件流
InputStream inputStream1 = YModemUtil.getInputStream(mContext, filePath);
如果升级的bin文件放在APP的内部,则通过下面的方法拿到bin文件的文件流
InputStream inputStream1 = mContext.getAssets().open("radar-sensor-firmware_weifu_change_name.bin");
3.2:bin文件在拿到文件流后再转换成byte数组
//转换成byte数组
bytesInputStream1 = toByteArray(inputStream1);
四:CRC的流程
说明:
FileStreamThread.java中的变量fileByteSize和fileAndCrcSize两个在赋值时不是很准确,但是不影响升级,这两个变量并没有重要的实际使用价值
4.1具体CRC计算流程
【4.1.1】
CrcCalculate.calculateCrcArray()--->crcDebugArray
直接调用函数得到最原始的CRC数组,一个元素32字节
【4.1.2】
CrcCalculate.oneToFour(crcDebugArray[j])--->fourArray--->
将先前得到的CRC数组的元素,一个32位拆成8位转uint8,一个元素拆分成四个
【4.1.3】
forOriginalIntArray--->originalIntArray--->functionByteArray
得到uint8 8字节的整形数组后在转换为byte数组
4.2crc的byte数组最终和bin的byte数组合并
crcArray = getByteArray();
上面4.1最终得到的数组functionByteArray就是getByteArray()方法的返回值,
进而赋值给crcArray,
最终crcArray作为实参传入,得到bin+CRC合并后的byte数组
byte[] allData = mergeArrays(bytesInputStream1, crcArray)
五:CrcCalculate.calculateCrcArray函数步骤流程
package com.leonxtp.library;
import com.leonxtp.library.FileStreamThread;
import java.util.Arrays;
import android.util.Log;
/**
* created by jim Xu
* date:2023/12/6
* describe:
**/
public class CrcCalculate {
public static int POLYNOMIAL= (int)0xD419CC15L;
public static int crc32_table[] = new int[256];
public static int appendZeroSize;
public static byte[] dataSourceAppendZero;
public static int crcLength;
private static String crcResultArrayString;
//调用函数一,问题crc_accum的数据类型,位运算是否可以直接移植
public static void gen_crc_table(){
int i, j;
int crc_accum;
for(i=0; i < 256; i++) {
crc_accum = ((int) i << 24);
for(j=0; j < 8; j++) {
if ((crc_accum & 0x80000000) !=0) {
crc_accum = (crc_accum << 1) ^ POLYNOMIAL;
} else {
crc_accum = (crc_accum << 1);
}
}
crc32_table[i] = crc_accum;
Log.d("XTQ_YModem_1207","crc32_table"+"第"+(i+1)+"个元素"+crc32_table[i]+"!!!");
}
}
//调用函数二,参数列表的数据类型,位运算符号是否可以直接移植
public static int update_crc(int crc_accum, byte[] datap, int datak_size)
{
int i, j;
for(j = 0; j < datak_size; j++) {
i = ((int) (crc_accum >> 24) ^ datap[j]) & 0xff;
crc_accum = (crc_accum << 8) ^ crc32_table[i];
}
return crc_accum;
}
public static int[] calculateCrcArray(){
gen_crc_table();
//数据源,bin文件强转为byte数组
byte[] dataSource = FileStreamThread.bytesInputStream1;
//不算CRC的bin 的 byte[] size
int dataSourceLength = dataSource.length;
//下面是数据源转换为byte数组后,数组dataSource不足4的整数倍的地方补齐0
if(dataSourceLength % 4 > 0){
int appendZeroSize = 4 -(dataSourceLength % 4);
byte[] byteZero = new byte[appendZeroSize];
for(int j = 0; j < appendZeroSize; j++){
byteZero[j] = 0;
}
dataSourceAppendZero = mergeArrays(dataSource,byteZero);
}else{
dataSourceAppendZero = dataSource;
}
//计算CRC的长度 //一个CRC32位4byte 4K内容算一个CRC
if(dataSourceLength % 4096 > 0){
crcLength = dataSourceLength / 4096 + 1;
}else{
crcLength = dataSourceLength / 4096;
}
int[] crcResultArray = new int[crcLength];
for(int k = 0; k < crcLength - 1; k++ ){
byte[] subArray = Arrays.copyOfRange(dataSourceAppendZero,k*4096,(k+1)*4096);
crcResultArray[k] = update_crc(0,subArray,4096);
Log.d("XTQ_YModem_1207","crcResultArray"+"第"+(k+1)+"个元素"+crcResultArray[k]+"!!!");
//下面两行是为了打印结果写的,没有实际的逻辑功能
crcResultArrayString = crcResultArrayString + crcResultArray[k]+",";
Log.d("XTQ_YModem_1207","crcResultArray的整体结果:"+"\n"+crcResultArrayString);
}
//上面的for循环最大值是到crcLength - 1,因为防止dataSourceLength的长度不是4096的整数倍
//那么crcResultArray最后一个元素就要单独用下面的两行代码求值,注意update_crc方法的最后一个参数、
//除了crcResultArray的最后一个元素计算时传入的参数是subArraySecond.length,其余的都是传入的4096
byte[] subArraySecond = Arrays.copyOfRange(dataSourceAppendZero,(crcLength - 1)*4096,dataSourceLength);
crcResultArray[crcLength - 1] = update_crc(0,subArraySecond,subArraySecond.length);
return crcResultArray;
}
//合并byte数组的封装函数
//合并byte
public static byte[] mergeArrays(byte[] arr1, byte[] arr2) {
byte[] merged = new byte[arr1.length + arr2.length];
System.arraycopy(arr1, 0, merged, 0, arr1.length);
System.arraycopy(arr2, 0, merged, arr1.length, arr2.length);
return merged;
}
//封装拆分的方法
//总长度4倍的static数组然后不断更新数组
//32字节拆成8字节转uint8★★★★★
public static int[] oneToFour(int numberSource){
//
int int32Value = numberSource;
int[] int8Array = new int[4];
int8Array[0] = (int32Value >> 24)& 0xFF;
int8Array[1] = (int32Value >> 16)& 0xFF;
int8Array[2] = (int32Value >> 8) & 0xFF;
int8Array[3] = int32Value& 0xFF;
for(int i = 0;i<4;i++){
Log.d("XTQ_YModem_1207","无符号测试值"+int8Array[i]+"!!!");
}
return int8Array;
}
}
六:CrcCalculate.oneToFour函数步骤流程
一个32位拆成8位转uint8,该函数方法详见第五模块的oneToFour函数
七:关于文件源
如果是放在手机中:
那么主要代码如下,文件放在手机的/sdcard/Download/calgateradar_1028.bin路径中
nputStream inputStream1 = YModemUtil.getInputStream(mContext, filePath);
ymodem = new YModem.Builder()
.with(this)
.filePath("/sdcard/Download/calgateradar_1028.bin")
.fileName("calgateradar_1028.bin")
.checkMd5(" ")// 没有md5校验直接空字符串就行
.callback(new YModemListener() {
如果放在apk中: