实例介绍
【实例截图】

【核心代码】
package com.android.jt808demo.utils;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class JT808ProtocolUtils {
private String TAG = "JT808ProtocolUtils";
private JTBitOperator bitOperator;
private JT8421Operater bcd8421Operater;
public JT808ProtocolUtils() {
this.bitOperator = new JTBitOperator();
this.bcd8421Operater = new JT8421Operater();
}
/**
* 接收消息时转义<br>
* <pre>
* 0x7d01 <====> 0x7d
* 0x7d02 <====> 0x7e
* </pre>
* @param bs 要转义的字节数组
* @param start 起始索引
* @param end 结束索引
* @return 转义后的字节数组
* @throws Exception
*/
public byte[] doEscape4Receive(byte[] bs, int start, int end) throws Exception {
if (start < 0 || end > bs.length)
throw new ArrayIndexOutOfBoundsException("doEscape4Receive error : index out of bounds(start=" start
",end=" end ",bytes length=" bs.length ")");
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
for (int i = 0; i < start; i ) {
baos.write(bs[i]);
}
for (int i = start; i < end - 1; i ) {
if (bs[i] == 0x7d && bs[i 1] == 0x01) {
baos.write(0x7d);
i ;
} else if (bs[i] == 0x7d && bs[i 1] == 0x02) {
baos.write(0x7e);
i ;
} else {
baos.write(bs[i]);
}
}
for (int i = end - 1; i < bs.length; i ) {
baos.write(bs[i]);
}
return baos.toByteArray();
} catch (Exception e) {
throw e;
} finally {
if (baos != null) {
baos.close();
baos = null;
}
}
}
/**
* 发送消息时转义<br>
* <pre>
* 0x7e <====> 0x7d02
* </pre>
* @param bs 要转义的字节数组
* @param start 起始索引
* @param end 结束索引
* @return 转义后的字节数组
* @throws Exception
*/
public byte[] doEscape4Send(byte[] bs, int start, int end) throws Exception {
if (start < 0 || end > bs.length)
throw new ArrayIndexOutOfBoundsException("doEscape4Send error : index out of bounds(start=" start
",end=" end ",bytes length=" bs.length ")");
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
for (int i = 0; i < start; i ) {
baos.write(bs[i]);
}
for (int i = start; i < end; i ) {
if (bs[i] == 0x7e) {
baos.write(0x7d);
baos.write(0x02);
} else {
baos.write(bs[i]);
}
}
for (int i = end; i < bs.length; i ) {
baos.write(bs[i]);
}
return baos.toByteArray();
} catch (Exception e) {
throw e;
} finally {
if (baos != null) {
baos.close();
baos = null;
}
}
}
public byte[] generateMsgHeader(String phone, int msgType, byte[] body, byte[] msgBodyProps, int flowId) {
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
// 1. 消息ID word(16)
// Log.i(TAG,"=消息ID length=" bitOperator.integerTo2Bytes(msgType).length);
baos.write(bitOperator.integerTo2Bytes(msgType));
// 2. 消息体属性 word(16)
// Log.i(TAG,"=msgBodyProps length=" msgBodyProps.length);
baos.write(msgBodyProps);
// 3. 终端手机号 bcd[6]
// Log.i(TAG,"=终端手机号 length=" bcd8421Operater.string2Bcd(phone).length);
baos.write(bcd8421Operater.string2Bcd(phone));
// 4. 消息流水号 word(16),按发送顺序从 0 开始循环累加
//Log.i(TAG,"=消息流水号 length=" bitOperator.integerTo2Bytes(flowId).length);
baos.write(bitOperator.integerTo2Bytes(flowId));
// 消息包封装项 此处不予考虑,放在头部消息封装成协议消息时候封装加入
return baos.toByteArray();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* 包装808数据,带有分包的数据
* @param msgId 消息id
* @param phone 终端手机号
* @param msgBody 消息体
* @return
*/
public byte[] create808Data(int msgId, String phone, byte[] msgBody, int subpkg , int flowId) {
// Log.i(TAG,"=msgBody.length=" msgBody.length);
//=========================标识位==================================//
byte[] flag = new byte[]{0x7E};
//=========================消息头==================================//
//[0,1]消息Id
byte[] msgIdb = bitOperator.integerTo2Bytes(msgId);
//[2,3]消息体属性
byte[] msgBodyAttributes = msgBodyAttributes(msgBody.length, subpkg);
//int msgBodyProps = generateMsgBodyProps(msgBody.length, 0b000, false, 0);
//[4,9]终端手机号 BCD[6](占6位)
//byte[] terminalPhone = bcd8421Operater.string2Bcd(phone);
byte[] terminalPhone =bitOperator.str2Bcd(phone);
//[10,11]流水号
byte[] flowNum = bitOperator.integerTo2Bytes(flowId);
//[12]消息包封装项 不分包 就没有
// 分包:当消息体属性中第 13 位为1 时表示消息体为长消息,进行分包发送处理,具体
// 分包信息由消息包封装项决定;若第13位为0,则消息头中无消息包封装项字段。
// 消息包封装项内容见表:
// 起始字节 字段 数据类型 描述及要求
// 0 消息包总数 WORD 该消息分包后的总包数
// 2 包序号 WORD 从1 开始
byte[] msgHeader =null;
if(subpkg==1){
msgHeader=bitOperator.concatAll(terminalPhone,msgIdb,msgBody,msgBodyAttributes,flowNum);
}else{
msgHeader=generateMsgHeader(phone, msgId, msgBody, msgBodyAttributes, flowId);
}
//Log.i(TAG,"=msgHeader.length=" msgHeader.length);
//=========================数据合并(消息头,消息体)=====================//
byte[] bytes = bitOperator.concatAll(msgHeader, msgBody);
//Log.i(TAG,"total data length=" bytes.length);
/** 添加校验码 */
bytes = bitOperator.byteMerge(bytes, bitOperator.getCheckCode(bytes));
//Log.i(TAG,"添加校验码后 data length=" bytes.length);
/** 转义 */
bytes = bitOperator.escape(bytes);
// Log.i(TAG,"转义后 data length=" bytes.length);
/** 添加标识位 */
bytes = bitOperator.byteMerge(new byte[] {0x7e}, bytes);
bytes = bitOperator.byteMerge(bytes, new byte[] {0x7e});
//Log.i(TAG,"添加标识位后 data length=" bytes.length);
return bytes;
}
/**
* 包装808数据,带有分包的数据
* @param msgId 消息id
* @param phone 终端手机号
* @param msgBody 消息体
* @return
*/
public byte[] create808Data(int msgId, String phone, byte[] msgBody, int subpkg , int totalPkgCount, int pkgIndex, int flowId) {
//=========================标识位==================================//
byte[] flag = new byte[]{0x7E};
//=========================消息头==================================//
//[0,1]消息Id
byte[] msgIdb = bitOperator.integerTo2Bytes(msgId);
//[2,3]消息体属性
byte[] msgBodyAttributes = msgBodyAttributes(msgBody.length, subpkg);
//int msgBodyProps = generateMsgBodyProps(msgBody.length, 0b000, false, 0);
//[4,9]终端手机号 BCD[6](占6位)
byte[] terminalPhone = bcd8421Operater.string2Bcd(phone);
//[10,11]流水号
byte[] flowNum = bitOperator.integerTo2Bytes(flowId);
//[12]消息包封装项 不分包 就没有
// 分包:当消息体属性中第 13 位为1 时表示消息体为长消息,进行分包发送处理,具体
// 分包信息由消息包封装项决定;若第13位为0,则消息头中无消息包封装项字段。
// 消息包封装项内容见表:
// 起始字节 字段 数据类型 描述及要求
// 0 消息包总数 WORD 该消息分包后的总包数
// 2 包序号 WORD 从1 开始
byte[] msgHeader =null;
if(subpkg==1){
byte[] totalPkgCountData=bitOperator.integerTo2Bytes(totalPkgCount);
byte[] pkgIndexData=bitOperator.integerTo2Bytes(pkgIndex);
msgHeader=bitOperator.concatAll(terminalPhone,msgIdb,msgBody,msgBodyAttributes,flowNum,totalPkgCountData,pkgIndexData);
}else{
msgHeader=generateMsgHeader(phone, msgId, msgBody, msgBodyAttributes, flowId);
}
//=========================数据合并(消息头,消息体)=====================//
byte[] bytes = bitOperator.concatAll(msgHeader, msgBody);
// //=========================计算校验码==================================//
// String checkCodeHexStr = bitOperator.getBCC(bytes);
// byte[] checkCode = bitOperator.hexStringToByte(checkCodeHexStr);
// //=========================合并:消息头 消息体 校验码 得到总数据============//
// byte[] totalData = bitOperator.concatAll(bytes, checkCode);
// //=========================转义 7E和7D==================================//
// // 转成16进制字符串
// String hexStr = bitOperator.bytesToHexString(totalData);
// // 替换 7E和7D
// String replaceHexStr = hexStr.replaceAll("7D", " 7D 01")
// .replaceAll("7E", " 7D 02")
// // 最后去除空格
// .replaceAll(" ", "");
// //替换好后 转回byte[]
// byte[] replaceByte = bitOperator.hexStringToByte(replaceHexStr);
// //=========================最终传输给服务器的数据==================================//
// return bitOperator.concatAll(flag, replaceByte, flag);
/** 添加校验码 */
bytes = bitOperator.byteMerge(bytes, bitOperator.getCheckCode(bytes));
/** 转义 */
bytes = bitOperator.escape(bytes);
/** 添加标识位 */
bytes = bitOperator.byteMerge(new byte[] {0x7e}, bytes);
bytes = bitOperator.byteMerge(bytes, new byte[] {0x7e});
return bytes;
}
public int generateMsgBodyProps(int msgLen, int enctyptionType, boolean isSubPackage, int reversed_14_15) {
// [ 0-9 ] 0000,0011,1111,1111(3FF)(消息体长度)
// [10-12] 0001,1100,0000,0000(1C00)(加密类型)
// [ 13_ ] 0010,0000,0000,0000(2000)(是否有子包)
// [14-15] 1100,0000,0000,0000(C000)(保留位)
if (msgLen >= 1024) {
Log.i(TAG, "The max value of msgLen is 1023, but {}=msgLen=" msgLen);
}
int subPkg = isSubPackage ? 1 : 0;
int ret = (msgLen & 0x3FF) | ((enctyptionType << 10) & 0x1C00) | ((subPkg << 13) & 0x2000)
| ((reversed_14_15 << 14) & 0xC000);
return ret & 0xffff;
}
/**
* 生成消息体属性
* @param subpackage [13]是否分包 0:不分包 1:分包
*/
public byte[] msgBodyAttributes(int msgLength, int subpackage) {
byte[] length = bitOperator.integerTo2Bytes(msgLength);
//[0,9]消息体长度
String msgBodyLength = ""
//第一个字节最后2bit
(byte) ((length[0] >> 1) & 0x1) (byte) ((length[0] >> 0) & 0x1)
//第二个字节8bit
(byte) ((length[1] >> 7) & 0x1) (byte) ((length[1] >> 6) & 0x1)
(byte) ((length[1] >> 5) & 0x1) (byte) ((length[1] >> 4) & 0x1)
(byte) ((length[1] >> 3) & 0x1) (byte) ((length[1] >> 2) & 0x1)
(byte) ((length[1] >> 1) & 0x1) (byte) ((length[1] >> 0) & 0x1);
//[10,12]数据加密方式 0 表示不加密
String encryption = "000";
//[13]分包
String subpackageB = String.valueOf(subpackage);
//[14,15]保留位
String reserve = "00";
String msgAttributes = reserve subpackageB encryption msgBodyLength;
// 消息体属性
int msgBodyAttr = Integer.parseInt(msgAttributes, 2);
return bitOperator.integerTo2Bytes(msgBodyAttr);
}
}
标签: demo
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论