From 1021104866ba2406d8ca7773dcfbf5a1904eef7a Mon Sep 17 00:00:00 2001 From: simonhmorris1 <112178216+simonhmorris1@users.noreply.github.com> Date: Wed, 22 Nov 2023 09:29:14 +0000 Subject: [PATCH] Implement Non concurrent mode (#30201) * Add non-concurrent SupportsConcurrentConnection * Address CI build issues (#29865) * Fix style issue (#29865) * Fix read of SupportsConcurrentConnection (#29865) * Correct intermittent missing SSID(#29865) * ConnectNetworkResponse Supression (#29865) * Add non-concurrent SupportsConcurrentConnection * Address CI build issues (#29865) * Fix style issue (#29865) * Fix read of SupportsConcurrentConnection (#29865) * Fix merge issue with ICD attributes(#29865) * Fix darwin-tests workflow file syntax. (#30162) There were extra curly braces that failed on some (but not all?) CI runs. * Add non-concurrent SupportsConcurrentConnection * Address CI build issues (#29865) * Fix style issue (#29865) * Fix read of SupportsConcurrentConnection (#29865) * Fix merge issue with ICD attributes(#29865) * Only start WiFi on BLE Commissioning pass(#29865) * Remove use of Breadcrumb::Get from BLE (#29865) * Add non-concurrent SupportsConcurrentConnection * Address CI build issues (#29865) * Fix style issue (#29865) * Fix read of SupportsConcurrentConnection (#29865) * Fix merge issue with ICD attributes(#29865) * Only start WiFi on BLE Commissioning pass(#29865) * Remove use of Breadcrumb::Get from BLE (#29865) * Tidy comments (#29865) * Default on error, check timeout, tidy up (#29865) * Make log messages user friendly (#29865) * Change to compile time non-concurrent mode(#29865) * Restyled by whitespace * Restyled by clang-format * Improve code style (#29865) * Restyled by clang-format * Add CommandHandler issue reference 30576 (#29865) --------- Co-authored-by: Boris Zbarsky Co-authored-by: Restyled.io --- examples/platform/linux/AppMain.cpp | 17 ++-- .../network-commissioning.cpp | 32 +++++++- .../network-commissioning.h | 1 + src/app/server/CommissioningWindowManager.cpp | 10 ++- src/controller/AutoCommissioner.cpp | 41 +++++----- src/controller/CHIPDeviceController.cpp | 81 +++++++++++++++---- src/controller/CommissioningDelegate.h | 22 +++-- src/include/platform/CHIPDeviceConfig.h | 13 +++ src/include/platform/CHIPDeviceEvent.h | 12 +++ src/include/platform/DeviceControlServer.h | 3 +- src/platform/DeviceControlServer.cpp | 14 ++++ src/platform/Linux/BLEManagerImpl.cpp | 4 + .../Linux/ConnectivityManagerImpl.cpp | 18 +++++ src/platform/Linux/ConnectivityManagerImpl.h | 1 + 14 files changed, 220 insertions(+), 49 deletions(-) diff --git a/examples/platform/linux/AppMain.cpp b/examples/platform/linux/AppMain.cpp index 56e6edd44687f2..b4eb6ecfd3baab 100644 --- a/examples/platform/linux/AppMain.cpp +++ b/examples/platform/linux/AppMain.cpp @@ -20,6 +20,7 @@ #include #include "app/clusters/network-commissioning/network-commissioning.h" +#include #include #include #include @@ -238,15 +239,15 @@ void InitNetworkCommissioning() using chip::Shell::Engine; #endif -#if CHIP_DEVICE_CONFIG_ENABLE_WPA +#if CHIP_DEVICE_CONFIG_ENABLE_WPA && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION /* * The device shall check every kWiFiStartCheckTimeUsec whether Wi-Fi management * has been fully initialized. If after kWiFiStartCheckAttempts Wi-Fi management * still hasn't been initialized, the device configuration is reset, and device * needs to be paired again. */ -static constexpr useconds_t kWiFiStartCheckTimeUsec = 100 * 1000; // 100 ms -static constexpr uint8_t kWiFiStartCheckAttempts = 5; +static constexpr useconds_t kWiFiStartCheckTimeUsec = WIFI_START_CHECK_TIME_USEC; +static constexpr uint8_t kWiFiStartCheckAttempts = WIFI_START_CHECK_ATTEMPTS; #endif namespace { @@ -264,6 +265,11 @@ void EventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg) { ChipLogProgress(DeviceLayer, "Receive kCHIPoBLEConnectionEstablished"); } + else if ((event->Type == chip::DeviceLayer::DeviceEventType::kInternetConnectivityChange)) + { + // Restart the server on connectivity change + app::DnssdServer::Instance().StartServer(); + } } void Cleanup() @@ -298,7 +304,7 @@ void StopSignalHandler(int signal) } // namespace -#if CHIP_DEVICE_CONFIG_ENABLE_WPA +#if CHIP_DEVICE_CONFIG_ENABLE_WPA && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION static bool EnsureWiFiIsStarted() { for (int cnt = 0; cnt < kWiFiStartCheckAttempts; cnt++) @@ -462,9 +468,10 @@ int ChipLinuxAppInit(int argc, char * const argv[], OptionSet * customOptions, DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(true); #endif -#if CHIP_DEVICE_CONFIG_ENABLE_WPA +#if CHIP_DEVICE_CONFIG_ENABLE_WPA && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION if (LinuxDeviceOptions::GetInstance().mWiFi) { + // Start WiFi management in Concurrent mode DeviceLayer::ConnectivityMgrImpl().StartWiFiManagement(); if (!EnsureWiFiIsStarted()) { diff --git a/src/app/clusters/network-commissioning/network-commissioning.cpp b/src/app/clusters/network-commissioning/network-commissioning.cpp index 68dfed344e0da6..471b6038b85b09 100644 --- a/src/app/clusters/network-commissioning/network-commissioning.cpp +++ b/src/app/clusters/network-commissioning/network-commissioning.cpp @@ -171,11 +171,18 @@ void Instance::InvokeCommand(HandlerContext & ctxt) ctxt, [this](HandlerContext & ctx, const auto & req) { HandleRemoveNetwork(ctx, req); }); return; - case Commands::ConnectNetwork::Id: + case Commands::ConnectNetwork::Id: { VerifyOrReturn(mFeatureFlags.Has(Feature::kWiFiNetworkInterface) || mFeatureFlags.Has(Feature::kThreadNetworkInterface)); +#if CONFIG_NETWORK_LAYER_BLE && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION + // If commissionee does not support Concurrent Connections, request the BLE to be stopped. + // Start the ConnectNetwork, but this will not complete until the BLE is off. + ChipLogProgress(NetworkProvisioning, "Closing BLE connections due to non-concurrent mode"); + DeviceLayer::DeviceControlServer::DeviceControlSvr().PostCloseAllBLEConnectionsToOperationalNetworkEvent(); +#endif HandleCommand( ctxt, [this](HandlerContext & ctx, const auto & req) { HandleConnectNetwork(ctx, req); }); return; + } case Commands::ReorderNetwork::Id: VerifyOrReturn(mFeatureFlags.Has(Feature::kWiFiNetworkInterface) || mFeatureFlags.Has(Feature::kThreadNetworkInterface)); @@ -623,7 +630,20 @@ void Instance::HandleConnectNetwork(HandlerContext & ctx, const Commands::Connec memcpy(mConnectingNetworkID, req.networkID.data(), mConnectingNetworkIDLen); mAsyncCommandHandle = CommandHandler::Handle(&ctx.mCommandHandler); mCurrentOperationBreadcrumb = req.breadcrumb; + + // In Non-concurrent mode postpone the final execution of ConnectNetwork until the operational + // network has been fully brought up and kWiFiDeviceAvailable is delivered. + // mConnectingNetworkIDLen and mConnectingNetworkID contains the received SSID +#if CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION mpWirelessDriver->ConnectNetwork(req.networkID, this); +#endif +} + +void Instance::HandleNonConcurrentConnectNetwork() +{ + ByteSpan nonConcurrentNetworkID = ByteSpan(mConnectingNetworkID, mConnectingNetworkIDLen); + ChipLogProgress(NetworkProvisioning, "HandleNonConcurrentConnectNetwork() SSID=%s", mConnectingNetworkID); + mpWirelessDriver->ConnectNetwork(nonConcurrentNetworkID, this); } void Instance::HandleReorderNetwork(HandlerContext & ctx, const Commands::ReorderNetwork::DecodableType & req) @@ -759,7 +779,13 @@ void Instance::OnResult(Status commissioningError, CharSpan debugText, int32_t i memcpy(mLastNetworkID, mConnectingNetworkID, mLastNetworkIDLen); mLastNetworkingStatusValue.SetNonNull(commissioningError); +#if CONFIG_NETWORK_LAYER_BLE && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION + ChipLogProgress(NetworkProvisioning, "Non-concurrent mode, ConnectNetworkResponse will NOT be sent"); + // Do not send the ConnectNetworkResponse if in non-concurrent mode + // Issue #30576 raised to modify CommandHandler to notify it if no response required +#else commandHandle->AddResponse(mPath, response); +#endif if (commissioningError == Status::kSuccess) { CommitSavedBreadcrumb(); @@ -956,6 +982,10 @@ void Instance::OnPlatformEventHandler(const DeviceLayer::ChipDeviceEvent * event { this_->OnFailSafeTimerExpired(); } + else if (event->Type == DeviceLayer::DeviceEventType::kWiFiDeviceAvailable) + { + this_->HandleNonConcurrentConnectNetwork(); + } } void Instance::OnCommissioningComplete() diff --git a/src/app/clusters/network-commissioning/network-commissioning.h b/src/app/clusters/network-commissioning/network-commissioning.h index d11b118a5be854..03fa72f6bfbd26 100644 --- a/src/app/clusters/network-commissioning/network-commissioning.h +++ b/src/app/clusters/network-commissioning/network-commissioning.h @@ -117,6 +117,7 @@ class Instance : public CommandHandlerInterface, void HandleRemoveNetwork(HandlerContext & ctx, const Commands::RemoveNetwork::DecodableType & req); void HandleConnectNetwork(HandlerContext & ctx, const Commands::ConnectNetwork::DecodableType & req); void HandleReorderNetwork(HandlerContext & ctx, const Commands::ReorderNetwork::DecodableType & req); + void HandleNonConcurrentConnectNetwork(void); void HandleQueryIdentity(HandlerContext & ctx, const Commands::QueryIdentity::DecodableType & req); public: diff --git a/src/app/server/CommissioningWindowManager.cpp b/src/app/server/CommissioningWindowManager.cpp index cfa201c57a3757..c4257fe7e2ef02 100644 --- a/src/app/server/CommissioningWindowManager.cpp +++ b/src/app/server/CommissioningWindowManager.cpp @@ -64,7 +64,8 @@ void CommissioningWindowManager::OnPlatformEvent(const DeviceLayer::ChipDeviceEv Cleanup(); mServer->GetSecureSessionManager().ExpireAllPASESessions(); // That should have cleared out mPASESession. -#if CONFIG_NETWORK_LAYER_BLE +#if CONFIG_NETWORK_LAYER_BLE && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION + // If in NonConcurrentConnection, this will already have been completed mServer->GetBleLayerObject()->CloseAllBleConnections(); #endif } @@ -82,6 +83,13 @@ void CommissioningWindowManager::OnPlatformEvent(const DeviceLayer::ChipDeviceEv app::DnssdServer::Instance().AdvertiseOperational(); ChipLogProgress(AppServer, "Operational advertising enabled"); } +#if CONFIG_NETWORK_LAYER_BLE + else if (event->Type == DeviceLayer::DeviceEventType::kCloseAllBleConnections) + { + ChipLogProgress(AppServer, "Received kCloseAllBleConnections"); + mServer->GetBleLayerObject()->CloseAllBleConnections(); + } +#endif } void CommissioningWindowManager::Shutdown() diff --git a/src/controller/AutoCommissioner.cpp b/src/controller/AutoCommissioner.cpp index 397497ab80f206..075c5eeb243b23 100644 --- a/src/controller/AutoCommissioner.cpp +++ b/src/controller/AutoCommissioner.cpp @@ -687,35 +687,32 @@ CHIP_ERROR AutoCommissioner::CommissioningStepFinished(CHIP_ERROR err, Commissio mNeedsDST = false; break; case CommissioningStage::kReadCommissioningInfo2: { - bool shouldReadCommissioningInfo2 = - mParams.GetCheckForMatchingFabric() || (mParams.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore); - if (shouldReadCommissioningInfo2) + + if (!report.Is()) { - if (!report.Is()) - { - ChipLogError( - Controller, - "[BUG] Should read commissioning info (part 2), but report is not ReadCommissioningInfo2. THIS IS A BUG."); - } + ChipLogError( + Controller, + "[BUG] Should read commissioning info (part 2), but report is not ReadCommissioningInfo2. THIS IS A BUG."); + } - ReadCommissioningInfo2 commissioningInfo = report.Get(); + ReadCommissioningInfo2 commissioningInfo = report.Get(); + mParams.SetSupportsConcurrentConnection(commissioningInfo.supportsConcurrentConnection); - if (mParams.GetCheckForMatchingFabric()) + if (mParams.GetCheckForMatchingFabric()) + { + chip::NodeId nodeId = commissioningInfo.nodeId; + if (nodeId != kUndefinedNodeId) { - chip::NodeId nodeId = commissioningInfo.nodeId; - if (nodeId != kUndefinedNodeId) - { - mParams.SetRemoteNodeId(nodeId); - } + mParams.SetRemoteNodeId(nodeId); } + } - if (mParams.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore) + if (mParams.GetICDRegistrationStrategy() != ICDRegistrationStrategy::kIgnore) + { + if (commissioningInfo.isIcd) { - if (commissioningInfo.isIcd) - { - mNeedIcdRegistraion = true; - ChipLogDetail(Controller, "AutoCommissioner: Device is ICD"); - } + mNeedIcdRegistraion = true; + ChipLogDetail(Controller, "AutoCommissioner: Device is ICD"); } } break; diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 29c6cabb72184e..11c966cb84f207 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -1611,6 +1611,27 @@ void OnBasicFailure(void * context, CHIP_ERROR error) commissioner->CommissioningStageComplete(error); } +static void NonConcurrentTimeout(void * context, CHIP_ERROR error) +{ + if (error == CHIP_ERROR_TIMEOUT) + { + ChipLogProgress(Controller, "Non-concurrent mode: Expected NetworkResponse Timeout, do nothing"); + } + else + { + ChipLogProgress(Controller, "Non-concurrent mode: Received failure response %" CHIP_ERROR_FORMAT, error.Format()); + } +} + +static void NonConcurrentNetworkResponse(void * context, + const NetworkCommissioning::Commands::ConnectNetworkResponse::DecodableType & data) +{ + // In Non Concurrent mode the commissioning network should have been shut down and not sent the + // ConnectNetworkResponse. In case it does send it this handles the message + ChipLogError(Controller, "Non-concurrent Mode : Received Unexpected ConnectNetwork response, ignoring. Status=%u", + to_underlying(data.networkingStatus)); +} + void DeviceCommissioner::CleanupCommissioning(DeviceProxy * proxy, NodeId nodeId, const CompletionStatus & completionStatus) { commissioningCompletionStatus = completionStatus; @@ -2111,6 +2132,16 @@ void DeviceCommissioner::ParseCommissioningInfo2() ReadCommissioningInfo2 info; CHIP_ERROR return_err = CHIP_NO_ERROR; + using namespace chip::app::Clusters::GeneralCommissioning::Attributes; + CHIP_ERROR err = + mAttributeCache->Get(kRootEndpointId, info.supportsConcurrentConnection); + if (err != CHIP_NO_ERROR) + { + // May not be present so don't return the error code, non fatal, default concurrent + ChipLogError(Controller, "Failed to read SupportsConcurrentConnection: %" CHIP_ERROR_FORMAT, err.Format()); + info.supportsConcurrentConnection = true; + } + return_err = ParseFabrics(info); if (return_err == CHIP_NO_ERROR) @@ -2206,6 +2237,8 @@ CHIP_ERROR DeviceCommissioner::ParseICDInfo(ReadCommissioningInfo2 & info) } else if (err == CHIP_ERROR_KEY_NOT_FOUND) { + // This key is optional so not an error + err = CHIP_NO_ERROR; info.isIcd = false; } else if (err == CHIP_ERROR_IM_STATUS_CODE_RECEIVED) @@ -2440,6 +2473,7 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio case CommissioningStage::kReadCommissioningInfo: { ChipLogProgress(Controller, "Sending read request for commissioning information"); // NOTE: this array cannot have more than 9 entries, since the spec mandates that server only needs to support 9 + // See R1.1, 2.11.2 Interaction Model Limits app::AttributePathParams readPaths[9]; // Read all the feature maps for all the networking clusters on any endpoint to determine what is supported readPaths[0] = app::AttributePathParams(app::Clusters::NetworkCommissioning::Id, @@ -2471,7 +2505,14 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio case CommissioningStage::kReadCommissioningInfo2: { size_t numberOfAttributes = 0; // This is done in a separate step since we've already used up all the available read paths in the previous read step - app::AttributePathParams readPaths[9]; + // NOTE: this array cannot have more than 9 entries, since the spec mandates that server only needs to support 9 + // See R1.1, 2.11.2 Interaction Model Limits + app::AttributePathParams readPaths[3]; + + // Mandatory attribute + readPaths[numberOfAttributes++] = + app::AttributePathParams(endpoint, app::Clusters::GeneralCommissioning::Id, + app::Clusters::GeneralCommissioning::Attributes::SupportsConcurrentConnection::Id); // Read the current fabrics if (params.GetCheckForMatchingFabric()) @@ -2486,18 +2527,6 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio app::AttributePathParams(endpoint, IcdManagement::Id, IcdManagement::Attributes::FeatureMap::Id); } - // Current implementation makes sense when we only have a few attributes to read with conditions. Should revisit this if we - // are adding more attributes here. - - if (numberOfAttributes == 0) - { - // We don't actually want to do this step, so just bypass it - ChipLogProgress(Controller, "kReadCommissioningInfo2 step called without parameter set, skipping"); - CommissioningStageComplete(CHIP_NO_ERROR); - return; - } - - ChipLogProgress(Controller, "Sending request for commissioning information -- Part 2"); SendCommissioningReadRequest(proxy, timeout, readPaths, numberOfAttributes); } break; @@ -2918,7 +2947,31 @@ void DeviceCommissioner::PerformCommissioningStep(DeviceProxy * proxy, Commissio NetworkCommissioning::Commands::ConnectNetwork::Type request; request.networkID = params.GetWiFiCredentials().Value().ssid; request.breadcrumb.Emplace(breadcrumb); - CHIP_ERROR err = SendCommand(proxy, request, OnConnectNetworkResponse, OnBasicFailure, endpoint, timeout); + + CHIP_ERROR err = CHIP_NO_ERROR; + GeneralCommissioning::Attributes::SupportsConcurrentConnection::TypeInfo::Type supportsConcurrentConnection; + supportsConcurrentConnection = params.GetSupportsConcurrentConnection().Value(); + ChipLogProgress(Controller, "SendCommand kWiFiNetworkEnable, supportsConcurrentConnection=%d", + supportsConcurrentConnection); + if (supportsConcurrentConnection) + { + err = SendCommand(proxy, request, OnConnectNetworkResponse, OnBasicFailure, endpoint, timeout); + } + else + { + // Concurrent Connections not allowed. Send the ConnectNetwork command but do not wait for the + // ConnectNetworkResponse on the Commissioning network as it will not be present. Log the expected timeout + // and run what would have been in the onConnectNetworkResponse callback. + err = SendCommand(proxy, request, NonConcurrentNetworkResponse, NonConcurrentTimeout, endpoint, NullOptional); + if (err == CHIP_NO_ERROR) + { + // As there will be no ConnectNetworkResponse, it is an implicit kSuccess so a default report is fine + CommissioningDelegate::CommissioningReport report; + CommissioningStageComplete(CHIP_NO_ERROR, report); + return; + } + } + if (err != CHIP_NO_ERROR) { // We won't get any async callbacks here, so just complete our stage. diff --git a/src/controller/CommissioningDelegate.h b/src/controller/CommissioningDelegate.h index cbfff76adc6b3b..2919a026701bd0 100644 --- a/src/controller/CommissioningDelegate.h +++ b/src/controller/CommissioningDelegate.h @@ -35,7 +35,7 @@ enum CommissioningStage : uint8_t kError, kSecurePairing, ///< Establish a PASE session with the device kReadCommissioningInfo, ///< Query General Commissioning Attributes, Network Features and Time Synchronization Cluster - kReadCommissioningInfo2, ///< Query ICD state, check for matching fabric + kReadCommissioningInfo2, ///< Query SupportsConcurrentConnection, ICD state, check for matching fabric kArmFailsafe, ///< Send ArmFailSafe (0x30:0) command to the device kConfigRegulatory, ///< Send SetRegulatoryConfig (0x30:2) command to the device kConfigureUTCTime, ///< SetUTCTime if the DUT has a time cluster @@ -144,6 +144,10 @@ class CommissioningParameters return mDeviceRegulatoryLocation; } + // Value to determine whether the node supports Concurrent Connections as read from the GeneralCommissioning cluster. + // In the AutoCommissioner, this is automatically set from from the kReadCommissioningInfo2 stage. + Optional GetSupportsConcurrentConnection() const { return mSupportsConcurrentConnection; } + // The country code to be used for the node, if set. Optional GetCountryCode() const { return mCountryCode; } @@ -305,6 +309,12 @@ class CommissioningParameters return *this; } + CommissioningParameters & SetSupportsConcurrentConnection(bool concurrentConnection) + { + mSupportsConcurrentConnection.SetValue(concurrentConnection); + return *this; + } + // The lifetime of the buffer countryCode is pointing to should exceed the // lifetime of CommissioningParameters object. CommissioningParameters & SetCountryCode(CharSpan countryCode) @@ -561,6 +571,7 @@ class CommissioningParameters Optional mRemoteProductId; Optional mDefaultRegulatoryLocation; Optional mLocationCapability; + Optional mSupportsConcurrentConnection; CompletionStatus completionStatus; Credentials::DeviceAttestationDelegate * mDeviceAttestationDelegate = nullptr; // Delegate to handle device attestation failures during commissioning @@ -653,9 +664,10 @@ struct ReadCommissioningInfo struct ReadCommissioningInfo2 { - NodeId nodeId = kUndefinedNodeId; - bool isIcd = false; - bool checkInProtocolSupport = false; + NodeId nodeId = kUndefinedNodeId; + bool isIcd = false; + bool checkInProtocolSupport = false; + bool supportsConcurrentConnection = true; }; struct TimeZoneResponseInfo @@ -688,7 +700,7 @@ class CommissioningDelegate public: virtual ~CommissioningDelegate(){}; /* CommissioningReport is returned after each commissioning step is completed. The reports for each step are: - * kReadCommissioningInfo - ReadCommissioningInfo + * kReadCommissioningInfo: ReadCommissioningInfo * kReadCommissioningInfo2: ReadCommissioningInfo2 * kArmFailsafe: CommissioningErrorInfo if there is an error * kConfigRegulatory: CommissioningErrorInfo if there is an error diff --git a/src/include/platform/CHIPDeviceConfig.h b/src/include/platform/CHIPDeviceConfig.h index c5b2359fdcab89..f6989ac2590942 100644 --- a/src/include/platform/CHIPDeviceConfig.h +++ b/src/include/platform/CHIPDeviceConfig.h @@ -302,6 +302,19 @@ #define CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION 1 #endif // CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION +/** + * The device shall check every WIFI_START_CHECK_TIME_USEC whether Wi-Fi management + * has been fully initialized. If after WIFI_START_CHECK_ATTEMPTS Wi-Fi management + * still hasn't been initialized, the device configuration is reset, and device + * needs to be paired again. + */ +#ifndef WIFI_START_CHECK_TIME_USEC +#define WIFI_START_CHECK_TIME_USEC 100000 // 100ms +#endif +#ifndef WIFI_START_CHECK_ATTEMPTS +#define WIFI_START_CHECK_ATTEMPTS 5 +#endif + /** * CHIP_DEVICE_CONFIG_USER_SELECTED_MODE_TIMEOUT_SEC * diff --git a/src/include/platform/CHIPDeviceEvent.h b/src/include/platform/CHIPDeviceEvent.h index 561cd5f539367b..28e5c22400c0a7 100644 --- a/src/include/platform/CHIPDeviceEvent.h +++ b/src/include/platform/CHIPDeviceEvent.h @@ -168,6 +168,18 @@ enum PublicEventTypes */ kCHIPoBLEConnectionClosed, + /** + * Request BLE connections to be closed. + * This is used in the supportsConcurrentConnection = False case. + */ + kCloseAllBleConnections, + + /** + * When supportsConcurrentConnection = False, the ConnectNetwork command cannot start until + * the BLE device is closed and the WiFi device has been started. + */ + kWiFiDeviceAvailable, + /** * Thread State Change * diff --git a/src/include/platform/DeviceControlServer.h b/src/include/platform/DeviceControlServer.h index ce98110c2154d4..073f6a035e95b0 100644 --- a/src/include/platform/DeviceControlServer.h +++ b/src/include/platform/DeviceControlServer.h @@ -36,7 +36,8 @@ class DeviceControlServer final CHIP_ERROR PostCommissioningCompleteEvent(NodeId peerNodeId, FabricIndex accessingFabricIndex); CHIP_ERROR SetRegulatoryConfig(uint8_t location, const CharSpan & countryCode); CHIP_ERROR PostConnectedToOperationalNetworkEvent(ByteSpan networkID); - + CHIP_ERROR PostCloseAllBLEConnectionsToOperationalNetworkEvent(); + CHIP_ERROR PostWiFiDeviceAvailableNetworkEvent(); static DeviceControlServer & DeviceControlSvr(); private: diff --git a/src/platform/DeviceControlServer.cpp b/src/platform/DeviceControlServer.cpp index da27293ada6008..76008965498028 100644 --- a/src/platform/DeviceControlServer.cpp +++ b/src/platform/DeviceControlServer.cpp @@ -73,5 +73,19 @@ CHIP_ERROR DeviceControlServer::PostConnectedToOperationalNetworkEvent(ByteSpan return PlatformMgr().PostEvent(&event); } +CHIP_ERROR DeviceControlServer::PostCloseAllBLEConnectionsToOperationalNetworkEvent() +{ + ChipDeviceEvent event; + event.Type = DeviceEventType::kCloseAllBleConnections; + return PlatformMgr().PostEvent(&event); +} + +CHIP_ERROR DeviceControlServer::PostWiFiDeviceAvailableNetworkEvent() +{ + ChipDeviceEvent event; + event.Type = DeviceEventType::kWiFiDeviceAvailable; + return PlatformMgr().PostEvent(&event); +} + } // namespace DeviceLayer } // namespace chip diff --git a/src/platform/Linux/BLEManagerImpl.cpp b/src/platform/Linux/BLEManagerImpl.cpp index 196dd480872f84..978dc158124c12 100644 --- a/src/platform/Linux/BLEManagerImpl.cpp +++ b/src/platform/Linux/BLEManagerImpl.cpp @@ -635,6 +635,10 @@ void BLEManagerImpl::DriveBLEState(intptr_t arg) void BLEManagerImpl::NotifyChipConnectionClosed(BLE_CONNECTION_OBJECT conId) { ChipLogProgress(Ble, "Got notification regarding chip connection closure"); +#if CHIP_DEVICE_CONFIG_ENABLE_WPA && !CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION + // In Non-Concurrent mode start the Wi-Fi, as BLE has been stopped + DeviceLayer::ConnectivityMgrImpl().StartNonConcurrentWiFiManagement(); +#endif } void BLEManagerImpl::InitiateScan(BleScanState scanType) diff --git a/src/platform/Linux/ConnectivityManagerImpl.cpp b/src/platform/Linux/ConnectivityManagerImpl.cpp index c93a723628fa81..01d7a9668ff615 100644 --- a/src/platform/Linux/ConnectivityManagerImpl.cpp +++ b/src/platform/Linux/ConnectivityManagerImpl.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -765,6 +766,23 @@ bool ConnectivityManagerImpl::IsWiFiManagementStarted() return ret; } +void ConnectivityManagerImpl::StartNonConcurrentWiFiManagement() +{ + StartWiFiManagement(); + + for (int cnt = 0; cnt < WIFI_START_CHECK_ATTEMPTS; cnt++) + { + if (IsWiFiManagementStarted()) + { + DeviceControlServer::DeviceControlSvr().PostWiFiDeviceAvailableNetworkEvent(); + ChipLogProgress(DeviceLayer, "Non-concurrent mode Wi-Fi Management Started."); + return; + } + usleep(WIFI_START_CHECK_TIME_USEC); + } + ChipLogError(Ble, "Non-concurrent mode Wi-Fi Management taking too long to start."); +} + void ConnectivityManagerImpl::DriveAPState() { CHIP_ERROR err = CHIP_NO_ERROR; diff --git a/src/platform/Linux/ConnectivityManagerImpl.h b/src/platform/Linux/ConnectivityManagerImpl.h index df9e893f8ec5a6..1325c6cd83f21d 100644 --- a/src/platform/Linux/ConnectivityManagerImpl.h +++ b/src/platform/Linux/ConnectivityManagerImpl.h @@ -137,6 +137,7 @@ class ConnectivityManagerImpl final : public ConnectivityManager, void StartWiFiManagement(); bool IsWiFiManagementStarted(); + void StartNonConcurrentWiFiManagement(); int32_t GetDisconnectReason(); CHIP_ERROR GetWiFiBssId(MutableByteSpan & value); CHIP_ERROR GetWiFiSecurityType(app::Clusters::WiFiNetworkDiagnostics::SecurityTypeEnum & securityType);