/src/connectedhomeip/examples/platform/linux/AppMain.cpp
Line | Count | Source |
1 | | /* |
2 | | * |
3 | | * Copyright (c) 2021-2022 Project CHIP Authors |
4 | | * All rights reserved. |
5 | | * |
6 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
7 | | * you may not use this file except in compliance with the License. |
8 | | * You may obtain a copy of the License at |
9 | | * |
10 | | * http://www.apache.org/licenses/LICENSE-2.0 |
11 | | * |
12 | | * Unless required by applicable law or agreed to in writing, software |
13 | | * distributed under the License is distributed on an "AS IS" BASIS, |
14 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
15 | | * See the License for the specific language governing permissions and |
16 | | * limitations under the License. |
17 | | */ |
18 | | |
19 | | #include <string> |
20 | | |
21 | | #include <platform/CHIPDeviceLayer.h> |
22 | | #include <platform/PlatformManager.h> |
23 | | |
24 | | #include <app/InteractionModelEngine.h> |
25 | | #include <app/clusters/network-commissioning/network-commissioning.h> |
26 | | #include <app/server/Dnssd.h> |
27 | | #include <app/server/Server.h> |
28 | | #include <app/util/endpoint-config-api.h> |
29 | | #include <crypto/CHIPCryptoPAL.h> |
30 | | #include <data-model-providers/codegen/Instance.h> |
31 | | #include <lib/core/CHIPError.h> |
32 | | #include <lib/core/NodeId.h> |
33 | | #include <lib/core/Optional.h> |
34 | | #include <lib/support/logging/CHIPLogging.h> |
35 | | #include <setup_payload/OnboardingCodesUtil.h> |
36 | | |
37 | | #include <credentials/DeviceAttestationCredsProvider.h> |
38 | | |
39 | | #include <lib/support/CHIPMem.h> |
40 | | #include <lib/support/CHIPMemString.h> |
41 | | #include <lib/support/CodeUtils.h> |
42 | | #include <lib/support/ScopedBuffer.h> |
43 | | #include <lib/support/TestGroupData.h> |
44 | | #include <platform/CHIPDeviceEvent.h> |
45 | | #include <platform/ConnectivityManager.h> |
46 | | #include <platform/OpenThread/GenericNetworkCommissioningThreadDriver.h> |
47 | | #include <setup_payload/QRCodeSetupPayloadGenerator.h> |
48 | | #include <setup_payload/SetupPayload.h> |
49 | | |
50 | | #include <platform/CommissionableDataProvider.h> |
51 | | #include <platform/DiagnosticDataProvider.h> |
52 | | #include <platform/RuntimeOptionsProvider.h> |
53 | | |
54 | | #include <AllClustersExampleDeviceInfoProviderImpl.h> |
55 | | #include <DeviceInfoProviderImpl.h> |
56 | | |
57 | | #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE |
58 | | #include "CommissionerMain.h" |
59 | | #include <ControllerShellCommands.h> |
60 | | #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE |
61 | | |
62 | | #if defined(ENABLE_CHIP_SHELL) |
63 | | #include <CommissioneeShellCommands.h> |
64 | | #include <lib/shell/Engine.h> // nogncheck |
65 | | #include <thread> |
66 | | #endif |
67 | | |
68 | | #if defined(PW_RPC_ENABLED) |
69 | | #include <Rpc.h> |
70 | | #endif |
71 | | |
72 | | #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED |
73 | | #include "TraceDecoder.h" |
74 | | #include "TraceHandlers.h" |
75 | | #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED |
76 | | |
77 | | #if ENABLE_TRACING |
78 | | #include <TracingCommandLineArgument.h> // nogncheck |
79 | | #endif |
80 | | |
81 | | #if CHIP_DEVICE_CONFIG_ENABLE_SOFTWARE_DIAGNOSTIC_TRIGGER |
82 | | #include <app/clusters/software-diagnostics-server/SoftwareDiagnosticsTestEventTriggerHandler.h> |
83 | | #endif |
84 | | #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_DIAGNOSTIC_TRIGGER |
85 | | #include <app/clusters/wifi-network-diagnostics-server/WiFiDiagnosticsTestEventTriggerHandler.h> |
86 | | #endif |
87 | | #if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR |
88 | | #include <app/clusters/ota-requestor/OTATestEventTriggerHandler.h> |
89 | | #endif |
90 | | #if CHIP_DEVICE_CONFIG_ENABLE_SMOKE_CO_TRIGGER |
91 | | #include <app/clusters/smoke-co-alarm-server/SmokeCOTestEventTriggerHandler.h> |
92 | | #endif |
93 | | #if CHIP_DEVICE_CONFIG_ENABLE_BOOLEAN_STATE_CONFIGURATION_TRIGGER |
94 | | #include <app/clusters/boolean-state-configuration-server/BooleanStateConfigurationTestEventTriggerHandler.h> |
95 | | #endif |
96 | | #if CHIP_DEVICE_CONFIG_ENABLE_COMMODITY_PRICE_TRIGGER |
97 | | #include <app/clusters/commodity-price-server/CommodityPriceTestEventTriggerHandler.h> |
98 | | #endif |
99 | | #if CHIP_DEVICE_CONFIG_ENABLE_ELECTRICAL_GRID_CONDITIONS_TRIGGER |
100 | | #include <app/clusters/electrical-grid-conditions-server/ElectricalGridConditionsTestEventTriggerHandler.h> |
101 | | #endif |
102 | | #if CHIP_DEVICE_CONFIG_ENABLE_COMMODITY_TARIFF_TRIGGER |
103 | | #include <app/clusters/commodity-tariff-server/CommodityTariffTestEventTriggerHandler.h> |
104 | | #endif |
105 | | #if CHIP_DEVICE_CONFIG_ENABLE_ENERGY_EVSE_TRIGGER |
106 | | #include <app/clusters/energy-evse-server/EnergyEvseTestEventTriggerHandler.h> |
107 | | #endif |
108 | | #if CHIP_DEVICE_CONFIG_ENABLE_ENERGY_REPORTING_TRIGGER |
109 | | #include <app/clusters/electrical-energy-measurement-server/EnergyReportingTestEventTriggerHandler.h> |
110 | | #endif |
111 | | #if CHIP_DEVICE_CONFIG_ENABLE_METER_IDENTIFICATION_TRIGGER |
112 | | #include <app/clusters/meter-identification-server/MeterIdentificationTestEventTriggerHandler.h> |
113 | | #endif |
114 | | #if CHIP_DEVICE_CONFIG_ENABLE_WATER_HEATER_MANAGEMENT_TRIGGER |
115 | | #include <app/clusters/water-heater-management-server/WaterHeaterManagementTestEventTriggerHandler.h> |
116 | | #endif |
117 | | #if CHIP_DEVICE_CONFIG_ENABLE_DEVICE_ENERGY_MANAGEMENT_TRIGGER |
118 | | #include <app/clusters/device-energy-management-server/DeviceEnergyManagementTestEventTriggerHandler.h> |
119 | | #endif |
120 | | #if CHIP_DEVICE_CONFIG_ENABLE_COMMODITY_METERING_TRIGGER |
121 | | #include <app/clusters/commodity-metering-server/CommodityMeteringTestEventTriggerHandler.h> |
122 | | #endif |
123 | | #if CHIP_CONFIG_ENABLE_ICD_SERVER |
124 | | #include <app/icd/server/ICDManager.h> // nogncheck |
125 | | #endif |
126 | | #include <app/TestEventTriggerDelegate.h> |
127 | | |
128 | | #include <signal.h> |
129 | | |
130 | | #include "AppMain.h" |
131 | | #include "CommissionableInit.h" |
132 | | |
133 | | #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS |
134 | | #include "ExampleAccessRestrictionProvider.h" |
135 | | #endif |
136 | | |
137 | | #if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED |
138 | | #include <app/server/TermsAndConditionsManager.h> // nogncheck |
139 | | #endif |
140 | | |
141 | | #if CHIP_DEVICE_LAYER_TARGET_DARWIN |
142 | | #include <platform/Darwin/NetworkCommissioningDriver.h> |
143 | | #if CHIP_DEVICE_CONFIG_ENABLE_WIFI |
144 | | #include <platform/Darwin/WiFi/NetworkCommissioningWiFiDriver.h> |
145 | | #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI |
146 | | #endif // CHIP_DEVICE_LAYER_TARGET_DARWIN |
147 | | |
148 | | #if CHIP_DEVICE_LAYER_TARGET_LINUX |
149 | | #include <platform/Linux/NetworkCommissioningDriver.h> |
150 | | #endif // CHIP_DEVICE_LAYER_TARGET_LINUX |
151 | | |
152 | | #if CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT |
153 | | #include <inet/EndPointStateOpenThread.h> |
154 | | #include <openthread-system.h> |
155 | | #include <openthread/instance.h> |
156 | | #endif |
157 | | |
158 | | using namespace chip; |
159 | | using namespace chip::ArgParser; |
160 | | using namespace chip::Credentials; |
161 | | using namespace chip::DeviceLayer; |
162 | | using namespace chip::Inet; |
163 | | using namespace chip::Transport; |
164 | | using namespace chip::app::Clusters; |
165 | | using namespace chip::Access; |
166 | | using namespace chip::Platform; |
167 | | |
168 | | // Network comissioning implementation |
169 | | namespace { |
170 | | // If secondaryNetworkCommissioningEndpoint has a value and both Thread and WiFi |
171 | | // are enabled, we put the WiFi network commissioning cluster on |
172 | | // secondaryNetworkCommissioningEndpoint. |
173 | | Optional<EndpointId> sSecondaryNetworkCommissioningEndpoint; |
174 | | |
175 | | #if CHIP_DEVICE_LAYER_TARGET_LINUX |
176 | | #if CHIP_DEVICE_CONFIG_ENABLE_THREAD |
177 | | #define CHIP_APP_MAIN_HAS_THREAD_DRIVER 1 |
178 | | #if CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT |
179 | | DeviceLayer::NetworkCommissioning::GenericThreadDriver sThreadDriver; |
180 | | #else |
181 | | DeviceLayer::NetworkCommissioning::LinuxThreadDriver sThreadDriver; |
182 | | #endif |
183 | | #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD |
184 | | |
185 | | #if CHIP_DEVICE_CONFIG_ENABLE_WIFI |
186 | | #define CHIP_APP_MAIN_HAS_WIFI_DRIVER 1 |
187 | | DeviceLayer::NetworkCommissioning::LinuxWiFiDriver sWiFiDriver; |
188 | | #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI |
189 | | |
190 | | #define CHIP_APP_MAIN_HAS_ETHERNET_DRIVER 1 |
191 | | DeviceLayer::NetworkCommissioning::LinuxEthernetDriver sEthernetDriver; |
192 | | #endif // CHIP_DEVICE_LAYER_TARGET_LINUX |
193 | | |
194 | | #if CHIP_DEVICE_LAYER_TARGET_DARWIN |
195 | | #if CHIP_DEVICE_CONFIG_ENABLE_WIFI |
196 | | #define CHIP_APP_MAIN_HAS_WIFI_DRIVER 1 |
197 | | DeviceLayer::NetworkCommissioning::DarwinWiFiDriver sWiFiDriver; |
198 | | #endif // CHIP_DEVICE_CONFIG_ENABLE_WIFI |
199 | | |
200 | | #define CHIP_APP_MAIN_HAS_ETHERNET_DRIVER 1 |
201 | | DeviceLayer::NetworkCommissioning::DarwinEthernetDriver sEthernetDriver; |
202 | | #endif // CHIP_DEVICE_LAYER_TARGET_DARWIN |
203 | | |
204 | | #ifndef CHIP_APP_MAIN_HAS_THREAD_DRIVER |
205 | | #define CHIP_APP_MAIN_HAS_THREAD_DRIVER 0 |
206 | | #endif // CHIP_APP_MAIN_HAS_THREAD_DRIVER |
207 | | |
208 | | #ifndef CHIP_APP_MAIN_HAS_WIFI_DRIVER |
209 | | #define CHIP_APP_MAIN_HAS_WIFI_DRIVER 0 |
210 | | #endif // CHIP_APP_MAIN_HAS_WIFI_DRIVER |
211 | | |
212 | | #ifndef CHIP_APP_MAIN_HAS_ETHERNET_DRIVER |
213 | | #define CHIP_APP_MAIN_HAS_ETHERNET_DRIVER 0 |
214 | | #endif // CHIP_APP_MAIN_HAS_ETHERNET_DRIVER |
215 | | |
216 | | #if CHIP_APP_MAIN_HAS_THREAD_DRIVER |
217 | | app::Clusters::NetworkCommissioning::Instance sThreadNetworkCommissioningInstance(kRootEndpointId, &sThreadDriver); |
218 | | #endif // CHIP_APP_MAIN_HAS_THREAD_DRIVER |
219 | | |
220 | | #if CHIP_APP_MAIN_HAS_WIFI_DRIVER |
221 | | // The WiFi network commissioning instance cannot be constructed until we know |
222 | | // whether we have an sSecondaryNetworkCommissioningEndpoint. |
223 | | Optional<app::Clusters::NetworkCommissioning::Instance> sWiFiNetworkCommissioningInstance; |
224 | | #endif // CHIP_APP_MAIN_HAS_WIFI_DRIVER |
225 | | |
226 | | #if CHIP_APP_MAIN_HAS_ETHERNET_DRIVER |
227 | | app::Clusters::NetworkCommissioning::Instance sEthernetNetworkCommissioningInstance(kRootEndpointId, &sEthernetDriver); |
228 | | #endif // CHIP_APP_MAIN_HAS_ETHERNET_DRIVER |
229 | | |
230 | | #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS |
231 | | auto exampleAccessRestrictionProvider = std::make_unique<ExampleAccessRestrictionProvider>(); |
232 | | #endif |
233 | | |
234 | | void EnableThreadNetworkCommissioning() |
235 | 0 | { |
236 | | #if CHIP_APP_MAIN_HAS_THREAD_DRIVER |
237 | | SuccessOrDie(sThreadNetworkCommissioningInstance.Init()); |
238 | | #endif // CHIP_APP_MAIN_HAS_THREAD_DRIVER |
239 | 0 | } |
240 | | |
241 | | void EnableWiFiNetworkCommissioning(EndpointId endpoint) |
242 | 0 | { |
243 | 0 | #if CHIP_APP_MAIN_HAS_WIFI_DRIVER |
244 | 0 | sWiFiNetworkCommissioningInstance.Emplace(endpoint, &sWiFiDriver); |
245 | 0 | SuccessOrDie(sWiFiNetworkCommissioningInstance.Value().Init()); |
246 | 0 | #endif // CHIP_APP_MAIN_HAS_WIFI_DRIVER |
247 | 0 | } |
248 | | |
249 | | void InitNetworkCommissioning() |
250 | 0 | { |
251 | 0 | if (sSecondaryNetworkCommissioningEndpoint.HasValue()) |
252 | 0 | { |
253 | | // Enable secondary endpoint only when we need it, this should be applied to all platforms. |
254 | 0 | emberAfEndpointEnableDisable(sSecondaryNetworkCommissioningEndpoint.Value(), false); |
255 | 0 | } |
256 | |
|
257 | 0 | bool isThreadEnabled = false; |
258 | | #if CHIP_APP_MAIN_HAS_THREAD_DRIVER |
259 | | #if CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT |
260 | | isThreadEnabled = LinuxDeviceOptions::GetInstance().mThreadNodeId > 0; |
261 | | #else |
262 | | isThreadEnabled = LinuxDeviceOptions::GetInstance().mThread; |
263 | | #endif |
264 | | #endif // CHIP_APP_MAIN_HAS_THREAD_DRIVER |
265 | |
|
266 | 0 | bool isWiFiEnabled = false; |
267 | 0 | #if CHIP_APP_MAIN_HAS_WIFI_DRIVER |
268 | 0 | isWiFiEnabled = LinuxDeviceOptions::GetInstance().mWiFi; |
269 | | |
270 | | // On Linux, command-line indicates whether Wi-Fi is supported since determining it from |
271 | | // the OS level is not easily portable. |
272 | 0 | #if CHIP_DEVICE_LAYER_TARGET_LINUX |
273 | 0 | sWiFiDriver.Set5gSupport(LinuxDeviceOptions::GetInstance().wifiSupports5g); |
274 | 0 | #endif // CHIP_DEVICE_LAYER_TARGET_LINUX |
275 | |
|
276 | 0 | #endif // CHIP_APP_MAIN_HAS_WIFI_DRIVER |
277 | |
|
278 | 0 | if (isThreadEnabled && isWiFiEnabled) |
279 | 0 | { |
280 | 0 | if (sSecondaryNetworkCommissioningEndpoint.HasValue()) |
281 | 0 | { |
282 | 0 | EnableThreadNetworkCommissioning(); |
283 | 0 | EnableWiFiNetworkCommissioning(sSecondaryNetworkCommissioningEndpoint.Value()); |
284 | | // Only enable secondary endpoint for network commissioning cluster when both WiFi and Thread are enabled. |
285 | 0 | emberAfEndpointEnableDisable(sSecondaryNetworkCommissioningEndpoint.Value(), true); |
286 | 0 | } |
287 | 0 | else |
288 | 0 | { |
289 | | // Just use the Thread one. |
290 | 0 | EnableThreadNetworkCommissioning(); |
291 | 0 | } |
292 | 0 | } |
293 | 0 | else if (isThreadEnabled) |
294 | 0 | { |
295 | 0 | EnableThreadNetworkCommissioning(); |
296 | 0 | } |
297 | 0 | else if (isWiFiEnabled) |
298 | 0 | { |
299 | 0 | EnableWiFiNetworkCommissioning(kRootEndpointId); |
300 | 0 | } |
301 | 0 | else |
302 | 0 | { |
303 | 0 | #if CHIP_APP_MAIN_HAS_ETHERNET_DRIVER |
304 | 0 | TEMPORARY_RETURN_IGNORED sEthernetNetworkCommissioningInstance.Init(); |
305 | 0 | #if CHIP_DEVICE_LAYER_TARGET_LINUX |
306 | 0 | DeviceLayer::ConnectivityMgrImpl().UpdateEthernetNetworkingStatus(); |
307 | 0 | #endif // CHIP_DEVICE_LAYER_TARGET_LINUX |
308 | 0 | #endif // CHIP_APP_MAIN_HAS_ETHERNET_DRIVER |
309 | 0 | } |
310 | 0 | } |
311 | | |
312 | | } // anonymous namespace |
313 | | |
314 | | #if defined(ENABLE_CHIP_SHELL) |
315 | | using chip::Shell::Engine; |
316 | | #endif |
317 | | |
318 | | #if CHIP_DEVICE_CONFIG_ENABLE_WPA && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION |
319 | | /* |
320 | | * The device shall check every kWiFiStartCheckTimeUsec whether Wi-Fi management |
321 | | * has been fully initialized. If after kWiFiStartCheckAttempts Wi-Fi management |
322 | | * still hasn't been initialized, the device configuration is reset, and device |
323 | | * needs to be paired again. |
324 | | */ |
325 | | static constexpr useconds_t kWiFiStartCheckTimeUsec = WIFI_START_CHECK_TIME_USEC; |
326 | | static constexpr uint8_t kWiFiStartCheckAttempts = WIFI_START_CHECK_ATTEMPTS; |
327 | | #endif |
328 | | |
329 | | namespace { |
330 | | AppMainLoopImplementation * gMainLoopImplementation = nullptr; |
331 | | |
332 | | // To hold SPAKE2+ verifier, discriminator, passcode |
333 | | LinuxCommissionableDataProvider gCommissionableDataProvider; |
334 | | |
335 | | chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; |
336 | | chip::DeviceLayer::AllClustersExampleDeviceInfoProviderImpl gAllClustersExampleDeviceInfoProvider; |
337 | | |
338 | | void EventHandler(const DeviceLayer::ChipDeviceEvent * event, intptr_t arg) |
339 | 0 | { |
340 | 0 | (void) arg; |
341 | 0 | if (event->Type == DeviceLayer::DeviceEventType::kCHIPoBLEConnectionEstablished) |
342 | 0 | { |
343 | 0 | ChipLogProgress(DeviceLayer, "Receive kCHIPoBLEConnectionEstablished"); |
344 | 0 | } |
345 | 0 | else if ((event->Type == chip::DeviceLayer::DeviceEventType::kInternetConnectivityChange)) |
346 | 0 | { |
347 | | // Restart the server on connectivity change |
348 | 0 | app::DnssdServer::Instance().StartServer(); |
349 | 0 | } |
350 | 0 | } |
351 | | |
352 | | void StopMainEventLoop() |
353 | 0 | { |
354 | 0 | if (gMainLoopImplementation != nullptr) |
355 | 0 | { |
356 | 0 | gMainLoopImplementation->SignalSafeStopMainLoop(); |
357 | 0 | } |
358 | 0 | else |
359 | 0 | { |
360 | 0 | Server::GetInstance().GenerateShutDownEvent(); |
361 | 0 | TEMPORARY_RETURN_IGNORED SystemLayer().ScheduleLambda([]() { TEMPORARY_RETURN_IGNORED PlatformMgr().StopEventLoopTask(); }); |
362 | 0 | } |
363 | 0 | } |
364 | | |
365 | | void Cleanup() |
366 | 0 | { |
367 | 0 | #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED |
368 | 0 | chip::trace::DeInitTrace(); |
369 | 0 | #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED |
370 | | |
371 | | // TODO(16968): Lifecycle management of storage-using components like GroupDataProvider, etc |
372 | 0 | } |
373 | | |
374 | | void StopSignalHandler(int /* signal */) |
375 | 0 | { |
376 | | #if defined(ENABLE_CHIP_SHELL) |
377 | | Engine::Root().StopMainLoop(); |
378 | | #endif |
379 | 0 | StopMainEventLoop(); |
380 | 0 | } |
381 | | |
382 | | } // namespace |
383 | | |
384 | | #if CHIP_DEVICE_CONFIG_ENABLE_WPA && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION |
385 | | static bool EnsureWiFiIsStarted() |
386 | 0 | { |
387 | 0 | for (int cnt = 0; cnt < kWiFiStartCheckAttempts; cnt++) |
388 | 0 | { |
389 | 0 | if (DeviceLayer::ConnectivityMgrImpl().IsWiFiManagementStarted()) |
390 | 0 | { |
391 | 0 | return true; |
392 | 0 | } |
393 | | |
394 | 0 | usleep(kWiFiStartCheckTimeUsec); |
395 | 0 | } |
396 | | |
397 | 0 | return DeviceLayer::ConnectivityMgrImpl().IsWiFiManagementStarted(); |
398 | 0 | } |
399 | | #endif |
400 | | |
401 | | class SampleTestEventTriggerHandler : public TestEventTriggerHandler |
402 | | { |
403 | | /// NOTE: If you copy this for NON-STANDARD CLUSTERS OR USAGES, please use the reserved range FFFF_FFFF_<VID_HEX>_xxxx for your |
404 | | /// trigger codes. NOTE: Standard codes are <CLUSTER_ID_HEX>_xxxx_xxxx_xxxx. |
405 | | static constexpr uint64_t kSampleTestEventTriggerAlwaysSuccess = static_cast<uint64_t>(0xFFFF'FFFF'FFF1'0000ull); |
406 | | |
407 | | public: |
408 | | CHIP_ERROR HandleEventTrigger(uint64_t eventTrigger) override |
409 | 0 | { |
410 | 0 | ChipLogProgress(Support, "Saw TestEventTrigger: " ChipLogFormatX64, ChipLogValueX64(eventTrigger)); |
411 | |
|
412 | 0 | if (eventTrigger == kSampleTestEventTriggerAlwaysSuccess) |
413 | 0 | { |
414 | | // Do nothing, successfully |
415 | 0 | ChipLogProgress(Support, "Handling \"Always success\" internal test event"); |
416 | 0 | return CHIP_NO_ERROR; |
417 | 0 | } |
418 | | |
419 | 0 | return CHIP_ERROR_INVALID_ARGUMENT; |
420 | 0 | } |
421 | | }; |
422 | | |
423 | | #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION |
424 | | /* |
425 | | Get the freq_list from args. |
426 | | Format: |
427 | | "freq_list=[freq#1],[freq#2]...[freq#n]" |
428 | | [freq#1] - [freq#n]: frequence number, separated by ',' |
429 | | */ |
430 | | static uint16_t WiFiPAFGet_FreqList(const char * args, std::unique_ptr<uint16_t[]> & freq_list) |
431 | 0 | { |
432 | 0 | const char hdstr[] = "freq_list="; |
433 | 0 | std::vector<uint16_t> freq_vect; |
434 | 0 | const std::string argstrn(args); |
435 | 0 | auto pos = argstrn.find(hdstr); |
436 | 0 | if (pos == std::string::npos) |
437 | 0 | { |
438 | 0 | return 0; |
439 | 0 | } |
440 | 0 | std::string nums = argstrn.substr(pos + strlen(hdstr)); |
441 | 0 | std::stringstream ss(nums); |
442 | 0 | std::string item; |
443 | 0 | while (std::getline(ss, item, ',')) |
444 | 0 | { |
445 | 0 | freq_vect.push_back(std::stoi(item)); |
446 | 0 | } |
447 | 0 | uint16_t freq_size = freq_vect.size(); |
448 | 0 | freq_list = std::make_unique<uint16_t[]>(freq_size); |
449 | 0 | for (int i = 0; i < freq_size; i++) |
450 | 0 | { |
451 | 0 | freq_list.get()[i] = freq_vect[i]; |
452 | 0 | } |
453 | 0 | return freq_size; |
454 | 0 | } |
455 | | #endif |
456 | | |
457 | | // Wrapper for DeviceInstanceInfoProvider that allows the example app to set |
458 | | // attribute values from the command-line, provide hardcoded values, or fall |
459 | | // back to the default DeviceInstanceInfoProvider. |
460 | | class ExampleDeviceInstanceInfoProvider : public DeviceInstanceInfoProvider |
461 | | { |
462 | | public: |
463 | 0 | void Init(DeviceInstanceInfoProvider * defaultProvider) { mDefaultProvider = defaultProvider; } |
464 | | |
465 | | CHIP_ERROR GetVendorName(char * buf, size_t bufSize) override |
466 | 0 | { |
467 | | // Check if it was set from the command line or fall back to default provider. |
468 | 0 | if (mVendorName.has_value()) |
469 | 0 | { |
470 | 0 | VerifyOrReturnError(CanFitInNullTerminatedString(mVendorName.value(), bufSize), CHIP_ERROR_BUFFER_TOO_SMALL); |
471 | 0 | CopyString(buf, bufSize, mVendorName.value().c_str()); |
472 | 0 | return CHIP_NO_ERROR; |
473 | 0 | } |
474 | | |
475 | 0 | return mDefaultProvider->GetVendorName(buf, bufSize); |
476 | 0 | } |
477 | | |
478 | 0 | CHIP_ERROR GetVendorId(uint16_t & vendorId) override { return mDefaultProvider->GetVendorId(vendorId); } |
479 | | |
480 | | CHIP_ERROR GetProductName(char * buf, size_t bufSize) override |
481 | 0 | { |
482 | | // Check if it was set from the command line or fall back to default provider. |
483 | 0 | if (mProductName.has_value()) |
484 | 0 | { |
485 | 0 | VerifyOrReturnError(CanFitInNullTerminatedString(mProductName.value(), bufSize), CHIP_ERROR_BUFFER_TOO_SMALL); |
486 | 0 | CopyString(buf, bufSize, mProductName.value().c_str()); |
487 | 0 | return CHIP_NO_ERROR; |
488 | 0 | } |
489 | | |
490 | 0 | return mDefaultProvider->GetProductName(buf, bufSize); |
491 | 0 | } |
492 | | |
493 | 0 | CHIP_ERROR GetProductId(uint16_t & productId) override { return mDefaultProvider->GetProductId(productId); } |
494 | 0 | CHIP_ERROR GetPartNumber(char * buf, size_t bufSize) override { return mDefaultProvider->GetPartNumber(buf, bufSize); } |
495 | 0 | CHIP_ERROR GetProductURL(char * buf, size_t bufSize) override { return mDefaultProvider->GetProductURL(buf, bufSize); } |
496 | 0 | CHIP_ERROR GetProductLabel(char * buf, size_t bufSize) override { return mDefaultProvider->GetProductLabel(buf, bufSize); } |
497 | | |
498 | | CHIP_ERROR GetSerialNumber(char * buf, size_t bufSize) override |
499 | 0 | { |
500 | | // Check if it was set from the command line or fall back to default provider. |
501 | 0 | if (mSerialNumber.has_value()) |
502 | 0 | { |
503 | 0 | VerifyOrReturnError(CanFitInNullTerminatedString(mSerialNumber.value(), bufSize), CHIP_ERROR_BUFFER_TOO_SMALL); |
504 | 0 | CopyString(buf, bufSize, mSerialNumber.value().c_str()); |
505 | 0 | return CHIP_NO_ERROR; |
506 | 0 | } |
507 | | |
508 | 0 | return mDefaultProvider->GetSerialNumber(buf, bufSize); |
509 | 0 | } |
510 | | |
511 | | CHIP_ERROR GetManufacturingDate(uint16_t & year, uint8_t & month, uint8_t & day) override |
512 | 0 | { |
513 | 0 | return mDefaultProvider->GetManufacturingDate(year, month, day); |
514 | 0 | } |
515 | | CHIP_ERROR GetHardwareVersion(uint16_t & hardwareVersion) override |
516 | 0 | { |
517 | 0 | return mDefaultProvider->GetHardwareVersion(hardwareVersion); |
518 | 0 | } |
519 | | CHIP_ERROR GetHardwareVersionString(char * buf, size_t bufSize) override |
520 | 0 | { |
521 | | // Check if it was set from the command line or fall back to default provider. |
522 | 0 | if (mHardwareVersionString.has_value()) |
523 | 0 | { |
524 | 0 | VerifyOrReturnError(CanFitInNullTerminatedString(mHardwareVersionString.value(), bufSize), CHIP_ERROR_BUFFER_TOO_SMALL); |
525 | 0 | CopyString(buf, bufSize, mHardwareVersionString.value().c_str()); |
526 | 0 | return CHIP_NO_ERROR; |
527 | 0 | } |
528 | | |
529 | 0 | return mDefaultProvider->GetHardwareVersionString(buf, bufSize); |
530 | 0 | } |
531 | | |
532 | | CHIP_ERROR GetRotatingDeviceIdUniqueId(MutableByteSpan & uniqueIdSpan) override |
533 | 0 | { |
534 | 0 | return mDefaultProvider->GetRotatingDeviceIdUniqueId(uniqueIdSpan); |
535 | 0 | } |
536 | | |
537 | | CHIP_ERROR GetProductFinish(chip::app::Clusters::BasicInformation::ProductFinishEnum * finish) override |
538 | 0 | { |
539 | | // Our example device claims to have a Satin finish for now. We can make |
540 | | // this configurable as needed. |
541 | 0 | *finish = chip::app::Clusters::BasicInformation::ProductFinishEnum::kSatin; |
542 | 0 | return CHIP_NO_ERROR; |
543 | 0 | } |
544 | | |
545 | | CHIP_ERROR GetProductPrimaryColor(chip::app::Clusters::BasicInformation::ColorEnum * primaryColor) override |
546 | 0 | { |
547 | | // Our example device claims to have a nice purple color for now. We can |
548 | | // make this configurable as needed. |
549 | 0 | *primaryColor = chip::app::Clusters::BasicInformation::ColorEnum::kPurple; |
550 | 0 | return CHIP_NO_ERROR; |
551 | 0 | } |
552 | | |
553 | | // Once an attribute has been set with one of these Set methods, the |
554 | | // corresponding Get method will return the stored value instead of getting |
555 | | // the value from the default provider. |
556 | 0 | void SetVendorName(const std::string & buf) { mVendorName = buf; } |
557 | 0 | void SetProductName(const std::string & buf) { mProductName = buf; } |
558 | 0 | void SetSerialNumber(const std::string & buf) { mSerialNumber = buf; } |
559 | 0 | void SetHardwareVersionString(const std::string & buf) { mHardwareVersionString = buf; } |
560 | | |
561 | | private: |
562 | | DeviceInstanceInfoProvider * mDefaultProvider; |
563 | | |
564 | | // Values of basic information cluster attributes that may be set from the command-line. |
565 | | // When GetX is called, if this has a value it will be returned instead of getting the |
566 | | // value from the default provider. |
567 | | std::optional<std::string> mVendorName; |
568 | | std::optional<std::string> mProductName; |
569 | | std::optional<std::string> mSerialNumber; |
570 | | std::optional<std::string> mHardwareVersionString; |
571 | | |
572 | | static inline bool CanFitInNullTerminatedString(const std::string & candidate, size_t bufSizeIncludingNull) |
573 | 0 | { |
574 | 0 | return bufSizeIncludingNull >= (candidate.size() + 1); |
575 | 0 | } |
576 | | }; |
577 | | |
578 | | ExampleDeviceInstanceInfoProvider gExampleDeviceInstanceInfoProvider; |
579 | | |
580 | | int ChipLinuxAppInit(int argc, char * const argv[], OptionSet * customOptions, |
581 | | const Optional<EndpointId> secondaryNetworkCommissioningEndpoint) |
582 | 0 | { |
583 | 0 | CHIP_ERROR err = CHIP_NO_ERROR; |
584 | 0 | bool isAllClustersVariant = (std::string(argv[0]).find("all-clusters") != std::string::npos); |
585 | 0 | DeviceInstanceInfoProvider * defaultDeviceInstanceInfoProvider = nullptr; |
586 | |
|
587 | 0 | #if CONFIG_NETWORK_LAYER_BLE |
588 | 0 | RendezvousInformationFlags rendezvousFlags = RendezvousInformationFlag::kBLE; |
589 | | #else // CONFIG_NETWORK_LAYER_BLE |
590 | | RendezvousInformationFlags rendezvousFlags = RendezvousInformationFlag::kOnNetwork; |
591 | | #endif // CONFIG_NETWORK_LAYER_BLE |
592 | |
|
593 | | #ifdef CONFIG_RENDEZVOUS_MODE |
594 | | rendezvousFlags = static_cast<RendezvousInformationFlags>(CONFIG_RENDEZVOUS_MODE); |
595 | | #endif |
596 | |
|
597 | 0 | err = Platform::MemoryInit(); |
598 | 0 | SuccessOrExit(err); |
599 | | |
600 | 0 | err = ParseArguments(argc, argv, customOptions); |
601 | 0 | SuccessOrExit(err); |
602 | | |
603 | 0 | #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF |
604 | 0 | if (LinuxDeviceOptions::GetInstance().mWiFiPAF) |
605 | 0 | { |
606 | 0 | rendezvousFlags.Set(RendezvousInformationFlag::kWiFiPAF); |
607 | 0 | } |
608 | 0 | #endif |
609 | |
|
610 | 0 | sSecondaryNetworkCommissioningEndpoint = secondaryNetworkCommissioningEndpoint; |
611 | |
|
612 | 0 | #ifdef CHIP_CONFIG_KVS_PATH |
613 | 0 | if (LinuxDeviceOptions::GetInstance().KVS == nullptr) |
614 | 0 | { |
615 | 0 | err = DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(CHIP_CONFIG_KVS_PATH); |
616 | 0 | } |
617 | 0 | else |
618 | 0 | { |
619 | 0 | err = DeviceLayer::PersistedStorage::KeyValueStoreMgrImpl().Init(LinuxDeviceOptions::GetInstance().KVS); |
620 | 0 | } |
621 | 0 | SuccessOrExit(err); |
622 | 0 | #endif |
623 | | |
624 | | #if defined(ENABLE_CHIP_SHELL) |
625 | | /* Block SIGINT and SIGTERM. Other threads created by the main thread |
626 | | * will inherit the signal mask. Then we can explicitly unblock signals |
627 | | * in the shell thread to handle them, so the read(stdin) call can be |
628 | | * interrupted by a signal. */ |
629 | | sigset_t set; |
630 | | sigemptyset(&set); |
631 | | sigaddset(&set, SIGINT); |
632 | | sigaddset(&set, SIGTERM); |
633 | | pthread_sigmask(SIG_BLOCK, &set, nullptr); |
634 | | #endif |
635 | | |
636 | 0 | err = DeviceLayer::PlatformMgr().InitChipStack(); |
637 | 0 | SuccessOrExit(err); |
638 | | |
639 | | // Init the commissionable data provider based on command line options |
640 | | // to handle custom verifiers, discriminators, etc. |
641 | 0 | err = chip::examples::InitCommissionableDataProvider(gCommissionableDataProvider, LinuxDeviceOptions::GetInstance()); |
642 | 0 | SuccessOrExit(err); |
643 | 0 | DeviceLayer::SetCommissionableDataProvider(&gCommissionableDataProvider); |
644 | |
|
645 | 0 | err = chip::examples::InitConfigurationManager(reinterpret_cast<ConfigurationManagerImpl &>(ConfigurationMgr()), |
646 | 0 | LinuxDeviceOptions::GetInstance()); |
647 | 0 | SuccessOrExit(err); |
648 | | |
649 | 0 | if (LinuxDeviceOptions::GetInstance().payload.rendezvousInformation.HasValue()) |
650 | 0 | { |
651 | 0 | rendezvousFlags = LinuxDeviceOptions::GetInstance().payload.rendezvousInformation.Value(); |
652 | 0 | } |
653 | |
|
654 | 0 | err = GetPayloadContents(LinuxDeviceOptions::GetInstance().payload, rendezvousFlags); |
655 | 0 | SuccessOrExit(err); |
656 | | |
657 | | // We need to set DeviceInfoProvider before Server::Init to set up the storage of DeviceInfoProvider properly. |
658 | 0 | if (isAllClustersVariant) |
659 | 0 | { |
660 | 0 | DeviceLayer::SetDeviceInfoProvider(&gAllClustersExampleDeviceInfoProvider); |
661 | 0 | } |
662 | 0 | else |
663 | 0 | { |
664 | 0 | DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); |
665 | 0 | } |
666 | |
|
667 | 0 | ConfigurationMgr().LogDeviceConfig(); |
668 | |
|
669 | 0 | { |
670 | 0 | ChipLogProgress(NotSpecified, "==== Onboarding payload for Standard Commissioning Flow ===="); |
671 | 0 | PrintOnboardingCodes(LinuxDeviceOptions::GetInstance().payload); |
672 | 0 | } |
673 | |
|
674 | | #if defined(PW_RPC_ENABLED) |
675 | | rpc::Init(LinuxDeviceOptions::GetInstance().rpcServerPort); |
676 | | ChipLogProgress(NotSpecified, "PW_RPC initialized."); |
677 | | #endif // defined(PW_RPC_ENABLED) |
678 | |
|
679 | 0 | TEMPORARY_RETURN_IGNORED DeviceLayer::PlatformMgrImpl().AddEventHandler(EventHandler, 0); |
680 | |
|
681 | 0 | #if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED |
682 | 0 | if (LinuxDeviceOptions::GetInstance().traceStreamFilename.HasValue()) |
683 | 0 | { |
684 | 0 | const char * traceFilename = LinuxDeviceOptions::GetInstance().traceStreamFilename.Value().c_str(); |
685 | 0 | auto traceStream = new chip::trace::TraceStreamFile(traceFilename); |
686 | 0 | chip::trace::AddTraceStream(traceStream); |
687 | 0 | } |
688 | 0 | else if (LinuxDeviceOptions::GetInstance().traceStreamToLogEnabled) |
689 | 0 | { |
690 | 0 | auto traceStream = new chip::trace::TraceStreamLog(); |
691 | 0 | chip::trace::AddTraceStream(traceStream); |
692 | 0 | } |
693 | |
|
694 | 0 | if (LinuxDeviceOptions::GetInstance().traceStreamDecodeEnabled) |
695 | 0 | { |
696 | 0 | chip::trace::TraceDecoderOptions options; |
697 | 0 | options.mEnableProtocolInteractionModelResponse = false; |
698 | |
|
699 | 0 | chip::trace::TraceDecoder * decoder = new chip::trace::TraceDecoder(); |
700 | 0 | decoder->SetOptions(options); |
701 | 0 | chip::trace::AddTraceStream(decoder); |
702 | 0 | } |
703 | 0 | chip::trace::InitTrace(); |
704 | 0 | #endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED |
705 | |
|
706 | 0 | #if CONFIG_NETWORK_LAYER_BLE |
707 | 0 | TEMPORARY_RETURN_IGNORED DeviceLayer::ConnectivityMgr().SetBLEDeviceName(nullptr); // Use default device name (CHIP-XXXX) |
708 | 0 | TEMPORARY_RETURN_IGNORED DeviceLayer::Internal::BLEMgrImpl().ConfigureBle(LinuxDeviceOptions::GetInstance().mBleDevice, false); |
709 | 0 | TEMPORARY_RETURN_IGNORED DeviceLayer::ConnectivityMgr().SetBLEAdvertisingEnabled(true); |
710 | 0 | #endif |
711 | |
|
712 | 0 | #if CHIP_DEVICE_CONFIG_ENABLE_WPA && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION |
713 | 0 | if (LinuxDeviceOptions::GetInstance().mWiFi) |
714 | 0 | { |
715 | | // Start WiFi management in Concurrent mode |
716 | 0 | DeviceLayer::ConnectivityMgrImpl().StartWiFiManagement(); |
717 | 0 | if (!EnsureWiFiIsStarted()) |
718 | 0 | { |
719 | 0 | ChipLogError(NotSpecified, "Wi-Fi Management taking too long to start - device configuration will be reset."); |
720 | 0 | } |
721 | 0 | } |
722 | 0 | #endif // CHIP_DEVICE_CONFIG_ENABLE_WPA |
723 | 0 | #if CHIP_DEVICE_CONFIG_ENABLE_WPA && CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF && CHIP_DEVICE_CONFIG_SUPPORTS_CONCURRENT_CONNECTION |
724 | 0 | if (LinuxDeviceOptions::GetInstance().mWiFi && LinuxDeviceOptions::GetInstance().mWiFiPAF) |
725 | 0 | { |
726 | 0 | ChipLogProgress(WiFiPAF, "WiFi-PAF: initialzing"); |
727 | 0 | if (EnsureWiFiIsStarted()) |
728 | 0 | { |
729 | 0 | ChipLogProgress(WiFiPAF, "Wi-Fi Management started"); |
730 | 0 | DeviceLayer::ConnectivityManager::WiFiPAFAdvertiseParam args; |
731 | |
|
732 | 0 | args.enable = LinuxDeviceOptions::GetInstance().mWiFiPAF; |
733 | 0 | args.freq_list_len = WiFiPAFGet_FreqList(LinuxDeviceOptions::GetInstance().mWiFiPAFExtCmds, args.freq_list); |
734 | 0 | TEMPORARY_RETURN_IGNORED DeviceLayer::ConnectivityMgr().WiFiPAFPublish(args); |
735 | 0 | LinuxDeviceOptions::GetInstance().mPublishId = args.publish_id; |
736 | 0 | } |
737 | 0 | } |
738 | 0 | #endif |
739 | |
|
740 | | #if CHIP_ENABLE_OPENTHREAD |
741 | | #if CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT |
742 | | if (LinuxDeviceOptions::GetInstance().mThreadNodeId) |
743 | | { |
744 | | std::string nodeid = std::to_string(LinuxDeviceOptions::GetInstance().mThreadNodeId); |
745 | | std::string logfile = "--log-file=thread.log"; |
746 | | char * args[] = { argv[0], logfile.data(), nodeid.data() }; |
747 | | |
748 | | otSysInit(MATTER_ARRAY_SIZE(args), args); |
749 | | SuccessOrExit(err = DeviceLayer::ThreadStackMgrImpl().InitThreadStack()); |
750 | | SuccessOrExit(err = DeviceLayer::ThreadStackMgrImpl().StartThreadTask()); |
751 | | ChipLogProgress(NotSpecified, "Thread initialized."); |
752 | | } |
753 | | #else |
754 | | if (LinuxDeviceOptions::GetInstance().mThread) |
755 | | { |
756 | | SuccessOrExit(err = DeviceLayer::ThreadStackMgrImpl().InitThreadStack()); |
757 | | SuccessOrExit(err = DeviceLayer::ThreadStackMgrImpl().StartThreadTask()); |
758 | | ChipLogProgress(NotSpecified, "Thread initialized."); |
759 | | } |
760 | | #endif |
761 | | #endif |
762 | |
|
763 | | #if CHIP_CONFIG_ENABLE_ICD_SERVER |
764 | | if (LinuxDeviceOptions::GetInstance().icdActiveModeDurationMs.HasValue() || |
765 | | LinuxDeviceOptions::GetInstance().icdIdleModeDurationMs.HasValue() || |
766 | | LinuxDeviceOptions::GetInstance().shortIdleModeDurationS.has_value()) |
767 | | { |
768 | | // Convert icdIdleModeDurationMs to seconds for SetModeDurations api |
769 | | std::optional<System::Clock::Seconds32> tmpIdleModeDuration = std::nullopt; |
770 | | if (LinuxDeviceOptions::GetInstance().icdIdleModeDurationMs.HasValue()) |
771 | | tmpIdleModeDuration = std::chrono::duration_cast<System::Clock::Seconds32>( |
772 | | LinuxDeviceOptions::GetInstance().icdIdleModeDurationMs.Value()); |
773 | | |
774 | | err = Server::GetInstance().GetICDManager().SetModeDurations( |
775 | | LinuxDeviceOptions::GetInstance().icdActiveModeDurationMs.std_optional(), tmpIdleModeDuration, |
776 | | LinuxDeviceOptions::GetInstance().shortIdleModeDurationS); |
777 | | |
778 | | if (err != CHIP_NO_ERROR) |
779 | | { |
780 | | ChipLogError(NotSpecified, "Invalid arguments to set ICD mode durations"); |
781 | | SuccessOrExit(err); |
782 | | } |
783 | | } |
784 | | #endif // CHIP_CONFIG_ENABLE_ICD_SERVER |
785 | | |
786 | | // Initialize the ExampleDeviceInstanceInfoProvider. |
787 | 0 | defaultDeviceInstanceInfoProvider = GetDeviceInstanceInfoProvider(); |
788 | 0 | if (defaultDeviceInstanceInfoProvider != &gExampleDeviceInstanceInfoProvider) |
789 | 0 | { |
790 | 0 | gExampleDeviceInstanceInfoProvider.Init(defaultDeviceInstanceInfoProvider); |
791 | 0 | SetDeviceInstanceInfoProvider(&gExampleDeviceInstanceInfoProvider); |
792 | 0 | } |
793 | | |
794 | | // Command line arguments to set attributes of the basic information cluster. |
795 | 0 | if (LinuxDeviceOptions::GetInstance().vendorName.HasValue()) |
796 | 0 | gExampleDeviceInstanceInfoProvider.SetVendorName(LinuxDeviceOptions::GetInstance().vendorName.Value()); |
797 | |
|
798 | 0 | if (LinuxDeviceOptions::GetInstance().productName.HasValue()) |
799 | 0 | gExampleDeviceInstanceInfoProvider.SetProductName(LinuxDeviceOptions::GetInstance().productName.Value()); |
800 | |
|
801 | 0 | if (LinuxDeviceOptions::GetInstance().serialNumber.HasValue()) |
802 | 0 | gExampleDeviceInstanceInfoProvider.SetSerialNumber(LinuxDeviceOptions::GetInstance().serialNumber.Value()); |
803 | |
|
804 | 0 | if (LinuxDeviceOptions::GetInstance().hardwareVersionString.HasValue()) |
805 | 0 | gExampleDeviceInstanceInfoProvider.SetHardwareVersionString( |
806 | 0 | LinuxDeviceOptions::GetInstance().hardwareVersionString.Value()); |
807 | |
|
808 | 0 | exit: |
809 | 0 | if (err != CHIP_NO_ERROR) |
810 | 0 | { |
811 | 0 | ChipLogProgress(NotSpecified, "Failed to init Linux App: %s ", ErrorStr(err)); |
812 | 0 | Cleanup(); |
813 | | |
814 | | // End the program with non zero error code to indicate a error. |
815 | 0 | return 1; |
816 | 0 | } |
817 | 0 | return 0; |
818 | 0 | } |
819 | | |
820 | | struct LinuxCommonCaseDeviceServerInitParams final : public chip::CommonCaseDeviceServerInitParams |
821 | | { |
822 | | LinuxCommonCaseDeviceServerInitParams() |
823 | 0 | { |
824 | 0 | SuccessOrDie(InitializeStaticResourcesBeforeServerInit()); |
825 | 0 | dataModelProvider = app::CodegenDataModelProviderInstance(persistentStorageDelegate); |
826 | 0 | } |
827 | | }; |
828 | | |
829 | | chip::CommonCaseDeviceServerInitParams & ChipLinuxDefaultServerInitParams() |
830 | 0 | { |
831 | 0 | static LinuxCommonCaseDeviceServerInitParams sInitParams; |
832 | 0 | return sInitParams; |
833 | 0 | } |
834 | | |
835 | | void ChipLinuxAppMainLoop(chip::ServerInitParams & initParams, AppMainLoopImplementation * impl) |
836 | 0 | { |
837 | 0 | gMainLoopImplementation = impl; |
838 | |
|
839 | | #if CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED |
840 | | if (LinuxDeviceOptions::GetInstance().tcVersion.HasValue() && LinuxDeviceOptions::GetInstance().tcRequired.HasValue()) |
841 | | { |
842 | | uint16_t version = LinuxDeviceOptions::GetInstance().tcVersion.Value(); |
843 | | uint16_t required = LinuxDeviceOptions::GetInstance().tcRequired.Value(); |
844 | | Optional<app::TermsAndConditions> requiredAcknowledgements(app::TermsAndConditions(required, version)); |
845 | | SuccessOrDie( |
846 | | app::TermsAndConditionsManager::GetInstance().Init(initParams.persistentStorageDelegate, requiredAcknowledgements)); |
847 | | } |
848 | | #endif // CHIP_CONFIG_TERMS_AND_CONDITIONS_REQUIRED |
849 | |
|
850 | | #if defined(ENABLE_CHIP_SHELL) |
851 | | Engine::Root().Init(); |
852 | | Shell::RegisterCommissioneeCommands(); |
853 | | std::thread shellThread([]() { |
854 | | sigset_t set; |
855 | | sigemptyset(&set); |
856 | | sigaddset(&set, SIGINT); |
857 | | sigaddset(&set, SIGTERM); |
858 | | // Unblock SIGINT and SIGTERM, so that the shell thread can handle |
859 | | // them - we need read() call to be interrupted. |
860 | | pthread_sigmask(SIG_UNBLOCK, &set, nullptr); |
861 | | Engine::Root().RunMainLoop(); |
862 | | StopMainEventLoop(); |
863 | | }); |
864 | | #endif |
865 | 0 | initParams.operationalServicePort = CHIP_PORT; |
866 | 0 | initParams.userDirectedCommissioningPort = CHIP_UDC_PORT; |
867 | |
|
868 | 0 | #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS |
869 | | // use a different service port to make testing possible with other sample devices running on same host |
870 | 0 | initParams.operationalServicePort = LinuxDeviceOptions::GetInstance().securedDevicePort; |
871 | 0 | initParams.userDirectedCommissioningPort = LinuxDeviceOptions::GetInstance().unsecuredCommissionerPort; |
872 | 0 | #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE |
873 | |
|
874 | | #if CHIP_DEVICE_CONFIG_ENABLE_PORT_RETRY |
875 | | // Enable automatic port retry to handle port conflicts |
876 | | initParams.portRetryCount = CHIP_DEVICE_CONFIG_PORT_RETRY_COUNT; |
877 | | #endif |
878 | |
|
879 | | #if ENABLE_TRACING |
880 | | chip::CommandLineApp::TracingSetup tracing_setup; |
881 | | |
882 | | for (const auto & trace_destination : LinuxDeviceOptions::GetInstance().traceTo) |
883 | | { |
884 | | tracing_setup.EnableTracingFor(trace_destination.c_str()); |
885 | | } |
886 | | #endif |
887 | |
|
888 | 0 | initParams.interfaceId = LinuxDeviceOptions::GetInstance().interfaceId; |
889 | |
|
890 | 0 | if (LinuxDeviceOptions::GetInstance().mCSRResponseOptions.csrExistingKeyPair) |
891 | 0 | { |
892 | 0 | SuccessOrDie(LinuxDeviceOptions::GetInstance().mCSRResponseOptions.badCsrOperationalKeyStoreForTest.Init( |
893 | 0 | initParams.persistentStorageDelegate)); |
894 | 0 | initParams.operationalKeystore = &LinuxDeviceOptions::GetInstance().mCSRResponseOptions.badCsrOperationalKeyStoreForTest; |
895 | 0 | } |
896 | | |
897 | | // For general testing of TestEventTrigger, we have a common "core" event trigger delegate. |
898 | 0 | static SimpleTestEventTriggerDelegate sTestEventTriggerDelegate; |
899 | 0 | static SampleTestEventTriggerHandler sTestEventTriggerHandler; |
900 | 0 | VerifyOrDie(sTestEventTriggerDelegate.Init(ByteSpan(LinuxDeviceOptions::GetInstance().testEventTriggerEnableKey)) == |
901 | 0 | CHIP_NO_ERROR); |
902 | 0 | VerifyOrDie(sTestEventTriggerDelegate.AddHandler(&sTestEventTriggerHandler) == CHIP_NO_ERROR); |
903 | | |
904 | | #if CHIP_DEVICE_CONFIG_ENABLE_SOFTWARE_DIAGNOSTIC_TRIGGER |
905 | | static SoftwareDiagnosticsTestEventTriggerHandler sSoftwareDiagnosticsTestEventTriggerHandler; |
906 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sSoftwareDiagnosticsTestEventTriggerHandler)); |
907 | | #endif |
908 | | #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_DIAGNOSTIC_TRIGGER |
909 | | static WiFiDiagnosticsTestEventTriggerHandler sWiFiDiagnosticsTestEventTriggerHandler; |
910 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sWiFiDiagnosticsTestEventTriggerHandler)); |
911 | | #endif |
912 | | #if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR |
913 | | // We want to allow triggering OTA queries if OTA requestor is enabled |
914 | | static OTATestEventTriggerHandler sOtaTestEventTriggerHandler; |
915 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sOtaTestEventTriggerHandler)); |
916 | | #endif |
917 | | #if CHIP_DEVICE_CONFIG_ENABLE_SMOKE_CO_TRIGGER |
918 | | static SmokeCOTestEventTriggerHandler sSmokeCOTestEventTriggerHandler; |
919 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sSmokeCOTestEventTriggerHandler)); |
920 | | #endif |
921 | | #if CHIP_DEVICE_CONFIG_ENABLE_BOOLEAN_STATE_CONFIGURATION_TRIGGER |
922 | | static BooleanStateConfigurationTestEventTriggerHandler sBooleanStateConfigurationTestEventTriggerHandler; |
923 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sBooleanStateConfigurationTestEventTriggerHandler)); |
924 | | #endif |
925 | | #if CHIP_DEVICE_CONFIG_ENABLE_COMMODITY_PRICE_TRIGGER |
926 | | static CommodityPriceTestEventTriggerHandler sCommodityPriceTestEventTriggerHandler; |
927 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sCommodityPriceTestEventTriggerHandler)); |
928 | | #endif |
929 | | #if CHIP_DEVICE_CONFIG_ENABLE_ELECTRICAL_GRID_CONDITIONS_TRIGGER |
930 | | static ElectricalGridConditionsTestEventTriggerHandler sElectricalGridConditionsTestEventTriggerHandler; |
931 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sElectricalGridConditionsTestEventTriggerHandler)); |
932 | | #endif |
933 | | #if CHIP_DEVICE_CONFIG_ENABLE_COMMODITY_TARIFF_TRIGGER |
934 | | static CommodityTariffTestEventTriggerHandler sCommodityTariffTestEventTriggerHandler; |
935 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sCommodityTariffTestEventTriggerHandler)); |
936 | | #endif |
937 | | #if CHIP_DEVICE_CONFIG_ENABLE_ENERGY_EVSE_TRIGGER |
938 | | static EnergyEvseTestEventTriggerHandler sEnergyEvseTestEventTriggerHandler; |
939 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sEnergyEvseTestEventTriggerHandler)); |
940 | | #endif |
941 | | #if CHIP_DEVICE_CONFIG_ENABLE_ENERGY_REPORTING_TRIGGER |
942 | | static EnergyReportingTestEventTriggerHandler sEnergyReportingTestEventTriggerHandler; |
943 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sEnergyReportingTestEventTriggerHandler)); |
944 | | #endif |
945 | | #if CHIP_DEVICE_CONFIG_ENABLE_METER_IDENTIFICATION_TRIGGER |
946 | | static MeterIdentificationTestEventTriggerHandler sMeterIdentificationTestEventTriggerHandler; |
947 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sMeterIdentificationTestEventTriggerHandler)); |
948 | | #endif |
949 | | #if CHIP_DEVICE_CONFIG_ENABLE_WATER_HEATER_MANAGEMENT_TRIGGER |
950 | | static WaterHeaterManagementTestEventTriggerHandler sWaterHeaterManagementTestEventTriggerHandler; |
951 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sWaterHeaterManagementTestEventTriggerHandler)); |
952 | | #endif |
953 | | #if CHIP_DEVICE_CONFIG_ENABLE_DEVICE_ENERGY_MANAGEMENT_TRIGGER |
954 | | static DeviceEnergyManagementTestEventTriggerHandler sDeviceEnergyManagementTestEventTriggerHandler; |
955 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&sDeviceEnergyManagementTestEventTriggerHandler)); |
956 | | #endif |
957 | | #if CHIP_DEVICE_CONFIG_ENABLE_COMMODITY_METERING_TRIGGER |
958 | | static CommodityMeteringTestEventTriggerHandler CommodityMeteringTestEventTriggerHandler; |
959 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&CommodityMeteringTestEventTriggerHandler)); |
960 | | #endif |
961 | | #if CHIP_CONFIG_ENABLE_ICD_SERVER |
962 | | SuccessOrDie(sTestEventTriggerDelegate.AddHandler(&Server::GetInstance().GetICDManager())); |
963 | | #endif |
964 | | |
965 | 0 | initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate; |
966 | |
|
967 | 0 | chip::app::RuntimeOptionsProvider::Instance().SetSimulateNoInternalTime( |
968 | 0 | LinuxDeviceOptions::GetInstance().mSimulateNoInternalTime); |
969 | |
|
970 | | #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS |
971 | | initParams.accessRestrictionProvider = exampleAccessRestrictionProvider.get(); |
972 | | #endif |
973 | |
|
974 | | #if CHIP_SYSTEM_CONFIG_USE_OPENTHREAD_ENDPOINT |
975 | | chip::Inet::EndPointStateOpenThread::OpenThreadEndpointInitParam nativeParams; |
976 | | nativeParams.lockCb = []() { chip::DeviceLayer::ThreadStackMgr().LockThreadStack(); }; |
977 | | nativeParams.unlockCb = []() { chip::DeviceLayer::ThreadStackMgr().UnlockThreadStack(); }; |
978 | | nativeParams.openThreadInstancePtr = chip::DeviceLayer::ThreadStackMgrImpl().OTInstance(); |
979 | | initParams.endpointNativeParams = static_cast<void *>(&nativeParams); |
980 | | #endif |
981 | 0 | if (LinuxDeviceOptions::GetInstance().payload.commissioningFlow == CommissioningFlow::kUserActionRequired) |
982 | 0 | { |
983 | 0 | initParams.advertiseCommissionableIfNoFabrics = false; |
984 | 0 | } |
985 | | |
986 | | // Init ZCL Data Model and CHIP App Server |
987 | 0 | CHIP_ERROR err = Server::GetInstance().Init(initParams); |
988 | 0 | if (err != CHIP_NO_ERROR) |
989 | 0 | { |
990 | 0 | ChipLogError(AppServer, "Server init failed: %" CHIP_ERROR_FORMAT, err.Format()); |
991 | 0 | chipDie(); |
992 | 0 | } |
993 | | |
994 | | #if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS |
995 | | if (LinuxDeviceOptions::GetInstance().commissioningArlEntries.HasValue()) |
996 | | { |
997 | | SuccessOrDie(exampleAccessRestrictionProvider->SetCommissioningEntries( |
998 | | LinuxDeviceOptions::GetInstance().commissioningArlEntries.Value())); |
999 | | } |
1000 | | |
1001 | | if (LinuxDeviceOptions::GetInstance().arlEntries.HasValue()) |
1002 | | { |
1003 | | // This example use of the ARL feature proactively installs the provided entries on fabric index 1 |
1004 | | SuccessOrDie(exampleAccessRestrictionProvider->SetEntries(1, LinuxDeviceOptions::GetInstance().arlEntries.Value())); |
1005 | | } |
1006 | | #endif |
1007 | 0 | #if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF |
1008 | 0 | if (Server::GetInstance().GetFabricTable().FabricCount() != 0) |
1009 | 0 | { |
1010 | 0 | ChipLogProgress(AppServer, "Fabric already commissioned. Canceling publishing"); |
1011 | | // TODO #40789: Should we just NOT call WiFiPAFShutdown at startup and instead make sure that WiFiPAF is not published at |
1012 | | // all? or Change the handling within WiFiPAFShutdown? |
1013 | | // TODO #40814: Check the Return Value of the call to WiFiPAFShutdown |
1014 | 0 | TEMPORARY_RETURN_IGNORED DeviceLayer::ConnectivityMgr().WiFiPAFShutdown(LinuxDeviceOptions::GetInstance().mPublishId, |
1015 | 0 | chip::WiFiPAF::WiFiPafRole::kWiFiPafRole_Publisher); |
1016 | 0 | } |
1017 | 0 | #endif |
1018 | |
|
1019 | 0 | #if CONFIG_BUILD_FOR_HOST_UNIT_TEST |
1020 | | // Set ReadHandler Capacity for Subscriptions |
1021 | 0 | chip::app::InteractionModelEngine::GetInstance()->SetHandlerCapacityForSubscriptions( |
1022 | 0 | LinuxDeviceOptions::GetInstance().subscriptionCapacity); |
1023 | 0 | chip::app::InteractionModelEngine::GetInstance()->SetForceHandlerQuota(true); |
1024 | 0 | #if CHIP_CONFIG_PERSIST_SUBSCRIPTIONS && CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION |
1025 | | // Set subscription time resumption retry interval seconds |
1026 | 0 | chip::app::InteractionModelEngine::GetInstance()->SetSubscriptionTimeoutResumptionRetryIntervalSeconds( |
1027 | 0 | LinuxDeviceOptions::GetInstance().subscriptionResumptionRetryIntervalSec); |
1028 | 0 | #endif // CHIP_CONFIG_PERSIST_SUBSCRIPTIONS && CHIP_CONFIG_SUBSCRIPTION_TIMEOUT_RESUMPTION |
1029 | 0 | #endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST |
1030 | | |
1031 | | // Now that the server has started and we are done with our startup logging, |
1032 | | // log our discovery/onboarding information again so it's not lost in the |
1033 | | // noise. |
1034 | 0 | ConfigurationMgr().LogDeviceConfig(); |
1035 | |
|
1036 | 0 | PrintOnboardingCodes(LinuxDeviceOptions::GetInstance().payload); |
1037 | | |
1038 | | // Initialize device attestation config |
1039 | 0 | SetDeviceAttestationCredentialsProvider(LinuxDeviceOptions::GetInstance().dacProvider); |
1040 | |
|
1041 | | #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE |
1042 | | ChipLogProgress(AppServer, "Starting commissioner"); |
1043 | | VerifyOrReturn(InitCommissioner(LinuxDeviceOptions::GetInstance().securedCommissionerPort, |
1044 | | LinuxDeviceOptions::GetInstance().unsecuredCommissionerPort, |
1045 | | LinuxDeviceOptions::GetInstance().commissionerFabricId) == CHIP_NO_ERROR); |
1046 | | ChipLogProgress(AppServer, "Started commissioner"); |
1047 | | #if defined(ENABLE_CHIP_SHELL) |
1048 | | Shell::RegisterControllerCommands(); |
1049 | | #endif // defined(ENABLE_CHIP_SHELL) |
1050 | | #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE |
1051 | |
|
1052 | 0 | InitNetworkCommissioning(); |
1053 | |
|
1054 | 0 | ApplicationInit(); |
1055 | |
|
1056 | | #if CHIP_DEVICE_LAYER_TARGET_DARWIN |
1057 | | #if CHIP_SYSTEM_CONFIG_USE_DISPATCH |
1058 | | auto & platformMgr = chip::DeviceLayer::PlatformMgrImpl(); |
1059 | | platformMgr.RegisterSignalHandler(SIGINT, ^{ |
1060 | | platformMgr.UnregisterAllSignalHandlers(); |
1061 | | StopSignalHandler(SIGINT); |
1062 | | }); |
1063 | | |
1064 | | platformMgr.RegisterSignalHandler(SIGTERM, ^{ |
1065 | | platformMgr.UnregisterAllSignalHandlers(); |
1066 | | StopSignalHandler(SIGTERM); |
1067 | | }); |
1068 | | #else |
1069 | | // NOTE: For some reason, on Darwin, the signal handler is not called if the signal is |
1070 | | // registered with sigaction() call and TSAN is enabled. The problem seems to be |
1071 | | // related with the dispatch_semaphore_wait() function in the RunEventLoop() method. |
1072 | | // If this call is commented out, the signal handler is called as expected... |
1073 | | // NOLINTBEGIN(bugprone-signal-handler) |
1074 | | signal(SIGINT, StopSignalHandler); |
1075 | | signal(SIGTERM, StopSignalHandler); |
1076 | | // NOLINTEND(bugprone-signal-handler) |
1077 | | #endif |
1078 | | #else |
1079 | 0 | struct sigaction sa = {}; |
1080 | 0 | sa.sa_handler = StopSignalHandler; |
1081 | 0 | sa.sa_flags = SA_RESETHAND; |
1082 | 0 | sigaction(SIGINT, &sa, nullptr); |
1083 | 0 | sigaction(SIGTERM, &sa, nullptr); |
1084 | 0 | #endif |
1085 | | |
1086 | | // This message is used as a marker for when the application process has started. |
1087 | | // See: scripts/tests/chiptest/test_definition.py |
1088 | | // TODO: A cleaner and more generic mechanism needs to be developed as a follow-up. |
1089 | | // Currently other places (OTA, TV) also scrape logs for information and a better way should be |
1090 | | // possible. |
1091 | 0 | ChipLogProgress(DeviceLayer, "===== APP STATUS: Starting event loop ====="); |
1092 | 0 | if (impl != nullptr) |
1093 | 0 | { |
1094 | 0 | impl->RunMainLoop(); |
1095 | 0 | } |
1096 | 0 | else |
1097 | 0 | { |
1098 | 0 | DeviceLayer::PlatformMgr().RunEventLoop(); |
1099 | 0 | } |
1100 | 0 | gMainLoopImplementation = nullptr; |
1101 | |
|
1102 | 0 | ApplicationShutdown(); |
1103 | |
|
1104 | | #if defined(ENABLE_CHIP_SHELL) |
1105 | | shellThread.join(); |
1106 | | #endif |
1107 | |
|
1108 | 0 | Server::GetInstance().Shutdown(); |
1109 | |
|
1110 | | #if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE |
1111 | | // Commissioner shutdown call shuts down entire stack, including the platform manager. |
1112 | | ShutdownCommissioner(); |
1113 | | #else |
1114 | 0 | DeviceLayer::PlatformMgr().Shutdown(); |
1115 | 0 | #endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE |
1116 | |
|
1117 | | #if ENABLE_TRACING |
1118 | | tracing_setup.StopTracing(); |
1119 | | #endif |
1120 | |
|
1121 | 0 | Cleanup(); |
1122 | 0 | } |