private void SendFrame(AshFrame ashFrame) { switch (ashFrame.GetFrameType()) { case AshFrame.FrameType.ACK: _statsTxAcks++; break; case AshFrame.FrameType.DATA: _statsTxData++; // Set the frame number ((AshFrameData)ashFrame).SetFrmNum(_frmNum); _frmNum = (_frmNum + 1) & 0x07; // DATA frames need to go into a sent queue so we can retry if needed _sentQueue.Enqueue((AshFrameData)ashFrame); break; case AshFrame.FrameType.NAK: _statsTxNaks++; break; default: break; } OutputFrame(ashFrame); }
private void OutputFrame(AshFrame ashFrame) { ashFrame.SetAckNum(_ackNum); Log.Debug("--> TX ASH frame: {Frame}", ashFrame); // Send the data int[] data = ashFrame.GetOutputBuffer(); byte[] bytes = new byte[data.Length]; for (int i = 0; i < data.Length; i++) { bytes[i] = (byte)data[i]; } _port.Write(bytes); // Only start the timer for data and reset frames if (ashFrame is AshFrameData || ashFrame is AshFrameRst) { _sentTime = DateTime.Now; StartRetryTimer(); } }
private void ParserTaskLoop() { Log.Debug("AshFrameHandler parser task started"); int exceptionCnt = 0; while (!_parserCancellationToken.IsCancellationRequested) { try { int[] packetData = GetPacket(); if (packetData == null) { continue; } AshFrame packet = AshFrame.CreateFromInput(packetData); AshFrame responseFrame = null; if (packet == null) { Log.Debug("<-- RX ASH error: BAD PACKET {Frame}", FrameToString(packetData)); // Send a NAK responseFrame = new AshFrameNak(_ackNum); } else { Log.Debug("<-- RX ASH frame: {Frame}", packet.ToString()); // Reset the exception counter exceptionCnt = 0; // Extract the flags for DATA/ACK/NAK frames switch (packet.GetFrameType()) { case AshFrame.FrameType.DATA: _statsRxData++; // Always use the ackNum - even if this frame is discarded AckSentQueue(packet.GetAckNum()); AshFrameData dataPacket = (AshFrameData)packet; // Check for out of sequence frame number if (packet.GetFrmNum() == _ackNum) { // Frame was in sequence - prepare the response _ackNum = (_ackNum + 1) & 0x07; responseFrame = new AshFrameAck(_ackNum); // Get the EZSP frame EzspFrameResponse response = EzspFrame.CreateHandler(dataPacket.GetDataBuffer()); Log.Verbose("ASH RX EZSP: {Response}", response); if (response == null) { Log.Debug("ASH: No frame handler created for {Packet}", packet); } else { NotifyTransactionComplete(response); HandleIncomingFrame(response); } } else if (!dataPacket.GetReTx()) { // Send a NAK - this is out of sequence and not a retransmission Log.Debug("ASH: Frame out of sequence - expected {Expected}, received {Received}", _ackNum, packet.GetFrmNum()); responseFrame = new AshFrameNak(_ackNum); } else { // Send an ACK - this was out of sequence but was a retransmission responseFrame = new AshFrameAck(_ackNum); } break; case AshFrame.FrameType.ACK: _statsRxAcks++; AckSentQueue(packet.GetAckNum()); break; case AshFrame.FrameType.NAK: _statsRxNaks++; SendRetry(); break; case AshFrame.FrameType.RSTACK: // Stack has been reset! HandleReset((AshFrameRstAck)packet); break; case AshFrame.FrameType.ERROR: // Stack has entered FAILED state HandleError((AshFrameError)packet); break; default: break; } } // Due to possible I/O buffering, it is important to note that the Host could receive several // valid or invalid frames after triggering a reset of the NCP. The Host must discard all frames // and errors until a valid RSTACK frame is received. if (!_stateConnected) { continue; } // Send the next frame // Note that ASH protocol requires the host always sends an ack. // Piggybacking on data packets is not allowed if (responseFrame != null) { SendFrame(responseFrame); } SendNextFrame(); } catch (Exception e) { Log.Error(e, "AshFrameHandler Exception: ", e); if (exceptionCnt++ > 10) { Log.Error("AshFrameHandler exception count exceeded: {Exception}"); _parserCancellationToken.Cancel(); } } } Log.Debug("AshFrameHandler exited."); }