All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.github.nichetoolkit.socket.util.Jt808Utils Maven / Gradle / Ivy

package io.github.nichetoolkit.socket.util;

import io.github.nichetoolkit.socket.constant.SocketJt808Constants;
import io.github.nichetoolkit.socket.manager.Jt808SessionManager;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * 

RequestHelper

* @author Cyan ([email protected]) * @version v1.0.0 */ @Slf4j public class Jt808Utils { /** * 0x8100 终端注册应答 * @param phoneBytes sim卡号 * @param flowIdBytes 终端对应信息流水 * @param result 结果 0 成功 1 车辆已经被注册 2 数据库中无车辆 3 终端已被注册 4 数据库中无终端 * @param auth 结果为0的时候的鉴权码 * @return byte[] 返回应答 */ public static byte[] buildJt8100(byte[] phoneBytes, byte[] flowIdBytes, byte result, String auth) { byte[] bytes; /** 如果应答为0 则后缀鉴权码 否则不携带鉴权码 */ if (result == 0) { bytes = ByteHexUtils.union(new byte[]{result}, auth.getBytes(SocketJt808Constants.GBK_CHARSET)); } else { bytes = new byte[]{result}; } return warp( new byte[]{(byte) 0x81, 0x00}, phoneBytes, ByteHexUtils.union(flowIdBytes, bytes) ); } /** * 0x8004 查询服务器时间应答 [v2019 新增] * @param phoneBytes sim卡号 * @return byte[] 返回应答 */ public static byte[] buildJt8004(byte[] phoneBytes) { SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyMMddHHmmss"); String timeHex = simpleDateFormat.format(new Date(System.currentTimeMillis())); byte[] timeBytes = ByteHexUtils.parseByte(timeHex); return warp( new byte[]{(byte) 0x80, 0x04}, phoneBytes, timeBytes ); } /** * 0x8003 补传分包请求 * @param phoneBytes sim卡号 * @param originFlowIdBytes 对应要求补传的原始消息第一包的流水号 * @param size 重传包总数 * @param idList 重传包id列表 * @return byte[] 返回应答 */ public static byte[] buildJt8003(byte[] phoneBytes, byte[] originFlowIdBytes, byte size, byte[] idList) { return warp( new byte[]{(byte) 0x80, 0x03}, phoneBytes, ByteHexUtils.union(originFlowIdBytes, new byte[]{size}, idList) ); } /** * 0x8001 平台通用应答 * @param phoneBytes sim卡号 * @param terminalFlowIdBytes 对应终端流水号 * @param terminalMessageIdBytes 对应终端消息Id * @param body 应答参数 0 成功/确认 1 失败 2 消息有误 3 不支持 4 报警处理确认 * @return byte[] 返回应答 */ public static byte[] buildJt8001(byte[] phoneBytes, byte[] terminalFlowIdBytes, byte[] terminalMessageIdBytes, byte body) { return warp( new byte[]{(byte) 0x80, 0x01}, phoneBytes, ByteHexUtils.union(terminalFlowIdBytes, terminalMessageIdBytes, new byte[]{body})); } public static String parseDatetime(byte[] dateTime) { return ByteHexUtils.parseBcd(ByteHexUtils.subbyte(dateTime, 0, 1)) + "-" + ByteHexUtils.parseBcd(ByteHexUtils.subbyte(dateTime, 1, 2)) + "-" + ByteHexUtils.parseBcd(ByteHexUtils.subbyte(dateTime, 2, 3)) + " " + ByteHexUtils.parseBcd(ByteHexUtils.subbyte(dateTime, 3, 4)) + ":" + ByteHexUtils.parseBcd(ByteHexUtils.subbyte(dateTime, 4, 5)) + ":" + ByteHexUtils.parseBcd(ByteHexUtils.subbyte(dateTime, 5, 6)); } public static String parseGBK(byte[] bytes) { return new String(bytes, SocketJt808Constants.GBK_CHARSET).trim(); } public static String parseAscII(byte[] bytes) { return new String(bytes, StandardCharsets.US_ASCII).trim(); } /** * 判断否是 2019 版本 协议 * 通过版本标识判断 * @param bodyProps 消息体属性 * @return boolean 是否是2019版本 */ public static boolean isVersion2019(byte[] bodyProps) { return (bodyProps[0] & 0x40) == 0x40; } /** * 检查是否是基本定位信息 * @param location 位置信息 * @return boolean */ public static boolean verifyLocation(byte[] location) { /** 纬度[以度为单位的值乘以 10 的 6 次方,精确到百万分之一度] */ byte[] latitude = ByteHexUtils.subbyte(location, 8, 12); /** 经度[以度为单位的值乘以 10 的 6 次方,精确到百万分之一度] */ byte[] longitude = ByteHexUtils.subbyte(location, 12, 16); /** 高程 [单位 m] */ byte[] height = ByteHexUtils.subbyte(location, 16, 18); /** 速度 [单位 0.1 km/h] */ byte[] speed = ByteHexUtils.subbyte(location, 18, 20); /** 方向 [0~359 正北为0 顺时针] */ byte[] direction = ByteHexUtils.subbyte(location, 20, 22); /** 时间 [yy-MM-dd-hh-mm-ss] */ byte[] datetime = ByteHexUtils.subbyte(location, 22, 28); double longitudeDouble = (double) ByteHexUtils.parseFourInt(longitude) / (double) 1000000; if (longitudeDouble > 180.0 || longitudeDouble < -180.0) { return false; } double latitudeDouble = (double) ByteHexUtils.parseFourInt(latitude) / (double) 1000000; if (latitudeDouble > 90.0 || latitudeDouble < -90.0) { return false; } int heightInt = ByteHexUtils.parseTwoInt(height); if (heightInt > 10000 || heightInt < 0) { return false; } double speedDouble = (double) (ByteHexUtils.parseTwoInt(speed)) / (double) 10; if (speedDouble < 0 || speedDouble > 600) { return false; } int directionInt = ByteHexUtils.parseTwoInt(direction); if (directionInt < 0 || directionInt > 359) { return false; } String month = ByteHexUtils.parseBcd(new byte[]{datetime[1]}); int monthInt = Integer.parseInt(month); if (monthInt < 1 || monthInt > 12) { return false; } String day = ByteHexUtils.parseBcd(new byte[]{datetime[2]}); int dayInt = Integer.parseInt(day); if (dayInt < 1 || dayInt > 31) { return false; } String hour = ByteHexUtils.parseBcd(new byte[]{datetime[3]}); int hourInt = Integer.parseInt(hour); if (hourInt < 1 || hourInt > 24) { return false; } String minute = ByteHexUtils.parseBcd(new byte[]{datetime[4]}); int minuteInt = Integer.parseInt(minute); if (minuteInt < 1 || minuteInt > 60) { return false; } String second = ByteHexUtils.parseBcd(new byte[]{datetime[5]}); int secondInt = Integer.parseInt(second); if (secondInt < 1 || secondInt > 60) { return false; } return true; } /** * 获取消息体长度 * @param bodyProps 消息体属性 * @return int 消息体长度 */ public static int messageBodyLength(byte[] bodyProps) { int length = 0; if (bodyProps.length == SocketJt808Constants.NUMBER_2) { int buf = 0x03ff; int body = ((bodyProps[0] << 8) & 0xff00) ^ (bodyProps[1] & 0x00ff); length = body & buf; } log.trace("body length is " + length); return length; } /** * 验证校验 * @param bytes 需要验证的数据 * @return boolean true 校验成功 false 校验失败 */ public static boolean verify(byte[] bytes) { boolean b = false; byte verify = bytes[0]; for (int i = 1; i < bytes.length - 1; i++) { verify = (byte) (verify ^ bytes[i]); } if (verify == bytes[bytes.length - 1]) { b = true; } if (!b) { log.warn("verify code is " + ByteHexUtils.parseHex(verify) + " return " + b); } return b; } /** * 验证是否分包 * @param bodyProps 消息体属性 * @return 是否分包 */ public static boolean isSlicePackage(byte[] bodyProps) { if (bodyProps.length == SocketJt808Constants.NUMBER_2) { byte buffer = (byte) (bodyProps[0] & 0x20); return buffer != 0; } else { return false; } } /** * 转译还原 * @param bytes 需要转义还原的数据 * @return byte[] 转义还原后的数据 */ public static byte[] retrans(byte[] bytes) { byte[] buffer = ByteHexUtils.subbyte(bytes, 1, bytes.length - 1); for (int i = 0; i < buffer.length - 1; i++) { if (buffer[i] == 0x7d && buffer[i + 1] == 0x01) { buffer = ByteHexUtils.union(ByteHexUtils.subbyte(buffer, 0, i + 1), ByteHexUtils.subbyte(buffer, i + 2)); } else if (buffer[i] == 0x7d && buffer[i + 1] == 0x02) { buffer = ByteHexUtils.union( ByteHexUtils.subbyte(buffer, 0, i), new byte[]{0x7e}, ByteHexUtils.subbyte(buffer, i + 2) ); } } return buffer; } /** * 填充校验码 * @param bytes 需要填充校验的消息数据 * @return byte[] 填充校验后的数据 */ public static byte[] addVerify(byte[] bytes) { byte verify = bytes[0]; for (int i = 1; i < bytes.length; i++) { verify = (byte) (verify ^ bytes[i]); } return ByteHexUtils.union(bytes, new byte[]{verify}); } /** * 数据包转义 * @param bytes 转义之前的数据 * @return byte[] 转义之后的数据 */ public static byte[] trans(byte[] bytes) { for (int i = 0; i < bytes.length - 1; i++) { if (bytes[i] == 0x7d) { bytes = ByteHexUtils.union( ByteHexUtils.subbyte(bytes, 0, i + 1), new byte[]{0x01}, ByteHexUtils.subbyte(bytes, i + 1) ); } else if (bytes[i] == 0x7e) { bytes = ByteHexUtils.union( ByteHexUtils.subbyte(bytes, 0, i), new byte[]{0x7d, 0x02}, ByteHexUtils.subbyte(bytes, i + 1) ); } } bytes = ByteHexUtils.union(new byte[]{0x7e}, bytes); bytes = ByteHexUtils.union(bytes, new byte[]{0x7e}); return bytes; } /** * 包装返回值 * @param messageId 消息ID * @param phoneBytes 电话 * @param total 分包总数 * @param count 分包序号 从1开始 * @param flowId 平台流水号 * @param messageBody 消息体 * @return 返回值 */ public static byte[] warp(byte[] messageId, byte[] phoneBytes, int total, int count, int flowId, byte[] messageBody) { int bodyLen = messageBody.length; if (phoneBytes.length == 10) { // 2019 return ByteHexUtils.union( messageId, new byte[]{(byte) (((bodyLen >>> 8) & 0x03) | 0x40), (byte) (bodyLen & 0xff), 0x01}, phoneBytes, new byte[]{(byte) ((flowId >>> 8) & 0xff), (byte) (flowId & 0xff)}, new byte[]{(byte) ((total >>> 8) & 0xff), (byte) (total & 0xff)}, new byte[]{(byte) ((count >>> 8) & 0xff), (byte) (count & 0xff)}, messageBody); } else { // 2011 2013 return ByteHexUtils.union( messageId, new byte[]{(byte) ((bodyLen >>> 8) & 0x03), (byte) (bodyLen & 0xff)}, phoneBytes, new byte[]{(byte) ((flowId >>> 8) & 0xff), (byte) (flowId & 0xff)}, new byte[]{(byte) ((total >>> 8) & 0xff), (byte) (total & 0xff)}, new byte[]{(byte) ((count >>> 8) & 0xff), (byte) (count & 0xff)}, messageBody); } } /** * 包装命令 * @param messageId 消息编号 * @param phoneBytes 手机号包 * @param messageBody 消息体 * @return byte[] 命令 */ public static byte[] warp(byte[] messageId, byte[] phoneBytes, byte[] messageBody) { int bodyLength = messageBody.length; int flowId = parseFlowId(phoneBytes); if (phoneBytes.length == 10) { // 2019 return ByteHexUtils.union( messageId, new byte[]{(byte) (((bodyLength >>> 8) & 0x03) | 0x40), (byte) (bodyLength & 0xff), 0x01}, phoneBytes, new byte[]{(byte) ((flowId >>> 8) & 0xff), (byte) (flowId & 0xff)}, messageBody); } else if (phoneBytes.length == 6) { // 2011 2013 return ByteHexUtils.union( messageId, new byte[]{(byte) ((bodyLength >>> 8) & 0x03), (byte) (bodyLength & 0xff)}, phoneBytes, new byte[]{(byte) ((flowId >>> 8) & 0xff), (byte) (flowId & 0xff)}, messageBody); } else { return null; } } /** * 包装命令 * @param messageId 消息编号 * @param phoneBytes 手机号包 * @return byte[] 命令 */ public static byte[] warp(byte[] messageId, byte[] phoneBytes) { int flowId = parseFlowId(phoneBytes); if (phoneBytes.length == 10) { // 2019 return ByteHexUtils.union( messageId, new byte[]{0x40, 0x00, 0x01}, phoneBytes, new byte[]{(byte) ((flowId >>> 8) & 0xff), (byte) (flowId & 0xff)}); } else if (phoneBytes.length == 6) { // 2011 2013 return ByteHexUtils.union( messageId, new byte[]{0x00, 0x00}, phoneBytes, new byte[]{(byte) ((flowId >>> 8) & 0xff), (byte) (flowId & 0xff)}); } else { return null; } } /** * 获取流水号 * @param phoneBytes 手机号包 * @return int 流水号 */ public static int parseFlowId(byte[] phoneBytes) { return parseFlowId(phoneBytes, 1); } /** * 获取流水号 * @param phoneBytes 手机号包 * @param index 脚标序列 * @return int 流水号 */ public static int parseFlowId(byte[] phoneBytes, int index) { String phone = ByteHexUtils.parseHex(phoneBytes); Object session = Jt808SessionManager.get(phone); if (session == null) { return 0; } int ret = 0; if (session instanceof ChannelHandlerContext) { ChannelHandlerContext ctx = (ChannelHandlerContext) session; Object flowId = ctx.channel().attr(AttributeKey.valueOf(SocketJt808Constants.FLOW_ID)).get(); if (flowId != null) { ret = (int) flowId; } ctx.channel().attr(AttributeKey.valueOf(SocketJt808Constants.FLOW_ID)).set(ret + index); } return ret; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy