diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index a4864c61f..ad28116cf 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -322,6 +322,7 @@ // #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_MY92X1 // Add support for MY92X1 RGBCW led controller as used in Sonoff B1, Ailight and Lohas #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) diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index b15719534..ca09fce44 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -550,8 +550,10 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_ARIRFRCV, // AriLux RF Receive input GPIO_ARIRFSEL, // Arilux RF Receive input selected #endif +#ifdef USE_MY92X1 GPIO_DI, // my92x1 PWM input GPIO_DCKI, // my92x1 CLK input +#endif // USE_MY92X1 #ifdef USE_SM16716 GPIO_SM16716_CLK, // SM16716 CLOCK GPIO_SM16716_DAT, // SM16716 DATA diff --git a/sonoff/xdrv_04_light.ino b/sonoff/xdrv_04_light.ino index 0b9df7205..07d7899eb 100644 --- a/sonoff/xdrv_04_light.ino +++ b/sonoff/xdrv_04_light.ino @@ -1185,91 +1185,6 @@ void AriluxRfDisable(void) } #endif // USE_ARILUX_RF -/*********************************************************************************************\ - * Sonoff B1 and AiLight inspired by OpenLight https://github.com/icamgo/noduino-sdk -\*********************************************************************************************/ - -extern "C" { - void os_delay_us(unsigned int); -} - -uint8_t light_pdi_pin; -uint8_t light_pdcki_pin; - -void LightDiPulse(uint8_t times) -{ - for (uint32_t i = 0; i < times; i++) { - digitalWrite(light_pdi_pin, HIGH); - digitalWrite(light_pdi_pin, LOW); - } -} - -void LightDckiPulse(uint8_t times) -{ - for (uint32_t i = 0; i < times; i++) { - digitalWrite(light_pdcki_pin, HIGH); - digitalWrite(light_pdcki_pin, LOW); - } -} - -void LightMy92x1Write(uint8_t data) -{ - for (uint32_t i = 0; i < 4; i++) { // Send 8bit Data - digitalWrite(light_pdcki_pin, LOW); - digitalWrite(light_pdi_pin, (data & 0x80)); - digitalWrite(light_pdcki_pin, HIGH); - data = data << 1; - digitalWrite(light_pdi_pin, (data & 0x80)); - digitalWrite(light_pdcki_pin, LOW); - digitalWrite(light_pdi_pin, LOW); - data = data << 1; - } -} - -void LightMy92x1Init(void) -{ - uint8_t chips = 1; // 1 (AiLight) - if (LT_RGBWC == light_type) { - chips = 2; // 2 (Sonoff B1) - } - - LightDckiPulse(chips * 32); // Clear all duty register - os_delay_us(12); // TStop > 12us. - // Send 12 DI pulse, after 6 pulse's falling edge store duty data, and 12 - // pulse's rising edge convert to command mode. - LightDiPulse(12); - os_delay_us(12); // Delay >12us, begin send CMD data - for (uint32_t n = 0; n < chips; n++) { // Send CMD data - LightMy92x1Write(0x18); // ONE_SHOT_DISABLE, REACTION_FAST, BIT_WIDTH_8, FREQUENCY_DIVIDE_1, SCATTER_APDM - } - os_delay_us(12); // TStart > 12us. Delay 12 us. - // Send 16 DI pulse, at 14 pulse's falling edge store CMD data, and - // at 16 pulse's falling edge convert to duty mode. - LightDiPulse(16); - os_delay_us(12); // TStop > 12us. -} - -void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t duty_w, uint8_t duty_c) -{ - uint8_t channels[2] = { 4, 6 }; - - uint8_t didx = 0; // 0 (AiLight) - if (LT_RGBWC == light_type) { - didx = 1; // 1 (Sonoff B1) - } - - uint8_t duty[2][6] = {{ duty_r, duty_g, duty_b, duty_w, 0, 0 }, // Definition for RGBW channels - { duty_w, duty_c, 0, duty_g, duty_r, duty_b }}; // Definition for RGBWC channels - - os_delay_us(12); // TStop > 12us. - for (uint32_t channel = 0; channel < channels[didx]; channel++) { - LightMy92x1Write(duty[didx][channel]); // Send 8bit Data - } - os_delay_us(12); // TStart > 12us. Ready for send DI pulse. - LightDiPulse(8); // Send 8 DI pulse. After 8 pulse falling edge, store old data. - os_delay_us(12); // TStop > 12us. -} - /********************************************************************************************/ void LightPwmOffset(uint32_t offset) @@ -1309,12 +1224,6 @@ bool LightModuleInit(void) } 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; @@ -1380,6 +1289,7 @@ void LightInit(void) max_scheme = LS_MAX + WS2812_SCHEMES; } #endif // USE_WS2812 ************************************************************************ +/* else { light_pdi_pin = pin[GPIO_DI]; light_pdcki_pin = pin[GPIO_DCKI]; @@ -1391,7 +1301,7 @@ void LightInit(void) LightMy92x1Init(); } - +*/ if (Light.subtype < LST_RGB) { max_scheme = LS_POWER; } @@ -1954,10 +1864,6 @@ void LightAnimate(void) Ws2812SetColor(0, cur_col[0], cur_col[1], cur_col[2], cur_col[3]); } #endif // USE_ES2812 ************************************************************************ - 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]); - } XdrvMailbox.data = tmp_data; XdrvMailbox.data_len = tmp_data_len; } diff --git a/sonoff/xlgt_02_my92x1.ino b/sonoff/xlgt_02_my92x1.ino new file mode 100644 index 000000000..0f74f5713 --- /dev/null +++ b/sonoff/xlgt_02_my92x1.ino @@ -0,0 +1,166 @@ +/* + xlgt_02_my92x1.ino - 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_MY92X1 +/*********************************************************************************************\ + * Sonoff B1 and AiLight inspired by OpenLight https://github.com/icamgo/noduino-sdk +\*********************************************************************************************/ + +#define XLGT_02 2 + +struct MY92X1 { + uint8_t pdi_pin; + uint8_t pdcki_pin; +} My92x1; + +extern "C" { + void os_delay_us(unsigned int); +} + +void LightDiPulse(uint8_t times) +{ + for (uint32_t i = 0; i < times; i++) { + digitalWrite(My92x1.pdi_pin, HIGH); + digitalWrite(My92x1.pdi_pin, LOW); + } +} + +void LightDckiPulse(uint8_t times) +{ + for (uint32_t i = 0; i < times; i++) { + digitalWrite(My92x1.pdcki_pin, HIGH); + digitalWrite(My92x1.pdcki_pin, LOW); + } +} + +void LightMy92x1Write(uint8_t data) +{ + for (uint32_t i = 0; i < 4; i++) { // Send 8bit Data + digitalWrite(My92x1.pdcki_pin, LOW); + digitalWrite(My92x1.pdi_pin, (data & 0x80)); + digitalWrite(My92x1.pdcki_pin, HIGH); + data = data << 1; + digitalWrite(My92x1.pdi_pin, (data & 0x80)); + digitalWrite(My92x1.pdcki_pin, LOW); + digitalWrite(My92x1.pdi_pin, LOW); + data = data << 1; + } +} + +void LightMy92x1Init(void) +{ + uint8_t chips = 1; // 1 (AiLight) + if (LT_RGBWC == light_type) { + chips = 2; // 2 (Sonoff B1) + } + + LightDckiPulse(chips * 32); // Clear all duty register + os_delay_us(12); // TStop > 12us. + // Send 12 DI pulse, after 6 pulse's falling edge store duty data, and 12 + // pulse's rising edge convert to command mode. + LightDiPulse(12); + os_delay_us(12); // Delay >12us, begin send CMD data + for (uint32_t n = 0; n < chips; n++) { // Send CMD data + LightMy92x1Write(0x18); // ONE_SHOT_DISABLE, REACTION_FAST, BIT_WIDTH_8, FREQUENCY_DIVIDE_1, SCATTER_APDM + } + os_delay_us(12); // TStart > 12us. Delay 12 us. + // Send 16 DI pulse, at 14 pulse's falling edge store CMD data, and + // at 16 pulse's falling edge convert to duty mode. + LightDiPulse(16); + os_delay_us(12); // TStop > 12us. +} + +void LightMy92x1Duty(uint8_t duty_r, uint8_t duty_g, uint8_t duty_b, uint8_t duty_w, uint8_t duty_c) +{ + uint8_t channels[2] = { 4, 6 }; + + uint8_t didx = 0; // 0 (AiLight) + if (LT_RGBWC == light_type) { + didx = 1; // 1 (Sonoff B1) + } + + uint8_t duty[2][6] = {{ duty_r, duty_g, duty_b, duty_w, duty_w, duty_w }, // Definition for RGBW(WW) channels + { duty_w, duty_c, 0, duty_g, duty_r, duty_b }}; // Definition for RGBWC channels + + os_delay_us(12); // TStop > 12us. + for (uint32_t channel = 0; channel < channels[didx]; channel++) { + LightMy92x1Write(duty[didx][channel]); // Send 8bit Data + } + os_delay_us(12); // TStart > 12us. Ready for send DI pulse. + LightDiPulse(8); // Send 8 DI pulse. After 8 pulse falling edge, store old data. + os_delay_us(12); // TStop > 12us. +} + +/********************************************************************************************/ + +bool My92x1SetChannels(void) +{ + uint8_t *cur_col = (uint8_t*)XdrvMailbox.data; + + LightMy92x1Duty(cur_col[0], cur_col[1], cur_col[2], cur_col[3], cur_col[4]); + + return true; +} + +void My92x1ModuleSelected(void) +{ + if ((pin[GPIO_DCKI] < 99) && (pin[GPIO_DI] < 99)) { + My92x1.pdi_pin = pin[GPIO_DI]; + My92x1.pdcki_pin = pin[GPIO_DCKI]; + + pinMode(My92x1.pdi_pin, OUTPUT); + pinMode(My92x1.pdcki_pin, OUTPUT); + digitalWrite(My92x1.pdi_pin, LOW); + digitalWrite(My92x1.pdcki_pin, LOW); + + LightMy92x1Init(); + + if (AILIGHT == my_module_type) { // RGBW(WW) led + light_type = LT_RGBW; + } + else if (SONOFF_B1 == my_module_type) { // RGBWC led + light_type = LT_RGBWC; + } + light_flg = XLGT_02; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: MY29x1 Found")); + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xlgt02(uint8_t function) +{ + bool result = false; + + switch (function) { + case FUNC_SET_CHANNELS: + result = My92x1SetChannels(); + break; + case FUNC_MODULE_INIT: + My92x1ModuleSelected(); + break; + } + return result; +} + +#endif // USE_MY92X1 +#endif // USE_LIGHT \ No newline at end of file