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;
            }
        }
Exemple #6
0
 public abstract void HandleMessage(FunctionCodePrimary fcp, bool isBroadcast, int address, bool fcb, bool fcv, byte[] msg, int userDataStart, int userDataLength);
Exemple #7
0
        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;
            }
        }