From 8c12424d78d747f208bdc9ee878898e91b37192f Mon Sep 17 00:00:00 2001 From: jziolkowski Date: Sat, 4 Dec 2021 15:39:00 +0100 Subject: [PATCH 1/3] WIP --- tasmota/i18n.h | 5 ++ tasmota/language/en_GB.h | 6 ++ tasmota/my_user_config.h | 2 + tasmota/settings.h | 5 +- tasmota/settings.ino | 3 + tasmota/tasmota_template.h | 14 ++++- tasmota/xdrv_60_shift595.ino | 114 +++++++++++++++++++++++++++++++++++ 7 files changed, 146 insertions(+), 3 deletions(-) create mode 100644 tasmota/xdrv_60_shift595.ino diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 462774a53..db93df902 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -716,6 +716,11 @@ #define D_CMND_BR_RUN "" #define D_BR_NOT_STARTED "Berry not started" +// Commands xdrv_60_shift595.ino - 74x595 family shift register driver +#ifdef USE_SHIFT595 +#define D_CMND_SHIFT595_DEVICE_COUNT "Shift595DeviceCount" +#endif + // Commands xsns_02_analog.ino #define D_CMND_ADCPARAM "AdcParam" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 79eb011f1..0fed4b222 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -1083,4 +1083,10 @@ #define D_NEOPOOL_PH_LOW "too low" #define D_NEOPOOL_PUMP_TIME_EXCEEDED "pump time exceeded" +// xdrv_60_shift595.ino +#define D_GPIO_SHIFT595_SRCLK "74HC595 SRCLK" +#define D_GPIO_SHIFT595_RCLK "74HC595 RCLK" +#define D_GPIO_SHIFT595_OE "74HC595 OE" +#define D_GPIO_SHIFT595_SER "74HC595 SER" + #endif // _LANGUAGE_EN_GB_H_ diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index f04b79d93..d34174a56 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -350,6 +350,8 @@ #define ZIGBEE_DISTINCT_TOPICS false // [SetOption89] Enable unique device topic based on Zigbee device ShortAddr #define ZIGBEE_RMV_ZBRECEIVED false // [SetOption100] Remove ZbReceived form JSON message #define ZIGBEE_INDEX_EP false // [SetOption101] Add the source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 +#define SHIFT595_INVERT_OUTPUTS false // [SetOption133] Don't invert outputs of 74x595 shift register +#define SHIFT595_DEVICE_COUNT 1 // [Shift595Devices] Set the number of connected 74x595 shift registers /*********************************************************************************************\ * END OF SECTION 1 diff --git a/tasmota/settings.h b/tasmota/settings.h index 3686b1d42..02571350a 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -162,7 +162,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t show_heap_with_timestamp : 1; // bit 16 (v9.5.0.9) - SetOption130 - (Debug) Show heap with logging timestamp uint32_t tuya_allow_dimmer_0 : 1; // bit 17 (v10.0.0.3) - SetOption131 - (Tuya) Allow save dimmer = 0 receved by MCU uint32_t tls_use_fingerprint : 1; // bit 18 (v10.0.0.4) - SetOption132 - (TLS) use fingerprint validation instead of CA based - uint32_t spare19 : 1; // bit 19 + uint32_t shift595_invert_outputs : 1; // bit 19 (v10.0.0.5) - SetOption133 - (Shift595) invert outputs of 74x595 shift registers uint32_t spare20 : 1; // bit 20 uint32_t spare21 : 1; // bit 21 uint32_t spare22 : 1; // bit 22 @@ -487,7 +487,8 @@ typedef struct { int32_t energy_kWhyesterday_ph[3]; // 320 int32_t energy_kWhtotal_ph[3]; // 32C - uint8_t free_338[7]; // 338 + uint8_t shift595_device_count; // 338 + uint8_t free_339[6]; // 339 uint8_t tuyamcu_topic; // 33F Manage tuyaSend topic. ex_energy_power_delta on 6.6.0.20, replaced on 8.5.0.1 uint16_t domoticz_update_timer; // 340 diff --git a/tasmota/settings.ino b/tasmota/settings.ino index faee15800..b2a58e2ae 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -1196,6 +1196,9 @@ void SettingsDefaultSet2(void) { flag4.mqtt_tls |= MQTT_TLS_ENABLED; flag4.mqtt_no_retain |= MQTT_NO_RETAIN; + flag5.shift595_invert_outputs |= SHIFT595_INVERT_OUTPUTS; + Settings->shift595_device_count = SHIFT595_DEVICE_COUNT; + Settings->flag = flag; Settings->flag2 = flag2; Settings->flag3 = flag3; diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index bbbce4d01..9e08aedb1 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -176,6 +176,7 @@ enum UserSelectablePins { GPIO_BL0942_RX, // BL0942 Serial interface GPIO_HM330X_SET, // HM330X SET pin (sleep when low) GPIO_HEARTBEAT, GPIO_HEARTBEAT_INV, + GPIO_SHIFT595_SRCLK, GPIO_SHIFT595_RCLK, GPIO_SHIFT595_OE, GPIO_SHIFT595_SER, // 74HC595 Shift register GPIO_SENSOR_END }; enum ProgramSelectablePins { @@ -372,7 +373,11 @@ const char kSensorNames[] PROGMEM = D_SENSOR_BL0942_RX "|" D_SENSOR_HM330X_SET "|" D_SENSOR_HEARTBEAT "|" D_SENSOR_HEARTBEAT "_i|" - ; + +#ifdef USE_SHIFT595 + D_GPIO_SHIFT595_SRCLK "|" D_GPIO_SHIFT595_RCLK "|" D_GPIO_SHIFT595_OE "|" D_GPIO_SHIFT595_SER "|" +#endif +; const char kSensorNamesFixed[] PROGMEM = D_SENSOR_USER; @@ -930,6 +935,13 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_ADC_JOY) + MAX_ADCS, // Joystick AGPIO(GPIO_ADC_PH) + MAX_ADCS, // Analog PH Sensor #endif // ESP32 + +#ifdef USE_SHIFT595 + AGPIO(GPIO_SHIFT595_SRCLK), // 74HC595 shift register + AGPIO(GPIO_SHIFT595_RCLK), + AGPIO(GPIO_SHIFT595_OE), + AGPIO(GPIO_SHIFT595_SER), +#endif }; /*-------------------------------------------------------------------------------------------*\ diff --git a/tasmota/xdrv_60_shift595.ino b/tasmota/xdrv_60_shift595.ino new file mode 100644 index 000000000..6e45194fa --- /dev/null +++ b/tasmota/xdrv_60_shift595.ino @@ -0,0 +1,114 @@ +/* + xdrv_60_shift595.ino - 74x595 shift register family support for Tasmota + + Copyright (C) 2021 Jacek Ziółkowski + + 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_SHIFT595 + +#define XDRV_60 60 + +const char kShift595Commands[] PROGMEM = "|" D_CMND_SHIFT595_DEVICE_COUNT ; +void (* const Shit595Command[])(void) PROGMEM = { &CmndShift595Devices }; + +struct Shift595 { + int8_t pinSRCLK; + int8_t pinRCLK; + int8_t pinSER; + int8_t pinOE; + bool connected = false; + int8_t outputs; + int8_t first = TasmotaGlobal.devices_present; +} Shift595; + +void Shift595Init(void) +{ + if (PinUsed(GPIO_SHIFT595_SRCLK) && PinUsed(GPIO_SHIFT595_RCLK) && PinUsed(GPIO_SHIFT595_SER)) { + Shift595.pinSRCLK = Pin(GPIO_SHIFT595_SRCLK); + pinMode(Shift595.pinSRCLK, OUTPUT); + digitalWrite(Shift595.pinSRCLK, 0); + + Shift595.pinRCLK = Pin(GPIO_SHIFT595_RCLK); + pinMode(Shift595.pinRCLK, OUTPUT); + digitalWrite(Shift595.pinRCLK, 0); + + Shift595.pinSER = Pin(GPIO_SHIFT595_SER); + pinMode(Shift595.pinSER, OUTPUT); + digitalWrite(Shift595.pinSER, 0); + + if (PinUsed(GPIO_SHIFT595_OE)) { + Shift595.pinOE = Pin(GPIO_SHIFT595_OE); + pinMode(Shift595.pinOE, OUTPUT); + digitalWrite(Shift595.pinOE, 1); + } + Shift595.outputs = Settings->shift595_device_count * 8; + TasmotaGlobal.devices_present += Shift595.outputs; + Shift595.connected = true; + AddLog(LOG_LEVEL_DEBUG, PSTR("595: Controlling relays POWER%d to POWER%d"), Shift595.first + 1, Shift595.outputs); + } +} + +void Shift595LatchPin(uint8 pin) { + digitalWrite(pin, 1); + digitalWrite(pin, 0); +} + +void Shift595SwitchRelay(void) +{ + if (Shift595.connected == true) { + for (uint32_t i = 0; i < Shift595.outputs; i++) { + uint8_t relay_state = bitRead(XdrvMailbox.index, Shift595.first + Shift595.outputs -1 -i); + // digitalWrite(Shift595.pinSER, Settings->flag5.shift595_invert_outputs ? !relay_state : relay_state); + digitalWrite(Shift595.pinSER, relay_state); + Shift595LatchPin(Shift595.pinSRCLK); + } + + Shift595LatchPin(Shift595.pinRCLK); + + if (PinUsed(GPIO_SHIFT595_OE)) { + digitalWrite(Shift595.pinOE, 0); + } + } +} + +void CmndShift595Devices(void) { + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) { + Settings->shift595_device_count = (1 == XdrvMailbox.payload) ? SHIFT595_DEVICE_COUNT : XdrvMailbox.payload; + TasmotaGlobal.restart_flag = 2; + } + ResponseCmndNumber(Settings->shift595_device_count); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv60(uint8_t function) +{ + bool result = false; + switch (function) { + case FUNC_PRE_INIT: + Shift595Init(); + break; + case FUNC_SET_POWER: + Shift595SwitchRelay(); + break; + case FUNC_COMMAND: + result = DecodeCommand(kShift595Commands, Shift595Command); + break; + return result; +} + +#endif // USE_SHIFT595 From 8288d74bb2f654f01e27c86c8ef8bd62a8275973 Mon Sep 17 00:00:00 2001 From: jziolkowski Date: Sat, 4 Dec 2021 18:12:41 +0100 Subject: [PATCH 2/3] Reduce the max count of devices to never exceed MAX_RELAYS --- tasmota/xdrv_60_shift595.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/xdrv_60_shift595.ino b/tasmota/xdrv_60_shift595.ino index 9bae92196..27200d52f 100644 --- a/tasmota/xdrv_60_shift595.ino +++ b/tasmota/xdrv_60_shift595.ino @@ -83,7 +83,7 @@ void Shift595SwitchRelay(void) } void CmndShift595Devices(void) { - if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 4)) { + if ((XdrvMailbox.payload > 0) && (XdrvMailbox.payload <= 3)) { Settings->shift595_device_count = (1 == XdrvMailbox.payload) ? SHIFT595_DEVICE_COUNT : XdrvMailbox.payload; TasmotaGlobal.restart_flag = 2; } From 63ff462f53b026ba552fe55a82d9508166e67180 Mon Sep 17 00:00:00 2001 From: jziolkowski Date: Sun, 5 Dec 2021 13:40:01 +0100 Subject: [PATCH 3/3] using pointer for Shift595, refactored pin init --- tasmota/i18n.h | 2 - tasmota/my_user_config.h | 6 ++- tasmota/tasmota_template.h | 2 - tasmota/xdrv_60_shift595.ino | 92 +++++++++++++++++++----------------- 4 files changed, 53 insertions(+), 49 deletions(-) diff --git a/tasmota/i18n.h b/tasmota/i18n.h index db93df902..387ba8f33 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -717,9 +717,7 @@ #define D_BR_NOT_STARTED "Berry not started" // Commands xdrv_60_shift595.ino - 74x595 family shift register driver -#ifdef USE_SHIFT595 #define D_CMND_SHIFT595_DEVICE_COUNT "Shift595DeviceCount" -#endif // Commands xsns_02_analog.ino #define D_CMND_ADCPARAM "AdcParam" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index dcdb5acc9..9eb87e186 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -350,8 +350,6 @@ #define ZIGBEE_DISTINCT_TOPICS false // [SetOption89] Enable unique device topic based on Zigbee device ShortAddr #define ZIGBEE_RMV_ZBRECEIVED false // [SetOption100] Remove ZbReceived form JSON message #define ZIGBEE_INDEX_EP false // [SetOption101] Add the source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 -#define SHIFT595_INVERT_OUTPUTS false // [SetOption133] Don't invert outputs of 74x595 shift register -#define SHIFT595_DEVICE_COUNT 1 // [Shift595DeviceCount] Set the number of connected 74x595 shift registers /*********************************************************************************************\ * END OF SECTION 1 @@ -895,6 +893,10 @@ // -- Other sensors/drivers ----------------------- +// #define USE_SHIFT595 + #define SHIFT595_INVERT_OUTPUTS false // [SetOption133] Don't invert outputs of 74x595 shift register + #define SHIFT595_DEVICE_COUNT 1 // [Shift595DeviceCount] Set the number of connected 74x595 shift registers + //#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code) //#define USE_HX711 // Add support for HX711 load cell (+1k5 code) // #define USE_HX711_GUI // Add optional web GUI to HX711 as scale (+1k8 code) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 311ac9388..d8aa87742 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -374,9 +374,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_HM330X_SET "|" D_SENSOR_HEARTBEAT "|" D_SENSOR_HEARTBEAT "_i|" -#ifdef USE_SHIFT595 D_GPIO_SHIFT595_SRCLK "|" D_GPIO_SHIFT595_RCLK "|" D_GPIO_SHIFT595_OE "|" D_GPIO_SHIFT595_SER "|" -#endif ; const char kSensorNamesFixed[] PROGMEM = diff --git a/tasmota/xdrv_60_shift595.ino b/tasmota/xdrv_60_shift595.ino index 27200d52f..cf9a3868c 100644 --- a/tasmota/xdrv_60_shift595.ino +++ b/tasmota/xdrv_60_shift595.ino @@ -24,60 +24,64 @@ const char kShift595Commands[] PROGMEM = "|" D_CMND_SHIFT595_DEVICE_COUNT ; void (* const Shift595Command[])(void) PROGMEM = { &CmndShift595Devices }; struct Shift595 { - int8_t pinSRCLK; - int8_t pinRCLK; - int8_t pinSER; - int8_t pinOE; - int8_t outputs; - int8_t first = TasmotaGlobal.devices_present; + uint8_t pinSRCLK; + uint8_t pinRCLK; + uint8_t pinSER; + uint8_t pinOE; + uint8_t outputs; + uint8_t first; bool connected = false; -} Shift595; +} *Shift595 = nullptr; + +void Shift595ConfigurePin(uint8_t pin, uint8_t value = 0){ + pinMode(pin, OUTPUT); + digitalWrite(pin, value); +} void Shift595Init(void) { if (PinUsed(GPIO_SHIFT595_SRCLK) && PinUsed(GPIO_SHIFT595_RCLK) && PinUsed(GPIO_SHIFT595_SER)) { - Shift595.pinSRCLK = Pin(GPIO_SHIFT595_SRCLK); - pinMode(Shift595.pinSRCLK, OUTPUT); - digitalWrite(Shift595.pinSRCLK, 0); - - Shift595.pinRCLK = Pin(GPIO_SHIFT595_RCLK); - pinMode(Shift595.pinRCLK, OUTPUT); - digitalWrite(Shift595.pinRCLK, 0); + Shift595 = (struct Shift595*)calloc(1, sizeof(struct Shift595)); - Shift595.pinSER = Pin(GPIO_SHIFT595_SER); - pinMode(Shift595.pinSER, OUTPUT); - digitalWrite(Shift595.pinSER, 0); + Shift595->pinSRCLK = Pin(GPIO_SHIFT595_SRCLK); + Shift595->pinRCLK = Pin(GPIO_SHIFT595_RCLK); + Shift595->pinSER = Pin(GPIO_SHIFT595_SER); + + Shift595ConfigurePin(Shift595->pinSRCLK); + Shift595ConfigurePin(Shift595->pinRCLK); + Shift595ConfigurePin(Shift595->pinSER); if (PinUsed(GPIO_SHIFT595_OE)) { - Shift595.pinOE = Pin(GPIO_SHIFT595_OE); - pinMode(Shift595.pinOE, OUTPUT); - digitalWrite(Shift595.pinOE, 1); + Shift595->pinOE = Pin(GPIO_SHIFT595_OE); + Shift595ConfigurePin(Shift595->pinOE, 1); } - Shift595.outputs = Settings->shift595_device_count * 8; - TasmotaGlobal.devices_present += Shift595.outputs; - Shift595.connected = true; - AddLog(LOG_LEVEL_DEBUG, PSTR("595: Controlling relays POWER%d to POWER%d"), Shift595.first + 1, Shift595.first + Shift595.outputs); + + Shift595->first = TasmotaGlobal.devices_present; + Shift595->outputs = Settings->shift595_device_count * 8; + TasmotaGlobal.devices_present += Shift595->outputs; + Shift595->connected = true; + AddLog(LOG_LEVEL_DEBUG, PSTR("595: Controlling relays POWER%d to POWER%d"), Shift595->first + 1, Shift595->first + Shift595->outputs); } } -void Shift595LatchPin(uint8 pin) { +void Shift595LatchPin(uint8_t pin) { digitalWrite(pin, 1); digitalWrite(pin, 0); } void Shift595SwitchRelay(void) { - if (Shift595.connected == true) { - for (uint32_t i = 0; i < Shift595.outputs; i++) { - uint8_t relay_state = bitRead(XdrvMailbox.index, Shift595.first + Shift595.outputs -1 -i); - digitalWrite(Shift595.pinSER, Settings->flag5.shift595_invert_outputs ? !relay_state : relay_state); - Shift595LatchPin(Shift595.pinSRCLK); + if (Shift595 && Shift595->connected == true) { + for (uint32_t i = 0; i < Shift595->outputs; i++) { + uint8_t relay_state = bitRead(XdrvMailbox.index, Shift595->first + Shift595->outputs -1 -i); + digitalWrite(Shift595->pinSER, Settings->flag5.shift595_invert_outputs ? !relay_state : relay_state); + Shift595LatchPin(Shift595->pinSRCLK); } - Shift595LatchPin(Shift595.pinRCLK); + Shift595LatchPin(Shift595->pinRCLK); if (PinUsed(GPIO_SHIFT595_OE)) { - digitalWrite(Shift595.pinOE, 0); + digitalWrite(Shift595->pinOE, 0); } } } @@ -97,17 +101,19 @@ void CmndShift595Devices(void) { bool Xdrv60(uint8_t function) { bool result = false; - switch (function) { - case FUNC_PRE_INIT: - Shift595Init(); - break; - case FUNC_SET_POWER: - Shift595SwitchRelay(); - break; - case FUNC_COMMAND: - result = DecodeCommand(kShift595Commands, Shift595Command); - break; - } + + if (FUNC_PRE_INIT == function) { + Shift595Init(); + } else if (Shift595) { + switch (function) { + case FUNC_SET_POWER: + Shift595SwitchRelay(); + break; + case FUNC_COMMAND: + result = DecodeCommand(kShift595Commands, Shift595Command); + break; + } + } return result; }