From a237d076d79feaa406b4689ddad83ea44f63ab2d Mon Sep 17 00:00:00 2001 From: fvanroie Date: Fri, 12 Jun 2020 13:32:35 +0200 Subject: [PATCH] Add gpio config --- src/hasp_gpio.cpp | 284 ++++++++++++++++++++++++++++++++++++++++++++-- src/hasp_gpio.h | 53 ++++++--- src/hasp_http.cpp | 153 +++++++++++++++++++------ 3 files changed, 428 insertions(+), 62 deletions(-) diff --git a/src/hasp_gpio.cpp b/src/hasp_gpio.cpp index 391f56a1..b59152bd 100644 --- a/src/hasp_gpio.cpp +++ b/src/hasp_gpio.cpp @@ -15,14 +15,6 @@ uint8_t gpioUsedInputCount = 0; using namespace ace_button; static AceButton * button[HASP_NUM_INPUTS]; -struct hasp_gpio_config_t -{ - uint8_t pin; // pin number - uint8_t group; // groupid - uint8_t type; // switch, button, ... - uint8_t gpio_function; // INPUT, OUTPUT, PULLUP, etc -}; - hasp_gpio_config_t gpioConfig[HASP_NUM_GPIO_CONFIG]; #if defined(ARDUINO_ARCH_ESP32) @@ -192,8 +184,8 @@ void gpioSetup() #endif #if defined(ARDUINO_ARCH_ESP32) - gpioConfig[0] = {D2, 0, HASP_GPIO_SWITCH, INPUT}; - gpioConfig[1] = {D1, 1, HASP_GPIO_RELAY, OUTPUT}; + gpioConfig[0] = {D2, 0, HASP_GPIO_SWITCH, INPUT}; + gpioConfig[1] = {D1, 1, HASP_GPIO_RELAY, OUTPUT}; // gpioAddButton(D2, INPUT, HIGH, 1); // pinMode(D1, OUTPUT); @@ -234,7 +226,7 @@ void gpioSetup() gpioAddButton(gpioConfig[i].pin, input_mode, HIGH, i); break; case HASP_GPIO_SWITCH_INVERTED: - case HASP_GPIO_INPUT_BUTTON_INVERTED: + case HASP_GPIO_BUTTON_INVERTED: gpioAddButton(gpioConfig[i].pin, input_mode, LOW, i); break; @@ -295,6 +287,276 @@ void gpio_set_group_outputs(uint8_t groupid, uint8_t eventid) } } +bool gpioIsSystemPin(uint8_t gpio) +{ + if((gpio >= NUM_DIGITAL_PINS) // invalid pins + +// Use individual checks instead of switch statement, as some case labels could be duplicated +#ifdef TOUCH_CS + || (gpio == TOUCH_CS) +#endif +#ifdef TFT_MOSI + || (gpio == TFT_MOSI) +#endif +#ifdef TFT_MISO + || (gpio == TFT_MISO) +#endif +#ifdef TFT_SCLK + || (gpio == TFT_SCLK) +#endif +#ifdef TFT_CS + || (gpio == TFT_CS) +#endif +#ifdef TFT_DC + || (gpio == TFT_DC) +#endif +#ifdef TFT_BL + || (gpio == TFT_BL) +#endif +#ifdef TFT_RST + || (gpio == TFT_RST) +#endif +#ifdef TFT_WR + || (gpio == TFT_WR) +#endif +#ifdef TFT_RD + || (gpio == TFT_RD) +#endif +#ifdef TFT_D0 + || (gpio == TFT_D0) +#endif +#ifdef TFT_D1 + || (gpio == TFT_D1) +#endif +#ifdef TFT_D2 + || (gpio == TFT_D2) +#endif +#ifdef TFT_D3 + || (gpio == TFT_D3) +#endif +#ifdef TFT_D4 + || (gpio == TFT_D4) +#endif +#ifdef TFT_D5 + || (gpio == TFT_D5) +#endif +#ifdef TFT_D6 + || (gpio == TFT_D6) +#endif +#ifdef TFT_D7 + || (gpio == TFT_D7) +#endif +#ifdef TFT_D8 + || (gpio == TFT_D8) +#endif +#ifdef TFT_D9 + || (gpio == TFT_D9) +#endif +#ifdef TFT_D10 + || (gpio == TFT_D10) +#endif +#ifdef TFT_D11 + || (gpio == TFT_D11) +#endif +#ifdef TFT_D12 + || (gpio == TFT_D12) +#endif +#ifdef TFT_D13 + || (gpio == TFT_D13) +#endif +#ifdef TFT_D14 + || (gpio == TFT_D14) +#endif +#ifdef TFT_D15 + || (gpio == TFT_D15) +#endif + ) { + return true; + } // if tft_espi pins + + // To-do: + // Network GPIOs + // Serial GPIOs + // Tasmota GPIOs + +#ifdef ARDUINO_ARCH_ESP8266 + if((gpio >= 6) && (gpio <= 11)) return true; // VSPI +#ifndef TFT_SPI_OVERLAP + if((gpio >= 12) && (gpio <= 14)) return true; // HSPI +#endif +#endif + + return false; +} + +bool gpioInUse(uint8_t gpio) +{ + for(uint8_t i = 0; i < HASP_NUM_GPIO_CONFIG; i++) { + if(gpioConfigInUse(i) && (gpioConfig[i].pin == gpio)) { + return true; // pin matches and is in use + } + } + + return false; +} + +bool gpioSavePinConfig(uint8_t config_num, uint8_t pin, uint8_t type, uint8_t group, uint8_t pinfunc) +{ + // Input validation + + // ESP8266: Only Pullups except on gpio16 + + // ESP32: Pullup or Pulldown except on 34-39 + + if(config_num < HASP_NUM_GPIO_CONFIG && !gpioIsSystemPin(pin)) { + gpioConfig[config_num].pin = pin; + gpioConfig[config_num].type = type; + gpioConfig[config_num].group = group; + gpioConfig[config_num].gpio_function = pinfunc; + Log.notice(F("GPIO: Saving Pin config #%d pin %d - type %d - group %d - func %d"), config_num, pin, type, group, + pinfunc); + return true; + } + + return false; +} + +bool gpioConfigInUse(uint8_t num) +{ + if(num >= HASP_NUM_GPIO_CONFIG) return false; + return gpioConfig[num].type != HASP_GPIO_FREE; +} + +int8_t gpioGetFreeConfigId() +{ + uint8_t id = 0; + while(id < HASP_NUM_GPIO_CONFIG) { + if(!gpioConfigInUse(id)) return id; + id++; + } + return -1; +} + +hasp_gpio_config_t gpioGetPinConfig(uint8_t num) +{ + return gpioConfig[num]; +} + +String gpioName(uint8_t gpio) +{ +#if defined(STM32F4xx) + String ioName; + uint16_t name = digitalPin[gpio]; + uint8_t num = name % 16; + switch(name / 16) { + case PortName::PortA: + ioName = F("PA"); + break; + case PortName::PortB: + ioName = F("PB"); + break; +#if defined GPIOC_BASE + case PortName::PortC: + ioName = F("PC"); + break; +#endif +#if defined GPIOD_BASE + case PortName::PortD: + ioName = F("PD"); + break; +#endif +#if defined GPIOE_BASE + case PortName::PortE: + ioName = F("PE"); + break; +#endif +#if defined GPIOF_BASE + case PortName::PortF: + ioName = F("PF"); + break; +#endif +#if defined GPIOG_BASE + case PortName::PortG: + ioName = F("PG"); + break; +#endif +#if defined GPIOH_BASE + case PortName::PortH: + ioName = F("PH"); + break; +#endif +#if defined GPIOI_BASE + case PortName::PortI: + ioName = F("PI"); + break; +#endif +#if defined GPIOJ_BASE + case PortName::PortJ: + ioName = F("PJ"); + break; +#endif +#if defined GPIOK_BASE + case PortName::PortK: + ioName = F("PK"); + break; +#endif +#if defined GPIOZ_BASE + case PortName::PortZ: + ioName = F("PZ"); + break; +#endif + default: + ioName = F("P?"); + } + ioName += num; + ioName += F(" (io"); + ioName += gpio; + ioName += F(")"); + return ioName; +#endif + +// For ESP32 pin labels on boards use the GPIO number +#ifdef ARDUINO_ARCH_ESP32 + return String(F("gpio")) + gpio; +#endif + +#ifdef ARDUINO_ARCH_ESP8266 + // For ESP8266 the pin labels are not the same as the GPIO number + // These are for the NodeMCU pin definitions: + // GPIO Dxx + switch(gpio) { + case 16: + return F("D0"); + case 5: + return F("D1"); + case 4: + return F("D2"); + case 0: + return F("D3"); + case 2: + return F("D4"); + case 14: + return F("D5"); + case 12: + return F("D6"); + case 13: + return F("D7"); + case 15: + return F("D8"); + case 3: + return F("TX"); + case 1: + return F("RX"); + // case 9: + // return F("D11"); + // case 10: + // return F("D12"); + default: + return F("D?"); // Invalid pin + } +#endif +} + //////////////////////////////////////////////////////////////////////////////////////////////////// bool gpioGetConfig(const JsonObject & settings) { diff --git a/src/hasp_gpio.h b/src/hasp_gpio.h index f7fa73af..6f529bb5 100644 --- a/src/hasp_gpio.h +++ b/src/hasp_gpio.h @@ -7,31 +7,56 @@ extern "C" { #endif +struct hasp_gpio_config_t +{ + uint8_t pin; // pin number + uint8_t group; // groupid + uint8_t type; // switch, button, ... + uint8_t gpio_function; // INPUT, OUTPUT, PULLUP, etc +}; + void gpioSetup(void); void IRAM_ATTR gpioLoop(void); void gpio_set_group_outputs(uint8_t groupid, uint8_t eventid); +String gpioName(uint8_t gpio); +bool gpioSavePinConfig(uint8_t config_num, uint8_t pin, uint8_t type, uint8_t group, uint8_t pinfunc); +bool gpioIsSystemPin(uint8_t gpio); +bool gpioInUse(uint8_t gpio); +bool gpioConfigInUse(uint8_t num); +int8_t gpioGetFreeConfigId(); +hasp_gpio_config_t gpioGetPinConfig(uint8_t num); bool gpioGetConfig(const JsonObject & settings); bool gpioSetConfig(const JsonObject & settings); #define HASP_GPIO_FREE 0x00 #define HASP_GPIO_USED 0x01 -#define HASP_GPIO_SWITCH 0x02 +#define HASP_GPIO_SWITCH 0x02 // User Inputs #define HASP_GPIO_SWITCH_INVERTED 0x03 #define HASP_GPIO_BUTTON 0x04 -#define HASP_GPIO_INPUT_BUTTON_INVERTED 0x05 -#define HASP_GPIO_COUNTER 0x06 -#define HASP_GPIO_COUNTER_INVERTED 0x07 -#define HASP_GPIO_ADC 0x08 -#define HASP_GPIO_ADC_INVERTED 0x09 -#define HASP_GPIO_RELAY 0x0A -#define HASP_GPIO_RELAY_INVERTED 0x0B -#define HASP_GPIO_LED 0x0C -#define HASP_GPIO_LED_INVERTED 0x0D -#define HASP_GPIO_PWM 0x0E -#define HASP_GPIO_PWM_INVERTED 0x0F -#define HASP_GPIO_DAC 0x10 -#define HASP_GPIO_DAC_INVERTED 0x11 +#define HASP_GPIO_BUTTON_INVERTED 0x05 +#define HASP_GPIO_TOUCH 0x06 +#define HASP_GPIO_TOUCH_INVERTED 0x07 +#define HASP_GPIO_COUNTER_RISE 0x10 // User Counters +#define HASP_GPIO_COUNTER_RISE_INVERTED 0x11 +#define HASP_GPIO_COUNTER_FALL 0x12 +#define HASP_GPIO_COUNTER_FALL_INVERTED 0x13 +#define HASP_GPIO_COUNTER_BOTH 0x14 +#define HASP_GPIO_COUNTER_BOTH_INVERTED 0x15 +#define HASP_GPIO_RELAY 0x20 // User Outputs +#define HASP_GPIO_RELAY_INVERTED 0x21 +#define HASP_GPIO_LED 0x22 +#define HASP_GPIO_LED_INVERTED 0x23 +#define HASP_GPIO_BUZZER 0x30 +#define HASP_GPIO_BUZZER_INVERTED 0x31 +#define HASP_GPIO_HAPTIC 0x32 +#define HASP_GPIO_HAPTIC_INVERTED 0x33 +#define HASP_GPIO_PWM 0x40 +#define HASP_GPIO_PWM_INVERTED 0x41 +#define HASP_GPIO_DAC 0x50 +#define HASP_GPIO_DAC_INVERTED 0x51 +#define HASP_GPIO_ADC 0x52 +#define HASP_GPIO_ADC_INVERTED 0x53 #define HASP_GPIO_USER 0xFF #ifdef __cplusplus diff --git a/src/hasp_http.cpp b/src/hasp_http.cpp index 16667ad2..a4d4f050 100644 --- a/src/hasp_http.cpp +++ b/src/hasp_http.cpp @@ -1180,12 +1180,23 @@ void webHandleHttpConfig() #endif //////////////////////////////////////////////////////////////////////////////////////////////////// +#if defined(HASP_USE_GPIO) && (HASP_USE_GPIO > 0) void webHandleGpioConfig() { // http://plate01/config/gpio if(!httpIsAuthenticated(F("config/gpio"))) return; + uint8_t configCount = 0; - DynamicJsonDocument settings(256); - debugGetConfig(settings.to()); + // DynamicJsonDocument settings(256); + // gpioGetConfig(settings.to()); + + if(webServer.hasArg(PSTR("save"))) { + uint8_t id = webServer.arg(F("id")).toInt(); + uint8_t pin = webServer.arg(F("pin")).toInt() + webServer.arg(F("state")).toInt(); + uint8_t type = webServer.arg(F("type")).toInt(); + uint8_t group = webServer.arg(F("chan")).toInt(); + uint8_t pinfunc = webServer.arg(F("func")).toInt(); + gpioSavePinConfig(id, pin, type, group, pinfunc); + } { String httpMessage((char *)0); @@ -1196,26 +1207,64 @@ void webHandleGpioConfig() httpMessage += F("
"); - httpMessage += F(""); - // httpMessage += F(""); - // httpMessage += F(""); - // httpMessage += F(""); + httpMessage += F("
PinTypeChannelNormalOptions
D1Button1HighOptions
D2Switch2HighOptions
D4Backligth15LowOptions
"); - for(uint8_t i = 0; i < NUM_DIGITAL_PINS; i++) { - httpMessage += F(""); + for(uint8_t gpio = 0; gpio < NUM_DIGITAL_PINS; gpio++) { + for(uint8_t id = 0; id < HASP_NUM_GPIO_CONFIG; id++) { + hasp_gpio_config_t conf = gpioGetPinConfig(id); + if((conf.pin == gpio) && gpioConfigInUse(id) && gpioInUse(gpio) && !gpioIsSystemPin(gpio)) { + httpMessage += F(""); + configCount++; + } + } } - httpMessage += F("
PinTypeGroupDefaultAction
"); - httpMessage += String(i); - httpMessage += F("None15LowOptions
"); + httpMessage += gpioName(gpio); + httpMessage += F(""); + + switch(conf.type) { + case HASP_GPIO_SWITCH: + case HASP_GPIO_SWITCH_INVERTED: + httpMessage += F("Switch"); + break; + case HASP_GPIO_BUTTON: + case HASP_GPIO_BUTTON_INVERTED: + httpMessage += F("Button"); + break; + case HASP_GPIO_LED: + case HASP_GPIO_LED_INVERTED: + httpMessage += F("Led"); + break; + case HASP_GPIO_RELAY: + case HASP_GPIO_RELAY_INVERTED: + httpMessage += F("Relay"); + break; + case HASP_GPIO_PWM: + case HASP_GPIO_PWM_INVERTED: + httpMessage += F("PWM"); + break; + default: + httpMessage += F("Unknown"); + } + + httpMessage += F(""); + httpMessage += conf.group; + httpMessage += F("LowEdit Delete
"); + httpMessage += F("
"); - // httpMessage += F("

"); + if(configCount < HASP_NUM_GPIO_CONFIG) { + httpMessage += PSTR("

"); + httpMessage += F("

"); + } - httpMessage += - PSTR("

"); + httpMessage += PSTR( + "

"); webSendPage(httpGetNodename(), httpMessage.length(), false); webServer.sendContent(httpMessage); @@ -1227,50 +1276,79 @@ void webHandleGpioConfig() //////////////////////////////////////////////////////////////////////////////////////////////////// void webHandleGpioOptions() { // http://plate01/config/gpio/options - if(!httpIsAuthenticated(F("config/gpio"))) return; + if(!httpIsAuthenticated(F("config/gpio/options"))) return; { DynamicJsonDocument settings(256); guiGetConfig(settings.to()); + uint8_t config_id = webServer.arg(F("id")).toInt(); + String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); httpMessage += F("

"); httpMessage += httpGetNodename(); httpMessage += F("


"); - httpMessage += F("
"); + httpMessage += F(""); + httpMessage += F(""); - httpMessage += F("

GPIO >"); - httpMessage += webServer.arg(0); - httpMessage += F("< Options

"); + httpMessage += F("

GPIO Options"); + httpMessage += config_id; + httpMessage += F(" Options

"); + + httpMessage += F("

Pin

"); + + bool selected; + httpMessage += F("

Type "); - httpMessage += getOption(HASP_GPIO_FREE, F("None"), false); - httpMessage += getOption(HASP_GPIO_SWITCH, F("Switch"), false); - httpMessage += getOption(HASP_GPIO_BUTTON, F("Button"), false); - httpMessage += getOption(HASP_GPIO_LED, F("Switch"), false); - httpMessage += getOption(HASP_GPIO_RELAY, F("Button"), false); if(digitalPinHasPWM(webServer.arg(0).toInt())) { - httpMessage += getOption(HASP_GPIO_PWM, F("PWM"), false); + selected = (conf.type == HASP_GPIO_PWM) || (conf.type == HASP_GPIO_PWM_INVERTED); + httpMessage += getOption(HASP_GPIO_PWM, F("PWM"), selected); } httpMessage += F("

"); - httpMessage += F("

Channel "); for(uint8_t i = 0; i < 15; i++) { - httpMessage += getOption(i, "Channel " + String(i), false); + httpMessage += getOption(i, "Channel " + String(i), i == conf.group); } httpMessage += F("

"); - httpMessage += F("

Default State "); + selected = (conf.type == HASP_GPIO_BUTTON_INVERTED) || (conf.type == HASP_GPIO_SWITCH_INVERTED) || + (conf.type == HASP_GPIO_LED_INVERTED) || (conf.type == HASP_GPIO_RELAY_INVERTED) || + (conf.type == HASP_GPIO_PWM_INVERTED); + httpMessage += getOption(0, F("High"), !selected); + httpMessage += getOption(1, F("Low"), selected); httpMessage += F("

"); - httpMessage += F("

"); + httpMessage += F("

"); - httpMessage += PSTR( - "

"); + httpMessage += + PSTR("

"); webSendPage(httpGetNodename(), httpMessage.length(), false); webServer.sendContent(httpMessage); @@ -1279,6 +1357,7 @@ void webHandleGpioOptions() if(webServer.hasArg(F("action"))) dispatchCommand(webServer.arg(F("action"))); } +#endif // HASP_USE_GPIO //////////////////////////////////////////////////////////////////////////////////////////////////// void webHandleDebugConfig()