From 49a2d01f978c0e671b80ceac439e2e1a9f20be73 Mon Sep 17 00:00:00 2001 From: Thorsten von Eicken Date: Fri, 19 Jun 2015 12:30:59 -0700 Subject: [PATCH] lots of UI tweaks --- BOARDS.md | 2 +- Makefile | 6 +++-- espfs/mkespfsimage/main.c | 6 ++--- html/console.tpl | 2 +- html/head.tpl | 5 ++-- html/help.tpl | 17 ------------ html/home.tpl | 19 +++++++++++--- html/jl-200x55.png | Bin 0 -> 2751 bytes html/jl-400x110.png- | Bin 0 -> 4085 bytes html/log.tpl | 2 +- html/style.css | 54 +++++++++++++++++++++----------------- html/wifi/wifi.tpl | 4 +-- user/cgi.c | 3 +-- user/cgipins.c | 2 +- user/log.c | 4 +-- 15 files changed, 65 insertions(+), 61 deletions(-) delete mode 100644 html/help.tpl create mode 100755 html/jl-200x55.png create mode 100755 html/jl-400x110.png- diff --git a/BOARDS.md b/BOARDS.md index b98f831..3d01799 100644 --- a/BOARDS.md +++ b/BOARDS.md @@ -1,4 +1,4 @@ -Boards with ESP-Link +Boards with esp-link ==================== This readme provides instructions for PCBs that I've made that are designed for esp-link. diff --git a/Makefile b/Makefile index 27fd4cd..1b2820b 100644 --- a/Makefile +++ b/Makefile @@ -189,7 +189,7 @@ $1/%.o: %.c $(Q) $(CC) $(INCDIR) $(MODULE_INCDIR) $(EXTRA_INCDIR) $(SDK_INCDIR) $(CFLAGS) -c $$< -o $$@ endef -.PHONY: all checkdirs clean webpages.espfs +.PHONY: all checkdirs clean webpages.espfs wiflash all: echo_version checkdirs $(FW_BASE) firmware/user1.bin firmware/user2.bin @@ -199,7 +199,8 @@ echo_version: $(TARGET_OUT): $(APP_AR) $(LD_SCRIPT) $(vecho) "LD $@" $(Q) $(LD) -L$(SDK_LIBDIR) -T$(LD_SCRIPT) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@ - $(OBJDP) -x $(TARGET_OUT) | egrep '(espfs_img)' + @echo Dump: $(OBJDP) -x $(TARGET_OUT) +# $(OBJDP) -x $(TARGET_OUT) | egrep '(espfs_img)' $(USER1_OUT): $(APP_AR) $(LD_SCRIPT1) $(vecho) "LD $@" @@ -269,6 +270,7 @@ ifeq ("$(COMPRESS_W_YUI)","yes") $(Q) cd html_compressed; find | ../espfs/mkespfsimage/mkespfsimage > ../build/espfs.img; cd ..; else $(Q) cd html; find . \! -name \*- | ../espfs/mkespfsimage/mkespfsimage > ../build/espfs.img; cd .. + $(Q) ls -sl build/espfs.img endif $(Q) cd build; $(OBJCP) -I binary -O elf32-xtensa-le -B xtensa --rename-section .data=.espfs \ espfs.img espfs_img.o; cd .. diff --git a/espfs/mkespfsimage/main.c b/espfs/mkespfsimage/main.c index 64187ff..7c2d958 100644 --- a/espfs/mkespfsimage/main.c +++ b/espfs/mkespfsimage/main.c @@ -20,7 +20,7 @@ //Gzip #ifdef ESPFS_GZIP -// If compiler complains about missing header, try running "sudo apt-get install zlib1g-dev" +// If compiler complains about missing header, try running "sudo apt-get install zlib1g-dev" // to install missing package. #include #endif @@ -229,7 +229,7 @@ int handleFile(int f, char *name, int compression, int level, char **compName) { h.nameLen=htoxs(h.nameLen); h.fileLenComp=htoxl(csize); h.fileLenDecomp=htoxl(size); - + write(1, &h, sizeof(EspFsHeader)); write(1, name, nameLen); while (nameLen&3) { @@ -309,7 +309,7 @@ int main(int argc, char **argv) { #ifdef ESPFS_GZIP if (gzipExtensions == NULL) { - parseGzipExtensions(strdup("html,css,js")); + parseGzipExtensions(strdup("html,css,js,ico")); } #endif diff --git a/html/console.tpl b/html/console.tpl index e45bb63..395b6d1 100644 --- a/html/console.tpl +++ b/html/console.tpl @@ -1,6 +1,6 @@
-

esp link - Microcontroller Console

+

Microcontroller Console

diff --git a/html/head.tpl b/html/head.tpl index 17de31f..f7ceaf9 100644 --- a/html/head.tpl +++ b/html/head.tpl @@ -1,6 +1,6 @@ - ESP Link + esp-link @@ -18,7 +18,8 @@ diff --git a/html/help.tpl b/html/help.tpl deleted file mode 100644 index e022025..0000000 --- a/html/help.tpl +++ /dev/null @@ -1,17 +0,0 @@ -
-
-

esp link - Help

-
- -
- -

Please refer to -the online README -for up-to-date help.

- -
-
-
- - - diff --git a/html/home.tpl b/html/home.tpl index 73bb10a..e9c1e22 100644 --- a/html/home.tpl +++ b/html/home.tpl @@ -1,15 +1,28 @@
-

esp link

+
+

esp-link

-

The ESP Link bridges the ESP8266 serial port to Wifi and it can +

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-series ARM processors.

+ NXP's LPC800 and other ARM processors.

+

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

/home/arduino-1.0.5/hardware/tools/avrdude \
+   -DV -patmega328p -Pnet:esp-link.local:23 -carduino -b115200 -U \
+   -C /home/arduino-1.0.5/hardware/tools/avrdude.conf flash:w:my_sketch.hex:i +
+ where -Pnet:esp-link.local:23 tells avrdude to connect to port 23 of esp-link. + You can substitute the IP address of your esp-link for esp-link.local if necessary.

+

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

diff --git a/html/jl-200x55.png b/html/jl-200x55.png new file mode 100755 index 0000000000000000000000000000000000000000..3bc4a42cdfe781b8e1b0a9e2dc48e6b6e8577a4c GIT binary patch literal 2751 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 FV1fk~Lhb+n literal 0 HcmV?d00001 diff --git a/html/jl-400x110.png- b/html/jl-400x110.png- new file mode 100755 index 0000000000000000000000000000000000000000..92d2d9e27ab688a31f36f3d8f4aeac05215ba881 GIT binary patch literal 4085 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 literal 0 HcmV?d00001 diff --git a/html/log.tpl b/html/log.tpl index 3003168..70e5f2b 100644 --- a/html/log.tpl +++ b/html/log.tpl @@ -1,6 +1,6 @@
-

esp link - Debug Log

+

Debug Log

diff --git a/html/style.css b/html/style.css index 78efb8c..034d2c3 100644 --- a/html/style.css +++ b/html/style.css @@ -6,6 +6,12 @@ html, button, input, select, textarea, .pure-g [class *= "pure-u"] { body { color: #777; } +a:visited, a:link { + color: #009; +} +a:hover { + color: #00c; +} .card { background-color: #eee; @@ -74,6 +80,16 @@ fieldset fields { left: 150px; } +div.tt { + font-family: monospace; + font-size: 120%; + color: #390; + background-color: #ddd; + padding: 2px; + margin: 2px 0; + line-height: 100%; +} + /* The content `
` */ .content { margin: 0 auto; @@ -133,59 +149,57 @@ pre.console a { display: inline-block; } -/* The `#menu` `
` is the parent `
` that contains the `.pure-menu` that - * appears on the left side of the page */ #menu { - margin-left: -150px; /* "#menu" width */ + margin-left: -150px; width: 150px; position: fixed; top: 0; left: 0; bottom: 0; - z-index: 1000; /* so the menu or its navicon stays above all content */ + z-index: 1000; background: #191818; overflow-y: auto; -webkit-overflow-scrolling: touch; } -/* All anchors inside the menu should be styled like this */ #menu a { color: #999; border: none; padding: 0.6em 0 0.6em 0.6em; } -/* Remove all background/borders, since we are applying them to #menu */ #menu .pure-menu, #menu .pure-menu ul { border: none; background: transparent; } -/* Add that light border to separate items into groups */ #menu .pure-menu ul, #menu .pure-menu .menu-item-divided { border-top: 1px solid #333; } -/* Change color of the anchor links on hover/focus */ #menu .pure-menu li a:hover, #menu .pure-menu li a:focus { background: #333; } -/* This styles the selected menu item `
  • ` */ #menu .pure-menu-selected, #menu .pure-menu-heading { - background: #c60; + background: #9d1414; } -/* This styles a link within a selected menu item `
  • ` */ #menu .pure-menu-selected a { color: #fff; } -/* This styles the menu heading */ #menu .pure-menu-heading { font-size: 110%; color: #fff; margin: 0; + text-transform: none; +} + +#menu .pure-menu-heading img { + vertical-align: middle; + top: -1px; + position: relative; } #menu .pure-menu-item { @@ -194,15 +208,14 @@ pre.console a { /* -- Dynamic Button For Responsive Menu -------------------------------------*/ -/* `.menu-link` represents the responsive menu toggle that shows/hides on small screens */ .menu-link { position: fixed; - display: block; /* show this only on small screens */ + display: block; top: 0; - left: 0; /* "#menu width" */ + left: 0; background: #000; background: rgba(0,0,0,0.7); - font-size: 10px; /* change this value to increase/decrease button size */ + font-size: 10px; z-index: 10; width: 2em; height: auto; @@ -236,7 +249,6 @@ pre.console a { /* -- Responsive Styles (Media Queries) ------------------------------------- */ -/* Hides the menu at `48em`, but modify this based on your app's needs */ @media (min-width: 48em) { .header, .content { padding-left: 2em; @@ -244,7 +256,7 @@ pre.console a { } #layout { - padding-left: 150px; /* left col width "#menu" */ + padding-left: 150px; left: 0; } #menu { @@ -263,12 +275,6 @@ pre.console a { } @media (max-width: 48em) { - /* Only apply this when the window is small. Otherwise, the following - case results in extra padding on the left: - * Make the window small. - * Tap the menu to trigger the active state. - * Make the window large again. - */ #layout.active { position: relative; left: 150px; diff --git a/html/wifi/wifi.tpl b/html/wifi/wifi.tpl index 946c59d..a83ad3f 100644 --- a/html/wifi/wifi.tpl +++ b/html/wifi/wifi.tpl @@ -1,6 +1,6 @@
    -

    esp link - Wifi Configuration

    +

    Wifi Configuration

    @@ -147,7 +147,7 @@ function getStatus() { showWifiInfo(data); blockScan = 0; - var txt2 = "ESP Link will switch to STA-only mode in a few seconds"; + var txt2 = "esp-link will switch to STA-only mode in a few seconds"; window.setTimeout(function() { showNotification(txt2); }, 4000); $("#reconnect").removeAttribute("hidden"); diff --git a/user/cgi.c b/user/cgi.c index ec55dfe..35e0080 100644 --- a/user/cgi.c +++ b/user/cgi.c @@ -54,8 +54,7 @@ void ICACHE_FLASH_ATTR printGlobalJSON(HttpdConnData *connData) { httpdSend(connData, "