New file |
| | |
| | | package com.dy.common.softUpgrade.parse; |
| | | |
| | | 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; |
| | | |
| | | /** |
| | | * @Author: liurunyu |
| | | * @Date: 2024/11/2 8:51 |
| | | * @Description |
| | | */ |
| | | public class HexFileParse { |
| | | |
| | | private static final int hexFileMinLine = 4 ; |
| | | private static final int lineHeadEndIndex = 9 ; |
| | | private static final int lineValidCharCount = 43 ;//每行有效字符(冒号与十六进制)个数,例如“:1096C000DC96010010020020203E00000441000052”,但倒数第3行不受限制 |
| | | private static final int bytesSplitUnit512 = 512 ; |
| | | |
| | | public static void main(String[] args) throws Exception{ |
| | | boolean fromBytes = false ; |
| | | HexFileParse obj = new HexFileParse() ; |
| | | if(!fromBytes){ |
| | | 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_20250116_01.hex"; |
| | | File file = new File(filePath) ; |
| | | byte[] fileContent = new byte[(int)file.length()] ; |
| | | FileInputStream fileInputStream = new FileInputStream(file) ; |
| | | fileInputStream.read(fileContent) ; |
| | | HexFileVo vo = obj.doParse(fileContent) ; |
| | | System.out.println(vo.toString()); |
| | | } |
| | | } |
| | | /** |
| | | * 解析Hex文件 |
| | | * @param path |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public HexFileVo doParse(String path) throws Exception { |
| | | File file = new File(path) ; |
| | | return this.doParse(file) ; |
| | | } |
| | | |
| | | /** |
| | | * 解析Hex文件 |
| | | * @param file |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public HexFileVo doParse(File file) throws Exception{ |
| | | if(file == null){ |
| | | throw new Exception("Hex文件对象为null") ; |
| | | } |
| | | if(!file.exists()){ |
| | | throw new Exception("Hex文件不存在") ; |
| | | } |
| | | Stream<String> linesStream = new BufferedReader(new FileReader(file)).lines() ; |
| | | List<String> lineList = linesStream.toList() ; |
| | | HexFileVo vo = new HexFileVo() ; |
| | | this.checkAndCalculate(vo, lineList); |
| | | this.parse(vo, lineList); |
| | | this.splitBytesByUnit512(vo); |
| | | this.calculateCrc(vo); |
| | | return vo ; |
| | | } |
| | | |
| | | /** |
| | | * 解析Hex文件 |
| | | * @param fileContent |
| | | * @return |
| | | * @throws Exception |
| | | */ |
| | | public HexFileVo doParse(byte[] fileContent) throws Exception{ |
| | | if(fileContent == null || fileContent.length == 0){ |
| | | throw new Exception("Hex文件对象为null") ; |
| | | } |
| | | ByteArrayInputStream byteInputStream = new ByteArrayInputStream(fileContent); |
| | | Stream<String> linesStream = new BufferedReader(new InputStreamReader(byteInputStream)).lines() ; |
| | | List<String> lineList = linesStream.toList() ; |
| | | HexFileVo vo = new HexFileVo() ; |
| | | this.checkAndCalculate(vo, lineList); |
| | | this.parse(vo, lineList); |
| | | this.splitBytesByUnit512(vo); |
| | | this.calculateCrc(vo); |
| | | return vo ; |
| | | } |
| | | |
| | | /** |
| | | * 合法性检查,并计算数据包数 |
| | | * @param vo |
| | | * @param lineList |
| | | * @throws Exception |
| | | */ |
| | | private void checkAndCalculate(HexFileVo vo, List<String> lineList) throws Exception{ |
| | | if(lineList == null){ |
| | | throw new Exception("Hex文件内容为空") ; |
| | | } |
| | | vo.totalLines = lineList.size() ; |
| | | if(vo.totalLines <= 0){ |
| | | throw new Exception("Hex文件内容为空") ; |
| | | } |
| | | if(vo.totalLines < hexFileMinLine){ |
| | | throw new Exception("Hex文件内容行数" + vo.totalLines + "不正确(最小行数" + hexFileMinLine +")") ; |
| | | } |
| | | vo.calculateBytes = ((((vo.totalLines - 4) * 32) / 1024) |
| | | + ((((vo.totalLines - 4) * 32) % 1024) > 0?1 : 0)) |
| | | * 512 ; |
| | | } |
| | | |
| | | /** |
| | | * 解析Hex文件内容,组合成一个大数据包 |
| | | * @param vo |
| | | * @param lineList |
| | | * @throws Exception |
| | | */ |
| | | private void parse(HexFileVo vo, List<String> lineList) throws Exception{ |
| | | int counter = 0 ; |
| | | for(String line : lineList){ |
| | | if(counter == 0){ |
| | | // 文件头 |
| | | }else if(counter == vo.totalLines - 2){ |
| | | // 文件尾倒数第2行 |
| | | }else if(counter == vo.totalLines - 1){ |
| | | // 文件尾倒数第1行 |
| | | }else{ |
| | | // 文件内容 |
| | | if(line == null){ |
| | | vo.errors.add("第" + counter + "行内容为空") ; |
| | | }else{ |
| | | line = line.trim() ; |
| | | if(line.length() == 0){ |
| | | vo.errors.add("第" + counter + "行内容为空") ; |
| | | }else{ |
| | | if(!line.startsWith(":")){ |
| | | vo.errors.add("第" + counter + "行内容不是以:开头") ; |
| | | }else{ |
| | | if(counter != vo.totalLines - 3 && line.length() != lineValidCharCount){ |
| | | //无效数据,舍弃本行数据 |
| | | }else{ |
| | | 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) ; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | counter ++ ; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 以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 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, bytesSplitUnit512) ; |
| | | vo.listByte512.add(bytes) ; |
| | | vo.totalBytes512 += bytes.length ; |
| | | }else{ |
| | | break ; |
| | | } |
| | | 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 ; |
| | | } |
| | | |
| | | } |