You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2026/10/19 21:49:15 UTC

(nuttx) 15/17: arch/arm/nrf52: do not start a transmission during the ACK TX

This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit 67b7fb00c560a51acb1ce8368769544ded1422be
Author: raiden00pl <ra...@railab.me>
AuthorDate: Mon Oct 19 11:28:38 2026 +0200

    arch/arm/nrf52: do not start a transmission during the ACK TX
    
    The ACK of a received frame is sent from the interrupt handler. A CSMA
    transaction polled from the MAC, or a no CSMA transaction that waited
    for the CSMA transaction, could be set up and triggered while that ACK
    was on air: norm_setup() overwrote the radio state and a zero backoff
    restarted the radio. The sender then received an empty frame with a CRC
    error instead of the ACK and retransmitted, and the replies to
    fragmented 6LoWPAN datagrams were lost in 15 to 28% of the cases.
    Start such a transaction when the ACK TX is done, as txdelayed() does.
    
    Assisted-by: Claude Code
    Signed-off-by: raiden00pl <ra...@railab.me>
---
 arch/arm/src/nrf52/nrf52_ieee802154_priv.h  |  1 +
 arch/arm/src/nrf52/nrf52_ieee802154_radio.c | 49 +++++++++++++++++++++++++----
 2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_priv.h b/arch/arm/src/nrf52/nrf52_ieee802154_priv.h
index b61fc59760f..9aadc2598a9 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_priv.h
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_priv.h
@@ -97,6 +97,7 @@ struct nrf52_radioi8_state_s
 
   bool     txdelayed_busy;      /* No CSMA transfer */
   bool     txdelayed_pending;   /* No CSMA transfer waits for CSMA */
+  bool     csma_pending;        /* CSMA transfer waits for ACK TX */
   uint32_t txdelayed_delay;     /* Delay of the pending no CSMA transfer */
 
 #ifdef CONFIG_NRF52_RADIO_IEEE802154_SUPERFRAME
diff --git a/arch/arm/src/nrf52/nrf52_ieee802154_radio.c b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
index 183ee1d0df5..7412065b4a8 100644
--- a/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
+++ b/arch/arm/src/nrf52/nrf52_ieee802154_radio.c
@@ -1290,13 +1290,25 @@ static void nrf52_radioi8_rxrestore(struct nrf52_radioi8_dev_s *dev)
 
 static void nrf52_radioi8_txpending(struct nrf52_radioi8_dev_s *dev)
 {
+  irqstate_t flags;
+
   /* Start the no CSMA transaction that waited for the CSMA transaction */
 
   if (dev->state.txdelayed_pending)
     {
+      flags = enter_critical_section();
+
       dev->state.txdelayed_pending = false;
       dev->state.txdelayed_busy    = true;
 
+      /* An ACK TX in progress starts it when done */
+
+      if (dev->radio->state.state == NRF52_RADIO_STATE_ACKTX)
+        {
+          leave_critical_section(flags);
+          return;
+        }
+
       nrf52_radioi8_norm_setup(dev, dev->state.txdelayed_desc->frame,
                                false);
 
@@ -1309,12 +1321,15 @@ static void nrf52_radioi8_txpending(struct nrf52_radioi8_dev_s *dev)
           dev->tim->ops->setup(dev, NRF52_TIMER_CHAN_TXDELAY,
                                dev->state.txdelayed_delay);
         }
+
+      leave_critical_section(flags);
     }
 }
 
 void nrf52_radioi8_dopoll_csma(void *arg)
 {
   struct nrf52_radioi8_dev_s *dev = (struct nrf52_radioi8_dev_s *)arg;
+  irqstate_t                  flags;
   int                         len = 0;
 
   /* Get exclusive access to the driver */
@@ -1325,8 +1340,8 @@ void nrf52_radioi8_dopoll_csma(void *arg)
 
   /* If this a CSMA transaction and we have room in the CSMA */
 
-  if (!dev->radio->state.csma_busy && !dev->state.txdelayed_busy &&
-      !dev->state.txdelayed_pending)
+  if (!dev->radio->state.csma_busy && !dev->state.csma_pending &&
+      !dev->state.txdelayed_busy && !dev->state.txdelayed_pending)
     {
       wlinfo("Polling for frame\n");
       len = dev->radiocb->poll(dev->radiocb, false, &dev->state.csma_desc);
@@ -1335,11 +1350,24 @@ void nrf52_radioi8_dopoll_csma(void *arg)
         {
           wlinfo("Frame received. Frame length: %d\n", len);
 
-          /* Setup the CSMA transaction */
+          flags = enter_critical_section();
+
+          /* An ACK TX in progress starts the transaction when done */
+
+          if (dev->radio->state.state == NRF52_RADIO_STATE_ACKTX)
+            {
+              dev->state.csma_pending = true;
+            }
+          else
+            {
+              /* Setup the CSMA transaction */
+
+              dev->radio->ops->norm_setup(dev, dev->state.csma_desc->frame,
+                                          true);
+              dev->radio->ops->norm_trigger(dev);
+            }
 
-          dev->radio->ops->norm_setup(dev, dev->state.csma_desc->frame,
-                                      true);
-          dev->radio->ops->norm_trigger(dev);
+          leave_critical_section(flags);
         }
     }
 
@@ -2078,6 +2106,15 @@ static void nrf52_radioi8_state_acktx(struct nrf52_radioi8_dev_s *dev)
         }
     }
 
+  /* Start the CSMA transaction that waited for the ACK TX */
+
+  else if (dev->state.csma_pending)
+    {
+      dev->state.csma_pending = false;
+      nrf52_radioi8_norm_setup(dev, dev->state.csma_desc->frame, true);
+      nrf52_radioi8_norm_trigger(dev);
+    }
+
   /* Restore RX */
 
   else if (dev->radio->state.rxrestore)