Пример #1
0
        public bool Send(MessageRaw raw)
        {
            try
            {
                // TX header
                var sendHeaderCount = SendRawBuffer(raw.Header);

                if (sendHeaderCount == raw.Header.Length)
                {
                    if (raw.Payload != null &&
                        raw.Payload.Length > 0)
                    {
                        // we have a payload to TX

                        var sendPayloadCount = SendRawBuffer(raw.Payload);

                        if (sendPayloadCount != raw.Payload.Length)
                        {
                            // failed TX the payload
                            return(false);
                        }
                    }

                    // all good
                    return(true);
                }
            }
            catch (TaskCanceledException)
            {
                // don't do anything here, as this is expected
            }
            catch (DeviceNotConnectedException)
            {
                throw;
            }
            catch (IOException)
            {
                App.ProcessExited();
            }
            catch (AggregateException)
            {
                App.ProcessExited();
            }
            catch (InvalidOperationException)
            {
                App.ProcessExited();
            }
            catch
            {
                // catch everything else here, doesn't matter
                return(false);
            }

            return(false);
        }
Пример #2
0
        public async Task <bool> QueueOutputAsync(MessageRaw raw)
        {
            await SendRawBufferAsync(raw.m_header, TimeSpan.FromMilliseconds(1000), new CancellationToken()).ConfigureAwait(false);

            if (raw.m_payload != null)
            {
                await SendRawBufferAsync(raw.m_payload, TimeSpan.FromMilliseconds(1000), new CancellationTokenSource().Token).ConfigureAwait(false);
            }

            return(true);
        }
Пример #3
0
        public async Task <bool> QueueOutputAsync(MessageRaw raw, CancellationToken cancellationToken)
        {
            Debug.WriteLine("QueueOutputAsync 1");
            await SendRawBufferAsync(raw.Header, TimeSpan.FromMilliseconds(1000), cancellationToken);

            // check for cancelation request
            if (cancellationToken.IsCancellationRequested)
            {
                // cancellation requested
                Debug.WriteLine("cancelation requested");
                return(false);
            }

            if (raw.Payload != null)
            {
                Debug.WriteLine("QueueOutputAsync 2");

                await SendRawBufferAsync(raw.Payload, TimeSpan.FromMilliseconds(1000), cancellationToken);
            }

            return(true);
        }
Пример #4
0
        internal void InitializeForSend(IController parent, Converter converter, uint cmd, uint flags, object payload)
        {
            Packet header = parent.NewPacket();

            header.Cmd   = cmd;
            header.Flags = flags;

            _parent = parent;

            _raw          = new MessageRaw();
            _base         = new MessageBase();
            _base.Header  = header;
            _base.Payload = payload;

            if (payload != null)
            {
                _raw.Payload = converter.Serialize(payload);

                _base.Header.Size    = (uint)_raw.Payload.Length;
                _base.Header.CrcData = CRC.ComputeCRC(_raw.Payload, 0);
            }
        }
Пример #5
0
        internal void InitializeForSend(IController parent, Converter converter, uint cmd, uint flags, object payload)
        {
            Packet header = parent.NewPacket();

            header.m_cmd   = cmd;
            header.m_flags = flags;

            m_parent = parent;

            m_raw            = new MessageRaw();
            m_base           = new MessageBase();
            m_base.m_header  = header;
            m_base.m_payload = payload;

            if (payload != null)
            {
                m_raw.m_payload = converter.Serialize(payload);

                m_base.m_header.m_size    = (uint)m_raw.m_payload.Length;
                m_base.m_header.m_crcData = CRC.ComputeCRC(m_raw.m_payload, 0);
            }
        }
 public IncomingMessage(IController parent, MessageRaw raw, MessageBase messageBase)
 {
     m_parent = parent;
     m_raw    = raw;
     m_base   = messageBase;
 }
Пример #7
0
        /// <summary>
        /// Essential Rx method. Drives state machine by reading data and processing it. This works in
        /// conjunction with NotificationThreadWorker [Tx].
        /// </summary>
        public async Task ProcessAsync(CancellationToken cancellationToken)
        {
            int count;
            int bytesRead;

            // compute operation timeout here to ease reuse on calls bellow
            TimeSpan operationTimeout = new TimeSpan(0, 0, 0, 0, 1000);

            try
            {
                // while cancellation is NOT requested
                while (!cancellationToken.IsCancellationRequested)
                {
                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                    switch (_state)
                    {
                    case ReceiveState.Initialize:
                        _rawPos = 0;

                        _messageBase = new MessageBase
                        {
                            Header = new Packet()
                        };

                        _messageRaw = new MessageRaw
                        {
                            Header = _parent.CreateConverter().Serialize(_messageBase.Header)
                        };

                        _state = ReceiveState.WaitingForHeader;
                        break;

                    case ReceiveState.WaitingForHeader:
                        count = _messageRaw.Header.Length - _rawPos;

                        // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                        // because we have an external cancellation token and the above timeout cancellation token, need to combine both
                        bytesRead = await _parent.ReadBufferAsync(_messageRaw.Header, _rawPos, count, operationTimeout, cancellationToken);

                        _rawPos += bytesRead;

                        // sanity check
                        if (bytesRead != 32)
                        {
                            // doesn't look like a header, better restart
                            _state = ReceiveState.Initialize;
                            break;
                        }

                        while (_rawPos > 0)
                        {
                            int flag_Debugger = ValidMarker(_markerDebugger);
                            int flag_Packet   = ValidMarker(_markerPacket);

                            if (flag_Debugger == 1 || flag_Packet == 1)
                            {
                                _state = ReceiveState.ReadingHeader;
                                break;
                            }

                            if (flag_Debugger == 0 || flag_Packet == 0)
                            {
                                break;     // Partial match.
                            }

                            _parent.App.SpuriousCharacters(_messageRaw.Header, 0, 1);

                            Array.Copy(_messageRaw.Header, 1, _messageRaw.Header, 0, --_rawPos);
                        }
                        break;

                    case ReceiveState.ReadingHeader:
                        count = _messageRaw.Header.Length - _rawPos;

                        // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                        // because we have an external cancellation token and the above timeout cancellation token, need to combine both
                        bytesRead = await _parent.ReadBufferAsync(_messageRaw.Header, _rawPos, count, operationTimeout, cancellationToken);

                        _rawPos += bytesRead;

                        if (bytesRead != count)
                        {
                            break;
                        }

                        _state = ReceiveState.CompleteHeader;
                        break;

                    case ReceiveState.CompleteHeader:
                        try
                        {
                            _parent.CreateConverter().Deserialize(_messageBase.Header, _messageRaw.Header);

                            if (VerifyHeader() == true)
                            {
                                bool fReply = (_messageBase.Header.Flags & Flags.c_Reply) != 0;

                                DebuggerEventSource.Log.WireProtocolRxHeader(_messageBase.Header.CrcHeader, _messageBase.Header.CrcData, _messageBase.Header.Cmd, _messageBase.Header.Flags, _messageBase.Header.Seq, _messageBase.Header.SeqReply, _messageBase.Header.Size);

                                if (_messageBase.Header.Size != 0)
                                {
                                    _messageRaw.Payload = new byte[_messageBase.Header.Size];
                                    //reuse m_rawPos for position in header to read.
                                    _rawPos = 0;

                                    _state = ReceiveState.ReadingPayload;
                                    break;
                                }
                                else
                                {
                                    _state = ReceiveState.CompletePayload;
                                    break;
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine("Fault at payload de-serialization:\n\n{0}", e.ToString());
                        }

                        _state = ReceiveState.Initialize;
                        break;

                    case ReceiveState.ReadingPayload:
                        count = _messageRaw.Payload.Length - _rawPos;

                        // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                        // because we have an external cancellation token and the above timeout cancellation token, need to combine both
                        bytesRead = await _parent.ReadBufferAsync(_messageRaw.Payload, _rawPos, count, operationTimeout, cancellationToken);

                        _rawPos += bytesRead;

                        if (bytesRead != count)
                        {
                            break;
                        }

                        _state = ReceiveState.CompletePayload;

                        break;

                    case ReceiveState.CompletePayload:
                        if (VerifyPayload() == true)
                        {
                            try
                            {
                                bool fReply = (_messageBase.Header.Flags & Flags.c_Reply) != 0;

                                if ((_messageBase.Header.Flags & Flags.c_NACK) != 0)
                                {
                                    _messageRaw.Payload = null;
                                }

                                _parent.App.ProcessMessage(GetCompleteMessage(), fReply);

                                // setup restart
                                _state = ReceiveState.Initialize;
                                return;
                            }
                            catch (Exception e)
                            {
                                Debug.WriteLine("Fault at payload de-serialization:\n\n{0}", e.ToString());
                            }
                        }

                        _state = ReceiveState.Initialize;
                        break;
                    }
                }

                if (cancellationToken.IsCancellationRequested)
                {
                    Debug.WriteLine($"---- cancelling message re-assembler ----");
                }
            }
            catch
            {
                Debug.WriteLine("*** EXCEPTION IN STATE MACHINE***");
                throw;
            }
        }
Пример #8
0
        public async Task <bool> SendAsync(MessageRaw raw, CancellationToken cancellationToken)
        {
            _sendSemaphore.WaitOne();

            // check for cancellation request
            if (cancellationToken.IsCancellationRequested)
            {
                // cancellation requested
                return(false);
            }

            try
            {
                // TX header
                var sendHeaderCount = await SendRawBufferAsync(raw.Header, TimeSpan.FromMilliseconds(1000), cancellationToken);

                // check for cancellation request
                if (cancellationToken.IsCancellationRequested)
                {
                    // cancellation requested
                    return(false);
                }

                if (raw.Payload != null)
                {
                    // we have a payload to TX
                    if (sendHeaderCount == raw.Header.Length)
                    {
                        var sendPayloadCount = await SendRawBufferAsync(raw.Payload, TimeSpan.FromMilliseconds(1000), cancellationToken);

                        if (sendPayloadCount == raw.Payload.Length)
                        {
                            // payload TX OK
                            return(true);
                        }
                        else
                        {
                            // failed TX the payload
                            return(false);
                        }
                    }
                    else
                    {
                        // already failed to TX header so don't bother with the payload
                        return(false);
                    }
                }
                else
                {
                    // no payload, header TX OK, we are good
                    return(true);
                }
            }
            catch (TaskCanceledException)
            {
                // don't do anything here, as this is expected
            }
            catch (DeviceNotConnectedException)
            {
                App.ProcessExited();
            }
            finally
            {
                _sendSemaphore.Release();
            }

            return(false);
        }
        /// <summary>
        /// Essential Rx method. Drives state machine by reading data and processing it. This works in
        /// conjunction with NotificationThreadWorker [Tx].
        /// </summary>
        internal async Task <IncomingMessage> ProcessAsync(CancellationToken cancellationToken)
        {
            int count;
            int bytesRead;

            try
            {
                while (true)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        // cancellation requested

                        Debug.WriteLine("cancel token");

                        return(GetCompleteMessage());
                    }

                    switch (_state)
                    {
                    case ReceiveState.Initialize:


                        _rawPos = 0;

                        _messageBase        = new MessageBase();
                        _messageBase.Header = new Packet();

                        _messageRaw        = new MessageRaw();
                        _messageRaw.Header = _parent.CreateConverter().Serialize(_messageBase.Header);

                        _state = ReceiveState.WaitingForHeader;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                        break;

                    case ReceiveState.WaitingForHeader:
                        count = _messageRaw.Header.Length - _rawPos;

                        Debug.WriteLine("WaitingForHeader");

                        // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                        // because we have an external cancellation token and the above timeout cancellation token, need to combine both

                        bytesRead = await _parent.ReadBufferAsync(_messageRaw.Header, _rawPos, count, request.waitRetryTimeout, cancellationToken.AddTimeout(request.waitRetryTimeout));

                        _rawPos += bytesRead;

                        // sanity check
                        if (bytesRead != 32)
                        {
                            // doesn't look like a header, better restart
                            _state = ReceiveState.Initialize;
                            break;
                        }

                        while (_rawPos > 0)
                        {
                            int flag_Debugger = ValidMarker(markerDebugger);
                            int flag_Packet   = ValidMarker(markerPacket);

                            if (flag_Debugger == 1 || flag_Packet == 1)
                            {
                                _state = ReceiveState.ReadingHeader;
                                DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                                break;
                            }

                            if (flag_Debugger == 0 || flag_Packet == 0)
                            {
                                break;     // Partial match.
                            }

                            _parent.App.SpuriousCharacters(_messageRaw.Header, 0, 1);

                            Array.Copy(_messageRaw.Header, 1, _messageRaw.Header, 0, --_rawPos);
                        }
                        break;

                    case ReceiveState.ReadingHeader:
                        count = _messageRaw.Header.Length - _rawPos;

                        Debug.WriteLine("ReadingHeader");

                        // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                        // because we have an external cancellation token and the above timeout cancellation token, need to combine both

                        bytesRead = await _parent.ReadBufferAsync(_messageRaw.Header, _rawPos, count, request.waitRetryTimeout, cancellationToken.AddTimeout(request.waitRetryTimeout));

                        _rawPos += bytesRead;

                        if (bytesRead != count)
                        {
                            break;
                        }

                        _state = ReceiveState.CompleteHeader;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                        break;

                    case ReceiveState.CompleteHeader:
                        try
                        {
                            Debug.WriteLine("CompleteHeader");

                            _parent.CreateConverter().Deserialize(_messageBase.Header, _messageRaw.Header);

                            if (VerifyHeader() == true)
                            {
                                Debug.WriteLine("CompleteHeader, header OK");

                                bool fReply = (_messageBase.Header.Flags & Flags.c_Reply) != 0;

                                DebuggerEventSource.Log.WireProtocolRxHeader(_messageBase.Header.CrcHeader, _messageBase.Header.CrcData, _messageBase.Header.Cmd, _messageBase.Header.Flags, _messageBase.Header.Seq, _messageBase.Header.SeqReply, _messageBase.Header.Size);

                                if (_messageBase.Header.Size != 0)
                                {
                                    _messageRaw.Payload = new byte[_messageBase.Header.Size];
                                    //reuse m_rawPos for position in header to read.
                                    _rawPos = 0;

                                    _state = ReceiveState.ReadingPayload;
                                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                                    break;
                                }
                                else
                                {
                                    _state = ReceiveState.CompletePayload;
                                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                                    break;
                                }
                            }

                            Debug.WriteLine("CompleteHeader, header not valid");
                        }
                        //catch (ThreadAbortException)
                        //{
                        //    throw;
                        //}
                        catch (Exception e)
                        {
                            Debug.WriteLine("Fault at payload deserialization:\n\n{0}", e.ToString());
                        }

                        _state = ReceiveState.Initialize;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                        if ((_messageBase.Header.Flags & Flags.c_NonCritical) == 0)
                        {
                            // FIXME
                            // evaluate the purpose of this reply back to the NanoFramework device, the nanoCLR doesn't seem to have to handle this. In the end it looks like this does have any real purpose and will only be wasting CPU.
                            //await IncomingMessage.ReplyBadPacketAsync(m_parent, Flags.c_BadHeader);
                            return(GetCompleteMessage());
                        }

                        break;

                    case ReceiveState.ReadingPayload:
                        count = _messageRaw.Payload.Length - _rawPos;

                        Debug.WriteLine("ReadingPayload");

                        // need to have a timeout to cancel the read task otherwise it may end up waiting forever for this to return
                        // because we have an external cancellation token and the above timeout cancellation token, need to combine both

                        bytesRead = await _parent.ReadBufferAsync(_messageRaw.Payload, _rawPos, count, request.waitRetryTimeout, cancellationToken.AddTimeout(request.waitRetryTimeout));

                        _rawPos += bytesRead;

                        if (bytesRead != count)
                        {
                            break;
                        }

                        _state = ReceiveState.CompletePayload;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                        break;

                    case ReceiveState.CompletePayload:
                        Debug.WriteLine("CompletePayload");

                        if (VerifyPayload() == true)
                        {
                            Debug.WriteLine("CompletePayload payload OK");

                            try
                            {
                                bool fReply = (_messageBase.Header.Flags & Flags.c_Reply) != 0;

                                if ((_messageBase.Header.Flags & Flags.c_NACK) != 0)
                                {
                                    _messageRaw.Payload = null;
                                }

                                if (await ProcessMessage(GetCompleteMessage(), fReply, cancellationToken))
                                {
                                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                                    //Debug.WriteLine("*** leaving reassembler");

                                    return(GetCompleteMessage());
                                }
                                else
                                {
                                    // this is not the message we were waiting
                                    // FIXME
                                }
                                //m_parent.App.ProcessMessage(this.GetCompleteMessage(), fReply);

                                //m_state = ReceiveState.Initialize;
                                //return;
                            }
                            //catch (ThreadAbortException)
                            //{
                            //    throw;
                            //}
                            catch (Exception e)
                            {
                                Debug.WriteLine("Fault at payload deserialization:\n\n{0}", e.ToString());
                            }
                        }
                        else
                        {
                            Debug.WriteLine("CompletePayload payload not valid");
                        }

                        _state = ReceiveState.Initialize;
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                        if ((_messageBase.Header.Flags & Flags.c_NonCritical) == 0)
                        {
                            // FIXME
                            // evaluate the purpose of this reply back to the NanoFramework device, the nanoCLR doesn't seem to have to handle this. In the end it looks like this does have any real purpose and will only be wasting CPU.
                            await IncomingMessage.ReplyBadPacketAsync(_parent, Flags.c_BadPayload, cancellationToken);

                            return(GetCompleteMessage());
                        }

                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                _state = ReceiveState.Initialize;
                DebuggerEventSource.Log.WireProtocolReceiveState(_state);
                Debug.WriteLine($"*** EXCEPTION IN STATE MACHINE***:\r\n{ex.Message} \r\n{ex.StackTrace}");
                throw;
            }

            Debug.WriteLine("??????? leaving reassembler");
            return(GetCompleteMessage());
        }
        /// <summary>
        /// Essential Rx method. Drives state machine by reading data and processing it. This works in
        /// conjunction with NotificationThreadWorker [Tx].
        /// </summary>
        public void Process()
        {
            int count;
            int bytesRead;
            int sleepTime = 0;

            _inactivityTime = (DateTime.UtcNow - _parent.LastActivity);

            // activity check, if not exiting idle state
            if (_state != ReceiveState.ExitingIdle)
            {
                // progressive back-off
                if (_inactivityTime.TotalMilliseconds >= MaxInactivityTime)
                {
                    sleepTime = MaxBackoffTime;
                }
                else if (_inactivityTime.TotalMilliseconds >= MaxInactivityTimeStep1)
                {
                    sleepTime = BackoffTimeStep1;
                }
                else if (_inactivityTime.TotalMilliseconds >= MaxInactivityTimeStep2)
                {
                    sleepTime = BackoffTimeStep2;
                }
                else if (_inactivityTime.TotalMilliseconds >= MaxInactivityTimeStep3)
                {
                    sleepTime = BackoffTimeStep3;
                }
                else if (_inactivityTime.TotalMilliseconds >= MaxInactivityTimeStep4)
                {
                    sleepTime = BackoffTimeStep4;
                }

                if (sleepTime > 0)
                {
                    _previousState = _state;
                    _state         = ReceiveState.Idle;

                    if (_lastInactivityReport == DateTime.MinValue)
                    {
                        _lastInactivityReport = DateTime.UtcNow.AddSeconds(10);
                    }
                }
            }
            else
            {
                // restore previous state
                _state = _previousState;
            }

            try
            {
                switch (_state)
                {
                case ReceiveState.Idle:

                    if (DateTime.UtcNow > _lastInactivityReport)
                    {
                        DebuggerEventSource.Log.WireProtocolReceiveState(_state, _inactivityTime);

                        // reset
                        _lastInactivityReport = DateTime.MinValue;
                    }

                    // sleep now
                    Thread.Sleep(sleepTime);

                    // restore previous state
                    _state = ReceiveState.ExitingIdle;

                    break;

                case ReceiveState.Initialize:

                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                    _rawPos = 0;

                    _messageBase = new MessageBase
                    {
                        Header = new Packet()
                    };

                    _messageRaw = new MessageRaw
                    {
                        Header = _parent.CreateConverter().Serialize(_messageBase.Header)
                    };

                    // reset event timeout
                    _messageEventTimeout = DateTime.MinValue;

                    _state = ReceiveState.WaitingForHeader;

                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                    goto case ReceiveState.WaitingForHeader;

                case ReceiveState.WaitingForHeader:

                    // try to read marker
                    count = Packet.SIZE_OF_MARKER - _rawPos;

                    bytesRead = _parent.ReadBuffer(_messageRaw.Header, _rawPos, count);

                    _rawPos += bytesRead;

                    // activity check
                    if (bytesRead > 0)
                    {
                        _parent.LastActivity = DateTime.UtcNow;
                    }

                    // loop trying to find the markers in the stream
                    while (_rawPos > 0)
                    {
                        var debuggerMarkerPresence = ValidMarker(_markerDebugger);
                        var packetMarkerPresence   = ValidMarker(_markerPacket);

                        if (debuggerMarkerPresence == MarkerPresence.Present ||
                            packetMarkerPresence == MarkerPresence.Present)
                        {
                            _state = ReceiveState.ReadingHeader;

                            DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                            goto case ReceiveState.ReadingHeader;
                        }

                        if (debuggerMarkerPresence == MarkerPresence.PresentButOutOfSync ||
                            packetMarkerPresence == MarkerPresence.PresentButOutOfSync)
                        {
                            break;
                        }

                        _parent.App.SpuriousCharacters(_messageRaw.Header, 0, 1);

                        Array.Copy(_messageRaw.Header, 1, _messageRaw.Header, 0, --_rawPos);
                    }

                    break;

                case ReceiveState.ReadingHeader:
                    count = _messageRaw.Header.Length - _rawPos;

                    // check timeout
                    if (_messageEventTimeout == DateTime.MinValue)
                    {
                        _messageEventTimeout = DateTime.UtcNow.AddSeconds(5);
                    }
                    else
                    {
                        if (DateTime.UtcNow > _messageEventTimeout)
                        {
                            // quit receiving this packet, abort
                            _state = ReceiveState.Initialize;

                            DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                            Debug.WriteLine("*** TIMEOUT ERROR waiting for header. Initializing.");

                            break;
                        }
                    }

                    bytesRead = _parent.ReadBuffer(_messageRaw.Header, _rawPos, count);

                    _rawPos += bytesRead;

                    // activity check
                    if (bytesRead > 0)
                    {
                        _parent.LastActivity = DateTime.UtcNow;
                    }

                    if (bytesRead != count)
                    {
                        break;
                    }

                    _state = ReceiveState.CompleteHeader;

                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                    goto case ReceiveState.CompleteHeader;

                case ReceiveState.CompleteHeader:
                    try
                    {
                        _parent.CreateConverter().Deserialize(_messageBase.Header, _messageRaw.Header);

                        var request = ((Engine)(_parent.App)).FindRequest(_messageBase.Header);

                        DebuggerEventSource.Log.WireProtocolRxHeader(
                            _messageBase.Header.CrcHeader,
                            _messageBase.Header.CrcData,
                            _messageBase.Header.Cmd,
                            _messageBase.Header.Flags,
                            _messageBase.Header.Seq,
                            _messageBase.Header.SeqReply,
                            _messageBase.Header.Size,
                            request != null ? request.RequestTimestamp : DateTime.MinValue);



                        if (VerifyHeader())
                        {
                            if (_messageBase.Header.Size != 0)
                            {
                                // sanity check for wrong size (can happen with CRC32 turned off)
                                if (_messageBase.Header.Size > 2048)
                                {
                                    Debug.WriteLine("Invalid payload requested. Initializing.");

                                    _state = ReceiveState.Initialize;

                                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                                    break;
                                }

                                // setup buffer to read payload
                                _messageRaw.Payload = new byte[_messageBase.Header.Size];

                                // reset timeout
                                _messageEventTimeout = DateTime.MinValue;

                                //reuse _rawPos for position in header for reading
                                _rawPos = 0;

                                _state = ReceiveState.ReadingPayload;

                                DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                                goto case ReceiveState.ReadingPayload;
                            }
                            else
                            {
                                _state = ReceiveState.CompletePayload;

                                DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                                goto case ReceiveState.CompletePayload;
                            }
                        }
                    }
                    catch (AggregateException)
                    {
                        throw;
                    }
                    catch (Exception e)
                    {
                        Debug.WriteLine("Fault at payload de-serialization:\n\n{0}", e.ToString());
                    }

                    _state = ReceiveState.Initialize;

                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                    if ((_messageBase.Header.Flags & Flags.c_NonCritical) == 0)
                    {
                        _parent.App.ReplyBadPacket(Flags.c_BadHeader);
                    }

                    break;

                case ReceiveState.ReadingPayload:
                    count = _messageRaw.Payload.Length - _rawPos;

                    // check timeout
                    if (_messageEventTimeout == DateTime.MinValue)
                    {
                        _messageEventTimeout = DateTime.UtcNow.AddMilliseconds(500);
                    }
                    else
                    {
                        if (DateTime.UtcNow > _messageEventTimeout)
                        {
                            Debug.WriteLine($"*** TIMEOUT ERROR waiting for payload. Missing {count}/{_messageRaw.Payload.Length}. Initializing.");

                            // quit receiving this packet, abort
                            _state = ReceiveState.Initialize;

                            DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                            break;
                        }
                    }

                    bytesRead = _parent.ReadBuffer(_messageRaw.Payload, _rawPos, count);

                    _rawPos += bytesRead;

                    // activity check
                    if (bytesRead > 0)
                    {
                        _parent.LastActivity = DateTime.UtcNow;
                    }

                    if (bytesRead != count)
                    {
                        break;
                    }

                    _state = ReceiveState.CompletePayload;

                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                    goto case ReceiveState.CompletePayload;

                case ReceiveState.CompletePayload:
                    if (VerifyPayload())
                    {
                        try
                        {
                            bool fReply = (_messageBase.Header.Flags & Flags.c_Reply) != 0;

                            if ((_messageBase.Header.Flags & Flags.c_NACK) != 0)
                            {
                                _messageRaw.Payload = null;
                            }

                            DebuggerEventSource.Log.OutputPayload(_messageRaw.Payload);

                            _parent.App.ProcessMessage(GetCompleteMessage(), fReply);

                            // setup restart
                            _state = ReceiveState.Initialize;

                            DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                            return;
                        }
                        catch (AggregateException)
                        {
                            throw;
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine($"Fault at payload de-serialization:\n\n{ex.Message}");
                        }
                    }

                    _state = ReceiveState.Initialize;

                    DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                    if ((_messageBase.Header.Flags & Flags.c_NonCritical) == 0)
                    {
                        _parent.App.ReplyBadPacket(Flags.c_BadPayload);
                    }

                    break;
                }
            }
            catch
            {
                _state = ReceiveState.Initialize;

                DebuggerEventSource.Log.WireProtocolReceiveState(_state);

                throw;
            }
        }