/* * * Copyright (c) 2022-2024 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 "AppTask.h" #include #include "ColorFormat.h" #include "LEDManager.h" #include "PWMManager.h" #include LOG_MODULE_DECLARE(app, CONFIG_CHIP_APP_LOG_LEVEL); namespace { bool sfixture_on; uint8_t sBrightness; AppTask::Fixture_Action sColorAction = AppTask::INVALID_ACTION; XyColor_t sXY; HsvColor_t sHSV; CtColor_t sCT; RgbColor_t sLedRgb; } // namespace AppTask AppTask::sAppTask; bool AppTask::IsTurnedOn() const { return sfixture_on; } #ifdef CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET void AppTask::PowerOnFactoryReset(void) { LOG_INF("Lighting App Power On Factory Reset"); AppEvent event; event.Type = AppEvent::kEventType_DeviceAction; event.Handler = PowerOnFactoryResetEventHandler; GetAppTask().PostEvent(&event); } #endif /* CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET */ CHIP_ERROR AppTask::Init(void) { SetExampleButtonCallbacks(LightingActionEventHandler); InitCommonParts(); Protocols::InteractionModel::Status status; app::DataModel::Nullable brightness; // Read brightness value status = Clusters::LevelControl::Attributes::CurrentLevel::Get(kExampleEndpointId, brightness); if (status == Protocols::InteractionModel::Status::Success && !brightness.IsNull()) { sBrightness = brightness.Value(); } memset(&sLedRgb, sBrightness, sizeof(RgbColor_t)); bool storedValue; // Read storedValue on/off value status = Clusters::OnOff::Attributes::OnOff::Get(1, &storedValue); if (status == Protocols::InteractionModel::Status::Success) { // Set actual state to stored before reboot SetInitiateAction(storedValue ? ON_ACTION : OFF_ACTION, static_cast(AppEvent::kEventType_DeviceAction), nullptr); } return CHIP_NO_ERROR; } void AppTask::LightingActionEventHandler(AppEvent * aEvent) { Fixture_Action action = INVALID_ACTION; int32_t actor = 0; if (aEvent->Type == AppEvent::kEventType_DeviceAction) { action = static_cast(aEvent->DeviceEvent.Action); actor = aEvent->DeviceEvent.Actor; } else if (aEvent->Type == AppEvent::kEventType_Button) { sfixture_on = !sfixture_on; sAppTask.UpdateClusterState(); } } void AppTask::UpdateClusterState(void) { Protocols::InteractionModel::Status status; bool isTurnedOn = sfixture_on; uint8_t setLevel = sBrightness; // write the new on/off value status = Clusters::OnOff::Attributes::OnOff::Set(kExampleEndpointId, isTurnedOn); if (status != Protocols::InteractionModel::Status::Success) { LOG_ERR("Update OnOff fail: %x", to_underlying(status)); } status = Clusters::LevelControl::Attributes::CurrentLevel::Set(kExampleEndpointId, setLevel); if (status != Protocols::InteractionModel::Status::Success) { LOG_ERR("Update CurrentLevel fail: %x", to_underlying(status)); } } void AppTask::SetInitiateAction(Fixture_Action aAction, int32_t aActor, uint8_t * value) { bool setRgbAction = false; if (aAction == ON_ACTION || aAction == OFF_ACTION) { if (aAction == ON_ACTION) { sfixture_on = true; #ifdef CONFIG_PWM PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, (((uint32_t) sLedRgb.r * 1000) / UINT8_MAX)); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, (((uint32_t) sLedRgb.g * 1000) / UINT8_MAX)); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, (((uint32_t) sLedRgb.b * 1000) / UINT8_MAX)); #else LedManager::getInstance().setLed(LedManager::EAppLed_App0, true); #endif } else { sfixture_on = false; #ifdef CONFIG_PWM PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, false); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, false); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, false); #else LedManager::getInstance().setLed(LedManager::EAppLed_App0, false); #endif } } else if (aAction == LEVEL_ACTION) { // Save a new brightness for ColorControl sBrightness = *value; if (sColorAction == COLOR_ACTION_XY) { sLedRgb = XYToRgb(sBrightness, sXY.x, sXY.y); } else if (sColorAction == COLOR_ACTION_HSV) { sHSV.v = sBrightness; sLedRgb = HsvToRgb(sHSV); } else { memset(&sLedRgb, sBrightness, sizeof(RgbColor_t)); } ChipLogProgress(Zcl, "New brightness: %u | R: %u, G: %u, B: %u", sBrightness, sLedRgb.r, sLedRgb.g, sLedRgb.b); setRgbAction = true; } else if (aAction == COLOR_ACTION_XY) { sXY = *reinterpret_cast(value); sLedRgb = XYToRgb(sBrightness, sXY.x, sXY.y); ChipLogProgress(Zcl, "XY to RGB: X: %u, Y: %u, Level: %u | R: %u, G: %u, B: %u", sXY.x, sXY.y, sBrightness, sLedRgb.r, sLedRgb.g, sLedRgb.b); setRgbAction = true; sColorAction = COLOR_ACTION_XY; } else if (aAction == COLOR_ACTION_HSV) { sHSV = *reinterpret_cast(value); sHSV.v = sBrightness; sLedRgb = HsvToRgb(sHSV); ChipLogProgress(Zcl, "HSV to RGB: H: %u, S: %u, V: %u | R: %u, G: %u, B: %u", sHSV.h, sHSV.s, sHSV.v, sLedRgb.r, sLedRgb.g, sLedRgb.b); setRgbAction = true; sColorAction = COLOR_ACTION_HSV; } else if (aAction == COLOR_ACTION_CT) { sCT = *reinterpret_cast(value); if (sCT.ctMireds) { sLedRgb = CTToRgb(sCT); ChipLogProgress(Zcl, "ColorTemp to RGB: CT: %u | R: %u, G: %u, B: %u", sCT.ctMireds, sLedRgb.r, sLedRgb.g, sLedRgb.b); setRgbAction = true; sColorAction = COLOR_ACTION_CT; } } if (setRgbAction) { PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, (((uint32_t) sLedRgb.r * 1000) / UINT8_MAX)); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, (((uint32_t) sLedRgb.g * 1000) / UINT8_MAX)); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, (((uint32_t) sLedRgb.b * 1000) / UINT8_MAX)); } } #ifdef CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET static constexpr uint32_t kPowerOnFactoryResetIndicationMax = 4; static constexpr uint32_t kPowerOnFactoryResetIndicationTimeMs = 1000; unsigned int AppTask::sPowerOnFactoryResetTimerCnt; k_timer AppTask::sPowerOnFactoryResetTimer; void AppTask::PowerOnFactoryResetEventHandler(AppEvent * aEvent) { LOG_INF("Lighting App Power On Factory Reset Handler"); sPowerOnFactoryResetTimerCnt = 1; PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, (bool) (sPowerOnFactoryResetTimerCnt % 2)); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, (bool) (sPowerOnFactoryResetTimerCnt % 2)); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, (bool) (sPowerOnFactoryResetTimerCnt % 2)); #if !CONFIG_PWM LedManager::getInstance().setLed(LedManager::EAppLed_App0, (bool) (sPowerOnFactoryResetTimerCnt % 2)); #endif k_timer_init(&sPowerOnFactoryResetTimer, PowerOnFactoryResetTimerEvent, nullptr); k_timer_start(&sPowerOnFactoryResetTimer, K_MSEC(kPowerOnFactoryResetIndicationTimeMs), K_MSEC(kPowerOnFactoryResetIndicationTimeMs)); } void AppTask::PowerOnFactoryResetTimerEvent(struct k_timer * timer) { sPowerOnFactoryResetTimerCnt++; LOG_INF("Lighting App Power On Factory Reset Handler %u", sPowerOnFactoryResetTimerCnt); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, (bool) (sPowerOnFactoryResetTimerCnt % 2)); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, (bool) (sPowerOnFactoryResetTimerCnt % 2)); PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, (bool) (sPowerOnFactoryResetTimerCnt % 2)); if (sPowerOnFactoryResetTimerCnt > kPowerOnFactoryResetIndicationMax) { k_timer_stop(timer); LOG_INF("schedule factory reset"); chip::Server::GetInstance().ScheduleFactoryReset(); } } #endif /* CONFIG_CHIP_ENABLE_POWER_ON_FACTORY_RESET */ void AppTask::LinkLeds(LedManager & ledManager) { #if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED ledManager.linkLed(LedManager::EAppLed_Status, 0); #endif #if !CONFIG_PWM ledManager.linkLed(LedManager::EAppLed_App0, 1); #endif /* !CONFIG_PWM */ }