From af8ac0cdb37355aa4778f0bdb9ecca41dc7d6f68 Mon Sep 17 00:00:00 2001
From: "Peter A. Bigot" <pab@pabigot.com>
Date: Sat, 26 May 2018 10:06:16 -0500
Subject: [PATCH] components/serialization: fix state machine error in phy_hci
 tx

A failure mode with nrfutil 3.5.1 is that a transmission that is started
never gets an ACK, possibly because the receiver is blocked waiting for
a packet for a command that was received after the transmission started.
The command is blocked because there's only one transmission buffer, and
it's in use.  Observed behavior is that the transmission times out, but
the state doesn't handle the event after the first send so the FSM makes
no progress.

Ensure that timeouts and retransmissions are processed in both
WAIT_FOR_ACK and WAIT_FOR_ACK_OR_TX_END.  In the failure case this means
that the TX does eventually timeout, notifying the application of the
error so it can recover.  (The client has already failed because it
didn't get the command response it expected.)

See: https://devzone.nordicsemi.com/f/nordic-q-a/34791/ble-connectivity-state-machine-error
---
 .../common/transport/ser_phy/ser_phy_hci.c    | 39 ++++++++-----------
 1 file changed, 16 insertions(+), 23 deletions(-)

diff --git a/components/serialization/common/transport/ser_phy/ser_phy_hci.c b/components/serialization/common/transport/ser_phy/ser_phy_hci.c
index be678f7f4..5a28b69a9 100644
--- a/components/serialization/common/transport/ser_phy/ser_phy_hci.c
+++ b/components/serialization/common/transport/ser_phy/ser_phy_hci.c
@@ -981,25 +981,6 @@ static void hci_tx_fsm_event_process(hci_evt_t * p_event)
             break;
 
         case HCI_TX_STATE_WAIT_FOR_ACK_OR_TX_END:
-
-            if ((p_event->evt_source == HCI_SLIP_EVT) &&
-                (p_event->evt.ser_phy_slip_evt.evt_type == SER_PHY_HCI_SLIP_EVT_PKT_SENT))
-            {
-                hci_timeout_setup(1);
-                m_hci_tx_fsm_state = HCI_TX_STATE_WAIT_FOR_ACK;
-            }
-            else if ((p_event->evt_source == HCI_SLIP_EVT) &&
-                     (p_event->evt.ser_phy_slip_evt.evt_type == SER_PHY_HCI_SLIP_EVT_PKT_RECEIVED))
-            {
-                if (rx_ack_pkt_valid(p_event->evt.ser_phy_slip_evt.evt_params.received_pkt.p_buffer))
-                {
-                    hci_timeout_setup(0);
-                    m_hci_tx_fsm_state = HCI_TX_STATE_WAIT_FOR_TX_END;
-                }
-                hci_release_ack_buffer(p_event);
-            }
-            break;
-
         case HCI_TX_STATE_WAIT_FOR_ACK:
 
             if ((p_event->evt_source == HCI_SLIP_EVT) &&
@@ -1008,8 +989,15 @@ static void hci_tx_fsm_event_process(hci_evt_t * p_event)
                 if (rx_ack_pkt_valid(p_event->evt.ser_phy_slip_evt.evt_params.received_pkt.p_buffer))
                 {
                     hci_timeout_setup(0);
-                    hci_pkt_sent_upcall();
-                    m_hci_tx_fsm_state = HCI_TX_STATE_SEND;
+                    if (HCI_TX_STATE_WAIT_FOR_ACK_OR_TX_END == m_hci_tx_fsm_state)
+                    {
+                        m_hci_tx_fsm_state = HCI_TX_STATE_WAIT_FOR_TX_END;
+                    }
+                    else if (HCI_TX_STATE_WAIT_FOR_ACK == m_hci_tx_fsm_state)
+                    {
+                        hci_pkt_sent_upcall();
+                        m_hci_tx_fsm_state = HCI_TX_STATE_SEND;
+                    }
                 }
                 hci_release_ack_buffer(p_event);
             }
@@ -1029,6 +1017,13 @@ static void hci_tx_fsm_event_process(hci_evt_t * p_event)
                     m_hci_tx_fsm_state = HCI_TX_STATE_SEND;
                 }
             }
+            else if ((HCI_TX_STATE_WAIT_FOR_ACK == m_hci_tx_fsm_state) &&
+                (p_event->evt_source == HCI_SLIP_EVT) &&
+                (p_event->evt.ser_phy_slip_evt.evt_type == SER_PHY_HCI_SLIP_EVT_PKT_SENT))
+            {
+                hci_timeout_setup(1);
+                m_hci_tx_fsm_state = HCI_TX_STATE_WAIT_FOR_ACK;
+            }
             break;
 
         case HCI_TX_STATE_WAIT_FOR_TX_END:
@@ -1675,5 +1670,3 @@ void ser_phy_close(void)
     uint32_t err_code = hci_timer_close();
     ser_phy_hci_assert(err_code == NRF_SUCCESS);
 }
-
-
-- 
2.17.0

