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); }
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); }
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); }
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); } }
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; }
/// <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; } }
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; } }