diff --git a/.vscode/launch.json b/.vscode/launch.json index c06ee168b63190..24e1a3db313ae1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "request": "launch", "cwd": "${workspaceRoot}", "executable": "${workspaceFolder}/out/${input:efr32Examples}-app/${input:efr32Boards}/chip-efr32-${input:efr32Examples}-example.out", - "serverpath": "/Applications/SEGGER/JLink_V758e/JLinkGDBServerCLExe", + "serverpath": "/Applications/SEGGER/JLink_V780/JLinkGDBServerCLExe", "servertype": "jlink", "device": "${input:efr32MCU}", "interface": "swd", diff --git a/scripts/examples/gn_efr32_example.sh b/scripts/examples/gn_efr32_example.sh index eb9afb4a9dbd79..005feb7d558a28 100755 --- a/scripts/examples/gn_efr32_example.sh +++ b/scripts/examples/gn_efr32_example.sh @@ -28,6 +28,7 @@ else CHIP_ROOT="$MATTER_ROOT" fi + source "$CHIP_ROOT/scripts/activate.sh" set -x @@ -196,9 +197,9 @@ else USE_WIFI=true fi - optArgs+=$1" " - shift - ;; + optArgs+=$1" " + shift + ;; esac done diff --git a/silabs_examples/sl-newLight/efr32/BUILD.gn b/silabs_examples/sl-newLight/efr32/BUILD.gn index 421f7bfc2711fa..c0435e89c86018 100644 --- a/silabs_examples/sl-newLight/efr32/BUILD.gn +++ b/silabs_examples/sl-newLight/efr32/BUILD.gn @@ -78,7 +78,7 @@ if (efr32_board == "BRD4166A" || efr32_board == "BRD4180A") { show_qr_code = false } -if (efr32_board == "BRD4166A" || efr32_board == "BRD4160A" || efr32_board == "BRD2207A") { +if (efr32_board == "BRD4166A" || efr32_board == "BRD2601B") { rgb_led = true } @@ -171,15 +171,16 @@ efr32_executable("newLight_app") { defines = [] sources = [ + "${examples_plat_dir}/BaseApplication.cpp", "${examples_plat_dir}/LEDWidget.cpp", "${examples_plat_dir}/efr32_utils.cpp", "${examples_plat_dir}/heap_4_silabs.c", "${examples_plat_dir}/init_efrPlatform.cpp", "${examples_plat_dir}/matter_config.cpp", + "light_modules/LightingManager.cpp", "src/AppTask.cpp", "src/ZclCallbacks.cpp", "src/main.cpp", - "light_modules/LightingManager.cpp", ] if (chip_enable_pw_rpc || chip_build_libshell || enable_openthread_cli) { @@ -188,6 +189,7 @@ efr32_executable("newLight_app") { deps = [ ":sdk", + "${chip_root}/examples/providers:device_info_provider", "${chip_root}/silabs_examples/sl-newLight/newLight_DataModel_config", "${chip_root}/src/lib", "${chip_root}/src/setup_payload", @@ -196,14 +198,15 @@ efr32_executable("newLight_app") { # OpenThread Settings if (chip_enable_openthread) { deps += [ - "${chip_root}/third_party/openthread/platforms:libopenthread-platform", - "${chip_root}/third_party/openthread/platforms:libopenthread-platform-utils", + "${chip_root}/third_party/openthread:openthread", + "${chip_root}/third_party/openthread:openthread-platform", "${examples_plat_dir}:efr-matter-shell", ] if (chip_openthread_ftd) { deps += [ - "${chip_root}/third_party/openthread/repo:libopenthread-cli-ftd", - "${chip_root}/third_party/openthread/repo:libopenthread-ftd", + "${chip_root}/third_party/openthread:openthread", + "${chip_root}/third_party/openthread:openthread-platform", + "${examples_plat_dir}:efr-matter-shell", ] } else { deps += [ @@ -248,8 +251,16 @@ efr32_executable("newLight_app") { } if (lcd_on) { - sources += [ "${examples_plat_dir}/display/lcd.c" ] - defines += [ "DISPLAY_ENABLED" ] + sources += [ + "${examples_plat_dir}/display/demo-ui.c", + "${examples_plat_dir}/display/lcd.cpp", + ] + + include_dirs += [ "${examples_plat_dir}/display" ] + defines += [ + "DISPLAY_ENABLED", + "IS_DEMO_LIGHT=1", + ] if (show_qr_code) { defines += [ "QR_CODE_ENABLED" ] @@ -333,6 +344,12 @@ efr32_executable("newLight_app") { ] } + # Attestation Credentials + + if (chip_build_platform_attestation_credentials_provider) { + deps += [ "${examples_plat_dir}:efr32-attestation-credentials" ] + } + output_dir = root_out_dir } diff --git a/silabs_examples/sl-newLight/efr32/args.gni b/silabs_examples/sl-newLight/efr32/args.gni index 96b6262f50b93e..980622cac98ac1 100644 --- a/silabs_examples/sl-newLight/efr32/args.gni +++ b/silabs_examples/sl-newLight/efr32/args.gni @@ -23,3 +23,6 @@ chip_enable_ota_requestor = true pw_log_BACKEND = "${chip_root}/src/lib/support/pw_log_chip" pw_assert_BACKEND = "$dir_pw_assert_log" chip_enable_openthread = true + +openthread_external_platform = + "${chip_root}/third_party/openthread/platforms/efr32:libopenthread-efr32" diff --git a/silabs_examples/sl-newLight/efr32/include/AppTask.h b/silabs_examples/sl-newLight/efr32/include/AppTask.h index dd0628b67cda4a..e58f56e497d9cb 100644 --- a/silabs_examples/sl-newLight/efr32/include/AppTask.h +++ b/silabs_examples/sl-newLight/efr32/include/AppTask.h @@ -21,14 +21,15 @@ #include #include - +#include "BaseApplication.h" #include "AppEvent.h" #include "FreeRTOS.h" -#include "LightingManager.h" #include "sl_simple_button_instances.h" - +#include "LightingManager.h" #include "timers.h" // provides FreeRTOS timer support +#include #include +#include #include // Application-defined error codes in the CHIP_ERROR space. @@ -39,59 +40,32 @@ #define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) #define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) -class AppTask +class AppTask : public BaseApplication { public: - CHIP_ERROR StartAppTask(); + + AppTask() = default; + static AppTask & GetAppTask() { return sAppTask; } static void AppTaskMain(void * pvParameter); + CHIP_ERROR StartAppTask(); + + + void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) override; + static void OnIdentifyStart(Identify * identify); + static void OnIdentifyStop(Identify * identify); void PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction); void PostLightControlActionRequest(int32_t aActor, LightingManager::Action_t aAction, uint8_t value); - void PostEvent(const AppEvent * event); - - void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction); private: - friend AppTask & GetAppTask(void); - - CHIP_ERROR Init(); + static AppTask sAppTask; static void ActionInitiated(LightingManager::Action_t aAction, int32_t aActor); static void ActionCompleted(LightingManager::Action_t aAction); - - void CancelTimer(void); - - void DispatchEvent(AppEvent * event); - - static void FunctionTimerEventHandler(AppEvent * aEvent); - static void FunctionHandler(AppEvent * aEvent); static void LightActionEventHandler(AppEvent * aEvent); static void LightControlEventHandler(AppEvent * aEvent); - static void TimerEventHandler(TimerHandle_t xTimer); - static void UpdateClusterState(intptr_t context); - - void StartTimer(uint32_t aTimeoutMs); - - enum Function_t - { - kFunction_NoneSelected = 0, - kFunction_SoftwareUpdate = 0, - kFunction_StartBleAdv = 1, - kFunction_FactoryReset = 2, - - kFunction_Invalid - } Function; - - Function_t mFunction; - bool mFunctionTimerActive; - bool mSyncClusterToButtonAction; - - static AppTask sAppTask; + static void ButtonHandler(AppEvent * aEvent); + CHIP_ERROR Init(); }; - -inline AppTask & GetAppTask(void) -{ - return AppTask::sAppTask; -} diff --git a/silabs_examples/sl-newLight/efr32/light_modules/LightingManager.cpp b/silabs_examples/sl-newLight/efr32/light_modules/LightingManager.cpp index b97d0cedc0177a..55426a099bb69c 100644 --- a/silabs_examples/sl-newLight/efr32/light_modules/LightingManager.cpp +++ b/silabs_examples/sl-newLight/efr32/light_modules/LightingManager.cpp @@ -23,8 +23,6 @@ #include "AppTask.h" #include -#include - using namespace chip; using namespace ::chip::DeviceLayer; @@ -32,6 +30,21 @@ LightingManager LightingManager::sLight; TimerHandle_t sLightTimer; +namespace { + +/********************************************************** + * OffWithEffect Callbacks + *********************************************************/ + +OnOffEffect gEffect = { + chip::EndpointId{ 1 }, + LightMgr().OnTriggerOffWithEffect, + EMBER_ZCL_ON_OFF_EFFECT_IDENTIFIER_DELAYED_ALL_OFF, + static_cast(EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_FADE_TO_OFF_IN_0P8_SECONDS), +}; + +} // namespace + CHIP_ERROR LightingManager::Init() { // Create FreeRTOS sw timer for light timer. @@ -58,6 +71,7 @@ CHIP_ERROR LightingManager::Init() mAutoTurnOffTimerArmed = false; mAutoTurnOff = false; mAutoTurnOffDuration = 0; + mOffEffectArmed = false; return CHIP_NO_ERROR; } @@ -94,13 +108,13 @@ bool LightingManager::InitiateAction(int32_t aActor, Action_t aAction) State_t new_state; // Initiate Turn On/Off Action only when the previous one is complete. - if (mState == kState_OffCompleted && aAction == ON_ACTION) + if (((mState == kState_OffCompleted) || mOffEffectArmed) && aAction == ON_ACTION) { action_initiated = true; new_state = kState_OnInitiated; } - else if (mState == kState_OnCompleted && aAction == OFF_ACTION) + else if (mState == kState_OnCompleted && aAction == OFF_ACTION && mOffEffectArmed == false) { action_initiated = true; @@ -118,6 +132,12 @@ bool LightingManager::InitiateAction(int32_t aActor, Action_t aAction) CancelTimer(); } + if (mOffEffectArmed && new_state == kState_OnInitiated) + { + CancelTimer(); + mOffEffectArmed = false; + } + StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS); // Since the timer started successfully, update the state and trigger callback @@ -131,7 +151,6 @@ bool LightingManager::InitiateAction(int32_t aActor, Action_t aAction) return action_initiated; } - bool LightingManager::InitiateActionLight(int32_t aActor, Action_t aAction, uint16_t endpoint, uint8_t value) { bool action_initiated = false; @@ -142,7 +161,7 @@ bool LightingManager::InitiateActionLight(int32_t aActor, Action_t aAction, uint case MOVE_TO_HUE: case MOVE_TO_SAT: action_initiated = true; - GetAppTask().PostLightControlActionRequest(aActor, aAction, value); + AppTask::GetAppTask().PostLightControlActionRequest(aActor, aAction, value); break; default: break; @@ -193,17 +212,21 @@ void LightingManager::TimerEventHandler(TimerHandle_t xTimer) { event.Handler = AutoTurnOffTimerEventHandler; } + else if (light->mOffEffectArmed) + { + event.Handler = OffEffectTimerEventHandler; + } else { event.Handler = ActuatorMovementTimerEventHandler; } - GetAppTask().PostEvent(&event); + AppTask::GetAppTask().PostEvent(&event); } void LightingManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) { LightingManager * light = static_cast(aEvent->TimerEvent.Context); - int32_t actor = 0; + int32_t actor = AppEvent::kEventType_Timer; // Make sure auto turn off timer is still armed. if (!light->mAutoTurnOffTimerArmed) @@ -218,6 +241,24 @@ void LightingManager::AutoTurnOffTimerEventHandler(AppEvent * aEvent) light->InitiateAction(actor, OFF_ACTION); } +void LightingManager::OffEffectTimerEventHandler(AppEvent * aEvent) +{ + LightingManager * light = static_cast(aEvent->TimerEvent.Context); + int32_t actor = AppEvent::kEventType_Timer; + + // Make sure auto turn off timer is still armed. + if (!light->mOffEffectArmed) + { + return; + } + + light->mOffEffectArmed = false; + + EFR32_LOG("OffEffect completed"); + + light->InitiateAction(actor, OFF_ACTION); +} + void LightingManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) { Action_t actionCompleted = INVALID_ACTION; @@ -253,3 +294,47 @@ void LightingManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) } } } + +void LightingManager::OnTriggerOffWithEffect(OnOffEffect * effect) +{ + chip::app::Clusters::OnOff::OnOffEffectIdentifier effectId = effect->mEffectIdentifier; + uint8_t effectVariant = effect->mEffectVariant; + uint32_t offEffectDuration = 0; + + // Temporary print outs and delay to test OffEffect behaviour + // Until dimming is supported for dev boards. + if (effectId == EMBER_ZCL_ON_OFF_EFFECT_IDENTIFIER_DELAYED_ALL_OFF) + { + if (effectVariant == EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_FADE_TO_OFF_IN_0P8_SECONDS) + { + offEffectDuration = 800; + ChipLogProgress(Zcl, "EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_FADE_TO_OFF_IN_0P8_SECONDS"); + } + else if (effectVariant == EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_NO_FADE) + { + offEffectDuration = 800; + ChipLogProgress(Zcl, "EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_NO_FADE"); + } + else if (effectVariant == + EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_50_PERCENT_DIM_DOWN_IN_0P8_SECONDS_THEN_FADE_TO_OFF_IN_12_SECONDS) + { + offEffectDuration = 12800; + ChipLogProgress(Zcl, + "EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_50_PERCENT_DIM_DOWN_IN_0P8_SECONDS_THEN_FADE_TO_OFF_" + "IN_12_SECONDS"); + } + } + else if (effectId == EMBER_ZCL_ON_OFF_EFFECT_IDENTIFIER_DYING_LIGHT) + { + if (effectVariant == + EMBER_ZCL_ON_OFF_DYING_LIGHT_EFFECT_VARIANT_20_PERCENTER_DIM_UP_IN_0P5_SECONDS_THEN_FADE_TO_OFF_IN_1_SECOND) + { + offEffectDuration = 1500; + ChipLogProgress( + Zcl, "EMBER_ZCL_ON_OFF_DYING_LIGHT_EFFECT_VARIANT_20_PERCENTER_DIM_UP_IN_0P5_SECONDS_THEN_FADE_TO_OFF_IN_1_SECOND"); + } + } + + LightMgr().mOffEffectArmed = true; + LightMgr().StartTimer(offEffectDuration); +} diff --git a/silabs_examples/sl-newLight/efr32/light_modules/LightingManager.h b/silabs_examples/sl-newLight/efr32/light_modules/LightingManager.h index 53e3533fbf9c5e..3775902ea703ec 100644 --- a/silabs_examples/sl-newLight/efr32/light_modules/LightingManager.h +++ b/silabs_examples/sl-newLight/efr32/light_modules/LightingManager.h @@ -25,6 +25,7 @@ #include "FreeRTOS.h" #include "timers.h" // provides FreeRTOS timer support +#include #include @@ -33,8 +34,8 @@ class LightingManager public: enum Action_t { - OFF_ACTION = 0, - ON_ACTION, + ON_ACTION = 0, + OFF_ACTION, MOVE_TO_LEVEL, MOVE_TO_HUE, MOVE_TO_SAT, @@ -63,6 +64,8 @@ class LightingManager typedef void (*Callback_fn_completed)(Action_t); void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB); + static void OnTriggerOffWithEffect(OnOffEffect * effect); + private: friend LightingManager & LightMgr(void); State_t mState; @@ -73,6 +76,7 @@ class LightingManager bool mAutoTurnOff; uint32_t mAutoTurnOffDuration; bool mAutoTurnOffTimerArmed; + bool mOffEffectArmed; void CancelTimer(void); void StartTimer(uint32_t aTimeoutMs); @@ -80,6 +84,7 @@ class LightingManager static void TimerEventHandler(TimerHandle_t xTimer); static void AutoTurnOffTimerEventHandler(AppEvent * aEvent); static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); + static void OffEffectTimerEventHandler(AppEvent * aEvent); static LightingManager sLight; }; diff --git a/silabs_examples/sl-newLight/efr32/light_modules/led_widget_rgb.cpp b/silabs_examples/sl-newLight/efr32/light_modules/led_widget_rgb.cpp index 5982b0dbbf5ff2..921ad9fe59ba74 100644 --- a/silabs_examples/sl-newLight/efr32/light_modules/led_widget_rgb.cpp +++ b/silabs_examples/sl-newLight/efr32/light_modules/led_widget_rgb.cpp @@ -34,14 +34,14 @@ #include #include #include - +#include #include "AppConfig.h" #include "em_gpio.h" #include "sl_led.h" #include "sl_pwm_led.h" #include "sl_simple_rgb_pwm_led.h" - +using namespace chip::app::Clusters::OnOff; /** * @brief Red led instance. */ @@ -136,7 +136,8 @@ void LEDWidgetRGB::InitGpioRGB() sl_pwm_led_init(&led_pwm_red); sl_pwm_led_init(&led_pwm_green); sl_pwm_led_init(&led_pwm_blue); - sl_led_init(&sl_led_rgb); + sl_led_init((sl_led_t *)&sl_led_rgb_pwm); + } @@ -166,6 +167,8 @@ void LEDWidgetRGB::Init(const sl_led_rgb_pwm_t* led) void LEDWidgetRGB::SetLevel(uint8_t level) { + bool currentValue; + EmberAfStatus status; /* 1. Check if the input value is correct. */ if (level > ATTRIBUTE_LEVEL_MAX) { diff --git a/silabs_examples/sl-newLight/efr32/src/AppTask.cpp b/silabs_examples/sl-newLight/efr32/src/AppTask.cpp index 0e9ca4b00f7734..74df5747bc3200 100644 --- a/silabs_examples/sl-newLight/efr32/src/AppTask.cpp +++ b/silabs_examples/sl-newLight/efr32/src/AppTask.cpp @@ -24,10 +24,7 @@ #ifdef RGB_LED_ENABLED #include "led_widget_rgb.h" #endif //RGB_LED_ENABLED -#ifdef DISPLAY_ENABLED -#include "lcd.h" -#include "qrcodegen.h" -#endif // DISPLAY_ENABLED + #include "sl_simple_led_instances.h" #include #include @@ -51,23 +48,7 @@ #include #include -#if CHIP_ENABLE_OPENTHREAD -#include -#include -#include -#endif -#ifdef SL_WIFI -#include "wfx_host_events.h" -#include -#include -#endif /* SL_WIFI */ - -#define FACTORY_RESET_TRIGGER_TIMEOUT 3000 -#define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 -#define APP_TASK_STACK_SIZE (4096) -#define APP_TASK_PRIORITY 2 -#define APP_EVENT_QUEUE_SIZE 10 -#define EXAMPLE_VENDOR_ID 0xcafe + #define SYSTEM_STATE_LED &sl_led_led0 #define LIGHT_LED &sl_led_led1 @@ -78,12 +59,8 @@ using namespace chip; using namespace ::chip::DeviceLayer; namespace { -TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. -TaskHandle_t sAppTaskHandle; -QueueHandle_t sAppEventQueue; -LEDWidget sStatusLED; #ifdef RGB_LED_ENABLED #define LIGHT_LED_RGB &sl_led_rgb_pwm LEDWidgetRGB sLightLED; @@ -91,28 +68,8 @@ LEDWidgetRGB sLightLED; LEDWidget sLightLED; #endif -#ifdef SL_WIFI -bool sIsWiFiProvisioned = false; -bool sIsWiFiEnabled = false; -bool sIsWiFiAttached = false; - -app::Clusters::NetworkCommissioning::Instance - sWiFiNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::SlWiFiDriver::GetInstance())); -#endif /* SL_WIFI */ - -#if CHIP_ENABLE_OPENTHREAD -bool sIsThreadProvisioned = false; -bool sIsThreadEnabled = false; -#endif /* CHIP_ENABLE_OPENTHREAD */ -bool sHaveBLEConnections = false; - EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; -uint8_t sAppEventQueueBuffer[APP_EVENT_QUEUE_SIZE * sizeof(AppEvent)]; -StaticQueue_t sAppEventQueueStruct; - -StackType_t appStack[APP_TASK_STACK_SIZE / sizeof(StackType_t)]; -StaticTask_t appTaskStruct; /********************************************************** @@ -216,111 +173,58 @@ OnOffEffect gEffect = { } // namespace using namespace chip::TLV; -using namespace ::chip::Credentials; using namespace ::chip::DeviceLayer; AppTask AppTask::sAppTask; -CHIP_ERROR AppTask::StartAppTask() -{ - sAppEventQueue = xQueueCreateStatic(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent), sAppEventQueueBuffer, &sAppEventQueueStruct); - if (sAppEventQueue == NULL) - { - EFR32_LOG("Failed to allocate app event queue"); - appError(APP_ERROR_EVENT_QUEUE_FAILED); - } - - // Start App task. - sAppTaskHandle = xTaskCreateStatic(AppTaskMain, APP_TASK_NAME, ArraySize(appStack), NULL, 1, appStack, &appTaskStruct); - return (sAppTaskHandle == nullptr) ? APP_ERROR_CREATE_TASK_FAILED : CHIP_NO_ERROR; -} CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; -#ifdef SL_WIFI - /* - * Wait for the WiFi to be initialized - */ - EFR32_LOG("APP: Wait WiFi Init"); - while (!wfx_hw_ready()) - { - vTaskDelay(10); - } - EFR32_LOG("APP: Done WiFi Init"); - /* We will init server when we get IP */ - - sWiFiNetworkCommissioningInstance.Init(); +#ifdef DISPLAY_ENABLED + GetLCD().Init((uint8_t *) "Lighting-App"); #endif - chip::DeviceLayer::PlatformMgr().LockChipStack(); - // Initialize device attestation config - SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); - chip::DeviceLayer::PlatformMgr().UnlockChipStack(); - - // Create FreeRTOS sw timer for Function Selection. - sFunctionTimer = xTimerCreate("FnTmr", // Just a text name, not used by the RTOS kernel - 1, // == default timer period (mS) - false, // no timer reload (==one-shot) - (void *) this, // init timer id = app task obj context - TimerEventHandler // timer callback handler - ); - if (sFunctionTimer == NULL) + err = BaseApplication::Init(&gIdentify); + + if (err != CHIP_NO_ERROR) { - EFR32_LOG("funct timer create failed"); - appError(APP_ERROR_CREATE_TIMER_FAILED); + EFR32_LOG("BaseApplication::Init() failed"); + appError(err); } - EFR32_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); - err = LightMgr().Init(); if (err != CHIP_NO_ERROR) { - EFR32_LOG("LightMgr().Init() failed"); + EFR32_LOG("LightMgr::Init() failed"); appError(err); } - LightMgr().SetCallbacks(ActionInitiated, ActionCompleted); - // Initialize LEDs - LEDWidget::InitGpio(); - sStatusLED.Init(SYSTEM_STATE_LED); + + #if defined(RGB_LED_ENABLED) LEDWidgetRGB::InitGpioRGB(); sLightLED.Init(LIGHT_LED_RGB); -#else +#else sLightLED.Init(LIGHT_LED); -#endif //RGB_LED_ENABLED - sLightLED.Set(LightMgr().IsLightOn()); - - ConfigurationMgr().LogDeviceConfig(); - -// Print setup info on LCD if available -#ifdef DISPLAY_ENABLED - // Create buffer for QR code that can fit max size and null terminator. - char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; - chip::MutableCharSpan QRCode(qrCodeBuffer); - - if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) - { - LCDWriteQRCode((uint8_t *) QRCode.data()); - } - else - { - EFR32_LOG("Getting QR code failed!"); - } -#else - PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); #endif + sLightLED.Set(LightMgr().IsLightOn()); + return err; } +CHIP_ERROR AppTask::StartAppTask() +{ + return BaseApplication::StartAppTask(AppTaskMain); +} + void AppTask::AppTaskMain(void * pvParameter) { AppEvent event; - + QueueHandle_t sAppEventQueue = *(static_cast(pvParameter)); CHIP_ERROR err = sAppTask.Init(); if (err != CHIP_NO_ERROR) { @@ -338,76 +242,24 @@ void AppTask::AppTaskMain(void * pvParameter) sAppTask.DispatchEvent(&event); eventReceived = xQueueReceive(sAppEventQueue, &event, 0); } - - // Collect connectivity and configuration state from the CHIP stack. Because - // the CHIP event loop is being run in a separate task, the stack must be - // locked while these values are queried. However we use a non-blocking - // lock request (TryLockCHIPStack()) to avoid blocking other UI activities - // when the CHIP task is busy (e.g. with a long crypto operation). - if (PlatformMgr().TryLockChipStack()) - { -#ifdef SL_WIFI - sIsWiFiProvisioned = ConnectivityMgr().IsWiFiStationProvisioned(); - sIsWiFiEnabled = ConnectivityMgr().IsWiFiStationEnabled(); - sIsWiFiAttached = ConnectivityMgr().IsWiFiStationConnected(); -#endif /* SL_WIFI */ -#if CHIP_ENABLE_OPENTHREAD - sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); -#endif /* CHIP_ENABLE_OPENTHREAD */ - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - PlatformMgr().UnlockChipStack(); - } - - // Update the status LED if factory reset has not been initiated. - // - // If system has "full connectivity", keep the LED On constantly. - // - // If thread and service provisioned, but not attached to the thread network - // yet OR no connectivity to the service OR subscriptions are not fully - // established THEN blink the LED Off for a short period of time. - // - // If the system has ble connection(s) uptill the stage above, THEN blink - // the LEDs at an even rate of 100ms. - // - // Otherwise, blink the LED ON for a very short time. - if (sAppTask.mFunction != kFunction_FactoryReset) - { - if (gIdentify.mActive) - { - sStatusLED.Blink(250, 250); - } - if (sIdentifyEffect != EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT) - { - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK) - { - sStatusLED.Blink(50, 50); - } - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE) - { - sStatusLED.Blink(1000, 1000); - } - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY) - { - sStatusLED.Blink(300, 700); - } - } -#if CHIP_ENABLE_OPENTHREAD - if (sIsThreadProvisioned && sIsThreadEnabled) -#else - if (sIsWiFiProvisioned && sIsWiFiEnabled && !sIsWiFiAttached) -#endif - { - sStatusLED.Blink(950, 50); - } - else if (sHaveBLEConnections) { sStatusLED.Blink(100, 100); } - else { sStatusLED.Blink(50, 950); } - } - - sStatusLED.Animate(); sLightLED.Animate(); } } +void AppTask::OnIdentifyStart(Identify * identify) +{ + ChipLogProgress(Zcl, "onIdentifyStart"); +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + sAppTask.StartStatusLEDTimer(); +#endif +} +void AppTask::OnIdentifyStop(Identify * identify) +{ + ChipLogProgress(Zcl, "onIdentifyStop"); +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + sAppTask.StopStatusLEDTimer(); +#endif +} + void AppTask::LightActionEventHandler(AppEvent * aEvent) { @@ -426,10 +278,12 @@ void AppTask::LightActionEventHandler(AppEvent * aEvent) if (LightMgr().IsLightOn()) { action = LightingManager::OFF_ACTION; + } else { action = LightingManager::ON_ACTION; + } actor = AppEvent::kEventType_Button; } @@ -448,7 +302,39 @@ void AppTask::LightActionEventHandler(AppEvent * aEvent) } } } +void AppTask::ActionInitiated(LightingManager::Action_t aAction, int32_t aActor) +{ + bool lightOn = aAction == LightingManager::ON_ACTION; + EFR32_LOG("Turning light %s", (lightOn) ? "On" : "Off") + sLightLED.Set(lightOn); +#ifdef DISPLAY_ENABLED + sAppTask.GetLCD().WriteDemoUI(lightOn); +#endif + + if (aActor == AppEvent::kEventType_Button) + { + sAppTask.mSyncClusterToButtonAction = true; + } +} + +void AppTask::ActionCompleted(LightingManager::Action_t aAction) +{ + // action has been completed on the light + if (aAction == LightingManager::ON_ACTION) + { + EFR32_LOG("Light ON") + } + else if (aAction == LightingManager::OFF_ACTION) + { + EFR32_LOG("Light OFF") + } + if (sAppTask.mSyncClusterToButtonAction) + { + chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(nullptr)); + sAppTask.mSyncClusterToButtonAction = false; + } +} void AppTask::LightControlEventHandler(AppEvent * aEvent) { @@ -498,177 +384,12 @@ void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAc } else if (buttonHandle == APP_FUNCTION_BUTTON) { - button_event.Handler = FunctionHandler; + button_event.Handler = BaseApplication::ButtonHandler; sAppTask.PostEvent(&button_event); } } -void AppTask::TimerEventHandler(TimerHandle_t xTimer) -{ - AppEvent event; - event.Type = AppEvent::kEventType_Timer; - event.TimerEvent.Context = (void *) xTimer; - event.Handler = FunctionTimerEventHandler; - sAppTask.PostEvent(&event); -} - -void AppTask::FunctionTimerEventHandler(AppEvent * aEvent) -{ - if (aEvent->Type != AppEvent::kEventType_Timer) - { - return; - } - - // If we reached here, the button was held past FACTORY_RESET_TRIGGER_TIMEOUT, - // initiate factory reset - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv) - { - EFR32_LOG("Factory Reset Triggered. Release button within %ums to cancel.", FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); - - // Start timer for FACTORY_RESET_CANCEL_WINDOW_TIMEOUT to allow user to - // cancel, if required. - sAppTask.StartTimer(FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); - - sAppTask.mFunction = kFunction_FactoryReset; - - // Turn off all LEDs before starting blink to make sure blink is - // co-ordinated. - sStatusLED.Set(false); - sLightLED.Set(false); - - sStatusLED.Blink(500); - sLightLED.Blink(500); - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - // Actually trigger Factory Reset - sAppTask.mFunction = kFunction_NoneSelected; - chip::Server::GetInstance().ScheduleFactoryReset(); - } -} - -void AppTask::FunctionHandler(AppEvent * aEvent) -{ - // To trigger software update: press the APP_FUNCTION_BUTTON button briefly (< - // FACTORY_RESET_TRIGGER_TIMEOUT) To initiate factory reset: press the - // APP_FUNCTION_BUTTON for FACTORY_RESET_TRIGGER_TIMEOUT + - // FACTORY_RESET_CANCEL_WINDOW_TIMEOUT All LEDs start blinking after - // FACTORY_RESET_TRIGGER_TIMEOUT to signal factory reset has been initiated. - // To cancel factory reset: release the APP_FUNCTION_BUTTON once all LEDs - // start blinking within the FACTORY_RESET_CANCEL_WINDOW_TIMEOUT - if (aEvent->ButtonEvent.Action == SL_SIMPLE_BUTTON_PRESSED) - { - if (!sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_NoneSelected) - { - sAppTask.StartTimer(FACTORY_RESET_TRIGGER_TIMEOUT); - sAppTask.mFunction = kFunction_StartBleAdv; - } - } - else - { - // If the button was released before factory reset got initiated, start BLE advertissement in fast mode - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv) - { - sAppTask.CancelTimer(); - sAppTask.mFunction = kFunction_NoneSelected; - -#ifdef SL_WIFI - if (!ConnectivityMgr().IsWiFiStationProvisioned()) -#else - if (!ConnectivityMgr().IsThreadProvisioned()) -#endif /* !SL_WIFI */ - { - // Enable BLE advertisements - ConnectivityMgr().SetBLEAdvertisingEnabled(true); - ConnectivityMgr().SetBLEAdvertisingMode(ConnectivityMgr().kFastAdvertising); - } - else { EFR32_LOG("Network is already provisioned, Ble advertissement not enabled"); } - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - // Set Light status LED back to show state of light. - sLightLED.Set(LightMgr().IsLightOn()); - - sAppTask.CancelTimer(); - - // Change the function to none selected since factory reset has been - // canceled. - sAppTask.mFunction = kFunction_NoneSelected; - - EFR32_LOG("Factory Reset has been Canceled"); - } - } -} - -void AppTask::CancelTimer() -{ - if (xTimerStop(sFunctionTimer, 0) == pdFAIL) - { - EFR32_LOG("app timer stop() failed"); - appError(APP_ERROR_STOP_TIMER_FAILED); - } - mFunctionTimerActive = false; -} - -void AppTask::StartTimer(uint32_t aTimeoutInMs) -{ - if (xTimerIsTimerActive(sFunctionTimer)) - { - EFR32_LOG("app timer already started!"); - CancelTimer(); - } - - // timer is not active, change its period to required value (== restart). - // FreeRTOS- Block for a maximum of 100 ticks if the change period command - // cannot immediately be sent to the timer command queue. - if (xTimerChangePeriod(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) - { - EFR32_LOG("app timer start() failed"); - appError(APP_ERROR_START_TIMER_FAILED); - } - - mFunctionTimerActive = true; -} - -void AppTask::ActionInitiated(LightingManager::Action_t aAction, int32_t aActor) -{ - // Action initiated, update the light led - if (aAction == LightingManager::ON_ACTION) - { - EFR32_LOG("Turning light ON") - sLightLED.Set(true); - } - else if (aAction == LightingManager::OFF_ACTION) - { - EFR32_LOG("Turning light OFF") - sLightLED.Set(false); - } - - if (aActor == AppEvent::kEventType_Button) - { - sAppTask.mSyncClusterToButtonAction = true; - } -} - -void AppTask::ActionCompleted(LightingManager::Action_t aAction) -{ - // action has been completed on the light - if (aAction == LightingManager::ON_ACTION) - { - EFR32_LOG("Light ON") - } - else if (aAction == LightingManager::OFF_ACTION) - { - EFR32_LOG("Light OFF") - } - - if (sAppTask.mSyncClusterToButtonAction) - { - chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(nullptr)); - sAppTask.mSyncClusterToButtonAction = false; - } -} void AppTask::PostLightActionRequest(int32_t aActor, LightingManager::Action_t aAction) { @@ -679,7 +400,6 @@ void AppTask::PostLightActionRequest(int32_t aActor, LightingManager::Action_t a event.Handler = LightActionEventHandler; PostEvent(&event); } - void AppTask::PostLightControlActionRequest(int32_t aActor, LightingManager::Action_t aAction, uint8_t value) { AppEvent light_event = {}; @@ -690,58 +410,11 @@ void AppTask::PostLightControlActionRequest(int32_t aActor, LightingManager::Act light_event.Handler = LightControlEventHandler; PostEvent(&light_event); } - -void AppTask::PostEvent(const AppEvent * aEvent) -{ - if (sAppEventQueue != NULL) - { - BaseType_t status; - if (xPortIsInsideInterrupt()) - { - BaseType_t higherPrioTaskWoken = pdFALSE; - status = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken); - -#ifdef portYIELD_FROM_ISR - portYIELD_FROM_ISR(higherPrioTaskWoken); -#elif portEND_SWITCHING_ISR // portYIELD_FROM_ISR or portEND_SWITCHING_ISR - portEND_SWITCHING_ISR(higherPrioTaskWoken); -#else // portYIELD_FROM_ISR or portEND_SWITCHING_ISR -#error "Must have portYIELD_FROM_ISR or portEND_SWITCHING_ISR" -#endif // portYIELD_FROM_ISR or portEND_SWITCHING_ISR - } - else - { - status = xQueueSend(sAppEventQueue, aEvent, 1); - } - - if (!status) - EFR32_LOG("Failed to post event to app task event queue"); - } - else - { - EFR32_LOG("Event Queue is NULL should never happen"); - } -} - -void AppTask::DispatchEvent(AppEvent * aEvent) -{ - if (aEvent->Handler) - { - aEvent->Handler(aEvent); - } - else - { - EFR32_LOG("Event received with no handler. Dropping event."); - } -} - void AppTask::UpdateClusterState(intptr_t context) { uint8_t newValue = LightMgr().IsLightOn(); - // write the new on/off value EmberAfStatus status = OnOffServer::Instance().setOnOffValue(1, newValue, false); - if (status != EMBER_ZCL_STATUS_SUCCESS) { EFR32_LOG("ERR: updating on/off %x", status); diff --git a/silabs_examples/sl-newLight/efr32/src/ZclCallbacks.cpp b/silabs_examples/sl-newLight/efr32/src/ZclCallbacks.cpp index dfda9bbab22563..83e0ed858fe0ae 100644 --- a/silabs_examples/sl-newLight/efr32/src/ZclCallbacks.cpp +++ b/silabs_examples/sl-newLight/efr32/src/ZclCallbacks.cpp @@ -31,7 +31,6 @@ using namespace ::chip; using namespace ::chip::app::Clusters; - void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size, uint8_t * value) { @@ -86,6 +85,7 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & } } + /** @brief OnOff Cluster Init * * This function is called when a specific cluster is initialized. It gives the diff --git a/silabs_examples/sl-newLight/efr32/src/main.cpp b/silabs_examples/sl-newLight/efr32/src/main.cpp index 07c5732bc4e5c2..ff8e38061fd8ce 100644 --- a/silabs_examples/sl-newLight/efr32/src/main.cpp +++ b/silabs_examples/sl-newLight/efr32/src/main.cpp @@ -23,17 +23,26 @@ #include "init_efrPlatform.h" #include "sl_simple_button_instances.h" #include "sl_system_kernel.h" +#include +#include +#include #include +#ifdef EFR32_ATTESTATION_CREDENTIALS +#include +#else +#include +#endif #define BLE_DEV_NAME "SL-newLight" using namespace ::chip; using namespace ::chip::Inet; using namespace ::chip::DeviceLayer; +using namespace ::chip::Credentials; #define UNUSED_PARAMETER(a) (a = a) volatile int apperror_cnt; - +static chip::DeviceLayer::DeviceInfoProviderImpl gExampleDeviceInfoProvider; // ================================================================================ // Main Code // ================================================================================ @@ -42,9 +51,21 @@ int main(void) init_efrPlatform(); if (EFR32MatterConfig::InitMatter(BLE_DEV_NAME) != CHIP_NO_ERROR) appError(CHIP_ERROR_INTERNAL); + gExampleDeviceInfoProvider.SetStorageDelegate(&chip::Server::GetInstance().GetPersistentStorage()); + chip::DeviceLayer::SetDeviceInfoProvider(&gExampleDeviceInfoProvider); + + chip::DeviceLayer::PlatformMgr().LockChipStack(); + // Initialize device attestation config +#ifdef EFR32_ATTESTATION_CREDENTIALS + SetDeviceAttestationCredentialsProvider(EFR32::GetEFR32DacProvider()); +#else + SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); +#endif + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); EFR32_LOG("Starting App Task"); - if (GetAppTask().StartAppTask() != CHIP_NO_ERROR) + + if (AppTask::GetAppTask().StartAppTask() != CHIP_NO_ERROR) appError(CHIP_ERROR_INTERNAL); EFR32_LOG("Starting FreeRTOS scheduler"); @@ -58,5 +79,6 @@ int main(void) void sl_button_on_change(const sl_button_t * handle) { - GetAppTask().ButtonEventHandler(handle, sl_button_get_state(handle)); + + AppTask::GetAppTask().ButtonEventHandler(handle, sl_button_get_state(handle)); } diff --git a/silabs_examples/template/efr32/BUILD.gn b/silabs_examples/template/efr32/BUILD.gn index 2f7794a633b0e4..627a7eb3a9e288 100644 --- a/silabs_examples/template/efr32/BUILD.gn +++ b/silabs_examples/template/efr32/BUILD.gn @@ -160,6 +160,7 @@ efr32_executable("template_app") { defines = [] sources = [ + "${examples_plat_dir}/BaseApplication.cpp", "${examples_plat_dir}/LEDWidget.cpp", "${examples_plat_dir}/efr32_utils.cpp", "${examples_plat_dir}/heap_4_silabs.c", @@ -190,8 +191,9 @@ efr32_executable("template_app") { ] if (chip_openthread_ftd) { deps += [ - "${chip_root}/third_party/openthread/repo:libopenthread-cli-ftd", - "${chip_root}/third_party/openthread/repo:libopenthread-ftd", + "${chip_root}/third_party/openthread:openthread", + "${chip_root}/third_party/openthread:openthread-platform", + "${examples_plat_dir}:efr-matter-shell", ] } else { deps += [ @@ -236,8 +238,16 @@ efr32_executable("template_app") { } if (lcd_on) { - sources += [ "${examples_plat_dir}/display/lcd.c" ] - defines += [ "DISPLAY_ENABLED" ] + sources += [ + "${examples_plat_dir}/display/demo-ui.c", + "${examples_plat_dir}/display/lcd.cpp", + ] + + include_dirs += [ "${examples_plat_dir}/display" ] + defines += [ + "DISPLAY_ENABLED", + "IS_DEMO_LIGHT=1", + ] if (show_qr_code) { defines += [ "QR_CODE_ENABLED" ] diff --git a/silabs_examples/template/efr32/args.gni b/silabs_examples/template/efr32/args.gni index 96b6262f50b93e..980622cac98ac1 100644 --- a/silabs_examples/template/efr32/args.gni +++ b/silabs_examples/template/efr32/args.gni @@ -23,3 +23,6 @@ chip_enable_ota_requestor = true pw_log_BACKEND = "${chip_root}/src/lib/support/pw_log_chip" pw_assert_BACKEND = "$dir_pw_assert_log" chip_enable_openthread = true + +openthread_external_platform = + "${chip_root}/third_party/openthread/platforms/efr32:libopenthread-efr32" diff --git a/silabs_examples/template/efr32/include/AppTask.h b/silabs_examples/template/efr32/include/AppTask.h index 79c28fe51e6d50..6f839f447ae031 100644 --- a/silabs_examples/template/efr32/include/AppTask.h +++ b/silabs_examples/template/efr32/include/AppTask.h @@ -21,13 +21,15 @@ #include #include - +#include "BaseApplication.h" #include "AppEvent.h" #include "FreeRTOS.h" #include "sl_simple_button_instances.h" #include "timers.h" // provides FreeRTOS timer support +#include #include +#include #include // Application-defined error codes in the CHIP_ERROR space. @@ -38,52 +40,43 @@ #define APP_ERROR_START_TIMER_FAILED CHIP_APPLICATION_ERROR(0x05) #define APP_ERROR_STOP_TIMER_FAILED CHIP_APPLICATION_ERROR(0x06) -class AppTask +class AppTask : public BaseApplication { + public: + AppTask() = default; + static AppTask & GetAppTask() { return sAppTask; } CHIP_ERROR StartAppTask(); + static void AppTaskMain(void * pvParameter); - void PostEvent(const AppEvent * event); + void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) override; + + static void OnIdentifyStart(Identify * identify); + static void OnIdentifyStop(Identify * identify); - void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction); private: friend AppTask & GetAppTask(void); CHIP_ERROR Init(); - - void CancelTimer(void); - - void DispatchEvent(AppEvent * event); - - static void FunctionTimerEventHandler(AppEvent * aEvent); - static void FunctionHandler(AppEvent * aEvent); - static void TimerEventHandler(TimerHandle_t xTimer); - - static void UpdateClusterState(intptr_t context); - - void StartTimer(uint32_t aTimeoutMs); - - enum Function_t - { - kFunction_NoneSelected = 0, - kFunction_SoftwareUpdate = 0, - kFunction_StartBleAdv = 1, - kFunction_FactoryReset = 2, - - kFunction_Invalid - } Function; - - Function_t mFunction; - bool mFunctionTimerActive; - bool mSyncClusterToButtonAction; - static AppTask sAppTask; + /** + * @brief PB0 Button event processing function + * Press and hold will trigger a factory reset timer start + * Press and release will restart BLEAdvertising if not commisionned + * + * @param aEvent button event being processed + */ + static void ButtonHandler(AppEvent * aEvent); + + /** + * @brief PB1 Button event processing function + * Function triggers a switch action sent to the CHIP task + * + * @param aEvent button event being processed + */ + static void SwitchActionEventHandler(AppEvent * aEvent); + }; - -inline AppTask & GetAppTask(void) -{ - return AppTask::sAppTask; -} diff --git a/silabs_examples/template/efr32/src/AppTask.cpp b/silabs_examples/template/efr32/src/AppTask.cpp index 74f2c429e6ddb1..ce33a1adee9116 100644 --- a/silabs_examples/template/efr32/src/AppTask.cpp +++ b/silabs_examples/template/efr32/src/AppTask.cpp @@ -21,10 +21,7 @@ #include "AppConfig.h" #include "AppEvent.h" #include "LEDWidget.h" -#ifdef DISPLAY_ENABLED -#include "lcd.h" -#include "qrcodegen.h" -#endif // DISPLAY_ENABLED + #include "sl_simple_led_instances.h" #include #include @@ -48,16 +45,6 @@ #include #include -#if CHIP_ENABLE_OPENTHREAD -#include -#include -#include -#endif -#ifdef SL_WIFI -#include "wfx_host_events.h" -#include -#include -#endif /* SL_WIFI */ #define FACTORY_RESET_TRIGGER_TIMEOUT 3000 #define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 @@ -75,49 +62,21 @@ using namespace chip; using namespace ::chip::DeviceLayer; namespace { -TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. - -TaskHandle_t sAppTaskHandle; -QueueHandle_t sAppEventQueue; - -LEDWidget sStatusLED; -LEDWidget sLightLED; - -#ifdef SL_WIFI -bool sIsWiFiProvisioned = false; -bool sIsWiFiEnabled = false; -bool sIsWiFiAttached = false; - -app::Clusters::NetworkCommissioning::Instance - sWiFiNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::SlWiFiDriver::GetInstance())); -#endif /* SL_WIFI */ - -#if CHIP_ENABLE_OPENTHREAD -bool sIsThreadProvisioned = false; -bool sIsThreadEnabled = false; -#endif /* CHIP_ENABLE_OPENTHREAD */ -bool sHaveBLEConnections = false; +#ifdef EMBER_AF_PLUGIN_IDENTIFY_SERVER EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; - -uint8_t sAppEventQueueBuffer[APP_EVENT_QUEUE_SIZE * sizeof(AppEvent)]; -StaticQueue_t sAppEventQueueStruct; - -StackType_t appStack[APP_TASK_STACK_SIZE / sizeof(StackType_t)]; -StaticTask_t appTaskStruct; - - -/********************************************************** - * Identify Callbacks - *********************************************************/ +#endif // EMBER_AF_PLUGIN_IDENTIFY_SERVER namespace { +#ifdef EMBER_AF_PLUGIN_IDENTIFY_SERVER void OnTriggerIdentifyEffectCompleted(chip::System::Layer * systemLayer, void * appState) { sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; } +#endif // EMBER_AF_PLUGIN_IDENTIFY_SERVER } // namespace +#ifdef EMBER_AF_PLUGIN_IDENTIFY_SERVER void OnTriggerIdentifyEffect(Identify * identify) { sIdentifyEffect = identify->mCurrentEffectIdentifier; @@ -150,7 +109,9 @@ void OnTriggerIdentifyEffect(Identify * identify) ChipLogProgress(Zcl, "No identifier effect"); } } +#endif // EMBER_AF_PLUGIN_IDENTIFY_SERVER +#ifdef EMBER_AF_PLUGIN_IDENTIFY_SERVER Identify gIdentify = { chip::EndpointId{ 1 }, [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStart"); }, @@ -158,7 +119,7 @@ Identify gIdentify = { EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED, OnTriggerIdentifyEffect, }; - +#endif /********************************************************** * OffWithEffect Callbacks *********************************************************/ @@ -168,7 +129,7 @@ void OnTriggerOffWithEffect(OnOffEffect * effect) chip::app::Clusters::OnOff::OnOffEffectIdentifier effectId = effect->mEffectIdentifier; uint8_t effectVariant = effect->mEffectVariant; - // Uses print outs until we can support the effects + // Uses printouts until we can support the effects if (effectId == EMBER_ZCL_ON_OFF_EFFECT_IDENTIFIER_DELAYED_ALL_OFF) { if (effectVariant == EMBER_ZCL_ON_OFF_DELAYED_ALL_OFF_EFFECT_VARIANT_FADE_TO_OFF_IN_0P8_SECONDS) @@ -208,95 +169,34 @@ OnOffEffect gEffect = { } // namespace using namespace chip::TLV; -using namespace ::chip::Credentials; using namespace ::chip::DeviceLayer; AppTask AppTask::sAppTask; -CHIP_ERROR AppTask::StartAppTask() -{ - sAppEventQueue = xQueueCreateStatic(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent), sAppEventQueueBuffer, &sAppEventQueueStruct); - if (sAppEventQueue == NULL) - { - EFR32_LOG("Failed to allocate app event queue"); - appError(APP_ERROR_EVENT_QUEUE_FAILED); - } - - // Start App task. - sAppTaskHandle = xTaskCreateStatic(AppTaskMain, APP_TASK_NAME, ArraySize(appStack), NULL, 1, appStack, &appTaskStruct); - return (sAppTaskHandle == nullptr) ? APP_ERROR_CREATE_TASK_FAILED : CHIP_NO_ERROR; -} CHIP_ERROR AppTask::Init() { CHIP_ERROR err = CHIP_NO_ERROR; -#ifdef SL_WIFI - /* - * Wait for the WiFi to be initialized - */ - EFR32_LOG("APP: Wait WiFi Init"); - while (!wfx_hw_ready()) - { - vTaskDelay(10); - } - EFR32_LOG("APP: Done WiFi Init"); - /* We will init server when we get IP */ - - sWiFiNetworkCommissioningInstance.Init(); -#endif - - chip::DeviceLayer::PlatformMgr().LockChipStack(); - // Initialize device attestation config - SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); - chip::DeviceLayer::PlatformMgr().UnlockChipStack(); - - // Create FreeRTOS sw timer for Function Selection. - sFunctionTimer = xTimerCreate("FnTmr", // Just a text name, not used by the RTOS kernel - 1, // == default timer period (mS) - false, // no timer reload (==one-shot) - (void *) this, // init timer id = app task obj context - TimerEventHandler // timer callback handler - ); - if (sFunctionTimer == NULL) - { - EFR32_LOG("funct timer create failed"); - appError(APP_ERROR_CREATE_TIMER_FAILED); - } - - EFR32_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); - - // Initialize LEDs - LEDWidget::InitGpio(); - sStatusLED.Init(SYSTEM_STATE_LED); - sLightLED.Init(LIGHT_LED); - - ConfigurationMgr().LogDeviceConfig(); - -// Print setup info on LCD if available -#ifdef DISPLAY_ENABLED - // Create buffer for QR code that can fit max size and null terminator. - char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1]; - chip::MutableCharSpan QRCode(qrCodeBuffer); - - if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR) - { - LCDWriteQRCode((uint8_t *) QRCode.data()); - } - else + err = BaseApplication::Init(&gIdentify); + if (err != CHIP_NO_ERROR) { - EFR32_LOG("Getting QR code failed!"); + EFR32_LOG("BaseApplication::Init() failed"); + appError(err); } -#else - PrintOnboardingCodes(chip::RendezvousInformationFlag(chip::RendezvousInformationFlag::kBLE)); -#endif return err; } +CHIP_ERROR AppTask::StartAppTask() +{ + return BaseApplication::StartAppTask(AppTaskMain); +} + void AppTask::AppTaskMain(void * pvParameter) { AppEvent event; + QueueHandle_t sAppEventQueue = *(static_cast(pvParameter)); CHIP_ERROR err = sAppTask.Init(); if (err != CHIP_NO_ERROR) @@ -315,76 +215,22 @@ void AppTask::AppTaskMain(void * pvParameter) sAppTask.DispatchEvent(&event); eventReceived = xQueueReceive(sAppEventQueue, &event, 0); } - - // Collect connectivity and configuration state from the CHIP stack. Because - // the CHIP event loop is being run in a separate task, the stack must be - // locked while these values are queried. However we use a non-blocking - // lock request (TryLockCHIPStack()) to avoid blocking other UI activities - // when the CHIP task is busy (e.g. with a long crypto operation). - if (PlatformMgr().TryLockChipStack()) - { -#ifdef SL_WIFI - sIsWiFiProvisioned = ConnectivityMgr().IsWiFiStationProvisioned(); - sIsWiFiEnabled = ConnectivityMgr().IsWiFiStationEnabled(); - sIsWiFiAttached = ConnectivityMgr().IsWiFiStationConnected(); -#endif /* SL_WIFI */ -#if CHIP_ENABLE_OPENTHREAD - sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); - sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); -#endif /* CHIP_ENABLE_OPENTHREAD */ - sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); - PlatformMgr().UnlockChipStack(); - } - - // Update the status LED if factory reset has not been initiated. - // - // If system has "full connectivity", keep the LED On constantly. - // - // If thread and service provisioned, but not attached to the thread network - // yet OR no connectivity to the service OR subscriptions are not fully - // established THEN blink the LED Off for a short period of time. - // - // If the system has ble connection(s) uptill the stage above, THEN blink - // the LEDs at an even rate of 100ms. - // - // Otherwise, blink the LED ON for a very short time. - if (sAppTask.mFunction != kFunction_FactoryReset) - { - if (gIdentify.mActive) - { - sStatusLED.Blink(250, 250); - } - if (sIdentifyEffect != EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT) - { - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK) - { - sStatusLED.Blink(50, 50); - } - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE) - { - sStatusLED.Blink(1000, 1000); - } - if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY) - { - sStatusLED.Blink(300, 700); - } - } -#if CHIP_ENABLE_OPENTHREAD - if (sIsThreadProvisioned && sIsThreadEnabled) -#else - if (sIsWiFiProvisioned && sIsWiFiEnabled && !sIsWiFiAttached) -#endif - { - sStatusLED.Blink(950, 50); - } - else if (sHaveBLEConnections) { sStatusLED.Blink(100, 100); } - else { sStatusLED.Blink(50, 950); } - } - - sStatusLED.Animate(); - sLightLED.Animate(); } } +void AppTask::OnIdentifyStart(Identify * identify) +{ + ChipLogProgress(Zcl, "onIdentifyStart"); +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + sAppTask.StartStatusLEDTimer(); +#endif +} +void AppTask::OnIdentifyStop(Identify * identify) +{ + ChipLogProgress(Zcl, "onIdentifyStop"); +#if CHIP_DEVICE_CONFIG_ENABLE_SED == 1 + sAppTask.StopStatusLEDTimer(); +#endif +} void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction) { @@ -399,177 +245,7 @@ void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAc if (buttonHandle == APP_FUNCTION_BUTTON) { - button_event.Handler = FunctionHandler; + button_event.Handler = BaseApplication::ButtonHandler; sAppTask.PostEvent(&button_event); } } - -void AppTask::TimerEventHandler(TimerHandle_t xTimer) -{ - AppEvent event; - event.Type = AppEvent::kEventType_Timer; - event.TimerEvent.Context = (void *) xTimer; - event.Handler = FunctionTimerEventHandler; - sAppTask.PostEvent(&event); -} - -void AppTask::FunctionTimerEventHandler(AppEvent * aEvent) -{ - if (aEvent->Type != AppEvent::kEventType_Timer) - { - return; - } - - // If we reached here, the button was held past FACTORY_RESET_TRIGGER_TIMEOUT, - // initiate factory reset - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv) - { - EFR32_LOG("Factory Reset Triggered. Release button within %ums to cancel.", FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); - - // Start timer for FACTORY_RESET_CANCEL_WINDOW_TIMEOUT to allow user to - // cancel, if required. - sAppTask.StartTimer(FACTORY_RESET_CANCEL_WINDOW_TIMEOUT); - - sAppTask.mFunction = kFunction_FactoryReset; - - // Turn off all LEDs before starting blink to make sure blink is - // co-ordinated. - sStatusLED.Set(false); - sLightLED.Set(false); - - sStatusLED.Blink(500); - sLightLED.Blink(500); - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - // Actually trigger Factory Reset - sAppTask.mFunction = kFunction_NoneSelected; - chip::Server::GetInstance().ScheduleFactoryReset(); - } -} - -void AppTask::FunctionHandler(AppEvent * aEvent) -{ - // To trigger software update: press the APP_FUNCTION_BUTTON button briefly (< - // FACTORY_RESET_TRIGGER_TIMEOUT) To initiate factory reset: press the - // APP_FUNCTION_BUTTON for FACTORY_RESET_TRIGGER_TIMEOUT + - // FACTORY_RESET_CANCEL_WINDOW_TIMEOUT All LEDs start blinking after - // FACTORY_RESET_TRIGGER_TIMEOUT to signal factory reset has been initiated. - // To cancel factory reset: release the APP_FUNCTION_BUTTON once all LEDs - // start blinking within the FACTORY_RESET_CANCEL_WINDOW_TIMEOUT - if (aEvent->ButtonEvent.Action == SL_SIMPLE_BUTTON_PRESSED) - { - if (!sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_NoneSelected) - { - sAppTask.StartTimer(FACTORY_RESET_TRIGGER_TIMEOUT); - sAppTask.mFunction = kFunction_StartBleAdv; - } - } - else - { - // If the button was released before factory reset got initiated, start BLE advertissement in fast mode - if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_StartBleAdv) - { - sAppTask.CancelTimer(); - sAppTask.mFunction = kFunction_NoneSelected; - -#ifdef SL_WIFI - if (!ConnectivityMgr().IsWiFiStationProvisioned()) -#else - if (!ConnectivityMgr().IsThreadProvisioned()) -#endif /* !SL_WIFI */ - { - // Enable BLE advertisements - ConnectivityMgr().SetBLEAdvertisingEnabled(true); - ConnectivityMgr().SetBLEAdvertisingMode(ConnectivityMgr().kFastAdvertising); - } - else { EFR32_LOG("Network is already provisioned, Ble advertissement not enabled"); } - } - else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) - { - - sAppTask.CancelTimer(); - - // Change the function to none selected since factory reset has been - // canceled. - sAppTask.mFunction = kFunction_NoneSelected; - - EFR32_LOG("Factory Reset has been Canceled"); - } - } -} - -void AppTask::CancelTimer() -{ - if (xTimerStop(sFunctionTimer, 0) == pdFAIL) - { - EFR32_LOG("app timer stop() failed"); - appError(APP_ERROR_STOP_TIMER_FAILED); - } - - mFunctionTimerActive = false; -} - -void AppTask::StartTimer(uint32_t aTimeoutInMs) -{ - if (xTimerIsTimerActive(sFunctionTimer)) - { - EFR32_LOG("app timer already started!"); - CancelTimer(); - } - - // timer is not active, change its period to required value (== restart). - // FreeRTOS- Block for a maximum of 100 ticks if the change period command - // cannot immediately be sent to the timer command queue. - if (xTimerChangePeriod(sFunctionTimer, aTimeoutInMs / portTICK_PERIOD_MS, 100) != pdPASS) - { - EFR32_LOG("app timer start() failed"); - appError(APP_ERROR_START_TIMER_FAILED); - } - - mFunctionTimerActive = true; -} - -void AppTask::PostEvent(const AppEvent * aEvent) -{ - if (sAppEventQueue != NULL) - { - BaseType_t status; - if (xPortIsInsideInterrupt()) - { - BaseType_t higherPrioTaskWoken = pdFALSE; - status = xQueueSendFromISR(sAppEventQueue, aEvent, &higherPrioTaskWoken); - -#ifdef portYIELD_FROM_ISR - portYIELD_FROM_ISR(higherPrioTaskWoken); -#elif portEND_SWITCHING_ISR // portYIELD_FROM_ISR or portEND_SWITCHING_ISR - portEND_SWITCHING_ISR(higherPrioTaskWoken); -#else // portYIELD_FROM_ISR or portEND_SWITCHING_ISR -#error "Must have portYIELD_FROM_ISR or portEND_SWITCHING_ISR" -#endif // portYIELD_FROM_ISR or portEND_SWITCHING_ISR - } - else - { - status = xQueueSend(sAppEventQueue, aEvent, 1); - } - - if (!status) - EFR32_LOG("Failed to post event to app task event queue"); - } - else - { - EFR32_LOG("Event Queue is NULL should never happen"); - } -} - -void AppTask::DispatchEvent(AppEvent * aEvent) -{ - if (aEvent->Handler) - { - aEvent->Handler(aEvent); - } - else - { - EFR32_LOG("Event received with no handler. Dropping event."); - } -} diff --git a/silabs_examples/template/efr32/src/main.cpp b/silabs_examples/template/efr32/src/main.cpp index 6c169602c5ba16..046fb626b4e864 100644 --- a/silabs_examples/template/efr32/src/main.cpp +++ b/silabs_examples/template/efr32/src/main.cpp @@ -45,7 +45,7 @@ int main(void) appError(CHIP_ERROR_INTERNAL); EFR32_LOG("Starting App Task"); - if (GetAppTask().StartAppTask() != CHIP_NO_ERROR) + if (AppTask::GetAppTask().StartAppTask() != CHIP_NO_ERROR) appError(CHIP_ERROR_INTERNAL); EFR32_LOG("Starting FreeRTOS scheduler"); @@ -59,5 +59,5 @@ int main(void) void sl_button_on_change(const sl_button_t * handle) { - GetAppTask().ButtonEventHandler(handle, sl_button_get_state(handle)); + AppTask::GetAppTask().ButtonEventHandler(handle, sl_button_get_state(handle)); }