Example #1
0
        /**
         * Acknowledge frames we've sent and removes the from the sent queue.
         * This method is called for each DATA or ACK frame where we have the 'ack' property.
         *
         * @param ackNum the last ack from the NCP
         */
        private void AckSentQueue(int ackNum)
        {
            // Handle the timer if it's running
            if (_sentTime.HasValue)
            {
                StopTimer();
                receiveTimeout = (int)((receiveTimeout * 7 / 8) + ((DateTime.Now - _sentTime.Value).TotalMilliseconds / 2));

                if (receiveTimeout < T_RX_ACK_MIN)
                {
                    receiveTimeout = T_RX_ACK_MIN;
                }
                else if (receiveTimeout > T_RX_ACK_MAX)
                {
                    receiveTimeout = T_RX_ACK_MAX;
                }

                Log.Verbose("ASH: RX Timer took {TimeSpent}ms, timer now {ReceiveTimeout}ms", (int)(DateTime.Now - _sentTime.Value).TotalMilliseconds, receiveTimeout);
                _sentTime = null;
            }

            AshFrameData ackedFrame = null;

            while (_sentQueue.TryPeek(out ackedFrame) && ackedFrame.GetFrmNum() != ackNum)
            {
                _sentQueue.TryDequeue(out ackedFrame);
                Log.Debug("ASH: Frame acked and removed {Frame}", ackedFrame);
            }
        }
Example #2
0
        private bool SendNextFrame()
        {
            // We're not allowed to send if we're not connected
            if (!_stateConnected)
            {
                return(false);
            }

            // Check how many frames are outstanding
            if (_sentQueue.Count >= TX_WINDOW)
            {
                // check timer task
                if (_timer == null)
                {
                    StartRetryTimer();
                }
                return(false);
            }

            EzspFrameRequest nextFrame = null;

            if (!_sendQueue.TryDequeue(out nextFrame) || nextFrame == null)
            {
                // Nothing to send
                return(false);
            }

            // Encapsulate the EZSP frame into the ASH packet
            Log.Verbose("TX ASH EZSP: {Frame}", nextFrame);
            AshFrameData ashFrame = new AshFrameData(nextFrame);

            _retries = 0;
            SendFrame(ashFrame);
            return(true);
        }
Example #3
0
        private void SendRetry()
        {
            Log.Debug("ASH: Retry Sent Queue Length {Count}", _sentQueue.Count);
            AshFrameData ashFrame = null;

            if (!_sentQueue.TryPeek(out ashFrame) || ashFrame == null)
            {
                Log.Debug("ASH: Retry nothing to resend!");
                return;
            }

            ashFrame.SetReTx();
            OutputFrame(ashFrame);
        }
Example #4
0
        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.");
        }