Bladeren bron

104召唤报文格式调试修改

songwenbin 2 jaren geleden
bovenliggende
commit
da216f3183

+ 9 - 3
gddlly/src/main/java/com/gyee/edge/gddlly/config/Iec104Config.java

@@ -15,20 +15,26 @@ public class Iec104Config {
     //服务监听端口
     private short port = 8019;
 
-    //轮询发送时间
-    private int pollingInterval = 3000;
+    //全量推送时间间隔
+    private int fullPushInterval = 30000;
+    //变化推送时间间隔
+    private int changedPushInterval = 10000;
 
     //接收到帧的数量到该值就要发一个确认帧
     private short frameAmountMax;
 
+    //每帧遥测点最大点数
     private int frameAiMax = 16;
+    //每帧遥测点最大点数
     private int frameDiMax = 22;
 
 
 
+
+
     @Override
     public String toString() {
-        return "port = " + port + ", pollingInteral = " + pollingInterval;
+        return "port = " + port + ", pollingInteral = " + fullPushInterval;
     }
 
 }

+ 81 - 45
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/Iec104Session.java

@@ -56,60 +56,67 @@ public class Iec104Session {
         return state;
     }
 
-    public Iec104Message processMessage(Iec104Message request) {
+    public void processMessage(Iec104Message request) {
         if (request == null)
-            return null;
+            return;
 
         try {
+            acceptSeq++;
             if (request.getTypeIdentifier() == null) {
                 //U帧或S帧处理
                 //TODO: 标准化处理,状态校验
+                Iec104Message response = null;
                 byte fun = request.getControl()[0];
                 switch (fun) {
                     case 0x07: //启动命令
-                        state = SessionState.START104;
-                        return  BasicInstruction104.createSysMessage(UControlEnum.STARTDT_YES);
+                        if(state == SessionState.NEW || state == SessionState.INACTIVE)
+                            state = SessionState.START104;
+                        acceptSeq = 0;
+                        sendSeq = 0;
+                        response = BasicInstruction104.createSysMessage(UControlEnum.STARTDT_YES);
+                        break;
                     case 0x43: //测试命令
-                        return BasicInstruction104.createSysMessage(UControlEnum.TESTFR_YES);
+                        response = BasicInstruction104.createSysMessage(UControlEnum.TESTFR_YES);
                     case 0x13: //停止命令
                         state = SessionState.STOP104;
                         //todo: 停止数据的发送
                         this.stop();
-                        return BasicInstruction104.createSysMessage(UControlEnum.STOPDT_YES);
+                        response = BasicInstruction104.createSysMessage(UControlEnum.STOPDT_YES);
+                        break;
                     default:
-                        return null;
+                        break;
                 }
-            } else if (request.getTypeIdentifier() == TypeIdentifierEnum.generalCall) {
-                // 总召唤命令
-                if (TransferReason.ACTIVATE == TransferReason.valueOf(request.getTransferReason())) {
-                    state = SessionState.CALL_ALL;
+                if (response != null)
+                    sendMessage(response);
+                    //channelHandlerContext.writeAndFlush(response);
+            } else {
+                //acceptSeq = (short)(request.getSendSeq() + 1);
+                if (request.getTypeIdentifier() == TypeIdentifierEnum.generalCall) {
+                    // 总召唤命令
                     publicAddress = request.getTerminalAddress();
                     aiList = pointService.getAiList().get((int)publicAddress);
                     diList = pointService.getDiList().get((int)publicAddress);
-                    //todo: 启动全量传输
-                    this.start();
-                    acceptSeq = request.getAcceptSeq();
-                    sendSeq += 1;
-                    return BasicInstruction104.getYesGeneralCallRuleDetail104(acceptSeq, sendSeq);
-
-                } else if (TransferReason.STOP_ACTIVATION == TransferReason.valueOf(request.getTransferReason())) {
-                    state = SessionState.CALL_ALL_END;
-                    //todo: 启动变化传输
-                    this.start();
-                    return null;
-                }
+                    if (TransferReason.ACTIVATE == TransferReason.valueOf(request.getTransferReason())) {
+                        state = SessionState.CALL_ALL;
+                        sendMessage(BasicInstruction104.getYesGeneralCallRuleDetail104(acceptSeq, sendSeq));
+                        //todo: 启动全量传输
+                        this.start();
 
-            } else {
-                //todo: 其它命令处理
+                    } else if (TransferReason.STOP_ACTIVATION == TransferReason.valueOf(request.getTransferReason())) {
+                        state = SessionState.CALL_ALL_END;
+                        //todo: 启动变化传输
+                        this.start();
+                    }
+
+                } else {
+                    //todo: 其它命令处理
+                }
             }
 
         }catch (Exception ex) {
             log.error(ex.getMessage());
             ex.printStackTrace();
-            return null;
         }
-
-        return null;
     }
 
     public void start() {
@@ -158,7 +165,10 @@ public class Iec104Session {
                             }
                         }
 
-                        Thread.sleep(iec104Config.getPollingInterval());
+                        if (state == SessionState.CALL_ALL_END)
+                            Thread.sleep(iec104Config.getChangedPushInterval());
+                        else
+                            Thread.sleep(iec104Config.getFullPushInterval());
                     }
                 } catch (Exception e) {
                     //todo: 异常处理
@@ -182,37 +192,55 @@ public class Iec104Session {
         }
 
         Iec104Message msg104 = createNewMessage(isContinous, pointType);
-        //消息地址为信息体中第一个元素的地址
-        int firstMsgAddr = allPoints.get(0).getPointAddr();
-        msg104.setMessageAddress(firstMsgAddr);
+
+        if (isContinous) {
+            //消息地址为信息体中第一个元素的地址
+            int firstMsgAddr = allPoints.get(0).getPointAddr();
+            msg104.setMessageAddress(firstMsgAddr);
+        }
 
         for(int i=0;i<allPoints.size();i++) {
             Point point = allPoints.get(i);
+            if (!isContinous && point.isConsumed())
+                continue;
+
             if (pointList.size() >= maxPointsPerMessage) {
-                msg104.setAiPointList(pointList);
-                msg104.setSendSeq(sendSeq++);
+                if ("AI".equals(pointType.toUpperCase())) {
+                    msg104.setAiPointList(pointList);
+                } else {
+                    msg104.setDiPointList(pointList);
+                }
+
                 msg104.setInfosize(pointList.size());
-                channelHandlerContext.writeAndFlush(msg104);
+                sendMessage(msg104);
+
+
                 //todo:考虑实现确认S帧
 
                 //重置point列表缓存,消息地址,其它内容不变
-                if (i < aiList.size()-1) {
+                if (i < allPoints.size()-1) {
                     pointList = new ArrayList<>();
                     msg104 = createNewMessage(isContinous,pointType);
-                    firstMsgAddr = allPoints.get(i+1).getPointAddr();
-
-                    msg104.setMessageAddress(firstMsgAddr);
+                    if (isContinous)
+                        msg104.setMessageAddress(allPoints.get(i).getPointAddr());
                 }
+
+                ///////////////////todo :debug
+                //return true;
+                //////////////////
             }
-            pointList.add(aiList.get(i));
+            pointList.add(point);
             point.setConsumed(true);
         }
 
         if (pointList.size() > 0) {
-            msg104.setAiPointList(pointList);
-            msg104.setSendSeq(sendSeq++);
+            if ("AI".equals(pointType.toUpperCase())) {
+                msg104.setAiPointList(pointList);
+            } else {
+                msg104.setDiPointList(pointList);
+            }
             msg104.setInfosize(pointList.size());
-            channelHandlerContext.writeAndFlush(msg104);
+            sendMessage(msg104);
         }
 
         return true;
@@ -223,9 +251,9 @@ public class Iec104Session {
         msg104.setAcceptSeq(acceptSeq);
         msg104.setTransferReason((short)20);
         if ("AI".equals(pointType.toUpperCase())) {
-            msg104.setTypeIdentifier(TypeIdentifierEnum.shortFloatingPointTelemetry); //M_ME_TF_1
+            msg104.setTypeIdentifier(TypeIdentifierEnum.M_ME_TF_1); //M_ME_TF_1
         } else {
-            msg104.setTypeIdentifier(TypeIdentifierEnum.onePointTimeTeleindication); //M_SP_TB_1
+            msg104.setTypeIdentifier(TypeIdentifierEnum.M_SP_TB_1); //M_SP_TB_1
         }
         //todo: 设置VSQ,可变结构描述限定词
         msg104.setContinuous(isContinous);
@@ -233,4 +261,12 @@ public class Iec104Session {
         return msg104;
     }
 
+    private synchronized void sendMessage(Iec104Message msg) {
+
+        msg.setSendSeq(sendSeq++);
+        log.info("send message:" + msg.getSendSeq() + ", address = " + msg.getMessageAddress()
+                + ",type= " + msg.getTypeIdentifier()) ;
+        channelHandlerContext.writeAndFlush(msg);
+    }
+
 }

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

@@ -185,7 +185,7 @@ public class Iec104Util {
 				|| TypeIdentifierEnum.twoPointTelecontrol.equals(msg104.getTypeIdentifier())); // 双命令遥控
 		msg104.setQualifiers(isQualifiers);
 		boolean isTimeScale = TypeIdentifierEnum.timeSynchronization.equals(msg104.getTypeIdentifier())  // 时钟同步
-				|| TypeIdentifierEnum.onePointTimeTeleindication.equals(msg104.getTypeIdentifier()) // 摇信带时标 单点
+				|| TypeIdentifierEnum.M_SP_TB_1.equals(msg104.getTypeIdentifier()) // 摇信带时标 单点
 				|| TypeIdentifierEnum.twoPointTimeTeleindication.equals(msg104.getTypeIdentifier()); //摇信带时标 双点
 		msg104.setTimeScaleExit(isTimeScale);
 	}

+ 12 - 19
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/builder/Encoder104.java

@@ -15,22 +15,16 @@ import java.io.IOException;
 public class Encoder104 {
 	
 	public static byte[] encoder(Iec104Message msg104) throws IOException {
-		try {
-			Iec104Util.setMeaageAttribute(msg104);
-			ByteArrayOutputStream bytes = new ByteArrayOutputStream();
-			bytes.write(msg104.getStart());
-			byte[]  apduBytes = getApduBytes(msg104);
-			int messageLen =  apduBytes.length;
-			msg104.setApduLength(messageLen);
-			bytes.write((byte) messageLen);
-			bytes.write(apduBytes);
-
-			return bytes.toByteArray();
-		} catch (Exception e) {
-			log.error(e.getMessage(), e.fillInStackTrace());
-			throw new IOException();
-		}
+		Iec104Util.setMeaageAttribute(msg104);
+		ByteArrayOutputStream bytes = new ByteArrayOutputStream();
+		bytes.write(msg104.getStart());
+		byte[]  apduBytes = getApduBytes(msg104);
+		int messageLen =  apduBytes.length;
+		msg104.setApduLength(messageLen);
+		bytes.write((byte) messageLen);
+		bytes.write(apduBytes);
 
+		return bytes.toByteArray();
 	}
 	
 	private static byte[] getApduBytes(Iec104Message msg104) throws IOException {
@@ -59,15 +53,14 @@ public class Encoder104 {
 				//按照M_ME_TF_1序列化数据
 				for(Point point: msg104.getAiPointList()) {
 					bOutput.write(ByteUtil.float2Bytes((float) point.getValue()));
+					bOutput.write((byte)0);	//品质描述针对遥测值,放在浮点数之后
 					bOutput.write(ByteUtil.date2Hbyte(point.getLastUpdateTime()));
-					//todo: 考虑是否写品质描述词?
 				}
 			} else if (msg104.getDiPointList() != null && msg104.getDiPointList().size() > 0) {
 				//按照M_SP_TB_1序列化数据
 				for(Point point: msg104.getDiPointList()) {
 					bOutput.write(point.getValue() == 0 ? (byte)0 : (byte)1);
 					bOutput.write(ByteUtil.date2Hbyte(point.getLastUpdateTime()));
-					//todo: 考虑是否写品质描述词?
 				}
 			}
 
@@ -77,8 +70,8 @@ public class Encoder104 {
 				for(Point point: msg104.getAiPointList()) {
 					bOutput.write(Iec104Util.intToMessageAddress(point.getPointAddr()));
 					bOutput.write(ByteUtil.float2Bytes((float) point.getValue()));
+					bOutput.write((byte)0);
 					bOutput.write(ByteUtil.date2Hbyte(point.getLastUpdateTime()));
-					//todo: 考虑是否写品质描述词?
 				}
 			} else if (msg104.getDiPointList() != null && msg104.getDiPointList().size() > 0) {
 				//按照M_SP_TB_1序列化数据
@@ -86,7 +79,7 @@ public class Encoder104 {
 					bOutput.write(Iec104Util.intToMessageAddress(point.getPointAddr()));
 					bOutput.write(point.getValue() == 0 ? (byte)0 : (byte)1);
 					bOutput.write(ByteUtil.date2Hbyte(point.getLastUpdateTime()));
-					//todo: 考虑是否写品质描述词?
+					//bOutput.write((byte)0);
 				}
 			}
 		}

+ 1 - 1
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/handler/FrameDecoder.java

@@ -18,7 +18,7 @@ public class FrameDecoder extends ByteToMessageDecoder {
 	@Override
     protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List<Object> out) throws Exception {
 
-	    System.out.println("Enter Iec104Decoder ......");
+	    //System.out.println("Enter Iec104Decoder ......");
         // 记录包头开始的index
         int beginReader = 0;
         int newDataLength = 0;

+ 7 - 4
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/handler/Iec104Decoder.java

@@ -8,6 +8,7 @@ import com.gyee.edge.gddlly.utils.ByteUtil;
 import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.ByteToMessageDecoder;
+import lombok.extern.slf4j.Slf4j;
 
 import java.util.List;
 
@@ -15,17 +16,19 @@ import java.util.List;
 /**
  * 解码器
  */
+@Slf4j
 public class Iec104Decoder extends ByteToMessageDecoder {
 	
 	@Override
 	protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
 		byte[] data = new byte[in.readableBytes()];
 		in.readBytes(data);
-		String str= Analysis.analysis(ByteUtil.byteArrayToHexString(data));
-		System.out.println(str);
+//		log.info("收到报文:" + ByteUtil.byteArrayToHexString(data));
+//		String str= Analysis.analysis(ByteUtil.byteArrayToHexString(data));
+//		System.out.println(str);
 //		short send = Iec104Util.getSend(ByteUtil.getByte(data, 2, 4));
 //		Iec104ThreadLocal.getControlPool().setAccept(send);
-		Iec104Message ruleDetail104 = Decoder104.decode(data);
-		out.add(ruleDetail104);
+		Iec104Message msg104 = Decoder104.decode(data);
+		out.add(msg104);
 	}
 }

+ 1 - 4
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/handler/Iec104ServerHandler.java

@@ -50,11 +50,8 @@ public class Iec104ServerHandler extends SimpleChannelInboundHandler<Iec104Messa
 		if (session == null)
 			ReferenceCountUtil.release(msg104);
 
-		Iec104Message rsp = session.processMessage(msg104);
-		if (rsp == null)
-			ReferenceCountUtil.release(msg104);
+		session.processMessage(msg104);
 
-		ctx.writeAndFlush(rsp);
 	}
 
 	@Override

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

@@ -122,9 +122,11 @@ public class BasicInstruction104 {
 		message.setMessageInfos(new byte[] {});
 		
 		messages.add(message);
-		Iec104Message ruleDetail104 = new Iec104Message(control, typeIdentifierEnum, isContinuous, isTest, isPN, transferReason,
+		Iec104Message msg = new Iec104Message(control, typeIdentifierEnum, isContinuous, isTest, isPN, transferReason,
 				terminalAddress, messageAddress, messages, null, null);
-		return ruleDetail104;
+		msg.setAcceptSeq(accept);
+		msg.setSendSeq(send);
+		return msg;
 	}
 	
 	

+ 1 - 1
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/protocol/QualifiersEnum.java

@@ -80,7 +80,7 @@ public enum QualifiersEnum {
 		}
 		if ((TypeIdentifierEnum.readOneParameter.equals(typeIdentifier)
 				|| TypeIdentifierEnum.readMultipleParameter.equals(typeIdentifier)
-				|| TypeIdentifierEnum.prefabActivationOneParameter.equals(typeIdentifier)
+				|| TypeIdentifierEnum.M_SP_TB_1.equals(typeIdentifier)
 				|| TypeIdentifierEnum.prefabActivationMultipleParameter.equals(typeIdentifier))
 				&& qualityQualifiers.getValue() == value) {
 			qualifiersEnum = qualityQualifiers;

+ 5 - 1
gddlly/src/main/java/com/gyee/edge/gddlly/iec104/protocol/TypeIdentifierEnum.java

@@ -26,10 +26,14 @@ public enum TypeIdentifierEnum {
 	 * 测量值 短浮点数 遥测   Short floating point
 	 */
 	shortFloatingPointTelemetry(0x0D),
+	M_ME_TF_1(0x24),
+	//M_SP_TB_1(0x30),
+
 	/**
 	 * 摇信带时标 单点
 	 */
-	onePointTimeTeleindication(0x1E),
+	M_SP_TB_1(0x1E),
+
 	/**
 	 * 摇信带时标 双点
 	 */

+ 4 - 3
gddlly/src/main/java/com/gyee/edge/gddlly/redis/RedisDataService.java

@@ -100,14 +100,15 @@ public class RedisDataService {
                 long time = Long.valueOf(ts.substring(ts.indexOf("\"") + 1, ts.length() - 1));
                 double value = Double.valueOf(vs.substring(1, vs.lastIndexOf("\"")));
 
-                point.setLastUpdateTime(new Date(time));
                 if (point.getValue() != value ) {
                     point.setConsumed(false);
                     point.setValue(value);
+                    point.setLastUpdateTime(new Date(time));
                 }
-                // point.setConsumed(point.getValue() == value ? true : false);
 
-                //map.replace(points.get(i), point);
+                if (point.getLastUpdateTime() == null)
+                    point.setLastUpdateTime(new Date(time));
+
             }
         } catch (Exception e){
             log.error(e.getMessage());

+ 6 - 2
gddlly/src/main/resources/application.yaml

@@ -24,5 +24,9 @@ spring:
 
 
 iec104:
-  port: 8019
-  pollingInterval: 1000
+  port: 2404
+  fullPushInterval: 60000
+  changedPushInterval: 10000
+  frameAiMax: 16
+  frameDiMax: 22
+