diff --git a/front-end b/front-end index ef05565..f729d91 160000 --- a/front-end +++ b/front-end @@ -1 +1 @@ -Subproject commit ef055651557a23376995a79278e4b2e85ba96ee1 +Subproject commit f729d91651fda22ebdd94d41ebc7e0aa47a2c2e6 diff --git a/user/api.h b/user/api.h index 7f16a8b..21e5ac7 100644 --- a/user/api.h +++ b/user/api.h @@ -11,5 +11,6 @@ #define API_REBOOT "/api/v1/reboot" #define API_PING "/api/v1/ping" #define API_CLEAR "/api/v1/clear" +#define API_GPIO "/api/v1/gpio" #endif //ESPTERM_API_H diff --git a/user/cgi_d2d.c b/user/cgi_d2d.c index 1c28235..fd4fa79 100644 --- a/user/cgi_d2d.c +++ b/user/cgi_d2d.c @@ -178,7 +178,7 @@ d2d_parse_command(char *msg) else if (strstarts(msg, "H;")) { if (request_pending) return false; - // Send a esp-esp message + // Send a HTTP request msg += 2; const char *method = NULL; const char *params = NULL; diff --git a/user/cgi_system.c b/user/cgi_system.c index b780268..33ec37b 100755 --- a/user/cgi_system.c +++ b/user/cgi_system.c @@ -234,3 +234,129 @@ tplSystemCfg(HttpdConnData *connData, char *token, void **arg) tplSend(connData, buff, -1); return HTTPD_CGI_DONE; } + + +static ETSTimer tmrPulse; + +static void ICACHE_FLASH_ATTR tmrPulseCb(void *arg) +{ + u32 mask = sysconf->gpio2_conf==GPIOCONF_OFF ? 0x30 : 0x34; + u32 argu = (u32) arg; + u32 set_on = argu & mask; + u32 set_off = (argu >> 16) & mask; + gpio_output_set(set_off, set_on, 0, 0); // the args are swapped here to achieve the opposite +} + +/** + * API to set GPIOs + * + * @param connData + * @return + */ +httpd_cgi_state ICACHE_FLASH_ATTR cgiGPIO(HttpdConnData *connData) +{ +#define BUFLEN 100 + char buff[BUFLEN]; + + if (connData->conn==NULL) { + //Connection aborted. Clean up. + return HTTPD_CGI_DONE; + } + + bool set = 0; + u32 inputs = gpio_input_get(); + + // TODO pulse option + + // args are do2, do4, do5. Values: 0 - off, 1 - on, -1 - toggle + + s8 set_d2 = -1, set_d4 = -1, set_d5 = -1; + + if (sysconf->gpio2_conf == GPIOCONF_OUT_START_0 || sysconf->gpio2_conf == GPIOCONF_OUT_START_1) { + if (GET_ARG("do2")) { + if (buff[0] == 't') { + set = ((inputs&(1<<2)) == 0); + } else { + set = buff[0] == '1'; + } + set_d2 = set; + gpio_output_set((uint32) (set << 2), (uint32) ((!set) << 2), 0, 0); + } + } + + if (sysconf->gpio4_conf == GPIOCONF_OUT_START_0 || sysconf->gpio4_conf == GPIOCONF_OUT_START_1) { + if (GET_ARG("do4")) { + if (buff[0] == 't') { + set = ((inputs&(1<<4)) == 0); + } else { + set = buff[0] == '1'; + } + set_d4 = set; + gpio_output_set((uint32) (set << 4), (uint32) ((!set) << 4), 0, 0); + } + } + + if (sysconf->gpio5_conf == GPIOCONF_OUT_START_0 || sysconf->gpio5_conf == GPIOCONF_OUT_START_1) { + if (GET_ARG("do5")) { + if (buff[0] == 't') { + set = ((inputs&(1<<5)) == 0); + } else { + set = buff[0] == '1'; + } + set_d5 = set; + gpio_output_set((uint32) (set << 5), (uint32) ((!set) << 5), 0, 0); + } + } + + if (GET_ARG("pulse")) { + int duration = atoi(buff); + + if (duration > 0) { + u32 cmd = 0; + if (set_d2 != -1) { + if (set_d2) { + cmd |= 1<<2; + } else { + cmd |= 1<<(16+2); + } + } + + if (set_d4 != -1) { + if (set_d4) { + cmd |= 1<<4; + } else { + cmd |= 1<<(16+4); + } + } + + if (set_d5 != -1) { + if (set_d5) { + cmd |= 1<<5; + } else { + cmd |= 1<<(16+5); + } + } + + os_timer_disarm(&tmrPulse); + os_timer_setfn(&tmrPulse, tmrPulseCb, (void*) cmd); + os_timer_arm(&tmrPulse, duration, false); + } + } + + httpdStartResponse(connData, 200); + httpdHeader(connData, "Content-Type", "application/json"); + httpdEndHeaders(connData); + + // refresh inputs + inputs = gpio_input_get(); + + sprintf(buff, "{\"io2\":%d,\"io4\":%d,\"io5\":%d}", + ((inputs&(1<<2)) != 0), + ((inputs&(1<<4)) != 0), + ((inputs&(1<<5)) != 0) + ); + + httpdSend(connData, buff, -1); + + return HTTPD_CGI_DONE; +} diff --git a/user/cgi_system.h b/user/cgi_system.h index 6aca8b8..0c0626e 100755 --- a/user/cgi_system.h +++ b/user/cgi_system.h @@ -9,5 +9,6 @@ httpd_cgi_state cgiResetDevice(HttpdConnData *connData); httpd_cgi_state cgiSystemCfgSetParams(HttpdConnData *connData); httpd_cgi_state tplSystemCfg(HttpdConnData *connData, char *token, void **arg); httpd_cgi_state cgiResetScreen(HttpdConnData *connData); +httpd_cgi_state cgiGPIO(HttpdConnData *connData); #endif // CGI_PING_H diff --git a/user/io.c b/user/io.c index 223fea1..98d330d 100644 --- a/user/io.c +++ b/user/io.c @@ -98,7 +98,10 @@ static void ICACHE_FLASH_ATTR resetBtnTimerCb(void *arg) { } else { // Switch LED pins back to UART mode PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + if (sysconf->gpio2_conf == GPIOCONF_OFF) { + // only if uart is enabled + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + } if (resetCnt>=12) { //6 secs pressed - FR (timer is at 500 ms) info("Restoring to default settings via BOOT button!"); @@ -140,3 +143,61 @@ void ICACHE_FLASH_ATTR ioInit() { } } +struct pinmapping { + bool set; + bool reset; + bool enable; + bool disable; + bool input; + bool pullup; +}; + +void ICACHE_FLASH_ATTR userGpioInit(void) +{ + const struct pinmapping pin_mappings[5] = { + // S R E D I P + {0, 1, 0, 1, 0, 0}, // OFF + {0, 1, 1, 0, 0, 0}, // OUT 0 + {1, 0, 1, 0, 0, 0}, // OUT 1 + {0, 0, 0, 1, 1, 1}, // IN PULL + {0, 0, 0, 1, 1, 0}, // IN NOPULL + }; + + u8 num; + const struct pinmapping *pm; + + // GPIO2 + num = 2; + pm = &pin_mappings[sysconf->gpio2_conf]; + gpio_output_set((uint32) (pm->set << num), (uint32) (pm->reset << num), (uint32) (pm->enable << num), (uint32) (pm->disable << num)); + if (pm->pullup) { + PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO2_U); + } else { + PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO2_U); + } + if (sysconf->gpio2_conf == GPIOCONF_OFF) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + } else { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); + } + + // GPIO4 + num = 4; + pm = &pin_mappings[sysconf->gpio4_conf]; + gpio_output_set((uint32) (pm->set << num), (uint32) (pm->reset << num), (uint32) (pm->enable << num), (uint32) (pm->disable << num)); + if (pm->pullup) { + PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO4_U); + } else { + PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO4_U); + } + + // GPIO5 + num = 5; + pm = &pin_mappings[sysconf->gpio5_conf]; + gpio_output_set((uint32) (pm->set << num), (uint32) (pm->reset << num), (uint32) (pm->enable << num), (uint32) (pm->disable << num)); + if (pm->pullup) { + PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO5_U); + } else { + PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO5_U); + } +} diff --git a/user/io.h b/user/io.h index 7969b65..5da3984 100644 --- a/user/io.h +++ b/user/io.h @@ -2,5 +2,6 @@ #define IO_H void ioInit(void); +void userGpioInit(void); #endif diff --git a/user/routes.c b/user/routes.c index add3c97..1154903 100644 --- a/user/routes.c +++ b/user/routes.c @@ -114,6 +114,7 @@ const HttpdBuiltInUrl routes[] ESP_CONST_DATA = { ROUTE_CGI(API_PING"/?", cgiPing), ROUTE_CGI(API_CLEAR"/?", cgiResetScreen), ROUTE_CGI(API_D2D_MSG"/?", cgiD2DMessage), + ROUTE_CGI(API_GPIO"/?", cgiGPIO), ROUTE_REDIRECT("/cfg/?", "/cfg/wifi"), diff --git a/user/serial.c b/user/serial.c index d7382a2..daa54b3 100644 --- a/user/serial.c +++ b/user/serial.c @@ -11,10 +11,12 @@ static ETSTimer flushLogTimer; static void buf_putc(char c) { - if (lb_ls != lb_nw) { - logbuf[lb_nw++] = c; - if (lb_nw >= DEBUG_LOGBUF_SIZE) lb_nw = 0; - } + if (sysconf->gpio2_conf == GPIOCONF_OFF) { + if (lb_ls != lb_nw) { + logbuf[lb_nw++] = c; + if (lb_nw >= DEBUG_LOGBUF_SIZE) lb_nw = 0; + } + } } static void ICACHE_FLASH_ATTR @@ -42,7 +44,9 @@ buf_pop(void *unused) LOCAL void my_putc(char c) { - UART_WriteCharCRLF(UART1, (u8) c, 200); + if (sysconf->gpio2_conf == GPIOCONF_OFF) { + UART_WriteCharCRLF(UART1, (u8) c, 200); + } } /** @@ -79,6 +83,14 @@ void ICACHE_FLASH_ATTR serialInit(void) UART_SetStopBits(UART0, (UartStopBitsNum) sysconf->uart_stopbits); UART_SetBaudrate(UART0, sysconf->uart_baudrate); + // GPIO2 may be used as a remotely controlled GPIO + if (sysconf->gpio2_conf == GPIOCONF_OFF) { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + } else { + PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); + // further config of the GPIO will be done in persist.c after calling this func + } + info("COM SERIAL: %d baud, %s parity, %s stopbit(s)", sysconf->uart_baudrate, (sysconf->uart_parity == PARITY_NONE ? "NONE" : (sysconf->uart_parity == PARITY_ODD ? "ODD" : "EVEN")), diff --git a/user/syscfg.c b/user/syscfg.c index fc5f17c..081ccc0 100644 --- a/user/syscfg.c +++ b/user/syscfg.c @@ -7,6 +7,7 @@ #include "uart_driver.h" #include "serial.h" #include "cgi_logging.h" +#include "io.h" SystemConfigBundle * const sysconf = &persist.current.sysconf; @@ -119,6 +120,14 @@ sysconf_apply_settings(void) changed = true; } + if (sysconf->config_version < 2) { + dbg("Upgrading syscfg to v 2"); + sysconf->gpio2_conf = GPIOCONF_OFF; + sysconf->gpio4_conf = GPIOCONF_OUT_START_0; + sysconf->gpio5_conf = GPIOCONF_OUT_START_0; + changed = true; + } + sysconf->config_version = SYSCONF_VERSION; if (changed) { @@ -128,6 +137,9 @@ sysconf_apply_settings(void) // uart settings live here, but the CGI handler + form has been moved to the Terminal config page serialInit(); + // initialize user GPIOs + userGpioInit(); + system_update_cpu_freq((uint8) (sysconf->overclock ? 160 : 80)); } @@ -143,4 +155,7 @@ sysconf_restore_defaults(void) strcpy((char *)sysconf->access_pw, DEF_ACCESS_PW); strcpy((char *)sysconf->access_name, DEF_ACCESS_NAME); sysconf->overclock = false; + sysconf->gpio2_conf = GPIOCONF_OFF; // means 'use debug uart' + sysconf->gpio4_conf = GPIOCONF_OUT_START_0; + sysconf->gpio5_conf = GPIOCONF_OUT_START_0; } diff --git a/user/syscfg.h b/user/syscfg.h index 2bb0684..27033e3 100644 --- a/user/syscfg.h +++ b/user/syscfg.h @@ -11,7 +11,7 @@ // Size designed for the wifi config structure // Must be constant to avoid corrupting user config after upgrade #define SYSCONF_SIZE 300 -#define SYSCONF_VERSION 1 +#define SYSCONF_VERSION 2 #define DEF_ACCESS_PW "1234" #define DEF_ACCESS_NAME "espterm" @@ -25,6 +25,14 @@ enum pwlock { PWLOCK_MAX = 5, }; +enum gpioconf { + GPIOCONF_OFF = 0, + GPIOCONF_OUT_START_0 = 1, + GPIOCONF_OUT_START_1 = 2, + GPIOCONF_IN_PULL = 3, + GPIOCONF_IN_NOPULL = 4, +}; + //....Type................Name..Suffix...............Deref..XGET............XSET.........................NOTIFY....Allow // Deref is used to pass the field to xget. Cast is used to convert the &'d field to what xset wants (needed for static arrays) #define XTABLE_SYSCONF \ @@ -39,7 +47,9 @@ enum pwlock { X(uchar, access_name, [32], /**/, xget_ustring, xset_ustring, NULL, /**/, admin|tpl) \ \ X(bool, overclock, /**/, /**/, xget_bool, xset_bool, NULL, /**/, 1) \ - + X(u8, gpio2_conf, /**/, /**/, xget_dec, xset_u8, NULL, /**/, 1) \ + X(u8, gpio4_conf, /**/, /**/, xget_dec, xset_u8, NULL, /**/, 1) \ + X(u8, gpio5_conf, /**/, /**/, xget_dec, xset_u8, NULL, /**/, 1) typedef struct { #define X XSTRUCT_FIELD @@ -54,6 +64,7 @@ typedef struct { // char access_pw[64]; // access password // char access_name[32]; // access name // bool overclock; +// bool debug_uart; } SystemConfigBundle; extern SystemConfigBundle * const sysconf; diff --git a/user/uart_handler.c b/user/uart_handler.c index 622565a..0f3a42c 100755 --- a/user/uart_handler.c +++ b/user/uart_handler.c @@ -56,6 +56,7 @@ void ICACHE_FLASH_ATTR UART_Init(void) // U1TXD (GPIO2) PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_U1TXD_BK); + PIN_PULLUP_DIS(PERIPHS_IO_MUX_GPIO2_U); // Configure the UART peripherals UART_SetWordLength(UART0, EIGHT_BITS); // main diff --git a/user/user_main.c b/user/user_main.c index 9dee6b7..c86a954 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -96,6 +96,8 @@ static ETSTimer prHeapTimer; //Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. void ICACHE_FLASH_ATTR user_init(void) { + sysconf->gpio2_conf = GPIOCONF_OFF; // enable debug UART for the start-up (sysconf is not loaded yet) + ansi_parser_inhibit = true; serialInitBase(); @@ -110,7 +112,7 @@ void ICACHE_FLASH_ATTR user_init(void) banner_gap(); banner("================ ESPTerm ================"); banner_info(); - banner_info("Project by Ondrej Hruska, 2017"); + banner_info("Project by Ondrej Hruska, 2017-2018"); banner_info(); banner_info(TERMINAL_GITHUB_REPO_NOPROTO); banner_info(); diff --git a/user/version.h b/user/version.h index 3f8ace6..e3c83d6 100644 --- a/user/version.h +++ b/user/version.h @@ -9,10 +9,10 @@ #define STR(x) STR_HELPER(x) #define FW_V_MAJOR 2 -#define FW_V_MINOR 3 -#define FW_V_PATCH 1 -#define FW_V_SUFFIX "" -#define FW_CODENAME "Cricket" // 2.3 +#define FW_V_MINOR 4 +#define FW_V_PATCH 0 +#define FW_V_SUFFIX "-pre1" +#define FW_CODENAME "Damselfly" #define FW_CODENAME_QUOTED "\""FW_CODENAME"\"" #define FW_VERSION STR(FW_V_MAJOR) "." STR(FW_V_MINOR) "." STR(FW_V_PATCH) FW_V_SUFFIX