Beispiel #1
0
        public void Decode(byte[] buffer, ref int pos)
        {
            networkNumber  = (uint)buffer[pos++] << 8;
            networkNumber |= buffer[pos++];

            MACaddress.length = buffer[pos++];

            switch (MACaddress.length)
            {
            case 0:
                // indicates a broadcast, perfectly legal.
                break;

            case 1:
                MACaddress.uintMACaddress = buffer[pos++];
                break;

            case 6:
                // extract the IP address
                myIPEndPoint ipep = new myIPEndPoint();
                ipep.Decode(buffer, pos);
                MACaddress.ipMACaddress = ipep;
                pos += 6;
                break;

            default:
                BACnetLibraryCL.Panic("Illegal MAC address length??");
                break;
            }
        }
Beispiel #2
0
        public bool Equals(MACaddress madr)
        {
            if (length != madr.length)
            {
                return(false);
            }

            switch (length)
            {
            case 0:
                break;

            case 1:
                if (madr.uintMACaddress != uintMACaddress)
                {
                    return(false);
                }
                break;

            case 6:
                if (ipMACaddress.Equals(madr.ipMACaddress) != true)
                {
                    return(false);
                }
                break;

            default:
                BACnetLibraryCL.Panic("Illegal MAC address length??");
                return(false);
            }
            return(true);
        }
Beispiel #3
0
        public bool seenOnRouterInit;           // These flags help us establish that.

        public bool Decode(byte[] buf, ref int iptr)
        {
            networkNumber = BACnetLibraryCL.ExtractUint16(buf, ref iptr);
            ID            = buf[iptr++];
            portInfoLen   = buf[iptr++];
            if (portInfoLen != 0)
            {
                // we are not ready to handle this.
                BACnetLibraryCL.Panic("todo");
            }
            iptr += (int)portInfoLen;
            return(true);
        }
Beispiel #4
0
        public override string ToString()
        {
            switch (length)
            {
            case 0:
                return("Broadcast");

            case 1:
                return(uintMACaddress.ToString());

            case 6:
                return(ipMACaddress.ToString());

            default:
                BACnetLibraryCL.Panic("Illegal MAC length");
                return("Illegal MAC address");
            }
        }
Beispiel #5
0
        // Create a new Application Tag

        public BACnetObjectIdentifier(byte[] buf, ref int offset, BACnetEnums.TAG tagType, BACnetEnums.BACNET_APPLICATION_TAG appTag)
        {
            // is the next parameter even an application tag
            if ((buf[offset] & 0x08) != 0x00)
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Not a context tag");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }

            if ((BACnetEnums.BACNET_APPLICATION_TAG)(((buf[offset] & 0xf0) >> 4)) != appTag)
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Unexpected application tag");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }

            int contextTagSize = buf[offset] & 0x07;

            offset++;

            switch (appTag)
            {
            case BACnetEnums.BACNET_APPLICATION_TAG.BACNET_APPLICATION_TAG_OBJECT_ID:
                if (contextTagSize != 4)
                {
                    // we dont have a legal object ID!
                    BACnetLibraryCL.Panic("Illegal length");
                    return;
                }

                this.objectType = (BACnetEnums.BACNET_OBJECT_TYPE)(((uint)buf[offset] << 2) | ((uint)buf[offset + 1] >> 6));

                objectInstance  = ((uint)buf[offset + 1] & 0x3f) << 16;
                objectInstance |= ((uint)buf[offset + 2]) << 8;
                objectInstance |= ((uint)buf[offset + 3]);

                offset += 4;
                return;
            }
        }
Beispiel #6
0
        // Create a new Context Tag

        public BACnetObjectIdentifier(byte[] buf, ref int offset, BACnetEnums.TAG tagType, int tagValue)
        {
            // is the next parameter even a context tag
            if ((buf[offset] & 0x08) != 0x08)
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Not a context tag");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }

            if ((buf[offset] & 0xf0) != (tagValue << 4))
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Unexpected context tag");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }

            int contextTagSize = buf[offset] & 0x07;

            // the length of a bacnet object identifier better be 4

            if (contextTagSize != 4)
            {
                // we have an unexpected context tag, sort this out
                BACnetLibraryCL.Panic("Unbelievable length of object identifier");
                // todo, now is there a way to avoid creating the object? Have to flag it at least...
                return;
            }


            objectType = (BACnetEnums.BACNET_OBJECT_TYPE)(((uint)buf[offset + 1] << 2) | ((uint)buf[offset + 2] >> 6));

            objectInstance  = ((uint)buf[offset + 2] & 0x3f) << 16;
            objectInstance |= ((uint)buf[offset + 3]) << 8;
            objectInstance |= ((uint)buf[offset + 4]);

            offset += 5;
        }
Beispiel #7
0
        public void Encode(byte[] buffer, ref int pos)
        {
            buffer[pos++] = (byte)(this.networkNumber >> 8);
            buffer[pos++] = (byte)(this.networkNumber & 0xff);

            buffer[pos++] = (byte)MACaddress.length;

            switch (MACaddress.length)
            {
            case 1:
                buffer[pos++] = (byte)MACaddress.uintMACaddress;
                break;

            case 6:
                MACaddress.ipMACaddress.Encode(buffer, ref pos);
                break;

            default:
                BACnetLibraryCL.Panic("Illegal MAC address length??");
                break;
            }
        }
Beispiel #8
0
        public bool DecodeBACnet(byte[] buffer, int totalMessageLength)
        {
            int offset = 0;

            try
            {
                // this whole section http://www.bacnetwiki.com/wiki/index.php?title=BACnet_Virtual_Link_Control
                ADR sadr = null;

                if (buffer[offset] != BACnetEnums.BACNET_BVLC_TYPE_BIP)
                {
                    // todo3, panic log
                    _apm.MessageProtocolError("m0013 - Not a BACnet/IP message");
                    return(false);
                }

                // we could receive an original broadcast, a unicast, a forwarded here...
                // BVLC Function Types. See http://www.bacnetwiki.com/wiki/index.php?title=BVLC_Function

                switch ((BACnetEnums.BACNET_BVLC_FUNCTION)buffer[offset + 1])
                {
                case BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_FORWARDED_NPDU:
                    npdu_offset = offset + 10;
                    break;

                case BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_ORIGINAL_UNICAST_NPDU:
                case BACnetEnums.BACNET_BVLC_FUNCTION.BVLC_ORIGINAL_BROADCAST_NPDU:
                    // all these OK
                    npdu_offset = offset + 4;
                    break;

                default:
                    BACnetLibraryCL.Panic("m0012 nosuch bvlc function");
                    break;
                }


                // Investigate the NPDU
                // http://www.bacnetwiki.com/wiki/index.php?title=NPDU

                if (buffer[npdu_offset] != BACnetEnums.BACNET_PROTOCOL_VERSION)
                {
                    // we have a major problem, microprotocol version has changed. http://www.bacnetwiki.com/wiki/index.php?title=BACnet_Virtual_Link_Control
                    BACnetLibraryCL.Panic("m0011 BVLC microprotocol problem");
                    return(false);
                }

                // expecting reply?

                if ((buffer[npdu_offset + 1] & 0x04) == 0x04)
                {
                    npdu.expectingReply = true;
                }


                // destination address present?
                // http://www.bacnetwiki.com/wiki/index.php?title=NPCI

                if ((buffer[npdu_offset + 1] & 0x20) == 0x20)
                {
                    //da_present = true;
                    dadr = new ADR();

                    // dnet, dadr and hop count present

                    int dAddrOffset = npdu_offset + 2;
                    dadr.Decode(buffer, ref dAddrOffset);

                    if (dadr.MACaddress.length == 0)
                    {
                        npdu.isBroadcast = true;

                        // broadcast, but check the DNET
                        if (dadr.networkNumber != 0xffff)
                        {
                            throw new Exception("m0010 - Broadcast according to DLEN, but DNET not 0xffff");
                            // todo, this means directed broadcast, need to deal with this still
                        }
                    }
                    if (dadr.MACaddress.length != 1 && dadr.MACaddress.length != 6 && dadr.MACaddress.length != 0)
                    {
                        // panic
                        throw new Exception("m0009 - Unexpected DADR len");
                    }
                    // todo, pick up variable length destination address
                }


                // Source address present?
                // http://www.bacnetwiki.com/wiki/index.php?title=NPCI

                if ((buffer[npdu_offset + 1] & 0x08) == 0x08)
                {
                    //sa_present = true;

                    sadr = new ADR();

                    int sa_offset = npdu_offset + 2;

                    // however, if there is a destination address, move the sa_offset up appropriate amount

                    if (dadr != null)
                    {
                        sa_offset = npdu_offset + 2 + 3 + (int)dadr.MACaddress.length;
                    }

                    // means SADR, SNET present

                    sadr.Decode(buffer, ref sa_offset);

                    // SA exists (included MAC and so this means the received IP address needs to be the fromBIP
                }
                else
                {
                    // at this point, if SADR not discovered within the NPDU, then the SADR MAC address is the Ethernet/IP fromaddress
                    // and the device can (must) be considered 'direcly connected'
                    if (directlyConnectedIPEndPointOfDevice != null)
                    {
                        // and even though the device is directly connected, because we are a router, we have an allocated network number to provide
                        // the network number is available outside this class, and will be filled in by the calling function if it is relevant.
                        srcDevice.adr = new ADR(0, directlyConnectedIPEndPointOfDevice);
                    }
                    else
                    {
                        throw new Exception("m0063 - No From-Address can be determined");
                    }
                }



                if (dadr != null)
                {
                    if (sadr != null)
                    {
                        hopcount = (uint)(buffer[npdu_offset + 2 + 2 + 1 + dadr.MACaddress.length + 2 + 1 + sadr.MACaddress.length]);
                    }
                    else
                    {
                        hopcount = (uint)(buffer[npdu_offset + 2 + 2 + 1 + dadr.MACaddress.length]);
                    }
                    // true broadcast, but check the hopcount

                    if (hopcount == 0)
                    {
                        // out of hops, should never happen to us, so sound a warning
                        // todo, remove this for a functioning systems
                        System.Windows.Forms.MessageBox.Show("m0008 Hopcount of 0 detected");
                        return(false);
                    }
                }

                // finished resolving sadr, and dadr. Now populate our devices as required

                if (sadr != null)
                {
                    if (srcDevice.adr != null)
                    {
                        // means this adr was partially populated elsewhere.
                        srcDevice.adr.networkNumber = sadr.networkNumber;
                        srcDevice.adr.MACaddress    = sadr.MACaddress;
                    }
                    else
                    {
                        srcDevice.adr = sadr;
                    }
                }



                if ((buffer[npdu_offset + 1] & 0x80) == 0x80)  // todo magic number
                {
                    // NSDU contains Network Layer Message
                    // http://www.bacnetwiki.com/wiki/index.php?title=Network_Layer_Protocol_Control_Information

                    apdu_present       = false;
                    npdu.isNPDUmessage = true;

                    // calculate offset to the NSDU

                    nsdu_offset = npdu_offset + 2;

                    if (sadr != null)
                    {
                        nsdu_offset += 2 + 1 + (int)sadr.MACaddress.length;
                    }
                    if (dadr != null)
                    {
                        nsdu_offset += 2 + 1 + (int)dadr.MACaddress.length + 1;
                    }

                    npdu.function = (BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE)buffer[nsdu_offset];

                    switch (npdu.function)
                    {
                    case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK:
                        // there may be a list of network numbers after the header

                        if ((length - nsdu_offset >= 3))
                        {
                            numberList = new List <uint>();
                        }

                        for (int i = 0; i < (length - nsdu_offset - 1) / 2; i++)
                        {
                            int tref = nsdu_offset + 1 + i * 2;
                            numberList.Add(BACnetLibraryCL.ExtractUint16(buffer, ref tref));
                        }
                        break;

                    case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_INIT_RT_TABLE_ACK:
                        int tiptr    = nsdu_offset + 1;
                        int numPorts = buffer[tiptr++];
                        routerPortList = new List <RouterPort>();

                        for (int i = 0; i < numPorts; i++)
                        {
                            RouterPort rp = new RouterPort();
                            rp.Decode(buffer, ref tiptr);
                            routerPortList.Add(rp);
                        }
                        break;

                    default:
                        // todo
                        break;
                    }
                }
                else
                {
                    // NSDU contains APDU
                    // http://www.bacnetwiki.com/wiki/index.php?title=Network_Layer_Protocol_Control_Information

                    // determine if SNET, SLEN, SADR present

                    apdu_present = true;

                    apdu_offset = npdu_offset + 2;

                    if (sadr != null)
                    {
                        apdu_offset += 2 + 1 + (int)sadr.MACaddress.length;
                    }
                    if (dadr != null)
                    {
                        apdu_offset += 2 + 1 + (int)dadr.MACaddress.length + 1;
                    }

                    apdu_length = length - apdu_offset;
                    if (apdu_length < 0)
                    {
                        _apm.MessagePanic("m0006 Illegal APDU length");
                        return(false);
                    }

                    // todo - need to extract the apdu for others to refer to. However, APDUs may be customer specific, so extract this as a buffer
                    // only for now, and do some spot checks for relevant functions such as I-Am and Who-Is.

                    apdu_buf = new byte[2000];

                    Buffer.BlockCopy(buffer, apdu_offset, apdu_buf, 0, apdu_length);

                    // the offset here is the APDU. Start parsing APDU.
                    // todo, decided to leave the enum values unshifted today 11/27/09
                    pduType = (BACnetEnums.BACNET_PDU_TYPE)(buffer[apdu_offset] & 0xf0);

                    // make sure that we can handle the rest of the packet

                    //if ((buffer[apdu_offset] & 0x0f) != 0 )
                    //{
                    //    throw new Exception("m0056 - Cannot handle segmented messages yet");
                    //}

                    int tptr = apdu_offset + 1;

                    if (pduType == BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_CONFIRMED_SERVICE_REQUEST)
                    {
                        // some PDUs have max segs here
                        tptr++;
                    }

                    //_apm.MessageTodo("Remove apdu++");
                    //apdu_offset++;
                    //apdu_offset++;

                    // now the next byte is the invoke ID

                    invokeID = buffer[tptr++];

                    switch (pduType)
                    {
                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
                        // todo, offset is not always 1, depends on the flags in the first byte.
                        DecodeUnconfirmedService(apdu_buf, apdu_length);
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
                        DecodeConfirmedService(apdu_buf);
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_SIMPLE_ACK:
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_COMPLEX_ACK:
                        confirmedServiceChoice = (BACnetEnums.BACNET_CONFIRMED_SERVICE)buffer[apdu_offset + 2];
                        DecodeComplexACK(buffer, apdu_offset);
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_SEGMENT_ACK:
                        _apm.MessageTodo("m0093 - Segment ACK");
                        errorFlag = true;
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_ERROR:
                        _apm.MessageTodo("m0064 - Error");
                        errorFlag = true;
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_REJECT:
                        pduRejectReason = (BACnetEnums.BACNET_BACNET_REJECT_REASON)buffer[apdu_offset++];
                        errorFlag       = true;
                        break;

                    case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_ABORT:
                        _apm.MessageTodo("m0066 - PDU abort");
                        errorFlag = true;
                        break;

                    default:
                        throw new Exception("m0003 - Illegal PDU type");
                    }
                }
            }
            catch (Exception ex)
            {
                _apm.MessagePanic("m0001 - BACnet Decode Failed " + ex.ToString());
            }
            return(true);
        }
Beispiel #9
0
        public void UpdateDeviceTreeView(BACnetManager bnm, BACnetPacket pkt)
        {
            if (!pkt.apdu_present)
            {
                // means that this packet must be a NPDU message. Treat it differently

                switch (pkt.npdu.function)
                {
                case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_I_AM_ROUTER_TO_NETWORK:
                    //if (pkt.numberList.Count > 0)
                    //{
                    // means we had a response from a router - establish the router in our tree.
                    myTreeNode mtnd = EstablishTreeNodeDevice(bnm, pkt);

                    if (mtnd != null)
                    {
                        // found, or established, the treenode matching the device,
                        // now add the objects to it.

                        // update the type of device - we now know it is a router (even if we did not know before).

                        mtnd.device.type = BACnetEnums.DEVICE_TYPE.Router;
                        mtnd.Text        = "Router";

                        if (pkt.numberList != null)
                        {
                            foreach (int bno in pkt.numberList)
                            {
                                bool found = false;

                                for (int i = 0; i < mtnd.Nodes.Count; i++)
                                {
                                    if (mtnd.Nodes[i].GetType() == typeof(myTreeNode))
                                    {
                                        myTreeNode mtnObj = (myTreeNode)mtnd.Nodes[i];
                                        if (mtnObj.type == myTreeNode.TREENODE_OBJ_TYPE.NetworkNumber && mtnObj.networkNumber == bno)
                                        {
                                            // if we get here, the object already exists in the list and we must not add it again.
                                            mtnObj.networkNumberFromWhoIsRouter = true;
                                            found = true;
                                            break;
                                        }
                                    }
                                }

                                if (!found)
                                {
                                    //// not found, so add
                                    myTreeNode ntn = mtnd.AddMyTreeNodeObject(myTreeNode.TREENODE_OBJ_TYPE.NetworkNumber, "Network " + bno.ToString());
                                    ntn.networkNumber = (uint)bno;
                                    ntn.networkNumberFromWhoIsRouter = true;
                                    ntn.ToolTipText = "Do not right click on this item, it has no effect";
                                    mtnd.Expand();
                                }
                            }
                        }
                        else
                        {
                            _apm.MessageTodo("m0032");
                        }
                    }

                    //}
                    break;

                case BACnetEnums.BACNET_NETWORK_MESSAGE_TYPE.NETWORK_MESSAGE_INIT_RT_TABLE_ACK:

                    myTreeNode mtnrt = EstablishTreeNodeDevice(bnm, pkt);

                    if (mtnrt != null)
                    {
                        // found, or established, the treenode matching the device,
                        // now add the objects to it.
                        // update the type of device - we now know it is a router (even if we did not know before).

                        mtnrt.device.type = BACnetEnums.DEVICE_TYPE.Router;
                        mtnrt.Text        = "Router";

                        foreach (RouterPort rp in pkt.routerPortList)
                        {
                            bool found = false;

                            for (int i = 0; i < mtnrt.Nodes.Count; i++)
                            {
                                if (mtnrt.Nodes[i].GetType() == typeof(myTreeNode))
                                {
                                    myTreeNode mtnObj = (myTreeNode)mtnrt.Nodes[i];
                                    if (mtnObj.type == myTreeNode.TREENODE_OBJ_TYPE.NetworkNumber && mtnObj.networkNumber == rp.networkNumber)
                                    {
                                        // if we get here, the object already exists in the list and we must not add it again.
                                        found = true;
                                        mtnObj.networkNumberFromInitRouterTable = true;
                                        break;
                                    }
                                }
                            }

                            if (!found)
                            {
                                //// not found, so add
                                myTreeNode ntn = mtnrt.AddMyTreeNodeObject(myTreeNode.TREENODE_OBJ_TYPE.NetworkNumber, "Network " + rp.networkNumber.ToString());
                                ntn.networkNumber = rp.networkNumber;
                                ntn.networkNumberFromInitRouterTable = true;
                                // ntn.ToolTipText = "Do not right click on this item, it has no effect";
                                mtnrt.Expand();
                            }
                        }
                    }

                    break;
                }

                return;
            }

            switch (pkt.pduType)
            {
            case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
                switch (pkt.unconfirmedServiceChoice)
                {
                case BACnetEnums.BACNET_UNCONFIRMED_SERVICE.SERVICE_UNCONFIRMED_I_AM:
                    pkt.srcDevice.directlyConnectedIPEndPointOfDevice = pkt.directlyConnectedIPEndPointOfDevice;           // was fromBIP

                    // todo, not sure where I use this - check
                    bnm.deviceList.Add(pkt.srcDevice);

                    AddDeviceToTreeNode(bnm, pkt);
                    // bnm.newPacketQueue.Enqueue(packet);
                    break;

                case BACnetEnums.BACNET_UNCONFIRMED_SERVICE.SERVICE_UNCONFIRMED_WHO_IS:
                    // ignore reflected who-is messages
                    break;

                default:
                    BACnetLibraryCL.Panic("Todo");
                    break;
                }
                break;

            case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_COMPLEX_ACK:
                switch (pkt.confirmedServiceChoice)
                {
                case BACnetEnums.BACNET_CONFIRMED_SERVICE.SERVICE_CONFIRMED_READ_PROPERTY:
                    switch (pkt.propertyID)
                    {
                    case BACnetEnums.BACNET_PROPERTY_ID.PROP_OBJECT_LIST:
                        // what we need to do here is list the objects on the treeview...

                        // find the device in the tree
                        // add the objects to it

                        myTreeNode mtn = findTreeNodeDevice(bnm, pkt);

                        if (mtn != null)
                        {
                            // found the treenode matching the device, add the objects to it.

                            if (pkt.objectList != null)
                            {
                                foreach (BACnetObjectIdentifier bno in pkt.objectList)
                                {
                                    // does it exist? if so, ignore
                                    if (findTreeNodeObject(mtn, bno) == null)
                                    {
                                        // not found, so add
                                        myTreeNode ntn = new myTreeNode();
                                        ntn.oID         = bno;
                                        ntn.type        = myTreeNode.TREENODE_OBJ_TYPE.BACnetObject;
                                        ntn.Text        = bno.objectType.ToString() + "   Instance: " + bno.objectInstance.ToString();
                                        ntn.ToolTipText = "Do not right click on this item, it has no effect";
                                        mtn.Nodes.Add(ntn);
                                    }
                                }
                            }

                            // now remove the object list??? (but it will be removed when packet is destroyed....
                        }

                        break;

                    default:
                        _apm.MessagePanic("m0030 " + pkt.propertyID.ToString());
                        break;
                    }
                    break;

                default:
                    _apm.MessagePanic("m0029");
                    break;
                }
                break;


            case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
            case BACnetEnums.BACNET_PDU_TYPE.PDU_TYPE_REJECT:
                // These messages do not affect the Device TreeView, so we will ignore them..
                break;

            default:
                _apm.MessageTodo("m0027 - Device Treeview needs to parse this message still: " + pkt.pduType.ToString());
                break;
            }
        }