Compare commits

...

2 Commits

Author SHA1 Message Date
Martin Böh dd198ef4c1 Fix enhanced hue colors 2022-04-05 18:29:25 +02:00
MartB fbe192ef8b EnhancedHue support for HSV + 3khz PWM 2022-04-04 20:50:06 +02:00
5 changed files with 110 additions and 37 deletions

View File

@ -33,7 +33,7 @@
/********************************************************************** /**********************************************************************
* TIMER CONSTANTS * TIMER CONSTANTS
*/ */
#define ZCL_LEVEL_CHANGE_INTERVAL 20 // Step 50 times a second, every 20ms #define ZCL_LEVEL_CHANGE_INTERVAL 20 // 50 steps a second, every 20ms
#define ZCL_COLOR_CHANGE_INTERVAL 20 // see above #define ZCL_COLOR_CHANGE_INTERVAL 20 // see above
#define ZCL_REMAINING_TIME_INTERVAL 100 // 1/10th of a second according to the zigbee spec #define ZCL_REMAINING_TIME_INTERVAL 100 // 1/10th of a second according to the zigbee spec

View File

@ -34,7 +34,7 @@
/********************************************************************** /**********************************************************************
* LOCAL CONSTANTS * LOCAL CONSTANTS
*/ */
#define PWM_FREQUENCY 1000 // 1KHz #define PWM_FREQUENCY 3000 // 3KHz
#define PWM_FULL_DUTYCYCLE 100 #define PWM_FULL_DUTYCYCLE 100
#define PMW_MAX_TICK (PWM_CLOCK_SOURCE / PWM_FREQUENCY) #define PMW_MAX_TICK (PWM_CLOCK_SOURCE / PWM_FREQUENCY)
@ -230,13 +230,13 @@ void hwLight_colorUpdate_colorTemperature(u16 colorTemperatureMireds, u8 level)
* *
* @return None * @return None
*/ */
void hsvToRGB(u8 hue, u8 saturation, u8 level, u8 *R, u8 *G, u8 *B) void hsvToRGB(u16 hue, u8 saturation, u8 level, u8 *R, u8 *G, u8 *B, bool enhanced)
{ {
u8 region; u8 region;
u8 remainder; u8 remainder;
u8 p, q, t; u8 p, q, t;
u16 rHue = (u16)hue * 360 / ZCL_COLOR_ATTR_HUE_MAX; u16 rHue = (u32)hue * 360 / (enhanced ? ZCL_COLOR_ATTR_ENHANCED_HUE_MAX : ZCL_COLOR_ATTR_HUE_MAX);
u8 rS = saturation; u8 rS = saturation;
u8 rV = level; u8 rV = level;
@ -309,18 +309,20 @@ void hsvToRGB(u8 hue, u8 saturation, u8 level, u8 *R, u8 *G, u8 *B)
* @param hue - hue attribute value * @param hue - hue attribute value
* saturation - saturation attribute value * saturation - saturation attribute value
* level - level attribute value * level - level attribute value
* bool - whether the enhanced calculation should be used or not
* *
* @return None * @return None
*/ */
void hwLight_colorUpdate_HSV2RGB(u8 hue, u8 saturation, u8 level) void hwLight_colorUpdate_HSV2RGB(u16 hue, u8 saturation, u8 level, bool enhanced)
{ {
u8 R = 0; u8 R = 0;
u8 G = 0; u8 G = 0;
u8 B = 0; u8 B = 0;
level = (level < 0x10) ? 0x10 : level; // No idea why this is here, lets see what happens with a more minimal value
level = (level < 0x01) ? 0x01 : level;
hsvToRGB(hue, saturation, level, &R, &G, &B); hsvToRGB(hue, saturation, level, &R, &G, &B, enhanced);
hwLight_colorUpdate_RGB(R, G, B); hwLight_colorUpdate_RGB(R, G, B);
} }

View File

@ -35,7 +35,7 @@ void hwLight_init(void);
void hwLight_onOffUpdate(u8 onOff); void hwLight_onOffUpdate(u8 onOff);
void hwLight_levelUpdate(u8 level); void hwLight_levelUpdate(u8 level);
void hwLight_colorUpdate_colorTemperature(u16 colorTemperatureMireds, u8 level); void hwLight_colorUpdate_colorTemperature(u16 colorTemperatureMireds, u8 level);
void hwLight_colorUpdate_HSV2RGB(u8 hue, u8 saturation, u8 level); void hwLight_colorUpdate_HSV2RGB(u16 hue, u8 saturation, u8 level, bool enhanced);
void hwLight_colorUpdate_RGB(u8 R, u8 G, u8 B); void hwLight_colorUpdate_RGB(u8 R, u8 G, u8 B);
void hwLight_colorUpdate_XY2RGB(u16 x, u16 y, u8 level); void hwLight_colorUpdate_XY2RGB(u16 x, u16 y, u8 level);

View File

@ -266,7 +266,7 @@ zcl_lightColorCtrlAttr_t g_zcl_colorCtrlAttrs =
.options = 0, .options = 0,
.enhancedColorMode = ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS, .enhancedColorMode = ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS,
.numOfPrimaries = 0xFF, // 0xFF is used if the primaries are unknown .numOfPrimaries = 0xFF, // 0xFF is used if the primaries are unknown
.colorCapabilities = ZCL_COLOR_CAPABILITIES_BIT_COLOR_TEMPERATURE | ZCL_COLOR_CAPABILITIES_BIT_X_Y_ATTRIBUTES | ZCL_COLOR_CAPABILITIES_BIT_HUE_SATURATION, .colorCapabilities = ZCL_COLOR_CAPABILITIES_BIT_HUE_SATURATION | ZCL_COLOR_CAPABILITIES_BIT_COLOR_LOOP | ZCL_COLOR_CAPABILITIES_BIT_ENHANCED_HUE | ZCL_COLOR_CAPABILITIES_BIT_COLOR_TEMPERATURE | ZCL_COLOR_CAPABILITIES_BIT_X_Y_ATTRIBUTES,
.currentHue = 0x00, .currentHue = 0x00,
.currentSaturation = 0x00, .currentSaturation = 0x00,
.currentX = 0x616b, .currentX = 0x616b,

View File

@ -31,6 +31,7 @@
#include "sampleLight.h" #include "sampleLight.h"
#include "sampleLightCtrl.h" #include "sampleLightCtrl.h"
#include "app_ui.h"
#ifdef ZCL_LIGHT_COLOR_CONTROL #ifdef ZCL_LIGHT_COLOR_CONTROL
/********************************************************************** /**********************************************************************
@ -57,6 +58,10 @@ typedef struct
u32 currentX256; u32 currentX256;
u32 currentY256; u32 currentY256;
u16 xyRemainingTime; u16 xyRemainingTime;
u32 currentEnhancedHue256;
s32 stepEnhancedHue256;
u16 enhancedHueRemainingTime;
} zcl_colorInfo_t; } zcl_colorInfo_t;
/********************************************************************** /**********************************************************************
@ -82,6 +87,10 @@ static zcl_colorInfo_t colorInfo = {
.currentX256 = 0, .currentX256 = 0,
.currentY256 = 0, .currentY256 = 0,
.xyRemainingTime = 0, .xyRemainingTime = 0,
.currentEnhancedHue256 = 0,
.stepEnhancedHue256 = 0,
.enhancedHueRemainingTime = 0,
}; };
static ev_timer_event_t *colorTimerEvt = NULL; static ev_timer_event_t *colorTimerEvt = NULL;
@ -105,18 +114,18 @@ void sampleLight_colorInit(void)
{ {
zcl_lightColorCtrlAttr_t *pColor = zcl_colorAttrGet(); zcl_lightColorCtrlAttr_t *pColor = zcl_colorAttrGet();
pColor->colorCapabilities = ZCL_COLOR_CAPABILITIES_BIT_HUE_SATURATION | ZCL_COLOR_CAPABILITIES_BIT_COLOR_TEMPERATURE | ZCL_COLOR_CAPABILITIES_BIT_X_Y_ATTRIBUTES;
colorInfo.currentHue256 = (u16)(pColor->currentHue) << 8; colorInfo.currentHue256 = (u16)(pColor->currentHue) << 8;
colorInfo.currentSaturation256 = (u16)(pColor->currentSaturation) << 8; colorInfo.currentSaturation256 = (u16)(pColor->currentSaturation) << 8;
colorInfo.currentColorTemp256 = (u32)(pColor->colorTemperatureMireds) << 8; colorInfo.currentColorTemp256 = (u32)(pColor->colorTemperatureMireds) << 8;
colorInfo.currentX256 = (u32)(pColor->currentX) << 8; colorInfo.currentX256 = (u32)(pColor->currentX) << 8;
colorInfo.currentY256 = (u32)(pColor->currentY) << 8; colorInfo.currentY256 = (u32)(pColor->currentY) << 8;
colorInfo.currentEnhancedHue256 = (u32)(pColor->enhancedCurrentHue) << 8;
colorInfo.hueRemainingTime = 0; colorInfo.hueRemainingTime = 0;
colorInfo.saturationRemainingTime = 0; colorInfo.saturationRemainingTime = 0;
colorInfo.colorTempRemainingTime = 1; // Start-up with a 1 second transition colorInfo.colorTempRemainingTime = 0;
colorInfo.xyRemainingTime = 0; colorInfo.xyRemainingTime = 0;
colorInfo.enhancedHueRemainingTime = 0;
// Startup is only defined for color temperature, so why would we load any colors here ... // Startup is only defined for color temperature, so why would we load any colors here ...
pColor->colorMode = ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS; pColor->colorMode = ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS;
@ -142,18 +151,29 @@ void sampleLight_updateColorMode(u8 colorMode)
{ {
zcl_lightColorCtrlAttr_t *pColor = zcl_colorAttrGet(); zcl_lightColorCtrlAttr_t *pColor = zcl_colorAttrGet();
if (colorMode != pColor->colorMode)
{
if (colorMode == ZCL_COLOR_MODE_CURRENT_X_Y) if (colorMode == ZCL_COLOR_MODE_CURRENT_X_Y)
{ {
led_off(LED_STATUS_R);
led_on(LED_STATUS_G);
led_off(LED_STATUS_B);
} }
else if (colorMode == ZCL_COLOR_MODE_CURRENT_HUE_SATURATION) else if (colorMode == ZCL_COLOR_MODE_CURRENT_HUE_SATURATION)
{ {
if (pColor->enhancedColorMode == ZCL_ENHANCED_COLOR_MODE_CURRENT_HUE_SATURATION) {
led_on(LED_STATUS_G);
}
led_off(LED_STATUS_R);
led_off(LED_STATUS_G);
led_on(LED_STATUS_B);
} }
else if (colorMode == ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS) else if (colorMode == ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS)
{ {
led_on(LED_STATUS_R);
led_off(LED_STATUS_G);
led_off(LED_STATUS_B);
} }
}
} }
/********************************************************************* /*********************************************************************
@ -174,9 +194,11 @@ void sampleLight_updateColor(void)
{ {
hwLight_colorUpdate_XY2RGB(pColor->currentX, pColor->currentY, pLevel->curLevel); hwLight_colorUpdate_XY2RGB(pColor->currentX, pColor->currentY, pLevel->curLevel);
} }
else if (pColor->colorMode == ZCL_COLOR_MODE_CURRENT_HUE_SATURATION || pColor->enhancedColorMode == ZCL_ENHANCED_COLOR_MODE_CURRENT_HUE_SATURATION) else if (pColor->colorMode == ZCL_COLOR_MODE_CURRENT_HUE_SATURATION)
{ {
hwLight_colorUpdate_HSV2RGB(pColor->currentHue, pColor->currentSaturation, pLevel->curLevel); // If we are in the enhanced mode, we have to make use of the enhanced hue values!
bool enhanced = pColor->enhancedColorMode == ZCL_ENHANCED_COLOR_MODE_CURRENT_HUE_SATURATION;
hwLight_colorUpdate_HSV2RGB(enhanced ? pColor->enhancedCurrentHue : pColor->currentHue, pColor->currentSaturation, pLevel->curLevel, enhanced);
} }
else if (pColor->colorMode == ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS) else if (pColor->colorMode == ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS)
{ {
@ -197,8 +219,8 @@ static s32 sampleLight_colorTimerEvtCb(void *arg)
{ {
zcl_lightColorCtrlAttr_t *pColor = zcl_colorAttrGet(); zcl_lightColorCtrlAttr_t *pColor = zcl_colorAttrGet();
if ((pColor->colorMode == ZCL_COLOR_MODE_CURRENT_HUE_SATURATION) || if ((pColor->enhancedColorMode == ZCL_COLOR_MODE_CURRENT_HUE_SATURATION) ||
(pColor->colorMode == ZCL_ENHANCED_COLOR_MODE_CURRENT_HUE_SATURATION)) (pColor->enhancedColorMode == ZCL_ENHANCED_COLOR_MODE_CURRENT_HUE_SATURATION))
{ {
if (colorInfo.saturationRemainingTime) if (colorInfo.saturationRemainingTime)
{ {
@ -211,8 +233,14 @@ static s32 sampleLight_colorTimerEvtCb(void *arg)
light_applyUpdate(&pColor->currentHue, &colorInfo.currentHue256, &colorInfo.stepHue256, &colorInfo.hueRemainingTime, light_applyUpdate(&pColor->currentHue, &colorInfo.currentHue256, &colorInfo.stepHue256, &colorInfo.hueRemainingTime,
ZCL_COLOR_ATTR_HUE_MIN, ZCL_COLOR_ATTR_HUE_MAX, TRUE); ZCL_COLOR_ATTR_HUE_MIN, ZCL_COLOR_ATTR_HUE_MAX, TRUE);
} }
if (colorInfo.enhancedHueRemainingTime)
{
light_applyUpdate_16(&pColor->enhancedCurrentHue, &colorInfo.currentEnhancedHue256, &colorInfo.stepEnhancedHue256, &colorInfo.enhancedHueRemainingTime,
ZCL_COLOR_ATTR_ENHANCED_HUE_MIN, ZCL_COLOR_ATTR_ENHANCED_HUE_MAX, TRUE);
} }
else if (pColor->colorMode == ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS) }
else if (pColor->enhancedColorMode == ZCL_COLOR_MODE_COLOR_TEMPERATURE_MIREDS)
{ {
if (colorInfo.colorTempRemainingTime) if (colorInfo.colorTempRemainingTime)
{ {
@ -220,7 +248,7 @@ static s32 sampleLight_colorTimerEvtCb(void *arg)
colorInfo.colorTempMinMireds, colorInfo.colorTempMaxMireds, FALSE); colorInfo.colorTempMinMireds, colorInfo.colorTempMaxMireds, FALSE);
} }
} }
else if (pColor->colorMode == ZCL_COLOR_MODE_CURRENT_X_Y) else if (pColor->enhancedColorMode == ZCL_COLOR_MODE_CURRENT_X_Y)
{ {
if (colorInfo.xyRemainingTime) if (colorInfo.xyRemainingTime)
{ {
@ -228,7 +256,8 @@ static s32 sampleLight_colorTimerEvtCb(void *arg)
&colorInfo.xyRemainingTime, ZCL_COLOR_ATTR_XY_MIN, ZCL_COLOR_ATTR_XY_MAX, FALSE); &colorInfo.xyRemainingTime, ZCL_COLOR_ATTR_XY_MIN, ZCL_COLOR_ATTR_XY_MAX, FALSE);
} }
} }
if (colorInfo.saturationRemainingTime || colorInfo.hueRemainingTime || colorInfo.colorTempRemainingTime || colorInfo.xyRemainingTime)
if (colorInfo.saturationRemainingTime || colorInfo.hueRemainingTime || colorInfo.enhancedHueRemainingTime || colorInfo.colorTempRemainingTime || colorInfo.xyRemainingTime)
{ {
return 0; return 0;
} }
@ -474,14 +503,16 @@ static void sampleLight_stepHueProcess(zcl_colorCtrlStepHueCmd_t *cmd)
* *
* @return None * @return None
*/ */
static void sampleLight_moveToSaturationProcess(zcl_colorCtrlMoveToSaturationCmd_t *cmd) static void sampleLight_moveToSaturationProcess(zcl_colorCtrlMoveToSaturationCmd_t *cmd, bool preserveMode)
{ {
zcl_lightColorCtrlAttr_t *pColor = zcl_colorAttrGet(); zcl_lightColorCtrlAttr_t *pColor = zcl_colorAttrGet();
if (!preserveMode)
{
sampleLight_updateColorMode(ZCL_COLOR_MODE_CURRENT_HUE_SATURATION); sampleLight_updateColorMode(ZCL_COLOR_MODE_CURRENT_HUE_SATURATION);
pColor->colorMode = ZCL_COLOR_MODE_CURRENT_HUE_SATURATION; pColor->colorMode = ZCL_COLOR_MODE_CURRENT_HUE_SATURATION;
pColor->enhancedColorMode = ZCL_COLOR_MODE_CURRENT_HUE_SATURATION; pColor->enhancedColorMode = ZCL_COLOR_MODE_CURRENT_HUE_SATURATION;
}
colorInfo.currentSaturation256 = (u16)(pColor->currentSaturation) << 8; colorInfo.currentSaturation256 = (u16)(pColor->currentSaturation) << 8;
@ -615,7 +646,7 @@ static void sampleLight_moveToHueAndSaturationProcess(zcl_colorCtrlMoveToHueAndS
moveToSaturationCmd.transitionTime = cmd->transitionTime; moveToSaturationCmd.transitionTime = cmd->transitionTime;
sampleLight_moveToHueProcess(&moveToHueCmd); sampleLight_moveToHueProcess(&moveToHueCmd);
sampleLight_moveToSaturationProcess(&moveToSaturationCmd); sampleLight_moveToSaturationProcess(&moveToSaturationCmd, false);
} }
@ -725,19 +756,59 @@ static void sampleLight_enhancedMoveToHueProcess(zcl_colorCtrlEnhancedMoveToHueC
pColor->colorMode = ZCL_COLOR_MODE_CURRENT_HUE_SATURATION; pColor->colorMode = ZCL_COLOR_MODE_CURRENT_HUE_SATURATION;
pColor->enhancedColorMode = ZCL_ENHANCED_COLOR_MODE_CURRENT_HUE_SATURATION; pColor->enhancedColorMode = ZCL_ENHANCED_COLOR_MODE_CURRENT_HUE_SATURATION;
colorInfo.currentEnhancedHue256 = (u32)(pColor->enhancedCurrentHue) << 8;
s32 hueDiff = (s32)cmd->enhancedHue - pColor->enhancedCurrentHue;
switch (cmd->direction) switch (cmd->direction)
{ {
case COLOR_CTRL_DIRECTION_SHORTEST_DISTANCE: case COLOR_CTRL_DIRECTION_SHORTEST_DISTANCE:
if (hueDiff > (ZCL_COLOR_ATTR_ENHANCED_HUE_MAX / 2))
{
hueDiff -= (ZCL_COLOR_ATTR_ENHANCED_HUE_MAX + 1);
}
else if (hueDiff < -ZCL_COLOR_ATTR_ENHANCED_HUE_MAX / 2)
{
hueDiff += (ZCL_COLOR_ATTR_ENHANCED_HUE_MAX + 1);
}
break; break;
case COLOR_CTRL_DIRECTION_LONGEST_DISTANCE: case COLOR_CTRL_DIRECTION_LONGEST_DISTANCE:
if ((hueDiff > 0) && (hueDiff < (ZCL_COLOR_ATTR_ENHANCED_HUE_MAX / 2)))
{
hueDiff -= (ZCL_COLOR_ATTR_ENHANCED_HUE_MAX + 1);
}
else if ((hueDiff < 0) && (hueDiff > -ZCL_COLOR_ATTR_ENHANCED_HUE_MAX / 2))
{
hueDiff += (ZCL_COLOR_ATTR_ENHANCED_HUE_MAX + 1);
}
break; break;
case COLOR_CTRL_DIRECTION_UP: case COLOR_CTRL_DIRECTION_UP:
if (hueDiff < 0)
{
hueDiff += ZCL_COLOR_ATTR_ENHANCED_HUE_MAX;
}
break; break;
case COLOR_CTRL_DIRECTION_DOWN: case COLOR_CTRL_DIRECTION_DOWN:
if (hueDiff > 0)
{
hueDiff -= ZCL_COLOR_ATTR_ENHANCED_HUE_MAX;
}
break; break;
default: default:
break; break;
} }
colorInfo.enhancedHueRemainingTime = (cmd->transitionTime == 0) ? 1 : INTERP_STEPS_FROM_REM_TIME(cmd->transitionTime, ZCL_COLOR_CHANGE_INTERVAL);
colorInfo.stepEnhancedHue256 = ((s32)hueDiff) << 8;
colorInfo.stepEnhancedHue256 /= (s32)colorInfo.enhancedHueRemainingTime;
light_applyUpdate_16(&pColor->enhancedCurrentHue, &colorInfo.currentEnhancedHue256, &colorInfo.stepEnhancedHue256, &colorInfo.enhancedHueRemainingTime,
ZCL_COLOR_ATTR_ENHANCED_HUE_MIN, ZCL_COLOR_ATTR_ENHANCED_HUE_MAX, TRUE);
sampleLight_colorTimerStop();
if (colorInfo.enhancedHueRemainingTime)
{
colorTimerEvt = TL_ZB_TIMER_SCHEDULE(sampleLight_colorTimerEvtCb, NULL, ZCL_COLOR_CHANGE_INTERVAL);
}
} }
/********************************************************************* /*********************************************************************
@ -821,8 +892,8 @@ static void sampleLight_enhancedMoveToHueAndSaturationProcess(zcl_colorCtrlEnhan
moveToSaturationCmd.saturation = cmd->saturation; moveToSaturationCmd.saturation = cmd->saturation;
moveToSaturationCmd.transitionTime = cmd->transitionTime; moveToSaturationCmd.transitionTime = cmd->transitionTime;
sampleLight_moveToSaturationProcess(&moveToSaturationCmd, true);
sampleLight_enhancedMoveToHueProcess(&enhancedMoveToHueCmd); sampleLight_enhancedMoveToHueProcess(&enhancedMoveToHueCmd);
sampleLight_moveToSaturationProcess(&moveToSaturationCmd);
} }
/********************************************************************* /*********************************************************************
@ -1087,7 +1158,7 @@ status_t sampleLight_colorCtrlCb(zclIncomingAddrInfo_t *pAddrInfo, u8 cmdId, voi
sampleLight_stepHueProcess((zcl_colorCtrlStepHueCmd_t *)cmdPayload); sampleLight_stepHueProcess((zcl_colorCtrlStepHueCmd_t *)cmdPayload);
break; break;
case ZCL_CMD_LIGHT_COLOR_CONTROL_MOVE_TO_SATURATION: case ZCL_CMD_LIGHT_COLOR_CONTROL_MOVE_TO_SATURATION:
sampleLight_moveToSaturationProcess((zcl_colorCtrlMoveToSaturationCmd_t *)cmdPayload); sampleLight_moveToSaturationProcess((zcl_colorCtrlMoveToSaturationCmd_t *)cmdPayload, false);
break; break;
case ZCL_CMD_LIGHT_COLOR_CONTROL_MOVE_SATURATION: case ZCL_CMD_LIGHT_COLOR_CONTROL_MOVE_SATURATION:
sampleLight_moveSaturationProcess((zcl_colorCtrlMoveSaturationCmd_t *)cmdPayload); sampleLight_moveSaturationProcess((zcl_colorCtrlMoveSaturationCmd_t *)cmdPayload);