Teltonika FMXXX系列定位器解析说明

1.产品外观

2.数据包说明

2.1.登录包

**模块第一次上线,先发送其对应的IMEI号,数据包如下:**
000F313233343536373839303132333435**数据包解析如下:**
000F --packet starts
313233343536373839303132333435 --IMEI 123456789012345**服务器收到此模块IMEI后,如果允许上线,则回复01,否则回复00**

2.2.定位数据包Codec 8

**模块运行上线后,上报定位数据包Codec 8**
000000000000003608010000016B40D8EA30010000000000000000000000000000000105021503010101425E0F01F10000601A014E0000000000000000010000C7CF**数据包解析如下:**
00 00 00 00 --packet starts
00 00 00 36 --Data field length
08 --Codec ID(Codec 8)
01 --Priority(0:Low;1:High;2:Panic;3:Security)
00 00 01 6B 40 D8 EA 30 --Timestamp
01 --Number of Data 1
00 00 00 00 --Longitude
00 00 00 00 --Latitude
00 00 --Altitude(In meters above sea level)
00 00 --Angle(In degrees, 0 is north, increasing clock-wise)
00 --Satellites(Number of visible satellites)
00 00 --Speed (Speed in km/h)
01 --Event IO ID – if data is acquired on event – this field defines which IO property has changed and generated an event. If data cause is not event – the value is 0.
05 --total number of properties coming with record (N=N1+N2+N4+N8)
02 --N1 number of properties, which length is 1 byte
15 03 
01 01 
01 --N2 number of properties, which length is 2 bytes
42 5E0F 
01 --N4 number of properties, which length is 4 bytes
F1 0000601A 
01 --N8 number of properties, which length is 8 bytes
4E 0000000000000000
01 --Number of Data2(This number must be the same as "number of Data 1")
0000C7CF --CRC-16**服务器收到数据后,应答收到的数据条数,对应的是数据包中的Number of Data,应答4个字节**
00000001

3.代码实例

服务端收到数据包,先进行初步解包:

package com.gnss.teltonika.netty.codec;import com.gnss.common.utils.SessionUtil;
import com.gnss.core.constants.ProtocolEnum;
import com.gnss.core.proto.TerminalProto;
import com.gnss.teltonika.model.TeltonikaMessage;
import com.gnss.teltonika.utils.PacketUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import lombok.extern.slf4j.Slf4j;import java.util.List;/*** Preprocess the received data* @author Mr.Li* @date 2024-07-25*/
@Slf4j
public class ProtocolDecoder extends ByteToMessageDecoder {private ProtocolEnum protocolType;public ProtocolDecoder(ProtocolEnum protocolType) {this.protocolType = protocolType;}@Overrideprotected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {TerminalProto terminalProto= SessionUtil.getTerminalInfo(ctx);if(terminalProto!=null) {log.info("received:{}:{}", terminalProto.getTerminalNum(), ByteBufUtil.hexDump(in));}else {log.info("received:{}", ByteBufUtil.hexDump(in));}Object decoded = null;in.markReaderIndex();if(in.readUnsignedShort()==0x000F) {in.resetReaderIndex();decoded = decodeLogin(in);}else{in.resetReaderIndex();Object obj = PacketUtil.decodePacket(in);if (obj != null) {decoded = decodeMessage(ctx,(ByteBuf) obj);}}if (decoded != null) {out.add(decoded);}}/*** Login package* @param frame* @return*/private TeltonikaMessage decodeLogin(ByteBuf frame){int msgLen=frame.readUnsignedShort();byte[] terminalNumArr=new byte[msgLen];frame.readBytes(terminalNumArr);String terminalNum=new String(terminalNumArr);TeltonikaMessage message=new TeltonikaMessage();//Give the login frame a default message ID of 0x01message.setMsgId(0x01);message.setMsgLen(msgLen);message.setTerminalNum(terminalNum);message.setTerminalNumArr(terminalNumArr);message.setProtocolType(protocolType);return message;}/*** Preliminary analysis of the message body to obtain basic information of the device* @param frame* @return*/private TeltonikaMessage decodeMessage(ChannelHandlerContext ctx,ByteBuf frame){frame.readInt();long bodyLen=frame.readUnsignedInt();//Codec IDint msgId=frame.readUnsignedByte();//记录条数int records=frame.readUnsignedByte();//size is calculated starting from Codec ID to Number of Data 2.byte[] bodyArr=new byte[(int)bodyLen-3];frame.readBytes(bodyArr);//Number Of Data 2frame.readByte();//CRC-16frame.readInt();String terminalNum = SessionUtil.getTerminalInfo(ctx).getTerminalNum();TeltonikaMessage message=new TeltonikaMessage();message.setMsgId(msgId);message.setMsgLen(bodyLen);message.setTerminalNum(terminalNum);message.setTerminalNumArr(terminalNum.getBytes());message.setProtocolType(protocolType);message.setMsgBodyArr(bodyArr);message.setMsgBody(Unpooled.wrappedBuffer(bodyArr));message.setDataNum(records);return message;}
}

然后根据不同的数据包ID进行详细解码Codec 8

package com.gnss.teltonika.utils;import com.gnss.core.proto.LocationProto;
import com.gnss.core.proto.TerminalProto;
import com.gnss.teltonika.model.TeltonikaMessage;
import io.netty.buffer.ByteBuf;import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;/*** Decoding of positioning data class* @author Mr.Li* @date 2024-07-26*/
public class LocationParser {/*** Decoding of positioning data* @param msg* @param terminalProto* @param msgBodyBuf* @return*/public static List<LocationProto> parseLocation(TeltonikaMessage msg, TerminalProto terminalProto, ByteBuf msgBodyBuf){List<LocationProto> locationProtoList=new ArrayList<>();while (msgBodyBuf.readableBytes()>24){long gpsTimestamp=msgBodyBuf.readLong();int priority=msgBodyBuf.readUnsignedByte();double lon=msgBodyBuf.readInt()/10000000.0;double lat=msgBodyBuf.readInt()/10000000.0;int altitude=msgBodyBuf.readUnsignedShort();int direction=msgBodyBuf.readUnsignedShort();//卫星个数int gpsSignal=msgBodyBuf.readUnsignedByte();int speed=msgBodyBuf.readUnsignedShort();int locationType=1;if(lon==0||lat==0) {locationType=0;}LocationProto locationProto=new LocationProto();if(msg.getMsgId()==0x08) {int eventIO = msgBodyBuf.readUnsignedByte();int totalIO = msgBodyBuf.readUnsignedByte();parseIO08(locationProto, msgBodyBuf, totalIO);}else if(msg.getMsgId()==0x8E||msg.getMsgId()==0x10){int eventIO = msgBodyBuf.readUnsignedShort();int totalIO = msgBodyBuf.readUnsignedShort();parseIO8E(locationProto, msgBodyBuf, totalIO);}//当前时间ZonedDateTime currentDateTime = ZonedDateTime.now(ZoneOffset.UTC);locationProto.setTerminalId(terminalProto.getTerminalId());locationProto.setTerminalNum(terminalProto.getTerminalNum());locationProto.setTerminalType(terminalProto.getTerminalType());locationProto.setVehicleId(terminalProto.getVehicleId());locationProto.setVehicleNum(terminalProto.getVehicleNum());locationProto.setGnssTime(ZonedDateTime.ofInstant(Instant.ofEpochMilli(gpsTimestamp), ZoneOffset.UTC).toString());locationProto.setRecvTime(currentDateTime.toString());locationProto.setGnssTimestamp(gpsTimestamp);locationProto.setRecvTimestamp(currentDateTime.toInstant().toEpochMilli());locationProto.setLocationType(locationType);locationProto.setLat(lat);locationProto.setLon(lon);locationProto.setSpeed(speed*1.0);locationProto.setDirection(direction);locationProto.setGnssValue(gpsSignal);locationProto.setBattery(-1);locationProto.setAltitude(altitude);locationProtoList.add(locationProto);}return locationProtoList;}/*** Analyze the IO content* @param locationProto* @param msgBodyBuf* @param totalIO*/private static void parseIO08(LocationProto locationProto,ByteBuf msgBodyBuf,int totalIO) {int n1Count=msgBodyBuf.readUnsignedByte();for(int n1=0;n1<n1Count;n1++){int avlID=msgBodyBuf.readUnsignedByte();int value=msgBodyBuf.readUnsignedByte();if(avlID==0x15){locationProto.setGsmValue(value);}}int n2Count =0;if(totalIO>n1Count && msgBodyBuf.readableBytes()>0) {n2Count = msgBodyBuf.readUnsignedByte();for(int n2=0;n2<n2Count;n2++){int avlID=msgBodyBuf.readUnsignedByte();int value=msgBodyBuf.readUnsignedShort();}}int n4Count =0;if(totalIO>(n1Count+n2Count) && msgBodyBuf.readableBytes()>0) {n4Count = msgBodyBuf.readUnsignedByte();for(int n4=0;n4<n4Count;n4++){int avlID=msgBodyBuf.readUnsignedByte();long value=msgBodyBuf.readUnsignedInt();if(avlID==0x10) {locationProto.setMileage(value*1.0);}}}if(totalIO>(n1Count+n2Count+n4Count) && msgBodyBuf.readableBytes()>0) {int n8Count = msgBodyBuf.readUnsignedByte();for(int n8=0;n8<n8Count;n8++){int avlID=msgBodyBuf.readUnsignedByte();long value=msgBodyBuf.readLong();}}}/*** Analyze the IO content* @param locationProto* @param msgBodyBuf* @param totalIO*/private static void parseIO8E(LocationProto locationProto,ByteBuf msgBodyBuf,int totalIO) {int n1Count=msgBodyBuf.readUnsignedShort();for(int n1=0;n1<n1Count;n1++){int avlID=msgBodyBuf.readUnsignedShort();int value=msgBodyBuf.readUnsignedByte();if(avlID==21){locationProto.setGsmValue(value);}}int n2Count =0;if(totalIO>n1Count && msgBodyBuf.readableBytes()>0) {n2Count = msgBodyBuf.readUnsignedShort();for(int n2=0;n2<n2Count;n2++){int avlID=msgBodyBuf.readUnsignedShort();int value=msgBodyBuf.readUnsignedShort();}}int n4Count =0;if(totalIO>(n1Count+n2Count) && msgBodyBuf.readableBytes()>0) {n4Count = msgBodyBuf.readUnsignedShort();for(int n4=0;n4<n4Count;n4++){int avlID=msgBodyBuf.readUnsignedShort();long value=msgBodyBuf.readUnsignedInt();if(avlID==0x10) {locationProto.setMileage(value*1.0);}}}int n8Count =0;if(totalIO>(n1Count+n2Count+n4Count) && msgBodyBuf.readableBytes()>0) {n8Count = msgBodyBuf.readUnsignedShort();for(int n8=0;n8<n8Count;n8++){int avlID=msgBodyBuf.readUnsignedShort();long value=msgBodyBuf.readLong();}}if(totalIO>(n1Count+n2Count+n4Count+n8Count) && msgBodyBuf.readableBytes()>0) {int nxCount = msgBodyBuf.readUnsignedShort();for(int nx=0;nx<nxCount;nx++){int length=msgBodyBuf.readUnsignedShort();byte[] nxArr=new byte[length];msgBodyBuf.readBytes(nxArr);}}}
}

专注各种物联网网关开发,有兴趣的朋友可以加一起交流学习。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3280738.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

区块链软硬件协同,做产业数字化转型的“安全官” |《超话区块链》直播预告

今年的两会政府工作报告提出&#xff1a;“产业的数字化&#xff08;行业数字化转型&#xff09;是发展新质生产力的核心&#xff0c;是推动产业升级实现高质量发展的关键。”全面推进产业数字化&#xff0c;需要技术创新与产业应用深入协同&#xff1b;立足可持续发展的长远目…

泰迪智能科技入选广东省2024年第三批职业技能等级认定社会培训评价组织名单

7月17日&#xff0c;根据《关于公布广东省2023年社会培训评价组织新申请机构进入培育辅导期名单的通知》&#xff08;粤人社函〔2023〕269号&#xff09;、《关于公布广东省2023年社会培训评价组织&#xff08;“产教评”链主培育单位&#xff09;进入培育辅导期名单的通知》&a…

网络安全是什么?怎么入门网络安全?

一、网络安全的定义 网络安全&#xff0c;简单来说&#xff0c;就是保护网络系统中的硬件、软件以及其中的数据不因偶然或恶意的原因而遭到破坏、更改、泄露&#xff0c;保障系统连续可靠正常地运行&#xff0c;网络服务不中断。 随着信息技术的飞速发展&#xff0c;网络安全的…

docker compose 安装 kafka

一 前置准备 创建 /data/kafkadata /data/zookeeper-1用于保存kafka和zookeeper的配置文件 kafkadata中创建三个文件夹 /kafka1 /kafka2 /kafka3&#xff0c;用于存放三个kafka节点的配置文件 zookeeper-1文件夹中创建 /conf /data /logs /datalog四个文件夹&#xff0c;用于…

IoTDB 入门教程 实战篇④——C#示例(开源)

文章目录 一、前文二、新建C#项目三、NuGet安装四、示例源码五、查询数据六、参考 一、前文 IoTDB入门教程——导读 本文详细阐述了如何通过一个C#项目成功连接到IoTDB时序数据库&#xff0c;进而展示了如何向该数据库高效地写入数据以及执行精确的数据查询操作。 此示例旨在为…

Redis高可用之持久化,以及reids的性能管理

一、redis高可用&#xff1a; 在集群当中有一个非常重要的指标&#xff0c;提供正常服务的时间的百分比&#xff08;365天&#xff09;99.9% redis的高可用含义更加宽泛&#xff0c;正常服务是指标之一&#xff0c;数据容量的扩展&#xff0c;数据的安全性 在redis中实现高可…

多模态大模型(MM-LLMs)近期概述

《MM-LLMs: Recent Advances in MultiModal Large Language Models》 论文地址&#xff1a;https://arxiv.org/abs/2401.13601 GitHub地址&#xff1a;https://mm-llms.github.io/ 1.介绍 目的&#xff1a;MM-LLMs旨在减少计算费用并提高多模态预训练的效率, 因为从头开始训…

Data Augmentation数据增强

目录 数据增强是什么 为什么数据增强 数组增强分类 有监督数据增强 无监督数据增强 数据增强是什么 数据增强又称数据扩增&#xff0c;是一种通过应用合理且随机的变换&#xff08;例如图像位移、旋转&#xff09;来增加训练集多样性的技术。让有限的数据产生等价于更多数…

Jenkins集成JDK、git、gitee、maven逐步实现自动拉取,自动部署,自动启动

1. jenkins集成JDK 成功登录Jenkins后&#xff0c;选择Manage Jenkins&#xff0c;选择Tools 集成JDK 2. jenkins集成git 因为Jenkins自动从git远程仓库拉取代码 首先要在Jenkins所在的linux服务器上安装git yum install -y git然后&#xff0c;实行集成JDK的第一步 配置g…

C#:枚举及位标志周边知识详解(小白入门)

文章目录 枚举为什么要有枚举?枚举的性质设置默认类型和显式设置成员的值 位标志(重要)位标记是什么及作用位标志周边知识HasFlag判断是否有该功能枚举前面加Flags的好处 关于枚举的更多知识using static简化代码获取枚举成员的字面量 枚举 为什么要有枚举? 为了增加代码的…

FlowUs息流作为一款技术驱动的笔记和知识管理平台,其核心功能和技术优势为新媒体行业带来了革命性的工作效率提升

FlowUs息流作为一款技术驱动的笔记和知识管理平台&#xff0c;其核心功能和技术优势为新媒体行业带来了革命性的工作效率提升。以下是对其技术特色的深入解析&#xff1a; 本地化技术优化&#xff1a;FlowUs息流通过深入研究中文用户的操作习惯&#xff0c;实现了界面的本地化设…

【WRF安装第二期(Ubuntu)】搭建WRF编译所需系统-系统环境检验

WRF安装第二期&#xff1a;搭建WRF编译所需系统-系统环境检验 0 升级和安装基础环境1 系统环境检验&#xff08;System Environment Tests&#xff09;1.1 检验和安装基础包1.1.1 安装指令1.1.2 检验指令 1.2 WRF安装的目录结构1.2.1 WRF系统环境测试 1.3 测试编译器&#xff0…

Python文件加密库之cryptography使用详解

概要 在现代信息社会中,数据的安全性变得越来越重要。为了保护敏感信息,文件加密技术被广泛应用。Python的cryptography库提供了强大的加密功能,可以轻松实现文件加密和解密。本文将详细介绍如何使用cryptography库进行文件加密,包含具体的示例代码。 cryptography库简介 …

模型剪枝综述

目录 1 深度神经网络的稀疏性&#xff1a; 2 剪枝算法分类&#xff1a; 3 具体的剪枝方法包括&#xff1a; 4 剪枝算法流程&#xff1a; 5 几种常见的剪枝算法&#xff1a; 6 结构化剪枝和非结构化剪枝各有其优缺点&#xff1a; 7 剪枝算法对模型精度的影响 8 影响剪枝…

《集成电路应用》是什么级别的期刊?是正规期刊吗?能评职称吗?

​问题解答 问&#xff1a;《集成电路应用》是不是核心期刊&#xff1f; 答&#xff1a;不是&#xff0c;是知网收录的第一批认定学术期刊。 问&#xff1a;《集成电路应用》级别&#xff1f; 答&#xff1a;国家级。主管单位&#xff1a;中国电子信息产业集团有限公司 主…

【错误总结】Ubuntu系统中执行 sudo apt-get update报错

Ubuntu系统中执行 sudo apt-get update报错 命令行描述升级sudo报错并解决错误描述错误解决原因1&#xff1a;系统网络问题 原因2&#xff1a;设置清华源后/etc/apt/sources.list不匹配原因3&#xff1a;ubuntu自带的源/etc/apt/sources.list有问题 apt-get update成功log参考 …

电脑的录屏功能在哪?精准操作,电脑录屏方法大揭秘

电脑的录屏功能已成为数字时代创作和分享的重要工具。然而&#xff0c;对于许多人来说&#xff0c;要找到电脑上的录屏功能可能并不容易。究竟它们隐藏在哪里&#xff1f;如何启用这个功能呢&#xff1f;这些问题可能会让人感到困惑。 本文将带您一起探索电脑上的录屏功能所在…

ip地址会因为位置不同而改变吗

在数字化时代&#xff0c;IP地址作为互联网用户的“数字指纹”&#xff0c;扮演着至关重要的角色。它不仅是设备接入网络的唯一标识&#xff0c;还常常与用户的地理位置紧密相连。然而&#xff0c;随着移动互联网的普及和人们日常活动的多样化&#xff0c;一个有趣的现象逐渐显…

【漏洞复现】泛微E-Cology9 WorkPlanService 前台SQL注入漏洞(XVE-2024-18112)

0x01 产品简介 泛微e-cology是一款由泛微网络科技开发的协同管理平台&#xff0c;支持人力资源、财务、行政等多功能管理和移动办公。 0x02 漏洞概述 该漏洞是由于泛微e-cology未对用户的输入进行有效的过滤&#xff0c;直接将其拼接进了SQL查询语句中&#xff0c;导致系统出…

Kafka的入门及简单使用

文章目录 前言一、Kafka 的基本架构&#xff1f;1. Producer&#xff08;生产者&#xff09;2. Broker&#xff08;代理/服务器&#xff09;3. Consumer&#xff08;消费者&#xff09;4. Consumer Group&#xff08;消费者组&#xff09;5. Topic&#xff08;主题&#xff09;…