lots of ifdef

pull/47/head
Benjamin Runnels 9 years ago
parent 965b70a408
commit b7dd0b180f
  1. 1
      .gitignore
  2. 85
      Makefile
  3. 2
      cmd/cmd.c
  4. 4
      cmd/cmd.h
  5. 22
      cmd/handlers.c
  6. 11
      esp-link.vcxproj
  7. 10
      esp-link/cgi.c
  8. 1
      esp-link/cgi.h
  9. 12
      esp-link/cgiflash.c
  10. 50
      esp-link/cgimqtt.c
  11. 3
      esp-link/cgipins.c
  12. 48
      esp-link/cgiwifi.c
  13. 49
      esp-link/config.c
  14. 9
      esp-link/config.h
  15. 4
      esp-link/log.c
  16. 5
      esp-link/main.c
  17. 15
      esp-link/status.c
  18. 8
      espfs/espfs.c
  19. 72
      html/console.js
  20. BIN
      html/favicon.ico
  21. 10
      html/head-
  22. 88
      html/home.html
  23. 49
      html/log.html
  24. 15
      html/mqtt.html
  25. 1388
      html/pure.css
  26. 5
      html/style.css
  27. BIN
      html/wifi/icons.png
  28. 85
      html/wifi/wifi.html
  29. 200
      html/wifi/wifi.js
  30. 382
      httpd/httpd.c
  31. 44
      include/user_config.h
  32. 78
      mqtt/mqtt.c
  33. 33
      mqtt/mqtt_cmd.c
  34. 4
      mqtt/pktbuf.c
  35. 2
      mqtt/pktbuf.h
  36. 58
      rest/rest.c
  37. 41
      serial/serbridge.c
  38. 2
      serial/serled.c
  39. 5
      serial/slip.c
  40. 0
      tcpclient/tcpclient.c
  41. 0
      tcpclient/tcpclient.h
  42. 64
      user/latch_json.c
  43. 12
      user/latch_json.h
  44. 9
      user/user_funcs.c
  45. 1
      user/user_funcs.h
  46. 64
      user/user_main.c

1
.gitignore vendored

@ -15,3 +15,4 @@ esp-link.opensdf
esp-link.sdf esp-link.sdf
espfs/mkespfsimage/mman-win32/libmman.a espfs/mkespfsimage/mman-win32/libmman.a
.localhistory/ .localhistory/
tools/

@ -32,7 +32,7 @@ ESPBAUD ?= 230400
# --------------- chipset configuration --------------- # --------------- chipset configuration ---------------
# Pick your flash size: "512KB", "1MB", or "4MB" # Pick your flash size: "512KB", "1MB", or "4MB"
FLASH_SIZE ?= 512KB FLASH_SIZE ?= 4MB
ifeq ("$(FLASH_SIZE)","512KB") ifeq ("$(FLASH_SIZE)","512KB")
# Winbond 25Q40 512KB flash, typ for esp-01 thru esp-11 # 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 endif
# hostname or IP address for wifi flashing # 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 # The pin assignments below are used when the settings in flash are invalid, they
# can be changed via the web interface # can be changed via the web interface
@ -122,15 +122,20 @@ CHANGE_TO_STA ?= yes
#Static gzipping is disabled by default. #Static gzipping is disabled by default.
GZIP_COMPRESSION ?= yes GZIP_COMPRESSION ?= yes
# If COMPRESS_W_YUI is set to "yes" then the static css and js files will be compressed with # If COMPRESS_W_HTMLCOMPRESSOR 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". # 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/ # http://yui.github.io/yuicompressor/
#Disabled by default. # enabled by default.
COMPRESS_W_YUI ?= yes COMPRESS_W_HTMLCOMPRESSOR ?= yes
HTML-COMPRESSOR ?= htmlcompressor-1.5.3.jar
YUI-COMPRESSOR ?= yuicompressor-2.4.8.jar YUI-COMPRESSOR ?= yuicompressor-2.4.8.jar
HTML_PATH = $(abspath ./html)/
WIFI_PATH = $(HTML_PATH)wifi/
# Optional Modules # Optional Modules
MODULES ?= MODULES ?= mqtt rest
# -------------- End of config options ------------- # -------------- End of config options -------------
@ -144,7 +149,6 @@ TARGET = httpd
# espressif tool to concatenate sections for OTA upload using bootloader v1.2+ # espressif tool to concatenate sections for OTA upload using bootloader v1.2+
APPGEN_TOOL ?= gen_appbin.py APPGEN_TOOL ?= gen_appbin.py
CFLAGS= CFLAGS=
# set defines for optional modules # set defines for optional modules
@ -156,19 +160,23 @@ ifneq (,$(findstring rest,$(MODULES)))
CFLAGS += -DREST CFLAGS += -DREST
endif endif
ifneq (,$(findstring tcpclient,$(MODULES)))
CFLAGS += -DTCPCLIENT
endif
# which modules (subdirectories) of the project to include in compiling # which modules (subdirectories) of the project to include in compiling
LIBRARIES_DIR = libraries LIBRARIES_DIR = libraries
MODULES = espfs httpd user serial cmd mqtt esp-link MODULES += espfs httpd user serial cmd esp-link
MODULES += $(foreach sdir,$(LIBRARIES_DIR),$(wildcard $(sdir)/*)) 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 # 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 # 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 \ -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) \ -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) \ -DMCU_RESET_PIN=$(MCU_RESET_PIN) -DMCU_ISP_PIN=$(MCU_ISP_PIN) \
-DLED_CONN_PIN=$(LED_CONN_PIN) -DLED_SERIAL_PIN=$(LED_SERIAL_PIN) \ -DLED_CONN_PIN=$(LED_CONN_PIN) -DLED_SERIAL_PIN=$(LED_SERIAL_PIN) \
@ -275,7 +283,7 @@ $(FW_BASE)/user1.bin: $(USER1_OUT) $(FW_BASE)
$(Q) rm -f eagle.app.v6.*.bin $(Q) rm -f eagle.app.v6.*.bin
$(Q) mv eagle.app.flash.bin $@ $(Q) mv eagle.app.flash.bin $@
@echo "** user1.bin uses $$(stat -c '%s' $@) bytes of" $(ESP_FLASH_MAX) "available" @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) $(FW_BASE)/user2.bin: $(USER2_OUT) $(FW_BASE)
$(Q) $(OBJCP) --only-section .text -O binary $(USER2_OUT) eagle.app.v6.text.bin $(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) 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) rm -f eagle.app.v6.*.bin
$(Q) mv eagle.app.flash.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) $(APP_AR): $(OBJ)
$(vecho) "AR $@" $(vecho) "AR $@"
@ -307,34 +315,51 @@ flash: all
0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin \ 0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin \
$(ET_BLANK) $(SDK_BASE)/bin/blank.bin $(ET_BLANK) $(SDK_BASE)/bin/blank.bin
yui/$(YUI-COMPRESSOR): tools/$(HTML-COMPRESSOR):
$(Q) mkdir -p yui $(Q) mkdir -p tools
ifeq ($(OS),Windows_NT) 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 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 endif
ifeq ("$(COMPRESS_W_YUI)","yes") ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes")
$(BUILD_BASE)/espfs_img.o: yui/$(YUI-COMPRESSOR) $(BUILD_BASE)/espfs_img.o: tools/$(HTML-COMPRESSOR)
endif endif
$(BUILD_BASE)/espfs_img.o: html/ html/wifi/ espfs/mkespfsimage/mkespfsimage $(BUILD_BASE)/espfs_img.o: html/ html/wifi/ espfs/mkespfsimage/mkespfsimage
$(Q) rm -rf html_compressed; $(Q) rm -rf html_compressed; mkdir html_compressed; mkdir html_compressed/wifi;
$(Q) cp -r html html_compressed; $(Q) cp -r html/*.ico html_compressed;
$(Q) for file in `find html_compressed -type f -name "*.htm*"`; do \ $(Q) cp -r html/*.css html_compressed;
cat html_compressed/head- $$file >$${file}-; \ $(Q) cp -r html/*.js html_compressed;
mv $$file- $$file; \ $(Q) cp -r html/wifi/*.png html_compressed/wifi;
done $(Q) cp -r html/wifi/*.js html_compressed/wifi;
ifeq ("$(COMPRESS_W_YUI)","yes") 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) echo "Compression assets with yui-compressor. This may take a while..."
$(Q) for file in `find html_compressed -type f -name "*.js"`; do \ $(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 done
$(Q) for file in `find html_compressed -type f -name "*.css"`; do \ $(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 done
endif 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) cd html_compressed; find . \! -name \*- | ../espfs/mkespfsimage/mkespfsimage > ../build/espfs.img; cd ..;
$(Q) ls -sl build/espfs.img $(Q) ls -sl build/espfs.img
$(Q) cd build; $(OBJCP) -I binary -O elf32-xtensa-le -B xtensa --rename-section .data=.espfs \ $(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) make -C espfs/mkespfsimage/ clean
$(Q) rm -rf $(FW_BASE) $(Q) rm -rf $(FW_BASE)
$(Q) rm -f webpages.espfs $(Q) rm -f webpages.espfs
ifeq ("$(COMPRESS_W_YUI)","yes") ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes")
$(Q) rm -rf html_compressed $(Q) rm -rf html_compressed
endif endif

@ -2,10 +2,8 @@
// //
// Adapted from: github.com/tuanpmt/esp_bridge, Created on: Jan 9, 2015, Author: Minh // Adapted from: github.com/tuanpmt/esp_bridge, Created on: Jan 9, 2015, Author: Minh
#include "esp8266.h"
#include "cmd.h" #include "cmd.h"
#include "crc16.h" #include "crc16.h"
#include "serbridge.h"
#include "uart.h" #include "uart.h"
extern const CmdList commands[]; extern const CmdList commands[];

@ -55,8 +55,8 @@ typedef enum {
CMD_REST_REQUEST, CMD_REST_REQUEST,
CMD_REST_SETHEADER, CMD_REST_SETHEADER,
CMD_REST_EVENTS, CMD_REST_EVENTS,
CMD_ADD_CALLBACK, // 15 CMD_CB_ADD, // 15
CMD_SENSOR_EVENTS CMD_CB_EVENTS
} CmdName; } CmdName;
typedef uint32_t (*cmdfunc_t)(CmdPacket *cmd); typedef uint32_t (*cmdfunc_t)(CmdPacket *cmd);

@ -41,7 +41,7 @@ const CmdList commands[] = {
{CMD_REST_REQUEST, REST_Request}, {CMD_REST_REQUEST, REST_Request},
{CMD_REST_SETHEADER, REST_SetHeader}, {CMD_REST_SETHEADER, REST_SetHeader},
#endif #endif
{ CMD_CB_ADD, CMD_AddCallback }, {CMD_CB_ADD, CMD_AddCallback},
{CMD_NULL, NULL} {CMD_NULL, NULL}
}; };
@ -52,14 +52,18 @@ cmdCallback callbacks[MAX_CALLBACKS]; // cleared in CMD_Reset
// Command handler for IsReady (healthcheck) command // Command handler for IsReady (healthcheck) command
static uint32_t ICACHE_FLASH_ATTR static uint32_t ICACHE_FLASH_ATTR
CMD_IsReady(CmdPacket *cmd) { CMD_IsReady(CmdPacket *cmd) {
#ifdef CMD_DBG
os_printf("CMD_IsReady: Check ready\n"); os_printf("CMD_IsReady: Check ready\n");
#endif
return 1; return 1;
} }
// Command handler for Null command // Command handler for Null command
static uint32_t ICACHE_FLASH_ATTR static uint32_t ICACHE_FLASH_ATTR
CMD_Null(CmdPacket *cmd) { CMD_Null(CmdPacket *cmd) {
#ifdef CMD_DBG
os_printf("CMD_Null: NULL/unsupported command\n"); os_printf("CMD_Null: NULL/unsupported command\n");
#endif
return 1; return 1;
} }
@ -68,7 +72,9 @@ CMD_Null(CmdPacket *cmd) {
// uC. // uC.
static uint32_t ICACHE_FLASH_ATTR static uint32_t ICACHE_FLASH_ATTR
CMD_Reset(CmdPacket *cmd) { CMD_Reset(CmdPacket *cmd) {
#ifdef CMD_DBG
os_printf("CMD_Reset\n"); os_printf("CMD_Reset\n");
#endif
// clear callbacks table // clear callbacks table
os_memset(callbacks, 0, sizeof(callbacks)); os_memset(callbacks, 0, sizeof(callbacks));
return 1; 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') { if (os_strcmp(callbacks[i].name, name) == 0 || callbacks[i].name[0] == '\0') {
os_strncpy(callbacks[i].name, name, sizeof(callbacks[i].name)); os_strncpy(callbacks[i].name, name, sizeof(callbacks[i].name));
callbacks[i].callback = cb; callbacks[i].callback = cb;
#ifdef CMD_DBG
os_printf("CMD_AddCb: cb %s added at index %d\n", callbacks[i].name, i); os_printf("CMD_AddCb: cb %s added at index %d\n", callbacks[i].name, i);
#endif
return 1; return 1;
} }
} }
@ -99,7 +107,9 @@ CMD_GetCbByName(char* name) {
// (void *)callbacks[i].callback); // (void *)callbacks[i].callback);
// if callback doesn't exist or it's null // if callback doesn't exist or it's null
if (os_strcmp(callbacks[i].name, checkname) == 0) { 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); os_printf("CMD_GetCbByName: cb %s found at index %d\n", callbacks[i].name, i);
#endif
return &callbacks[i]; return &callbacks[i];
} }
} }
@ -111,7 +121,9 @@ CMD_GetCbByName(char* name) {
static void ICACHE_FLASH_ATTR static void ICACHE_FLASH_ATTR
CMD_WifiCb(uint8_t wifiStatus) { CMD_WifiCb(uint8_t wifiStatus) {
if (wifiStatus != lastWifiStatus){ if (wifiStatus != lastWifiStatus){
#ifdef CMD_DBG
os_printf("CMD_WifiCb: wifiStatus=%d\n", wifiStatus); os_printf("CMD_WifiCb: wifiStatus=%d\n", wifiStatus);
#endif
lastWifiStatus = wifiStatus; lastWifiStatus = wifiStatus;
cmdCallback *wifiCb = CMD_GetCbByName("wifiCb"); cmdCallback *wifiCb = CMD_GetCbByName("wifiCb");
if ((uint32_t)wifiCb->callback != -1) { if ((uint32_t)wifiCb->callback != -1) {
@ -128,7 +140,9 @@ static uint32_t ICACHE_FLASH_ATTR
CMD_WifiConnect(CmdPacket *cmd) { CMD_WifiConnect(CmdPacket *cmd) {
CmdRequest req; CmdRequest req;
CMD_Request(&req, cmd); CMD_Request(&req, cmd);
#ifdef CMD_DBG
os_printf("CMD_WifiConnect: setup argc=%ld\n", CMD_GetArgc(&req)); os_printf("CMD_WifiConnect: setup argc=%ld\n", CMD_GetArgc(&req));
#endif
if(cmd->argc != 2 || cmd->callback == 0) if(cmd->argc != 2 || cmd->callback == 0)
return 0; return 0;
@ -148,7 +162,9 @@ static uint32_t ICACHE_FLASH_ATTR
CMD_AddCallback(CmdPacket *cmd) { CMD_AddCallback(CmdPacket *cmd) {
CmdRequest req; CmdRequest req;
CMD_Request(&req, cmd); CMD_Request(&req, cmd);
#ifdef CMD_DBG
os_printf("CMD_AddCallback: setup argc=%ld\n", CMD_GetArgc(&req)); os_printf("CMD_AddCallback: setup argc=%ld\n", CMD_GetArgc(&req));
#endif
if (cmd->argc != 1 || cmd->callback == 0) if (cmd->argc != 1 || cmd->callback == 0)
return 0; return 0;
@ -157,11 +173,15 @@ CMD_AddCallback(CmdPacket *cmd) {
// get the sensor name // get the sensor name
len = CMD_ArgLen(&req); len = CMD_ArgLen(&req);
#ifdef CMD_DBG
os_printf("CMD_AddCallback: name len=%d\n", len); os_printf("CMD_AddCallback: name len=%d\n", len);
#endif
if (len > 15) return 0; // max size of name is 15 characters if (len > 15) return 0; // max size of name is 15 characters
if (CMD_PopArg(&req, (uint8_t *)name, len)) return 0; if (CMD_PopArg(&req, (uint8_t *)name, len)) return 0;
name[len] = 0; name[len] = 0;
#ifdef CMD_DBG
os_printf("CMD_AddCallback: name=%s\n", name); os_printf("CMD_AddCallback: name=%s\n", name);
#endif
return CMD_AddCb(name, (uint32_t)cmd->callback); // save the sensor callback return CMD_AddCb(name, (uint32_t)cmd->callback); // save the sensor callback
} }

@ -65,9 +65,11 @@
<ItemGroup> <ItemGroup>
<ClCompile Include="cmd\cmd.c" /> <ClCompile Include="cmd\cmd.c" />
<ClCompile Include="cmd\handlers.c" /> <ClCompile Include="cmd\handlers.c" />
<ClCompile Include="tcpclient\tcpclient.c" />
<ClCompile Include="esp-link\cgimqtt.c" />
<ClCompile Include="mqtt\mqtt_cmd.c" /> <ClCompile Include="mqtt\mqtt_cmd.c" />
<ClCompile Include="mqtt\pktbuf.c" />
<ClCompile Include="rest\rest.c" /> <ClCompile Include="rest\rest.c" />
<ClCompile Include="cmd\tcpclient.c" />
<ClCompile Include="espfs\espfs.c" /> <ClCompile Include="espfs\espfs.c" />
<ClCompile Include="espfs\mkespfsimage\main.c" /> <ClCompile Include="espfs\mkespfsimage\main.c" />
<ClCompile Include="espfs\mkespfsimage\mman-win32\mman.c" /> <ClCompile Include="espfs\mkespfsimage\mman-win32\mman.c" />
@ -103,6 +105,7 @@
<ClCompile Include="user\cgitcp.c" /> <ClCompile Include="user\cgitcp.c" />
<ClCompile Include="user\cgiwifi.c" /> <ClCompile Include="user\cgiwifi.c" />
<ClCompile Include="user\config.c" /> <ClCompile Include="user\config.c" />
<ClCompile Include="user\latch_json.c" />
<ClCompile Include="user\log.c" /> <ClCompile Include="user\log.c" />
<ClCompile Include="user\status.c" /> <ClCompile Include="user\status.c" />
<ClCompile Include="user\user_funcs.c" /> <ClCompile Include="user\user_funcs.c" />
@ -111,9 +114,12 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="cmd\cmd.h" /> <ClInclude Include="cmd\cmd.h" />
<ClInclude Include="tcpclient\tcpclient.h" />
<ClInclude Include="esp-link\cgimqtt.h" />
<ClInclude Include="mqtt\mqtt_cmd.h" /> <ClInclude Include="mqtt\mqtt_cmd.h" />
<ClInclude Include="mqtt\pktbuf.h" />
<ClInclude Include="rest\rest.h" /> <ClInclude Include="rest\rest.h" />
<ClInclude Include="cmd\tcpclient.h" /> <ClInclude Include="serial\slip.h" />
<ClInclude Include="espfs\espfs.h" /> <ClInclude Include="espfs\espfs.h" />
<ClInclude Include="espfs\espfsformat.h" /> <ClInclude Include="espfs\espfsformat.h" />
<ClInclude Include="espfs\mkespfsimage\mman-win32\mman.h" /> <ClInclude Include="espfs\mkespfsimage\mman-win32\mman.h" />
@ -150,6 +156,7 @@
<ClInclude Include="user\cgitcp.h" /> <ClInclude Include="user\cgitcp.h" />
<ClInclude Include="user\cgiwifi.h" /> <ClInclude Include="user\cgiwifi.h" />
<ClInclude Include="user\config.h" /> <ClInclude Include="user\config.h" />
<ClInclude Include="user\latch_json.h" />
<ClInclude Include="user\log.h" /> <ClInclude Include="user\log.h" />
<ClInclude Include="user\status.h" /> <ClInclude Include="user\status.h" />
<ClInclude Include="user\user_funcs.h" /> <ClInclude Include="user\user_funcs.h" />

@ -16,14 +16,6 @@ Some random cgi routines.
#include <esp8266.h> #include <esp8266.h>
#include "cgi.h" #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) { void noCacheHeaders(HttpdConnData *connData, int code) {
httpdStartResponse(connData, code); httpdStartResponse(connData, code);
@ -44,7 +36,9 @@ errorResponse(HttpdConnData *connData, int code, char *message) {
noCacheHeaders(connData, code); noCacheHeaders(connData, code);
httpdEndHeaders(connData); httpdEndHeaders(connData);
httpdSend(connData, message, -1); httpdSend(connData, message, -1);
#ifdef CGI_DBG
os_printf("HTTP %d error response: \"%s\"\n", code, message); 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 // look for the HTTP arg 'name' and store it at 'config' with max length 'max_len' (incl

@ -10,6 +10,5 @@ int getStringArg(HttpdConnData *connData, char *name, char *config, int max_len)
int getBoolArg(HttpdConnData *connData, char *name, bool*config); int getBoolArg(HttpdConnData *connData, char *name, bool*config);
int cgiMenu(HttpdConnData *connData); int cgiMenu(HttpdConnData *connData);
uint8_t UTILS_StrToIP(const char* str, void *ip); uint8_t UTILS_StrToIP(const char* str, void *ip);
char* system_get_chip_id_str();
#endif #endif

@ -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... // Check that the header of the firmware blob looks like actual firmware...
static char* ICACHE_FLASH_ATTR check_header(void *buf) { static char* ICACHE_FLASH_ATTR check_header(void *buf) {
uint8_t *cd = (uint8_t *)buf; uint8_t *cd = (uint8_t *)buf;
#ifdef CGIFLASH_DBG
uint32_t *buf32 = buf; uint32_t *buf32 = buf;
os_printf("%p: %08lX %08lX %08lX %08lX\n", buf, buf32[0], buf32[1], buf32[2], buf32[3]); 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[0] != 0xEA) return "IROM magic missing";
if (cd[1] != 4 || cd[2] > 3 || (cd[3]>>4) > 6) return "bad flash header"; 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"; if (((uint16_t *)buf)[3] != 0x4010) return "Invalid entry addr";
@ -42,7 +44,9 @@ int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) {
httpdEndHeaders(connData); httpdEndHeaders(connData);
char *next = id == 1 ? "user1.bin" : "user2.bin"; char *next = id == 1 ? "user1.bin" : "user2.bin";
httpdSend(connData, next, -1); httpdSend(connData, next, -1);
#ifdef CGIFLASH_DBG
os_printf("Next firmware: %s (got %d)\n", next, id); os_printf("Next firmware: %s (got %d)\n", next, id);
#endif
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
@ -80,7 +84,9 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) {
// return an error if there is one // return an error if there is one
if (err != NULL) { if (err != NULL) {
#ifdef CGIFLASH_DBG
os_printf("Error %d: %s\n", code, err); os_printf("Error %d: %s\n", code, err);
#endif
httpdStartResponse(connData, code); httpdStartResponse(connData, code);
httpdHeader(connData, "Content-Type", "text/plain"); httpdHeader(connData, "Content-Type", "text/plain");
//httpdHeader(connData, "Content-Length", strlen(err)+2); //httpdHeader(connData, "Content-Length", strlen(err)+2);
@ -99,7 +105,9 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) {
// erase next flash block if necessary // erase next flash block if necessary
if (address % SPI_FLASH_SEC_SIZE == 0){ if (address % SPI_FLASH_SEC_SIZE == 0){
#ifdef CGIFLASH_DBG
os_printf("Flashing 0x%05x (id=%d)\n", address, 2-id); os_printf("Flashing 0x%05x (id=%d)\n", address, 2-id);
#endif
spi_flash_erase_sector(address/SPI_FLASH_SEC_SIZE); 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 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 : 4*1024 + FIRMWARE_SIZE + 16*1024 + 4*1024; // 4KB boot, fw1, 16KB user param, 4KB reserved
uint32 buf[8]; uint32 buf[8];
#ifdef CGIFLASH_DBG
os_printf("Checking %p\n", (void *)address); os_printf("Checking %p\n", (void *)address);
#endif
spi_flash_read(address, buf, sizeof(buf)); spi_flash_read(address, buf, sizeof(buf));
char *err = check_header(buf); char *err = check_header(buf);
if (err != NULL) { if (err != NULL) {
#ifdef CGIFLASH_DBG
os_printf("Error %d: %s\n", 400, err); os_printf("Error %d: %s\n", 400, err);
#endif
httpdStartResponse(connData, 400); httpdStartResponse(connData, 400);
httpdHeader(connData, "Content-Type", "text/plain"); httpdHeader(connData, "Content-Type", "text/plain");
//httpdHeader(connData, "Content-Length", strlen(err)+2); //httpdHeader(connData, "Content-Length", strlen(err)+2);

@ -17,17 +17,29 @@ int ICACHE_FLASH_ATTR cgiMqttGet(HttpdConnData *connData) {
"\"slip-enable\":%d, " "\"slip-enable\":%d, "
"\"mqtt-enable\":%d, " "\"mqtt-enable\":%d, "
"\"mqtt-status-enable\":%d, " "\"mqtt-status-enable\":%d, "
"\"mqtt-clean-session\":%d, "
"\"mqtt-port\":%d, " "\"mqtt-port\":%d, "
"\"mqtt-timeout\":%d, "
"\"mqtt-keepalive\":%d, "
"\"mqtt-host\":\"%s\", " "\"mqtt-host\":\"%s\", "
"\"mqtt-client-id\":\"%s\", " "\"mqtt-client-id\":\"%s\", "
"\"mqtt-username\":\"%s\", " "\"mqtt-username\":\"%s\", "
"\"mqtt-password\":\"%s\", " "\"mqtt-password\":\"%s\", "
"\"mqtt-status-topic\":\"%s\", " "\"mqtt-status-topic\":\"%s\", "
"\"mqtt-state\":\"%s\" }", "\"mqtt-state\":\"%s\" }",
flashConfig.slip_enable, flashConfig.mqtt_enable, flashConfig.mqtt_status_enable, flashConfig.slip_enable,
flashConfig.mqtt_port, flashConfig.mqtt_hostname, flashConfig.mqtt_client, flashConfig.mqtt_enable,
flashConfig.mqtt_username, flashConfig.mqtt_password, flashConfig.mqtt_status_enable,
flashConfig.mqtt_status_topic, "connected"); 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); jsonHeader(connData, 200);
httpdSend(connData, buff, len); httpdSend(connData, buff, len);
@ -41,22 +53,30 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) {
// handle MQTT server settings // handle MQTT server settings
int mqtt_server = 0; // accumulator for changes/errors int mqtt_server = 0; // accumulator for changes/errors
mqtt_server |= getStringArg(connData, "mqtt-host", 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; if (mqtt_server < 0) return HTTPD_CGI_DONE;
mqtt_server |= getStringArg(connData, "mqtt-client-id", 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; if (mqtt_server < 0) return HTTPD_CGI_DONE;
mqtt_server |= getStringArg(connData, "mqtt-username", mqtt_server |= getStringArg(connData, "mqtt-username",
flashConfig.mqtt_username, sizeof(flashConfig.mqtt_username)); flashConfig.mqtt_username, sizeof(flashConfig.mqtt_username));
if (mqtt_server < 0) return HTTPD_CGI_DONE; if (mqtt_server < 0) return HTTPD_CGI_DONE;
mqtt_server |= getStringArg(connData, "mqtt-password", mqtt_server |= getStringArg(connData, "mqtt-password",
flashConfig.mqtt_password, sizeof(flashConfig.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; if (mqtt_server < 0) return HTTPD_CGI_DONE;
mqtt_server |= getBoolArg(connData, "mqtt-enable", mqtt_server |= getBoolArg(connData, "mqtt-enable",
&flashConfig.mqtt_enable); &flashConfig.mqtt_enable);
// handle mqtt port
char buff[16]; char buff[16];
// handle mqtt port
if (httpdFindArg(connData->getArgs, "mqtt-port", buff, sizeof(buff)) > 0) { if (httpdFindArg(connData->getArgs, "mqtt-port", buff, sizeof(buff)) > 0) {
int32_t port = atoi(buff); int32_t port = atoi(buff);
if (port > 0 && port < 65536) { 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 server setting changed, we need to "make it so"
if (mqtt_server) { if (mqtt_server) {
#ifdef CGIMQTT_DBG
os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable); os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable);
#endif
// TODO // 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 // if SLIP-enable is toggled it gets picked-up immediately by the parser
int slip_update = getBoolArg(connData, "slip-enable", &flashConfig.slip_enable); int slip_update = getBoolArg(connData, "slip-enable", &flashConfig.slip_enable);
if (slip_update < 0) return HTTPD_CGI_DONE; 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); if (slip_update > 0) os_printf("SLIP-enable changed: %d\n", flashConfig.slip_enable);
os_printf("Saving config\n"); os_printf("Saving config\n");
#endif
if (configSave()) { if (configSave()) {
httpdStartResponse(connData, 200); httpdStartResponse(connData, 200);
httpdEndHeaders(connData); httpdEndHeaders(connData);

@ -85,8 +85,9 @@ int ICACHE_FLASH_ATTR cgiPinsSet(HttpdConnData *connData) {
jsonHeader(connData, 400); jsonHeader(connData, 400);
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
#ifdef CGIPINS_DBG
os_printf("Switching pin map to %s (%d)\n", map_names[m], m); os_printf("Switching pin map to %s (%d)\n", map_names[m], m);
#endif
int8_t *map = map_asn[m]; int8_t *map = map_asn[m];
flashConfig.reset_pin = map[0]; flashConfig.reset_pin = map[0];
flashConfig.isp_pin = map[1]; flashConfig.isp_pin = map[1];

@ -55,36 +55,48 @@ static void ICACHE_FLASH_ATTR wifiHandleEventCb(System_Event_t *evt) {
case EVENT_STAMODE_CONNECTED: case EVENT_STAMODE_CONNECTED:
wifiState = wifiIsConnected; wifiState = wifiIsConnected;
wifiReason = 0; wifiReason = 0;
#ifdef CGIWIFI_DBG
os_printf("Wifi connected to ssid %s, ch %d\n", evt->event_info.connected.ssid, os_printf("Wifi connected to ssid %s, ch %d\n", evt->event_info.connected.ssid,
evt->event_info.connected.channel); evt->event_info.connected.channel);
#endif
statusWifiUpdate(wifiState); statusWifiUpdate(wifiState);
break; break;
case EVENT_STAMODE_DISCONNECTED: case EVENT_STAMODE_DISCONNECTED:
wifiState = wifiIsDisconnected; wifiState = wifiIsDisconnected;
wifiReason = evt->event_info.disconnected.reason; wifiReason = evt->event_info.disconnected.reason;
#ifdef CGIWIFI_DBG
os_printf("Wifi disconnected from ssid %s, reason %s (%d)\n", os_printf("Wifi disconnected from ssid %s, reason %s (%d)\n",
evt->event_info.disconnected.ssid, wifiGetReason(), evt->event_info.disconnected.reason); evt->event_info.disconnected.ssid, wifiGetReason(), evt->event_info.disconnected.reason);
#endif
statusWifiUpdate(wifiState); statusWifiUpdate(wifiState);
break; break;
case EVENT_STAMODE_AUTHMODE_CHANGE: case EVENT_STAMODE_AUTHMODE_CHANGE:
#ifdef CGIWIFI_DBG
os_printf("Wifi auth mode: %d -> %d\n", os_printf("Wifi auth mode: %d -> %d\n",
evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode);
#endif
break; break;
case EVENT_STAMODE_GOT_IP: case EVENT_STAMODE_GOT_IP:
wifiState = wifiGotIP; wifiState = wifiGotIP;
wifiReason = 0; wifiReason = 0;
#ifdef CGIWIFI_DBG
os_printf("Wifi got ip:" IPSTR ",mask:" IPSTR ",gw:" IPSTR "\n", 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.ip), IP2STR(&evt->event_info.got_ip.mask),
IP2STR(&evt->event_info.got_ip.gw)); IP2STR(&evt->event_info.got_ip.gw));
#endif
statusWifiUpdate(wifiState); statusWifiUpdate(wifiState);
break; break;
case EVENT_SOFTAPMODE_STACONNECTED: case EVENT_SOFTAPMODE_STACONNECTED:
#ifdef CGIWIFI_DBG
os_printf("Wifi AP: station " MACSTR " joined, AID = %d\n", os_printf("Wifi AP: station " MACSTR " joined, AID = %d\n",
MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid); MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid);
#endif
break; break;
case EVENT_SOFTAPMODE_STADISCONNECTED: case EVENT_SOFTAPMODE_STADISCONNECTED:
#ifdef CGIWIFI_DBG
os_printf("Wifi AP: station " MACSTR " left, AID = %d\n", os_printf("Wifi AP: station " MACSTR " left, AID = %d\n",
MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid); MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid);
#endif
break; break;
default: default:
break; break;
@ -103,7 +115,9 @@ wifiAddStateChangeCb(WifiStateChangeCb cb) {
return; return;
} }
} }
#ifdef CGIWIFI_DBG
os_printf("WIFI: max state change cb count exceeded\n"); os_printf("WIFI: max state change cb count exceeded\n");
#endif
} }
// ===== wifi scanning // ===== wifi scanning
@ -132,7 +146,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) {
struct bss_info *bss_link = (struct bss_info *)arg; struct bss_info *bss_link = (struct bss_info *)arg;
if (status!=OK) { if (status!=OK) {
#ifdef CGIWIFI_DBG
os_printf("wifiScanDoneCb status=%d\n", status); os_printf("wifiScanDoneCb status=%d\n", status);
#endif
cgiWifiAps.scanInProgress=0; cgiWifiAps.scanInProgress=0;
return; return;
} }
@ -152,7 +168,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) {
//Allocate memory for access point data //Allocate memory for access point data
cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n); cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n);
cgiWifiAps.noAps=n; cgiWifiAps.noAps=n;
#ifdef CGIWIFI_DBG
os_printf("Scan done: found %d APs\n", n); os_printf("Scan done: found %d APs\n", n);
#endif
//Copy access point data to the static struct //Copy access point data to the static struct
n=0; n=0;
@ -161,7 +179,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) {
if (n>=cgiWifiAps.noAps) { if (n>=cgiWifiAps.noAps) {
//This means the bss_link changed under our nose. Shouldn't happen! //This means the bss_link changed under our nose. Shouldn't happen!
//Break because otherwise we will write in unallocated memory. //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); os_printf("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps);
#endif
break; break;
} }
//Save the ap data. //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]->rssi=bss_link->rssi;
cgiWifiAps.apData[n]->enc=bss_link->authmode; cgiWifiAps.apData[n]->enc=bss_link->authmode;
strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32); 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); os_printf("bss%d: %s (%d)\n", n+1, (char*)bss_link->ssid, bss_link->rssi);
#endif
bss_link = bss_link->next.stqe_next; bss_link = bss_link->next.stqe_next;
n++; n++;
@ -180,7 +202,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) {
static ETSTimer scanTimer; static ETSTimer scanTimer;
static void ICACHE_FLASH_ATTR scanStartCb(void *arg) { static void ICACHE_FLASH_ATTR scanStartCb(void *arg) {
#ifdef CGIWIFI_DBG
os_printf("Starting a scan\n"); os_printf("Starting a scan\n");
#endif
wifi_station_scan(NULL, wifiScanDoneCb); wifi_station_scan(NULL, wifiScanDoneCb);
} }
@ -245,13 +269,17 @@ static ETSTimer resetTimer;
static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) {
int x = wifi_station_get_connect_status(); int x = wifi_station_get_connect_status();
int m = wifi_get_opmode() & 0x3; int m = wifi_get_opmode() & 0x3;
#ifdef CGIWIFI_DBG
os_printf("Wifi check: mode=%s status=%d\n", wifiMode[m], x); os_printf("Wifi check: mode=%s status=%d\n", wifiMode[m], x);
#endif
if (x == STATION_GOT_IP) { if (x == STATION_GOT_IP) {
if (m != 1) { if (m != 1) {
#ifdef CHANGE_TO_STA #ifdef CHANGE_TO_STA
// We're happily connected, go to STA mode // We're happily connected, go to STA mode
#ifdef CGIWIFI_DBG
os_printf("Wifi got IP. Going into STA mode..\n"); os_printf("Wifi got IP. Going into STA mode..\n");
#endif
wifi_set_opmode(1); wifi_set_opmode(1);
wifi_set_sleep_type(SLEEP_MODE); wifi_set_sleep_type(SLEEP_MODE);
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); 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 // no more resetTimer at this point, gotta use physical reset to recover if in trouble
} else { } else {
if (m != 3) { if (m != 3) {
#ifdef CGIWIFI_DBG
os_printf("Wifi connect failed. Going into STA+AP mode..\n"); os_printf("Wifi connect failed. Going into STA+AP mode..\n");
#endif
wifi_set_opmode(3); wifi_set_opmode(3);
} }
log_uart(true); log_uart(true);
#ifdef CGIWIFI_DBG
os_printf("Enabling/continuing uart log\n"); os_printf("Enabling/continuing uart log\n");
#endif
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
} }
} }
@ -277,7 +309,9 @@ static ETSTimer reassTimer;
// Callback actually doing reassociation // Callback actually doing reassociation
static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) { static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) {
#ifdef CGIWIFI_DBG
os_printf("Wifi changing association\n"); os_printf("Wifi changing association\n");
#endif
wifi_station_disconnect(); wifi_station_disconnect();
stconf.bssid_set = 0; stconf.bssid_set = 0;
wifi_station_set_config(&stconf); 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 //Set to 0 if you want to disable the actual reconnecting bit
os_strncpy((char*)stconf.ssid, essid, 32); os_strncpy((char*)stconf.ssid, essid, 32);
os_strncpy((char*)stconf.password, passwd, 64); os_strncpy((char*)stconf.password, passwd, 64);
#ifdef CGIWIFI_DBG
os_printf("Wifi try to connect to AP %s pw %s\n", essid, passwd); os_printf("Wifi try to connect to AP %s pw %s\n", essid, passwd);
#endif
//Schedule disconnect/connect //Schedule disconnect/connect
os_timer_disarm(&reassTimer); os_timer_disarm(&reassTimer);
@ -342,7 +378,6 @@ static bool parse_ip(char *buff, ip_addr_t *ip_ptr) {
return false; return false;
} }
#define DEBUGIP
#ifdef DEBUGIP #ifdef DEBUGIP
static void ICACHE_FLASH_ATTR debugIP() { static void ICACHE_FLASH_ATTR debugIP() {
struct ip_info info; struct ip_info info;
@ -365,7 +400,9 @@ static void ICACHE_FLASH_ATTR configWifiIP() {
if (wifi_station_dhcpc_status() == DHCP_STARTED) if (wifi_station_dhcpc_status() == DHCP_STARTED)
wifi_station_dhcpc_stop(); wifi_station_dhcpc_stop();
wifi_station_dhcpc_start(); wifi_station_dhcpc_start();
#ifdef CGIWIFI_DBG
os_printf("Wifi uses DHCP, hostname=%s\n", flashConfig.hostname); os_printf("Wifi uses DHCP, hostname=%s\n", flashConfig.hostname);
#endif
} else { } else {
// no DHCP, we got static network config! // no DHCP, we got static network config!
wifi_station_dhcpc_stop(); wifi_station_dhcpc_stop();
@ -374,7 +411,9 @@ static void ICACHE_FLASH_ATTR configWifiIP() {
ipi.netmask.addr = flashConfig.netmask; ipi.netmask.addr = flashConfig.netmask;
ipi.gw.addr = flashConfig.gateway; ipi.gw.addr = flashConfig.gateway;
wifi_set_ip_info(0, &ipi); wifi_set_ip_info(0, &ipi);
#ifdef CGIWIFI_DBG
os_printf("Wifi uses static IP %d.%d.%d.%d\n", IP2STR(&ipi.ip.addr)); os_printf("Wifi uses static IP %d.%d.%d.%d\n", IP2STR(&ipi.ip.addr));
#endif
} }
#ifdef DEBUGIP #ifdef DEBUGIP
debugIP(); debugIP();
@ -454,7 +493,9 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff));
if (len!=0) { if (len!=0) {
int m = atoi(buff); int m = atoi(buff);
#ifdef CGIWIFI_DBG
os_printf("Wifi switching to mode %d\n", m); os_printf("Wifi switching to mode %d\n", m);
#endif
wifi_set_opmode(m&3); wifi_set_opmode(m&3);
if (m == 1) { if (m == 1) {
wifi_set_sleep_type(SLEEP_MODE); wifi_set_sleep_type(SLEEP_MODE);
@ -557,8 +598,9 @@ int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
#endif #endif
len += os_sprintf(buff+len, "\"x\":0}\n"); len += os_sprintf(buff+len, "\"x\":0}\n");
#ifdef CGIWIFI_DBG
os_printf(" -> %s\n", buff); os_printf(" -> %s\n", buff);
#endif
httpdSend(connData, buff, len); httpdSend(connData, buff, len);
return HTTPD_CGI_DONE; 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. // so we can revert to STA+AP mode if we can't connect.
void ICACHE_FLASH_ATTR wifiInit() { void ICACHE_FLASH_ATTR wifiInit() {
wifi_set_phy_mode(2); wifi_set_phy_mode(2);
#ifdef CGIWIFI_DBG
int x = wifi_get_opmode() & 0x3; int x = wifi_get_opmode() & 0x3;
os_printf("Wifi init, mode=%s\n", wifiMode[x]); os_printf("Wifi init, mode=%s\n", wifiMode[x]);
#endif
configWifiIP(); configWifiIP();
wifi_set_event_handler_cb(wifiHandleEventCb); wifi_set_event_handler_cb(wifiHandleEventCb);

@ -6,6 +6,7 @@
#include "config.h" #include "config.h"
#include "espfs.h" #include "espfs.h"
#include "crc16.h" #include "crc16.h"
#include <user_funcs.h>
FlashConfig flashConfig; FlashConfig flashConfig;
FlashConfig flashDefault = { FlashConfig flashDefault = {
@ -19,8 +20,9 @@ FlashConfig flashDefault = {
1, 0, // tcp_enable, rssi_enable 1, 0, // tcp_enable, rssi_enable
"\0", // api_key "\0", // api_key
0, 0, 0, // slip_enable, mqtt_enable, mqtt_status_enable 0, 0, 0, // slip_enable, mqtt_enable, mqtt_status_enable
1833, // mqtt port 2, 1, // mqtt_timeout, mqtt_clean_session
"\0", "\0", "\0", "\0", "\0", // mqtt host, client, user, password, status-topic 1833, 600, // mqtt port, mqtt_keepalive
"\0", "\0", "\0", "\0", "\0", // mqtt host, client_id, user, password, status-topic
}; };
typedef union { typedef union {
@ -51,8 +53,8 @@ static void memDump(void *addr, int len) {
bool ICACHE_FLASH_ATTR configSave(void) { bool ICACHE_FLASH_ATTR configSave(void) {
FlashFull ff; FlashFull ff;
memset(&ff, 0, sizeof(ff)); os_memset(&ff, 0, sizeof(ff));
memcpy(&ff, &flashConfig, sizeof(FlashConfig)); os_memcpy(&ff, &flashConfig, sizeof(FlashConfig));
uint32_t seq = ff.fc.seq+1; uint32_t seq = ff.fc.seq+1;
// erase secondary // erase secondary
uint32_t addr = FLASH_ADDR + (1-flash_pri)*FLASH_SECT; uint32_t addr = FLASH_ADDR + (1-flash_pri)*FLASH_SECT;
@ -104,19 +106,28 @@ bool ICACHE_FLASH_ATTR configRestore(void) {
FlashFull ff0, ff1; FlashFull ff0, ff1;
// read both flash sectors // read both flash sectors
if (spi_flash_read(FLASH_ADDR, (void *)&ff0, sizeof(ff0)) != SPI_FLASH_RESULT_OK) 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) 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 // figure out which one is good
flash_pri = selectPrimary(&ff0, &ff1); flash_pri = selectPrimary(&ff0, &ff1);
// if neither is OK, we revert to defaults // if neither is OK, we revert to defaults
if (flash_pri < 0) { 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; flash_pri = 0;
return false; return false;
} }
// copy good one into global var and return // 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; return true;
} }
@ -125,10 +136,14 @@ static int ICACHE_FLASH_ATTR selectPrimary(FlashFull *ff0, FlashFull *ff1) {
uint16_t crc = ff0->fc.crc; uint16_t crc = ff0->fc.crc;
ff0->fc.crc = 0; ff0->fc.crc = 0;
bool ff0_crc_ok = crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0) == crc; bool ff0_crc_ok = crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0) == crc;
#ifdef CONFIG_DBG
os_printf("FLASH chk=0x%04x crc=0x%04x full_sz=%d sz=%d\n", 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), crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0),
crc, sizeof(FlashFull), sizeof(FlashConfig)); crc,
sizeof(FlashFull),
sizeof(FlashConfig),
getFlashSize());
#endif
// check CRC of ff1 // check CRC of ff1
crc = ff1->fc.crc; crc = ff1->fc.crc;
@ -144,3 +159,15 @@ static int ICACHE_FLASH_ATTR selectPrimary(FlashFull *ff0, FlashFull *ff1) {
else else
return ff1_crc_ok ? 1 : -1; 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;
}

@ -17,9 +17,11 @@ typedef struct {
uint8_t tcp_enable, rssi_enable; // TCP client settings uint8_t tcp_enable, rssi_enable; // TCP client settings
char api_key[48]; // RSSI submission API key (Grovestreams for now) char api_key[48]; // RSSI submission API key (Grovestreams for now)
uint8_t slip_enable, mqtt_enable, // SLIP protocol, MQTT client uint8_t slip_enable, mqtt_enable, // SLIP protocol, MQTT client
mqtt_status_enable; // MQTT status reporting mqtt_status_enable, // MQTT status reporting
uint16_t mqtt_port; mqtt_timeout, // MQTT send timeout
char mqtt_hostname[32], mqtt_client[48], mqtt_username[32], mqtt_password[32]; 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]; char mqtt_status_topic[32];
} FlashConfig; } FlashConfig;
extern FlashConfig flashConfig; extern FlashConfig flashConfig;
@ -27,5 +29,6 @@ extern FlashConfig flashConfig;
bool configSave(void); bool configSave(void);
bool configRestore(void); bool configRestore(void);
void configWipe(void); void configWipe(void);
const size_t getFlashSize();
#endif #endif

@ -25,14 +25,18 @@ log_uart(bool enable) {
if (!enable && !log_no_uart && flashConfig.log_mode != LOG_MODE_ON) { 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 // we're asked to turn uart off, and uart is on, and the flash setting isn't always-on
#if 1 #if 1
#ifdef LOG_DBG
os_printf("Turning OFF uart log\n"); os_printf("Turning OFF uart log\n");
#endif
os_delay_us(4*1000L); // time for uart to flush os_delay_us(4*1000L); // time for uart to flush
log_no_uart = !enable; log_no_uart = !enable;
#endif #endif
} else if (enable && log_no_uart && flashConfig.log_mode != LOG_MODE_OFF) { } 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 // we're asked to turn uart on, and uart is off, and the flash setting isn't always-off
log_no_uart = !enable; log_no_uart = !enable;
#ifdef LOG_DBG
os_printf("Turning ON uart log\n"); os_printf("Turning ON uart log\n");
#endif
} }
} }

@ -30,7 +30,7 @@
#include "log.h" #include "log.h"
#include <gpio.h> #include <gpio.h>
#define SHOW_HEAP_USE //#define SHOW_HEAP_USE
//Function that tells the authentication system what users/passwords live on the system. //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 //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 } { NULL, NULL, NULL }
}; };
//#define SHOW_HEAP_USE
#ifdef SHOW_HEAP_USE #ifdef SHOW_HEAP_USE
static ETSTimer prHeapTimer; static ETSTimer prHeapTimer;

@ -4,8 +4,9 @@
#include "config.h" #include "config.h"
#include "serled.h" #include "serled.h"
#include "cgiwifi.h" #include "cgiwifi.h"
#include "tcpclient.h" #ifdef TCPCLIENT
#include <tcpclient.h>
#endif
//===== "CONN" LED status indication //===== "CONN" LED status indication
static ETSTimer ledTimer; static ETSTimer ledTimer;
@ -66,6 +67,8 @@ void ICACHE_FLASH_ATTR statusWifiUpdate(uint8_t state) {
os_timer_arm(&ledTimer, 500, 0); os_timer_arm(&ledTimer, 500, 0);
} }
#ifdef TCPCLIENT
//===== RSSI Status update sent to GroveStreams //===== RSSI Status update sent to GroveStreams
#define RSSI_INTERVAL (60*1000) #define RSSI_INTERVAL (60*1000)
@ -112,6 +115,7 @@ static void ICACHE_FLASH_ATTR rssiTimerCb(void *v) {
} }
tcpClientSendPush(chan); tcpClientSendPush(chan);
} }
#endif // TCPCLIENT
//===== Init status stuff //===== Init status stuff
@ -120,15 +124,20 @@ void ICACHE_FLASH_ATTR statusInit(void) {
makeGpio(flashConfig.conn_led_pin); makeGpio(flashConfig.conn_led_pin);
setLed(1); setLed(1);
} }
#ifdef STATUS_DBG
os_printf("CONN led=%d\n", flashConfig.conn_led_pin); os_printf("CONN led=%d\n", flashConfig.conn_led_pin);
#endif
os_timer_disarm(&ledTimer); os_timer_disarm(&ledTimer);
os_timer_setfn(&ledTimer, ledTimerCb, NULL); os_timer_setfn(&ledTimer, ledTimerCb, NULL);
os_timer_arm(&ledTimer, 2000, 0); os_timer_arm(&ledTimer, 2000, 0);
#ifdef TCPCLIENT
os_timer_disarm(&rssiTimer); os_timer_disarm(&rssiTimer);
os_timer_setfn(&rssiTimer, rssiTimerCb, NULL); os_timer_setfn(&rssiTimer, rssiTimerCb, NULL);
os_timer_arm(&rssiTimer, RSSI_INTERVAL, 1); // recurring timer os_timer_arm(&rssiTimer, RSSI_INTERVAL, 1); // recurring timer
#endif // TCPCLIENT
} }

@ -109,7 +109,9 @@ void ICACHE_FLASH_ATTR memcpyAligned(char *dst, char *src, int len) {
// Returns flags of opened file. // Returns flags of opened file.
int ICACHE_FLASH_ATTR espFsFlags(EspFsFile *fh) { int ICACHE_FLASH_ATTR espFsFlags(EspFsFile *fh) {
if (fh == NULL) { if (fh == NULL) {
#ifdef ESPFS_DBG
os_printf("File handle not ready\n"); os_printf("File handle not ready\n");
#endif
return -1; 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. //Open a file and return a pointer to the file desc struct.
EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) { EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) {
if (espFsData == NULL) { if (espFsData == NULL) {
#ifdef ESPFS_DBG
os_printf("Call espFsInit first!\n"); os_printf("Call espFsInit first!\n");
#endif
return NULL; return NULL;
} }
char *p=espFsData; char *p=espFsData;
@ -137,7 +141,9 @@ EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) {
//Grab the next file header. //Grab the next file header.
os_memcpy(&h, p, sizeof(EspFsHeader)); os_memcpy(&h, p, sizeof(EspFsHeader));
if (h.magic!=ESPFS_MAGIC) { if (h.magic!=ESPFS_MAGIC) {
#ifdef ESPFS_DBG
os_printf("Magic mismatch. EspFS image broken.\n"); os_printf("Magic mismatch. EspFS image broken.\n");
#endif
return NULL; return NULL;
} }
if (h.flags&FLAG_LASTFILE) { if (h.flags&FLAG_LASTFILE) {
@ -163,7 +169,9 @@ EspFsFile ICACHE_FLASH_ATTR *espFsOpen(char *fileName) {
if (h.compression==COMPRESS_NONE) { if (h.compression==COMPRESS_NONE) {
r->decompData=NULL; r->decompData=NULL;
} else { } else {
#ifdef ESPFS_DBG
os_printf("Invalid compression: %d\n", h.compression); os_printf("Invalid compression: %d\n", h.compression);
#endif
return NULL; return NULL;
} }
return r; return r;

@ -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<missing lines\r\n");
}
el.innerHTML = el.innerHTML.concat(resp.text);
el.textEnd = resp.start + resp.len;
delay = 500;
}
return delay;
}
function retryLoad(repeat) {
fetchText(1000, repeat);
}
//===== Console page
function showRate(rate) {
rates.forEach(function(r) {
var el = $("#"+r+"-button");
el.className = el.className.replace(" button-selected", "");
});
var el = $("#"+rate+"-button");
if (el != null) el.className += " button-selected";
}
function baudButton(baud) {
$("#baud-btns").appendChild(m(
' <a id="'+baud+'-button" href="#" class="pure-button">'+baud+'</a>'));
$("#"+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");
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 498 B

@ -0,0 +1,10 @@
<!doctype html>
<html><head>
<title>esp-link</title>
<link rel="stylesheet" href="/pure.css">
<link rel="stylesheet" href="/style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="/ui.js"></script>
</head>
<body>
<div id="layout">

@ -1 +1,87 @@
<!DOCTYPE html><script src='http://linux-ws/esplink/home.js'></script> <div id="main">
<div class="header">
<div><img src="favicon.ico" height="64"><span class="jl">JEELABS</span></div>
<h1 style="margin-top:0"><span class="esp">esp</span>-link</h1>
<h2 id="version"></h2>
</div>
<div class="content">
<div class="pure-g">
<div class="pure-u-1"><div class="card">
<p>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.</p>
<p style="margin-bottom:0;">Program an Arduino/AVR using avrdude using a command
line similar to:</p>
<div class="tt">/home/arduino-1.0.5/hardware/tools/avrdude \<br>
&nbsp;&nbsp;-DV -patmega328p -Pnet:esp-link.local:23 -carduino -b115200 -U \<br>
&nbsp;&nbsp;-C /home/arduino-1.0.5/hardware/tools/avrdude.conf flash:w:my_sketch.hex:i
</div>
<p>where <tt>-Pnet:esp-link.local:23</tt> 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.</p>
<p>Please refer to
<a href="https://github.com/jeelabs/esp-link/blob/master/README.md">the online README</a>
for up-to-date help and to the forthcoming
<a href="http://jeelabs.org">JeeLabs blog</a> for an intro to the codebase.</p>
</div></div>
</div>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<h1>Wifi summary</h1>
<div id="wifi-spinner" class="spinner spinner-small"></div>
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>Configured network</td><td id="wifi-ssid"></td></tr>
<tr><td>Wifi channel</td><td id="wifi-chan"></td></tr>
<tr><td>Wifi status</td><td id="wifi-status"></td></tr>
<tr><td>Wifi address</td><td id="wifi-ip"></td></tr>
<tr><td>Configured hostname</td><td id="wifi-hostname"></td></tr>
</tbody> </table>
</div>
<div class="card">
<h1>TCP client</h1>
<form action="#" id="tcpform" class="pure-form">
<legend>TCP client support in esp-link</legend>
<div class="form-horizontal">
<input type="checkbox" name="tcp_enable"/>
<label>Enable serial port TCP client</label>
</div>
<br>
<legend>Grovestreams data push</legend>
<div class="form-horizontal">
<input type="checkbox" name="rssi_enable"/>
<label>Send RSSI</label>
</div>
<div class="pure-form-stacked">
<label>API key/passwd</label>
<input type="password" name="api_key"/>
</div>
<button id="tcp-button" type="submit"
class="pure-button button-primary">Change!</button>
</form>
</div>
</div>
<div class="pure-u-1 pure-u-md-1-2"><div class="card">
<h1>Pin assignment</h1>
<legend>Select one of the following signal/pin assignments to match your hardware</legend>
<fieldset class='radios' id='pin-mux'>
<div class="spinner spinner-small"></div>
</fieldset>
</div></div>
</div>
<div class="pure-g">
</div>
</div>
</div>
</div>
<script type="text/javascript">
onLoad(function() {
fetchPins();
getWifiInfo();
fetchTcpClient();
bnd($("#tcpform"), "submit", changeTcpClient);
});
</script>
</body></html>

@ -1 +1,48 @@
<!DOCTYPE html><script src='http://linux-ws/esplink/log.js'></script> <div id="main">
<div class="header">
<h1>Debug Log</h1>
</div>
<div class="content">
<p>The debug log shows the most recent characters printed by the esp-link software itself to
its own debug log.</p>
<div class="pure-g">
<p class="pure-u-1-4">
<a id="refresh-button" class="pure-button button-primary" href="#">Refresh</a>
</p>
<p class="pure-u-3-4" style="vertical-align: baseline">
UART debug log:
<a id="dbg-auto" class="dbg-btn pure-button" href="#">auto</a>
<a id="dbg-off" class="dbg-btn pure-button" href="#">off</a>
<a id="dbg-on" class="dbg-btn pure-button" href="#">on</a>
</p>
</div>
<pre id="console" class="console" style="margin-top: 0px;"></pre>
</div>
</div>
</div>
<script type="text/javascript">console_url = "/log/text"</script>
<script src="console.js"></script>
<script type="text/javascript">
onLoad(function() {
fetchText(100, false);
$("#refresh-button").addEventListener("click", function(e) {
e.preventDefault();
fetchText(100, false);
});
["auto", "off", "on"].forEach(function(mode) {
bnd($('#dbg-'+mode), "click", function(el) {
ajaxJsonSpin('POST', "/log/dbg?mode="+mode,
function(data) { showNotification("UART mode " + data.mode); showDbgMode(data.mode); },
function(s, st) { showWarning("Error setting UART mode: " + st); }
);
});
});
ajaxJson('GET', "/log/dbg", function(data) { showDbgMode(data.mode); }, function() {});
});
</script>
</body></html>

@ -28,27 +28,30 @@
<div id="mqtt-spinner" class="spinner spinner-small"></div> <div id="mqtt-spinner" class="spinner spinner-small"></div>
</h1> </h1>
<form action="#" id="mqtt-form" class="pure-form" hidden> <form action="#" id="mqtt-form" class="pure-form" hidden>
<div class="form-horizontal">
<input type="checkbox" name="mqtt-enable"/> <input type="checkbox" name="mqtt-enable"/>
<label>Enable MQTT client</label> <label>Enable MQTT client</label>
</div> <br>
<div class="form-horizontal">
<label>MQTT client state: </label> <label>MQTT client state: </label>
<b id="mqtt-state"></b> <b id="mqtt-state"></b>
</div>
<br> <br>
<legend>MQTT server settings</legend> <legend>MQTT server settings</legend>
<div class="pure-form-stacked"> <div class="pure-form-stacked">
<label>Server hostname/ip</label> <label>Server hostname or IP</label>
<input type="text" name="mqtt-host"/> <input type="text" name="mqtt-host"/>
<label>Server port/ip</label> <label>Server port</label>
<input type="text" name="mqtt-port"/> <input type="text" name="mqtt-port"/>
<label>Client Timeout</label>
<input type="text" name="mqtt-timeout" />
<label>Client ID</label> <label>Client ID</label>
<input type="text" name="mqtt-client-id"/> <input type="text" name="mqtt-client-id"/>
<label>Username</label> <label>Username</label>
<input type="text" name="mqtt-username"/> <input type="text" name="mqtt-username"/>
<label>Password</label> <label>Password</label>
<input type="password" name="mqtt-password"/> <input type="password" name="mqtt-password"/>
<label>Keep Alive Interval (seconds)</label>
<input type="text" name="mqtt-keepalive" />
<input type="checkbox" name="mqtt-clean-session" />
<label>Clean Session?</label>
</div> </div>
<button id="mqtt-button" type="submit" class="pure-button button-primary"> <button id="mqtt-button" type="submit" class="pure-button button-primary">
Update server settings! Update server settings!

File diff suppressed because it is too large Load Diff

@ -7,6 +7,11 @@ input[type="text"], input[type="password"] {
width: 100%; width: 100%;
} }
input[type=checkbox] {
float: left;
margin: .35em 0.4em;
}
body { body {
color: #777; color: #777;
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

@ -1 +1,84 @@
<!DOCTYPE html><script src='http://linux-ws/esplink/wifi/wifi.js'></script> <div id="main">
<div class="header">
<h1>Wifi Configuration</h1>
</div>
<div class="content">
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2"><div class="card">
<h1>Wifi State</h1>
<div id="wifi-spinner" class="spinner spinner-small"></div>
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>Wifi channel</td><td id="wifi-chan"></td></tr>
<tr><td>Configured network</td><td id="wifi-ssid"></td></tr>
<tr><td>Wifi status</td><td id="wifi-status"></td></tr>
<tr><td>Wifi address</td><td id="wifi-ip"></td></tr>
<tr><td>Wifi rssi</td><td id="wifi-rssi"></td></tr>
<tr><td>Wifi phy</td><td id="wifi-phy"></td></tr>
<tr><td>Wifi MAC</td><td id="wifi-mac"></td></tr>
<tr><td colspan="2" id="wifi-warn"></td></tr>
</tbody> </table>
</div></div>
<div class="pure-u-1 pure-u-md-1-2"><div class="card">
<h1>Wifi Association</h1>
<p id="reconnect" style="color: #600" hidden></p>
<form action="#" id="wifiform" class="pure-form pure-form-stacked">
<legend>To connect to a WiFi network, please select one of the detected networks,
enter the password, and hit the connect button...</legend>
<label>Network SSID</label>
<div id="aps">Scanning... <div class="spinner spinner-small"></div></div>
<label>WiFi password, if applicable:</label>
<input id="wifi-passwd" type="password" name="passwd" placeholder="password">
<button id="connect-button" type="submit" class="pure-button button-primary">Connect!</button>
</form>
</div></div>
</div>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2"><div class="card">
<h1>Special Settings</h1>
<form action="#" id="specform" class="pure-form">
<legend>Special settings, use with care!</legend>
<div class="form-horizontal">
<label for="dhcp-ron" style="margin-right:1em">
<input type="radio" name="dhcp" value="on" id="dhcp-ron"/>
DHCP</label>
<label for="dhcp-roff">
<input type="radio" name="dhcp" value="off" id="dhcp-roff"/>
Static IP</label>
</div>
<div id="dhcp-on" class="pure-form-stacked">
<label>Hostname when requesting DHCP lease</label>
<input id="wifi-hostname" type="text" name="hostname"/>
</div>
<div id="dhcp-off" class="pure-form-stacked">
<label>Static IP address</label>
<input id="wifi-staticip" type="text" name="staticip"/>
<label>Netmask (for static IP)</label>
<input id="wifi-netmask" type="text" name="netmask"/>
<label>Gateway (for static IP)</label>
<input id="wifi-gateway" type="text" name="gateway"/>
</div>
<button id="special-button" type="submit"
class="pure-button button-primary">Change!</button>
</form>
</div></div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
</script>
<script src="wifi.js"></script>
<script type="text/javascript">
onLoad(function() {
getWifiInfo();
bnd($("#wifiform"), "submit", changeWifiAp);
bnd($("#specform"), "submit", changeSpecial);
bnd($("#dhcp-ron"), "click", doDhcp);
bnd($("#dhcp-roff"), "click", doStatic);
scanTimeout = window.setTimeout(scanAPs, 500);
});
</script>
</body></html>

@ -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('<label for=\"opt-' + ap.essid + '"></label>').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<e.length; i++) {
if (e[i].type == "radio" && e[i].checked) return e[i].value;
}
return currAp;
}
var scanTimeout = null;
var scanReqCnt = 0;
function scanResult() {
if (scanReqCnt > 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.result.APs.length; i++) {
if (data.result.APs[i].essid == "" && data.result.APs[i].rssi == 0) continue;
$("#aps").appendChild(createInputForAp(data.result.APs[i]));
n = n+1;
}
showNotification("Scan found " + n + " networks");
var cb = $("#connect-button");
cb.className = cb.className.replace(" pure-button-disabled", "");
if (scanTimeout != null) clearTimeout(scanTimeout);
scanTimeout = window.setTimeout(scanAPs, 20000);
} else {
window.setTimeout(scanResult, 1000);
}
}, function(s, st) {
window.setTimeout(scanResult, 5000);
});
}
function scanAPs() {
console.log("scanning now");
if (blockScan) {
scanTimeout = window.setTimeout(scanAPs, 1000);
return;
}
scanTimeout = null;
scanReqCnt = 0;
ajaxReq('POST', "scan", function(data) {
//showNotification("Wifi scan started");
window.setTimeout(scanResult, 1000);
}, function(s, st) {
//showNotification("Wifi scan may have started?");
window.setTimeout(scanResult, 1000);
});
}
function getStatus() {
ajaxJsonSpin("GET", "connstatus", function(data) {
if (data.status == "idle" || data.status == "connecting") {
$("#aps").innerHTML = "Connecting...";
showNotification("Connecting...");
window.setTimeout(getStatus, 1000);
} else if (data.status == "got IP address") {
var txt = "Connected! Got IP "+data.ip;
showNotification(txt);
showWifiInfo(data);
blockScan = 0;
if (data.modechange == "yes") {
var txt2 = "esp-link will switch to STA-only mode in a few seconds";
window.setTimeout(function() { showNotification(txt2); }, 4000);
}
$("#reconnect").removeAttribute("hidden");
$("#reconnect").innerHTML =
"If you are in the same network, go to <a href=\"http://"+data.ip+
"/\">"+data.ip+"</a>, else connect to network "+data.ssid+" first.";
} else {
blockScan = 0;
showWarning("Connection failed: " + data.status + ", " + data.reason);
$("#aps").innerHTML =
"Check password and selected AP. <a href=\"wifi.tpl\">Go Back</a>";
}
}, 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', '');
}

@ -3,15 +3,15 @@ Esp8266 http server - core routines
*/ */
/* /*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42): * "THE BEER-WARE LICENSE" (Revision 42):
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain * Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
* this notice you can do whatever you want with this stuff. If we meet some day, * 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. * 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 * Modified and enhanced by Thorsten von Eicken in 2015
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
*/ */
#include <esp8266.h> #include <esp8266.h>
@ -56,29 +56,29 @@ typedef struct {
//The mappings from file extensions to mime types. If you need an extra mime type, //The mappings from file extensions to mime types. If you need an extra mime type,
//add it here. //add it here.
static const MimeMap mimeTypes[]={ static const MimeMap mimeTypes[] = {
{"htm", "text/htm"}, { "htm", "text/htm" },
{"html", "text/html; charset=UTF-8"}, { "html", "text/html; charset=UTF-8" },
{"css", "text/css"}, { "css", "text/css" },
{"js", "text/javascript"}, { "js", "text/javascript" },
{"txt", "text/plain"}, { "txt", "text/plain" },
{"jpg", "image/jpeg"}, { "jpg", "image/jpeg" },
{"jpeg", "image/jpeg"}, { "jpeg", "image/jpeg" },
{"png", "image/png"}, { "png", "image/png" },
{"tpl", "text/html; charset=UTF-8"}, { "tpl", "text/html; charset=UTF-8" },
{NULL, "text/html"}, //default value { NULL, "text/html" }, //default value
}; };
//Returns a static char* to a mime type for a given url to a file. //Returns a static char* to a mime type for a given url to a file.
const char ICACHE_FLASH_ATTR *httpdGetMimetype(char *url) { const char ICACHE_FLASH_ATTR *httpdGetMimetype(char *url) {
int i=0; int i = 0;
//Go find the extension //Go find the extension
char *ext=url+(strlen(url)-1); char *ext = url + (strlen(url) - 1);
while (ext!=url && *ext!='.') ext--; while (ext != url && *ext != '.') ext--;
if (*ext=='.') ext++; if (*ext == '.') ext++;
//ToDo: os_strcmp is case sensitive; we may want to do case-intensive matching here... //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++; while (mimeTypes[i].ext != NULL && os_strcmp(ext, mimeTypes[i].ext) != 0) i++;
return mimeTypes[i].mimetype; return mimeTypes[i].mimetype;
} }
@ -98,21 +98,25 @@ static void debugConn(void *arg, char *what) {
//Looks up the connData info for a specific esp connection //Looks up the connData info for a specific esp connection
static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) { static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) {
struct espconn *espconn = arg; struct espconn *espconn = arg;
for (int i=0; i<MAX_CONN; i++) { for (int i = 0; i<MAX_CONN; i++) {
if (connData[i].remote_port == espconn->proto.tcp->remote_port && if (connData[i].remote_port == espconn->proto.tcp->remote_port &&
os_memcmp(connData[i].remote_ip, espconn->proto.tcp->remote_ip, 4) == 0) os_memcmp(connData[i].remote_ip, espconn->proto.tcp->remote_ip, 4) == 0)
{ {
#if 0 #if 0
#ifdef HTTPD_DBG
os_printf("FindConn: 0x%p->0x%p", arg, &connData[i]); os_printf("FindConn: 0x%p->0x%p", arg, &connData[i]);
if (arg == connData[i].conn) os_printf("\n"); if (arg == connData[i].conn) os_printf("\n");
else os_printf(" *** was 0x%p\n", connData[i].conn); else os_printf(" *** was 0x%p\n", connData[i].conn);
#endif
#endif #endif
if (arg != connData[i].conn) connData[i].conn = arg; // yes, this happens!? if (arg != connData[i].conn) connData[i].conn = arg; // yes, this happens!?
return &connData[i]; return &connData[i];
} }
} }
//Shouldn't happen. //Shouldn't happen.
#ifdef HTTPD_DBG
os_printf("%s *** Unknown connection 0x%p\n", connStr, arg); os_printf("%s *** Unknown connection 0x%p\n", connStr, arg);
#endif
return NULL; return NULL;
} }
@ -123,22 +127,24 @@ static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) {
if (conn->post->buff != NULL) { if (conn->post->buff != NULL) {
os_free(conn->post->buff); os_free(conn->post->buff);
} }
conn->cgi=NULL; conn->cgi = NULL;
conn->post->buff=NULL; conn->post->buff = NULL;
conn->remote_port = 0; conn->remote_port = 0;
conn->remote_ip[0] = 0; conn->remote_ip[0] = 0;
uint32 dt = conn->startTime; uint32 dt = conn->startTime;
if (dt > 0) dt = (system_get_time() - dt)/1000; if (dt > 0) dt = (system_get_time() - dt) / 1000;
#ifdef HTTPD_DBG
os_printf("%s Closed, %ums, heap=%ld\n", connStr, dt, os_printf("%s Closed, %ums, heap=%ld\n", connStr, dt,
(unsigned long)system_get_free_heap_size()); (unsigned long)system_get_free_heap_size());
#endif
} }
//Stupid li'l helper function that returns the value of a hex char. //Stupid li'l helper function that returns the value of a hex char.
static int httpdHexVal(char c) { static int httpdHexVal(char c) {
if (c>='0' && c<='9') return c-'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;
if (c>='a' && c<='f') return c-'a'+10; if (c >= 'a' && c <= 'f') return c - 'a' + 10;
return 0; return 0;
} }
@ -147,26 +153,30 @@ static int httpdHexVal(char c) {
//are stored in the ret buffer. Returns the actual amount of bytes used in ret. Also //are stored in the ret buffer. Returns the actual amount of bytes used in ret. Also
//zero-terminates the ret buffer. //zero-terminates the ret buffer.
int httpdUrlDecode(char *val, int valLen, char *ret, int retLen) { int httpdUrlDecode(char *val, int valLen, char *ret, int retLen) {
int s=0, d=0; int s = 0, d = 0;
int esced=0, escVal=0; int esced = 0, escVal = 0;
while (s<valLen && d<retLen) { while (s<valLen && d<retLen) {
if (esced==1) { if (esced == 1) {
escVal=httpdHexVal(val[s])<<4; escVal = httpdHexVal(val[s]) << 4;
esced=2; esced = 2;
} else if (esced==2) { }
escVal+=httpdHexVal(val[s]); else if (esced == 2) {
ret[d++]=escVal; escVal += httpdHexVal(val[s]);
esced=0; ret[d++] = escVal;
} else if (val[s]=='%') { esced = 0;
esced=1; }
} else if (val[s]=='+') { else if (val[s] == '%') {
ret[d++]=' '; esced = 1;
} else { }
ret[d++]=val[s]; else if (val[s] == '+') {
ret[d++] = ' ';
}
else {
ret[d++] = val[s];
} }
s++; s++;
} }
if (d<retLen) ret[d]=0; if (d<retLen) ret[d] = 0;
return d; return d;
} }
@ -177,19 +187,19 @@ int httpdUrlDecode(char *val, int valLen, char *ret, int retLen) {
//returned string will be urldecoded already. //returned string will be urldecoded already.
int ICACHE_FLASH_ATTR httpdFindArg(char *line, char *arg, char *buff, int buffLen) { int ICACHE_FLASH_ATTR httpdFindArg(char *line, char *arg, char *buff, int buffLen) {
char *p, *e; char *p, *e;
if (line==NULL) return 0; if (line == NULL) return 0;
p=line; p = line;
while(p!=NULL && *p!='\n' && *p!='\r' && *p!=0) { while (p != NULL && *p != '\n' && *p != '\r' && *p != 0) {
//os_printf("findArg: %s\n", p); //os_printf("findArg: %s\n", p);
if (os_strncmp(p, arg, os_strlen(arg))==0 && p[strlen(arg)]=='=') { if (os_strncmp(p, arg, os_strlen(arg)) == 0 && p[strlen(arg)] == '=') {
p+=os_strlen(arg)+1; //move p to start of value p += os_strlen(arg) + 1; //move p to start of value
e=(char*)os_strstr(p, "&"); e = (char*)os_strstr(p, "&");
if (e==NULL) e=p+os_strlen(p); if (e == NULL) e = p + os_strlen(p);
//os_printf("findArg: val %s len %d\n", p, (e-p)); //os_printf("findArg: val %s len %d\n", p, (e-p));
return httpdUrlDecode(p, (e-p), buff, buffLen); return httpdUrlDecode(p, (e - p), buff, buffLen);
} }
p=(char*)os_strstr(p, "&"); p = (char*)os_strstr(p, "&");
if (p!=NULL) p+=1; if (p != NULL) p += 1;
} }
//os_printf("Finding %s in %s: Not found :/\n", arg, line); //os_printf("Finding %s in %s: Not found :/\n", arg, line);
return -1; //not found return -1; //not found
@ -197,28 +207,28 @@ int ICACHE_FLASH_ATTR httpdFindArg(char *line, char *arg, char *buff, int buffLe
//Get the value of a certain header in the HTTP client head //Get the value of a certain header in the HTTP client head
int ICACHE_FLASH_ATTR httpdGetHeader(HttpdConnData *conn, char *header, char *ret, int retLen) { int ICACHE_FLASH_ATTR httpdGetHeader(HttpdConnData *conn, char *header, char *ret, int retLen) {
char *p=conn->priv->head; char *p = conn->priv->head;
p=p+strlen(p)+1; //skip GET/POST part p = p + strlen(p) + 1; //skip GET/POST part
p=p+strlen(p)+1; //skip HTTP part p = p + strlen(p) + 1; //skip HTTP part
while (p<(conn->priv->head+conn->priv->headPos)) { while (p<(conn->priv->head + conn->priv->headPos)) {
while(*p<=32 && *p!=0) p++; //skip crap at start while (*p <= 32 && *p != 0) p++; //skip crap at start
//See if this is the header //See if this is the header
if (os_strncmp(p, header, strlen(header))==0 && p[strlen(header)]==':') { if (os_strncmp(p, header, strlen(header)) == 0 && p[strlen(header)] == ':') {
//Skip 'key:' bit of header line //Skip 'key:' bit of header line
p=p+strlen(header)+1; p = p + strlen(header) + 1;
//Skip past spaces after the colon //Skip past spaces after the colon
while(*p==' ') p++; while (*p == ' ') p++;
//Copy from p to end //Copy from p to end
while (*p!=0 && *p!='\r' && *p!='\n' && retLen>1) { while (*p != 0 && *p != '\r' && *p != '\n' && retLen>1) {
*ret++=*p++; *ret++ = *p++;
retLen--; retLen--;
} }
//Zero-terminate string //Zero-terminate string
*ret=0; *ret = 0;
//All done :) //All done :)
return 1; return 1;
} }
p+=strlen(p)+1; //Skip past end of string and \0 terminator p += strlen(p) + 1; //Skip past end of string and \0 terminator
} }
return 0; return 0;
} }
@ -237,7 +247,7 @@ void ICACHE_FLASH_ATTR httpdHeader(HttpdConnData *conn, const char *field, const
char buff[256]; char buff[256];
int l; int l;
l=os_sprintf(buff, "%s: %s\r\n", field, val); l = os_sprintf(buff, "%s: %s\r\n", field, val);
httpdSend(conn, buff, l); httpdSend(conn, buff, l);
} }
@ -251,13 +261,13 @@ void ICACHE_FLASH_ATTR httpdEndHeaders(HttpdConnData *conn) {
void ICACHE_FLASH_ATTR httpdRedirect(HttpdConnData *conn, char *newUrl) { void ICACHE_FLASH_ATTR httpdRedirect(HttpdConnData *conn, char *newUrl) {
char buff[1024]; char buff[1024];
int l; 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); 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); httpdSend(conn, buff, l);
} }
//Use this as a cgi function to redirect one url to another. //Use this as a cgi function to redirect one url to another.
int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) { int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) {
if (connData->conn==NULL) { if (connData->conn == NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
@ -270,25 +280,29 @@ int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) {
//the data is seen as a C-string. //the data is seen as a C-string.
//Returns 1 for success, 0 for out-of-memory. //Returns 1 for success, 0 for out-of-memory.
int ICACHE_FLASH_ATTR httpdSend(HttpdConnData *conn, const char *data, int len) { int ICACHE_FLASH_ATTR httpdSend(HttpdConnData *conn, const char *data, int len) {
if (len<0) len=strlen(data); if (len<0) len = strlen(data);
if (conn->priv->sendBuffLen+len>MAX_SENDBUFF_LEN) { if (conn->priv->sendBuffLen + len>MAX_SENDBUFF_LEN) {
#ifdef HTTPD_DBG
os_printf("%s ERROR! httpdSend full (%d of %d)\n", os_printf("%s ERROR! httpdSend full (%d of %d)\n",
connStr, conn->priv->sendBuffLen, MAX_SENDBUFF_LEN); connStr, conn->priv->sendBuffLen, MAX_SENDBUFF_LEN);
#endif
return 0; return 0;
} }
os_memcpy(conn->priv->sendBuff+conn->priv->sendBuffLen, data, len); os_memcpy(conn->priv->sendBuff + conn->priv->sendBuffLen, data, len);
conn->priv->sendBuffLen+=len; conn->priv->sendBuffLen += len;
return 1; return 1;
} }
//Helper function to send any data in conn->priv->sendBuff //Helper function to send any data in conn->priv->sendBuff
static void ICACHE_FLASH_ATTR xmitSendBuff(HttpdConnData *conn) { static void ICACHE_FLASH_ATTR xmitSendBuff(HttpdConnData *conn) {
if (conn->priv->sendBuffLen!=0) { if (conn->priv->sendBuffLen != 0) {
sint8 status = espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen); sint8 status = espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen);
if (status != 0) { if (status != 0) {
#ifdef HTTPD_DBG
os_printf("%s ERROR! espconn_sent returned %d\n", connStr, status); os_printf("%s ERROR! espconn_sent returned %d\n", connStr, status);
#endif
} }
conn->priv->sendBuffLen=0; conn->priv->sendBuffLen = 0;
} }
} }
@ -296,31 +310,33 @@ static void ICACHE_FLASH_ATTR xmitSendBuff(HttpdConnData *conn) {
static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) { static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) {
debugConn(arg, "httpdSentCb"); debugConn(arg, "httpdSentCb");
int r; int r;
HttpdConnData *conn=httpdFindConnData(arg); HttpdConnData *conn = httpdFindConnData(arg);
char sendBuff[MAX_SENDBUFF_LEN]; char sendBuff[MAX_SENDBUFF_LEN];
if (conn==NULL) return; if (conn == NULL) return;
conn->priv->sendBuff=sendBuff; conn->priv->sendBuff = sendBuff;
conn->priv->sendBuffLen=0; conn->priv->sendBuffLen = 0;
if (conn->cgi==NULL) { //Marked for destruction? if (conn->cgi == NULL) { //Marked for destruction?
//os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn); //os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn);
espconn_disconnect(conn->conn); // we will get a disconnect callback espconn_disconnect(conn->conn); // we will get a disconnect callback
return; //No need to call xmitSendBuff. return; //No need to call xmitSendBuff.
} }
r=conn->cgi(conn); //Execute cgi fn. r = conn->cgi(conn); //Execute cgi fn.
if (r==HTTPD_CGI_DONE) { if (r == HTTPD_CGI_DONE) {
conn->cgi=NULL; //mark for destruction. conn->cgi = NULL; //mark for destruction.
} }
if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { if (r == HTTPD_CGI_NOTFOUND || r == HTTPD_CGI_AUTHENTICATED) {
#ifdef HTTPD_DBG
os_printf("%s ERROR! Bad CGI code %d\n", connStr, r); os_printf("%s ERROR! Bad CGI code %d\n", connStr, r);
conn->cgi=NULL; //mark for destruction. #endif
conn->cgi = NULL; //mark for destruction.
} }
xmitSendBuff(conn); 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 //This is called when the headers have been received and the connection is ready to send
//the result headers and data. //the result headers and data.
@ -328,53 +344,59 @@ static const char *httpNotFoundHeader="HTTP/1.0 404 Not Found\r\nConnection: clo
//find the next cgi function, wait till the cgi data is sent or close up the connection. //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) { static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) {
int r; int r;
int i=0; int i = 0;
if (conn->url==NULL) { if (conn->url == NULL) {
#ifdef HTTPD_DBG
os_printf("%s WtF? url = NULL\n", connStr); os_printf("%s WtF? url = NULL\n", connStr);
#endif
return; //Shouldn't happen return; //Shouldn't happen
} }
//See if we can find a CGI that's happy to handle the request. //See if we can find a CGI that's happy to handle the request.
while (1) { while (1) {
//Look up URL in the built-in URL table. //Look up URL in the built-in URL table.
while (builtInUrls[i].url!=NULL) { while (builtInUrls[i].url != NULL) {
int match=0; int match = 0;
//See if there's a literal match //See if there's a literal match
if (os_strcmp(builtInUrls[i].url, conn->url)==0) match=1; if (os_strcmp(builtInUrls[i].url, conn->url) == 0) match = 1;
//See if there's a wildcard match //See if there's a wildcard match
if (builtInUrls[i].url[os_strlen(builtInUrls[i].url)-1]=='*' && 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; os_strncmp(builtInUrls[i].url, conn->url, os_strlen(builtInUrls[i].url) - 1) == 0) match = 1;
if (match) { if (match) {
//os_printf("Is url index %d\n", i); //os_printf("Is url index %d\n", i);
conn->cgiData=NULL; conn->cgiData = NULL;
conn->cgi=builtInUrls[i].cgiCb; conn->cgi = builtInUrls[i].cgiCb;
conn->cgiArg=builtInUrls[i].cgiArg; conn->cgiArg = builtInUrls[i].cgiArg;
break; break;
} }
i++; i++;
} }
if (builtInUrls[i].url==NULL) { if (builtInUrls[i].url == NULL) {
//Drat, we're at the end of the URL table. This usually shouldn't happen. Well, just //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. //generate a built-in 404 to handle this.
#ifdef HTTPD_DBG
os_printf("%s %s not found. 404!\n", connStr, conn->url); os_printf("%s %s not found. 404!\n", connStr, conn->url);
#endif
httpdSend(conn, httpNotFoundHeader, -1); httpdSend(conn, httpNotFoundHeader, -1);
xmitSendBuff(conn); xmitSendBuff(conn);
conn->cgi=NULL; //mark for destruction conn->cgi = NULL; //mark for destruction
return; return;
} }
//Okay, we have a CGI function that matches the URL. See if it wants to handle the //Okay, we have a CGI function that matches the URL. See if it wants to handle the
//particular URL we're supposed to handle. //particular URL we're supposed to handle.
r=conn->cgi(conn); r = conn->cgi(conn);
if (r==HTTPD_CGI_MORE) { if (r == HTTPD_CGI_MORE) {
//Yep, it's happy to do so and has more data to send. //Yep, it's happy to do so and has more data to send.
xmitSendBuff(conn); xmitSendBuff(conn);
return; return;
} else if (r==HTTPD_CGI_DONE) { }
else if (r == HTTPD_CGI_DONE) {
//Yep, it's happy to do so and already is done sending data. //Yep, it's happy to do so and already is done sending data.
xmitSendBuff(conn); xmitSendBuff(conn);
conn->cgi=NULL; //mark conn for destruction conn->cgi = NULL; //mark conn for destruction
return; return;
} else if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { }
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 //URL doesn't want to handle the request: either the data isn't found or there's no
//need to generate a login screen. //need to generate a login screen.
i++; //look at next url the next iteration of the loop. i++; //look at next url the next iteration of the loop.
@ -387,10 +409,11 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
int i; int i;
char first_line = false; char first_line = false;
if (os_strncmp(h, "GET ", 4)==0) { if (os_strncmp(h, "GET ", 4) == 0) {
conn->requestType = HTTPD_METHOD_GET; conn->requestType = HTTPD_METHOD_GET;
first_line = true; first_line = true;
} else if (os_strncmp(h, "POST ", 5)==0) { }
else if (os_strncmp(h, "POST ", 5) == 0) {
conn->requestType = HTTPD_METHOD_POST; conn->requestType = HTTPD_METHOD_POST;
first_line = true; first_line = true;
} }
@ -399,49 +422,56 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
char *e; char *e;
//Skip past the space after POST/GET //Skip past the space after POST/GET
i=0; i = 0;
while (h[i]!=' ') i++; while (h[i] != ' ') i++;
conn->url=h+i+1; conn->url = h + i + 1;
//Figure out end of url. //Figure out end of url.
e=(char*)os_strstr(conn->url, " "); e = (char*)os_strstr(conn->url, " ");
if (e==NULL) return; //wtf? if (e == NULL) return; //wtf?
*e=0; //terminate url part *e = 0; //terminate url part
// Count number of open connections // Count number of open connections
int open = 0; int open = 0;
for (int j=0; j<MAX_CONN; j++) if (connData[j].conn != NULL) open++; for (int j = 0; j<MAX_CONN; j++) if (connData[j].conn != NULL) open++;
#ifdef HTTPD_DBG
os_printf("%s %s %s (%d conn open)\n", connStr, os_printf("%s %s %s (%d conn open)\n", connStr,
conn->requestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url, open); conn->requestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url, open);
#endif
//Parse out the URL part before the GET parameters. //Parse out the URL part before the GET parameters.
conn->getArgs=(char*)os_strstr(conn->url, "?"); conn->getArgs = (char*)os_strstr(conn->url, "?");
if (conn->getArgs!=0) { if (conn->getArgs != 0) {
*conn->getArgs=0; *conn->getArgs = 0;
conn->getArgs++; conn->getArgs++;
#ifdef HTTPD_DBG
os_printf("%s args = %s\n", connStr, conn->getArgs); os_printf("%s args = %s\n", connStr, conn->getArgs);
} else { #endif
conn->getArgs=NULL; }
else {
conn->getArgs = NULL;
} }
} else if (os_strncmp(h, "Content-Length:", 15)==0) { }
i=15; else if (os_strncmp(h, "Content-Length:", 15) == 0) {
i = 15;
//Skip trailing spaces //Skip trailing spaces
while (h[i]==' ') i++; while (h[i] == ' ') i++;
//Get POST data length //Get POST data length
conn->post->len=atoi(h+i); conn->post->len = atoi(h + i);
// Allocate the buffer // Allocate the buffer
if (conn->post->len > MAX_POST) { if (conn->post->len > MAX_POST) {
// we'll stream this in in chunks // we'll stream this in in chunks
conn->post->buffSize = MAX_POST; conn->post->buffSize = MAX_POST;
} else { }
else {
conn->post->buffSize = conn->post->len; conn->post->buffSize = conn->post->len;
} }
//os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); //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->buff = (char*)os_malloc(conn->post->buffSize + 1);
conn->post->buffLen=0; conn->post->buffLen = 0;
} else if (os_strncmp(h, "Content-Type: ", 14)==0) { }
else if (os_strncmp(h, "Content-Type: ", 14) == 0) {
if (os_strstr(h, "multipart/form-data")) { if (os_strstr(h, "multipart/form-data")) {
// It's multipart form data so let's pull out the boundary for future use // It's multipart form data so let's pull out the boundary for future use
char *b; char *b;
@ -462,10 +492,10 @@ static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short
int x; int x;
char *p, *e; char *p, *e;
char sendBuff[MAX_SENDBUFF_LEN]; char sendBuff[MAX_SENDBUFF_LEN];
HttpdConnData *conn=httpdFindConnData(arg); HttpdConnData *conn = httpdFindConnData(arg);
if (conn==NULL) return; if (conn == NULL) return;
conn->priv->sendBuff=sendBuff; conn->priv->sendBuff = sendBuff;
conn->priv->sendBuffLen=0; 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: //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 (-1): Post len unknown because we're still receiving headers
@ -473,38 +503,39 @@ static void ICACHE_FLASH_ATTR httpdRecvCb(void *arg, char *data, unsigned short
//>0: Need to receive post data //>0: Need to receive post data
//ToDo: See if we can use something more elegant for this. //ToDo: See if we can use something more elegant for this.
for (x=0; x<len; x++) { for (x = 0; x<len; x++) {
if (conn->post->len<0) { if (conn->post->len<0) {
//This byte is a header byte. //This byte is a header byte.
if (conn->priv->headPos!=MAX_HEAD_LEN) conn->priv->head[conn->priv->headPos++]=data[x]; if (conn->priv->headPos != MAX_HEAD_LEN) conn->priv->head[conn->priv->headPos++] = data[x];
conn->priv->head[conn->priv->headPos]=0; conn->priv->head[conn->priv->headPos] = 0;
//Scan for /r/n/r/n. Receiving this indicate the headers end. //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) { if (data[x] == '\n' && (char *)os_strstr(conn->priv->head, "\r\n\r\n") != NULL) {
//Indicate we're done with the headers. //Indicate we're done with the headers.
conn->post->len=0; conn->post->len = 0;
//Reset url data //Reset url data
conn->url=NULL; conn->url = NULL;
//Iterate over all received headers and parse them. //Iterate over all received headers and parse them.
p=conn->priv->head; p = conn->priv->head;
while(p<(&conn->priv->head[conn->priv->headPos-4])) { while (p<(&conn->priv->head[conn->priv->headPos - 4])) {
e=(char *)os_strstr(p, "\r\n"); //Find end of header line e = (char *)os_strstr(p, "\r\n"); //Find end of header line
if (e==NULL) break; //Shouldn't happen. if (e == NULL) break; //Shouldn't happen.
e[0]=0; //Zero-terminate header e[0] = 0; //Zero-terminate header
httpdParseHeader(p, conn); //and parse it. httpdParseHeader(p, conn); //and parse it.
p=e+2; //Skip /r/n (now /0/n) 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 we don't need to receive post data, we can send the response now.
if (conn->post->len==0) { if (conn->post->len == 0) {
httpdProcessRequest(conn); httpdProcessRequest(conn);
} }
} }
} else if (conn->post->len!=0) { }
else if (conn->post->len != 0) {
//This byte is a POST byte. //This byte is a POST byte.
conn->post->buff[conn->post->buffLen++]=data[x]; conn->post->buff[conn->post->buffLen++] = data[x];
conn->post->received++; conn->post->received++;
if (conn->post->buffLen >= conn->post->buffSize || conn->post->received == conn->post->len) { if (conn->post->buffLen >= conn->post->buffSize || conn->post->received == conn->post->len) {
//Received a chunk of post data //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 conn->post->buff[conn->post->buffLen] = 0; //zero-terminate, in case the cgi handler knows it can use strings
//Send the response. //Send the response.
httpdProcessRequest(conn); httpdProcessRequest(conn);
conn->post->buffLen = 0; conn->post->buffLen = 0;
@ -525,7 +556,9 @@ static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) {
static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) { static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) {
debugConn(arg, "httpdReconCb"); debugConn(arg, "httpdReconCb");
HttpdConnData *conn = httpdFindConnData(arg); HttpdConnData *conn = httpdFindConnData(arg);
#ifdef HTTPD_DBG
os_printf("%s ***** reset, err=%d\n", connStr, err); os_printf("%s ***** reset, err=%d\n", connStr, err);
#endif
if (conn == NULL) return; if (conn == NULL) return;
httpdRetireConn(conn); httpdRetireConn(conn);
} }
@ -533,33 +566,37 @@ static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) {
static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) { static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) {
debugConn(arg, "httpdConnectCb"); debugConn(arg, "httpdConnectCb");
struct espconn *conn=arg; struct espconn *conn = arg;
int i; int i;
//Find empty conndata in pool //Find empty conndata in pool
for (i=0; i<MAX_CONN; i++) if (connData[i].conn==NULL) break; for (i = 0; i<MAX_CONN; i++) if (connData[i].conn == NULL) break;
//os_printf("Con req, conn=%p, pool slot %d\n", conn, i); //os_printf("Con req, conn=%p, pool slot %d\n", conn, i);
if (i==MAX_CONN) { if (i == MAX_CONN) {
#ifdef HTTPD_DBG
os_printf("%s Aiee, conn pool overflow!\n", connStr); os_printf("%s Aiee, conn pool overflow!\n", connStr);
#endif
espconn_disconnect(conn); espconn_disconnect(conn);
return; return;
} }
#if 0 #if 0
int num = 0; int num = 0;
for (int j=0; j<MAX_CONN; j++) if (connData[j].conn != NULL) num++; for (int j = 0; j<MAX_CONN; j++) if (connData[j].conn != NULL) num++;
os_printf("%s Connect (%d open)\n", connStr, num+1); #ifdef HTTPD_DBG
os_printf("%s Connect (%d open)\n", connStr, num + 1);
#endif
#endif #endif
connData[i].priv=&connPrivData[i]; connData[i].priv = &connPrivData[i];
connData[i].conn=conn; connData[i].conn = conn;
connData[i].remote_port = conn->proto.tcp->remote_port; connData[i].remote_port = conn->proto.tcp->remote_port;
os_memcpy(connData[i].remote_ip, conn->proto.tcp->remote_ip, 4); os_memcpy(connData[i].remote_ip, conn->proto.tcp->remote_ip, 4);
connData[i].priv->headPos=0; connData[i].priv->headPos = 0;
connData[i].post=&connPostData[i]; connData[i].post = &connPostData[i];
connData[i].post->buff=NULL; connData[i].post->buff = NULL;
connData[i].post->buffLen=0; connData[i].post->buffLen = 0;
connData[i].post->received=0; connData[i].post->received = 0;
connData[i].post->len=-1; connData[i].post->len = -1;
connData[i].startTime = system_get_time(); connData[i].startTime = system_get_time();
espconn_regist_recvcb(conn, httpdRecvCb); espconn_regist_recvcb(conn, httpdRecvCb);
@ -567,23 +604,24 @@ static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) {
espconn_regist_disconcb(conn, httpdDisconCb); espconn_regist_disconcb(conn, httpdDisconCb);
espconn_regist_sentcb(conn, httpdSentCb); espconn_regist_sentcb(conn, httpdSentCb);
espconn_set_opt(conn, ESPCONN_REUSEADDR|ESPCONN_NODELAY); espconn_set_opt(conn, ESPCONN_REUSEADDR | ESPCONN_NODELAY);
} }
//Httpd initialization routine. Call this to kick off webserver functionality. //Httpd initialization routine. Call this to kick off webserver functionality.
void ICACHE_FLASH_ATTR httpdInit(HttpdBuiltInUrl *fixedUrls, int port) { void ICACHE_FLASH_ATTR httpdInit(HttpdBuiltInUrl *fixedUrls, int port) {
int i; int i;
for (i=0; i<MAX_CONN; i++) { for (i = 0; i<MAX_CONN; i++) {
connData[i].conn=NULL; connData[i].conn = NULL;
} }
httpdConn.type=ESPCONN_TCP; httpdConn.type = ESPCONN_TCP;
httpdConn.state=ESPCONN_NONE; httpdConn.state = ESPCONN_NONE;
httpdTcp.local_port=port; httpdTcp.local_port = port;
httpdConn.proto.tcp=&httpdTcp; httpdConn.proto.tcp = &httpdTcp;
builtInUrls=fixedUrls; builtInUrls = fixedUrls;
#ifdef HTTPD_DBG
os_printf("Httpd init, conn=%p\n", &httpdConn); os_printf("Httpd init, conn=%p\n", &httpdConn);
#endif
espconn_regist_connectcb(&httpdConn, httpdConnectCb); espconn_regist_connectcb(&httpdConn, httpdConnectCb);
espconn_accept(&httpdConn); espconn_accept(&httpdConn);
espconn_tcp_set_max_con_allow(&httpdConn, MAX_CONN); espconn_tcp_set_max_con_allow(&httpdConn, MAX_CONN);

@ -4,30 +4,32 @@
#ifdef __WIN32__ #ifdef __WIN32__
#include <_mingw.h> #include <_mingw.h>
#endif #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 CMD_DBG
#define MQTT_PORT 1883 #define ESPFS_DBG
#define MQTT_SECURITY 0 #define CGI_DBG
#define CGIFLASH_DBG
#define MQTT_CLIENT_ID system_get_chip_id_str() // "esp-link" #define CGIMQTT_DBG
#define MQTT_USER "" #define CGIPINS_DBG
#define MQTT_PASS "" #define CGIWIFI_DBG
#define MQTT_KEEPALIVE 120 // seconds #define CONFIG_DBG
#define MQTT_CLSESSION true #define LOG_DBG
#define STATUS_DBG
#define PROTOCOL_NAMEv31 // MQTT version 3.1 compatible with Mosquitto v0.15/ #define HTTPD_DBG
//PROTOCOL_NAMEv311 // MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/ #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 char* esp_link_version;
extern uint8_t UTILS_StrToIP(const char* str, void *ip); 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 #endif

@ -57,10 +57,12 @@ sint8 espconn_secure_sent(struct espconn *espconn, uint8 *psent, uint16 length)
// max message size for sending (except publish) // max message size for sending (except publish)
#define MQTT_MAX_SHORT_MESSAGE 128 #define MQTT_MAX_SHORT_MESSAGE 128
#ifdef MQTT_DBG
static char* mqtt_msg_type[] = { static char* mqtt_msg_type[] = {
"NULL", "TYPE_CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP", "NULL", "TYPE_CONNECT", "CONNACK", "PUBLISH", "PUBACK", "PUBREC", "PUBREL", "PUBCOMP",
"SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", "DISCONNECT", "RESV", "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", "PINGREQ", "PINGRESP", "DISCONNECT", "RESV",
}; };
#endif
// forward declarations // forward declarations
static void mqtt_enq_message(MQTT_Client *client, const uint8_t *data, uint16_t len); 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) { if (msg_len > client->in_buffer_size) {
// oops, too long a message for us to digest, disconnect and hope for a miracle // 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); os_printf("MQTT: Too long a message (%d bytes)\n", msg_len);
#endif
mqtt_doAbort(client); mqtt_doAbort(client);
return; return;
} }
@ -135,7 +139,9 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) {
if (client->connState != MQTT_CONNECTED) { if (client->connState != MQTT_CONNECTED) {
// why are we receiving something?? // why are we receiving something??
#ifdef MQTT_DBG
os_printf("MQTT ERROR: recv in invalid state %d\n", client->connState); os_printf("MQTT ERROR: recv in invalid state %d\n", client->connState);
#endif
mqtt_doAbort(client); mqtt_doAbort(client);
return; 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_type = mqtt_get_type(client->pending_buffer->data);
pending_msg_id = mqtt_get_id(client->pending_buffer->data, client->pending_buffer->filled); 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", 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); mqtt_msg_type[msg_type], msg_id, msg_len, mqtt_msg_type[pending_msg_type], pending_msg_id);
#endif
switch (msg_type) { switch (msg_type) {
case MQTT_MSG_TYPE_CONNACK: case MQTT_MSG_TYPE_CONNACK:
#ifdef MQTT_DBG
os_printf("MQTT: Connect successful\n"); os_printf("MQTT: Connect successful\n");
#endif
// callbacks for internal and external clients // callbacks for internal and external clients
if (client->connectedCb) client->connectedCb((uint32_t*)client); if (client->connectedCb) client->connectedCb((uint32_t*)client);
if (client->cmdConnectedCb) client->cmdConnectedCb((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: case MQTT_MSG_TYPE_SUBACK:
if (pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && pending_msg_id == msg_id) { if (pending_msg_type == MQTT_MSG_TYPE_SUBSCRIBE && pending_msg_id == msg_id) {
#ifdef MQTT_DBG
os_printf("MQTT: Subscribe successful\n"); os_printf("MQTT: Subscribe successful\n");
#endif
client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer);
} }
break; break;
case MQTT_MSG_TYPE_UNSUBACK: case MQTT_MSG_TYPE_UNSUBACK:
if (pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && pending_msg_id == msg_id) { if (pending_msg_type == MQTT_MSG_TYPE_UNSUBSCRIBE && pending_msg_id == msg_id) {
#ifdef MQTT_DBG
os_printf("MQTT: Unsubscribe successful\n"); os_printf("MQTT: Unsubscribe successful\n");
#endif
client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer);
} }
break; break;
case MQTT_MSG_TYPE_PUBACK: // ack for a publish we sent case MQTT_MSG_TYPE_PUBACK: // ack for a publish we sent
if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) { if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) {
#ifdef MQTT_DBG
os_printf("MQTT: QoS1 Publish successful\n"); os_printf("MQTT: QoS1 Publish successful\n");
#endif
client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer);
} }
break; break;
case MQTT_MSG_TYPE_PUBREC: // rec for a publish we sent case MQTT_MSG_TYPE_PUBREC: // rec for a publish we sent
if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) { if (pending_msg_type == MQTT_MSG_TYPE_PUBLISH && pending_msg_id == msg_id) {
#ifdef MQTT_DBG
os_printf("MQTT: QoS2 publish cont\n"); os_printf("MQTT: QoS2 publish cont\n");
#endif
client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer);
// we need to send PUBREL // we need to send PUBREL
mqtt_msg_pubrel(&client->mqtt_connection, msg_id); 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) 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) { if (pending_msg_type == MQTT_MSG_TYPE_PUBREL && pending_msg_id == msg_id) {
#ifdef MQTT_DBG
os_printf("MQTT: QoS2 Publish successful\n"); os_printf("MQTT: QoS2 Publish successful\n");
#endif
client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer);
} }
break; break;
@ -201,9 +220,11 @@ mqtt_tcpclient_recv(void* arg, char* pdata, unsigned short len) {
case MQTT_MSG_TYPE_PUBLISH: { // incoming publish case MQTT_MSG_TYPE_PUBLISH: { // incoming publish
// we may need to ACK the publish // we may need to ACK the publish
uint8_t msg_qos = mqtt_get_qos(client->in_buffer); uint8_t msg_qos = mqtt_get_qos(client->in_buffer);
#ifdef MQTT_DBG
uint16_t topic_length = msg_len; uint16_t topic_length = msg_len;
os_printf("MQTT: Recv PUBLISH qos=%d %s\n", msg_qos, os_printf("MQTT: Recv PUBLISH qos=%d %s\n", msg_qos,
mqtt_get_publish_topic(client->in_buffer, &topic_length)); 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 == 1) mqtt_msg_puback(&client->mqtt_connection, msg_id);
if (msg_qos == 2) mqtt_msg_pubrec(&client->mqtt_connection, msg_id); if (msg_qos == 2) mqtt_msg_pubrec(&client->mqtt_connection, msg_id);
if (msg_qos == 1 || msg_qos == 2) { 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) 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) { if (pending_msg_type == MQTT_MSG_TYPE_PUBREC && pending_msg_id == msg_id) {
#ifdef MQTT_DBG
os_printf("MQTT: Cont QoS2 recv\n"); os_printf("MQTT: Cont QoS2 recv\n");
#endif
client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer); client->pending_buffer = PktBuf_ShiftFree(client->pending_buffer);
// we need to send PUBCOMP // we need to send PUBCOMP
mqtt_msg_pubcomp(&client->mqtt_connection, msg_id); mqtt_msg_pubcomp(&client->mqtt_connection, msg_id);
@ -294,7 +317,9 @@ mqtt_timer(void* arg) {
// check whether our last keep-alive timed out // check whether our last keep-alive timed out
if (client->keepAliveAckTick > 0 && --client->keepAliveAckTick == 0) { if (client->keepAliveAckTick > 0 && --client->keepAliveAckTick == 0) {
#ifdef MQTT_DBG
os_printf("\nMQTT ERROR: Keep-alive timed out\n"); os_printf("\nMQTT ERROR: Keep-alive timed out\n");
#endif
mqtt_doAbort(client); mqtt_doAbort(client);
return; return;
} }
@ -337,15 +362,17 @@ void ICACHE_FLASH_ATTR
mqtt_tcpclient_discon_cb(void* arg) { mqtt_tcpclient_discon_cb(void* arg) {
struct espconn* pespconn = (struct espconn *)arg; struct espconn* pespconn = (struct espconn *)arg;
MQTT_Client* client = (MQTT_Client *)pespconn->reverse; MQTT_Client* client = (MQTT_Client *)pespconn->reverse;
#ifdef MQTT_DBG
os_printf("MQTT: Disconnect CB, freeing espconn %p\n", arg); os_printf("MQTT: Disconnect CB, freeing espconn %p\n", arg);
#endif
if (pespconn->proto.tcp) os_free(pespconn->proto.tcp); if (pespconn->proto.tcp) os_free(pespconn->proto.tcp);
os_free(pespconn); os_free(pespconn);
// if this is an aborted connection we're done // if this is an aborted connection we're done
if (client == NULL) return; if (client == NULL) return;
#ifdef MQTT_DBG
os_printf("MQTT: Disconnected from %s:%d\n", client->host, client->port); os_printf("MQTT: Disconnected from %s:%d\n", client->host, client->port);
#endif
if (client->disconnectedCb) client->disconnectedCb((uint32_t*)client); if (client->disconnectedCb) client->disconnectedCb((uint32_t*)client);
if (client->cmdDisconnectedCb) client->cmdDisconnectedCb((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) { mqtt_tcpclient_recon_cb(void* arg, int8_t err) {
struct espconn* pespconn = (struct espconn *)arg; struct espconn* pespconn = (struct espconn *)arg;
MQTT_Client* client = (MQTT_Client *)pespconn->reverse; MQTT_Client* client = (MQTT_Client *)pespconn->reverse;
#ifdef MQTT_DBG
os_printf("MQTT: Reset CB, freeing espconn %p (err=%d)\n", arg, err); os_printf("MQTT: Reset CB, freeing espconn %p (err=%d)\n", arg, err);
#endif
if (pespconn->proto.tcp) os_free(pespconn->proto.tcp); if (pespconn->proto.tcp) os_free(pespconn->proto.tcp);
os_free(pespconn); os_free(pespconn);
#ifdef MQTT_DBG
os_printf("MQTT: Connection reset from %s:%d\n", client->host, client->port); os_printf("MQTT: Connection reset from %s:%d\n", client->host, client->port);
#endif
if (client->disconnectedCb) client->disconnectedCb((uint32_t*)client); if (client->disconnectedCb) client->disconnectedCb((uint32_t*)client);
if (client->cmdDisconnectedCb) client->cmdDisconnectedCb((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_disconcb(client->pCon, mqtt_tcpclient_discon_cb);
espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv); espconn_regist_recvcb(client->pCon, mqtt_tcpclient_recv);
espconn_regist_sentcb(client->pCon, mqtt_tcpclient_sent_cb); 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); os_printf("MQTT: TCP connected to %s:%d\n", client->host, client->port);
#endif
// send MQTT connect message to broker // send MQTT connect message to broker
mqtt_msg_connect(&client->mqtt_connection, &client->connect_info); 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 // get some details about the message
uint16_t msg_type = mqtt_get_type(buf->data); uint16_t msg_type = mqtt_get_type(buf->data);
uint8_t msg_id = mqtt_get_id(buf->data, buf->filled); 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); 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; i<buf->filled; i++) { for (int i=0; i<buf->filled; i++) {
if (buf->data[i] >= ' ' && buf->data[i] <= '~') os_printf("%c", buf->data[i]); if (buf->data[i] >= ' ' && buf->data[i] <= '~') os_printf("%c", buf->data[i]);
else os_printf("\\x%02X", 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; MQTT_Client* client = (MQTT_Client *)pConn->reverse;
if (ipaddr == NULL) { if (ipaddr == NULL) {
#ifdef MQTT_DBG
os_printf("MQTT DNS: Got no ip, try to reconnect\n"); os_printf("MQTT DNS: Got no ip, try to reconnect\n");
#endif
client->timeoutTick = 10; client->timeoutTick = 10;
client->connState = TCP_RECONNECT_REQ; // the timer will kick-off a reconnection client->connState = TCP_RECONNECT_REQ; // the timer will kick-off a reconnection
return; return;
} }
#ifdef MQTT_DBG
os_printf("MQTT DNS: found ip %d.%d.%d.%d\n", os_printf("MQTT DNS: found ip %d.%d.%d.%d\n",
*((uint8 *)&ipaddr->addr), *((uint8 *)&ipaddr->addr),
*((uint8 *)&ipaddr->addr + 1), *((uint8 *)&ipaddr->addr + 1),
*((uint8 *)&ipaddr->addr + 2), *((uint8 *)&ipaddr->addr + 2),
*((uint8 *)&ipaddr->addr + 3)); *((uint8 *)&ipaddr->addr + 3));
#endif
if (client->ip.addr == 0 && ipaddr->addr != 0) { if (client->ip.addr == 0 && ipaddr->addr != 0) {
os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); 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 else
err = espconn_connect(client->pCon); err = espconn_connect(client->pCon);
if (err != 0) { if (err != 0) {
#ifdef MQTT_DBG
os_printf("MQTT ERROR: Failed to connect\n"); os_printf("MQTT ERROR: Failed to connect\n");
#endif
client->connState = TCP_RECONNECT_REQ; client->connState = TCP_RECONNECT_REQ;
client->timeoutTick = 10; client->timeoutTick = 10;
} else { } else {
#ifdef MQTT_DBG
os_printf("MQTT: connecting...\n"); 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; uint16_t buf_len = 3 + 2 + 2 + topic_length + data_length + 16;
PktBuf *buf = PktBuf_New(buf_len); PktBuf *buf = PktBuf_New(buf_len);
if (buf == NULL) { if (buf == NULL) {
#ifdef MQTT_DBG
os_printf("MQTT ERROR: Cannot allocate buffer for %d byte publish\n", buf_len); os_printf("MQTT ERROR: Cannot allocate buffer for %d byte publish\n", buf_len);
#endif
return FALSE; return FALSE;
} }
// use a temporary mqtt_message_t pointing to our buffer, this is a bit of a mess because we // 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); msg_conn_init(&msg, &client->mqtt_connection, buf->data, buf_len);
uint16_t msg_id; uint16_t msg_id;
if (!mqtt_msg_publish(&msg, topic, data, data_length, qos, retain, &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"); os_printf("MQTT ERROR: Queuing Publish failed\n");
#endif
os_free(buf); os_free(buf);
return FALSE; return FALSE;
} }
client->mqtt_connection.message_id = msg.message_id; client->mqtt_connection.message_id = msg.message_id;
#ifdef MQTT_DBG
os_printf("MQTT: Publish, topic: \"%s\", length: %d\n", topic, msg.message.length); os_printf("MQTT: Publish, topic: \"%s\", length: %d\n", topic, msg.message.length);
#endif
client->msgQueue = PktBuf_Push(client->msgQueue, buf); client->msgQueue = PktBuf_Push(client->msgQueue, buf);
if (!client->sending && client->pending_buffer == NULL) { 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) { MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos) {
uint16_t msg_id; uint16_t msg_id;
if (!mqtt_msg_subscribe(&client->mqtt_connection, topic, 0, &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"); os_printf("MQTT ERROR: Queuing Subscribe failed (too long)\n");
#endif
return FALSE; return FALSE;
} }
#ifdef MQTT_DBG
os_printf("MQTT: Subscribe, topic: \"%s\"\n", topic); os_printf("MQTT: Subscribe, topic: \"%s\"\n", topic);
#endif
mqtt_enq_message(client, client->mqtt_connection.message.data, mqtt_enq_message(client, client->mqtt_connection.message.data,
client->mqtt_connection.message.length); client->mqtt_connection.message.length);
return TRUE; return TRUE;
@ -595,14 +643,20 @@ MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos) {
* @param client_user: MQTT client user * @param client_user: MQTT client user
* @param client_pass: MQTT client password * @param client_pass: MQTT client password
* @param keepAliveTime: MQTT keep alive timer, in second * @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 * @retval None
*/ */
void ICACHE_FLASH_ATTR void ICACHE_FLASH_ATTR
MQTT_Init(MQTT_Client* mqttClient, char* host, uint32 port, uint8_t security, uint8_t sendTimeout, MQTT_Init(MQTT_Client* mqttClient, char* host, uint32 port, uint8_t security, uint8_t sendTimeout,
char* client_id, char* client_user, char* client_pass, char* client_id, char* client_user, char* client_pass,
uint8_t keepAliveTime, uint8_t cleanSession) { uint8_t keepAliveTime, uint8_t cleanSession) {
#ifdef MQTT_DBG
os_printf("MQTT_Init\n"); os_printf("MQTT_Init\n");
#endif
os_memset(mqttClient, 0, sizeof(MQTT_Client)); os_memset(mqttClient, 0, sizeof(MQTT_Client));
@ -679,7 +733,9 @@ MQTT_Connect(MQTT_Client* mqttClient) {
os_timer_arm(&mqttClient->mqttTimer, 1000, 1); os_timer_arm(&mqttClient->mqttTimer, 1000, 1);
// initiate the TCP connection or DNS lookup // 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); os_printf("MQTT: Connect to %s:%d %p\n", mqttClient->host, mqttClient->port, mqttClient->pCon);
#endif
if (UTILS_StrToIP((const char *)mqttClient->host, if (UTILS_StrToIP((const char *)mqttClient->host,
(void*)&mqttClient->pCon->proto.tcp->remote_ip)) { (void*)&mqttClient->pCon->proto.tcp->remote_ip)) {
uint8_t err; uint8_t err;
@ -688,7 +744,9 @@ MQTT_Connect(MQTT_Client* mqttClient) {
else else
err = espconn_connect(mqttClient->pCon); err = espconn_connect(mqttClient->pCon);
if (err != 0) { if (err != 0) {
#ifdef MQTT_DBG
os_printf("MQTT ERROR: Failed to connect\n"); os_printf("MQTT ERROR: Failed to connect\n");
#endif
os_free(mqttClient->pCon->proto.tcp); os_free(mqttClient->pCon->proto.tcp);
os_free(mqttClient->pCon); os_free(mqttClient->pCon);
mqttClient->pCon = NULL; mqttClient->pCon = NULL;
@ -707,7 +765,9 @@ MQTT_Connect(MQTT_Client* mqttClient) {
static void ICACHE_FLASH_ATTR static void ICACHE_FLASH_ATTR
mqtt_doAbort(MQTT_Client* client) { mqtt_doAbort(MQTT_Client* client) {
#ifdef MQTT_DBG
os_printf("MQTT: Disconnecting from %s:%d (%p)\n", client->host, client->port, client->pCon); 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... client->pCon->reverse = NULL; // ensure we jettison this pCon...
if (client->security) if (client->security)
espconn_secure_disconnect(client->pCon); espconn_secure_disconnect(client->pCon);

@ -8,11 +8,13 @@ void ICACHE_FLASH_ATTR
cmdMqttConnectedCb(uint32_t* args) { cmdMqttConnectedCb(uint32_t* args) {
MQTT_Client* client = (MQTT_Client*)args; MQTT_Client* client = (MQTT_Client*)args;
MqttCmdCb* cb = (MqttCmdCb*)client->user_data; MqttCmdCb* cb = (MqttCmdCb*)client->user_data;
#ifdef MQTTCMD_DBG
os_printf("MQTT: Connected connectedCb=%p, disconnectedCb=%p, publishedCb=%p, dataCb=%p\n", os_printf("MQTT: Connected connectedCb=%p, disconnectedCb=%p, publishedCb=%p, dataCb=%p\n",
(void*)cb->connectedCb, (void*)cb->connectedCb,
(void*)cb->disconnectedCb, (void*)cb->disconnectedCb,
(void*)cb->publishedCb, (void*)cb->publishedCb,
(void*)cb->dataCb); (void*)cb->dataCb);
#endif
uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->connectedCb, 0, 0); uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->connectedCb, 0, 0);
CMD_ResponseEnd(crc); CMD_ResponseEnd(crc);
} }
@ -21,7 +23,9 @@ void ICACHE_FLASH_ATTR
cmdMqttTcpDisconnectedCb(uint32_t *args) { cmdMqttTcpDisconnectedCb(uint32_t *args) {
MQTT_Client* client = (MQTT_Client*)args; MQTT_Client* client = (MQTT_Client*)args;
MqttCmdCb *cb = (MqttCmdCb*)client->user_data; MqttCmdCb *cb = (MqttCmdCb*)client->user_data;
#ifdef MQTTCMD_DBG
os_printf("MQTT: TCP Disconnected\n"); os_printf("MQTT: TCP Disconnected\n");
#endif
uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->tcpDisconnectedCb, 0, 0); uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->tcpDisconnectedCb, 0, 0);
CMD_ResponseEnd(crc); CMD_ResponseEnd(crc);
} }
@ -30,7 +34,9 @@ void ICACHE_FLASH_ATTR
cmdMqttDisconnectedCb(uint32_t* args) { cmdMqttDisconnectedCb(uint32_t* args) {
MQTT_Client* client = (MQTT_Client*)args; MQTT_Client* client = (MQTT_Client*)args;
MqttCmdCb* cb = (MqttCmdCb*)client->user_data; MqttCmdCb* cb = (MqttCmdCb*)client->user_data;
#ifdef MQTTCMD_DBG
os_printf("MQTT: Disconnected\n"); os_printf("MQTT: Disconnected\n");
#endif
uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->disconnectedCb, 0, 0); uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->disconnectedCb, 0, 0);
CMD_ResponseEnd(crc); CMD_ResponseEnd(crc);
} }
@ -39,7 +45,9 @@ void ICACHE_FLASH_ATTR
cmdMqttPublishedCb(uint32_t* args) { cmdMqttPublishedCb(uint32_t* args) {
MQTT_Client* client = (MQTT_Client*)args; MQTT_Client* client = (MQTT_Client*)args;
MqttCmdCb* cb = (MqttCmdCb*)client->user_data; MqttCmdCb* cb = (MqttCmdCb*)client->user_data;
#ifdef MQTTCMD_DBG
os_printf("MQTT: Published\n"); os_printf("MQTT: Published\n");
#endif
uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->publishedCb, 0, 0); uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->publishedCb, 0, 0);
CMD_ResponseEnd(crc); CMD_ResponseEnd(crc);
} }
@ -103,8 +111,9 @@ MQTTCMD_Setup(CmdPacket *cmd) {
// get clean session // get clean session
CMD_PopArg(&req, (uint8_t*)&clean_session, 4); 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); 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 // init client
// TODO: why malloc these all here, pass to MQTT_InitClient to be malloc'd again? // 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; uint32_t client_ptr;
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
MQTT_Client* client = (MQTT_Client*)client_ptr; MQTT_Client* client = (MQTT_Client*)client_ptr;
#ifdef MQTTCMD_DBG
os_printf("MQTT: MQTTCMD_Lwt client ptr=%p\n", (void*)client_ptr); os_printf("MQTT: MQTTCMD_Lwt client ptr=%p\n", (void*)client_ptr);
#endif
uint16_t len; uint16_t len;
@ -182,12 +193,13 @@ MQTTCMD_Lwt(CmdPacket *cmd) {
// get retain // get retain
CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_retain, 4); 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", os_printf("MQTT: MQTTCMD_Lwt topic=%s, message=%s, qos=%d, retain=%d\n",
client->connect_info.will_topic, client->connect_info.will_topic,
client->connect_info.will_message, client->connect_info.will_message,
client->connect_info.will_qos, client->connect_info.will_qos,
client->connect_info.will_retain); client->connect_info.will_retain);
#endif
return 1; return 1;
} }
@ -203,7 +215,9 @@ MQTTCMD_Connect(CmdPacket *cmd) {
uint32_t client_ptr; uint32_t client_ptr;
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
MQTT_Client* client = (MQTT_Client*)client_ptr; MQTT_Client* client = (MQTT_Client*)client_ptr;
#ifdef MQTTCMD_DBG
os_printf("MQTT: MQTTCMD_Connect client ptr=%p\n", (void*)client_ptr); os_printf("MQTT: MQTTCMD_Connect client ptr=%p\n", (void*)client_ptr);
#endif
uint16_t len; uint16_t len;
@ -221,11 +235,12 @@ MQTTCMD_Connect(CmdPacket *cmd) {
// get security // get security
CMD_PopArg(&req, (uint8_t*)&client->security, 4); CMD_PopArg(&req, (uint8_t*)&client->security, 4);
#ifdef MQTTCMD_DBG
os_printf("MQTT: MQTTCMD_Connect host=%s, port=%d, security=%d\n", os_printf("MQTT: MQTTCMD_Connect host=%s, port=%d, security=%d\n",
client->host, client->host,
client->port, client->port,
client->security); client->security);
#endif
MQTT_Connect(client); MQTT_Connect(client);
return 1; return 1;
@ -243,7 +258,9 @@ MQTTCMD_Disconnect(CmdPacket *cmd) {
uint32_t client_ptr; uint32_t client_ptr;
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
MQTT_Client* client = (MQTT_Client*)client_ptr; MQTT_Client* client = (MQTT_Client*)client_ptr;
#ifdef MQTTCMD_DBG
os_printf("MQTT: MQTTCMD_Disconnect client ptr=%p\n", (void*)client_ptr); os_printf("MQTT: MQTTCMD_Disconnect client ptr=%p\n", (void*)client_ptr);
#endif
// disconnect // disconnect
MQTT_Disconnect(client); MQTT_Disconnect(client);
@ -262,7 +279,9 @@ MQTTCMD_Publish(CmdPacket *cmd) {
uint32_t client_ptr; uint32_t client_ptr;
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
MQTT_Client* client = (MQTT_Client*)client_ptr; MQTT_Client* client = (MQTT_Client*)client_ptr;
#ifdef MQTTCMD_DBG
os_printf("MQTT: MQTTCMD_Publish client ptr=%p\n", (void*)client_ptr); os_printf("MQTT: MQTTCMD_Publish client ptr=%p\n", (void*)client_ptr);
#endif
uint16_t len; uint16_t len;
uint8_t *topic, *data; uint8_t *topic, *data;
@ -293,12 +312,13 @@ MQTTCMD_Publish(CmdPacket *cmd) {
// get retain // get retain
CMD_PopArg(&req, (uint8_t*)&retain, 4); 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", os_printf("MQTT: MQTTCMD_Publish topic=%s, data_len=%d, qos=%ld, retain=%ld\n",
topic, topic,
os_strlen((char*)data), os_strlen((char*)data),
qos, qos,
retain); retain);
#endif
MQTT_Publish(client, (char*)topic, (char*)data, (uint8_t)qos, (uint8_t)retain); MQTT_Publish(client, (char*)topic, (char*)data, (uint8_t)qos, (uint8_t)retain);
os_free(topic); os_free(topic);
@ -318,7 +338,9 @@ MQTTCMD_Subscribe(CmdPacket *cmd) {
uint32_t client_ptr; uint32_t client_ptr;
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
MQTT_Client* client = (MQTT_Client*)client_ptr; MQTT_Client* client = (MQTT_Client*)client_ptr;
#ifdef MQTTCMD_DBG
os_printf("MQTT: MQTTCMD_Subscribe client ptr=%p\n", (void*)client_ptr); os_printf("MQTT: MQTTCMD_Subscribe client ptr=%p\n", (void*)client_ptr);
#endif
uint16_t len; uint16_t len;
uint8_t* topic; uint8_t* topic;
@ -333,8 +355,9 @@ MQTTCMD_Subscribe(CmdPacket *cmd) {
// get qos // get qos
CMD_PopArg(&req, (uint8_t*)&qos, 4); CMD_PopArg(&req, (uint8_t*)&qos, 4);
#ifdef MQTTCMD_DBG
os_printf("MQTT: MQTTCMD_Subscribe topic=%s, qos=%ld\n", topic, qos); os_printf("MQTT: MQTTCMD_Subscribe topic=%s, qos=%ld\n", topic, qos);
#endif
MQTT_Subscribe(client, (char*)topic, (uint8_t)qos); MQTT_Subscribe(client, (char*)topic, (uint8_t)qos);
os_free(topic); os_free(topic);
return 1; return 1;

@ -3,7 +3,8 @@
#include <esp8266.h> #include <esp8266.h>
#include "pktbuf.h" #include "pktbuf.h"
void ICACHE_FLASH_ATTR #ifdef PKTBUF_DBG
static void ICACHE_FLASH_ATTR
PktBuf_Print(PktBuf *buf) { PktBuf_Print(PktBuf *buf) {
os_printf("PktBuf:"); os_printf("PktBuf:");
for (int i=-16; i<0; i++) for (int i=-16; i<0; i++)
@ -15,6 +16,7 @@ PktBuf_Print(PktBuf *buf) {
os_printf("PktBuf: next=%p len=0x%04x\n", os_printf("PktBuf: next=%p len=0x%04x\n",
((void**)buf)[-4], ((uint16_t*)buf)[-6]); ((void**)buf)[-4], ((uint16_t*)buf)[-6]);
} }
#endif
PktBuf * ICACHE_FLASH_ATTR PktBuf * ICACHE_FLASH_ATTR

@ -24,6 +24,4 @@ PktBuf *PktBuf_Shift(PktBuf *headBuf);
// Shift first buffer off queue, free it, return new head // Shift first buffer off queue, free it, return new head
PktBuf *PktBuf_ShiftFree(PktBuf *headBuf); PktBuf *PktBuf_ShiftFree(PktBuf *headBuf);
void PktBuf_Print(PktBuf *buf);
#endif #endif

@ -73,16 +73,20 @@ tcpclient_recv(void *arg, char *pdata, unsigned short len) {
// collect body and send it // collect body and send it
uint16_t crc; uint16_t crc;
int body_len = len-pi; int body_len = len-pi;
#ifdef REST_DBG
os_printf("REST: status=%ld, body=%d\n", code, body_len); os_printf("REST: status=%ld, body=%d\n", code, body_len);
#endif
if (pi == len) { if (pi == len) {
crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 0); crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 0);
} else { } else {
crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 1); crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 1);
crc = CMD_ResponseBody(crc, (uint8_t*)(pdata+pi), body_len); crc = CMD_ResponseBody(crc, (uint8_t*)(pdata+pi), body_len);
CMD_ResponseEnd(crc); CMD_ResponseEnd(crc);
#ifdef REST_DBG
os_printf("REST: body="); os_printf("REST: body=");
for (int j=pi; j<len; j++) os_printf(" %02x", pdata[j]); for (int j=pi; j<len; j++) os_printf(" %02x", pdata[j]);
os_printf("\n"); os_printf("\n");
#endif
} }
//if(client->security) //if(client->security)
@ -96,7 +100,9 @@ static void ICACHE_FLASH_ATTR
tcpclient_sent_cb(void *arg) { tcpclient_sent_cb(void *arg) {
struct espconn *pCon = (struct espconn *)arg; struct espconn *pCon = (struct espconn *)arg;
RestClient* client = (RestClient *)pCon->reverse; RestClient* client = (RestClient *)pCon->reverse;
#ifdef REST_DBG
os_printf("REST: Sent\n"); os_printf("REST: Sent\n");
#endif
if (client->data_sent != client->data_len) { if (client->data_sent != client->data_len) {
// we only sent part of the buffer, send the rest // we only sent part of the buffer, send the rest
espconn_sent(client->pCon, (uint8_t*)(client->data+client->data_sent), 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) { tcpclient_connect_cb(void *arg) {
struct espconn *pCon = (struct espconn *)arg; struct espconn *pCon = (struct espconn *)arg;
RestClient* client = (RestClient *)pCon->reverse; RestClient* client = (RestClient *)pCon->reverse;
#ifdef REST_DBG
os_printf("REST #%d: connected\n", client-restClient); os_printf("REST #%d: connected\n", client-restClient);
#endif
espconn_regist_disconcb(client->pCon, tcpclient_discon_cb); espconn_regist_disconcb(client->pCon, tcpclient_discon_cb);
espconn_regist_recvcb(client->pCon, tcpclient_recv); espconn_regist_recvcb(client->pCon, tcpclient_recv);
espconn_regist_sentcb(client->pCon, tcpclient_sent_cb); espconn_regist_sentcb(client->pCon, tcpclient_sent_cb);
client->data_sent = client->data_len <= 1400 ? client->data_len : 1400; 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); os_printf("REST #%d: sending %d\n", client-restClient, client->data_sent);
#endif
//if(client->security){ //if(client->security){
// espconn_secure_sent(client->pCon, client->data, client->data_sent); // 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) { tcpclient_recon_cb(void *arg, sint8 errType) {
struct espconn *pCon = (struct espconn *)arg; struct espconn *pCon = (struct espconn *)arg;
RestClient* client = (RestClient *)pCon->reverse; RestClient* client = (RestClient *)pCon->reverse;
#ifdef REST_DBG
os_printf("REST #%d: conn reset\n", client-restClient); os_printf("REST #%d: conn reset\n", client-restClient);
#endif
} }
static void ICACHE_FLASH_ATTR 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; RestClient* client = (RestClient *)pConn->reverse;
if(ipaddr == NULL) { if(ipaddr == NULL) {
#ifdef REST_DBG
os_printf("REST DNS: Got no ip, try to reconnect\n"); os_printf("REST DNS: Got no ip, try to reconnect\n");
#endif
return; return;
} }
#ifdef REST_DBG
os_printf("REST DNS: found ip %d.%d.%d.%d\n", os_printf("REST DNS: found ip %d.%d.%d.%d\n",
*((uint8 *) &ipaddr->addr), *((uint8 *) &ipaddr->addr),
*((uint8 *) &ipaddr->addr + 1), *((uint8 *) &ipaddr->addr + 1),
*((uint8 *) &ipaddr->addr + 2), *((uint8 *) &ipaddr->addr + 2),
*((uint8 *) &ipaddr->addr + 3)); *((uint8 *) &ipaddr->addr + 3));
#endif
if(client->ip.addr == 0 && ipaddr->addr != 0) { if(client->ip.addr == 0 && ipaddr->addr != 0) {
os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4); os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4);
#ifdef CLIENT_SSL_ENABLE #ifdef CLIENT_SSL_ENABLE
@ -160,7 +173,9 @@ rest_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) {
} else } else
#endif #endif
espconn_connect(client->pCon); espconn_connect(client->pCon);
#ifdef REST_DBG
os_printf("REST: connecting...\n"); os_printf("REST: connecting...\n");
#endif
} }
} }
@ -213,8 +228,9 @@ REST_Setup(CmdPacket *cmd) {
os_free(client->pCon); os_free(client->pCon);
} }
os_memset(client, 0, sizeof(RestClient)); 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); os_printf("REST: setup #%d host=%s port=%ld security=%ld\n", clientNum, rest_host, port, security);
#endif
client->resp_cb = cmd->callback; client->resp_cb = cmd->callback;
@ -273,7 +289,9 @@ REST_SetHeader(CmdPacket *cmd) {
client->header[len] = '\r'; client->header[len] = '\r';
client->header[len+1] = '\n'; client->header[len+1] = '\n';
client->header[len+2] = 0; client->header[len+2] = 0;
#ifdef CMDREST_DBG
os_printf("REST: Set header: %s\r\n", client->header); os_printf("REST: Set header: %s\r\n", client->header);
#endif
break; break;
case HEADER_CONTENT_TYPE: case HEADER_CONTENT_TYPE:
if(client->content_type) os_free(client->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] = '\r';
client->content_type[len+1] = '\n'; client->content_type[len+1] = '\n';
client->content_type[len+2] = 0; client->content_type[len+2] = 0;
#ifdef CMDREST_DBG
os_printf("REST: Set content_type: %s\r\n", client->content_type); os_printf("REST: Set content_type: %s\r\n", client->content_type);
#endif
break; break;
case HEADER_USER_AGENT: case HEADER_USER_AGENT:
if(client->user_agent) os_free(client->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] = '\r';
client->user_agent[len+1] = '\n'; client->user_agent[len+1] = '\n';
client->user_agent[len+2] = 0; client->user_agent[len+2] = 0;
#ifdef CMDREST_DBG
os_printf("REST: Set user_agent: %s\r\n", client->user_agent); os_printf("REST: Set user_agent: %s\r\n", client->user_agent);
#endif
break; break;
} }
return 1; return 1;
@ -301,32 +323,36 @@ uint32_t ICACHE_FLASH_ATTR
REST_Request(CmdPacket *cmd) { REST_Request(CmdPacket *cmd) {
CmdRequest req; CmdRequest req;
CMD_Request(&req, cmd); CMD_Request(&req, cmd);
#ifdef CMDREST_DBG
os_printf("REST: request"); os_printf("REST: request");
#endif
// Get client // Get client
uint32_t clientNum; uint32_t clientNum;
if (CMD_PopArg(&req, (uint8_t*)&clientNum, 4)) goto fail; if (CMD_PopArg(&req, (uint8_t*)&clientNum, 4)) goto fail;
if ((clientNum & 0xffff0000) != REST_CB) goto fail; if ((clientNum & 0xffff0000) != REST_CB) goto fail;
clientNum &= 0xffff; clientNum &= 0xffff;
RestClient *client = restClient + clientNum % MAX_REST; RestClient *client = restClient + clientNum % MAX_REST;
#ifdef CMDREST_DBG
os_printf(" #%ld", clientNum); os_printf(" #%ld", clientNum);
#endif
// Get HTTP method // Get HTTP method
uint16_t len = CMD_ArgLen(&req); uint16_t len = CMD_ArgLen(&req);
if (len > 15) goto fail; if (len > 15) goto fail;
char method[16]; char method[16];
CMD_PopArg(&req, method, len); CMD_PopArg(&req, method, len);
method[len] = 0; method[len] = 0;
#ifdef CMDREST_DBG
os_printf(" method=%s", method); os_printf(" method=%s", method);
#endif
// Get HTTP path // Get HTTP path
len = CMD_ArgLen(&req); len = CMD_ArgLen(&req);
if (len > 1023) goto fail; if (len > 1023) goto fail;
char path[1024]; char path[1024];
CMD_PopArg(&req, path, len); CMD_PopArg(&req, path, len);
path[len] = 0; path[len] = 0;
#ifdef CMDREST_DBG
os_printf(" path=%s", path); os_printf(" path=%s", path);
#endif
// Get HTTP body // Get HTTP body
uint32_t realLen = 0; uint32_t realLen = 0;
if (CMD_GetArgc(&req) == 3) { if (CMD_GetArgc(&req) == 3) {
@ -338,7 +364,9 @@ REST_Request(CmdPacket *cmd) {
len = CMD_ArgLen(&req); len = CMD_ArgLen(&req);
if (len > 2048 || realLen > len) goto fail; if (len > 2048 || realLen > len) goto fail;
} }
#ifdef CMDREST_DBG
os_printf(" bodyLen=%ld", realLen); os_printf(" bodyLen=%ld", realLen);
#endif
// we need to allocate memory for the header plus the body. First we count the length of the // 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 // 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"; "User-Agent: %s\r\n\r\n";
uint16_t headerLen = strlen(headerFmt) + strlen(method) + strlen(path) + strlen(client->host) + uint16_t headerLen = strlen(headerFmt) + strlen(method) + strlen(path) + strlen(client->host) +
strlen(client->header) + strlen(client->content_type) + strlen(client->user_agent); strlen(client->header) + strlen(client->content_type) + strlen(client->user_agent);
#ifdef CMDREST_DBG
os_printf(" hdrLen=%d", headerLen); os_printf(" hdrLen=%d", headerLen);
#endif
if (client->data) os_free(client->data); if (client->data) os_free(client->data);
client->data = (char*)os_zalloc(headerLen + realLen); client->data = (char*)os_zalloc(headerLen + realLen);
if (client->data == NULL) goto fail; if (client->data == NULL) goto fail;
#ifdef CMDREST_DBG
os_printf(" totLen=%ld data=%p", headerLen + realLen, client->data); 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->data_len = os_sprintf((char*)client->data, headerFmt, method, path, client->host,
client->header, realLen, client->content_type, client->user_agent); client->header, realLen, client->content_type, client->user_agent);
#ifdef CMDREST_DBG
os_printf(" hdrLen=%d", client->data_len); os_printf(" hdrLen=%d", client->data_len);
#endif
if (realLen > 0) { if (realLen > 0) {
CMD_PopArg(&req, client->data + client->data_len, realLen); CMD_PopArg(&req, client->data + client->data_len, realLen);
client->data_len += realLen; client->data_len += realLen;
} }
#ifdef CMDREST_DBG
os_printf("\n"); os_printf("\n");
//os_printf("REST request: %s", (char*)client->data); //os_printf("REST request: %s", (char*)client->data);
os_printf("REST: pCon state=%d\n", client->pCon->state); os_printf("REST: pCon state=%d\n", client->pCon->state);
#endif
client->pCon->state = ESPCONN_NONE; client->pCon->state = ESPCONN_NONE;
espconn_regist_connectcb(client->pCon, tcpclient_connect_cb); espconn_regist_connectcb(client->pCon, tcpclient_connect_cb);
espconn_regist_reconcb(client->pCon, tcpclient_recon_cb); espconn_regist_reconcb(client->pCon, tcpclient_recon_cb);
if(UTILS_StrToIP((char *)client->host, &client->pCon->proto.tcp->remote_ip)) { 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); os_printf("REST: Connect to ip %s:%ld\n",client->host, client->port);
#endif
//if(client->security){ //if(client->security){
// espconn_secure_connect(client->pCon); // espconn_secure_connect(client->pCon);
//} //}
@ -384,13 +422,17 @@ REST_Request(CmdPacket *cmd) {
espconn_connect(client->pCon); espconn_connect(client->pCon);
//} //}
} else { } else {
#ifdef CMDREST_DBG
os_printf("REST: Connect to host %s:%ld\n", client->host, client->port); 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); espconn_gethostbyname(client->pCon, (char *)client->host, &client->ip, rest_dns_found);
} }
return 1; return 1;
fail: fail:
#ifdef CMDREST_DBG
os_printf("\n"); os_printf("\n");
#endif
return 0; return 0;
} }

@ -100,10 +100,15 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state)
switch (c) { switch (c) {
case DTR_ON: case DTR_ON:
if (mcu_reset_pin >= 0) { if (mcu_reset_pin >= 0) {
#ifdef SERBR_DBG
os_printf("MCU reset gpio%d\n", mcu_reset_pin); os_printf("MCU reset gpio%d\n", mcu_reset_pin);
#endif
GPIO_OUTPUT_SET(mcu_reset_pin, 0); GPIO_OUTPUT_SET(mcu_reset_pin, 0);
os_delay_us(100L); 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; break;
case DTR_OFF: case DTR_OFF:
if (mcu_reset_pin >= 0) { if (mcu_reset_pin >= 0) {
@ -113,10 +118,15 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state)
break; break;
case RTS_ON: case RTS_ON:
if (mcu_isp_pin >= 0) { if (mcu_isp_pin >= 0) {
#ifdef SERBR_DBG
os_printf("MCU ISP gpio%d\n", mcu_isp_pin); os_printf("MCU ISP gpio%d\n", mcu_isp_pin);
#endif
GPIO_OUTPUT_SET(mcu_isp_pin, 0); GPIO_OUTPUT_SET(mcu_isp_pin, 0);
os_delay_us(100L); 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++; slip_disabled++;
break; break;
case RTS_OFF: case RTS_OFF:
@ -137,11 +147,16 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state)
// Generate a reset pulse for the attached microcontroller // Generate a reset pulse for the attached microcontroller
void ICACHE_FLASH_ATTR serbridgeReset() { void ICACHE_FLASH_ATTR serbridgeReset() {
if (mcu_reset_pin >= 0) { if (mcu_reset_pin >= 0) {
#ifdef SERBR_DBG
os_printf("MCU reset gpio%d\n", mcu_reset_pin); os_printf("MCU reset gpio%d\n", mcu_reset_pin);
#endif
GPIO_OUTPUT_SET(mcu_reset_pin, 0); GPIO_OUTPUT_SET(mcu_reset_pin, 0);
os_delay_us(100L); os_delay_us(100L);
GPIO_OUTPUT_SET(mcu_reset_pin, 1); 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 // 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) || if ((len == 2 && strncmp(data, "0 ", 2) == 0) ||
(len == 2 && strncmp(data, "?\n", 2) == 0) || (len == 2 && strncmp(data, "?\n", 2) == 0) ||
(len == 3 && strncmp(data, "?\r\n", 3) == 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); 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 os_delay_us(2*1000L); // time for os_printf to happen
// send reset to arduino/ARM // send reset to arduino/ARM
if (mcu_reset_pin >= 0) GPIO_OUTPUT_SET(mcu_reset_pin, 0); 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 slip_disabled++; // disable SLIP so it doesn't interfere with flashing
// If the connection starts with a telnet negotiation we will do telnet // 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->conn_mode = cmTelnet;
conn->telnet_state = TN_normal; conn->telnet_state = TN_normal;
// note that the three negotiation chars will be gobbled-up by telnetUnwrap // note that the three negotiation chars will be gobbled-up by telnetUnwrap
#ifdef SERBR_DBG
os_printf("telnet mode\n"); os_printf("telnet mode\n");
#endif
// looks like a plain-vanilla connection! // looks like a plain-vanilla connection!
} else { }
else {
conn->conn_mode = cmTransparent; conn->conn_mode = cmTransparent;
} }
@ -218,9 +239,11 @@ sendtxbuffer(serbridgeConnData *conn) {
conn->readytosend = false; conn->readytosend = false;
result = espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen); result = espconn_sent(conn->conn, (uint8_t*)conn->txbuffer, conn->txbufferlen);
conn->txbufferlen = 0; conn->txbufferlen = 0;
#ifdef SERBR_DBG
if (result != ESPCONN_OK) { if (result != ESPCONN_OK) {
os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn); os_printf("sendtxbuffer: espconn_sent error %d on conn %p\n", result, conn);
} }
#endif
} }
return result; return result;
} }
@ -233,7 +256,9 @@ sendtxbuffer(serbridgeConnData *conn) {
static sint8 ICACHE_FLASH_ATTR static sint8 ICACHE_FLASH_ATTR
espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) { espbuffsend(serbridgeConnData *conn, const char *data, uint16 len) {
if (conn->txbufferlen + len > MAX_TXBUFFER) { if (conn->txbufferlen + len > MAX_TXBUFFER) {
#ifdef SERBR_DBG
os_printf("espbuffsend: txbuffer full on conn %p\n", conn); os_printf("espbuffsend: txbuffer full on conn %p\n", conn);
#endif
return -128; return -128;
} }
os_memcpy(conn->txbuffer + conn->txbufferlen, data, len); 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 // Find empty conndata in pool
int i; int i;
for (i=0; i<MAX_CONN; i++) if (connData[i].conn==NULL) break; for (i=0; i<MAX_CONN; i++) if (connData[i].conn==NULL) break;
#ifdef SERBR_DBG
os_printf("Accept port 23, conn=%p, pool slot %d\n", conn, i); os_printf("Accept port 23, conn=%p, pool slot %d\n", conn, i);
#endif
if (i==MAX_CONN) { if (i==MAX_CONN) {
#ifdef SERBR_DBG
os_printf("Aiee, conn pool overflow!\n"); os_printf("Aiee, conn pool overflow!\n");
#endif
espconn_disconnect(conn); espconn_disconnect(conn);
return; return;
} }
@ -351,8 +380,10 @@ static void ICACHE_FLASH_ATTR serbridgeConnectCb(void *arg) {
void ICACHE_FLASH_ATTR serbridgeInitPins() { void ICACHE_FLASH_ATTR serbridgeInitPins() {
mcu_reset_pin = flashConfig.reset_pin; mcu_reset_pin = flashConfig.reset_pin;
mcu_isp_pin = flashConfig.isp_pin; mcu_isp_pin = flashConfig.isp_pin;
#ifdef SERBR_DBG
os_printf("Serbridge pins: reset=%d isp=%d swap=%d\n", os_printf("Serbridge pins: reset=%d isp=%d swap=%d\n",
mcu_reset_pin, mcu_isp_pin, flashConfig.swap_uart); mcu_reset_pin, mcu_isp_pin, flashConfig.swap_uart);
#endif
if (flashConfig.swap_uart) { if (flashConfig.swap_uart) {
PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 4); PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 4);

@ -35,7 +35,9 @@ void ICACHE_FLASH_ATTR serledInit(void) {
gpio_output_set(0, 0, (1<<pin), 0); gpio_output_set(0, 0, (1<<pin), 0);
serledFlash(1000); // turn it on for 1 second serledFlash(1000); // turn it on for 1 second
} }
#ifdef SERLED_DBG
os_printf("SER led=%d\n", pin); os_printf("SER led=%d\n", pin);
#endif
} }
// Make a pin be GPIO, i.e. set the mux so the pin has the gpio function // Make a pin be GPIO, i.e. set the mux so the pin has the gpio function

@ -46,7 +46,9 @@ slip_process() {
if (crc == rcv) { if (crc == rcv) {
CMD_parse_packet((uint8_t*)slip_buf, slip_len-2); CMD_parse_packet((uint8_t*)slip_buf, slip_len-2);
} else { } else {
#ifdef SLIP_DBG
os_printf("SLIP: bad CRC, crc=%x rcv=%x\n", crc, rcv); os_printf("SLIP: bad CRC, crc=%x rcv=%x\n", crc, rcv);
for (short i=0; i<slip_len; i++) { for (short i=0; i<slip_len; i++) {
if (slip_buf[i] >= ' ' && slip_buf[i] <= '~') if (slip_buf[i] >= ' ' && slip_buf[i] <= '~')
os_printf("%c", slip_buf[i]); os_printf("%c", slip_buf[i]);
@ -54,6 +56,7 @@ slip_process() {
os_printf("\\%02X", slip_buf[i]); os_printf("\\%02X", slip_buf[i]);
} }
os_printf("\n"); os_printf("\n");
#endif
} }
} }
} }
@ -83,7 +86,9 @@ slip_parse_char(char c) {
if (slip_len > 0) console_process(slip_buf, slip_len); if (slip_len > 0) console_process(slip_buf, slip_len);
slip_reset(); slip_reset();
slip_inpkt = true; slip_inpkt = true;
#ifdef SLIP_DBG
os_printf("SLIP: start\n"); os_printf("SLIP: start\n");
#endif
return; return;
} }
} else if (slip_escaped) { } else if (slip_escaped) {

@ -0,0 +1,64 @@
#include "latch_json.h"
#include "user_funcs.h"
#include <json/jsontree.h>
#include <json/jsonparse.h>
#include <cmd.h>
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));

@ -0,0 +1,12 @@
#ifndef _LATCH_JSON_H_
#define _LATCH_JSON_H_
#include <esp8266.h>
typedef struct {
uint8_t fallbackStateBits;
uint8_t stateBits;
uint8_t init;
uint8_t fallbackSecondsForBits[8];
} LatchState;
#endif // _LATCH_JSON_H_

@ -1,6 +1,7 @@
#include "user_funcs.h" #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()); uint16_t NumMinsToday = totalMinutes(hour(), minute());
bool state = false; bool state = false;
@ -19,7 +20,8 @@ bool ICACHE_FLASH_ATTR pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute,
return state; return state;
} }
const char* ICACHE_FLASH_ATTR byteToBin(uint8_t num) { const char* ICACHE_FLASH_ATTR
byteToBin(uint8_t num) {
static char b[9]; static char b[9];
b[0] = '\0'; b[0] = '\0';
@ -30,7 +32,8 @@ const char* ICACHE_FLASH_ATTR byteToBin(uint8_t num) {
return b; return b;
} }
const uint8_t ICACHE_FLASH_ATTR binToByte(char* bin_str) { const uint8_t ICACHE_FLASH_ATTR
binToByte(char* bin_str) {
char * tmp; char * tmp;
long x = strtol(bin_str, &tmp, 2); long x = strtol(bin_str, &tmp, 2);
return (x <= 255) ? (uint8_t)x : -1; return (x <= 255) ? (uint8_t)x : -1;

@ -7,4 +7,5 @@ bool pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, u
const char* byteToBin(uint8_t num); const char* byteToBin(uint8_t num);
const uint8_t binToByte(char* bin_str); const uint8_t binToByte(char* bin_str);
#endif // _USER_FUNCS_H_ #endif // _USER_FUNCS_H_

@ -1,38 +1,14 @@
#include <esp8266.h> #include <esp8266.h>
#include "cgiwifi.h" #include "cgiwifi.h"
#include "mqtt.h" #include <mqtt.h>
#include <config.h>
#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; MQTT_Client mqttClient;
//static ETSTimer mqttTimer;
void ICACHE_FLASH_ATTR void ICACHE_FLASH_ATTR
mqttConnectedCb(uint32_t *args) { mqttConnectedCb(uint32_t *args) {
@ -60,11 +36,10 @@ mqttPublishedCb(uint32_t *args) {
void ICACHE_FLASH_ATTR void ICACHE_FLASH_ATTR
mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) { 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 *topicBuf = (char*)os_zalloc(topic_len + 1);
char *dataBuf = (char*)os_zalloc(data_len + 1); char *dataBuf = (char*)os_zalloc(data_len + 1);
// MQTT_Client* client = (MQTT_Client*)args;
os_memcpy(topicBuf, topic, topic_len); os_memcpy(topicBuf, topic, topic_len);
topicBuf[topic_len] = 0; 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); os_free(dataBuf);
} }
MQTT_InitConnection(&mqttClient, MQTT_HOST, MQTT_PORT, MQTT_SECURITY); void ICACHE_FLASH_ATTR
MQTT_InitClient(&mqttClient, MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS, MQTT_KEEPALIVE, MQTT_CLSESSION); 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_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
MQTT_OnConnected(&mqttClient, mqttConnectedCb); MQTT_OnConnected(&mqttClient, mqttConnectedCb);
MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb); MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb);
MQTT_OnDisconnected(&mqttClient, mqttTcpDisconnectedCb); MQTT_OnDisconnected(&mqttClient, mqttTcpDisconnectedCb);
MQTT_OnPublished(&mqttClient, mqttPublishedCb); MQTT_OnPublished(&mqttClient, mqttPublishedCb);
MQTT_OnData(&mqttClient, mqttDataCb); MQTT_OnData(&mqttClient, mqttDataCb);
#endif }
wifiAddStateChangeCb(wifiStateChangeCb);
}

Loading…
Cancel
Save