diff --git a/examples/chip-tool/commands/pairing/Commands.h b/examples/chip-tool/commands/pairing/Commands.h index 388dc4741ffe30..cd244b56aded28 100644 --- a/examples/chip-tool/commands/pairing/Commands.h +++ b/examples/chip-tool/commands/pairing/Commands.h @@ -165,6 +165,14 @@ class PairBleThread : public PairingCommand {} }; +class PairBleWiFiOrThread : public PairingCommand +{ +public: + PairBleWiFiOrThread(CredentialIssuerCommands * credsIssuerConfig) : + PairingCommand("ble-wifi-thread", PairingMode::Ble, PairingNetworkType::WiFiOrThread, credsIssuerConfig) + {} +}; + class PairSoftAP : public PairingCommand { public: @@ -233,6 +241,7 @@ void registerCommandsPairing(Commands & commands, CredentialIssuerCommands * cre make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), diff --git a/examples/chip-tool/commands/pairing/PairingCommand.cpp b/examples/chip-tool/commands/pairing/PairingCommand.cpp index 76c8ac8a58cc19..a0437c53f56a7d 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.cpp +++ b/examples/chip-tool/commands/pairing/PairingCommand.cpp @@ -111,6 +111,10 @@ CommissioningParameters PairingCommand::GetCommissioningParameters() case PairingNetworkType::Thread: params.SetThreadOperationalDataset(mOperationalDataset); break; + case PairingNetworkType::WiFiOrThread: + params.SetWiFiCredentials(Controller::WiFiCredentials(mSSID, mPassword)); + params.SetThreadOperationalDataset(mOperationalDataset); + break; case PairingNetworkType::None: break; } diff --git a/examples/chip-tool/commands/pairing/PairingCommand.h b/examples/chip-tool/commands/pairing/PairingCommand.h index aaa8dc714e1017..9ff63e37878576 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.h +++ b/examples/chip-tool/commands/pairing/PairingCommand.h @@ -44,6 +44,7 @@ enum class PairingNetworkType None, WiFi, Thread, + WiFiOrThread, }; class PairingCommand : public CHIPCommand, @@ -85,6 +86,11 @@ class PairingCommand : public CHIPCommand, case PairingNetworkType::Thread: AddArgument("operationalDataset", &mOperationalDataset); break; + case PairingNetworkType::WiFiOrThread: + AddArgument("ssid", &mSSID); + AddArgument("password", &mPassword); + AddArgument("operationalDataset", &mOperationalDataset); + break; } switch (mode) diff --git a/src/controller/AutoCommissioner.cpp b/src/controller/AutoCommissioner.cpp index a72543853fa2d1..e8ccab8bd113a2 100644 --- a/src/controller/AutoCommissioner.cpp +++ b/src/controller/AutoCommissioner.cpp @@ -298,6 +298,22 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStage(CommissioningStag CommissioningStage AutoCommissioner::GetNextCommissioningStageNetworkSetup(CommissioningStage currentStage, CHIP_ERROR & lastErr) { + if (IsSecondaryNetworkSupported()) + { + if (IsTriedSecondaryNetwork()) + { + // Try secondary network interface. + return mDeviceCommissioningInfo.network.wifi.endpoint == kRootEndpointId ? CommissioningStage::kThreadNetworkSetup + : CommissioningStage::kWiFiNetworkSetup; + } + else + { + // Try primary network interface + return mDeviceCommissioningInfo.network.wifi.endpoint == kRootEndpointId ? CommissioningStage::kWiFiNetworkSetup + : CommissioningStage::kThreadNetworkSetup; + } + } + if (mParams.GetWiFiCredentials().HasValue() && mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId) { return CommissioningStage::kWiFiNetworkSetup; @@ -455,35 +471,15 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio case CommissioningStage::kNeedsNetworkCreds: return GetNextCommissioningStageNetworkSetup(currentStage, lastErr); case CommissioningStage::kWiFiNetworkSetup: - if (mParams.GetThreadOperationalDataset().HasValue() && - mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId) - { - return CommissioningStage::kThreadNetworkSetup; - } - else - { - return CommissioningStage::kFailsafeBeforeWiFiEnable; - } + return CommissioningStage::kFailsafeBeforeWiFiEnable; case CommissioningStage::kThreadNetworkSetup: - if (mParams.GetWiFiCredentials().HasValue() && mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId) - { - return CommissioningStage::kFailsafeBeforeWiFiEnable; - } - else - { - return CommissioningStage::kFailsafeBeforeThreadEnable; - } + return CommissioningStage::kFailsafeBeforeThreadEnable; case CommissioningStage::kFailsafeBeforeWiFiEnable: return CommissioningStage::kWiFiNetworkEnable; case CommissioningStage::kFailsafeBeforeThreadEnable: return CommissioningStage::kThreadNetworkEnable; case CommissioningStage::kWiFiNetworkEnable: - if (mParams.GetThreadOperationalDataset().HasValue() && - mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId) - { - return CommissioningStage::kThreadNetworkEnable; - } - else if (mParams.GetSkipCommissioningComplete().ValueOr(false)) + if (mParams.GetSkipCommissioningComplete().ValueOr(false)) { SetCASEFailsafeTimerIfNeeded(); return CommissioningStage::kCleanup; @@ -502,6 +498,10 @@ CommissioningStage AutoCommissioner::GetNextCommissioningStageInternal(Commissio return CommissioningStage::kEvictPreviousCaseSessions; case CommissioningStage::kEvictPreviousCaseSessions: return CommissioningStage::kFindOperationalForStayActive; + case CommissioningStage::kPrimaryOperationalNetworkFailed: + return CommissioningStage::kDisablePrimaryNetworkInterface; + case CommissioningStage::kDisablePrimaryNetworkInterface: + return GetNextCommissioningStageNetworkSetup(currentStage, lastErr); case CommissioningStage::kFindOperationalForStayActive: return CommissioningStage::kICDSendStayActive; case CommissioningStage::kICDSendStayActive: @@ -564,6 +564,8 @@ EndpointId AutoCommissioner::GetEndpoint(const CommissioningStage & stage) const case CommissioningStage::kThreadNetworkSetup: case CommissioningStage::kThreadNetworkEnable: return mDeviceCommissioningInfo.network.thread.endpoint; + case CommissioningStage::kDisablePrimaryNetworkInterface: + return kRootEndpointId; default: return kRootEndpointId; } @@ -729,6 +731,16 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio report.stageCompleted = CommissioningStage::kScanNetworks; } } + + if (err != CHIP_NO_ERROR && IsSecondaryNetworkSupported() && !IsTriedSecondaryNetwork() && + completionStatus.failedStage.HasValue() && completionStatus.failedStage.Value() >= kWiFiNetworkSetup && + completionStatus.failedStage.Value() <= kICDSendStayActive) + { + // Primary network failed, disable primary network interface and try secondary network interface. + SetTrySecondaryNetwork(); + err = CHIP_NO_ERROR; + report.stageCompleted = CommissioningStage::kPrimaryOperationalNetworkFailed; + } } else { diff --git a/src/controller/AutoCommissioner.h b/src/controller/AutoCommissioner.h index 3399e2776946de..78a01fd6e37fa7 100644 --- a/src/controller/AutoCommissioner.h +++ b/src/controller/AutoCommissioner.h @@ -94,6 +94,21 @@ class AutoCommissioner : public CommissioningDelegate mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId)); }; + // Helper function to Determine whether secondary network interface is supported. + // Only true if information is provided for both networks, and the target has endpoint + // for wifi and thread. + bool IsSecondaryNetworkSupported() const + { + return ((mParams.GetSupportsConcurrentConnection().ValueOr(false) && mParams.GetWiFiCredentials().HasValue() && + mDeviceCommissioningInfo.network.wifi.endpoint != kInvalidEndpointId) && + mParams.GetThreadOperationalDataset().HasValue() && + mDeviceCommissioningInfo.network.thread.endpoint != kInvalidEndpointId); + } + + void SetTrySecondaryNetwork() { mAttemptedSecondaryNetwork = true; } + bool IsTriedSecondaryNetwork() const { return mAttemptedSecondaryNetwork; } + bool mAttemptedSecondaryNetwork = false; + bool mStopCommissioning = false; DeviceCommissioner * mCommissioner = nullptr; diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 75c95ee20abc06..98b6b3b16197b4 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1801,6 +1802,12 @@ void DeviceCommissioner::OnBasicSuccess(void * context, const chip::app::DataMod commissioner->CommissioningStageComplete(CHIP_NO_ERROR); } +void DeviceCommissioner::OnInterfaceEnableWriteSuccessResponse(void * context) +{ + DeviceCommissioner * commissioner = static_cast(context); + commissioner->CommissioningStageComplete(CHIP_NO_ERROR); +} + void DeviceCommissioner::OnBasicFailure(void * context, CHIP_ERROR error) { ChipLogProgress(Controller, "Received failure response %s\n", chip::ErrorStr(error)); @@ -2740,6 +2747,18 @@ DeviceCommissioner::SendCommissioningCommand(DeviceProxy * device, const Request onFailureCb, NullOptional, timeout, (!fireAndForget) ? &mInvokeCancelFn : nullptr); } +template +CHIP_ERROR DeviceCommissioner::SendCommissioningWriteRequest(DeviceProxy * device, EndpointId endpoint, ClusterId cluster, + AttributeId attribute, const AttrType & requestData, + WriteResponseSuccessCallback successCb, + WriteResponseFailureCallback failureCb) +{ + auto onSuccessCb = [this, successCb](const app::ConcreteAttributePath & aPath) { successCb(this); }; + auto onFailureCb = [this, failureCb](const app::ConcreteAttributePath * aPath, CHIP_ERROR aError) { failureCb(this, aError); }; + return WriteAttribute(device->GetSecureSession().Value(), endpoint, cluster, attribute, requestData, onSuccessCb, onFailureCb, + NullOptional, nullptr, NullOptional); +} + void DeviceCommissioner::SendCommissioningReadRequest(DeviceProxy * proxy, Optional timeout, app::AttributePathParams * readPaths, size_t readPathsSize) { @@ -3419,11 +3438,31 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio &mOnDeviceConnectionFailureCallback #if CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES , - /* attemptCount = */ 3, &mOnDeviceConnectionRetryCallback + /* attemptCount = */ 1, &mOnDeviceConnectionRetryCallback #endif // CHIP_DEVICE_CONFIG_ENABLE_AUTOMATIC_CASE_RETRIES ); } break; + case CommissioningStage::kPrimaryOperationalNetworkFailed: { + // nothing to do. This stage indicates that the primary operation network failed and the network interface should be + // disabled later. + break; + } + case CommissioningStage::kDisablePrimaryNetworkInterface: { + NetworkCommissioning::Attributes::InterfaceEnabled::TypeInfo::Type request = false; + CHIP_ERROR err = SendCommissioningWriteRequest( + proxy, endpoint, NetworkCommissioning::Attributes::InterfaceEnabled::TypeInfo::GetClusterId(), + NetworkCommissioning::Attributes::InterfaceEnabled::TypeInfo::GetAttributeId(), request, + OnInterfaceEnableWriteSuccessResponse, OnBasicFailure); + if (err != CHIP_NO_ERROR) + { + // We won't get any async callbacks here, so just complete our stage. + ChipLogError(Controller, "Failed to send InterfaceEnabled write request: %" CHIP_ERROR_FORMAT, err.Format()); + CommissioningStageComplete(err); + return; + } + break; + } case CommissioningStage::kICDSendStayActive: { if (!(params.GetICDStayActiveDurationMsec().HasValue())) { diff --git a/src/controller/CHIPDeviceController.h b/src/controller/CHIPDeviceController.h index 8bef525e9cd773..7ff21922b02591 100644 --- a/src/controller/CHIPDeviceController.h +++ b/src/controller/CHIPDeviceController.h @@ -965,6 +965,8 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, OnICDManagementStayActiveResponse(void * context, const app::Clusters::IcdManagement::Commands::StayActiveResponse::DecodableType & data); + static void OnInterfaceEnableWriteSuccessResponse(void * context); + /** * @brief * This function processes the CSR sent by the device. @@ -1025,6 +1027,10 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, Optional timeout = NullOptional, bool fireAndForget = false); void SendCommissioningReadRequest(DeviceProxy * proxy, Optional timeout, app::AttributePathParams * readPaths, size_t readPathsSize); + template + CHIP_ERROR SendCommissioningWriteRequest(DeviceProxy * device, EndpointId endpoint, ClusterId cluster, AttributeId attribute, + const AttrType & requestData, WriteResponseSuccessCallback successCb, + WriteResponseFailureCallback failureCb); void CancelCommissioningInteractions(); void CancelCASECallbacks(); diff --git a/src/controller/CommissioningDelegate.cpp b/src/controller/CommissioningDelegate.cpp index 30f469932a800a..7afecc8ac2be59 100644 --- a/src/controller/CommissioningDelegate.cpp +++ b/src/controller/CommissioningDelegate.cpp @@ -136,6 +136,12 @@ const char * StageToString(CommissioningStage stage) case kNeedsNetworkCreds: return "NeedsNetworkCreds"; + case kPrimaryOperationalNetworkFailed: + return "kPrimaryOperationalNetworkFailed"; + + case kDisablePrimaryNetworkInterface: + return "kDisablePrimaryNetworkInterface"; + default: return "???"; } diff --git a/src/controller/CommissioningDelegate.h b/src/controller/CommissioningDelegate.h index 57d6a0c9a8da53..c1885bcc3e7692 100644 --- a/src/controller/CommissioningDelegate.h +++ b/src/controller/CommissioningDelegate.h @@ -79,6 +79,9 @@ enum CommissioningStage : uint8_t /// Call CHIPDeviceController::NetworkCredentialsReady() when CommissioningParameters is populated with /// network credentials to use in kWiFiNetworkSetup or kThreadNetworkSetup steps. kNeedsNetworkCreds, + kPrimaryOperationalNetworkFailed, ///< Indicate that the primary operational network (on root endpoint) failed, should disable + ///< the primary network interface later. + kDisablePrimaryNetworkInterface, ///< Send InterfaceEnabled write request to the device. }; enum class ICDRegistrationStrategy : uint8_t diff --git a/src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp b/src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp index bbeaf6cdbc7169..aed25e2356cbcc 100644 --- a/src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp +++ b/src/platform/ESP32/ConnectivityManagerImpl_WiFi.cpp @@ -391,6 +391,10 @@ CHIP_ERROR ConnectivityManagerImpl::InitWiFi() mWiFiStationMode = kWiFiStationMode_Disabled; mWiFiStationState = kWiFiStationState_NotConnected; mWiFiStationReconnectInterval = System::Clock::Milliseconds32(CHIP_DEVICE_CONFIG_WIFI_STATION_RECONNECT_INTERVAL); + if (!NetworkCommissioning::ESPWiFiDriver::GetInstance().GetEnabled()) + { + mWiFiStationMode = kWiFiStationMode_ApplicationControlled; + } #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_AP mLastAPDemandTime = System::Clock::kZero; diff --git a/src/platform/ESP32/NetworkCommissioningDriver.cpp b/src/platform/ESP32/NetworkCommissioningDriver.cpp index 2871c4c3f2031d..bf4bc98a1fbb87 100644 --- a/src/platform/ESP32/NetworkCommissioningDriver.cpp +++ b/src/platform/ESP32/NetworkCommissioningDriver.cpp @@ -147,6 +147,11 @@ CHIP_ERROR ESPWiFiDriver::CommitConfiguration() CHIP_ERROR ESPWiFiDriver::RevertConfiguration() { mStagingNetwork = mSavedNetwork; + if (!GetEnabled()) + { + // When reverting, set InterfaceEnabled to default value (true). + ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Delete(kInterfaceEnabled)); + } return CHIP_NO_ERROR; } @@ -196,6 +201,12 @@ Status ESPWiFiDriver::ReorderNetwork(ByteSpan networkId, uint8_t index, MutableC CHIP_ERROR ESPWiFiDriver::ConnectWiFiNetwork(const char * ssid, uint8_t ssidLen, const char * key, uint8_t keyLen) { + if (!GetEnabled()) + { + // Set InterfaceEnabled to default value (true). + ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Delete(kInterfaceEnabled)); + } + // If device is already connected to WiFi, then disconnect the WiFi, // clear the WiFi configurations and add the newly provided WiFi configurations. if (chip::DeviceLayer::Internal::ESP32Utils::IsStationProvisioned()) @@ -307,6 +318,44 @@ void ESPWiFiDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * callbac } } +CHIP_ERROR ESPWiFiDriver::SetEnabled(bool enabled) +{ + if (enabled == GetEnabled()) + { + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kInterfaceEnabled, &enabled, sizeof(enabled))); + + if (!enabled) + { + if (chip::DeviceLayer::Internal::ESP32Utils::IsStationProvisioned()) + { + ChipLogProgress(DeviceLayer, "Disconnecting WiFi station interface"); + esp_err_t err = esp_wifi_disconnect(); + if (err != ESP_OK) + { + ChipLogError(DeviceLayer, "esp_wifi_disconnect() failed: %s", esp_err_to_name(err)); + return chip::DeviceLayer::Internal::ESP32Utils::MapError(err); + } + return ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_ApplicationControlled); + } + } + else + { + ReturnErrorOnFailure(ConnectivityMgr().SetWiFiStationMode(ConnectivityManager::kWiFiStationMode_Enabled)); + } + return CHIP_NO_ERROR; +} + +bool ESPWiFiDriver::GetEnabled() +{ + bool value; + // InterfaceEnabled default value is true. + VerifyOrReturnValue(PersistedStorage::KeyValueStoreMgr().Get(kInterfaceEnabled, &value, sizeof(value)) == CHIP_NO_ERROR, true); + return value; +} + CHIP_ERROR ESPWiFiDriver::StartScanWiFiNetworks(ByteSpan ssid) { esp_err_t err = ESP_OK; diff --git a/src/platform/ESP32/NetworkCommissioningDriver.h b/src/platform/ESP32/NetworkCommissioningDriver.h index 447d6346dcbd1c..5e85c0e61a2e08 100644 --- a/src/platform/ESP32/NetworkCommissioningDriver.h +++ b/src/platform/ESP32/NetworkCommissioningDriver.h @@ -94,6 +94,8 @@ class ESPWiFiDriver final : public WiFiDriver // BaseDriver NetworkIterator * GetNetworks() override { return new WiFiNetworkIterator(this); } CHIP_ERROR Init(NetworkStatusChangeCallback * networkStatusChangeCallback) override; + CHIP_ERROR SetEnabled(bool enabled) override; + bool GetEnabled() override; void Shutdown() override; // WirelessDriver @@ -131,6 +133,7 @@ class ESPWiFiDriver final : public WiFiDriver } private: + static constexpr const char * kInterfaceEnabled = "g/esp/en"; bool NetworkMatch(const WiFiNetwork & network, ByteSpan networkId); CHIP_ERROR StartScanWiFiNetworks(ByteSpan ssid); diff --git a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp index 0a961a9f8e4afa..af517afe62ca20 100644 --- a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp +++ b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.cpp @@ -95,6 +95,12 @@ CHIP_ERROR GenericThreadDriver::RevertConfiguration() // since the fail-safe was armed, so return with no error. ReturnErrorCodeIf(error == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND, CHIP_NO_ERROR); + if (!GetEnabled()) + { + // If backup is found, set InterfaceEnabled to default value (true). + ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Delete(kInterfaceEnabled)); + } + ChipLogProgress(NetworkProvisioning, "Reverting Thread operational dataset"); if (error == CHIP_NO_ERROR) @@ -166,6 +172,12 @@ void GenericThreadDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * c { NetworkCommissioning::Status status = MatchesNetworkId(mStagingNetwork, networkId); + if (!GetEnabled()) + { + // Set InterfaceEnabled to default value (true). + ReturnOnFailure(PersistedStorage::KeyValueStoreMgr().Delete(kInterfaceEnabled)); + } + if (status == Status::kSuccess && BackupConfiguration() != CHIP_NO_ERROR) { status = Status::kUnknownError; @@ -183,6 +195,31 @@ void GenericThreadDriver::ConnectNetwork(ByteSpan networkId, ConnectCallback * c } } +CHIP_ERROR GenericThreadDriver::SetEnabled(bool enabled) +{ + if (enabled == GetEnabled()) + { + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(PersistedStorage::KeyValueStoreMgr().Put(kInterfaceEnabled, &enabled, sizeof(enabled))); + + if ((!enabled && DeviceLayer::ThreadStackMgrImpl().IsThreadEnabled()) || + (enabled && DeviceLayer::ThreadStackMgrImpl().IsThreadProvisioned())) + { + ReturnErrorOnFailure(DeviceLayer::ThreadStackMgrImpl().SetThreadEnabled(enabled)); + } + return CHIP_NO_ERROR; +} + +bool GenericThreadDriver::GetEnabled() +{ + bool value; + // InterfaceEnabled default value is true. + VerifyOrReturnValue(PersistedStorage::KeyValueStoreMgr().Get(kInterfaceEnabled, &value, sizeof(value)) == CHIP_NO_ERROR, true); + return value; +} + void GenericThreadDriver::ScanNetworks(ThreadDriver::ScanCallback * callback) { if (DeviceLayer::ThreadStackMgrImpl().StartThreadScan(callback) != CHIP_NO_ERROR) diff --git a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h index 28dc8f176ddd1f..e98b9393818abe 100644 --- a/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h +++ b/src/platform/OpenThread/GenericNetworkCommissioningThreadDriver.h @@ -90,6 +90,8 @@ class GenericThreadDriver final : public ThreadDriver // BaseDriver NetworkIterator * GetNetworks() override { return new ThreadNetworkIterator(this); } CHIP_ERROR Init(Internal::BaseDriver::NetworkStatusChangeCallback * statusChangeCallback) override; + CHIP_ERROR SetEnabled(bool enabled) override; + bool GetEnabled() override; void Shutdown() override; // WirelessDriver @@ -114,6 +116,7 @@ class GenericThreadDriver final : public ThreadDriver void ScanNetworks(ThreadDriver::ScanCallback * callback) override; private: + static constexpr const char * kInterfaceEnabled = "g/gtd/en"; uint8_t scanNetworkTimeoutSeconds; uint8_t connectNetworkTimeout; static void OnThreadStateChangeHandler(const ChipDeviceEvent * event, intptr_t arg); diff --git a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp index cf1894cf93fc74..5ef4d8e748d08a 100644 --- a/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp +++ b/src/platform/OpenThread/GenericThreadStackManagerImpl_OpenThread.hpp @@ -1093,6 +1093,9 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::DoInit(otInstanc CHIP_ERROR err = CHIP_NO_ERROR; otError otErr = OT_ERROR_NONE; + // If InterfaceEnabled is false, do not start Thread + bool InterfaceEnabled = true; + // Arrange for OpenThread errors to be translated to text. RegisterOpenThreadErrorFormatter(); @@ -1130,8 +1133,15 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::DoInit(otInstanc memset(&mSrpClient, 0, sizeof(mSrpClient)); #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_SRP_CLIENT + initNetworkCommissioningThreadDriver(); + +#ifndef _NO_NETWORK_COMMISSIONING_DRIVER_ + InterfaceEnabled = sGenericThreadDriver.GetEnabled(); + ChipLogError(DeviceLayer, "%s:%d interface:%d", __FILE__, __LINE__, InterfaceEnabled); +#endif + // If the Thread stack has been provisioned, but is not currently enabled, enable it now. - if (otThreadGetDeviceRole(mOTInst) == OT_DEVICE_ROLE_DISABLED && otDatasetIsCommissioned(otInst)) + if (InterfaceEnabled && otThreadGetDeviceRole(mOTInst) == OT_DEVICE_ROLE_DISABLED && otDatasetIsCommissioned(otInst)) { // Enable the Thread IPv6 interface. otErr = otIp6SetEnabled(otInst, true); @@ -1143,8 +1153,6 @@ CHIP_ERROR GenericThreadStackManagerImpl_OpenThread::DoInit(otInstanc ChipLogProgress(DeviceLayer, "OpenThread ifconfig up and thread start"); } - initNetworkCommissioningThreadDriver(); - exit: ChipLogProgress(DeviceLayer, "OpenThread started: %s", otThreadErrorToString(otErr));