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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
package com.dy.common.mw.protocol.p206V2;
 
import com.dy.common.mw.channel.tcp.TcpIoSessionAttrIdIsRtuAddr;
import com.dy.common.mw.protocol.p206V1.ProtocolConstantV206V1;
import com.dy.common.util.ByteUtil;
import com.dy.common.util.ByteUtilUnsigned;
import com.dy.common.util.CRC16;
import com.dy.common.util.CRC8_for_2_0;
import org.apache.mina.core.session.IoSession;
 
 
public class CommonV2 {
 
    /**
     * 在Io会话中设置协议名称及版本号
     * @param ioSession 会话
     */
    public void setThisProtocolArr2IoSession(IoSession ioSession){
        ioSession.setAttribute(TcpIoSessionAttrIdIsRtuAddr.sessionArrProtocolName, ProtocolConstantV206V1.protocolName) ;
        ioSession.setAttribute(TcpIoSessionAttrIdIsRtuAddr.sessionArrProtocolName, ProtocolConstantV206V1.protocolVer) ;
    }
    /**
     * 检查头
     * @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)
                && bs[ProtocolConstantV206V2.headFlag1Index] == ProtocolConstantV206V2.P_Head_Byte
                && bs[ProtocolConstantV206V2.headFlag2Index] == ProtocolConstantV206V2.P_Head_Byte){
            Short vs = this.parseVersion(bs) ;
            if(vs.shortValue() == ProtocolConstantV206V2.protocolVer){
                return new Boolean[]{true, true};
            }else{
                return new Boolean[]{false, true};
            }
        }else if(bs.length >= (ProtocolConstantV206V2.UG_codeIndex)
                && bs[0] == ProtocolConstantV206V2.UG_P_Head_Byte
                && bs[3] == ProtocolConstantV206V2.UG_P_Head_Byte){
            return new Boolean[]{true, false} ;
        }else{
            return new Boolean[]{false, false} ;
        }
    }
 
    /**
     * 检查协议类型
     * @param bs 上行字节数组
     * @return 协议类型
     * @throws Exception 异常
     */
    public Boolean protocolType_p206TrueUgFalse(byte[] bs){
        if(bs == null){
            return null ;
        }else if(bs.length >= (ProtocolConstantV206V2.ctrlIndex)
                && bs[0] == ProtocolConstantV206V2.P_Head_Byte
                && bs[2] == ProtocolConstantV206V2.P_Head_Byte){
            return true ;
        }else if(bs.length >= (ProtocolConstantV206V2.UG_codeIndex)
                && bs[0] == ProtocolConstantV206V2.UG_P_Head_Byte
                && bs[3] == ProtocolConstantV206V2.UG_P_Head_Byte){
            return false ;
        }else{
            return null ;
        }
    }
    /**
     * 分析版本号
     * @param bs
     * @return
     */
    public Short parseVersion(byte[] bs)throws Exception{
        return ByteUtil.byte2PlusInt(bs[ProtocolConstantV206V2.versionIndex]) ;
    }
 
    /**
     * 检查尾
     * @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 上行字节数组
     * @param p206TrueUgFalse 206协议为true,升级协议为false
     * @return 数据长度
     * @throws Exception 异常
     */
    public int parseFrameLen(byte[] bs, boolean p206TrueUgFalse)throws Exception{
        if(p206TrueUgFalse) {
            int len = ByteUtilUnsigned.byte2Byte(bs, ProtocolConstantV206V2.dataLenIndex);
            return len + ProtocolConstantV206V2.lenHead2ctrl + ProtocolConstantV206V2.lenTail;
        }else{
            int len = ByteUtilUnsigned.bytes2Short_BE(bs, ProtocolConstantV206V2.UG_dataLenIndex_start);
            return len + ProtocolConstantV206V2.UG_lenHead2Cmd + ProtocolConstantV206V2.UG_lenTail;
        }
    }
 
    /**
     * 分析用户数据域字节数(默认是非升级协议)
     * @param bs 上行字节数组
     * @return 数据长度
     * @throws Exception 异常
     */
    public int parseDataLen4P206(byte[] bs)throws Exception{
        int len = ByteUtilUnsigned.byte2Byte(bs, ProtocolConstantV206V2.dataLenIndex) ;
        return len - ProtocolConstantV206V2.lenCtrl - ProtocolConstantV206V2.lenRtuAddr ;
    }
 
    /**
     * 分析用户数据域字节数(升级协议)
     * @param bs 上行字节数组
     * @return 数据长度
     * @throws Exception 异常
     */
    public int parseDataLen4Ug(byte[] bs)throws Exception{
        int len = ByteUtilUnsigned.bytes2Short_LE(bs, ProtocolConstantV206V2.UG_dataLenIndex_start) ;
        return len - ProtocolConstantV206V2.UG_lenCmd - ProtocolConstantV206V2.UG_lenRtuAddr ;
    }
 
 
    /**
     * 分析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 功能码
     */
    public String parseCode(byte[] bs, boolean p206TrueUgFalse){
        if(p206TrueUgFalse) {
            return ByteUtil.bytes2Hex(bs, false, ProtocolConstantV206V1.codeIndex, 1);
        }else{
            return ByteUtil.bytes2Hex(bs, false, ProtocolConstantV206V1.UG_codeIndex, 2);
        }
    }
 
    /**
     * 校验和检查
     * @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 ;
        }
    }
 
 
    /**
     * 校验和检查
     * @param bs  上行字节数组
     * @param p206TrueUgFalse 206协议为true,升级协议为false
     * @return 通过null,未通过返回原因
     * @throws Exception 异常
     */
    public String checkCrc_str(byte[] bs, boolean p206TrueUgFalse) throws Exception {
        if(p206TrueUgFalse){
            byte crcCompute = (byte)new CRC8_for_2_0().CRC8(bs, ProtocolConstantV206V1.ctrlIndex, bs.length - 3) ;
            byte crcInBs = bs[bs.length - 2] ;
            if(crcCompute == crcInBs){
                return null ;
            }else{
                return "计算CRC是:" + crcCompute + ",上传CRC是" + crcInBs ;
            }
        }else{
            short crcCompute = new CRC16().CRC(bs, 0, bs.length - 4) ;
            short crcInBs = ByteUtil.bytes2Short_BE(bs,bs.length - 3) ;
            //int crcInBs = ByteUtilUnsigned.bytes2Short_BE(bs, bs.length - 3) ;
            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 ;
        };
    }
 
 
}