Skip to content

Commit

Permalink
[low-power] enhance mCslFrameRequestAheadUs calculation for RCP
Browse files Browse the repository at this point in the history
Implement `otPlatRadioGetBusLatency` API, add optional
`bus-latency` argument to ot-daemon and `diag rcp buslatency`
diagnostic commands.

Add APIs 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>
  • Loading branch information
maciejbaczmanski committed Jul 15, 2024
1 parent 20c9bcb commit 90f79a5
Show file tree
Hide file tree
Showing 11 changed files with 172 additions and 14 deletions.
11 changes: 11 additions & 0 deletions include/openthread/platform/radio.h
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,17 @@ uint64_t otPlatRadioGetNow(otInstance *aInstance);
*/
uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance);

/**
* Get the bus latency in microseconds between the host and the radio chip.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @returns The bus latency in microseconds between the host and the radio chip.
* Return 0 when the MAC and above layer and Radio layer resides on the same chip.
*
*/
uint32_t otPlatRadioGetBusLatency(otInstance *aInstance);

/**
* @}
*
Expand Down
9 changes: 9 additions & 0 deletions include/openthread/thread_ftd.h
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,15 @@ void otThreadGetNextHopAndPathCost(otInstance *aInstance,
uint16_t *aNextHopRloc16,
uint8_t *aPathCost);

/**
* Calculates and updates value of CSL Frame Request Ahead, based on bus speed, bus latency and
* `OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US`.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
*/
void otThreadUpdateFrameRequestAhead(otInstance *aInstance);

/**
* @}
*
Expand Down
8 changes: 8 additions & 0 deletions src/core/api/thread_ftd_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -428,4 +428,12 @@ void otThreadGetNextHopAndPathCost(otInstance *aInstance,
(aPathCost != nullptr) ? *aPathCost : pathcost);
}

#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
void otThreadUpdateFrameRequestAhead(otInstance *aInstance)
{
AsCoreType(aInstance).Get<CslTxScheduler>().UpdateFrameRequestAhead();
}

#endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE

#endif // OPENTHREAD_FTD
20 changes: 20 additions & 0 deletions src/core/diags/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ The diagnostics module supports common diagnostics features that are listed belo
- [diag stats](#diag-stats)
- [diag gpio](#diag-gpio-get-gpio)
- [diag stop](#diag-stop)
- [diag rcp](#diag-rcp)

### diag

Expand Down Expand Up @@ -359,6 +360,25 @@ Stop RCP diagnostics mode.
Done
```

### diag rcp buslatency

Get the bus latency in microseconds between the host and the radio chip.

```bash
> rcp buslatency
0
Done
```

### diag rcp buslatency \<buslatency\>

Set the bus latency in microseconds between the host and the radio chip.

```bash
> rcp buslatency 1000
Done
```

#### diag rcp channel \<channel\>

Set the RCP IEEE 802.15.4 Channel value for diagnostics module.
Expand Down
7 changes: 7 additions & 0 deletions src/core/radio/radio_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@ OT_TOOL_WEAK uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
return 0;
}

OT_TOOL_WEAK uint32_t otPlatRadioGetBusLatency(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);

return 0;
}

#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE
OT_TOOL_WEAK otError otPlatRadioResetCsl(otInstance *aInstance)
{
Expand Down
11 changes: 8 additions & 3 deletions src/core/thread/csl_tx_scheduler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#include "common/locator_getters.hpp"
#include "common/log.hpp"
#include "common/num_utils.hpp"
#include "common/time.hpp"
#include "mac/mac.hpp"

Expand Down Expand Up @@ -68,16 +69,20 @@ CslTxScheduler::CslTxScheduler(Instance &aInstance)
, mFrameContext()
, mCallbacks(aInstance)
{
InitFrameRequestAhead();
UpdateFrameRequestAhead();
}

void CslTxScheduler::InitFrameRequestAhead(void)
void CslTxScheduler::UpdateFrameRequestAhead(void)
{
uint32_t busSpeedHz = otPlatRadioGetBusSpeed(&GetInstance());
uint32_t busLatency = otPlatRadioGetBusLatency(&GetInstance());

// longest frame on bus is 127 bytes with some metadata, use 150 bytes for bus Tx time estimation
uint32_t busTxTimeUs = ((busSpeedHz == 0) ? 0 : (150 * 8 * 1000000 + busSpeedHz - 1) / busSpeedHz);

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

void CslTxScheduler::Update(void)
Expand Down
8 changes: 7 additions & 1 deletion src/core/thread/csl_tx_scheduler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,11 +231,17 @@ class CslTxScheduler : public InstanceLocator, private NonCopyable
*/
void Clear(void);

/**
* Updates the value of `mCslFrameRequestAheadUs`, based on bus speed, bus latency
* and `OPENTHREAD_CONFIG_MAC_CSL_REQUEST_AHEAD_US`.
*
*/
void UpdateFrameRequestAhead(void);

private:
// Guard time in usec to add when checking delay while preparing 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, uint32_t aAheadUs) const;
Expand Down
56 changes: 56 additions & 0 deletions src/lib/spinel/radio_spinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <stdlib.h>

#include <openthread/logging.h>
#include <openthread/thread_ftd.h>
#include <openthread/platform/diag.h>
#include <openthread/platform/time.h>

Expand Down Expand Up @@ -79,6 +80,7 @@ RadioSpinel::RadioSpinel(void)
, mPanId(0xffff)
, mChannel(0)
, mRxSensitivity(0)
, mBusLatency(0)
, mState(kStateDisabled)
, mIsPromiscuous(false)
, mRxOnWhenIdle(true)
Expand Down Expand Up @@ -1775,6 +1777,47 @@ void RadioSpinel::GetDiagOutputCallback(otPlatDiagOutputCallback &aCallback, voi
aContext = mOutputContext;
}

otError RadioSpinel::PlatDiagProcess(uint8_t aArgsLength, char *aArgs[])
{
otError error = OT_ERROR_NONE;
char cmd[OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE] = {'\0'};
char *cur = cmd;
char *end = cmd + sizeof(cmd);

if (strcmp(aArgs[0], "rcp") == 0)
{
if (strcmp(aArgs[1], "buslatency") == 0)
{
if (aArgsLength == 2)
{
uint32_t latency;
char *endptr;

latency = static_cast<uint32_t>(strtoul(aArgs[2], &endptr, 0));
VerifyOrExit(*endptr == '\0', error = OT_ERROR_INVALID_ARGS);

SetBusLatency(latency);
ExitNow();
}
else
{
PlatDiagOutput("%lu\n", ToUlong(GetBusLatency()));
ExitNow();
}
}
}

for (uint8_t index = 0; (index < aArgsLength) && (cur < end); index++)
{
cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", aArgs[index]);
}

SuccessOrExit(error = PlatDiagProcess(cmd));

exit:
return error;
}

otError RadioSpinel::PlatDiagProcess(const char *aString)
{
return Set(SPINEL_PROP_NEST_STREAM_MFG, SPINEL_DATATYPE_UTF8_S, aString);
Expand Down Expand Up @@ -1904,6 +1947,19 @@ uint64_t RadioSpinel::GetNow(void) { return (mIsTimeSynced) ? (otPlatTimeGet() +

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

uint32_t RadioSpinel::GetBusLatency(void) const { return mBusLatency; }

void RadioSpinel::SetBusLatency(uint32_t aBusLatency)
{
mBusLatency = aBusLatency;
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
if (IsEnabled())
{
otThreadUpdateFrameRequestAhead(mInstance);
}
#endif // OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
}

void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus)
{
OT_UNUSED_VARIABLE(aStatus);
Expand Down
31 changes: 31 additions & 0 deletions src/lib/spinel/radio_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,20 @@ class RadioSpinel : private Logger
*/
bool IsDiagEnabled(void) const { return mDiagMode; }

/**
* Processes platform diagnostics commands.
*
* @param[in] aArgsLength The number of arguments in @p aArgs.
* @param[in] aArgs The arguments of diagnostics command line.
*
* @retval OT_ERROR_NONE Succeeded.
* @retval OT_ERROR_INVALID_ARGS Failed due to invalid arguments provided.
* @retval OT_ERROR_BUSY Failed due to another operation is on going.
* @retval OT_ERROR_RESPONSE_TIMEOUT Failed due to no response received from the transceiver.
*
*/
otError PlatDiagProcess(uint8_t aArgsLength, char *aArgs[]);

/**
* Processes platform diagnostics commands.
*
Expand Down Expand Up @@ -857,6 +871,22 @@ class RadioSpinel : private Logger
*/
uint32_t GetBusSpeed(void) const;

/**
* Returns the bus latency between the host and the radio.
*
* @returns Bus latency in microseconds.
*
*/
uint32_t GetBusLatency(void) const;

/**
* Sets the bus latency between the host and the radio.
*
* @param[in] aBusLatency Bus latency in microseconds.
*
*/
void SetBusLatency(uint32_t aBusLatency);

/**
* Returns the co-processor sw version string.
*
Expand Down Expand Up @@ -1231,6 +1261,7 @@ class RadioSpinel : private Logger
otError mTxError;
static otExtAddress sIeeeEui64;
static otRadioCaps sRadioCaps;
uint32_t mBusLatency;

State mState;
bool mIsPromiscuous : 1; ///< Promiscuous mode.
Expand Down
24 changes: 14 additions & 10 deletions src/posix/platform/radio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ void Radio::ProcessRadioUrl(const RadioUrl &aRadioUrl)
SuccessOrDie(otPlatRadioSetRegion(gInstance, regionCode));
}

if (aRadioUrl.HasParam("bus-latency"))
{
uint32_t busLatency;
SuccessOrDie(aRadioUrl.ParseUint32("bus-latency", busLatency));
mRadioSpinel.SetBusLatency(busLatency);
}

ProcessMaxPowerTable(aRadioUrl);

#if OPENTHREAD_CONFIG_PLATFORM_RADIO_COEX_ENABLE
Expand Down Expand Up @@ -548,11 +555,7 @@ void otPlatDiagSetOutputCallback(otInstance *aInstance, otPlatDiagOutputCallback

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

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

for (uint8_t index = 0; (index < aArgsLength) && (cur < end); index++)
{
cur += snprintf(cur, static_cast<size_t>(end - cur), "%s ", aArgs[index]);
}

return GetRadioSpinel().PlatDiagProcess(cmd);
return GetRadioSpinel().PlatDiagProcess(aArgsLength, aArgs);
}

void otPlatDiagModeSet(bool aMode)
Expand Down Expand Up @@ -900,6 +898,12 @@ uint32_t otPlatRadioGetBusSpeed(otInstance *aInstance)
return GetRadioSpinel().GetBusSpeed();
}

uint32_t otPlatRadioGetBusLatency(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
return GetRadioSpinel().GetBusLatency();
}

#if OPENTHREAD_CONFIG_MAC_CSL_RECEIVER_ENABLE || OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
uint8_t otPlatRadioGetCslAccuracy(otInstance *aInstance)
{
Expand Down
1 change: 1 addition & 0 deletions src/posix/platform/radio_url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ const char *otSysGetRadioUrlHelpString(void)
" fem-lnagain[=dbm] Set the Rx LNA gain in dBm of the external FEM.\n"
" no-reset Do not send Spinel reset command to RCP on initialization.\n"
" skip-rcp-compatibility-check Skip checking RCP API version and capabilities during initialization.\n"
" bus-latency[=usec] Communication latency in usec, default is 0.\n"
#if OPENTHREAD_CONFIG_MULTIPAN_RCP_ENABLE
" iid Set the Spinel Interface ID for this process. Valid values are 0-3.\n"
" iid-list List of IIDs a host can subscribe to receive spinel frames other than \n"
Expand Down

0 comments on commit 90f79a5

Please sign in to comment.