Apdu.java 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. package wei.yigulu.iec104.apdumodel;
  2. import io.netty.buffer.ByteBuf;
  3. import io.netty.buffer.Unpooled;
  4. import io.netty.channel.Channel;
  5. import lombok.AllArgsConstructor;
  6. import lombok.Data;
  7. import lombok.NoArgsConstructor;
  8. import lombok.experimental.Accessors;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. import wei.yigulu.iec104.exception.Iec104Exception;
  12. import wei.yigulu.iec104.nettyconfig.TechnicalTerm;
  13. import wei.yigulu.iec104.util.SendAndReceiveNumUtil;
  14. import wei.yigulu.netty.BaseProtocolBuilder;
  15. import java.util.ArrayList;
  16. import java.util.List;
  17. /**
  18. * 104协议内核处理类
  19. * 104信息体模型类
  20. * 消息分为 S I U 格式帧
  21. * I格式帧具有ASDU消息体
  22. *
  23. * @author 修唯xiuwei
  24. * @version 3.0
  25. */
  26. @Data
  27. @Accessors(chain = true)
  28. @NoArgsConstructor
  29. @AllArgsConstructor
  30. public class Apdu {
  31. private Logger log = LoggerFactory.getLogger(this.getClass());
  32. /**
  33. * 本端的发送序号
  34. */
  35. protected int sendSeqNum = 0;
  36. /**
  37. * 本端的接收序号
  38. */
  39. protected int receiveSeqNum = 0;
  40. /**
  41. * 本帧的类型
  42. */
  43. protected ApciType apciType = ApciType.I_FORMAT;
  44. /**
  45. * Asdu
  46. */
  47. protected Asdu asdu = null;
  48. /**
  49. * Iec 104 builder
  50. */
  51. protected BaseProtocolBuilder iec104Builder;
  52. /**
  53. * 记录了该条APDU是在哪条通道里传输的
  54. */
  55. protected Channel channel;
  56. /**
  57. * 枚举,APCI类型,即I帧,S帧,U帧
  58. */
  59. public enum ApciType {
  60. /**
  61. * I帧
  62. */
  63. I_FORMAT,
  64. /**
  65. * S帧
  66. */
  67. S_FORMAT,
  68. /**
  69. * U帧,测试确认
  70. */
  71. TESTFR_CON,
  72. /**
  73. * U帧,测试命令
  74. */
  75. TESTFR_ACT,
  76. /**
  77. * U帧,停止确认
  78. */
  79. STOPDT_CON,
  80. /**
  81. * U帧,停止命令
  82. */
  83. STOPDT_ACT,
  84. /**
  85. * U帧,启动确认
  86. */
  87. STARTDT_CON,
  88. /**
  89. * U帧,启动命令
  90. */
  91. STARTDT_ACT
  92. }
  93. /**
  94. * 读取字节流 将数据帧转化为APDU
  95. *
  96. * @param dis dis
  97. * @return apdu
  98. * @throws Exception exception
  99. */
  100. public Apdu loadByteBuf(ByteBuf dis) throws Exception {
  101. this.channel = channel;
  102. int start = dis.readByte() & 0xff;
  103. int len = dis.readByte() & 0xff;
  104. log.debug("APDU长度:" + len);
  105. byte[] controlFields = new byte[4];
  106. if (start != 0x68) {
  107. new Iec104Exception("起始字符错误" + start);
  108. } else if (len < 4 || len > 253) {
  109. new Iec104Exception("帧长度有误" + len);
  110. } else {
  111. //读4字节控制域
  112. dis.readBytes(controlFields);
  113. //第一比特=0 ===》I格式
  114. if ((controlFields[0] & 0x01) == 0) {
  115. //I帧
  116. this.apciType = ApciType.I_FORMAT;
  117. //发送序列号 先是最低有效位 ,接下来是最高有效位,最高有效位拿到后面,最低有效位后面补0,LSB 0;MSB
  118. sendSeqNum = ((controlFields[0] & 0xfe) >> 1) + ((controlFields[1] & 0xff) << 7);
  119. //接收序列号 原理同发送序列号
  120. receiveSeqNum = ((controlFields[2] & 0xfe) >> 1) + ((controlFields[3] & 0xff) << 7);
  121. log.debug("I帧,发送序列号:" + sendSeqNum + ",接收序列号:" + receiveSeqNum);
  122. if (this.channel != null) {
  123. SendAndReceiveNumUtil.receiveIFrame(this, this.channel.id());
  124. }
  125. //第一比特=1 第二比特=0 ===》S格式
  126. } else if ((controlFields[0] & 0x03) == 1) {
  127. //S帧
  128. this.apciType = ApciType.S_FORMAT;
  129. receiveSeqNum = ((controlFields[2] & 0xfe) >> 1) + ((controlFields[3] & 0xff) << 7);
  130. log.debug("S帧,接收序列号:" + receiveSeqNum);
  131. //第一比特=1 第二比特=1 ===》S格式
  132. } else if ((controlFields[0] & 0x03) == 3) {
  133. //U帧
  134. switch (controlFields[0]) {
  135. case 0x07:
  136. this.apciType = ApciType.STARTDT_ACT;
  137. log.debug("U帧,启动命令");
  138. break;
  139. case 0x0B:
  140. this.apciType = ApciType.STARTDT_CON;
  141. log.debug("U帧启动确认");
  142. break;
  143. case 0x13:
  144. this.apciType = ApciType.STOPDT_ACT;
  145. log.debug("U帧停止命令");
  146. break;
  147. case 0x23:
  148. this.apciType = ApciType.STOPDT_CON;
  149. log.debug("U帧停止确认");
  150. break;
  151. case 0x43:
  152. this.apciType = ApciType.TESTFR_ACT;
  153. log.debug("U帧测试命令");
  154. break;
  155. case (byte) 0x83:
  156. this.apciType = ApciType.TESTFR_CON;
  157. log.debug("U帧测试确认");
  158. break;
  159. default:
  160. log.debug("U帧类型异常");
  161. break;
  162. }
  163. }
  164. //构建数据单元
  165. if (len > 6) {
  166. this.asdu = new Asdu().setLog(log).loadByteBuf(dis);
  167. }
  168. }
  169. return this;
  170. }
  171. /**
  172. * APDU编码由当前的apdu编码成数据帧
  173. *
  174. * @return byte [ ]
  175. * @throws Exception exception
  176. */
  177. public byte[] encode() throws Exception {
  178. List<Byte> buffer = new ArrayList<>();
  179. buffer.add((byte) 0x68);
  180. buffer.add((byte) 0x00);
  181. if (apciType == ApciType.I_FORMAT) {
  182. buffer.add((byte) (sendSeqNum << 1));
  183. buffer.add((byte) (sendSeqNum >> 7));
  184. buffer.add((byte) (receiveSeqNum << 1));
  185. buffer.add((byte) (receiveSeqNum >> 7));
  186. asdu.encode(buffer);
  187. } else if (apciType == ApciType.STARTDT_ACT) {
  188. buffer.add((byte) 0x07);
  189. buffer.add((byte) 0x00);
  190. buffer.add((byte) 0x00);
  191. buffer.add((byte) 0x00);
  192. } else if (apciType == ApciType.STARTDT_CON) {
  193. buffer.add((byte) 0x0b);
  194. buffer.add((byte) 0x00);
  195. buffer.add((byte) 0x00);
  196. buffer.add((byte) 0x00);
  197. } else if (apciType == ApciType.S_FORMAT) {
  198. buffer.add((byte) 0x01);
  199. buffer.add((byte) 0x00);
  200. buffer.add((byte) (receiveSeqNum << 1));
  201. buffer.add((byte) (receiveSeqNum >> 7));
  202. }
  203. buffer.set(1, (byte) (buffer.size() - 2));
  204. byte[] bs = new byte[buffer.size()];
  205. for (int i = 0; i < buffer.size(); i++) {
  206. bs[i] = buffer.get(i);
  207. }
  208. return bs;
  209. }
  210. /**
  211. * Sets asdu *
  212. *
  213. * @param asdu asdu
  214. * @return the asdu
  215. */
  216. public Apdu setAsdu(Asdu asdu) {
  217. this.asdu = asdu;
  218. this.apciType = ApciType.I_FORMAT;
  219. return this;
  220. }
  221. /**
  222. * 接收帧后的应答措施
  223. *
  224. * @throws Iec104Exception iec exception
  225. */
  226. public void answer() throws Iec104Exception {
  227. byte[][] bb = new byte[0][];
  228. if (this.apciType == ApciType.I_FORMAT) {
  229. try {
  230. if(this.asdu.getDataFrame()==null){
  231. log.error("I帧数据体为空");
  232. return;
  233. }
  234. bb = this.asdu.getDataFrame().handleAndAnswer(this);
  235. } catch (Exception e) {
  236. log.error("数据帧解析后的逻辑处理出现异常:{}", e.getMessage());
  237. }
  238. } else if (this.apciType == ApciType.S_FORMAT) {
  239. bb = sHandleAndAnswer();
  240. } else {
  241. bb = uHandleAndAnswer();
  242. }
  243. if (bb != null) {
  244. ByteBuf buffer = Unpooled.compositeBuffer();
  245. for (byte[] b : bb) {
  246. buffer.writeBytes(b);
  247. }
  248. this.channel.pipeline().writeAndFlush(buffer);
  249. }
  250. }
  251. /**
  252. * U帧的应答措施
  253. *
  254. * @return byte [ ] [ ]
  255. * @throws Iec104Exception iec exception
  256. */
  257. public byte[][] uHandleAndAnswer() throws Iec104Exception {
  258. byte[][] bb = null;
  259. if (this.apciType == ApciType.STARTDT_ACT) {
  260. bb = new byte[1][];
  261. bb[0] = TechnicalTerm.STARTBACK;
  262. } else if (this.apciType == ApciType.STARTDT_CON) {
  263. //bb = new byte[1][];
  264. //bb[0] = TechnicalTerm.GENERALINTERROGATION;
  265. } else if (this.apciType == ApciType.STOPDT_ACT) {
  266. bb = new byte[1][];
  267. bb[0] = TechnicalTerm.STOPBACK;
  268. } else if (this.apciType == ApciType.TESTFR_ACT) {
  269. bb = new byte[1][];
  270. bb[0] = TechnicalTerm.TESTBACK;
  271. }
  272. return bb;
  273. }
  274. /**
  275. * 对方响应S帧的应答措施
  276. *
  277. * @return byte [ ] [ ]
  278. * @throws Iec104Exception iec exception
  279. */
  280. public byte[][] sHandleAndAnswer() throws Iec104Exception {
  281. return null;
  282. }
  283. /**
  284. * 我方丢失 通道对方放出的 i帧
  285. */
  286. public void loseReceive() {
  287. }
  288. /**
  289. * 通道对方丢失 我方发出的i帧
  290. */
  291. public void loseSend() {
  292. }
  293. }