diff --git a/.travis.yml b/.travis.yml index 008251c9..6ce3d58d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,31 +1,28 @@ -# Travis-CI file for Esp-Link - language: c - before_install: - - curl -Ls http://s3.voneicken.com/xtensa-lx106-elf-20160330.tgx | tar Jxf - - - curl -Ls http://s3.voneicken.com/esp_iot_sdk_v2.0.0.p1.tgx | tar -C .. -Jxf - - -after_script: - # upload to an S3 bucket, requires S3_BUCKET, AWS_ACCESS_KEY_ID and AWS_SECRET_KEY to be set - # in environment using travis' repository settings - - "if [[ -n \"$S3_BUCKET\" && -n \"$AWS_ACCESS_KEY_ID\" ]]; then - echo Uploading *.tgz to $S3_BUCKET; - curl -Ls https://github.com/rlmcpherson/s3gof3r/releases/download/v0.5.0/gof3r_0.5.0_linux_amd64.tar.gz | tar zxf - gof3r_0.5.0_linux_amd64/gof3r; - mv gof3r*/gof3r .; - ls *.tgz | xargs -I {} ./gof3r put -b $S3_BUCKET -k esp-link/{} --acl public-read -p {}; - ls *.tgz | xargs -I {} echo \"URL: http://$S3_BUCKET/esp-link/{}\"; - fi" - -compiler: gcc - -env: - +- curl -Ls http://s3.voneicken.com/xtensa-lx106-elf-20160330.tgx | tar Jxf - +- curl -Ls http://s3.voneicken.com/esp_iot_sdk_v2.0.0.p1.tgx | tar -C .. -Jxf - script: - - export XTENSA_TOOLS_ROOT=$PWD/xtensa-lx106-elf/bin/ - - export BRANCH=$TRAVIS_BRANCH - #- export SDK_BASE=$PWD/esp_iot_sdk_v2.0.0.p1 - - make release - +- printenv +- export XTENSA_TOOLS_ROOT=$PWD/xtensa-lx106-elf/bin/ +- export BRANCH=$TRAVIS_BRANCH +- echo "Travis Branch is $TRAVIS_BRANCH" +- echo "Travis Tag is $TRAVIS_TAG" +- echo "Travis COMMIT is $TRAVIS_COMMIT" +- echo "Travis COMMIT is $TRAVIS_COMMIT_RANGE" +- echo "Dont forget to set VARIABLES for S3 to function. SEE gof3r README" +- make release notifications: email: false +deploy: + overwrite: true + skip_cleanup: true + provider: releases + api_key: + secure: unYyTCLpk1ixcNOyoUwroBqqx0yBhii56IXm57kjo5kl3umf1GRb3FUIE6la+B0njsNwAUNR/uLn6wF4FqYTUJzNQZskJDJfZjb53vwuoHaoa5j4K/bWB9zRlQ1XZBTkV48cxz8Ef2KyNduK2IciOHwsw3LQS0em3dpK7oG/20VzELt23Gx8uhBYa+OUzlr3Y+PYPynkwM30YwVQXpCy/GMgEbrcKheGbLTAIp7tms0KDAvbb98U0BI3tWBckE5GzAYYAmrXgyDXtEsU/poCMqUj/lpPl1s/5uxGVevTO7XuL4AYtF//AixsM20bPKtIZDHZS9b7JHtVhU655bY2aAfpMgf7xzkKbJkRzeAzT9HucFDjLY48yW4vztdJxBgkAL9d064gTHhThtn4hylZAYpHnqUiM0j4DKil5A0VG2F8EVEqZ7Q2tNzy6aqq37wzTuYXsYpz3mglpazaXXp/LoSurDHy1gz6aB/mdaeBoL3MX1q09LBE8lFGYBILQ8KUkrLyJathxAVvDBnl7nXFv2NWoZ2i7CfXdpCwmOVUN2WhudNfgbbaMung+voTFB+yLq9PBQP5gdP0MKU3zDTB/msmZo1pp/SbnNETCrKAdRtxNI+bxTQ98njAIkxI+7ZiVV8SMNEPyNcWq/6ViYDcIHJMR4Gq0DZunre1voEs1F4= + file_glob: true + file: esp-link-master-*.t*gz + on: + branch: master + repo: fuzzball03/esp-link + condition: "$TRAVIS_BRANCH = master" diff --git a/Makefile b/Makefile index 4172785d..5c22bd9e 100644 --- a/Makefile +++ b/Makefile @@ -52,12 +52,15 @@ ESP_HOSTNAME ?= esp-link # Base directory for the compiler. Needs a / at the end. # Typically you'll install https://github.com/pfalcon/esp-open-sdk # IMPORTANT: use esp-open-sdk `make STANDALONE=n`: the SDK bundled with esp-open-sdk will *not* work! -XTENSA_TOOLS_ROOT ?= $(abspath ../esp-open-sdk/xtensa-lx106-elf/bin)/ +XTENSA_TOOLS_ROOT ?= $(abspath ../espressif/xtensa-lx106-elf/bin)/ +$(warning Using XTENSA TOOLS from $(XTENSA_TOOLS_ROOT)) # Firmware version # WARNING: if you change this expect to make code adjustments elsewhere, don't expect # that esp-link will magically work with a different version of the SDK!!! SDK_VERS ?= esp_iot_sdk_v2.0.0.p1 +# Uncomment this line if you're using windows to build with the C:\espressif structure +# SDK_VERS ?= ESP8266_SDK # Try to find the firmware manually extracted, e.g. after downloading from Espressif's BBS, # http://bbs.espressif.com/viewforum.php?f=46 @@ -66,16 +69,17 @@ SDK_BASE ?= $(wildcard ../$(SDK_VERS)) # If the firmware isn't there, see whether it got downloaded as part of esp-open-sdk # This used to work at some point, but is not supported, uncomment if you feel lucky ;-) -#ifeq ($(SDK_BASE),) -#SDK_BASE := $(wildcard $(XTENSA_TOOLS_ROOT)/../../$(SDK_VERS)) -#endif +ifeq ($(SDK_BASE),) +SDK_BASE := $(wildcard $(XTENSA_TOOLS_ROOT)/../../$(SDK_VERS)) +endif # Clean up SDK path SDK_BASE := $(abspath $(SDK_BASE)) $(warning Using SDK from $(SDK_BASE)) # Path to bootloader file -BOOTFILE ?= $(SDK_BASE/bin/boot_v1.6.bin) +BOOTFILE ?= $(SDK_BASE)/bin/boot_v1.6.bin +$(warning Using boot file-> $(BOOTFILE)) # Esptool.py path and port, only used for 1-time serial flashing # Typically you'll use https://github.com/themadinventor/esptool @@ -127,8 +131,10 @@ GZIP_COMPRESSION ?= yes # http://yui.github.io/yuicompressor/ # enabled by default. COMPRESS_W_HTMLCOMPRESSOR ?= yes -HTML_COMPRESSOR ?= htmlcompressor-1.5.3.jar -YUI_COMPRESSOR ?= yuicompressor-2.4.8.jar +HTML_COMPRESSOR_VER ?= htmlcompressor-1.5.3.jar +HTML_COMPRESSOR = tools/$(HTML_COMPRESSOR_VER) +YUI_COMPRESSOR_VER ?= yuicompressor-2.4.8.jar +YUI_COMPRESSOR = tools/$(YUI_COMPRESSOR_VER) # -------------- End of config options ------------- @@ -296,6 +302,13 @@ Q := @ vecho := @echo endif +#Fix for issues on some windows systems that call non GNU FIND +FIND ?= $(which FIND) +ifeq (,$(findstring system32,$(FIND))) + $(warning Non GNU 'find' called. Trying alternate path /usr/bin/find) + FIND = /usr/bin/find +endif + ifneq ($(strip $(STA_SSID)),) CFLAGS += -DSTA_SSID="$(STA_SSID)" endif @@ -387,6 +400,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) 1 >/dev/null $(Q) rm -f eagle.app.v6.*.bin $(Q) mv eagle.app.flash.bin $@ + @echo "** user2.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 $(APP_AR): $(OBJ) @@ -406,18 +420,18 @@ baseflash: all flash: all $(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash -fs $(ET_FS) -ff $(ET_FF) \ - 0x00000 "$(SDK_BASE)/bin/boot_v1.5.bin" 0x01000 $(FW_BASE)/user1.bin \ + 0x00000 "$(BOOTFILE)" 0x01000 $(FW_BASE)/user1.bin \ $(ET_BLANK) $(SDK_BASE)/bin/blank.bin tools/$(HTML_COMPRESSOR): $(Q) echo "The jar files in the tools dir are missing, they should be in the source repo" $(Q) echo "The following commands can be used to fetch them, but the URLs have changed..." $(Q) echo mkdir -p tools - $(Q) echo "cd tools; wget --no-check-certificate https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI_COMPRESSOR) -O $(YUI_COMPRESSOR)" - $(Q) echo "cd tools; wget --no-check-certificate https://htmlcompressor.googlecode.com/files/$(HTML_COMPRESSOR) -O $(HTML_COMPRESSOR)" + $(Q) echo "cd tools; wget --no-check-certificate https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI_COMPRESSOR_VER) -O $(YUI_COMPRESSOR_VER)" + $(Q) echo "cd tools; wget --no-check-certificate https://htmlcompressor.googlecode.com/files/$(HTML_COMPRESSOR_VER) -O $(HTML_COMPRESSOR_VER)" ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes") -$(BUILD_BASE)/espfs_img.o: tools/$(HTML_COMPRESSOR) +$(BUILD_BASE)/espfs_img.o: $(HTML_COMPRESSOR) endif $(BUILD_BASE)/espfs_img.o: html/ html/wifi/ espfs/mkespfsimage/mkespfsimage @@ -428,38 +442,38 @@ $(BUILD_BASE)/espfs_img.o: html/ html/wifi/ espfs/mkespfsimage/mkespfsimage $(Q) cp -r html/wifi/*.png html_compressed/wifi; $(Q) cp -r html/wifi/*.js html_compressed/wifi; ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes") - $(Q) echo "Compressing assets with htmlcompressor. This may take a while..." - $(Q) java -jar tools/$(HTML_COMPRESSOR) \ + $(Q) echo "Compressing assets with htmlcompressor. This may take a while..."; + $(Q) java -jar $(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) \ + $(Q) java -jar $(HTML_COMPRESSOR) \ -t html --remove-surrounding-spaces max --remove-quotes --remove-intertag-spaces \ -o $(abspath ./html_compressed)/wifi/ \ $(WIFI_PATH)*.html $(Q) echo "Compressing assets with yui-compressor. This may take a while..." - $(Q) for file in `find html_compressed -type f -name "*.js"`; do \ - java -jar tools/$(YUI_COMPRESSOR) $$file --line-break 0 -o $$file; \ - done - $(Q) for file in `find html_compressed -type f -name "*.css"`; do \ - java -jar tools/$(YUI_COMPRESSOR) $$file -o $$file; \ - done + $(Q) java -jar $(YUI_COMPRESSOR) ./html_compressed/*.css -o '.css$:.css' + $(Q) java -jar $(YUI_COMPRESSOR) ./html_compressed/*.js -o '.js$:.js' + $(Q) java -jar $(YUI_COMPRESSOR) ./html_compressed/wifi/*.js -o '.js$:.js' else $(Q) cp -r html/head- html_compressed; $(Q) cp -r html/*.html html_compressed; $(Q) cp -r html/wifi/*.html html_compressed/wifi; endif + ifeq (,$(findstring mqtt,$(MODULES))) $(Q) rm -rf html_compressed/mqtt.html $(Q) rm -rf html_compressed/mqtt.js endif - $(Q) for file in `find html_compressed -type f -name "*.htm*"`; do \ + + $(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) echo "Compressing assets into espfs.img with Gzip. This may take a while..." + $(Q) cd html_compressed; $(FIND) . \! -name \*- | ../espfs/mkespfsimage/mkespfsimage > ../build/espfs.img; cd ..; $(Q) ls -sl build/espfs.img $(Q) cd build; $(OBJCP) -I binary -O elf32-xtensa-le -B xtensa --rename-section .data=.espfs \ espfs.img espfs_img.o; cd .. @@ -483,7 +497,7 @@ release: all $(Q) egrep -a 'esp-link [a-z0-9.]+ - 201' $(FW_BASE)/user1.bin | cut -b 1-80 $(Q) egrep -a 'esp-link [a-z0-9.]+ - 201' $(FW_BASE)/user2.bin | cut -b 1-80 $(Q) cp $(FW_BASE)/user1.bin $(FW_BASE)/user2.bin $(SDK_BASE)/bin/blank.bin \ - "$(SDK_BASE)/bin/boot_v1.6.bin" "$(SDK_BASE)/bin/esp_init_data_default.bin" \ + "$(BOOTFILE)" "$(SDK_BASE)/bin/esp_init_data_default.bin" \ wiflash avrflash release/esp-link-$(BRANCH) $(Q) tar zcf esp-link-$(BRANCH)-$(SHA).tgz -C release esp-link-$(BRANCH) $(Q) echo "Release file: esp-link-$(BRANCH)-$(SHA).tgz" @@ -494,7 +508,7 @@ docker: clean: $(Q) rm -f $(APP_AR) $(Q) rm -f $(TARGET_OUT) - $(Q) find $(BUILD_BASE) -type f | xargs rm -f + $(Q) $(FIND) $(BUILD_BASE) -type f | xargs rm -f $(Q) make -C espfs/mkespfsimage/ clean $(Q) rm -rf $(FW_BASE) $(Q) rm -f webpages.espfs @@ -502,4 +516,4 @@ ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes") $(Q) rm -rf html_compressed endif -$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir)))) +$(foreach bdir,$(BUILD_DIR),$(eval $(call compile-objects,$(bdir)))) \ No newline at end of file diff --git a/README.md b/README.md index 17ef3a0d..3bda6151 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,8 @@ From there, more advanced steps are: ### Serial bridge +Note that the default ports of 23 & 2323 may be changed via the webinterface. + In order to connect through the esp-link to a microcontroller use port 23. For example, on linux you can use `nc esp-hostname 23` or `telnet esp-hostname 23`. diff --git a/esp-link/cgi.c b/esp-link/cgi.c index d667be3f..6d0d79e6 100644 --- a/esp-link/cgi.c +++ b/esp-link/cgi.c @@ -190,7 +190,7 @@ int ICACHE_FLASH_ATTR printGlobalInfo(char *buff, int buflen, char *token) { extern char *esp_link_version; // in user_main.c -int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) { +int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) { //This is where we can modify the navigation that is auto generated if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. char buff[1024]; // don't use jsonHeader so the response does get cached diff --git a/esp-link/cgipins.c b/esp-link/cgipins.c index b763d125..0f62212d 100644 --- a/esp-link/cgipins.c +++ b/esp-link/cgipins.c @@ -1,4 +1,3 @@ - #include #include "cgi.h" #include "espfs.h" diff --git a/esp-link/cgitelnet.c b/esp-link/cgitelnet.c new file mode 100644 index 00000000..2791e34e --- /dev/null +++ b/esp-link/cgitelnet.c @@ -0,0 +1,120 @@ +#include +#include "cgi.h" +#include "config.h" +#include "serbridge.h" + +static char *portMode[] = { "open", "disabled", "secure" }; + +// Cgi to return choice of Telnet ports +int ICACHE_FLASH_ATTR cgiTelnetGet(HttpdConnData *connData) { + char buff[80]; + + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted + + int len; + + os_printf("Current telnet ports: port0=%d port1=%d\n", + flashConfig.telnet_port0, flashConfig.telnet_port1); + + len = os_sprintf(buff, + "{ \"port0\": \"%d\", \"port1\": \"%d\" }", + flashConfig.telnet_port0, flashConfig.telnet_port1); + + jsonHeader(connData, 200); + httpdSend(connData, buff, len); + + return HTTPD_CGI_DONE; +} + +// Cgi to change choice of Telnet ports +int ICACHE_FLASH_ATTR cgiTelnetSet(HttpdConnData *connData) { + char buf[80]; + + if (connData->conn==NULL) { + return HTTPD_CGI_DONE; // Connection aborted + } + + int8_t ok = 0; + uint16_t port0, port1; + ok |= getUInt16Arg(connData, "port0", &port0); + ok |= getUInt16Arg(connData, "port1", &port1); + + if (ok <= 0) { //If we get at least one good value, this should be >= 1 + ets_sprintf(buf, "Unable to fetch telnet ports.\n Received: port0=%d port1=%d\n", + flashConfig.telnet_port0, flashConfig.telnet_port1); + os_printf(buf); + errorResponse(connData, 400, buf); + return HTTPD_CGI_DONE; + } + + if (ok > 0) { + // fill both port variables from flash or ajax provided value + if (!port0) port0 = flashConfig.telnet_port0; + if (!port1) port1 = flashConfig.telnet_port1; + + // check whether ports are different + if (port0 == port1) { + os_sprintf(buf, "Ports cannot be the same.\n Tried to set: port0=%d port1=%d\n", + flashConfig.telnet_port0, flashConfig.telnet_port1); + os_printf(buf); + errorResponse(connData, 400, buf); + return HTTPD_CGI_DONE; + } + + // we're good, set flashconfig + flashConfig.telnet_port0 = port0; + flashConfig.telnet_port1 = port1; + os_printf("Telnet ports changed: port0=%d port1=%d\n", + flashConfig.telnet_port0, flashConfig.telnet_port1); + + // save to flash + if (configSave()) { + httpdStartResponse(connData, 204); + httpdEndHeaders(connData); + } else { + httpdStartResponse(connData, 500); + httpdEndHeaders(connData); + httpdSend(connData, "Failed to save config", -1); + } + + // apply the changes + serbridgeInit(); + serbridgeStart(0, flashConfig.telnet_port0, flashDefault.telnet_port0mode); + serbridgeStart(1, flashConfig.telnet_port1, flashDefault.telnet_port1mode); + + } + + return HTTPD_CGI_DONE; +} + +int ICACHE_FLASH_ATTR cgiTelnet(HttpdConnData *connData) { + if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. + if (connData->requestType == HTTPD_METHOD_GET) { + return cgiTelnetGet(connData); + } else if (connData->requestType == HTTPD_METHOD_POST) { + return cgiTelnetSet(connData); + } else { + jsonHeader(connData, 404); + return HTTPD_CGI_DONE; + } +} + +static char *portMode2string(int8_t m) { //Should we put this into flash? + if (m < 0 || m > 2) return "?"; + return portMode[m]; + } + + // print various Telnet information into json buffer + int ICACHE_FLASH_ATTR printTelnetSecurity(char *buff) { + int len; + + len = os_sprintf(buff, + "{ \"port0mode\": \"%s\", \"port0portnumber\": \"%d\", \"port0pwd\": \"%s\", " + "\"port1mode\": \"%s\", \"port1portnumber\": \"%d\", \"port1pwd\": \"%s\" }", + portMode2string(flashConfig.telnet_port0mode), flashConfig.telnet_port0, flashConfig.telnet_port0pass, + portMode2string(flashConfig.telnet_port1mode), flashConfig.telnet_port1, flashConfig.telnet_port1pass + ); + + return len; + } + \ No newline at end of file diff --git a/esp-link/cgitelnet.h b/esp-link/cgitelnet.h new file mode 100644 index 00000000..516d5d9f --- /dev/null +++ b/esp-link/cgitelnet.h @@ -0,0 +1,8 @@ +#ifndef CGITELNET_H +#define CGITELNET_H + +#include "httpd.h" + +int cgiTelnet(HttpdConnData *connData); + +#endif // CGITELNET_H diff --git a/esp-link/config.c b/esp-link/config.c index d12f7a78..9ac57b9c 100644 --- a/esp-link/config.c +++ b/esp-link/config.c @@ -35,6 +35,12 @@ FlashConfig flashDefault = { .data_bits = EIGHT_BITS, .parity = NONE_BITS, .stop_bits = ONE_STOP_BIT, + .telnet_port0 = 23, + .telnet_port1 = 2323, + .telnet_port0mode = 0, + .telnet_port1mode = 0, + .telnet_port0pass = "\0", + .telnet_port1pass = "\0", }; typedef union { @@ -161,6 +167,17 @@ bool ICACHE_FLASH_ATTR configRestore(void) { flashConfig.parity = flashDefault.parity; flashConfig.stop_bits = flashDefault.stop_bits; } + + if (flashConfig.telnet_port0 == 0) { + flashConfig.telnet_port0 = flashDefault.telnet_port0; + flashConfig.telnet_port0mode = flashDefault.telnet_port0mode; + os_memcpy(flashConfig.telnet_port0pass, flashDefault.telnet_port0pass, 32); + } + if (flashConfig.telnet_port1 == 0) { + flashConfig.telnet_port1 = flashDefault.telnet_port1; + flashConfig.telnet_port1mode = flashDefault.telnet_port1mode; + os_memcpy(flashConfig.telnet_port1pass, flashDefault.telnet_port1pass, 32); + } return true; } diff --git a/esp-link/config.h b/esp-link/config.h index 65195d29..59982154 100644 --- a/esp-link/config.h +++ b/esp-link/config.h @@ -13,7 +13,7 @@ typedef struct { char hostname[32]; // if using DHCP uint32_t staticip, netmask, gateway; // using DHCP if staticip==0 uint8_t log_mode; // UART log debug mode - uint8_t swap_uart; // swap uart0 to gpio 13&15 + uint8_t swap_uart; // swap uart0 to gpio 13&15 uint8_t tcp_enable, rssi_enable; // TCP client settings char api_key[48]; // RSSI submission API key (Grovestreams for now) uint8_t slip_enable, mqtt_enable, // SLIP protocol, MQTT client @@ -41,8 +41,15 @@ typedef struct { int8_t data_bits; int8_t parity; int8_t stop_bits; + uint16_t telnet_port0, // Telnet port settings + telnet_port1; + int8_t telnet_port0mode, + telnet_port1mode; + char telnet_port0pass[32], + telnet_port1pass[32]; } FlashConfig; extern FlashConfig flashConfig; +extern FlashConfig flashDefault; bool configSave(void); bool configRestore(void); diff --git a/esp-link/main.c b/esp-link/main.c index e775de9d..38a68177 100644 --- a/esp-link/main.c +++ b/esp-link/main.c @@ -32,6 +32,7 @@ #include "gpio.h" #include "cgiservices.h" #include "web-server.h" +#include "cgitelnet.h" #ifdef SYSLOG #include "syslog.h" @@ -96,6 +97,7 @@ HttpdBuiltInUrl builtInUrls[] = { { "/services/info", cgiServicesInfo, NULL }, { "/services/update", cgiServicesSet, NULL }, { "/pins", cgiPins, NULL }, + { "/telnet", cgiTelnet, NULL}, #ifdef MQTT { "/mqtt", cgiMqtt, NULL }, #endif @@ -178,8 +180,11 @@ user_init(void) { httpdInit(builtInUrls, 80); WEB_Init(); - // init the wifi-serial transparent bridge (port 23) - serbridgeInit(23, 2323); + // init the wifi-serial configurable transparent bridge (port defaults 23&2323) + serbridgeInit(); + serbridgeStart(0, flashConfig.telnet_port0, flashDefault.telnet_port0mode); + serbridgeStart(1, flashConfig.telnet_port1, flashDefault.telnet_port1mode); + uart_add_recv_cb(&serbridgeUartCb); #ifdef SHOW_HEAP_USE os_timer_disarm(&prHeapTimer); diff --git a/espmake.cmd b/espmake.cmd index 42e25a65..f475e01c 100644 --- a/espmake.cmd +++ b/espmake.cmd @@ -1,5 +1,6 @@ @echo off - +SETLOCAL +REM LOCAL IS NEEDED ELSE WE KEEP ADDING TO WINDOW PATH EACH TIME SCRIPT IS CALLED. REM remove automatic created obj folder rd obj /S /Q >nul 2>&1 diff --git a/html/home.html b/html/home.html index de9862f2..62930263 100644 --- a/html/home.html +++ b/html/home.html @@ -50,6 +50,38 @@

Info

the online README for up-to-date help.

+
+

Telnet Serial-Bridge

+

There are two ports available for telnet to use by default: 23 & 2323
+ Note - this time, only port0 may be changed & used sucessfully.

+
+ + + + + + +
@@ -152,9 +184,13 @@

System details

onLoad(function() { makeAjaxInput("system", "description"); makeAjaxInput("system", "name"); + makeAjaxInput("telnet", "port0"); + makeAjaxInput("telnet", "port1"); + makeAjaxInput("telnet", "port0mode"); fetchPins(); getWifiInfo(); getSystemInfo(); + getTelnetInfo(); bnd($("#pinform"), "submit", setPins); }); diff --git a/html/ui.js b/html/ui.js index 67361c9b..3a00ef83 100644 --- a/html/ui.js +++ b/html/ui.js @@ -302,6 +302,22 @@ function getWifiInfo() { function(s, st) { window.setTimeout(getWifiInfo, 1000); }); } +//===== Telnet info + +function showTelnetInfo(data) { + Object.keys(data).forEach(function(v) { + setEditToClick("telnet-"+v, data[v]); + }); + $("#telnet-spinner").setAttribute("hidden", ""); + $("#telnet-table").removeAttribute("hidden"); + currAp = data.ssid; +} + +function getTelnetInfo() { + ajaxJson('GET', "/telnet", showTelnetInfo, + function(s, st) { window.setTimeout(getTelnetInfo, 1000); }); +} + //===== System info function showSystemInfo(data) { @@ -323,6 +339,8 @@ function makeAjaxInput(klass, field) { var eon = $(".edit-on", div); var eoff = $(".edit-off", div)[0]; var url = "/"+klass+"/update?"+field; + //Dirty fix to avoid to seperate name spaces to GET or PUT telnet ports + if (klass == "telnet") { var url = "/"+klass+"?"+field; } if (eoff === undefined || eon == undefined) return; @@ -383,6 +401,7 @@ function showNotification(text) { var el = $("#notification"); el.innerHTML = text; el.removeAttribute('hidden'); + window.scrollTo(0, 0); //Uncomment this line so window will scroll up on regular notifications if (notifTimeout != null) clearTimeout(notifTimeout); notifTimout = setTimeout(function() { el.setAttribute('hidden', ''); diff --git a/serial/serbridge.c b/serial/serbridge.c index cebc5615..8e9e0411 100644 --- a/serial/serbridge.c +++ b/serial/serbridge.c @@ -16,14 +16,14 @@ #define syslog(X1...) #endif -static struct espconn serbridgeConn1; // plain bridging port -static struct espconn serbridgeConn2; // programming port -static esp_tcp serbridgeTcp1, serbridgeTcp2; +static struct espconn serbridgeConn[2]; // 0 = plain bridging port, 1 = programming port +static esp_tcp serbridgeTcp[2]; static int8_t mcu_reset_pin, mcu_isp_pin; uint8_t in_mcu_flashing; // for disabling slip during MCU flashing void (*programmingCB)(char *buffer, short length) = NULL; +void ICACHE_FLASH_ATTR serbridgeCleanup(int ix); // Connection pool serbridgeConnData connData[MAX_CONN]; @@ -421,7 +421,7 @@ serbridgeConnectCb(void *arg) connData[i].readytosend = true; connData[i].conn_mode = cmInit; // if it's the second port we start out in programming mode - if (conn->proto.tcp->local_port == serbridgeConn2.proto.tcp->local_port) + if (conn->proto.tcp->local_port == serbridgeConn[1].proto.tcp->local_port) connData[i].conn_mode = cmPGMInit; espconn_regist_recvcb(conn, serbridgeRecvCb); @@ -470,35 +470,46 @@ serbridgeInitPins() // Start transparent serial bridge TCP server on specified port (typ. 23) void ICACHE_FLASH_ATTR -serbridgeInit(int port1, int port2) +serbridgeInit() { serbridgeInitPins(); os_memset(connData, 0, sizeof(connData)); - os_memset(&serbridgeTcp1, 0, sizeof(serbridgeTcp1)); - os_memset(&serbridgeTcp2, 0, sizeof(serbridgeTcp2)); - - // set-up the primary port for plain bridging - serbridgeConn1.type = ESPCONN_TCP; - serbridgeConn1.state = ESPCONN_NONE; - serbridgeTcp1.local_port = port1; - serbridgeConn1.proto.tcp = &serbridgeTcp1; - - espconn_regist_connectcb(&serbridgeConn1, serbridgeConnectCb); - espconn_accept(&serbridgeConn1); - espconn_tcp_set_max_con_allow(&serbridgeConn1, MAX_CONN); - espconn_regist_time(&serbridgeConn1, SER_BRIDGE_TIMEOUT, 0); - - // set-up the secondary port for programming - serbridgeConn2.type = ESPCONN_TCP; - serbridgeConn2.state = ESPCONN_NONE; - serbridgeTcp2.local_port = port2; - serbridgeConn2.proto.tcp = &serbridgeTcp2; - - espconn_regist_connectcb(&serbridgeConn2, serbridgeConnectCb); - espconn_accept(&serbridgeConn2); - espconn_tcp_set_max_con_allow(&serbridgeConn2, MAX_CONN); - espconn_regist_time(&serbridgeConn2, SER_BRIDGE_TIMEOUT, 0); + os_memset(&serbridgeTcp[0], 0, sizeof(serbridgeTcp[0])); + os_memset(&serbridgeTcp[1], 0, sizeof(serbridgeTcp[1])); +} + +// Start transparent serial bridge TCP server on specified port (typ. 23) +void ICACHE_FLASH_ATTR +serbridgeStart(int ix, int port, int mode) +{ + + if (ix < 0 || ix > 2) // FIXME hardcoded limit + return; + + // If we are already initialized, let's clean it up. + if (serbridgeConn[ix].type != 0) { + serbridgeCleanup(ix); + } + + if (0 < port && port < 65536 && port != 80) { + serbridgeConn[ix].type = ESPCONN_TCP; + serbridgeConn[ix].state = ESPCONN_NONE; + serbridgeTcp[ix].local_port = port; + serbridgeConn[ix].proto.tcp = &serbridgeTcp[ix]; + + espconn_regist_connectcb(&serbridgeConn[ix], serbridgeConnectCb); + espconn_accept(&serbridgeConn[ix]); + espconn_tcp_set_max_con_allow(&serbridgeConn[ix], MAX_CONN); + espconn_regist_time(&serbridgeConn[ix], SER_BRIDGE_TIMEOUT, 0); + } +} + +void ICACHE_FLASH_ATTR +serbridgeCleanup(int ix) +{ + os_memset(&serbridgeTcp[ix], 0, sizeof(serbridgeTcp[ix])); + // Looks like none of the espconn_..() calls in serbridgeStart() needs cleanup here. } int ICACHE_FLASH_ATTR serbridgeInMCUFlashing() diff --git a/serial/serbridge.h b/serial/serbridge.h index ed661e1c..a1122ef7 100644 --- a/serial/serbridge.h +++ b/serial/serbridge.h @@ -31,11 +31,11 @@ typedef struct serbridgeConnData { } serbridgeConnData; // port1 is transparent&programming, second port is programming only -void ICACHE_FLASH_ATTR serbridgeInit(int port1, int port2); +void ICACHE_FLASH_ATTR serbridgeInit(); +void ICACHE_FLASH_ATTR serbridgeStart(int ix, int port, int mode); void ICACHE_FLASH_ATTR serbridgeInitPins(void); void ICACHE_FLASH_ATTR serbridgeUartCb(char *buf, short len); void ICACHE_FLASH_ATTR serbridgeReset(); - int ICACHE_FLASH_ATTR serbridgeInMCUFlashing(); // callback when receiving UART chars when in programming mode