diff --git a/src/cmnds/cmd_newLEDDriver.c b/src/cmnds/cmd_newLEDDriver.c index cebcdd968..cd6144095 100644 --- a/src/cmnds/cmd_newLEDDriver.c +++ b/src/cmnds/cmd_newLEDDriver.c @@ -5,6 +5,7 @@ #include "cmd_public.h" #include "../obk_config.h" #include "../driver/drv_public.h" +#include "../driver/drv_local.h" #include "../hal/hal_flashVars.h" #include "../hal/hal_flashConfig.h" #include "../rgb2hsv.h" @@ -140,6 +141,7 @@ bool LED_IsLedDriverChipRunning() return DRV_IsRunning("SM2135") || DRV_IsRunning("BP5758D") || DRV_IsRunning("TESTLED") || DRV_IsRunning("SM2235") || DRV_IsRunning("BP1658CJ") || DRV_IsRunning("KP18058") + || DRV_IsRunning("SM16703P") ; #else return false; @@ -577,6 +579,12 @@ void apply_smart_light() { #if ENABLE_DRIVER_TUYAMCU TuyaMCU_OnRGBCWChange(finalColors, g_lightEnableAll, g_lightMode, g_brightness0to100*0.01f, LED_GetTemperature0to1Range()); #endif +#if ENABLE_DRIVER_SM16703P + if (pixel_count > 0) { + SM16703P_setAllPixels(finalColors[0], finalColors[1], finalColors[2]); + SM16703P_Show(); + } +#endif // I am not sure if it's the best place to do it // NOTE: this will broadcast MQTT only if a flag is set diff --git a/src/cmnds/cmd_public.h b/src/cmnds/cmd_public.h index 5b4e523e1..c2d16ea04 100644 --- a/src/cmnds/cmd_public.h +++ b/src/cmnds/cmd_public.h @@ -150,6 +150,7 @@ enum LightMode { Light_Temperature, Light_RGB, Light_All, + Light_Anim, }; #define TOKENIZER_ALLOW_QUOTES 1 diff --git a/src/driver/drv_local.h b/src/driver/drv_local.h index 15bba5674..f1887cd7f 100644 --- a/src/driver/drv_local.h +++ b/src/driver/drv_local.h @@ -52,6 +52,11 @@ void KP18058_Init(); void SM16703P_Init(); +void SM16703P_setPixel(int pixel, int r, int g, int b); +void SM16703P_setPixelWithBrig(int pixel, int r, int g, int b); +void SM16703P_setAllPixels(int r, int g, int b); +void SM16703P_Show(); +extern uint32_t pixel_count; void TM1637_Init(); @@ -142,6 +147,9 @@ void Freeze_Init(); void Freeze_OnEverySecond(); void Freeze_RunFrame(); +void PixelAnim_Init(); +void PixelAnim_RunQuickTick(); +void PixelAnim_Run(int j); #define SM2135_DELAY 4 diff --git a/src/driver/drv_main.c b/src/driver/drv_main.c index 974eb03f7..d7466dddd 100644 --- a/src/driver/drv_main.c +++ b/src/driver/drv_main.c @@ -49,6 +49,14 @@ static driver_t g_drivers[] = { //drvdetail:"requires":""} { "Freeze", Freeze_Init, Freeze_OnEverySecond, NULL, Freeze_RunFrame, NULL, NULL, false }, #endif +#if ENABLE_DRIVER_PIXELANIM + //drvdetail:{"name":"PixelAnim", + //drvdetail:"title":"TODO", + //drvdetail:"descr":"PixelAnim provides a simple set of WS2812B animations", + //drvdetail:"requires":""} + { "PixelAnim", PixelAnim_Init, NULL, NULL, PixelAnim_RunQuickTick, NULL, NULL, false }, +#endif + #if ENABLE_NTP //drvdetail:{"name":"NTP", //drvdetail:"title":"TODO", diff --git a/src/driver/drv_pixelAnim.c b/src/driver/drv_pixelAnim.c new file mode 100644 index 000000000..eb7ced3a4 --- /dev/null +++ b/src/driver/drv_pixelAnim.c @@ -0,0 +1,185 @@ +// WS2812B etc animations +// For the animations themselves credit goes to https://github.com/Electriangle +#include "../new_common.h" +#include "../new_pins.h" +#include "../new_cfg.h" +// Commands register, execution API and cmd tokenizer +#include "../cmnds/cmd_public.h" +#include "../mqtt/new_mqtt.h" +#include "../logging/logging.h" +#include "drv_local.h" +#include "../hal/hal_pins.h" +#include + +/* +// Usage: +startDriver SM16703P +SM16703P_Init 16 +startDriver PixelAnim + +*/ + +// Credit: https://github.com/Electriangle/RainbowCycle_Main +byte *RainbowWheel_Wheel(byte WheelPosition) { + static byte c[3]; + + if (WheelPosition < 85) { + c[0] = WheelPosition * 3; + c[1] = 255 - WheelPosition * 3; + c[2] = 0; + } + else if (WheelPosition < 170) { + WheelPosition -= 85; + c[0] = 255 - WheelPosition * 3; + c[1] = 0; + c[2] = WheelPosition * 3; + } + else { + WheelPosition -= 170; + c[0] = 0; + c[1] = WheelPosition * 3; + c[2] = 255 - WheelPosition * 3; + } + + return c; +} +uint16_t j = 0; + +void RainbowWheel_Run() { + byte *c; + uint16_t i; + + for (i = 0; i < pixel_count; i++) { + c = RainbowWheel_Wheel(((i * 256 / pixel_count) + j) & 255); + SM16703P_setPixelWithBrig(pixel_count - 1 - i, *c, *(c + 1), *(c + 2)); + } + SM16703P_Show(); + j++; + j %= 256; +} + +void Fire_setPixelHeatColor(int Pixel, byte temperature) { + // Rescale heat from 0-255 to 0-191 + byte t192 = round((temperature / 255.0) * 191); + + // Calculate ramp up from + byte heatramp = t192 & 0x3F; // 0...63 + heatramp <<= 2; // scale up to 0...252 + + // Figure out which third of the spectrum we're in: + if (t192 > 0x80) { // hottest + SM16703P_setPixelWithBrig(Pixel, 255, 255, heatramp); + } + else if (t192 > 0x40) { // middle + SM16703P_setPixelWithBrig(Pixel, 255, heatramp, 0); + } + else { // coolest + SM16703P_setPixelWithBrig(Pixel, heatramp, 0, 0); + } +} +// FlameHeight - Use larger value for shorter flames, default=50. +// Sparks - Use larger value for more ignitions and a more active fire (between 0 to 255), default=100. +// DelayDuration - Use larger value for slower flame speed, default=10. +int FlameHeight = 50; +int Sparks = 100; +static byte heat[32]; +int RandomRange(int min, int max) { + int r = rand() % (max - min); + return min + r; +} +void Fire_Run() { + int cooldown; + + // Cool down each cell a little + for (int i = 0; i < pixel_count; i++) { + cooldown = RandomRange(0, ((FlameHeight * 10) / pixel_count) + 2); + + if (cooldown > heat[i]) { + heat[i] = 0; + } + else { + heat[i] = heat[i] - cooldown; + } + } + + // Heat from each cell drifts up and diffuses slightly + for (int k = (pixel_count - 1); k >= 2; k--) { + heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3; + } + + // Randomly ignite new Sparks near bottom of the flame + if (rand()%255 < Sparks) { + int y = rand()%7; + heat[y] = heat[y] + RandomRange(160, 255); + } + + // Convert heat to LED colors + for (int j = 0; j < pixel_count; j++) { + Fire_setPixelHeatColor(j, heat[j]); + } + +} + +// startDriver PixelAnim + +typedef struct ledAnim_s { + const char *name; + void(*runFunc)(); +} ledAnim_t; + +int activeAnim = -1; +ledAnim_t g_anims[] = { + { "Rainbow Wheel", RainbowWheel_Run }, + { "Fire", Fire_Run } +}; +int g_numAnims = sizeof(g_anims) / sizeof(g_anims[0]); + +void PixelAnim_Init() { + +} +extern byte g_lightEnableAll; +extern byte g_lightMode; +void PixelAnim_CreatePanel(http_request_t *request) { + const char* activeStr = ""; + int i; + + if (g_lightMode == Light_Anim) { + activeStr = "[ACTIVE]"; + } + poststr(request, ""); + hprintf255(request, "
LED Animation %s
", activeStr); + + for (i = 0; i < g_numAnims; i++) { + const char* c; + if (i == activeAnim) { + c = "bgrn"; + } + else { + c = "bred"; + } + poststr(request, "
"); + hprintf255(request, "", i); + hprintf255(request, "
", + c, g_anims[i].name); + } + poststr(request, ""); +} +void PixelAnim_Run(int j) { + activeAnim = j; + g_lightMode = Light_Anim; +} +void PixelAnim_RunQuickTick() { + if (g_lightEnableAll == 0) { + // disabled + return; + } + if (g_lightMode != Light_Anim) { + // disabled + return; + } + if (activeAnim != -1) { + g_anims[activeAnim].runFunc(); + } +} + + diff --git a/src/driver/drv_sm16703P.c b/src/driver/drv_sm16703P.c index 6bdcd8ecf..33ba1a453 100644 --- a/src/driver/drv_sm16703P.c +++ b/src/driver/drv_sm16703P.c @@ -205,6 +205,8 @@ void SM16703P_setMultiplePixel(uint32_t pixel, uint8_t *data, bool push) { } } void SM16703P_setPixel(int pixel, int r, int g, int b) { + if (!initialized) + return; // Load data in correct format int b0, b1, b2; if (color_order == SM16703P_COLOR_ORDER_RGB) { @@ -241,6 +243,56 @@ void SM16703P_setPixel(int pixel, int r, int g, int b) { translate_byte(b1, spi_msg->send_buf + (pixel_offset + 4 + (pixel * 3 * 4))); translate_byte(b2, spi_msg->send_buf + (pixel_offset + 8 + (pixel * 3 * 4))); } +extern float g_brightness0to100;//TODO +void SM16703P_setPixelWithBrig(int pixel, int r, int g, int b) { + r = (int)(r * g_brightness0to100*0.01f); + g = (int)(g * g_brightness0to100*0.01f); + b = (int)(b * g_brightness0to100*0.01f); + SM16703P_setPixel(pixel,r, g, b); +} +void SM16703P_setAllPixels(int r, int g, int b) { + int pixel; + if (!initialized) + return; + // Load data in correct format + int b0, b1, b2; + if (color_order == SM16703P_COLOR_ORDER_RGB) { + b0 = r; + b1 = g; + b2 = b; + } + if (color_order == SM16703P_COLOR_ORDER_RBG) { + b0 = r; + b1 = b; + b2 = g; + } + if (color_order == SM16703P_COLOR_ORDER_BRG) { + b0 = b; + b1 = r; + b2 = g; + } + if (color_order == SM16703P_COLOR_ORDER_BGR) { + b0 = b; + b1 = g; + b2 = r; + } + if (color_order == SM16703P_COLOR_ORDER_GRB) { + b0 = g; + b1 = r; + b2 = b; + } + if (color_order == SM16703P_COLOR_ORDER_GBR) { + b0 = g; + b1 = b; + b2 = r; + } + for (pixel = 0; pixel < pixel_count; pixel++) { + translate_byte(b0, spi_msg->send_buf + (pixel_offset + 0 + (pixel * 3 * 4))); + translate_byte(b1, spi_msg->send_buf + (pixel_offset + 4 + (pixel * 3 * 4))); + translate_byte(b2, spi_msg->send_buf + (pixel_offset + 8 + (pixel * 3 * 4))); + } +} + // SM16703P_SetRaw bUpdate byteOfs HexData // SM16703P_SetRaw 1 0 FF000000FF000000FF @@ -380,11 +432,13 @@ commandResult_t SM16703P_InitForLEDCount(const void *context, const char *cmd, c return CMD_RES_OK; } +void SM16703P_Show() { + SPIDMA_StartTX(spi_msg); +} static commandResult_t SM16703P_StartTX(const void *context, const char *cmd, const char *args, int flags) { if (!initialized) return CMD_RES_ERROR; - - SPIDMA_StartTX(spi_msg); + SM16703P_Show(); return CMD_RES_OK; } diff --git a/src/httpserver/http_fns.c b/src/httpserver/http_fns.c index e7629a592..bb8744fa3 100644 --- a/src/httpserver/http_fns.c +++ b/src/httpserver/http_fns.c @@ -205,6 +205,13 @@ int http_fn_index(http_request_t* request) { hprintf255(request, "

Enabled %s!

", CHANNEL_GetLabel(j)); CHANNEL_Set(j, 255, 1); } +#if ENABLE_DRIVER_PIXELANIM + if (http_getArg(request->url, "an", tmpA, sizeof(tmpA))) { + j = atoi(tmpA); + hprintf255(request, "

Ran %i!

", (j)); + PixelAnim_Run(j); + } +#endif if (http_getArg(request->url, "rgb", tmpA, sizeof(tmpA))) { hprintf255(request, "

Set RGB to %s!

", tmpA); LED_SetBaseColor(0, "led_basecolor", tmpA, 0); @@ -662,6 +669,11 @@ int http_fn_index(http_request_t* request) { hprintf255(request, ""); poststr(request, ""); } +#if ENABLE_DRIVER_PIXELANIM + if (DRV_IsRunning("PixelAnim")) { + PixelAnim_CreatePanel(request); + } +#endif if (c_pwms == 2 || c_pwms >= 4) { // TODO: temperature slider int pwmValue; diff --git a/src/obk_config.h b/src/obk_config.h index 019de166d..0c02561bb 100644 --- a/src/obk_config.h +++ b/src/obk_config.h @@ -62,6 +62,7 @@ #define ENABLE_EXPAND_CONSTANT 1 #define ENABLE_DRIVER_DHT 1 #define ENABLE_DRIVER_SM16703P 1 +#define ENABLE_DRIVER_PIXELANIM 1 #elif PLATFORM_BL602