private BacnetMstpProtocolTransport.GetMessageStatus GetNextMessage(byte[] buffer, ref int offset,
                                                                            int timeoutMs, out BacnetPtpFrameTypes frameType, out int msgLength)
        {
            BacnetMstpProtocolTransport.GetMessageStatus status;
            var timeout = timeoutMs;

            frameType = BacnetPtpFrameTypes.FRAME_TYPE_HEARTBEAT_XOFF;
            msgLength = 0;
            var complimentNext = false;

            //fetch header
            while (offset < PTP.PTP_HEADER_LENGTH)
            {
                if (_port == null)
                {
                    return(BacnetMstpProtocolTransport.GetMessageStatus.ConnectionClose);
                }

                timeout = offset > 0 ? T_FRAME_ABORT : timeoutMs;

                //read
                var rx = _port.Read(buffer, offset, PTP.PTP_HEADER_LENGTH - offset, timeout);
                status = ProcessRxStatus(buffer, ref offset, rx);
                if (status != BacnetMstpProtocolTransport.GetMessageStatus.Good)
                {
                    return(status);
                }

                //remove XON/XOFF
                var newOffset = offset + rx;
                RemoveXonOff(buffer, offset, ref newOffset, ref complimentNext);
                offset = newOffset;

                //remove garbage
                RemoveGarbage(buffer, ref offset);
            }

            //greeting
            if (IsGreeting(buffer, 0, offset))
            {
                //get last byte
                var rx = _port.Read(buffer, offset, 1, timeout);
                status = ProcessRxStatus(buffer, ref offset, rx);
                if (status != BacnetMstpProtocolTransport.GetMessageStatus.Good)
                {
                    return(status);
                }
                offset += 1;
                if (IsGreeting(buffer, 0, offset))
                {
                    frameType = BacnetPtpFrameTypes.FRAME_TYPE_GREETING;
                    Log.AddCustomEvent(LagoVista.Core.PlatformSupport.LogLevel.Message, "BacnetPtpProtocol", frameType.ToString());
                    return(BacnetMstpProtocolTransport.GetMessageStatus.Good);
                }
                //drop message
                buffer[0] = 0xFF;
                RemoveGarbage(buffer, ref offset);
                return(BacnetMstpProtocolTransport.GetMessageStatus.DecodeError);
            }

            //decode
            if (PTP.Decode(buffer, 0, offset, out frameType, out msgLength) < 0)
            {
                //drop message
                buffer[0] = 0xFF;
                RemoveGarbage(buffer, ref offset);
                return(BacnetMstpProtocolTransport.GetMessageStatus.DecodeError);
            }

            //valid length?
            var fullMsgLength = msgLength + PTP.PTP_HEADER_LENGTH + (msgLength > 0 ? 2 : 0);

            if (msgLength > MaxBufferLength)
            {
                //drop message
                buffer[0] = 0xFF;
                RemoveGarbage(buffer, ref offset);
                return(BacnetMstpProtocolTransport.GetMessageStatus.DecodeError);
            }

            //fetch data
            if (msgLength > 0)
            {
                timeout = T_FRAME_ABORT; //set sub timeout
                while (offset < fullMsgLength)
                {
                    //read
                    var rx = _port.Read(buffer, offset, fullMsgLength - offset, timeout);
                    status = ProcessRxStatus(buffer, ref offset, rx);
                    if (status != BacnetMstpProtocolTransport.GetMessageStatus.Good)
                    {
                        return(status);
                    }

                    //remove XON/XOFF
                    var newOffset = offset + rx;
                    RemoveXonOff(buffer, offset, ref newOffset, ref complimentNext);
                    offset = newOffset;
                }

                //verify data crc
                if (PTP.Decode(buffer, 0, offset, out frameType, out msgLength) < 0)
                {
                    //drop message
                    buffer[0] = 0xFF;
                    RemoveGarbage(buffer, ref offset);
                    return(BacnetMstpProtocolTransport.GetMessageStatus.DecodeError);
                }
            }

            Log.AddCustomEvent(LagoVista.Core.PlatformSupport.LogLevel.Message, "BacnetPtpProtocol", frameType.ToString());

            //done
            return(BacnetMstpProtocolTransport.GetMessageStatus.Good);
        }
        private void SendFrame(BacnetPtpFrameTypes frameType, byte[] buffer = null, int msgLength = 0)
        {
            if (_port == null)
            {
                return;
            }

            var fullLength = PTP.PTP_HEADER_LENGTH + msgLength + (msgLength > 0 ? 2 : 0);

            if (buffer == null)
            {
                buffer = new byte[fullLength];
            }
            PTP.Encode(buffer, 0, frameType, msgLength);

            Log.AddCustomEvent(LagoVista.Core.PlatformSupport.LogLevel.Message, "BacnetPtpProtocol", frameType.ToString());

            //send
            SendWithXonXoff(buffer, 0, fullLength);
        }