| /** |
| * |
| * Copyright (c) 2020 Project CHIP Authors |
| * |
| * 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. |
| */ |
| |
| #pragma once |
| |
| #include <app-common/zap-generated/cluster-objects.h> |
| #include <app/CommandHandler.h> |
| #include <app/ConcreteCommandPath.h> |
| #include <app/clusters/scenes-server/SceneTable.h> |
| #include <app/util/af-types.h> |
| #include <app/util/attribute-storage.h> |
| #include <app/util/basic-types.h> |
| #include <app/util/config.h> |
| #include <platform/CHIPDeviceConfig.h> |
| #include <protocols/interaction_model/StatusCode.h> |
| |
| /********************************************************** |
| * Defines and Macros |
| *********************************************************/ |
| |
| static constexpr chip::System::Clock::Milliseconds32 TRANSITION_UPDATE_TIME_MS = chip::System::Clock::Milliseconds32(100); |
| static constexpr uint16_t TRANSITION_STEPS_PER_1S = 10; |
| |
| static constexpr uint16_t MIN_CIE_XY_VALUE = 0; |
| static constexpr uint16_t MAX_CIE_XY_VALUE = 0xfeff; // this value comes directly from the ZCL specification table 5.3 |
| |
| static constexpr uint16_t MIN_TEMPERATURE_VALUE = 0; |
| static constexpr uint16_t MAX_TEMPERATURE_VALUE = 0xfeff; |
| |
| static constexpr uint8_t MIN_HUE_VALUE = 0; |
| static constexpr uint8_t MAX_HUE_VALUE = 254; |
| |
| static constexpr uint8_t MIN_SATURATION_VALUE = 0; |
| static constexpr uint8_t MAX_SATURATION_VALUE = 254; |
| |
| static constexpr uint8_t HALF_MAX_UINT8T = 127; |
| static constexpr uint16_t HALF_MAX_UINT16T = 0x7FFF; |
| |
| static constexpr uint16_t MAX_ENHANCED_HUE_VALUE = 0xFFFF; |
| |
| static constexpr uint8_t MIN_CURRENT_LEVEL = 0x01; |
| static constexpr uint8_t MAX_CURRENT_LEVEL = 0xFE; |
| |
| static constexpr uint8_t REPORT_FAILED = 0xFF; |
| |
| /** |
| * @brief color-control-server class |
| */ |
| class ColorControlServer |
| { |
| public: |
| /********************************************************** |
| * Enums |
| *********************************************************/ |
| using HueStepMode = chip::app::Clusters::ColorControl::HueStepMode; |
| using HueMoveMode = chip::app::Clusters::ColorControl::HueMoveMode; |
| using HueDirection = chip::app::Clusters::ColorControl::HueDirection; |
| using Feature = chip::app::Clusters::ColorControl::Feature; |
| |
| enum EnhancedColorMode : uint8_t |
| { |
| kCurrentHueAndCurrentSaturation = 0, |
| kCurrentXAndCurrentY = 1, |
| kColorTemperature = 2, |
| kEnhancedCurrentHueAndCurrentSaturation = 3, |
| }; |
| |
| enum Conversion |
| { |
| HSV_TO_HSV = 0x00, |
| HSV_TO_CIE_XY = 0x01, |
| HSV_TO_TEMPERATURE = 0x02, |
| CIE_XY_TO_HSV = 0x10, |
| CIE_XY_TO_CIE_XY = 0x11, |
| CIE_XY_TO_TEMPERATURE = 0x12, |
| TEMPERATURE_TO_HSV = 0x20, |
| TEMPERATURE_TO_CIE_XY = 0x21, |
| TEMPERATURE_TO_TEMPERATURE = 0x22 |
| }; |
| |
| /********************************************************** |
| * Structures |
| *********************************************************/ |
| |
| struct ColorHueTransitionState |
| { |
| uint8_t initialHue; |
| uint8_t currentHue; |
| uint8_t finalHue; |
| uint16_t stepsRemaining; |
| uint16_t stepsTotal; |
| // The amount of time remaining until the transition completes. Measured in tenths of a second. |
| // When the transition repeats indefinitely, this will hold the maximum value possible. |
| uint16_t timeRemaining; |
| uint16_t initialEnhancedHue; |
| uint16_t currentEnhancedHue; |
| uint16_t finalEnhancedHue; |
| chip::EndpointId endpoint; |
| bool up; |
| bool repeat; |
| bool isEnhancedHue; |
| }; |
| |
| struct Color16uTransitionState |
| { |
| uint16_t initialValue; |
| uint16_t currentValue; |
| uint16_t finalValue; |
| uint16_t stepsRemaining; |
| uint16_t stepsTotal; |
| // The amount of time remaining until the transition completes. Measured in tenths of a second. |
| uint16_t timeRemaining; |
| uint16_t lowLimit; |
| uint16_t highLimit; |
| chip::EndpointId endpoint; |
| }; |
| |
| /********************************************************** |
| * Functions Definitions |
| *********************************************************/ |
| static ColorControlServer & Instance(); |
| |
| chip::scenes::SceneHandler * GetSceneHandler(); |
| |
| bool HasFeature(chip::EndpointId endpoint, Feature feature); |
| chip::Protocols::InteractionModel::Status stopAllColorTransitions(chip::EndpointId endpoint); |
| bool stopMoveStepCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| uint8_t optionsMask, uint8_t optionsOverride); |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_HSV |
| bool moveHueCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| HueMoveMode moveMode, uint16_t rate, uint8_t optionsMask, uint8_t optionsOverride, bool isEnhanced); |
| bool moveToHueCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, uint16_t hue, |
| HueDirection moveDirection, uint16_t transitionTime, uint8_t optionsMask, uint8_t optionsOverride, |
| bool isEnhanced); |
| bool moveToHueAndSaturationCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| uint16_t hue, uint8_t saturation, uint16_t transitionTime, uint8_t optionsMask, |
| uint8_t optionsOverride, bool isEnhanced); |
| bool stepHueCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| HueStepMode stepMode, uint16_t stepSize, uint16_t transitionTime, uint8_t optionsMask, |
| uint8_t optionsOverride, bool isEnhanced); |
| bool moveSaturationCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::MoveSaturation::DecodableType & commandData); |
| bool moveToSaturationCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::MoveToSaturation::DecodableType & commandData); |
| bool stepSaturationCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::StepSaturation::DecodableType & commandData); |
| bool colorLoopCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::ColorLoopSet::DecodableType & commandData); |
| void updateHueSatCommand(chip::EndpointId endpoint); |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_HSV |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_XY |
| bool moveToColorCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::MoveToColor::DecodableType & commandData); |
| bool moveColorCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::MoveColor::DecodableType & commandData); |
| bool stepColorCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::StepColor::DecodableType & commandData); |
| void updateXYCommand(chip::EndpointId endpoint); |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_XY |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |
| bool moveColorTempCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::MoveColorTemperature::DecodableType & commandData); |
| bool |
| moveToColorTempCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::MoveToColorTemperature::DecodableType & commandData); |
| bool stepColorTempCommand(chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, |
| const chip::app::Clusters::ColorControl::Commands::StepColorTemperature::DecodableType & commandData); |
| void levelControlColorTempChangeCommand(chip::EndpointId endpoint); |
| void startUpColorTempCommand(chip::EndpointId endpoint); |
| void updateTempCommand(chip::EndpointId endpoint); |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |
| |
| void cancelEndpointTimerCallback(chip::EndpointId endpoint); |
| |
| private: |
| /********************************************************** |
| * Functions Definitions |
| *********************************************************/ |
| |
| ColorControlServer() {} |
| bool shouldExecuteIfOff(chip::EndpointId endpoint, uint8_t optionMask, uint8_t optionOverride); |
| void handleModeSwitch(chip::EndpointId endpoint, uint8_t newColorMode); |
| uint16_t computeTransitionTimeFromStateAndRate(Color16uTransitionState * p, uint16_t rate); |
| EmberEventControl * getEventControl(chip::EndpointId endpoint); |
| void computePwmFromHsv(chip::EndpointId endpoint); |
| void computePwmFromTemp(chip::EndpointId endpoint); |
| void computePwmFromXy(chip::EndpointId endpoint); |
| bool computeNewColor16uValue(Color16uTransitionState * p); |
| |
| // Matter timer scheduling glue logic |
| static void timerCallback(chip::System::Layer *, void * callbackContext); |
| void scheduleTimerCallbackMs(EmberEventControl * control, uint32_t delayMs); |
| void cancelEndpointTimerCallback(EmberEventControl * control); |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_HSV |
| chip::Protocols::InteractionModel::Status moveToSaturation(uint8_t saturation, uint16_t transitionTime, |
| chip::EndpointId endpoint); |
| chip::Protocols::InteractionModel::Status moveToHueAndSaturation(uint16_t hue, uint8_t saturation, uint16_t transitionTime, |
| bool isEnhanced, chip::EndpointId endpoint); |
| ColorHueTransitionState * getColorHueTransitionState(chip::EndpointId endpoint); |
| Color16uTransitionState * getSaturationTransitionState(chip::EndpointId endpoint); |
| uint8_t getSaturation(chip::EndpointId endpoint); |
| uint8_t addHue(uint8_t hue1, uint8_t hue2); |
| uint8_t subtractHue(uint8_t hue1, uint8_t hue2); |
| uint8_t addSaturation(uint8_t saturation1, uint8_t saturation2); |
| uint8_t subtractSaturation(uint8_t saturation1, uint8_t saturation2); |
| uint16_t addEnhancedHue(uint16_t hue1, uint16_t hue2); |
| uint16_t subtractEnhancedHue(uint16_t hue1, uint16_t hue2); |
| void startColorLoop(chip::EndpointId endpoint, uint8_t startFromStartHue); |
| void initHueTransitionState(chip::EndpointId endpoint, ColorHueTransitionState * colorHueTransitionState, bool isEnhancedHue); |
| void initSaturationTransitionState(chip::EndpointId endpoint, Color16uTransitionState * colorSatTransitionState); |
| void SetHSVRemainingTime(chip::EndpointId endpoint); |
| bool computeNewHueValue(ColorHueTransitionState * p); |
| EmberEventControl * configureHSVEventControl(chip::EndpointId); |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_HSV |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_XY |
| chip::Protocols::InteractionModel::Status moveToColor(uint16_t colorX, uint16_t colorY, uint16_t transitionTime, |
| chip::EndpointId endpoint); |
| Color16uTransitionState * getXTransitionState(chip::EndpointId endpoint); |
| Color16uTransitionState * getYTransitionState(chip::EndpointId endpoint); |
| uint16_t findNewColorValueFromStep(uint16_t oldValue, int16_t step); |
| EmberEventControl * configureXYEventControl(chip::EndpointId); |
| #endif // #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_XY |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |
| Color16uTransitionState * getTempTransitionState(chip::EndpointId endpoint); |
| chip::Protocols::InteractionModel::Status moveToColorTemp(chip::EndpointId aEndpoint, uint16_t colorTemperature, |
| uint16_t transitionTime); |
| uint16_t getTemperatureCoupleToLevelMin(chip::EndpointId endpoint); |
| EmberEventControl * configureTempEventControl(chip::EndpointId); |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |
| |
| /********************************************************** |
| * Attributes Declaration |
| *********************************************************/ |
| static ColorControlServer instance; |
| static constexpr size_t kColorControlClusterServerMaxEndpointCount = |
| MATTER_DM_COLOR_CONTROL_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; |
| static_assert(kColorControlClusterServerMaxEndpointCount <= kEmberInvalidEndpointIndex, "ColorControl endpoint count error"); |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_HSV |
| ColorHueTransitionState colorHueTransitionStates[kColorControlClusterServerMaxEndpointCount]; |
| Color16uTransitionState colorSatTransitionStates[kColorControlClusterServerMaxEndpointCount]; |
| #endif |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_XY |
| Color16uTransitionState colorXtransitionStates[kColorControlClusterServerMaxEndpointCount]; |
| Color16uTransitionState colorYtransitionStates[kColorControlClusterServerMaxEndpointCount]; |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_XY |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |
| Color16uTransitionState colorTempTransitionStates[kColorControlClusterServerMaxEndpointCount]; |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |
| |
| EmberEventControl eventControls[kColorControlClusterServerMaxEndpointCount]; |
| |
| friend class DefaultColorControlSceneHandler; |
| }; |
| |
| /********************************************************** |
| * Callbacks |
| *********************************************************/ |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |
| void emberAfPluginColorControlServerTempTransitionEventHandler(chip::EndpointId endpoint); |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_XY |
| void emberAfPluginColorControlServerXyTransitionEventHandler(chip::EndpointId endpoint); |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_XY |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_HSV |
| void emberAfPluginColorControlServerHueSatTransitionEventHandler(chip::EndpointId endpoint); |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_HSV |
| |
| #ifdef MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |
| void emberAfPluginLevelControlCoupledColorTempChangeCallback(chip::EndpointId endpoint); |
| #endif // MATTER_DM_PLUGIN_COLOR_CONTROL_SERVER_TEMP |