diff --git a/.gitignore b/.gitignore
index 2672ca3..8f81706 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,4 +6,6 @@ webpages.espfs
espfs/espfstest/*.o
espfs/espfstest/espfstest
*.DS_Store
-html_compressed/
\ No newline at end of file
+html_compressed/
+esp-link.tgz
+tve-patch/
diff --git a/Makefile b/Makefile
index 8c9c450..154a781 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,63 @@
+#
+# Makefile for esp-link - https://github.com/jeelabs/esp-link
+#
+# Start by setting the directories for the toolchain a few lines down
+# the default target will build the firmware images
+# `make flash` will flash the esp serially
+# `make wiflash` will flash the esp over wifi
+# `VERBOSE=1 make ...` will print debug info
+# `ESP_HOSTNAME=my.esp.example.com make wiflash` is an easy way to override a variable
+#
+# Makefile heavily adapted to esp-link and wireless flashing by Thorsten von Eicken
+# Original from esphttpd and others...
+
+# --------------- toolchain configuration ---------------
+
+# Base directory for the compiler. Needs a / at the end.
+# Typically you'll install https://github.com/pfalcon/esp-open-sdk
+XTENSA_TOOLS_ROOT ?= $(abspath ../esp-open-sdk/xtensa-lx106-elf/bin)/
+
+# Base directory of the ESP8266 SDK package, absolute
+# Typically you'll download from Espressif's BBS, http://bbs.espressif.com/viewforum.php?f=5
+SDK_BASE ?= $(abspath ../esp_iot_sdk_v1.1.0)
+
+# Esptool.py path and port, only used for 1-time serial flashing
+# Typically you'll use https://github.com/themadinventor/esptool
+ESPTOOL ?= $(abspath ../esptool/esptool.py)
+ESPPORT ?= /dev/ttyUSB0
+ESPBAUD ?= 460800
+
+# --------------- chipset configuration ---------------
+
+ESP_SPI_SIZE ?= 0 # 0->512KB
+ESP_FLASH_MODE ?= 0 # 0->QIO
+ESP_FLASH_FREQ_DIV ?= 0 # 0->40Mhz
+ESP_FLASH_MAX ?= 241664 # max bin file for 512KB flash: 236KB
+
+# hostname or IP address for wifi flashing
+ESP_HOSTNAME ?= esp8266
+
+# The pin assignments below are used when the settings in flash are invalid, they
+# can be changed via the web interface
+# GPIO pin used to reset attached microcontroller, acative low
+MCU_RESET_PIN ?= 12
+# GPIO pin used with reset to reprogram MCU (ISP=in-system-programming, unused with AVRs), active low
+MCU_ISP_PIN ?= 13
+# GPIO pin used for "connectivity" LED, active low
+LED_CONN_PIN ?= 0
+# GPIO pin used for "serial activity" LED, active low
+LED_SERIAL_PIN ?= 2
+
+# --------------- esp-link version ---------------
+
+# This queries git to produce a version string like "esp-link v0.9.0 2015-06-01 34bc76"
+# If you don't have a proper git checkout or are on windows, then simply swap for the constant
+VERSION := "esp-link custom version"
+DATE := $(shell date '+%F %T')
+BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
+SHA := $(shell if git diff --quiet HEAD; then git symbolic-ref HEAD | cut -d"/" -f 3; \
+ else echo "development"; fi)
+VERSION := esp-link - $(BRANCH) - $(DATE) - $(SHA)
# --------------- esphttpd config options ---------------
@@ -30,54 +90,33 @@ YUI-COMPRESSOR ?= /usr/bin/yui-compressor
# Because the decompression is done in the esp8266, it does not require any support in the browser.
USE_HEATSHRINK ?= yes
-# -------------- End of esphttpd config options -------------
-
+# -------------- End of config options -------------
# Output directors to store intermediate compiled files
# relative to the project directory
BUILD_BASE = build
FW_BASE = firmware
-# Base directory for the compiler. Needs a / at the end;
-XTENSA_TOOLS_ROOT ?= $(abspath ../esp-open-sdk/xtensa-lx106-elf/bin)/
-
-# Base directory of the ESP8266 SDK package, absolute
-SDK_BASE ?= $(abspath ../esp_iot_sdk_v1.1.0)
-
-#Esptool.py path and port
-ESPTOOL ?= esptool.py
-ESPPORT ?= /dev/ttyUSB0
-#ESPDELAY indicates seconds to wait between flashing the two binary images
-ESPDELAY ?= 3
-ESPBAUD ?= 460800
-
# name for the target project
TARGET = httpd
# espressif tool to concatenate sections for OTA upload using bootloader v1.2+
APPGEN_TOOL ?= gen_appbin.py
-ESP_SPI_SIZE ?= 0 # 0->512KB
-ESP_FLASH_MODE ?= 0 # 0->QIO
-ESP_FLASH_FREQ_DIV ?= 0 # 0->40Mhz
-ESP_FLASH_MAX ?= 241664 # max bin file for 512KB flash: 236KB
-ESP_HOSTNAME ?= esp8266
-
-
# which modules (subdirectories) of the project to include in compiling
-#MODULES = driver user lwip/api lwip/app lwip/core lwip/core/ipv4 lwip/netif
MODULES = espfs httpd user serial
EXTRA_INCDIR = include . lib/heatshrink/
# libraries used in this project, mainly provided by the SDK
LIBS = c gcc hal phy pp net80211 wpa main lwip
-
-
# compiler flags using during compilation of source files
CFLAGS = -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \
-nostdlib -mlongcalls -mtext-section-literals -D__ets__ -DICACHE_FLASH -D_STDINT_H \
- -Wno-address -DFIRMWARE_SIZE=$(ESP_FLASH_MAX)
+ -Wno-address -DFIRMWARE_SIZE=$(ESP_FLASH_MAX) \
+ -DMCU_RESET_PIN=$(MCU_RESET_PIN) -DMCU_ISP_PIN=$(MCU_ISP_PIN) \
+ -DLED_CONN_PIN=$(LED_CONN_PIN) -DLED_SERIAL_PIN=$(LED_SERIAL_PIN) \
+ "-DVERSION=$(VERSION)"
# linker flags used to generate the main object file
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static
@@ -101,8 +140,6 @@ OBJCP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy
OBJDP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objdump
-####
-#### no user configurable options below here
####
SRC_DIR := $(MODULES)
BUILD_DIR := $(addprefix $(BUILD_BASE)/,$(MODULES))
@@ -152,7 +189,12 @@ endef
.PHONY: all checkdirs clean webpages.espfs
-all: checkdirs $(FW_BASE) firmware/user1.bin firmware/user2.bin
+all: echo_version checkdirs $(FW_BASE) firmware/user1.bin firmware/user2.bin
+
+echo_version:
+ @echo VERSION: $(VERSION)
+
+user/version.h:
$(TARGET_OUT): $(APP_AR) $(LD_SCRIPT)
$(vecho) "LD $@"
@@ -209,8 +251,10 @@ $(BUILD_DIR):
wiflash: all
./wiflash $(ESP_HOSTNAME) firmware/user1.bin firmware/user2.bin
-flash: $(TARGET_OUT) $(FW_BASE)
- $(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash 0x00000 $(FW_BASE)/0x00000.bin 0x40000 $(FW_BASE)/0x40000.bin
+flash: all
+ $(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash \
+ 0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin \
+ 0x7E000 $(SDK_BASE)/bin/blank.bin
$(BUILD_BASE)/espfs_img.o: html/ html/wifi/ espfs/mkespfsimage/mkespfsimage
ifeq ("$(COMPRESS_W_YUI)","yes")
@@ -245,12 +289,16 @@ build/eagle.esphttpd2.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.512.app2.ld
-e '/^ irom0_0_seg/ s/2B000/38000/' \
$(SDK_LDDIR)/eagle.app.v6.new.512.app2.ld >$@
-blankflash:
- $(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash 0x7E000 $(SDK_BASE)/bin/blank.bin
-
espfs/mkespfsimage/mkespfsimage: espfs/mkespfsimage/
$(Q) $(MAKE) -C espfs/mkespfsimage USE_HEATSHRINK="$(USE_HEATSHRINK)" GZIP_COMPRESSION="$(GZIP_COMPRESSION)"
+release: all
+ $(Q) rm -rf release; mkdir -p release/esp-link
+ $(Q) cp firmware/user1.bin firmware/user2.bin $(SDK_BASE)/bin/blank.bin \
+ "$(SDK_BASE)/bin/boot_v1.4(b1).bin" wiflash release/esp-link
+ $(Q) tar zcf esp-link.tgz -C release esp-link
+ $(Q) rm -rf release
+
clean:
$(Q) rm -f $(APP_AR)
$(Q) rm -f $(TARGET_OUT)
diff --git a/html/index.tpl b/html/index.tpl
index 3d3c01c..ddb4f7d 100644
--- a/html/index.tpl
+++ b/html/index.tpl
@@ -3,6 +3,7 @@
diff --git a/serial/serbridge.c b/serial/serbridge.c
index bec6545..0cb5f83 100644
--- a/serial/serbridge.c
+++ b/serial/serbridge.c
@@ -8,19 +8,10 @@
#include "uart.h"
#include "serbridge.h"
+#include "serled.h"
#include "console.h"
-#if 1
-// GPIO for esp-03 module with gpio12->reset, gpio13->isp, gpio2->"ser" LED
-#define MCU_RESET 12
-#define MCU_ISP 13
-#define MCU_LED 2
-#else
-// GPIO for esp-01 module with gpio0->reset, gpio2->isp
-#define MCU_RESET 0
-#define MCU_ISP 2
-#undef MCU_LED
-#endif
+static uint8_t mcu_reset_pin, mcu_isp_pin;
static struct espconn serbridgeConn;
static esp_tcp serbridgeTcp;
@@ -88,6 +79,8 @@ static void ICACHE_FLASH_ATTR serbridgeSentCb(void *arg) {
//os_printf("%d ST\n", system_get_time());
conn->readytosend = true;
sendtxbuffer(conn); // send possible new data in txbuffer
+
+ serledFlash(50); // short blink on serial LED
}
// Telnet protocol characters
@@ -154,21 +147,21 @@ telnetUnwrap(uint8_t *inBuf, int len, uint8_t state)
case TN_setControl: // switch control line and delay a tad
switch (c) {
case DTR_ON:
- os_printf("MCU reset\n");
- GPIO_OUTPUT_SET(MCU_RESET, 0);
+ os_printf("MCU reset gpio%d\n", mcu_reset_pin);
+ GPIO_OUTPUT_SET(mcu_reset_pin, 0);
os_delay_us(100L);
break;
case DTR_OFF:
- GPIO_OUTPUT_SET(MCU_RESET, 1);
+ GPIO_OUTPUT_SET(mcu_reset_pin, 1);
os_delay_us(100L);
break;
case RTS_ON:
- os_printf("MCU ISP\n");
- GPIO_OUTPUT_SET(MCU_ISP, 0);
+ os_printf("MCU ISP gpio%d\n", mcu_isp_pin);
+ GPIO_OUTPUT_SET(mcu_isp_pin, 0);
os_delay_us(100L);
break;
case RTS_OFF:
- GPIO_OUTPUT_SET(MCU_ISP, 1);
+ GPIO_OUTPUT_SET(mcu_isp_pin, 1);
os_delay_us(100L);
break;
}
@@ -198,16 +191,16 @@ static void ICACHE_FLASH_ATTR serbridgeRecvCb(void *arg, char *data, unsigned sh
if ((len == 2 && strncmp(data, "0 ", 2) == 0) ||
(len == 2 && strncmp(data, "?\n", 2) == 0) ||
(len == 3 && strncmp(data, "?\r\n", 3) == 0)) {
- os_printf("MCU Reset=%d ISP=%d\n", MCU_RESET, MCU_ISP);
+ os_printf("MCU Reset=%d ISP=%d\n", mcu_reset_pin, mcu_isp_pin);
os_delay_us(2*1000L); // time for os_printf to happen
// send reset to arduino/ARM
- GPIO_OUTPUT_SET(MCU_RESET, 0);
+ GPIO_OUTPUT_SET(mcu_reset_pin, 0);
os_delay_us(100L);
- GPIO_OUTPUT_SET(MCU_ISP, 0);
+ GPIO_OUTPUT_SET(mcu_isp_pin, 0);
os_delay_us(100L);
- GPIO_OUTPUT_SET(MCU_RESET, 1);
+ GPIO_OUTPUT_SET(mcu_reset_pin, 1);
os_delay_us(100L);
- GPIO_OUTPUT_SET(MCU_ISP, 1);
+ GPIO_OUTPUT_SET(mcu_isp_pin, 1);
os_delay_us(1000L);
conn->conn_mode = cmAVR;
@@ -231,6 +224,8 @@ static void ICACHE_FLASH_ATTR serbridgeRecvCb(void *arg, char *data, unsigned sh
} else {
uart0_tx_buffer(data, len);
}
+
+ serledFlash(50); // short blink on serial LED
}
// Error callback (it's really poorly named, it's not a "connection reconnected" callback,
@@ -253,9 +248,9 @@ static void ICACHE_FLASH_ATTR serbridgeDisconCb(void *arg) {
{
if (connData[i].conn_mode == cmAVR) {
// send reset to arduino/ARM
- GPIO_OUTPUT_SET(MCU_RESET, 0);
+ GPIO_OUTPUT_SET(mcu_reset_pin, 0);
os_delay_us(100L);
- GPIO_OUTPUT_SET(MCU_RESET, 1);
+ GPIO_OUTPUT_SET(mcu_reset_pin, 1);
}
connData[i].conn = NULL;
}
@@ -303,7 +298,7 @@ serbridgeUartCb(char *buf, int length) {
}
// Start transparent serial bridge TCP server on specified port (typ. 23)
-void ICACHE_FLASH_ATTR serbridgeInit(int port) {
+void ICACHE_FLASH_ATTR serbridgeInit(int port, uint8_t reset_pin, uint8_t isp_pin) {
int i;
for (i = 0; i < MAX_CONN; i++) {
connData[i].conn = NULL;
@@ -314,13 +309,14 @@ void ICACHE_FLASH_ATTR serbridgeInit(int port) {
serbridgeTcp.local_port = port;
serbridgeConn.proto.tcp = &serbridgeTcp;
- PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, FUNC_GPIO12);
- PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U , FUNC_GPIO13);
- //GPIO_OUTPUT_SET(MCU_ISP, 1);
- //GPIO_OUTPUT_SET(MCU_RESET, 0);
-#ifdef MCU_LED
- GPIO_OUTPUT_SET(MCU_LED, 1);
-#endif
+ mcu_reset_pin = reset_pin;
+ mcu_isp_pin = isp_pin;
+ // set both pins to 1 so we don't cause a reset
+ GPIO_OUTPUT_SET(mcu_isp_pin, 1);
+ GPIO_OUTPUT_SET(mcu_reset_pin, 1);
+ // switch pin mux to make these pins GPIO pins
+ makeGpio(mcu_reset_pin);
+ makeGpio(mcu_isp_pin);
espconn_regist_connectcb(&serbridgeConn, serbridgeConnectCb);
espconn_accept(&serbridgeConn);
diff --git a/serial/serbridge.h b/serial/serbridge.h
index 22dc4a1..095b38a 100644
--- a/serial/serbridge.h
+++ b/serial/serbridge.h
@@ -32,7 +32,7 @@ struct serbridgeConnData {
uint8_t telnet_state;
};
-void ICACHE_FLASH_ATTR serbridgeInit(int port);
+void ICACHE_FLASH_ATTR serbridgeInit(int port, uint8_t reset_pin, uint8_t isp_pin);
void ICACHE_FLASH_ATTR serbridgeUartCb(char *buf, int len);
#endif /* __SER_BRIDGE_H__ */
diff --git a/serial/serled.c b/serial/serled.c
new file mode 100644
index 0000000..82390f8
--- /dev/null
+++ b/serial/serled.c
@@ -0,0 +1,79 @@
+#include
+#include
+
+static ETSTimer serledTimer;
+static uint8_t serledPin;
+
+static void ICACHE_FLASH_ATTR setSerled(int on) {
+ // LED is active-low
+ if (on) {
+ gpio_output_set(0, (1<cgiData;
@@ -48,6 +49,7 @@ int ICACHE_FLASH_ATTR cgiReadFlash(HttpdConnData *connData) {
*pos+=1024;
if (*pos>=0x40200000+(512*1024)) return HTTPD_CGI_DONE; else return HTTPD_CGI_MORE;
}
+#endif
//===== Cgi to query which firmware needs to be uploaded next
int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) {
diff --git a/user/console.c b/user/console.c
index c872b55..98cdb51 100644
--- a/user/console.c
+++ b/user/console.c
@@ -6,20 +6,27 @@
// Microcontroller console capturing the last 1024 characters received on the uart so
// they can be shown on a web page
+// Buffer to hold concole contents.
+// Invariants:
+// - console_rd==console_wr <=> buffer empty
+// - *console_rd == next char to read
+// - *console_wr == next char to write
+// - 0 <= console_xx < BUF_MAX
+// - (console_wr+1)%BUF_MAX) == console_rd <=> buffer full
#define BUF_MAX (1024)
static char console_buf[BUF_MAX];
static int console_wr, console_rd;
-static int console_pos; // offset since reset of console_rd position
+static int console_pos; // offset since reset of buffer
static void ICACHE_FLASH_ATTR
console_write(char c) {
- int wr = (console_wr+1)%BUF_MAX;
- if (wr == console_rd) {
+ console_buf[console_wr] = c;
+ console_wr = (console_wr+1) % BUF_MAX;
+ if (console_wr == console_rd) {
+ // full, we write anyway and loose the oldest char
console_rd = (console_rd+1) % BUF_MAX; // full, eat first char
console_pos++;
}
- console_buf[console_wr] = c;
- console_wr = wr;
}
// return previous character in console, 0 if at start
@@ -41,11 +48,13 @@ tplConsole(HttpdConnData *connData, char *token, void **arg) {
if (token==NULL) return HTTPD_CGI_DONE;
if (os_strcmp(token, "console") == 0) {
- if (console_wr < console_rd) {
+ if (console_wr > console_rd) {
httpdSend(connData, console_buf+console_rd, console_wr-console_rd);
} else if (console_rd != console_wr) {
httpdSend(connData, console_buf+console_rd, BUF_MAX-console_rd);
httpdSend(connData, console_buf, console_wr);
+ } else {
+ httpdSend(connData, "", -1);
}
} else if (os_strcmp(token, "head")==0) {
printHead(connData);
diff --git a/user/log.c b/user/log.c
index d1fd59b..9b4dd98 100644
--- a/user/log.c
+++ b/user/log.c
@@ -7,6 +7,7 @@
// The web log has a 1KB circular in-memory buffer which os_printf prints into and
// the HTTP handler simply displays the buffer content on a web page.
+// see consolse.c for invariants (same here)
#define BUF_MAX (1024)
static char log_buf[BUF_MAX];
static int log_wr, log_rd;
@@ -27,11 +28,10 @@ log_uart(bool enable) {
static void ICACHE_FLASH_ATTR
log_write(char c) {
- int wr = (log_wr+1)%BUF_MAX;
- if (wr == log_rd)
- log_rd = (log_rd+1) % BUF_MAX; // full, eat first char
log_buf[log_wr] = c;
- log_wr = wr;
+ log_wr = (log_wr+1) % BUF_MAX;
+ if (log_wr == log_rd)
+ log_rd = (log_rd+1) % BUF_MAX; // full, eat first char
}
#if 0
@@ -74,6 +74,8 @@ tplLog(HttpdConnData *connData, char *token, void **arg) {
} else if (log_rd != log_wr) {
httpdSend(connData, log_buf+log_rd, BUF_MAX-log_rd);
httpdSend(connData, log_buf, log_wr);
+ } else {
+ httpdSend(connData, "", -1);
}
} else if (os_strcmp(token, "head")==0) {
printHead(connData);
diff --git a/user/status.h b/user/status.h
index 0f89edf..4ce8b02 100644
--- a/user/status.h
+++ b/user/status.h
@@ -2,7 +2,7 @@
#define STATUS_H
void statusWifiUpdate(uint8_t state);
-void statusInit(void);
+void statusInit(uint8_t pin);
#endif
diff --git a/user/user_main.c b/user/user_main.c
index 219eea4..6892b5c 100644
--- a/user/user_main.c
+++ b/user/user_main.c
@@ -21,6 +21,7 @@
#include "uart.h"
#include "serbridge.h"
#include "status.h"
+#include "serled.h"
#include "console.h"
#include "log.h"
#define MCU_RESET 12
@@ -59,7 +60,7 @@ should be placed above the URLs they protect.
*/
HttpdBuiltInUrl builtInUrls[]={
{"/", cgiRedirect, "/index.tpl"},
- {"/flash/read", cgiReadFlash, NULL},
+ //{"/flash/read", cgiReadFlash, NULL},
{"/flash/next", cgiGetFirmwareNext, NULL},
{"/flash/upload", cgiUploadFirmware, NULL},
{"/flash/reboot", cgiRebootFirmware, NULL},
@@ -110,9 +111,12 @@ void user_init(void) {
uart_init(BIT_RATE_115200, BIT_RATE_115200);
// say hello (leave some time to cause break in TX after boot loader's msg
os_delay_us(10000L);
- os_printf("\n\nInitializing esp-link\n");
+# define VERS_STR_STR(V) #V
+# define VERS_STR(V) VERS_STR_STR(V)
+ os_printf("\n\nInitializing esp-link\n" VERS_STR(VERSION) "\n");
// Status LEDs
- statusInit();
+ statusInit(LED_CONN_PIN);
+ serledInit(LED_SERIAL_PIN);
// Wifi
wifiInit();
// init the flash filesystem with the html stuff
@@ -121,7 +125,7 @@ void user_init(void) {
// mount the http handlers
httpdInit(builtInUrls, 80);
// init the wifi-serial transparent bridge (port 23)
- serbridgeInit(23);
+ serbridgeInit(23, MCU_RESET_PIN, MCU_ISP_PIN);
uart_add_recv_cb(&serbridgeUartCb);
#ifdef SHOW_HEAP_USE
os_timer_disarm(&prHeapTimer);
diff --git a/wiflash b/wiflash
index e9f2671..d8c12ea 100755
--- a/wiflash
+++ b/wiflash
@@ -82,7 +82,7 @@ while true; do
next=`curl -m 10 $v -s "http://$hostname/flash/next"`
if [[ $? != 0 ]]; then
echo "Error retrieving http://$hostname/flash/next" >&2
- break
+ exit 1
fi
case "$next" in
user1.bin)
@@ -94,8 +94,8 @@ while true; do
fw="$user2"
break;;
*)
- echo "Cannot parse result of retrieving http://$hostname/flash/next" >&2
- sleep 2
+ echo "Error retrieving or parsing http://$hostname/flash/next" >&2
+ exit 1
;;
esac
done