Skip to content

Commit dd4ff2b

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 API to update frame request ahead from runtime, which recalculate `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 dd4ff2b

File tree

11 files changed

+186
-14
lines changed

11 files changed

+186
-14
lines changed

include/openthread/platform/radio.h

+11
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
*

include/openthread/thread_ftd.h

+9
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,15 @@ void otThreadGetNextHopAndPathCost(otInstance *aInstance,
953953
uint16_t *aNextHopRloc16,
954954
uint8_t *aPathCost);
955955

956+
/**
957+
* Calculates and updates value of CSL Frame Request Ahead, based on bus speed, bus latency and
958+
* `OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US`.
959+
*
960+
* @param[in] aInstance A pointer to an OpenThread instance.
961+
*
962+
*/
963+
void otThreadUpdateFrameRequestAhead(otInstance *aInstance);
964+
956965
/**
957966
* @}
958967
*

src/core/api/thread_ftd_api.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -428,4 +428,12 @@ void otThreadGetNextHopAndPathCost(otInstance *aInstance,
428428
(aPathCost != nullptr) ? *aPathCost : pathcost);
429429
}
430430

431+
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
432+
void otThreadUpdateFrameRequestAhead(otInstance *aInstance)
433+
{
434+
AsCoreType(aInstance).Get<CslTxScheduler>().UpdateFrameRequestAhead();
435+
}
436+
437+
#endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
438+
431439
#endif // OPENTHREAD_FTD

src/core/diags/README.md

+24
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ The diagnostics module supports common diagnostics features that are listed belo
2020
- [diag stats](#diag-stats)
2121
- [diag gpio](#diag-gpio-get-gpio)
2222
- [diag stop](#diag-stop)
23+
- [diag radiospinel](#diag-radiospinel)
2324

2425
### diag
2526

@@ -337,6 +338,29 @@ stop diagnostics mode
337338
status 0x00
338339
```
339340

341+
### diag radiospinel
342+
343+
Spinel based radio transceiver diagnostics commands.
344+
345+
#### diag radiospinel buslatency
346+
347+
Get the bus latency in microseconds between the host and the radio chip.
348+
349+
```bash
350+
> radiospinel buslatency
351+
0
352+
Done
353+
```
354+
355+
#### diag radiospinel buslatency \<buslatency\>
356+
357+
Set the bus latency in microseconds between the host and the radio chip.
358+
359+
```bash
360+
> radiospinel buslatency 1000
361+
Done
362+
```
363+
340364
### diag rcp
341365

342366
RCP-related diagnostics commands. These commands are used for debugging and testing only.

src/core/radio/radio_platform.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,13 @@ OT_TOOL_WEAK uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
250250
return 0;
251251
}
252252

253+
OT_TOOL_WEAK uint32_t otPlatRadioGetBusLatency(otInstance *aInstance)
254+
{
255+
OT_UNUSED_VARIABLE(aInstance);
256+
257+
return 0;
258+
}
259+
253260
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
254261
OT_TOOL_WEAK otError otPlatRadioResetCsl(otInstance *aInstance)
255262
{

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;

src/lib/spinel/radio_spinel.cpp

+66
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include <stdlib.h>
4040

4141
#include <openthread/logging.h>
42+
#include <openthread/thread_ftd.h>
4243
#include <openthread/platform/diag.h>
4344
#include <openthread/platform/time.h>
4445

@@ -79,6 +80,7 @@ RadioSpinel::RadioSpinel(void)
7980
, mPanId(0xffff)
8081
, mChannel(0)
8182
, mRxSensitivity(0)
83+
, mBusLatency(0)
8284
, mState(kStateDisabled)
8385
, mIsPromiscuous(false)
8486
, mRxOnWhenIdle(true)
@@ -1775,6 +1777,57 @@ void RadioSpinel::GetDiagOutputCallback(otPlatDiagOutputCallback &aCallback, voi
17751777
aContext = mOutputContext;
17761778
}
17771779

1780+
otError RadioSpinel::PlatDiagProcess(uint8_t aArgsLength, char *aArgs[])
1781+
{
1782+
otError error = OT_ERROR_NONE;
1783+
char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'};
1784+
char *cur = cmd;
1785+
char *end = cmd + sizeof(cmd);
1786+
1787+
// RadioSpinel-specific diag sub-commands
1788+
if (strcmp(aArgs[0], "radiospinel") == 0)
1789+
{
1790+
aArgs++;
1791+
aArgsLength--;
1792+
1793+
VerifyOrExit(aArgsLength > 0, error = OT_ERROR_INVALID_ARGS);
1794+
1795+
if (strcmp(aArgs[0], "buslatency") == 0)
1796+
{
1797+
if (aArgsLength == 1)
1798+
{
1799+
PlatDiagOutput("%lu\n", ToUlong(GetBusLatency()));
1800+
}
1801+
else if (aArgsLength == 2)
1802+
{
1803+
uint32_t busLatency;
1804+
char *endptr;
1805+
1806+
busLatency = static_cast<uint32_t>(strtoul(aArgs[1], &endptr, 0));
1807+
VerifyOrExit(*endptr == '\0', error = OT_ERROR_INVALID_ARGS);
1808+
1809+
SetBusLatency(busLatency);
1810+
}
1811+
else
1812+
{
1813+
error = OT_ERROR_INVALID_ARGS;
1814+
}
1815+
}
1816+
1817+
ExitNow();
1818+
}
1819+
1820+
for (uint8_t index = 0; (index < aArgsLength) && (cur < end); index++)
1821+
{
1822+
cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", aArgs[index]);
1823+
}
1824+
1825+
SuccessOrExit(error = PlatDiagProcess(cmd));
1826+
1827+
exit:
1828+
return error;
1829+
}
1830+
17781831
otError RadioSpinel::PlatDiagProcess(const char *aString)
17791832
{
17801833
return Set(SPINEL_PROP_NEST_STREAM_MFG, SPINEL_DATATYPE_UTF8_S, aString);
@@ -1904,6 +1957,19 @@ uint64_t RadioSpinel::GetNow(void) { return (mIsTimeSynced) ? (otPlatTimeGet() +
19041957

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

1960+
uint32_t RadioSpinel::GetBusLatency(void) const { return mBusLatency; }
1961+
1962+
void RadioSpinel::SetBusLatency(uint32_t aBusLatency)
1963+
{
1964+
mBusLatency = aBusLatency;
1965+
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1966+
if (IsEnabled())
1967+
{
1968+
otThreadUpdateFrameRequestAhead(mInstance);
1969+
}
1970+
#endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
1971+
}
1972+
19071973
void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus)
19081974
{
19091975
OT_UNUSED_VARIABLE(aStatus);

src/lib/spinel/radio_spinel.hpp

+31
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,20 @@ class RadioSpinel : private Logger
680680
*/
681681
bool IsDiagEnabled(void) const { return mDiagMode; }
682682

683+
/**
684+
* Processes platform diagnostics commands.
685+
*
686+
* @param[in] aArgsLength The number of arguments in @p aArgs.
687+
* @param[in] aArgs The arguments of diagnostics command line.
688+
*
689+
* @retval OT_ERROR_NONE Succeeded.
690+
* @retval OT_ERROR_INVALID_ARGS Failed due to invalid arguments provided.
691+
* @retval OT_ERROR_BUSY Failed due to another operation is on going.
692+
* @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver.
693+
*
694+
*/
695+
otError PlatDiagProcess(uint8_t aArgsLength, char *aArgs[]);
696+
683697
/**
684698
* Processes platform diagnostics commands.
685699
*
@@ -857,6 +871,22 @@ class RadioSpinel : private Logger
857871
*/
858872
uint32_t GetBusSpeed(void) const;
859873

874+
/**
875+
* Returns the bus latency between the host and the radio.
876+
*
877+
* @returns Bus latency in microseconds.
878+
*
879+
*/
880+
uint32_t GetBusLatency(void) const;
881+
882+
/**
883+
* Sets the bus latency between the host and the radio.
884+
*
885+
* @param[in] aBusLatency Bus latency in microseconds.
886+
*
887+
*/
888+
void SetBusLatency(uint32_t aBusLatency);
889+
860890
/**
861891
* Returns the co-processor sw version string.
862892
*
@@ -1231,6 +1261,7 @@ class RadioSpinel : private Logger
12311261
otError mTxError;
12321262
static otExtAddress sIeeeEui64;
12331263
static otRadioCaps sRadioCaps;
1264+
uint32_t mBusLatency;
12341265

12351266
State mState;
12361267
bool mIsPromiscuous : 1; ///< Promiscuous mode.

src/posix/platform/radio.cpp

+14-10
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ void Radio::ProcessRadioUrl(const RadioUrl &aRadioUrl)
130130
SuccessOrDie(otPlatRadioSetRegion(gInstance, regionCode));
131131
}
132132

133+
if (aRadioUrl.HasParam("bus-latency"))
134+
{
135+
uint32_t busLatency;
136+
SuccessOrDie(aRadioUrl.ParseUint32("bus-latency", busLatency));
137+
mRadioSpinel.SetBusLatency(busLatency);
138+
}
139+
133140
ProcessMaxPowerTable(aRadioUrl);
134141

135142
#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
@@ -548,11 +555,7 @@ void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback
548555

549556
otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArgs[])
550557
{
551-
// deliver the platform specific diags commands to radio only ncp.
552558
OT_UNUSED_VARIABLE(aInstance);
553-
char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'};
554-
char *cur = cmd;
555-
char *end = cmd + sizeof(cmd);
556559

557560
#if OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
558561
if (strcmp(aArgs[0], "rcpcaps") == 0)
@@ -561,12 +564,7 @@ otError otPlatDiagProcess(otInstance *aInstance, uint8_t aArgsLength, char *aArg
561564
}
562565
#endif
563566

564-
for (uint8_t index = 0; (index < aArgsLength) && (cur < end); index++)
565-
{
566-
cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", aArgs[index]);
567-
}
568-
569-
return GetRadioSpinel().PlatDiagProcess(cmd);
567+
return GetRadioSpinel().PlatDiagProcess(aArgsLength, aArgs);
570568
}
571569

572570
void otPlatDiagModeSet(bool aMode)
@@ -900,6 +898,12 @@ uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
900898
return GetRadioSpinel().GetBusSpeed();
901899
}
902900

901+
uint32_t otPlatRadioGetBusLatency(otInstance *aInstance)
902+
{
903+
OT_UNUSED_VARIABLE(aInstance);
904+
return GetRadioSpinel().GetBusLatency();
905+
}
906+
903907
#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
904908
uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
905909
{

src/posix/platform/radio_url.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ const char *otSysGetRadioUrlHelpString(void)
121121
" fem-lnagain[=dbm] Set the Rx LNA gain in dBm of the external FEM.\n"
122122
" no-reset Do not send Spinel reset command to RCP on initialization.\n"
123123
" skip-rcp-compatibility-check Skip checking RCP API version and capabilities during initialization.\n"
124+
" bus-latency[=usec] Communication latency in usec, default is 0.\n"
124125
#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
125126
" iid Set the Spinel Interface ID for this process. Valid values are 0-3.\n"
126127
" iid-list List of IIDs a host can subscribe to receive spinel frames other than \n"

0 commit comments

Comments
 (0)