YModem在Android上的实现(二)

本节着重介绍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中:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值