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("
");
+ if(configCount < HASP_NUM_GPIO_CONFIG) {
+ httpMessage += PSTR("");
+ }
- 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 += 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()