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 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>
  • Loading branch information
maciejbaczmanski committed Jul 18, 2024
1 parent b0790b3 commit 1ceed7d
Show file tree
Hide file tree
Showing 12 changed files with 219 additions and 15 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 (428)
#define OPENTHREAD_API_VERSION (429)

/**
* @addtogroup api-instance
Expand Down
19 changes: 19 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 Expand Up @@ -1003,6 +1014,14 @@ otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint1
*/
extern void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi);

/**
* The radio driver calls this method to notify OpenThread that the spinel bus latency has been changed.
*
* @param[in] aInstance The OpenThread instance structure.
*
*/
extern void otPlatRadioBusLatencyChanged(otInstance *aInstance);

/**
* Enable/Disable source address match feature.
*
Expand Down
6 changes: 6 additions & 0 deletions src/core/radio/radio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,12 @@ class Radio : public InstanceLocator, private NonCopyable
*/
void HandleEnergyScanDone(int8_t aMaxRssi);

/**
* This callback method handles "Bus Latency Changed" event from radio platform.
*
*/
void HandleBusLatencyChanged(void);

#if OPENTHREAD_CONFIG_DIAG_ENABLE
/**
* This callback method handles a "Receive Done" event from radio platform when diagnostics mode is enabled.
Expand Down
7 changes: 7 additions & 0 deletions src/core/radio/radio_callbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ void Radio::Callbacks::HandleTransmitDone(Mac::TxFrame &aFrame, Mac::RxFrame *aA

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

void Radio::Callbacks::HandleBusLatencyChanged(void)
{
#if OPENTHREAD_FTD && OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
Get<CslTxScheduler>().UpdateFrameRequestAhead();
#endif
}

#if OPENTHREAD_CONFIG_DIAG_ENABLE
void Radio::Callbacks::HandleDiagsReceiveDone(Mac::RxFrame *aFrame, Error aError)
{
Expand Down
20 changes: 20 additions & 0 deletions src/core/radio/radio_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,17 @@ extern "C" void otPlatRadioEnergyScanDone(otInstance *aInstance, int8_t aEnergyS
return;
}

extern "C" void otPlatRadioBusLatencyChanged(otInstance *aInstance)
{
Instance &instance = AsCoreType(aInstance);

VerifyOrExit(instance.IsInitialized());
instance.Get<Radio::Callbacks>().HandleBusLatencyChanged();

exit:
return;
}

#if OPENTHREAD_CONFIG_DIAG_ENABLE
extern "C" void otPlatDiagRadioReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError)
{
Expand Down Expand Up @@ -153,6 +164,8 @@ extern "C" void otPlatRadioTxDone(otInstance *, otRadioFrame *, otRadioFrame *,

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

extern "C" void otPlatRadioBusLatencyChanged(otInstance *) {}

#if OPENTHREAD_CONFIG_DIAG_ENABLE
extern "C" void otPlatDiagRadioReceiveDone(otInstance *, otRadioFrame *, otError) {}

Expand Down Expand Up @@ -250,6 +263,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
30 changes: 30 additions & 0 deletions src/lib/spinel/README_RADIO_SPINEL_DIAG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# OpenThread Diagnostics - Radio Spinel diagnostic commands

This module provides Spinel based radio transceiver diagnostic commands.

`OPENTHREAD_CONFIG_DIAG_ENABLE` is required.

## Command List

- [buslatency](#buslatency)

## Command Details

### buslatency

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

```bash
> diag radiospinel buslatency
0
Done
```

#### buslatency \<buslatency\>

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

```bash
> diag radiospinel buslatency 1000
Done
```
48 changes: 48 additions & 0 deletions src/lib/spinel/radio_spinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ RadioSpinel::RadioSpinel(void)
, mPanId(0xffff)
, mChannel(0)
, mRxSensitivity(0)
, mBusLatency(0)
, mState(kStateDisabled)
, mIsPromiscuous(false)
, mRxOnWhenIdle(true)
Expand Down Expand Up @@ -1775,6 +1776,41 @@ void RadioSpinel::GetDiagOutputCallback(otPlatDiagOutputCallback &aCallback, voi
aContext = mOutputContext;
}

otError RadioSpinel::RadioSpinelDiagProcess(char *aArgs[], uint8_t aArgsLength)
{
otError error = OT_ERROR_NONE;

VerifyOrExit(aArgsLength > 1, error = OT_ERROR_INVALID_ARGS);

aArgs++;
aArgsLength--;

if (strcmp(aArgs[0], "buslatency") == 0)
{
if (aArgsLength == 1)
{
PlatDiagOutput("%lu\n", ToUlong(GetBusLatency()));
}
else if (aArgsLength == 2)
{
uint32_t busLatency;
char *endptr;

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

SetBusLatency(busLatency);
}
else
{
error = OT_ERROR_INVALID_ARGS;
}
}

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 +1940,18 @@ 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 (IsEnabled() && mCallbacks.mBusLatencyChanged != nullptr)
{
mCallbacks.mBusLatencyChanged(mInstance);
}
}

void RadioSpinel::HandleRcpUnexpectedReset(spinel_status_t aStatus)
{
OT_UNUSED_VARIABLE(aStatus);
Expand Down
37 changes: 37 additions & 0 deletions src/lib/spinel/radio_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ struct RadioSpinelCallbacks
*/
void (*mEnergyScanDone)(otInstance *aInstance, int8_t aMaxRssi);

/**
* This callback notifies user of `RadioSpinel` that the bus latency has been changed.
*
* @param[in] aInstance The OpenThread instance structure.
*
*/
void (*mBusLatencyChanged)(otInstance *aInstance);

/**
* This callback notifies user of `RadioSpinel` that the transmission has started.
*
Expand Down Expand Up @@ -680,6 +688,18 @@ class RadioSpinel : private Logger
*/
bool IsDiagEnabled(void) const { return mDiagMode; }

/**
* Processes RadioSpinel - specific 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.
*
*/
otError RadioSpinelDiagProcess(char *aArgs[], uint8_t aArgsLength);

/**
* Processes platform diagnostics commands.
*
Expand Down Expand Up @@ -857,6 +877,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 +1267,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
Loading

0 comments on commit 1ceed7d

Please sign in to comment.