Skip to content

Commit e3f354b

Browse files
[low-power] enhance mCslFrameRequestAheadUs calculation for RCP
Implement `otPlatRadioGetBusLatency` API, add optional `bus-latency` argument to ot-daemon and `diag radiospinel buslatency`diagnostic commands. Add callback to notify that the bus latency has been updated and update frame request ahead from runtime, by recalculating the `mCslFrameRequestAheadUs` value. Changes allow setting a bus latency while starting a new session between host and RCP device. This way, one host can be connected to different devices and vice versa, ensuring that the latency will be added to `mCslFrameRequestAheadUs` calculations and CSL tx requests will not be sent too late. Signed-off-by: Maciej Baczmanski <maciej.baczmanski@nordicsemi.no>
1 parent b0790b3 commit e3f354b

12 files changed

+219
-15
lines changed

include/openthread/instance.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ extern "C" {
5353
* @note This number versions both OpenThread platform and user APIs.
5454
*
5555
*/
56-
#define OPENTHREAD_API_VERSION (428)
56+
#define OPENTHREAD_API_VERSION (429)
5757

5858
/**
5959
* @addtogroup api-instance

include/openthread/platform/radio.h

+19
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,17 @@ uint64_t otPlatRadioGetNow(otInstance *aInstance);
757757
*/
758758
uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance);
759759

760+
/**
761+
* Get the bus latency in microseconds between the host and the radio chip.
762+
*
763+
* @param[in] aInstance A pointer to an OpenThread instance.
764+
*
765+
* @returns The bus latency in microseconds between the host and the radio chip.
766+
* Return 0 when the MAC and above layer and Radio layer resides on the same chip.
767+
*
768+
*/
769+
uint32_t otPlatRadioGetBusLatency(otInstance *aInstance);
770+
760771
/**
761772
* @}
762773
*
@@ -1003,6 +1014,14 @@ otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint1
10031014
*/
10041015
extern void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi);
10051016

1017+
/**
1018+
* The radio driver calls this method to notify OpenThread that the spinel bus latency has been updated.
1019+
*
1020+
* @param[in] aInstance The OpenThread instance structure.
1021+
*
1022+
*/
1023+
extern void otPlatRadioBusLatencyUpdated(otInstance *aInstance);
1024+
10061025
/**
10071026
* Enable/Disable source address match feature.
10081027
*

src/core/radio/radio.hpp

+6
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,12 @@ class Radio : public InstanceLocator, private NonCopyable
229229
*/
230230
void HandleEnergyScanDone(int8_t aMaxRssi);
231231

232+
/**
233+
* This callback method handles "Bus Latency Updated" event from radio platform.
234+
*
235+
*/
236+
void HandleBusLatencyUpdated(void);
237+
232238
#if OPENTHREAD_CONFIG_DIAG_ENABLE
233239
/**
234240
* This callback method handles a "Receive Done" event from radio platform when diagnostics mode is enabled.

src/core/radio/radio_callbacks.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ void Radio::Callbacks::HandleTransmitDone(Mac::TxFrame &aFrame, Mac::RxFrame *aA
5858

5959
void Radio::Callbacks::HandleEnergyScanDone(int8_t aMaxRssi) { Get<Mac::SubMac>().HandleEnergyScanDone(aMaxRssi); }
6060

61+
void Radio::Callbacks::HandleBusLatencyUpdated(void)
62+
{
63+
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
64+
Get<CslTxScheduler>().UpdateFrameRequestAhead();
65+
#endif
66+
}
67+
6168
#if OPENTHREAD_CONFIG_DIAG_ENABLE
6269
void Radio::Callbacks::HandleDiagsReceiveDone(Mac::RxFrame *aFrame, Error aError)
6370
{

src/core/radio/radio_platform.cpp

+20
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyS
116116
return;
117117
}
118118

119+
extern "C" void otPlatRadioBusLatencyUpdated(otInstance *aInstance)
120+
{
121+
Instance &instance = AsCoreType(aInstance);
122+
123+
VerifyOrExit(instance.IsInitialized());
124+
instance.Get<Radio::Callbacks>().HandleBusLatencyUpdated();
125+
126+
exit:
127+
return;
128+
}
129+
119130
#if OPENTHREAD_CONFIG_DIAG_ENABLE
120131
extern "C" void otPlatDiagRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
121132
{
@@ -153,6 +164,8 @@ extern "C" void otPlatRadioTxDone(otInstance *, otRadioFrame *, otRadioFrame *,
153164

154165
extern "C" void otPlatRadioEnergyScanDone(otInstance *, int8_t) {}
155166

167+
extern "C" void otPlatRadioBusLatencyUpdated(otInstance *) {}
168+
156169
#if OPENTHREAD_CONFIG_DIAG_ENABLE
157170
extern "C" void otPlatDiagRadioReceiveDone(otInstance *, otRadioFrame *, otError) {}
158171

@@ -250,6 +263,13 @@ OT_TOOL_WEAK uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
250263
return 0;
251264
}
252265

266+
OT_TOOL_WEAK uint32_t otPlatRadioGetBusLatency(otInstance *aInstance)
267+
{
268+
OT_UNUSED_VARIABLE(aInstance);
269+
270+
return 0;
271+
}
272+
253273
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
254274
OT_TOOL_WEAK otError otPlatRadioResetCsl(otInstance *aInstance)
255275
{

src/core/thread/csl_tx_scheduler.cpp

+8-3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#include "common/locator_getters.hpp"
3434
#include "common/log.hpp"
35+
#include "common/num_utils.hpp"
3536
#include "common/time.hpp"
3637
#include "mac/mac.hpp"
3738

@@ -68,16 +69,20 @@ CslTxScheduler::CslTxScheduler(Instance &aInstance)
6869
, mFrameContext()
6970
, mCallbacks(aInstance)
7071
{
71-
InitFrameRequestAhead();
72+
UpdateFrameRequestAhead();
7273
}
7374

74-
void CslTxScheduler::InitFrameRequestAhead(void)
75+
void CslTxScheduler::UpdateFrameRequestAhead(void)
7576
{
7677
uint32_t busSpeedHz = otPlatRadioGetBusSpeed(&GetInstance());
78+
uint32_t busLatency = otPlatRadioGetBusLatency(&GetInstance());
79+
7780
// longest frame on bus is 127 bytes with some metadata, use 150 bytes for bus Tx time estimation
7881
uint32_t busTxTimeUs = ((busSpeedHz == 0) ? 0 : (150 * 8 * 1000000 + busSpeedHz - 1) / busSpeedHz);
7982

80-
mCslFrameRequestAheadUs = OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US + busTxTimeUs;
83+
mCslFrameRequestAheadUs = OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US + busTxTimeUs + busLatency;
84+
LogInfo("Bus TX Time: %lu usec, Latency: %lu usec. Calculated CSL Frame Request Ahead: %lu usec",
85+
ToUlong(busTxTimeUs), ToUlong(busLatency), ToUlong(mCslFrameRequestAheadUs));
8186
}
8287

8388
void CslTxScheduler::Update(void)

src/core/thread/csl_tx_scheduler.hpp

+7-1
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,17 @@ class CslTxScheduler : public InstanceLocator, private NonCopyable
231231
*/
232232
void Clear(void);
233233

234+
/**
235+
* Updates the value of `mCslFrameRequestAheadUs`, based on bus speed, bus latency
236+
* and `OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US`.
237+
*
238+
*/
239+
void UpdateFrameRequestAhead(void);
240+
234241
private:
235242
// Guard time in usec to add when checking delay while preparing the CSL frame for tx.
236243
static constexpr uint32_t kFramePreparationGuardInterval = 1500;
237244

238-
void InitFrameRequestAhead(void);
239245
void RescheduleCslTx(void);
240246

241247
uint32_t GetNextCslTransmissionDelay(const Child &aChild, uint32_t &aDelayFromLastRx, uint32_t aAheadUs) const;
+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# OpenThread Diagnostics - Radio Spinel diagnostic commands
2+
3+
This module provides Spinel based radio transceiver diagnostic commands.
4+
5+
`OPENTHREAD_CONFIG_DIAG_ENABLE` is required.
6+
7+
## Command List
8+
9+
- [buslatency](#buslatency)
10+
11+
## Command Details
12+
13+
### buslatency
14+
15+
Get the bus latency in microseconds between the host and the radio chip.
16+
17+
```bash
18+
> diag radiospinel buslatency
19+
0
20+
Done
21+
```
22+
23+
#### buslatency \<buslatency\>
24+
25+
Set the bus latency in microseconds between the host and the radio chip.
26+
27+
```bash
28+
> diag radiospinel buslatency 1000
29+
Done
30+
```

src/lib/spinel/radio_spinel.cpp

+48
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ RadioSpinel::RadioSpinel(void)
7979
, mPanId(0xffff)
8080
, mChannel(0)
8181
, mRxSensitivity(0)
82+
, mBusLatency(0)
8283
, mState(kStateDisabled)
8384
, mIsPromiscuous(false)
8485
, mRxOnWhenIdle(true)
@@ -1775,6 +1776,41 @@ void RadioSpinel::GetDiagOutputCallback(otPlatDiagOutputCallback &aCallback, voi
17751776
aContext = mOutputContext;
17761777
}
17771778

1779+
otError RadioSpinel::RadioSpinelDiagProcess(char *aArgs[], uint8_t aArgsLength)
1780+
{
1781+
otError error = OT_ERROR_NONE;
1782+
1783+
VerifyOrExit(aArgsLength > 1, error = OT_ERROR_INVALID_ARGS);
1784+
1785+
aArgs++;
1786+
aArgsLength--;
1787+
1788+
if (strcmp(aArgs[0], "buslatency") == 0)
1789+
{
1790+
if (aArgsLength == 1)
1791+
{
1792+
PlatDiagOutput("%lu\n", ToUlong(GetBusLatency()));
1793+
}
1794+
else if (aArgsLength == 2)
1795+
{
1796+
uint32_t busLatency;
1797+
char *endptr;
1798+
1799+
busLatency = static_cast<uint32_t>(strtoul(aArgs[1], &endptr, 0));
1800+
VerifyOrExit(*endptr == '\0', error = OT_ERROR_INVALID_ARGS);
1801+
1802+
SetBusLatency(busLatency);
1803+
}
1804+
else
1805+
{
1806+
error = OT_ERROR_INVALID_ARGS;
1807+
}
1808+
}
1809+
1810+
exit:
1811+
return error;
1812+
}
1813+
17781814
otError RadioSpinel::PlatDiagProcess(const char *aString)
17791815
{
17801816
return Set(SPINEL_PROP_NEST_STREAM_MFG, SPINEL_DATATYPE_UTF8_S, aString);
@@ -1904,6 +1940,18 @@ uint64_t RadioSpinel::GetNow(void) { return (mIsTimeSynced) ? (otPlatTimeGet() +
19041940

19051941
uint32_t RadioSpinel::GetBusSpeed(void) const { return GetSpinelDriver().GetSpinelInterface()->GetBusSpeed(); }
19061942

1943+
uint32_t RadioSpinel::GetBusLatency(void) const { return mBusLatency; }
1944+
1945+
void RadioSpinel::SetBusLatency(uint32_t aBusLatency)
1946+
{
1947+
mBusLatency = aBusLatency;
1948+
1949+
if (IsEnabled() && mCallbacks.mBusLatencyUpdated != nullptr)
1950+
{
1951+
mCallbacks.mBusLatencyUpdated(mInstance);
1952+
}
1953+
}
1954+
19071955
void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus)
19081956
{
19091957
OT_UNUSED_VARIABLE(aStatus);

src/lib/spinel/radio_spinel.hpp

+37
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ struct RadioSpinelCallbacks
8787
*/
8888
void (*mEnergyScanDone)(otInstance *aInstance, int8_t aMaxRssi);
8989

90+
/**
91+
* This callback notifies user of `RadioSpinel` that the bus latency has been updated.
92+
*
93+
* @param[in] aInstance The OpenThread instance structure.
94+
*
95+
*/
96+
void (*mBusLatencyUpdated)(otInstance *aInstance);
97+
9098
/**
9199
* This callback notifies user of `RadioSpinel` that the transmission has started.
92100
*
@@ -680,6 +688,18 @@ class RadioSpinel : private Logger
680688
*/
681689
bool IsDiagEnabled(void) const { return mDiagMode; }
682690

691+
/**
692+
* Processes RadioSpinel - specific diagnostics commands.
693+
*
694+
* @param[in] aArgsLength The number of arguments in @p aArgs.
695+
* @param[in] aArgs The arguments of diagnostics command line.
696+
*
697+
* @retval OT_ERROR_NONE Succeeded.
698+
* @retval OT_ERROR_INVALID_ARGS Failed due to invalid arguments provided.
699+
*
700+
*/
701+
otError RadioSpinelDiagProcess(char *aArgs[], uint8_t aArgsLength);
702+
683703
/**
684704
* Processes platform diagnostics commands.
685705
*
@@ -857,6 +877,22 @@ class RadioSpinel : private Logger
857877
*/
858878
uint32_t GetBusSpeed(void) const;
859879

880+
/**
881+
* Returns the bus latency between the host and the radio.
882+
*
883+
* @returns Bus latency in microseconds.
884+
*
885+
*/
886+
uint32_t GetBusLatency(void) const;
887+
888+
/**
889+
* Sets the bus latency between the host and the radio.
890+
*
891+
* @param[in] aBusLatency Bus latency in microseconds.
892+
*
893+
*/
894+
void SetBusLatency(uint32_t aBusLatency);
895+
860896
/**
861897
* Returns the co-processor sw version string.
862898
*
@@ -1231,6 +1267,7 @@ class RadioSpinel : private Logger
12311267
otError mTxError;
12321268
static otExtAddress sIeeeEui64;
12331269
static otRadioCaps sRadioCaps;
1270+
uint32_t mBusLatency;
12341271

12351272
State mState;
12361273
bool mIsPromiscuous : 1; ///< Promiscuous mode.

0 commit comments

Comments
 (0)