mirror of
https://github.com/espressif/openthread.git
synced 2026-08-15 07:07:46 +00:00
[posix] add rcp diag command to check RCP's radio and spinel capability flags (#10400)
This commit is contained in:
@@ -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.
|
||||
@@ -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
|
||||
```
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 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);
|
||||
|
||||
static_assert(kMaxLength < sizeof(kPadding), "Padding bytes are too short");
|
||||
|
||||
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, ...)
|
||||
@@ -547,6 +675,45 @@ 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
|
||||
};
|
||||
const char *string = "invalid";
|
||||
uint16_t index = 0;
|
||||
|
||||
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");
|
||||
|
||||
for (; !(aCapability & 0x1); (aCapability >>= 1), index++)
|
||||
{
|
||||
VerifyOrExit(index < OT_ARRAY_LENGTH(kCapbilityStrings));
|
||||
}
|
||||
|
||||
string = kCapbilityStrings[index];
|
||||
|
||||
exit:
|
||||
return string;
|
||||
}
|
||||
|
||||
} // namespace Posix
|
||||
} // namespace ot
|
||||
#endif // OPENTHREAD_POSIX_CONFIG_RCP_CAPS_DIAG_ENABLE
|
||||
|
||||
@@ -109,11 +109,24 @@ private:
|
||||
};
|
||||
|
||||
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[];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user