private void SendASDUInternal(ASDU asdu) { lock (socket) { if (running == false) { throw new ConnectionException("not connected", new SocketException(10057)); } if (useSendMessageQueue) { lock (waitingToBeSent) { waitingToBeSent.Enqueue(asdu); } SendNextWaitingASDU(); } else { if (IsSentBufferFull()) { throw new ConnectionException("Flow control congestion. Try again later."); } SendIMessageAndUpdateSentASDUs(asdu); } } }
/// <summary> /// Enqueues the ASDU to the transmission queue. /// </summary> /// If an active connection exists the ASDU will be sent to the active client immediately. Otherwhise /// the ASDU will be added to the transmission queue for later transmission. /// <param name="asdu">ASDU to be sent</param> public void EnqueueASDU(ASDU asdu) { if (serverMode == ServerMode.SINGLE_REDUNDANCY_GROUP) { asduQueue.EnqueueAsdu(asdu); foreach (ServerConnection connection in allOpenConnections) { if (connection.IsActive) { connection.ASDUReadyToSend(); } } } else { foreach (ServerConnection connection in allOpenConnections) { if (connection.IsActive) { connection.GetASDUQueue().EnqueueAsdu(asdu); connection.ASDUReadyToSend(); } } } }
public void SendACT_CON(ASDU asdu, bool negative) { asdu.Cot = CauseOfTransmission.ACTIVATION_CON; asdu.IsNegative = negative; SendASDU(asdu); }
/// <summary> /// Enqueues the ASDU to the transmission queue. /// 将ASDU加入队列,并同时发送到当前激活的连接中 /// </summary> /// If an active connection exists the ASDU will be sent to the active client immediately. Otherwhise /// the ASDU will be added to the transmission queue for later transmission. /// <param name="asdu">ASDU to be sent</param> public void EnqueueASDU(ASDU asdu) { if (enqueuedASDUs == null) { enqueuedASDUs = new Queue <ASDU>(); } if (enqueuedASDUs.Count == maxQueueSize) { enqueuedASDUs.Dequeue(); } enqueuedASDUs.Enqueue(asdu); Console.WriteLine("Queue contains " + enqueuedASDUs.Count + " messages"); foreach (ServerConnection connection in allOpenConnections) { //通知当前激活的连接,赶紧读取ASDU if (connection.IsActive) { connection.ASDUReadyToSend(); } } }
public void SendACT_TERM(ASDU asdu) { asdu.Cot = CauseOfTransmission.ACTIVATION_TERMINATION; asdu.IsNegative = false; SendASDU(asdu); }
/// <summary> /// Sends a clock synchronization command (C_CS_NA_1 typeID: 103). /// </summary> /// <param name="ca">Common address</param> /// <param name="time">the new time to set</param> /// <exception cref="ConnectionException">description</exception> public void SendClockSyncCommand(int ca, CP56Time2a time) { ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false); asdu.AddInformationObject(new ClockSynchronizationCommand(0, time)); SendASDUInternal(asdu); }
/// <summary> /// Sends a read command (C_RD_NA_1 typeID: 102). /// </summary> /// /// This will send a read command C_RC_NA_1 (102) to the slave/outstation. The COT is always REQUEST (5). /// It is used to implement the cyclical polling of data application function. /// /// <param name="ca">Common address</param> /// <param name="ioa">Information object address</param> /// <exception cref="ConnectionException">description</exception> public void SendReadCommand(int ca, int ioa) { ASDU asdu = new ASDU(parameters, CauseOfTransmission.REQUEST, false, false, (byte)parameters.OriginatorAddress, ca, false); asdu.AddInformationObject(new ReadCommand(ioa)); SendASDUInternal(asdu); }
/// <summary> /// Sends the counter interrogation command (C_CI_NA_1 typeID: 101) /// </summary> /// <param name="cot">Cause of transmission</param> /// <param name="ca">Common address</param> /// <param name="qcc">Qualifier of counter interrogation command</param> /// <exception cref="ConnectionException">description</exception> public void SendCounterInterrogationCommand(CauseOfTransmission cot, int ca, byte qcc) { ASDU asdu = new ASDU(parameters, cot, false, false, (byte)parameters.OriginatorAddress, ca, false); asdu.AddInformationObject(new CounterInterrogationCommand(0, qcc)); SendASDUInternal(asdu); }
/// <summary> /// Sends a test command (C_TS_NA_1 typeID: 104). /// </summary> /// /// Not required and supported by IEC 60870-5-104. /// /// <param name="ca">Common address</param> /// <exception cref="ConnectionException">description</exception> public void SendTestCommand(int ca) { ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false); asdu.AddInformationObject(new TestCommand()); SendASDUInternal(asdu); }
/// <summary> /// Sends a reset process command (C_RP_NA_1 typeID: 105). /// </summary> /// <param name="cot">Cause of transmission</param> /// <param name="ca">Common address</param> /// <param name="qrp">Qualifier of reset process command</param> /// <exception cref="ConnectionException">description</exception> public void SendResetProcessCommand(CauseOfTransmission cot, int ca, byte qrp) { ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false); asdu.AddInformationObject(new ResetProcessCommand(0, qrp)); SendASDUInternal(asdu); }
/// <summary> /// Sends a test command with CP56Time2a time (C_TS_TA_1 typeID: 107). /// </summary> /// <param name="ca">Common address</param> /// <param name="tsc">test sequence number</param> /// <param name="time">test timestamp</param> /// <exception cref="ConnectionException">description</exception> public void SendTestCommandWithCP56Time2a(int ca, ushort tsc, CP56Time2a time) { ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false); asdu.AddInformationObject(new TestCommandWithCP56Time2a(tsc, time)); SendASDUInternal(asdu); }
/// <summary> /// Sends the control command. /// </summary> /// /// The type ID has to match the type of the InformationObject! /// /// C_SC_NA_1 -> SingleCommand /// C_DC_NA_1 -> DoubleCommand /// C_RC_NA_1 -> StepCommand /// C_SC_TA_1 -> SingleCommandWithCP56Time2a /// C_SE_NA_1 -> SetpointCommandNormalized /// C_SE_NB_1 -> SetpointCommandScaled /// C_SE_NC_1 -> SetpointCommandShort /// C_BO_NA_1 -> Bitstring32Command /// /// <param name="cot">Cause of transmission (use ACTIVATION to start a control sequence)</param> /// <param name="ca">Common address</param> /// <param name="sc">Information object of the command</param> /// <exception cref="ConnectionException">description</exception> public void SendControlCommand(CauseOfTransmission cot, int ca, InformationObject sc) { ASDU controlCommand = new ASDU(parameters, cot, false, false, (byte)parameters.OriginatorAddress, ca, false); controlCommand.AddInformationObject(sc); SendASDUInternal(controlCommand); }
/// <summary> /// Sends a delay acquisition command (C_CD_NA_1 typeID: 106). /// </summary> /// <param name="cot">Cause of transmission</param> /// <param name="ca">Common address</param> /// <param name="delay">delay for acquisition</param> /// <exception cref="ConnectionException">description</exception> public void SendDelayAcquisitionCommand(CauseOfTransmission cot, int ca, CP16Time2a delay) { ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false); asdu.AddInformationObject(new DelayAcquisitionCommand(0, delay)); SendASDUInternal(asdu); }
/// <summary> /// 发送激活确认报文(镜像报文) /// </summary> /// <param name="asdu">原报文</param> /// <param name="negative"></param> public void SendACT_CON(ASDU asdu, bool negative) { //传送原因改下 asdu.Cot = CauseOfTransmission.ACTIVATION_CON; //肯定/否定激活改进去 asdu.IsNegative = negative; SendASDU(asdu); }
/// <summary> /// 发送ASDU /// </summary> /// <param name="asdu"></param> public void SendASDU(ASDU asdu) { Frame frame = new T104Frame(); asdu.Encode(frame, parameters); //发送I帧 sendIMessage(frame); }
/// <summary> /// 检查服务端的ASDU并发送?? /// </summary> private void checkServerQueue() { ASDU asdu = server.DequeueASDU(); if (asdu != null) { SendASDU(asdu); } }
/// <summary> /// Send a response ASDU over this connection /// </summary> /// <exception cref="ConnectionException">Throws an exception if the connection is no longer active (e.g. because it has been closed by the other side).</exception> /// <param name="asdu">The ASDU to send</param> public void SendASDU(ASDU asdu) { if (isActive) { SendASDUInternal(asdu); } else { throw new ConnectionException("Connection not active"); } }
/// <summary> /// 准备发送ASDU,为啥这里要发送一次?难道是镜像报文?还需要再读读。。。 /// </summary> public void ASDUReadyToSend() { if (isActive) { ASDU asdu = server.DequeueASDU(); if (asdu != null) { SendASDU(asdu); } } }
/// <summary> /// Enqueues the ASDU to the transmission queue. /// </summary> /// If an active connection exists the ASDU will be sent to the active client immediately. Otherwhise /// the ASDU will be added to the transmission queue for later transmission. /// <param name="asdu">ASDU to be sent</param> public void EnqueueASDU(ASDU asdu) { if (enqueuedASDUs != null) { lock (enqueuedASDUs) { if (oldestQueueEntry == -1) { oldestQueueEntry = 0; latestQueueEntry = 0; numberOfAsduInQueue = 1; enqueuedASDUs [0].asdu.ResetFrame(); asdu.Encode(enqueuedASDUs [0].asdu, parameters); enqueuedASDUs [0].entryTimestamp = SystemUtils.currentTimeMillis(); enqueuedASDUs [0].state = QueueEntryState.WAITING_FOR_TRANSMISSION; } else { latestQueueEntry = (latestQueueEntry + 1) % maxQueueSize; if (latestQueueEntry == oldestQueueEntry) { oldestQueueEntry = (oldestQueueEntry + 1) % maxQueueSize; } else { numberOfAsduInQueue++; } enqueuedASDUs [latestQueueEntry].asdu.ResetFrame(); asdu.Encode(enqueuedASDUs [latestQueueEntry].asdu, parameters); enqueuedASDUs [latestQueueEntry].entryTimestamp = SystemUtils.currentTimeMillis(); enqueuedASDUs [latestQueueEntry].state = QueueEntryState.WAITING_FOR_TRANSMISSION; } } DebugLog("Queue contains " + numberOfAsduInQueue + " messages (oldest: " + oldestQueueEntry + " latest: " + latestQueueEntry + ")"); foreach (ServerConnection connection in allOpenConnections) { if (connection.IsActive) { connection.ASDUReadyToSend(); } } } }
private void SendASDUInternal(ASDU asdu) { if (isActive) { lock (waitingASDUsHighPrio) { BufferFrame frame = new BufferFrame(new byte[256], 6); asdu.Encode(frame, parameters); waitingASDUsHighPrio.Enqueue(frame); } SendWaitingASDUs(); } }
private int SendIMessage(ASDU asdu) { BufferFrame frame = new BufferFrame(new byte[260], 6); /* reserve space for ACPI */ asdu.Encode(frame, parameters); byte[] buffer = frame.GetBuffer(); int msgSize = frame.GetMsgSize(); /* ACPI + ASDU */ buffer [0] = 0x68; /* set size field */ buffer [1] = (byte)(msgSize - 2); buffer [2] = (byte)((sendSequenceNumber % 128) * 2); buffer [3] = (byte)(sendSequenceNumber / 128); buffer [4] = (byte)((receiveSequenceNumber % 128) * 2); buffer [5] = (byte)(receiveSequenceNumber / 128); if (running) { socket.NoDelay = true; socket.Send(buffer, msgSize, SocketFlags.None); sendSequenceNumber = (sendSequenceNumber + 1) % 32768; statistics.SentMsgCounter++; unconfirmedReceivedIMessages = 0; if (sentMessageHandler != null) { sentMessageHandler(sentMessageHandlerParameter, buffer, msgSize); } return(sendSequenceNumber); } else { if (lastException != null) { throw new ConnectionException(lastException.Message, lastException); } else { throw new ConnectionException("not connected", new SocketException(10057)); } } }
public void EnqueueAsdu(ASDU asdu) { lock (enqueuedASDUs) { if (oldestQueueEntry == -1) { oldestQueueEntry = 0; latestQueueEntry = 0; numberOfAsduInQueue = 1; enqueuedASDUs[0].asdu.ResetFrame(); asdu.Encode(enqueuedASDUs[0].asdu, parameters); enqueuedASDUs[0].entryTimestamp = SystemUtils.currentTimeMillis(); enqueuedASDUs[0].state = QueueEntryState.WAITING_FOR_TRANSMISSION; } else { latestQueueEntry = (latestQueueEntry + 1) % maxQueueSize; if (latestQueueEntry == oldestQueueEntry) { oldestQueueEntry = (oldestQueueEntry + 1) % maxQueueSize; } else { numberOfAsduInQueue++; } enqueuedASDUs[latestQueueEntry].asdu.ResetFrame(); asdu.Encode(enqueuedASDUs[latestQueueEntry].asdu, parameters); enqueuedASDUs[latestQueueEntry].entryTimestamp = SystemUtils.currentTimeMillis(); enqueuedASDUs[latestQueueEntry].state = QueueEntryState.WAITING_FOR_TRANSMISSION; } } DebugLog("Queue contains " + numberOfAsduInQueue + " messages (oldest: " + oldestQueueEntry + " latest: " + latestQueueEntry + ")"); }
private bool SendNextWaitingASDU() { bool sentAsdu = false; if (running == false) { throw new ConnectionException("connection lost"); } try { lock (waitingToBeSent) { while (waitingToBeSent.Count > 0) { if (IsSentBufferFull() == true) { break; } ASDU asdu = waitingToBeSent.Dequeue(); if (asdu != null) { SendIMessageAndUpdateSentASDUs(asdu); sentAsdu = true; } else { break; } } } } catch (Exception) { running = false; throw new ConnectionException("connection lost"); } return(sentAsdu); }
private void SendIMessageAndUpdateSentASDUs(ASDU asdu) { lock (sentASDUs) { int currentIndex = 0; if (oldestSentASDU == -1) { oldestSentASDU = 0; newestSentASDU = 0; } else { currentIndex = (newestSentASDU + 1) % maxSentASDUs; } sentASDUs [currentIndex].seqNo = SendIMessage(asdu); sentASDUs [currentIndex].sentTime = SystemUtils.currentTimeMillis(); newestSentASDU = currentIndex; PrintSendBuffer(); } }
private bool checkMessage(Socket socket, byte[] buffer, int msgSize) { long currentTime = SystemUtils.currentTimeMillis(); if ((buffer [2] & 1) == 0) /* I format frame */ { if (firstIMessageReceived == false) { firstIMessageReceived = true; lastConfirmationTime = currentTime; /* start timeout T2 */ } if (msgSize < 7) { DebugLog("I msg too small!"); return(false); } int frameSendSequenceNumber = ((buffer [3] * 0x100) + (buffer [2] & 0xfe)) / 2; int frameRecvSequenceNumber = ((buffer [5] * 0x100) + (buffer [4] & 0xfe)) / 2; DebugLog("Received I frame: N(S) = " + frameSendSequenceNumber + " N(R) = " + frameRecvSequenceNumber); /* check the receive sequence number N(R) - connection will be closed on an unexpected value */ if (frameSendSequenceNumber != receiveSequenceNumber) { DebugLog("Sequence error: Close connection!"); return(false); } if (CheckSequenceNumber(frameRecvSequenceNumber) == false) { return(false); } receiveSequenceNumber = (receiveSequenceNumber + 1) % 32768; unconfirmedReceivedIMessages++; try { ASDU asdu = new ASDU(parameters, buffer, 6, msgSize); if (asduReceivedHandler != null) { asduReceivedHandler(asduReceivedHandlerParameter, asdu); } } catch (ASDUParsingException e) { DebugLog("ASDU parsing failed: " + e.Message); return(false); } } else if ((buffer [2] & 0x03) == 0x01) /* S format frame */ { int seqNo = (buffer[4] + buffer[5] * 0x100) / 2; DebugLog("Recv S(" + seqNo + ") (own sendcounter = " + sendSequenceNumber + ")"); if (CheckSequenceNumber(seqNo) == false) { return(false); } } else if ((buffer [2] & 0x03) == 0x03) /* U format frame */ { uMessageTimeout = 0; if (buffer [2] == 0x43) // Check for TESTFR_ACT message { statistics.RcvdTestFrActCounter++; DebugLog("RCVD TESTFR_ACT"); DebugLog("SEND TESTFR_CON"); socket.Send(TESTFR_CON_MSG); statistics.SentMsgCounter++; } else if (buffer [2] == 0x83) /* TESTFR_CON */ { DebugLog("RCVD TESTFR_CON"); statistics.RcvdTestFrConCounter++; outStandingTestFRConMessages = 0; } else if (buffer [2] == 0x07) /* STARTDT ACT */ { DebugLog("RCVD STARTDT_ACT"); socket.Send(STARTDT_CON_MSG); statistics.SentMsgCounter++; } else if (buffer [2] == 0x0b) /* STARTDT_CON */ { DebugLog("RCVD STARTDT_CON"); if (connectionHandler != null) { connectionHandler(connectionHandlerParameter, ConnectionEvent.STARTDT_CON_RECEIVED); } } else if (buffer [2] == 0x23) /* STOPDT_CON */ { DebugLog("RCVD STOPDT_CON"); if (connectionHandler != null) { connectionHandler(connectionHandlerParameter, ConnectionEvent.STOPDT_CON_RECEIVED); } } } else { DebugLog("Unknown message type"); return(false); } ResetT3Timeout(); return(true); }
/// <summary> /// Sends an arbitrary ASDU to the connected slave /// </summary> /// <param name="asdu">The ASDU to send</param> public void SendASDU(ASDU asdu) { SendASDUInternal(asdu); }
private void HandleASDU(ASDU asdu) { DebugLog("Handle received ASDU"); bool messageHandled = false; switch (asdu.TypeId) { case TypeID.C_IC_NA_1: /* 100 - interrogation command */ DebugLog("Rcvd interrogation command C_IC_NA_1"); if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION)) { if (server.interrogationHandler != null) { InterrogationCommand irc = (InterrogationCommand)asdu.GetElement(0); if (server.interrogationHandler(server.InterrogationHandlerParameter, this, asdu, irc.QOI)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDUInternal(asdu); } break; case TypeID.C_CI_NA_1: /* 101 - counter interrogation command */ DebugLog("Rcvd counter interrogation command C_CI_NA_1"); if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION)) { if (server.counterInterrogationHandler != null) { CounterInterrogationCommand cic = (CounterInterrogationCommand)asdu.GetElement(0); if (server.counterInterrogationHandler(server.counterInterrogationHandlerParameter, this, asdu, cic.QCC)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDUInternal(asdu); } break; case TypeID.C_RD_NA_1: /* 102 - read command */ DebugLog("Rcvd read command C_RD_NA_1"); if (asdu.Cot == CauseOfTransmission.REQUEST) { DebugLog("Read request for object: " + asdu.Ca); if (server.readHandler != null) { ReadCommand rc = (ReadCommand)asdu.GetElement(0); if (server.readHandler(server.readHandlerParameter, this, asdu, rc.ObjectAddress)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDUInternal(asdu); } break; case TypeID.C_CS_NA_1: /* 103 - Clock synchronization command */ DebugLog("Rcvd clock sync command C_CS_NA_1"); if (asdu.Cot == CauseOfTransmission.ACTIVATION) { if (server.clockSynchronizationHandler != null) { ClockSynchronizationCommand csc = (ClockSynchronizationCommand)asdu.GetElement(0); if (server.clockSynchronizationHandler(server.clockSynchronizationHandlerParameter, this, asdu, csc.NewTime)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDUInternal(asdu); } break; case TypeID.C_TS_NA_1: /* 104 - test command */ DebugLog("Rcvd test command C_TS_NA_1"); if (asdu.Cot != CauseOfTransmission.ACTIVATION) { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; } else { asdu.Cot = CauseOfTransmission.ACTIVATION_CON; } this.SendASDUInternal(asdu); messageHandled = true; break; case TypeID.C_RP_NA_1: /* 105 - Reset process command */ DebugLog("Rcvd reset process command C_RP_NA_1"); if (asdu.Cot == CauseOfTransmission.ACTIVATION) { if (server.resetProcessHandler != null) { ResetProcessCommand rpc = (ResetProcessCommand)asdu.GetElement(0); if (server.resetProcessHandler(server.resetProcessHandlerParameter, this, asdu, rpc.QRP)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDUInternal(asdu); } break; case TypeID.C_CD_NA_1: /* 106 - Delay acquisition command */ DebugLog("Rcvd delay acquisition command C_CD_NA_1"); if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.SPONTANEOUS)) { if (server.delayAcquisitionHandler != null) { DelayAcquisitionCommand dac = (DelayAcquisitionCommand)asdu.GetElement(0); if (server.delayAcquisitionHandler(server.delayAcquisitionHandlerParameter, this, asdu, dac.Delay)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDUInternal(asdu); } break; } if ((messageHandled == false) && (server.asduHandler != null)) { if (server.asduHandler(server.asduHandlerParameter, this, asdu)) { messageHandled = true; } } if (messageHandled == false) { asdu.Cot = CauseOfTransmission.UNKNOWN_TYPE_ID; this.SendASDUInternal(asdu); } }
/// <summary> /// 处理消息 /// </summary> /// <param name="socket"></param> /// <param name="buffer"></param> /// <param name="msgSize"></param> /// <returns></returns> private bool HandleMessage(Socket socket, byte[] buffer, int msgSize) { if ((buffer[2] & 1) == 0) { if (debugOutput) { Console.WriteLine("Received I frame"); } if (msgSize < 7) { if (debugOutput) { Console.WriteLine("I msg too small!"); } return(false); } IncreaseReceivedMessageCounters(); if (isActive) { bool messageHandled = false; ASDU asdu = new ASDU(parameters, buffer, msgSize); //根据类型来分别处理 switch (asdu.TypeId) { case TypeID.C_IC_NA_1: /* 100 - interrogation command 总召*/ if (debugOutput) { Console.WriteLine("Rcvd interrogation command C_IC_NA_1"); } if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION)) { if (server.interrogationHandler != null) { InterrogationCommand irc = (InterrogationCommand)asdu.GetElement(0); if (server.interrogationHandler(server.InterrogationHandlerParameter, this, asdu, irc.QOI)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_CI_NA_1: /* 101 - counter interrogation command 累计量总召*/ if (debugOutput) { Console.WriteLine("Rcvd counter interrogation command C_CI_NA_1"); } if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION)) { if (server.counterInterrogationHandler != null) { CounterInterrogationCommand cic = (CounterInterrogationCommand)asdu.GetElement(0); if (server.counterInterrogationHandler(server.counterInterrogationHandlerParameter, this, asdu, cic.QCC)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_RD_NA_1: /* 102 - read command 读命令*/ if (debugOutput) { Console.WriteLine("Rcvd read command C_RD_NA_1"); } if (asdu.Cot == CauseOfTransmission.REQUEST) { if (debugOutput) { Console.WriteLine("Read request for object: " + asdu.Ca); } if (server.readHandler != null) { ReadCommand rc = (ReadCommand)asdu.GetElement(0); if (server.readHandler(server.readHandlerParameter, this, asdu, rc.ObjectAddress)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_CS_NA_1: /* 103 - Clock synchronization command 时钟同步 */ if (debugOutput) { Console.WriteLine("Rcvd clock sync command C_CS_NA_1"); } if (asdu.Cot == CauseOfTransmission.ACTIVATION) { if (server.clockSynchronizationHandler != null) { ClockSynchronizationCommand csc = (ClockSynchronizationCommand)asdu.GetElement(0); if (server.clockSynchronizationHandler(server.clockSynchronizationHandlerParameter, this, asdu, csc.NewTime)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_TS_NA_1: /* 104 - test command */ if (debugOutput) { Console.WriteLine("Rcvd test command C_TS_NA_1"); } //直接处理 if (asdu.Cot != CauseOfTransmission.ACTIVATION) { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; } else { asdu.Cot = CauseOfTransmission.ACTIVATION_CON; } this.SendASDU(asdu); messageHandled = true; break; case TypeID.C_RP_NA_1: /* 105 - Reset process command 复位命令*/ if (debugOutput) { Console.WriteLine("Rcvd reset process command C_RP_NA_1"); } if (asdu.Cot == CauseOfTransmission.ACTIVATION) { if (server.resetProcessHandler != null) { ResetProcessCommand rpc = (ResetProcessCommand)asdu.GetElement(0); if (server.resetProcessHandler(server.resetProcessHandlerParameter, this, asdu, rpc.QRP)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; case TypeID.C_CD_NA_1: /* 106 - Delay acquisition command 延时获得*/ if (debugOutput) { Console.WriteLine("Rcvd delay acquisition command C_CD_NA_1"); } if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.SPONTANEOUS)) { if (server.delayAcquisitionHandler != null) { DelayAcquisitionCommand dac = (DelayAcquisitionCommand)asdu.GetElement(0); if (server.delayAcquisitionHandler(server.delayAcquisitionHandlerParameter, this, asdu, dac.Delay)) { messageHandled = true; } } } else { asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION; this.SendASDU(asdu); } break; } //都没处理,就直接当通用ASDU处理掉了 if ((messageHandled == false) && (server.asduHandler != null)) { if (server.asduHandler(server.asduHandlerParameter, this, asdu)) { messageHandled = true; } } //依旧没处理,那就返回未知 if (messageHandled == false) { asdu.Cot = CauseOfTransmission.UNKNOWN_TYPE_ID; this.SendASDU(asdu); } } else { // connection not activated --> skip message if (debugOutput) { Console.WriteLine("Message not activated. Skip I message"); } } return(true); } // Check for TESTFR_ACT message else if ((buffer[2] & 0x43) == 0x43) { if (debugOutput) { Console.WriteLine("Send TESTFR_CON"); } socket.Send(TESTFR_CON_MSG); } // Check for STARTDT_ACT message else if ((buffer[2] & 0x07) == 0x07) { if (debugOutput) { Console.WriteLine("Send STARTDT_CON"); } this.isActive = true; socket.Send(STARTDT_CON_MSG); } // Check for STOPDT_ACT message else if ((buffer[2] & 0x13) == 0x13) { if (debugOutput) { Console.WriteLine("Send STOPDT_CON"); } this.isActive = false; socket.Send(STOPDT_CON_MSG); } // S-message S帧(用于确认对方的接收序号) else if (buffer[2] == 0x01) { int messageCount = (buffer[4] + buffer[5] * 0x100) / 2; Console.WriteLine("Recv S(" + messageCount + ") (own sendcounter = " + sendCount + ")"); } else { Console.WriteLine("Unknown message"); return(true); } return(true); }
private bool HandleMessage(byte[] buffer, int msgSize) { long currentTime = SystemUtils.currentTimeMillis(); if ((buffer [2] & 1) == 0) { if (msgSize < 7) { DebugLog("I msg too small!"); return(false); } if (firstIMessageReceived == false) { firstIMessageReceived = true; lastConfirmationTime = currentTime; /* start timeout T2 */ } int frameSendSequenceNumber = ((buffer [3] * 0x100) + (buffer [2] & 0xfe)) / 2; int frameRecvSequenceNumber = ((buffer [5] * 0x100) + (buffer [4] & 0xfe)) / 2; DebugLog("Received I frame: N(S) = " + frameSendSequenceNumber + " N(R) = " + frameRecvSequenceNumber); /* check the receive sequence number N(R) - connection will be closed on an unexpected value */ if (frameSendSequenceNumber != receiveCount) { DebugLog("Sequence error: Close connection!"); return(false); } if (CheckSequenceNumber(frameRecvSequenceNumber) == false) { DebugLog("Sequence number check failed"); return(false); } receiveCount = (receiveCount + 1) % 32768; unconfirmedReceivedIMessages++; if (isActive) { try { ASDU asdu = new ASDU(parameters, buffer, 6, msgSize); // push to handler thread for processing DebugLog("Enqueue received I-message for processing"); receivedASDUs.Enqueue(asdu); } catch (ASDUParsingException e) { DebugLog("ASDU parsing failed: " + e.Message); return(false); } } else { // connection not activated --> skip message DebugLog("Connection not activated. Skip I message"); } } // Check for TESTFR_ACT message else if ((buffer [2] & 0x43) == 0x43) { DebugLog("Send TESTFR_CON"); socketStream.Write(TESTFR_CON_MSG, 0, TESTFR_CON_MSG.Length); } // Check for STARTDT_ACT message else if ((buffer [2] & 0x07) == 0x07) { DebugLog("Send STARTDT_CON"); this.isActive = true; this.server.Activated(this); socketStream.Write(STARTDT_CON_MSG, 0, TESTFR_CON_MSG.Length); } // Check for STOPDT_ACT message else if ((buffer [2] & 0x13) == 0x13) { DebugLog("Send STOPDT_CON"); this.isActive = false; socketStream.Write(STOPDT_CON_MSG, 0, TESTFR_CON_MSG.Length); } // Check for TESTFR_CON message else if ((buffer [2] & 0x83) == 0x83) { DebugLog("Recv TESTFR_CON"); outStandingTestFRConMessages = 0; } // S-message else if (buffer [2] == 0x01) { int seqNo = (buffer[4] + buffer[5] * 0x100) / 2; DebugLog("Recv S(" + seqNo + ") (own sendcounter = " + sendCount + ")"); if (CheckSequenceNumber(seqNo) == false) { return(false); } } else { DebugLog("Unknown message"); } ResetT3Timeout(); return(true); }
/// <summary> /// 信息检查,按说每收到一条信息都要来这里检查。。。 /// </summary> /// <param name="socket"></param> /// <param name="buffer"></param> /// <param name="msgSize"></param> /// <returns></returns> private bool checkMessage(Socket socket, byte[] buffer, int msgSize) { //这里检测I帧和U帧,不知道为什么不检测S帧,难道是S帧已经处理过了? //update:似乎他这里只需要发送S帧,不主动监测S帧。。。 if ((buffer[2] & 1) == 0) { /* I format frame */ if (debugOutput) { Console.WriteLine("Received I frame"); } if (msgSize < 7) { if (debugOutput) { Console.WriteLine("I msg too small!"); } return(false); } receiveCount++; unconfirmedMessages++; long currentTime = SystemUtils.currentTimeMillis(); if ((unconfirmedMessages > parameters.W) || checkConfirmTimeout(currentTime)) { //未确认消息超过W,或者t2超时,则发送S帧 lastConfirmationTime = currentTime; unconfirmedMessages = 0; sendSMessage(); } //新建一个ASDU,准备解析 ASDU asdu = new ASDU(parameters, buffer, msgSize); //解析ASDU if (asduReceivedHandler != null) { asduReceivedHandler(asduReceivedHandlerParameter, asdu); } } else if ((buffer[2] & 0x03) == 0x03) { /* U format frame */ if (buffer[2] == 0x43) { // Check for TESTFR_ACT message //收到了测试命令,回复测试确认 socket.Send(TESTFR_CON_MSG); } else if (buffer[2] == 0x07) { /* STARTDT ACT */ //收到了开启命令,回复开启命令确认 socket.Send(STARTDT_CON_MSG); } else if (buffer[2] == 0x0b) { /* STARTDT_CON */ //收到了开启确认,处理[已连接]事件 if (connectionHandler != null) { connectionHandler(connectionHandlerParameter, ConnectionEvent.STARTDT_CON_RECEIVED); } } else if (buffer[2] == 0x23) { /* STOPDT_CON */ //收到了停止确认,处理[已断开]事件 if (connectionHandler != null) { connectionHandler(connectionHandlerParameter, ConnectionEvent.STOPDT_CON_RECEIVED); } } } return(true); }