lizhanwei
2020-02-17 ee16db5e1cbc1c27bdbc1984567b5e61a3d005dd
提交协议库
4个文件已修改
50个文件已添加
2022 ■■■■■ 已修改文件
app/src/main/java/safeluck/drive/evaluation/fragment/TcpFragment.java 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/im/MessageProcessor.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/JK2019MessageBase.java 167 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/JKClientCommonMessage.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/JKRegisterMessage.java 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/ServerCommonRsp.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/JWD.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/JWDCoder.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/Param0104.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/Param8103.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/Phone.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/PhoneCoder.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/utils/MessageEscaper.java 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/platformMessage/utils/MessageManager.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/AnnotationRegister.java 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Ascii.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/BcdDate.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/BcdDateTime.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/BitState.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Bytes.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/FromEnd.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/GBK.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Hex.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Int16.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Int16LE.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Int32.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Int32LE.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Int8.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Length.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Message.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/Order.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/annotation/UTF8.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/BCDCoder.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/BaseDecoder.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/BcdDateCoder.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/BcdDateTimeCoder.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/BinMessageCoder.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/BitStateCoder.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/ByteCoder.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/BytesCoder.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/DefaultHexCoder.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/GBKStringDecoder.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/IMessageCoder.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/Int16Coder.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/Int16LECoder.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/Int32Coder.java 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/Int32LECoder.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/decoder/UTF8StringDecoder.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/message/BinMessageBase.java 397 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/message/ParseException.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/utils/ArrayUtils.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/utils/BitState.java 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
im_lib/src/main/java/com/safeluck/aykj/utils/BytesUtils.java 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
app/src/main/java/safeluck/drive/evaluation/fragment/TcpFragment.java
@@ -16,12 +16,18 @@
import androidx.lifecycle.Observer;
import com.anyun.exam.lib.util.Speaker;
import com.anyun.im_lib.util.ByteUtil;
import com.google.android.material.textfield.TextInputEditText;
import com.safeluck.aykj.utils.BytesUtils;
import me.yokeyword.fragmentation.SupportFragment;
import safeluck.drive.evaluation.DB.criterias.CriteriaForI;
import safeluck.drive.evaluation.DB.criterias.viewmodel.CriteriaIViewModel;
import safeluck.drive.evaluation.R;
import safeluck.drive.evaluation.im.MessageProcessor;
import safeluck.drive.evaluation.platformMessage.GainStuMessage;
import safeluck.drive.evaluation.platformMessage.JKClientCommonMessage;
import safeluck.drive.evaluation.platformMessage.JKRegisterMessage;
import safeluck.drive.evaluation.platformMessage.RegisterMessage;
import safeluck.drive.evaluation.im.IMSClientBootstrap;
@@ -103,8 +109,9 @@
                String userId = "100002";
                String token = "token_" + userId;
                String hosts = "[{\"host\":\"47.93.80.84\", \"port\":12125}]";
//                String hosts = "[{\"host\":\"192.168.31.77\", \"port\":12125}]";
//                String hosts = "[{\"host\":\"47.93.80.84\", \"port\":12125}]";
//                String hosts = "[{\"host\":\"47.93.157.103\", \"port\":2020}]";
                String hosts = "[{\"host\":\"192.168.31.77\", \"port\":12125}]";
                IMSClientBootstrap.getInstance().init(userId,token,hosts,1);
                break;
@@ -122,12 +129,51 @@
                //清除app_status 表
//                OneTimeWorkRequest oneTimeWorkRequest = new OneTimeWorkRequest.Builder(AppStatusInitWork.class).build();
//                WorkManager.getInstance(_mActivity).enqueue(oneTimeWorkRequest);
                RegisterMessage registerMessage = new RegisterMessage((short)0x802);
                registerMessage.setCityid((short) 1);
                registerMessage.setProviceId((short)23);
                registerMessage.setImei("460123874561");
                registerMessage.setModel("123");
                registerMessage.setSn("2019101500000001");
//                RegisterMessage registerMessage = new RegisterMessage((short)0x802);
//                registerMessage.setCityid((short) 1);
//                registerMessage.setProviceId((short)23);
//                registerMessage.setImei("460123874561");
//                registerMessage.setModel("123");
//                registerMessage.setSn("2019101500000001");
//                GainStuMessage gainStuMessage = new GainStuMessage((short) 0x201);
//                gainStuMessage.setId("123456789");
//                gainStuMessage.setExamaCourse((short) 0);
//                MessageProcessor.getInstance().sendMessage(gainStuMessage.toBytes());
                ByteUtil.str2Bcd("13021245");
                String strbcd=ByteUtil.bcd2Str(ByteUtil.str2Bcd("13021245"));
                Log.i(TAG, "onClick: strbcd="+strbcd);
                JKRegisterMessage jkRegisterMessage = new JKRegisterMessage();
                jkRegisterMessage.setMessageLen(55);
//                jkRegisterMessage.phone = "13021245";
                jkRegisterMessage.phone = "0008618513021245";
                jkRegisterMessage.proviceid = 23;
                jkRegisterMessage.messageId = 0x100;
                jkRegisterMessage.protocalVer = 235;
                jkRegisterMessage.cityid = 1;
                jkRegisterMessage.imei = "460123874561";
                jkRegisterMessage.model = "123";
                jkRegisterMessage.sn = "0314200100000004";
                Log.i(TAG, "onClick: msg len "+jkRegisterMessage.getMessageLen()+" "+       jkRegisterMessage.props.value);
                byte[] str = jkRegisterMessage.toBytes();
                MessageProcessor.getInstance().sendMessage(str);
                Log.i(TAG, "onClick: "+ BytesUtils.bytesToHexString(str)+" ============");
                JKClientCommonMessage jkClientCommonMessage =new JKClientCommonMessage();
                jkClientCommonMessage.setMessageLen(5);
                jkClientCommonMessage.messageId = 0x8100;
                jkClientCommonMessage.protocalVer = 235;
//                jkClientCommonMessage.phone = "13021245";
                jkClientCommonMessage.respMessageId = "8001";
                jkClientCommonMessage.respNo = 15;
                jkClientCommonMessage.result =1;
                String str1 = jkClientCommonMessage.toString();
                Log.i(TAG, "onClick1: "+ str1+" ============");
                break;
        }
    }
app/src/main/java/safeluck/drive/evaluation/im/MessageProcessor.java
@@ -2,9 +2,12 @@
import android.util.Log;
import com.anyun.exam.lib.MyLog;
import com.anyun.im_lib.util.ByteUtil;
import safeluck.drive.evaluation.platformMessage.PlatFormConstant;
import safeluck.drive.evaluation.platformMessage.RegisterResp;
import safeluck.drive.evaluation.platformMessage.ServerCommonRsp;
import safeluck.drive.evaluation.util.CThreadPoolExecutor;
import safeluck.drive.evaluation.util.Utils;
@@ -49,6 +52,13 @@
            case (short) 0x8100:
                RegisterResp registerResp = new RegisterResp(datas);
                break;
            case (short) 0x8001://服务器端 通用应答
                ServerCommonRsp serverCommonRsp = new ServerCommonRsp(datas);
                if (serverCommonRsp.getResult() == PlatFormConstant.SUCCESS){
                    MyLog.i(PlatFormConstant.TAG,"确认"+serverCommonRsp.getMsgId()+"消息成功");
                }
                break;
        }
    }
app/src/main/java/safeluck/drive/evaluation/platformMessage/JK2019MessageBase.java
New file
@@ -0,0 +1,167 @@
package safeluck.drive.evaluation.platformMessage;
import android.util.Log;
import com.safeluck.aykj.annotation.AnnotationRegister;
import com.safeluck.aykj.annotation.Int16;
import com.safeluck.aykj.annotation.Int8;
import com.safeluck.aykj.annotation.Length;
import com.safeluck.aykj.annotation.Order;
import com.safeluck.aykj.decoder.BitStateCoder;
import com.safeluck.aykj.decoder.Int16Coder;
import com.safeluck.aykj.message.BinMessageBase;
import com.safeluck.aykj.utils.BitState;
import com.safeluck.aykj.utils.BytesUtils;
import safeluck.drive.evaluation.platformMessage.decoder.JWD;
import safeluck.drive.evaluation.platformMessage.decoder.JWDCoder;
import safeluck.drive.evaluation.platformMessage.decoder.Phone;
import safeluck.drive.evaluation.platformMessage.decoder.PhoneCoder;
public class JK2019MessageBase extends BinMessageBase {
    static {
        AnnotationRegister.register(JWD.class, new JWDCoder());
        AnnotationRegister.register(Phone.class, new PhoneCoder());
    }
    static Int16Coder coder = new Int16Coder();
    public JK2019MessageBase()
    {
        this.messageNo = getMessageNo();
        String message_name = this.getClass().getSimpleName();
        if(message_name.startsWith("JTMessage"))
        {
            String message_id = message_name.substring(9,13);
            if(message_id.equals("Unkn") ){
                return;
            }
            this.messageId= coder.decode(message_id);
        }
        this.setMultiPacket(false);
        this.registerDisableField("totalPacket");
        this.registerDisableField("packetNo");
    }
    @Override
    public void parse(String hex){
        BitStateCoder coder = new BitStateCoder();
        this.props = coder.decode(hex.substring(8,12));
        if(this.isMultiPacket())
        {
            this.removeDisableField("totalPacket");
            this.removeDisableField("packetNo");
        }
        super.parse(hex);
    }
    @Override
    public String toString()
    {
        if(!this.isMultiPacket())
        {
            this.registerDisableField("totalPacket");
            this.registerDisableField("packetNo");
        }
        //计算消息体长度
        String hex = super.toString();
        Log.i(PlatFormConstant.TAG, "toString: 消息体长度:"+hex);
        int message_head_len = 19;
        if(this.isMultiPacket())
        {
            message_head_len+=4;
        }
//        int len1 = this.getMessageLen();
        int len2 = hex.length()/2-message_head_len;
        this.setMessageLen(len2);
        //计算校验
        hex = super.toString();
        byte[] bytes = BytesUtils.hexStringToBytes(hex);
        bytes[bytes.length - 2] = BytesUtils.xor(bytes,1,bytes.length -2);
        return BytesUtils.bytesToHexString(bytes);
    }
    @Order(1)
    @Int8
    public int head=0x7E;
    @Order(2)
    @Int8
    public int protocalVer=0x80;
    @Order(3)
    @Int16
    public int messageId;
    @Order(4)
    @Length(2)
    @com.safeluck.aykj.annotation.BitState
    public BitState props = new BitState((byte) 0);
    @Order(5)
    @Phone
    public String phone;
    @Order(6)
    @Int16
    public int messageNo;
    @Order(7)
    @Int8
    public int reserved = 0;
    @Order(8)
    @Int16
    public int totalPacket;
    @Order(9)
    @Int16
    public int packetNo;
    @Order(Integer.MAX_VALUE-10001)
    @Int8
    public int checksum;
    @Order(Integer.MAX_VALUE-10000)
    @Int8
    public int end=0x7E;
    /**
     * 是否消息经过分包处理
     * @param b
     */
    public void setMultiPacket(boolean b)
    {
        this.props.set(13,b);
    }
    public boolean isMultiPacket()
    {
        return this.props.get(13);
    }
    /**
     * 获取属性中的消息体长度
     * @return
     */
    public int getMessageLen()
    {
        BitState state = new BitState((short)this.props.value);
        for (int i = 0; i < 10; i++)
        {
            state.set(10 + i, false);
        }
        return (int) state.value;
    }
    /**
     * 设置属性中的消息体长度
     * @param len
     */
    public void setMessageLen(int len)
    {
        BitState state = new BitState((short)len);
        for (int i = 0; i < 10; i++)
        {
            this.props.set(i, state.get(i));
        }
    }
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/JKClientCommonMessage.java
New file
@@ -0,0 +1,26 @@
package safeluck.drive.evaluation.platformMessage;
import com.safeluck.aykj.annotation.Hex;
import com.safeluck.aykj.annotation.Int16;
import com.safeluck.aykj.annotation.Int8;
import com.safeluck.aykj.annotation.Length;
import com.safeluck.aykj.annotation.Order;
public class JKClientCommonMessage extends JK2019MessageBase {
    public static int SUCCESS=0;
    public static int FAIL=1;
    public static int ERROR_MSG=2;
    public static int NOT_SUPPORT=3;
    @Order(1)
    @Int16
    public int respNo;
    @Order(2)
    @Length(2)
    @Hex
    public String respMessageId;
    @Order(3)
    @Int8
    public int result;
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/JKRegisterMessage.java
New file
@@ -0,0 +1,31 @@
package safeluck.drive.evaluation.platformMessage;
import com.safeluck.aykj.annotation.Ascii;
import com.safeluck.aykj.annotation.Int16;
import com.safeluck.aykj.annotation.Length;
import com.safeluck.aykj.annotation.Order;
public class JKRegisterMessage extends JK2019MessageBase {
    @Order(1)
    @Int16
    public int proviceid;
    @Order(2)
    @Int16
    public int cityid;
    @Order(3)
    @Length(20)
    @Ascii
    public String model;
    @Order(4)
    @Length(16)
    @Ascii
    public String sn;
    @Order(5)
    @Length(15)
    @Ascii
    public String imei;
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/ServerCommonRsp.java
@@ -49,4 +49,12 @@
    public short getResult() {
        return result;
    }
    public short getMsgId() {
        return msgId;
    }
    public short getMsg_serial_num() {
        return msg_serial_num;
    }
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/JWD.java
New file
@@ -0,0 +1,19 @@
package safeluck.drive.evaluation.platformMessage.decoder;
import com.safeluck.aykj.annotation.Length;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zw on 2017/6/15.
 */
@Length(4)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface JWD {
//    Class<? extends IMessageCoder<?>>[] coder() default Int32Coder.class;
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/JWDCoder.java
New file
@@ -0,0 +1,29 @@
package safeluck.drive.evaluation.platformMessage.decoder;
import com.safeluck.aykj.decoder.BaseDecoder;
import com.safeluck.aykj.decoder.Int32Coder;
import java.math.BigDecimal;
import java.util.Date;
/**
 * Created by zw on 2017/6/15.
 */
public class JWDCoder  extends BaseDecoder<Double> {
    Int32Coder coder = new Int32Coder();
    @Override
    public Double decode(String str) {
        double ret = coder.decode(str);
        double x = ret / 1000000;
        BigDecimal bg = new BigDecimal(x);
        double f1 = bg.setScale(6, BigDecimal.ROUND_HALF_UP).doubleValue();
        return f1;
    }
    @Override
    public String encode(Double str) {
        int jwd = (int)(str * 1000000);
        return coder.encode(jwd);
    }
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/Param0104.java
New file
@@ -0,0 +1,14 @@
package safeluck.drive.evaluation.platformMessage.decoder;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by shiyu on 2016/12/28.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Param0104 {
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/Param8103.java
New file
@@ -0,0 +1,14 @@
package safeluck.drive.evaluation.platformMessage.decoder;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by shiyu on 2016/12/28.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Param8103 {
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/Phone.java
New file
@@ -0,0 +1,19 @@
package safeluck.drive.evaluation.platformMessage.decoder;
import com.safeluck.aykj.annotation.Length;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zw on 2017/6/15.
 */
@Length(8)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Phone {
//    Class<? extends IMessageCoder<?>>[] coder() default Int32Coder.class;
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/decoder/PhoneCoder.java
New file
@@ -0,0 +1,29 @@
package safeluck.drive.evaluation.platformMessage.decoder;
import android.util.Log;
import com.anyun.im_lib.util.ByteUtil;
import com.safeluck.aykj.decoder.BaseDecoder;
import com.safeluck.aykj.utils.BytesUtils;
public class PhoneCoder  extends BaseDecoder<String> {
    private static final String TAG = "PhoneCoder";
    @Override
    public String decode(String str) {
        return str.substring(8);
    }
    @Override
    public String encode(String str) {
        Log.i(TAG, "encode: "+str);
        if(str==null||"".equalsIgnoreCase(str))
        {
//            str ="00000000000";
            str ="0000000000000000";
        }
     byte[] bcdBytes = ByteUtil.str2Bcd(str);
//        return "00000"+str;
        return BytesUtils.bytesToHexString(bcdBytes);
    }
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/utils/MessageEscaper.java
New file
@@ -0,0 +1,85 @@
package safeluck.drive.evaluation.platformMessage.utils;
import com.safeluck.aykj.utils.ArrayUtils;
/**
 * Created by zw on 2017/7/8.
 * 蓝牙协议转义
 */
public class MessageEscaper {
    public  byte[] escape(byte[] source_bytes)
    {
        byte[] return_bytes = new byte[source_bytes.length*2];
        int size = source_bytes.length;
        int pos = 0;
        for (int i = 0; i < size; i++)
        {
            if (i == 0||i==size-1)
            {
                return_bytes[pos++] = source_bytes[i];
                continue;
            }
            if (source_bytes[i] == 0x7d)
            {
                return_bytes[pos++] = 0x7d;
                return_bytes[pos++] = 0x01;
            }
            else if (source_bytes[i] == 0x7e)
            {
                return_bytes[pos++] = 0x7d;
                return_bytes[pos++] = 0x02;
            }
            else
            {
                return_bytes[pos++] = source_bytes[i];
            }
        }
        return ArrayUtils.subArray(return_bytes,0,pos);
    }
    public  byte[] unescape(byte[] cmd_bytes)
    {
        //转义还原
        int len = cmd_bytes.length;
        byte[] return_bytes = new byte[cmd_bytes.length];
        //int len = ByteHelper.HexString2Byte(cmd, cmd_bytes);
        int pos = 0;
        for (int i = 0; i < len; i++)
        {
            if (i == len - 1)
            {
                return_bytes[pos++] = cmd_bytes[i];
                continue;
            }
            if (cmd_bytes[i] == 0x7d && cmd_bytes[i + 1] == 0x02)
            {
                return_bytes[pos++] = 0x7e;
                i++;
                continue;
            }
            else if (cmd_bytes[i] == 0x7d && cmd_bytes[i + 1] == 0x01)
            {
                return_bytes[pos++] = 0x7d;
                i++;
                continue;
            }
            else
            {
                return_bytes[pos++] = cmd_bytes[i];
            }
        }
        return ArrayUtils.subArray(return_bytes,0,pos);
    }
}
app/src/main/java/safeluck/drive/evaluation/platformMessage/utils/MessageManager.java
New file
@@ -0,0 +1,63 @@
//package safeluck.drive.evaluation.platformMessage.utils;
//
//import com.safeluck.aykj.decoder.BitStateCoder;
//import com.safeluck.aykj.decoder.Int16Coder;
//import com.safeluck.aykj.utils.BitState;
//
//import safeluck.drive.evaluation.platformMessage.JK2019MessageBase;
//
///**
// * Created by zhouwei on 2016/12/7.
// */
//
//public final class MessageManager {
//
//    public static JK2019MessageBase get(String cmd) {
//        String head = cmd.substring(4,8);
//        String classname = "aykj.message.jt808_2016.server.JTMessage"+head;
//        if("0900".equals(head)||"8900".equals(head))
//            classname = "aykj.message.jt808_2016.JTMessage"+head;
//        Class c = null;
//        try {
//            c = Class.forName(classname);
//        } catch (ClassNotFoundException e) {
//            classname = "aykj.message.jt808_2016.device.JTMessage"+head;
//            try {
//                c = Class.forName(classname);
//            } catch (ClassNotFoundException e1) {
////                c = JTMessageUnknown.class;
//            }
//        }
//        try {
//
//            JK2019MessageBase ret = (JK2019MessageBase)c.newInstance();
//            ret.parse(cmd);
//            if(ret.messageId==0x8900||ret.messageId==0x0900){
////                JTMessageExtend ext = (JTMessageExtend)ret;
//                if(ret.messageId==0x8900)
////                    classname = "aykj.message.jt808_2016.server.ExtendMessage"+ String.format("%04X", ext.extend_id);
//                else
////                    classname = "aykj.message.jt808_2016.device.ExtendMessage"+ String.format("%04X", ext.extend_id);
//                try {
//                    c = Class.forName(classname);
//                } catch (ClassNotFoundException e) {
//                    classname = "aykj.message.jt808_2016.device.JTMessage"+head;
//                    try {
//                        c = Class.forName(classname);
//                    } catch (ClassNotFoundException e1) {
////                        c = JTMessageUnknown.class;
//                    }
//                }
//
//                JK2019MessageBase ext_ret = (JK2019MessageBase)c.newInstance();
//                ext_ret.parse(cmd);
//                ret = ext_ret;
//            }
//            return ret;
//        } catch (InstantiationException e) {
//            throw new RuntimeException(e);
//        } catch (IllegalAccessException e) {
//            throw new RuntimeException(e);
//        }
//    }
//}
im_lib/src/main/java/com/anyun/im_lib/netty/NettyTcpClient.java
@@ -12,6 +12,7 @@
import com.anyun.im_lib.listener.IMSConnectStatusCallback;
import com.anyun.im_lib.listener.OnEventListener;
import com.anyun.im_lib.util.ByteUtil;
import com.safeluck.aykj.utils.BytesUtils;
import java.nio.ByteBuffer;
import java.util.Vector;
@@ -218,14 +219,14 @@
                    imsConnectStatusCallback.onConnected();
                }
                // TODO: 2019/12/12  连接成功 ,发送握手消息(需要的话——)
                try {
                    ByteBuf byteBuf = ByteBufAllocator.DEFAULT.ioBuffer();
                    byteBuf.writeBytes(mOnEventListener.getRegisterMessage());
                    Log.i(TAG, "发送消息: "+ ByteUtil.byte2HexStr(mOnEventListener.getRegisterMessage()));
                    channel.writeAndFlush(byteBuf);
                } catch (Exception e) {
                    Log.i(TAG, "发送消息失败,reason="+e.getMessage()+"\t");
                }
//                try {
//                    ByteBuf byteBuf = ByteBufAllocator.DEFAULT.ioBuffer();
//                    byteBuf.writeBytes(mOnEventListener.getRegisterMessage());
//                    Log.i(TAG, "发送消息: "+ ByteUtil.byte2HexStr(mOnEventListener.getRegisterMessage()));
//                    channel.writeAndFlush(byteBuf);
//                } catch (Exception e) {
//                    Log.i(TAG, "发送消息失败,reason="+e.getMessage()+"\t");
//                }
                break;
            case IMSConfig.CONNECT_STATE_FAILURE:
                default:
@@ -331,6 +332,7 @@
            Log.i(TAG, "sendMsg fail,channel为空"+msg);
        }
        try {
            Log.i(TAG, "sendMsg: "+ BytesUtils.bytesToHexString(msg));
            ByteBuf byteBuf = ByteBufAllocator.DEFAULT.ioBuffer();
            byteBuf.writeBytes(msg);
            channel.writeAndFlush(byteBuf);
im_lib/src/main/java/com/safeluck/aykj/annotation/AnnotationRegister.java
New file
@@ -0,0 +1,58 @@
package com.safeluck.aykj.annotation;
import com.safeluck.aykj.decoder.*;
import java.lang.reflect.Field;
import java.util.HashMap;
/**
 * Created by zhouwei on 2016/12/1.
 */
public final class AnnotationRegister {
    static HashMap hashMap = new HashMap();
    static
    {
        register(Int16.class,new Int16Coder());
        register(Int32.class,new Int32Coder());
        register(Int8.class,new ByteCoder());
        register(GBK.class,new GBKStringDecoder());
        register(Ascii.class,new GBKStringDecoder());
        register(BitState.class,new BitStateCoder());
        register(Hex.class,new DefaultHexCoder());
        register(UTF8.class,new UTF8StringDecoder());
        register(Bytes.class,new BytesCoder());
        register(Message.class,new BinMessageCoder());
        register(BcdDate.class,new BcdDateCoder());
        register(BcdDateTime.class,new BcdDateTimeCoder());
        register(Int16LE.class,new Int16LECoder());
        register(Int32LE.class,new Int32LECoder());
    }
    public static void register(Class annotation, IMessageCoder<?> coder)
    {
        hashMap.put(annotation,coder);
    }
    public static IMessageCoder getCoder(Class annotation)
    {
        IMessageCoder decoder =  (IMessageCoder)hashMap.get(annotation);
        if(decoder instanceof BaseDecoder)
        {
            BaseDecoder baseDecoder = (BaseDecoder)decoder;
            if(!baseDecoder.isSingleton)
            {
                try {
                    decoder = decoder.getClass().newInstance();
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
        return decoder;
    }
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Ascii.java
New file
@@ -0,0 +1,14 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Ascii {
}
im_lib/src/main/java/com/safeluck/aykj/annotation/BcdDate.java
New file
@@ -0,0 +1,16 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zw on 2017/6/15.
 */
@Length(3)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BcdDate {
//    Class<? extends IMessageCoder<?>>[] coder() default Int32Coder.class;
}
im_lib/src/main/java/com/safeluck/aykj/annotation/BcdDateTime.java
New file
@@ -0,0 +1,16 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zw on 2017/6/15.
 */
@Length(6)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BcdDateTime {
//    Class<? extends IMessageCoder<?>>[] coder() default Int32Coder.class;
}
im_lib/src/main/java/com/safeluck/aykj/annotation/BitState.java
New file
@@ -0,0 +1,15 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BitState {
//    Class<? extends IMessageCoder<?>>[] coder() default Int32Coder.class;
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Bytes.java
New file
@@ -0,0 +1,14 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Bytes {
}
im_lib/src/main/java/com/safeluck/aykj/annotation/FromEnd.java
New file
@@ -0,0 +1,17 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zw on 2017/7/11.
 * 从结尾开始解析而不是从开头
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface FromEnd {
    int value();
}
im_lib/src/main/java/com/safeluck/aykj/annotation/GBK.java
New file
@@ -0,0 +1,15 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface GBK {
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Hex.java
New file
@@ -0,0 +1,14 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Hex {
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Int16.java
New file
@@ -0,0 +1,20 @@
package com.safeluck.aykj.annotation;
import com.safeluck.aykj.decoder.IMessageCoder;
import com.safeluck.aykj.decoder.Int16Coder;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Length(2)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Int16 {
//    Class<? extends IMessageCoder<?>>[] coder() default Int16Coder.class;
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Int16LE.java
New file
@@ -0,0 +1,18 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 * 小端模式 低位在前
 */
@Length(2)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Int16LE {
//    Class<? extends IMessageCoder<?>>[] coder() default Int16Coder.class;
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Int32.java
New file
@@ -0,0 +1,20 @@
package com.safeluck.aykj.annotation;
import com.safeluck.aykj.decoder.IMessageCoder;
import com.safeluck.aykj.decoder.Int16Coder;
import com.safeluck.aykj.decoder.Int32Coder;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Length(4)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Int32 {
//    Class<? extends IMessageCoder<?>>[] coder() default Int32Coder.class;
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Int32LE.java
New file
@@ -0,0 +1,17 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 * 小端模式 低位在前
 */
@Length(4)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Int32LE {
//    Class<? extends IMessageCoder<?>>[] coder() default Int32Coder.class;
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Int8.java
New file
@@ -0,0 +1,16 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Length(1)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Int8 {
//    Class<? extends IMessageCoder<?>>[] coder() default Int16Coder.class;
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Length.java
New file
@@ -0,0 +1,34 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Length {
    int value() default 0;
    String lengthField() default "";
    /**
     * 如果长度不足的填充方向
     * @return
     */
    PaddingWay paddingWay() default PaddingWay.RIGHT;
    /**
     * 长度不足的填充字符
     * @return
     */
    byte paddingByte() default 0x00;
    enum PaddingWay {
        LEFT,RIGHT;
    }
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Message.java
New file
@@ -0,0 +1,15 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface Message {
}
im_lib/src/main/java/com/safeluck/aykj/annotation/Order.java
New file
@@ -0,0 +1,15 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface Order {
    int value() default -1;
}
im_lib/src/main/java/com/safeluck/aykj/annotation/UTF8.java
New file
@@ -0,0 +1,14 @@
package com.safeluck.aykj.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Created by zhouwei on 2016/12/1.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE})
public @interface UTF8 {
}
im_lib/src/main/java/com/safeluck/aykj/decoder/BCDCoder.java
New file
@@ -0,0 +1,18 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BytesUtils;
/**
 * Created by zhouwei on 2016/12/1.
 */
//public class BCDCoder implements IMessageCoder<String> {
//    @Override
//    public String decode(String str) {
//        return Integer.valueOf(str, 16).intValue();
//    }
//
//    @Override
//    public String encode(String i) {
//        return BytesUtils.toHexString(i.byteValue());
//    }
//}
im_lib/src/main/java/com/safeluck/aykj/decoder/BaseDecoder.java
New file
@@ -0,0 +1,23 @@
package com.safeluck.aykj.decoder;
/**
 * Created by zhouwei on 2016/12/20.
 */
public abstract class BaseDecoder<T> implements IMessageCoder<T>  {
    public boolean isSingleton = true;
    protected Class<? extends T> fieldClass;
    @Override
    public Class<? extends T> getFieldClass() {
        return fieldClass;
    }
    @Override
    public void setFieldClass(Class<? extends T> value) {
        fieldClass =value;
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/BcdDateCoder.java
New file
@@ -0,0 +1,28 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BitState;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * Created by zw on 2017/6/15.
 */
public class BcdDateCoder extends BaseDecoder<Date>  {
    SimpleDateFormat f= new SimpleDateFormat("yyMMdd");
    @Override
    public Date decode(String date) {
        try {
            return f.parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public String encode(Date date) {
        return f.format(date);
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/BcdDateTimeCoder.java
New file
@@ -0,0 +1,26 @@
package com.safeluck.aykj.decoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * Created by zw on 2017/6/15.
 */
public class BcdDateTimeCoder extends BaseDecoder<Date>  {
    SimpleDateFormat f= new SimpleDateFormat("yyMMddHHmmss");
    @Override
    public Date decode(String date) {
        try {
            return f.parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public String encode(Date date) {
        return f.format(date);
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/BinMessageCoder.java
New file
@@ -0,0 +1,30 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.message.BinMessageBase;
/**
 * Created by zhouwei on 2016/12/1.
 */
public class BinMessageCoder extends BaseDecoder<BinMessageBase> {
    public BinMessageCoder()
    {
        this.isSingleton = false;
    }
    @Override
    public BinMessageBase decode(String str) {
        try {
            BinMessageBase messageBase = this.fieldClass.newInstance();
            messageBase.parse(str);
            return messageBase;
        } catch (Exception ex)
        {
            throw new RuntimeException(ex);
        }
    }
    @Override
    public String encode(BinMessageBase i) {
        return i.toString();
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/BitStateCoder.java
New file
@@ -0,0 +1,45 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BitState;
import com.safeluck.aykj.utils.BytesUtils;
/**
 * Created by zhouwei on 2016/12/1.
 */
public class BitStateCoder extends BaseDecoder<BitState> {
    Int16Coder int16Coder = new Int16Coder();
    Int32Coder int32Coder = new Int32Coder();
    @Override
    public BitState decode(String str) {
        if(str.length()==2)
        {
            return new BitState(Byte.valueOf(str,16));
        }
        if(str.length()==4)
        {
            return new BitState(Short.valueOf(str,16));
        }
        if(str.length()==8)
        {
            return new BitState(Integer.valueOf(str,16));
        }
        throw new RuntimeException("BitState长度不对,数据="+str);
    }
    @Override
    public String encode(BitState i) {
        if(i.total==8)
        {
            return BytesUtils.toHexString((byte)i.value);
        }
        if(i.total==16)
        {
            return int16Coder.encode((int)i.value);
        }
        if(i.total==32)
        {
            return int32Coder.encode((int)i.value);
        }
        throw new RuntimeException("BitState长度不对,数据="+i.total);
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/ByteCoder.java
New file
@@ -0,0 +1,24 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BytesUtils;
/**
 * Created by zhouwei on 2016/12/1.
 */
public class ByteCoder extends BaseDecoder<Integer> {
    public static ByteCoder instance = new ByteCoder();
    @Override
    public Integer decode(String str) {
        if(str==null||"".equals(str))
            return 0;
        return Integer.valueOf(str, 16).intValue();
    }
    @Override
    public String encode(Integer i) {
        if(i==null)
            i=0;
        return BytesUtils.toHexString(i.byteValue());
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/BytesCoder.java
New file
@@ -0,0 +1,19 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BytesUtils;
/**
 * Created by zhouwei on 2016/12/1.
 */
public class BytesCoder extends BaseDecoder<Object> {
    @Override
    public Object decode(String str) {
        return BytesUtils.hexStringToBytes(str);
    }
    @Override
    public String encode(Object i) {
        byte[] bytes = (byte[])i;
        return BytesUtils.bytesToHexString(bytes);
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/DefaultHexCoder.java
New file
@@ -0,0 +1,18 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BytesUtils;
/**
 * Created by zhouwei on 2016/12/1.
 */
public class DefaultHexCoder extends BaseDecoder<String> {
    @Override
    public String decode(String str) {
        return str;
    }
    @Override
    public String encode(String i) {
        return i;
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/GBKStringDecoder.java
New file
@@ -0,0 +1,63 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BytesUtils;
import java.io.UnsupportedEncodingException;
/**
 * Created by zhouwei on 2016/12/3.
 */
public class GBKStringDecoder extends BaseDecoder<String> {
    public String stripEnd(String str, String stripChars) {
        int end;
        if(str != null && (end = str.length()) != 0) {
            if(stripChars == null) {
                while(end != 0 && Character.isWhitespace(str.charAt(end - 1))) {
                    --end;
                }
            } else {
                if(stripChars.length() == 0) {
                    return str;
                }
                while(end != 0 && stripChars.indexOf(str.charAt(end - 1)) != -1) {
                    --end;
                }
            }
            return str.substring(0, end);
        } else {
            return str;
        }
    }
    @Override
    public String decode(String str) {
        if(str==null)
            return null;
        byte[] bytes = BytesUtils.hexStringToBytes(str);
        try {
            String ret = new String(bytes,"gbk").trim();
            return ret;// this.stripEnd(ret,"\0");
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }
    @Override
    public String encode(String str) {
        try {
            if(str==null)
                return null;
            return BytesUtils.bytesToHexString(str.getBytes("gbk"));
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/IMessageCoder.java
New file
@@ -0,0 +1,13 @@
package com.safeluck.aykj.decoder;
/**
 * Created by zhouwei on 2016/12/1.
 */
public interface IMessageCoder<T> {
    T decode(String str);
    String encode(T str);
    Class<? extends T> getFieldClass();
    void setFieldClass(Class<? extends T> value);
}
im_lib/src/main/java/com/safeluck/aykj/decoder/Int16Coder.java
New file
@@ -0,0 +1,29 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.annotation.Int16;
import com.safeluck.aykj.utils.BytesUtils;
/**
 * Created by zhouwei on 2016/12/1.
 */
public class Int16Coder extends BaseDecoder<Integer> {
    public static Int16Coder instance = new Int16Coder();
    @Override
    public Integer decode(String str) {
        if(str==null||"".equals(str))
            return 0;
        return Integer.valueOf(str, 16);
    }
    @Override
    public String encode(Integer i) {
        if(i==null)
            i=0;
        byte[] b = new byte[2];
        b[1]= (byte)(i&0xff);
        b[0]= (byte)(i >> 8);
        return BytesUtils.bytesToHexString(b);
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/Int16LECoder.java
New file
@@ -0,0 +1,42 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BytesUtils;
/**
 * Created by zhouwei on 2016/12/1.
 */
public class Int16LECoder extends BaseDecoder<Integer> {
    public static Int16LECoder instance = new Int16LECoder();
    @Override
    public Integer decode(String str) {
        byte[] src = BytesUtils.hexStringToBytes(str);
        int offset = 0;
        int value;
        value =  (src[offset] & 0xFF)
                | ((src[offset + 1] & 0xFF) << 8);
//                | ((src[offset + 2] & 0xFF) << 16)
//                | ((src[offset + 3] & 0xFF) << 24));
        return value;
//        return Integer.valueOf(Short.reverseBytes(Int16Coder.instance.decode(str).shortValue())&0xFF);
//        if(str==null||"".equals(str))
//            return 0;
//
//        return Integer.valueOf(str, 16);
    }
    @Override
    public String encode(Integer i) {
        if(i==null)
            i=0;
        int value = i.intValue();
        byte[] src = new byte[2];
//        src[3] = (byte) ((value >> 24) & 0xFF);
//        src[2] = (byte) ((value >> 16) & 0xFF);
        src[1] = (byte) ((value >> 8) & 0xFF);
        src[0] = (byte) (value & 0xFF);
        return BytesUtils.bytesToHexString(src);
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/Int32Coder.java
New file
@@ -0,0 +1,33 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.annotation.Int32;
import com.safeluck.aykj.utils.BytesUtils;
/**
 * Created by zhouwei on 2016/12/1.
 */
public class Int32Coder extends BaseDecoder<Integer> {
    public static Int32Coder instance = new Int32Coder();
    @Override
    public Integer decode(String str) {
        if(str==null||"".equals(str))
            return 0;
        return Integer.valueOf(str, 16);
    }
    @Override
    public String encode(Integer i) {
        if(i==null)
            i=0;
        //高位在前 32位整数
        int num = i.intValue();
        byte[] b = new byte[4];
        b[3]= (byte)(num&0xff);
        b[2]= (byte)(num >> 8);
        b[1]= (byte)(num >> 16);
        b[0]= (byte)(num >> 24);
        return BytesUtils.bytesToHexString(b);
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/Int32LECoder.java
New file
@@ -0,0 +1,39 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BytesUtils;
/**
 * Created by zhouwei on 2016/12/1.
 */
public class Int32LECoder extends BaseDecoder<Integer> {
    public static Int32LECoder instance = new Int32LECoder();
    @Override
    public Integer decode(String str) {
        return Integer.reverseBytes(Int32Coder.instance.decode(str));
//        byte[] src = BytesUtils.hexStringToBytes(str);
//        int offset = 0;
//        int value;
//        value = (int) ((src[offset] & 0xFF)
//                | ((src[offset + 1] & 0xFF) << 8)
//                | ((src[offset + 2] & 0xFF) << 16)
//                | ((src[offset + 3] & 0xFF) << 24));
//        return value;
    }
    //低位在前 32位整数
    @Override
    public String encode(Integer i) {
        return Int32Coder.instance.encode(Integer.reverseBytes(i));
//        if(i==null)
//            i=0;
//        int value = i.intValue();
//        byte[] src = new byte[4];
//        src[3] = (byte) ((value >> 24) & 0xFF);
//        src[2] = (byte) ((value >> 16) & 0xFF);
//        src[1] = (byte) ((value >> 8) & 0xFF);
//        src[0] = (byte) (value & 0xFF);
//        return BytesUtils.bytesToHexString(src);
    }
}
im_lib/src/main/java/com/safeluck/aykj/decoder/UTF8StringDecoder.java
New file
@@ -0,0 +1,37 @@
package com.safeluck.aykj.decoder;
import com.safeluck.aykj.utils.BytesUtils;
import java.io.UnsupportedEncodingException;
/**
 * Created by zhouwei on 2016/12/3.
 */
public class UTF8StringDecoder extends BaseDecoder<String> {
    @Override
    public String decode(String str) {
        if(str==null)
            return null;
        byte[] bytes = BytesUtils.hexStringToBytes(str);
        try {
            return new String(bytes,"utf-8");
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }
    @Override
    public String encode(String str) {
        try {
            if(str==null)
                return null;
            return BytesUtils.bytesToHexString(str.getBytes("utf-8"));
        } catch (UnsupportedEncodingException e) {
            return null;
        }
    }
}
im_lib/src/main/java/com/safeluck/aykj/message/BinMessageBase.java
New file
@@ -0,0 +1,397 @@
package com.safeluck.aykj.message;
import android.util.Log;
import com.safeluck.aykj.annotation.AnnotationRegister;
import com.safeluck.aykj.annotation.FromEnd;
import com.safeluck.aykj.annotation.Length;
import com.safeluck.aykj.annotation.Order;
import com.safeluck.aykj.decoder.IMessageCoder;
import com.safeluck.aykj.utils.BytesUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import io.netty.util.internal.PlatformDependent;
@SuppressWarnings("Since15")
public class BinMessageBase {
    static short m_messageNo;
    protected  synchronized short getMessageNo()
    {
        m_messageNo++;
        if(m_messageNo>=Short.MAX_VALUE-1)
        {
            m_messageNo = 0;
        }
        return m_messageNo;
    }
    static HashMap<Class,FieldDefine[]> fieldDefines = new HashMap<>();
    protected List<String> disabledFields = new ArrayList<>();
    public void parse(String hex)
    {
        try {
            FieldDefine[] fields = this.getFieldDefines();
            int total = hex.length();
            int used = 0;
            int dynamic_len_field_count = 0;
            int relative_len_field_count = 0;
            //如果有为动态长度的,计算出长度
            for (FieldDefine fieldDefine : fields) {
                if (this.disabledFields.contains(fieldDefine.field.getName())) {
                    continue;
                }
                //计算依赖长度字段数量
                if (fieldDefine.relativeLengthField != null) {
                    relative_len_field_count++;
                }
                if (fieldDefine.relativeLengthField == null && fieldDefine.getFieldLen() == 0) {
                    dynamic_len_field_count++;
                }
                //动态长度,去掉其他所有字段的长度,剩余的为此字段长度
                if (fieldDefine.getFieldLen() > 0) {
                    System.out.println(fieldDefine.field.getName() + "长度=" + fieldDefine.getFieldLen() * 2);
                    used += (fieldDefine.getFieldLen() * 2);
                }
            }
            if (dynamic_len_field_count > 1) {
                buildException("动态长度字段只能有一个");
            }
            if (dynamic_len_field_count > 0 && relative_len_field_count > 0) {
                buildException("动态长度字段和依赖长度字段只能有一个");
            }
            int dynamic_len = (total - used);
            int start = 0;
            for (FieldDefine fieldDefine : fields) {
                if (this.disabledFields.contains(fieldDefine.field.getName())) {
                    continue;
                }
                //解析依赖长度
                if (fieldDefine.relativeLengthField != null) {
                    try {
                        Field lengthField = this.getClass().getField(fieldDefine.length.lengthField());
                        int len = (int) lengthField.get(this);
                        System.out.println(fieldDefine.field.getName() + ":依赖长度=" + len);
                        fieldDefine.setFieldLen(len);
                        ;
                    } catch (Exception e) {
                        buildException(e.getMessage());
                    }
                }
                int str_hex_len = fieldDefine.getFieldLen() * 2;
                if (str_hex_len <= 0) {
                    str_hex_len = dynamic_len;
                }
                String field_hex = null;
                Object value = null;
                if (fieldDefine.from_end_index >= 0) {
                    field_hex = hex.substring(hex.length() - str_hex_len - fieldDefine.from_end_index, hex.length() - fieldDefine.from_end_index);
                    value = fieldDefine.coder.decode(field_hex);
                } else {
                    field_hex = hex.substring(start, start + str_hex_len);
                    start += str_hex_len;
                    value = fieldDefine.coder.decode(field_hex);
                }
                try {
                    fieldDefine.field.set(this, value);
//                Object val = fieldDefine.field.get(this);
//                System.out.println(fieldDefine.field.getName()+":get="+val);
                } catch (IllegalAccessException e) {
                    this.buildException(e.getMessage());
                }
            }
        }
        catch (ParseException ex)
        {
            throw ex;
        }
        catch (Exception ex)
        {
            this.buildException(ex.getMessage());
        }
    }
    public void registerDisableField(String field)
    {
        if(!this.disabledFields.contains(field)) {
            this.disabledFields.add(field);
        }
    }
    public void removeDisableField(String field)
    {
        this.disabledFields.remove(field);
    }
    protected void buildException(String error)
    {
        throw new ParseException(error,this);
    }
    public byte[] toBytes()
    {
        String hex = this.toString();
        return BytesUtils.hexStringToBytes(hex);
    }
    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder();
        FieldDefine[] fields = this.getFieldDefines();
        //写动态长度字段长度
        for (FieldDefine fieldDefine:fields) {
            if (this.disabledFields.contains(fieldDefine.field.getName())) {
                continue;
            }
            Log.i("PlatFormMessage", "1field: "+fieldDefine.field.getName());
            if(fieldDefine.relativeLengthField==null)
                continue;
            try {
                Object value = fieldDefine.field.get(this);
                String hex = fieldDefine.coder.encode(value);
                if (hex == null) {
                    fieldDefine.relativeLengthField.set(this, 0);
                } else {
                    fieldDefine.relativeLengthField.set(this, hex.length() / 2);
                }
            }
            catch(IllegalAccessException e)
            {
                this.buildException(e.getMessage());
            }
        }
        for (FieldDefine fieldDefine:fields)
        {
            if(this.disabledFields.contains(fieldDefine.field.getName()))
            {
                continue;
            }
            Log.i("PlatFormMessage", "2field: "+fieldDefine.field.getName());
            try {
                Object obj  = fieldDefine.field.get(this);
                String hex = fieldDefine.coder.encode(obj);
                if(hex==null)
                {
                    hex = "";
                }
                if (fieldDefine.field.getName().equalsIgnoreCase("phone")){
                    Log.i("PlatFormMessage", "phone toString: "+hex
                    );
                }
                int defineLen = fieldDefine.getFieldLen();
                if(hex.length()>defineLen*2&&defineLen>0)
                {
                    this.buildException("字段"+fieldDefine.field.getName()+"长度超过限制");
                }
                if(hex.length()<defineLen*2&&defineLen>0)
                {
                    if(fieldDefine.length.paddingWay()== Length.PaddingWay.RIGHT)
                    {
                        hex = this.getPaddingRightString(hex,fieldDefine.getFieldLen()*2, BytesUtils.toHexString(fieldDefine.length.paddingByte()));
                    }
                    else
                    {
                        hex = this.getPaddingLeftString(hex,fieldDefine.getFieldLen()*2, BytesUtils.toHexString(fieldDefine.length.paddingByte()));
                    }
                }
//                System.out.println(hex);
                sb.append(hex);
            } catch (IllegalAccessException e) {
                this.buildException(e.getMessage());
            }
        }
        return sb.toString();
    }
    String getPaddingLeftString(String str, int total_len,String padding) {
        while (str.length() < total_len) {
            str = padding + str;
        }
        return str;
    }
    String getPaddingRightString(String str, int total_len,String padding) {
        while (str.length() < total_len) {
            str = str+padding;
        }
        return str;
    }
    public synchronized FieldDefine[] getFieldDefines()
    {
        if(!fieldDefines.containsKey(this.getClass()))
        {
            Field[] fields = this.getClass().getFields();
            List<FieldDefine> fieldDefineList = new ArrayList<>();
//            int sort = 0;
            List<Class> baseClassList = new ArrayList<>();
            for (Field field:fields)
            {
                if(Modifier.isStatic(field.getModifiers()))
                    continue;
                if(Modifier.isPrivate(field.getModifiers()))
                    continue;
                if(field.getAnnotation(Order.class)==null)
                    continue;
                FieldDefine fieldDefine = new FieldDefine(field);
                if(fieldDefine.coder!=null) {
                    fieldDefineList.add(fieldDefine);
                    if(baseClassList.indexOf(field.getDeclaringClass())<0)
                    {
                        baseClassList.add(field.getDeclaringClass());
                    }
                }
                if(fieldDefine.length.lengthField()!=null&&!"".equals(fieldDefine.length.lengthField()))
                {
                    try {
                        fieldDefine.relativeLengthField = this.getClass().getField(fieldDefine.length.lengthField());
                    } catch (NoSuchFieldException e) {
                        this.buildException(e.getMessage());
                    }
                }
            }
            //排序出基类
            Collections.sort(baseClassList,new Comparator<Class>() {
                @Override
                public int compare(Class c1, Class c2) {
                    if(c2.isAssignableFrom(c1))
                    {
                        return 1;
                    }
                    return -1;
                }
            });
            //重新排序
            int sort = 0;
            for(Class c:baseClassList)
            {
                sort+=100;
                for(FieldDefine fieldDefine:fieldDefineList)
                {
                    if(fieldDefine.field.getDeclaringClass().equals(c))//&&fieldDefine.order==0)
                    {
                        if(fieldDefine.order+sort>0) {
                            fieldDefine.order += sort;
                        }
                    }
                }
            }
            Collections.sort(fieldDefineList,new Comparator<FieldDefine>() {
                @Override
                public int compare(FieldDefine t0, FieldDefine t1) {
                    int order0 = t0.order;//+(pos0+1);
                    int order1 = t1.order;//+(pos1+1);
                    if(order0>order1)
                        return 1;
                    if(order0==order1)
                        return 0;
                    return -1;
                }
            });
            fieldDefines.put(this.getClass(),fieldDefineList.toArray(new FieldDefine[0]));
        }
        FieldDefine[] result = fieldDefines.get(this.getClass());
        for(FieldDefine fieldDefine:result)
        {
            fieldDefine.setFieldLen(0);
        }
        return result;
    }
    class FieldDefine
    {
        public FieldDefine(Field field)
        {
            Annotation[] annotations = field.getAnnotations();
            for (Annotation annotation:annotations) {
                IMessageCoder  decoder =  AnnotationRegister.getCoder(annotation.annotationType());
                if(decoder!=null) {
                    decoder.setFieldClass(field.getType());
                    coder = decoder;
                    this.length =  annotation.annotationType().getAnnotation(Length.class);
                    break;
                }
            }
            this.field = field;
            if(this.length==null) {
                this.length = field.getAnnotation(Length.class);
            }
            if(this.length==null)
            {
                buildException(field.getName()+"未定义长度");
            }
            Order orderAnnotation = field.getAnnotation(Order.class);
            if(orderAnnotation!=null)
            {
                this.order = orderAnnotation.value();
            }
            FromEnd fromEnd = field.getAnnotation(FromEnd.class);
            if(fromEnd!=null)
            {
                from_end_index = fromEnd.value();
            }
        }
        public Field relativeLengthField;
        public IMessageCoder coder;
        public Length length;
        public Field field;
        public int order;
        public int from_end_index = -1;
        private int field_len;
        public int getFieldLen()
        {
            if(this.length.value()>0)
                return this.length.value();
            return field_len;
        }
        public void setFieldLen(int len)
        {
            this.field_len = len;
        }
        @Override
        public String toString() {
            return this.field.toString();
        }
    }
    public String getDescription()
    {
        return this.toString();
    }
}
im_lib/src/main/java/com/safeluck/aykj/message/ParseException.java
New file
@@ -0,0 +1,15 @@
package com.safeluck.aykj.message;
/**
 * Created by zhouwei on 2016/12/3.
 */
public class ParseException extends RuntimeException {
    public ParseException(String error,BinMessageBase message)
    {
        super(error);
        this.message = message;
    }
    public BinMessageBase message;
}
im_lib/src/main/java/com/safeluck/aykj/utils/ArrayUtils.java
New file
@@ -0,0 +1,15 @@
package com.safeluck.aykj.utils;
import android.util.Log;
import static com.anyun.im_lib.util.ByteUtil.byte2HexStr;
public class ArrayUtils {
    public static byte[] subArray(byte[] srcBytes, int begin, int length) {
        byte[] bytes = new byte[length];
        System.arraycopy(srcBytes,begin,bytes,0,length);
        Log.i("ArrayUtils", "subArray: "+byte2HexStr(bytes));
        return bytes;
    }
}
im_lib/src/main/java/com/safeluck/aykj/utils/BitState.java
New file
@@ -0,0 +1,56 @@
package com.safeluck.aykj.utils;
public class BitState {
    public BitState(int b)
    {
        this.value = b;
        this.total = 32;
    }
    public BitState(byte b)
    {
        this.value = b;
        this.total = 8;
    }
    public BitState(short b)
    {
        this.value = b;
        this.total = 16;
    }
    public int total = 32;
    public int value;
    public boolean get(int bit)
    {
        int pos = bit;//32 - bit;
        return (this.value >> pos & 1) == 1;
    }
    public void set(int pos, boolean state)
    {
        //11000110
        int move_pos = pos;// 32 - pos;
        if (state)
        {
            this.value = this.value | 1 << move_pos;
        }
        else
        {
            this.value = this.value & ~(1 << move_pos);
        }
    }
    @Override
    public String toString()
    {
        String str = Integer.toBinaryString(this.value);
        return getPaddingRightString(str, this.total,"00");
    }
    String getPaddingRightString(String str, int total_len,String padding) {
        while (str.length() < total_len) {
            str = str+padding;
        }
        return str;
    }
}
im_lib/src/main/java/com/safeluck/aykj/utils/BytesUtils.java
New file
@@ -0,0 +1,110 @@
package com.safeluck.aykj.utils;
public final class BytesUtils {
    public static String bytesToHexString(byte[] src,int len){
        return bytesToHexString(src,0,len);
    }
    public static String bytesToHexString(byte[] src){
        return bytesToHexString(src,0,src.length);
    }
    public static String bytesToHexString(byte[] src,int start,int len){
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = start; i < len; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString().toUpperCase();
    }
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }
    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }
    public static byte xor(byte[] bytes,int start,int end)
    {
        if (bytes.length < end)
        {
            throw new RuntimeException("计算xor的时候size不足");
        }
        int s1 = bytes[start];
        for (int i = start + 1; i < end; i++)
        {
            s1 = s1 ^ bytes[i];
        }
        return (byte)s1;
    }
    public static byte xor(byte[] bytes)
    {
        return xor(bytes,0,bytes.length);
    }
    public static String toHexString(byte b)
    {
        String hex = Integer.toHexString(b&0xff).toUpperCase();
        if(hex.length()==1)
        {
            return "0"+hex;
        }
        return hex;
    }
    public static int sum(byte[] bytes,int start,int end)
    {
        if (bytes.length < end)
        {
            throw new RuntimeException("计算sum的时候size不足");
        }
        int s1 = 0;
        for (int i = start; i < end; i++)
        {
//            System.out.println(bytes[i]&0xFF);
            s1 += (bytes[i]&0xFF);
//            System.out.println("sum="+s1);
        }
        return s1;
//        int sum = 0;
//        for(byte b:bytes)
//        {
//            sum+=b;
//        }
//        return sum;
    }
    public static int sum(byte[] bytes)
    {
        return sum(bytes,0,bytes.length);
    }
    public static int getInt32(byte[] bytes,int start){
        int result = 0;
        int a = (bytes[0+start] & 0xff) << 24;
        int b = (bytes[1+start] & 0xff) << 16;
        int c = (bytes[2+start] & 0xff) << 8;
        int d = (bytes[3+start] & 0xff);
        result = a | b | c | d;
        return result;
    }
}