From b7e359e81ab80b7e514c0d15971ea5ccb807d58b Mon Sep 17 00:00:00 2001 From: Tester23 Date: Mon, 11 Dec 2023 10:01:32 +0100 Subject: [PATCH] bugfix for edge case with CW LED driver channels, along with a self test --- src/cmnds/cmd_newLEDDriver.c | 43 +++++---- src/selftest/selftest_led.c | 169 ++++++++++++++++++++++++++--------- 2 files changed, 156 insertions(+), 56 deletions(-) diff --git a/src/cmnds/cmd_newLEDDriver.c b/src/cmnds/cmd_newLEDDriver.c index 967e3eeb4..b2e49cc5e 100644 --- a/src/cmnds/cmd_newLEDDriver.c +++ b/src/cmnds/cmd_newLEDDriver.c @@ -310,14 +310,8 @@ void LED_RunQuickColorLerp(int deltaMS) { deltaSeconds = deltaMS * 0.001f; - // The color order is RGBCW. - // some people set RED to channel 0, and some of them set RED to channel 1 - // Let's detect if there is a PWM on channel 0 - if(CHANNEL_HasChannelPinWithRoleOrRole(0, IOR_PWM, IOR_PWM_n)) { - firstChannelIndex = 0; - } else { - firstChannelIndex = 1; - } + firstChannelIndex = LED_GetFirstChannelIndex(); + if (CFG_HasFlag(OBK_FLAG_LED_EMULATE_COOL_WITH_RGB)) { emulatedCool = firstChannelIndex + 3; } @@ -423,6 +417,29 @@ float led_gamma_correction (int color, float iVal) { // apply LED gamma and RGB void LED_SaveStateToFlashVarsNow() { HAL_FlashVars_SaveLED(g_lightMode, g_brightness0to100, led_temperature_current, baseColors[0], baseColors[1], baseColors[2], g_lightEnableAll); } +// The color order is RGBCW. +// some people set RED to channel 0, and some of them set RED to channel 1 +// Let's detect if there is a PWM on channel 0 +int LED_GetFirstChannelIndex() { +#if 0 + int firstChannelIndex; + if (CHANNEL_HasChannelPinWithRoleOrRole(0, IOR_PWM, IOR_PWM_n)) { + firstChannelIndex = 0; + } + else { + firstChannelIndex = 1; + } + return firstChannelIndex; +#else + int i; + for (i = 0; i < 5; i++) { + if (CHANNEL_HasChannelPinWithRoleOrRole(i, IOR_PWM, IOR_PWM_n)) { + return i; + } + } + return 0; +#endif +} void apply_smart_light() { int i; int firstChannelIndex; @@ -434,14 +451,8 @@ void apply_smart_light() { int value_brightness = 0; int value_cold_or_warm = 0; - // The color order is RGBCW. - // some people set RED to channel 0, and some of them set RED to channel 1 - // Let's detect if there is a PWM on channel 0 - if(CHANNEL_HasChannelPinWithRoleOrRole(0, IOR_PWM, IOR_PWM_n)) { - firstChannelIndex = 0; - } else { - firstChannelIndex = 1; - } + + firstChannelIndex = LED_GetFirstChannelIndex(); if (CFG_HasFlag(OBK_FLAG_LED_EMULATE_COOL_WITH_RGB)) { emulatedCool = firstChannelIndex + 3; diff --git a/src/selftest/selftest_led.c b/src/selftest/selftest_led.c index e45b5dd6a..f1ec80825 100644 --- a/src/selftest/selftest_led.c +++ b/src/selftest/selftest_led.c @@ -89,6 +89,92 @@ void Test_LEDDriver_CW() { } } +void Test_LEDDriver_CW_OtherChannels() { + int i; + // reset whole device + SIM_ClearOBK(0); + + // CW bulb requires two PWMs - first on channel 1, second on channel 2 + // NOTE: we also support case where first PWM is on channel 0, and second on 1 + PIN_SetPinRoleForPinIndex(24, IOR_PWM); + PIN_SetPinChannelForPinIndex(24, 3); + + PIN_SetPinRoleForPinIndex(26, IOR_PWM); + PIN_SetPinChannelForPinIndex(26, 4); + + CMD_ExecuteCommand("led_enableAll 1", 0); + + + // check expressions (not really LED related but ok) + SELFTEST_ASSERT_EXPRESSION("$led_enableAll", 1.0f); + // Set 100% Warm + CMD_ExecuteCommand("led_temperature 500", 0); + + printf("Channel C is %i, channel W is %i\n", CHANNEL_Get(3), CHANNEL_Get(4)); + SELFTEST_ASSERT_CHANNEL(3, 0); + SELFTEST_ASSERT_CHANNEL(4, 100); + + // check read access + SELFTEST_ASSERT_EXPRESSION("$led_temperature", 500.0f); + + // check expressions (not really LED related but ok) + SELFTEST_ASSERT_EXPRESSION("$led_temperature*2", 1000.0f); + SELFTEST_ASSERT_EXPRESSION("2*$led_temperature", 1000.0f); + + // Set 100% Cold + CMD_ExecuteCommand("led_temperature 154", 0); + // check read access + SELFTEST_ASSERT_EXPRESSION("$led_temperature", 154.0f); + SELFTEST_ASSERT_EXPRESSION("$led_enableAll", 1.0f); + SELFTEST_ASSERT_CHANNEL(3, 100); + SELFTEST_ASSERT_CHANNEL(4, 0); + + // Tasmota style command should disable LED + Test_FakeHTTPClientPacket_GET("cm?cmnd=POWER%200"); + SELFTEST_ASSERT_EXPRESSION("$led_enableAll", 0.0f); + SELFTEST_ASSERT_CHANNEL(3, 0); + SELFTEST_ASSERT_CHANNEL(4, 0); + // Tasmota style command should enable LED + Test_FakeHTTPClientPacket_GET("cm?cmnd=POWER%201"); + SELFTEST_ASSERT_EXPRESSION("$led_enableAll", 1.0f); + SELFTEST_ASSERT_CHANNEL(3, 100); + SELFTEST_ASSERT_CHANNEL(4, 0); + + + SIM_SendFakeMQTTAndRunSimFrame_CMND("POWER", "ON"); + SELFTEST_ASSERT_EXPRESSION("$led_enableAll", 1.0f); + SELFTEST_ASSERT_CHANNEL(3, 100); + SELFTEST_ASSERT_CHANNEL(4, 0); + SIM_SendFakeMQTTAndRunSimFrame_CMND("POWER", "OFF"); + SELFTEST_ASSERT_EXPRESSION("$led_enableAll", 0.0f); + SELFTEST_ASSERT_CHANNEL(3, 0); + SELFTEST_ASSERT_CHANNEL(4, 0); + SIM_SendFakeMQTTAndRunSimFrame_CMND("POWER", "ON"); + SELFTEST_ASSERT_EXPRESSION("$led_enableAll", 1.0f); + SELFTEST_ASSERT_CHANNEL(3, 100); + SELFTEST_ASSERT_CHANNEL(4, 0); + + for (i = 0; i <= 100; i++) { + char buffer[64]; + sprintf(buffer, "Dimmer %i", i); + CMD_ExecuteCommand(buffer, 0); + //printf("Dimmer loop test: %i\n",i); + SELFTEST_ASSERT_EXPRESSION("$led_dimmer", i); + } + for (i = 154; i <= 500; i++) { + char buffer[64]; + sprintf(buffer, "CT %i", i); + CMD_ExecuteCommand(buffer, 0); + //printf("Dimmer loop test: %i\n",i); + SELFTEST_ASSERT_EXPRESSION("$led_temperature", i); + } + CMD_ExecuteCommand("Dimmer 0", 0); + for (i = 0; i < 100; i++) { + SELFTEST_ASSERT_EXPRESSION("$led_dimmer", i); + CMD_ExecuteCommand("add_dimmer 1", 0); + SELFTEST_ASSERT_EXPRESSION("$led_dimmer", i + 1); + } +} void Test_LEDDriver_CW_Alternate() { int i; // reset whole device @@ -271,20 +357,20 @@ void Test_LEDDriver_RGBCW() { //CMD_ExecuteCommand("{\"color\":{\"b\":255,\"c\":0,\"g\":255,\"r\":255},\"state\":\"1\"}", ""); } -void Test_LEDDriver_RGB() { +void Test_LEDDriver_RGB(int firstChannel) { // reset whole device SIM_ClearOBK(0); // RGB bulb requires three PWMs - first on channel 1, second on channel 2, third on channel 3 // NOTE: we also support case where first PWM is on channel 0, and second on 1 PIN_SetPinRoleForPinIndex(24, IOR_PWM); - PIN_SetPinChannelForPinIndex(24, 1); + PIN_SetPinChannelForPinIndex(24, firstChannel); PIN_SetPinRoleForPinIndex(26, IOR_PWM); - PIN_SetPinChannelForPinIndex(26, 2); + PIN_SetPinChannelForPinIndex(26, firstChannel+1); PIN_SetPinRoleForPinIndex(9, IOR_PWM); - PIN_SetPinChannelForPinIndex(9, 3); + PIN_SetPinChannelForPinIndex(9, firstChannel + 2); CMD_ExecuteCommand("led_enableAll 1", 0); // check expressions (not really LED related but ok) @@ -304,74 +390,77 @@ void Test_LEDDriver_RGB() { SELFTEST_ASSERT_EXPRESSION("$led_dimmer+$led_dimmer", 200.0f); SELFTEST_ASSERT_EXPRESSION("$led_dimmer+$led_dimmer+$led_dimmer", 300.0f); - printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(1), CHANNEL_Get(2), CHANNEL_Get(3)); - SELFTEST_ASSERT_CHANNEL(1, 100); - SELFTEST_ASSERT_CHANNEL(2, 0); - SELFTEST_ASSERT_CHANNEL(3, 0); + printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(firstChannel), CHANNEL_Get(firstChannel+1), CHANNEL_Get(firstChannel+2)); + SELFTEST_ASSERT_CHANNEL(firstChannel, 100); + SELFTEST_ASSERT_CHANNEL(firstChannel+1, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+2, 0); // Set green CMD_ExecuteCommand("led_baseColor_rgb 00FF00", 0); - printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(1), CHANNEL_Get(2), CHANNEL_Get(3)); - SELFTEST_ASSERT_CHANNEL(1, 0); - SELFTEST_ASSERT_CHANNEL(2, 100); - SELFTEST_ASSERT_CHANNEL(3, 0); + printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(firstChannel), CHANNEL_Get(firstChannel+1), CHANNEL_Get(firstChannel+2)); + SELFTEST_ASSERT_CHANNEL(firstChannel, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+1, 100); + SELFTEST_ASSERT_CHANNEL(firstChannel+2, 0); // Set blue - also support # CMD_ExecuteCommand("led_baseColor_rgb #0000FF", 0); - printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(1), CHANNEL_Get(2), CHANNEL_Get(3)); - SELFTEST_ASSERT_CHANNEL(1, 0); - SELFTEST_ASSERT_CHANNEL(2, 0); - SELFTEST_ASSERT_CHANNEL(3, 100); + printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(firstChannel), CHANNEL_Get(firstChannel+1), CHANNEL_Get(firstChannel+2)); + SELFTEST_ASSERT_CHANNEL(firstChannel, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+1, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+2, 100); // set 50% brightness CMD_ExecuteCommand("led_dimmer 50", 0); // check expressions (not really LED related but ok) SELFTEST_ASSERT_EXPRESSION("$led_dimmer", 50.0f); - printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(1), CHANNEL_Get(2), CHANNEL_Get(3)); - SELFTEST_ASSERT_CHANNEL(1, 0); - SELFTEST_ASSERT_CHANNEL(2, 0); - SELFTEST_ASSERT_CHANNEL(3, 21); + printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(firstChannel), CHANNEL_Get(firstChannel+1), CHANNEL_Get(firstChannel+2)); + SELFTEST_ASSERT_CHANNEL(firstChannel, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+1, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+2, 21); // set 90% brightness CMD_ExecuteCommand("led_dimmer 90", 0); // check expressions (not really LED related but ok) SELFTEST_ASSERT_EXPRESSION("$led_dimmer", 90.0f); - printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(1), CHANNEL_Get(2), CHANNEL_Get(3)); - SELFTEST_ASSERT_CHANNEL(1, 0); - SELFTEST_ASSERT_CHANNEL(2, 0); - SELFTEST_ASSERT_CHANNEL(3, 79); + printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(firstChannel), CHANNEL_Get(firstChannel+1), CHANNEL_Get(firstChannel+2)); + SELFTEST_ASSERT_CHANNEL(firstChannel, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+1, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+2, 79); // disable CMD_ExecuteCommand("led_enableAll 0", 0); - printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(1), CHANNEL_Get(2), CHANNEL_Get(3)); - SELFTEST_ASSERT_CHANNEL(1, 0); - SELFTEST_ASSERT_CHANNEL(2, 0); - SELFTEST_ASSERT_CHANNEL(3, 0); + printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(firstChannel), CHANNEL_Get(firstChannel+1), CHANNEL_Get(firstChannel+2)); + SELFTEST_ASSERT_CHANNEL(firstChannel, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+1, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+2, 0); // reenable, it should remember last state CMD_ExecuteCommand("led_enableAll 1", 0); - printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(1), CHANNEL_Get(2), CHANNEL_Get(3)); - SELFTEST_ASSERT_CHANNEL(1, 0); - SELFTEST_ASSERT_CHANNEL(2, 0); - SELFTEST_ASSERT_CHANNEL(3, 79); + printf("Channel R is %i, channel G is %i, channel B is %i\n", CHANNEL_Get(firstChannel), CHANNEL_Get(firstChannel+1), CHANNEL_Get(firstChannel+2)); + SELFTEST_ASSERT_CHANNEL(firstChannel, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+1, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+2, 79); // Tasmota style command should disable LED Test_FakeHTTPClientPacket_GET("cm?cmnd=POWER%200"); - SELFTEST_ASSERT_CHANNEL(1, 0); - SELFTEST_ASSERT_CHANNEL(2, 0); - SELFTEST_ASSERT_CHANNEL(3, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+1, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+2, 0); // Tasmota style command should enable LED Test_FakeHTTPClientPacket_GET("cm?cmnd=POWER%201"); - SELFTEST_ASSERT_CHANNEL(1, 0); - SELFTEST_ASSERT_CHANNEL(2, 0); - SELFTEST_ASSERT_CHANNEL(3, 79); + SELFTEST_ASSERT_CHANNEL(firstChannel, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+1, 0); + SELFTEST_ASSERT_CHANNEL(firstChannel+2, 79); // make error - //SELFTEST_ASSERT_CHANNEL(3, 666); + //SELFTEST_ASSERT_CHANNEL(firstChannel+2, 666); } void Test_LEDDriver() { Test_LEDDriver_CW_Alternate(); Test_LEDDriver_CW(); - Test_LEDDriver_RGB(); + Test_LEDDriver_CW_OtherChannels(); + // support both indexing from 0 and 1 + Test_LEDDriver_RGB(0); + Test_LEDDriver_RGB(1); Test_LEDDriver_RGBCW(); }