**JAVA实现GBT32960报文解析系列文章链接:**
JAVA实现GBT32960报文解析(一):协议的数据类型和完整的报文结构解析
JAVA实现GBT32960报文解析(二):数据包结构解析源码
JAVA实现GBT32960报文解析(三):0x01整车数据解析源码
JAVA实现GBT32960报文解析(四):0x02驱动电机数据解析源码
JAVA实现GBT32960报文解析(五):0x03燃料电池数据解析源码(待更…)
JAVA实现GBT32960报文解析(六):0x04发动机数据解析源码(待更…)
JAVA实现GBT32960报文解析(七):0x05车辆位置数据解析源码(待更…)
JAVA实现GBT32960报文解析(八):0x06极值数据解析源码(待更…)
JAVA实现GBT32960报文解析(九):0x07报警数据解析源码(待更…)
实战需求示例:车辆月度充电详情统计报表,含快充、慢充区分统计(待更…)
在做报文的封装或者解析工作前,首先要对“各种进制”有一个简单的了解。大家可以通过百度百科对进制进行初步了解。
十六进制信息从阅读清晰到简洁传输:
在c语言中用添加前缀0x以表示十六进制数,也就是最前面的形式。但报文数据在需要作数据传输时,就需要更多的考虑到简洁化,因此我们的报文信息往往都是最后这种形式“一长串看似无规则的字符”。
通过对《GBT32960.3-2016》这份协议文档的阅读,能够发现以上各数据类型常用于使用的数据如下:
BYTE:各种状态或数值长度在3位数以内的数据;
WORD:数值长度在5位数以内。例如电压值、电流值、转速;
DWORD:数值长度在8位数以内。例如历史行驶里程数、坐标经纬度;
BYTE[,]:例如燃料电池的温度探针会涉及N个;
STRING:车辆VIN码、SIM卡的ICCID
结合以上对数据类型的了解,其实我们也就只需要准备3、4个针对十六进制字符解析的方法就能完全满足。
代码如下(示例):
String hexStr = "232303FE584C32434546355030414C30303730323301012D15071C110B320102030100000000010E0C58271000021013510065020101014F4E204E2055001F271005000633555501D2D2CE0601220D00011F0B1501014B010B49070300000450000000000801010C58271000600001600CBD0CD90CD00CCF0CE00CF00CE00CCB0CE10CE00CDF0CC80CC50CD30CCF0CE70CE50CE30CD90CE90CF60CEF0CE10CDF0CEA0CED0CE80CD10CDA0CEE0B150CD30CED0D000CCA0CED0CD60CDA0CED0CDC0CE70CF00CED0CDF0CF40CF30CDC0CE50CE00CEF0CE10CD20CDD0CE80CD60CEA0CDD0CE90CD90CD60CC90CCB0CDE0CCC0CD30CD60CE60CF20CE20CCC0CE90CE40CF80CA00CE50CE10CE90CE80CE20CF70CF50CEA0CCD0CF80CE50CDD0CE00CE10CE90CDD0CEB0CEE0CF40CF60CFC0CE109010100104B4A4A4A4949494A4A49494A4A4A4A4A5F";
国标报文大部分都是作数值处理,因此我没有采用第6行代码将"0x"带进去造成多余的处理。
public static String[] hexStrToArray(String hexStr) {
String[] array = new String[hexStr.length() / 2];
int k = 2;
for (int i = 0; i < array.length; i++) {
array[i] = hexStr.substring(i * 2, k);
//array[i] = "0x" + hexStr.substring(i * 2, k);
k += 2;
}
return array;
}
十六进制转数值其实很粗暴,直接使用java.lang包的Integer.parseInt(String, int)方法
代码如下(示例):
int value = Integer.parseInt(hexStr, 16);
代码如下(示例):
public static String hexStr2Byte(String hexStr) {
if (null == hexStr || 0 != hexStr.length() % 2)
return null;
String bString = "", tmp;
for (int i = 0; i < hexStr.length(); i++) {
tmp = "0000" + Integer.toBinaryString(Integer.parseInt(hexStr.substring(i, i + 1), 16));
bString += tmp.substring(tmp.length() - 4);
}
return bString;
}
代码如下(示例):
public static String hexStr2Str(String hexStr) {
if (null == hexStr || hexStr.equals("")) {
return null;
}
hexStr = hexStr.replace(" ", "");
byte[] baKeyword = new byte[hexStr.length() / 2];
try {
for (int i = 0; i < baKeyword.length; i++) {
baKeyword[i] = (byte) (0xff & Integer.parseInt(hexStr.substring(i * 2, i * 2 + 2), 16));
}
hexStr = new String(baKeyword, "UTF-8");
new String();
} catch (Exception e) {
e.printStackTrace();
}
return hexStr;
}
一个完整的数据包结构应由起始符号、命令单元、唯一识别码(也就是车辆的VIN码)、数据加密方式、数据单元长度、数据单元和效验码组成。
注:在数据包中的数据单元会存在N个,而数据单元具体有哪些,则是根据“车辆实际状况”和“命令标识”而定。
以下是各种数据单元信息,对应的信息类型标识。
针对上表中备注所提及的详见位置内容,作一个简单的解读。如下:
0x01整车数据:车辆一般运营数据,以仪表盘数据为主;
0x02驱动电机数据:以电机控制器数据为主,车辆充电时可不传输;
0x03燃料电池数据:采用燃料电池驱动的车辆需传输此项,如无此种可充电储能子系统可不传输;
0x04发动机数据:采用油电混合的车辆需在使用发动机时传输此项数据;
0x05车辆位置数据:车辆GPS或北斗位置数据,一般使用车载终端的GPS信号,如车载终端无GPS数据,也可使用车辆数据;
0x06极值数据:车辆特征点数据,可作为绝大多数车辆故障判定依据;
0x07报警数据:车辆本身判定发生报警后上传的报警信息;
0x30~0x7F预留数据:单体信息预留信息类型;
其他:均为终端、平台交互、用户等角度的自定义数据;
为什么没提及“命令标识”就直接讲数据单元有哪些信息类型,因为我打算先从数据进行分析的角度去做讲解。而不是一开始就根据命令标识来做业务的处理。
为了数据更简单的实体化使用,把完整的数据包直接拆分为两个大的分类,即:头部信息和各数据单元信息。
从下一篇文章开始,正式对GB32960协议进行报文解析分享。将用一段命令标识为0x02【实际信息上报】的完整数据包进行逐字节解析
** 相关下载:**
国标协议GBT32960文档 (包含《GB/T 32960-2016 电动汽车远程服务与管理系统技术规范》完整的1、2、3部分)
源码部分:
JAVA解析GBT32960协议 - 数据包结构源码(另含ParseUtils.java和BCCVerifyUtils.java两个工具类)
JAVA解析GBT32960协议 - 0x01整车数据源码
JAVA解析GBT32960协议 - 0x02驱动电机数据源码
JAVA解析GBT32960协议 - 0x03燃料电池数据源码(待更…)
JAVA解析GBT32960协议 - 0x04发动机数据源码(待更…)
JAVA解析GBT32960协议 - 0x05车辆位置数据源码(待更…)
JAVA解析GBT32960协议 - 0x06极值数据源码(待更…)
JAVA解析GBT32960协议 - 0x07报警数据源码(待更…)