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` and `otPlatRadioSetBusLatency`
APIs, add optional latency arguments to ot-daemon and `rcp latency`
CLI 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 <[email protected]>
  • Loading branch information
maciejbaczmanski committed Jul 13, 2024
1 parent 78ecafb commit 631527a
Show file tree
Hide file tree
Showing 13 changed files with 173 additions and 16 deletions.
2 changes: 1 addition & 1 deletion include/openthread/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (427)
#define OPENTHREAD_API_VERSION (428)

/**
* @addtogroup api-instance
Expand Down
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
19 changes: 19 additions & 0 deletions src/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3218,6 +3218,25 @@ OPENTHREAD/20191113-00825-g82053cc9d-dirty; SIMULATION; Jun 4 2020 17:53:16
Done
```
### rcp latency
Get the bus latency in microseconds between the host and the radio chip.
```bash
> rcp latency
0
Done
```
### rcp latency \<latency\>
Set the bus latency in microseconds between the host and the radio chip.
```bash
> rcp latency 1000
Done
```
### releaserouterid \<routerid\>
Release a Router ID that has been allocated by the device in the Leader role.
Expand Down
1 change: 0 additions & 1 deletion src/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5928,7 +5928,6 @@ template <> otError Interpreter::Process<Cmd("rcp")>(Arg aArgs[])
{
OutputLine("%s", version);
}

else
{
error = OT_ERROR_INVALID_ARGS;
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
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
54 changes: 54 additions & 0 deletions src/lib/spinel/radio_spinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
#include <openthread/logging.h>
#include <openthread/platform/diag.h>
#include <openthread/platform/time.h>
#include <openthread/thread_ftd.h>

#include "core/utils/parse_cmdline.hpp"
#include "lib/platform/exit_code.h"
#include "lib/spinel/logger.hpp"
#include "lib/spinel/spinel_decoder.hpp"
Expand Down Expand Up @@ -78,6 +80,7 @@ RadioSpinel::RadioSpinel(void)
, mPanId(0xffff)
, mChannel(0)
, mRxSensitivity(0)
, mBusLatency(0)
, mState(kStateDisabled)
, mIsPromiscuous(false)
, mRxOnWhenIdle(true)
Expand Down Expand Up @@ -1774,6 +1777,44 @@ 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], "buslatency") == 0)
{
if (aArgsLength == 2)
{
uint32_t latency;
char *endptr;
latency = (uint32_t)strtoul(aArgs[1], &endptr, 0);

VerifyOrExit(*endptr == '\0', error = OT_ERROR_INVALID_ARGS);
SetBusLatency(latency);
ExitNow();
}
else
{
uint32_t latency = GetBusLatency();
PlatDiagOutput("%lu\n", ToUlong(latency));
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 @@ -1903,6 +1944,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
33 changes: 33 additions & 0 deletions src/lib/spinel/radio_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,6 +680,18 @@ class RadioSpinel : private Logger
*/
bool IsDiagEnabled(void) const { return mDiagMode; }

/**
* Processes platform diagnostics commands.
*
* @param[in] aString A null-terminated input string.
*
* @retval OT_ERROR_NONE Succeeded.
* @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 +869,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 @@ -1254,6 +1282,8 @@ class RadioSpinel : private Logger
static otExtAddress sIeeeEui64;
static otRadioCaps sRadioCaps;

uint32_t mBusLatency;

State mState;
bool mIsPromiscuous : 1; ///< Promiscuous mode.
bool mRxOnWhenIdle : 1; ///< RxOnWhenIdle mode.
Expand Down Expand Up @@ -1307,6 +1337,9 @@ class RadioSpinel : private Logger
#endif // OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0

#if OPENTHREAD_CONFIG_DIAG_ENABLE
static constexpr uint16_t kMaxCommandBuffer = OPENTHREAD_CONFIG_DIAG_CMD_LINE_BUFFER_SIZE;
static constexpr uint8_t kMaxArgs = OPENTHREAD_CONFIG_DIAG_CMD_LINE_ARGS_MAX;

bool mDiagMode;
otPlatDiagOutputCallback mOutputCallback;
void *mOutputContext;
Expand Down
25 changes: 15 additions & 10 deletions src/posix/platform/radio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include <string.h>

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

#include "common/code_utils.hpp"
Expand Down Expand Up @@ -130,6 +131,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 +556,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 +565,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 +899,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 631527a

Please sign in to comment.