1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
package com.dy.common.mw.protocol.p206V2;
 
import com.dy.common.util.ByteUtil;
import com.dy.common.util.ByteUtilUnsigned;
import com.dy.common.util.CRC8_for_2_0;
 
 
public class CommonV2 {
    /**
     * 检查头
     * @param bs 上行字节数组
     * @return true是,false否
     * @throws Exception  异常
     */
    public Boolean isThisProtocolHead(byte[] bs) throws Exception{
        if(bs == null){
            return null ;
        }else if(bs.length >= (ProtocolConstantV206V2.ctrlIndex - 1)
                && bs[ProtocolConstantV206V2.headFlag1Index] == ProtocolConstantV206V2.P_Head_Byte
                && bs[ProtocolConstantV206V2.headFlag2Index] == ProtocolConstantV206V2.P_Head_Byte){
            Short vs = this.parseVersion(bs) ;
            return vs.shortValue() == ProtocolConstantV206V2.protocolVer.shortValue() ;
        }else{
            return false ;
        }
    }
 
    /**
     * 分析版本号
     * @param bs
     * @return
     */
    public Short parseVersion(byte[] bs)throws Exception{
        return ByteUtil.byte2PlusInt(bs[ProtocolConstantV206V2.versionIndex]) ;
    }
    
    /**
     * 检查头
     * @param bs 上行字节数组
     * @throws Exception 异常
     */
    public void checkHead(byte[] bs) throws Exception{
        if(bs.length < ProtocolConstantV206V2.onLineDataMinLength || bs[0] != ProtocolConstantV206V2.P_Head_Byte || bs[2] != ProtocolConstantV206V2.P_Head_Byte){
            throw new Exception("上行数据帧头不正确!") ;
        }
    }
    
    /**
     * 检查尾
     * @param bs 上行字节数组
     * @throws Exception 异常
     */
    public void checkTail(byte[] bs) throws Exception{
        if(bs.length < 1 || bs[bs.length - 1] != ProtocolConstantV206V2.P_Tail_Byte){
            throw new Exception("上行数据尾不正确!") ;
        }
    }
 
 
    /**
     * 分析帧长度
     * @param bs 上行字节数组
     * @return 数据长度
     * @throws Exception 异常
     */
    public int parseFrameLen(byte[] bs)throws Exception{
        int len = ByteUtilUnsigned.byte2Byte(bs, ProtocolConstantV206V2.dataLenIndex) ;
        return len + ProtocolConstantV206V2.lenHead2ctrl + ProtocolConstantV206V2.lenTail ;
    }
 
 
    /**
     * 分析用户数据域字节数
     * @param bs 上行字节数组
     * @return 数据长度
     * @throws Exception 异常
     */
    public int parseDataLen(byte[] bs)throws Exception{
        int len = ByteUtilUnsigned.byte2Byte(bs, ProtocolConstantV206V2.dataLenIndex) ;
        return len + ProtocolConstantV206V2.lenHead2ctrl + ProtocolConstantV206V2.lenTail ;
    }
 
 
    /**
     * 分析Rtu地址
     * @param bs 上行字节数组
     * @return 控制器地址
     * @throws Exception 异常
     */
    public String parseRtuAddr(byte[] bs)throws Exception{
        String rtuAddrBCD = "" + ByteUtil.BCD2Long_BE(bs, ProtocolConstantV206V2.rtuAddr1Index_start, ProtocolConstantV206V2.rtuAddr1Index_end) ;
        String rtuAddrStr = "" + ByteUtilUnsigned.bytes2Short_LE(bs, ProtocolConstantV206V2.rtuAddr2Index_start) ;
        while(rtuAddrStr.length() <= 5){
            rtuAddrStr = "0" + rtuAddrStr ;
        }
        return rtuAddrBCD + rtuAddrStr ;
    }
 
 
    /**
     * 分析Rtu地址
     * @param bs 上行字节数组
     * @param index 启始位
     * @return 控制器地址
     * @throws Exception 异常
     */
    public String parseRtuAddr(byte[] bs, int index)throws Exception{
        String rtuAddrBCD = "" + ByteUtil.BCD2Long_BE(bs, index, index + 2) ;//地址是大端模式
        String rtuAddrStr = "" + ByteUtilUnsigned.bytes2Short_LE(bs, index + 3) ;
        while(rtuAddrStr.length() <= 5){
            rtuAddrStr = "0" + rtuAddrStr ;
        }
        return rtuAddrBCD + rtuAddrStr ;
    }
 
 
    /**
     * 分析功能码
     * @param bs 上行字节数组
     * @return 功能码
     */
    public String parseCode(byte[] bs){
        return ByteUtil.bytes2Hex(bs, false, ProtocolConstantV206V2.codeIndex, 1) ;
    }
 
    /**
     * 校验和检查
     * @param bs  上行字节数组
     * @return 通过null,未通过返回原因
     * @throws Exception 异常
     */
    public String checkCrc_str(byte[] bs) throws Exception {
        byte crcCompute = (byte)new CRC8_for_2_0().CRC8(bs, ProtocolConstantV206V2.ctrlIndex, bs.length - 3) ;
        byte crcInBs = bs[bs.length - 2] ;
        if(crcCompute == crcInBs){
            return null ;
        }else{
            return "计算CRC是:" + crcCompute + ",上传CRC是" + crcInBs ;
        }
    }
 
 
    /*
    构造控制域
    D7                  D6                  D5~D4            D3~D0
    传输方向位 DIR        拆分标志位 DIV       帧计数位 FCB       功能码
    */
    public byte createCtrl(byte dir, byte funcCode){
        byte b = dir;//(byte)0x80//控制域:DIR=1,表示此帧报文是由终端发出的上行报文;
        b = (byte)(b | funcCode) ;
        //FCB == 3
        b = (byte)(b | (byte)0x18) ;
        //DIV = 0
        //DIR = 0
        return b ;
    }
    /**
     * 得到IC卡类型名称 ( 卡类型(1:用户卡;2:管理员卡;3:调试卡;4:巡检卡;5:清空卡))
     * @param type 字节
     * @return 名称
     */
    public static String icCardType(byte type){
        return switch (type) {
            case 0 -> "无卡";
            case 1 -> "用户卡";
            case 2 -> "管理员卡";
            case 3 -> "调试卡";
            case 4 -> "巡检卡";
            case 5 -> "清空卡";
            default -> "未知";
        };
    }
 
    /**
     * 得到关开阀类型名称
     * 开关阀类型(
     * 1:刷卡开阀;
     * 2:刷卡关阀;
     * 3:中心站开阀;
     * 4:中心站关阀;
     * 5:余额不足关阀;
     * 6:流量计故障关阀;
     * 7:紧急关闭;
     * 8:用户远程开阀;
     * 9:用户远程关阀;
     * 10:巡检卡关阀;
     * 11:巡检卡刷卡卡开阀;
     * 12:黑名单命令关阀;
     * 13:远程定时关阀;
     * 14:远程定量关阀;
     * 16:管道无水自动关阀;(王江海协议)
     * )
     * @param type 字节
     * @return 名称
     */
    public static String openCloseValveType(Byte type){
        if(type == null){
            return "" ;
        }
        return switch (type) {
            case 1 -> "刷卡开阀";
            case 2 -> "刷卡关阀";
            case 3 -> "中心站开阀";
            case 4 -> "中心站关阀";
            case 5 -> "余额不足关阀";
            case 6 -> "流量计故障关阀";
            case 7 -> "紧急关阀";
            case 8 -> "用户远程开阀";
            case 9 -> "用户远程关阀";
            case 10 -> "巡检卡关阀";
            case 11 -> "巡检卡开阀";
            case 12 -> "黑名单命令关阀";
            case 13 -> "远程定时关阀";
            case 14 -> "远程定量关阀";
            case 16 -> "管道无水自动关阀";
            default -> "未知";
        };
    }
    public static Boolean isCloseValveType(byte type){
        return switch (type) {
            case 1, 3, 8, 11 -> false ;
            case 2, 4, 5, 6, 7, 9, 10, 12, 13, 14 -> true ;
            default -> null ;
        };
    }
 
 
}