浏览代码

104协议bug修正

songwenbin 2 年之前
父节点
当前提交
0da5c76e56

+ 2 - 0
gddlly/src/main/java/com/gyee/edge/gddlly/config/Iec104Config.java

@@ -19,6 +19,8 @@ public class Iec104Config {
     private int fullPushInterval = 30000;
     //变化推送时间间隔
     private int changedPushInterval = 10000;
+    //心跳信号发送时间间隔
+    private int sendSysFrameInterval = 10000;
 
     //接收到帧的数量到该值就要发一个确认帧
     private short frameAmountMax;

+ 7 - 1
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/Iec104Message.java

@@ -14,7 +14,13 @@ import java.util.List;
  */
 @Data
 public class Iec104Message {
-	
+
+
+	/**
+	 * U帧直接拼
+	 */
+	private byte[] udata;
+
 	/**
 	 * 启动字符 固定 一个字节
 	 */

+ 79 - 10
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/Iec104Session.java

@@ -28,6 +28,7 @@ public class Iec104Session {
     private short acceptSeq = 0;    //接收序列号
     private short sendSeq = 0;      //发送序列号
     private boolean isRunning = false;
+    private boolean isStarted = false;
 
     private ChannelHandlerContext channelHandlerContext;
 
@@ -61,7 +62,7 @@ public class Iec104Session {
             return;
 
         try {
-            acceptSeq++;
+
             if (request.getTypeIdentifier() == null) {
                 //U帧或S帧处理
                 //TODO: 标准化处理,状态校验
@@ -69,7 +70,7 @@ public class Iec104Session {
                 byte fun = request.getControl()[0];
                 switch (fun) {
                     case 0x07: //启动命令
-                        if(state == SessionState.NEW || state == SessionState.INACTIVE)
+                        if(state == SessionState.NEW || state == SessionState.ACTIVE)
                             state = SessionState.START104;
                         acceptSeq = 0;
                         sendSeq = 0;
@@ -77,6 +78,7 @@ public class Iec104Session {
                         break;
                     case 0x43: //测试命令
                         response = BasicInstruction104.createSysMessage(UControlEnum.TESTFR_YES);
+                        break;
                     case 0x13: //停止命令
                         state = SessionState.STOP104;
                         //todo: 停止数据的发送
@@ -87,9 +89,13 @@ public class Iec104Session {
                         break;
                 }
                 if (response != null)
-                    sendMessage(response);
+                    sendMessage2(response);
+
+                if (state == SessionState.START104)
+                    this.start();
                     //channelHandlerContext.writeAndFlush(response);
             } else {
+                acceptSeq++;
                 //acceptSeq = (short)(request.getSendSeq() + 1);
                 if (request.getTypeIdentifier() == TypeIdentifierEnum.generalCall) {
                     // 总召唤命令
@@ -120,16 +126,32 @@ public class Iec104Session {
     }
 
     public void start() {
+        if (isStarted) {
+            log.warn("104测试帧发送线程已启动!client = " +getId());
+        } else {
+            getTest104Thread().start();
+        }
+
         if (isRunning) {
             log.warn("数据轮询和转发线程已启动!client = " +getId());
-            return;
+        } else {
+            if (publicAddress > 0) {
+                //有意延迟3秒,错开测试帧和数据帧
+                try {
+                    Thread.sleep(3000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+                getPushThread().start();
+            }
         }
 
-        getPushThread().start();
+
     }
 
     public void stop() {
         isRunning = false;
+        isStarted = false;
     }
 
     private Thread getPushThread() {
@@ -165,10 +187,18 @@ public class Iec104Session {
                             }
                         }
 
-                        if (state == SessionState.CALL_ALL_END)
-                            Thread.sleep(iec104Config.getChangedPushInterval());
-                        else
-                            Thread.sleep(iec104Config.getFullPushInterval());
+                        if (state == SessionState.CALL_ALL) {
+                            state = SessionState.CALL_ALL_END;
+                            //Thread.sleep(iec104Config.getFullPushInterval());
+                        }
+
+                        Thread.sleep(iec104Config.getChangedPushInterval());
+
+
+//                        if (state == SessionState.CALL_ALL_END)
+//                            Thread.sleep(iec104Config.getChangedPushInterval());
+//                        else
+//                            Thread.sleep(iec104Config.getFullPushInterval());
                     }
                 } catch (Exception e) {
                     //todo: 异常处理
@@ -250,7 +280,10 @@ public class Iec104Session {
     private Iec104Message createNewMessage(boolean isContinous, String pointType) {
         Iec104Message msg104 = new Iec104Message();
         msg104.setAcceptSeq(acceptSeq);
-        msg104.setTransferReason((short)20);
+        if (isContinous)
+            msg104.setTransferReason((short)20);
+        else
+            msg104.setTransferReason((short)3);
         if ("AI".equals(pointType.toUpperCase())) {
             msg104.setTypeIdentifier(TypeIdentifierEnum.M_ME_TF_1); //M_ME_TF_1
         } else {
@@ -269,4 +302,40 @@ public class Iec104Session {
         channelHandlerContext.writeAndFlush(msg);
     }
 
+    private synchronized void sendMessage2(Iec104Message msg) {
+//        msg.setSendSeq(sendSeq++);
+//        log.info("send message:" + msg.getSendSeq() + ", address = " + msg.getMessageAddress()
+//                + ",type= " + msg.getTypeIdentifier()) ;
+        channelHandlerContext.writeAndFlush(msg);
+    }
+
+
+    private Thread getTest104Thread() {
+        return new Thread(new Runnable() {
+            public void run() {
+                log.info("开始启动104测试信号发送...");
+                try {
+                    isStarted = true;
+                    while(isStarted) {
+                        try {
+                            //间隔发送104测试帧
+                            Iec104Message testMessage = BasicInstruction104.createSysMessage(UControlEnum.TESTFR);
+                            sendMessage2(testMessage);
+                            Thread.sleep(iec104Config.getSendSysFrameInterval());
+                        } catch (Exception e) {
+                            log.error(e.getMessage());
+                        }
+                    }
+                } catch (Exception e) {
+                    //todo: 异常处理
+                    log.error(e.getMessage());
+
+                } finally {
+                    isStarted = false;
+                }
+            }
+        });
+    }
+
+
 }

+ 8 - 0
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/builder/Encoder104.java

@@ -5,6 +5,7 @@ import com.gyee.edge.gddlly.config.Point;
 import com.gyee.edge.gddlly.iec104.Iec104Util;
 import com.gyee.edge.gddlly.iec104.Iec104Message;
 import com.gyee.edge.gddlly.iec104.MessageInfo;
+import com.gyee.edge.gddlly.iec104.protocol.TypeIdentifierEnum;
 import com.gyee.edge.gddlly.utils.ByteUtil;
 import lombok.extern.slf4j.Slf4j;
 
@@ -20,10 +21,17 @@ public class Encoder104 {
 		bytes.write(msg104.getStart());
 		byte[]  apduBytes = getApduBytes(msg104);
 		int messageLen =  apduBytes.length;
+		if (msg104.getTypeIdentifier() == TypeIdentifierEnum.generalCall && apduBytes.length == 10) {
+			messageLen = 14;
+		}
 		msg104.setApduLength(messageLen);
 		bytes.write((byte) messageLen);
 		bytes.write(apduBytes);
 
+		if (msg104.getTypeIdentifier() == TypeIdentifierEnum.generalCall && apduBytes.length == 10) {
+			bytes.write(new byte[] {0x00, 0x00,0x00, 0x14});
+		}
+
 		return bytes.toByteArray();
 	}
 	

+ 7 - 2
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/handler/Iec104Encoder.java

@@ -23,8 +23,13 @@ public class Iec104Encoder extends MessageToByteEncoder<Iec104Message> {
 	@Override
 	protected void encode(ChannelHandlerContext ctx, Iec104Message msg, ByteBuf out) throws Exception {
 		try {
-			byte[] bytes = Encoder104.encoder(msg);
-			out.writeBytes(bytes);
+			if (msg.getUdata() != null) {
+				out.writeBytes(msg.getUdata());
+			} else {
+				byte[] bytes = Encoder104.encoder(msg);
+				out.writeBytes(bytes);
+			}
+
 		} catch (Exception e) {
 //			log.error(e.getMessage());
 //			e.printStackTrace();

+ 16 - 9
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/handler/Iec104ServerHandler.java

@@ -31,15 +31,7 @@ public class Iec104ServerHandler extends SimpleChannelInboundHandler<Iec104Messa
 
 	@Override
 	public void channelInactive(ChannelHandlerContext ctx) throws Exception {
-		// 清理Session
-		String sessionId = getSessionId(ctx);
-		if (sessionMap.containsKey(sessionId)) {
-			Iec104Session session = sessionMap.get(sessionId);
-			session.stop();
-			Thread.sleep(5000);
-			sessionMap.remove(sessionId);
-		}
-
+		closeSession(ctx);
 	}
 	
 	@Override
@@ -57,6 +49,10 @@ public class Iec104ServerHandler extends SimpleChannelInboundHandler<Iec104Messa
 	@Override
 	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
 		cause.printStackTrace();
+
+		closeSession(ctx);
+
+
 		//todo: 异常处理
 		//ctx.close();
 	}
@@ -67,4 +63,15 @@ public class Iec104ServerHandler extends SimpleChannelInboundHandler<Iec104Messa
 		int clientPort = ipSocket.getPort();
 		return clientIp + ":" + clientPort;
 	}
+
+	private void closeSession(ChannelHandlerContext ctx) throws InterruptedException {
+		// 清理Session
+		String sessionId = getSessionId(ctx);
+		if (sessionMap.containsKey(sessionId)) {
+			Iec104Session session = sessionMap.get(sessionId);
+			session.stop();
+			Thread.sleep(5000);
+			sessionMap.remove(sessionId);
+		}
+	}
 }

+ 16 - 2
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/protocol/BasicInstruction104.java

@@ -173,8 +173,22 @@ public class BasicInstruction104 {
 
 	//U帧消息创建
 	public static Iec104Message createSysMessage(UControlEnum cmd) {
-		byte[] control = ByteUtil.intToByteArray(cmd.getValue());
-		return new Iec104Message(control);
+		Iec104Message msg = new Iec104Message();
+
+		if (cmd == UControlEnum.STARTDT_YES)
+			msg.setUdata(BasicInstruction104.STARTDT_YES);
+		else if (cmd == UControlEnum.STARTDT)
+			msg.setUdata(BasicInstruction104.STARTDT);
+		else if (cmd == UControlEnum.STOPDT_YES)
+			msg.setUdata(BasicInstruction104.STOPDT_YES);
+		else if (cmd == UControlEnum.TESTFR)
+			msg.setUdata(BasicInstruction104.TESTFR);
+		else
+			msg.setUdata(BasicInstruction104.TESTFR_YES);
+
+		return msg;
+
+
 	}
 
 }

+ 1 - 0
gddlly/src/main/resources/application.yaml

@@ -27,6 +27,7 @@ iec104:
   port: 2404
   fullPushInterval: 60000
   changedPushInterval: 10000
+  sendSysFrameInterval: 10000
   frameAiMax: 16
   frameDiMax: 22