From 2b36daa6cbe0f333de9efd6f31c9881234e13456 Mon Sep 17 00:00:00 2001 From: Mason Tran Date: Thu, 5 Oct 2023 17:41:22 -0400 Subject: [PATCH] Add 'bootloader' spinel reset type and `otPlatResetBootloader()` API --- etc/cmake/options.cmake | 1 + examples/platforms/simulation/misc.c | 8 ++++++++ include/openthread/instance.h | 10 +++++++++- include/openthread/platform/misc.h | 8 ++++++++ src/core/api/instance_api.cpp | 4 ++++ src/core/common/instance.cpp | 4 ++++ src/core/common/instance.hpp | 7 +++++++ src/lib/spinel/spinel.h | 11 +++++++---- src/ncp/ncp_base.cpp | 8 ++++++++ tests/unit/test_platform.cpp | 2 ++ 10 files changed, 58 insertions(+), 5 deletions(-) diff --git a/etc/cmake/options.cmake b/etc/cmake/options.cmake index 0c667d0eed5b..227e0faa1609 100644 --- a/etc/cmake/options.cmake +++ b/etc/cmake/options.cmake @@ -225,6 +225,7 @@ ot_option(OT_NETDIAG_CLIENT OPENTHREAD_CONFIG_TMF_NETDIAG_CLIENT_ENABLE "Network ot_option(OT_OPERATIONAL_DATASET_AUTO_INIT OPENTHREAD_CONFIG_OPERATIONAL_DATASET_AUTO_INIT "operational dataset auto init") ot_option(OT_OTNS OPENTHREAD_CONFIG_OTNS_ENABLE "OTNS") ot_option(OT_PING_SENDER OPENTHREAD_CONFIG_PING_SENDER_ENABLE "ping sender" ${OT_APP_CLI}) +ot_option(OT_PLATFORM_BOOTLOADER_MODE OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE "platform bootloader mode") ot_option(OT_PLATFORM_NETIF OPENTHREAD_CONFIG_PLATFORM_NETIF_ENABLE "platform netif") ot_option(OT_PLATFORM_UDP OPENTHREAD_CONFIG_PLATFORM_UDP_ENABLE "platform UDP") ot_option(OT_REFERENCE_DEVICE OPENTHREAD_CONFIG_REFERENCE_DEVICE_ENABLE "test harness reference device") diff --git a/examples/platforms/simulation/misc.c b/examples/platforms/simulation/misc.c index 2fa7900113d6..000bb656d5e2 100644 --- a/examples/platforms/simulation/misc.c +++ b/examples/platforms/simulation/misc.c @@ -60,6 +60,14 @@ void otPlatReset(otInstance *aInstance) #endif // OPENTHREAD_PLATFORM_USE_PSEUDO_RESET } +#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE +void otPlatResetToBootloader(otInstance *aInstance) +{ + OT_UNUSED_VARIABLE(aInstance); + assert(false); +} +#endif + otPlatResetReason otPlatGetResetReason(otInstance *aInstance) { OT_UNUSED_VARIABLE(aInstance); diff --git a/include/openthread/instance.h b/include/openthread/instance.h index 782a0b353b6f..7859193fd5d9 100644 --- a/include/openthread/instance.h +++ b/include/openthread/instance.h @@ -53,7 +53,7 @@ extern "C" { * @note This number versions both OpenThread platform and user APIs. * */ -#define OPENTHREAD_API_VERSION (364) +#define OPENTHREAD_API_VERSION (365) /** * @addtogroup api-instance @@ -255,6 +255,14 @@ void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback a */ void otInstanceReset(otInstance *aInstance); +/** + * Triggers a platform reset to bootloader mode, if supported. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + */ +void otInstanceResetToBootloader(otInstance *aInstance); + /** * Deletes all the settings stored on non-volatile memory, and then triggers a platform reset. * diff --git a/include/openthread/platform/misc.h b/include/openthread/platform/misc.h index e11577dfea2e..f608b0ff2b8c 100644 --- a/include/openthread/platform/misc.h +++ b/include/openthread/platform/misc.h @@ -61,6 +61,14 @@ extern "C" { */ void otPlatReset(otInstance *aInstance); +/** + * Performs a hardware reset on the platform to launch bootloader mode, if supported. + * + * @param[in] aInstance The OpenThread instance structure. + * + */ +void otPlatResetToBootloader(otInstance *aInstance); + /** * Enumeration of possible reset reason codes. * diff --git a/src/core/api/instance_api.cpp b/src/core/api/instance_api.cpp index ad2a89e16ce2..29be6130495f 100644 --- a/src/core/api/instance_api.cpp +++ b/src/core/api/instance_api.cpp @@ -86,6 +86,10 @@ void otInstanceFinalize(otInstance *aInstance) { AsCoreType(aInstance).Finalize( void otInstanceReset(otInstance *aInstance) { AsCoreType(aInstance).Reset(); } +#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE +void otInstanceResetToBootloader(otInstance *aInstance) { AsCoreType(aInstance).ResetToBootloader(); } +#endif + #if OPENTHREAD_CONFIG_UPTIME_ENABLE uint64_t otInstanceGetUptime(otInstance *aInstance) { return AsCoreType(aInstance).Get().GetUptime(); } diff --git a/src/core/common/instance.cpp b/src/core/common/instance.cpp index 6dcc3e8927c3..b45b101d3d07 100644 --- a/src/core/common/instance.cpp +++ b/src/core/common/instance.cpp @@ -312,6 +312,10 @@ Instance *Instance::Init(void *aBuffer, size_t *aBufferSize) void Instance::Reset(void) { otPlatReset(this); } +#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE +void Instance::ResetToBootloader(void) { otPlatResetToBootloader(this); } +#endif + #if OPENTHREAD_RADIO void Instance::ResetRadioStack(void) { diff --git a/src/core/common/instance.hpp b/src/core/common/instance.hpp index d213c692e014..eebce354f935 100644 --- a/src/core/common/instance.hpp +++ b/src/core/common/instance.hpp @@ -236,6 +236,13 @@ class Instance : public otInstance, private NonCopyable */ void Reset(void); +#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE + /** + * Triggers a platform reset to bootloader mode, if supported. + */ + void ResetToBootloader(void); +#endif + #if OPENTHREAD_RADIO /** * Resets the internal states of the radio. diff --git a/src/lib/spinel/spinel.h b/src/lib/spinel/spinel.h index 36a201665b89..a01388847078 100644 --- a/src/lib/spinel/spinel.h +++ b/src/lib/spinel/spinel.h @@ -898,8 +898,9 @@ enum enum { - SPINEL_RESET_PLATFORM = 1, - SPINEL_RESET_STACK = 2, + SPINEL_RESET_PLATFORM = 1, + SPINEL_RESET_STACK = 2, + SPINEL_RESET_BOOTLOADER = 3, }; enum @@ -929,8 +930,10 @@ enum * `PROP_LAST_STATUS` has been set to `STATUS_RESET_SOFTWARE`. * * The optional command payload specifies the reset type, can be - * `SPINEL_RESET_PLATFORM` or `SPINEL_RESET_STACK`. Defaults to stack - * reset if unspecified. + * `SPINEL_RESET_PLATFORM`, `SPINEL_RESET_STACK`, or + * `SPINEL_RESET_BOOTLOADER`. + * + * Defaults to stack reset if unspecified. * * If an error occurs, the value of `PROP_LAST_STATUS` will be emitted * instead with the value set to the generated status code for the error. diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 1d7192ca1141..abde910ebd31 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -1211,6 +1211,14 @@ otError NcpBase::CommandHandler_RESET(uint8_t aHeader) SuccessOrAssert( error = WriteLastStatusFrame(SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_STATUS_RESET_POWER_ON)); } +#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE + else if (reset_type == SPINEL_RESET_BOOTLOADER) + { + // Signal a platform reset to bootloader mode. If implemented, this function + // shouldn't return. + otInstanceResetToBootloader(mInstance); + } +#endif else #endif { diff --git a/tests/unit/test_platform.cpp b/tests/unit/test_platform.cpp index 5487643140e5..4ba51161bfa6 100644 --- a/tests/unit/test_platform.cpp +++ b/tests/unit/test_platform.cpp @@ -223,6 +223,8 @@ OT_TOOL_WEAK void otPlatUartReceived(const uint8_t *, uint16_t) {} OT_TOOL_WEAK void otPlatReset(otInstance *) {} +OT_TOOL_WEAK void otPlatResetToBootloader(otInstance *) {} + OT_TOOL_WEAK otPlatResetReason otPlatGetResetReason(otInstance *) { return OT_PLAT_RESET_REASON_POWER_ON; } OT_TOOL_WEAK void otPlatLog(otLogLevel, otLogRegion, const char *, ...) {}