基本信息
源码名称:Jt808 Demo源码
源码大小:32.63M
文件格式:.zip
开发语言:Java
更新时间:2021-05-28
   友情提示:(无需注册或充值,赞助后即可获取资源下载链接)

     嘿,亲!知识可是无价之宝呢,但咱这精心整理的资料也耗费了不少心血呀。小小地破费一下,绝对物超所值哦!如有下载和支付问题,请联系我们QQ(微信同号):813200300

本次赞助数额为: 2 元 
   源码介绍
联系方式wx  blueLuo88


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);
    }
}