blob: 2cf0f1d86c5adf9703465ab1db949e52fceda1c5 [file] [log] [blame]
/*
*
* Copyright (c) 2025 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "AppTaskBase.h"
#include "AppEvent.h"
#include "CHIPDeviceManager.h"
#include "CommonDeviceCallbacks.h"
#include <app/server/Dnssd.h>
#include <lib/dnssd/Advertiser.h>
#include <data-model-providers/codegen/Instance.h>
#include <setup_payload/OnboardingCodesUtil.h>
#include <app/clusters/network-commissioning/network-commissioning.h>
#include <platform/CommissionableDataProvider.h>
#include <lib/core/ErrorStr.h>
#include <platform/DeviceInstanceInfoProvider.h>
#include <DeviceInfoProviderImpl.h>
#include <credentials/DeviceAttestationCredsProvider.h>
#include <credentials/examples/DeviceAttestationCredsExample.h>
#include <platform/CommissionableDataProvider.h>
#include <platform/DeviceInstanceInfoProvider.h>
#include <platform/Zephyr/DeviceInstanceInfoProviderImpl.h>
#if CONFIG_NET_L2_OPENTHREAD
#include <inet/EndPointStateOpenThread.h>
#include <lib/support/ThreadOperationalDataset.h>
#endif
#if CONFIG_CHIP_APP_WIFI_CONNECT_AT_BOOT
#include "WifiConnect.h"
#endif
#if CONFIG_OPERATIONAL_KEYSTORE
#include "OperationalKeystore.h"
#endif
#if CONFIG_CHIP_OTA_PROVIDER
#include <OTAProvider.h>
#endif
#if CONFIG_DIAG_LOGS_DEMO
#include "DiagnosticLogsDemo.h"
#endif
#if CONFIG_LOW_POWER
#include "LowPower.h"
#include "PWR_Interface.h"
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR
#include "OTARequestorInitiator.h"
#endif
#if CONFIG_CHIP_TEST_EVENT && CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR
#include <app/clusters/ota-requestor/OTATestEventTriggerDelegate.h>
#endif
#ifdef ENABLE_CHIP_SHELL
#include <lib/shell/commands/WiFi.h>
#endif
#ifdef SMOKE_CO_ALARM
#include <app/TestEventTriggerDelegate.h>
#include <app/clusters/smoke-co-alarm-server/SmokeCOTestEventTriggerHandler.h>
#endif
#if CHIP_CONFIG_ENABLE_ICD_SERVER
#include <app/TestEventTriggerDelegate.h>
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_TBR
#include "platform/OpenThread/GenericThreadBorderRouterDelegate.h"
#include <app/clusters/thread-border-router-management-server/thread-border-router-management-server.h>
#endif
#ifndef CONFIG_THREAD_DEVICE_TYPE
#define CONFIG_THREAD_DEVICE_TYPE kThreadDeviceType_Router
#endif
extern "C" uint64_t settingsNVSLoadTimeMs;
extern "C" uint64_t settingsNVSLoadCount;
using namespace chip;
using namespace chip::TLV;
using namespace ::chip::Credentials;
using namespace ::chip::DeviceLayer;
using namespace ::chip::DeviceManager;
using namespace ::chip::app::Clusters;
chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider;
#if CONFIG_CHIP_WIFI || CHIP_DEVICE_CONFIG_ENABLE_WPA
app::Clusters::NetworkCommissioning::Instance
sNetworkCommissioningInstance(0, chip::Zephyr::App::GetAppTask().GetWifiDriverInstance());
#endif
#if CHIP_CONFIG_ENABLE_ICD_SERVER || (CONFIG_CHIP_TEST_EVENT && CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR)
static uint8_t sTestEventTriggerEnableKey[TestEventTriggerDelegate::kEnableKeyLength] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55,
0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
0xcc, 0xdd, 0xee, 0xff };
#endif
#if CONFIG_NET_L2_OPENTHREAD
void LockOpenThreadTask(void)
{
chip::Zephyr::App::GetAppTask().AppMatter_DisallowDeviceToSleep();
chip::DeviceLayer::ThreadStackMgr().LockThreadStack();
}
void UnlockOpenThreadTask(void)
{
chip::DeviceLayer::ThreadStackMgr().UnlockThreadStack();
chip::Zephyr::App::GetAppTask().AppMatter_AllowDeviceToSleep();
}
#endif
void chip::Zephyr::App::AppTaskBase::InitServer(intptr_t arg)
{
GetAppTask().PreInitMatterServerInstance();
#if CONFIG_CHIP_TEST_EVENT && CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR
static OTATestEventTriggerDelegate testEventTriggerDelegate{ ByteSpan(sTestEventTriggerEnableKey) };
initParams.testEventTriggerDelegate = &testEventTriggerDelegate;
#endif
#ifdef SMOKE_CO_ALARM
static SimpleTestEventTriggerDelegate sTestEventTriggerDelegate{};
static SmokeCOTestEventTriggerHandler sSmokeCOTestEventTriggerHandler{};
VerifyOrDie(sTestEventTriggerDelegate.Init(ByteSpan(sTestEventTriggerEnableKey)) == CHIP_NO_ERROR);
VerifyOrDie(sTestEventTriggerDelegate.AddHandler(&sSmokeCOTestEventTriggerHandler) == CHIP_NO_ERROR);
initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate;
#endif
#if CHIP_CONFIG_ENABLE_ICD_SERVER
static SimpleTestEventTriggerDelegate sTestEventTriggerDelegate{};
VerifyOrDie(sTestEventTriggerDelegate.Init(ByteSpan(sTestEventTriggerEnableKey)) == CHIP_NO_ERROR);
initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate;
#endif
#if CONFIG_OPERATIONAL_KEYSTORE
initParams.operationalKeystore = chip::Zephyr::App::OperationalKeystore::GetInstance();
#endif
(void) initParams.InitializeStaticResourcesBeforeServerInit();
initParams.dataModelProvider = app::CodegenDataModelProviderInstance(initParams.persistentStorageDelegate);
#if CONFIG_NET_L2_OPENTHREAD
// Init ZCL Data Model and start server
chip::Inet::EndPointStateOpenThread::OpenThreadEndpointInitParam nativeParams;
nativeParams.lockCb = LockOpenThreadTask;
nativeParams.unlockCb = UnlockOpenThreadTask;
nativeParams.openThreadInstancePtr = chip::DeviceLayer::ThreadStackMgrImpl().OTInstance();
initParams.endpointNativeParams = static_cast<void *>(&nativeParams);
#endif
VerifyOrDie((chip::Server::GetInstance().Init(initParams)) == CHIP_NO_ERROR);
auto * persistentStorage = &Server::GetInstance().GetPersistentStorage();
#if CONFIG_OPERATIONAL_KEYSTORE
chip::Zephyr::App::OperationalKeystore::Init(persistentStorage);
#endif
gExampleDeviceInfoProvider.SetStorageDelegate(persistentStorage);
chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider);
GetAppTask().PostInitMatterServerInstance();
ChipLogDetail(DeviceLayer, "finishing init");
#if CONFIG_DIAG_LOGS_DEMO
chip::Zephyr::App::DiagnosticLogsDemo::DisplayUsage();
#endif
#if CONFIG_CHIP_OTA_PROVIDER
InitOTAServer();
#endif
#if CONFIG_CHIP_APP_WIFI_CONNECT_AT_BOOT
VerifyOrDie(WifiConnectAtboot(chip::Zephyr::App::GetAppTask().GetWifiDriverInstance()) == CHIP_NO_ERROR);
#endif
}
CHIP_ERROR chip::Zephyr::App::AppTaskBase::Init()
{
CHIP_ERROR err = CHIP_NO_ERROR;
/* Init Chip memory management before the stack */
err = chip::Platform::MemoryInit();
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "chip::Platform::MemoryInit() failed: %s", ErrorStr(err));
goto exit;
}
#if CONFIG_LOW_POWER
chip::Zephyr::App::LowPower::Init();
#endif
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Pre Factory Data Provider init failed");
goto exit;
}
/*
* Initialize the CHIP stack.
* Would also initialize all required platform modules
*/
err = PlatformMgr().InitChipStack();
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "PlatformMgr().InitChipStack() failed: %s", ErrorStr(err));
goto exit;
}
/* Initialize Matter factory data after initializing the Matter stack */
err = InitFactoryDataProvider();
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Factory Data Provider init failed");
goto exit;
}
/*
* Register all application callbacks allowing to be informed of stack events
*/
err = CHIPDeviceManager::GetInstance().Init(&GetDeviceCallbacks());
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "CHIPDeviceManager.Init() failed: %s", ErrorStr(err));
goto exit;
}
/* Make sure to initialize the Matter CLI which will include the ot-cli first.
* In fact it is mandatory to enable first the ot-cli before initializing the Matter openthread layer
* which would modify some contexts of the openthread instance.
*/
err = AppMatter_Register();
VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Error during APP features registration"));
#if CONFIG_NET_L2_OPENTHREAD
err = ThreadStackMgr().InitThreadStack();
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Error during ThreadStackMgr().InitThreadStack()");
return err;
}
err = ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::CONFIG_THREAD_DEVICE_TYPE);
if (err != CHIP_NO_ERROR)
{
return err;
}
#endif
/*
* Schedule an event to the Matter stack to initialize
* the ZCL Data Model and start server
*/
PlatformMgr().ScheduleWork(InitServer, 0);
#if CONFIG_CHIP_WIFI || CHIP_DEVICE_CONFIG_ENABLE_WPA
sNetworkCommissioningInstance.Init();
#ifdef ENABLE_CHIP_SHELL
Shell::SetWiFiDriver(chip::Zephyr::App::GetAppTask().GetWifiDriverInstance());
#endif
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_OTA_REQUESTOR
if (err == CHIP_NO_ERROR)
{
/* If an update is under test make it permanent */
OTARequestorInitiator::Instance().HandleSelfTest();
}
#endif
ConfigurationMgr().LogDeviceConfig();
// QR code will be used with CHIP Tool
PrintOnboardingInfo();
PrintCurrentVersion();
/* Start a task to run the CHIP Device event loop. */
err = PlatformMgr().StartEventLoopTask();
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Error during PlatformMgr().StartEventLoopTask()");
goto exit;
}
#if CONFIG_NET_L2_OPENTHREAD
// Start OpenThread task
err = ThreadStackMgrImpl().StartThreadTask();
if (err != CHIP_NO_ERROR)
{
ChipLogError(DeviceLayer, "Error during ThreadStackMgrImpl().StartThreadTask()");
}
#endif
exit:
return err;
}
void chip::Zephyr::App::AppTaskBase::StartCommissioning(intptr_t arg)
{
/* Check the status of the commissioning */
if (ConfigurationMgr().IsFullyProvisioned())
{
ChipLogProgress(DeviceLayer, "Device already commissioned");
}
else if (chip::Server::GetInstance().GetCommissioningWindowManager().IsCommissioningWindowOpen())
{
ChipLogProgress(DeviceLayer, "Commissioning window already opened");
}
else
{
chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow();
}
}
void chip::Zephyr::App::AppTaskBase::StopCommissioning(intptr_t arg)
{
/* Check the status of the commissioning */
if (ConfigurationMgr().IsFullyProvisioned())
{
ChipLogProgress(DeviceLayer, "Device already commissioned");
}
else if (!chip::Server::GetInstance().GetCommissioningWindowManager().IsCommissioningWindowOpen())
{
ChipLogProgress(DeviceLayer, "Commissioning window not opened");
}
else
{
chip::Server::GetInstance().GetCommissioningWindowManager().CloseCommissioningWindow();
}
}
void chip::Zephyr::App::AppTaskBase::SwitchCommissioningState(intptr_t arg)
{
/* Check the status of the commissioning */
if (ConfigurationMgr().IsFullyProvisioned())
{
ChipLogProgress(DeviceLayer, "Device already commissioned");
}
else if (!chip::Server::GetInstance().GetCommissioningWindowManager().IsCommissioningWindowOpen())
{
chip::Server::GetInstance().GetCommissioningWindowManager().OpenBasicCommissioningWindow();
}
else
{
chip::Server::GetInstance().GetCommissioningWindowManager().CloseCommissioningWindow();
}
}
void chip::Zephyr::App::AppTaskBase::StartCommissioningHandler(void)
{
/* Publish an event to the Matter task to always set the commissioning state in the Matter task context */
PlatformMgr().ScheduleWork(StartCommissioning, 0);
}
void chip::Zephyr::App::AppTaskBase::StopCommissioningHandler(void)
{
/* Publish an event to the Matter task to always set the commissioning state in the Matter task context */
PlatformMgr().ScheduleWork(StopCommissioning, 0);
}
void chip::Zephyr::App::AppTaskBase::SwitchCommissioningStateHandler(void)
{
/* Publish an event to the Matter task to always set the commissioning state in the Matter task context */
PlatformMgr().ScheduleWork(SwitchCommissioningState, 0);
}
void chip::Zephyr::App::AppTaskBase::FactoryResetHandler(void)
{
/* Emit the ShutDown event before factory reset */
chip::Server::GetInstance().GenerateShutDownEvent();
chip::Server::GetInstance().ScheduleFactoryReset();
}
void chip::Zephyr::App::AppTaskBase::AppMatter_DisallowDeviceToSleep(void)
{
#if CONFIG_LOW_POWER
PWR_DisallowDeviceToSleep();
#endif
}
void chip::Zephyr::App::AppTaskBase::AppMatter_AllowDeviceToSleep(void)
{
#if CONFIG_LOW_POWER
PWR_AllowDeviceToSleep();
#endif
}
void chip::Zephyr::App::AppTaskBase::PrintOnboardingInfo()
{
#if CONFIG_NETWORK_LAYER_BLE
ChipLogDetail(AppServer, "Retrieving BLE Info");
auto flags = chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE);
#else
auto flags = chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kOnNetwork);
#endif /* CONFIG_NETWORK_LAYER_BLE */
chip::PayloadContents payload;
CHIP_ERROR err = GetPayloadContents(payload, flags);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "GetPayloadContents() failed: %" CHIP_ERROR_FORMAT, err.Format());
}
#if CONFIG_USER_ACTION_REQUIRED
payload.commissioningFlow = chip::CommissioningFlow::kUserActionRequired;
#endif
PrintOnboardingCodes(payload);
}
void chip::Zephyr::App::AppTaskBase::PrintCurrentVersion()
{
// Print the current software version
char currentSoftwareVer[ConfigurationManager::kMaxSoftwareVersionStringLength + 1] = { 0 };
auto err = ConfigurationMgr().GetSoftwareVersionString(currentSoftwareVer, sizeof(currentSoftwareVer));
ReturnOnFailure(err);
uint32_t currentVersion;
err = ConfigurationMgr().GetSoftwareVersion(currentVersion);
ReturnOnFailure(err);
ChipLogProgress(DeviceLayer, "Current Software Version: %s, %d", currentSoftwareVer, static_cast<int>(currentVersion));
}
CHIP_ERROR chip::Zephyr::App::AppTaskBase::InitFactoryDataProvider(void)
{
#if CONFIG_CHIP_FACTORY_DATA
#if CONFIG_CHIP_ENCRYPTED_FACTORY_DATA
FactoryDataPrvdImpl().SetEncryptionMode(FactoryDataProvider::encrypt_ecb);
FactoryDataPrvdImpl().SetAes128Key(&aes128TestKey[0]);
#endif /* CONFIG_CHIP_ENCRYPTED_FACTORY_DATA */
ReturnErrorOnFailure(FactoryDataPrvdImpl().Init());
SetDeviceInstanceInfoProvider(&FactoryDataPrvd());
SetDeviceAttestationCredentialsProvider(&FactoryDataPrvd());
SetCommissionableDataProvider(&FactoryDataPrvd());
#else
SetDeviceInstanceInfoProvider(&DeviceInstanceInfoProviderMgrImpl());
SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider());
#endif /* CONFIG_CHIP_FACTORY_DATA */
return CHIP_NO_ERROR;
}