private void ParseHeaderSecondaryUnbalanced(byte[] msg, int msgSize) { int userDataLength = 0; int userDataStart = 0; byte c; int csStart; int csIndex; int address = 0; if (msg [0] == 0x68) { if (msg [1] != msg [2]) { DebugLog("ERROR: L fields differ!"); return; } userDataLength = (int)msg [1] - linkLayerParameters.AddressLength - 1; userDataStart = 5 + linkLayerParameters.AddressLength; csStart = 4; csIndex = userDataStart + userDataLength; // check if message size is reasonable if (msgSize != (userDataStart + userDataLength + 2 /* CS + END */)) { DebugLog("ERROR: Invalid message length"); return; } c = msg [4]; } else if (msg [0] == 0x10) { c = msg [1]; csStart = 1; csIndex = 2 + linkLayerParameters.AddressLength; } else if (msg [0] == 0xE5) { /* Confirmation message from other slave --> ignore */ return; } else { DebugLog("ERROR: Received unexpected message type in unbalanced slave mode!"); return; } bool isBroadcast = false; //check address if (linkLayerParameters.AddressLength > 0) { address = msg [csStart + 1]; if (linkLayerParameters.AddressLength > 1) { address += (msg [csStart + 2] * 0x100); if (address == 65535) { isBroadcast = true; } } else { if (address == 255) { isBroadcast = true; } } } int fc = c & 0x0f; FunctionCodePrimary fcp = (FunctionCodePrimary)fc; if (isBroadcast) { if (fcp != FunctionCodePrimary.USER_DATA_NO_REPLY) { DebugLog("ERROR: Invalid function code for broadcast message!"); return; } } else { if (address != secondaryLinkLayer.Address) { DebugLog("INFO: unknown link layer address -> ignore message"); return; } } //check checksum byte checksum = 0; for (int i = csStart; i < csIndex; i++) { checksum += msg [i]; } if (checksum != msg [csIndex]) { DebugLog("ERROR: checksum invalid!"); return; } // parse C field bits bool prm = ((c & 0x40) == 0x40); if (prm == false) { DebugLog("ERROR: Received secondary message in unbalanced slave mode!"); return; } bool fcb = ((c & 0x20) == 0x20); bool fcv = ((c & 0x10) == 0x10); DebugLog("PRM=" + (prm == true ? "1":"0") + " FCB=" + (fcb == true ? "1":"0") + " FCV=" + (fcv == true ? "1":"0") + " FC=" + fc + "(" + fcp.ToString() + ")"); if (secondaryLinkLayer != null) { secondaryLinkLayer.HandleMessage(fcp, isBroadcast, address, fcb, fcv, msg, userDataStart, userDataLength); } else { DebugLog("No secondary link layer available!"); } }
public void HandleMessageBalancedAndPrimaryUnbalanced(byte[] msg, int msgSize) { int userDataLength = 0; int userDataStart = 0; byte c = 0; int csStart = 0; int csIndex = 0; int address = 0; /* address can be ignored in balanced mode? */ bool prm = true; int fc = 0; bool isAck = false; if (msg [0] == 0x68) { if (msg [1] != msg [2]) { DebugLog("ERROR: L fields differ!"); return; } userDataLength = (int)msg [1] - linkLayerParameters.AddressLength - 1; userDataStart = 5 + linkLayerParameters.AddressLength; csStart = 4; csIndex = userDataStart + userDataLength; // check if message size is reasonable if (msgSize != (userDataStart + userDataLength + 2 /* CS + END */)) { DebugLog("ERROR: Invalid message length"); return; } c = msg [4]; if (linkLayerParameters.AddressLength > 0) { address += msg [5]; } if (linkLayerParameters.AddressLength > 1) { address += msg [6] * 0x100; } } else if (msg [0] == 0x10) { c = msg [1]; csStart = 1; csIndex = 2 + linkLayerParameters.AddressLength; if (linkLayerParameters.AddressLength > 0) { address += msg [2]; } if (linkLayerParameters.AddressLength > 1) { address += msg [3] * 0x100; } } else if (msg [0] == 0xe5) { isAck = true; fc = (int)FunctionCodeSecondary.ACK; prm = false; /* single char ACK is only sent by secondary station */ DebugLog("Received single char ACK"); } else { DebugLog("ERROR: Received unexpected message type!"); return; } if (isAck == false) { //check checksum byte checksum = 0; for (int i = csStart; i < csIndex; i++) { checksum += msg [i]; } if (checksum != msg [csIndex]) { DebugLog("ERROR: checksum invalid!"); return; } // parse C field bits fc = c & 0x0f; prm = ((c & 0x40) == 0x40); if (prm) /* we are secondary link layer */ { bool fcb = ((c & 0x20) == 0x20); bool fcv = ((c & 0x10) == 0x10); DebugLog("PRM=" + (prm == true ? "1" : "0") + " FCB=" + (fcb == true ? "1" : "0") + " FCV=" + (fcv == true ? "1" : "0") + " FC=" + fc + "(" + ((FunctionCodePrimary)c).ToString() + ")"); FunctionCodePrimary fcp = (FunctionCodePrimary)fc; if (secondaryLinkLayer != null) { secondaryLinkLayer.HandleMessage(fcp, false, address, fcb, fcv, msg, userDataStart, userDataLength); } else { DebugLog("No secondary link layer available!"); } } else /* we are primary link layer */ { bool dir = ((c & 0x80) == 0x80); /* DIR - direction for balanced transmission */ bool dfc = ((c & 0x10) == 0x10); /* DFC - Data flow control */ bool acd = ((c & 0x20) == 0x20); /* ACD - access demand for class 1 data - for unbalanced transmission */ DebugLog("PRM=" + (prm == true ? "1" : "0") + " DIR=" + (dir == true ? "1" : "0") + " DFC=" + (dfc == true ? "1" : "0") + " FC=" + fc + "(" + ((FunctionCodeSecondary)c).ToString() + ")"); FunctionCodeSecondary fcs = (FunctionCodeSecondary)fc; if (primaryLinkLayer != null) { if (linkLayerMode == LinkLayerMode.BALANCED) { primaryLinkLayer.HandleMessage(fcs, dir, dfc, address, msg, userDataStart, userDataLength); } else { primaryLinkLayer.HandleMessage(fcs, acd, dfc, address, msg, userDataStart, userDataLength); } } else { DebugLog("No primary link layer available!"); } } } else /* Single byte ACK */ { if (primaryLinkLayer != null) { primaryLinkLayer.HandleMessage(FunctionCodeSecondary.ACK, false, false, -1, null, 0, 0); } } }
public void SendVariableLengthFramePrimary(FunctionCodePrimary fc, int address, bool fcb, bool fcv, BufferFrame frame) { buffer [0] = 0x68; /* START */ buffer [3] = 0x68; /* START */ byte c = (byte)fc; if (dir) { c += 0x80; } c += 0x40; // PRM = 1; if (fcv) { c += 0x10; } if (fcb) { c += 0x20; } buffer [4] = c; int bufPos = 5; if (linkLayerParameters.AddressLength > 0) { buffer [bufPos++] = (byte)(address % 0x100); if (linkLayerParameters.AddressLength > 1) { buffer [bufPos++] = (byte)((address / 0x100) % 0x100); } } byte[] userData = frame.GetBuffer(); int userDataLength = frame.GetMsgSize(); for (int i = 0; i < userDataLength; i++) { buffer [bufPos++] = userData[i]; } int l = 1 + linkLayerParameters.AddressLength + frame.GetMsgSize(); if (l > 255) { return; } buffer [1] = (byte)l; buffer [2] = (byte)l; byte checksum = 0; for (int i = 4; i < bufPos; i++) { checksum += buffer[i]; } buffer [bufPos++] = checksum; buffer [bufPos++] = 0x16; /* END */ if (sentRawMessageHandler != null) { sentRawMessageHandler(sentRawMessageHandlerParameter, buffer, bufPos); } transceiver.SendMessage(buffer, bufPos); }
public void SendFixedFramePrimary(FunctionCodePrimary fc, int address, bool fcb, bool fcv) { SendFixedFrame((byte)fc, address, true, dir, fcb, fcv); }
public override void HandleMessage(FunctionCodePrimary fcp, bool isBroadcast, int address, bool fcb, bool fcv, byte[] msg, int userDataStart, int userDataLength) { // check frame count bit if fcv == true if (fcv) { if (CheckFCB(fcb) == false) { return; } } switch (fcp) { case FunctionCodePrimary.REQUEST_LINK_STATUS: DebugLog("SLL - REQUEST LINK STATUS"); { bool accessDemand = applicationLayer.IsClass1DataAvailable(); linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.STATUS_OF_LINK_OR_ACCESS_DEMAND, linkLayerAddress, accessDemand, false); } break; case FunctionCodePrimary.RESET_REMOTE_LINK: DebugLog("SLL - RESET REMOTE LINK"); { expectedFcb = true; if (linkLayer.linkLayerParameters.UseSingleCharACK) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.ACK, linkLayerAddress, false, false); } applicationLayer.ResetCUReceived(false); } break; case FunctionCodePrimary.RESET_FCB: DebugLog("SLL - RESET FCB"); { expectedFcb = true; if (linkLayer.linkLayerParameters.UseSingleCharACK) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.ACK, linkLayerAddress, false, false); } applicationLayer.ResetCUReceived(true); } break; case FunctionCodePrimary.REQUEST_USER_DATA_CLASS_2: DebugLog("SLL - REQUEST USER DATA CLASS 2"); { BufferFrame asdu = applicationLayer.GetCLass2Data(); bool accessDemand = applicationLayer.IsClass1DataAvailable(); if (asdu != null) { linkLayer.SendVariableLengthFrameSecondary(FunctionCodeSecondary.RESP_USER_DATA, linkLayerAddress, accessDemand, false, asdu); } else { if (linkLayer.linkLayerParameters.UseSingleCharACK && (accessDemand == false)) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.RESP_NACK_NO_DATA, linkLayerAddress, accessDemand, false); } } } break; case FunctionCodePrimary.REQUEST_USER_DATA_CLASS_1: DebugLog("SLL - REQUEST USER DATA CLASS 1"); { BufferFrame asdu = applicationLayer.GetClass1Data(); bool accessDemand = applicationLayer.IsClass1DataAvailable(); if (asdu != null) { linkLayer.SendVariableLengthFrameSecondary(FunctionCodeSecondary.RESP_USER_DATA, linkLayerAddress, accessDemand, false, asdu); } else { if (linkLayer.linkLayerParameters.UseSingleCharACK && (accessDemand == false)) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.RESP_NACK_NO_DATA, linkLayerAddress, accessDemand, false); } } } break; case FunctionCodePrimary.USER_DATA_CONFIRMED: DebugLog("SLL - USER DATA CONFIRMED"); if (userDataLength > 0) { if (applicationLayer.HandleReceivedData(msg, isBroadcast, userDataStart, userDataLength)) { bool accessDemand = applicationLayer.IsClass1DataAvailable(); linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.ACK, linkLayerAddress, accessDemand, false); } } break; case FunctionCodePrimary.USER_DATA_NO_REPLY: DebugLog("SLL - USER DATA NO REPLY"); if (userDataLength > 0) { applicationLayer.HandleReceivedData(msg, isBroadcast, userDataStart, userDataLength); } break; default: DebugLog("SLL - UNEXPECTED LINK LAYER MESSAGE"); linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.LINK_SERVICE_NOT_IMPLEMENTED, linkLayerAddress, false, false); break; } }
public abstract void HandleMessage(FunctionCodePrimary fcp, bool isBroadcast, int address, bool fcb, bool fcv, byte[] msg, int userDataStart, int userDataLength);
public override void HandleMessage(FunctionCodePrimary fcp, bool isBroadcast, bool fcb, bool fcv, byte[] msg, int userDataStart, int userDataLength) { if (fcv) { if (CheckFCB(fcb) == false) { return; } } switch (fcp) { case FunctionCodePrimary.RESET_REMOTE_LINK: expectedFcb = true; DebugLog("SLL - RECV RESET REMOTE LINK"); if (linkLayer.linkLayerParameters.UseSingleCharACK) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.ACK, linkLayerAddress, false, false); } break; case FunctionCodePrimary.TEST_FUNCTION_FOR_LINK: DebugLog("SLL -TEST FUNCTION FOR LINK"); // TODO check if DCF has to be sent if (linkLayer.linkLayerParameters.UseSingleCharACK) { linkLayer.SendSingleCharACK(); } else { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.ACK, linkLayerAddress, false, false); } break; case FunctionCodePrimary.USER_DATA_CONFIRMED: DebugLog("SLL - USER DATA CONFIRMED"); if (userDataLength > 0) { if (HandleApplicationLayer(msg, userDataStart, userDataLength)) { linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.ACK, linkLayerAddress, false, false); } } break; case FunctionCodePrimary.USER_DATA_NO_REPLY: DebugLog("SLL - USER DATA NO REPLY"); if (userDataLength > 0) { HandleApplicationLayer(msg, userDataStart, userDataLength); } break; case FunctionCodePrimary.REQUEST_LINK_STATUS: DebugLog("SLL - RECV REQUEST LINK STATUS"); SendStatusOfLink(linkLayerAddress); break; default: DebugLog("SLL - UNEXPECTED LINK LAYER MESSAGE"); linkLayer.SendFixedFrameSecondary(FunctionCodeSecondary.LINK_SERVICE_NOT_IMPLEMENTED, linkLayerAddress, false, false); break; } }