diff --git a/Makefile b/Makefile index 070a1f5..fc10531 100644 --- a/Makefile +++ b/Makefile @@ -90,9 +90,10 @@ LED_SERIAL_PIN ?= 14 # on the release tag, make release, upload esp-link.tgz into the release files #VERSION ?= "esp-link custom version" DATE := $(shell date '+%F %T') -BRANCH := $(shell git describe --tags) +BRANCH := $(shell if git diff --quiet HEAD; then git describe --tags; \ + else git symbolic-ref --short HEAD; fi) SHA := $(shell if git diff --quiet HEAD; then git rev-parse --short HEAD | cut -d"/" -f 3; \ - else echo "development"; fi) + else echo "development"; fi) VERSION ?=esp-link $(BRANCH) - $(DATE) - $(SHA) # --------------- esp-link config options --------------- @@ -142,11 +143,13 @@ TARGET = httpd APPGEN_TOOL ?= gen_appbin.py # which modules (subdirectories) of the project to include in compiling -MODULES = espfs httpd user serial cmd mqtt esp-link -EXTRA_INCDIR = include . +LIBRARIES_DIR = libraries +MODULES = espfs httpd user serial cmd mqtt esp-link +MODULES += $(foreach sdir,$(LIBRARIES_DIR),$(wildcard $(sdir)/*)) +EXTRA_INCDIR = include . include/json # libraries used in this project, mainly provided by the SDK -LIBS = c gcc hal phy pp net80211 wpa main lwip +LIBS = c gcc hal phy pp net80211 wpa main lwip json # compiler flags using during compilation of source files CFLAGS = -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \ @@ -285,7 +288,7 @@ baseflash: all $(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash 0x01000 $(FW_BASE)/user1.bin flash: all - $(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) -fs $(ET_FS) -ff $(ET_FF) write_flash \ + $(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash -fs $(ET_FS) -ff $(ET_FF) \ 0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin \ $(ET_BLANK) $(SDK_BASE)/bin/blank.bin @@ -350,10 +353,13 @@ espfs/mkespfsimage/mkespfsimage: espfs/mkespfsimage/ $(Q) $(MAKE) -C espfs/mkespfsimage GZIP_COMPRESSION="$(GZIP_COMPRESSION)" release: all - $(Q) rm -rf release; mkdir -p release/esp-link + $(Q) rm -rf release; mkdir -p release/esp-link-$(BRANCH) + $(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.4(b1).bin" wiflash release/esp-link - $(Q) tar zcf esp-link.tgz -C release esp-link + "$(SDK_BASE)/bin/boot_v1.4(b1).bin" wiflash release/esp-link-$(BRANCH) + $(Q) tar zcf esp-link-$(BRANCH)-$(FLASH_SIZE).tgz -C release esp-link-$(BRANCH) + $(Q) echo "Release file: esp-link-$(BRANCH)-$(FLASH_SIZE).tgz" $(Q) rm -rf release clean: diff --git a/README.md b/README.md index e7898ae..34d3090 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,24 @@ It implements a number of features: - flash-programming attached Arduino/AVR microcontrollers as well as LPC800-series and other ARM microcontrollers via Wifi - outbound TCP (and thus HTTP) connections from the attached micro-controller to the internet +- outbound REST HTTP requests from the attached micro-controller to the internet, protocol + based on espduino and compatible with [tuanpmt/espduino](https://github.com/tuanpmt/espduino) The firmware includes a tiny HTTP server based on [esphttpd](http://www.esp8266.com/viewforum.php?f=34) with a simple web interface, many thanks to Jeroen Domburg for making it available! +Many thanks to https://github.com/brunnels for contributions around the espduino functionality. -[![Chat at https://gitter.im/jeelabs/esp-link](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jeelabs/esp-link?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +###[Releases](https://github.com/jeelabs/esp-link/releases) + +- [V2.0.beta2](https://github.com/jeelabs/esp-link/releases/tag/v2.0.beta2) has REST support but + requires a 1MByte or 4MByte ESP8266 flash, e.g. esp-12 or wroom-02 +- [V1.0.1](https://github.com/jeelabs/esp-link/releases/tag/v1.0.1) is _stable_ + and has the web server, transparent bridge, flash-programming support, but lacks + the REST and upcoming MQTT support. V1 works with 512KB flash, e.g. esp-1, esp-3, ... -###[Latest release](https://github.com/jeelabs/esp-link/releases) -Note that the [stable V1.0 release](https://github.com/jeelabs/esp-link/releases/tag/v1.0.0) is -recommended if you do not need the outbound TCP connections and have a 512KB flash chip. +For quick support and questions: +[![Chat at https://gitter.im/jeelabs/esp-link](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jeelabs/esp-link?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) Eye Candy --------- @@ -31,7 +39,7 @@ attached microcontroller, and the pin assignments card: Hardware info ------------- This firmware is designed for esp8266 modules which have most ESP I/O pins available and -512KB flash. +at least 1MB flash. (The V1 firmware supports modules with 512KB flash). The default connections are: - URXD: connect to TX of microcontroller - UTXD: connect to RX of microcontroller @@ -42,6 +50,9 @@ The default connections are: If you are using an FTDI connector, GPIO12 goes to DTR and GPIO13 goes to CTS. +If you are using an esp-12 module, you can avoid the initial boot message from the esp8266 +bootloader by using the swap-pins option. This swaps the esp8266 TX/RX to gpio15/gpio13 respectively. + The GPIO pin assignments can be changed dynamically in the web UI and are saved in flash. Initial flashing diff --git a/cmd/cmd.c b/cmd/cmd.c index 64aeef7..07a92a5 100644 --- a/cmd/cmd.c +++ b/cmd/cmd.c @@ -83,22 +83,30 @@ CMD_Exec(const CmdList *scp, CmdPacket *packet) { // Iterate through the command table and call the appropriate function while (scp->sc_function != NULL) { if(scp->sc_name == packet->cmd) { - //os_printf("CMD: Dispatching cmd=%d\n", packet->cmd); +#ifdef CMD_DBG + os_printf("CMD: Dispatching cmd=%d\n", packet->cmd); +#endif // call command function uint32_t ret = scp->sc_function(packet); // if requestor asked for a response, send it if (packet->_return){ +#ifdef CMD_DBG os_printf("CMD: Response: 0x%lx, cmd: %d\r\n", ret, packet->cmd); +#endif crc = CMD_ResponseStart(packet->cmd, 0, ret, 0); CMD_ResponseEnd(crc); } else { - //os_printf("CMD: no response (%lu)\n", packet->_return); +#ifdef CMD_DBG + os_printf("CMD: no response (%lu)\n", packet->_return); +#endif } return ret; } scp++; } +#ifdef CMD_DBG os_printf("CMD: cmd=%d not found\n", packet->cmd); +#endif return 0; } @@ -112,27 +120,36 @@ CMD_parse_packet(uint8_t *buf, short len) { CmdPacket *packet = (CmdPacket*)buf; uint8_t *data_ptr = (uint8_t*)&packet->args; uint8_t *data_limit = data_ptr+len; - uint16_t argc = packet->argc; + uint16_t argc = packet->argc; +#ifdef CMD_DBG uint16_t argn = 0; - os_printf("CMD: cmd=%d argc=%d cb=%p ret=%lu\n", packet->cmd, packet->argc, (void *)packet->callback, packet->_return); +#endif // print out arguments while (data_ptr+2 < data_limit && argc--) { short l = *(uint16_t*)data_ptr; +#ifdef CMD_DBG os_printf("CMD: arg[%d] len=%d:", argn++, l); +#endif data_ptr += 2; while (data_ptr < data_limit && l--) { +#ifdef CMD_DBG os_printf(" %02X", *data_ptr++); +#endif } +#ifdef CMD_DBG os_printf("\n"); +#endif } if (data_ptr <= data_limit) { CMD_Exec(commands, packet); } else { +#ifdef CMD_DBG os_printf("CMD: packet length overrun, parsing arg %d\n", argn-1); +#endif } } diff --git a/cmd/cmd.h b/cmd/cmd.h index b489108..97c8236 100644 --- a/cmd/cmd.h +++ b/cmd/cmd.h @@ -55,7 +55,7 @@ typedef enum { CMD_REST_REQUEST, CMD_REST_SETHEADER, CMD_REST_EVENTS, - CMD_ADD_SENSOR, // 15 + CMD_ADD_CALLBACK, // 15 CMD_SENSOR_EVENTS } CmdName; @@ -71,19 +71,23 @@ typedef struct { uint32_t callback; } cmdCallback; -void ICACHE_FLASH_ATTR CMD_parse_packet(uint8_t *buf, short len); -cmdCallback* ICACHE_FLASH_ATTR CMD_GetCbByName(char* name); +// Used by slip protocol to cause parsing of a received packet +void CMD_parse_packet(uint8_t *buf, short len); + +// Return the info about a callback to the attached uC by name, these are callbacks that the +// attached uC registers using the ADD_SENSOR command +cmdCallback* CMD_GetCbByName(char* name); // Responses // Start a response, returns the partial CRC -uint16_t ICACHE_FLASH_ATTR CMD_ResponseStart(uint16_t cmd, uint32_t callback, uint32_t _return, uint16_t argc); +uint16_t CMD_ResponseStart(uint16_t cmd, uint32_t callback, uint32_t _return, uint16_t argc); // Adds data to a response, returns the partial CRC -uint16_t ICACHE_FLASH_ATTR CMD_ResponseBody(uint16_t crc_in, uint8_t* data, short len); +uint16_t CMD_ResponseBody(uint16_t crc_in, uint8_t* data, short len); // Ends a response -void ICACHE_FLASH_ATTR CMD_ResponseEnd(uint16_t crc); +void CMD_ResponseEnd(uint16_t crc); -//void ICACHE_FLASH_ATTR CMD_Response(uint16_t cmd, uint32_t callback, uint32_t _return, uint16_t argc, CmdArg* args[]); +//void CMD_Response(uint16_t cmd, uint32_t callback, uint32_t _return, uint16_t argc, CmdArg* args[]); // Requests diff --git a/cmd/handlers.c b/cmd/handlers.c index d5359cb..e50a10a 100644 --- a/cmd/handlers.c +++ b/cmd/handlers.c @@ -11,18 +11,20 @@ #include "cgiwifi.h" #include "mqtt_cmd.h" -static uint32_t ICACHE_FLASH_ATTR CMD_Null(CmdPacket *cmd); -static uint32_t ICACHE_FLASH_ATTR CMD_IsReady(CmdPacket *cmd); -static uint32_t ICACHE_FLASH_ATTR CMD_WifiConnect(CmdPacket *cmd); -static uint32_t ICACHE_FLASH_ATTR CMD_AddSensor(CmdPacket *cmd); +static uint32_t CMD_Null(CmdPacket *cmd); +static uint32_t CMD_IsReady(CmdPacket *cmd); +static uint32_t CMD_Reset(CmdPacket *cmd); +static uint32_t CMD_WifiConnect(CmdPacket *cmd); +static uint32_t CMD_AddCallback(CmdPacket *cmd); +// keep track of last status sent to uC so we can notify it when it changes static uint8_t lastWifiStatus = wifiIsDisconnected; static bool wifiCbAdded = false; // Command dispatch table for serial -> ESP commands const CmdList commands[] = { {CMD_NULL, CMD_Null}, - {CMD_RESET, CMD_Null}, + {CMD_RESET, CMD_Reset}, {CMD_IS_READY, CMD_IsReady}, {CMD_WIFI_CONNECT, CMD_WifiConnect}, @@ -37,54 +39,65 @@ const CmdList commands[] = { {CMD_REST_REQUEST, REST_Request}, {CMD_REST_SETHEADER, REST_SetHeader}, - {CMD_ADD_SENSOR, CMD_AddSensor }, + {CMD_ADD_CALLBACK, CMD_AddCallback }, {CMD_NULL, NULL} }; // WifiCb plus 10 for sensors -cmdCallback callbacks[12] = { - { { '\0' }, -1 }, - { { '\0' }, -1 }, - { { '\0' }, -1 }, - { { '\0' }, -1 }, - { { '\0' }, -1 }, - { { '\0' }, -1 }, - { { '\0' }, -1 }, - { { '\0' }, -1 }, - { { '\0' }, -1 }, - { { '\0' }, -1 }, - { { '\0' }, -1 } -}; +#define MAX_CALLBACKS 12 +cmdCallback callbacks[MAX_CALLBACKS]; // cleared in CMD_Reset // Command handler for IsReady (healthcheck) command static uint32_t ICACHE_FLASH_ATTR CMD_IsReady(CmdPacket *cmd) { +#ifdef CMD_DBG os_printf("CMD_IsReady: Check ready\n"); +#endif return 1; } // Command handler for Null command static uint32_t ICACHE_FLASH_ATTR CMD_Null(CmdPacket *cmd) { +#ifdef CMD_DBG os_printf("CMD_Null: NULL/unsupported command\n"); +#endif + return 1; +} + +// Command handler for Reset command, this was originally to reset the ESP but we don't want to +// do that is esp-link. It is still good to clear any information the ESP has about the attached +// uC. +static uint32_t ICACHE_FLASH_ATTR +CMD_Reset(CmdPacket *cmd) { +#ifdef CMD_DBG + os_printf("CMD_Reset\n"); +#endif + // clear callbacks table + os_memset(callbacks, 0, sizeof(callbacks)); return 1; } -static void ICACHE_FLASH_ATTR +static uint32_t ICACHE_FLASH_ATTR CMD_AddCb(char* name, uint32_t cb) { char checkname[16]; os_strncpy(checkname, name, sizeof(checkname)); - for (uint8_t i = 0; i < sizeof(commands); i++) { + for (uint8_t i = 0; i < MAX_CALLBACKS; i++) { +#ifdef CMD_DBG os_printf("CMD_AddCb: index %d name=%s cb=%p\n", i, callbacks[i].name, (void *)callbacks[i].callback); +#endif // find existing callback or add to the end if (os_strcmp(callbacks[i].name, checkname) == 0 || callbacks[i].name[0] == '\0') { - os_strncpy(callbacks[i].name, checkname, sizeof(checkname)); + os_strncpy(callbacks[i].name, name, sizeof(callbacks[i].name)); callbacks[i].callback = cb; +#ifdef CMD_DBG os_printf("CMD_AddCb: cb %s added at index %d\n", callbacks[i].name, i); - break; +#endif + return 1; } } + return 0; } cmdCallback* ICACHE_FLASH_ATTR @@ -92,14 +105,20 @@ CMD_GetCbByName(char* name) { char checkname[16]; os_strncpy(checkname, name, sizeof(checkname)); for (uint8_t i = 0; i < sizeof(commands); i++) { +#ifdef CMD_DBG os_printf("CMD_GetCbByName: index %d name=%s cb=%p\n", i, callbacks[i].name, (void *)callbacks[i].callback); +#endif // if callback doesn't exist or it's null 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); +#endif return &callbacks[i]; } } +#ifdef CMD_DBG os_printf("CMD_GetCbByName: cb %s not found\n", name); +#endif return 0; } @@ -107,7 +126,9 @@ CMD_GetCbByName(char* name) { static void ICACHE_FLASH_ATTR CMD_WifiCb(uint8_t wifiStatus) { if (wifiStatus != lastWifiStatus){ +#ifdef CMD_DBG os_printf("CMD_WifiCb: wifiStatus=%d\n", wifiStatus); +#endif lastWifiStatus = wifiStatus; cmdCallback *wifiCb = CMD_GetCbByName("wifiCb"); if ((uint32_t)wifiCb->callback != -1) { @@ -124,7 +145,9 @@ static uint32_t ICACHE_FLASH_ATTR CMD_WifiConnect(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); +#ifdef CMD_DBG os_printf("CMD_WifiConnect: setup argc=%ld\n", CMD_GetArgc(&req)); +#endif if(cmd->argc != 2 || cmd->callback == 0) return 0; @@ -133,33 +156,37 @@ CMD_WifiConnect(CmdPacket *cmd) { wifiCbAdded = true; } CMD_AddCb("wifiCb", (uint32_t)cmd->callback); // save the MCU's callback - lastWifiStatus = wifiIsDisconnected; + lastWifiStatus = 0xff; // set to invalid value so we immediately send status cb in all cases CMD_WifiCb(wifiState); return 1; } -// Command handler for Wifi connect command +// Command handler to add a callback to the named-callbacks list, this is for a callback to the uC static uint32_t ICACHE_FLASH_ATTR -CMD_AddSensor(CmdPacket *cmd) { +CMD_AddCallback(CmdPacket *cmd) { CmdRequest req; CMD_Request(&req, cmd); - os_printf("CMD_AddSensor: setup argc=%ld\n", CMD_GetArgc(&req)); +#ifdef CMD_DBG + os_printf("CMD_AddCallback: setup argc=%ld\n", CMD_GetArgc(&req)); +#endif if (cmd->argc != 1 || cmd->callback == 0) return 0; - uint8_t* name; + char name[16]; uint16_t len; // get the sensor name len = CMD_ArgLen(&req); - os_printf("CMD_AddSensor: name len=%d\n", len); +#ifdef CMD_DBG + os_printf("CMD_AddCallback: name len=%d\n", len); +#endif if (len > 15) return 0; // max size of name is 15 characters - name = (uint8_t*)os_zalloc(len + 1); - if (CMD_PopArg(&req, name, len)) return 0; + if (CMD_PopArg(&req, (uint8_t *)name, len)) return 0; name[len] = 0; - os_printf("CMD_AddSensor: name=%s\n", name); +#ifdef CMD_DBG + os_printf("CMD_AddCallback: name=%s\n", name); +#endif - CMD_AddCb((char*)name, (uint32_t)cmd->callback); // save the sensor callback - return 1; + return CMD_AddCb(name, (uint32_t)cmd->callback); // save the sensor callback } diff --git a/cmd/mqtt_cmd.c b/cmd/mqtt_cmd.c index 358ad48..e699847 100644 --- a/cmd/mqtt_cmd.c +++ b/cmd/mqtt_cmd.c @@ -6,11 +6,13 @@ void ICACHE_FLASH_ATTR cmdMqttConnectedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; - os_printf("MQTT: Connected connectedCb=%p, disconnectedCb=%p, publishedCb=%p, dataCb=%p\n", +#ifdef MQTT_CMD_DBG + os_printf("cmdMqttConnectedCb: connectedCb=%p, disconnectedCb=%p, publishedCb=%p, dataCb=%p\n", (void*)cb->connectedCb, (void*)cb->disconnectedCb, (void*)cb->publishedCb, (void*)cb->dataCb); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->connectedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -19,7 +21,9 @@ void ICACHE_FLASH_ATTR cmdMqttTcpDisconnectedCb(uint32_t *args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb *cb = (MqttCmdCb*)client->user_data; - os_printf("MQTT: TCP Disconnected\n"); +#ifdef MQTT_CMD_DBG + os_printf("cmdMqttTcpDisconnectedCb\n"); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->tcpDisconnectedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -28,7 +32,9 @@ void ICACHE_FLASH_ATTR cmdMqttDisconnectedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; - os_printf("MQTT: Disconnected\n"); +#ifdef MQTT_CMD_DBG + os_printf("cmdMqttDisconnectedCb\n"); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->disconnectedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -37,7 +43,9 @@ void ICACHE_FLASH_ATTR cmdMqttPublishedCb(uint32_t* args) { MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; - os_printf("MQTT: Published\n"); +#ifdef MQTT_CMD_DBG + os_printf("cmdMqttPublishedCb\n"); +#endif uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->publishedCb, 0, 0); CMD_ResponseEnd(crc); } @@ -47,7 +55,9 @@ cmdMqttDataCb(uint32_t* args, const char* topic, uint32_t topic_len, const char* uint16_t crc = 0; MQTT_Client* client = (MQTT_Client*)args; MqttCmdCb* cb = (MqttCmdCb*)client->user_data; - +#ifdef MQTT_CMD_DBG + os_printf("cmdMqttDataCb\n"); +#endif crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->dataCb, 0, 2); crc = CMD_ResponseBody(crc, (uint8_t*)topic, topic_len); crc = CMD_ResponseBody(crc, (uint8_t*)data, data_len); @@ -99,9 +109,9 @@ MQTTCMD_Setup(CmdPacket *cmd) { // get clean session CMD_PopArg(&req, (uint8_t*)&clean_session, 4); - - 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); - +#ifdef MQTT_CMD_DBG + os_printf("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 // TODO: why malloc these all here, pass to MQTT_InitClient to be malloc'd again? MQTT_InitClient(client, (char*)client_id, (char*)user_data, (char*)pass_data, keepalive, clean_session); @@ -150,8 +160,9 @@ MQTTCMD_Lwt(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; - os_printf("MQTT: MQTTCMD_Lwt client ptr=%p\n", (void*)client_ptr); - +#ifdef MQTT_CMD_DBG + os_printf("MQTTCMD_Lwt: client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; // get topic @@ -177,12 +188,13 @@ MQTTCMD_Lwt(CmdPacket *cmd) { // get retain CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_retain, 4); - - os_printf("MQTT: MQTTCMD_Lwt topic=%s, message=%s, qos=%d, retain=%d\n", +#ifdef MQTT_CMD_DBG + os_printf("MQTTCMD_Lwt: topic=%s, message=%s, qos=%d, retain=%d\n", client->connect_info.will_topic, client->connect_info.will_message, client->connect_info.will_qos, client->connect_info.will_retain); +#endif return 1; } @@ -198,8 +210,9 @@ MQTTCMD_Connect(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; - os_printf("MQTT: MQTTCMD_Connect client ptr=%p\n", (void*)client_ptr); - +#ifdef MQTT_CMD_DBG + os_printf("MQTTCMD_Connect: client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; // get host @@ -216,12 +229,12 @@ MQTTCMD_Connect(CmdPacket *cmd) { // get security CMD_PopArg(&req, (uint8_t*)&client->security, 4); - - os_printf("MQTT: MQTTCMD_Connect host=%s, port=%ld, security=%d\n", +#ifdef MQTT_CMD_DBG + os_printf("MQTTCMD_Connect: host=%s, port=%ld, security=%d\n", client->host, client->port, client->security); - +#endif MQTT_Connect(client); return 1; } @@ -238,8 +251,9 @@ MQTTCMD_Disconnect(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; - os_printf("MQTT: MQTTCMD_Disconnect client ptr=%p\n", (void*)client_ptr); - +#ifdef MQTT_CMD_DBG + os_printf("MQTTCMD_Disconnect: client ptr=%p\n", (void*)client_ptr); +#endif // disconnect MQTT_Disconnect(client); return 1; @@ -257,8 +271,9 @@ MQTTCMD_Publish(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; - os_printf("MQTT: MQTTCMD_Publish client ptr=%p\n", (void*)client_ptr); - +#ifdef MQTT_CMD_DBG + os_printf("MQTTCMD_Publish: client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; uint8_t *topic, *data; uint32_t qos = 0, retain = 0, data_len; @@ -288,13 +303,13 @@ MQTTCMD_Publish(CmdPacket *cmd) { // get retain CMD_PopArg(&req, (uint8_t*)&retain, 4); - - os_printf("MQTT: MQTTCMD_Publish topic=%s, data_len=%d, qos=%ld, retain=%ld\n", +#ifdef MQTT_CMD_DBG + os_printf("MQTTCMD_Publish: topic=%s, data_len=%d, qos=%ld, retain=%ld\n", topic, os_strlen((char*)data), qos, retain); - +#endif MQTT_Publish(client, (char*)topic, (char*)data, (uint8_t)qos, (uint8_t)retain); os_free(topic); os_free(data); @@ -313,8 +328,9 @@ MQTTCMD_Subscribe(CmdPacket *cmd) { uint32_t client_ptr; CMD_PopArg(&req, (uint8_t*)&client_ptr, 4); MQTT_Client* client = (MQTT_Client*)client_ptr; - os_printf("MQTT: MQTTCMD_Subscribe client ptr=%p\n", (void*)client_ptr); - +#ifdef MQTT_CMD_DBG + os_printf("MQTTCMD_Subscribe: client ptr=%p\n", (void*)client_ptr); +#endif uint16_t len; uint8_t* topic; uint32_t qos = 0; @@ -328,8 +344,9 @@ MQTTCMD_Subscribe(CmdPacket *cmd) { // get qos CMD_PopArg(&req, (uint8_t*)&qos, 4); - +#ifdef MQTT_CMD_DBG os_printf("MQTT: MQTTCMD_Subscribe topic=%s, qos=%ld\n", topic, qos); +#endif MQTT_Subscribe(client, (char*)topic, (uint8_t)qos); os_free(topic); return 1; diff --git a/cmd/rest.c b/cmd/rest.c index 3ae6575..3556681 100644 --- a/cmd/rest.c +++ b/cmd/rest.c @@ -25,59 +25,66 @@ tcpclient_discon_cb(void *arg) { client->data = 0; } +// Receive HTTP response - this hacky function assumes that the full response is received in +// one go. Sigh... static void ICACHE_FLASH_ATTR tcpclient_recv(void *arg, char *pdata, unsigned short len) { - uint8_t currentLineIsBlank = 0; - uint8_t httpBody = 0; - uint8_t inStatus = 0; - char statusCode[4]; - int i = 0, j; - uint32_t code = 0; - uint16_t crc; - struct espconn *pCon = (struct espconn*)arg; RestClient *client = (RestClient *)pCon->reverse; - for(j=0 ;jresp_cb, code, 0); - } else { - crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 1); - crc = CMD_ResponseBody(crc, (uint8_t*)(pdata+j), body_len); - } - CMD_ResponseEnd(crc); - break; - } else { - if (c == '\n' && currentLineIsBlank) { - httpBody = true; - } - if (c == '\n') { - // you're starting a new line - currentLineIsBlank = true; - } else if (c != '\r') { - // you've gotten a character on the current line - currentLineIsBlank = false; + // parse header, all this does is look for the end of the header + bool currentLineIsBlank = false; + while (pi < len) { + if (pdata[pi] == '\n') { + if (currentLineIsBlank) { + // body is starting + pi++; + break; } + currentLineIsBlank = true; + } else if (pdata[pi] != '\r') { + currentLineIsBlank = false; } + pi++; } + //if (pi < len && pdata[pi] == '\r') pi++; // hacky! + + // collect body and send it + uint16_t crc; + int body_len = len-pi; + os_printf("REST: status=%ld, body=%d\n", code, body_len); + if (pi == len) { + crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 0); + } else { + crc = CMD_ResponseStart(CMD_REST_EVENTS, client->resp_cb, code, 1); + crc = CMD_ResponseBody(crc, (uint8_t*)(pdata+pi), body_len); + CMD_ResponseEnd(crc); + os_printf("REST: body="); + for (int j=pi; jsecurity) // espconn_secure_disconnect(client->pCon); //else @@ -336,7 +343,8 @@ REST_Request(CmdPacket *cmd) { // 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 // whole shebang and copy everything into it. - char *headerFmt = "%s %s HTTP/1.1\r\n" + // BTW, use http/1.0 to avoid responses with transfer-encoding: chunked + char *headerFmt = "%s %s HTTP/1.0\r\n" "Host: %s\r\n" "%s" "Content-Length: %d\r\n" @@ -358,11 +366,12 @@ REST_Request(CmdPacket *cmd) { CMD_PopArg(&req, client->data + client->data_len, realLen); client->data_len += realLen; } + os_printf("\n"); + os_printf("REST: pCon state=%d\n", client->pCon->state); client->pCon->state = ESPCONN_NONE; espconn_regist_connectcb(client->pCon, tcpclient_connect_cb); espconn_regist_reconcb(client->pCon, tcpclient_recon_cb); - os_printf("\n"); if(UTILS_StrToIP((char *)client->host, &client->pCon->proto.tcp->remote_ip)) { os_printf("REST: Connect to ip %s:%ld\n",client->host, client->port); diff --git a/esp-link.vcxproj b/esp-link.vcxproj index f371f1a..c3bef32 100644 --- a/esp-link.vcxproj +++ b/esp-link.vcxproj @@ -28,7 +28,7 @@ __ets__;_STDINT_H;ICACHE_FLASH;__MINGW32__;__WIN32__ - .\esp-link;.\mqtt;.\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.3.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include + .\libraries\Time;.\esp-link;.\mqtt;.\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.3.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include @@ -76,6 +76,7 @@ + @@ -104,6 +105,8 @@ + + @@ -122,6 +125,7 @@ + @@ -148,6 +152,8 @@ + + diff --git a/esp-link/cgiwifi.c b/esp-link/cgiwifi.c index 42ddf24..f19507b 100644 --- a/esp-link/cgiwifi.c +++ b/esp-link/cgiwifi.c @@ -24,7 +24,8 @@ Cgi/template routines for the /wifi url. //#define SLEEP_MODE LIGHT_SLEEP_T #define SLEEP_MODE MODEM_SLEEP_T -// ===== wifi status change callback +// ===== wifi status change callbacks +static WifiStateChangeCb wifi_state_change_cb[4]; uint8_t wifiState = wifiIsDisconnected; // reasons for which a connection failed @@ -54,41 +55,69 @@ static void ICACHE_FLASH_ATTR wifiHandleEventCb(System_Event_t *evt) { case EVENT_STAMODE_CONNECTED: wifiState = wifiIsConnected; wifiReason = 0; +#ifdef WIFI_DBG os_printf("Wifi connected to ssid %s, ch %d\n", evt->event_info.connected.ssid, evt->event_info.connected.channel); +#endif statusWifiUpdate(wifiState); break; case EVENT_STAMODE_DISCONNECTED: wifiState = wifiIsDisconnected; wifiReason = evt->event_info.disconnected.reason; +#ifdef WIFI_DBG os_printf("Wifi disconnected from ssid %s, reason %s (%d)\n", evt->event_info.disconnected.ssid, wifiGetReason(), evt->event_info.disconnected.reason); +#endif statusWifiUpdate(wifiState); break; case EVENT_STAMODE_AUTHMODE_CHANGE: +#ifdef WIFI_DBG os_printf("Wifi auth mode: %d -> %d\n", evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode); +#endif break; case EVENT_STAMODE_GOT_IP: wifiState = wifiGotIP; wifiReason = 0; +#ifdef WIFI_DBG 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.gw)); +#endif statusWifiUpdate(wifiState); break; case EVENT_SOFTAPMODE_STACONNECTED: +#ifdef WIFI_DBG os_printf("Wifi AP: station " MACSTR " joined, AID = %d\n", MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid); +#endif break; case EVENT_SOFTAPMODE_STADISCONNECTED: +#ifdef WIFI_DBG os_printf("Wifi AP: station " MACSTR " left, AID = %d\n", MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid); +#endif break; default: break; } - if (wifiStatusCb) (*wifiStatusCb)(wifiState); + + for (int i = 0; i < 4; i++) { + if (wifi_state_change_cb[i] != NULL) (wifi_state_change_cb[i])(wifiState); + } +} + +void ICACHE_FLASH_ATTR +wifiAddStateChangeCb(WifiStateChangeCb cb) { + for (int i = 0; i < 4; i++) { + if (wifi_state_change_cb[i] == NULL) { + wifi_state_change_cb[i] = cb; + return; + } + } +#ifdef WIFI_DBG + os_printf("WIFI: max state change cb count exceeded\n"); +#endif } // ===== wifi scanning @@ -117,7 +146,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { struct bss_info *bss_link = (struct bss_info *)arg; if (status!=OK) { +#ifdef WIFI_DBG os_printf("wifiScanDoneCb status=%d\n", status); +#endif cgiWifiAps.scanInProgress=0; return; } @@ -137,7 +168,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { //Allocate memory for access point data cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n); cgiWifiAps.noAps=n; +#ifdef WIFI_DBG os_printf("Scan done: found %d APs\n", n); +#endif //Copy access point data to the static struct n=0; @@ -146,7 +179,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { if (n>=cgiWifiAps.noAps) { //This means the bss_link changed under our nose. Shouldn't happen! //Break because otherwise we will write in unallocated memory. +#ifdef WIFI_DBG os_printf("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps); +#endif break; } //Save the ap data. @@ -154,7 +189,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { cgiWifiAps.apData[n]->rssi=bss_link->rssi; cgiWifiAps.apData[n]->enc=bss_link->authmode; strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32); +#ifdef WIFI_DBG os_printf("bss%d: %s (%d)\n", n+1, (char*)bss_link->ssid, bss_link->rssi); +#endif bss_link = bss_link->next.stqe_next; n++; @@ -165,7 +202,9 @@ void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) { static ETSTimer scanTimer; static void ICACHE_FLASH_ATTR scanStartCb(void *arg) { +#ifdef WIFI_DBG os_printf("Starting a scan\n"); +#endif wifi_station_scan(NULL, wifiScanDoneCb); } @@ -202,7 +241,9 @@ static int ICACHE_FLASH_ATTR cgiWiFiGetScan(HttpdConnData *connData) { cgiWifiAps.apData[pos]->enc, (pos==cgiWifiAps.noAps-1)?"":","); } len += os_sprintf(buff+len, "]}}\n"); - //os_printf("Sending %d bytes: %s\n", len, buff); +#ifdef WIFI_DBG + os_printf("Sending %d bytes: %s\n", len, buff); +#endif httpdSend(connData, buff, len); return HTTPD_CGI_DONE; } @@ -230,13 +271,17 @@ static ETSTimer resetTimer; static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { int x = wifi_station_get_connect_status(); int m = wifi_get_opmode() & 0x3; +#ifdef WIFI_DBG os_printf("Wifi check: mode=%s status=%d\n", wifiMode[m], x); +#endif if (x == STATION_GOT_IP) { if (m != 1) { #ifdef CHANGE_TO_STA // We're happily connected, go to STA mode +#ifdef WIFI_DBG os_printf("Wifi got IP. Going into STA mode..\n"); +#endif wifi_set_opmode(1); wifi_set_sleep_type(SLEEP_MODE); os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); @@ -246,11 +291,15 @@ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) { // no more resetTimer at this point, gotta use physical reset to recover if in trouble } else { if (m != 3) { +#ifdef WIFI_DBG os_printf("Wifi connect failed. Going into STA+AP mode..\n"); +#endif wifi_set_opmode(3); } log_uart(true); +#ifdef WIFI_DBG os_printf("Enabling/continuing uart log\n"); +#endif os_timer_arm(&resetTimer, RESET_TIMEOUT, 0); } } @@ -262,7 +311,9 @@ static ETSTimer reassTimer; // Callback actually doing reassociation static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) { +#ifdef WIFI_DBG os_printf("Wifi changing association\n"); +#endif wifi_station_disconnect(); stconf.bssid_set = 0; wifi_station_set_config(&stconf); @@ -288,7 +339,9 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { //Set to 0 if you want to disable the actual reconnecting bit os_strncpy((char*)stconf.ssid, essid, 32); os_strncpy((char*)stconf.password, passwd, 64); +#ifdef WIFI_DBG os_printf("Wifi try to connect to AP %s pw %s\n", essid, passwd); +#endif //Schedule disconnect/connect os_timer_disarm(&reassTimer); @@ -327,8 +380,7 @@ static bool parse_ip(char *buff, ip_addr_t *ip_ptr) { return false; } -#define DEBUGIP -#ifdef DEBUGIP +#ifdef WIFI_DBG static void ICACHE_FLASH_ATTR debugIP() { struct ip_info info; if (wifi_get_ip_info(0, &info)) { @@ -350,7 +402,9 @@ static void ICACHE_FLASH_ATTR configWifiIP() { if (wifi_station_dhcpc_status() == DHCP_STARTED) wifi_station_dhcpc_stop(); wifi_station_dhcpc_start(); +#ifdef WIFI_DBG os_printf("Wifi uses DHCP, hostname=%s\n", flashConfig.hostname); +#endif } else { // no DHCP, we got static network config! wifi_station_dhcpc_stop(); @@ -359,7 +413,9 @@ static void ICACHE_FLASH_ATTR configWifiIP() { ipi.netmask.addr = flashConfig.netmask; ipi.gw.addr = flashConfig.gateway; wifi_set_ip_info(0, &ipi); +#ifdef WIFI_DBG os_printf("Wifi uses static IP %d.%d.%d.%d\n", IP2STR(&ipi.ip.addr)); +#endif } #ifdef DEBUGIP debugIP(); @@ -439,7 +495,9 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff)); if (len!=0) { int m = atoi(buff); +#ifdef WIFI_DBG os_printf("Wifi switching to mode %d\n", m); +#endif wifi_set_opmode(m&3); if (m == 1) { wifi_set_sleep_type(SLEEP_MODE); @@ -542,8 +600,9 @@ int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) { #endif len += os_sprintf(buff+len, "\"x\":0}\n"); - +#ifdef WIFI_DBG os_printf(" -> %s\n", buff); +#endif httpdSend(connData, buff, len); return HTTPD_CGI_DONE; } @@ -567,8 +626,10 @@ int ICACHE_FLASH_ATTR cgiWifiInfo(HttpdConnData *connData) { // so we can revert to STA+AP mode if we can't connect. void ICACHE_FLASH_ATTR wifiInit() { wifi_set_phy_mode(2); +#ifdef WIFI_DBG int x = wifi_get_opmode() & 0x3; os_printf("Wifi init, mode=%s\n", wifiMode[x]); +#endif configWifiIP(); wifi_set_event_handler_cb(wifiHandleEventCb); diff --git a/esp-link/cgiwifi.h b/esp-link/cgiwifi.h index 3f7fe09..a2782a5 100644 --- a/esp-link/cgiwifi.h +++ b/esp-link/cgiwifi.h @@ -17,6 +17,5 @@ void wifiInit(void); void wifiAddStateChangeCb(WifiStateChangeCb cb); extern uint8_t wifiState; -//extern void (*wifiStatusCb)(uint8_t); // callback when wifi status changes #endif diff --git a/esp-link/config.c b/esp-link/config.c index b44b329..1397e8e 100644 --- a/esp-link/config.c +++ b/esp-link/config.c @@ -86,7 +86,9 @@ bool ICACHE_FLASH_ATTR configSave(void) { spi_flash_write(addr, (void *)&ff, sizeof(uint32_t)); return true; fail: +#ifdef CONFIG_DBG os_printf("*** Failed to save config ***\n"); +#endif return false; } diff --git a/esp-link/main.c b/esp-link/main.c index 5febf87..c77e693 100644 --- a/esp-link/main.c +++ b/esp-link/main.c @@ -34,19 +34,19 @@ //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 //the builtInUrls below. -int myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) { - if (no == 0) { - os_strcpy(user, "admin"); - os_strcpy(pass, "s3cr3t"); - return 1; +//int myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen) { +// if (no == 0) { +// os_strcpy(user, "admin"); +// os_strcpy(pass, "s3cr3t"); +// return 1; //Add more users this way. Check against incrementing no for each user added. // } else if (no==1) { // os_strcpy(user, "user1"); // os_strcpy(pass, "something"); // return 1; - } - return 0; -} +// } +// return 0; +//} /* diff --git a/httpd/html-old/console.html b/httpd/html-old/console.html deleted file mode 100644 index db4c0a6..0000000 --- a/httpd/html-old/console.html +++ /dev/null @@ -1,46 +0,0 @@ -
-
-

Microcontroller Console

-
- -
-

The Microcontroller console shows the last 1024 characters - received from UART0, to which a microcontroller is typically attached. - The UART is configured for 8 bits, no parity, 1 stop bit (8N1).

-

- Reset µC -  Baud: - -

-

-    
-
- - - - - - diff --git a/httpd/html-old/console.js b/httpd/html-old/console.js deleted file mode 100644 index 87f7d1a..0000000 --- a/httpd/html-old/console.js +++ /dev/null @@ -1,72 +0,0 @@ -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'+baud+'')); - - $("#"+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"); - } -} diff --git a/httpd/html-old/favicon.ico b/httpd/html-old/favicon.ico deleted file mode 100644 index fe24a7b..0000000 Binary files a/httpd/html-old/favicon.ico and /dev/null differ diff --git a/httpd/html-old/head- b/httpd/html-old/head- deleted file mode 100644 index 514ff53..0000000 --- a/httpd/html-old/head- +++ /dev/null @@ -1,10 +0,0 @@ - - - esp-link - - - - - - -
diff --git a/httpd/html-old/home.html b/httpd/html-old/home.html deleted file mode 100644 index 46a984d..0000000 --- a/httpd/html-old/home.html +++ /dev/null @@ -1,87 +0,0 @@ -
-
-
JEELABS
-

esp-link

-

-
- -
-
-
-

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.

-

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.

-
-
-
-
-
-

Wifi summary

-
- - - - - - - - -
-
-

TCP client

-
- TCP client support in esp-link -
- - -
-
- Grovestreams data push -
- - -
-
- - -
- -
-
-
-
-

Pin assignment

- Select one of the following signal/pin assignments to match your hardware -
-
-
-
-
-
-
-
-
-
- - - diff --git a/httpd/html-old/jl-400x110.png- b/httpd/html-old/jl-400x110.png- deleted file mode 100644 index 92d2d9e..0000000 Binary files a/httpd/html-old/jl-400x110.png- and /dev/null differ diff --git a/httpd/html-old/log.html b/httpd/html-old/log.html deleted file mode 100644 index 46ec785..0000000 --- a/httpd/html-old/log.html +++ /dev/null @@ -1,48 +0,0 @@ -
-
-

Debug Log

-
- -
-

The debug log shows the most recent characters printed by the esp-link software itself to - its own debug log.

-
-

- Refresh -

-

- UART debug log: - auto - off - on -

-
-

-    
-
- - - - - - diff --git a/httpd/html-old/pure.css b/httpd/html-old/pure.css deleted file mode 100644 index b895c0e..0000000 --- a/httpd/html-old/pure.css +++ /dev/null @@ -1,1388 +0,0 @@ -/*! -Pure v0.6.0 -Copyright 2014 Yahoo! Inc. All rights reserved. -Licensed under the BSD License. -https://github.com/yahoo/pure/blob/master/LICENSE.md -*/ -/*! -normalize.css v^3.0 | MIT License | git.io/normalize -Copyright (c) Nicolas Gallagher and Jonathan Neal -*/ -/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ - -/** - * 1. Set default font family to sans-serif. - * 2. Prevent iOS text size adjust after orientation change, without disabling - * user zoom. - */ - -html { - font-family: sans-serif; /* 1 */ - -ms-text-size-adjust: 100%; /* 2 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/** - * Remove default margin. - */ - -body { - margin: 0; -} - -/* HTML5 display definitions - ========================================================================== */ - -/** - * Correct `block` display not defined for any HTML5 element in IE 8/9. - * Correct `block` display not defined for `details` or `summary` in IE 10/11 - * and Firefox. - * Correct `block` display not defined for `main` in IE 11. - */ - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -menu, -nav, -section, -summary { - display: block; -} - -/** - * 1. Correct `inline-block` display not defined in IE 8/9. - * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. - */ - -audio, -canvas, -progress, -video { - display: inline-block; /* 1 */ - vertical-align: baseline; /* 2 */ -} - -/** - * Prevent modern browsers from displaying `audio` without controls. - * Remove excess height in iOS 5 devices. - */ - -audio:not([controls]) { - display: none; - height: 0; -} - -/** - * Address `[hidden]` styling not present in IE 8/9/10. - * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. - */ - -[hidden], -template { - display: none; -} - -/* Links - ========================================================================== */ - -/** - * Remove the gray background color from active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * Improve readability when focused and also mouse hovered in all browsers. - */ - -a:active, -a:hover { - outline: 0; -} - -/* Text-level semantics - ========================================================================== */ - -/** - * Address styling not present in IE 8/9/10/11, Safari, and Chrome. - */ - -abbr[title] { - border-bottom: 1px dotted; -} - -/** - * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. - */ - -b, -strong { - font-weight: bold; -} - -/** - * Address styling not present in Safari and Chrome. - */ - -dfn { - font-style: italic; -} - -/** - * Address variable `h1` font-size and margin within `section` and `article` - * contexts in Firefox 4+, Safari, and Chrome. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/** - * Address styling not present in IE 8/9. - */ - -mark { - background: #ff0; - color: #000; -} - -/** - * Address inconsistent and variable font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` affecting `line-height` in all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove border when inside `a` element in IE 8/9/10. - */ - -img { - border: 0; -} - -/** - * Correct overflow not hidden in IE 9/10/11. - */ - -svg:not(:root) { - overflow: hidden; -} - -/* Grouping content - ========================================================================== */ - -/** - * Address margin not present in IE 8/9 and Safari. - */ - -figure { - margin: 1em 40px; -} - -/** - * Address differences between Firefox and other browsers. - */ - -hr { - -moz-box-sizing: content-box; - box-sizing: content-box; - height: 0; -} - -/** - * Contain overflow in all browsers. - */ - -pre { - overflow: auto; -} - -/** - * Address odd `em`-unit font size rendering in all browsers. - */ - -code, -kbd, -pre, -samp { - font-family: monospace, monospace; - font-size: 1em; -} - -/* Forms - ========================================================================== */ - -/** - * Known limitation: by default, Chrome and Safari on OS X allow very limited - * styling of `select`, unless a `border` property is set. - */ - -/** - * 1. Correct color not being inherited. - * Known issue: affects color of disabled elements. - * 2. Correct font properties not being inherited. - * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. - */ - -button, -input, -optgroup, -select, -textarea { - color: inherit; /* 1 */ - font: inherit; /* 2 */ - margin: 0; /* 3 */ -} - -/** - * Address `overflow` set to `hidden` in IE 8/9/10/11. - */ - -button { - overflow: visible; -} - -/** - * Address inconsistent `text-transform` inheritance for `button` and `select`. - * All other form control elements do not inherit `text-transform` values. - * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. - * Correct `select` style inheritance in Firefox. - */ - -button, -select { - text-transform: none; -} - -/** - * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` - * and `video` controls. - * 2. Correct inability to style clickable `input` types in iOS. - * 3. Improve usability and consistency of cursor style between image-type - * `input` and others. - */ - -button, -html input[type="button"], /* 1 */ -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; /* 2 */ - cursor: pointer; /* 3 */ -} - -/** - * Re-set default cursor for disabled elements. - */ - -button[disabled], -html input[disabled] { - cursor: default; -} - -/** - * Remove inner padding and border in Firefox 4+. - */ - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; -} - -/** - * Address Firefox 4+ setting `line-height` on `input` using `!important` in - * the UA stylesheet. - */ - -input { - line-height: normal; -} - -/** - * It's recommended that you don't attempt to style these elements. - * Firefox's implementation doesn't respect box-sizing, padding, or width. - * - * 1. Address box sizing set to `content-box` in IE 8/9/10. - * 2. Remove excess padding in IE 8/9/10. - */ - -input[type="checkbox"], -input[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Fix the cursor style for Chrome's increment/decrement buttons. For certain - * `font-size` values of the `input`, it causes the cursor style of the - * decrement button to change from `default` to `text`. - */ - -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Address `appearance` set to `searchfield` in Safari and Chrome. - * 2. Address `box-sizing` set to `border-box` in Safari and Chrome - * (include `-moz` to future-proof). - */ - -input[type="search"] { - -webkit-appearance: textfield; /* 1 */ - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; /* 2 */ - box-sizing: content-box; -} - -/** - * Remove inner padding and search cancel button in Safari and Chrome on OS X. - * Safari (but not Chrome) clips the cancel button when the search input has - * padding (and `textfield` appearance). - */ - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * Define consistent border, margin, and padding. - */ - -fieldset { - border: 1px solid #c0c0c0; - margin: 0 2px; - padding: 0.35em 0.625em 0.75em; -} - -/** - * 1. Correct `color` not being inherited in IE 8/9/10/11. - * 2. Remove padding so people aren't caught out if they zero out fieldsets. - */ - -legend { - border: 0; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Remove default vertical scrollbar in IE 8/9/10/11. - */ - -textarea { - overflow: auto; -} - -/** - * Don't inherit the `font-weight` (applied by a rule above). - * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. - */ - -optgroup { - font-weight: bold; -} - -/* Tables - ========================================================================== */ - -/** - * Remove most spacing between table cells. - */ - -table { - border-collapse: collapse; - border-spacing: 0; -} - -td, -th { - padding: 0; -} - -/*csslint important:false*/ - -/* ========================================================================== - Pure Base Extras - ========================================================================== */ - -/** - * Extra rules that Pure adds on top of Normalize.css - */ - -/** - * Always hide an element when it has the `hidden` HTML attribute. - */ - -.hidden, -[hidden] { - display: none !important; -} - -/** - * Add this class to an image to make it fit within it's fluid parent wrapper while maintaining - * aspect ratio. - */ -.pure-img { - max-width: 100%; - height: auto; - display: block; -} - -/*csslint regex-selectors:false, known-properties:false, duplicate-properties:false*/ - -.pure-g { - letter-spacing: -0.31em; /* Webkit: collapse white-space between units */ - *letter-spacing: normal; /* reset IE < 8 */ - *word-spacing: -0.43em; /* IE < 8: collapse white-space between units */ - text-rendering: optimizespeed; /* Webkit: fixes text-rendering: optimizeLegibility */ - - /* - Sets the font stack to fonts known to work properly with the above letter - and word spacings. See: https://github.com/yahoo/pure/issues/41/ - - The following font stack makes Pure Grids work on all known environments. - - * FreeSans: Ships with many Linux distros, including Ubuntu - - * Arimo: Ships with Chrome OS. Arimo has to be defined before Helvetica and - Arial to get picked up by the browser, even though neither is available - in Chrome OS. - - * Droid Sans: Ships with all versions of Android. - - * Helvetica, Arial, sans-serif: Common font stack on OS X and Windows. - */ - font-family: FreeSans, Arimo, "Droid Sans", Helvetica, Arial, sans-serif; - - /* - Use flexbox when possible to avoid `letter-spacing` side-effects. - - NOTE: Firefox (as of 25) does not currently support flex-wrap, so the - `-moz-` prefix version is omitted. - */ - - display: -webkit-flex; - -webkit-flex-flow: row wrap; - - /* IE10 uses display: flexbox */ - display: -ms-flexbox; - -ms-flex-flow: row wrap; - - /* Prevents distributing space between rows */ - -ms-align-content: flex-start; - -webkit-align-content: flex-start; - align-content: flex-start; -} - -/* Opera as of 12 on Windows needs word-spacing. - The ".opera-only" selector is used to prevent actual prefocus styling - and is not required in markup. -*/ -.opera-only :-o-prefocus, -.pure-g { - word-spacing: -0.43em; -} - -.pure-u { - display: inline-block; - *display: inline; /* IE < 8: fake inline-block */ - zoom: 1; - letter-spacing: normal; - word-spacing: normal; - vertical-align: top; - text-rendering: auto; -} - -/* -Resets the font family back to the OS/browser's default sans-serif font, -this the same font stack that Normalize.css sets for the `body`. -*/ -.pure-g [class *= "pure-u"] { - font-family: sans-serif; -} - -/* Pure 4 column grid */ - -.pure-u-1, -.pure-u-1-1, -.pure-u-1-2, -.pure-u-1-4, -.pure-u-2-4, -.pure-u-3-4, -.pure-u-4-4 { - display: inline-block; - *display: inline; - zoom: 1; - letter-spacing: normal; - word-spacing: normal; - vertical-align: top; - text-rendering: auto; -} - -.pure-u-1-4 { - width: 25%; - *width: 24.9690%; -} - -.pure-u-1-2, -.pure-u-2-4 { - width: 50%; - *width: 49.9690%; -} - -.pure-u-3-4 { - width: 75%; - *width: 74.9690%; -} - -.pure-u-1, -.pure-u-1-1, -.pure-u-4-4 { - width: 100%; -} - -/* responsive grid */ - -@media screen and (min-width: 48em) { - .pure-u-md-1, - .pure-u-md-1-1, - .pure-u-md-1-2, - .pure-u-md-1-4, - .pure-u-md-2-4, - .pure-u-md-3-4, - .pure-u-md-4-4 { - display: inline-block; - *display: inline; - zoom: 1; - letter-spacing: normal; - word-spacing: normal; - vertical-align: top; - text-rendering: auto; - } - - .pure-u-md-1-4 { - width: 25%; - *width: 24.9690%; - } - - .pure-u-md-1-2, - .pure-u-md-2-4 { - width: 50%; - *width: 49.9690%; - } - - .pure-u-md-3-4 { - width: 75%; - *width: 74.9690%; - } - - .pure-u-md-1, - .pure-u-md-1-1, - .pure-u-md-4-4 { - width: 100%; - } -} - -@media screen and (min-width: 64em) { - .pure-u-lg-1, - .pure-u-lg-1-1, - .pure-u-lg-1-2, - .pure-u-lg-1-4, - .pure-u-lg-2-4, - .pure-u-lg-3-4, - .pure-u-lg-4-4 { - display: inline-block; - *display: inline; - zoom: 1; - letter-spacing: normal; - word-spacing: normal; - vertical-align: top; - text-rendering: auto; - } - - .pure-u-lg-1-4 { - width: 25%; - *width: 24.9690%; - } - - .pure-u-lg-1-2, - .pure-u-lg-2-4 { - width: 50%; - *width: 49.9690%; - } - - .pure-u-lg-3-4 { - width: 75%; - *width: 74.9690%; - } - - .pure-u-lg-1, - .pure-u-lg-1-1, - .pure-u-lg-4-4 { - width: 100%; - } -} - -/* Pure buttons */ - -.pure-button { - /* Structure */ - display: inline-block; - zoom: 1; - line-height: normal; - white-space: nowrap; - vertical-align: middle; - text-align: center; - cursor: pointer; - -webkit-user-drag: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -/* Firefox: Get rid of the inner focus border */ -.pure-button::-moz-focus-inner { - padding: 0; - border: 0; -} - -/*csslint outline-none:false*/ - -.pure-button { - font-family: inherit; - font-size: 100%; - padding: 0.5em 1em; - 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; -} - -.pure-button-hover, -.pure-button:hover, -.pure-button: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)); -} -.pure-button:focus { - outline: 0; -} -.pure-button-active, -.pure-button: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; -} - -.pure-button[disabled], -.pure-button-disabled, -.pure-button-disabled:hover, -.pure-button-disabled:focus, -.pure-button-disabled:active { - border: none; - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - filter: alpha(opacity=40); - -khtml-opacity: 0.40; - -moz-opacity: 0.40; - opacity: 0.40; - cursor: not-allowed; - box-shadow: none; -} - -.pure-button-hidden { - display: none; -} - -/* Firefox: Get rid of the inner focus border */ -.pure-button::-moz-focus-inner{ - padding: 0; - border: 0; -} - -.pure-button-primary, -.pure-button-selected, -a.pure-button-primary, -a.pure-button-selected { - background-color: rgb(0, 120, 231); - color: #fff; -} - -/*csslint box-model:false*/ -/* -Box-model set to false because we're setting a height on select elements, which -also have border and padding. This is done because some browsers don't render -the padding. We explicitly set the box-model for select elements to border-box, -so we can ignore the csslint warning. -*/ - -.pure-form input[type="text"], -.pure-form input[type="password"], -.pure-form input[type="email"], -.pure-form input[type="url"], -.pure-form input[type="date"], -.pure-form input[type="month"], -.pure-form input[type="time"], -.pure-form input[type="datetime"], -.pure-form input[type="datetime-local"], -.pure-form input[type="week"], -.pure-form input[type="number"], -.pure-form input[type="search"], -.pure-form input[type="tel"], -.pure-form input[type="color"], -.pure-form select, -.pure-form textarea { - padding: 0.5em 0.6em; - display: inline-block; - border: 1px solid #ccc; - box-shadow: inset 0 1px 3px #ddd; - border-radius: 4px; - vertical-align: middle; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -/* -Need to separate out the :not() selector from the rest of the CSS 2.1 selectors -since IE8 won't execute CSS that contains a CSS3 selector. -*/ -.pure-form input:not([type]) { - padding: 0.5em 0.6em; - display: inline-block; - border: 1px solid #ccc; - box-shadow: inset 0 1px 3px #ddd; - border-radius: 4px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - - -/* Chrome (as of v.32/34 on OS X) needs additional room for color to display. */ -/* May be able to remove this tweak as color inputs become more standardized across browsers. */ -.pure-form input[type="color"] { - padding: 0.2em 0.5em; -} - - -.pure-form input[type="text"]:focus, -.pure-form input[type="password"]:focus, -.pure-form input[type="email"]:focus, -.pure-form input[type="url"]:focus, -.pure-form input[type="date"]:focus, -.pure-form input[type="month"]:focus, -.pure-form input[type="time"]:focus, -.pure-form input[type="datetime"]:focus, -.pure-form input[type="datetime-local"]:focus, -.pure-form input[type="week"]:focus, -.pure-form input[type="number"]:focus, -.pure-form input[type="search"]:focus, -.pure-form input[type="tel"]:focus, -.pure-form input[type="color"]:focus, -.pure-form select:focus, -.pure-form textarea:focus { - outline: 0; - border-color: #129FEA; -} - -/* -Need to separate out the :not() selector from the rest of the CSS 2.1 selectors -since IE8 won't execute CSS that contains a CSS3 selector. -*/ -.pure-form input:not([type]):focus { - outline: 0; - border-color: #129FEA; -} - -.pure-form input[type="file"]:focus, -.pure-form input[type="radio"]:focus, -.pure-form input[type="checkbox"]:focus { - outline: thin solid #129FEA; - outline: 1px auto #129FEA; -} -.pure-form .pure-checkbox, -.pure-form .pure-radio { - margin: 0.5em 0; - display: block; -} - -.pure-form input[type="text"][disabled], -.pure-form input[type="password"][disabled], -.pure-form input[type="email"][disabled], -.pure-form input[type="url"][disabled], -.pure-form input[type="date"][disabled], -.pure-form input[type="month"][disabled], -.pure-form input[type="time"][disabled], -.pure-form input[type="datetime"][disabled], -.pure-form input[type="datetime-local"][disabled], -.pure-form input[type="week"][disabled], -.pure-form input[type="number"][disabled], -.pure-form input[type="search"][disabled], -.pure-form input[type="tel"][disabled], -.pure-form input[type="color"][disabled], -.pure-form select[disabled], -.pure-form textarea[disabled] { - cursor: not-allowed; - background-color: #eaeded; - color: #cad2d3; -} - -/* -Need to separate out the :not() selector from the rest of the CSS 2.1 selectors -since IE8 won't execute CSS that contains a CSS3 selector. -*/ -.pure-form input:not([type])[disabled] { - cursor: not-allowed; - background-color: #eaeded; - color: #cad2d3; -} -.pure-form input[readonly], -.pure-form select[readonly], -.pure-form textarea[readonly] { - background-color: #eee; /* menu hover bg color */ - color: #777; /* menu text color */ - border-color: #ccc; -} - -.pure-form input:focus:invalid, -.pure-form textarea:focus:invalid, -.pure-form select:focus:invalid { - color: #b94a48; - border-color: #e9322d; -} -.pure-form input[type="file"]:focus:invalid:focus, -.pure-form input[type="radio"]:focus:invalid:focus, -.pure-form input[type="checkbox"]:focus:invalid:focus { - outline-color: #e9322d; -} -.pure-form select { - /* Normalizes the height; padding is not sufficient. */ - height: 2.25em; - border: 1px solid #ccc; - background-color: white; -} -.pure-form select[multiple] { - height: auto; -} -.pure-form label { - margin: 0.5em 0 0.2em; -} -.pure-form fieldset { - margin: 0; - padding: 0.35em 0 0.75em; - border: 0; -} -.pure-form legend { - display: block; - width: 100%; - padding: 0.3em 0; - margin-bottom: 0.3em; - color: #333; - border-bottom: 1px solid #e5e5e5; -} - -.pure-form-stacked input[type="text"], -.pure-form-stacked input[type="password"], -.pure-form-stacked input[type="email"], -.pure-form-stacked input[type="url"], -.pure-form-stacked input[type="date"], -.pure-form-stacked input[type="month"], -.pure-form-stacked input[type="time"], -.pure-form-stacked input[type="datetime"], -.pure-form-stacked input[type="datetime-local"], -.pure-form-stacked input[type="week"], -.pure-form-stacked input[type="number"], -.pure-form-stacked input[type="search"], -.pure-form-stacked input[type="tel"], -.pure-form-stacked input[type="color"], -.pure-form-stacked input[type="file"], -.pure-form-stacked select, -.pure-form-stacked label, -.pure-form-stacked textarea { - display: block; - margin: 0.25em 0; -} - -/* -Need to separate out the :not() selector from the rest of the CSS 2.1 selectors -since IE8 won't execute CSS that contains a CSS3 selector. -*/ -.pure-form-stacked input:not([type]) { - display: block; - margin: 0.25em 0; -} -.pure-form-aligned input, -.pure-form-aligned textarea, -.pure-form-aligned select, -/* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ -.pure-form-aligned .pure-help-inline, -.pure-form-message-inline { - display: inline-block; - *display: inline; - *zoom: 1; - vertical-align: middle; -} -.pure-form-aligned textarea { - vertical-align: top; -} - -/* Aligned Forms */ -.pure-form-aligned .pure-control-group { - margin-bottom: 0.5em; -} -.pure-form-aligned .pure-control-group label { - text-align: right; - display: inline-block; - vertical-align: middle; - width: 10em; - margin: 0 1em 0 0; -} -.pure-form-aligned .pure-controls { - margin: 1.5em 0 0 11em; -} - -/* Rounded Inputs */ -.pure-form input.pure-input-rounded, -.pure-form .pure-input-rounded { - border-radius: 2em; - padding: 0.5em 1em; -} - -/* Grouped Inputs */ -.pure-form .pure-group fieldset { - margin-bottom: 10px; -} -.pure-form .pure-group input, -.pure-form .pure-group textarea { - display: block; - padding: 10px; - margin: 0 0 -1px; - border-radius: 0; - position: relative; - top: -1px; -} -.pure-form .pure-group input:focus, -.pure-form .pure-group textarea:focus { - z-index: 3; -} -.pure-form .pure-group input:first-child, -.pure-form .pure-group textarea:first-child { - top: 1px; - border-radius: 4px 4px 0 0; - margin: 0; -} -.pure-form .pure-group input:first-child:last-child, -.pure-form .pure-group textarea:first-child:last-child { - top: 1px; - border-radius: 4px; - margin: 0; -} -.pure-form .pure-group input:last-child, -.pure-form .pure-group textarea:last-child { - top: -2px; - border-radius: 0 0 4px 4px; - margin: 0; -} -.pure-form .pure-group button { - margin: 0.35em 0; -} - -.pure-form .pure-input-1 { - width: 100%; -} -.pure-form .pure-input-2-3 { - width: 66%; -} -.pure-form .pure-input-1-2 { - width: 50%; -} -.pure-form .pure-input-1-3 { - width: 33%; -} -.pure-form .pure-input-1-4 { - width: 25%; -} - -/* Inline help for forms */ -/* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ -.pure-form .pure-help-inline, -.pure-form-message-inline { - display: inline-block; - padding-left: 0.3em; - color: #666; - vertical-align: middle; - font-size: 0.875em; -} - -/* Block help for forms */ -.pure-form-message { - display: block; - color: #666; - font-size: 0.875em; -} - -@media only screen and (max-width : 480px) { - .pure-form button[type="submit"] { - margin: 0.7em 0 0; - } - - .pure-form input:not([type]), - .pure-form input[type="text"], - .pure-form input[type="password"], - .pure-form input[type="email"], - .pure-form input[type="url"], - .pure-form input[type="date"], - .pure-form input[type="month"], - .pure-form input[type="time"], - .pure-form input[type="datetime"], - .pure-form input[type="datetime-local"], - .pure-form input[type="week"], - .pure-form input[type="number"], - .pure-form input[type="search"], - .pure-form input[type="tel"], - .pure-form input[type="color"], - .pure-form label { - margin-bottom: 0.3em; - display: block; - } - - .pure-group input:not([type]), - .pure-group input[type="text"], - .pure-group input[type="password"], - .pure-group input[type="email"], - .pure-group input[type="url"], - .pure-group input[type="date"], - .pure-group input[type="month"], - .pure-group input[type="time"], - .pure-group input[type="datetime"], - .pure-group input[type="datetime-local"], - .pure-group input[type="week"], - .pure-group input[type="number"], - .pure-group input[type="search"], - .pure-group input[type="tel"], - .pure-group input[type="color"] { - margin-bottom: 0; - } - - .pure-form-aligned .pure-control-group label { - margin-bottom: 0.3em; - text-align: left; - display: block; - width: 100%; - } - - .pure-form-aligned .pure-controls { - margin: 1.5em 0 0 0; - } - - /* NOTE: pure-help-inline is deprecated. Use .pure-form-message-inline instead. */ - .pure-form .pure-help-inline, - .pure-form-message-inline, - .pure-form-message { - display: block; - font-size: 0.75em; - /* Increased bottom padding to make it group with its related input element. */ - padding: 0.2em 0 0.8em; - } -} - -/*csslint adjoining-classes: false, box-model:false*/ -.pure-menu { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -.pure-menu-fixed { - position: fixed; - left: 0; - top: 0; - z-index: 3; -} - -.pure-menu-list, -.pure-menu-item { - position: relative; -} - -.pure-menu-list { - list-style: none; - margin: 0; - padding: 0; -} - -.pure-menu-item { - padding: 0; - margin: 0; - height: 100%; -} - -.pure-menu-link, -.pure-menu-heading { - display: block; - text-decoration: none; - white-space: nowrap; -} - -/* HORIZONTAL MENU */ -.pure-menu-horizontal { - width: 100%; - white-space: nowrap; -} - -.pure-menu-horizontal .pure-menu-list { - display: inline-block; -} - -/* Initial menus should be inline-block so that they are horizontal */ -.pure-menu-horizontal .pure-menu-item, -.pure-menu-horizontal .pure-menu-heading, -.pure-menu-horizontal .pure-menu-separator { - display: inline-block; - *display: inline; - zoom: 1; - vertical-align: middle; -} - -/* Submenus should still be display: block; */ -.pure-menu-item .pure-menu-item { - display: block; -} - -.pure-menu-children { - display: none; - position: absolute; - left: 100%; - top: 0; - margin: 0; - padding: 0; - z-index: 3; -} - -.pure-menu-horizontal .pure-menu-children { - left: 0; - top: auto; - width: inherit; -} - -.pure-menu-allow-hover:hover > .pure-menu-children, -.pure-menu-active > .pure-menu-children { - display: block; - position: absolute; -} - -/* Vertical Menus - show the dropdown arrow */ -.pure-menu-has-children > .pure-menu-link:after { - padding-left: 0.5em; - content: "\25B8"; - font-size: small; -} - -/* Horizontal Menus - show the dropdown arrow */ -.pure-menu-horizontal .pure-menu-has-children > .pure-menu-link:after { - content: "\25BE"; -} - -/* scrollable menus */ -.pure-menu-scrollable { - overflow-y: scroll; - overflow-x: hidden; -} - -.pure-menu-scrollable .pure-menu-list { - display: block; -} - -.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list { - display: inline-block; -} - -.pure-menu-horizontal.pure-menu-scrollable { - white-space: nowrap; - overflow-y: hidden; - overflow-x: auto; - -ms-overflow-style: none; - -webkit-overflow-scrolling: touch; - /* a little extra padding for this style to allow for scrollbars */ - padding: .5em 0; -} - -.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar { - display: none; -} - -/* misc default styling */ - -.pure-menu-separator { - background-color: #ccc; - height: 1px; - margin: .3em 0; -} - -.pure-menu-horizontal .pure-menu-separator { - width: 1px; - height: 1.3em; - margin: 0 .3em ; -} - -.pure-menu-heading { - text-transform: uppercase; - color: #565d64; -} - -.pure-menu-link { - color: #777; -} - -.pure-menu-children { - background-color: #fff; -} - -.pure-menu-link, -.pure-menu-disabled, -.pure-menu-heading { - padding: .5em 1em; -} - -.pure-menu-disabled { - opacity: .5; -} - -.pure-menu-disabled .pure-menu-link:hover { - background-color: transparent; -} - -.pure-menu-active > .pure-menu-link, -.pure-menu-link:hover, -.pure-menu-link:focus { - background-color: #eee; -} - -.pure-menu-selected .pure-menu-link, -.pure-menu-selected .pure-menu-link:visited { - color: #000; -} - -.pure-table { - /* Remove spacing between table cells (from Normalize.css) */ - border-collapse: collapse; - border-spacing: 0; - empty-cells: show; - border: 1px solid #cbcbcb; -} - -.pure-table caption { - color: #000; - font: italic 85%/1 arial, sans-serif; - padding: 1em 0; - text-align: center; -} - -.pure-table td, -.pure-table th { - border-left: 1px solid #cbcbcb;/* inner column border */ - border-width: 0 0 0 1px; - font-size: inherit; - margin: 0; - overflow: visible; /*to make ths where the title is really long work*/ - padding: 0.5em 1em; /* cell padding */ -} - -/* Consider removing this next declaration block, as it causes problems when -there's a rowspan on the first cell. Case added to the tests. issue#432 */ -.pure-table td:first-child, -.pure-table th:first-child { - border-left-width: 0; -} - -.pure-table thead { - background-color: #e0e0e0; - color: #000; - text-align: left; - vertical-align: bottom; -} - -/* -striping: - even - #fff (white) - odd - #f2f2f2 (light gray) -*/ -.pure-table td { - background-color: transparent; -} -.pure-table-odd td { - background-color: #f2f2f2; -} - -/* nth-child selector for modern browsers */ -.pure-table-striped tr:nth-child(2n-1) td { - background-color: #f2f2f2; -} - -/* BORDERED TABLES */ -.pure-table-bordered td { - border-bottom: 1px solid #cbcbcb; -} -.pure-table-bordered tbody > tr:last-child > td { - border-bottom-width: 0; -} - - -/* HORIZONTAL BORDERED TABLES */ - -.pure-table-horizontal td, -.pure-table-horizontal th { - border-width: 0 0 1px 0; - border-bottom: 1px solid #cbcbcb; -} -.pure-table-horizontal tbody > tr:last-child > td { - border-bottom-width: 0; -} diff --git a/httpd/html-old/style.css b/httpd/html-old/style.css deleted file mode 100644 index 29d15a3..0000000 --- a/httpd/html-old/style.css +++ /dev/null @@ -1,380 +0,0 @@ -/* All fonts */ -html, button, input, select, textarea, .pure-g [class *= "pure-u"] { - font-family: sans-serif; -} - -body { - color: #777; -} -a:visited, a:link { - color: #009; -} -a:hover { - color: #00c; -} - -.card { - background-color: #eee; - padding: 1em; - margin: 0.5em; - -moz-border-radius: 0.5em; - -webkit-border-radius: 0.5em; - border-radius: 0.5em; - border: 0px solid #000000; -} - -/* wifi AP selection form */ -#aps label div { - display: inline-block; - margin: 0em 0.2em; -} -fieldset.radios { - border: none; - padding-left: 0px; -} -fieldset fields { - clear: both; -} -#pin-mux input { - display: block; - margin-top: 0.4em; - float: left; -} -#pin-mux label { - display: block; - margin: 0em 0.2em 0em 1em; - width: 90%; -} - -.pure-table td, .pure-table th { - padding: 0.5em 0.5em; -} - -/* make images size-up */ -.xx-pure-img-responsive { - max-width: 100%; - height: auto; -} - -/* Add transition to containers so they can push in and out */ -#layout, #menu, .menu-link { - -webkit-transition: all 0.2s ease-out; - -moz-transition: all 0.2s ease-out; - -ms-transition: all 0.2s ease-out; - -o-transition: all 0.2s ease-out; - transition: all 0.2s ease-out; -} - -/* This is the parent `
` that contains the menu and the content area */ -#layout { - position: relative; - padding-left: 0; -} -#layout.active #menu { - left: 150px; - width: 150px; -} - -#layout.active .menu-link { - 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; - padding: 0 2em; - max-width: 800px; - margin-bottom: 50px; - line-height: 1.6em; -} - -.header { - margin: 0; - color: #333; - text-align: center; - padding: 2.5em 2em 0; - border-bottom: 1px solid #eee; - background-color: #fc0; -} -.header h1 { - margin: 0.2em 0; - font-size: 3em; - font-weight: 300; -} -.header h1 .esp { - font-size: 1.25em; -} -.jl { - font: normal 800 1.5em sans-serif; - position: relative; - bottom: 19px; - color: #9d1414; - margin-left: 3px; -} - -.content-subhead { - margin: 50px 0 20px 0; - font-weight: 300; - color: #888; -} - -form button { - margin-top: 0.5em; -} -.button-primary { - background-color: #99f; -} -.button-selected { - background-color: #fc6; -} - -/* Text console */ -pre.console { - background-color: #663300; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; - border-radius: 5px; - border: 0px solid #000000; - color: #66ff66; - padding: 5px; -} - -pre.console a { - color: #66ff66; -} - -/* log page */ -.dbg-btn, #refresh-button { - vertical-align: baseline; -} - -.lock-icon { - background-image: url("/wifi/icons.png"); - background-color: transparent; - width: 32px; - height: 32px; - display: inline-block; -} - -#menu { - margin-left: -150px; - width: 150px; - position: fixed; - top: 0; - left: 0; - bottom: 0; - z-index: 1000; - background: #191818; - overflow-y: auto; - -webkit-overflow-scrolling: touch; -} - -#menu a { - color: #999; - border: none; - padding: 0.6em 0 0.6em 0.6em; -} - -#menu .pure-menu, #menu .pure-menu ul { - border: none; - background: transparent; -} - -#menu .pure-menu ul, #menu .pure-menu .menu-item-divided { - border-top: 1px solid #333; -} - -#menu .pure-menu li a:hover, #menu .pure-menu li a:focus { - background: #333; -} - -#menu .pure-menu-selected, #menu .pure-menu-heading { - background: #9d1414; -} - -#menu .pure-menu-selected a { - color: #fff; -} - -#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 { - height:2em; -} - -/* -- Dynamic Button For Responsive Menu -------------------------------------*/ - -.menu-link { - position: fixed; - display: block; - top: 0; - left: 0; - background: #000; - background: rgba(0,0,0,0.7); - font-size: 10px; - z-index: 10; - width: 2em; - height: auto; - padding: 2.1em 1.6em; -} - -.menu-link:hover, .menu-link:focus { - background: #000; -} - -.menu-link span { - position: relative; - display: block; -} - -.menu-link span, .menu-link span:before, .menu-link span:after { - background-color: #fff; - width: 100%; - height: 0.2em; -} - -.menu-link span:before, .menu-link span:after { - position: absolute; - margin-top: -0.6em; - content: " "; -} - -.menu-link span:after { - margin-top: 0.6em; -} - -/* -- Responsive Styles (Media Queries) ------------------------------------- */ - -@media (min-width: 56em) { - .header, .content { - padding-left: 2em; - padding-right: 2em; - } - - #layout { - padding-left: 150px; - left: 0; - } - #menu { - left: 150px; - } - - .menu-link { - position: fixed; - left: 150px; - display: none; - } - - #layout.active .menu-link { - left: 150px; - } -} - -@media (max-width: 56em) { - #layout.active { - position: relative; - left: 150px; - } -} - -/*===== spinners and notification messages */ - -#messages { - position: absolute; - left: 25%; - width: 50%; - top: 10; - z-index: 200; - font-size: 110%; - text-align: center; -} -#warning { - background-color: #933; - color: #fcc; - padding: 0.1em 0.4em; -} -#notification { - background-color: #693; - color: #cfc; - padding: 0.1em 0.4em; -} - -#spinner { - position: absolute; - right: 10%; - top: 20; - z-index: 1000; -} -.spinner { - height: 50px; - width: 50px; - -webkit-animation: rotation 1s infinite linear; - -moz-animation: rotation 1s infinite linear; - -o-animation: rotation 1s infinite linear; - animation: rotation 1s infinite linear; - border-left: 10px solid rgba(204, 51, 0, 0.15); - border-right: 10px solid rgba(204, 51, 0, 0.15); - border-bottom: 10px solid rgba(204, 51, 0, 0.15); - border-top: 10px solid rgba(204, 51, 0, 0.8); - border-radius: 100%; -} -.spinner-small { - display: inline-block; - height: 1em; - width: 1em; - border-width: 4px; -} - -@-webkit-keyframes rotation { - from { - -webkit-transform: rotate(0deg); - } - to { - -webkit-transform: rotate(359deg); - } -} -@-moz-keyframes rotation { - from { - -moz-transform: rotate(0deg); - } - to { - -moz-transform: rotate(359deg); - } -} -@-o-keyframes rotation { - from { - -o-transform: rotate(0deg); - } - to { - -o-transform: rotate(359deg); - } -} -@keyframes rotation { - from { - transform: rotate(0deg); - } - to { - transform: rotate(359deg); - } -} diff --git a/httpd/html-old/ui.js b/httpd/html-old/ui.js deleted file mode 100644 index 56cc256..0000000 --- a/httpd/html-old/ui.js +++ /dev/null @@ -1,397 +0,0 @@ -//===== Collection of small utilities - -/* - * Bind/Unbind events - * - * Usage: - * var el = document.getElementyById('#container'); - * bnd(el, 'click', function() { - * console.log('clicked'); - * }); - */ - -var bnd = function( - d, // a DOM element - e, // an event name such as "click" - f // a handler function -){ - d.addEventListener(e, f, false); -} - -/* - * Create DOM element - * - * Usage: - * var el = m('

Hello

'); - * document.body.appendChild(el); - * - * Copyright (C) 2011 Jed Schmidt - WTFPL - * More: https://gist.github.com/966233 - */ - -var m = function( - a, // an HTML string - b, // placeholder - c // placeholder -){ - b = document; // get the document, - c = b.createElement("p"); // create a container element, - c.innerHTML = a; // write the HTML to it, and - a = b.createDocumentFragment(); // create a fragment. - - while ( // while - b = c.firstChild // the container element has a first child - ) a.appendChild(b); // append the child to the fragment, - - return a // and then return the fragment. -} - -/* - * DOM selector - * - * Usage: - * $('div'); - * $('#name'); - * $('.name'); - * - * Copyright (C) 2011 Jed Schmidt - WTFPL - * More: https://gist.github.com/991057 - */ - -var $ = function( - a, // take a simple selector like "name", "#name", or ".name", and - b // an optional context, and -){ - a = a.match(/^(\W)?(.*)/); // split the selector into name and symbol. - return( // return an element or list, from within the scope of - b // the passed context - || document // or document, - )[ - "getElement" + ( // obtained by the appropriate method calculated by - a[1] - ? a[1] == "#" - ? "ById" // the node by ID, - : "sByClassName" // the nodes by class name, or - : "sByTagName" // the nodes by tag name, - ) - ]( - a[2] // called with the name. - ) -} - -/* - * Get cross browser xhr object - * - * Copyright (C) 2011 Jed Schmidt - * More: https://gist.github.com/993585 - */ - -var j = function( - a // cursor placeholder -){ - for( // for all a - a=0; // from 0 - a<4; // to 4, - a++ // incrementing - ) try { // try - return a // returning - ? new ActiveXObject( // a new ActiveXObject - [ // reflecting - , // (elided) - "Msxml2", // the various - "Msxml3", // working - "Microsoft" // options - ][a] + // for Microsoft implementations, and - ".XMLHTTP" // the appropriate suffix, - ) // but make sure to - : new XMLHttpRequest // try the w3c standard first, and - } - - catch(e){} // ignore when it fails. -} - -// createElement short-hand - -e = function(a) { return document.createElement(a); } - -// chain onload handlers - -function onLoad(f) { - var old = window.onload; - if (typeof old != 'function') { - window.onload = f; - } else { - window.onload = function() { - old(); - f(); - } - } -} - -//===== helpers to add/remove/toggle HTML element classes - -function addClass(el, cl) { - el.className += ' ' + cl; -} -function removeClass(el, cl) { - var cls = el.className.split(/\s+/), - l = cls.length; - for (var i=0; i= 200 && xhr.status < 300) { - console.log("XHR done:", method, url, "->", xhr.status); - ok_cb(xhr.responseText); - } else { - console.log("XHR ERR :", method, url, "->", xhr.status, xhr.responseText, xhr); - err_cb(xhr.status, xhr.responseText); - } - } - console.log("XHR send:", method, url); - try { - xhr.send(); - } catch(err) { - console.log("XHR EXC :", method, url, "->", err); - err_cb(599, err); - } -} - -function dispatchJson(resp, ok_cb, err_cb) { - var j; - try { j = JSON.parse(resp); } - catch(err) { - console.log("JSON parse error: " + err + ". In: " + resp); - err_cb(500, "JSON parse error: " + err); - return; - } - ok_cb(j); -} - -function ajaxJson(method, url, ok_cb, err_cb) { - ajaxReq(method, url, function(resp) { dispatchJson(resp, ok_cb, err_cb); }, err_cb); -} - -function ajaxSpin(method, url, ok_cb, err_cb) { - $("#spinner").removeAttribute('hidden'); - ajaxReq(method, url, function(resp) { - $("#spinner").setAttribute('hidden', ''); - ok_cb(resp); - }, function(status, statusText) { - $("#spinner").setAttribute('hidden', ''); - //showWarning("Error: " + statusText); - err_cb(status, statusText); - }); -} - -function ajaxJsonSpin(method, url, ok_cb, err_cb) { - ajaxSpin(method, url, function(resp) { dispatchJson(resp, ok_cb, err_cb); }, err_cb); -} - -//===== main menu, header spinner and notification boxes - -onLoad(function() { - var l = $("#layout"); - var o = l.childNodes[0]; - // spinner - l.insertBefore(m(''), o); - // notification boxes - l.insertBefore(m( - '
'), o); - // menu hamburger button - l.insertBefore(m(''), o); - // menu left-pane - var mm = m( - '\ - '); - l.insertBefore(mm, o); - - // make hamburger button pull out menu - var ml = $('#menuLink'), mm = $('#menu'); - bnd(ml, 'click', function (e) { - console.log("hamburger time"); - var active = 'active'; - e.preventDefault(); - toggleClass(l, active); - toggleClass(mm, active); - toggleClass(ml, active); - }); - - // populate menu via ajax call - var getMenu = function() { - ajaxJson("GET", "/menu", function(data) { - var html = "", path = window.location.pathname; - for (var i=0; i" + - "" + - data.menu[i] + ""); - } - $("#menu-list").innerHTML = html; - - v = $("#version"); - if (v != null) { v.innerHTML = data.version; } - }, function() { setTimeout(getMenu, 1000); }); - }; - getMenu(); -}); - -//===== Wifi info - -function showWifiInfo(data) { - Object.keys(data).forEach(function(v) { - el = $("#wifi-" + v); - if (el != null) { - if (el.nodeName === "INPUT") el.value = data[v]; - else el.innerHTML = data[v]; - } - }); - var dhcp = $('#dhcp-r'+data.dhcp); - if (dhcp) dhcp.click(); - $("#wifi-spinner").setAttribute("hidden", ""); - $("#wifi-table").removeAttribute("hidden"); - currAp = data.ssid; -} - -function getWifiInfo() { - ajaxJson('GET', "/wifi/info", showWifiInfo, - function(s, st) { window.setTimeout(getWifiInfo, 1000); }); -} - -//===== Notifications - -function showWarning(text) { - var el = $("#warning"); - el.innerHTML = text; - el.removeAttribute('hidden'); -} -function hideWarning() { - el = $("#warning").setAttribute('hidden', ''); -} -var notifTimeout = null; -function showNotification(text) { - var el = $("#notification"); - el.innerHTML = text; - el.removeAttribute('hidden'); - if (notifTimeout != null) clearTimeout(notifTimeout); - notifTimout = setTimeout(function() { - el.setAttribute('hidden', ''); - notifTimout = null; - }, 4000); -} - -//===== 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; -} - -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; - rssiEn().checked = resp.rssi_enable > 0; - apiKey().value = resp.api_key; -} - -function fetchTcpClient() { - ajaxJson("GET", "/tcpclient", displayTcpClient, function() { - window.setTimeout(fetchTcpClient, 1000); - }); -} - - diff --git a/httpd/html-old/wifi/icons.png b/httpd/html-old/wifi/icons.png deleted file mode 100644 index 03109e1..0000000 Binary files a/httpd/html-old/wifi/icons.png and /dev/null differ diff --git a/httpd/html-old/wifi/wifi.html b/httpd/html-old/wifi/wifi.html deleted file mode 100644 index b6c142b..0000000 --- a/httpd/html-old/wifi/wifi.html +++ /dev/null @@ -1,84 +0,0 @@ -
-
-

Wifi Configuration

-
- -
-
-
-

Wifi State

-
- - - - - - - - - - - -
-
-

Wifi Association

- -
- To connect to a WiFi network, please select one of the detected networks, - enter the password, and hit the connect button... - -
Scanning...
- - - -
-
-
-
-
-

Special Settings

-
- Special settings, use with care! -
- - -
-
- - -
-
- - - - - - -
- -
-
-
-
-
-
- - - - - diff --git a/httpd/html-old/wifi/wifi.js b/httpd/html-old/wifi/wifi.js deleted file mode 100644 index 0024248..0000000 --- a/httpd/html-old/wifi/wifi.js +++ /dev/null @@ -1,200 +0,0 @@ -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('').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 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.ip+", else connect to network "+data.ssid+" first."; - } else { - blockScan = 0; - showWarning("Connection failed: " + data.status + ", " + data.reason); - $("#aps").innerHTML = - "Check password and selected AP. Go Back"; - } - }, 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', ''); -} diff --git a/httpd/httpd.c b/httpd/httpd.c index fe22047..cc586b2 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -92,7 +92,9 @@ static void debugConn(void *arg, char *what) { os_sprintf(connStr, "%d.%d.%d.%d:%d", tcp->remote_ip[0], tcp->remote_ip[1], tcp->remote_ip[2], tcp->remote_ip[3], tcp->remote_port); - //os_printf("%s %s\n", connStr, what); +#ifdef HTTPD_DBG + os_printf("%s %s\n", connStr, what); +#endif } //Looks up the connData info for a specific esp connection @@ -102,7 +104,7 @@ static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) { if (connData[i].remote_port == espconn->proto.tcp->remote_port && os_memcmp(connData[i].remote_ip, espconn->proto.tcp->remote_ip, 4) == 0) { -#if 0 +#ifdef HTTPD_DBG os_printf("FindConn: 0x%p->0x%p", arg, &connData[i]); if (arg == connData[i].conn) os_printf("\n"); else os_printf(" *** was 0x%p\n", connData[i].conn); @@ -112,7 +114,9 @@ static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(void *arg) { } } //Shouldn't happen. +#ifdef HTTPD_DBG os_printf("%s *** Unknown connection 0x%p\n", connStr, arg); +#endif return NULL; } @@ -130,8 +134,10 @@ static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) { uint32 dt = conn->startTime; if (dt > 0) dt = (system_get_time() - dt)/1000; +#ifdef HTTPD_DBG os_printf("%s Closed, %ums, heap=%ld\n", connStr, dt, (unsigned long)system_get_free_heap_size()); +#endif } //Stupid li'l helper function that returns the value of a hex char. @@ -180,18 +186,24 @@ int ICACHE_FLASH_ATTR httpdFindArg(char *line, char *arg, char *buff, int buffLe if (line==NULL) return 0; p=line; while(p!=NULL && *p!='\n' && *p!='\r' && *p!=0) { - //os_printf("findArg: %s\n", p); +#ifdef HTTPD_DBG + os_printf("findArg: %s\n", p); +#endif if (os_strncmp(p, arg, os_strlen(arg))==0 && p[strlen(arg)]=='=') { p+=os_strlen(arg)+1; //move p to start of value e=(char*)os_strstr(p, "&"); if (e==NULL) e=p+os_strlen(p); - //os_printf("findArg: val %s len %d\n", p, (e-p)); +#ifdef HTTPD_DBG + os_printf("findArg: val %s len %d\n", p, (e-p)); +#endif return httpdUrlDecode(p, (e-p), buff, buffLen); } p=(char*)os_strstr(p, "&"); if (p!=NULL) p+=1; } +#ifdef HTTPD_DBG os_printf("Finding %s in %s: Not found :/\n", arg, line); +#endif return -1; //not found } @@ -272,8 +284,10 @@ int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) { int ICACHE_FLASH_ATTR httpdSend(HttpdConnData *conn, const char *data, int len) { if (len<0) len=strlen(data); if (conn->priv->sendBuffLen+len>MAX_SENDBUFF_LEN) { +#ifdef HTTPD_DBG os_printf("%s ERROR! httpdSend full (%d of %d)\n", connStr, conn->priv->sendBuffLen, MAX_SENDBUFF_LEN); +#endif return 0; } os_memcpy(conn->priv->sendBuff+conn->priv->sendBuffLen, data, len); @@ -286,7 +300,9 @@ static void ICACHE_FLASH_ATTR xmitSendBuff(HttpdConnData *conn) { if (conn->priv->sendBuffLen!=0) { sint8 status = espconn_sent(conn->conn, (uint8_t*)conn->priv->sendBuff, conn->priv->sendBuffLen); if (status != 0) { +#ifdef HTTPD_DBG os_printf("%s ERROR! espconn_sent returned %d\n", connStr, status); +#endif } conn->priv->sendBuffLen=0; } @@ -304,7 +320,9 @@ static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) { conn->priv->sendBuffLen=0; if (conn->cgi==NULL) { //Marked for destruction? - //os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn); +#ifdef HTTPD_DBG + os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn); +#endif espconn_disconnect(conn->conn); // we will get a disconnect callback return; //No need to call xmitSendBuff. } @@ -314,7 +332,9 @@ static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) { conn->cgi=NULL; //mark for destruction. } if (r==HTTPD_CGI_NOTFOUND || r==HTTPD_CGI_AUTHENTICATED) { +#ifdef HTTPD_DBG os_printf("%s ERROR! Bad CGI code %d\n", connStr, r); +#endif conn->cgi=NULL; //mark for destruction. } xmitSendBuff(conn); @@ -330,7 +350,9 @@ static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { int r; int i=0; if (conn->url==NULL) { +#ifdef HTTPD_DBG os_printf("%s WtF? url = NULL\n", connStr); +#endif return; //Shouldn't happen } //See if we can find a CGI that's happy to handle the request. @@ -344,7 +366,9 @@ static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { 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; if (match) { - //os_printf("Is url index %d\n", i); +#ifdef HTTPD_DBG + os_printf("Is url index %d\n", i); +#endif conn->cgiData=NULL; conn->cgi=builtInUrls[i].cgiCb; conn->cgiArg=builtInUrls[i].cgiArg; @@ -355,7 +379,9 @@ static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) { if (builtInUrls[i].url==NULL) { //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. +#ifdef HTTPD_DBG os_printf("%s %s not found. 404!\n", connStr, conn->url); +#endif httpdSend(conn, httpNotFoundHeader, -1); xmitSendBuff(conn); conn->cgi=NULL; //mark for destruction @@ -411,15 +437,18 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { // Count number of open connections int open = 0; for (int j=0; jrequestType == HTTPD_METHOD_GET ? "GET" : "POST", conn->url, open); +#endif //Parse out the URL part before the GET parameters. conn->getArgs=(char*)os_strstr(conn->url, "?"); if (conn->getArgs!=0) { *conn->getArgs=0; conn->getArgs++; +#ifdef HTTPD_DBG os_printf("%s args = %s\n", connStr, conn->getArgs); +#endif } else { conn->getArgs=NULL; } @@ -438,7 +467,9 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { } else { conn->post->buffSize = conn->post->len; } - //os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); +#ifdef HTTPD_DBG + os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize); +#endif conn->post->buff=(char*)os_malloc(conn->post->buffSize + 1); conn->post->buffLen=0; } else if (os_strncmp(h, "Content-Type: ", 14)==0) { @@ -449,7 +480,9 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) { conn->post->multipartBoundary = b + 7; // move the pointer 2 chars before boundary then fill them with dashes conn->post->multipartBoundary[0] = '-'; conn->post->multipartBoundary[1] = '-'; - //os_printf("boundary = %s\n", conn->post->multipartBoundary); +#ifdef HTTPD_DBG + os_printf("boundary = %s\n", conn->post->multipartBoundary); +#endif } } } @@ -525,7 +558,9 @@ static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) { static void ICACHE_FLASH_ATTR httpdReconCb(void *arg, sint8 err) { debugConn(arg, "httpdReconCb"); HttpdConnData *conn = httpdFindConnData(arg); +#ifdef HTTPD_DBG os_printf("%s ***** reset, err=%d\n", connStr, err); +#endif if (conn == NULL) return; httpdRetireConn(conn); } @@ -537,14 +572,18 @@ static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) { int i; //Find empty conndata in pool for (i=0; i #include #include @@ -19,7 +22,14 @@ extern char* esp_link_version; void ICACHE_FLASH_ATTR init(void); +inline char* ICACHE_FLASH_ATTR system_get_chip_id_str(){ + char *chipId = (char*)os_zalloc(9); + os_sprintf(chipId, "%06x", system_get_chip_id()); + return chipId; +} #ifdef __WIN32__ #include <_mingw.h> #endif + +#endif // _ESP8266_H_ \ No newline at end of file diff --git a/include/user_config.h b/include/user_config.h index 7bdfd38..de558e3 100644 --- a/include/user_config.h +++ b/include/user_config.h @@ -8,13 +8,13 @@ #define MQTT_PORT 1883 #define MQTT_SECURITY 0 -#define MQTT_CLIENT_ID "esp-link" // "" +#define MQTT_CLIENT_ID system_get_chip_id_str() // "esp-link" #define MQTT_USER "" #define MQTT_PASS "" #define MQTT_KEEPALIVE 120 // seconds #define MQTT_CLSESSION true -#define PROTOCOL_NAMEv31 // MQTT version 3.1 compatible with Mosquitto v0.15 +#define PROTOCOL_NAMEv31 // MQTT version 3.1 compatible with Mosquitto v0.15/ //PROTOCOL_NAMEv311 // MQTT version 3.11 compatible with https://eclipse.org/paho/clients/testing/ #endif \ No newline at end of file diff --git a/libraries/Time/Time.c b/libraries/Time/Time.c new file mode 100644 index 0000000..7e66286 --- /dev/null +++ b/libraries/Time/Time.c @@ -0,0 +1,274 @@ +#include "Time.h" + +static tmElements_t tm; // a cache of time elements +static time_t cacheTime; // the time the cache was updated +static time_t syncInterval = 300; // time sync will be attempted after this many seconds + +static os_timer_t micros_overflow_timer; +static uint32_t micros_at_last_overflow_tick = 0; +static uint32_t micros_overflow_count = 0; + +static time_t sysTime = 0; +static time_t prevMillis = 0; +static time_t nextSyncTime = 0; +static timeStatus_t Status = timeNotSet; + +getExternalTime getTimePtr; + +int16_t ICACHE_FLASH_ATTR +totalMinutes(int16_t hours, int8_t minutes) +{ + return (hours * 60) + minutes; +} + +void ICACHE_FLASH_ATTR +micros_overflow_tick(void* arg) { + uint32_t m = system_get_time(); + if (m < micros_at_last_overflow_tick) + ++micros_overflow_count; + micros_at_last_overflow_tick = m; +} + +unsigned long ICACHE_FLASH_ATTR +millis() { + uint32_t m = system_get_time(); + uint32_t c = micros_overflow_count + ((m < micros_at_last_overflow_tick) ? 1 : 0); + return c * 4294967 + m / 1000; +} + +unsigned long ICACHE_FLASH_ATTR +micros() { + return system_get_time(); +} + +void ICACHE_FLASH_ATTR +time_init() { + os_timer_setfn(µs_overflow_timer, (os_timer_func_t*)µs_overflow_tick, 0); + os_timer_arm(µs_overflow_timer, 60000, 1); +} + +void ICACHE_FLASH_ATTR +breakTime(time_t time, tmElements_t *tm){ + + uint8_t year; + uint8_t month, monthLength; + unsigned long days; + + tm->Second = time % 60; + time /= 60; // now it is minutes + tm->Minute = time % 60; + time /= 60; // now it is hours + tm->Hour = time % 24; + time /= 24; // now it is days + tm->Wday = ((time + 4) % 7) + 1; // Sunday is day 1 + + year = 0; + days = 0; + while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; + } + tm->Year = year; // year is offset from 1970 + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // now it is days in this year, starting at 0 + + days = 0; + month = 0; + monthLength = 0; + for (month = 0; month<12; month++) { + if (month == 1) { // february + if (LEAP_YEAR(year)) { + monthLength = 29; + } + else { + monthLength = 28; + } + } + else { + monthLength = monthDays[month]; + } + + if (time >= monthLength) { + time -= monthLength; + } + else { + break; + } + } + tm->Month = month + 1; // jan is month 1 + tm->Day = time + 1; // day of month +} + +/* +* Convert the "timeInput" time_t count into "struct tm" time components. +* This is a more compact version of the C library localtime function. +* Note that year is offset from 1970 !!! +*/ +void ICACHE_FLASH_ATTR +timet_to_tm(time_t timeInput, struct tmElements *tmel){ + + uint8_t year; + uint8_t month, monthLength; + uint32_t time; + unsigned long days; + + time = (uint32_t)timeInput; + tmel->Second = time % 60; + time /= 60; // Now it is minutes. + tmel->Minute = time % 60; + time /= 60; // Now it is hours. + tmel->Hour = time % 24; + time /= 24; // Now it is days. + tmel->Wday = ((time + 4) % 7) + 1; // Sunday is day 1. + + year = 0; + days = 0; + while ((unsigned)(days += (LEAP_YEAR(year) ? 366 : 365)) <= time) { + year++; + } + tmel->Year = year; // The year is offset from 1970. + + days -= LEAP_YEAR(year) ? 366 : 365; + time -= days; // Now it is days in this year, starting at 0. + + days = 0; + month = 0; + monthLength = 0; + for (month = 0; month<12; month++) { + if (month == 1) { // February. + if (LEAP_YEAR(year)) { + monthLength = 29; + } + else { + monthLength = 28; + } + } + else { + monthLength = monthDays[month]; + } + + if (time >= monthLength) { + time -= monthLength; + } + else { + break; + } + } + tmel->Month = month + 1; // Jan is month 1. + tmel->Day = time + 1; // Day of month. +} + +/* +* Reconstitute "struct tm" elements into a time_t count value. +* Note that the year argument is offset from 1970. +*/ +time_t ICACHE_FLASH_ATTR +tm_to_timet(struct tmElements *tmel){ + + int i; + uint32_t seconds; + + // Seconds from 1970 till 1st Jan 00:00:00 of the given year. + seconds = tmel->Year*(SECS_PER_DAY * 365); + for (i = 0; i < tmel->Year; i++) { + if (LEAP_YEAR(i)) { + seconds += SECS_PER_DAY; // Add extra days for leap years. + } + } + + // Add the number of elapsed days for the given year. Months start from 1. + for (i = 1; i < tmel->Month; i++) { + if ((i == 2) && LEAP_YEAR(tmel->Year)) { + seconds += SECS_PER_DAY * 29; + } + else { + seconds += SECS_PER_DAY * monthDays[i - 1]; // "monthDay" array starts from 0. + } + } + seconds += (tmel->Day - 1) * SECS_PER_DAY; // Days... + seconds += tmel->Hour * SECS_PER_HOUR; // Hours... + seconds += tmel->Minute * SECS_PER_MIN; // Minutes... + seconds += tmel->Second; // ...and finally, Seconds. + return (time_t)seconds; +} + +void ICACHE_FLASH_ATTR +refreshCache(time_t t){ + if (t != cacheTime) + { + breakTime(t, &tm); + cacheTime = t; + } +} + +int ICACHE_FLASH_ATTR +hour() { // the hour now + time_t t = now(); + refreshCache(t); + return tm.Hour; +} + +int ICACHE_FLASH_ATTR +minute() { // the minute now + time_t t = now(); + refreshCache(t); + return tm.Minute; +} + +int ICACHE_FLASH_ATTR +second() { // the second now + time_t t = now(); + refreshCache(t); + return tm.Second; +} + +void ICACHE_FLASH_ATTR +setTime(time_t t){ +#ifdef TIME_DRIFT_INFO + if (sysUnsyncedTime == 0) + sysUnsyncedTime = t; // store the time of the first call to set a valid Time +#endif + + sysTime = t; + nextSyncTime = t + syncInterval; + Status = timeSet; + prevMillis = millis(); // restart counting from now (thanks to Korman for this fix) +} + +time_t ICACHE_FLASH_ATTR +now(){ + while (millis() - prevMillis >= 1000){ + sysTime++; + prevMillis += 1000; +#ifdef TIME_DRIFT_INFO + sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift +#endif + } + if (nextSyncTime <= sysTime){ + if (getTimePtr != 0){ + time_t t = getTimePtr(); + if (t != 0) + setTime(t); + else + Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync; + } + } + return sysTime; +} + +timeStatus_t ICACHE_FLASH_ATTR +timeStatus(){ // indicates if time has been set and recently synchronized + return Status; +} + +void ICACHE_FLASH_ATTR +setSyncProvider(getExternalTime getTimeFunction){ + getTimePtr = getTimeFunction; + nextSyncTime = sysTime; + now(); // this will sync the clock +} + +void ICACHE_FLASH_ATTR +setSyncInterval(time_t interval){ // set the number of seconds between re-sync + syncInterval = interval; +} \ No newline at end of file diff --git a/libraries/Time/Time.h b/libraries/Time/Time.h new file mode 100644 index 0000000..31e4088 --- /dev/null +++ b/libraries/Time/Time.h @@ -0,0 +1,130 @@ +#ifndef _TIME_H_ +#define _TIME_H_ + +#include + +/* +* Constants. +*/ +#define SECS_PER_MIN (60UL) +#define SECS_PER_HOUR (3600UL) +#define SECS_PER_DAY (SECS_PER_HOUR * 24UL) +#define DAYS_PER_WEEK (7UL) +#define SECS_PER_WEEK (SECS_PER_DAY * DAYS_PER_WEEK) +#define SECS_PER_YEAR (SECS_PER_WEEK * 52UL) +#define SECS_YR_2000 (946684800UL) // The time_t value at the very start of Y2K. + +/* +* Days per month. +* Note that the standard time.h starts months from "1", but this +* version starts from "0". +*/ +static const uint8_t monthDays[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +/* +* Standard "struct tm" equivalent. +* =NOTE= Differences:- +* - Year offset is from 1970 (standard tm is from 1900). +* - Wday Sunday is day "1" (standard tm has it as day "0"). +* - The "Day" field is what standard tm refers to as "yday". +* - There is no "date" or Day-of-Month field. +* - There is no "isdst" field. +*/ +struct tmElements { + uint8_t Second; + uint8_t Minute; + uint8_t Hour; + uint8_t Wday; // Day of week, with Sunday as day 1. + uint8_t Day; // This is "yday" - Day of Year. + uint8_t Month; + uint8_t Year; // Offset from 1970. +}; + +typedef enum { + timeNotSet, timeNeedsSync, timeSet +} timeStatus_t; + +typedef enum { + dowInvalid, dowSunday, dowMonday, dowTuesday, dowWednesday, dowThursday, dowFriday, dowSaturday +} timeDayOfWeek_t; + +typedef enum { + tmSecond, tmMinute, tmHour, tmWday, tmDay, tmMonth, tmYear, tmNbrFields +} tmByteFields; + +typedef struct { + uint8_t Second; + uint8_t Minute; + uint8_t Hour; + uint8_t Wday; // day of week, sunday is day 1 + uint8_t Day; + uint8_t Month; + uint8_t Year; // offset from 1970; +} tmElements_t, TimeElements, *tmElementsPtr_t; + +// This leap year calulator expects year argument as years offset from 1970. +#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) ) + +/* +* Convenience macros to convert to and from tm years. +*/ +#define tmYearToCalendar(Y) ((Y) + 1970) // Full, four-digit year. +#define CalendarYrToTm(Y) ((Y) - 1970) +#define tmYearToY2k(Y) ((Y) - 30) // Offset from 2000. +#define y2kYearToTm(Y) ((Y) + 30) + +typedef time_t(*getExternalTime)(); + +/* +* Useful Macros for getting elapsed time values. +*/ +#define numberOfSeconds(_time_) (_time_ % SECS_PER_MIN) +#define numberOfMinutes(_time_) ((_time_ / SECS_PER_MIN) % SECS_PER_MIN) +#define numberOfHours(_time_) (( _time_% SECS_PER_DAY) / SECS_PER_HOUR) +#define dayOfWeek(_time_) ((( _time_ / SECS_PER_DAY + 4) % DAYS_PER_WEEK)+1) // 1 = Sunday. +#define elapsedDays(_time_) ( _time_ / SECS_PER_DAY) // The number of days since Jan 1 1970. +#define elapsedSecsToday(_time_) (_time_ % SECS_PER_DAY) // The number of seconds since last midnight. + + +/* +* The following macros are used in calculating alarms and assume the clock is set to a date later than Jan 1 1971. +* Always set the correct time before setting alarms. +*/ +#define previousMidnight(_time_) (( _time_ / SECS_PER_DAY) * SECS_PER_DAY) // Time at the start of the given day. +#define nextMidnight(_time_) ( previousMidnight(_time_) + SECS_PER_DAY ) // Time at the end of the given day. +#define elapsedSecsThisWeek(_time_) (elapsedSecsToday(_time_) + ((dayOfWeek(_time_)-1) * SECS_PER_DAY) ) // Week starts on day 1. +#define previousSunday(_time_) (_time_ - elapsedSecsThisWeek(_time_)) // Time at the start of the week for the given time. +#define nextSunday(_time_) ( previousSunday(_time_)+SECS_PER_WEEK) // Time at the end of the week for the given time. + + +/* +* Useful Macros for converting elapsed time to a time_t value. +*/ +#define minutesToTime_t ((M)) ( (M) * SECS_PER_MIN) +#define hoursToTime_t ((H)) ( (H) * SECS_PER_HOUR) +#define daysToTime_t ((D)) ( (D) * SECS_PER_DAY) // Fixed on Jul 22 2011. +#define weeksToTime_t ((W)) ( (W) * SECS_PER_WEEK) + +/* +* Time and date function defines. +* Low-level functions to convert to and from system time. +*/ +int16_t totalMinutes(int16_t hours, int8_t minutes); +void breakTime(time_t time, tmElements_t* tm); +void timet_to_tm(time_t time, struct tmElements *tmel); // Convert a time_t value into "struct tm" elements. +time_t tm_to_timet(struct tmElements *tmel); // Reconstitute "struct tm" elements into a time_t value. +time_t now(); +void setTime(time_t t); +int hour(); +int minute(); +int second(); +void time_init(); +unsigned long micros(); +unsigned long millis(); + +/* time sync functions */ +timeStatus_t timeStatus(); // indicates if time has been set and recently synchronized +void setSyncProvider(getExternalTime getTimeFunction); // identify the external time provider +void setSyncInterval(time_t interval); // set the number of seconds between re-sync + +#endif // _TIME_H_ \ No newline at end of file diff --git a/mqtt/mqtt.c b/mqtt/mqtt.c index 12b9514..0a23290 100644 --- a/mqtt/mqtt.c +++ b/mqtt/mqtt.c @@ -497,7 +497,7 @@ MQTT_InitConnection(MQTT_Client* mqttClient, char* host, uint32 port, uint8_t se void ICACHE_FLASH_ATTR MQTT_InitClient(MQTT_Client* mqttClient, char* client_id, char* client_user, char* client_pass, uint8_t keepAliveTime, uint8_t cleanSession) { uint32_t temp; - os_printf("MQTT_InitClient\n"); + os_printf("MQTT_InitClient: "); os_memset(&mqttClient->connect_info, 0, sizeof(mqtt_connect_info_t)); @@ -516,7 +516,6 @@ MQTT_InitClient(MQTT_Client* mqttClient, char* client_id, char* client_user, cha os_strcpy(mqttClient->connect_info.password, client_pass); mqttClient->connect_info.password[temp] = 0; - mqttClient->connect_info.keepalive = keepAliveTime; mqttClient->connect_info.clean_session = cleanSession; @@ -532,6 +531,11 @@ MQTT_InitClient(MQTT_Client* mqttClient, char* client_id, char* client_user, cha system_os_task(MQTT_Task, MQTT_TASK_PRIO, mqtt_procTaskQueue, MQTT_TASK_QUEUE_SIZE); system_os_post(MQTT_TASK_PRIO, 0, (os_param_t)mqttClient); + os_printf("client_id:%s, keepAlive:%d, cleanSession:%d\n", + mqttClient->connect_info.client_id, + mqttClient->connect_info.keepalive, + mqttClient->connect_info.clean_session + ); } void ICACHE_FLASH_ATTR diff --git a/mqtt/mqtt_msg.h b/mqtt/mqtt_msg.h index bf305df..84ebf27 100644 --- a/mqtt/mqtt_msg.h +++ b/mqtt/mqtt_msg.h @@ -71,7 +71,7 @@ typedef struct mqtt_connect_info { char* password; char* will_topic; char* will_message; - uint32_t keepalive; + uint8_t keepalive; uint8_t will_qos; uint8_t will_retain; uint8_t clean_session; diff --git a/serial/slip.c b/serial/slip.c index 0c76103..0e067a1 100644 --- a/serial/slip.c +++ b/serial/slip.c @@ -70,6 +70,7 @@ slip_printable(char c) { static void ICACHE_FLASH_ATTR slip_reset() { + //os_printf("SLIP: reset\n"); slip_inpkt = false; slip_escaped = false; slip_len = 0; @@ -83,6 +84,7 @@ slip_parse_char(char c) { if (slip_len > 0) console_process(slip_buf, slip_len); slip_reset(); slip_inpkt = true; + os_printf("SLIP: start\n"); return; } } else if (slip_escaped) { @@ -101,6 +103,9 @@ slip_parse_char(char c) { return; case SLIP_START: os_printf("SLIP: got SLIP_START while in packet?\n"); + //os_printf("SLIP: rcv %d:", slip_len); + //for (int i=0; i one_sec) { +#ifdef UART_DBG os_printf("UART framing error (bad baud rate?)\n"); +#endif last_frm_err = now; } // clear rx fifo (apparently this is not optional at this point) @@ -206,7 +208,9 @@ uart0_rx_intr_handler(void *para) if (UART_RXFIFO_FULL_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_FULL_INT_ST) || UART_RXFIFO_TOUT_INT_ST == (READ_PERI_REG(UART_INT_ST(uart_no)) & UART_RXFIFO_TOUT_INT_ST)) { - //os_printf("stat:%02X",*(uint8 *)UART_INT_ENA(uart_no)); +#ifdef UART_DBG + os_printf("stat:%02X",*(uint8 *)UART_INT_ENA(uart_no)); +#endif ETS_UART_INTR_DISABLE(); system_os_post(recvTaskPrio, 0, 0); } @@ -229,7 +233,9 @@ uart_recvTask(os_event_t *events) (length < 128)) { buf[length++] = READ_PERI_REG(UART_FIFO(UART0)) & 0xFF; } - //os_printf("%d ix %d\n", system_get_time(), length); +#ifdef UART_DBG + os_printf("%d ix %d\n", system_get_time(), length); +#endif for (int i=0; i totalMinutes(onHour, onMinute)) { + state = (NumMinsToday >= totalMinutes(onHour, onMinute)) ? true : false; + + if (NumMinsToday >= totalMinutes(offHour, offMinute)) + state = false; + } + else { + state = (NumMinsToday >= totalMinutes(offHour, offMinute)) ? false : true; + + if (NumMinsToday >= totalMinutes(onHour, onMinute)) + state = true; + } + return state; +} + +const char* ICACHE_FLASH_ATTR byteToBin(uint8_t num) { + static char b[9]; + b[0] = '\0'; + + int z; + for (z = 128; z > 0; z >>= 1) { + strcat(b, ((num & z) == z) ? "1" : "0"); + } + return b; +} + +const uint8_t ICACHE_FLASH_ATTR binToByte(char* bin_str) { + char * tmp; + long x = strtol(bin_str, &tmp, 2); + return (x <= 255) ? (uint8_t)x : -1; +} diff --git a/user/user_funcs.h b/user/user_funcs.h new file mode 100644 index 0000000..156e432 --- /dev/null +++ b/user/user_funcs.h @@ -0,0 +1,10 @@ +#ifndef _USER_FUNCS_H_ +#define _USER_FUNCS_H_ +#include +#include + +bool pwmPinStateForSchedule(uint8_t onHour, uint8_t onMinute, uint8_t offHour, uint8_t offMinute); +const char* byteToBin(uint8_t num); +const uint8_t binToByte(char* bin_str); + +#endif // _USER_FUNCS_H_ \ No newline at end of file diff --git a/user/user_json.c b/user/user_json.c new file mode 100644 index 0000000..658ad92 --- /dev/null +++ b/user/user_json.c @@ -0,0 +1,158 @@ +/****************************************************************************** +* Copyright 2013-2014 Espressif Systems (Wuxi) +* +* FileName: user_json.c +* +* Description: JSON format set up and parse. +* Check your hardware transmation while use this data format. +* +* Modification history: +* 2014/5/09, v1.0 create this file. +*******************************************************************************/ +#include "user_json.h" + +LOCAL char* json_buf; +LOCAL int pos; +LOCAL int size; + +/****************************************************************************** +* FunctionName : find_json_path +* Description : find the JSON format tree's path +* Parameters : json -- A pointer to a JSON set up +* path -- A pointer to the JSON format tree's path +* Returns : A pointer to the JSON format tree +*******************************************************************************/ +struct jsontree_value*ICACHE_FLASH_ATTR +find_json_path(struct jsontree_context* json, const char* path) { + struct jsontree_value* v; + const char* start; + const char* end; + int len; + + v = json->values[0]; + start = path; + + do { + end = (const char *)os_strstr(start, "/"); + + if (end == start) { + break; + } + + if (end != NULL) { + len = end - start; + end++; + } + else { + len = os_strlen(start); + } + + if (v->type != JSON_TYPE_OBJECT) { + v = NULL; + } + else { + struct jsontree_object* o; + int i; + + o = (struct jsontree_object *)v; + v = NULL; + + for (i = 0; i < o->count; i++) { + if (os_strncmp(start, o->pairs[i].name, len) == 0) { + v = o->pairs[i].value; + json->index[json->depth] = i; + json->depth++; + json->values[json->depth] = v; + json->index[json->depth] = 0; + break; + } + } + } + + start = end; + } + while (end != NULL && *end != '\0' && v != NULL); + + json->callback_state = 0; + return v; +} + +/****************************************************************************** +* FunctionName : json_putchar +* Description : write the value to the JSON format tree +* Parameters : c -- the value which write the JSON format tree +* Returns : result +*******************************************************************************/ +int ICACHE_FLASH_ATTR +json_putchar(int c) { + if (json_buf != NULL && pos <= size) { + json_buf[pos++] = c; + return c; + } + + return 0; +} + +/****************************************************************************** +* FunctionName : json_ws_send +* Description : set up the JSON format tree for string +* Parameters : tree -- A pointer to the JSON format tree +* path -- A pointer to the JSON format tree's path +* pbuf -- A pointer for the data sent +* Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +json_ws_send(struct jsontree_value* tree, const char* path, char* pbuf) { + struct jsontree_context json; + /* maxsize = 128 bytes */ + json_buf = (char *)os_malloc(JSON_SIZE); + + /* reset state and set max-size */ + /* NOTE: packet will be truncated at 512 bytes */ + pos = 0; + size = JSON_SIZE; + + json.values[0] = (struct jsontree_value *)tree; + jsontree_reset(&json); + find_json_path(&json, path); + json.path = json.depth; + json.putchar = json_putchar; + + while (jsontree_print_next(&json) && json.path <= json.depth); + + json_buf[pos] = 0; + os_memcpy(pbuf, json_buf, pos); + os_free(json_buf); +} + +/****************************************************************************** +* FunctionName : json_parse +* Description : parse the data as a JSON format +* Parameters : js_ctx -- A pointer to a JSON set up +* ptrJSONMessage -- A pointer to the data +* Returns : none +*******************************************************************************/ +void ICACHE_FLASH_ATTR +json_parse(struct jsontree_context* json, char* ptrJSONMessage) { + /* Set value */ + struct jsontree_value* v; + struct jsontree_callback* c; + struct jsontree_callback* c_bak = NULL; + + while ((v = jsontree_find_next(json, JSON_TYPE_CALLBACK)) != NULL) { + c = (struct jsontree_callback *)v; + + if (c == c_bak) { + continue; + } + + c_bak = c; + + if (c->set != NULL) { + struct jsonparse_state js; + + jsonparse_setup(&js, ptrJSONMessage, os_strlen(ptrJSONMessage)); + c->set(json, &js); + } + } +} diff --git a/user/user_json.h b/user/user_json.h new file mode 100644 index 0000000..2375f03 --- /dev/null +++ b/user/user_json.h @@ -0,0 +1,14 @@ +#ifndef __USER_JSON_H__ +#define __USER_JSON_H__ + +#include +#include "json/jsonparse.h" +#include "json/jsontree.h" + +#define JSON_SIZE 1024 +void json_parse(struct jsontree_context* json, char* ptrJSONMessage); +void json_ws_send(struct jsontree_value* tree, const char* path, char* pbuf); +int json_putchar(int c); +struct jsontree_value* find_json_path(struct jsontree_context* json, const char* path); + +#endif diff --git a/user/user_main.c b/user/user_main.c index 5738807..78b69aa 100644 --- a/user/user_main.c +++ b/user/user_main.c @@ -1,31 +1,100 @@ #include #include #include +#include +#include +#include "user_json.h" +#include "user_funcs.h" MQTT_Client mqttClient; -void ICACHE_FLASH_ATTR -mqttConnectedCb(uint32_t *args) { - MQTT_Client* client = (MQTT_Client*)args; - MQTT_Publish(client, "announce/all", "Hello World!", 0, 0); +typedef struct { + uint8_t fallbackStateBits; + uint8_t stateBits; + uint8_t init; + uint8_t fallbackSecondsForBits[8]; +} LatchState; + +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_SENSOR_EVENTS, (uint32_t)&latchCb->callback, 0, 1); +// crc = CMD_ResponseBody(crc, (uint8_t*)&latch, sizeof(LatchState)); +// CMD_ResponseEnd(crc); + } } -void ICACHE_FLASH_ATTR -mqttDisconnectedCb(uint32_t *args) { -// MQTT_Client* client = (MQTT_Client*)args; - os_printf("MQTT Disconnected\n"); +LOCAL int ICACHE_FLASH_ATTR +latchGet(struct jsontree_context *js_ctx) { + return 0; } -void ICACHE_FLASH_ATTR -mqttTcpDisconnectedCb(uint32_t *args) { -// MQTT_Client* client = (MQTT_Client*)args; - os_printf("MQTT TCP Disconnected\n"); +LOCAL int ICACHE_FLASH_ATTR +latchSet(struct jsontree_context *js_ctx, struct jsonparse_state *parser) { + int type; + int ix = -1; + bool sendLatchUpdate = false; + 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); +// if (latch.stateBits != states) { + latch.stateBits = states; + sendLatchUpdate = true; +// } + } + 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); +// if (latch.fallbackStateBits != fbstates) { + latch.fallbackStateBits = fbstates; + sendLatchUpdate = true; +// } + } + } + + if (sendLatchUpdate) { + updateLatch(); + } + } + 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)); + void ICACHE_FLASH_ATTR -mqttPublishedCb(uint32_t *args) { -// MQTT_Client* client = (MQTT_Client*)args; - os_printf("MQTT Published\n"); +mqttConnectedCb(uint32_t *args) { + MQTT_Client* client = (MQTT_Client*)args; + MQTT_Publish(client, "announce/all", "Hello World!", 0, 0); + + char* latchQueue = "/latch"; + char *buff = (char*)os_zalloc(strlen(system_get_chip_id_str()) + strlen(latchQueue) + 1); + os_strcpy(buff, system_get_chip_id_str()); + os_strcat(buff, latchQueue); + latchQueueName = buff; + MQTT_Subscribe(client, latchQueueName, 0); } void ICACHE_FLASH_ATTR @@ -41,7 +110,14 @@ mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *da os_memcpy(dataBuf, data, data_len); dataBuf[data_len] = 0; - os_printf("Receive topic: %s, data: %s\n", topicBuf, dataBuf); + os_printf("Receive topic: %s\n Data: %s\n", topicBuf, dataBuf); + + if (!strcoll(topicBuf, latchQueueName)) { + struct jsontree_context js; + jsontree_setup(&js, (struct jsontree_value *)&latchJsonObj, json_putchar); + json_parse(&js, dataBuf); + } + os_free(topicBuf); os_free(dataBuf); } @@ -57,6 +133,24 @@ wifiStateChangeCb(uint8_t status) } } +void ICACHE_FLASH_ATTR +mqttDisconnectedCb(uint32_t *args) { + // MQTT_Client* client = (MQTT_Client*)args; + os_printf("MQTT Disconnected\n"); +} + +void ICACHE_FLASH_ATTR +mqttTcpDisconnectedCb(uint32_t *args) { + // MQTT_Client* client = (MQTT_Client*)args; + os_printf("MQTT TCP Disconnected\n"); +} + +void ICACHE_FLASH_ATTR +mqttPublishedCb(uint32_t *args) { + // MQTT_Client* client = (MQTT_Client*)args; + os_printf("MQTT Published\n"); +} + void init() { wifiAddStateChangeCb(wifiStateChangeCb); MQTT_InitConnection(&mqttClient, MQTT_HOST, MQTT_PORT, MQTT_SECURITY);