android蓝牙通信和Hex文件解析升级

针对蓝牙硬件里的软件程序包HEX文件解析和升级

1、思路
    
    选择手机中的HEX升级包文件,比如(/Download下的 update.hex),
    然后通过java读取文件每一行获取每一行的数据,然后根据HEX文件数据的规则来解析,
    
    hex文件数据:
        
        android蓝牙通信和Hex文件解析升级_第1张图片
    
    hex文件规则:https://blog.csdn.net/a1037488611/article/details/43340055
                 https://www.cnblogs.com/blogzhangwei/p/8781183.html
                 https://blog.csdn.net/artmcu/article/details/8151581?utm_source=blogxgwz1
                 
2、hex文件中数据要注意的有:
    
    比如:
    
        :020000040800F2
        :04BFF00003000156F3
        :020000040800F2
        :10C00000806B002039C1000869F200083DE5000896
        :10C0100065F20008B9DA0008F91F01080000000005
        :106B20003C2910191729102988E9782A543CF100CA
        :040000050800C12509
        :00000001FF
        
    格式:
        
        :020000040800F2 , 其实就是字节串: 0x02 0x00 0x00 0x04 0x08 0x00 0xF2
        
        第一个 0x02 为数据长度。
      紧跟着后面的0x00 0x00 为地址。
      再后面的0x04为数据类型,类型共分以下几类:
      '00' Data Record
      '01' End of File Record
      '02' Extended Segment Address Record
      '03' Start Segment Address Record
      '04' Extended Linear Address Record
      '05' Start Linear Address Record
      然后,接着0x04后面的两个 0x00 0x00就是数据。最后一个0xFA是校验码。
    
    
    解析:也就是说每一行的数据格式是:[数据长度1Byte]、[数据地址2Byte]、[数据类型1Byte]、[数据nByte]、[校验1Byte]
    
        原数据【:020000040800F2】
        解析:【02  0000  04 0800 F2】  04是段地址数据行
        
        原数据【:04BFF00003000156F3】
        解析:【04  BFF0  00  03000156 F3】 00是有效数据,取的是00后面的4个字节03000156
        
        原数据【:020000040800F2】
        解析:【02  0000  04 0800 F2】  04是段地址数据行
        
        原数据【:10C00000806B002039C1000869F200083DE5000896】
        解析:【10  C000  00 806B002039C1000869F200083DE50008 96】 
               C000是偏移地址,00是有效数据,取的是00后面的16(10转16进制)个字节806B002039C1000869F200083DE50008
        
        原数据【:10C0100065F20008B9DA0008F91F01080000000005】
        解析:【10  C010  00 65F20008B9DA0008F91F010800000000 05】  
               C010是偏移地址,00是有效数据,取的是00后面的16(10转16进制)个字节65F20008B9DA0008F91F010800000000
        
        原数据【:106B20003C2910191729102988E9782A543CF100CA】
        解析:【10  6B20  00 3C2910191729102988E9782A543CF100 CA】  
               6B20是偏移地址,00是有效数据,取的是00后面的16(10转16进制)个字节3C2910191729102988E9782A543CF100
        
        原数据【:040000050800C12509】
        解析:【04  0000  05 0800C125 09】  05是开始行地址记录,一般不会对05数据处理
        
        原数据【:00000001FF】
        解析:【00  0000  01 FF】  01是文件结束标志行

        
3、文件解析的android端代码:(解析部分重点)

     /**
     * 解析HEX文件,读取每行并拆解成数据对象(包括第一行段地址)
     * @param filePath      String
     * @return              List
     */
    private static List analysisFile(String filePath) {
        File tempFile = new File(filePath);
        List fileStructList = new ArrayList<>();
        InputStream inputStream = null;
        BufferedReader bufferedReader = null;
        try {
            inputStream = new FileInputStream(tempFile);
            //转成 reader 以 行 为单位读取文件
            bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            //当前行字符串
            String hexLineStr;
            while ((hexLineStr = bufferedReader.readLine()) != null) {
                if (!hexLineStr.startsWith(":", 0)) {
                    return null;
                }
                FileStruct hex = new FileStruct();
                if (hexLineStr.length() >= 11) {
                    hex.setStart(":");
                    byte[] data = hexString2ByteArray(hexLineStr.substring(1));//判断数据的正确是是不是0—F
                    if (data == null) return null;
                    //解析数据
                    hex.setLength(Integer.parseInt(hexLineStr.substring(1, 3), 16));
                    hex.setOffset(Integer.parseInt(hexLineStr.substring(3, 7), 16));
                    hex.setType(Integer.parseInt(hexLineStr.substring(7, 9), 16));

                    if (0x05 == hex.getType()|| 0x01 == hex.getType()) {//不处理05类型的数据,和01的结尾数据
                        continue;
                    }
                    if (hex.getLength() > 0) {
                        hex.setData(hexLineStr.substring(9, 9 + hex.getLength() * 2));
                    }
                }
                if (!checkValue(hexLineStr)) return null;
                //判断数据类型是否合法,只处理00有效数据
                fileStructList.add(hex);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
                if (bufferedReader != null) {
                    bufferedReader.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return fileStructList;
    }
     这里只是给出读取每一行数据的解析过程,
    具体数据List看自己需要,也可以跟我扯扯,
    交流一下:扫码关注公众号回复(HEX解析),获取微信号加我。

                      android蓝牙通信和Hex文件解析升级_第2张图片
4、解析HEX的数据组合成自己对接硬件要求的数据格式,转成字节数组传输写入。
    
    硬件要求的数据格式,比如:段地址+偏移地址+长度+有效数据+校验和
    
5、写入蓝牙硬件,一般在android端对接蓝牙硬件设备的时候,设备厂商都会给出对应的读写SDK,
    所以集成好SDK(SDK的集成简单,只要注意一些权限即可),然后通过字节流数据写入即可。

    当然没有对应的SDK,自己也可以对蓝牙通信部分配合硬件去调试,也是通过字节写入,调通即可。
    
6、在解析HEX的过程中会用到16进制10进制的转换、高低位替换、字节流和字符串的转换等等,
    这里给出我写的对应转换方法的工具类。

    

/**
 * Description: 解析Hex文件工具类
 * Author: BAI
 * Date: 2020/6/19 14:33
 * Email : [email protected]
 **/
public class HexUtil {

    /**
     * 获取Hex文件里的00类型的所有有效数据的字节字符串
     * @param filePath  String 文件地址
     * @return          String 字节字符串  【用做有效00数据的校验和】
     */
    public static String getHexFile00ValidData(String filePath) {
        List totalList= analysisFile(filePath);
        if(totalList==null){
            return null;
        }

        List> partSplitList = getPartSplitList(totalList);
        StringBuilder stringBuilder = new StringBuilder();

        //第一段数据默认是版本号信息,所以   不做返回
        for(int partIndex=1;partIndex map = new HashMap<>();
        for(int i = 0;i <= 9;i++){
            map.put(i+"",i);
        }
        for(int j= 10;j splitBytes(byte[] bytes, int size) {
        double splitLength = Double.parseDouble(size + "");
        int arrayLength = (int) Math.ceil(bytes.length / splitLength);

        List resultList = new ArrayList<>();
        int from, to;
        for (int i = 0; i < arrayLength; i++) {
            from = (int) (i * splitLength);
            to = (int) (from + splitLength);
            if (to > bytes.length)
                to = bytes.length;
            resultList.add(Arrays.copyOfRange(bytes, from, to));
        }
        return resultList;
    }

}


    
7、对数据CRC16Check的算法校验,这个每个硬件的要求都不同,不过都差不多,硬件那边给出的C文件,可以在这个基础上修改。
    

/**
 * Description: 对HEX文件的00类型的纯数据进行CRC16校验
 * Author: BAI
 * Date: 2020/6/23 17:33
 * Email : [email protected]
 **/
public class CRC16CheckUtil {

    /**
     * 查表法计算CRC16校验
     *
     * @param data 需要计算的字节数组
     */
    public static String getCRC16(byte[] data) {
        byte[] crc16_h = {
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41,
                (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40
        };

        byte[] crc16_l = {
                (byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04,
                (byte) 0xCC, (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8,
                (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC,
                (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12, (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10,
                (byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4,
                (byte) 0x3C, (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE, (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38,
                (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C,
                (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7, (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0,
                (byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66, (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4,
                (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9, (byte) 0xA8, (byte) 0x68,
                (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C,
                (byte) 0xB4, (byte) 0x74, (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0,
                (byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54,
                (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58, (byte) 0x98,
                (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D, (byte) 0x4C, (byte) 0x8C,
                (byte) 0x44, (byte) 0x84, (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40
        };

        int crc;
        int ucCRCHi = 0x00ff;
        int ucCRCLo = 0x00ff;
        int iIndex;
        for (byte aData : data) {
            iIndex = (ucCRCLo ^ aData) & 0x00ff;
            ucCRCLo = ucCRCHi ^ crc16_h[iIndex];
            ucCRCHi = crc16_l[iIndex];
        }

        crc = ((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;
        //高低位互换,输出符合相关工具对Modbus CRC16的运算
        crc = ( (crc & 0xFF00) >> 8) | ( (crc & 0x00FF ) << 8);
        return String.format("%04X", crc);
    }

}

8、具体hex解析逻辑可以具体沟通。
    

 

你可能感兴趣的:(android)