Add gpio config

This commit is contained in:
fvanroie 2020-06-12 13:32:35 +02:00
parent 4fcf0e19e7
commit a237d076d7
3 changed files with 428 additions and 62 deletions

View File

@ -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)
{

View File

@ -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

View File

@ -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<JsonObject>());
// DynamicJsonDocument settings(256);
// gpioGetConfig(settings.to<JsonObject>());
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("<form method='POST' action='/config'>");
httpMessage += F("<table><tr><th>Pin</th><th>Type</th><th>Channel</th><th>Normal</th><th>Options</th></tr>");
// httpMessage += F("<tr><td>D1</td><td>Button</td><td>1</td><td>High</td><td>Options</td><tr>");
// httpMessage += F("<tr><td>D2</td><td>Switch</td><td>2</td><td>High</td><td>Options</td><tr>");
// httpMessage += F("<tr><td>D4</td><td>Backligth</td><td>15</td><td>Low</td><td>Options</td><tr>");
httpMessage += F("<table><tr><th>Pin</th><th>Type</th><th>Group</th><th>Default</th><th>Action</th></tr>");
for(uint8_t i = 0; i < NUM_DIGITAL_PINS; i++) {
httpMessage += F("<tr><td>");
httpMessage += String(i);
httpMessage += F("</td><td>None</td><td>15</td><td>Low</td><td><a href='/config/gpio/options?io=");
httpMessage += String(i);
httpMessage += ("'>Options</a></td><tr>");
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("<tr><td>");
httpMessage += gpioName(gpio);
httpMessage += F("</td><td>");
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("</td><td>");
httpMessage += conf.group;
httpMessage += F("</td><td>Low</td><td><a href='/config/gpio/options?id=");
httpMessage += id;
httpMessage += ("'>Edit</a> <a href='/config/gpio?save=&id=");
httpMessage += id;
httpMessage += ("'>Delete</a></td><tr>");
configCount++;
}
}
}
httpMessage += F("</table>");
httpMessage += F("</table></form>");
// httpMessage += F("</p><p><button type='submit' name='save' value='debug'>Save
// Settings</button></p></form>");
if(configCount < HASP_NUM_GPIO_CONFIG) {
httpMessage += PSTR("<p><form method='GET' action='gpio/options'>");
httpMessage += F("<input type='hidden' name='id' value='");
httpMessage += gpioGetFreeConfigId();
httpMessage += PSTR("'><button type='submit'>Add New Pin</button></form></p>");
}
httpMessage +=
PSTR("<p><form method='get' action='/config'><button type='submit'>Configuration</button></form></p>");
httpMessage += PSTR(
"<p><form method='get' action='/config'><button type='submit'>&#8617; Configuration</button></form></p>");
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<JsonObject>());
uint8_t config_id = webServer.arg(F("id")).toInt();
String httpMessage((char *)0);
httpMessage.reserve(HTTP_PAGE_SIZE);
httpMessage += F("<h1>");
httpMessage += httpGetNodename();
httpMessage += F("</h1><hr>");
httpMessage += F("<form method='POST' action='/config/gpio'>");
httpMessage += F("<form method='GET' action='/config/gpio'>");
httpMessage += F("<input type='hidden' name='id' value='");
httpMessage += config_id;
httpMessage += F("'>");
httpMessage += F("<p><b>GPIO >");
httpMessage += webServer.arg(0);
httpMessage += F("< Options</b></p>");
httpMessage += F("<p><b>GPIO Options");
httpMessage += config_id;
httpMessage += F(" Options</b></p>");
httpMessage += F("<p><b>Pin</b> <select id='pin' name='pin'>");
hasp_gpio_config_t conf = gpioGetPinConfig(config_id);
for(uint8_t io = 0; io < NUM_DIGITAL_PINS; io++) {
if(((conf.pin == io) || !gpioInUse(io)) && !gpioIsSystemPin(io)) {
httpMessage += getOption(io, gpioName(io), conf.pin == io);
}
}
httpMessage += F("</select></p>");
bool selected;
httpMessage += F("<p><b>Type</b> <select id='type' name='type'>");
// httpMessage += getOption(HASP_GPIO_FREE, F("Unused"), false);
selected = (conf.type == HASP_GPIO_SWITCH) || (conf.type == HASP_GPIO_SWITCH_INVERTED);
httpMessage += getOption(HASP_GPIO_SWITCH, F("Switch"), selected);
selected = (conf.type == HASP_GPIO_BUTTON) || (conf.type == HASP_GPIO_BUTTON_INVERTED);
httpMessage += getOption(HASP_GPIO_BUTTON, F("Button"), selected);
selected = (conf.type == HASP_GPIO_LED) || (conf.type == HASP_GPIO_LED_INVERTED);
httpMessage += getOption(HASP_GPIO_LED, F("Led"), selected);
selected = (conf.type == HASP_GPIO_RELAY) || (conf.type == HASP_GPIO_RELAY_INVERTED);
httpMessage += getOption(HASP_GPIO_RELAY, F("Relay"), selected);
httpMessage += F("<p><b>Type</b> <select id='ioType' name='ioType'>");
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("</select></p>");
httpMessage += F("<p><b>Channel</b> <select id='ioChannel' name='ioChannel'>");
httpMessage += F("<p><b>Channel</b> <select id='chan' name='chan'>");
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("</select></p>");
httpMessage += F("<p><b>Default State</b> <select id='ioState' name='ioState'>");
httpMessage += getOption(0, F("High"), false);
httpMessage += getOption(1, F("Low"), false);
httpMessage += F("<p><b>Default State</b> <select id='state' name='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("</select></p>");
httpMessage += F("<p><button type='submit' name='save' value='gui'>Save Settings</button></p></form>");
httpMessage += F("<p><button type='submit' name='save' value='gpio'>Save Settings</button></p></form>");
httpMessage += PSTR(
"<p><form method='get' action='/config/gpio'><button type='submit'> GPIO Settings</button></form></p>");
httpMessage +=
PSTR("<p><form method='get' action='/config/gpio'><button type='submit'>&#8617; Back</button></form></p>");
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()