blob: 0789c12f37aaaccbb15d4068e973238c635af9ce [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2022 Silabs.
* 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 "AppConfig.h"
#include "BaseApplication.h"
#include "OTAConfig.h"
#include <MatterConfig.h>
#include <cmsis_os2.h>
#include <mbedtls/platform.h>
#ifdef SL_WIFI
#include "wfx_host_events.h"
#endif /* SL_WIFI */
#if PW_RPC_ENABLED
#include "Rpc.h"
#endif
#ifdef ENABLE_CHIP_SHELL
#include "matter_shell.h"
#endif
#ifdef HEAP_MONITORING
#include "MemMonitoring.h"
#endif
#ifdef SLI_SI91X_MCU_INTERFACE
#include "wfx_rsi.h"
#if CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED
#include "rsi_m4.h"
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED
#endif // SLI_SI91X_MCU_INTERFACE
#include <crypto/CHIPCryptoPAL.h>
// If building with the EFR32-provided crypto backend, we can use the
// opaque keystore
#if CHIP_CRYPTO_PLATFORM && !(defined(SLI_SI91X_MCU_INTERFACE))
#include <platform/silabs/efr32/Efr32PsaOperationalKeystore.h>
static chip::DeviceLayer::Internal::Efr32PsaOperationalKeystore gOperationalKeystore;
#endif
#include "SilabsDeviceDataProvider.h"
#include <app/InteractionModelEngine.h>
#include <app/TimerDelegates.h>
#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED
#include "SilabsTestEventTriggerDelegate.h" // nogncheck
#endif
#if CHIP_CONFIG_SYNCHRONOUS_REPORTS_ENABLED
#include <app/reporting/SynchronizedReportSchedulerImpl.h>
#else
#include <app/reporting/ReportSchedulerImpl.h>
#endif
#include <lib/support/BytesToHex.h>
#ifdef PERFORMANCE_TEST_ENABLED
#include <performance_test_commands.h>
#endif
#include <AppTask.h>
#include <DeviceInfoProviderImpl.h>
#include <app/server/Server.h>
#include <credentials/DeviceAttestationCredsProvider.h>
#include <examples/platform/silabs/SilabsDeviceAttestationCreds.h>
#include <platform/silabs/platformAbstraction/SilabsPlatform.h>
/**********************************************************
* Defines
*********************************************************/
using namespace ::chip;
using namespace ::chip::Inet;
using namespace ::chip::DeviceLayer;
using namespace ::chip::Credentials::Silabs;
using namespace chip::DeviceLayer::Silabs;
#if CHIP_ENABLE_OPENTHREAD
#include <inet/EndPointStateOpenThread.h>
#include <openthread/cli.h>
#include <openthread/dataset.h>
#include <openthread/error.h>
#include <openthread/heap.h>
#include <openthread/icmp6.h>
#include <openthread/instance.h>
#include <openthread/link.h>
#include <openthread/platform/openthread-system.h>
#include <openthread/tasklet.h>
#include <openthread/thread.h>
// ================================================================================
// Matter Networking Callbacks
// ================================================================================
void LockOpenThreadTask(void)
{
chip::DeviceLayer::ThreadStackMgr().LockThreadStack();
}
void UnlockOpenThreadTask(void)
{
chip::DeviceLayer::ThreadStackMgr().UnlockThreadStack();
}
// ================================================================================
// SilabsMatterConfig Methods
// ================================================================================
CHIP_ERROR SilabsMatterConfig::InitOpenThread(void)
{
SILABS_LOG("Initializing OpenThread stack");
ReturnErrorOnFailure(ThreadStackMgr().InitThreadStack());
#if CHIP_DEVICE_CONFIG_THREAD_FTD
ReturnErrorOnFailure(ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_Router));
#else // CHIP_DEVICE_CONFIG_THREAD_FTD
#if CHIP_CONFIG_ENABLE_ICD_SERVER
#if CHIP_DEVICE_CONFIG_THREAD_SSED
ReturnErrorOnFailure(ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SynchronizedSleepyEndDevice));
#else
ReturnErrorOnFailure(ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_SleepyEndDevice));
#endif
#else // CHIP_CONFIG_ENABLE_ICD_SERVER
ReturnErrorOnFailure(ConnectivityMgr().SetThreadDeviceType(ConnectivityManager::kThreadDeviceType_MinimalEndDevice));
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER
#endif // CHIP_DEVICE_CONFIG_THREAD_FTD
SILABS_LOG("Starting OpenThread task");
return ThreadStackMgrImpl().StartThreadTask();
}
#endif // CHIP_ENABLE_OPENTHREAD
namespace {
constexpr uint32_t kMainTaskStackSize = (1024 * 5);
// Task is dynamically allocated with max priority. This task gets deleted once the inits are completed.
constexpr osThreadAttr_t kMainTaskAttr = { .name = "main",
.attr_bits = osThreadDetached,
.cb_mem = NULL,
.cb_size = 0U,
.stack_mem = NULL,
.stack_size = kMainTaskStackSize,
.priority = osPriorityRealtime7 };
osThreadId_t sMainTaskHandle;
static chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider;
void ApplicationStart(void * unused)
{
CHIP_ERROR err = SilabsMatterConfig::InitMatter(BLE_DEV_NAME);
if (err != CHIP_NO_ERROR)
appError(err);
gExampleDeviceInfoProvider.SetStorageDelegate(&chip::Server::GetInstance().GetPersistentStorage());
chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider);
chip::DeviceLayer::PlatformMgr().LockChipStack();
// Initialize device attestation config
SetDeviceAttestationCredentialsProvider(Credentials::Silabs::GetSilabsDacProvider());
chip::DeviceLayer::PlatformMgr().UnlockChipStack();
SILABS_LOG("Starting App Task");
err = AppTask::GetAppTask().StartAppTask();
if (err != CHIP_NO_ERROR)
appError(err);
VerifyOrDie(osThreadTerminate(sMainTaskHandle) == osOK); // Deleting the main task should never fail.
sMainTaskHandle = nullptr;
}
} // namespace
void SilabsMatterConfig::AppInit()
{
GetPlatform().Init();
sMainTaskHandle = osThreadNew(ApplicationStart, nullptr, &kMainTaskAttr);
SILABS_LOG("Starting scheduler");
VerifyOrDie(sMainTaskHandle); // We can't proceed if the Main Task creation failed.
GetPlatform().StartScheduler();
// Should never get here.
chip::Platform::MemoryShutdown();
SILABS_LOG("Start Scheduler Failed");
appError(CHIP_ERROR_INTERNAL);
}
#if SILABS_OTA_ENABLED
void SilabsMatterConfig::InitOTARequestorHandler(System::Layer * systemLayer, void * appState)
{
OTAConfig::Init();
}
#endif
void SilabsMatterConfig::ConnectivityEventCallback(const ChipDeviceEvent * event, intptr_t arg)
{
// Initialize OTA only when Thread or WiFi connectivity is established
if (((event->Type == DeviceEventType::kThreadConnectivityChange) &&
(event->ThreadConnectivityChange.Result == kConnectivity_Established)) ||
((event->Type == DeviceEventType::kInternetConnectivityChange) &&
(event->InternetConnectivityChange.IPv6 == kConnectivity_Established)))
{
#if SILABS_OTA_ENABLED
SILABS_LOG("Scheduling OTA Requestor initialization")
chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds32(OTAConfig::kInitOTARequestorDelaySec),
InitOTARequestorHandler, nullptr);
#endif
}
}
CHIP_ERROR SilabsMatterConfig::InitMatter(const char * appName)
{
CHIP_ERROR err;
mbedtls_platform_set_calloc_free(CHIPPlatformMemoryCalloc, CHIPPlatformMemoryFree);
SILABS_LOG("==================================================");
SILABS_LOG("%s starting", appName);
SILABS_LOG("==================================================");
#if PW_RPC_ENABLED
chip::rpc::Init();
#endif
#ifdef HEAP_MONITORING
MemMonitoring::StartMonitor();
#endif
//==============================================
// Init Matter Stack
//==============================================
SILABS_LOG("Init CHIP Stack");
// Init Chip memory management before the stack
ReturnErrorOnFailure(chip::Platform::MemoryInit());
// WiFi needs to be initialized after Memory Init for some reason
#ifdef SL_WIFI
ReturnErrorOnFailure(InitWiFi());
#endif
ReturnErrorOnFailure(PlatformMgr().InitChipStack());
SetDeviceInstanceInfoProvider(&Silabs::SilabsDeviceDataProvider::GetDeviceDataProvider());
SetCommissionableDataProvider(&Silabs::SilabsDeviceDataProvider::GetDeviceDataProvider());
chip::DeviceLayer::ConnectivityMgr().SetBLEDeviceName(appName);
#if CHIP_ENABLE_OPENTHREAD
ReturnErrorOnFailure(InitOpenThread());
#endif
// Stop Matter event handling while setting up resources
chip::DeviceLayer::PlatformMgr().LockChipStack();
// Create initParams with SDK example defaults here
// TODO: replace with our own init param to avoid double allocation in examples
static chip::CommonCaseDeviceServerInitParams initParams;
// Report scheduler and timer delegate instance
static chip::app::DefaultTimerDelegate sTimerDelegate;
#if CHIP_CONFIG_SYNCHRONOUS_REPORTS_ENABLED
static chip::app::reporting::SynchronizedReportSchedulerImpl sReportScheduler(&sTimerDelegate);
#else
static chip::app::reporting::ReportSchedulerImpl sReportScheduler(&sTimerDelegate);
#endif
initParams.reportScheduler = &sReportScheduler;
#ifdef SL_MATTER_TEST_EVENT_TRIGGER_ENABLED
static SilabsTestEventTriggerDelegate sTestEventTriggerDelegate;
initParams.testEventTriggerDelegate = &sTestEventTriggerDelegate;
#endif // SL_MATTER_TEST_EVENT_TRIGGER_ENABLED
#if CHIP_CRYPTO_PLATFORM && !(defined(SLI_SI91X_MCU_INTERFACE))
// When building with EFR32 crypto, use the opaque key store
// instead of the default (insecure) one.
gOperationalKeystore.Init();
initParams.operationalKeystore = &gOperationalKeystore;
#endif
// Initialize the remaining (not overridden) providers to the SDK example defaults
(void) initParams.InitializeStaticResourcesBeforeServerInit();
#if CHIP_ENABLE_OPENTHREAD
// Set up OpenThread configuration when OpenThread is included
chip::Inet::EndPointStateOpenThread::OpenThreadEndpointInitParam nativeParams;
nativeParams.lockCb = LockOpenThreadTask;
nativeParams.unlockCb = UnlockOpenThreadTask;
nativeParams.openThreadInstancePtr = chip::DeviceLayer::ThreadStackMgrImpl().OTInstance();
initParams.endpointNativeParams = static_cast<void *>(&nativeParams);
#endif
#if CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI917
initParams.appDelegate = &BaseApplication::sAppDelegate;
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SLI_SI917
// Init Matter Server and Start Event Loop
err = chip::Server::GetInstance().Init(initParams);
chip::DeviceLayer::PlatformMgr().UnlockChipStack();
ReturnErrorOnFailure(err);
// OTA Requestor initialization will be triggered by the connectivity events
PlatformMgr().AddEventHandler(ConnectivityEventCallback, reinterpret_cast<intptr_t>(nullptr));
SILABS_LOG("Starting Platform Manager Event Loop");
ReturnErrorOnFailure(PlatformMgr().StartEventLoopTask());
#ifdef ENABLE_CHIP_SHELL
chip::startShellTask();
#endif
return CHIP_NO_ERROR;
}
#ifdef SL_WIFI
CHIP_ERROR SilabsMatterConfig::InitWiFi(void)
{
#ifdef WF200_WIFI
// Start wfx bus communication task.
wfx_bus_start();
#ifdef SL_WFX_USE_SECURE_LINK
wfx_securelink_task_start(); // start securelink key renegotiation task
#endif // SL_WFX_USE_SECURE_LINK
#endif /* WF200_WIFI */
#ifdef SLI_SI91X_MCU_INTERFACE
sl_status_t status;
if ((status = wfx_wifi_rsi_init()) != SL_STATUS_OK)
{
ReturnErrorOnFailure((CHIP_ERROR) status);
}
#endif // SLI_SI91X_MCU_INTERFACE
return CHIP_NO_ERROR;
}
#endif // SL_WIFI
// ================================================================================
// FreeRTOS Callbacks
// ================================================================================
#if CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED
static bool is_sleep_ready = false;
void vTaskPreSuppressTicksAndSleepProcessing(uint16_t * xExpectedIdleTime)
{
// pointer check
if (xExpectedIdleTime == NULL)
{
return;
}
if (!is_sleep_ready)
{
*xExpectedIdleTime = 0;
}
else
{
// a preliminary check of the expected idle time is performed without making M4 inactive
if (*xExpectedIdleTime >= configEXPECTED_IDLE_TIME_BEFORE_SLEEP)
{
// Indicate M4 is Inactive
P2P_STATUS_REG &= ~M4_is_active;
// Waiting for one more clock cycle to make sure M4 H/W Register is updated
P2P_STATUS_REG;
// TODO: This delay is added to sync between M4 and TA. It should be removed once the logic is moved to wifi SDK
for (uint8_t delay = 0; delay < 10; delay++)
{
__ASM("NOP");
}
// Checking if TA has already triggered a packet to M4
// RX_BUFFER_VALID will be cleared by TA if any packet is triggered
if ((P2P_STATUS_REG & TA_wakeup_M4) || (P2P_STATUS_REG & M4_wakeup_TA) || (!(M4SS_P2P_INTR_SET_REG & RX_BUFFER_VALID)))
{
P2P_STATUS_REG |= M4_is_active;
*xExpectedIdleTime = 0;
}
else
{
M4SS_P2P_INTR_CLR_REG = RX_BUFFER_VALID;
M4SS_P2P_INTR_CLR_REG;
TASS_P2P_INTR_MASK_SET = (TX_PKT_TRANSFER_DONE_INTERRUPT | RX_PKT_TRANSFER_DONE_INTERRUPT |
TA_WRITING_ON_COMM_FLASH | NWP_DEINIT_IN_COMM_FLASH
#ifdef SL_SI91X_SIDE_BAND_CRYPTO
| SIDE_BAND_CRYPTO_DONE
#endif
);
}
}
}
}
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED
extern "C" void vApplicationIdleHook(void)
{
#if CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED
invoke_btn_press_event();
// is_sleep_ready is required since wfx_is_sleep_ready() is not FreeRTOS scheduler agnostic
is_sleep_ready = wfx_is_sleep_ready();
#endif // CHIP_CONFIG_ENABLE_ICD_SERVER && SI917_M4_SLEEP_ENABLED
}