diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h
index 631ddfc7c..a4864c61f 100644
--- a/sonoff/my_user_config.h
+++ b/sonoff/my_user_config.h
@@ -315,9 +315,16 @@
#define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code)
#define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer and Sonoff L1 (+2k code)
//#define ROTARY_V1 // Add support for MI Desk Lamp
-#define USE_SM2135 // Add support for SM2135 RGBCW led control (+0k6 code)
//#define USE_SHUTTER // Add Shutter support for up to 4 shutter with different motortypes (+6k code)
+// -- Optional light modules ----------------------
+#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
+// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
+ #define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106)
+ #define USE_WS2812_CTYPE NEO_GRB // Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)
+#define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code)
+#define USE_SM2135 // Add support for SM2135 RGBCW led control as used in Action LSC (+0k6 code)
+
// -- Counter input -------------------------------
#define USE_COUNTER // Enable inputs as counter (+0k8 code)
@@ -513,11 +520,6 @@
// ------------------------------------------------
-#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
-// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
- #define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106)
- #define USE_WS2812_CTYPE NEO_GRB // Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)
-
#define USE_ARILUX_RF // Add support for Arilux RF remote controller (+0k8 code, 252 iram (non 2.3.0))
#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code)
@@ -536,8 +538,6 @@
// #define USE_THEO_V2 // Add support for decoding Theo V2 sensors as documented on https://sidweb.nl using 434MHz RF sensor receiver (+1k4 code)
// #define USE_ALECTO_V2 // Add support for decoding Alecto V2 sensors like ACH2010, WS3000 and DKW2012 weather stations using 868MHz RF sensor receiver (+1k7 code)
-#define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code)
-
//#define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code)
//#define USE_A4988_Stepper // Add support for A4988 stepper-motor-driver-circuit (+10k5 code)
diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino
index 8f0627b1b..df7de51ec 100755
--- a/sonoff/sonoff.ino
+++ b/sonoff/sonoff.ino
@@ -130,6 +130,7 @@ uint8_t led_power = 0; // LED power state
uint8_t ledlnk_inverted = 0; // Link LED inverted flag (1 = (0 = On, 1 = Off))
uint8_t pwm_inverted = 0; // PWM inverted flag (1 = inverted)
uint8_t energy_flg = 0; // Energy monitor configured
+uint8_t light_flg = 0; // Light module configured
uint8_t light_type = 0; // Light types
uint8_t serial_in_byte; // Received byte
uint8_t ota_retry_counter = OTA_ATTEMPTS; // OTA retry counter
@@ -1391,14 +1392,6 @@ void GpioInit(void)
devices_present = 1;
light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0
-#ifdef USE_LIGHT
- if (Settings.flag.pwm_control) {
- for (uint32_t i = 0; i < MAX_PWMS; i++) {
- if (pin[GPIO_PWM1 +i] < 99) { light_type++; } // Use Dimmer/Color control for all PWM as SetOption15 = 1
- }
- }
-#endif // USE_LIGHT
-
if (XdrvCall(FUNC_MODULE_INIT)) {
// Serviced
}
@@ -1420,30 +1413,24 @@ void GpioInit(void)
devices_present = 0;
baudrate = 19200;
}
-#ifdef USE_LIGHT
- else if (SONOFF_BN == my_module_type) { // PWM Single color led (White)
- light_type = LT_PWM1;
+
+ if (!light_type) {
+ devices_present = 0;
+ for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
+ if (pin[GPIO_PWM1 +i] < 99) {
+ pwm_present = true;
+ pinMode(pin[GPIO_PWM1 +i], OUTPUT);
+ analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - Settings.pwm_value[i] : Settings.pwm_value[i]);
+ }
+ }
}
- else if (SONOFF_LED == my_module_type) { // PWM Dual color led (White warm and cold)
- light_type = LT_PWM2;
- }
- else if (AILIGHT == my_module_type) { // RGBW led
- light_type = LT_RGBW;
- }
- else if (SONOFF_B1 == my_module_type) { // RGBWC led
- light_type = LT_RGBWC;
- }
-#endif // USE_LIGHT
- else {
- if (!light_type) { devices_present = 0; }
- for (uint32_t i = 0; i < MAX_RELAYS; i++) {
- if (pin[GPIO_REL1 +i] < 99) {
- pinMode(pin[GPIO_REL1 +i], OUTPUT);
- devices_present++;
- if (EXS_RELAY == my_module_type) {
- digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0);
- if (i &1) { devices_present--; }
- }
+ for (uint32_t i = 0; i < MAX_RELAYS; i++) {
+ if (pin[GPIO_REL1 +i] < 99) {
+ pinMode(pin[GPIO_REL1 +i], OUTPUT);
+ devices_present++;
+ if (EXS_RELAY == my_module_type) {
+ digitalWrite(pin[GPIO_REL1 +i], bitRead(rel_inverted, i) ? 1 : 0);
+ if (i &1) { devices_present--; }
}
}
}
@@ -1475,37 +1462,6 @@ void GpioInit(void)
RotaryInit();
#endif
-#ifdef USE_LIGHT
-#ifdef USE_WS2812
- if (!light_type && (pin[GPIO_WS2812] < 99)) { // RGB led
- devices_present++;
- light_type = LT_WS2812;
- }
-#endif // USE_WS2812
-#ifdef USE_SM16716
- if (SM16716_ModuleSelected()) {
- light_type += 3;
- light_type |= LT_SM16716;
- }
-#endif // USE_SM16716
-
- // post-process for lights
- if (Settings.flag3.pwm_multi_channels) {
- uint32_t pwm_channels = (light_type & 7) > LST_MAX ? LST_MAX : (light_type & 7);
- if (0 == pwm_channels) { pwm_channels = 1; }
- devices_present += pwm_channels - 1; // add the pwm channels controls at the end
- }
-#endif // USE_LIGHT
- if (!light_type) {
- for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only
- if (pin[GPIO_PWM1 +i] < 99) {
- pwm_present = true;
- pinMode(pin[GPIO_PWM1 +i], OUTPUT);
- analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - Settings.pwm_value[i] : Settings.pwm_value[i]);
- }
- }
- }
-
SetLedPower(Settings.ledstate &8);
SetLedLink(Settings.ledstate &8);
diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino
index e1cc82418..0b9df7205 100644
--- a/sonoff/xdrv_04_light.ino
+++ b/sonoff/xdrv_04_light.ino
@@ -257,6 +257,7 @@ struct LIGHT {
uint8_t wakeup_active = 0;
uint8_t wakeup_dimmer = 0;
uint8_t fixed_color_index = 1;
+ uint8_t pwm_offset = 0; // Offset in color buffer
bool update = true;
bool pwm_multi_channels = false; // SetOption68, treat each PWM channel as an independant dimmer
@@ -1269,102 +1270,66 @@ void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t dut
os_delay_us(12); // TStop > 12us.
}
-#ifdef USE_SM16716
-/*********************************************************************************************\
- * SM16716 - Controlling RGB over a synchronous serial line
- * Copyright (C) 2019 Gabor Simon
- *
- * Source: https://community.home-assistant.io/t/cheap-uk-wifi-bulbs-with-tasmota-teardown-help-tywe3s/40508/27
- *
-\*********************************************************************************************/
-
-#define D_LOG_SM16716 "SM16716: "
-
-uint8_t sm16716_pin_clk = 100;
-uint8_t sm16716_pin_dat = 100;
-uint8_t sm16716_pin_sel = 100;
-uint8_t sm16716_enabled = 0;
-
-void SM16716_SendBit(uint8_t v)
-{
- /* NOTE:
- * According to the spec sheet, max freq is 30 MHz, that is 16.6 ns per high/low half of the
- * clk square wave. That is less than the overhead of 'digitalWrite' at this clock rate,
- * so no additional delays are needed yet. */
-
- digitalWrite(sm16716_pin_dat, (v != 0) ? HIGH : LOW);
- //delayMicroseconds(1);
- digitalWrite(sm16716_pin_clk, HIGH);
- //delayMicroseconds(1);
- digitalWrite(sm16716_pin_clk, LOW);
-}
-
-void SM16716_SendByte(uint8_t v)
-{
- uint8_t mask;
-
- for (mask = 0x80; mask; mask >>= 1) {
- SM16716_SendBit(v & mask);
- }
-}
-
-void SM16716_Update(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b)
-{
- if (sm16716_pin_sel < 99) {
- uint8_t sm16716_should_enable = (duty_r | duty_g | duty_b);
- if (!sm16716_enabled && sm16716_should_enable) {
- DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color on"));
- sm16716_enabled = 1;
- digitalWrite(sm16716_pin_sel, HIGH);
- // in testing I found it takes a minimum of ~380us to wake up the chip
- // tested on a Merkury RGBW with an SM726EB
- delayMicroseconds(1000);
- SM16716_Init();
- }
- else if (sm16716_enabled && !sm16716_should_enable) {
- DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color off"));
- sm16716_enabled = 0;
- digitalWrite(sm16716_pin_sel, LOW);
- }
- }
- DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "Update; rgb=%02x%02x%02x"), duty_r, duty_g, duty_b);
-
- // send start bit
- SM16716_SendBit(1);
- SM16716_SendByte(duty_r);
- SM16716_SendByte(duty_g);
- SM16716_SendByte(duty_b);
-
- // send a 'do it' pulse
- // (if multiple chips are chained, each one processes the 1st '1rgb' 25-bit block and
- // passes on the rest, right until the one starting with 0)
- //SM16716_Init();
- SM16716_SendBit(0);
- SM16716_SendByte(0);
- SM16716_SendByte(0);
- SM16716_SendByte(0);
-}
-
-bool SM16716_ModuleSelected(void)
-{
- sm16716_pin_clk = pin[GPIO_SM16716_CLK];
- sm16716_pin_dat = pin[GPIO_SM16716_DAT];
- sm16716_pin_sel = pin[GPIO_SM16716_SEL];
- DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "ModuleSelected; clk_pin=%d, dat_pin=%d)"), sm16716_pin_clk, sm16716_pin_dat);
- return (sm16716_pin_clk < 99) && (sm16716_pin_dat < 99);
-}
-
-void SM16716_Init(void)
-{
- for (uint32_t t_init = 0; t_init < 50; ++t_init) {
- SM16716_SendBit(0);
- }
-}
-
-#endif // ifdef USE_SM16716
-
/********************************************************************************************/
+void LightPwmOffset(uint32_t offset)
+{
+ Light.pwm_offset = offset;
+}
+
+bool LightModuleInit(void)
+{
+ light_type = LT_BASIC; // Use basic PWM control if SetOption15 = 0
+
+ if (Settings.flag.pwm_control) {
+ for (uint32_t i = 0; i < MAX_PWMS; i++) {
+ if (pin[GPIO_PWM1 +i] < 99) { light_type++; } // Use Dimmer/Color control for all PWM as SetOption15 = 1
+ }
+ }
+
+ light_flg = 0;
+ if (XlgtCall(FUNC_MODULE_INIT)) {
+ // serviced
+ }
+ else if (SONOFF_BN == my_module_type) { // PWM Single color led (White)
+ light_type = LT_PWM1;
+ }
+ else if (SONOFF_LED == my_module_type) { // PWM Dual color led (White warm and cold)
+ if (!my_module.io[4]) { // Fix Sonoff Led instabilities
+ pinMode(4, OUTPUT); // Stop floating outputs
+ digitalWrite(4, LOW);
+ }
+ if (!my_module.io[5]) {
+ pinMode(5, OUTPUT); // Stop floating outputs
+ digitalWrite(5, LOW);
+ }
+ if (!my_module.io[14]) {
+ pinMode(14, OUTPUT); // Stop floating outputs
+ digitalWrite(14, LOW);
+ }
+ light_type = LT_PWM2;
+ }
+ else if (AILIGHT == my_module_type) { // RGBW led
+ light_type = LT_RGBW;
+ }
+ else if (SONOFF_B1 == my_module_type) { // RGBWC led
+ light_type = LT_RGBWC;
+ }
+#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);
+ if (0 == pwm_channels) { pwm_channels = 1; }
+ devices_present += pwm_channels - 1; // add the pwm channels controls at the end
+ }
+
+ return (light_type > 0);
+}
+
void LightInit(void)
{
uint8_t max_scheme = LS_MAX -1;
@@ -1402,20 +1367,6 @@ void LightInit(void)
pinMode(pin[GPIO_PWM1 +i], OUTPUT);
}
}
- if (SONOFF_LED == my_module_type) { // Fix Sonoff Led instabilities
- if (!my_module.io[4]) {
- pinMode(4, OUTPUT); // Stop floating outputs
- digitalWrite(4, LOW);
- }
- if (!my_module.io[5]) {
- pinMode(5, OUTPUT); // Stop floating outputs
- digitalWrite(5, LOW);
- }
- if (!my_module.io[14]) {
- pinMode(14, OUTPUT); // Stop floating outputs
- digitalWrite(14, LOW);
- }
- }
if (pin[GPIO_ARIRFRCV] < 99) {
if (pin[GPIO_ARIRFSEL] < 99) {
pinMode(pin[GPIO_ARIRFSEL], OUTPUT);
@@ -1429,32 +1380,6 @@ void LightInit(void)
max_scheme = LS_MAX + WS2812_SCHEMES;
}
#endif // USE_WS2812 ************************************************************************
-#ifdef USE_SM16716
- else if (LT_SM16716 == light_type - Light.subtype) {
- // init PWM
- for (uint32_t i = 0; i < Light.subtype; i++) {
- Settings.pwm_value[i] = 0; // Disable direct PWM control
- if (pin[GPIO_PWM1 +i] < 99) {
- pinMode(pin[GPIO_PWM1 +i], OUTPUT);
- }
- }
- // init sm16716
- pinMode(sm16716_pin_clk, OUTPUT);
- digitalWrite(sm16716_pin_clk, LOW);
-
- pinMode(sm16716_pin_dat, OUTPUT);
- digitalWrite(sm16716_pin_dat, LOW);
-
- if (sm16716_pin_sel < 99) {
- pinMode(sm16716_pin_sel, OUTPUT);
- digitalWrite(sm16716_pin_sel, LOW);
- // no need to call SM16716_Init here, it will be called after sel goes HIGH
- } else {
- // no sel pin means you have an 'always on' chip, so init right away
- SM16716_Init();
- }
- }
-#endif // ifdef USE_SM16716
else {
light_pdi_pin = pin[GPIO_DI];
light_pdcki_pin = pin[GPIO_DCKI];
@@ -2001,10 +1926,10 @@ void LightAnimate(void)
// now apply the actual PWM values, adjusted and remapped 10-bits range
if (light_type < LT_PWM6) { // only for direct PWM lights, not for Tuya, Armtronix...
- for (uint32_t i = 0; i < Light.subtype; i++) {
+ for (uint32_t i = 0; i < (Light.subtype - Light.pwm_offset); i++) {
if (pin[GPIO_PWM1 +i] < 99) {
//AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d 10 bits %d, Pwm%d %d"), i, cur_col_10bits[i], i+1, cur_col[i]);
- analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - cur_col_10bits[i] : cur_col_10bits[i]);
+ analogWrite(pin[GPIO_PWM1 +i], bitRead(pwm_inverted, i) ? Settings.pwm_range - cur_col_10bits[(i + Light.pwm_offset)] : cur_col_10bits[(i + Light.pwm_offset)]);
}
}
}
@@ -2018,7 +1943,10 @@ void LightAnimate(void)
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "R%d G%d B%d, C%d W%d"),
cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
- if (XdrvCall(FUNC_SET_CHANNELS)) {
+ if (XlgtCall(FUNC_SET_CHANNELS)) {
+ // Serviced
+ }
+ else if (XdrvCall(FUNC_SET_CHANNELS)) {
// Serviced
}
#ifdef USE_WS2812 // ************************************************************************
@@ -2026,19 +1954,6 @@ void LightAnimate(void)
Ws2812SetColor(0, cur_col[0], cur_col[1], cur_col[2], cur_col[3]);
}
#endif // USE_ES2812 ************************************************************************
-#ifdef USE_SM16716
- else if (LT_SM16716 == light_type - Light.subtype) {
- // handle any PWM pins, skipping the first 3 values for sm16716
- for (uint32_t i = 3; i < Light.subtype; i++) {
- if (pin[GPIO_PWM1 +i-3] < 99) {
- //AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d 10 bits %d, Pwm%d %d"), i, cur_col[i], i+1, curcol);
- analogWrite(pin[GPIO_PWM1 +i-3], bitRead(pwm_inverted, i-3) ? Settings.pwm_range - cur_col_10bits[i] : cur_col_10bits[i]);
- }
- }
- // handle sm16716 update
- SM16716_Update(cur_col[0], cur_col[1], cur_col[2]);
- }
-#endif // ifdef USE_SM16716
else if (light_type > LT_WS2812) {
//AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_APPLICATION "Cur_Col %d,%d,%d,%d,%d"), cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]);
@@ -2588,11 +2503,11 @@ bool Xdrv04(uint8_t function)
{
bool result = false;
- if (light_type) {
+ if (FUNC_MODULE_INIT == function) {
+ return LightModuleInit();
+ }
+ else if (light_type) {
switch (function) {
- case FUNC_PRE_INIT:
- LightInit();
- break;
case FUNC_EVERY_50_MSECOND:
LightAnimate();
#ifdef USE_ARILUX_RF
@@ -2610,6 +2525,9 @@ bool Xdrv04(uint8_t function)
case FUNC_COMMAND:
result = DecodeCommand(kLightCommands, LightCommand);
break;
+ case FUNC_PRE_INIT:
+ LightInit();
+ break;
}
}
return result;
diff --git a/sonoff/xlgt_03_sm16716.ino b/sonoff/xlgt_03_sm16716.ino
new file mode 100644
index 000000000..d12636e85
--- /dev/null
+++ b/sonoff/xlgt_03_sm16716.ino
@@ -0,0 +1,200 @@
+/*
+ xlgt_03_sm16716.ino - sm16716 three channel led support for Sonoff-Tasmota
+
+ 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifdef USE_LIGHT
+#ifdef USE_SM16716
+/*********************************************************************************************\
+ * SM16716 - Controlling RGB over a synchronous serial line
+ * Copyright (C) 2019 Gabor Simon
+ *
+ * Source: https://community.home-assistant.io/t/cheap-uk-wifi-bulbs-with-tasmota-teardown-help-tywe3s/40508/27
+\*********************************************************************************************/
+
+#define XLGT_03 3
+
+#define D_LOG_SM16716 "SM16716: "
+
+struct SM16716 {
+ uint8_t pin_clk = 0;
+ uint8_t pin_dat = 0;
+ uint8_t pin_sel = 0;
+ bool enabled = false;
+} Sm16716;
+
+void SM16716_SendBit(uint8_t v)
+{
+ /* NOTE:
+ * According to the spec sheet, max freq is 30 MHz, that is 16.6 ns per high/low half of the
+ * clk square wave. That is less than the overhead of 'digitalWrite' at this clock rate,
+ * so no additional delays are needed yet. */
+
+ digitalWrite(Sm16716.pin_dat, (v != 0) ? HIGH : LOW);
+ //delayMicroseconds(1);
+ digitalWrite(Sm16716.pin_clk, HIGH);
+ //delayMicroseconds(1);
+ digitalWrite(Sm16716.pin_clk, LOW);
+}
+
+void SM16716_SendByte(uint8_t v)
+{
+ uint8_t mask;
+
+ for (mask = 0x80; mask; mask >>= 1) {
+ SM16716_SendBit(v & mask);
+ }
+}
+
+void SM16716_Update(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b)
+{
+ if (Sm16716.pin_sel < 99) {
+ bool should_enable = (duty_r | duty_g | duty_b);
+ if (!Sm16716.enabled && should_enable) {
+ DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color on"));
+ Sm16716.enabled = true;
+ digitalWrite(Sm16716.pin_sel, HIGH);
+ // in testing I found it takes a minimum of ~380us to wake up the chip
+ // tested on a Merkury RGBW with an SM726EB
+ delayMicroseconds(1000);
+ SM16716_Init();
+ }
+ else if (Sm16716.enabled && !should_enable) {
+ DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "turning color off"));
+ Sm16716.enabled = false;
+ digitalWrite(Sm16716.pin_sel, LOW);
+ }
+ }
+ DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "Update; rgb=%02x%02x%02x"), duty_r, duty_g, duty_b);
+
+ // send start bit
+ SM16716_SendBit(1);
+ SM16716_SendByte(duty_r);
+ SM16716_SendByte(duty_g);
+ SM16716_SendByte(duty_b);
+
+ // send a 'do it' pulse
+ // (if multiple chips are chained, each one processes the 1st '1rgb' 25-bit block and
+ // passes on the rest, right until the one starting with 0)
+ //SM16716_Init();
+ SM16716_SendBit(0);
+ SM16716_SendByte(0);
+ SM16716_SendByte(0);
+ SM16716_SendByte(0);
+}
+
+/*
+bool SM16716_ModuleSelected(void)
+{
+ Sm16716.pin_clk = pin[GPIO_SM16716_CLK];
+ Sm16716.pin_dat = pin[GPIO_SM16716_DAT];
+ Sm16716.pin_sel = pin[GPIO_SM16716_SEL];
+ DEBUG_DRIVER_LOG(PSTR(D_LOG_SM16716 "ModuleSelected; clk_pin=%d, dat_pin=%d)"), Sm16716.pin_clk, Sm16716.pin_dat);
+ return (Sm16716.pin_clk < 99) && (Sm16716.pin_dat < 99);
+}
+*/
+
+void SM16716_Init(void)
+{
+ for (uint32_t t_init = 0; t_init < 50; ++t_init) {
+ SM16716_SendBit(0);
+ }
+}
+
+/********************************************************************************************/
+
+bool Sm16716SetChannels(void)
+{
+/*
+ // handle any PWM pins, skipping the first 3 values for sm16716
+ for (uint32_t i = 3; i < Light.subtype; i++) {
+ if (pin[GPIO_PWM1 +i-3] < 99) {
+ //AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_APPLICATION "Cur_Col%d 10 bits %d, Pwm%d %d"), i, cur_col[i], i+1, curcol);
+ analogWrite(pin[GPIO_PWM1 +i-3], bitRead(pwm_inverted, i-3) ? Settings.pwm_range - cur_col_10bits[i] : cur_col_10bits[i]);
+ }
+ }
+*/
+ // handle sm16716 update
+ uint8_t *cur_col = (uint8_t*)XdrvMailbox.data;
+
+ SM16716_Update(cur_col[0], cur_col[1], cur_col[2]);
+
+ return true;
+}
+
+void Sm16716ModuleSelected(void)
+{
+ if ((pin[GPIO_SM16716_CLK] < 99) && (pin[GPIO_SM16716_DAT] < 99)) {
+ Sm16716.pin_clk = pin[GPIO_SM16716_CLK];
+ Sm16716.pin_dat = pin[GPIO_SM16716_DAT];
+ Sm16716.pin_sel = pin[GPIO_SM16716_SEL];
+
+/*
+ // init PWM
+ for (uint32_t i = 0; i < Light.subtype; i++) {
+ Settings.pwm_value[i] = 0; // Disable direct PWM control
+ if (pin[GPIO_PWM1 +i] < 99) {
+ pinMode(pin[GPIO_PWM1 +i], OUTPUT);
+ }
+ }
+*/
+
+ // init sm16716
+ pinMode(Sm16716.pin_clk, OUTPUT);
+ digitalWrite(Sm16716.pin_clk, LOW);
+
+ pinMode(Sm16716.pin_dat, OUTPUT);
+ digitalWrite(Sm16716.pin_dat, LOW);
+
+ if (Sm16716.pin_sel < 99) {
+ pinMode(Sm16716.pin_sel, OUTPUT);
+ digitalWrite(Sm16716.pin_sel, LOW);
+ // no need to call SM16716_Init here, it will be called after sel goes HIGH
+ } else {
+ // no sel pin means you have an 'always on' chip, so init right away
+ SM16716_Init();
+ }
+
+ LightPwmOffset(LST_RGB); // Handle any PWM pins, skipping the first 3 color values for sm16716
+ light_type += LST_RGB; // Add RGB to be controlled by sm16716
+ light_flg = XLGT_03;
+ AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: SM16716 Found"));
+ }
+}
+
+/*********************************************************************************************\
+ * Interface
+\*********************************************************************************************/
+
+bool Xlgt03(uint8_t function)
+{
+ bool result = false;
+
+ switch (function) {
+ case FUNC_SET_CHANNELS:
+ result = Sm16716SetChannels();
+ break;
+ case FUNC_MODULE_INIT:
+ Sm16716ModuleSelected();
+ break;
+ }
+ return result;
+}
+
+#endif // USE_SM16716
+#endif // USE_LIGHT
+
diff --git a/sonoff/xdrv_26_sm2135.ino b/sonoff/xlgt_04_sm2135.ino
similarity index 81%
rename from sonoff/xdrv_26_sm2135.ino
rename to sonoff/xlgt_04_sm2135.ino
index a54a6ccb8..21755d656 100644
--- a/sonoff/xdrv_26_sm2135.ino
+++ b/sonoff/xlgt_04_sm2135.ino
@@ -1,5 +1,5 @@
/*
- xdrv_26_sm2135.ino - sm2135 five channel led support for Sonoff-Tasmota
+ xlgt_04_sm2135.ino - sm2135 five channel led support for Sonoff-Tasmota
Copyright (C) 2019 Theo Arends
@@ -25,7 +25,7 @@
* {"NAME":"LSC RGBCW LED","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18}
\*********************************************************************************************/
-#define XDRV_26 26
+#define XLGT_04 4
#define SM2135_ADDR_MC 0xC0 // Max current register
#define SM2135_ADDR_CH 0xC1 // RGB or CW channel select register
@@ -56,7 +56,6 @@ const uint8_t SM2135_CURRENT = (SM2135_20MA << 4) | SM2135_10MA;
struct SM2135 {
uint8_t clk = 0;
uint8_t data = 0;
- bool found = true;
} Sm2135;
uint8_t Sm2135Write(uint8_t data)
@@ -87,19 +86,21 @@ void Sm2135Send(uint8_t *buffer, uint8_t size)
digitalWrite(Sm2135.data, HIGH);
}
+/********************************************************************************************/
+
bool Sm2135SetChannels(void)
{
- char *buffer = XdrvMailbox.data;
- uint8_t data[8];
+ uint8_t *cur_col = (uint8_t*)XdrvMailbox.data;
+ uint8_t data[6];
- if (('\0' == buffer[0]) && ('\0' == buffer[1]) && ('\0' == buffer[2])) {
+ if ((0 == cur_col[0]) && (0 == cur_col[1]) && (0 == cur_col[2])) {
// No color so must be Cold/Warm
/*
- if ((buffer[3] + buffer[4]) >= (1 * 256)) {
+ if ((cur_col[3] + cur_col[4]) >= (1 * 256)) {
// Scale down to 255 total to fix max power usage of 9W (=40mA)
-// buffer[3] >>= 1; // Divide by 2
-// buffer[4] >>= 1; // Divide by 2
+// cur_col[3] >>= 1; // Divide by 2
+// cur_col[4] >>= 1; // Divide by 2
}
*/
data[0] = SM2135_ADDR_MC;
@@ -108,13 +109,13 @@ bool Sm2135SetChannels(void)
Sm2135Send(data, 3);
delay(1);
data[0] = SM2135_ADDR_C;
- data[1] = buffer[4]; // Warm
- data[2] = buffer[3]; // Cold
+ data[1] = cur_col[4]; // Warm
+ data[2] = cur_col[3]; // Cold
Sm2135Send(data, 3);
} else {
// Color
/*
- if ((buffer[0] + buffer[1] + buffer[2]) >= (3 * 256)) {
+ if ((cur_col[0] + cur_col[1] + cur_col[2]) >= (3 * 256)) {
// Scale down to 765 total to fix max power usage of 9W
// Currently not needed with setting 3 x 15mA = 45mA = 11W = 765
}
@@ -122,16 +123,16 @@ bool Sm2135SetChannels(void)
data[0] = SM2135_ADDR_MC;
data[1] = SM2135_CURRENT;
data[2] = SM2135_RGB;
- data[3] = buffer[1]; // Green
- data[4] = buffer[0]; // Red
- data[5] = buffer[2]; // Blue
+ data[3] = cur_col[1]; // Green
+ data[4] = cur_col[0]; // Red
+ data[5] = cur_col[2]; // Blue
Sm2135Send(data, 6);
}
return true;
}
-bool Sm2135ModuleSelected(void)
+void Sm2135ModuleSelected(void)
{
if ((pin[GPIO_SM2135_CLK] < 99) && (pin[GPIO_SM2135_DAT] < 99)) {
Sm2135.clk = pin[GPIO_SM2135_CLK];
@@ -143,30 +144,26 @@ bool Sm2135ModuleSelected(void)
digitalWrite(Sm2135.clk, HIGH);
light_type = LT_RGBWC;
+ light_flg = XLGT_04;
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: SM2135 Found"));
- } else {
- Sm2135.found = false;
}
- return Sm2135.found;
}
/*********************************************************************************************\
* Interface
\*********************************************************************************************/
-bool Xdrv26(uint8_t function)
+bool Xlgt04(uint8_t function)
{
bool result = false;
- if (Sm2135.found) {
- switch (function) {
- case FUNC_SET_CHANNELS:
- result = Sm2135SetChannels();
- break;
- case FUNC_MODULE_INIT:
- result = Sm2135ModuleSelected();
- break;
- }
+ switch (function) {
+ case FUNC_SET_CHANNELS:
+ result = Sm2135SetChannels();
+ break;
+ case FUNC_MODULE_INIT:
+ Sm2135ModuleSelected();
+ break;
}
return result;
}
diff --git a/sonoff/xlgt_interface.ino b/sonoff/xlgt_interface.ino
new file mode 100644
index 000000000..cb963dc5c
--- /dev/null
+++ b/sonoff/xlgt_interface.ino
@@ -0,0 +1,114 @@
+/*
+ xlgt_interface.ino - Light driver interface support for Sonoff-Tasmota
+
+ 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
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+*/
+
+#ifdef USE_LIGHT
+
+#ifdef XFUNC_PTR_IN_ROM
+bool (* const xlgt_func_ptr[])(uint8_t) PROGMEM = { // Light driver Function Pointers
+#else
+bool (* const xlgt_func_ptr[])(uint8_t) = { // Light driver Function Pointers
+#endif
+
+#ifdef XLGT_01
+ &Xlgt01,
+#endif
+
+#ifdef XLGT_02
+ &Xlgt02,
+#endif
+
+#ifdef XLGT_03
+ &Xlgt03,
+#endif
+
+#ifdef XLGT_04
+ &Xlgt04,
+#endif
+
+#ifdef XLGT_05
+ &Xlgt05,
+#endif
+
+#ifdef XLGT_06
+ &Xlgt06,
+#endif
+
+#ifdef XLGT_07
+ &Xlgt07,
+#endif
+
+#ifdef XLGT_08
+ &Xlgt08,
+#endif
+
+#ifdef XLGT_09
+ &Xlgt09,
+#endif
+
+#ifdef XLGT_10
+ &Xlgt10,
+#endif
+
+#ifdef XLGT_11
+ &Xlgt11,
+#endif
+
+#ifdef XLGT_12
+ &Xlgt12,
+#endif
+
+#ifdef XLGT_13
+ &Xlgt13,
+#endif
+
+#ifdef XLGT_14
+ &Xlgt14,
+#endif
+
+#ifdef XLGT_15
+ &Xlgt15,
+#endif
+
+#ifdef XLGT_16
+ &Xlgt16
+#endif
+};
+
+const uint8_t xlgt_present = sizeof(xlgt_func_ptr) / sizeof(xlgt_func_ptr[0]); // Number of drivers found
+
+uint8_t xlgt_active = 0;
+
+bool XlgtCall(uint8_t function)
+{
+ if (FUNC_MODULE_INIT == function) {
+ for (uint32_t x = 0; x < xlgt_present; x++) {
+ xlgt_func_ptr[x](function);
+ if (light_flg) {
+ xlgt_active = x;
+ return true; // Stop further driver investigation
+ }
+ }
+ }
+ else if (light_flg) {
+ return xlgt_func_ptr[xlgt_active](function);
+ }
+ return false;
+}
+
+#endif // USE_LIGHT