diff --git a/esp-link/cgi.c b/esp-link/cgi.c index f2881cf..ba08c00 100644 --- a/esp-link/cgi.c +++ b/esp-link/cgi.c @@ -59,6 +59,23 @@ getStringArg(HttpdConnData *connData, char *name, char *config, int max_len) { return 1; } +// look for the HTTP arg 'name' and store it at 'config' as an 8-bit integer +// returns -1 on error, 0 if not found, 1 if found and OK +int8_t ICACHE_FLASH_ATTR +getInt8Arg(HttpdConnData *connData, char *name, int8_t *config) { + char buff[16]; + int len = httpdFindArg(connData->getArgs, name, buff, sizeof(buff)); + if (len < 0) return 0; // not found, skip + int m = atoi(buff); + if (len >= 6 || m < -128 || m > 255) { + os_sprintf(buff, "Value for %s out of range", name); + errorResponse(connData, 400, buff); + return -1; + } + *config = m; + return 1; +} + int8_t ICACHE_FLASH_ATTR getBoolArg(HttpdConnData *connData, char *name, bool*config) { char buff[64]; @@ -150,6 +167,10 @@ int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) { httpdHeader(connData, "Cache-Control", "max-age=3600, must-revalidate"); httpdHeader(connData, "Content-Type", "application/json"); httpdEndHeaders(connData); + // limit hostname to 12 chars + char name[13]; + os_strncpy(name, flashConfig.hostname, 12); + name[12] = 0; // construct json response os_sprintf(buff, "{\"menu\": [\"Home\", \"/home.html\", " @@ -160,7 +181,7 @@ int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) { #endif "\"Debug log\", \"/log.html\" ],\n" " \"version\": \"%s\"," - "\"name\":\"%s\"}", esp_link_version, flashConfig.sys_name); + "\"name\":\"%s\"}", esp_link_version, name); httpdSend(connData, buff, -1); return HTTPD_CGI_DONE; } diff --git a/esp-link/cgi.h b/esp-link/cgi.h index 2b8893c..e64b301 100644 --- a/esp-link/cgi.h +++ b/esp-link/cgi.h @@ -12,6 +12,10 @@ void errorResponse(HttpdConnData *connData, int code, char *message); // 'max_len' (incl terminating zero), returns -1 on error, 0 if not found, 1 if found int8_t getStringArg(HttpdConnData *connData, char *name, char *config, int max_len); +// Get the HTTP query-string param 'name' and store it as a int8 value at 'config', +// supports signed and unsigned, returns -1 on error, 0 if not found, 1 if found +int8_t getInt8Arg(HttpdConnData *connData, char *name, int8_t *config); + // Get the HTTP query-string param 'name' and store it boolean value at 'config', // supports 1/true and 0/false, returns -1 on error, 0 if not found, 1 if found int8_t getBoolArg(HttpdConnData *connData, char *name, bool*config); diff --git a/esp-link/cgipins.c b/esp-link/cgipins.c index da4a8d1..913d9fa 100644 --- a/esp-link/cgipins.c +++ b/esp-link/cgipins.c @@ -7,6 +7,7 @@ #include "status.h" #include "serbridge.h" +#if 0 static char *map_names[] = { "esp-bridge", "jn-esp-v2", "esp-01(AVR)", "esp-01(ARM)", "esp-br-rev", "wifi-link-12", }; @@ -21,46 +22,19 @@ static int8_t map_asn[][5] = { }; static const int num_map_names = sizeof(map_names)/sizeof(char*); static const int num_map_func = sizeof(map_func)/sizeof(char*); +#endif // Cgi to return choice of pin assignments int ICACHE_FLASH_ATTR cgiPinsGet(HttpdConnData *connData) { if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted - char buff[2048]; + char buff[1024]; int len; - // figure out current mapping - int curr = 0; - for (int i=0; i= 0) - len += os_sprintf(buff+len, " %s:gpio%d", map_func[f], p); - else - len += os_sprintf(buff+len, " %s:n/a", map_func[f]); - } - len += os_sprintf(buff+len, "\" }"); - } - len += os_sprintf(buff+len, "\n] }"); + len = os_sprintf(buff, + "{ \"reset\":%d, \"isp\":%d, \"conn\":%d, \"ser\":%d, \"swap\":%d, \"rxpup\":%d }", + flashConfig.reset_pin, flashConfig.isp_pin, flashConfig.conn_led_pin, + flashConfig.ser_led_pin, !!flashConfig.swap_uart, 1); jsonHeader(connData, 200); httpdSend(connData, buff, len); @@ -73,41 +47,73 @@ int ICACHE_FLASH_ATTR cgiPinsSet(HttpdConnData *connData) { return HTTPD_CGI_DONE; // Connection aborted } - char buff[128]; - int len = httpdFindArg(connData->getArgs, "map", buff, sizeof(buff)); - if (len <= 0) { - jsonHeader(connData, 400); - return HTTPD_CGI_DONE; - } + int8_t ok = 0; + int8_t reset, isp, conn, ser; + bool swap, rxpup; + ok |= getInt8Arg(connData, "reset", &reset); + ok |= getInt8Arg(connData, "isp", &isp); + ok |= getInt8Arg(connData, "conn", &conn); + ok |= getInt8Arg(connData, "ser", &ser); + ok |= getBoolArg(connData, "swap", &swap); + ok |= getBoolArg(connData, "rxpup", &rxpup); + if (ok < 0) return HTTPD_CGI_DONE; - int m = atoi(buff); - if (m < 0 || m >= num_map_names) { - jsonHeader(connData, 400); - return HTTPD_CGI_DONE; - } -#ifdef CGIPINS_DBG - os_printf("Switching pin map to %s (%d)\n", map_names[m], m); -#endif - int8_t *map = map_asn[m]; - flashConfig.reset_pin = map[0]; - flashConfig.isp_pin = map[1]; - flashConfig.conn_led_pin = map[2]; - flashConfig.ser_led_pin = map[3]; - flashConfig.swap_uart = map[4]; + char *coll; + if (ok > 0) { + // check whether two pins collide + uint16_t pins = 0; + if (reset >= 0) pins = 1 << reset; + if (isp >= 0) { + if (pins & (1<= 0) { + if (pins & (1<= 0) { + if (pins & (1<reason, rst_codes[rst_info->reason], + flashConfig.hostname, rst_info->reason, rst_codes[rst_info->reason], flash_maps[system_get_flash_size_map()], fid & 0xff, (fid&0xff00)|((fid>>16)&0xff), part_id ? "user2.bin" : "user1.bin", flashConfig.slip_enable ? "enabled" : "disabled", @@ -134,7 +134,7 @@ static int ICACHE_FLASH_ATTR cgiSystemSet(HttpdConnData *connData) { if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up. int8_t status = 0; - status |= getStringArg(connData, "name", flashConfig.sys_name, sizeof(flashConfig.sys_name)); + status |= getStringArg(connData, "name", flashConfig.hostname, sizeof(flashConfig.hostname)); status |= getStringArg(connData, "description", flashConfig.sys_descr, sizeof(flashConfig.sys_descr)); if (status < 0) return HTTPD_CGI_DONE; // getStringArg has produced an error response @@ -172,7 +172,6 @@ void user_init(void) { os_delay_us(10000L); os_printf("\n\n** %s\n", esp_link_version); os_printf("Flash config restore %s\n", restoreOk ? "ok" : "*FAILED*"); - if (flashConfig.sys_name[0] == 0) os_strcpy(flashConfig.sys_name, "name-me"); #if defined(STA_SSID) && defined(STA_PASS) int x = wifi_get_opmode() & 0x3; diff --git a/html/home.html b/html/home.html index 69dccff..2e0e0bc 100644 --- a/html/home.html +++ b/html/home.html @@ -7,65 +7,132 @@
-
-

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. Typical avrdude command line to - program an Arduino:

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

where -Pnet:esp-link.local:23 tells avrdude to connect to port 23 of esp-link. - You can substitute the IP address of your esp-link for esp-link.local if necessary. - Please refer to - the online README - for up-to-date help.

-
-
-
+
-

Wifi summary

+

System overview

- - - - - - + + + + + + +
-

Esp-link summary

+

Info

+

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. Typical avrdude command line to + program an Arduino:

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

where -Pnet:esp-link.local:23 tells avrdude to connect to port 23 of esp-link. + You can substitute the IP address of your esp-link for esp-link.local if necessary. + Please refer to + the online README + for up-to-date help.

+
+
+ +
+
+

Pin assignment

+
+ +
+
+

System details

- - + + + + - - - -
-
-

Pin assignment

- Select one of the following signal/pin assignments to match your hardware -
-
-
-
@@ -76,9 +143,11 @@ diff --git a/html/style.css b/html/style.css index e105354..d3f9348 100644 --- a/html/style.css +++ b/html/style.css @@ -42,16 +42,71 @@ a:hover { background-color: #eee; width: 100%; } -div.edit-on.popup { +.click-to-edit span, .click-to-edit div { + /*background-color: #e0e0e0;*/ + /*color: #1c0099;*/ + padding: 0.3em; + width: 100%; + color: #444; /* rgba not supported (IE 8) */ + color: rgba(0, 0, 0, 0.80); /* rgba supported */ + border: 1px solid #999; /*IE 6/7/8*/ + border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/ + background-color: #E6E6E6; + text-decoration: none; + border-radius: 2px; +} +.click-to-edit span:hover, .click-to-edit div:hover, +.click-to-edit span:focus, .click-to-edit div:focus { + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000',GradientType=0); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(transparent), color-stop(40%, rgba(0,0,0, 0.05)), to(rgba(0,0,0, 0.10))); + background-image: -webkit-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); + background-image: -moz-linear-gradient(top, rgba(0,0,0, 0.05) 0%, rgba(0,0,0, 0.10)); + background-image: -o-linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); + background-image: linear-gradient(transparent, rgba(0,0,0, 0.05) 40%, rgba(0,0,0, 0.10)); +} +.click-to-edit span:focus, .click-to-edit div:focus { + outline: 0; +} +.click-to-edit span:active, .click-to-edit div:active { + box-shadow: 0 0 0 1px rgba(0,0,0, 0.15) inset, 0 0 6px rgba(0,0,0, 0.20) inset; + border-color: #000\9; +} +/* Firefox: Get rid of the inner focus border */ +.click-to-edit span::-moz-focus-inner, +.click-to-edit div::-moz-focus-inner { + padding: 0; + border: 0; +} + +/* pop-ups */ +.popup-hidden { + display: none; +} +.popup, div.popup { position: absolute; - top: 100%; - left: 20px; - background-color: cornsilk; + /*top: 100%;*/ + bottom: 100%; + background-color: #fff0b3; + border-radius: 5px; + border: 0px solid #000; color: #333; font-size: 80%; line-height: 110%; z-index: 100; - padding: 3px; + padding: 5px; + min-width: 20em; +} +.popup:not(.pop-left) { + left: 20px; +} +.popup.pop-left { + right: 20px; +} +.popup-target:hover .popup { + display: block; +} +.popup-target { + position: relative; } /* wifi AP selection form */ @@ -81,6 +136,16 @@ fieldset fields { padding: 0.5em 0.5em; } +/* Narrow left-aligned Forms */ +.pure-form-aligned.form-narrow .pure-control-group label { + text-align: left; + width: 6em; +} +.pure-form-aligned.form-narrow input[type=checkbox], +.pure-form-aligned.form-narrow input[type=radio] { + float: none; +} + /* make images size-up */ .xx-pure-img-responsive { max-width: 100%; @@ -172,6 +237,10 @@ select.pure-button { padding: 0.465em 1em; color: #009; /* same as a:link */ } +.button-small { + font-size: 75%; + background: #ccc; +} input.inline { float:none; diff --git a/html/ui.js b/html/ui.js index 8268385..a9bef1d 100644 --- a/html/ui.js +++ b/html/ui.js @@ -213,6 +213,11 @@ function ajaxJsonSpin(method, url, ok_cb, err_cb) { //===== main menu, header spinner and notification boxes +function hidePopup(el) { + addClass(el, "popup-hidden"); + addClass(el.parentNode, "popup-target"); +} + onLoad(function() { var l = $("#layout"); var o = l.childNodes[0]; @@ -229,11 +234,7 @@ onLoad(function() {
\ \  esp-link\ -
\ - \ - \ - \ -
\ +
\ \
\
\ @@ -251,6 +252,11 @@ onLoad(function() { toggleClass(ml, active); }); + // hide pop-ups + domForEach($(".popup"), function(el) { + hidePopup(el); + }); + // populate menu via ajax call var getMenu = function() { ajaxJson("GET", "/menu", function(data) { @@ -267,8 +273,7 @@ onLoad(function() { var v = $("#version"); if (v != null) { v.innerHTML = data.version; } - setEditToClick("system-name", data.name); - makeAjaxInput("system", "name"); + setEditToClick("system-name", data["name"]); }, function() { setTimeout(getMenu, 1000); }); }; getMenu(); @@ -313,7 +318,7 @@ function setEditToClick(klass, value) { function showSystemInfo(data) { Object.keys(data).forEach(function(v) { - setEditToClick("system-" + v, data[v]); + setEditToClick("system-"+v, data[v]); }); $("#system-spinner").setAttribute("hidden", ""); $("#system-table").removeAttribute("hidden"); @@ -331,6 +336,8 @@ function makeAjaxInput(klass, field) { var eoff = $(".edit-off", div)[0]; var url = "/"+klass+"/update?"+field; + if (eoff === undefined || eon == undefined) return; + var enableEditToClick = function() { eoff.setAttribute('hidden',''); domForEach(eon, function(el){ el.removeAttribute('hidden'); }); @@ -366,6 +373,7 @@ function showWarning(text) { var el = $("#warning"); el.innerHTML = text; el.removeAttribute('hidden'); + window.scrollTo(0, 0); } function hideWarning() { el = $("#warning").setAttribute('hidden', ''); @@ -384,36 +392,70 @@ function showNotification(text) { //===== GPIO Pin mux card -var currPin; -// pin={reset:12, isp:13, LED_conn:0, LED_ser:2} -function createInputForPin(pin) { - var input = document.createElement("input"); - input.type = "radio"; - input.name = "pins"; - input.data = pin.name; - input.className = "pin-input"; - input.value= pin.value; - input.id = "opt-" + pin.value; - if (currPin == pin.name) input.checked = "1"; - - var descr = m('"); - var div = document.createElement("div"); - div.appendChild(input); - div.appendChild(descr); - return div; +var pinPresets = { + // array: reset, isp, conn, ser, swap, rxpup + "esp-01": [ 0, -1, 2, -1, 0, 1 ], + "esp-12": [ 12, 14, 0, 2, 0, 1 ], + "esp-12 swap": [ 1, 3, 0, 2, 1, 1 ], + "esp-bridge": [ 12, 13, 0, 14, 0, 0 ], + "wifi-link-12": [ 1, 3, 0, 2, 1, 0 ], +}; + +function createPresets(sel) { + for (var p in pinPresets) { + var opt = m(''); + sel.appendChild(opt); + } + + function applyPreset(v) { + var pp = pinPresets[v]; + if (pp === undefined) return pp; + console.log("apply preset:", v, pp); + function setPP(k, v) { $("#pin-"+k).value = v; }; + setPP("reset", pp[0]); + setPP("isp", pp[1]); + setPP("conn", pp[2]); + setPP("ser", pp[3]); + setPP("swap", pp[4]); + $("#pin-rxpup").checked = !!pp[5]; + }; + + bnd(sel, "change", function(ev) { + console.log("preset change:", sel.value); + ev.preventDefault(); + applyPreset(sel.value); + }); } function displayPins(resp) { - var po = $("#pin-mux"); - po.innerHTML = ""; - currPin = resp.curr; - resp.map.forEach(function(v) { - po.appendChild(createInputForPin(v)); - }); - var i, inputs = $(".pin-input"); - for (i=0; i= 0) opt.innerHTML = "gpio"+i; + else opt.innerHTML = "disabled"; + if (i===1) opt.innerHTML += "/TX0"; + if (i===2) opt.innerHTML += "/TX1"; + if (i===3) opt.innerHTML += "/RX0"; + if (i==v) opt.selected = true; + sel.appendChild(opt); + }); + var pup = $(".popup", sel.parentNode); + if (pup !== undefined) hidePopup(pup[0]); }; + + createSelectForPin("reset", resp["reset"]); + createSelectForPin("isp", resp["isp"]); + createSelectForPin("conn", resp["conn"]); + createSelectForPin("ser", resp["ser"]); + $("#pin-swap").value = resp["swap"]; + $("#pin-rxpup").checked = !!resp["rxpup"]; + createPresets($("#pin-preset")); + + $("#pin-spinner").setAttribute("hidden", ""); + $("#pin-table").removeAttribute("hidden"); } function fetchPins() { @@ -423,10 +465,17 @@ function fetchPins() { } function setPins(v, name) { - ajaxSpin("POST", "/pins?map="+v, function() { - showNotification("Pin assignment changed to " + name); - }, function() { - showNotification("Pin assignment change failed"); + var url = "/pins"; + var sep = "?"; + ["reset", "isp", "conn", "ser", "swap"].forEach(function(p) { + url += sep + p + "=" + $("#pin-"+p).value; + sep = "&"; + }); + url += "&rxpup=" + ($("#pin-rxpup").selected ? "1" : "0"); + ajaxSpin("POST", url, function() { + showNotification("Pin assignment changed"); + }, function(status, errMsg) { + showWarning(errMsg); window.setTimeout(fetchPins, 100); }); } diff --git a/html/wifi/wifi.html b/html/wifi/wifi.html index 4ddfc20..200cf53 100644 --- a/html/wifi/wifi.html +++ b/html/wifi/wifi.html @@ -30,7 +30,8 @@
Scanning...
@@ -51,10 +52,7 @@ Static IP -
- - -
+
diff --git a/serial/serbridge.c b/serial/serbridge.c index da8835a..c996b9a 100644 --- a/serial/serbridge.c +++ b/serial/serbridge.c @@ -446,11 +446,15 @@ serbridgeInitPins() PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 4); PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 4); PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTCK_U); - PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTDO_U); + if (flashConfig.rx_pullup) PIN_PULLUP_EN(PERIPHS_IO_MUX_MTDO_U); + else PIN_PULLUP_DIS(PERIPHS_IO_MUX_MTDO_U); system_uart_swap(); } else { PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, 0); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, 0); + PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); + if (flashConfig.rx_pullup) PIN_PULLUP_EN(PERIPHS_IO_MUX_U0RXD_U); + else PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0RXD_U); system_uart_de_swap(); } diff --git a/serial/uart.c b/serial/uart.c index 5358cf1..8e61f7e 100644 --- a/serial/uart.c +++ b/serial/uart.c @@ -56,10 +56,10 @@ uart_config(uint8 uart_no) } else { /* rcv_buff size is 0x100 */ ETS_UART_INTR_ATTACH(uart0_rx_intr_handler, &(UartDev.rcv_buff)); - PIN_PULLUP_DIS (PERIPHS_IO_MUX_U0TXD_U); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_U0TXD); - PIN_PULLUP_DIS (PERIPHS_IO_MUX_U0RXD_U); PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0RXD_U, 0); // FUNC_U0RXD==0 + //PIN_PULLUP_DIS (PERIPHS_IO_MUX_U0TXD_U); now done in serbridgeInitPins + //PIN_PULLUP_DIS (PERIPHS_IO_MUX_U0RXD_U); } uart_div_modify(uart_no, UART_CLK_FREQ / UartDev.baut_rate);