diff --git a/examples/drivers/windows/include/otLwfIoctl.h b/examples/drivers/windows/include/otLwfIoctl.h index 2b2c3d025..08fdc3827 100644 --- a/examples/drivers/windows/include/otLwfIoctl.h +++ b/examples/drivers/windows/include/otLwfIoctl.h @@ -677,9 +677,14 @@ typedef struct otCommissionConfig #define IOCTL_OTLWF_OT_FACTORY_RESET \ OTLWF_CTL_CODE(192, METHOD_BUFFERED, FILE_WRITE_DATA) // GUID - InterfaceGuid + +#define IOCTL_OTLWF_OT_THREAD_AUTO_START \ + OTLWF_CTL_CODE(193, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA) + // GUID - InterfaceGuid + // BOOLEAN - aAutoStart // OpenThread function IOCTL codes #define MIN_OTLWF_IOCTL_FUNC_CODE 100 -#define MAX_OTLWF_IOCTL_FUNC_CODE 192 +#define MAX_OTLWF_IOCTL_FUNC_CODE 193 #endif //__OTLWFIOCTL_H__ diff --git a/examples/drivers/windows/otApi/otApi.cpp b/examples/drivers/windows/otApi/otApi.cpp index c044a6694..87077fb88 100644 --- a/examples/drivers/windows/otApi/otApi.cpp +++ b/examples/drivers/windows/otApi/otApi.cpp @@ -1244,6 +1244,30 @@ otThreadStop( return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_THREAD, (BOOLEAN)FALSE)); } +OTAPI +ThreadError +OTCALL +otThreadSetAutoStart( + _In_ otInstance *aInstance, + bool aStartAutomatically + ) +{ + if (aInstance == nullptr) return kThreadError_InvalidArgs; + return DwordToThreadError(SetIOCTL(aInstance, IOCTL_OTLWF_OT_THREAD_AUTO_START, (BOOLEAN)(aStartAutomatically ? TRUE : FALSE))); +} + +OTAPI +bool +OTCALL +otThreadGetAutoStart( + otInstance *aInstance + ) +{ + BOOLEAN Result = FALSE; + if (aInstance) (void)QueryIOCTL(aInstance, IOCTL_OTLWF_OT_THREAD_AUTO_START, &Result); + return Result != FALSE; +} + OTAPI bool OTCALL diff --git a/examples/drivers/windows/otLwf/iocontrol.c b/examples/drivers/windows/otLwf/iocontrol.c index d2e3843d3..275796c94 100644 --- a/examples/drivers/windows/otLwf/iocontrol.c +++ b/examples/drivers/windows/otLwf/iocontrol.c @@ -137,7 +137,8 @@ OTLWF_IOCTL_HANDLER IoCtls[] = { "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_GET", REF_IOCTL_FUNC(otSendMgmtCommissionerGet) }, { "IOCTL_OTLWF_OT_SEND_MGMT_COMMISSIONER_SET", REF_IOCTL_FUNC(otSendMgmtCommissionerSet) }, { "IOCTL_OTLWF_OT_KEY_SWITCH_GUARDTIME", REF_IOCTL_FUNC_WITH_TUN(otKeySwitchGuardtime) }, - { "IOCTL_OTLWF_OT_FACTORY_RESET", REF_IOCTL_FUNC(otFactoryReset) } + { "IOCTL_OTLWF_OT_FACTORY_RESET", REF_IOCTL_FUNC(otFactoryReset) }, + { "IOCTL_OTLWF_OT_THREAD_AUTO_START", REF_IOCTL_FUNC(otThreadAutoStart) } }; static_assert(ARRAYSIZE(IoCtls) == (MAX_OTLWF_IOCTL_FUNC_CODE - MIN_OTLWF_IOCTL_FUNC_CODE) + 1, @@ -6072,3 +6073,41 @@ otLwfTunIoCtl_otKeySwitchGuardtime_Handler( } return status; } + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +otLwfIoCtl_otThreadAutoStart( + _In_ PMS_FILTER pFilter, + _In_reads_bytes_(InBufferLength) + PUCHAR InBuffer, + _In_ ULONG InBufferLength, + _Out_writes_bytes_(*OutBufferLength) + PVOID OutBuffer, + _Inout_ PULONG OutBufferLength + ) +{ + NTSTATUS status = STATUS_INVALID_PARAMETER; + + if (InBufferLength >= sizeof(BOOLEAN)) + { + status = + ThreadErrorToNtstatus( + otThreadSetAutoStart( + pFilter->otCtx, + *(BOOLEAN*)InBuffer != FALSE) + ); + *OutBufferLength = 0; + } + else if (*OutBufferLength >= sizeof(BOOLEAN)) + { + *(BOOLEAN*)OutBuffer = otThreadGetAutoStart(pFilter->otCtx) ? TRUE : FALSE; + *OutBufferLength = sizeof(BOOLEAN); + status = STATUS_SUCCESS; + } + else + { + *OutBufferLength = 0; + } + + return status; +} diff --git a/examples/drivers/windows/otLwf/iocontrol.h b/examples/drivers/windows/otLwf/iocontrol.h index 350ffedb2..2b3d58ee2 100644 --- a/examples/drivers/windows/otLwf/iocontrol.h +++ b/examples/drivers/windows/otLwf/iocontrol.h @@ -224,5 +224,6 @@ DECL_IOCTL_FUNC(otSendMgmtCommissionerGet); DECL_IOCTL_FUNC(otSendMgmtCommissionerSet); DECL_IOCTL_FUNC_WITH_TUN2(otKeySwitchGuardtime); DECL_IOCTL_FUNC(otFactoryReset); +DECL_IOCTL_FUNC(otThreadAutoStart); #endif // _IOCONTROL_H diff --git a/include/openthread.h b/include/openthread.h index 98343d9c2..1dc1bfaf4 100644 --- a/include/openthread.h +++ b/include/openthread.h @@ -315,6 +315,27 @@ OTAPI ThreadError OTCALL otThreadStart(otInstance *aInstance); */ OTAPI ThreadError OTCALL otThreadStop(otInstance *aInstance); +/** + * This function configures the Thread stack to automatically start on reinitialization. + * It has no effect on the current Thread state. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * @param[in] aStartAutomatically TRUE to automatically start; FALSE to not automatically start. + * + */ +OTAPI ThreadError OTCALL otThreadSetAutoStart(otInstance *aInstance, bool aStartAutomatically); + +/** + * This function queries if the Thread stack is configured to automatically start on reinitialization. + * + * @param[in] aInstance A pointer to an OpenThread instance. + * + * @retval TRUE It is configured to automatically start. + * @retval FALSE It is not configured to automatically start. + * + */ +OTAPI bool OTCALL otThreadGetAutoStart(otInstance *aInstance); + /** * This function indicates whether a node is the only router on the network. * diff --git a/src/cli/README.md b/src/cli/README.md index 366a44417..028decd04 100644 --- a/src/cli/README.md +++ b/src/cli/README.md @@ -7,6 +7,7 @@ OpenThread test scripts use the CLI to execute test cases. ## OpenThread Command List +* [autostart](#autostart) * [blacklist](#blacklist) * [channel](#channel) * [child](#child-list) @@ -63,6 +64,34 @@ OpenThread test scripts use the CLI to execute test cases. ## OpenThread Command Details +### autostart true + +Automatically start Thread on initialization. + +```bash +> autostart true +Done +``` + +### autostart false + +Don't automatically start Thread on initialization. + +```bash +> autostart false +Done +``` + +### autostart + +Show the status of automatically starting Thread on initialization. + +```bash +> autostart +false +Done +``` + ### blacklist List the blacklist entries. diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index 3e503e02d..356929aa0 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -67,6 +67,7 @@ namespace Cli { const struct Command Interpreter::sCommands[] = { { "help", &Interpreter::ProcessHelp }, + { "autostart", &Interpreter::ProcessAutoStart }, { "blacklist", &Interpreter::ProcessBlacklist }, { "bufferinfo", &Interpreter::ProcessBufferInfo }, { "channel", &Interpreter::ProcessChannel }, @@ -247,6 +248,37 @@ void Interpreter::ProcessHelp(int argc, char *argv[]) (void)argv; } +void Interpreter::ProcessAutoStart(int argc, char *argv[]) +{ + ThreadError error = kThreadError_None; + + if (argc == 0) + { + if (otThreadGetAutoStart(mInstance)) + { + sServer->OutputFormat("true\r\n"); + } + else + { + sServer->OutputFormat("false\r\n"); + } + } + else if (strcmp(argv[0], "true") == 0) + { + error = otThreadSetAutoStart(mInstance, true); + } + else if (strcmp(argv[0], "false") == 0) + { + error = otThreadSetAutoStart(mInstance, false); + } + else + { + error = kThreadError_InvalidArgs; + } + + AppendResult(error); +} + void Interpreter::ProcessBlacklist(int argc, char *argv[]) { ThreadError error = kThreadError_None; diff --git a/src/cli/cli.hpp b/src/cli/cli.hpp index cc3528a4f..2bee59c15 100644 --- a/src/cli/cli.hpp +++ b/src/cli/cli.hpp @@ -141,6 +141,7 @@ private: void OutputBytes(const uint8_t *aBytes, uint8_t aLength); void ProcessHelp(int argc, char *argv[]); + void ProcessAutoStart(int argc, char *argv[]); void ProcessBufferInfo(int argc, char *argv[]); void ProcessBlacklist(int argc, char *argv[]); void ProcessChannel(int argc, char *argv[]); diff --git a/src/core/common/settings.hpp b/src/core/common/settings.hpp index f53c0f987..4dd0d22e5 100644 --- a/src/core/common/settings.hpp +++ b/src/core/common/settings.hpp @@ -44,11 +44,12 @@ extern "C" { */ enum { - kKeyActiveDataset = 0x0001, - kKeyPendingDataset = 0x0002, - kKeyNetworkInfo = 0x0003, - kKeyParentInfo = 0x0004, - kKeyChildInfo = 0x0005, + kKeyActiveDataset = 0x0001, + kKeyPendingDataset = 0x0002, + kKeyNetworkInfo = 0x0003, + kKeyParentInfo = 0x0004, + kKeyChildInfo = 0x0005, + kKeyThreadAutoStart = 0x0006, }; #ifdef __cplusplus diff --git a/src/core/openthread-core-default-config.h b/src/core/openthread-core-default-config.h index afd79186e..68ec7c388 100644 --- a/src/core/openthread-core-default-config.h +++ b/src/core/openthread-core-default-config.h @@ -589,4 +589,14 @@ #define OPENTHREAD_CONFIG_ENABLE_SOFTWARE_ENERGY_SCAN 0 #endif +/** + * @def OPENTHREAD_CONFIG_ENABLE_AUTO_START_SUPPORT + * + * Define to 1 if you want to enable auto start logic. + * + */ +#ifndef OPENTHREAD_CONFIG_ENABLE_AUTO_START_SUPPORT +#define OPENTHREAD_CONFIG_ENABLE_AUTO_START_SUPPORT 1 +#endif + #endif // OPENTHREAD_CORE_DEFAULT_CONFIG_H_ diff --git a/src/core/openthread.cpp b/src/core/openthread.cpp index f7fb0527e..d9570592a 100644 --- a/src/core/openthread.cpp +++ b/src/core/openthread.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -1207,6 +1208,31 @@ ThreadError otSetPreferredRouterId(otInstance *aInstance, uint8_t aRouterId) return aInstance->mThreadNetif.GetMle().SetPreferredRouterId(aRouterId); } +void otInstancePostConstructor(otInstance *aInstance) +{ + // restore datasets and network information + otPlatSettingsInit(aInstance); + aInstance->mThreadNetif.GetMle().Restore(); + +#if OPENTHREAD_CONFIG_ENABLE_AUTO_START_SUPPORT + + // If auto start is configured, do that now + if (otThreadGetAutoStart(aInstance)) + { + if (otInterfaceUp(aInstance) == kThreadError_None) + { + // Only try to start Thread if we could bring up the interface + if (otThreadStart(aInstance) != kThreadError_None) + { + // Bring the interface down if Thread failed to start + otInterfaceDown(aInstance); + } + } + } + +#endif +} + #ifdef OPENTHREAD_MULTIPLE_INSTANCE otInstance *otInstanceInit(void *aInstanceBuffer, size_t *aInstanceBufferSize) @@ -1226,9 +1252,8 @@ otInstance *otInstanceInit(void *aInstanceBuffer, size_t *aInstanceBufferSize) // Construct the context aInstance = new(aInstanceBuffer)otInstance(); - // restore datasets and network information - otPlatSettingsInit(aInstance); - aInstance->mThreadNetif.GetMle().Restore(); + // Execute post constructor operations + otInstancePostConstructor(aInstance); exit: @@ -1249,9 +1274,8 @@ otInstance *otInstanceInit() // Construct the context sInstance = new(&sInstanceRaw)otInstance(); - // restore datasets and network information - otPlatSettingsInit(sInstance); - sInstance->mThreadNetif.GetMle().Restore(); + // Execute post constructor operations + otInstancePostConstructor(sInstance); exit: @@ -1370,6 +1394,36 @@ ThreadError otThreadStop(otInstance *aInstance) return error; } +ThreadError otThreadSetAutoStart(otInstance *aInstance, bool aStartAutomatically) +{ +#if OPENTHREAD_CONFIG_ENABLE_AUTO_START_SUPPORT + uint8_t autoStart = aStartAutomatically ? 1 : 0; + return otPlatSettingsSet(aInstance, kKeyThreadAutoStart, &autoStart, sizeof(autoStart)); +#else + (void)aInstance; + (void)aStartAutomatically; + return kThreadError_NotImplemented; +#endif +} + +bool otThreadGetAutoStart(otInstance *aInstance) +{ +#if OPENTHREAD_CONFIG_ENABLE_AUTO_START_SUPPORT + uint8_t autoStart = 0; + uint16_t autoStartLength = sizeof(autoStart); + + if (otPlatSettingsGet(aInstance, kKeyThreadAutoStart, 0, &autoStart, &autoStartLength) != kThreadError_None) + { + autoStart = 0; + } + + return autoStart != 0; +#else + (void)aInstance; + return false; +#endif +} + bool otIsSingleton(otInstance *aInstance) { return aInstance->mThreadNetif.GetMle().IsSingleton();