|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import cn.hutool.core.util.HexUtil; | 
|---|
|  |  |  | import com.dy.common.util.ByteUtil; | 
|---|
|  |  |  | import com.dy.common.util.CRC16; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | import java.io.*; | 
|---|
|  |  |  | import java.util.ArrayList; | 
|---|
|  |  |  | import java.util.List; | 
|---|
|  |  |  | import java.util.stream.Stream; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | private static final int hexFileMinLine = 4 ; | 
|---|
|  |  |  | private static final int lineHeadEndIndex = 9 ; | 
|---|
|  |  |  | private static final int bytesSplitUnit = 512 ; | 
|---|
|  |  |  | private static final int lineValidCharCount = 43 ;//每行有效字符(冒号与十六进制)个数,例如“:1096C000DC96010010020020203E00000441000052”,但倒数第3行不受限制 | 
|---|
|  |  |  | private static final int bytesSplitUnit512 = 512 ; | 
|---|
|  |  |  |  | 
|---|
|  |  |  | public static void main(String[] args) throws Exception{ | 
|---|
|  |  |  | boolean fromBytes = true ; | 
|---|
|  |  |  | boolean fromBytes = false ; | 
|---|
|  |  |  | HexFileParse obj = new HexFileParse() ; | 
|---|
|  |  |  | if(!fromBytes){ | 
|---|
|  |  |  | String filePath = "D:\\hexFile\\YuanMu_edit241007_01.hex"; | 
|---|
|  |  |  | String filePath = "D:\\hexFile\\YuanMu_20250116_01.hex"; | 
|---|
|  |  |  | //File file = new File(filePath) ; | 
|---|
|  |  |  | HexFileVo vo =  obj.doParse(filePath) ; | 
|---|
|  |  |  | System.out.println(vo.toString()); | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | String filePath = "D:\\hexFile\\YuanMu_edit241007_01.hex"; | 
|---|
|  |  |  | String filePath = "D:\\hexFile\\YuanMu_20250116_01.hex"; | 
|---|
|  |  |  | File file = new File(filePath) ; | 
|---|
|  |  |  | byte[] fileContent = new byte[(int)file.length()] ; | 
|---|
|  |  |  | FileInputStream fileInputStream = new FileInputStream(file) ; | 
|---|
|  |  |  | 
|---|
|  |  |  | HexFileVo vo = new HexFileVo() ; | 
|---|
|  |  |  | this.checkAndCalculate(vo, lineList); | 
|---|
|  |  |  | this.parse(vo, lineList); | 
|---|
|  |  |  | this.split(vo); | 
|---|
|  |  |  | this.splitBytesByUnit512(vo); | 
|---|
|  |  |  | this.calculateCrc(vo); | 
|---|
|  |  |  | return vo ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | HexFileVo vo = new HexFileVo() ; | 
|---|
|  |  |  | this.checkAndCalculate(vo, lineList); | 
|---|
|  |  |  | this.parse(vo, lineList); | 
|---|
|  |  |  | this.split(vo); | 
|---|
|  |  |  | this.splitBytesByUnit512(vo); | 
|---|
|  |  |  | this.calculateCrc(vo); | 
|---|
|  |  |  | return vo ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | 
|---|
|  |  |  | if(vo.totalLines < hexFileMinLine){ | 
|---|
|  |  |  | throw new Exception("Hex文件内容行数" + vo.totalLines + "不正确(最小行数" + hexFileMinLine +")") ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | vo.calculateBytes = ((vo.totalLines - 4) * 32) / 1024 * 512 ; | 
|---|
|  |  |  | vo.calculateBytes = ((((vo.totalLines - 4) * 32) / 1024) | 
|---|
|  |  |  | + ((((vo.totalLines - 4) * 32) % 1024) > 0?1 : 0)) | 
|---|
|  |  |  | * 512 ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | 
|---|
|  |  |  | if(!line.startsWith(":")){ | 
|---|
|  |  |  | vo.errors.add("第" + counter + "行内容不是以:开头") ; | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | line = line.substring(lineHeadEndIndex, line.length() - 2) ; | 
|---|
|  |  |  | if(vo.bytes.length == 0){ | 
|---|
|  |  |  | vo.bytes = HexUtil.decodeHex(line) ; | 
|---|
|  |  |  | if(counter != vo.totalLines - 3 && line.length() != lineValidCharCount){ | 
|---|
|  |  |  | //无效数据,舍弃本行数据 | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | byte[] bytes = HexUtil.decodeHex(line) ; | 
|---|
|  |  |  | vo.bytes = ByteUtil.bytesMerge(vo.bytes, bytes) ; | 
|---|
|  |  |  | line = line.substring(lineHeadEndIndex, line.length() - 2) ; | 
|---|
|  |  |  | if(vo.bytes.length == 0){ | 
|---|
|  |  |  | vo.bytes = HexUtil.decodeHex(line) ; | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | byte[] bytes = HexUtil.decodeHex(line) ; | 
|---|
|  |  |  | vo.bytes = ByteUtil.bytesMerge(vo.bytes, bytes) ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 以512为单位分割数据包 | 
|---|
|  |  |  | * @param bytes | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | public List<byte[]> splitBytesByUnit512(byte[] bytes){ | 
|---|
|  |  |  | List<byte[]> listByte512 = new ArrayList<>(); | 
|---|
|  |  |  | if(bytes != null && bytes.length > 0){ | 
|---|
|  |  |  | int index = 0 ; | 
|---|
|  |  |  | while (true){ | 
|---|
|  |  |  | if(index < bytes.length){ | 
|---|
|  |  |  | byte[] bs = ByteUtil.bytesSplit(bytes, index, bytesSplitUnit512) ; | 
|---|
|  |  |  | listByte512.add(bs) ; | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | break ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | index += bytesSplitUnit512; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | return listByte512 ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 以512为单位分割数据包 | 
|---|
|  |  |  | * @param vo | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | private void split(HexFileVo vo){ | 
|---|
|  |  |  | private void splitBytesByUnit512(HexFileVo vo){ | 
|---|
|  |  |  | if(vo.bytes != null && vo.bytes.length > 0){ | 
|---|
|  |  |  | vo.realBytes += vo.bytes.length ; | 
|---|
|  |  |  | int index = 0 ; | 
|---|
|  |  |  | while (true){ | 
|---|
|  |  |  | if(index < vo.bytes.length){ | 
|---|
|  |  |  | byte[] bytes = ByteUtil.bytesSplit(vo.bytes, index, bytesSplitUnit) ; | 
|---|
|  |  |  | byte[] bytes = ByteUtil.bytesSplit(vo.bytes, index, bytesSplitUnit512) ; | 
|---|
|  |  |  | vo.listByte512.add(bytes) ; | 
|---|
|  |  |  | vo.totalBytes512 += bytes.length ; | 
|---|
|  |  |  | }else{ | 
|---|
|  |  |  | break ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | index += bytesSplitUnit ; | 
|---|
|  |  |  | index += bytesSplitUnit512; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | /** | 
|---|
|  |  |  | * 计算CRC16 | 
|---|
|  |  |  | * @param vo | 
|---|
|  |  |  | */ | 
|---|
|  |  |  | private void calculateCrc(HexFileVo vo){ | 
|---|
|  |  |  | int crc = 0xffff ; | 
|---|
|  |  |  | if(vo.listByte512 != null && vo.listByte512.size() > 0){ | 
|---|
|  |  |  | CRC16 crc16 = new CRC16() ; | 
|---|
|  |  |  | for(byte[] bs : vo.listByte512){ | 
|---|
|  |  |  | crc =  crc16.CRC16_table(bs.length, bs, crc) ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  | } | 
|---|
|  |  |  | vo.bytesCrc16 = crc ; | 
|---|
|  |  |  | } | 
|---|
|  |  |  |  | 
|---|
|  |  |  | } | 
|---|