网站首页 > 技术文章 正文
因工作关系有机会与一家做汽车数据采集公司的Tbox终端产品做数据对接。
这个产品通过can口与汽车总线交换数据,再将采集的数据打包通过4G以tcp报文发送到云端。云端通过解析、格式转换后保存到数据库。
本文介绍用nodejs实现tcp报文的解析,报文描述如下:
TBOX通讯协议描述
协议:TCP
采用固定帧长度:186(4+20+16*10+2)字节
帧头(固定4字节) | 设备序列号(20字节) | 数据包1 (16字节) | 数据包2 (16字节) | ... | 数据包10 (16字节) | CRC16校验 (2字节) |
帧头: AABB ( ASCII码格式,4 字节)
设备序列号: ICITBOX_202103240040 (ASCII码格式,20字节)
数据包: 格式见下表
CRC16校验: 计算方法,见文档附录,从帧头开始,至数据的最后一个字节结束(共184字节)
数据包格式(长度固定为16byte):
时间(4字节) | CAN-ID(4字节) | CAN-Data(8字节) |
时间: unix时间戳
CAN-ID(32bit) :
bit0 -28 : CAN-ID
bit29-31: 无效
CAN-Data:CAN的8字节数据(具体含义参见CAN协议文档)
协议解析举例:
时间戳: 0x6049CFB4 -- 转北京时间:2021-03-11 16:07:16
ID: 0xF41A0301 (bit29-31无效) 则为:0x141A0301
数据: 0x03 0x10 0xC0 0x0F 0x3A 0x38 0x40 0x3D
解决思路:
1、通过ID数据项描述,提炼出数学模型;
2、编写js脚本,通过模拟payload数据驱动脚本,依据数据结构进行相应的处理,并将处理结果返回json格式;
{ // 数学建模-- 结构标准化
"ID": "141A0301",
"name": "组合仪表显示信息(3)",
"Byte": [{
"start": 0,
"length": 2,
"mark": "Oct",
"off": 0,
"unit": "mV",
"res": 1,
"type":"BIG",
"values": [{
"name": "电池最高单体电压",
"pinyin":"dczgdtdy",
"start": 0,
"bits": 16,
"mark": "Oct"
}]
},
{
"start": 2,
"length": 2,
"mark": "Oct",
"off": 0,
"unit": "mV",
"res": 1,
"type":"BIG",
"values": [{
"name": "电池最低单体电压",
"pinyin":"dczddtdy",
"start": 0,
"bits": 16,
"mark": "Oct"
}]
},
{
"start": 4,
"length": 1,
"mark": "Oct",
"off": -40,
"unit": "℃",
"res": 1,
"type":"BIG",
"values": [{
"name": "电池最高温度",
"pinyin":"dczgwd",
"start": 0,
"bits": 8,
"mark": "Oct"
}]
},
{
"start": 5,
"length": 1,
"mark": "Oct",
"off": -40,
"unit": "℃",
"res": 1,
"type":"BIG",
"values": [{
"name": "电池最低温度",
"pinyin":"dczdwd",
"start": 0,
"bits": 8,
"mark": "Oct"
}]
},
{
"start": 6,
"length": 1,
"mark": "Oct",
"off": -40,
"unit": "℃",
"res": 1,
"type":"BIG",
"values": [{
"name": "电机控制器温度",
"pinyin":"djkzqwd",
"start": 0,
"bits": 8,
"mark": "Oct"
}]
},
{
"start": 7,
"length": 1,
"mark": "Oct",
"off": -40,
"unit": "℃",
"res": 1,
"type":"BIG",
"values": [{
"name": "电机温度",
"pinyin":"djwd",
"start": 0,
"bits": 8,
"mark": "Oct"
}]
}
/*
* payload 车载终端数据定义
* ID 车载ID
* xxx 车载数据
*
*/
function dealTBox(payload,ID){
//var xxx= "8310C00F3A38403D";
var res = [];
// decode payload to string
for( var key in payload ){
if(payload[key]['ID'] == ID){
console.log(ID);
console.log(payload[key]["name"]);
var js = payload[key]['Byte'];
var byx = [];
/*for(var k in js)
//by.push(xxx.substring(js[k]['start'],js[k]['start']+js[k]['length']*2));
if(js[k]['type'] == "BIG"){
by.push(hexToDecLE2(xxx.substring(js[k]['start'],js[k]['start']+js[k]['length']*2)));
}else{
by.push(xxx.substring(js[k]['start'],js[k]['start']+js[k]['length']*2));
}*/
for(var l in js){
if(js[l]['values']){
var js_v = js[l]['values']; // 外层values
if(js[l]['type'] == "BIG"){ // 判断大小端模式,截取数据长度
var by = hexToDecLE2(xxx.substring(js[l]['start']*2,js[l]['start']*2+js[l]['length']*2));
}else{
var by = xxx.substring(js[l]['start']*2,js[l]['start']*2+js[l]['length']*2);
}
for(var v in js_v){ // 进入第一层values循环
if(js[l]['mark'] == "Bin"){ // 需要解析为二进制?
var sum_len = js[l]['length'] * 8;
console.log("sum_len:"+sum_len);
var lll = hex_to_bin(by); // 对应截取的数据转2进制
console.log(lll);
var t_start = sum_len - js_v[v]["start"] - js_v[v]["bits"]; // 2进制字串的截取开始位
var t_end = t_start + js_v[v]["bits"]; // 2进制字串的截取结束位
console.log(t_start + "------" + t_end);
console.log(lll.substring(t_start,t_end));
var v_n = lll.substring(t_start,t_end);
if(js_v[v]["mark"] == "Oct"){
var v_n_oct = parseInt(v_n,2);
if(js_v[v]["values"]){ // 如果还有对十进制的结果有定义,可以直接读取values数组
console.log(js_v[v]["name"] +":"+ js_v[v]["values"][v_n_oct] +" "+ js[l]["unit"]);
byx.push('{"'+js_v[v]["name"]+'":"'+js_v[v]["values"][v_n_oct]+'"}');
res
}else{
console.log(js_v[v]["name"] +":"+ v_n_oct +" "+ js[l]["unit"]);
byx.push('{"'+js_v[v]["name"]+'":"'+(v_n_oct*1 + js[l]["off"]*1)+'"}');
}
}
}else if(js[l]['mark'] == "Oct"){ // 直接解析为10进制
console.log(by);
var lll = hexToDec(by); // 对应截取的数据转10进制
if(js_v[v]["values"]){ // 如果还有对十进制的结果有定义,可以直接读取values数组
console.log(js_v[v]["name"] +":"+ js_v[v]["values"][lll] +" "+ js[l]["unit"]);
byx.push('{"'+js_v[v]["name"]+'":"'+js_v[v]["values"][lll]+'"}');
}else{
console.log(js_v[v]["name"] +":"+ lll +" "+ js[l]["unit"]);
byx.push('{"'+js_v[v]["name"]+'":"'+(lll*1 + js[l]["off"]*1)+'"}');
}
}
//console.log(js[l]['values'][v]['name'])
}
}
}
res.push(JSON.parse('{"deviceName":'+'"'+payload[key]["name"]+'","body":['+byx.join(",")+']}'));
}
}
return res;
}
处理结果
猜你喜欢
- 2024-12-20 微软确认Win10更新出现问题:建议完全重置系统
- 2024-12-20 【MFRC522】STM32 MFRC522 IC读卡 程序及原理图
- 2024-12-20 win10更新又双叒翻车 这几天出了这些问题都是它的锅
- 2024-12-20 微软 Win10 KB5003173 更新安装失败,原因是没有新版 Edge浏览器
- 2024-12-20 今年最后一次可选更新:微软Win11推送26100.2454
- 2024-12-20 关于BIOS的入口地址0xFFFF0 bios information
- 2024-12-20 部分Win11 24H2用户反馈微软12月更新BUG:安装失败、蓝屏等
- 2024-12-20 Win10用户反馈安装微软3月更新时遇到0xd0000034错误
- 2024-12-20 Win11 22H2 (KB5017321) 安装更新失败如何修复
- 2024-12-20 R730调整风扇转速 r710风扇速度设置
- 02-21走进git时代, 你该怎么玩?_gits
- 02-21GitHub是什么?它可不仅仅是云中的Git版本控制器
- 02-21Git常用操作总结_git基本用法
- 02-21为什么互联网巨头使用Git而放弃SVN?(含核心命令与原理)
- 02-21Git 高级用法,喜欢就拿去用_git基本用法
- 02-21Git常用命令和Git团队使用规范指南
- 02-21总结几个常用的Git命令的使用方法
- 02-21Git工作原理和常用指令_git原理详解
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)