[openthread] Apply CSL frame patch

Apply the following patch to ToT.

https://github.com/openthread/openthread/pull/8464

Test: Host<->RCP communication is working.
Sherlock/Nelson manual verification `lowpanctl network-scan` and
`lowpanctl energy-scan`.

Bug: 117440

Change-Id: Ibb19ab4521b53e65a7149b871ef9338a859709e8
Reviewed-on: https://fuchsia-review.googlesource.com/c/third_party/openthread/+/776204
Reviewed-by: Robert Quattlebaum <rquattle@google.com>
(cherry picked from commit e67312647f10a5822aaa3b57e297b7f099cc55e4)
diff --git a/src/core/thread/csl_tx_scheduler.cpp b/src/core/thread/csl_tx_scheduler.cpp
index 15beb59..f2dfbd4 100644
--- a/src/core/thread/csl_tx_scheduler.cpp
+++ b/src/core/thread/csl_tx_scheduler.cpp
@@ -134,7 +134,7 @@
             continue;
         }
 
-        delay = GetNextCslTransmissionDelay(child, cslTxDelay);
+        delay = GetNextCslTransmissionDelay(child, cslTxDelay, mCslFrameRequestAheadUs);
 
         if (delay < minDelayTime)
         {
@@ -151,18 +151,23 @@
     mCslTxChild = bestChild;
 }
 
-uint32_t CslTxScheduler::GetNextCslTransmissionDelay(const Child &aChild, uint32_t &aDelayFromLastRx) const
+uint32_t CslTxScheduler::GetNextCslTransmissionDelay(const Child &aChild,
+                                                     uint32_t &   aDelayFromLastRx,
+                                                     uint32_t     aAheadUs) const
 {
     uint64_t radioNow      = otPlatRadioGetNow(&GetInstance());
     uint32_t periodInUs    = aChild.GetCslPeriod() * kUsPerTenSymbols;
     uint64_t firstTxWindow = aChild.GetLastRxTimestamp() + aChild.GetCslPhase() * kUsPerTenSymbols;
     uint64_t nextTxWindow  = radioNow - (radioNow % periodInUs) + (firstTxWindow % periodInUs);
 
-    while (nextTxWindow < radioNow + mCslFrameRequestAheadUs) nextTxWindow += periodInUs;
+    while (nextTxWindow < radioNow + aAheadUs)
+    {
+        nextTxWindow += periodInUs;
+    }
 
     aDelayFromLastRx = static_cast<uint32_t>(nextTxWindow - aChild.GetLastRxTimestamp());
 
-    return static_cast<uint32_t>(nextTxWindow - radioNow - mCslFrameRequestAheadUs);
+    return static_cast<uint32_t>(nextTxWindow - radioNow - aAheadUs);
 }
 
 #if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE
@@ -171,6 +176,7 @@
 {
     Mac::TxFrame *frame = nullptr;
     uint32_t      txDelay;
+    uint32_t      delay;
 
     VerifyOrExit(mCslTxChild != nullptr);
 
@@ -207,7 +213,25 @@
     frame->SetChannel(mCslTxChild->GetCslChannel() == 0 ? Get<Mac::Mac>().GetPanChannel()
                                                         : mCslTxChild->GetCslChannel());
 
-    GetNextCslTransmissionDelay(*mCslTxChild, txDelay);
+    delay = GetNextCslTransmissionDelay(*mCslTxChild, txDelay, /* aAheadUs */ 0);
+
+    // We make sure that delay is less than `mCslFrameRequestAheadUs`
+    // plus some guard time. Note that we used `mCslFrameRequestAheadUs`
+    // in `RescheduleCslTx()` when determining the next CSL delay to
+    // schedule CSL tx with `Mac` but here we calculate the delay with
+    // zero `aAheadUs`. All the timings are in usec but when passing
+    // delay to `Mac` we divide by `1000` (to covert to msec) which
+    // can round the value down and cause `Mac` to start operation a
+    // bit (some usec) earlier. This is covered by adding the guard
+    // time `kFramePreparationGuardInterval`.
+    //
+    // In general this check handles the case where `Mac` is busy with
+    // other operations and therefore late to start the CSL tx operation
+    // and by the time `HandleFrameRequest()` is invoked, we miss the
+    // current CSL window and move to the next window.
+
+    VerifyOrExit(delay <= mCslFrameRequestAheadUs + kFramePreparationGuardInterval, frame = nullptr);
+
     frame->SetTxDelay(txDelay);
     frame->SetTxDelayBaseTime(
         static_cast<uint32_t>(mCslTxChild->GetLastRxTimestamp())); // Only LSB part of the time is required.
diff --git a/src/core/thread/csl_tx_scheduler.hpp b/src/core/thread/csl_tx_scheduler.hpp
index d8e0368..708de8a 100644
--- a/src/core/thread/csl_tx_scheduler.hpp
+++ b/src/core/thread/csl_tx_scheduler.hpp
@@ -187,10 +187,13 @@
     void Clear(void);
 
 private:
+    // Guard time in usec to add when checking delay while preparaing the CSL frame for tx.
+    static constexpr uint32_t kFramePreparationGuardInterval = 1500;
+
     void InitFrameRequestAhead(void);
     void RescheduleCslTx(void);
 
-    uint32_t GetNextCslTransmissionDelay(const Child &aChild, uint32_t &aDelayFromLastRx) const;
+    uint32_t GetNextCslTransmissionDelay(const Child &aChild, uint32_t &aDelayFromLastRx, uint32_t aAheadUs) const;
 
     // Callbacks from `Mac`
     Mac::TxFrame *HandleFrameRequest(Mac::TxFrames &aTxFrames);