From 547f52fe79501afaca120bc205693181548660cc Mon Sep 17 00:00:00 2001 From: dpeddi Date: Thu, 16 Jul 2020 04:15:34 +0200 Subject: [PATCH] hw: Implement support for ProDino WIFI (#2269) - implement mcp23s08 - support mcp pins in relays and buttons - add hardware profile for ProDino WiFi Co-authored-by: dpeddi Co-authored-by: Maxim Prokhorov --- code/espurna/board.cpp | 2 + code/espurna/button.cpp | 35 +++++-- code/espurna/config/arduino.h | 1 + code/espurna/config/general.h | 9 ++ code/espurna/config/hardware.h | 45 ++++++++ code/espurna/config/types.h | 2 + code/espurna/domoticz.cpp | 2 +- code/espurna/libs/BasePin.h | 22 ++-- code/espurna/main.cpp | 6 ++ code/espurna/mcp23s08.cpp | 184 +++++++++++++++++++++++++++++++++ code/espurna/mcp23s08.h | 46 +++++++++ code/espurna/relay.cpp | 120 +++++++++++++-------- code/espurna/relay.h | 2 +- code/platformio.ini | 5 + 14 files changed, 420 insertions(+), 61 deletions(-) create mode 100644 code/espurna/mcp23s08.cpp create mode 100644 code/espurna/mcp23s08.h diff --git a/code/espurna/board.cpp b/code/espurna/board.cpp index 4cc25ddc..ef6952ab 100644 --- a/code/espurna/board.cpp +++ b/code/espurna/board.cpp @@ -681,6 +681,8 @@ int getBoardId() { return 157; #elif defined(GENERIC_AG_L4_V3) return 158; + #elif defined(PRODINO_WIFI) + return 159; #else return -1; // CUSTOM #endif diff --git a/code/espurna/button.cpp b/code/espurna/button.cpp index 3d81acb6..18b5e906 100644 --- a/code/espurna/button.cpp +++ b/code/espurna/button.cpp @@ -21,6 +21,7 @@ Copyright (C) 2016-2019 by Xose Pérez #include "relay.h" #include "light.h" #include "ws.h" +#include "mcp23s08.h" #include "button_config.h" @@ -282,7 +283,8 @@ void _buttonWebSocketOnVisible(JsonObject& root) { } #if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \ - (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL) + (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL) || \ + (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08) void _buttonWebSocketOnConnected(JsonObject& root) { root["btnRepDel"] = getSetting("btnRepDel", _buttonRepeatDelay()); @@ -623,7 +625,8 @@ void _buttonLoopGeneric() { void buttonLoop() { - #if BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC + #if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC) || \ + (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08) _buttonLoopGeneric(); #elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \ (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL) @@ -642,7 +645,6 @@ void buttonSetup() { // Special hardware cases #if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL) || \ (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL) - size_t buttons = 0; #if BUTTON1_RELAY != RELAY_NONE ++buttons; @@ -677,11 +679,13 @@ void buttonSetup() { actions, delays ); + } // Generic GPIO input handlers - #elif BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC + #elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC) || \ + (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08) size_t buttons = 0; @@ -712,11 +716,25 @@ void buttonSetup() { _buttons.reserve(buttons); + // TODO: allow to change gpio pin type based on config? + #if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC) + using gpio_type = GpioPin; + #elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08) + using gpio_type = McpGpioPin; + #endif + for (unsigned char index = 0; index < ButtonsMax; ++index) { const auto pin = getSetting({"btnGPIO", index}, _buttonPin(index)); - if (!gpioValid(pin)) { - break; - } + #if (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_GENERIC) + if (!gpioValid(pin)) { + break; + } + #elif (BUTTON_EVENTS_SOURCE == BUTTON_EVENTS_SOURCE_MCP23S08) + if (!mcpGpioValid(pin)) { + break; + } + #endif + const auto relayID = getSetting({"btnRelay", index}, _buttonRelay(index)); // TODO: compatibility proxy, fetch global key before indexed @@ -738,9 +756,8 @@ void buttonSetup() { const auto config = _buttonConfig(index); - // TODO: allow to change GpioPin to something else based on config? _buttons.emplace_back( - std::make_shared(pin), config, + std::make_shared(pin), config, relayID, actions, delays ); } diff --git a/code/espurna/config/arduino.h b/code/espurna/config/arduino.h index b50ffcee..276b4ad3 100644 --- a/code/espurna/config/arduino.h +++ b/code/espurna/config/arduino.h @@ -144,6 +144,7 @@ //#define OUKITEL_P1 //#define PHYX_ESP12_RGB //#define PILOTAK_ESP_DIN_V1 +//#define PRODINO_WIFI //#define PSH_RGBW_CONTROLLER //#define PSH_WIFI_PLUG //#define PSH_WIFI_SENSOR diff --git a/code/espurna/config/general.h b/code/espurna/config/general.h index 6f0999e6..74278c03 100644 --- a/code/espurna/config/general.h +++ b/code/espurna/config/general.h @@ -405,6 +405,7 @@ // BUTTON_EVENTS_SOURCE_GENERIC - GPIOs (virtual or real) // BUTTON_EVENTS_SOURCE_SONOFF_DUAL - hardware specific, drive buttons through serial connection // BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL - similar to Itead Sonoff Dual, hardware specific + // BUTTON_EVENTS_SOURCE_MCP23S08 - activate virtual button connected to gpio expander #endif //------------------------------------------------------------------------------ @@ -1776,6 +1777,14 @@ #define TUYA_SERIAL Serial #endif +//-------------------------------------------------------------------------------- +// Support expander MCP23S08 +//-------------------------------------------------------------------------------- + +#ifndef MCP23S08_SUPPORT +#define MCP23S08_SUPPORT 0 +#endif + // ============================================================================= // Configuration helpers // ============================================================================= diff --git a/code/espurna/config/hardware.h b/code/espurna/config/hardware.h index 2b66f5c5..10b14786 100644 --- a/code/espurna/config/hardware.h +++ b/code/espurna/config/hardware.h @@ -4814,6 +4814,51 @@ #define LED1_PIN 1 #define LED1_PIN_INVERSE 1 +// ----------------------------------------------------------------------------- +// Prodino WIFI +// https://kmpelectronics.eu/products/prodino-wifi-v1/ +// ------------------------------------- + +#elif defined(PRODINO_WIFI) + + // Info + #define MANUFACTURER "PRODINO" + #define DEVICE "WIFI" + + // MCP23S08 + #define MCP23S08_SUPPORT 1 + + // Relays + #define RELAY_PROVIDER RELAY_PROVIDER_MCP23S08 + #define RELAY1_PIN 4 + #define RELAY2_PIN 5 + #define RELAY3_PIN 6 + #define RELAY4_PIN 7 + + // Buttons + #define BUTTON1_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON1_PIN 0 + + #define BUTTON2_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON2_PIN 1 + + #define BUTTON3_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON3_PIN 2 + + #define BUTTON4_CONFIG BUTTON_PUSHBUTTON | BUTTON_DEFAULT_HIGH + #define BUTTON4_PIN 3 + + #define BUTTON1_RELAY 1 + #define BUTTON2_RELAY 2 + #define BUTTON3_RELAY 3 + #define BUTTON4_RELAY 4 + + #define BUTTON_EVENTS_SOURCE BUTTON_EVENTS_SOURCE_MCP23S08 + + // LEDs + #define LED1_PIN 2 + #define LED1_PIN_INVERSE 1 + // ----------------------------------------------------------------------------- #else diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h index 3846ef3e..6f18a541 100644 --- a/code/espurna/config/types.h +++ b/code/espurna/config/types.h @@ -61,6 +61,7 @@ #define BUTTON_EVENTS_SOURCE_GENERIC 0 #define BUTTON_EVENTS_SOURCE_ITEAD_SONOFF_DUAL 1 #define BUTTON_EVENTS_SOURCE_FOXEL_LIGHTFOX_DUAL 2 +#define BUTTON_EVENTS_SOURCE_MCP23S08 3 //------------------------------------------------------------------------------ // ENCODER @@ -100,6 +101,7 @@ #define RELAY_PROVIDER_LIGHT 2 #define RELAY_PROVIDER_RFBRIDGE 3 #define RELAY_PROVIDER_STM 4 +#define RELAY_PROVIDER_MCP23S08 5 #define RELAY_GROUP_SYNC_NORMAL 0 #define RELAY_GROUP_SYNC_INVERSE 1 diff --git a/code/espurna/domoticz.cpp b/code/espurna/domoticz.cpp index b0691899..b6a179eb 100644 --- a/code/espurna/domoticz.cpp +++ b/code/espurna/domoticz.cpp @@ -19,7 +19,7 @@ Copyright (C) 2016-2019 by Xose Pérez #include "ws.h" bool _dcz_enabled = false; -std::bitset _dcz_relay_state; +std::bitset _dcz_relay_state; //------------------------------------------------------------------------------ // Private methods diff --git a/code/espurna/libs/BasePin.h b/code/espurna/libs/BasePin.h index 6e6c5a8d..593b5960 100644 --- a/code/espurna/libs/BasePin.h +++ b/code/espurna/libs/BasePin.h @@ -9,17 +9,21 @@ Copyright (C) 2020 by Maxim Prokhorov #pragma once #include +#include "config/types.h" // base interface for generic pin handler. -class BasePin { - public: - BasePin(unsigned char pin) : - pin(pin) - {} +struct BasePin { + BasePin(unsigned char pin) : + pin(pin) + {} - virtual void pinMode(int8_t mode) = 0; - virtual void digitalWrite(int8_t val) = 0; - virtual int digitalRead() = 0; + virtual operator bool() { + return GPIO_NONE != pin; + } - const unsigned char pin; + virtual void pinMode(int8_t mode) = 0; + virtual void digitalWrite(int8_t val) = 0; + virtual int digitalRead() = 0; + + const unsigned char pin; }; diff --git a/code/espurna/main.cpp b/code/espurna/main.cpp index ac8dd1c8..5c3ea914 100644 --- a/code/espurna/main.cpp +++ b/code/espurna/main.cpp @@ -60,6 +60,7 @@ along with this program. If not, see . #include "uartmqtt.h" #include "web.h" #include "ws.h" +#include "mcp23s08.h" std::vector _loop_callbacks; std::vector _reload_callbacks; @@ -193,6 +194,11 @@ void setup() { apiSetup(); #endif + // Hardware GPIO expander, needs to be available for modules down below + #if MCP23S08_SUPPORT + MCP23S08Setup(); + #endif + // lightSetup must be called before relaySetup #if LIGHT_PROVIDER != LIGHT_PROVIDER_NONE lightSetup(); diff --git a/code/espurna/mcp23s08.cpp b/code/espurna/mcp23s08.cpp new file mode 100644 index 00000000..735de92e --- /dev/null +++ b/code/espurna/mcp23s08.cpp @@ -0,0 +1,184 @@ +/* + +MCP23S08 MODULE + +Copyright (C) 2020 by Eddi De Pieri +Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016 Plamen Kovandjiev & Dimitar Antonov + +*/ + +#include "mcp23s08.h" + +#if MCP23S08_SUPPORT + +#include + +#include + +// TODO: check if this needed for SPI operation +#define MCP23S08_CS_PIN 15 + +// Known commands +#define READ_CMD 0x41 +#define WRITE_CMD 0x40 + +// Registers +#define IODIR 0x00 +#define IPOL 0x01 +#define GPINTEN 0x02 +#define DEFVAL 0x03 +#define INTCON 0x04 +#define IOCON 0x05 +#define GPPU 0x06 +#define INTF 0x07 +#define INTCAP 0x08 +#define GPIO 0x09 +#define OLAT 0x0A + +static uint8_t _mcp23s08TxData[16] __attribute__((aligned(4))); +static uint8_t _mcp23s08RxData[16] __attribute__((aligned(4))); + +McpGpioPin::McpGpioPin(unsigned char pin) : + BasePin(pin) +{} + +inline void McpGpioPin::pinMode(int8_t mode) { + ::MCP23S08SetDirection(this->pin, mode); +} + +inline void McpGpioPin::digitalWrite(int8_t val) { + ::MCP23S08SetPin(this->pin, val); +} + +inline int McpGpioPin::digitalRead() { + return ::MCP23S08GetPin(this->pin); +} + +void MCP23S08Setup() +{ + DEBUG_MSG_P(PSTR("[MCP23S08] Initialize SPI bus\n")); + + // Expander SPI settings + SPI.begin(); + SPI.setHwCs(true); + SPI.setFrequency(1000000); + SPI.setDataMode(SPI_MODE0); + + pinMode(MCP23S08_CS_PIN, OUTPUT); + digitalWrite(MCP23S08_CS_PIN, HIGH); +} + +/** + * @brief Set a expander MCP23S08 the pin direction. + * + * @param pinNumber Pin number for set. + * @param mode direction mode. 0 - INPUT, 1 - OUTPUT. + * + * @return void + */ +void MCP23S08SetDirection(uint8_t pinNumber, uint8_t mode) +{ + uint8_t registerData = MCP23S08ReadRegister(IODIR); + + if (INPUT == mode) + { + registerData |= (1 << pinNumber); + } + else + { + registerData &= ~(1 << pinNumber); + } + + MCP23S08WriteRegister(IODIR, registerData); +} + +/** + * @brief Read an expander MCP23S08 a register. + * + * @param address A register address. + * + * @return The data from the register. + */ +uint8_t MCP23S08ReadRegister(uint8_t address) +{ + _mcp23s08TxData[0] = READ_CMD; + _mcp23s08TxData[1] = address; + + digitalWrite(MCP23S08_CS_PIN, LOW); + SPI.transferBytes(_mcp23s08TxData, _mcp23s08RxData, 3); + digitalWrite(MCP23S08_CS_PIN, HIGH); + + return _mcp23s08RxData[2]; +} + +/** + * @brief Write data in expander MCP23S08 register. + * + * @param address A register address. + * @param data A byte for write. + * + * @return void. + */ +void MCP23S08WriteRegister(uint8_t address, uint8_t data) +{ + _mcp23s08TxData[0] = WRITE_CMD; + _mcp23s08TxData[1] = address; + _mcp23s08TxData[2] = data; + + digitalWrite(MCP23S08_CS_PIN, LOW); + SPI.transferBytes(_mcp23s08TxData, _mcp23s08RxData, 3); + digitalWrite(MCP23S08_CS_PIN, HIGH); +} + +/** + * @brief Set expander MCP23S08 pin state. + * + * @param pinNumber The number of pin to be set. + * @param state The pin state, true - 1, false - 0. + * + * @return void + */ +void MCP23S08SetPin(uint8_t pinNumber, bool state) +{ + uint8_t registerData = MCP23S08ReadRegister(OLAT); + + if (state) + { + registerData |= (1 << pinNumber); + } + else + { + registerData &= ~(1 << pinNumber); + } + + MCP23S08WriteRegister(OLAT, registerData); +} + +/** + * @brief Get MCP23S08 pin state. + * + * @param pinNumber The number of pin to get. + * + * @return State true - 1, false - 0. + */ +bool MCP23S08GetPin(uint8_t pinNumber) +{ + uint8_t registerData = MCP23S08ReadRegister(GPIO); + + return registerData & (1 << pinNumber); +} + +/** + * @brief Ensure pin number is valid. + * + * @param pinNumber The number of pin to be get. + * + * @return State true - 1, false - 0. + */ +bool mcpGpioValid(unsigned char gpio) +{ + return gpio < McpGpioPins; +} + +#endif // MCP23S08_SUPPORT diff --git a/code/espurna/mcp23s08.h b/code/espurna/mcp23s08.h new file mode 100644 index 00000000..56f712d4 --- /dev/null +++ b/code/espurna/mcp23s08.h @@ -0,0 +1,46 @@ +/* + +MCP23S08 MODULE + +Copyright (C) 2020-2020 by Eddi De Pieri +Copyright (C) 2016-2017 by Xose Pérez +Copyright (C) 2016-2017 Plamen Kovandjiev & Dimitar Antonov + +*/ + +#pragma once + +#ifndef MCP23S08_H +#define MCP23S08_H + +#include "espurna.h" +#include "libs/BasePin.h" + +#if MCP23S08_SUPPORT + +constexpr size_t McpGpioPins = 8; + +// real hardware pin +class McpGpioPin final : public BasePin { + public: + McpGpioPin(unsigned char pin); + + void pinMode(int8_t mode); + void digitalWrite(int8_t val); + int digitalRead(); +}; + +void MCP23S08Setup(); + +uint8_t MCP23S08ReadRegister(uint8_t address); +void MCP23S08WriteRegister(uint8_t address, uint8_t data); + +void MCP23S08SetDirection(uint8_t pinNumber, uint8_t mode); +void MCP23S08SetPin(uint8_t pinNumber, bool state); +bool MCP23S08GetPin(uint8_t pinNumber); + +bool mcpGpioValid(unsigned char gpio); + +#endif // MCP23S08_SUPPORT == 1 + +#endif diff --git a/code/espurna/relay.cpp b/code/espurna/relay.cpp index 4fec0b32..6935d215 100644 --- a/code/espurna/relay.cpp +++ b/code/espurna/relay.cpp @@ -28,17 +28,32 @@ Copyright (C) 2016-2019 by Xose Pérez #include "tuya.h" #include "utils.h" #include "ws.h" +#include "mcp23s08.h" + +#include "libs/BasePin.h" #include "relay_config.h" +struct DummyPin final : public BasePin { + DummyPin(unsigned char pin) : + BasePin(pin) + {} + + void pinMode(int8_t) override {} + void digitalWrite(int8_t) override {} + int digitalRead() override { return 0; } +}; + struct relay_t { - // Default to dummy (virtual) relay configuration + using pin_type = std::unique_ptr; + + // Default to empty relay configuration, as we allow switches to exist without real GPIOs - relay_t(unsigned char pin, unsigned char type, unsigned char reset_pin) : - pin(pin), + relay_t(pin_type&& pin, unsigned char type, pin_type&& reset_pin) : + pin(std::move(pin)), + reset_pin(std::move(reset_pin)), type(type), - reset_pin(reset_pin), delay_on(0), delay_off(0), pulse(RELAY_PULSE_NONE), @@ -55,20 +70,13 @@ struct relay_t { {} relay_t() : - relay_t(GPIO_NONE, RELAY_TYPE_NORMAL, GPIO_NONE) + relay_t(std::make_unique(GPIO_NONE), RELAY_TYPE_NORMAL, std::make_unique(GPIO_NONE)) {} - // ... unless there are pre-configured values + pin_type pin; // GPIO pin for the relay + pin_type reset_pin; // GPIO to reset the relay if RELAY_TYPE_LATCHED - relay_t(unsigned char id) : - relay_t(_relayPin(id), _relayType(id), _relayResetPin(id)) - {} - - // Configuration variables - - unsigned char pin; // GPIO pin for the relay unsigned char type; // RELAY_TYPE_NORMAL, RELAY_TYPE_INVERSE, RELAY_TYPE_LATCHED or RELAY_TYPE_LATCHED_INVERSE - unsigned char reset_pin; // GPIO to reset the relay if RELAY_TYPE_LATCHED unsigned long delay_on; // Delay to turn relay ON unsigned long delay_off; // Delay to turn relay OFF unsigned char pulse; // RELAY_PULSE_NONE, RELAY_PULSE_OFF or RELAY_PULSE_ON @@ -300,27 +308,33 @@ void _relayProviderStatus(unsigned char id, bool status) { #endif - #if (RELAY_PROVIDER == RELAY_PROVIDER_RELAY) || (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT) + #if (RELAY_PROVIDER == RELAY_PROVIDER_RELAY) || \ + (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT) || \ + (RELAY_PROVIDER == RELAY_PROVIDER_MCP23S08) // If this is a light, all dummy relays have already been processed above // we reach here if the user has toggled a physical relay if (_relays[id].type == RELAY_TYPE_NORMAL) { - digitalWrite(_relays[id].pin, status); + _relays[id].pin->digitalWrite(status); } else if (_relays[id].type == RELAY_TYPE_INVERSE) { - digitalWrite(_relays[id].pin, !status); + _relays[id].pin->digitalWrite(!status); } else if (_relays[id].type == RELAY_TYPE_LATCHED || _relays[id].type == RELAY_TYPE_LATCHED_INVERSE) { bool pulse = (_relays[id].type == RELAY_TYPE_LATCHED) ? HIGH : LOW; - digitalWrite(_relays[id].pin, !pulse); - if (GPIO_NONE != _relays[id].reset_pin) digitalWrite(_relays[id].reset_pin, !pulse); - if (status || (GPIO_NONE == _relays[id].reset_pin)) { - digitalWrite(_relays[id].pin, pulse); + _relays[id].pin->digitalWrite(!pulse); + if (GPIO_NONE != _relays[id].reset_pin->pin) { + _relays[id].reset_pin->digitalWrite(!pulse); + } + if (status || (GPIO_NONE == _relays[id].reset_pin->pin)) { + _relays[id].pin->digitalWrite(pulse); } else { - digitalWrite(_relays[id].reset_pin, pulse); + _relays[id].reset_pin->digitalWrite(pulse); } nice_delay(RELAY_LATCHING_PULSE); - digitalWrite(_relays[id].pin, !pulse); - if (GPIO_NONE != _relays[id].reset_pin) digitalWrite(_relays[id].reset_pin, !pulse); + _relays[id].pin->digitalWrite(!pulse); + if (GPIO_NONE != _relays[id].reset_pin->pin) { + _relays[id].reset_pin->digitalWrite(!pulse); + } } #endif @@ -471,7 +485,7 @@ void INLINE _relayMaskRtcmem(const RelayMask& mask) { _relayMaskRtcmem(mask.as_u32); } -void INLINE _relayMaskRtcmem(const std::bitset& bitset) { +void INLINE _relayMaskRtcmem(const std::bitset& bitset) { _relayMaskRtcmem(bitset.to_ulong()); } @@ -489,7 +503,7 @@ void INLINE _relayMaskSettings(const RelayMask& mask) { setSetting("relayBootMask", mask.as_string); } -void INLINE _relayMaskSettings(const std::bitset& bitset) { +void INLINE _relayMaskSettings(const std::bitset& bitset) { _relayMaskSettings(bitset.to_ulong()); } @@ -682,9 +696,9 @@ void relaySync(unsigned char id) { void relaySave(bool eeprom) { - const unsigned char count = constrain(relayCount(), 0, RELAYS_MAX); + const unsigned char count = constrain(relayCount(), 0, RelaysMax); - auto statuses = std::bitset(0); + auto statuses = std::bitset(0); for (unsigned int id = 0; id < count; ++id) { statuses.set(id, relayStatus(id)); } @@ -766,7 +780,7 @@ void _relayBoot() { DEBUG_MSG_P(PSTR("[RELAY] Retrieving mask: %s\n"), stored_mask.as_string.c_str()); - auto mask = std::bitset(stored_mask.as_u32); + auto mask = std::bitset(stored_mask.as_u32); // Walk the relays unsigned char lock; @@ -835,15 +849,17 @@ void _relayConfigure() { _relays[i].delay_on = getSetting({"relayDelayOn", i}, _relayDelayOn(i)); _relays[i].delay_off = getSetting({"relayDelayOff", i}, _relayDelayOff(i)); - if (GPIO_NONE == _relays[i].pin) continue; + // make sure pin is valid before continuing with writes + if (!static_cast(*_relays[i].pin)) continue; - pinMode(_relays[i].pin, OUTPUT); - if (GPIO_NONE != _relays[i].reset_pin) { - pinMode(_relays[i].reset_pin, OUTPUT); + _relays[i].pin->pinMode(OUTPUT); + if (static_cast(*_relays[i].reset_pin)) { + _relays[i].reset_pin->pinMode(OUTPUT); } + if (_relays[i].type == RELAY_TYPE_INVERSE) { //set to high to block short opening of relay - digitalWrite(_relays[i].pin, HIGH); + _relays[i].pin->digitalWrite(HIGH); } } @@ -887,9 +903,9 @@ void _relayWebSocketUpdate(JsonObject& root) { } String _relayFriendlyName(unsigned char i) { - String res = String("GPIO") + String(_relays[i].pin); + String res = String("GPIO") + String(_relays[i].pin->pin); - if (GPIO_NONE == _relays[i].pin) { + if (GPIO_NONE == _relays[i].pin->pin) { #if (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT) uint8_t physical = _relays.size() - _relayDummy; if (i >= physical) { @@ -942,7 +958,7 @@ void _relayWebSocketSendRelays(JsonObject& root) { gpio.add(_relayFriendlyName(i)); type.add(_relays[i].type); - reset.add(_relays[i].reset_pin); + reset.add(_relays[i].reset_pin->pin); boot.add(getSetting({"relayBoot", i}, RELAY_BOOT_MODE)); pulse.add(_relays[i].pulse); @@ -1401,7 +1417,7 @@ void relaySetupDummy(size_t size, bool reconfigure) { if (size == _relayDummy) return; const size_t new_size = ((_relays.size() - _relayDummy) + size); - if (new_size > RELAYS_MAX) return; + if (new_size > RelaysMax) return; _relayDummy = size; _relays.resize(new_size); @@ -1418,7 +1434,7 @@ void relaySetupDummy(size_t size, bool reconfigure) { void _relaySetupAdhoc() { - size_t relays = 0; + size_t relays [[gnu::unused]] = 0; #if RELAY1_PIN != GPIO_NONE ++relays; @@ -1446,8 +1462,30 @@ void _relaySetupAdhoc() { #endif _relays.reserve(relays); - for (unsigned char id = 0; id < relays; ++id) { - _relays.emplace_back(id); + + #if (RELAY_PROVIDER == RELAY_PROVIDER_RELAY) || (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT) + using gpio_type = GpioPin; + #elif (RELAY_PROVIDER == RELAY_PROVIDER_MCP23S08) + using gpio_type = McpGpioPin; + #endif + + for (unsigned char id = 0; id < RelaysMax; ++id) { + const auto pin = _relayPin(id); + #if (RELAY_PROVIDER == RELAY_PROVIDER_RELAY) || (RELAY_PROVIDER == RELAY_PROVIDER_LIGHT) + if (!gpioValid(pin)) { + break; + } + #elif (RELAY_PROVIDER == RELAY_PROVIDER_MCP23S08) + if (!mcpGpioValid(pin)) { + break; + } + #endif + + _relays.emplace_back( + std::make_unique(_relayPin(id)), + _relayType(id), + std::make_unique(_relayResetPin(id)) + ); } } diff --git a/code/espurna/relay.h b/code/espurna/relay.h index 4ac69618..a6ba5aa1 100644 --- a/code/espurna/relay.h +++ b/code/espurna/relay.h @@ -13,7 +13,7 @@ Copyright (C) 2016-2019 by Xose Pérez #include -constexpr size_t RELAYS_MAX = 32; +constexpr size_t RelaysMax = 32; PayloadStatus relayParsePayload(const char * payload); diff --git a/code/platformio.ini b/code/platformio.ini index 063cb92b..e38bf4ac 100644 --- a/code/platformio.ini +++ b/code/platformio.ini @@ -1064,3 +1064,8 @@ src_build_flags = -DARLEC_PC190HA [env:arlec-pb89ha] extends = env:esp8266-1m-base src_build_flags = -DARLEC_PB89HA + +[env:prodino-wifi] +extends = env:esp8266-2m-base +src_build_flags = -DPRODINO_WIFI -DNOWSAUTH +