Redesign light driver phase 3

Redesign light driver phase 3
This commit is contained in:
Theo Arends 2019-10-08 17:46:03 +02:00
parent 0062f7c84b
commit 8d17301433
3 changed files with 191 additions and 163 deletions

View File

@ -168,8 +168,6 @@ const uint32_t LOOP_SLEEP_DELAY = 50; // Lowest number of milliseconds to
#define NEO_RGBW 5 // Neopixel RGBW leds
#define NEO_GRBW 6 // Neopixel GRBW leds
#define LT_SM16716 16 // Lights that use SM16716 will have this bit set in light_type
#define RGB_REMAP_RGBW 0
#define RGB_REMAP_RBGW 6
#define RGB_REMAP_GRBW 24
@ -267,9 +265,7 @@ enum Ws2812Color { WS_RED, WS_GREEN, WS_BLUE };
enum LightSubtypes { LST_NONE, LST_SINGLE, LST_COLDWARM, LST_RGB, LST_RGBW, LST_RGBWC, LST_MAX=5 }; // Do not insert new fields
enum LightTypes { LT_BASIC, LT_PWM1, LT_PWM2, LT_PWM3, LT_PWM4, LT_PWM5, LT_PWM6, LT_PWM7,
LT_NU8, LT_SERIAL1, LT_SERIAL2, LT_WS2812, LT_RGBW, LT_RGBWC, LT_NU14, LT_NU15 }; // Do not insert new fields
enum LightSchemes {LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX};
LT_NU8, LT_SERIAL1, LT_SERIAL2, LT_RGB, LT_RGBW, LT_RGBWC, LT_NU14, LT_NU15 }; // Do not insert new fields
enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_MODULE_INIT, FUNC_PRE_INIT, FUNC_INIT,
FUNC_LOOP, FUNC_EVERY_50_MSECOND, FUNC_EVERY_100_MSECOND, FUNC_EVERY_200_MSECOND, FUNC_EVERY_250_MSECOND, FUNC_EVERY_300_MSECOND, FUNC_EVERY_SECOND,
@ -279,7 +275,7 @@ enum XsnsFunctions {FUNC_SETTINGS_OVERRIDE, FUNC_PIN_STATE, FUNC_MODULE_INIT, FU
FUNC_SET_POWER, FUNC_SET_DEVICE_POWER, FUNC_SHOW_SENSOR,
FUNC_ENERGY_EVERY_SECOND, FUNC_ENERGY_RESET,
FUNC_RULES_PROCESS, FUNC_SERIAL, FUNC_FREE_MEM, FUNC_BUTTON_PRESSED,
FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_MAIN_BUTTON, FUNC_WEB_ADD_HANDLER, FUNC_SET_CHANNELS};
FUNC_WEB_ADD_BUTTON, FUNC_WEB_ADD_MAIN_BUTTON, FUNC_WEB_ADD_HANDLER, FUNC_SET_CHANNELS, FUNC_SET_SCHEME};
enum AddressConfigSteps { ADDR_IDLE, ADDR_RECEIVE, ADDR_SEND };

View File

@ -31,12 +31,9 @@
* 5 PWM5 RGBCW yes (H801, Arilux LC11)
* 9 reserved no
* 10 reserved yes
* 11 +WS2812 RGB(W) no (One WS2812 RGB or RGBW ledstrip)
* 11 +WS2812 RGB no (One WS2812 RGB or RGBW ledstrip)
* 12 AiLight RGBW no
* 13 Sonoff B1 RGBCW yes
* 19 SM16716 RGB no
* 20 SM16716+W RGBW no
* 21 SM16716+CW RGBCW yes
*
* light_scheme WS2812 3+ Colors 1+2 Colors Effect
* ------------ ------ --------- ---------- -----------------
@ -56,7 +53,6 @@
*
\*********************************************************************************************/
/*********************************************************************************************\
*
* Light management has been refactored to provide a cleaner class-based interface.
@ -128,21 +124,16 @@
#define XDRV_04 4
// #define DEBUG_LIGHT
enum LightSchemes { LS_POWER, LS_WAKEUP, LS_CYCLEUP, LS_CYCLEDN, LS_RANDOM, LS_MAX };
const uint8_t LIGHT_COLOR_SIZE = 25; // Char array scolor size
const uint8_t WS2812_SCHEMES = 7; // Number of additional WS2812 schemes supported by xdrv_ws2812.ino
const char kLightCommands[] PROGMEM = "|" // No prefix
#ifdef USE_WS2812
D_CMND_LED "|" D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_WIDTH "|"
#endif // USE_WS2812
D_CMND_COLOR "|" D_CMND_COLORTEMPERATURE "|" D_CMND_DIMMER "|" D_CMND_LEDTABLE "|" D_CMND_FADE "|"
D_CMND_RGBWWTABLE "|" D_CMND_SCHEME "|" D_CMND_SPEED "|" D_CMND_WAKEUP "|" D_CMND_WAKEUPDURATION "|"
D_CMND_WHITE "|" D_CMND_CHANNEL "|" D_CMND_HSBCOLOR "|UNDOCA" ;
void (* const LightCommand[])(void) PROGMEM = {
#ifdef USE_WS2812
&CmndLed, &CmndPixels, &CmndRotation, &CmndWidth,
#endif // USE_WS2812
&CmndColor, &CmndColorTemperature, &CmndDimmer, &CmndLedTable, &CmndFade,
&CmndRgbwwTable, &CmndScheme, &CmndSpeed, &CmndWakeup, &CmndWakeupDuration,
&CmndWhite, &CmndChannel, &CmndHsbColor, &CmndUndocA };
@ -258,6 +249,7 @@ struct LIGHT {
uint8_t wakeup_dimmer = 0;
uint8_t fixed_color_index = 1;
uint8_t pwm_offset = 0; // Offset in color buffer
uint8_t max_scheme = LS_MAX -1;
bool update = true;
bool pwm_multi_channels = false; // SetOption68, treat each PWM channel as an independant dimmer
@ -1224,11 +1216,7 @@ bool LightModuleInit(void)
}
light_type = LT_PWM2;
}
#ifdef USE_WS2812
if (!light_type && (pin[GPIO_WS2812] < 99)) { // RGB led
light_type = LT_WS2812;
}
#endif // USE_WS2812
// post-process for lights
if (Settings.flag3.pwm_multi_channels) {
uint32_t pwm_channels = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7);
@ -1241,18 +1229,10 @@ bool LightModuleInit(void)
void LightInit(void)
{
uint8_t max_scheme = LS_MAX -1;
Light.device = devices_present;
Light.subtype = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7); // Always 0 - LST_MAX (5)
Light.pwm_multi_channels = Settings.flag3.pwm_multi_channels;
#if defined(USE_WS2812) && (USE_WS2812_CTYPE > NEO_3LED)
if (LT_WS2812 == light_type) {
Light.subtype++; // from RGB to RGBW
}
#endif
if ((LST_SINGLE < Light.subtype) && Light.pwm_multi_channels) {
// we treat each PWM channel as an independant one, hence we switch to
light_controller.setPWMMultiChannel(true);
@ -1283,25 +1263,8 @@ void LightInit(void)
}
}
}
#ifdef USE_WS2812 // ************************************************************************
else if (LT_WS2812 == light_type) {
Ws2812Init();
max_scheme = LS_MAX + WS2812_SCHEMES;
}
#endif // USE_WS2812 ************************************************************************
/*
else {
light_pdi_pin = pin[GPIO_DI];
light_pdcki_pin = pin[GPIO_DCKI];
pinMode(light_pdi_pin, OUTPUT);
pinMode(light_pdcki_pin, OUTPUT);
digitalWrite(light_pdi_pin, LOW);
digitalWrite(light_pdcki_pin, LOW);
LightMy92x1Init();
}
*/
uint32_t max_scheme = Light.max_scheme;
if (Light.subtype < LST_RGB) {
max_scheme = LS_POWER;
}
@ -1480,7 +1443,7 @@ void LightState(uint8_t append)
if (Light.subtype >= LST_RGB) {
ResponseAppend_P(PSTR(",\"" D_CMND_SCHEME "\":%d"), Settings.light_scheme);
}
if (LT_WS2812 == light_type) {
if (Light.max_scheme > LS_MAX) {
ResponseAppend_P(PSTR(",\"" D_CMND_WIDTH "\":%d"), Settings.light_width);
}
ResponseAppend_P(PSTR(",\"" D_CMND_FADE "\":\"%s\",\"" D_CMND_SPEED "\":%d,\"" D_CMND_LEDTABLE "\":\"%s\""),
@ -1736,12 +1699,8 @@ void LightAnimate(void)
case LS_RANDOM:
LightRandomColor();
break;
#ifdef USE_WS2812 // ************************************************************************
default:
if (LT_WS2812 == light_type) {
Ws2812ShowScheme(Settings.light_scheme -LS_MAX);
}
#endif // USE_WS2812 ************************************************************************
XlgtCall(FUNC_SET_SCHEME);
}
}
@ -1860,11 +1819,6 @@ void LightAnimate(void)
else if (XdrvCall(FUNC_SET_CHANNELS)) {
// Serviced
}
#ifdef USE_WS2812 // ************************************************************************
else if (LT_WS2812 == light_type) {
Ws2812SetColor(0, cur_col[0], cur_col[1], cur_col[2], cur_col[3]);
}
#endif // USE_ES2812 ************************************************************************
XdrvMailbox.data = tmp_data;
XdrvMailbox.data_len = tmp_data_len;
}
@ -1882,7 +1836,7 @@ void calcGammaCTPwm(uint8_t cur_col[5], uint16_t cur_col_10bits[5]) {
// overall brightness
uint16_t pxBri = cur_col[cw0] + cur_col[cw1];
if (pxBri > 255) { pxBri = 255; }
cur_col[cw1] = changeUIntScale(cold, 0, cold + warm, 0, 255); //
cur_col[cw1] = changeUIntScale(cold, 0, cold + warm, 0, 255); //
cur_col_10bits[cw1] = changeUIntScale(cur_col[cw1], 0, 255, 0, 1023);
// channel 0=intensity, channel1=temperature
if (Settings.light_correction) { // gamma correction
@ -2169,76 +2123,11 @@ void CmndHsbColor(void)
}
}
#ifdef USE_WS2812 // ***********************************************************************
void CmndLed(void)
{
if ((LT_WS2812 == light_type) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= Settings.light_pixels)) {
if (XdrvMailbox.data_len > 0) {
char *p;
uint16_t idx = XdrvMailbox.index;
Ws2812ForceSuspend();
for (char *color = strtok_r(XdrvMailbox.data, " ", &p); color; color = strtok_r(nullptr, " ", &p)) {
if (LightColorEntry(color, strlen(color))) {
Ws2812SetColor(idx, Light.entry_color[0], Light.entry_color[1], Light.entry_color[2], Light.entry_color[3]);
idx++;
if (idx > Settings.light_pixels) { break; }
} else {
break;
}
}
Ws2812ForceUpdate();
}
char scolor[LIGHT_COLOR_SIZE];
ResponseCmndIdxChar(Ws2812GetColor(XdrvMailbox.index, scolor));
}
}
void CmndPixels(void)
{
if (LT_WS2812 == light_type) {
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= WS2812_MAX_LEDS)) {
Settings.light_pixels = XdrvMailbox.payload;
Settings.light_rotation = 0;
Ws2812Clear();
Light.update = true;
}
ResponseCmndNumber(Settings.light_pixels);
}
}
void CmndRotation(void)
{
if (LT_WS2812 == light_type) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < Settings.light_pixels)) {
Settings.light_rotation = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.light_rotation);
}
}
void CmndWidth(void)
{
if ((LT_WS2812 == light_type) && (XdrvMailbox.index > 0) && (XdrvMailbox.index <= 4)) {
if (1 == XdrvMailbox.index) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 4)) {
Settings.light_width = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.light_width);
} else {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32)) {
Settings.ws_width[XdrvMailbox.index -2] = XdrvMailbox.payload;
}
ResponseCmndIdxNumber(Settings.ws_width[XdrvMailbox.index -2]);
}
}
}
#endif // USE_WS2812 ************************************************************************
void CmndScheme(void)
{
if (Light.subtype >= LST_RGB) {
uint32_t max_scheme = (LT_WS2812 == light_type) ? LS_MAX + WS2812_SCHEMES : LS_MAX -1;
uint32_t max_scheme = Light.max_scheme;
if (1 == XdrvMailbox.data_len) {
if (('+' == XdrvMailbox.data[0]) && (Settings.light_scheme < max_scheme)) {
XdrvMailbox.payload = Settings.light_scheme + ((0 == Settings.light_scheme) ? 2 : 1); // Skip wakeup
@ -2435,6 +2324,9 @@ bool Xdrv04(uint8_t function)
break;
case FUNC_COMMAND:
result = DecodeCommand(kLightCommands, LightCommand);
if (!result) {
result = XlgtCall(FUNC_COMMAND);
}
break;
case FUNC_PRE_INIT:
LightInit();

View File

@ -1,7 +1,7 @@
/*
xplg_ws2812.ino - ws2812 led string support for Sonoff-Tasmota
xlgt_01_ws2812.ino - led string support for Sonoff-Tasmota
Copyright (C) 2019 Heiko Krupp and Theo Arends
Copyright (C) 2019 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,8 +21,30 @@
#ifdef USE_WS2812
/*********************************************************************************************\
* WS2812 RGB / RGBW Leds using NeopixelBus library
*
* light_scheme WS2812 3+ Colors 1+2 Colors Effect
* ------------ ------ --------- ---------- -----------------
* 0 yes no no Clock
* 1 yes no no Incandescent
* 2 yes no no RGB
* 3 yes no no Christmas
* 4 yes no no Hanukkah
* 5 yes no no Kwanzaa
* 6 yes no no Rainbow
* 7 yes no no Fire
*
\*********************************************************************************************/
#define XLGT_01 1
const uint8_t WS2812_SCHEMES = 8; // Number of WS2812 schemes
const char kWs2812Commands[] PROGMEM = "|" // No prefix
D_CMND_LED "|" D_CMND_PIXELS "|" D_CMND_ROTATION "|" D_CMND_WIDTH ;
void (* const Ws2812Command[])(void) PROGMEM = {
&CmndLed, &CmndPixels, &CmndRotation, &CmndWidth };
#include <NeoPixelBus.h>
#if (USE_WS2812_CTYPE == NEO_GRB)
@ -83,7 +105,7 @@ WsColor kHanukkah[2] = { 0,0,255, 255,255,255 };
WsColor kwanzaa[3] = { 255,0,0, 0,0,0, 0,255,0 };
WsColor kRainbow[7] = { 255,0,0, 255,128,0, 255,255,0, 0,255,0, 0,0,255, 128,0,255, 255,0,255 };
WsColor kFire[3] = { 255,0,0, 255,102,0, 255,192,0 };
ColorScheme kSchemes[WS2812_SCHEMES] = {
ColorScheme kSchemes[WS2812_SCHEMES -1] = { // Skip clock scheme
kIncandescent, 2,
kRgb, 3,
kChristmas, 2,
@ -105,8 +127,11 @@ uint8_t kWsRepeat[5] = {
2, // Largest
1 }; // All
uint8_t ws_show_next = 1;
bool ws_suspend_update = false;
struct WS2812 {
uint8_t show_next = 1;
uint8_t scheme_offset = 0;
bool suspend_update = false;
} Ws2812;
/********************************************************************************************/
@ -313,23 +338,11 @@ void Ws2812Bars(uint32_t schemenr)
Ws2812StripShow();
}
/*********************************************************************************************\
* Public
\*********************************************************************************************/
void Ws2812Init(void)
{
// For DMA, the Pin is ignored as it uses GPIO3 due to DMA hardware use.
strip = new NeoPixelBus<selectedNeoFeatureType, selectedNeoSpeedType>(WS2812_MAX_LEDS, pin[GPIO_WS2812]);
strip->Begin();
Ws2812Clear();
}
void Ws2812Clear(void)
{
strip->ClearTo(0);
strip->Show();
ws_show_next = 1;
Ws2812.show_next = 1;
}
void Ws2812SetColor(uint32_t led, uint8_t red, uint8_t green, uint8_t blue, uint8_t white)
@ -353,22 +366,12 @@ void Ws2812SetColor(uint32_t led, uint8_t red, uint8_t green, uint8_t blue, uint
}
}
if (!ws_suspend_update) {
if (!Ws2812.suspend_update) {
strip->Show();
ws_show_next = 1;
Ws2812.show_next = 1;
}
}
void Ws2812ForceSuspend (void) {
ws_suspend_update = true;
}
void Ws2812ForceUpdate (void) {
ws_suspend_update = false;
strip->Show();
ws_show_next = 1;
}
char* Ws2812GetColor(uint32_t led, char* scolor)
{
uint8_t sl_ledcolor[4];
@ -393,13 +396,42 @@ char* Ws2812GetColor(uint32_t led, char* scolor)
return scolor;
}
void Ws2812ShowScheme(uint32_t scheme)
/*********************************************************************************************\
* Public - used by scripter only
\*********************************************************************************************/
void Ws2812ForceSuspend (void)
{
Ws2812.suspend_update = true;
}
void Ws2812ForceUpdate (void)
{
Ws2812.suspend_update = false;
strip->Show();
Ws2812.show_next = 1;
}
/********************************************************************************************/
bool Ws2812SetChannels(void)
{
uint8_t *cur_col = (uint8_t*)XdrvMailbox.data;
Ws2812SetColor(0, cur_col[0], cur_col[1], cur_col[2], cur_col[3]);
return true;
}
void Ws2812ShowScheme(void)
{
uint32_t scheme = Settings.light_scheme - Ws2812.scheme_offset;
switch (scheme) {
case 0: // Clock
if ((1 == state_250mS) || (ws_show_next)) {
if ((1 == state_250mS) || (Ws2812.show_next)) {
Ws2812Clock();
ws_show_next = 0;
Ws2812.show_next = 0;
}
break;
default:
@ -408,10 +440,118 @@ void Ws2812ShowScheme(uint32_t scheme)
} else {
Ws2812Bars(scheme -1);
}
ws_show_next = 1;
Ws2812.show_next = 1;
break;
}
}
void Ws2812ModuleSelected(void)
{
if (pin[GPIO_WS2812] < 99) { // RGB led
// For DMA, the Pin is ignored as it uses GPIO3 due to DMA hardware use.
strip = new NeoPixelBus<selectedNeoFeatureType, selectedNeoSpeedType>(WS2812_MAX_LEDS, pin[GPIO_WS2812]);
strip->Begin();
Ws2812Clear();
Ws2812.scheme_offset = Light.max_scheme +1;
Light.max_scheme += WS2812_SCHEMES;
#if (USE_WS2812_CTYPE > NEO_3LED)
light_type = LT_RGBW;
#else
light_type = LT_RGB;
#endif
light_flg = XLGT_01;
}
}
/********************************************************************************************/
void CmndLed(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= Settings.light_pixels)) {
if (XdrvMailbox.data_len > 0) {
char *p;
uint16_t idx = XdrvMailbox.index;
Ws2812ForceSuspend();
for (char *color = strtok_r(XdrvMailbox.data, " ", &p); color; color = strtok_r(nullptr, " ", &p)) {
if (LightColorEntry(color, strlen(color))) {
Ws2812SetColor(idx, Light.entry_color[0], Light.entry_color[1], Light.entry_color[2], Light.entry_color[3]);
idx++;
if (idx > Settings.light_pixels) { break; }
} else {
break;
}
}
Ws2812ForceUpdate();
}
char scolor[LIGHT_COLOR_SIZE];
ResponseCmndIdxChar(Ws2812GetColor(XdrvMailbox.index, scolor));
}
}
void CmndPixels(void)
{
if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= WS2812_MAX_LEDS)) {
Settings.light_pixels = XdrvMailbox.payload;
Settings.light_rotation = 0;
Ws2812Clear();
Light.update = true;
}
ResponseCmndNumber(Settings.light_pixels);
}
void CmndRotation(void)
{
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < Settings.light_pixels)) {
Settings.light_rotation = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.light_rotation);
}
void CmndWidth(void)
{
if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 4)) {
if (1 == XdrvMailbox.index) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 4)) {
Settings.light_width = XdrvMailbox.payload;
}
ResponseCmndNumber(Settings.light_width);
} else {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 32)) {
Settings.ws_width[XdrvMailbox.index -2] = XdrvMailbox.payload;
}
ResponseCmndIdxNumber(Settings.ws_width[XdrvMailbox.index -2]);
}
}
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
bool Xlgt01(uint8_t function)
{
bool result = false;
switch (function) {
case FUNC_SET_CHANNELS:
result = Ws2812SetChannels();
break;
case FUNC_SET_SCHEME:
Ws2812ShowScheme();
break;
case FUNC_COMMAND:
result = DecodeCommand(kWs2812Commands, Ws2812Command);
break;
case FUNC_MODULE_INIT:
Ws2812ModuleSelected();
break;
}
return result;
}
#endif // USE_WS2812
#endif // USE_LIGHT
#endif // USE_LIGHT