|
|
|
#include <esp8266.h>
|
|
|
|
#include <httpd.h>
|
|
|
|
#include <helpers.h>
|
|
|
|
#include <httpdespfs.h>
|
|
|
|
|
|
|
|
#include "cgi_system.h"
|
|
|
|
#include "persist.h"
|
|
|
|
#include "syscfg.h"
|
|
|
|
#include "ansi_parser.h"
|
|
|
|
#include "cgi_logging.h"
|
|
|
|
|
|
|
|
#define SET_REDIR_SUC "/cfg/system"
|
|
|
|
|
|
|
|
void buildInputsJson(char *buff);
|
|
|
|
|
|
|
|
static ETSTimer tmr;
|
|
|
|
|
|
|
|
static void ICACHE_FLASH_ATTR tmrCb(void *arg)
|
|
|
|
{
|
|
|
|
system_restart();
|
|
|
|
}
|
|
|
|
|
|
|
|
httpd_cgi_state ICACHE_FLASH_ATTR cgiResetScreen(HttpdConnData *connData)
|
|
|
|
{
|
|
|
|
if (connData->conn==NULL) {
|
|
|
|
//Connection aborted. Clean up.
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
info("--- User request to reset screen! ---");
|
|
|
|
// this copies termconf to scratch and also resets the screen
|
|
|
|
terminal_apply_settings();
|
|
|
|
ansi_parser_reset();
|
|
|
|
|
|
|
|
httpdRedirect(connData, "/");
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
httpd_cgi_state ICACHE_FLASH_ATTR cgiResetDevice(HttpdConnData *connData)
|
|
|
|
{
|
|
|
|
if (connData->conn==NULL) {
|
|
|
|
//Connection aborted. Clean up.
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
httpdStartResponse(connData, 200);
|
|
|
|
httpdHeader(connData, "Content-Type", "text/plain");
|
|
|
|
httpdEndHeaders(connData);
|
|
|
|
|
|
|
|
os_timer_disarm(&tmr);
|
|
|
|
os_timer_setfn(&tmr, tmrCb, NULL);
|
|
|
|
os_timer_arm(&tmr, 100, false);
|
|
|
|
|
|
|
|
httpdSend(connData, "system reset\r\n", -1);
|
|
|
|
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
httpd_cgi_state ICACHE_FLASH_ATTR cgiPing(HttpdConnData *connData)
|
|
|
|
{
|
|
|
|
if (connData->conn==NULL) {
|
|
|
|
//Connection aborted. Clean up.
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
httpdStartResponse(connData, 200);
|
|
|
|
httpdHeader(connData, "Content-Type", "text/plain");
|
|
|
|
httpdEndHeaders(connData);
|
|
|
|
|
|
|
|
httpdSend(connData, "pong\r\n", -1);
|
|
|
|
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Universal CGI endpoint to set Terminal params.
|
|
|
|
*/
|
|
|
|
httpd_cgi_state ICACHE_FLASH_ATTR
|
|
|
|
cgiSystemCfgSetParams(HttpdConnData *connData)
|
|
|
|
{
|
|
|
|
char buff[65];
|
|
|
|
char buff2[65];
|
|
|
|
char redir_url_buf[100];
|
|
|
|
|
|
|
|
char *redir_url = redir_url_buf;
|
|
|
|
|
|
|
|
if (GET_ARG("redir")) {
|
|
|
|
strncpy(redir_url, buff, 40);
|
|
|
|
u32 len = strlen(buff);
|
|
|
|
if (len > 40) len = 40;
|
|
|
|
redir_url += len;
|
|
|
|
} else {
|
|
|
|
redir_url += sprintf(redir_url, SET_REDIR_SUC);
|
|
|
|
}
|
|
|
|
char *end_of_redir_url = redir_url;
|
|
|
|
redir_url += sprintf(redir_url, "?err=");
|
|
|
|
char *end_of_failed_redir_url = redir_url;
|
|
|
|
// we'll test if anything was printed by looking for \0 in failed_keys_buf
|
|
|
|
|
|
|
|
if (connData->conn == NULL) {
|
|
|
|
//Connection aborted. Clean up.
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
AdminConfigBlock *admin_backup = malloc(sizeof(AdminConfigBlock));
|
|
|
|
SystemConfigBundle *sysconf_backup = malloc(sizeof(SystemConfigBundle));
|
|
|
|
memcpy(admin_backup, &persist.admin, sizeof(AdminConfigBlock));
|
|
|
|
memcpy(sysconf_backup, sysconf, sizeof(SystemConfigBundle));
|
|
|
|
|
|
|
|
// flags for the template builder
|
|
|
|
bool uart_changed = false; //!< this is set in uart notify, for use in terminal settings (dummy here)
|
|
|
|
bool admin = false;
|
|
|
|
const bool tpl = false; // this optionally disables some fields
|
|
|
|
do {
|
|
|
|
// Check admin PW
|
|
|
|
if (GET_ARG("pw")) {
|
|
|
|
if (!streq(buff, persist.admin.pw)) {
|
|
|
|
warn("Bad admin pw!");
|
|
|
|
redir_url += sprintf(redir_url, "pw,");
|
|
|
|
break; // Abort
|
|
|
|
} else {
|
|
|
|
admin = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Changing admin PW
|
|
|
|
if (admin && GET_ARG("admin_pw")) {
|
|
|
|
if (strlen(buff)) {
|
|
|
|
cgi_dbg("admin_pw: %s", buff);
|
|
|
|
|
|
|
|
strcpy(buff2, buff);
|
|
|
|
if (!GET_ARG("admin_pw2")) {
|
|
|
|
cgi_warn("Missing repeated admin_pw %s", buff);
|
|
|
|
redir_url += sprintf(redir_url, "admin_pw2,");
|
|
|
|
break; // Abort
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!streq(buff, buff2)) {
|
|
|
|
cgi_warn("Bad repeated admin_pw %s", buff);
|
|
|
|
redir_url += sprintf(redir_url, "admin_pw2,");
|
|
|
|
break; // Abort
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen(buff) >= 64) {
|
|
|
|
cgi_warn("Too long admin_pw %s", buff);
|
|
|
|
redir_url += sprintf(redir_url, "admin_pw,");
|
|
|
|
break; // Abort
|
|
|
|
}
|
|
|
|
|
|
|
|
cgi_dbg("Changing admin PW!");
|
|
|
|
strncpy(persist.admin.pw, buff, 64);
|
|
|
|
|
|
|
|
break; // this is the only field in this form
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reject filled but unconfirmed access PW
|
|
|
|
if (admin && GET_ARG("access_pw")) {
|
|
|
|
if (strlen(buff)) {
|
|
|
|
cgi_dbg("access_pw: %s", buff);
|
|
|
|
|
|
|
|
strcpy(buff2, buff);
|
|
|
|
if (!GET_ARG("access_pw2")) {
|
|
|
|
cgi_warn("Missing repeated access_pw %s", buff);
|
|
|
|
redir_url += sprintf(redir_url, "access_pw2,");
|
|
|
|
break; // Abort
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!streq(buff, buff2)) {
|
|
|
|
cgi_warn("Bad repeated access_pw %s", buff);
|
|
|
|
redir_url += sprintf(redir_url, "access_pw2,");
|
|
|
|
break; // Abort
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Settings in the system config block
|
|
|
|
#define XSTRUCT sysconf
|
|
|
|
#define X XSET_CGI_FUNC
|
|
|
|
XTABLE_SYSCONF
|
|
|
|
#undef X
|
|
|
|
#undef XSTRUCT
|
|
|
|
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
(void)redir_url;
|
|
|
|
(void)uart_changed; // unused
|
|
|
|
|
|
|
|
if (*end_of_failed_redir_url == '\0') {
|
|
|
|
// All was OK
|
|
|
|
cgi_info("Set system params - success, saving...");
|
|
|
|
|
|
|
|
sysconf_apply_settings();
|
|
|
|
persist_store();
|
|
|
|
|
|
|
|
strcpy(end_of_redir_url, "?msg=Settings%20saved%20and%20applied.");
|
|
|
|
|
|
|
|
httpdRedirect(connData, redir_url_buf);
|
|
|
|
} else {
|
|
|
|
cgi_warn("Some settings did not validate, asking for correction");
|
|
|
|
|
|
|
|
// revert any possible changes
|
|
|
|
memcpy(&persist.admin, admin_backup, sizeof(AdminConfigBlock));
|
|
|
|
memcpy(sysconf, sysconf_backup, sizeof(SystemConfigBundle));
|
|
|
|
|
|
|
|
// Some errors, appended to the URL as ?err=
|
|
|
|
httpdRedirect(connData, redir_url_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(admin_backup);
|
|
|
|
free(sysconf_backup);
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void tplSystemCfgFill(char *token, char *buff)
|
|
|
|
{
|
|
|
|
buff[0] = '\0';
|
|
|
|
|
|
|
|
const bool admin = false;
|
|
|
|
const bool tpl=true;
|
|
|
|
|
|
|
|
#define XSTRUCT sysconf
|
|
|
|
#define X XGET_CGI_FUNC_RETURN
|
|
|
|
XTABLE_SYSCONF
|
|
|
|
#undef X
|
|
|
|
#undef XSTRUCT
|
|
|
|
|
|
|
|
if (streq(token, "def_access_name")) {
|
|
|
|
sprintf(buff, "%s", DEF_ACCESS_NAME);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (streq(token, "def_access_pw")) {
|
|
|
|
sprintf(buff, "%s", DEF_ACCESS_PW);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (streq(token, "def_admin_pw")) {
|
|
|
|
sprintf(buff, "%s", DEFAULT_ADMIN_PW);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (streq(token, "gpio_initial")) {
|
|
|
|
buildInputsJson(buff);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
httpd_cgi_state ICACHE_FLASH_ATTR
|
|
|
|
tplSystemCfg(HttpdConnData *connData, char *token, void **arg)
|
|
|
|
{
|
|
|
|
#define BUFLEN 100
|
|
|
|
char buff[BUFLEN];
|
|
|
|
|
|
|
|
if (token == NULL) {
|
|
|
|
// We're done
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
tplSystemCfgFill(token, buff);
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ICACHE_FLASH_ATTR
|
|
|
|
buildInputsJson(char *buff)
|
|
|
|
{
|
|
|
|
u32 inputs = gpio_input_get();
|
|
|
|
|
|
|
|
sprintf(buff, "{\"io2\":%d,\"io4\":%d,\"io5\":%d}",
|
|
|
|
((inputs&(1<<2)) != 0),
|
|
|
|
((inputs&(1<<4)) != 0),
|
|
|
|
((inputs&(1<<5)) != 0)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* API to set GPIOs
|
|
|
|
*
|
|
|
|
* @param connData
|
|
|
|
* @return
|
|
|
|
*/
|
|
|
|
httpd_cgi_state ICACHE_FLASH_ATTR cgiGPIO(HttpdConnData *connData)
|
|
|
|
{
|
|
|
|
char buff[32];
|
|
|
|
|
|
|
|
if (connData->conn==NULL) {
|
|
|
|
//Connection aborted. Clean up.
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool set = 0;
|
|
|
|
u32 inputs = gpio_input_get();
|
|
|
|
|
|
|
|
// args are do2, do4, do5, pulse. Values: 0 - off, 1 - on, t - toggle. pulse is in ms
|
|
|
|
|
|
|
|
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
|
|
|
|
buildInputsJson(buff);
|
|
|
|
httpdSend(connData, buff, -1);
|
|
|
|
|
|
|
|
return HTTPD_CGI_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** "GPIO" page */
|
|
|
|
httpd_cgi_state ICACHE_FLASH_ATTR
|
|
|
|
tplGpio(HttpdConnData *connData, char *token, void **arg)
|
|
|
|
{
|
|
|
|
return tplSystemCfg(connData, token, arg);
|
|
|
|
}
|