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