diff --git a/.gitignore b/.gitignore index 899b7c3..a541909 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ esp-link.opensdf esp-link.sdf espfs/mkespfsimage/mman-win32/libmman.a .localhistory/ +tools/ diff --git a/Makefile b/Makefile index 23e57be..4956590 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ ESPBAUD ?= 230400 # --------------- chipset configuration --------------- # Pick your flash size: "512KB", "1MB", or "4MB" -FLASH_SIZE ?= 512KB +FLASH_SIZE ?= 4MB ifeq ("$(FLASH_SIZE)","512KB") # Winbond 25Q40 512KB flash, typ for esp-01 thru esp-11 @@ -70,7 +70,7 @@ ET_BLANK ?= 0x3FE000 # where to flash blank.bin to erase wireless set endif # hostname or IP address for wifi flashing -ESP_HOSTNAME ?= esp-link +ESP_HOSTNAME ?= esp-nodemcu # The pin assignments below are used when the settings in flash are invalid, they # can be changed via the web interface @@ -122,15 +122,20 @@ CHANGE_TO_STA ?= yes #Static gzipping is disabled by default. GZIP_COMPRESSION ?= yes -# If COMPRESS_W_YUI is set to "yes" then the static css and js files will be compressed with -# yui-compressor. This option works only when GZIP_COMPRESSION is set to "yes". +# If COMPRESS_W_HTMLCOMPRESSOR is set to "yes" then the static css and js files will be compressed with +# htmlcompressor and yui-compressor. This option works only when GZIP_COMPRESSION is set to "yes". +# https://code.google.com/p/htmlcompressor/#For_Non-Java_Projects # http://yui.github.io/yuicompressor/ -#Disabled by default. -COMPRESS_W_YUI ?= yes +# enabled by default. +COMPRESS_W_HTMLCOMPRESSOR ?= yes +HTML-COMPRESSOR ?= htmlcompressor-1.5.3.jar YUI-COMPRESSOR ?= yuicompressor-2.4.8.jar +HTML_PATH = $(abspath ./html)/ +WIFI_PATH = $(HTML_PATH)wifi/ + # Optional Modules -MODULES ?= +MODULES ?= mqtt rest # -------------- End of config options ------------- @@ -144,7 +149,6 @@ TARGET = httpd # espressif tool to concatenate sections for OTA upload using bootloader v1.2+ APPGEN_TOOL ?= gen_appbin.py - CFLAGS= # set defines for optional modules @@ -156,19 +160,23 @@ ifneq (,$(findstring rest,$(MODULES))) CFLAGS += -DREST endif +ifneq (,$(findstring tcpclient,$(MODULES))) + CFLAGS += -DTCPCLIENT +endif + # which modules (subdirectories) of the project to include in compiling -LIBRARIES_DIR = libraries -MODULES = espfs httpd user serial cmd mqtt esp-link +LIBRARIES_DIR = libraries +MODULES += espfs httpd user serial cmd esp-link MODULES += $(foreach sdir,$(LIBRARIES_DIR),$(wildcard $(sdir)/*)) -EXTRA_INCDIR = include . include/json +EXTRA_INCDIR = include . # libraries used in this project, mainly provided by the SDK -LIBS = c gcc hal phy pp net80211 wpa main lwip json +LIBS = c gcc hal phy pp net80211 wpa main lwip # compiler flags using during compilation of source files -CFLAGS += -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ +CFLAGS += -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ -nostdlib -mlongcalls -mtext-section-literals -ffunction-sections -fdata-sections \ - -Wno-unused-function \ + -Wno-unused-function -Wno-unused-variable \ -D__ets__ -DICACHE_FLASH -D_STDINT_H -Wno-address -DFIRMWARE_SIZE=$(ESP_FLASH_MAX) \ -DMCU_RESET_PIN=$(MCU_RESET_PIN) -DMCU_ISP_PIN=$(MCU_ISP_PIN) \ -DLED_CONN_PIN=$(LED_CONN_PIN) -DLED_SERIAL_PIN=$(LED_SERIAL_PIN) \ @@ -203,17 +211,17 @@ BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES)) SDK_LIBDIR := $(addprefix $(SDK_BASE)/,$(SDK_LIBDIR)) SDK_LDDIR := $(addprefix $(SDK_BASE)/,$(SDK_LDDIR)) SDK_INCDIR := $(addprefix -I$(SDK_BASE)/,$(SDK_INCDIR)) -SDK_TOOLS := $(addprefix $(SDK_BASE)/,$(SDK_TOOLSDIR)) +SDK_TOOLS := $(addprefix $(SDK_BASE)/,$(SDK_TOOLSDIR)) APPGEN_TOOL := $(addprefix $(SDK_TOOLS)/,$(APPGEN_TOOL)) -SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c)) -OBJ := $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC)) $(BUILD_BASE)/espfs_img.o +SRC := $(foreach sdir,$(SRC_DIR),$(wildcard $(sdir)/*.c)) +OBJ := $(patsubst %.c,$(BUILD_BASE)/%.o,$(SRC)) $(BUILD_BASE)/espfs_img.o LIBS := $(addprefix -l,$(LIBS)) APP_AR := $(addprefix $(BUILD_BASE)/,$(TARGET)_app.a) USER1_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).user1.out) USER2_OUT := $(addprefix $(BUILD_BASE)/,$(TARGET).user2.out) -INCDIR := $(addprefix -I,$(SRC_DIR)) +INCDIR := $(addprefix -I,$(SRC_DIR)) EXTRA_INCDIR := $(addprefix -I,$(EXTRA_INCDIR)) MODULE_INCDIR := $(addsuffix /include,$(INCDIR)) @@ -275,7 +283,7 @@ $(FW_BASE)/user1.bin: $(USER1_OUT) $(FW_BASE) $(Q) rm -f eagle.app.v6.*.bin $(Q) mv eagle.app.flash.bin $@ @echo "** user1.bin uses $$(stat -c '%s' $@) bytes of" $(ESP_FLASH_MAX) "available" - $(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; false; fi + $(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; true; fi $(FW_BASE)/user2.bin: $(USER2_OUT) $(FW_BASE) $(Q) $(OBJCP) --only-section .text -O binary $(USER2_OUT) eagle.app.v6.text.bin @@ -285,7 +293,7 @@ $(FW_BASE)/user2.bin: $(USER2_OUT) $(FW_BASE) $(Q) COMPILE=gcc PATH=$(XTENSA_TOOLS_ROOT):$(PATH) python $(APPGEN_TOOL) $(USER2_OUT) 2 $(ESP_FLASH_MODE) $(ESP_FLASH_FREQ_DIV) $(ESP_SPI_SIZE) $(Q) rm -f eagle.app.v6.*.bin $(Q) mv eagle.app.flash.bin $@ - $(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; false; fi + $(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; true; fi $(APP_AR): $(OBJ) $(vecho) "AR $@" @@ -306,35 +314,52 @@ flash: all $(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash -fs $(ET_FS) -ff $(ET_FF) \ 0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin \ $(ET_BLANK) $(SDK_BASE)/bin/blank.bin - -yui/$(YUI-COMPRESSOR): - $(Q) mkdir -p yui + +tools/$(HTML-COMPRESSOR): + $(Q) mkdir -p tools ifeq ($(OS),Windows_NT) - cd yui; wget --no-check-certificate https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI-COMPRESSOR) -O $(YUI-COMPRESSOR) + cd tools; wget --no-check-certificate https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI-COMPRESSOR) -O $(YUI-COMPRESSOR) + cd tools; wget --no-check-certificate https://htmlcompressor.googlecode.com/files/$(HTML-COMPRESSOR) -O $(HTML-COMPRESSOR) else - cd yui; wget https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI-COMPRESSOR) + cd tools; wget https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI-COMPRESSOR) + cd tools; wget https://htmlcompressor.googlecode.com/files/$(HTML-COMPRESSOR) endif -ifeq ("$(COMPRESS_W_YUI)","yes") -$(BUILD_BASE)/espfs_img.o: yui/$(YUI-COMPRESSOR) +ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes") +$(BUILD_BASE)/espfs_img.o: tools/$(HTML-COMPRESSOR) endif $(BUILD_BASE)/espfs_img.o: html/ html/wifi/ espfs/mkespfsimage/mkespfsimage - $(Q) rm -rf html_compressed; - $(Q) cp -r html html_compressed; - $(Q) for file in `find html_compressed -type f -name "*.htm*"`; do \ - cat html_compressed/head- $$file >$${file}-; \ - mv $$file- $$file; \ - done -ifeq ("$(COMPRESS_W_YUI)","yes") + $(Q) rm -rf html_compressed; mkdir html_compressed; mkdir html_compressed/wifi; + $(Q) cp -r html/*.ico html_compressed; + $(Q) cp -r html/*.css html_compressed; + $(Q) cp -r html/*.js html_compressed; + $(Q) cp -r html/wifi/*.png html_compressed/wifi; + $(Q) cp -r html/wifi/*.js html_compressed/wifi; +ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes") + $(Q) echo "Compression assets with htmlcompressor. This may take a while..." + $(Q) java -jar tools/$(HTML-COMPRESSOR) \ + -t html --remove-surrounding-spaces max --remove-quotes --remove-intertag-spaces \ + -o $(abspath ./html_compressed)/ \ + $(HTML_PATH)head- \ + $(HTML_PATH)*.html + $(Q) java -jar tools/$(HTML-COMPRESSOR) \ + -t html --remove-surrounding-spaces max --remove-quotes --remove-intertag-spaces \ + -o $(abspath ./html_compressed)/wifi/ \ + $(WIFI_PATH)*.html $(Q) echo "Compression assets with yui-compressor. This may take a while..." $(Q) for file in `find html_compressed -type f -name "*.js"`; do \ - java -jar yui/$(YUI-COMPRESSOR) $$file --nomunge --line-break 40 -o $$file; \ + java -jar tools/$(YUI-COMPRESSOR) $$file -o $$file; \ done $(Q) for file in `find html_compressed -type f -name "*.css"`; do \ - java -jar yui/$(YUI-COMPRESSOR) $$file -o $$file; \ + java -jar tools/$(YUI-COMPRESSOR) $$file -o $$file; \ done endif + $(Q) for file in `find html_compressed -type f -name "*.htm*"`; do \ + cat html_compressed/head- $$file >$${file}-; \ + mv $$file- $$file; \ + done + $(Q) rm html_compressed/head- $(Q) cd html_compressed; find . \! -name \*- | ../espfs/mkespfsimage/mkespfsimage > ../build/espfs.img; cd ..; $(Q) ls -sl build/espfs.img $(Q) cd build; $(OBJCP) -I binary -O elf32-xtensa-le -B xtensa --rename-section .data=.espfs \ @@ -384,7 +409,7 @@ clean: $(Q) make -C espfs/mkespfsimage/ clean $(Q) rm -rf $(FW_BASE) $(Q) rm -f webpages.espfs -ifeq ("$(COMPRESS_W_YUI)","yes") +ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes") $(Q) rm -rf html_compressed endif diff --git a/cmd/cmd.c b/cmd/cmd.c index 07a92a5..f3bcbba 100644 --- a/cmd/cmd.c +++ b/cmd/cmd.c @@ -2,10 +2,8 @@ // // Adapted from: github.com/tuanpmt/esp_bridge, Created on: Jan 9, 2015, Author: Minh -#include "esp8266.h" #include "cmd.h" #include "crc16.h" -#include "serbridge.h" #include "uart.h" extern const CmdList commands[]; diff --git a/cmd/cmd.h b/cmd/cmd.h index 97c8236..2d07e1c 100644 --- a/cmd/cmd.h +++ b/cmd/cmd.h @@ -55,8 +55,8 @@ typedef enum { CMD_REST_REQUEST, CMD_REST_SETHEADER, CMD_REST_EVENTS, - CMD_ADD_CALLBACK, // 15 - CMD_SENSOR_EVENTS + CMD_CB_ADD, // 15 + CMD_CB_EVENTS } CmdName; typedef uint32_t (*cmdfunc_t)(CmdPacket *cmd); diff --git a/cmd/handlers.c b/cmd/handlers.c index adf90b9..339c1dd 100644 --- a/cmd/handlers.c +++ b/cmd/handlers.c @@ -41,7 +41,7 @@ const CmdList commands[] = { {CMD_REST_REQUEST, REST_Request}, {CMD_REST_SETHEADER, REST_SetHeader}, #endif - { CMD_CB_ADD, CMD_AddCallback }, + {CMD_CB_ADD, CMD_AddCallback}, {CMD_NULL, NULL} }; @@ -52,14 +52,18 @@ cmdCallback callbacks[MAX_CALLBACKS]; // cleared in CMD_Reset // Command handler for IsReady (healthcheck) command static uint32_t ICACHE_FLASH_ATTR CMD_IsReady(CmdPacket *cmd) { +#ifdef CMD_DBG os_printf("CMD_IsReady: Check ready\n"); +#endif return 1; } // Command handler for Null command static uint32_t ICACHE_FLASH_ATTR CMD_Null(CmdPacket *cmd) { +#ifdef CMD_DBG os_printf("CMD_Null: NULL/unsupported command\n"); +#endif return 1; } @@ -68,7 +72,9 @@ CMD_Null(CmdPacket *cmd) { // uC. static uint32_t ICACHE_FLASH_ATTR CMD_Reset(CmdPacket *cmd) { +#ifdef CMD_DBG os_printf("CMD_Reset\n"); +#endif // clear callbacks table os_memset(callbacks, 0, sizeof(callbacks)); return 1; @@ -83,7 +89,9 @@ CMD_AddCb(char* name, uint32_t cb) { if (os_strcmp(callbacks[i].name, name) == 0 || callbacks[i].name[0] == '\0') { os_strncpy(callbacks[i].name, name, sizeof(callbacks[i].name)); callbacks[i].callback = cb; +#ifdef CMD_DBG os_printf("CMD_AddCb: cb %s added at index %d\n", callbacks[i].name, i); +#endif return 1; } } @@ -99,7 +107,9 @@ CMD_GetCbByName(char* name) { // (void *)callbacks[i].callback); // if callback doesn't exist or it's null if (os_strcmp(callbacks[i].name, checkname) == 0) { +#ifdef CMD_DBG os_printf("CMD_GetCbByName: cb %s found at index %d\n", callbacks[i].name, i); +#endif return &callbacks[i]; } } @@ -111,7 +121,9 @@ CMD_GetCbByName(char* name) { static void ICACHE_FLASH_ATTR CMD_WifiCb(uint8_t wifiStatus) { if (wifiStatus != lastWifiStatus){ +#ifdef CMD_DBG os_printf("CMD_WifiCb: wifiStatus=%d\n", wifiStatus); +#endif lastWifiStatus = wifiStatus; cmdCallback *wifiCb = CMD_GetCbByName("wifiCb"); if ((uint32_t)wifiCb->callback != -1) { @@ -128,7 +140,9 @@ static uint32_t ICACHE_FLASH_ATTR CMD_WifiConnect(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); +#ifdef CMD_DBG os_printf("CMD_WifiConnect: setup argc=%ld\n", CMD_GetArgc(&req)); +#endif if(cmd->argc != 2 || cmd->callback == 0) return 0; @@ -148,7 +162,9 @@ static uint32_t ICACHE_FLASH_ATTR CMD_AddCallback(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); +#ifdef CMD_DBG os_printf("CMD_AddCallback: setup argc=%ld\n", CMD_GetArgc(&req)); +#endif if (cmd->argc != 1 || cmd->callback == 0) return 0; @@ -157,11 +173,15 @@ CMD_AddCallback(CmdPacket *cmd) { // get the sensor name len = CMD_ArgLen(&req); +#ifdef CMD_DBG os_printf("CMD_AddCallback: name len=%d\n", len); +#endif if (len > 15) return 0; // max size of name is 15 characters if (CMD_PopArg(&req, (uint8_t *)name, len)) return 0; name[len] = 0; +#ifdef CMD_DBG os_printf("CMD_AddCallback: name=%s\n", name); +#endif return CMD_AddCb(name, (uint32_t)cmd->callback); // save the sensor callback } diff --git a/esp-link.vcxproj b/esp-link.vcxproj index 029fbb7..6a17160 100644 --- a/esp-link.vcxproj +++ b/esp-link.vcxproj @@ -65,9 +65,11 @@ + + + - @@ -103,6 +105,7 @@ + @@ -111,9 +114,12 @@ + + + - + @@ -150,6 +156,7 @@ + diff --git a/esp-link/cgi.c b/esp-link/cgi.c index 2b814fe..c99bada 100644 --- a/esp-link/cgi.c +++ b/esp-link/cgi.c @@ -16,14 +16,6 @@ Some random cgi routines. #include #include "cgi.h" -static char* chipIdStr = ""; -char* ICACHE_FLASH_ATTR system_get_chip_id_str(){ - if (os_strlen(chipIdStr) == 0) { - chipIdStr = (char*)os_zalloc(9); - os_sprintf(chipIdStr, "%06x", system_get_chip_id()); - } - return chipIdStr; -} void noCacheHeaders(HttpdConnData *connData, int code) { httpdStartResponse(connData, code); @@ -44,7 +36,9 @@ errorResponse(HttpdConnData *connData, int code, char *message) { noCacheHeaders(connData, code); httpdEndHeaders(connData); httpdSend(connData, message, -1); +#ifdef CGI_DBG os_printf("HTTP %d error response: \"%s\"\n", code, message); +#endif } // look for the HTTP arg 'name' and store it at 'config' with max length 'max_len' (incl @@ -58,7 +52,7 @@ getStringArg(HttpdConnData *connData, char *name, char *config, int max_len) { os_sprintf(buff, "Value for %s too long (%d > %d allowed)", name, len, max_len-1); errorResponse(connData, 400, buff); return -1; - } + } strcpy(config, buff); return 1; } diff --git a/esp-link/cgi.h b/esp-link/cgi.h index d1d73c6..aa124f1 100644 --- a/esp-link/cgi.h +++ b/esp-link/cgi.h @@ -10,6 +10,5 @@ int getStringArg(HttpdConnData *connData, char *name, char *config, int max_len) int getBoolArg(HttpdConnData *connData, char *name, bool*config); int cgiMenu(HttpdConnData *connData); uint8_t UTILS_StrToIP(const char* str, void *ip); -char* system_get_chip_id_str(); #endif diff --git a/esp-link/cgiflash.c b/esp-link/cgiflash.c index e07443b..ccd6865 100644 --- a/esp-link/cgiflash.c +++ b/esp-link/cgiflash.c @@ -22,8 +22,10 @@ Some flash handling cgi routines. Used for reading the existing flash and updati // Check that the header of the firmware blob looks like actual firmware... static char* ICACHE_FLASH_ATTR check_header(void *buf) { uint8_t *cd = (uint8_t *)buf; +#ifdef CGIFLASH_DBG uint32_t *buf32 = buf; os_printf("%p: %08lX %08lX %08lX %08lX\n", buf, buf32[0], buf32[1], buf32[2], buf32[3]); +#endif if (cd[0] != 0xEA) return "IROM magic missing"; if (cd[1] != 4 || cd[2] > 3 || (cd[3]>>4) > 6) return "bad flash header"; if (((uint16_t *)buf)[3] != 0x4010) return "Invalid entry addr"; @@ -42,7 +44,9 @@ int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) { httpdEndHeaders(connData); char *next = id == 1 ? "user1.bin" : "user2.bin"; httpdSend(connData, next, -1); +#ifdef CGIFLASH_DBG os_printf("Next firmware: %s (got %d)\n", next, id); +#endif return HTTPD_CGI_DONE; } @@ -80,7 +84,9 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) { // return an error if there is one if (err != NULL) { +#ifdef CGIFLASH_DBG os_printf("Error %d: %s\n", code, err); +#endif httpdStartResponse(connData, code); httpdHeader(connData, "Content-Type", "text/plain"); //httpdHeader(connData, "Content-Length", strlen(err)+2); @@ -99,7 +105,9 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) { // erase next flash block if necessary if (address % SPI_FLASH_SEC_SIZE == 0){ +#ifdef CGIFLASH_DBG os_printf("Flashing 0x%05x (id=%d)\n", address, 2-id); +#endif spi_flash_erase_sector(address/SPI_FLASH_SEC_SIZE); } @@ -129,11 +137,15 @@ int ICACHE_FLASH_ATTR cgiRebootFirmware(HttpdConnData *connData) { int address = id == 1 ? 4*1024 // either start after 4KB boot partition : 4*1024 + FIRMWARE_SIZE + 16*1024 + 4*1024; // 4KB boot, fw1, 16KB user param, 4KB reserved uint32 buf[8]; +#ifdef CGIFLASH_DBG os_printf("Checking %p\n", (void *)address); +#endif spi_flash_read(address, buf, sizeof(buf)); char *err = check_header(buf); if (err != NULL) { +#ifdef CGIFLASH_DBG os_printf("Error %d: %s\n", 400, err); +#endif httpdStartResponse(connData, 400); httpdHeader(connData, "Content-Type", "text/plain"); //httpdHeader(connData, "Content-Length", strlen(err)+2); diff --git a/esp-link/cgimqtt.c b/esp-link/cgimqtt.c index cbf4c16..2c3c7b0 100644 --- a/esp-link/cgimqtt.c +++ b/esp-link/cgimqtt.c @@ -17,17 +17,29 @@ int ICACHE_FLASH_ATTR cgiMqttGet(HttpdConnData *connData) { "\"slip-enable\":%d, " "\"mqtt-enable\":%d, " "\"mqtt-status-enable\":%d, " + "\"mqtt-clean-session\":%d, " "\"mqtt-port\":%d, " + "\"mqtt-timeout\":%d, " + "\"mqtt-keepalive\":%d, " "\"mqtt-host\":\"%s\", " "\"mqtt-client-id\":\"%s\", " "\"mqtt-username\":\"%s\", " "\"mqtt-password\":\"%s\", " "\"mqtt-status-topic\":\"%s\", " "\"mqtt-state\":\"%s\" }", - flashConfig.slip_enable, flashConfig.mqtt_enable, flashConfig.mqtt_status_enable, - flashConfig.mqtt_port, flashConfig.mqtt_hostname, flashConfig.mqtt_client, - flashConfig.mqtt_username, flashConfig.mqtt_password, - flashConfig.mqtt_status_topic, "connected"); + flashConfig.slip_enable, + flashConfig.mqtt_enable, + flashConfig.mqtt_status_enable, + flashConfig.mqtt_clean_session, + flashConfig.mqtt_port, + flashConfig.mqtt_timeout, + flashConfig.mqtt_keepalive, + flashConfig.mqtt_host, + flashConfig.mqtt_clientid, + flashConfig.mqtt_username, + flashConfig.mqtt_password, + flashConfig.mqtt_status_topic, + "connected"); jsonHeader(connData, 200); httpdSend(connData, buff, len); @@ -41,22 +53,30 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) { // handle MQTT server settings int mqtt_server = 0; // accumulator for changes/errors mqtt_server |= getStringArg(connData, "mqtt-host", - flashConfig.mqtt_hostname, sizeof(flashConfig.mqtt_hostname)); + flashConfig.mqtt_host, sizeof(flashConfig.mqtt_host)); if (mqtt_server < 0) return HTTPD_CGI_DONE; mqtt_server |= getStringArg(connData, "mqtt-client-id", - flashConfig.mqtt_client, sizeof(flashConfig.mqtt_client)); + flashConfig.mqtt_clientid, sizeof(flashConfig.mqtt_clientid)); + if (mqtt_server < 0) return HTTPD_CGI_DONE; mqtt_server |= getStringArg(connData, "mqtt-username", flashConfig.mqtt_username, sizeof(flashConfig.mqtt_username)); if (mqtt_server < 0) return HTTPD_CGI_DONE; mqtt_server |= getStringArg(connData, "mqtt-password", flashConfig.mqtt_password, sizeof(flashConfig.mqtt_password)); + + if (mqtt_server < 0) return HTTPD_CGI_DONE; + mqtt_server |= getBoolArg(connData, "mqtt-clean-session", + &flashConfig.mqtt_clean_session); + if (mqtt_server < 0) return HTTPD_CGI_DONE; mqtt_server |= getBoolArg(connData, "mqtt-enable", &flashConfig.mqtt_enable); - // handle mqtt port + char buff[16]; + + // handle mqtt port if (httpdFindArg(connData->getArgs, "mqtt-port", buff, sizeof(buff)) > 0) { int32_t port = atoi(buff); if (port > 0 && port < 65536) { @@ -68,9 +88,23 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) { } } + // handle mqtt timeout + if (httpdFindArg(connData->getArgs, "mqtt-timeout", buff, sizeof(buff)) > 0) { + int32_t timeout = atoi(buff); + flashConfig.mqtt_timeout = timeout; + } + + // handle mqtt keepalive + if (httpdFindArg(connData->getArgs, "mqtt-keepalive", buff, sizeof(buff)) > 0) { + int32_t keepalive = atoi(buff); + flashConfig.mqtt_keepalive = keepalive; + } + // if server setting changed, we need to "make it so" if (mqtt_server) { +#ifdef CGIMQTT_DBG os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable); +#endif // TODO } @@ -85,9 +119,11 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) { // if SLIP-enable is toggled it gets picked-up immediately by the parser int slip_update = getBoolArg(connData, "slip-enable", &flashConfig.slip_enable); if (slip_update < 0) return HTTPD_CGI_DONE; +#ifdef CGIMQTT_DBG if (slip_update > 0) os_printf("SLIP-enable changed: %d\n", flashConfig.slip_enable); os_printf("Saving config\n"); +#endif if (configSave()) { httpdStartResponse(connData, 200); httpdEndHeaders(connData); diff --git a/esp-link/cgipins.c b/esp-link/cgipins.c index dabc1fd..80326df 100644 --- a/esp-link/cgipins.c +++ b/esp-link/cgipins.c @@ -85,8 +85,9 @@ int ICACHE_FLASH_ATTR cgiPinsSet(HttpdConnData *connData) { jsonHeader(connData, 400); return HTTPD_CGI_DONE; } - +#ifdef CGIPINS_DBG os_printf("Switching pin map to %s (%d)\n", map_names[m], m); +#endif int8_t *map = map_asn[m]; flashConfig.reset_pin = map[0]; flashConfig.isp_pin = map[1]; diff --git a/esp-link/cgiwifi.c b/esp-link/cgiwifi.c index 69d59b4..7292447 100644 --- a/esp-link/cgiwifi.c +++ b/esp-link/cgiwifi.c @@ -55,36 +55,48 @@ static void ICACHE_FLASH_ATTR wifiHandleEventCb(System_Event_t *evt) { case EVENT_STAMODE_CONNECTED: wifiState = wifiIsConnected; wifiReason = 0; +#ifdef CGIWIFI_DBG os_printf("Wifi connected to ssid %s, ch %d\n", evt->event_info.connected.ssid, evt->event_info.connected.channel); +#endif statusWifiUpdate(wifiState); break; case EVENT_STAMODE_DISCONNECTED: wifiState = wifiIsDisconnected; wifiReason = evt->event_info.disconnected.reason; +#ifdef CGIWIFI_DBG os_printf("Wifi disconnected from ssid %s, reason %s (%d)\n", evt->event_info.disconnected.ssid, wifiGetReason(), evt->event_info.disconnected.reason); +#endif statusWifiUpdate(wifiState); break; case EVENT_STAMODE_AUTHMODE_CHANGE: +#ifdef CGIWIFI_DBG os_printf("Wifi auth mode: %d -> %d\n", evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); +#endif break; case EVENT_STAMODE_GOT_IP: wifiState = wifiGotIP; wifiReason = 0; +#ifdef CGIWIFI_DBG os_printf("Wifi got ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", IP2STR(&evt->event_info.got_ip.ip), IP2STR(&evt->event_info.got_ip.mask), IP2STR(&evt->event_info.got_ip.gw)); +#endif statusWifiUpdate(wifiState); break; case EVENT_SOFTAPMODE_STACONNECTED: +#ifdef CGIWIFI_DBG os_printf("Wifi AP: station " MACSTR " joined, AID = %d\n", MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid); +#endif break; case EVENT_SOFTAPMODE_STADISCONNECTED: +#ifdef CGIWIFI_DBG os_printf("Wifi AP: station " MACSTR " left, AID = %d\n", MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid); +#endif break; default: break; @@ -103,7 +115,9 @@ wifiAddStateChangeCb(WifiStateChangeCb cb) { return; } } +#ifdef CGIWIFI_DBG os_printf("WIFI: max state change cb count exceeded\n"); +#endif } // ===== wifi scanning @@ -132,7 +146,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { struct bss_info *bss_link = (struct bss_info *)arg; if (status!=OK) { +#ifdef CGIWIFI_DBG os_printf("wifiScanDoneCb status=%d\n", status); +#endif cgiWifiAps.scanInProgress=0; return; } @@ -152,7 +168,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { //Allocate memory for access point data cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n); cgiWifiAps.noAps=n; +#ifdef CGIWIFI_DBG os_printf("Scan done: found %d APs\n", n); +#endif //Copy access point data to the static struct n=0; @@ -161,7 +179,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { if (n>=cgiWifiAps.noAps) { //This means the bss_link changed under our nose. Shouldn't happen! //Break because otherwise we will write in unallocated memory. +#ifdef CGIWIFI_DBG os_printf("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps); +#endif break; } //Save the ap data. @@ -169,7 +189,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { cgiWifiAps.apData[n]->rssi=bss_link->rssi; cgiWifiAps.apData[n]->enc=bss_link->authmode; strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32); +#ifdef CGIWIFI_DBG os_printf("bss%d: %s (%d)\n", n+1, (char*)bss_link->ssid, bss_link->rssi); +#endif bss_link = bss_link->next.stqe_next; n++; @@ -180,7 +202,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { static ETSTimer scanTimer; static void ICACHE_FLASH_ATTR scanStartCb(void *arg) { +#ifdef CGIWIFI_DBG os_printf("Starting a scan\n"); +#endif wifi_station_scan(NULL, wifiScanDoneCb); } @@ -245,13 +269,17 @@ static ETSTimer resetTimer; static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { int x = wifi_station_get_connect_status(); int m = wifi_get_opmode() & 0x3; +#ifdef CGIWIFI_DBG os_printf("Wifi check: mode=%s status=%d\n", wifiMode[m], x); +#endif if (x == STATION_GOT_IP) { if (m != 1) { #ifdef CHANGE_TO_STA // We're happily connected, go to STA mode +#ifdef CGIWIFI_DBG os_printf("Wifi got IP. Going into STA mode..\n"); +#endif wifi_set_opmode(1); wifi_set_sleep_type(SLEEP_MODE); os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); @@ -261,11 +289,15 @@ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { // no more resetTimer at this point, gotta use physical reset to recover if in trouble } else { if (m != 3) { +#ifdef CGIWIFI_DBG os_printf("Wifi connect failed. Going into STA+AP mode..\n"); +#endif wifi_set_opmode(3); } log_uart(true); +#ifdef CGIWIFI_DBG os_printf("Enabling/continuing uart log\n"); +#endif os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); } } @@ -277,7 +309,9 @@ static ETSTimer reassTimer; // Callback actually doing reassociation static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) { +#ifdef CGIWIFI_DBG os_printf("Wifi changing association\n"); +#endif wifi_station_disconnect(); stconf.bssid_set = 0; wifi_station_set_config(&stconf); @@ -303,7 +337,9 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { //Set to 0 if you want to disable the actual reconnecting bit os_strncpy((char*)stconf.ssid, essid, 32); os_strncpy((char*)stconf.password, passwd, 64); +#ifdef CGIWIFI_DBG os_printf("Wifi try to connect to AP %s pw %s\n", essid, passwd); +#endif //Schedule disconnect/connect os_timer_disarm(&reassTimer); @@ -342,7 +378,6 @@ static bool parse_ip(char *buff, ip_addr_t *ip_ptr) { return false; } -#define DEBUGIP #ifdef DEBUGIP static void ICACHE_FLASH_ATTR debugIP() { struct ip_info info; @@ -365,7 +400,9 @@ static void ICACHE_FLASH_ATTR configWifiIP() { if (wifi_station_dhcpc_status() == DHCP_STARTED) wifi_station_dhcpc_stop(); wifi_station_dhcpc_start(); +#ifdef CGIWIFI_DBG os_printf("Wifi uses DHCP, hostname=%s\n", flashConfig.hostname); +#endif } else { // no DHCP, we got static network config! wifi_station_dhcpc_stop(); @@ -374,7 +411,9 @@ static void ICACHE_FLASH_ATTR configWifiIP() { ipi.netmask.addr = flashConfig.netmask; ipi.gw.addr = flashConfig.gateway; wifi_set_ip_info(0, &ipi); +#ifdef CGIWIFI_DBG os_printf("Wifi uses static IP %d.%d.%d.%d\n", IP2STR(&ipi.ip.addr)); +#endif } #ifdef DEBUGIP debugIP(); @@ -454,7 +493,9 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); if (len!=0) { int m = atoi(buff); +#ifdef CGIWIFI_DBG os_printf("Wifi switching to mode %d\n", m); +#endif wifi_set_opmode(m&3); if (m == 1) { wifi_set_sleep_type(SLEEP_MODE); @@ -557,8 +598,9 @@ int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) { #endif len += os_sprintf(buff+len, "\"x\":0}\n"); - +#ifdef CGIWIFI_DBG os_printf(" -> %s\n", buff); +#endif httpdSend(connData, buff, len); return HTTPD_CGI_DONE; } @@ -582,8 +624,10 @@ int ICACHE_FLASH_ATTR cgiWifiInfo(HttpdConnData *connData) { // so we can revert to STA+AP mode if we can't connect. void ICACHE_FLASH_ATTR wifiInit() { wifi_set_phy_mode(2); +#ifdef CGIWIFI_DBG int x = wifi_get_opmode() & 0x3; os_printf("Wifi init, mode=%s\n", wifiMode[x]); +#endif configWifiIP(); wifi_set_event_handler_cb(wifiHandleEventCb); diff --git a/esp-link/config.c b/esp-link/config.c index 2f405e7..0ab4745 100644 --- a/esp-link/config.c +++ b/esp-link/config.c @@ -6,6 +6,7 @@ #include "config.h" #include "espfs.h" #include "crc16.h" +#include FlashConfig flashConfig; FlashConfig flashDefault = { @@ -19,8 +20,9 @@ FlashConfig flashDefault = { 1, 0, // tcp_enable, rssi_enable "\0", // api_key 0, 0, 0, // slip_enable, mqtt_enable, mqtt_status_enable - 1833, // mqtt port - "\0", "\0", "\0", "\0", "\0", // mqtt host, client, user, password, status-topic + 2, 1, // mqtt_timeout, mqtt_clean_session + 1833, 600, // mqtt port, mqtt_keepalive + "\0", "\0", "\0", "\0", "\0", // mqtt host, client_id, user, password, status-topic }; typedef union { @@ -51,8 +53,8 @@ static void memDump(void *addr, int len) { bool ICACHE_FLASH_ATTR configSave(void) { FlashFull ff; - memset(&ff, 0, sizeof(ff)); - memcpy(&ff, &flashConfig, sizeof(FlashConfig)); + os_memset(&ff, 0, sizeof(ff)); + os_memcpy(&ff, &flashConfig, sizeof(FlashConfig)); uint32_t seq = ff.fc.seq+1; // erase secondary uint32_t addr = FLASH_ADDR + (1-flash_pri)*FLASH_SECT; @@ -104,19 +106,28 @@ bool ICACHE_FLASH_ATTR configRestore(void) { FlashFull ff0, ff1; // read both flash sectors if (spi_flash_read(FLASH_ADDR, (void *)&ff0, sizeof(ff0)) != SPI_FLASH_RESULT_OK) - memset(&ff0, 0, sizeof(ff0)); // clear in case of error + os_memset(&ff0, 0, sizeof(ff0)); // clear in case of error if (spi_flash_read(FLASH_ADDR+FLASH_SECT, (void *)&ff1, sizeof(ff1)) != SPI_FLASH_RESULT_OK) - memset(&ff1, 0, sizeof(ff1)); // clear in case of error + os_memset(&ff1, 0, sizeof(ff1)); // clear in case of error // figure out which one is good flash_pri = selectPrimary(&ff0, &ff1); // if neither is OK, we revert to defaults if (flash_pri < 0) { - memcpy(&flashConfig, &flashDefault, sizeof(FlashConfig)); + os_memcpy(&flashConfig, &flashDefault, sizeof(FlashConfig)); + char chipIdStr[6]; + os_sprintf(chipIdStr, "%06x", system_get_chip_id()); + os_memcpy(&flashConfig.mqtt_clientid, chipIdStr, os_strlen(chipIdStr)); +#ifdef CHIP_IN_HOSTNAME + char hostname[16]; + os_strcpy(hostname, "esp-link-"); + os_strcat(hostname, chipIdStr); + os_memcpy(&flashConfig.hostname, hostname, os_strlen(hostname)); +#endif flash_pri = 0; return false; } // copy good one into global var and return - memcpy(&flashConfig, flash_pri == 0 ? &ff0.fc : &ff1.fc, sizeof(FlashConfig)); + os_memcpy(&flashConfig, flash_pri == 0 ? &ff0.fc : &ff1.fc, sizeof(FlashConfig)); return true; } @@ -125,10 +136,14 @@ static int ICACHE_FLASH_ATTR selectPrimary(FlashFull *ff0, FlashFull *ff1) { uint16_t crc = ff0->fc.crc; ff0->fc.crc = 0; bool ff0_crc_ok = crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0) == crc; - - os_printf("FLASH chk=0x%04x crc=0x%04x full_sz=%d sz=%d\n", +#ifdef CONFIG_DBG + os_printf("FLASH chk=0x%04x crc=0x%04x full_sz=%d sz=%d chip_sz=%d\n", crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0), - crc, sizeof(FlashFull), sizeof(FlashConfig)); + crc, + sizeof(FlashFull), + sizeof(FlashConfig), + getFlashSize()); +#endif // check CRC of ff1 crc = ff1->fc.crc; @@ -144,3 +159,15 @@ static int ICACHE_FLASH_ATTR selectPrimary(FlashFull *ff0, FlashFull *ff1) { else return ff1_crc_ok ? 1 : -1; } + +// returns the flash chip's size, in BYTES +const size_t ICACHE_FLASH_ATTR +getFlashSize() { + uint32_t id = spi_flash_get_id(); + uint8_t mfgr_id = id & 0xff; + uint8_t type_id = (id >> 8) & 0xff; // not relevant for size calculation + uint8_t size_id = (id >> 16) & 0xff; // lucky for us, WinBond ID's their chips as a form that lets us calculate the size + if (mfgr_id != 0xEF) // 0xEF is WinBond; that's all we care about (for now) + return 0; + return 1 << size_id; +} diff --git a/esp-link/config.h b/esp-link/config.h index 89287e6..5a67058 100644 --- a/esp-link/config.h +++ b/esp-link/config.h @@ -17,9 +17,11 @@ typedef struct { uint8_t tcp_enable, rssi_enable; // TCP client settings char api_key[48]; // RSSI submission API key (Grovestreams for now) uint8_t slip_enable, mqtt_enable, // SLIP protocol, MQTT client - mqtt_status_enable; // MQTT status reporting - uint16_t mqtt_port; - char mqtt_hostname[32], mqtt_client[48], mqtt_username[32], mqtt_password[32]; + mqtt_status_enable, // MQTT status reporting + mqtt_timeout, // MQTT send timeout + mqtt_clean_session; // MQTT clean session + uint16_t mqtt_port, mqtt_keepalive; // MQTT Host port, MQTT Keepalive timer + char mqtt_host[32], mqtt_clientid[48], mqtt_username[32], mqtt_password[32]; char mqtt_status_topic[32]; } FlashConfig; extern FlashConfig flashConfig; @@ -27,5 +29,6 @@ extern FlashConfig flashConfig; bool configSave(void); bool configRestore(void); void configWipe(void); +const size_t getFlashSize(); #endif diff --git a/esp-link/log.c b/esp-link/log.c index 9103a41..9a58b4d 100644 --- a/esp-link/log.c +++ b/esp-link/log.c @@ -25,14 +25,18 @@ log_uart(bool enable) { if (!enable && !log_no_uart && flashConfig.log_mode != LOG_MODE_ON) { // we're asked to turn uart off, and uart is on, and the flash setting isn't always-on #if 1 +#ifdef LOG_DBG os_printf("Turning OFF uart log\n"); +#endif os_delay_us(4*1000L); // time for uart to flush log_no_uart = !enable; #endif } else if (enable && log_no_uart && flashConfig.log_mode != LOG_MODE_OFF) { // we're asked to turn uart on, and uart is off, and the flash setting isn't always-off log_no_uart = !enable; +#ifdef LOG_DBG os_printf("Turning ON uart log\n"); +#endif } } diff --git a/esp-link/main.c b/esp-link/main.c index aed1c7f..27a50e5 100644 --- a/esp-link/main.c +++ b/esp-link/main.c @@ -30,7 +30,7 @@ #include "log.h" #include -#define SHOW_HEAP_USE +//#define SHOW_HEAP_USE //Function that tells the authentication system what users/passwords live on the system. //This is disabled in the default build; if you want to try it, enable the authBasic line in @@ -97,9 +97,6 @@ HttpdBuiltInUrl builtInUrls[] = { { NULL, NULL, NULL } }; - -//#define SHOW_HEAP_USE - #ifdef SHOW_HEAP_USE static ETSTimer prHeapTimer; diff --git a/esp-link/status.c b/esp-link/status.c index 4e0da55..2a8346f 100644 --- a/esp-link/status.c +++ b/esp-link/status.c @@ -4,8 +4,9 @@ #include "config.h" #include "serled.h" #include "cgiwifi.h" -#include "tcpclient.h" - +#ifdef TCPCLIENT +#include +#endif //===== "CONN" LED status indication static ETSTimer ledTimer; @@ -66,6 +67,8 @@ void ICACHE_FLASH_ATTR statusWifiUpdate(uint8_t state) { os_timer_arm(&ledTimer, 500, 0); } +#ifdef TCPCLIENT + //===== RSSI Status update sent to GroveStreams #define RSSI_INTERVAL (60*1000) @@ -112,6 +115,7 @@ static void ICACHE_FLASH_ATTR rssiTimerCb(void *v) { } tcpClientSendPush(chan); } +#endif // TCPCLIENT //===== Init status stuff @@ -120,15 +124,20 @@ void ICACHE_FLASH_ATTR statusInit(void) { makeGpio(flashConfig.conn_led_pin); setLed(1); } +#ifdef STATUS_DBG os_printf("CONN led=%d\n", flashConfig.conn_led_pin); +#endif os_timer_disarm(&ledTimer); os_timer_setfn(&ledTimer, ledTimerCb, NULL); os_timer_arm(&ledTimer, 2000, 0); - +#ifdef TCPCLIENT os_timer_disarm(&rssiTimer); os_timer_setfn(&rssiTimer, rssiTimerCb, NULL); os_timer_arm(&rssiTimer, RSSI_INTERVAL, 1); // recurring timer +#endif // TCPCLIENT } + + diff --git a/espfs/espfs.c b/espfs/espfs.c index 128ca29..f9942f3 100644 --- a/espfs/espfs.c +++ b/espfs/espfs.c @@ -109,7 +109,9 @@ void ICACHE_FLASH_ATTR memcpyAligned(char *dst, char *src, int len) { // Returns flags of opened file. int ICACHE_FLASH_ATTR espFsFlags(EspFsFile *fh) { if (fh == NULL) { +#ifdef ESPFS_DBG os_printf("File handle not ready\n"); +#endif return -1; } @@ -121,7 +123,9 @@ int ICACHE_FLASH_ATTR espFsFlags(EspFsFile *fh) { //Open a file and return a pointer to the file desc struct. EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) { if (espFsData == NULL) { +#ifdef ESPFS_DBG os_printf("Call espFsInit first!\n"); +#endif return NULL; } char *p=espFsData; @@ -137,7 +141,9 @@ EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) { //Grab the next file header. os_memcpy(&h, p, sizeof(EspFsHeader)); if (h.magic!=ESPFS_MAGIC) { +#ifdef ESPFS_DBG os_printf("Magic mismatch. EspFS image broken.\n"); +#endif return NULL; } if (h.flags&FLAG_LASTFILE) { @@ -163,7 +169,9 @@ EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) { if (h.compression==COMPRESS_NONE) { r->decompData=NULL; } else { +#ifdef ESPFS_DBG os_printf("Invalid compression: %d\n", h.compression); +#endif return NULL; } return r; diff --git a/html/console.js b/html/console.js new file mode 100644 index 0000000..87f7d1a --- /dev/null +++ b/html/console.js @@ -0,0 +1,72 @@ +function fetchText(delay, repeat) { + var el = $("#console"); + if (el.textEnd == undefined) { + el.textEnd = 0; + el.innerHTML = ""; + } + window.setTimeout(function() { + ajaxJson('GET', console_url + "?start=" + el.textEnd, + function(resp) { + var dly = updateText(resp); + if (repeat) fetchText(dly, repeat); + }, + function() { retryLoad(repeat); }); + }, delay); +} + +function updateText(resp) { + var el = $("#console"); + + var delay = 3000; + if (resp != null && resp.len > 0) { + console.log("updateText got", resp.len, "chars at", resp.start); + if (resp.start > el.textEnd) { + el.innerHTML = el.innerHTML.concat("\r\n'+baud+'')); + + $("#"+baud+"-button").addEventListener("click", function(e) { + e.preventDefault(); + ajaxSpin('POST', "/console/baud?rate="+baud, + function(resp) { showNotification("" + baud + " baud set"); showRate(baud); }, + function(s, st) { showWarning("Error setting baud rate: " + st); } + ); + }); +} + +//===== Log page + +function showDbgMode(mode) { + var btns = $('.dbg-btn'); + for (var i=0; i < btns.length; i++) { + if (btns[i].id === "dbg-"+mode) + addClass(btns[i], "button-selected"); + else + removeClass(btns[i], "button-selected"); + } +} diff --git a/html/favicon.ico b/html/favicon.ico new file mode 100644 index 0000000..bf372a1 Binary files /dev/null and b/html/favicon.ico differ diff --git a/html/head- b/html/head- index e69de29..514ff53 100644 --- a/html/head- +++ b/html/head- @@ -0,0 +1,10 @@ + + + esp-link + + + + + + +
diff --git a/html/home.html b/html/home.html index 2677264..46a984d 100644 --- a/html/home.html +++ b/html/home.html @@ -1 +1,87 @@ - +
+
+
JEELABS
+

esp-link

+

+
+ +
+
+
+

The JeeLabs esp-link firmware bridges the ESP8266 serial port to Wifi and can + program microcontrollers over the serial port, in particular Arduinos, AVRs, and + NXP's LPC800 and other ARM processors.

+

Program an Arduino/AVR using avrdude using a command + line similar to:

+
/home/arduino-1.0.5/hardware/tools/avrdude \
+   -DV -patmega328p -Pnet:esp-link.local:23 -carduino -b115200 -U \
+   -C /home/arduino-1.0.5/hardware/tools/avrdude.conf flash:w:my_sketch.hex:i +
+

where -Pnet:esp-link.local:23 tells avrdude to connect to port 23 of esp-link. + You can substitute the IP address of your esp-link for esp-link.local if necessary.

+

Please refer to + the online README + for up-to-date help and to the forthcoming + JeeLabs blog for an intro to the codebase.

+
+
+
+
+
+

Wifi summary

+
+ + + + + + + + +
+
+

TCP client

+
+ TCP client support in esp-link +
+ + +
+
+ Grovestreams data push +
+ + +
+
+ + +
+ +
+
+
+
+

Pin assignment

+ Select one of the following signal/pin assignments to match your hardware +
+
+
+
+
+
+
+
+
+
+ + + diff --git a/html/log.html b/html/log.html index 7bec267..46ec785 100644 --- a/html/log.html +++ b/html/log.html @@ -1 +1,48 @@ - +
+
+

Debug Log

+
+ +
+

The debug log shows the most recent characters printed by the esp-link software itself to + its own debug log.

+
+

+ Refresh +

+

+ UART debug log: + auto + off + on +

+
+

+    
+
+ + + + + + diff --git a/html/mqtt.html b/html/mqtt.html index 257c137..edddb88 100644 --- a/html/mqtt.html +++ b/html/mqtt.html @@ -28,27 +28,30 @@
+ + +
+
+

Special Settings

+
+ Special settings, use with care! +
+ + +
+
+ + +
+
+ + + + + + +
+ +
+
+
+ + + + + + + + diff --git a/html/wifi/wifi.js b/html/wifi/wifi.js new file mode 100644 index 0000000..0024248 --- /dev/null +++ b/html/wifi/wifi.js @@ -0,0 +1,200 @@ +var currAp = ""; +var blockScan = 0; + +function createInputForAp(ap) { + if (ap.essid=="" && ap.rssi==0) return; + + var input = e("input"); + input.type = "radio"; + input.name = "essid"; + input.value=ap.essid; + input.id = "opt-" + ap.essid; + if (currAp == ap.essid) input.checked = "1"; + + var bars = e("div"); + var rssiVal = -Math.floor(ap.rssi/51)*32; + bars.className = "lock-icon"; + bars.style.backgroundPosition = "0px "+rssiVal+"px"; + + var rssi = e("div"); + rssi.innerHTML = "" + ap.rssi +"dB"; + + var encrypt = e("div"); + var encVal = "-64"; //assume wpa/wpa2 + if (ap.enc == "0") encVal = "0"; //open + if (ap.enc == "1") encVal = "-32"; //wep + encrypt.className = "lock-icon"; + encrypt.style.backgroundPosition = "-32px "+encVal+"px"; + + var label = e("div"); + label.innerHTML = ap.essid; + + var div = m('').childNodes[0]; + div.appendChild(input); + div.appendChild(encrypt); + div.appendChild(bars); + div.appendChild(rssi); + div.appendChild(label); + return div; +} + +function getSelectedEssid() { + var e = document.forms.wifiform.elements; + for (var i=0; i 60) { + return scanAPs(); + } + scanReqCnt += 1; + ajaxJson('GET', "scan", function(data) { + currAp = getSelectedEssid(); + if (data.result.inProgress == "0" && data.result.APs.length > 1) { + $("#aps").innerHTML = ""; + var n = 0; + for (var i=0; i"+data.ip+", else connect to network "+data.ssid+" first."; + } else { + blockScan = 0; + showWarning("Connection failed: " + data.status + ", " + data.reason); + $("#aps").innerHTML = + "Check password and selected AP. Go Back"; + } + }, function(s, st) { + //showWarning("Can't get status: " + st); + window.setTimeout(getStatus, 2000); + }); +} + +function changeWifiMode(m) { + blockScan = 1; + hideWarning(); + ajaxSpin("POST", "setmode?mode=" + m, function(resp) { + showNotification("Mode changed"); + window.setTimeout(getWifiInfo, 100); + blockScan = 0; + }, function(s, st) { + showWarning("Error changing mode: " + st); + window.setTimeout(getWifiInfo, 100); + blockScan = 0; + }); +} + +function changeWifiAp(e) { + e.preventDefault(); + var passwd = $("#wifi-passwd").value; + var essid = getSelectedEssid(); + showNotification("Connecting to " + essid); + var url = "connect?essid="+encodeURIComponent(essid)+"&passwd="+encodeURIComponent(passwd); + + hideWarning(); + $("#reconnect").setAttribute("hidden", ""); + $("#wifi-passwd").value = ""; + var cb = $("#connect-button"); + var cn = cb.className; + cb.className += ' pure-button-disabled'; + blockScan = 1; + ajaxSpin("POST", url, function(resp) { + $("#spinner").removeAttribute('hidden'); // hack + showNotification("Waiting for network change..."); + window.scrollTo(0, 0); + window.setTimeout(getStatus, 2000); + }, function(s, st) { + showWarning("Error switching network: "+st); + cb.className = cn; + window.setTimeout(scanAPs, 1000); + }); +} + +function changeSpecial(e) { + e.preventDefault(); + var url = "special"; + url += "?dhcp=" + document.querySelector('input[name="dhcp"]:checked').value; + url += "&hostname=" + encodeURIComponent($("#wifi-hostname").value); + url += "&staticip=" + encodeURIComponent($("#wifi-staticip").value); + url += "&netmask=" + encodeURIComponent($("#wifi-netmask").value); + url += "&gateway=" + encodeURIComponent($("#wifi-gateway").value); + + hideWarning(); + var cb = $("#special-button"); + addClass(cb, 'pure-button-disabled'); + ajaxSpin("POST", url, function(resp) { + removeClass(cb, 'pure-button-disabled'); + getWifiInfo(); + }, function(s, st) { + showWarning("Error: "+st); + removeClass(cb, 'pure-button-disabled'); + getWifiInfo(); + }); +} + +function doDhcp() { + $('#dhcp-on').removeAttribute('hidden'); + $('#dhcp-off').setAttribute('hidden', ''); +} + +function doStatic() { + $('#dhcp-off').removeAttribute('hidden'); + $('#dhcp-on').setAttribute('hidden', ''); +} diff --git a/httpd/httpd.c b/httpd/httpd.c index bccbbb0..2db8051 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -3,15 +3,15 @@ Esp8266 http server - core routines */ /* - * ---------------------------------------------------------------------------- - * "THE BEER-WARE LICENSE" (Revision 42): - * Jeroen Domburg wrote this file. As long as you retain - * this notice you can do whatever you want with this stuff. If we meet some day, - * and you think this stuff is worth it, you can buy me a beer in return. - * ---------------------------------------------------------------------------- - * Modified and enhanced by Thorsten von Eicken in 2015 - * ---------------------------------------------------------------------------- - */ +* ---------------------------------------------------------------------------- +* "THE BEER-WARE LICENSE" (Revision 42): +* Jeroen Domburg wrote this file. As long as you retain +* this notice you can do whatever you want with this stuff. If we meet some day, +* and you think this stuff is worth it, you can buy me a beer in return. +* ---------------------------------------------------------------------------- +* Modified and enhanced by Thorsten von Eicken in 2015 +* ---------------------------------------------------------------------------- +*/ #include @@ -33,10 +33,10 @@ static HttpdBuiltInUrl *builtInUrls; //Private data for http connection struct HttpdPriv { - char head[MAX_HEAD_LEN]; - int headPos; - char *sendBuff; - int sendBuffLen; + char head[MAX_HEAD_LEN]; + int headPos; + char *sendBuff; + int sendBuffLen; }; //Connection pool @@ -50,36 +50,36 @@ static esp_tcp httpdTcp; //Struct to keep extension->mime data in typedef struct { - const char *ext; - const char *mimetype; + const char *ext; + const char *mimetype; } MimeMap; //The mappings from file extensions to mime types. If you need an extra mime type, //add it here. -static const MimeMap mimeTypes[]={ - {"htm", "text/htm"}, - {"html", "text/html; charset=UTF-8"}, - {"css", "text/css"}, - {"js", "text/javascript"}, - {"txt", "text/plain"}, - {"jpg", "image/jpeg"}, - {"jpeg", "image/jpeg"}, - {"png", "image/png"}, - {"tpl", "text/html; charset=UTF-8"}, - {NULL, "text/html"}, //default value +static const MimeMap mimeTypes[] = { + { "htm", "text/htm" }, + { "html", "text/html; charset=UTF-8" }, + { "css", "text/css" }, + { "js", "text/javascript" }, + { "txt", "text/plain" }, + { "jpg", "image/jpeg" }, + { "jpeg", "image/jpeg" }, + { "png", "image/png" }, + { "tpl", "text/html; charset=UTF-8" }, + { NULL, "text/html" }, //default value }; //Returns a static char* to a mime type for a given url to a file. const char ICACHE_FLASH_ATTR *httpdGetMimetype(char *url) { - int i=0; - //Go find the extension - char *ext=url+(strlen(url)-1); - while (ext!=url && *ext!='.') ext--; - if (*ext=='.') ext++; - - //ToDo: os_strcmp is case sensitive; we may want to do case-intensive matching here... - while (mimeTypes[i].ext!=NULL && os_strcmp(ext, mimeTypes[i].ext)!=0) i++; - return mimeTypes[i].mimetype; + int i = 0; + //Go find the extension + char *ext = url + (strlen(url) - 1); + while (ext != url && *ext != '.') ext--; + if (*ext == '.') ext++; + + //ToDo: os_strcmp is case sensitive; we may want to do case-intensive matching here... + while (mimeTypes[i].ext != NULL && os_strcmp(ext, mimeTypes[i].ext) != 0) i++; + return mimeTypes[i].mimetype; } // debug string to identify connection (ip address & port) @@ -87,59 +87,65 @@ const char ICACHE_FLASH_ATTR *httpdGetMimetype(char *url) { static char connStr[24]; static void debugConn(void *arg, char *what) { - struct espconn *espconn = arg; - esp_tcp *tcp = espconn->proto.tcp; - os_sprintf(connStr, "%d.%d.%d.%d:%d", - tcp->remote_ip[0], tcp->remote_ip[1], tcp->remote_ip[2], tcp->remote_ip[3], - tcp->remote_port); - //os_printf("%s %s\n", connStr, what); + struct espconn *espconn = arg; + esp_tcp *tcp = espconn->proto.tcp; + os_sprintf(connStr, "%d.%d.%d.%d:%d", + tcp->remote_ip[0], tcp->remote_ip[1], tcp->remote_ip[2], tcp->remote_ip[3], + tcp->remote_port); + //os_printf("%s %s\n", connStr, what); } //Looks up the connData info for a specific esp connection static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) { - struct espconn *espconn = arg; - for (int i=0; iproto.tcp->remote_port && - os_memcmp(connData[i].remote_ip, espconn->proto.tcp->remote_ip, 4) == 0) - { + struct espconn *espconn = arg; + for (int i = 0; iproto.tcp->remote_port && + os_memcmp(connData[i].remote_ip, espconn->proto.tcp->remote_ip, 4) == 0) + { #if 0 - os_printf("FindConn: 0x%p->0x%p", arg, &connData[i]); - if (arg == connData[i].conn) os_printf("\n"); - else os_printf(" *** was 0x%p\n", connData[i].conn); +#ifdef HTTPD_DBG + os_printf("FindConn: 0x%p->0x%p", arg, &connData[i]); + if (arg == connData[i].conn) os_printf("\n"); + else os_printf(" *** was 0x%p\n", connData[i].conn); +#endif #endif - if (arg != connData[i].conn) connData[i].conn = arg; // yes, this happens!? - return &connData[i]; - } - } - //Shouldn't happen. - os_printf("%s *** Unknown connection 0x%p\n", connStr, arg); - return NULL; + if (arg != connData[i].conn) connData[i].conn = arg; // yes, this happens!? + return &connData[i]; + } + } + //Shouldn't happen. +#ifdef HTTPD_DBG + os_printf("%s *** Unknown connection 0x%p\n", connStr, arg); +#endif + return NULL; } //Retires a connection for re-use static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) { - conn->conn = NULL; // don't try to send anything, the SDK crashes... - if (conn->cgi != NULL) conn->cgi(conn); // free cgi data - if (conn->post->buff != NULL) { - os_free(conn->post->buff); - } - conn->cgi=NULL; - conn->post->buff=NULL; - conn->remote_port = 0; - conn->remote_ip[0] = 0; - - uint32 dt = conn->startTime; - if (dt > 0) dt = (system_get_time() - dt)/1000; - os_printf("%s Closed, %ums, heap=%ld\n", connStr, dt, - (unsigned long)system_get_free_heap_size()); + conn->conn = NULL; // don't try to send anything, the SDK crashes... + if (conn->cgi != NULL) conn->cgi(conn); // free cgi data + if (conn->post->buff != NULL) { + os_free(conn->post->buff); + } + conn->cgi = NULL; + conn->post->buff = NULL; + conn->remote_port = 0; + conn->remote_ip[0] = 0; + + uint32 dt = conn->startTime; + if (dt > 0) dt = (system_get_time() - dt) / 1000; +#ifdef HTTPD_DBG + os_printf("%s Closed, %ums, heap=%ld\n", connStr, dt, + (unsigned long)system_get_free_heap_size()); +#endif } //Stupid li'l helper function that returns the value of a hex char. static int httpdHexVal(char c) { - if (c>='0' && c<='9') return c-'0'; - if (c>='A' && c<='F') return c-'A'+10; - if (c>='a' && c<='f') return c-'a'+10; - return 0; + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + return 0; } //Decode a percent-encoded value. @@ -147,27 +153,31 @@ static int httpdHexVal(char c) { //are stored in the ret buffer. Returns the actual amount of bytes used in ret. Also //zero-terminates the ret buffer. int httpdUrlDecode(char *val, int valLen, char *ret, int retLen) { - int s=0, d=0; - int esced=0, escVal=0; - while (s1) { - *ret++=*p++; - retLen--; - } - //Zero-terminate string - *ret=0; - //All done :) - return 1; - } - p+=strlen(p)+1; //Skip past end of string and \0 terminator - } - return 0; + char *p = conn->priv->head; + p = p + strlen(p) + 1; //skip GET/POST part + p = p + strlen(p) + 1; //skip HTTP part + while (p<(conn->priv->head + conn->priv->headPos)) { + while (*p <= 32 && *p != 0) p++; //skip crap at start + //See if this is the header + if (os_strncmp(p, header, strlen(header)) == 0 && p[strlen(header)] == ':') { + //Skip 'key:' bit of header line + p = p + strlen(header) + 1; + //Skip past spaces after the colon + while (*p == ' ') p++; + //Copy from p to end + while (*p != 0 && *p != '\r' && *p != '\n' && retLen>1) { + *ret++ = *p++; + retLen--; + } + //Zero-terminate string + *ret = 0; + //All done :) + return 1; + } + p += strlen(p) + 1; //Skip past end of string and \0 terminator + } + return 0; } //Start the response headers. void ICACHE_FLASH_ATTR httpdStartResponse(HttpdConnData *conn, int code) { - char buff[128]; - int l; - char *status = code < 400 ? "OK" : "ERROR"; - l = os_sprintf(buff, "HTTP/1.0 %d %s\r\nServer: esp-link\r\nConnection: close\r\n", code, status); - httpdSend(conn, buff, l); + char buff[128]; + int l; + char *status = code < 400 ? "OK" : "ERROR"; + l = os_sprintf(buff, "HTTP/1.0 %d %s\r\nServer: esp-link\r\nConnection: close\r\n", code, status); + httpdSend(conn, buff, l); } //Send a http header. void ICACHE_FLASH_ATTR httpdHeader(HttpdConnData *conn, const char *field, const char *val) { - char buff[256]; - int l; + char buff[256]; + int l; - l=os_sprintf(buff, "%s: %s\r\n", field, val); - httpdSend(conn, buff, l); + l = os_sprintf(buff, "%s: %s\r\n", field, val); + httpdSend(conn, buff, l); } //Finish the headers. void ICACHE_FLASH_ATTR httpdEndHeaders(HttpdConnData *conn) { - httpdSend(conn, "\r\n", -1); + httpdSend(conn, "\r\n", -1); } //ToDo: sprintf->snprintf everywhere... esp doesn't have snprintf tho' :/ //Redirect to the given URL. void ICACHE_FLASH_ATTR httpdRedirect(HttpdConnData *conn, char *newUrl) { - char buff[1024]; - int l; - l=os_sprintf(buff, "HTTP/1.0 302 Found\r\nServer: esp8266-link\r\nConnection: close\r\nLocation: %s\r\n\r\nRedirecting to %s\r\n", newUrl, newUrl); - httpdSend(conn, buff, l); + char buff[1024]; + int l; + l = os_sprintf(buff, "HTTP/1.0 302 Found\r\nServer: esp8266-link\r\nConnection: close\r\nLocation: %s\r\n\r\nRedirecting to %s\r\n", newUrl, newUrl); + httpdSend(conn, buff, l); } //Use this as a cgi function to redirect one url to another. int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) { - if (connData->conn==NULL) { - //Connection aborted. Clean up. - return HTTPD_CGI_DONE; - } - httpdRedirect(connData, (char*)connData->cgiArg); - return HTTPD_CGI_DONE; + if (connData->conn == NULL) { + //Connection aborted. Clean up. + return HTTPD_CGI_DONE; + } + httpdRedirect(connData, (char*)connData->cgiArg); + return HTTPD_CGI_DONE; } @@ -270,321 +280,349 @@ int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) { //the data is seen as a C-string. //Returns 1 for success, 0 for out-of-memory. int ICACHE_FLASH_ATTR httpdSend(HttpdConnData *conn, const char *data, int len) { - if (len<0) len=strlen(data); - if (conn->priv->sendBuffLen+len>MAX_SENDBUFF_LEN) { - os_printf("%s ERROR! httpdSend full (%d of %d)\n", - connStr, conn->priv->sendBuffLen, MAX_SENDBUFF_LEN); - return 0; - } - os_memcpy(conn->priv->sendBuff+conn->priv->sendBuffLen, data, len); - conn->priv->sendBuffLen+=len; - return 1; + if (len<0) len = strlen(data); + if (conn->priv->sendBuffLen + len>MAX_SENDBUFF_LEN) { +#ifdef HTTPD_DBG + os_printf("%s ERROR! httpdSend full (%d of %d)\n", + connStr, conn->priv->sendBuffLen, MAX_SENDBUFF_LEN); +#endif + return 0; + } + os_memcpy(conn->priv->sendBuff + conn->priv->sendBuffLen, data, len); + conn->priv->sendBuffLen += len; + return 1; } //Helper function to send any data in conn->priv->sendBuff static void ICACHE_FLASH_ATTR xmitSendBuff(HttpdConnData *conn) { - if (conn->priv->sendBuffLen!=0) { - sint8 status = espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen); - if (status != 0) { - os_printf("%s ERROR! espconn_sent returned %d\n", connStr, status); - } - conn->priv->sendBuffLen=0; - } + if (conn->priv->sendBuffLen != 0) { + sint8 status = espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen); + if (status != 0) { +#ifdef HTTPD_DBG + os_printf("%s ERROR! espconn_sent returned %d\n", connStr, status); +#endif + } + conn->priv->sendBuffLen = 0; + } } //Callback called when the data on a socket has been successfully sent. static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) { - debugConn(arg, "httpdSentCb"); - int r; - HttpdConnData *conn=httpdFindConnData(arg); - char sendBuff[MAX_SENDBUFF_LEN]; - - if (conn==NULL) return; - conn->priv->sendBuff=sendBuff; - conn->priv->sendBuffLen=0; - - if (conn->cgi==NULL) { //Marked for destruction? - //os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn); - espconn_disconnect(conn->conn); // we will get a disconnect callback - return; //No need to call xmitSendBuff. - } - - r=conn->cgi(conn); //Execute cgi fn. - if (r==HTTPD_CGI_DONE) { - conn->cgi=NULL; //mark for destruction. - } - if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { - os_printf("%s ERROR! Bad CGI code %d\n", connStr, r); - conn->cgi=NULL; //mark for destruction. - } - xmitSendBuff(conn); + debugConn(arg, "httpdSentCb"); + int r; + HttpdConnData *conn = httpdFindConnData(arg); + char sendBuff[MAX_SENDBUFF_LEN]; + + if (conn == NULL) return; + conn->priv->sendBuff = sendBuff; + conn->priv->sendBuffLen = 0; + + if (conn->cgi == NULL) { //Marked for destruction? + //os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn); + espconn_disconnect(conn->conn); // we will get a disconnect callback + return; //No need to call xmitSendBuff. + } + + r = conn->cgi(conn); //Execute cgi fn. + if (r == HTTPD_CGI_DONE) { + conn->cgi = NULL; //mark for destruction. + } + if (r == HTTPD_CGI_NOTFOUND || r == HTTPD_CGI_AUTHENTICATED) { +#ifdef HTTPD_DBG + os_printf("%s ERROR! Bad CGI code %d\n", connStr, r); +#endif + conn->cgi = NULL; //mark for destruction. + } + xmitSendBuff(conn); } -static const char *httpNotFoundHeader="HTTP/1.0 404 Not Found\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nNot Found.\r\n"; +static const char *httpNotFoundHeader = "HTTP/1.0 404 Not Found\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nNot Found.\r\n"; //This is called when the headers have been received and the connection is ready to send //the result headers and data. //We need to find the CGI function to call, call it, and dependent on what it returns either //find the next cgi function, wait till the cgi data is sent or close up the connection. static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { - int r; - int i=0; - if (conn->url==NULL) { - os_printf("%s WtF? url = NULL\n", connStr); - return; //Shouldn't happen - } - //See if we can find a CGI that's happy to handle the request. - while (1) { - //Look up URL in the built-in URL table. - while (builtInUrls[i].url!=NULL) { - int match=0; - //See if there's a literal match - if (os_strcmp(builtInUrls[i].url, conn->url)==0) match=1; - //See if there's a wildcard match - if (builtInUrls[i].url[os_strlen(builtInUrls[i].url)-1]=='*' && - os_strncmp(builtInUrls[i].url, conn->url, os_strlen(builtInUrls[i].url)-1)==0) match=1; - if (match) { - //os_printf("Is url index %d\n", i); - conn->cgiData=NULL; - conn->cgi=builtInUrls[i].cgiCb; - conn->cgiArg=builtInUrls[i].cgiArg; - break; - } - i++; - } - if (builtInUrls[i].url==NULL) { - //Drat, we're at the end of the URL table. This usually shouldn't happen. Well, just - //generate a built-in 404 to handle this. - os_printf("%s %s not found. 404!\n", connStr, conn->url); - httpdSend(conn, httpNotFoundHeader, -1); - xmitSendBuff(conn); - conn->cgi=NULL; //mark for destruction - return; - } - - //Okay, we have a CGI function that matches the URL. See if it wants to handle the - //particular URL we're supposed to handle. - r=conn->cgi(conn); - if (r==HTTPD_CGI_MORE) { - //Yep, it's happy to do so and has more data to send. - xmitSendBuff(conn); - return; - } else if (r==HTTPD_CGI_DONE) { - //Yep, it's happy to do so and already is done sending data. - xmitSendBuff(conn); - conn->cgi=NULL; //mark conn for destruction - return; - } else if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { - //URL doesn't want to handle the request: either the data isn't found or there's no - //need to generate a login screen. - i++; //look at next url the next iteration of the loop. - } - } + int r; + int i = 0; + if (conn->url == NULL) { +#ifdef HTTPD_DBG + os_printf("%s WtF? url = NULL\n", connStr); +#endif + return; //Shouldn't happen + } + //See if we can find a CGI that's happy to handle the request. + while (1) { + //Look up URL in the built-in URL table. + while (builtInUrls[i].url != NULL) { + int match = 0; + //See if there's a literal match + if (os_strcmp(builtInUrls[i].url, conn->url) == 0) match = 1; + //See if there's a wildcard match + if (builtInUrls[i].url[os_strlen(builtInUrls[i].url) - 1] == '*' && + os_strncmp(builtInUrls[i].url, conn->url, os_strlen(builtInUrls[i].url) - 1) == 0) match = 1; + if (match) { + //os_printf("Is url index %d\n", i); + conn->cgiData = NULL; + conn->cgi = builtInUrls[i].cgiCb; + conn->cgiArg = builtInUrls[i].cgiArg; + break; + } + i++; + } + if (builtInUrls[i].url == NULL) { + //Drat, we're at the end of the URL table. This usually shouldn't happen. Well, just + //generate a built-in 404 to handle this. +#ifdef HTTPD_DBG + os_printf("%s %s not found. 404!\n", connStr, conn->url); +#endif + httpdSend(conn, httpNotFoundHeader, -1); + xmitSendBuff(conn); + conn->cgi = NULL; //mark for destruction + return; + } + + //Okay, we have a CGI function that matches the URL. See if it wants to handle the + //particular URL we're supposed to handle. + r = conn->cgi(conn); + if (r == HTTPD_CGI_MORE) { + //Yep, it's happy to do so and has more data to send. + xmitSendBuff(conn); + return; + } + else if (r == HTTPD_CGI_DONE) { + //Yep, it's happy to do so and already is done sending data. + xmitSendBuff(conn); + conn->cgi = NULL; //mark conn for destruction + return; + } + else if (r == HTTPD_CGI_NOTFOUND || r == HTTPD_CGI_AUTHENTICATED) { + //URL doesn't want to handle the request: either the data isn't found or there's no + //need to generate a login screen. + i++; //look at next url the next iteration of the loop. + } + } } //Parse a line of header data and modify the connection data accordingly. static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { - int i; - char first_line = false; - - if (os_strncmp(h, "GET ", 4)==0) { - conn->requestType = HTTPD_METHOD_GET; - first_line = true; - } else if (os_strncmp(h, "POST ", 5)==0) { - conn->requestType = HTTPD_METHOD_POST; - first_line = true; - } - - if (first_line) { - char *e; - - //Skip past the space after POST/GET - i=0; - while (h[i]!=' ') i++; - conn->url=h+i+1; - - //Figure out end of url. - e=(char*)os_strstr(conn->url, " "); - if (e==NULL) return; //wtf? - *e=0; //terminate url part - - // Count number of open connections - int open = 0; - for (int j=0; jrequestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url, open); - //Parse out the URL part before the GET parameters. - conn->getArgs=(char*)os_strstr(conn->url, "?"); - if (conn->getArgs!=0) { - *conn->getArgs=0; - conn->getArgs++; - os_printf("%s args = %s\n", connStr, conn->getArgs); - } else { - conn->getArgs=NULL; - } - - } else if (os_strncmp(h, "Content-Length:", 15)==0) { - i=15; - //Skip trailing spaces - while (h[i]==' ') i++; - //Get POST data length - conn->post->len=atoi(h+i); - - // Allocate the buffer - if (conn->post->len > MAX_POST) { - // we'll stream this in in chunks - conn->post->buffSize = MAX_POST; - } else { - conn->post->buffSize = conn->post->len; - } - //os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); - conn->post->buff=(char*)os_malloc(conn->post->buffSize + 1); - conn->post->buffLen=0; - } else if (os_strncmp(h, "Content-Type: ", 14)==0) { - if (os_strstr(h, "multipart/form-data")) { - // It's multipart form data so let's pull out the boundary for future use - char *b; - if ((b = os_strstr(h, "boundary=")) != NULL) { - conn->post->multipartBoundary = b + 7; // move the pointer 2 chars before boundary then fill them with dashes - conn->post->multipartBoundary[0] = '-'; - conn->post->multipartBoundary[1] = '-'; - //os_printf("boundary = %s\n", conn->post->multipartBoundary); - } - } - } + int i; + char first_line = false; + + if (os_strncmp(h, "GET ", 4) == 0) { + conn->requestType = HTTPD_METHOD_GET; + first_line = true; + } + else if (os_strncmp(h, "POST ", 5) == 0) { + conn->requestType = HTTPD_METHOD_POST; + first_line = true; + } + + if (first_line) { + char *e; + + //Skip past the space after POST/GET + i = 0; + while (h[i] != ' ') i++; + conn->url = h + i + 1; + + //Figure out end of url. + e = (char*)os_strstr(conn->url, " "); + if (e == NULL) return; //wtf? + *e = 0; //terminate url part + + // Count number of open connections + int open = 0; + for (int j = 0; jrequestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url, open); +#endif + //Parse out the URL part before the GET parameters. + conn->getArgs = (char*)os_strstr(conn->url, "?"); + if (conn->getArgs != 0) { + *conn->getArgs = 0; + conn->getArgs++; +#ifdef HTTPD_DBG + os_printf("%s args = %s\n", connStr, conn->getArgs); +#endif + } + else { + conn->getArgs = NULL; + } + + } + else if (os_strncmp(h, "Content-Length:", 15) == 0) { + i = 15; + //Skip trailing spaces + while (h[i] == ' ') i++; + //Get POST data length + conn->post->len = atoi(h + i); + + // Allocate the buffer + if (conn->post->len > MAX_POST) { + // we'll stream this in in chunks + conn->post->buffSize = MAX_POST; + } + else { + conn->post->buffSize = conn->post->len; + } + //os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); + conn->post->buff = (char*)os_malloc(conn->post->buffSize + 1); + conn->post->buffLen = 0; + } + else if (os_strncmp(h, "Content-Type: ", 14) == 0) { + if (os_strstr(h, "multipart/form-data")) { + // It's multipart form data so let's pull out the boundary for future use + char *b; + if ((b = os_strstr(h, "boundary=")) != NULL) { + conn->post->multipartBoundary = b + 7; // move the pointer 2 chars before boundary then fill them with dashes + conn->post->multipartBoundary[0] = '-'; + conn->post->multipartBoundary[1] = '-'; + //os_printf("boundary = %s\n", conn->post->multipartBoundary); + } + } + } } //Callback called when there's data available on a socket. static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short len) { - debugConn(arg, "httpdRecvCb"); - int x; - char *p, *e; - char sendBuff[MAX_SENDBUFF_LEN]; - HttpdConnData *conn=httpdFindConnData(arg); - if (conn==NULL) return; - conn->priv->sendBuff=sendBuff; - conn->priv->sendBuffLen=0; - - //This is slightly evil/dirty: we abuse conn->post->len as a state variable for where in the http communications we are: - //<0 (-1): Post len unknown because we're still receiving headers - //==0: No post data - //>0: Need to receive post data - //ToDo: See if we can use something more elegant for this. - - for (x=0; xpost->len<0) { - //This byte is a header byte. - if (conn->priv->headPos!=MAX_HEAD_LEN) conn->priv->head[conn->priv->headPos++]=data[x]; - conn->priv->head[conn->priv->headPos]=0; - //Scan for /r/n/r/n. Receiving this indicate the headers end. - if (data[x]=='\n' && (char *)os_strstr(conn->priv->head, "\r\n\r\n")!=NULL) { - //Indicate we're done with the headers. - conn->post->len=0; - //Reset url data - conn->url=NULL; - //Iterate over all received headers and parse them. - p=conn->priv->head; - while(p<(&conn->priv->head[conn->priv->headPos-4])) { - e=(char *)os_strstr(p, "\r\n"); //Find end of header line - if (e==NULL) break; //Shouldn't happen. - e[0]=0; //Zero-terminate header - httpdParseHeader(p, conn); //and parse it. - p=e+2; //Skip /r/n (now /0/n) - } - //If we don't need to receive post data, we can send the response now. - if (conn->post->len==0) { - httpdProcessRequest(conn); - } - } - } else if (conn->post->len!=0) { - //This byte is a POST byte. - conn->post->buff[conn->post->buffLen++]=data[x]; - conn->post->received++; - if (conn->post->buffLen >= conn->post->buffSize || conn->post->received == conn->post->len) { - //Received a chunk of post data - conn->post->buff[conn->post->buffLen]=0; //zero-terminate, in case the cgi handler knows it can use strings - //Send the response. - httpdProcessRequest(conn); - conn->post->buffLen = 0; - } - } - } + debugConn(arg, "httpdRecvCb"); + int x; + char *p, *e; + char sendBuff[MAX_SENDBUFF_LEN]; + HttpdConnData *conn = httpdFindConnData(arg); + if (conn == NULL) return; + conn->priv->sendBuff = sendBuff; + conn->priv->sendBuffLen = 0; + + //This is slightly evil/dirty: we abuse conn->post->len as a state variable for where in the http communications we are: + //<0 (-1): Post len unknown because we're still receiving headers + //==0: No post data + //>0: Need to receive post data + //ToDo: See if we can use something more elegant for this. + + for (x = 0; xpost->len<0) { + //This byte is a header byte. + if (conn->priv->headPos != MAX_HEAD_LEN) conn->priv->head[conn->priv->headPos++] = data[x]; + conn->priv->head[conn->priv->headPos] = 0; + //Scan for /r/n/r/n. Receiving this indicate the headers end. + if (data[x] == '\n' && (char *)os_strstr(conn->priv->head, "\r\n\r\n") != NULL) { + //Indicate we're done with the headers. + conn->post->len = 0; + //Reset url data + conn->url = NULL; + //Iterate over all received headers and parse them. + p = conn->priv->head; + while (p<(&conn->priv->head[conn->priv->headPos - 4])) { + e = (char *)os_strstr(p, "\r\n"); //Find end of header line + if (e == NULL) break; //Shouldn't happen. + e[0] = 0; //Zero-terminate header + httpdParseHeader(p, conn); //and parse it. + p = e + 2; //Skip /r/n (now /0/n) + } + //If we don't need to receive post data, we can send the response now. + if (conn->post->len == 0) { + httpdProcessRequest(conn); + } + } + } + else if (conn->post->len != 0) { + //This byte is a POST byte. + conn->post->buff[conn->post->buffLen++] = data[x]; + conn->post->received++; + if (conn->post->buffLen >= conn->post->buffSize || conn->post->received == conn->post->len) { + //Received a chunk of post data + conn->post->buff[conn->post->buffLen] = 0; //zero-terminate, in case the cgi handler knows it can use strings + //Send the response. + httpdProcessRequest(conn); + conn->post->buffLen = 0; + } + } + } } static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) { - debugConn(arg, "httpdDisconCb"); - HttpdConnData *conn = httpdFindConnData(arg); - if (conn == NULL) return; - httpdRetireConn(conn); + debugConn(arg, "httpdDisconCb"); + HttpdConnData *conn = httpdFindConnData(arg); + if (conn == NULL) return; + httpdRetireConn(conn); } // Callback indicating a failure in the connection. "Recon" is probably intended in the sense // of "you need to reconnect". Sigh... Note that there is no DisconCb after ReconCb static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) { - debugConn(arg, "httpdReconCb"); - HttpdConnData *conn = httpdFindConnData(arg); - os_printf("%s ***** reset, err=%d\n", connStr, err); - if (conn == NULL) return; - httpdRetireConn(conn); + debugConn(arg, "httpdReconCb"); + HttpdConnData *conn = httpdFindConnData(arg); +#ifdef HTTPD_DBG + os_printf("%s ***** reset, err=%d\n", connStr, err); +#endif + if (conn == NULL) return; + httpdRetireConn(conn); } static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) { - debugConn(arg, "httpdConnectCb"); - struct espconn *conn=arg; - int i; - //Find empty conndata in pool - for (i=0; iproto.tcp->remote_port; - os_memcpy(connData[i].remote_ip, conn->proto.tcp->remote_ip, 4); - connData[i].priv->headPos=0; - connData[i].post=&connPostData[i]; - connData[i].post->buff=NULL; - connData[i].post->buffLen=0; - connData[i].post->received=0; - connData[i].post->len=-1; - connData[i].startTime = system_get_time(); - - espconn_regist_recvcb(conn, httpdRecvCb); - espconn_regist_reconcb(conn, httpdReconCb); - espconn_regist_disconcb(conn, httpdDisconCb); - espconn_regist_sentcb(conn, httpdSentCb); - - espconn_set_opt(conn, ESPCONN_REUSEADDR|ESPCONN_NODELAY); + connData[i].priv = &connPrivData[i]; + connData[i].conn = conn; + connData[i].remote_port = conn->proto.tcp->remote_port; + os_memcpy(connData[i].remote_ip, conn->proto.tcp->remote_ip, 4); + connData[i].priv->headPos = 0; + connData[i].post = &connPostData[i]; + connData[i].post->buff = NULL; + connData[i].post->buffLen = 0; + connData[i].post->received = 0; + connData[i].post->len = -1; + connData[i].startTime = system_get_time(); + + espconn_regist_recvcb(conn, httpdRecvCb); + espconn_regist_reconcb(conn, httpdReconCb); + espconn_regist_disconcb(conn, httpdDisconCb); + espconn_regist_sentcb(conn, httpdSentCb); + + espconn_set_opt(conn, ESPCONN_REUSEADDR | ESPCONN_NODELAY); } //Httpd initialization routine. Call this to kick off webserver functionality. void ICACHE_FLASH_ATTR httpdInit(HttpdBuiltInUrl *fixedUrls, int port) { - int i; - - for (i=0; i #endif -//#define CMD_DBG -#define MQTT_RECONNECT_TIMEOUT 5 // seconds -#define MQTT_BUF_SIZE 512 -#define QUEUE_BUFFER_SIZE 512 -#define MQTT_HOST "10.0.0.220" // "mqtt.yourdomain.com" or ip "10.0.0.1" -#define MQTT_PORT 1883 -#define MQTT_SECURITY 0 - -#define MQTT_CLIENT_ID system_get_chip_id_str() // "esp-link" -#define MQTT_USER "" -#define MQTT_PASS "" -#define MQTT_KEEPALIVE 120 // seconds -#define MQTT_CLSESSION true - -#define PROTOCOL_NAMEv31 // MQTT version 3.1 compatible with Mosquitto v0.15/ -//PROTOCOL_NAMEv311 // MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/ +#define CMD_DBG +#define ESPFS_DBG +#define CGI_DBG +#define CGIFLASH_DBG +#define CGIMQTT_DBG +#define CGIPINS_DBG +#define CGIWIFI_DBG +#define CONFIG_DBG +#define LOG_DBG +#define STATUS_DBG +#define HTTPD_DBG +#define MQTT_DBG +#define MQTTCMD_DBG +#define PKTBUF_DBG +#define REST_DBG +#define RESTCMD_DBG +#define SERBR_DBG +#define SERLED_DBG +#define SLIP_DBG +#define UART_DBG +#define CHIP_IN_HOSTNAME + +//#define REST extern char* esp_link_version; - extern uint8_t UTILS_StrToIP(const char* str, void *ip); -extern void ICACHE_FLASH_ATTR init(void); - -extern char* ICACHE_FLASH_ATTR system_get_chip_id_str(); - #endif \ No newline at end of file diff --git a/mqtt/mqtt.c b/mqtt/mqtt.c index ba81b00..d65870b 100644 --- a/mqtt/mqtt.c +++ b/mqtt/mqtt.c @@ -57,10 +57,12 @@ sint8 espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length) // max message size for sending (except publish) #define MQTT_MAX_SHORT_MESSAGE 128 +#ifdef MQTT_DBG static char* mqtt_msg_type[] = { "NULL", "TYPE_CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", "DISCONNECT", "RESV", }; +#endif // forward declarations static void mqtt_enq_message(MQTT_Client *client, const uint8_t *data, uint16_t len); @@ -125,7 +127,9 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { if (msg_len > client->in_buffer_size) { // oops, too long a message for us to digest, disconnect and hope for a miracle +#ifdef MQTT_DBG os_printf("MQTT: Too long a message (%d bytes)\n", msg_len); +#endif mqtt_doAbort(client); return; } @@ -135,7 +139,9 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { if (client->connState != MQTT_CONNECTED) { // why are we receiving something?? +#ifdef MQTT_DBG os_printf("MQTT ERROR: recv in invalid state %d\n", client->connState); +#endif mqtt_doAbort(client); return; } @@ -147,13 +153,16 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { pending_msg_type = mqtt_get_type(client->pending_buffer->data); pending_msg_id = mqtt_get_id(client->pending_buffer->data, client->pending_buffer->filled); } - +#ifdef MQTT_DBG os_printf("MQTT: Recv type=%s id=%04X len=%d; Pend type=%s id=%02X\n", mqtt_msg_type[msg_type], msg_id, msg_len, mqtt_msg_type[pending_msg_type], pending_msg_id); +#endif switch (msg_type) { case MQTT_MSG_TYPE_CONNACK: +#ifdef MQTT_DBG os_printf("MQTT: Connect successful\n"); +#endif // callbacks for internal and external clients if (client->connectedCb) client->connectedCb((uint32_t*)client); if (client->cmdConnectedCb) client->cmdConnectedCb((uint32_t*)client); @@ -161,28 +170,36 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { case MQTT_MSG_TYPE_SUBACK: if (pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: Subscribe successful\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_UNSUBACK: if (pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: Unsubscribe successful\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_PUBACK: // ack for a publish we sent if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: QoS1 Publish successful\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; case MQTT_MSG_TYPE_PUBREC: // rec for a publish we sent if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: QoS2 publish cont\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); // we need to send PUBREL mqtt_msg_pubrel(&client->mqtt_connection, msg_id); @@ -193,7 +210,9 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { case MQTT_MSG_TYPE_PUBCOMP: // comp for a pubrel we sent (originally publish we sent) if (pending_msg_type == MQTT_MSG_TYPE_PUBREL && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: QoS2 Publish successful\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); } break; @@ -201,9 +220,11 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { case MQTT_MSG_TYPE_PUBLISH: { // incoming publish // we may need to ACK the publish uint8_t msg_qos = mqtt_get_qos(client->in_buffer); +#ifdef MQTT_DBG uint16_t topic_length = msg_len; os_printf("MQTT: Recv PUBLISH qos=%d %s\n", msg_qos, mqtt_get_publish_topic(client->in_buffer, &topic_length)); +#endif if (msg_qos == 1) mqtt_msg_puback(&client->mqtt_connection, msg_id); if (msg_qos == 2) mqtt_msg_pubrec(&client->mqtt_connection, msg_id); if (msg_qos == 1 || msg_qos == 2) { @@ -217,7 +238,9 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) { case MQTT_MSG_TYPE_PUBREL: // rel for a rec we sent (originally publish received) if (pending_msg_type == MQTT_MSG_TYPE_PUBREC && pending_msg_id == msg_id) { +#ifdef MQTT_DBG os_printf("MQTT: Cont QoS2 recv\n"); +#endif client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); // we need to send PUBCOMP mqtt_msg_pubcomp(&client->mqtt_connection, msg_id); @@ -294,7 +317,9 @@ mqtt_timer(void* arg) { // check whether our last keep-alive timed out if (client->keepAliveAckTick > 0 && --client->keepAliveAckTick == 0) { +#ifdef MQTT_DBG os_printf("\nMQTT ERROR: Keep-alive timed out\n"); +#endif mqtt_doAbort(client); return; } @@ -337,15 +362,17 @@ void ICACHE_FLASH_ATTR mqtt_tcpclient_discon_cb(void* arg) { struct espconn* pespconn = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pespconn->reverse; - +#ifdef MQTT_DBG os_printf("MQTT: Disconnect CB, freeing espconn %p\n", arg); +#endif if (pespconn->proto.tcp) os_free(pespconn->proto.tcp); os_free(pespconn); // if this is an aborted connection we're done if (client == NULL) return; - +#ifdef MQTT_DBG os_printf("MQTT: Disconnected from %s:%d\n", client->host, client->port); +#endif if (client->disconnectedCb) client->disconnectedCb((uint32_t*)client); if (client->cmdDisconnectedCb) client->cmdDisconnectedCb((uint32_t*)client); @@ -364,12 +391,14 @@ static void ICACHE_FLASH_ATTR mqtt_tcpclient_recon_cb(void* arg, int8_t err) { struct espconn* pespconn = (struct espconn *)arg; MQTT_Client* client = (MQTT_Client *)pespconn->reverse; - +#ifdef MQTT_DBG os_printf("MQTT: Reset CB, freeing espconn %p (err=%d)\n", arg, err); +#endif if (pespconn->proto.tcp) os_free(pespconn->proto.tcp); os_free(pespconn); - +#ifdef MQTT_DBG os_printf("MQTT: Connection reset from %s:%d\n", client->host, client->port); +#endif if (client->disconnectedCb) client->disconnectedCb((uint32_t*)client); if (client->cmdDisconnectedCb) client->cmdDisconnectedCb((uint32_t*)client); @@ -394,7 +423,9 @@ mqtt_tcpclient_connect_cb(void* arg) { espconn_regist_disconcb(client->pCon, mqtt_tcpclient_discon_cb); espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv); espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb); +#ifdef MQTT_DBG os_printf("MQTT: TCP connected to %s:%d\n", client->host, client->port); +#endif // send MQTT connect message to broker mqtt_msg_connect(&client->mqtt_connection, &client->connect_info); @@ -435,8 +466,9 @@ mqtt_send_message(MQTT_Client* client) { // get some details about the message uint16_t msg_type = mqtt_get_type(buf->data); uint8_t msg_id = mqtt_get_id(buf->data, buf->filled); + msg_id = msg_id; +#ifdef MQTT_DBG os_printf("MQTT: Send type=%s id=%04X len=%d\n", mqtt_msg_type[msg_type], msg_id, buf->filled); -#if 0 for (int i=0; ifilled; i++) { if (buf->data[i] >= ' ' && buf->data[i] <= '~') os_printf("%c", buf->data[i]); else os_printf("\\x%02X", buf->data[i]); @@ -481,17 +513,20 @@ mqtt_dns_found(const char* name, ip_addr_t* ipaddr, void* arg) { MQTT_Client* client = (MQTT_Client *)pConn->reverse; if (ipaddr == NULL) { +#ifdef MQTT_DBG os_printf("MQTT DNS: Got no ip, try to reconnect\n"); +#endif client->timeoutTick = 10; client->connState = TCP_RECONNECT_REQ; // the timer will kick-off a reconnection return; } - +#ifdef MQTT_DBG os_printf("MQTT DNS: found ip %d.%d.%d.%d\n", *((uint8 *)&ipaddr->addr), *((uint8 *)&ipaddr->addr + 1), *((uint8 *)&ipaddr->addr + 2), *((uint8 *)&ipaddr->addr + 3)); +#endif if (client->ip.addr == 0 && ipaddr->addr != 0) { os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); @@ -501,11 +536,15 @@ mqtt_dns_found(const char* name, ip_addr_t* ipaddr, void* arg) { else err = espconn_connect(client->pCon); if (err != 0) { +#ifdef MQTT_DBG os_printf("MQTT ERROR: Failed to connect\n"); +#endif client->connState = TCP_RECONNECT_REQ; client->timeoutTick = 10; } else { +#ifdef MQTT_DBG os_printf("MQTT: connecting...\n"); +#endif } } } @@ -539,7 +578,9 @@ MQTT_Publish(MQTT_Client* client, const char* topic, const char* data, uint8_t q uint16_t buf_len = 3 + 2 + 2 + topic_length + data_length + 16; PktBuf *buf = PktBuf_New(buf_len); if (buf == NULL) { +#ifdef MQTT_DBG os_printf("MQTT ERROR: Cannot allocate buffer for %d byte publish\n", buf_len); +#endif return FALSE; } // use a temporary mqtt_message_t pointing to our buffer, this is a bit of a mess because we @@ -548,13 +589,16 @@ MQTT_Publish(MQTT_Client* client, const char* topic, const char* data, uint8_t q msg_conn_init(&msg, &client->mqtt_connection, buf->data, buf_len); uint16_t msg_id; if (!mqtt_msg_publish(&msg, topic, data, data_length, qos, retain, &msg_id)){ +#ifdef MQTT_DBG os_printf("MQTT ERROR: Queuing Publish failed\n"); +#endif os_free(buf); return FALSE; } client->mqtt_connection.message_id = msg.message_id; - +#ifdef MQTT_DBG os_printf("MQTT: Publish, topic: \"%s\", length: %d\n", topic, msg.message.length); +#endif client->msgQueue = PktBuf_Push(client->msgQueue, buf); if (!client->sending && client->pending_buffer == NULL) { @@ -574,10 +618,14 @@ bool ICACHE_FLASH_ATTR MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos) { uint16_t msg_id; if (!mqtt_msg_subscribe(&client->mqtt_connection, topic, 0, &msg_id)) { +#ifdef MQTT_DBG os_printf("MQTT ERROR: Queuing Subscribe failed (too long)\n"); +#endif return FALSE; } +#ifdef MQTT_DBG os_printf("MQTT: Subscribe, topic: \"%s\"\n", topic); +#endif mqtt_enq_message(client, client->mqtt_connection.message.data, client->mqtt_connection.message.length); return TRUE; @@ -595,14 +643,20 @@ MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos) { * @param client_user: MQTT client user * @param client_pass: MQTT client password * @param keepAliveTime: MQTT keep alive timer, in second -* @param cleanSession: MQTT ... +* @param cleanSession: On connection, a client sets the "clean session" flag, which is sometimes also known as the "clean start" flag. +* If clean session is set to false, then the connection is treated as durable. This means that when the client +* disconnects, any subscriptions it has will remain and any subsequent QoS 1 or 2 messages will be stored until +* it connects again in the future. If clean session is true, then all subscriptions will be removed for the client +* when it disconnects. * @retval None */ void ICACHE_FLASH_ATTR MQTT_Init(MQTT_Client* mqttClient, char* host, uint32 port, uint8_t security, uint8_t sendTimeout, char* client_id, char* client_user, char* client_pass, uint8_t keepAliveTime, uint8_t cleanSession) { +#ifdef MQTT_DBG os_printf("MQTT_Init\n"); +#endif os_memset(mqttClient, 0, sizeof(MQTT_Client)); @@ -679,7 +733,9 @@ MQTT_Connect(MQTT_Client* mqttClient) { os_timer_arm(&mqttClient->mqttTimer, 1000, 1); // initiate the TCP connection or DNS lookup +#ifdef MQTT_DBG os_printf("MQTT: Connect to %s:%d %p\n", mqttClient->host, mqttClient->port, mqttClient->pCon); +#endif if (UTILS_StrToIP((const char *)mqttClient->host, (void*)&mqttClient->pCon->proto.tcp->remote_ip)) { uint8_t err; @@ -688,7 +744,9 @@ MQTT_Connect(MQTT_Client* mqttClient) { else err = espconn_connect(mqttClient->pCon); if (err != 0) { +#ifdef MQTT_DBG os_printf("MQTT ERROR: Failed to connect\n"); +#endif os_free(mqttClient->pCon->proto.tcp); os_free(mqttClient->pCon); mqttClient->pCon = NULL; @@ -707,7 +765,9 @@ MQTT_Connect(MQTT_Client* mqttClient) { static void ICACHE_FLASH_ATTR mqtt_doAbort(MQTT_Client* client) { +#ifdef MQTT_DBG os_printf("MQTT: Disconnecting from %s:%d (%p)\n", client->host, client->port, client->pCon); +#endif client->pCon->reverse = NULL; // ensure we jettison this pCon... if (client->security) espconn_secure_disconnect(client->pCon); diff --git a/mqtt/mqtt_cmd.c b/mqtt/mqtt_cmd.c index d2a01e2..ed2eb68 100644 --- a/mqtt/mqtt_cmd.c +++ b/mqtt/mqtt_cmd.c @@ -8,11 +8,13 @@ void ICACHE_FLASH_ATTR cmdMqttConnectedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; +#ifdef MQTTCMD_DBG os_printf("MQTT: Connected connectedCb=%p, disconnectedCb=%p, publishedCb=%p, dataCb=%p\n", (void*)cb->connectedCb, (void*)cb->disconnectedCb, (void*)cb->publishedCb, (void*)cb->dataCb); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->connectedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -21,7 +23,9 @@ void ICACHE_FLASH_ATTR cmdMqttTcpDisconnectedCb(uint32_t *args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb *cb = (MqttCmdCb*)client->user_data; +#ifdef MQTTCMD_DBG os_printf("MQTT: TCP Disconnected\n"); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->tcpDisconnectedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -30,7 +34,9 @@ void ICACHE_FLASH_ATTR cmdMqttDisconnectedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; +#ifdef MQTTCMD_DBG os_printf("MQTT: Disconnected\n"); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->disconnectedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -39,7 +45,9 @@ void ICACHE_FLASH_ATTR cmdMqttPublishedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; +#ifdef MQTTCMD_DBG os_printf("MQTT: Published\n"); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->publishedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -103,8 +111,9 @@ MQTTCMD_Setup(CmdPacket *cmd) { // get clean session CMD_PopArg(&req, (uint8_t*)&clean_session, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Setup clientid=%s, user=%s, pw=%s, keepalive=%ld, clean_session=%ld\n", client_id, user_data, pass_data, keepalive, clean_session); +#endif // init client // TODO: why malloc these all here, pass to MQTT_InitClient to be malloc'd again? @@ -155,7 +164,9 @@ MQTTCMD_Lwt(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Lwt client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; @@ -182,12 +193,13 @@ MQTTCMD_Lwt(CmdPacket *cmd) { // get retain CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_retain, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Lwt topic=%s, message=%s, qos=%d, retain=%d\n", client->connect_info.will_topic, client->connect_info.will_message, client->connect_info.will_qos, client->connect_info.will_retain); +#endif return 1; } @@ -203,7 +215,9 @@ MQTTCMD_Connect(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Connect client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; @@ -221,11 +235,12 @@ MQTTCMD_Connect(CmdPacket *cmd) { // get security CMD_PopArg(&req, (uint8_t*)&client->security, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Connect host=%s, port=%d, security=%d\n", client->host, client->port, client->security); +#endif MQTT_Connect(client); return 1; @@ -243,7 +258,9 @@ MQTTCMD_Disconnect(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Disconnect client ptr=%p\n", (void*)client_ptr); +#endif // disconnect MQTT_Disconnect(client); @@ -262,7 +279,9 @@ MQTTCMD_Publish(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Publish client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; uint8_t *topic, *data; @@ -293,12 +312,13 @@ MQTTCMD_Publish(CmdPacket *cmd) { // get retain CMD_PopArg(&req, (uint8_t*)&retain, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Publish topic=%s, data_len=%d, qos=%ld, retain=%ld\n", topic, os_strlen((char*)data), qos, retain); +#endif MQTT_Publish(client, (char*)topic, (char*)data, (uint8_t)qos, (uint8_t)retain); os_free(topic); @@ -318,7 +338,9 @@ MQTTCMD_Subscribe(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Subscribe client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; uint8_t* topic; @@ -333,8 +355,9 @@ MQTTCMD_Subscribe(CmdPacket *cmd) { // get qos CMD_PopArg(&req, (uint8_t*)&qos, 4); - +#ifdef MQTTCMD_DBG os_printf("MQTT: MQTTCMD_Subscribe topic=%s, qos=%ld\n", topic, qos); +#endif MQTT_Subscribe(client, (char*)topic, (uint8_t)qos); os_free(topic); return 1; diff --git a/mqtt/pktbuf.c b/mqtt/pktbuf.c index 2984fb4..a3ac7af 100644 --- a/mqtt/pktbuf.c +++ b/mqtt/pktbuf.c @@ -3,7 +3,8 @@ #include #include "pktbuf.h" -void ICACHE_FLASH_ATTR +#ifdef PKTBUF_DBG +static void ICACHE_FLASH_ATTR PktBuf_Print(PktBuf *buf) { os_printf("PktBuf:"); for (int i=-16; i<0; i++) @@ -15,6 +16,7 @@ PktBuf_Print(PktBuf *buf) { os_printf("PktBuf: next=%p len=0x%04x\n", ((void**)buf)[-4], ((uint16_t*)buf)[-6]); } +#endif PktBuf * ICACHE_FLASH_ATTR diff --git a/mqtt/pktbuf.h b/mqtt/pktbuf.h index 0c8ff2c..bccd60a 100644 --- a/mqtt/pktbuf.h +++ b/mqtt/pktbuf.h @@ -24,6 +24,4 @@ PktBuf *PktBuf_Shift(PktBuf *headBuf); // Shift first buffer off queue, free it, return new head PktBuf *PktBuf_ShiftFree(PktBuf *headBuf); -void PktBuf_Print(PktBuf *buf); - #endif diff --git a/rest/rest.c b/rest/rest.c index 40b62de..fbbd358 100644 --- a/rest/rest.c +++ b/rest/rest.c @@ -73,16 +73,20 @@ tcpclient_recv(void *arg, char *pdata, unsigned short len) { // collect body and send it uint16_t crc; int body_len = len-pi; +#ifdef REST_DBG os_printf("REST: status=%ld, body=%d\n", code, body_len); +#endif if (pi == len) { crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 0); } else { crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 1); crc = CMD_ResponseBody(crc, (uint8_t*)(pdata+pi), body_len); CMD_ResponseEnd(crc); +#ifdef REST_DBG os_printf("REST: body="); for (int j=pi; jsecurity) @@ -96,7 +100,9 @@ static void ICACHE_FLASH_ATTR tcpclient_sent_cb(void *arg) { struct espconn *pCon = (struct espconn *)arg; RestClient* client = (RestClient *)pCon->reverse; +#ifdef REST_DBG os_printf("REST: Sent\n"); +#endif if (client->data_sent != client->data_len) { // we only sent part of the buffer, send the rest espconn_sent(client->pCon, (uint8_t*)(client->data+client->data_sent), @@ -113,14 +119,17 @@ static void ICACHE_FLASH_ATTR tcpclient_connect_cb(void *arg) { struct espconn *pCon = (struct espconn *)arg; RestClient* client = (RestClient *)pCon->reverse; +#ifdef REST_DBG os_printf("REST #%d: connected\n", client-restClient); - +#endif espconn_regist_disconcb(client->pCon, tcpclient_discon_cb); espconn_regist_recvcb(client->pCon, tcpclient_recv); espconn_regist_sentcb(client->pCon, tcpclient_sent_cb); client->data_sent = client->data_len <= 1400 ? client->data_len : 1400; +#ifdef REST_DBG os_printf("REST #%d: sending %d\n", client-restClient, client->data_sent); +#endif //if(client->security){ // espconn_secure_sent(client->pCon, client->data, client->data_sent); //} @@ -133,7 +142,9 @@ static void ICACHE_FLASH_ATTR tcpclient_recon_cb(void *arg, sint8 errType) { struct espconn *pCon = (struct espconn *)arg; RestClient* client = (RestClient *)pCon->reverse; +#ifdef REST_DBG os_printf("REST #%d: conn reset\n", client-restClient); +#endif } static void ICACHE_FLASH_ATTR @@ -142,16 +153,18 @@ rest_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) { RestClient* client = (RestClient *)pConn->reverse; if(ipaddr == NULL) { +#ifdef REST_DBG os_printf("REST DNS: Got no ip, try to reconnect\n"); +#endif return; } - +#ifdef REST_DBG os_printf("REST DNS: found ip %d.%d.%d.%d\n", *((uint8 *) &ipaddr->addr), *((uint8 *) &ipaddr->addr + 1), *((uint8 *) &ipaddr->addr + 2), *((uint8 *) &ipaddr->addr + 3)); - +#endif if(client->ip.addr == 0 && ipaddr->addr != 0) { os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); #ifdef CLIENT_SSL_ENABLE @@ -159,8 +172,10 @@ rest_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) { espconn_secure_connect(client->pCon); } else #endif - espconn_connect(client->pCon); + espconn_connect(client->pCon); +#ifdef REST_DBG os_printf("REST: connecting...\n"); +#endif } } @@ -213,8 +228,9 @@ REST_Setup(CmdPacket *cmd) { os_free(client->pCon); } os_memset(client, 0, sizeof(RestClient)); - +#ifdef CMDREST_DBG os_printf("REST: setup #%d host=%s port=%ld security=%ld\n", clientNum, rest_host, port, security); +#endif client->resp_cb = cmd->callback; @@ -273,7 +289,9 @@ REST_SetHeader(CmdPacket *cmd) { client->header[len] = '\r'; client->header[len+1] = '\n'; client->header[len+2] = 0; +#ifdef CMDREST_DBG os_printf("REST: Set header: %s\r\n", client->header); +#endif break; case HEADER_CONTENT_TYPE: if(client->content_type) os_free(client->content_type); @@ -282,7 +300,9 @@ REST_SetHeader(CmdPacket *cmd) { client->content_type[len] = '\r'; client->content_type[len+1] = '\n'; client->content_type[len+2] = 0; +#ifdef CMDREST_DBG os_printf("REST: Set content_type: %s\r\n", client->content_type); +#endif break; case HEADER_USER_AGENT: if(client->user_agent) os_free(client->user_agent); @@ -291,7 +311,9 @@ REST_SetHeader(CmdPacket *cmd) { client->user_agent[len] = '\r'; client->user_agent[len+1] = '\n'; client->user_agent[len+2] = 0; +#ifdef CMDREST_DBG os_printf("REST: Set user_agent: %s\r\n", client->user_agent); +#endif break; } return 1; @@ -301,32 +323,36 @@ uint32_t ICACHE_FLASH_ATTR REST_Request(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); +#ifdef CMDREST_DBG os_printf("REST: request"); - +#endif // Get client uint32_t clientNum; if (CMD_PopArg(&req, (uint8_t*)&clientNum, 4)) goto fail; if ((clientNum & 0xffff0000) != REST_CB) goto fail; clientNum &= 0xffff; RestClient *client = restClient + clientNum % MAX_REST; +#ifdef CMDREST_DBG os_printf(" #%ld", clientNum); - +#endif // Get HTTP method uint16_t len = CMD_ArgLen(&req); if (len > 15) goto fail; char method[16]; CMD_PopArg(&req, method, len); method[len] = 0; +#ifdef CMDREST_DBG os_printf(" method=%s", method); - +#endif // Get HTTP path len = CMD_ArgLen(&req); if (len > 1023) goto fail; char path[1024]; CMD_PopArg(&req, path, len); path[len] = 0; +#ifdef CMDREST_DBG os_printf(" path=%s", path); - +#endif // Get HTTP body uint32_t realLen = 0; if (CMD_GetArgc(&req) == 3) { @@ -338,7 +364,9 @@ REST_Request(CmdPacket *cmd) { len = CMD_ArgLen(&req); if (len > 2048 || realLen > len) goto fail; } +#ifdef CMDREST_DBG os_printf(" bodyLen=%ld", realLen); +#endif // we need to allocate memory for the header plus the body. First we count the length of the // header (including some extra counted "%s" and then we add the body length. We allocate the @@ -353,30 +381,40 @@ REST_Request(CmdPacket *cmd) { "User-Agent: %s\r\n\r\n"; uint16_t headerLen = strlen(headerFmt) + strlen(method) + strlen(path) + strlen(client->host) + strlen(client->header) + strlen(client->content_type) + strlen(client->user_agent); +#ifdef CMDREST_DBG os_printf(" hdrLen=%d", headerLen); +#endif if (client->data) os_free(client->data); client->data = (char*)os_zalloc(headerLen + realLen); if (client->data == NULL) goto fail; +#ifdef CMDREST_DBG os_printf(" totLen=%ld data=%p", headerLen + realLen, client->data); +#endif client->data_len = os_sprintf((char*)client->data, headerFmt, method, path, client->host, client->header, realLen, client->content_type, client->user_agent); +#ifdef CMDREST_DBG os_printf(" hdrLen=%d", client->data_len); +#endif if (realLen > 0) { CMD_PopArg(&req, client->data + client->data_len, realLen); client->data_len += realLen; } +#ifdef CMDREST_DBG os_printf("\n"); //os_printf("REST request: %s", (char*)client->data); os_printf("REST: pCon state=%d\n", client->pCon->state); +#endif client->pCon->state = ESPCONN_NONE; espconn_regist_connectcb(client->pCon, tcpclient_connect_cb); espconn_regist_reconcb(client->pCon, tcpclient_recon_cb); if(UTILS_StrToIP((char *)client->host, &client->pCon->proto.tcp->remote_ip)) { +#ifdef CMDREST_DBG os_printf("REST: Connect to ip %s:%ld\n",client->host, client->port); +#endif //if(client->security){ // espconn_secure_connect(client->pCon); //} @@ -384,13 +422,17 @@ REST_Request(CmdPacket *cmd) { espconn_connect(client->pCon); //} } else { +#ifdef CMDREST_DBG os_printf("REST: Connect to host %s:%ld\n", client->host, client->port); +#endif espconn_gethostbyname(client->pCon, (char *)client->host, &client->ip, rest_dns_found); } return 1; fail: +#ifdef CMDREST_DBG os_printf("\n"); +#endif return 0; } diff --git a/serial/serbridge.c b/serial/serbridge.c index b91dbbc..ea5c848 100644 --- a/serial/serbridge.c +++ b/serial/serbridge.c @@ -100,10 +100,15 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state) switch (c) { case DTR_ON: if (mcu_reset_pin >= 0) { +#ifdef SERBR_DBG os_printf("MCU reset gpio%d\n", mcu_reset_pin); +#endif GPIO_OUTPUT_SET(mcu_reset_pin, 0); os_delay_us(100L); - } else os_printf("MCU reset: no pin\n"); + } +#ifdef SERBR_DBG + else os_printf("MCU reset: no pin\n"); +#endif break; case DTR_OFF: if (mcu_reset_pin >= 0) { @@ -113,10 +118,15 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state) break; case RTS_ON: if (mcu_isp_pin >= 0) { +#ifdef SERBR_DBG os_printf("MCU ISP gpio%d\n", mcu_isp_pin); +#endif GPIO_OUTPUT_SET(mcu_isp_pin, 0); os_delay_us(100L); - } else os_printf("MCU isp: no pin\n"); + } +#ifdef SERBR_DBG + else os_printf("MCU isp: no pin\n"); +#endif slip_disabled++; break; case RTS_OFF: @@ -137,11 +147,16 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state) // Generate a reset pulse for the attached microcontroller void ICACHE_FLASH_ATTR serbridgeReset() { if (mcu_reset_pin >= 0) { +#ifdef SERBR_DBG os_printf("MCU reset gpio%d\n", mcu_reset_pin); +#endif GPIO_OUTPUT_SET(mcu_reset_pin, 0); os_delay_us(100L); GPIO_OUTPUT_SET(mcu_reset_pin, 1); - } else os_printf("MCU reset: no pin\n"); + } +#ifdef SERBR_DBG + else os_printf("MCU reset: no pin\n"); +#endif } // Receive callback @@ -162,7 +177,9 @@ static void ICACHE_FLASH_ATTR serbridgeRecvCb(void *arg, char *data, unsigned sh if ((len == 2 && strncmp(data, "0 ", 2) == 0) || (len == 2 && strncmp(data, "?\n", 2) == 0) || (len == 3 && strncmp(data, "?\r\n", 3) == 0)) { +#ifdef SERBR_DBG os_printf("MCU Reset=gpio%d ISP=gpio%d\n", mcu_reset_pin, mcu_isp_pin); +#endif os_delay_us(2*1000L); // time for os_printf to happen // send reset to arduino/ARM if (mcu_reset_pin >= 0) GPIO_OUTPUT_SET(mcu_reset_pin, 0); @@ -177,14 +194,18 @@ static void ICACHE_FLASH_ATTR serbridgeRecvCb(void *arg, char *data, unsigned sh slip_disabled++; // disable SLIP so it doesn't interfere with flashing // If the connection starts with a telnet negotiation we will do telnet - } else if (len >= 3 && strncmp(data, (char[]){IAC, WILL, ComPortOpt}, 3) == 0) { + } + else if (len >= 3 && strncmp(data, (char[]){IAC, WILL, ComPortOpt}, 3) == 0) { conn->conn_mode = cmTelnet; conn->telnet_state = TN_normal; // note that the three negotiation chars will be gobbled-up by telnetUnwrap +#ifdef SERBR_DBG os_printf("telnet mode\n"); +#endif // looks like a plain-vanilla connection! - } else { + } + else { conn->conn_mode = cmTransparent; } @@ -218,9 +239,11 @@ sendtxbuffer(serbridgeConnData *conn) { conn->readytosend = false; result = espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen); conn->txbufferlen = 0; +#ifdef SERBR_DBG if (result != ESPCONN_OK) { os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn); } +#endif } return result; } @@ -233,7 +256,9 @@ sendtxbuffer(serbridgeConnData *conn) { static sint8 ICACHE_FLASH_ATTR espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) { if (conn->txbufferlen + len > MAX_TXBUFFER) { +#ifdef SERBR_DBG os_printf("espbuffsend: txbuffer full on conn %p\n", conn); +#endif return -128; } os_memcpy(conn->txbuffer + conn->txbufferlen, data, len); @@ -323,10 +348,14 @@ static void ICACHE_FLASH_ATTR serbridgeConnectCb(void *arg) { // Find empty conndata in pool int i; for (i=0; i= ' ' && slip_buf[i] <= '~') os_printf("%c", slip_buf[i]); @@ -54,6 +56,7 @@ slip_process() { os_printf("\\%02X", slip_buf[i]); } os_printf("\n"); +#endif } } } @@ -83,7 +86,9 @@ slip_parse_char(char c) { if (slip_len > 0) console_process(slip_buf, slip_len); slip_reset(); slip_inpkt = true; +#ifdef SLIP_DBG os_printf("SLIP: start\n"); +#endif return; } } else if (slip_escaped) { diff --git a/cmd/tcpclient.c b/tcpclient/tcpclient.c similarity index 100% rename from cmd/tcpclient.c rename to tcpclient/tcpclient.c diff --git a/cmd/tcpclient.h b/tcpclient/tcpclient.h similarity index 100% rename from cmd/tcpclient.h rename to tcpclient/tcpclient.h diff --git a/user/latch_json.c b/user/latch_json.c new file mode 100644 index 0000000..0994894 --- /dev/null +++ b/user/latch_json.c @@ -0,0 +1,64 @@ +#include "latch_json.h" +#include "user_funcs.h" +#include +#include +#include + +static LatchState latch; + +static void ICACHE_FLASH_ATTR +updateLatch() { + os_printf("ESP: Latch Callback\n"); + cmdCallback* latchCb = CMD_GetCbByName("Latch"); + if (latchCb->callback != -1) { + uint16_t crc = CMD_ResponseStart(CMD_CB_EVENTS, (uint32_t)&latchCb->callback, 0, 1); + crc = CMD_ResponseBody(crc, (uint8_t*)&latch, sizeof(LatchState)); + CMD_ResponseEnd(crc); + } +} + +static int ICACHE_FLASH_ATTR +latchGet(struct jsontree_context *js_ctx) { + return 0; +} + +static int ICACHE_FLASH_ATTR +latchSet(struct jsontree_context *js_ctx, struct jsonparse_state *parser) { + int type; + int ix = -1; + while ((type = jsonparse_next(parser)) != 0) { + if (type == JSON_TYPE_ARRAY) { + ix = -1; + } + else if (type == JSON_TYPE_OBJECT) { + ix++; + } + else if (type == JSON_TYPE_PAIR_NAME) { + if (jsonparse_strcmp_value(parser, "states") == 0) { + char latchStates[9]; + jsonparse_next(parser); jsonparse_next(parser); + jsonparse_copy_value(parser, latchStates, sizeof(latchStates)); + os_printf("latch states %s\n", latchStates); + uint8_t states = binToByte(latchStates); + latch.stateBits = states; + } + else if (jsonparse_strcmp_value(parser, "fallbackstates") == 0) { + char fallbackStates[9]; + jsonparse_next(parser); jsonparse_next(parser); + jsonparse_copy_value(parser, fallbackStates, sizeof(fallbackStates)); + os_printf("latch states %s\n", fallbackStates); + uint8_t fbstates = binToByte(fallbackStates); + latch.fallbackStateBits = fbstates; + } + } + } + return 0; +} + +static struct jsontree_callback latchCallback = JSONTREE_CALLBACK(latchGet, latchSet); +static char* latchQueueName; + +JSONTREE_OBJECT(latchJsonObj, + JSONTREE_PAIR("states", &latchCallback), + JSONTREE_PAIR("fallbackstates", &latchCallback)); + diff --git a/user/latch_json.h b/user/latch_json.h new file mode 100644 index 0000000..0bc4135 --- /dev/null +++ b/user/latch_json.h @@ -0,0 +1,12 @@ +#ifndef _LATCH_JSON_H_ +#define _LATCH_JSON_H_ +#include + +typedef struct { + uint8_t fallbackStateBits; + uint8_t stateBits; + uint8_t init; + uint8_t fallbackSecondsForBits[8]; +} LatchState; + +#endif // _LATCH_JSON_H_ \ No newline at end of file diff --git a/user/user_funcs.c b/user/user_funcs.c index bdb082b..49dedbd 100644 --- a/user/user_funcs.c +++ b/user/user_funcs.c @@ -1,6 +1,7 @@ #include "user_funcs.h" -bool ICACHE_FLASH_ATTR pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, uint8_t offMinute) { +bool ICACHE_FLASH_ATTR +pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, uint8_t offMinute) { uint16_t NumMinsToday = totalMinutes(hour(), minute()); bool state = false; @@ -19,7 +20,8 @@ bool ICACHE_FLASH_ATTR pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, return state; } -const char* ICACHE_FLASH_ATTR byteToBin(uint8_t num) { +const char* ICACHE_FLASH_ATTR +byteToBin(uint8_t num) { static char b[9]; b[0] = '\0'; @@ -30,7 +32,8 @@ const char* ICACHE_FLASH_ATTR byteToBin(uint8_t num) { return b; } -const uint8_t ICACHE_FLASH_ATTR binToByte(char* bin_str) { +const uint8_t ICACHE_FLASH_ATTR +binToByte(char* bin_str) { char * tmp; long x = strtol(bin_str, &tmp, 2); return (x <= 255) ? (uint8_t)x : -1; diff --git a/user/user_funcs.h b/user/user_funcs.h index 156e432..b1da228 100644 --- a/user/user_funcs.h +++ b/user/user_funcs.h @@ -7,4 +7,5 @@ bool pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, u const char* byteToBin(uint8_t num); const uint8_t binToByte(char* bin_str); + #endif // _USER_FUNCS_H_ \ No newline at end of file diff --git a/user/user_main.c b/user/user_main.c index cd0dbf0..a796e14 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -1,38 +1,14 @@ #include #include "cgiwifi.h" -#include "mqtt.h" +#include +#include +#include "latch_json.h" +#include "user_funcs.h" -MQTT_Client mqttClient; - -static ETSTimer mqttTimer; - -static int once = 0; -static void ICACHE_FLASH_ATTR mqttTimerCb(void *arg) { - if (once++ > 0) return; - MQTT_Init(&mqttClient, "h.voneicken.com", 1883, 0, 2, "test1", "", "", 10, 1); - MQTT_Connect(&mqttClient); - MQTT_Subscribe(&mqttClient, "system/time", 0); -} - -void ICACHE_FLASH_ATTR -wifiStateChangeCb(uint8_t status) -{ - if (status == wifiGotIP) { - os_timer_disarm(&mqttTimer); - os_timer_setfn(&mqttTimer, mqttTimerCb, NULL); - os_timer_arm(&mqttTimer, 15000, 0); - } -} - - -// initialize the custom stuff that goes beyond esp-link -void app_init() { - wifiAddStateChangeCb(wifiStateChangeCb); -} -#if 0 MQTT_Client mqttClient; +//static ETSTimer mqttTimer; void ICACHE_FLASH_ATTR mqttConnectedCb(uint32_t *args) { @@ -60,11 +36,10 @@ mqttPublishedCb(uint32_t *args) { void ICACHE_FLASH_ATTR mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) { +// MQTT_Client* client = (MQTT_Client*)args; char *topicBuf = (char*)os_zalloc(topic_len + 1); char *dataBuf = (char*)os_zalloc(data_len + 1); -// MQTT_Client* client = (MQTT_Client*)args; - os_memcpy(topicBuf, topic, topic_len); topicBuf[topic_len] = 0; @@ -76,12 +51,33 @@ mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *da os_free(dataBuf); } - MQTT_InitConnection(&mqttClient, MQTT_HOST, MQTT_PORT, MQTT_SECURITY); - MQTT_InitClient(&mqttClient, MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS, MQTT_KEEPALIVE, MQTT_CLSESSION); - MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0); - MQTT_OnConnected(&mqttClient, mqttConnectedCb); - MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb); - MQTT_OnDisconnected(&mqttClient, mqttTcpDisconnectedCb); - MQTT_OnPublished(&mqttClient, mqttPublishedCb); - MQTT_OnData(&mqttClient, mqttDataCb); -#endif +void ICACHE_FLASH_ATTR +wifiStateChangeCb(uint8_t status) { + if (flashConfig.mqtt_enable) { + if (status == wifiGotIP && mqttClient.connState != TCP_CONNECTING) { + MQTT_Connect(&mqttClient); + } + else if (status == wifiIsDisconnected && mqttClient.connState == TCP_CONNECTING) { + MQTT_Disconnect(&mqttClient); + } + } +} + +// initialize the custom stuff that goes beyond esp-link +void app_init() { + if (flashConfig.mqtt_enable) { + MQTT_Init(&mqttClient, flashConfig.mqtt_host, flashConfig.mqtt_port, 0, flashConfig.mqtt_timeout, + flashConfig.mqtt_clientid, flashConfig.mqtt_username, flashConfig.mqtt_password, flashConfig.mqtt_keepalive, flashConfig.mqtt_clean_session + ); + + MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0); + MQTT_OnConnected(&mqttClient, mqttConnectedCb); + MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb); + MQTT_OnDisconnected(&mqttClient, mqttTcpDisconnectedCb); + MQTT_OnPublished(&mqttClient, mqttPublishedCb); + MQTT_OnData(&mqttClient, mqttDataCb); + } + + wifiAddStateChangeCb(wifiStateChangeCb); +} +