blob: f250de450def21d8cd080acc10a52dbabaebef53 [file] [log] [blame]
/*
*
* 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 <app/server/Server.h>
#include "ColorFormat.h"
#include "PWMManager.h"
#include <app-common/zap-generated/attributes/Accessors.h>
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<uint8_t> 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<int32_t>(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<Fixture_Action>(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;
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
{
sfixture_on = false;
PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Red, false);
PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Green, false);
PwmManager::getInstance().setPwm(PwmManager::EAppPwm_Blue, false);
}
}
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<XyColor_t *>(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<HsvColor_t *>(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<CtColor_t *>(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));
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 */