[low-power] fix CSL scheduler to avoid packets stuck in queue (#5833)

This commit:
- Fixes the issue in CSL scheduler dealing with multiple SSEDs.
- Fixes the issue when CSL tx attempts reach max, CSL transmission to
  this child cannot resume.
- Reset CSL sync status after child mode change to RxOnWhenIdle.
- Adds MLE version, CSL synchronization status and queued message
  count to child table.
This commit is contained in:
Jintao Lin
2020-11-23 22:59:21 -08:00
committed by GitHub
parent d33c2f12af
commit 91d2c29fd8
11 changed files with 48 additions and 19 deletions
+1 -1
View File
@@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (47)
#define OPENTHREAD_API_VERSION (48)
/**
* @addtogroup api-instance
+3
View File
@@ -67,10 +67,13 @@ typedef struct
int8_t mLastRssi; ///< Last observed RSSI
uint16_t mFrameErrorRate; ///< Frame error rate (0xffff->100%). Requires error tracking feature.
uint16_t mMessageErrorRate; ///< (IPv6) msg error rate (0xffff->100%). Requires error tracking feature.
uint16_t mQueuedMessageCnt; ///< Number of queued messages for the child.
uint8_t mVersion; ///< MLE version
bool mRxOnWhenIdle : 1; ///< rx-on-when-idle
bool mFullThreadDevice : 1; ///< Full Thread Device
bool mFullNetworkData : 1; ///< Full Network Data
bool mIsStateRestoring : 1; ///< Is in restoring state
bool mIsCslSynced : 1; ///< Is child CSL synchronized
} otChildInfo;
#define OT_CHILD_IP6_ADDRESS_ITERATOR_INIT 0 ///< Initializer for otChildIP6AddressIterator
+4 -4
View File
@@ -403,10 +403,10 @@ Print table of attached children.
```bash
> child table
| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|S|D|N| Extended MAC |
+-----+--------+------------+------------+-------+------+-+-+-+-+------------------+
| 1 | 0xe001 | 240 | 44 | 3 | 237 |1|1|1|1| d28d7f875888fccb |
| 2 | 0xe002 | 240 | 27 | 3 | 237 |0|1|0|1| e2b3540590b0fd87 |
| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt| Extended MAC |
+-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+------------------+
| 1 | 0xc801 | 240 | 24 | 3 | 131 |1|0|0| 3| 0 | 0 | 4ecede68435358ac |
| 2 | 0xc802 | 240 | 2 | 3 | 131 |0|0|0| 3| 1 | 0 | a672a601d2ce37d8 |
Done
```
+7 -2
View File
@@ -782,8 +782,10 @@ otError Interpreter::ProcessChild(uint8_t aArgsLength, char *aArgs[])
if (isTable)
{
OutputLine("| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N| Extended MAC |");
OutputLine("+-----+--------+------------+------------+-------+------+-+-+-+------------------+");
OutputLine(
"| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt| Extended MAC |");
OutputLine(
"+-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+------------------+");
}
maxChildren = otThreadGetMaxAllowedChildren(mInstance);
@@ -806,6 +808,9 @@ otError Interpreter::ProcessChild(uint8_t aArgsLength, char *aArgs[])
OutputFormat("|%1d", childInfo.mRxOnWhenIdle);
OutputFormat("|%1d", childInfo.mFullThreadDevice);
OutputFormat("|%1d", childInfo.mFullNetworkData);
OutputFormat("|%3d", childInfo.mVersion);
OutputFormat("| %1d ", childInfo.mIsCslSynced);
OutputFormat("| %5d ", childInfo.mQueuedMessageCnt);
OutputFormat("| ");
OutputExtAddress(childInfo.mExtAddress);
OutputLine(" |");
-1
View File
@@ -105,7 +105,6 @@ public:
void SetIndirectKeyId(uint8_t aKeyId) { mIndirectKeyId = aKeyId; }
uint8_t GetIndirectTxAttempts(void) const { return mIndirectTxAttempts; }
void SetIndirectTxAttemptsToMax(void) { mIndirectTxAttempts = kMaxPollTriggeredTxAttempts; }
void ResetIndirectTxAttempts(void) { mIndirectTxAttempts = 0; }
void IncrementIndirectTxAttempts(void) { mIndirectTxAttempts++; }
+10 -3
View File
@@ -97,7 +97,7 @@ void CslTxScheduler::Clear(void)
{
for (Child &child : Get<ChildTable>().Iterate(Child::kInStateAnyExceptInvalid))
{
child.SetCslTxAttempts(0);
child.ResetCslTxAttempts();
child.SetCslSynchronized(false);
child.SetCslChannel(0);
child.SetCslTimeout(0);
@@ -128,8 +128,7 @@ void CslTxScheduler::RescheduleCslTx(void)
uint32_t delay;
uint32_t cslTxDelay;
if (!child.IsCslSynchronized() || child.GetIndirectMessageCount() == 0 ||
child.GetCslTxAttempts() >= kMaxCslTriggeredTxAttempts)
if (!child.IsCslSynchronized() || child.GetIndirectMessageCount() == 0)
{
continue;
}
@@ -233,12 +232,20 @@ void CslTxScheduler::HandleSentFrame(const Mac::TxFrame &aFrame, otError aError,
aChild.ResetCslTxAttempts();
aChild.ResetIndirectTxAttempts();
break;
case OT_ERROR_NO_ACK:
aChild.IncrementCslTxAttempts();
otLogInfoMac("CSL tx to child %04x failed, attempt %d/%d", aChild.GetRloc16(), aChild.GetCslTxAttempts(),
kMaxCslTriggeredTxAttempts);
if (aChild.GetCslTxAttempts() >= kMaxCslTriggeredTxAttempts)
{
// CSL transmission attempts reach max, consider child out of sync
aChild.SetCslSynchronized(false);
aChild.ResetCslTxAttempts();
}
// Fall through
case OT_ERROR_CHANNEL_ACCESS_FAILURE:
case OT_ERROR_ABORT:
+1 -2
View File
@@ -79,9 +79,8 @@ public:
{
public:
uint8_t GetCslTxAttempts(void) const { return mCslTxAttempts; }
void SetCslTxAttempts(uint8_t aCslTxAttempts) { mCslTxAttempts = aCslTxAttempts; }
void IncrementCslTxAttempts(void) { mCslTxAttempts++; }
void ResetCslTxAttempts(void) { SetCslTxAttempts(0); }
void ResetCslTxAttempts(void) { mCslTxAttempts = 0; }
bool IsCslSynchronized(void) const { return mCslSynchronized && mCslPeriod > 0; }
void SetCslSynchronized(bool aCslSynchronized) { mCslSynchronized = aCslSynchronized; }
+4 -3
View File
@@ -321,14 +321,15 @@ void IndirectSender::UpdateIndirectMessage(Child &aChild)
aChild.SetIndirectFragmentOffset(0);
aChild.SetIndirectTxSuccess(true);
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
mCslTxScheduler.Update();
#endif
if (message != nullptr)
{
Mac::Address childAddress;
mDataPollHandler.HandleNewFrame(aChild);
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
mCslTxScheduler.Update();
#endif
aChild.GetMacAddress(childAddress);
Get<MeshForwarder>().LogMessage(MeshForwarder::kMessagePrepareIndirect, *message, &childAddress, OT_ERROR_NONE);
+8
View File
@@ -2482,6 +2482,14 @@ void MleRouter::HandleChildUpdateRequest(const Message & aMessage,
childDidChange = true;
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
if (child->IsRxOnWhenIdle())
{
// Clear CSL synchronization state
child->SetCslSynchronized(false);
}
#endif
// The `IndirectSender::HandleChildModeChange()` needs to happen
// after "Child Update" message is fully parsed to ensure that
// any registered IPv6 addresses included in the "Child Update"
+7
View File
@@ -211,10 +211,17 @@ void Child::Info::SetFrom(const Child &aChild)
mLastRssi = aChild.GetLinkInfo().GetLastRss();
mFrameErrorRate = aChild.GetLinkInfo().GetFrameErrorRate();
mMessageErrorRate = aChild.GetLinkInfo().GetMessageErrorRate();
mQueuedMessageCnt = aChild.GetIndirectMessageCount();
mVersion = aChild.GetVersion();
mRxOnWhenIdle = aChild.IsRxOnWhenIdle();
mFullThreadDevice = aChild.IsFullThreadDevice();
mFullNetworkData = aChild.IsFullNetworkData();
mIsStateRestoring = aChild.IsStateRestoring();
#if OPENTHREAD_CONFIG_MAC_CSL_TRANSMITTER_ENABLE
mIsCslSynced = aChild.IsCslSynchronized();
#else
mIsCslSynced = false;
#endif
}
const Ip6::Address *Child::AddressIterator::GetAddress(void) const
+3 -3
View File
@@ -46,9 +46,9 @@ expect "Done"
switch_node 1
send "child table\n"
expect "| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N| Extended MAC |"
expect "+-----+--------+------------+------------+-------+------+-+-+-+------------------+"
expect -re "\\| +(\\d+) \\| 0x$rloc \\| +\\d+ \\| +\\d+ \\| +\\d+ \\| +\\d+ \\|\\d\\|\\d\\|\\d\\| $extaddr \\|"
expect "| ID | RLOC16 | Timeout | Age | LQ In | C_VN |R|D|N|Ver|CSL|QMsgCnt| Extended MAC |"
expect "+-----+--------+------------+------------+-------+------+-+-+-+---+---+-------+------------------+"
expect -re "\\| +(\\d+) \\| 0x$rloc \\| +\\d+ \\| +\\d+ \\| +\\d+ \\| +\\d+ \\|\\d\\|\\d\\|\\d\\| *\\d+\\| \\d \\| +\\d+ \\| $extaddr \\|"
set child_id $expect_out(1,string)
expect "Done"
send "child list\n"