Skip to content

Commit

Permalink
[api] add API to reset to bootloader mode (openthread#9523)
Browse files Browse the repository at this point in the history
  • Loading branch information
lmnotran authored Oct 27, 2023
1 parent 1528c88 commit 0b0db37
Show file tree
Hide file tree
Showing 18 changed files with 167 additions and 14 deletions.
1 change: 1 addition & 0 deletions etc/cmake/options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
9 changes: 9 additions & 0 deletions examples/platforms/simulation/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ void otPlatReset(otInstance *aInstance)
#endif // OPENTHREAD_PLATFORM_USE_PSEUDO_RESET
}

#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE
otError otPlatResetToBootloader(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);

return OT_ERROR_NOT_CAPABLE;
}
#endif

otPlatResetReason otPlatGetResetReason(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);
Expand Down
16 changes: 15 additions & 1 deletion include/openthread/instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ extern "C" {
* @note This number versions both OpenThread platform and user APIs.
*
*/
#define OPENTHREAD_API_VERSION (369)
#define OPENTHREAD_API_VERSION (370)

/**
* @addtogroup api-instance
Expand Down Expand Up @@ -255,6 +255,20 @@ void otRemoveStateChangeCallback(otInstance *aInstance, otStateChangedCallback a
*/
void otInstanceReset(otInstance *aInstance);

/**
* Triggers a platform reset to bootloader mode, if supported.
*
* Requires `OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE`.
*
* @param[in] aInstance A pointer to an OpenThread instance.
*
* @retval OT_ERROR_NONE Reset to bootloader successfully.
* @retval OT_ERROR_BUSY Failed due to another operation is ongoing.
* @retval OT_ERROR_NOT_CAPABLE Not capable of resetting to bootloader.
*
*/
otError otInstanceResetToBootloader(otInstance *aInstance);

/**
* Deletes all the settings stored on non-volatile memory, and then triggers a platform reset.
*
Expand Down
14 changes: 14 additions & 0 deletions include/openthread/platform/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ extern "C" {
*/
void otPlatReset(otInstance *aInstance);

/**
* Performs a hardware reset on the platform to launch bootloader mode, if supported.
*
* Used when `OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE` is enabled.
*
* @param[in] aInstance The OpenThread instance structure.
*
* @retval OT_ERROR_NONE Reset to bootloader successfully.
* @retval OT_ERROR_BUSY Failed due to another operation is ongoing.
* @retval OT_ERROR_NOT_CAPABLE Not capable of resetting to bootloader.
*
*/
otError otPlatResetToBootloader(otInstance *aInstance);

/**
* Enumeration of possible reset reason codes.
*
Expand Down
18 changes: 17 additions & 1 deletion script/test
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@ build_simulation()
options+=("-DOT_LINK_METRICS_MANAGER=ON")
fi

if [[ ${OT_NODE_TYPE} == cli* ]]; then
# Only enable OT_PLATFORM_BOOTLOADER_MODE when testing cli.
# This is intended to test that the "reset bootloader" CLI command returns a "NotCapable" error

# Note: Setting this option to ON for all OT_NODE_TYPEs will cause the posix/expects CI check to fail.
# This is because the simulation RCP will have the SPINEL_CAP_RCP_RESET_TO_BOOTLOADER capability,
# causing the ot-cli POSIX app to send the reset to simulation RCP successfully instead of printing
# the expected error.
options+=("-DOT_PLATFORM_BOOTLOADER_MODE=ON")
fi

if [[ ${ot_extra_options[*]+x} ]]; then
options+=("${ot_extra_options[@]}")
fi
Expand All @@ -158,7 +169,12 @@ build_simulation()
build_posix()
{
local version="$1"
local options=("-DOT_MESSAGE_USE_HEAP=ON" "-DOT_THREAD_VERSION=${version}" "-DBUILD_TESTING=ON")
local options=(
"-DBUILD_TESTING=ON"
"-DOT_MESSAGE_USE_HEAP=ON"
"-DOT_PLATFORM_BOOTLOADER_MODE=ON"
"-DOT_THREAD_VERSION=${version}"
)

if [[ ${version} != "1.1" ]]; then
options+=("-DOT_DUA=ON")
Expand Down
11 changes: 11 additions & 0 deletions src/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3075,6 +3075,17 @@ Signal a platform reset.
> reset
```
### reset bootloader
Signal a platform reset to bootloader mode, if supported.
Requires `OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE`.
```bash
> reset bootloader
Done
```
### rloc16
Get the Thread RLOC16 value.
Expand Down
29 changes: 26 additions & 3 deletions src/cli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,34 @@ template <> otError Interpreter::Process<Cmd("version")>(Arg aArgs[])

template <> otError Interpreter::Process<Cmd("reset")>(Arg aArgs[])
{
OT_UNUSED_VARIABLE(aArgs);
otError error = OT_ERROR_NONE;

otInstanceReset(GetInstancePtr());
if (aArgs[0].IsEmpty())
{
otInstanceReset(GetInstancePtr());
}

return OT_ERROR_NONE;
#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE
/**
* @cli reset bootloader
* @code
* reset bootloader
* @endcode
* @cparam reset bootloader
* @par api_copy
* #otInstanceResetToBootloader
*/
else if (aArgs[0] == "bootloader")
{
error = otInstanceResetToBootloader(GetInstancePtr());
}
#endif
else
{
error = OT_ERROR_INVALID_COMMAND;
}

return error;
}

void Interpreter::ProcessLine(char *aBuf)
Expand Down
4 changes: 4 additions & 0 deletions src/core/api/instance_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
otError otInstanceResetToBootloader(otInstance *aInstance) { return AsCoreType(aInstance).ResetToBootloader(); }
#endif

#if OPENTHREAD_CONFIG_UPTIME_ENABLE
uint64_t otInstanceGetUptime(otInstance *aInstance) { return AsCoreType(aInstance).Get<Uptime>().GetUptime(); }

Expand Down
4 changes: 4 additions & 0 deletions src/core/instance/instance.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Error Instance::ResetToBootloader(void) { return otPlatResetToBootloader(this); }
#endif

#if OPENTHREAD_RADIO
void Instance::ResetRadioStack(void)
{
Expand Down
12 changes: 12 additions & 0 deletions src/core/instance/instance.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,18 @@ 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.
*
* @retval kErrorNone Reset to bootloader successfully.
* @retval kErrorBusy Failed due to another operation is ongoing.
* @retval kErrorNotCapable Not capable of resetting to bootloader.
*
*/
Error ResetToBootloader(void);
#endif

#if OPENTHREAD_RADIO
/**
* Resets the internal states of the radio.
Expand Down
11 changes: 11 additions & 0 deletions src/lib/spinel/radio_spinel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ RadioSpinel::RadioSpinel(void)
, mIsPromiscuous(false)
, mIsReady(false)
, mSupportsLogStream(false)
, mSupportsResetToBootloader(false)
, mIsTimeSynced(false)
#if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0
, mRcpFailureCount(0)
Expand Down Expand Up @@ -236,6 +237,11 @@ bool RadioSpinel::IsRcp(bool &aSupportsRcpApiVersion, bool &aSupportsRcpMinHostA
aSupportsRcpApiVersion = true;
}

if (capability == SPINEL_CAP_RCP_RESET_TO_BOOTLOADER)
{
mSupportsResetToBootloader = true;
}

if (capability == SPINEL_PROP_RCP_MIN_HOST_API_VERSION)
{
aSupportsRcpMinHostApiVersion = true;
Expand Down Expand Up @@ -1469,6 +1475,11 @@ otError RadioSpinel::SendReset(uint8_t aResetType)
uint8_t buffer[kMaxSpinelFrame];
spinel_ssize_t packed;

if ((aResetType == SPINEL_RESET_BOOTLOADER) && !mSupportsResetToBootloader)
{
ExitNow(error = OT_ERROR_NOT_CAPABLE);
}

// Pack the header, command and key
packed = spinel_datatype_pack(buffer, sizeof(buffer), SPINEL_DATATYPE_COMMAND_S SPINEL_DATATYPE_UINT8_S,
SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, SPINEL_CMD_RESET, aResetType);
Expand Down
12 changes: 7 additions & 5 deletions src/lib/spinel/radio_spinel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -808,10 +808,11 @@ class RadioSpinel
/**
* Tries to reset the co-processor.
*
* @prarm[in] aResetType The reset type, SPINEL_RESET_PLATFORM or SPINEL_RESET_STACK.
* @prarm[in] aResetType The reset type, SPINEL_RESET_PLATFORM, SPINEL_RESET_STACK, or SPINEL_RESET_BOOTLOADER.
*
* @retval OT_ERROR_NONE Successfully removed item from the property.
* @retval OT_ERROR_BUSY Failed due to another operation is on going.
* @retval OT_ERROR_NOT_CAPABLE Requested reset type is not supported by the co-processor
*
*/
otError SendReset(uint8_t aResetType);
Expand Down Expand Up @@ -1065,10 +1066,11 @@ class RadioSpinel
otExtAddress mIeeeEui64;

State mState;
bool mIsPromiscuous : 1; ///< Promiscuous mode.
bool mIsReady : 1; ///< NCP ready.
bool mSupportsLogStream : 1; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format.
bool mIsTimeSynced : 1; ///< Host has calculated the time difference between host and RCP.
bool mIsPromiscuous : 1; ///< Promiscuous mode.
bool mIsReady : 1; ///< NCP ready.
bool mSupportsLogStream : 1; ///< RCP supports `LOG_STREAM` property with OpenThread log meta-data format.
bool mSupportsResetToBootloader : 1; ///< RCP supports resetting into bootloader mode.
bool mIsTimeSynced : 1; ///< Host has calculated the time difference between host and RCP.

#if OPENTHREAD_SPINEL_CONFIG_RCP_RESTORATION_MAX_COUNT > 0

Expand Down
2 changes: 2 additions & 0 deletions src/lib/spinel/spinel.c
Original file line number Diff line number Diff line change
Expand Up @@ -1606,6 +1606,8 @@ const char *spinel_capability_to_cstr(spinel_capability_t capability)
{SPINEL_CAP_NET_THREAD_1_1, "NET_THREAD_1_1"},
{SPINEL_CAP_NET_THREAD_1_2, "NET_THREAD_1_2"},
{SPINEL_CAP_RCP_API_VERSION, "RCP_API_VERSION"},
{SPINEL_CAP_RCP_MIN_HOST_API_VERSION, "RCP_MIN_HOST_API_VERSION"},
{SPINEL_CAP_RCP_RESET_TO_BOOTLOADER, "RCP_RESET_TO_BOOTLOADER"},
{SPINEL_CAP_MAC_ALLOWLIST, "MAC_ALLOWLIST"},
{SPINEL_CAP_MAC_RAW, "MAC_RAW"},
{SPINEL_CAP_OOB_STEERING_DATA, "OOB_STEERING_DATA"},
Expand Down
12 changes: 8 additions & 4 deletions src/lib/spinel/spinel.h
Original file line number Diff line number Diff line change
Expand Up @@ -897,8 +897,9 @@ enum

enum
{
SPINEL_RESET_PLATFORM = 1,
SPINEL_RESET_STACK = 2,
SPINEL_RESET_PLATFORM = 1,
SPINEL_RESET_STACK = 2,
SPINEL_RESET_BOOTLOADER = 3,
};

enum
Expand Down Expand Up @@ -928,8 +929,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.
Expand Down Expand Up @@ -1284,6 +1287,7 @@ enum
SPINEL_CAP_RCP__BEGIN = 64,
SPINEL_CAP_RCP_API_VERSION = (SPINEL_CAP_RCP__BEGIN + 0),
SPINEL_CAP_RCP_MIN_HOST_API_VERSION = (SPINEL_CAP_RCP__BEGIN + 1),
SPINEL_CAP_RCP_RESET_TO_BOOTLOADER = (SPINEL_CAP_RCP__BEGIN + 2),
SPINEL_CAP_RCP__END = 80,

SPINEL_CAP_OPENTHREAD__BEGIN = 512,
Expand Down
12 changes: 12 additions & 0 deletions src/ncp/ncp_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
error = otInstanceResetToBootloader(mInstance);
}
#endif
else
#endif
{
Expand Down Expand Up @@ -1843,6 +1851,10 @@ template <> otError NcpBase::HandlePropertyGet<SPINEL_PROP_CAPS>(void)
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_RCP_MIN_HOST_API_VERSION));
#endif

#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_RCP_RESET_TO_BOOTLOADER));
#endif

#if OPENTHREAD_PLATFORM_POSIX
SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_POSIX));
#endif
Expand Down
9 changes: 9 additions & 0 deletions src/posix/platform/radio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,15 @@ otError otPlatRadioReceiveAt(otInstance *aInstance, uint8_t aChannel, uint32_t a
return OT_ERROR_NOT_IMPLEMENTED;
}

#if OPENTHREAD_CONFIG_PLATFORM_BOOTLOADER_MODE_ENABLE
otError otPlatResetToBootloader(otInstance *aInstance)
{
OT_UNUSED_VARIABLE(aInstance);

return GetRadioSpinel().SendReset(SPINEL_RESET_BOOTLOADER);
}
#endif

const otRadioSpinelMetrics *otSysGetRadioSpinelMetrics(void) { return GetRadioSpinel().GetRadioSpinelMetrics(); }

const otRcpInterfaceMetrics *otSysGetRcpInterfaceMetrics(void)
Expand Down
3 changes: 3 additions & 0 deletions tests/scripts/expect/cli-reset.exp
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,7 @@ send "panid\n"
expect "0xffff"
expect_line "Done"

send "reset bootloader\n"
expect_line "Error 27: NotCapable"

dispose_all
2 changes: 2 additions & 0 deletions tests/unit/test_platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,8 @@ OT_TOOL_WEAK void otPlatUartReceived(const uint8_t *, uint16_t) {}

OT_TOOL_WEAK void otPlatReset(otInstance *) {}

OT_TOOL_WEAK otError otPlatResetToBootloader(otInstance *) { return OT_ERROR_NOT_CAPABLE; }

OT_TOOL_WEAK otPlatResetReason otPlatGetResetReason(otInstance *) { return OT_PLAT_RESET_REASON_POWER_ON; }

OT_TOOL_WEAK void otPlatLog(otLogLevel, otLogRegion, const char *, ...) {}
Expand Down

0 comments on commit 0b0db37

Please sign in to comment.