diff --git a/src/lib/spinel/spinel.c b/src/lib/spinel/spinel.c index e8389b1e7..7595a7f55 100644 --- a/src/lib/spinel/spinel.c +++ b/src/lib/spinel/spinel.c @@ -1995,6 +1995,14 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "SLAAC_ENABLED"; break; + case SPINEL_PROP_SUPPORTED_RADIO_LINKS: + ret = "SUPPORTED_RADIO_LINKS"; + break; + + case SPINEL_PROP_NEIGHBOR_TABLE_MULTI_RADIO_INFO: + ret = "NEIGHBOR_TABLE_MULTI_RADIO_INFO"; + break; + case SPINEL_PROP_SERVER_ALLOW_LOCAL_DATA_CHANGE: ret = "SERVER_ALLOW_LOCAL_DATA_CHANGE"; break; @@ -2267,6 +2275,14 @@ const char *spinel_prop_key_to_cstr(spinel_prop_key_t prop_key) ret = "RCP_MAC_KEY"; break; + case SPINEL_PROP_DEBUG_LOG_TIMESTAMP_BASE: + ret = "DEBUG_LOG_TIMESTAMP_BASE"; + break; + + case SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE: + ret = "DEBUG_TREL_TEST_MODE_ENABLE"; + break; + default: break; } @@ -2675,6 +2691,10 @@ const char *spinel_capability_to_cstr(spinel_capability_t capability) ret = "MAC_RETRY_HISTOGRAM"; break; + case SPINEL_CAP_MULTI_RADIO: + ret = "MULTI_RADIO"; + break; + case SPINEL_CAP_ERROR_RATE_TRACKING: ret = "ERROR_RATE_TRACKING"; break; @@ -2722,6 +2742,27 @@ const char *spinel_capability_to_cstr(spinel_capability_t capability) return ret; } +const char *spinel_radio_link_to_cstr(uint32_t radio) +{ + const char *ret = "UNKNOWN"; + + switch (radio) + { + case SPINEL_RADIO_LINK_IEEE_802_15_4: + ret = "IEEE_802_15_4"; + break; + + case SPINEL_RADIO_LINK_TREL_UDP6: + ret = "TREL_UDP6"; + break; + + default: + break; + } + + return ret; +} + // LCOV_EXCL_STOP /* -------------------------------------------------------------------------- */ diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index 07cd7f8c1..5452682a7 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -709,6 +709,12 @@ enum SPINEL_ADDRESS_CACHE_ENTRY_STATE_RETRY_QUERY = 3, // Entry is in retry mode (a prior query did not a response). }; +enum +{ + SPINEL_RADIO_LINK_IEEE_802_15_4 = 0, + SPINEL_RADIO_LINK_TREL_UDP6 = 1, +}; + typedef struct { uint8_t bytes[8]; @@ -1143,6 +1149,7 @@ enum SPINEL_CAP_SLAAC = (SPINEL_CAP_OPENTHREAD__BEGIN + 10), SPINEL_CAP_RADIO_COEX = (SPINEL_CAP_OPENTHREAD__BEGIN + 11), SPINEL_CAP_MAC_RETRY_HISTOGRAM = (SPINEL_CAP_OPENTHREAD__BEGIN + 12), + SPINEL_CAP_MULTI_RADIO = (SPINEL_CAP_OPENTHREAD__BEGIN + 13), SPINEL_CAP_OPENTHREAD__END = 640, SPINEL_CAP_THREAD__BEGIN = 1024, @@ -3592,6 +3599,34 @@ enum */ SPINEL_PROP_SLAAC_ENABLED = SPINEL_PROP_OPENTHREAD__BEGIN + 14, + // Supported Radio Links (by device) + /** + * Format `A(i)` - Read only + * + * This property returns list of supported radio links by the device itself. Enumeration `SPINEL_RADIO_LINK_{TYPE}` + * values indicate different radio link types. + * + */ + SPINEL_PROP_SUPPORTED_RADIO_LINKS = SPINEL_PROP_OPENTHREAD__BEGIN + 15, + + /// Neighbor Table Multi Radio Link Info + /** Format: `A(t(ESA(t(iC))))` - Read only + * Required capability: `SPINEL_CAP_MULTI_RADIO`. + * + * Each item represents info about a neighbor: + * + * `E`: Neighbor's Extended Address + * `S`: Neighbor's RLOC16 + * + * This is then followed by an array of radio link info structures indicating which radio links are supported by + * the neighbor: + * + * `i` : Radio link type (enumeration `SPINEL_RADIO_LINK_{TYPE}`). + * `C` : Preference value associated with radio link. + * + */ + SPINEL_PROP_NEIGHBOR_TABLE_MULTI_RADIO_INFO = SPINEL_PROP_OPENTHREAD__BEGIN + 16, + SPINEL_PROP_OPENTHREAD__END = 0x2000, SPINEL_PROP_SERVER__BEGIN = 0xA0, @@ -4137,6 +4172,18 @@ enum */ SPINEL_PROP_DEBUG_LOG_TIMESTAMP_BASE = SPINEL_PROP_DEBUG__BEGIN + 3, + /// TREL Radio Link - test mode enable + /** Format `b` (read-write) + * + * This property is intended for testing TREL (Thread Radio Encapsulation Link) radio type only (during simulation). + * It allows the TREL interface to be temporarily disabled and (re)enabled. While disabled all traffic through + * TREL interface is dropped silently (to emulate a radio/interface down scenario). + * + * This property is only available when the TREL radio link type is supported. + * + */ + SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE = SPINEL_PROP_DEBUG__BEGIN + 4, + SPINEL_PROP_DEBUG__END = 0x4400, SPINEL_PROP_EXPERIMENTAL__BEGIN = 2000000, @@ -4328,6 +4375,8 @@ SPINEL_API_EXTERN const char *spinel_status_to_cstr(spinel_status_t status); SPINEL_API_EXTERN const char *spinel_capability_to_cstr(spinel_capability_t capability); +SPINEL_API_EXTERN const char *spinel_radio_link_to_cstr(uint32_t radio); + // ---------------------------------------------------------------------------- #if defined(__cplusplus) diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 5435dea57..3ef0445af 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -43,6 +43,9 @@ #include #include #include +#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE +#include +#endif #include "common/code_utils.hpp" #include "common/debug.hpp" @@ -246,6 +249,9 @@ NcpBase::NcpBase(Instance *aInstance) , mRxSpinelOutOfOrderTidCounter(0) , mTxSpinelFrameCounter(0) , mDidInitialUpdates(false) +#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE + , mTrelTestModeEnable(true) +#endif , mLogTimestampBase(0) { OT_ASSERT(mInstance != nullptr); @@ -1889,6 +1895,10 @@ template <> otError NcpBase::HandlePropertyGet(void) SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_THREAD_SERVICE)); #endif +#if OPENTHREAD_CONFIG_MULTI_RADIO + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_MULTI_RADIO)); +#endif + #endif // OPENTHREAD_MTD || OPENTHREAD_FTD exit: @@ -2427,6 +2437,24 @@ exit: } #endif +#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE +template <> otError NcpBase::HandlePropertyGet(void) +{ + return mEncoder.WriteBool(mTrelTestModeEnable); +} + +template <> otError NcpBase::HandlePropertySet(void) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mDecoder.ReadBool(mTrelTestModeEnable)); + error = otPlatTrelUdp6SetTestMode(mInstance, mTrelTestModeEnable); + +exit: + return error; +} +#endif + } // namespace Ncp } // namespace ot diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index 073a68f1f..acb2ca49a 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -47,6 +47,9 @@ #endif #include #include +#if OPENTHREAD_CONFIG_MULTI_RADIO +#include +#endif #include "changed_props_set.hpp" #include "common/instance.hpp" @@ -340,6 +343,9 @@ protected: bool aAllowEmptyValues = false); otError EncodeNeighborInfo(const otNeighborInfo &aNeighborInfo); +#if OPENTHREAD_CONFIG_MULTI_RADIO + otError EncodeNeighborMultiRadioInfo(uint32_t aSpinelRadioLink, const otRadioLinkInfo &aInfo); +#endif #if OPENTHREAD_FTD otError EncodeChildInfo(const otChildInfo &aChildInfo); @@ -603,6 +609,10 @@ protected: bool mDidInitialUpdates; +#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE + bool mTrelTestModeEnable; +#endif + uint64_t mLogTimestampBase; // Timestamp base used for logging }; diff --git a/src/ncp/ncp_base_dispatcher.cpp b/src/ncp/ncp_base_dispatcher.cpp index 6e67adbe6..01dec49da 100644 --- a/src/ncp/ncp_base_dispatcher.cpp +++ b/src/ncp/ncp_base_dispatcher.cpp @@ -323,6 +323,10 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) #endif #if OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_SLAAC_ENABLED), +#endif + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_SUPPORTED_RADIO_LINKS), +#if OPENTHREAD_CONFIG_MULTI_RADIO + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_NEIGHBOR_TABLE_MULTI_RADIO_INFO), #endif #if OPENTHREAD_CONFIG_LEGACY_ENABLE OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_NEST_LEGACY_ULA_PREFIX), @@ -333,6 +337,9 @@ NcpBase::PropertyHandler NcpBase::FindGetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_DEBUG_NCP_LOG_LEVEL), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_DEBUG_TEST_WATCHDOG), OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_DEBUG_LOG_TIMESTAMP_BASE), +#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE + OT_NCP_GET_HANDLER_ENTRY(SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE), +#endif }; #undef OT_NCP_GET_HANDLER_ENTRY @@ -543,6 +550,9 @@ NcpBase::PropertyHandler NcpBase::FindSetPropertyHandler(spinel_prop_key_t aKey) OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DEBUG_NCP_LOG_LEVEL), #endif OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DEBUG_LOG_TIMESTAMP_BASE), +#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE + OT_NCP_SET_HANDLER_ENTRY(SPINEL_PROP_DEBUG_TREL_TEST_MODE_ENABLE), +#endif }; #undef OT_NCP_SET_HANDLER_ENTRY diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index 236efbe4e..77d0b0528 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -3144,6 +3144,74 @@ exit: #endif // OPENTHREAD_CONFIG_IP6_SLAAC_ENABLE +template <> otError NcpBase::HandlePropertyGet(void) +{ + otError error; + +#if OPENTHREAD_CONFIG_RADIO_LINK_IEEE_802_15_4_ENABLE + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_RADIO_LINK_IEEE_802_15_4)); +#endif + +#if OPENTHREAD_CONFIG_RADIO_LINK_TREL_ENABLE + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_RADIO_LINK_TREL_UDP6)); +#endif + +exit: + return error; +} + +#if OPENTHREAD_CONFIG_MULTI_RADIO + +otError NcpBase::EncodeNeighborMultiRadioInfo(uint32_t aSpinelRadioLink, const otRadioLinkInfo &aInfo) +{ + otError error; + + SuccessOrExit(error = mEncoder.OpenStruct()); + SuccessOrExit(error = mEncoder.WriteUintPacked(aSpinelRadioLink)); + SuccessOrExit(error = mEncoder.WriteUint8(aInfo.mPreference)); + SuccessOrExit(error = mEncoder.CloseStruct()); + +exit: + return error; +} + +template <> otError NcpBase::HandlePropertyGet(void) +{ + otError error = OT_ERROR_NONE; + otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; + otNeighborInfo neighInfo; + otMultiRadioNeighborInfo multiRadioInfo; + + while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE) + { + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteEui64(neighInfo.mExtAddress)); + SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mRloc16)); + + if (otMultiRadioGetNeighborInfo(mInstance, &neighInfo.mExtAddress, &multiRadioInfo) == OT_ERROR_NONE) + { + if (multiRadioInfo.mSupportsIeee802154) + { + SuccessOrExit(error = EncodeNeighborMultiRadioInfo(SPINEL_RADIO_LINK_IEEE_802_15_4, + multiRadioInfo.mIeee802154Info)); + } + + if (multiRadioInfo.mSupportsTrelUdp6) + { + SuccessOrExit( + error = EncodeNeighborMultiRadioInfo(SPINEL_RADIO_LINK_TREL_UDP6, multiRadioInfo.mTrelUdp6Info)); + } + } + + SuccessOrExit(error = mEncoder.CloseStruct()); + } + +exit: + return error; +} +#endif // OPENTHREAD_CONFIG_MULTI_RADIO + #if OPENTHREAD_CONFIG_LEGACY_ENABLE void NcpBase::RegisterLegacyHandlers(const otNcpLegacyHandlers *aHandlers)