Skip to content

Commit

Permalink
[posix] add rcp diag commnand to check RCP's radio and spinel capbili…
Browse files Browse the repository at this point in the history
…ty flags
  • Loading branch information
zhanglongxia committed Jun 20, 2024
1 parent 215c23f commit edefa22
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 13 deletions.
84 changes: 83 additions & 1 deletion src/posix/platform/README_RCP_CAPS_DIAG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,49 @@ This module provides diag commands for checking RCP capabilities.

## Command List

- [capflags](#capflags)
- [spinel](#spinel)

## Command Details

### capflags

Check RCP's radio and spinel capbility flags.

```bash
> diag rcpcaps capflags

Radio Capbility Flags :

Thread Version >= 1.1 :
RADIO_CAPS_ACK_TIMEOUT ------------------------------------ OK
RADIO_CAPS_TRANSMIT_RETRIES ------------------------------- OK
RADIO_CAPS_CSMA_BACKOFF ----------------------------------- OK

Thread Version >= 1.2 :
RADIO_CAPS_TRANSMIT_SEC ----------------------------------- OK
RADIO_CAPS_TRANSMIT_TIMING -------------------------------- OK

Utils :
RADIO_CAPS_ENERGY_SCAN ------------------------------------ OK
RADIO_CAPS_SLEEP_TO_TX ------------------------------------ NotSupported
RADIO_CAPS_RECEIVE_TIMING --------------------------------- NotSupported
RADIO_CAPS_RX_ON_WHEN_IDLE -------------------------------- NotSupported

Spinel Capbility Flags :

Basic :
SPINEL_CAPS_CONFIG_RADIO ---------------------------------- OK
SPINEL_CAPS_MAC_RAW --------------------------------------- OK
SPINEL_CAPS_RCP_API_VERSION ------------------------------- OK

Utils :
SPINEL_CAPS_OPENTHREAD_LOG_METADATA ----------------------- NotSupported
SPINEL_CAPS_RCP_MIN_HOST_API_VERSION ---------------------- OK
SPINEL_CAPS_RCP_RESET_TO_BOOTLOADER ----------------------- NotSupported
Done
```

### spinel

Check which Spinel commands RCP supports.
Expand All @@ -19,14 +58,57 @@ Check which Spinel commands RCP supports.

Basic :
PROP_VALUE_GET CAPS --------------------------------------- OK
PROP_VALUE_GET PROTOCOL_VERSION --------------------------- OK
PROP_VALUE_GET RADIO_CAPS --------------------------------- OK
PROP_VALUE_GET RCP_API_VERSION ---------------------------- OK
PROP_VALUE_GET NCP_VERSION -------------------------------- OK

Thread Version >= 1.1 :
PROP_VALUE_SET PHY_CHAN ----------------------------------- OK
PROP_VALUE_SET PHY_ENABLED -------------------------------- OK
PROP_VALUE_SET MAC_15_4_PANID ----------------------------- OK
PROP_VALUE_SET MAC_15_4_LADDR ----------------------------- OK
PROP_VALUE_SET MAC_15_4_SADDR ----------------------------- OK
PROP_VALUE_SET MAC_RAW_STREAM_ENABLED --------------------- OK
PROP_VALUE_SET MAC_SCAN_MASK ------------------------------ OK
PROP_VALUE_SET MAC_SCAN_PERIOD ---------------------------- OK
PROP_VALUE_SET MAC_SCAN_STATE ----------------------------- OK
PROP_VALUE_SET MAC_SRC_MATCH_ENABLED ---------------------- OK
PROP_VALUE_SET MAC_SRC_MATCH_SHORT_ADDRESSES -------------- OK
PROP_VALUE_SET MAC_SRC_MATCH_EXTENDED_ADDRESSES ----------- OK
PROP_VALUE_GET HWADDR ------------------------------------- OK
PROP_VALUE_GET PHY_CHAN_PREFERRED ------------------------- OK
PROP_VALUE_GET PHY_CHAN_SUPPORTED ------------------------- OK
PROP_VALUE_GET PHY_RSSI ----------------------------------- OK
PROP_VALUE_GET PHY_RX_SENSITIVITY ------------------------- OK
PROP_VALUE_INSERT MAC_SRC_MATCH_SHORT_ADDRESSES ----------- OK
PROP_VALUE_INSERT MAC_SRC_MATCH_EXTENDED_ADDRESSES -------- OK
PROP_VALUE_REMOVE MAC_SRC_MATCH_SHORT_ADDRESSES ----------- OK
PROP_VALUE_REMOVE MAC_SRC_MATCH_EXTENDED_ADDRESSES -------- OK

Thread Version >= 1.2 :
PROP_VALUE_SET ENH_ACK_PROBING ---------------------------- NotImplemented
PROP_VALUE_SET RCP_MAC_FRAME_COUNTER ---------------------- OK
PROP_VALUE_SET RCP_MAC_KEY -------------------------------- OK
PROP_VALUE_GET CSL_ACCURACY ------------------------------- OK
PROP_VALUE_GET CSL_UNCERTAINTY ---------------------------- OK
PROP_VALUE_GET TIMESTAMP ---------------------------------- OK

Optional :
Utils :
PROP_VALUE_SET MAC_PROMISCUOUS_MODE ----------------------- OK
PROP_VALUE_GET PHY_CCA_THRESHOLD -------------------------- OK
PROP_VALUE_GET PHY_FEM_LNA_GAIN --------------------------- OK
PROP_VALUE_GET PHY_REGION_CODE ---------------------------- OK
PROP_VALUE_GET PHY_TX_POWER ------------------------------- OK
PROP_VALUE_GET RADIO_COEX_ENABLE -------------------------- OK
PROP_VALUE_GET RADIO_COEX_METRICS ------------------------- OK
PROP_VALUE_GET RCP_MIN_HOST_API_VERSION ------------------- OK
PROP_VALUE_SET PHY_CCA_THRESHOLD -------------------------- OK
PROP_VALUE_SET PHY_CHAN_MAX_POWER ------------------------- OK
PROP_VALUE_SET PHY_CHAN_TARGET_POWER ---------------------- OK
PROP_VALUE_SET PHY_FEM_LNA_GAIN --------------------------- OK
PROP_VALUE_SET PHY_REGION_CODE ---------------------------- OK
PROP_VALUE_SET PHY_TX_POWER ------------------------------- OK
PROP_VALUE_SET RADIO_COEX_ENABLE -------------------------- OK
Done
```
182 changes: 171 additions & 11 deletions src/posix/platform/rcp_caps_diag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,11 @@ otError RcpCapsDiag::DiagProcess(char *aArgs[], uint8_t aArgsLength)

VerifyOrExit(aArgsLength == 2, error = OT_ERROR_INVALID_ARGS);

if (strcmp(aArgs[1], "spinel") == 0)
if (strcmp(aArgs[1], "capflags") == 0)
{
ProcessCapabilityFlags();
}
else if (strcmp(aArgs[1], "spinel") == 0)
{
ProcessSpinel();
}
Expand Down Expand Up @@ -498,22 +502,146 @@ void RcpCapsDiag::SetDiagOutputCallback(otPlatDiagOutputCallback aCallback, void
mOutputContext = aContext;
}

void RcpCapsDiag::ProcessCapabilityFlags(void)
{
TestRadioCapbilityFlags();
TestSpinelCapbilityFlags();
}

void RcpCapsDiag::TestRadioCapbilityFlags(void)
{
static constexpr uint32_t kRadioThread11Flags[] = {OT_RADIO_CAPS_ACK_TIMEOUT, OT_RADIO_CAPS_TRANSMIT_RETRIES,
OT_RADIO_CAPS_CSMA_BACKOFF};
static constexpr uint32_t kRadioThread12Flags[] = {OT_RADIO_CAPS_TRANSMIT_SEC, OT_RADIO_CAPS_TRANSMIT_TIMING};
static constexpr uint32_t kRadioUtilsFlags[] = {OT_RADIO_CAPS_ENERGY_SCAN, OT_RADIO_CAPS_SLEEP_TO_TX,
OT_RADIO_CAPS_RECEIVE_TIMING, OT_RADIO_CAPS_RX_ON_WHEN_IDLE};
otError error;
unsigned int radioCaps;

SuccessOrExit(error = mRadioSpinel.Get(SPINEL_PROP_RADIO_CAPS, SPINEL_DATATYPE_UINT_PACKED_S, &radioCaps));

Output("\r\nRadio Capbility Flags :\r\n");

OutputRadioCapFlags(kCategoryThread1_1, static_cast<uint32_t>(radioCaps), kRadioThread11Flags,
OT_ARRAY_LENGTH(kRadioThread11Flags));
OutputRadioCapFlags(kCategoryThread1_2, static_cast<uint32_t>(radioCaps), kRadioThread12Flags,
OT_ARRAY_LENGTH(kRadioThread12Flags));
OutputRadioCapFlags(kCategoryUtils, static_cast<uint32_t>(radioCaps), kRadioUtilsFlags,
OT_ARRAY_LENGTH(kRadioUtilsFlags));

exit:
if (error != OT_ERROR_NONE)
{
Output("Failed to get radio capability flags: %s", otThreadErrorToString(error));
}

return;
}

void RcpCapsDiag::OutputRadioCapFlags(Category aCategory,
uint32_t aRadioCaps,
const uint32_t *aFlags,
uint16_t aNumbFlags)
{
Output("\r\n%s :\r\n", CategoryToString(aCategory));
for (uint16_t i = 0; i < aNumbFlags; i++)
{
OutputFormat(RadioCapbilityToString(aFlags[i]), SupportToString((aRadioCaps & aFlags[i]) > 0));
}
}

void RcpCapsDiag::TestSpinelCapbilityFlags(void)
{
static constexpr uint8_t kCapsBufferSize = 100;
static constexpr uint32_t kSpinelBasicFlags[] = {SPINEL_CAP_CONFIG_RADIO, SPINEL_CAP_MAC_RAW,
SPINEL_CAP_RCP_API_VERSION};
static constexpr uint32_t kSpinelUtilsFlags[] = {
SPINEL_CAP_OPENTHREAD_LOG_METADATA, SPINEL_CAP_RCP_MIN_HOST_API_VERSION, SPINEL_CAP_RCP_RESET_TO_BOOTLOADER};
otError error;
uint8_t capsBuffer[kCapsBufferSize];
spinel_size_t capsLength = sizeof(capsBuffer);

SuccessOrExit(error = mRadioSpinel.Get(SPINEL_PROP_CAPS, SPINEL_DATATYPE_DATA_S, capsBuffer, &capsLength));

Output("\r\nSpinel Capbility Flags :\r\n");

OutputSpinelCapFlags(kCategoryBasic, capsBuffer, capsLength, kSpinelBasicFlags, OT_ARRAY_LENGTH(kSpinelBasicFlags));
OutputSpinelCapFlags(kCategoryUtils, capsBuffer, capsLength, kSpinelUtilsFlags, OT_ARRAY_LENGTH(kSpinelUtilsFlags));

exit:
if (error != OT_ERROR_NONE)
{
Output("Failed to get Spinel capbility flags: %s", otThreadErrorToString(error));
}

return;
}

void RcpCapsDiag::OutputSpinelCapFlags(Category aCategory,
const uint8_t *aCapsData,
spinel_size_t aCapsLength,
const uint32_t *aFlags,
uint16_t aNumbFlags)
{
static constexpr uint8_t kCapsNameSize = 40;
char capName[kCapsNameSize];

Output("\r\n%s :\r\n", CategoryToString(aCategory));

for (uint16_t i = 0; i < aNumbFlags; i++)
{
snprintf(capName, sizeof(capName), "SPINEL_CAPS_%s", spinel_capability_to_cstr(aFlags[i]));
OutputFormat(capName, SupportToString(IsSpinelCapabilitySupported(aCapsData, aCapsLength, aFlags[i])));
}
}

bool RcpCapsDiag::IsSpinelCapabilitySupported(const uint8_t *aCapsData, spinel_size_t aCapsLength, uint32_t aCapability)
{
bool ret = false;

while (aCapsLength > 0)
{
unsigned int capability;
spinel_ssize_t unpacked;

unpacked = spinel_datatype_unpack(aCapsData, aCapsLength, SPINEL_DATATYPE_UINT_PACKED_S, &capability);
VerifyOrExit(unpacked > 0);
VerifyOrExit(capability != aCapability, ret = true);

aCapsData += unpacked;
aCapsLength -= static_cast<spinel_size_t>(unpacked);
}

exit:
return ret;
}

void RcpCapsDiag::OutputFormat(const char *aName, const char *aValue)
{
static constexpr uint8_t kMaxNameLength = 56;
static const char kPadding[] = "----------------------------------------------------------";
uint16_t actualLength = static_cast<uint16_t>(strlen(aName));
uint16_t paddingOffset = (actualLength > kMaxNameLength) ? kMaxNameLength : actualLength;

static_assert(kMaxNameLength < sizeof(kPadding), "Padding bytes are too short");

Output("%.*s %s %s\r\n", kMaxNameLength, aName, &kPadding[paddingOffset], aValue);
}

void RcpCapsDiag::OutputResult(const SpinelEntry &aEntry, otError error)
{
static constexpr uint8_t kSpaceLength = 1;
static constexpr uint8_t kMaxCommandStringLength = 20;
static constexpr uint8_t kMaxKeyStringLength = 35;
static constexpr uint16_t kMaxLength = kMaxCommandStringLength + kMaxKeyStringLength + kSpaceLength;
static const char kPadding[] = "----------------------------------------------------------";
const char *commandString = spinel_command_to_cstr(aEntry.mCommand);
const char *keyString = spinel_prop_key_to_cstr(aEntry.mKey);
uint16_t actualLength = static_cast<uint16_t>(strlen(commandString) + strlen(keyString) + kSpaceLength);
uint16_t paddingOffset = (actualLength > kMaxLength) ? kMaxLength : actualLength;

static_assert(kMaxLength < sizeof(kPadding), "Padding bytes are too short");
static constexpr uint16_t kMaxBufferLength =
kMaxCommandStringLength + kMaxKeyStringLength + kSpaceLength + 1 /* size of '\0' */;
char buffer[kMaxBufferLength] = {0};
const char *commandString = spinel_command_to_cstr(aEntry.mCommand);
const char *keyString = spinel_prop_key_to_cstr(aEntry.mKey);

Output("%.*s %.*s %s %s\r\n", kMaxCommandStringLength, commandString, kMaxKeyStringLength, keyString,
&kPadding[paddingOffset], otThreadErrorToString(error));
snprintf(buffer, sizeof(buffer), "%.*s %.*s", kMaxCommandStringLength, commandString, kMaxKeyStringLength,
keyString);
OutputFormat(buffer, otThreadErrorToString(error));
}

void RcpCapsDiag::Output(const char *aFormat, ...)
Expand Down Expand Up @@ -547,6 +675,38 @@ const char *RcpCapsDiag::CategoryToString(Category aCategory)
return (aCategory < OT_ARRAY_LENGTH(kCategoryStrings)) ? kCategoryStrings[aCategory] : "invalid";
}

const char *RcpCapsDiag::SupportToString(bool aSupport) { return aSupport ? "OK" : "NotSupported"; }

const char *RcpCapsDiag::RadioCapbilityToString(uint32_t aCapability)
{
static const char *const kCapbilityStrings[] = {
"RADIO_CAPS_ACK_TIMEOUT", // (1 << 0) OT_RADIO_CAPS_ACK_TIMEOUT
"RADIO_CAPS_ENERGY_SCAN", // (1 << 1) OT_RADIO_CAPS_ENERGY_SCAN
"RADIO_CAPS_TRANSMIT_RETRIES", // (1 << 2) OT_RADIO_CAPS_TRANSMIT_RETRIES
"RADIO_CAPS_CSMA_BACKOFF", // (1 << 3) OT_RADIO_CAPS_CSMA_BACKOFF
"RADIO_CAPS_SLEEP_TO_TX", // (1 << 4) OT_RADIO_CAPS_SLEEP_TO_TX
"RADIO_CAPS_TRANSMIT_SEC", // (1 << 5) OT_RADIO_CAPS_TRANSMIT_SEC
"RADIO_CAPS_TRANSMIT_TIMING", // (1 << 6) OT_RADIO_CAPS_TRANSMIT_TIMING
"RADIO_CAPS_RECEIVE_TIMING", // (1 << 7) OT_RADIO_CAPS_RECEIVE_TIMING
"RADIO_CAPS_RX_ON_WHEN_IDLE", // (1 << 8) OT_RADIO_CAPS_RX_ON_WHEN_IDLE
};

static_assert(OT_RADIO_CAPS_ACK_TIMEOUT == 1 << 0, "OT_RADIO_CAPS_ACK_TIMEOUT value is incorrect");
static_assert(OT_RADIO_CAPS_ENERGY_SCAN == 1 << 1, "OT_RADIO_CAPS_ENERGY_SCAN value is incorrect");
static_assert(OT_RADIO_CAPS_TRANSMIT_RETRIES == 1 << 2, "OT_RADIO_CAPS_TRANSMIT_RETRIES value is incorrect");
static_assert(OT_RADIO_CAPS_CSMA_BACKOFF == 1 << 3, "OT_RADIO_CAPS_CSMA_BACKOFF value is incorrect");
static_assert(OT_RADIO_CAPS_SLEEP_TO_TX == 1 << 4, "OT_RADIO_CAPS_SLEEP_TO_TX value is incorrect");
static_assert(OT_RADIO_CAPS_TRANSMIT_SEC == 1 << 5, "OT_RADIO_CAPS_TRANSMIT_SEC value is incorrect");
static_assert(OT_RADIO_CAPS_TRANSMIT_TIMING == 1 << 6, "OT_RADIO_CAPS_TRANSMIT_TIMING value is incorrect");
static_assert(OT_RADIO_CAPS_RECEIVE_TIMING == 1 << 7, "OT_RADIO_CAPS_RECEIVE_TIMING value is incorrect");
static_assert(OT_RADIO_CAPS_RX_ON_WHEN_IDLE == 1 << 8, "OT_RADIO_CAPS_RX_ON_WHEN_IDLE value is incorrect");

int32_t pos = static_cast<int32_t>(ffs(static_cast<int>(aCapability))) - 1;

return ((pos >= 0) && static_cast<uint32_t>(pos) < (OT_ARRAY_LENGTH(kCapbilityStrings))) ? kCapbilityStrings[pos]
: "invalid";
}

} // namespace Posix
} // namespace ot
#endif // OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
15 changes: 14 additions & 1 deletion src/posix/platform/rcp_caps_diag.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,24 @@ class RcpCapsDiag
};

void ProcessSpinel(void);
void ProcessCapabilityFlags(void);
void TestSpinelCommands(Category aCategory);
void TestRadioCapbilityFlags(void);
void OutputRadioCapFlags(Category aCategory, uint32_t aRadioCaps, const uint32_t *aFlags, uint16_t aNumbFlags);
void TestSpinelCapbilityFlags(void);
void OutputSpinelCapFlags(Category aCategory,
const uint8_t *aCapsData,
spinel_size_t aCapsLength,
const uint32_t *aFlags,
uint16_t aNumbFlags);
bool IsSpinelCapabilitySupported(const uint8_t *aCapsData, spinel_size_t aCapsLength, uint32_t aCapability);
void OutputFormat(const char *aName, const char *aValue);
void OutputResult(const SpinelEntry &aEntry, otError error);
void Output(const char *aFormat, ...);

const char *CategoryToString(Category aCategory);
static const char *SupportToString(bool aSupport);
static const char *RadioCapbilityToString(uint32_t aCapability);
static const char *CategoryToString(Category aCategory);

static const struct SpinelEntry sSpinelEntries[];

Expand Down

0 comments on commit edefa22

Please sign in to comment.