mirror of
https://github.com/jeelabs/esp-link.git
synced 2026-02-20 02:31:19 +01:00
Merge branch 'master' into windows
Conflicts: Makefile cmd/handlers.c esp-link/cgi.c esp-link/cgiwifi.c html/console.html html/style.css html/ui.js httpd/httpd.c mqtt/mqtt.c mqtt/mqtt.h mqtt/mqtt_cmd.c user/user_main.c
This commit is contained in:
16
Makefile
16
Makefile
@@ -157,9 +157,9 @@ ifneq (,$(findstring rest,$(MODULES)))
|
||||
endif
|
||||
|
||||
# which modules (subdirectories) of the project to include in compiling
|
||||
LIBRARIES_DIR = libraries
|
||||
LIBRARIES_DIR = libraries
|
||||
MODULES = espfs httpd user serial cmd mqtt esp-link
|
||||
MODULES += $(foreach sdir,$(LIBRARIES_DIR),$(wildcard $(sdir)/*))
|
||||
MODULES += $(foreach sdir,$(LIBRARIES_DIR),$(wildcard $(sdir)/*))
|
||||
EXTRA_INCDIR = include . include/json
|
||||
|
||||
# libraries used in this project, mainly provided by the SDK
|
||||
@@ -184,7 +184,7 @@ LD_SCRIPT2 := build/eagle.esphttpd2.v6.ld
|
||||
|
||||
# various paths from the SDK used in this project
|
||||
SDK_LIBDIR = lib
|
||||
SDK_LDDIR = ld
|
||||
SDK_LDDIR = ld
|
||||
SDK_INCDIR = include include/json
|
||||
SDK_TOOLSDIR = tools
|
||||
|
||||
@@ -192,8 +192,8 @@ SDK_TOOLSDIR = tools
|
||||
CC := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc
|
||||
AR := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-ar
|
||||
LD := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-gcc
|
||||
OBJCP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy
|
||||
OBJDP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objdump
|
||||
OBJCP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objcopy
|
||||
OBJDP := $(XTENSA_TOOLS_ROOT)xtensa-lx106-elf-objdump
|
||||
|
||||
|
||||
####
|
||||
@@ -231,7 +231,7 @@ CFLAGS += -DGZIP_COMPRESSION
|
||||
endif
|
||||
|
||||
ifeq ("$(CHANGE_TO_STA)","yes")
|
||||
CFLAGS += -DCHANGE_TO_STA
|
||||
CFLAGS += -DCHANGE_TO_STA
|
||||
endif
|
||||
|
||||
vpath %.c $(SRC_DIR)
|
||||
@@ -373,8 +373,8 @@ release: all
|
||||
$(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-$(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) tar zcf esp-link-$(BRANCH).tgz -C release esp-link-$(BRANCH)
|
||||
$(Q) echo "Release file: esp-link-$(BRANCH).tgz"
|
||||
$(Q) rm -rf release
|
||||
|
||||
clean:
|
||||
|
||||
39
README.md
39
README.md
@@ -26,6 +26,28 @@ Many thanks to https://github.com/brunnels for contributions around the espduino
|
||||
For quick support and questions:
|
||||
[](https://gitter.im/jeelabs/esp-link?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
|
||||
Esp-link uses
|
||||
-------------
|
||||
The simplest use of esp-link is as a transparent serial to wifi bridge. You can flash an attached
|
||||
uC over wifi and you can watch the uC's serial debug output by connecting to port 23 or looking
|
||||
at the uC Console web page.
|
||||
|
||||
The next level is to use the outbound connectivity of esp-link in the uC code. For example, the
|
||||
uC can use REST requests to services like thingspeak.com to send sensor values that then get
|
||||
stored and plotted by the external service.
|
||||
The uC can also use REST requests to retrieve simple configuration
|
||||
information or push other forms of notifications. (MQTT functionality is forthcoming.)
|
||||
|
||||
An additional option is to add code to esp-link to customize it and put all the communication
|
||||
code into esp-link and only keep simple sensor/actuator control in the attached uC. In this
|
||||
mode the attached uC sends custom commands to esp-link with sensor/acturator info and
|
||||
registers a set of callbacks with esp-link that control sensors/actuators. This way, custom
|
||||
commands in esp-link can receive MQTT messages, make simple callbacks into the uC to get sensor
|
||||
values or change actuators, and then respond back with MQTT. The way this is architected is that
|
||||
the attached uC registers callbacks at start-up such that the code in the esp doesn't need to
|
||||
know which exact sensors/actuators the attached uC has, it learns thta through the initial
|
||||
callback registration.
|
||||
|
||||
Eye Candy
|
||||
---------
|
||||
These screen shots show the Home page, the Wifi configuration page, the console for the
|
||||
@@ -237,7 +259,22 @@ The attached micro-controller can open outbound TCP connections using a simple
|
||||
[serial protocol](https://gist.github.com/tve/a46c44bf1f6b42bc572e).
|
||||
More info and sample code forthcoming...
|
||||
|
||||
Outbound HTTP REST requests
|
||||
---------------------------
|
||||
The V2 versions of esp-link support the espduino SLIP protocol that supports simple outbound
|
||||
HTTP REST requests. The SLIP protocol consists of commands with binary arguments sent from the
|
||||
attached microcontroller to the esp8266, which then performs the command and responds back.
|
||||
The responses back use a callback address in the attached microcontroller code, i.e., the
|
||||
command sent by the uC contains a callback address and the response from the esp8266 starts
|
||||
with that callback address. This enables asynchronous communication where esp-link can notify the
|
||||
uC when requests complete or when other actions happen, such as wifi connectivity status changes.
|
||||
Support for MQTT is forthcoming.
|
||||
|
||||
You can find a demo sketch in a fork of the espduino library at
|
||||
https://github.com/tve/espduino in the
|
||||
[examples/demo folder](https://github.com/tve/espduino/tree/master/espduino/examples/demo).
|
||||
|
||||
Contact
|
||||
-------
|
||||
If you find problems with esp-link, please create a github issue. If you have a question, please
|
||||
use the gitter link at the top of this page.
|
||||
use the gitter chat link at the top of this page.
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
|
||||
#include "esp8266.h"
|
||||
#include "cmd.h"
|
||||
#include "rest.h"
|
||||
#include "crc16.h"
|
||||
#include "serbridge.h"
|
||||
#include "uart.h"
|
||||
#include "cgiwifi.h"
|
||||
#include "mqtt_cmd.h"
|
||||
#include <cgiwifi.h>
|
||||
#ifdef MQTT
|
||||
#include <mqtt_cmd.h>
|
||||
#endif
|
||||
#ifdef REST
|
||||
#include <rest.h>
|
||||
#endif
|
||||
|
||||
static uint32_t CMD_Null(CmdPacket *cmd);
|
||||
static uint32_t CMD_IsReady(CmdPacket *cmd);
|
||||
@@ -27,20 +28,20 @@ const CmdList commands[] = {
|
||||
{CMD_RESET, CMD_Reset},
|
||||
{CMD_IS_READY, CMD_IsReady},
|
||||
{CMD_WIFI_CONNECT, CMD_WifiConnect},
|
||||
|
||||
#ifdef MQTT
|
||||
{CMD_MQTT_SETUP, MQTTCMD_Setup},
|
||||
{CMD_MQTT_CONNECT, MQTTCMD_Connect},
|
||||
{CMD_MQTT_DISCONNECT, MQTTCMD_Disconnect},
|
||||
{CMD_MQTT_PUBLISH, MQTTCMD_Publish},
|
||||
{CMD_MQTT_SUBSCRIBE , MQTTCMD_Subscribe},
|
||||
{CMD_MQTT_LWT, MQTTCMD_Lwt},
|
||||
|
||||
{CMD_MQTT_LWT, MQTTCMD_Lwt},
|
||||
#endif
|
||||
#ifdef REST
|
||||
{CMD_REST_SETUP, REST_Setup},
|
||||
{CMD_REST_REQUEST, REST_Request},
|
||||
{CMD_REST_SETHEADER, REST_SetHeader},
|
||||
|
||||
{CMD_ADD_CALLBACK, CMD_AddCallback },
|
||||
|
||||
#endif
|
||||
{ CMD_CB_ADD, CMD_AddCallback },
|
||||
{CMD_NULL, NULL}
|
||||
};
|
||||
|
||||
@@ -51,18 +52,14 @@ 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;
|
||||
}
|
||||
|
||||
@@ -71,9 +68,7 @@ CMD_Null(CmdPacket *cmd) {
|
||||
// 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;
|
||||
@@ -81,19 +76,14 @@ CMD_Reset(CmdPacket *cmd) {
|
||||
|
||||
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 < 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
|
||||
//os_printf("CMD_AddCb: index %d name=%s cb=%p\n", i, callbacks[i].name,
|
||||
// (void *)callbacks[i].callback);
|
||||
// find existing callback or add to the end
|
||||
if (os_strcmp(callbacks[i].name, checkname) == 0 || callbacks[i].name[0] == '\0') {
|
||||
if (os_strcmp(callbacks[i].name, name) == 0 || callbacks[i].name[0] == '\0') {
|
||||
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);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -104,21 +94,16 @@ cmdCallback* ICACHE_FLASH_ATTR
|
||||
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
|
||||
for (uint8_t i = 0; i < MAX_CALLBACKS; i++) {
|
||||
//os_printf("CMD_GetCbByName: index %d name=%s cb=%p\n", i, callbacks[i].name,
|
||||
// (void *)callbacks[i].callback);
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -126,9 +111,7 @@ 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) {
|
||||
@@ -145,9 +128,7 @@ 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;
|
||||
|
||||
@@ -167,9 +148,7 @@ static uint32_t ICACHE_FLASH_ATTR
|
||||
CMD_AddCallback(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
CMD_Request(&req, cmd);
|
||||
#ifdef CMD_DBG
|
||||
os_printf("CMD_AddCallback: setup argc=%ld\n", CMD_GetArgc(&req));
|
||||
#endif
|
||||
if (cmd->argc != 1 || cmd->callback == 0)
|
||||
return 0;
|
||||
|
||||
@@ -178,15 +157,11 @@ CMD_AddCallback(CmdPacket *cmd) {
|
||||
|
||||
// get the sensor name
|
||||
len = CMD_ArgLen(&req);
|
||||
#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
|
||||
if (CMD_PopArg(&req, (uint8_t *)name, len)) return 0;
|
||||
name[len] = 0;
|
||||
#ifdef CMD_DBG
|
||||
os_printf("CMD_AddCallback: name=%s\n", name);
|
||||
#endif
|
||||
|
||||
return CMD_AddCb(name, (uint32_t)cmd->callback); // save the sensor callback
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ Some random cgi routines.
|
||||
* Heavily modified and enhanced by Thorsten von Eicken in 2015
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
|
||||
#include <esp8266.h>
|
||||
#include "cgi.h"
|
||||
static char* chipIdStr = "";
|
||||
char* ICACHE_FLASH_ATTR system_get_chip_id_str(){
|
||||
@@ -22,16 +25,63 @@ char* ICACHE_FLASH_ATTR system_get_chip_id_str(){
|
||||
return chipIdStr;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
jsonHeader(HttpdConnData *connData, int code) {
|
||||
void noCacheHeaders(HttpdConnData *connData, int code) {
|
||||
httpdStartResponse(connData, code);
|
||||
httpdHeader(connData, "Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
httpdHeader(connData, "Pragma", "no-cache");
|
||||
httpdHeader(connData, "Expires", "0");
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
jsonHeader(HttpdConnData *connData, int code) {
|
||||
noCacheHeaders(connData, code);
|
||||
httpdHeader(connData, "Content-Type", "application/json");
|
||||
httpdEndHeaders(connData);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
errorResponse(HttpdConnData *connData, int code, char *message) {
|
||||
noCacheHeaders(connData, code);
|
||||
httpdEndHeaders(connData);
|
||||
httpdSend(connData, message, -1);
|
||||
os_printf("HTTP %d error response: \"%s\"\n", code, message);
|
||||
}
|
||||
|
||||
// look for the HTTP arg 'name' and store it at 'config' with max length 'max_len' (incl
|
||||
// terminating zero), returns -1 on error, 0 if not found, 1 if found and OK
|
||||
int ICACHE_FLASH_ATTR
|
||||
getStringArg(HttpdConnData *connData, char *name, char *config, int max_len) {
|
||||
char buff[128];
|
||||
int len = httpdFindArg(connData->getArgs, name, buff, sizeof(buff));
|
||||
if (len < 0) return 0; // not found, skip
|
||||
if (len >= max_len) {
|
||||
os_sprintf(buff, "Value for %s too long (%d > %d allowed)", name, len, max_len-1);
|
||||
errorResponse(connData, 400, buff);
|
||||
return -1;
|
||||
}
|
||||
strcpy(config, buff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR
|
||||
getBoolArg(HttpdConnData *connData, char *name, bool*config) {
|
||||
char buff[64];
|
||||
int len = httpdFindArg(connData->getArgs, name, buff, sizeof(buff));
|
||||
if (len < 0) return 0; // not found, skip
|
||||
|
||||
if (strcmp(buff, "1") == 0 || strcmp(buff, "true") == 0) {
|
||||
*config = true;
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(buff, "0") == 0 || strcmp(buff, "false") == 0) {
|
||||
*config = false;
|
||||
return 1;
|
||||
}
|
||||
os_sprintf(buff, "Invalid value for %s", name);
|
||||
errorResponse(connData, 400, buff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t ICACHE_FLASH_ATTR
|
||||
UTILS_StrToIP(const char* str, void *ip){
|
||||
/* The count of the number of bytes processed. */
|
||||
@@ -106,8 +156,11 @@ int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) {
|
||||
httpdEndHeaders(connData);
|
||||
// construct json response
|
||||
os_sprintf(buff,
|
||||
"{\"menu\": [\"Home\", \"/home.html\", \"Wifi\", \"/wifi/wifi.html\","
|
||||
"\"\xC2\xB5" "C Console\", \"/console.html\", \"Debug log\", \"/log.html\" ],\n"
|
||||
"{\"menu\": [\"Home\", \"/home.html\", "
|
||||
"\"Wifi\", \"/wifi/wifi.html\","
|
||||
"\"\xC2\xB5" "C Console\", \"/console.html\", "
|
||||
"\"REST/MQTT\", \"/mqtt.html\","
|
||||
"\"Debug log\", \"/log.html\" ],\n"
|
||||
" \"version\": \"%s\" }", esp_link_version);
|
||||
httpdSend(connData, buff, -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include "httpd.h"
|
||||
|
||||
void jsonHeader(HttpdConnData *connData, int code);
|
||||
void errorResponse(HttpdConnData *connData, int code, char *message);
|
||||
int getStringArg(HttpdConnData *connData, char *name, char *config, int max_len);
|
||||
int getBoolArg(HttpdConnData *connData, char *name, bool*config);
|
||||
int cgiMenu(HttpdConnData *connData);
|
||||
uint8_t UTILS_StrToIP(const char* str, void *ip);
|
||||
char* system_get_chip_id_str();
|
||||
|
||||
111
esp-link/cgimqtt.c
Normal file
111
esp-link/cgimqtt.c
Normal file
@@ -0,0 +1,111 @@
|
||||
// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
|
||||
// // TCP Client settings
|
||||
|
||||
#include <esp8266.h>
|
||||
#include "cgi.h"
|
||||
#include "config.h"
|
||||
#include "cgimqtt.h"
|
||||
|
||||
// Cgi to return MQTT settings
|
||||
int ICACHE_FLASH_ATTR cgiMqttGet(HttpdConnData *connData) {
|
||||
char buff[2048];
|
||||
int len;
|
||||
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE;
|
||||
|
||||
len = os_sprintf(buff, "{ "
|
||||
"\"slip-enable\":%d, "
|
||||
"\"mqtt-enable\":%d, "
|
||||
"\"mqtt-status-enable\":%d, "
|
||||
"\"mqtt-port\":%d, "
|
||||
"\"mqtt-host\":\"%s\", "
|
||||
"\"mqtt-client-id\":\"%s\", "
|
||||
"\"mqtt-username\":\"%s\", "
|
||||
"\"mqtt-password\":\"%s\", "
|
||||
"\"mqtt-status-topic\":\"%s\", "
|
||||
"\"mqtt-state\":\"%s\" }",
|
||||
flashConfig.slip_enable, flashConfig.mqtt_enable, flashConfig.mqtt_status_enable,
|
||||
flashConfig.mqtt_port, flashConfig.mqtt_hostname, flashConfig.mqtt_client,
|
||||
flashConfig.mqtt_username, flashConfig.mqtt_password,
|
||||
flashConfig.mqtt_status_topic, "connected");
|
||||
|
||||
jsonHeader(connData, 200);
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
// Cgi to change choice of pin assignments
|
||||
int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) {
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE;
|
||||
|
||||
// handle MQTT server settings
|
||||
int mqtt_server = 0; // accumulator for changes/errors
|
||||
mqtt_server |= getStringArg(connData, "mqtt-host",
|
||||
flashConfig.mqtt_hostname, sizeof(flashConfig.mqtt_hostname));
|
||||
if (mqtt_server < 0) return HTTPD_CGI_DONE;
|
||||
mqtt_server |= getStringArg(connData, "mqtt-client-id",
|
||||
flashConfig.mqtt_client, sizeof(flashConfig.mqtt_client));
|
||||
if (mqtt_server < 0) return HTTPD_CGI_DONE;
|
||||
mqtt_server |= getStringArg(connData, "mqtt-username",
|
||||
flashConfig.mqtt_username, sizeof(flashConfig.mqtt_username));
|
||||
if (mqtt_server < 0) return HTTPD_CGI_DONE;
|
||||
mqtt_server |= getStringArg(connData, "mqtt-password",
|
||||
flashConfig.mqtt_password, sizeof(flashConfig.mqtt_password));
|
||||
if (mqtt_server < 0) return HTTPD_CGI_DONE;
|
||||
mqtt_server |= getBoolArg(connData, "mqtt-enable",
|
||||
&flashConfig.mqtt_enable);
|
||||
|
||||
// handle mqtt port
|
||||
char buff[16];
|
||||
if (httpdFindArg(connData->getArgs, "mqtt-port", buff, sizeof(buff)) > 0) {
|
||||
int32_t port = atoi(buff);
|
||||
if (port > 0 && port < 65536) {
|
||||
flashConfig.mqtt_port = port;
|
||||
mqtt_server |= 1;
|
||||
} else {
|
||||
errorResponse(connData, 400, "Invalid MQTT port");
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
// if server setting changed, we need to "make it so"
|
||||
if (mqtt_server) {
|
||||
os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable);
|
||||
// TODO
|
||||
}
|
||||
|
||||
// no action required if mqtt status settings change, they just get picked up at the
|
||||
// next status tick
|
||||
if (getBoolArg(connData, "mqtt-status-enable", &flashConfig.mqtt_status_enable) < 0)
|
||||
return HTTPD_CGI_DONE;
|
||||
if (getStringArg(connData, "mqtt-status-topic",
|
||||
flashConfig.mqtt_status_topic, sizeof(flashConfig.mqtt_status_topic)) < 0)
|
||||
return HTTPD_CGI_DONE;
|
||||
|
||||
// if SLIP-enable is toggled it gets picked-up immediately by the parser
|
||||
int slip_update = getBoolArg(connData, "slip-enable", &flashConfig.slip_enable);
|
||||
if (slip_update < 0) return HTTPD_CGI_DONE;
|
||||
if (slip_update > 0) os_printf("SLIP-enable changed: %d\n", flashConfig.slip_enable);
|
||||
|
||||
os_printf("Saving config\n");
|
||||
if (configSave()) {
|
||||
httpdStartResponse(connData, 200);
|
||||
httpdEndHeaders(connData);
|
||||
} else {
|
||||
httpdStartResponse(connData, 500);
|
||||
httpdEndHeaders(connData);
|
||||
httpdSend(connData, "Failed to save config", -1);
|
||||
}
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR cgiMqtt(HttpdConnData *connData) {
|
||||
if (connData->requestType == HTTPD_METHOD_GET) {
|
||||
return cgiMqttGet(connData);
|
||||
} else if (connData->requestType == HTTPD_METHOD_POST) {
|
||||
return cgiMqttSet(connData);
|
||||
} else {
|
||||
jsonHeader(connData, 404);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
}
|
||||
8
esp-link/cgimqtt.h
Normal file
8
esp-link/cgimqtt.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef CGIMQTT_H
|
||||
#define CGIMQTT_H
|
||||
|
||||
#include "httpd.h"
|
||||
|
||||
int cgiMqtt(HttpdConnData *connData);
|
||||
|
||||
#endif
|
||||
@@ -24,9 +24,9 @@ static const int num_map_func = sizeof(map_func)/sizeof(char*);
|
||||
|
||||
// Cgi to return choice of pin assignments
|
||||
int ICACHE_FLASH_ATTR cgiPinsGet(HttpdConnData *connData) {
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted
|
||||
|
||||
char buff[2048];
|
||||
char buff[2048];
|
||||
int len;
|
||||
|
||||
// figure out current mapping
|
||||
@@ -62,27 +62,27 @@ int ICACHE_FLASH_ATTR cgiPinsGet(HttpdConnData *connData) {
|
||||
}
|
||||
len += os_sprintf(buff+len, "\n] }");
|
||||
|
||||
jsonHeader(connData, 200);
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
jsonHeader(connData, 200);
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
// Cgi to change choice of pin assignments
|
||||
int ICACHE_FLASH_ATTR cgiPinsSet(HttpdConnData *connData) {
|
||||
if (connData->conn==NULL) {
|
||||
return HTTPD_CGI_DONE; // Connection aborted
|
||||
}
|
||||
if (connData->conn==NULL) {
|
||||
return HTTPD_CGI_DONE; // Connection aborted
|
||||
}
|
||||
|
||||
char buff[128];
|
||||
int len = httpdFindArg(connData->getArgs, "map", buff, sizeof(buff));
|
||||
if (len <= 0) {
|
||||
jsonHeader(connData, 400);
|
||||
int len = httpdFindArg(connData->getArgs, "map", buff, sizeof(buff));
|
||||
if (len <= 0) {
|
||||
jsonHeader(connData, 400);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
int m = atoi(buff);
|
||||
if (m < 0 || m >= num_map_names) {
|
||||
jsonHeader(connData, 400);
|
||||
if (m < 0 || m >= num_map_names) {
|
||||
jsonHeader(connData, 400);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
@@ -106,17 +106,17 @@ int ICACHE_FLASH_ATTR cgiPinsSet(HttpdConnData *connData) {
|
||||
httpdEndHeaders(connData);
|
||||
httpdSend(connData, "Failed to save config", -1);
|
||||
}
|
||||
return HTTPD_CGI_DONE;
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR cgiPins(HttpdConnData *connData) {
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
if (connData->requestType == HTTPD_METHOD_GET) {
|
||||
return cgiPinsGet(connData);
|
||||
} else if (connData->requestType == HTTPD_METHOD_POST) {
|
||||
return cgiPinsSet(connData);
|
||||
} else {
|
||||
jsonHeader(connData, 404);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
if (connData->requestType == HTTPD_METHOD_GET) {
|
||||
return cgiPinsGet(connData);
|
||||
} else if (connData->requestType == HTTPD_METHOD_POST) {
|
||||
return cgiPinsSet(connData);
|
||||
} else {
|
||||
jsonHeader(connData, 404);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,12 +31,12 @@ uint8_t wifiState = wifiIsDisconnected;
|
||||
// reasons for which a connection failed
|
||||
uint8_t wifiReason = 0;
|
||||
static char *wifiReasons[] = {
|
||||
"", "unspecified", "auth_expire", "auth_leave", "assoc_expire", "assoc_toomany", "not_authed",
|
||||
"not_assoced", "assoc_leave", "assoc_not_authed", "disassoc_pwrcap_bad", "disassoc_supchan_bad",
|
||||
"ie_invalid", "mic_failure", "4way_handshake_timeout", "group_key_update_timeout",
|
||||
"ie_in_4way_differs", "group_cipher_invalid", "pairwise_cipher_invalid", "akmp_invalid",
|
||||
"unsupp_rsn_ie_version", "invalid_rsn_ie_cap", "802_1x_auth_failed", "cipher_suite_rejected",
|
||||
"beacon_timeout", "no_ap_found" };
|
||||
"", "unspecified", "auth_expire", "auth_leave", "assoc_expire", "assoc_toomany", "not_authed",
|
||||
"not_assoced", "assoc_leave", "assoc_not_authed", "disassoc_pwrcap_bad", "disassoc_supchan_bad",
|
||||
"ie_invalid", "mic_failure", "4way_handshake_timeout", "group_key_update_timeout",
|
||||
"ie_in_4way_differs", "group_cipher_invalid", "pairwise_cipher_invalid", "akmp_invalid",
|
||||
"unsupp_rsn_ie_version", "invalid_rsn_ie_cap", "802_1x_auth_failed", "cipher_suite_rejected",
|
||||
"beacon_timeout", "no_ap_found" };
|
||||
|
||||
static char *wifiMode[] = { 0, "STA", "AP", "AP+STA" };
|
||||
static char *wifiPhy[] = { 0, "11b", "11g", "11n" };
|
||||
@@ -44,63 +44,51 @@ static char *wifiPhy[] = { 0, "11b", "11g", "11n" };
|
||||
void (*wifiStatusCb)(uint8_t); // callback when wifi status changes
|
||||
|
||||
static char* ICACHE_FLASH_ATTR wifiGetReason(void) {
|
||||
if (wifiReason <= 24) return wifiReasons[wifiReason];
|
||||
if (wifiReason >= 200 && wifiReason <= 201) return wifiReasons[wifiReason-200+24];
|
||||
return wifiReasons[1];
|
||||
if (wifiReason <= 24) return wifiReasons[wifiReason];
|
||||
if (wifiReason >= 200 && wifiReason <= 201) return wifiReasons[wifiReason-200+24];
|
||||
return wifiReasons[1];
|
||||
}
|
||||
|
||||
// handler for wifi status change callback coming in from espressif library
|
||||
static void ICACHE_FLASH_ATTR wifiHandleEventCb(System_Event_t *evt) {
|
||||
switch (evt->event) {
|
||||
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;
|
||||
}
|
||||
switch (evt->event) {
|
||||
case EVENT_STAMODE_CONNECTED:
|
||||
wifiState = wifiIsConnected;
|
||||
wifiReason = 0;
|
||||
os_printf("Wifi connected to ssid %s, ch %d\n", evt->event_info.connected.ssid,
|
||||
evt->event_info.connected.channel);
|
||||
statusWifiUpdate(wifiState);
|
||||
break;
|
||||
case EVENT_STAMODE_DISCONNECTED:
|
||||
wifiState = wifiIsDisconnected;
|
||||
wifiReason = evt->event_info.disconnected.reason;
|
||||
os_printf("Wifi disconnected from ssid %s, reason %s (%d)\n",
|
||||
evt->event_info.disconnected.ssid, wifiGetReason(), evt->event_info.disconnected.reason);
|
||||
statusWifiUpdate(wifiState);
|
||||
break;
|
||||
case EVENT_STAMODE_AUTHMODE_CHANGE:
|
||||
os_printf("Wifi auth mode: %d -> %d\n",
|
||||
evt->event_info.auth_change.old_mode, evt->event_info.auth_change.new_mode);
|
||||
break;
|
||||
case EVENT_STAMODE_GOT_IP:
|
||||
wifiState = wifiGotIP;
|
||||
wifiReason = 0;
|
||||
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));
|
||||
statusWifiUpdate(wifiState);
|
||||
break;
|
||||
case EVENT_SOFTAPMODE_STACONNECTED:
|
||||
os_printf("Wifi AP: station " MACSTR " joined, AID = %d\n",
|
||||
MAC2STR(evt->event_info.sta_connected.mac), evt->event_info.sta_connected.aid);
|
||||
break;
|
||||
case EVENT_SOFTAPMODE_STADISCONNECTED:
|
||||
os_printf("Wifi AP: station " MACSTR " left, AID = %d\n",
|
||||
MAC2STR(evt->event_info.sta_disconnected.mac), evt->event_info.sta_disconnected.aid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (wifi_state_change_cb[i] != NULL) (wifi_state_change_cb[i])(wifiState);
|
||||
@@ -115,25 +103,23 @@ wifiAddStateChangeCb(WifiStateChangeCb cb) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef WIFI_DBG
|
||||
os_printf("WIFI: max state change cb count exceeded\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// ===== wifi scanning
|
||||
|
||||
//WiFi access point data
|
||||
typedef struct {
|
||||
char ssid[32];
|
||||
sint8 rssi;
|
||||
char enc;
|
||||
char ssid[32];
|
||||
sint8 rssi;
|
||||
char enc;
|
||||
} ApData;
|
||||
|
||||
//Scan result
|
||||
typedef struct {
|
||||
char scanInProgress; //if 1, don't access the underlying stuff from the webpage.
|
||||
ApData **apData;
|
||||
int noAps;
|
||||
char scanInProgress; //if 1, don't access the underlying stuff from the webpage.
|
||||
ApData **apData;
|
||||
int noAps;
|
||||
} ScanResultData;
|
||||
|
||||
//Static scan status storage.
|
||||
@@ -142,121 +128,109 @@ static ScanResultData cgiWifiAps;
|
||||
//Callback the code calls when a wlan ap scan is done. Basically stores the result in
|
||||
//the cgiWifiAps struct.
|
||||
void ICACHE_FLASH_ATTR wifiScanDoneCb(void *arg, STATUS status) {
|
||||
int n;
|
||||
struct bss_info *bss_link = (struct bss_info *)arg;
|
||||
int n;
|
||||
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;
|
||||
}
|
||||
if (status!=OK) {
|
||||
os_printf("wifiScanDoneCb status=%d\n", status);
|
||||
cgiWifiAps.scanInProgress=0;
|
||||
return;
|
||||
}
|
||||
|
||||
//Clear prev ap data if needed.
|
||||
if (cgiWifiAps.apData!=NULL) {
|
||||
for (n=0; n<cgiWifiAps.noAps; n++) os_free(cgiWifiAps.apData[n]);
|
||||
os_free(cgiWifiAps.apData);
|
||||
}
|
||||
//Clear prev ap data if needed.
|
||||
if (cgiWifiAps.apData!=NULL) {
|
||||
for (n=0; n<cgiWifiAps.noAps; n++) os_free(cgiWifiAps.apData[n]);
|
||||
os_free(cgiWifiAps.apData);
|
||||
}
|
||||
|
||||
//Count amount of access points found.
|
||||
n=0;
|
||||
while (bss_link != NULL) {
|
||||
bss_link = bss_link->next.stqe_next;
|
||||
n++;
|
||||
}
|
||||
//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
|
||||
//Count amount of access points found.
|
||||
n=0;
|
||||
while (bss_link != NULL) {
|
||||
bss_link = bss_link->next.stqe_next;
|
||||
n++;
|
||||
}
|
||||
//Allocate memory for access point data
|
||||
cgiWifiAps.apData=(ApData **)os_malloc(sizeof(ApData *)*n);
|
||||
cgiWifiAps.noAps=n;
|
||||
os_printf("Scan done: found %d APs\n", n);
|
||||
|
||||
//Copy access point data to the static struct
|
||||
n=0;
|
||||
bss_link = (struct bss_info *)arg;
|
||||
while (bss_link != NULL) {
|
||||
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.
|
||||
cgiWifiAps.apData[n]=(ApData *)os_malloc(sizeof(ApData));
|
||||
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
|
||||
//Copy access point data to the static struct
|
||||
n=0;
|
||||
bss_link = (struct bss_info *)arg;
|
||||
while (bss_link != NULL) {
|
||||
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.
|
||||
os_printf("Huh? I have more than the allocated %d aps!\n", cgiWifiAps.noAps);
|
||||
break;
|
||||
}
|
||||
//Save the ap data.
|
||||
cgiWifiAps.apData[n]=(ApData *)os_malloc(sizeof(ApData));
|
||||
cgiWifiAps.apData[n]->rssi=bss_link->rssi;
|
||||
cgiWifiAps.apData[n]->enc=bss_link->authmode;
|
||||
strncpy(cgiWifiAps.apData[n]->ssid, (char*)bss_link->ssid, 32);
|
||||
os_printf("bss%d: %s (%d)\n", n+1, (char*)bss_link->ssid, bss_link->rssi);
|
||||
|
||||
bss_link = bss_link->next.stqe_next;
|
||||
n++;
|
||||
}
|
||||
//We're done.
|
||||
cgiWifiAps.scanInProgress=0;
|
||||
bss_link = bss_link->next.stqe_next;
|
||||
n++;
|
||||
}
|
||||
//We're done.
|
||||
cgiWifiAps.scanInProgress=0;
|
||||
}
|
||||
|
||||
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);
|
||||
os_printf("Starting a scan\n");
|
||||
wifi_station_scan(NULL, wifiScanDoneCb);
|
||||
}
|
||||
|
||||
static int ICACHE_FLASH_ATTR cgiWiFiStartScan(HttpdConnData *connData) {
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
jsonHeader(connData, 200);
|
||||
if (!cgiWifiAps.scanInProgress) {
|
||||
cgiWifiAps.scanInProgress = 1;
|
||||
os_timer_disarm(&scanTimer);
|
||||
os_timer_setfn(&scanTimer, scanStartCb, NULL);
|
||||
os_timer_arm(&scanTimer, 1000, 0);
|
||||
}
|
||||
return HTTPD_CGI_DONE;
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
jsonHeader(connData, 200);
|
||||
if (!cgiWifiAps.scanInProgress) {
|
||||
cgiWifiAps.scanInProgress = 1;
|
||||
os_timer_disarm(&scanTimer);
|
||||
os_timer_setfn(&scanTimer, scanStartCb, NULL);
|
||||
os_timer_arm(&scanTimer, 1000, 0);
|
||||
}
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
static int ICACHE_FLASH_ATTR cgiWiFiGetScan(HttpdConnData *connData) {
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
char buff[2048];
|
||||
int len;
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
char buff[2048];
|
||||
int len;
|
||||
|
||||
jsonHeader(connData, 200);
|
||||
jsonHeader(connData, 200);
|
||||
|
||||
if (cgiWifiAps.scanInProgress==1) {
|
||||
//We're still scanning. Tell Javascript code that.
|
||||
len = os_sprintf(buff, "{\n \"result\": { \n\"inProgress\": \"1\"\n }\n}\n");
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
if (cgiWifiAps.scanInProgress==1) {
|
||||
//We're still scanning. Tell Javascript code that.
|
||||
len = os_sprintf(buff, "{\n \"result\": { \n\"inProgress\": \"1\"\n }\n}\n");
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
len = os_sprintf(buff, "{\"result\": {\"inProgress\": \"0\", \"APs\": [\n");
|
||||
for (int pos=0; pos<cgiWifiAps.noAps; pos++) {
|
||||
len += os_sprintf(buff+len, "{\"essid\": \"%s\", \"rssi\": %d, \"enc\": \"%d\"}%s\n",
|
||||
cgiWifiAps.apData[pos]->ssid, cgiWifiAps.apData[pos]->rssi,
|
||||
cgiWifiAps.apData[pos]->enc, (pos==cgiWifiAps.noAps-1)?"":",");
|
||||
}
|
||||
len += os_sprintf(buff+len, "]}}\n");
|
||||
#ifdef WIFI_DBG
|
||||
os_printf("Sending %d bytes: %s\n", len, buff);
|
||||
#endif
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
len = os_sprintf(buff, "{\"result\": {\"inProgress\": \"0\", \"APs\": [\n");
|
||||
for (int pos=0; pos<cgiWifiAps.noAps; pos++) {
|
||||
len += os_sprintf(buff+len, "{\"essid\": \"%s\", \"rssi\": %d, \"enc\": \"%d\"}%s\n",
|
||||
cgiWifiAps.apData[pos]->ssid, cgiWifiAps.apData[pos]->rssi,
|
||||
cgiWifiAps.apData[pos]->enc, (pos==cgiWifiAps.noAps-1)?"":",");
|
||||
}
|
||||
len += os_sprintf(buff+len, "]}}\n");
|
||||
//os_printf("Sending %d bytes: %s\n", len, buff);
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) {
|
||||
if (connData->requestType == HTTPD_METHOD_GET) {
|
||||
return cgiWiFiGetScan(connData);
|
||||
} else if (connData->requestType == HTTPD_METHOD_POST) {
|
||||
return cgiWiFiStartScan(connData);
|
||||
} else {
|
||||
jsonHeader(connData, 404);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
if (connData->requestType == HTTPD_METHOD_GET) {
|
||||
return cgiWiFiGetScan(connData);
|
||||
} else if (connData->requestType == HTTPD_METHOD_POST) {
|
||||
return cgiWiFiStartScan(connData);
|
||||
} else {
|
||||
jsonHeader(connData, 404);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== timers to change state and rescue from failed associations
|
||||
@@ -269,39 +243,31 @@ static ETSTimer resetTimer;
|
||||
// the connect succeeds, this gets the module in STA-only mode. If it fails, it ensures
|
||||
// that the module is in STA+AP mode so the user has a chance to recover.
|
||||
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
|
||||
int x = wifi_station_get_connect_status();
|
||||
int m = wifi_get_opmode() & 0x3;
|
||||
os_printf("Wifi check: mode=%s status=%d\n", wifiMode[m], x);
|
||||
|
||||
if (x == STATION_GOT_IP) {
|
||||
if (m != 1) {
|
||||
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");
|
||||
// We're happily connected, go to STA mode
|
||||
os_printf("Wifi got IP. Going into STA mode..\n");
|
||||
wifi_set_opmode(1);
|
||||
wifi_set_sleep_type(SLEEP_MODE);
|
||||
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
|
||||
#endif
|
||||
wifi_set_opmode(1);
|
||||
wifi_set_sleep_type(SLEEP_MODE);
|
||||
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
|
||||
#endif
|
||||
}
|
||||
log_uart(false);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
log_uart(false);
|
||||
// no more resetTimer at this point, gotta use physical reset to recover if in trouble
|
||||
} else {
|
||||
if (m != 3) {
|
||||
os_printf("Wifi connect failed. Going into STA+AP mode..\n");
|
||||
wifi_set_opmode(3);
|
||||
}
|
||||
log_uart(true);
|
||||
os_printf("Enabling/continuing uart log\n");
|
||||
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Temp store for new ap info.
|
||||
@@ -311,215 +277,206 @@ 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);
|
||||
wifi_station_connect();
|
||||
// Schedule check
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
|
||||
os_printf("Wifi changing association\n");
|
||||
wifi_station_disconnect();
|
||||
stconf.bssid_set = 0;
|
||||
wifi_station_set_config(&stconf);
|
||||
wifi_station_connect();
|
||||
// Schedule check
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
|
||||
}
|
||||
|
||||
// This cgi uses the routines above to connect to a specific access point with the
|
||||
// given ESSID using the given password.
|
||||
int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) {
|
||||
char essid[128];
|
||||
char passwd[128];
|
||||
char essid[128];
|
||||
char passwd[128];
|
||||
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE;
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE;
|
||||
|
||||
int el = httpdFindArg(connData->getArgs, "essid", essid, sizeof(essid));
|
||||
int pl = httpdFindArg(connData->getArgs, "passwd", passwd, sizeof(passwd));
|
||||
int el = httpdFindArg(connData->getArgs, "essid", essid, sizeof(essid));
|
||||
int pl = httpdFindArg(connData->getArgs, "passwd", passwd, sizeof(passwd));
|
||||
|
||||
if (el > 0 && pl >= 0) {
|
||||
//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
|
||||
if (el > 0 && pl >= 0) {
|
||||
//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);
|
||||
os_printf("Wifi try to connect to AP %s pw %s\n", essid, passwd);
|
||||
|
||||
//Schedule disconnect/connect
|
||||
os_timer_disarm(&reassTimer);
|
||||
os_timer_setfn(&reassTimer, reassTimerCb, NULL);
|
||||
os_timer_arm(&reassTimer, 1000, 0);
|
||||
jsonHeader(connData, 200);
|
||||
} else {
|
||||
jsonHeader(connData, 400);
|
||||
httpdSend(connData, "Cannot parse ssid or password", -1);
|
||||
}
|
||||
return HTTPD_CGI_DONE;
|
||||
//Schedule disconnect/connect
|
||||
os_timer_disarm(&reassTimer);
|
||||
os_timer_setfn(&reassTimer, reassTimerCb, NULL);
|
||||
os_timer_arm(&reassTimer, 1000, 0);
|
||||
jsonHeader(connData, 200);
|
||||
} else {
|
||||
jsonHeader(connData, 400);
|
||||
httpdSend(connData, "Cannot parse ssid or password", -1);
|
||||
}
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
static bool parse_ip(char *buff, ip_addr_t *ip_ptr) {
|
||||
char *next = buff; // where to start parsing next integer
|
||||
int found = 0; // number of integers parsed
|
||||
uint32_t ip = 0; // the ip addres parsed
|
||||
for (int i=0; i<32; i++) { // 32 is just a safety limit
|
||||
char c = buff[i];
|
||||
if (c == '.' || c == 0) {
|
||||
// parse the preceding integer and accumulate into IP address
|
||||
bool last = c == 0;
|
||||
buff[i] = 0;
|
||||
uint32_t v = atoi(next);
|
||||
ip = ip | ((v&0xff)<<(found*8));
|
||||
next = buff+i+1; // next integer starts after the '.'
|
||||
found++;
|
||||
if (last) { // if at end of string we better got 4 integers
|
||||
ip_ptr->addr = ip;
|
||||
return found == 4;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (c < '0' || c > '9') return false;
|
||||
}
|
||||
return false;
|
||||
char *next = buff; // where to start parsing next integer
|
||||
int found = 0; // number of integers parsed
|
||||
uint32_t ip = 0; // the ip addres parsed
|
||||
for (int i=0; i<32; i++) { // 32 is just a safety limit
|
||||
char c = buff[i];
|
||||
if (c == '.' || c == 0) {
|
||||
// parse the preceding integer and accumulate into IP address
|
||||
bool last = c == 0;
|
||||
buff[i] = 0;
|
||||
uint32_t v = atoi(next);
|
||||
ip = ip | ((v&0xff)<<(found*8));
|
||||
next = buff+i+1; // next integer starts after the '.'
|
||||
found++;
|
||||
if (last) { // if at end of string we better got 4 integers
|
||||
ip_ptr->addr = ip;
|
||||
return found == 4;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (c < '0' || c > '9') return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef WIFI_DBG
|
||||
#define DEBUGIP
|
||||
#ifdef DEBUGIP
|
||||
static void ICACHE_FLASH_ATTR debugIP() {
|
||||
struct ip_info info;
|
||||
if (wifi_get_ip_info(0, &info)) {
|
||||
os_printf("\"ip\": \"%d.%d.%d.%d\"\n", IP2STR(&info.ip.addr));
|
||||
os_printf("\"netmask\": \"%d.%d.%d.%d\"\n", IP2STR(&info.netmask.addr));
|
||||
os_printf("\"gateway\": \"%d.%d.%d.%d\"\n", IP2STR(&info.gw.addr));
|
||||
os_printf("\"hostname\": \"%s\"\n", wifi_station_get_hostname());
|
||||
} else {
|
||||
os_printf("\"ip\": \"-none-\"\n");
|
||||
}
|
||||
struct ip_info info;
|
||||
if (wifi_get_ip_info(0, &info)) {
|
||||
os_printf("\"ip\": \"%d.%d.%d.%d\"\n", IP2STR(&info.ip.addr));
|
||||
os_printf("\"netmask\": \"%d.%d.%d.%d\"\n", IP2STR(&info.netmask.addr));
|
||||
os_printf("\"gateway\": \"%d.%d.%d.%d\"\n", IP2STR(&info.gw.addr));
|
||||
os_printf("\"hostname\": \"%s\"\n", wifi_station_get_hostname());
|
||||
} else {
|
||||
os_printf("\"ip\": \"-none-\"\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// configure Wifi, specifically DHCP vs static IP address based on flash config
|
||||
static void ICACHE_FLASH_ATTR configWifiIP() {
|
||||
if (flashConfig.staticip == 0) {
|
||||
// let's DHCP!
|
||||
wifi_station_set_hostname(flashConfig.hostname);
|
||||
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();
|
||||
struct ip_info ipi;
|
||||
ipi.ip.addr = flashConfig.staticip;
|
||||
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
|
||||
}
|
||||
if (flashConfig.staticip == 0) {
|
||||
// let's DHCP!
|
||||
wifi_station_set_hostname(flashConfig.hostname);
|
||||
if (wifi_station_dhcpc_status() == DHCP_STARTED)
|
||||
wifi_station_dhcpc_stop();
|
||||
wifi_station_dhcpc_start();
|
||||
os_printf("Wifi uses DHCP, hostname=%s\n", flashConfig.hostname);
|
||||
} else {
|
||||
// no DHCP, we got static network config!
|
||||
wifi_station_dhcpc_stop();
|
||||
struct ip_info ipi;
|
||||
ipi.ip.addr = flashConfig.staticip;
|
||||
ipi.netmask.addr = flashConfig.netmask;
|
||||
ipi.gw.addr = flashConfig.gateway;
|
||||
wifi_set_ip_info(0, &ipi);
|
||||
os_printf("Wifi uses static IP %d.%d.%d.%d\n", IP2STR(&ipi.ip.addr));
|
||||
}
|
||||
#ifdef DEBUGIP
|
||||
debugIP();
|
||||
debugIP();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Change special settings
|
||||
int ICACHE_FLASH_ATTR cgiWiFiSpecial(HttpdConnData *connData) {
|
||||
char dhcp[8];
|
||||
char hostname[32];
|
||||
char staticip[20];
|
||||
char netmask[20];
|
||||
char gateway[20];
|
||||
char dhcp[8];
|
||||
char hostname[32];
|
||||
char staticip[20];
|
||||
char netmask[20];
|
||||
char gateway[20];
|
||||
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE;
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE;
|
||||
|
||||
// get args and their string lengths
|
||||
int dl = httpdFindArg(connData->getArgs, "dhcp", dhcp, sizeof(dhcp));
|
||||
int hl = httpdFindArg(connData->getArgs, "hostname", hostname, sizeof(hostname));
|
||||
int sl = httpdFindArg(connData->getArgs, "staticip", staticip, sizeof(staticip));
|
||||
int nl = httpdFindArg(connData->getArgs, "netmask", netmask, sizeof(netmask));
|
||||
int gl = httpdFindArg(connData->getArgs, "gateway", gateway, sizeof(gateway));
|
||||
// get args and their string lengths
|
||||
int dl = httpdFindArg(connData->getArgs, "dhcp", dhcp, sizeof(dhcp));
|
||||
int hl = httpdFindArg(connData->getArgs, "hostname", hostname, sizeof(hostname));
|
||||
int sl = httpdFindArg(connData->getArgs, "staticip", staticip, sizeof(staticip));
|
||||
int nl = httpdFindArg(connData->getArgs, "netmask", netmask, sizeof(netmask));
|
||||
int gl = httpdFindArg(connData->getArgs, "gateway", gateway, sizeof(gateway));
|
||||
|
||||
if (!(dl > 0 && hl >= 0 && sl >= 0 && nl >= 0 && gl >= 0)) {
|
||||
jsonHeader(connData, 400);
|
||||
httpdSend(connData, "Request is missing fields", -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
if (!(dl > 0 && hl >= 0 && sl >= 0 && nl >= 0 && gl >= 0)) {
|
||||
jsonHeader(connData, 400);
|
||||
httpdSend(connData, "Request is missing fields", -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
char url[64]; // redirect URL
|
||||
if (os_strcmp(dhcp, "off") == 0) {
|
||||
// parse static IP params
|
||||
struct ip_info ipi;
|
||||
bool ok = parse_ip(staticip, &ipi.ip);
|
||||
if (nl > 0) ok = ok && parse_ip(netmask, &ipi.netmask);
|
||||
else IP4_ADDR(&ipi.netmask, 255, 255, 255, 0);
|
||||
if (gl > 0) ok = ok && parse_ip(gateway, &ipi.gw);
|
||||
else ipi.gw.addr = 0;
|
||||
if (!ok) {
|
||||
jsonHeader(connData, 400);
|
||||
httpdSend(connData, "Cannot parse static IP config", -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
// save the params in flash
|
||||
flashConfig.staticip = ipi.ip.addr;
|
||||
flashConfig.netmask = ipi.netmask.addr;
|
||||
flashConfig.gateway = ipi.gw.addr;
|
||||
// construct redirect URL
|
||||
os_sprintf(url, "{\"url\": \"http://%d.%d.%d.%d\"}", IP2STR(&ipi.ip));
|
||||
char url[64]; // redirect URL
|
||||
if (os_strcmp(dhcp, "off") == 0) {
|
||||
// parse static IP params
|
||||
struct ip_info ipi;
|
||||
bool ok = parse_ip(staticip, &ipi.ip);
|
||||
if (nl > 0) ok = ok && parse_ip(netmask, &ipi.netmask);
|
||||
else IP4_ADDR(&ipi.netmask, 255, 255, 255, 0);
|
||||
if (gl > 0) ok = ok && parse_ip(gateway, &ipi.gw);
|
||||
else ipi.gw.addr = 0;
|
||||
if (!ok) {
|
||||
jsonHeader(connData, 400);
|
||||
httpdSend(connData, "Cannot parse static IP config", -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
// save the params in flash
|
||||
flashConfig.staticip = ipi.ip.addr;
|
||||
flashConfig.netmask = ipi.netmask.addr;
|
||||
flashConfig.gateway = ipi.gw.addr;
|
||||
// construct redirect URL
|
||||
os_sprintf(url, "{\"url\": \"http://%d.%d.%d.%d\"}", IP2STR(&ipi.ip));
|
||||
|
||||
} else {
|
||||
// no static IP, set hostname
|
||||
if (hl == 0) os_strcpy(hostname, "esp-link");
|
||||
flashConfig.staticip = 0;
|
||||
os_strcpy(flashConfig.hostname, hostname);
|
||||
os_sprintf(url, "{\"url\": \"http://%s\"}", hostname);
|
||||
}
|
||||
} else {
|
||||
// no static IP, set hostname
|
||||
if (hl == 0) os_strcpy(hostname, "esp-link");
|
||||
flashConfig.staticip = 0;
|
||||
os_strcpy(flashConfig.hostname, hostname);
|
||||
os_sprintf(url, "{\"url\": \"http://%s\"}", hostname);
|
||||
}
|
||||
|
||||
configSave(); // ignore error...
|
||||
// schedule change-over
|
||||
os_timer_disarm(&reassTimer);
|
||||
os_timer_setfn(&reassTimer, configWifiIP, NULL);
|
||||
os_timer_arm(&reassTimer, 1000, 0);
|
||||
// return redirect info
|
||||
jsonHeader(connData, 200);
|
||||
httpdSend(connData, url, -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
configSave(); // ignore error...
|
||||
// schedule change-over
|
||||
os_timer_disarm(&reassTimer);
|
||||
os_timer_setfn(&reassTimer, configWifiIP, NULL);
|
||||
os_timer_arm(&reassTimer, 1000, 0);
|
||||
// return redirect info
|
||||
jsonHeader(connData, 200);
|
||||
httpdSend(connData, url, -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
//This cgi changes the operating mode: STA / AP / STA+AP
|
||||
int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
|
||||
int len;
|
||||
char buff[1024];
|
||||
int len;
|
||||
char buff[1024];
|
||||
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
|
||||
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);
|
||||
// STA-only mode, reset into STA+AP after a timeout
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
|
||||
}
|
||||
jsonHeader(connData, 200);
|
||||
} else {
|
||||
jsonHeader(connData, 400);
|
||||
}
|
||||
return HTTPD_CGI_DONE;
|
||||
len=httpdFindArg(connData->getArgs, "mode", buff, sizeof(buff));
|
||||
if (len!=0) {
|
||||
int m = atoi(buff);
|
||||
os_printf("Wifi switching to mode %d\n", m);
|
||||
wifi_set_opmode(m&3);
|
||||
if (m == 1) {
|
||||
wifi_set_sleep_type(SLEEP_MODE);
|
||||
// STA-only mode, reset into STA+AP after a timeout
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
|
||||
}
|
||||
jsonHeader(connData, 200);
|
||||
} else {
|
||||
jsonHeader(connData, 400);
|
||||
}
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
static char *connStatuses[] = { "idle", "connecting", "wrong password", "AP not found",
|
||||
"failed", "got IP address" };
|
||||
|
||||
static char *wifiWarn[] = { 0,
|
||||
"Switch to <a href=\\\"#\\\" onclick=\\\"changeWifiMode(3)\\\">STA+AP mode</a>",
|
||||
"<b>Can't scan in this mode!</b> Switch to <a href=\\\"#\\\" onclick=\\\"changeWifiMode(3)\\\">STA+AP mode</a>",
|
||||
"Switch to <a href=\\\"#\\\" onclick=\\\"changeWifiMode(1)\\\">STA mode</a>",
|
||||
"Switch to <a href=\\\"#\\\" onclick=\\\"changeWifiMode(3)\\\">STA+AP mode</a>",
|
||||
"<b>Can't scan in this mode!</b> Switch to <a href=\\\"#\\\" onclick=\\\"changeWifiMode(3)\\\">STA+AP mode</a>",
|
||||
"Switch to <a href=\\\"#\\\" onclick=\\\"changeWifiMode(1)\\\">STA mode</a>",
|
||||
};
|
||||
|
||||
#ifdef CHANGE_TO_STA
|
||||
@@ -530,112 +487,109 @@ static char *wifiWarn[] = { 0,
|
||||
|
||||
// print various Wifi information into json buffer
|
||||
int ICACHE_FLASH_ATTR printWifiInfo(char *buff) {
|
||||
int len;
|
||||
int len;
|
||||
|
||||
struct station_config stconf;
|
||||
wifi_station_get_config(&stconf);
|
||||
struct station_config stconf;
|
||||
wifi_station_get_config(&stconf);
|
||||
|
||||
uint8_t op = wifi_get_opmode() & 0x3;
|
||||
char *mode = wifiMode[op];
|
||||
char *status = "unknown";
|
||||
int st = wifi_station_get_connect_status();
|
||||
if (st >= 0 && st < sizeof(connStatuses)) status = connStatuses[st];
|
||||
int p = wifi_get_phy_mode();
|
||||
char *phy = wifiPhy[p&3];
|
||||
char *warn = wifiWarn[op];
|
||||
sint8 rssi = wifi_station_get_rssi();
|
||||
if (rssi > 0) rssi = 0;
|
||||
uint8 mac_addr[6];
|
||||
wifi_get_macaddr(0, mac_addr);
|
||||
uint8_t chan = wifi_get_channel();
|
||||
uint8_t op = wifi_get_opmode() & 0x3;
|
||||
char *mode = wifiMode[op];
|
||||
char *status = "unknown";
|
||||
int st = wifi_station_get_connect_status();
|
||||
if (st >= 0 && st < sizeof(connStatuses)) status = connStatuses[st];
|
||||
int p = wifi_get_phy_mode();
|
||||
char *phy = wifiPhy[p&3];
|
||||
char *warn = wifiWarn[op];
|
||||
sint8 rssi = wifi_station_get_rssi();
|
||||
if (rssi > 0) rssi = 0;
|
||||
uint8 mac_addr[6];
|
||||
wifi_get_macaddr(0, mac_addr);
|
||||
uint8_t chan = wifi_get_channel();
|
||||
|
||||
len = os_sprintf(buff,
|
||||
"\"mode\": \"%s\", \"modechange\": \"%s\", \"ssid\": \"%s\", \"status\": \"%s\", \"phy\": \"%s\", "
|
||||
"\"rssi\": \"%ddB\", \"warn\": \"%s\", \"mac\":\"%02x:%02x:%02x:%02x:%02x:%02x\", \"chan\":%d",
|
||||
mode, MODECHANGE, (char*)stconf.ssid, status, phy, rssi, warn,
|
||||
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], chan);
|
||||
len = os_sprintf(buff,
|
||||
"\"mode\": \"%s\", \"modechange\": \"%s\", \"ssid\": \"%s\", \"status\": \"%s\", \"phy\": \"%s\", "
|
||||
"\"rssi\": \"%ddB\", \"warn\": \"%s\", \"mac\":\"%02x:%02x:%02x:%02x:%02x:%02x\", \"chan\":%d",
|
||||
mode, MODECHANGE, (char*)stconf.ssid, status, phy, rssi, warn,
|
||||
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5], chan);
|
||||
|
||||
struct ip_info info;
|
||||
if (wifi_get_ip_info(0, &info)) {
|
||||
len += os_sprintf(buff+len, ", \"ip\": \"%d.%d.%d.%d\"", IP2STR(&info.ip.addr));
|
||||
len += os_sprintf(buff+len, ", \"netmask\": \"%d.%d.%d.%d\"", IP2STR(&info.netmask.addr));
|
||||
len += os_sprintf(buff+len, ", \"gateway\": \"%d.%d.%d.%d\"", IP2STR(&info.gw.addr));
|
||||
len += os_sprintf(buff+len, ", \"hostname\": \"%s\"", flashConfig.hostname);
|
||||
} else {
|
||||
len += os_sprintf(buff+len, ", \"ip\": \"-none-\"");
|
||||
}
|
||||
len += os_sprintf(buff+len, ", \"staticip\": \"%d.%d.%d.%d\"", IP2STR(&flashConfig.staticip));
|
||||
len += os_sprintf(buff+len, ", \"dhcp\": \"%s\"", flashConfig.staticip > 0 ? "off" : "on");
|
||||
struct ip_info info;
|
||||
if (wifi_get_ip_info(0, &info)) {
|
||||
len += os_sprintf(buff+len, ", \"ip\": \"%d.%d.%d.%d\"", IP2STR(&info.ip.addr));
|
||||
len += os_sprintf(buff+len, ", \"netmask\": \"%d.%d.%d.%d\"", IP2STR(&info.netmask.addr));
|
||||
len += os_sprintf(buff+len, ", \"gateway\": \"%d.%d.%d.%d\"", IP2STR(&info.gw.addr));
|
||||
len += os_sprintf(buff+len, ", \"hostname\": \"%s\"", flashConfig.hostname);
|
||||
} else {
|
||||
len += os_sprintf(buff+len, ", \"ip\": \"-none-\"");
|
||||
}
|
||||
len += os_sprintf(buff+len, ", \"staticip\": \"%d.%d.%d.%d\"", IP2STR(&flashConfig.staticip));
|
||||
len += os_sprintf(buff+len, ", \"dhcp\": \"%s\"", flashConfig.staticip > 0 ? "off" : "on");
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
|
||||
char buff[1024];
|
||||
int len;
|
||||
char buff[1024];
|
||||
int len;
|
||||
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
jsonHeader(connData, 200);
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
jsonHeader(connData, 200);
|
||||
|
||||
len = os_sprintf(buff, "{");
|
||||
len += printWifiInfo(buff+len);
|
||||
len += os_sprintf(buff+len, ", ");
|
||||
len = os_sprintf(buff, "{");
|
||||
len += printWifiInfo(buff+len);
|
||||
len += os_sprintf(buff+len, ", ");
|
||||
|
||||
if (wifiReason != 0) {
|
||||
len += os_sprintf(buff+len, "\"reason\": \"%s\", ", wifiGetReason());
|
||||
}
|
||||
if (wifiReason != 0) {
|
||||
len += os_sprintf(buff+len, "\"reason\": \"%s\", ", wifiGetReason());
|
||||
}
|
||||
|
||||
#if 0
|
||||
// commented out 'cause often the client that requested the change can't get a request in to
|
||||
// find out that it succeeded. Better to just wait the std 15 seconds...
|
||||
int st=wifi_station_get_connect_status();
|
||||
if (st == STATION_GOT_IP) {
|
||||
if (wifi_get_opmode() != 1) {
|
||||
// Reset into AP-only mode sooner.
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, 1000, 0);
|
||||
}
|
||||
}
|
||||
// commented out 'cause often the client that requested the change can't get a request in to
|
||||
// find out that it succeeded. Better to just wait the std 15 seconds...
|
||||
int st=wifi_station_get_connect_status();
|
||||
if (st == STATION_GOT_IP) {
|
||||
if (wifi_get_opmode() != 1) {
|
||||
// Reset into AP-only mode sooner.
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, 1000, 0);
|
||||
}
|
||||
}
|
||||
#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;
|
||||
len += os_sprintf(buff+len, "\"x\":0}\n");
|
||||
|
||||
os_printf(" -> %s\n", buff);
|
||||
httpdSend(connData, buff, len);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
// Cgi to return various Wifi information
|
||||
int ICACHE_FLASH_ATTR cgiWifiInfo(HttpdConnData *connData) {
|
||||
char buff[1024];
|
||||
char buff[1024];
|
||||
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
|
||||
|
||||
os_strcpy(buff, "{");
|
||||
printWifiInfo(buff+1);
|
||||
os_strcat(buff, "}");
|
||||
os_strcpy(buff, "{");
|
||||
printWifiInfo(buff+1);
|
||||
os_strcat(buff, "}");
|
||||
|
||||
jsonHeader(connData, 200);
|
||||
httpdSend(connData, buff, -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
jsonHeader(connData, 200);
|
||||
httpdSend(connData, buff, -1);
|
||||
return HTTPD_CGI_DONE;
|
||||
}
|
||||
|
||||
// Init the wireless, which consists of setting a timer if we expect to connect to an AP
|
||||
// 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_phy_mode(2);
|
||||
int x = wifi_get_opmode() & 0x3;
|
||||
os_printf("Wifi init, mode=%s\n", wifiMode[x]);
|
||||
configWifiIP();
|
||||
|
||||
wifi_set_event_handler_cb(wifiHandleEventCb);
|
||||
// check on the wifi in a few seconds to see whether we need to switch mode
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
|
||||
wifi_set_event_handler_cb(wifiHandleEventCb);
|
||||
// check on the wifi in a few seconds to see whether we need to switch mode
|
||||
os_timer_disarm(&resetTimer);
|
||||
os_timer_setfn(&resetTimer, resetTimerCb, NULL);
|
||||
os_timer_arm(&resetTimer, RESET_TIMEOUT, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,26 +5,27 @@
|
||||
#include <osapi.h>
|
||||
#include "config.h"
|
||||
#include "espfs.h"
|
||||
|
||||
// hack: this from LwIP
|
||||
extern uint16_t inet_chksum(void *dataptr, uint16_t len);
|
||||
#include "crc16.h"
|
||||
|
||||
FlashConfig flashConfig;
|
||||
FlashConfig flashDefault = {
|
||||
33, 0, 0,
|
||||
MCU_RESET_PIN, MCU_ISP_PIN, LED_CONN_PIN, LED_SERIAL_PIN,
|
||||
115200,
|
||||
"esp-link\0 ", // hostname
|
||||
"esp-link\0", // hostname
|
||||
0, 0x00ffffff, 0, // static ip, netmask, gateway
|
||||
0, // log mode
|
||||
0, // swap uart (don't by default)
|
||||
1, 0, // tcp_enable, rssi_enable
|
||||
"\0", // api_key
|
||||
0, 0, 0, // slip_enable, mqtt_enable, mqtt_status_enable
|
||||
1833, // mqtt port
|
||||
"\0", "\0", "\0", "\0", "\0", // mqtt host, client, user, password, status-topic
|
||||
};
|
||||
|
||||
typedef union {
|
||||
FlashConfig fc;
|
||||
uint8_t block[128];
|
||||
uint8_t block[1024];
|
||||
} FlashFull;
|
||||
|
||||
// magic number to recognize thet these are our flash settings as opposed to some random stuff
|
||||
@@ -63,7 +64,7 @@ bool ICACHE_FLASH_ATTR configSave(void) {
|
||||
ff.fc.crc = 0;
|
||||
//os_printf("cksum of: ");
|
||||
//memDump(&ff, sizeof(ff));
|
||||
ff.fc.crc = inet_chksum(&ff, sizeof(ff));
|
||||
ff.fc.crc = crc16_data((unsigned char*)&ff, sizeof(ff), 0);
|
||||
//os_printf("cksum is %04x\n", ff.fc.crc);
|
||||
// write primary with incorrect seq
|
||||
ff.fc.seq = 0xffffffff;
|
||||
@@ -123,12 +124,16 @@ static int ICACHE_FLASH_ATTR selectPrimary(FlashFull *ff0, FlashFull *ff1) {
|
||||
// check CRC of ff0
|
||||
uint16_t crc = ff0->fc.crc;
|
||||
ff0->fc.crc = 0;
|
||||
bool ff0_crc_ok = inet_chksum(ff0, sizeof(FlashFull)) == crc;
|
||||
bool ff0_crc_ok = crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0) == crc;
|
||||
|
||||
os_printf("FLASH chk=0x%04x crc=0x%04x full_sz=%d sz=%d\n",
|
||||
crc16_data((unsigned char*)ff0, sizeof(FlashFull), 0),
|
||||
crc, sizeof(FlashFull), sizeof(FlashConfig));
|
||||
|
||||
// check CRC of ff1
|
||||
crc = ff1->fc.crc;
|
||||
ff1->fc.crc = 0;
|
||||
bool ff1_crc_ok = inet_chksum(ff1, sizeof(FlashFull)) == crc;
|
||||
bool ff1_crc_ok = crc16_data((unsigned char*)ff1, sizeof(FlashFull), 0) == crc;
|
||||
|
||||
// decided which we like better
|
||||
if (ff0_crc_ok)
|
||||
|
||||
@@ -16,6 +16,11 @@ typedef struct {
|
||||
uint8_t swap_uart; // swap uart0 to gpio 13&15
|
||||
uint8_t tcp_enable, rssi_enable; // TCP client settings
|
||||
char api_key[48]; // RSSI submission API key (Grovestreams for now)
|
||||
uint8_t slip_enable, mqtt_enable, // SLIP protocol, MQTT client
|
||||
mqtt_status_enable; // MQTT status reporting
|
||||
uint16_t mqtt_port;
|
||||
char mqtt_hostname[32], mqtt_client[48], mqtt_username[32], mqtt_password[32];
|
||||
char mqtt_status_topic[32];
|
||||
} FlashConfig;
|
||||
extern FlashConfig flashConfig;
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "cgiwifi.h"
|
||||
#include "cgipins.h"
|
||||
#include "cgitcp.h"
|
||||
#include "cgimqtt.h"
|
||||
#include "cgiflash.h"
|
||||
#include "auth.h"
|
||||
#include "espfs.h"
|
||||
@@ -29,7 +30,7 @@
|
||||
#include "log.h"
|
||||
#include <gpio.h>
|
||||
|
||||
//#define SHOW_HEAP_USE
|
||||
#define SHOW_HEAP_USE
|
||||
|
||||
//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
|
||||
@@ -90,6 +91,7 @@ HttpdBuiltInUrl builtInUrls[] = {
|
||||
{ "/wifi/special", cgiWiFiSpecial, NULL },
|
||||
{ "/pins", cgiPins, NULL },
|
||||
{ "/tcpclient", cgiTcp, NULL },
|
||||
{ "/mqtt", cgiMqtt, NULL },
|
||||
|
||||
{ "*", cgiEspFsHook, NULL }, //Catch-all cgi function for the filesystem
|
||||
{ NULL, NULL, NULL }
|
||||
@@ -120,16 +122,22 @@ static char *rst_codes[] = {
|
||||
# define VERS_STR(V) VERS_STR_STR(V)
|
||||
char* esp_link_version = VERS_STR(VERSION);
|
||||
|
||||
//Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done.
|
||||
extern void app_init(void);
|
||||
|
||||
// Main routine to initialize esp-link.
|
||||
void user_init(void) {
|
||||
uart_init(115200, 115200);
|
||||
logInit(); // must come after init of uart
|
||||
os_delay_us(10000L);
|
||||
// get the flash config so we know how to init things
|
||||
//configWipe(); // uncomment to reset the config for testing purposes
|
||||
bool restoreOk = configRestore();
|
||||
// init gpio pin registers
|
||||
gpio_init();
|
||||
gpio_output_set(0, 0, 0, (1<<15)); // some people tie it GND, gotta ensure it's disabled
|
||||
// init UART
|
||||
uart_init(flashConfig.baud_rate, 115200);
|
||||
logInit(); // must come after init of uart
|
||||
// uart_init(flashConfig.baud_rate, 115200);
|
||||
// logInit(); // must come after init of uart
|
||||
// say hello (leave some time to cause break in TX after boot loader's msg
|
||||
os_delay_us(10000L);
|
||||
os_printf("\n\n** %s\n", esp_link_version);
|
||||
@@ -163,6 +171,5 @@ void user_init(void) {
|
||||
|
||||
os_printf("** esp-link ready\n");
|
||||
|
||||
// call user_main init
|
||||
init();
|
||||
}
|
||||
app_init();
|
||||
}
|
||||
|
||||
@@ -14,56 +14,56 @@ static ETSTimer ledTimer;
|
||||
static void ICACHE_FLASH_ATTR setLed(int on) {
|
||||
int8_t pin = flashConfig.conn_led_pin;
|
||||
if (pin < 0) return; // disabled
|
||||
// LED is active-low
|
||||
if (on) {
|
||||
gpio_output_set(0, (1<<pin), (1<<pin), 0);
|
||||
} else {
|
||||
gpio_output_set((1<<pin), 0, (1<<pin), 0);
|
||||
}
|
||||
// LED is active-low
|
||||
if (on) {
|
||||
gpio_output_set(0, (1<<pin), (1<<pin), 0);
|
||||
} else {
|
||||
gpio_output_set((1<<pin), 0, (1<<pin), 0);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t ledState = 0;
|
||||
|
||||
// Timer callback to update the LED
|
||||
static void ICACHE_FLASH_ATTR ledTimerCb(void *v) {
|
||||
int time = 1000;
|
||||
int time = 1000;
|
||||
|
||||
if (wifiState == wifiGotIP) {
|
||||
// connected, all is good, solid light with a short dark blip every 3 seconds
|
||||
ledState = 1-ledState;
|
||||
time = ledState ? 2900 : 100;
|
||||
} else if (wifiState == wifiIsConnected) {
|
||||
// waiting for DHCP, go on/off every second
|
||||
ledState = 1 - ledState;
|
||||
time = 1000;
|
||||
} else {
|
||||
// not connected
|
||||
switch (wifi_get_opmode()) {
|
||||
case 1: // STA
|
||||
ledState = 0;
|
||||
break;
|
||||
case 2: // AP
|
||||
ledState = 1-ledState;
|
||||
time = ledState ? 50 : 1950;
|
||||
break;
|
||||
case 3: // STA+AP
|
||||
ledState = 1-ledState;
|
||||
time = ledState ? 50 : 950;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (wifiState == wifiGotIP) {
|
||||
// connected, all is good, solid light with a short dark blip every 3 seconds
|
||||
ledState = 1-ledState;
|
||||
time = ledState ? 2900 : 100;
|
||||
} else if (wifiState == wifiIsConnected) {
|
||||
// waiting for DHCP, go on/off every second
|
||||
ledState = 1 - ledState;
|
||||
time = 1000;
|
||||
} else {
|
||||
// not connected
|
||||
switch (wifi_get_opmode()) {
|
||||
case 1: // STA
|
||||
ledState = 0;
|
||||
break;
|
||||
case 2: // AP
|
||||
ledState = 1-ledState;
|
||||
time = ledState ? 50 : 1950;
|
||||
break;
|
||||
case 3: // STA+AP
|
||||
ledState = 1-ledState;
|
||||
time = ledState ? 50 : 950;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setLed(ledState);
|
||||
os_timer_arm(&ledTimer, time, 0);
|
||||
setLed(ledState);
|
||||
os_timer_arm(&ledTimer, time, 0);
|
||||
}
|
||||
|
||||
// change the wifi state indication
|
||||
void ICACHE_FLASH_ATTR statusWifiUpdate(uint8_t state) {
|
||||
wifiState = state;
|
||||
// schedule an update (don't want to run into concurrency issues)
|
||||
os_timer_disarm(&ledTimer);
|
||||
os_timer_setfn(&ledTimer, ledTimerCb, NULL);
|
||||
os_timer_arm(&ledTimer, 500, 0);
|
||||
wifiState = state;
|
||||
// schedule an update (don't want to run into concurrency issues)
|
||||
os_timer_disarm(&ledTimer);
|
||||
os_timer_setfn(&ledTimer, ledTimerCb, NULL);
|
||||
os_timer_arm(&ledTimer, 500, 0);
|
||||
}
|
||||
|
||||
//===== RSSI Status update sent to GroveStreams
|
||||
@@ -76,59 +76,59 @@ static ETSTimer rssiTimer;
|
||||
|
||||
// Timer callback to send an RSSI update to a monitoring system
|
||||
static void ICACHE_FLASH_ATTR rssiTimerCb(void *v) {
|
||||
if (!flashConfig.rssi_enable || !flashConfig.tcp_enable || flashConfig.api_key[0]==0)
|
||||
return;
|
||||
if (!flashConfig.rssi_enable || !flashConfig.tcp_enable || flashConfig.api_key[0]==0)
|
||||
return;
|
||||
|
||||
sint8 rssi = wifi_station_get_rssi();
|
||||
os_printf("timer rssi=%d\n", rssi);
|
||||
if (rssi >= 0) return; // not connected or other error
|
||||
sint8 rssi = wifi_station_get_rssi();
|
||||
os_printf("timer rssi=%d\n", rssi);
|
||||
if (rssi >= 0) return; // not connected or other error
|
||||
|
||||
// compose TCP command
|
||||
uint8_t chan = MAX_TCP_CHAN-1;
|
||||
tcpClientCommand(chan, 'T', "grovestreams.com:80");
|
||||
// compose TCP command
|
||||
uint8_t chan = MAX_TCP_CHAN-1;
|
||||
tcpClientCommand(chan, 'T', "grovestreams.com:80");
|
||||
|
||||
// compose http header
|
||||
char buf[1024];
|
||||
int hdrLen = os_sprintf(buf,
|
||||
"PUT /api/feed?api_key=%s HTTP/1.0\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Content-Length: XXXXX\r\n\r\n",
|
||||
flashConfig.api_key);
|
||||
// compose http header
|
||||
char buf[1024];
|
||||
int hdrLen = os_sprintf(buf,
|
||||
"PUT /api/feed?api_key=%s HTTP/1.0\r\n"
|
||||
"Content-Type: application/json\r\n"
|
||||
"Content-Length: XXXXX\r\n\r\n",
|
||||
flashConfig.api_key);
|
||||
|
||||
// http body
|
||||
int dataLen = os_sprintf(buf+hdrLen,
|
||||
"[{\"compId\":\"%s\", \"streamId\":\"%s\", \"data\":%d}]\r",
|
||||
flashConfig.hostname, GS_STREAM, rssi);
|
||||
buf[hdrLen+dataLen++] = 0;
|
||||
buf[hdrLen+dataLen++] = '\n';
|
||||
// http body
|
||||
int dataLen = os_sprintf(buf+hdrLen,
|
||||
"[{\"compId\":\"%s\", \"streamId\":\"%s\", \"data\":%d}]\r",
|
||||
flashConfig.hostname, GS_STREAM, rssi);
|
||||
buf[hdrLen+dataLen++] = 0;
|
||||
buf[hdrLen+dataLen++] = '\n';
|
||||
|
||||
// hackish way to fill in the content-length
|
||||
os_sprintf(buf+hdrLen-9, "%5d", dataLen);
|
||||
buf[hdrLen-4] = '\r'; // fix-up the \0 inserted by sprintf (hack!)
|
||||
// hackish way to fill in the content-length
|
||||
os_sprintf(buf+hdrLen-9, "%5d", dataLen);
|
||||
buf[hdrLen-4] = '\r'; // fix-up the \0 inserted by sprintf (hack!)
|
||||
|
||||
// send the request off and forget about it...
|
||||
for (short i=0; i<hdrLen+dataLen; i++) {
|
||||
tcpClientSendChar(chan, buf[i]);
|
||||
}
|
||||
tcpClientSendPush(chan);
|
||||
// send the request off and forget about it...
|
||||
for (short i=0; i<hdrLen+dataLen; i++) {
|
||||
tcpClientSendChar(chan, buf[i]);
|
||||
}
|
||||
tcpClientSendPush(chan);
|
||||
}
|
||||
|
||||
//===== Init status stuff
|
||||
|
||||
void ICACHE_FLASH_ATTR statusInit(void) {
|
||||
if (flashConfig.conn_led_pin >= 0) {
|
||||
makeGpio(flashConfig.conn_led_pin);
|
||||
setLed(1);
|
||||
}
|
||||
os_printf("CONN led=%d\n", flashConfig.conn_led_pin);
|
||||
if (flashConfig.conn_led_pin >= 0) {
|
||||
makeGpio(flashConfig.conn_led_pin);
|
||||
setLed(1);
|
||||
}
|
||||
os_printf("CONN led=%d\n", flashConfig.conn_led_pin);
|
||||
|
||||
os_timer_disarm(&ledTimer);
|
||||
os_timer_setfn(&ledTimer, ledTimerCb, NULL);
|
||||
os_timer_arm(&ledTimer, 2000, 0);
|
||||
os_timer_disarm(&ledTimer);
|
||||
os_timer_setfn(&ledTimer, ledTimerCb, NULL);
|
||||
os_timer_arm(&ledTimer, 2000, 0);
|
||||
|
||||
os_timer_disarm(&rssiTimer);
|
||||
os_timer_setfn(&rssiTimer, rssiTimerCb, NULL);
|
||||
os_timer_arm(&rssiTimer, RSSI_INTERVAL, 1); // recurring timer
|
||||
os_timer_disarm(&rssiTimer);
|
||||
os_timer_setfn(&rssiTimer, rssiTimerCb, NULL);
|
||||
os_timer_arm(&rssiTimer, RSSI_INTERVAL, 1); // recurring timer
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1 +1,46 @@
|
||||
<!DOCTYPE html><script src='http://linux-ws/esplink/console.js'></script>
|
||||
<div id="main">
|
||||
<div class="header">
|
||||
<h1>Microcontroller Console</h1>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<p>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).</p>
|
||||
<p>
|
||||
<a id="reset-button" class="pure-button button-primary" href="#">Reset µC</a>
|
||||
Baud:
|
||||
<span id="baud-btns"></span>
|
||||
</p>
|
||||
<pre class="console" id="console"></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">console_url = "/console/text"</script>
|
||||
<script src="console.js"></script>
|
||||
<script type="text/javascript">
|
||||
var rates = [9600, 57600, 115200, 250000];
|
||||
|
||||
onLoad(function() {
|
||||
fetchText(100, true);
|
||||
|
||||
$("#reset-button").addEventListener("click", function(e) {
|
||||
e.preventDefault();
|
||||
var co = $("#console");
|
||||
co.innerHTML = "";
|
||||
ajaxSpin('POST', "/console/reset",
|
||||
function(resp) { showNotification("uC reset"); co.textEnd = 0; },
|
||||
function(s, st) { showWarning("Error resetting uC"); }
|
||||
);
|
||||
});
|
||||
|
||||
rates.forEach(function(r) { baudButton(r); });
|
||||
|
||||
ajaxJson('GET', "/console/baud",
|
||||
function(data) { showRate(data.rate); },
|
||||
function(s, st) { showNotification(st); }
|
||||
);
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
|
||||
99
html/mqtt.html
Normal file
99
html/mqtt.html
Normal file
@@ -0,0 +1,99 @@
|
||||
<div id="main">
|
||||
<div class="header">
|
||||
<h1>REST & MQTT</h1>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1"><div class="card">
|
||||
<p>The REST & MQTT support uses the SLIP protocol over the serial port to enable
|
||||
the attached microcontroller to initiate outbound connections.
|
||||
The REST support lets the uC initiate simple HTTP requests while the MQTT support
|
||||
lets it communicate with an MQTT server bidirectionally at QoS 0 thru 2.</p>
|
||||
<p>The MQTT support is in the form of a built-in client that connects to a server
|
||||
using parameters set below and stored in esp-link's flash settings. This allows
|
||||
esp-link to take care of connection parameters and disconnect/reconnect operations.</p>
|
||||
<p>The MQTT client also supports sending periodic status messages about esp-link itself,
|
||||
including Wifi RSSI, and free heap memory.</p>
|
||||
<div class="form-horizontal">
|
||||
<input type="checkbox" name="slip-enable"/>
|
||||
<label>Enable SLIP on serial port</label>
|
||||
</div>
|
||||
</div></div>
|
||||
</div>
|
||||
<div class="pure-g">
|
||||
<div class="pure-u-1 pure-u-md-1-2">
|
||||
<div class="card">
|
||||
<h1>MQTT
|
||||
<div id="mqtt-spinner" class="spinner spinner-small"></div>
|
||||
</h1>
|
||||
<form action="#" id="mqtt-form" class="pure-form" hidden>
|
||||
<div class="form-horizontal">
|
||||
<input type="checkbox" name="mqtt-enable"/>
|
||||
<label>Enable MQTT client</label>
|
||||
</div>
|
||||
<div class="form-horizontal">
|
||||
<label>MQTT client state: </label>
|
||||
<b id="mqtt-state"></b>
|
||||
</div>
|
||||
<br>
|
||||
<legend>MQTT server settings</legend>
|
||||
<div class="pure-form-stacked">
|
||||
<label>Server hostname/ip</label>
|
||||
<input type="text" name="mqtt-host"/>
|
||||
<label>Server port/ip</label>
|
||||
<input type="text" name="mqtt-port"/>
|
||||
<label>Client ID</label>
|
||||
<input type="text" name="mqtt-client-id"/>
|
||||
<label>Username</label>
|
||||
<input type="text" name="mqtt-username"/>
|
||||
<label>Password</label>
|
||||
<input type="password" name="mqtt-password"/>
|
||||
</div>
|
||||
<button id="mqtt-button" type="submit" class="pure-button button-primary">
|
||||
Update server settings!
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pure-u-1 pure-u-md-1-2">
|
||||
<div class="card">
|
||||
<h1>Status reporting
|
||||
<div id="mqtt-status-spinner" class="spinner spinner-small"></div>
|
||||
</h1>
|
||||
<form action="#" id="mqtt-status-form" class="pure-form" hidden>
|
||||
<div class="form-horizontal">
|
||||
<input type="checkbox" name="mqtt-status-enable"/>
|
||||
<label>Enable status reporting via MQTT</label>
|
||||
</div>
|
||||
<br>
|
||||
<legend>Status reporting settings</legend>
|
||||
<div class="pure-form-stacked">
|
||||
<label>Topic prefix</label>
|
||||
<input type="text" name="mqtt-status-topic"/>
|
||||
Suffixes: rssi, heap-free, ...
|
||||
</div>
|
||||
<button id="mqtt-status-button" type="submit" class="pure-button button-primary">
|
||||
Update status settings!
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h1>REST</h1>
|
||||
<p>REST requests are enabled as soon as SLIP is enabled.
|
||||
There are no REST-specific settings.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
onLoad(function() {
|
||||
fetchMqtt();
|
||||
bnd($("#mqtt-form"), "submit", changeMqtt);
|
||||
bnd($("#mqtt-status-form"), "submit", changeMqttStatus);
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
384
html/style.css
Normal file
384
html/style.css
Normal file
@@ -0,0 +1,384 @@
|
||||
/* All fonts */
|
||||
html, button, input, select, textarea, .pure-g [class *= "pure-u"] {
|
||||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
input[type="text"], input[type="password"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
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 `<div>` 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 `<div>` */
|
||||
.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);
|
||||
}
|
||||
}
|
||||
473
html/ui.js
Normal file
473
html/ui.js
Normal file
@@ -0,0 +1,473 @@
|
||||
//===== 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('<h1>Hello</h1>');
|
||||
* document.body.appendChild(el);
|
||||
*
|
||||
* Copyright (C) 2011 Jed Schmidt <http://jed.is> - 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 <http://jed.is> - 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 <http://jed.is>
|
||||
* 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<l; i++) {
|
||||
if (cls[i] === cl) cls.splice(i, 1);
|
||||
}
|
||||
el.className = cls.join(' ');
|
||||
return cls.length != l
|
||||
}
|
||||
function toggleClass(el, cl) {
|
||||
if (!removeClass(el, cl)) addClass(el, cl);
|
||||
}
|
||||
|
||||
//===== AJAX
|
||||
|
||||
function ajaxReq(method, url, ok_cb, err_cb) {
|
||||
var xhr = j();
|
||||
xhr.open(method, url, true);
|
||||
var timeout = setTimeout(function() {
|
||||
xhr.abort();
|
||||
console.log("XHR abort:", method, url);
|
||||
xhr.status = 599;
|
||||
xhr.responseText = "request time-out";
|
||||
}, 9000);
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState != 4) { return; }
|
||||
clearTimeout(timeout);
|
||||
if (xhr.status >= 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('<div id="spinner" class="spinner" hidden></div>'), o);
|
||||
// notification boxes
|
||||
l.insertBefore(m(
|
||||
'<div id="messages"><div id="warning" hidden></div><div id="notification" hidden></div></div>'), o);
|
||||
// menu hamburger button
|
||||
l.insertBefore(m('<a href="#menu" id="menuLink" class="menu-link"><span></span></a>'), o);
|
||||
// menu left-pane
|
||||
var mm = m(
|
||||
'<div id="menu">\
|
||||
<div class="pure-menu">\
|
||||
<a class="pure-menu-heading" href="https://github.com/jeelabs/esp-link">\
|
||||
<img src="/favicon.ico" height="32"> esp-link</a>\
|
||||
<ul id="menu-list" class="pure-menu-list"></ul>\
|
||||
</div>\
|
||||
</div>\
|
||||
');
|
||||
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.length; i+=2) {
|
||||
var href = data.menu[i+1];
|
||||
html = html.concat(" <li class=\"pure-menu-item" +
|
||||
(path === href ? " pure-menu-selected" : "") + "\">" +
|
||||
"<a href=\"" + href + "\" class=\"pure-menu-link\">" +
|
||||
data.menu[i] + "</a></li>");
|
||||
}
|
||||
$("#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('<label for="opt-'+pin.value+'"><b>'+pin.name+":</b>"+pin.descr+"</label>");
|
||||
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<inputs.length; i++) {
|
||||
inputs[i].onclick = function() { setPins(this.value, this.data) };
|
||||
};
|
||||
}
|
||||
|
||||
function fetchPins() {
|
||||
ajaxJson("GET", "/pins", displayPins, function() {
|
||||
window.setTimeout(fetchPins, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
function setPins(v, name) {
|
||||
ajaxSpin("POST", "/pins?map="+v, function() {
|
||||
showNotification("Pin assignment changed to " + name);
|
||||
}, function() {
|
||||
showNotification("Pin assignment change failed");
|
||||
window.setTimeout(fetchPins, 100);
|
||||
});
|
||||
}
|
||||
|
||||
//===== TCP client card
|
||||
|
||||
function tcpEn(){return document.querySelector('input[name="tcp_enable"]')}
|
||||
function rssiEn(){return document.querySelector('input[name="rssi_enable"]')}
|
||||
function apiKey(){return document.querySelector('input[name="api_key"]')}
|
||||
|
||||
function changeTcpClient(e) {
|
||||
e.preventDefault();
|
||||
var url = "tcpclient";
|
||||
url += "?tcp_enable=" + tcpEn().checked;
|
||||
url += "&rssi_enable=" + rssiEn().checked;
|
||||
url += "&api_key=" + encodeURIComponent(apiKey().value);
|
||||
|
||||
hideWarning();
|
||||
var cb = $("#tcp-button");
|
||||
addClass(cb, 'pure-button-disabled');
|
||||
ajaxSpin("POST", url, function(resp) {
|
||||
removeClass(cb, 'pure-button-disabled');
|
||||
fetchTcpClient();
|
||||
}, function(s, st) {
|
||||
showWarning("Error: "+st);
|
||||
removeClass(cb, 'pure-button-disabled');
|
||||
fetchTcpClient();
|
||||
});
|
||||
}
|
||||
|
||||
function displayTcpClient(resp) {
|
||||
tcpEn().checked = resp.tcp_enable > 0;
|
||||
rssiEn().checked = resp.rssi_enable > 0;
|
||||
apiKey().value = resp.api_key;
|
||||
}
|
||||
|
||||
function fetchTcpClient() {
|
||||
ajaxJson("GET", "/tcpclient", displayTcpClient, function() {
|
||||
window.setTimeout(fetchTcpClient, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
//===== MQTT cards
|
||||
|
||||
function changeMqtt(e) {
|
||||
e.preventDefault();
|
||||
var url = "mqtt?1=1";
|
||||
var i, inputs = document.querySelectorAll('#mqtt-form input');
|
||||
for (i=0; i<inputs.length; i++) {
|
||||
if (inputs[i].type != "checkbox")
|
||||
url += "&" + inputs[i].name + "=" + inputs[i].value;
|
||||
};
|
||||
|
||||
hideWarning();
|
||||
var cb = $("#mqtt-button");
|
||||
addClass(cb, 'pure-button-disabled');
|
||||
ajaxSpin("POST", url, function(resp) {
|
||||
showNotification("MQTT updated");
|
||||
removeClass(cb, 'pure-button-disabled');
|
||||
}, function(s, st) {
|
||||
showWarning("Error: "+st);
|
||||
removeClass(cb, 'pure-button-disabled');
|
||||
window.setTimeout(fetchMqtt, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function displayMqtt(data) {
|
||||
Object.keys(data).forEach(function(v) {
|
||||
el = $("#" + v);
|
||||
if (el != null) {
|
||||
if (el.nodeName === "INPUT") el.value = data[v];
|
||||
else el.innerHTML = data[v];
|
||||
return;
|
||||
}
|
||||
el = document.querySelector('input[name="' + v + '"]');
|
||||
if (el != null) {
|
||||
if (el.type == "checkbox") el.checked = data[v] > 0;
|
||||
else el.value = data[v];
|
||||
}
|
||||
});
|
||||
$("#mqtt-spinner").setAttribute("hidden", "");
|
||||
$("#mqtt-status-spinner").setAttribute("hidden", "");
|
||||
$("#mqtt-form").removeAttribute("hidden");
|
||||
$("#mqtt-status-form").removeAttribute("hidden");
|
||||
|
||||
var i, inputs = $("input");
|
||||
for (i=0; i<inputs.length; i++) {
|
||||
if (inputs[i].type == "checkbox")
|
||||
inputs[i].onclick = function() { console.log(this); setMqtt(this.name, this.checked) };
|
||||
}
|
||||
}
|
||||
|
||||
function fetchMqtt() {
|
||||
ajaxJson("GET", "/mqtt", displayMqtt, function() {
|
||||
window.setTimeout(fetchMqtt, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
function changeMqttStatus(e) {
|
||||
e.preventDefault();
|
||||
var v = document.querySelector('input[name="mqtt-status-topic"]').value;
|
||||
ajaxSpin("POST", "/mqtt?mqtt-status-topic=" + v, function() {
|
||||
showNotification("MQTT status settings updated");
|
||||
}, function(s, st) {
|
||||
showWarning("Error: "+st);
|
||||
window.setTimeout(fetchMqtt, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function setMqtt(name, v) {
|
||||
ajaxSpin("POST", "/mqtt?" + name + "=" + (v ? 1 : 0), function() {
|
||||
var n = name.replace("-enable", "");
|
||||
showNotification(n + " is now " + (v ? "enabled" : "disabled"));
|
||||
}, function() {
|
||||
showWarning("Enable/disable failed");
|
||||
window.setTimeout(fetchMqtt, 100);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -92,9 +92,7 @@ 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);
|
||||
#ifdef HTTPD_DBG
|
||||
os_printf("%s %s\n", connStr, what);
|
||||
#endif
|
||||
//os_printf("%s %s\n", connStr, what);
|
||||
}
|
||||
|
||||
//Looks up the connData info for a specific esp connection
|
||||
@@ -104,7 +102,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)
|
||||
{
|
||||
#ifdef HTTPD_DBG
|
||||
#if 0
|
||||
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);
|
||||
@@ -114,9 +112,7 @@ 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;
|
||||
}
|
||||
|
||||
@@ -134,10 +130,8 @@ 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.
|
||||
@@ -186,24 +180,18 @@ 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) {
|
||||
#ifdef HTTPD_DBG
|
||||
os_printf("findArg: %s\n", p);
|
||||
#endif
|
||||
//os_printf("findArg: %s\n", p);
|
||||
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);
|
||||
#ifdef HTTPD_DBG
|
||||
os_printf("findArg: val %s len %d\n", p, (e-p));
|
||||
#endif
|
||||
//os_printf("findArg: val %s len %d\n", p, (e-p));
|
||||
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
|
||||
//os_printf("Finding %s in %s: Not found :/\n", arg, line);
|
||||
return -1; //not found
|
||||
}
|
||||
|
||||
@@ -284,10 +272,8 @@ 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);
|
||||
@@ -300,9 +286,7 @@ 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;
|
||||
}
|
||||
@@ -320,9 +304,7 @@ static void ICACHE_FLASH_ATTR httpdSentCb(void *arg) {
|
||||
conn->priv->sendBuffLen=0;
|
||||
|
||||
if (conn->cgi==NULL) { //Marked for destruction?
|
||||
#ifdef HTTPD_DBG
|
||||
os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn);
|
||||
#endif
|
||||
//os_printf("Closing 0x%p/0x%p->0x%p\n", arg, conn->conn, conn);
|
||||
espconn_disconnect(conn->conn); // we will get a disconnect callback
|
||||
return; //No need to call xmitSendBuff.
|
||||
}
|
||||
@@ -332,9 +314,7 @@ 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);
|
||||
@@ -350,9 +330,7 @@ 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.
|
||||
@@ -366,9 +344,7 @@ 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) {
|
||||
#ifdef HTTPD_DBG
|
||||
os_printf("Is url index %d\n", i);
|
||||
#endif
|
||||
//os_printf("Is url index %d\n", i);
|
||||
conn->cgiData=NULL;
|
||||
conn->cgi=builtInUrls[i].cgiCb;
|
||||
conn->cgiArg=builtInUrls[i].cgiArg;
|
||||
@@ -379,9 +355,7 @@ 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
|
||||
@@ -437,18 +411,15 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
|
||||
// Count number of open connections
|
||||
int open = 0;
|
||||
for (int j=0; j<MAX_CONN; j++) if (connData[j].conn != NULL) open++;
|
||||
#ifdef HTTPD_DBG
|
||||
|
||||
os_printf("%s %s %s (%d conn open)\n", connStr,
|
||||
conn->requestType == 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;
|
||||
}
|
||||
@@ -467,9 +438,7 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
|
||||
} else {
|
||||
conn->post->buffSize = conn->post->len;
|
||||
}
|
||||
#ifdef HTTPD_DBG
|
||||
os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize);
|
||||
#endif
|
||||
//os_printf("Mallocced buffer for %d + 1 bytes of post data.\n", conn->post->buffSize);
|
||||
conn->post->buff=(char*)os_malloc(conn->post->buffSize + 1);
|
||||
conn->post->buffLen=0;
|
||||
} else if (os_strncmp(h, "Content-Type: ", 14)==0) {
|
||||
@@ -480,9 +449,7 @@ 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] = '-';
|
||||
#ifdef HTTPD_DBG
|
||||
os_printf("boundary = %s\n", conn->post->multipartBoundary);
|
||||
#endif
|
||||
//os_printf("boundary = %s\n", conn->post->multipartBoundary);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -554,13 +521,11 @@ static void ICACHE_FLASH_ATTR httpdDisconCb(void *arg) {
|
||||
}
|
||||
|
||||
// Callback indicating a failure in the connection. "Recon" is probably intended in the sense
|
||||
// of "you need to reconnect". Sigh... Note that there is no DiconCb after ReconCb
|
||||
// of "you need to reconnect". Sigh... Note that there is no DisconCb after ReconCb
|
||||
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);
|
||||
}
|
||||
@@ -572,18 +537,14 @@ static void ICACHE_FLASH_ATTR httpdConnectCb(void *arg) {
|
||||
int i;
|
||||
//Find empty conndata in pool
|
||||
for (i=0; i<MAX_CONN; i++) if (connData[i].conn==NULL) break;
|
||||
#ifdef HTTPD_DBG
|
||||
os_printf("Con req, conn=%p, pool slot %d\n", conn, i);
|
||||
#endif
|
||||
//os_printf("Con req, conn=%p, pool slot %d\n", conn, i);
|
||||
if (i==MAX_CONN) {
|
||||
#ifdef HTTPD_DBG
|
||||
os_printf("%s Aiee, conn pool overflow!\n", connStr);
|
||||
#endif
|
||||
espconn_disconnect(conn);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HTTPD_DBG
|
||||
#if 0
|
||||
int num = 0;
|
||||
for (int j=0; j<MAX_CONN; j++) if (connData[j].conn != NULL) num++;
|
||||
os_printf("%s Connect (%d open)\n", connStr, num+1);
|
||||
@@ -621,9 +582,8 @@ void ICACHE_FLASH_ATTR httpdInit(HttpdBuiltInUrl *fixedUrls, int port) {
|
||||
httpdTcp.local_port=port;
|
||||
httpdConn.proto.tcp=&httpdTcp;
|
||||
builtInUrls=fixedUrls;
|
||||
#ifdef HTTPD_DBG
|
||||
|
||||
os_printf("Httpd init, conn=%p\n", &httpdConn);
|
||||
#endif
|
||||
espconn_regist_connectcb(&httpdConn, httpdConnectCb);
|
||||
espconn_accept(&httpdConn);
|
||||
espconn_tcp_set_max_con_allow(&httpdConn, MAX_CONN);
|
||||
|
||||
1071
mqtt/mqtt.c
1071
mqtt/mqtt.c
File diff suppressed because it is too large
Load Diff
177
mqtt/mqtt.h
177
mqtt/mqtt.h
@@ -27,118 +27,101 @@
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef USER_AT_MQTT_H_
|
||||
#define USER_AT_MQTT_H_
|
||||
#ifndef MQTT_H_
|
||||
#define MQTT_H_
|
||||
|
||||
#include <esp8266.h>
|
||||
#include "mqtt_msg.h"
|
||||
#include "queue.h"
|
||||
#include <rest.h>
|
||||
#include "pktbuf.h"
|
||||
|
||||
typedef struct mqtt_event_data_t {
|
||||
uint8_t type;
|
||||
const char* topic;
|
||||
const char* data;
|
||||
uint16_t topic_length;
|
||||
uint16_t data_length;
|
||||
uint16_t data_offset;
|
||||
} mqtt_event_data_t;
|
||||
|
||||
typedef struct mqtt_state_t {
|
||||
uint16_t port;
|
||||
int auto_reconnect;
|
||||
mqtt_connect_info_t* connect_info;
|
||||
uint8_t* in_buffer;
|
||||
uint8_t* out_buffer;
|
||||
int in_buffer_length;
|
||||
int out_buffer_length;
|
||||
uint16_t message_length;
|
||||
uint16_t message_length_read;
|
||||
mqtt_message_t* outbound_message;
|
||||
mqtt_connection_t mqtt_connection;
|
||||
uint16_t pending_msg_id;
|
||||
int pending_msg_type;
|
||||
int pending_publish_qos;
|
||||
} mqtt_state_t;
|
||||
// in rest.c
|
||||
uint8_t UTILS_StrToIP(const char* str, void *ip);
|
||||
|
||||
// State of MQTT connection
|
||||
typedef enum {
|
||||
WIFI_INIT,
|
||||
WIFI_CONNECTING,
|
||||
WIFI_CONNECTING_ERROR,
|
||||
WIFI_CONNECTED,
|
||||
DNS_RESOLVE,
|
||||
TCP_DISCONNECTED,
|
||||
TCP_RECONNECT_REQ,
|
||||
TCP_RECONNECT,
|
||||
TCP_CONNECTING,
|
||||
TCP_CONNECTING_ERROR,
|
||||
TCP_CONNECTED,
|
||||
MQTT_CONNECT_SEND,
|
||||
MQTT_CONNECT_SENDING,
|
||||
MQTT_SUBSCIBE_SEND,
|
||||
MQTT_SUBSCIBE_SENDING,
|
||||
MQTT_DATA,
|
||||
MQTT_PUBLISH_RECV,
|
||||
MQTT_PUBLISHING
|
||||
MQTT_DISCONNECTED, // we're in disconnected state
|
||||
TCP_RECONNECT_REQ, // connect failed, needs reconnecting
|
||||
TCP_CONNECTING, // in TCP connection process
|
||||
MQTT_CONNECTED, // conneted (or connecting)
|
||||
} tConnState;
|
||||
|
||||
// Simple notification callback
|
||||
typedef void (*MqttCallback)(uint32_t* args);
|
||||
typedef void (*MqttDataCallback)(uint32_t* args, const char* topic, uint32_t topic_len, const char* data, uint32_t lengh);
|
||||
// Callback with data messge
|
||||
typedef void (*MqttDataCallback)(uint32_t* args, const char* topic, uint32_t topic_len,
|
||||
const char* data, uint32_t data_len);
|
||||
|
||||
// MQTTY client data structure
|
||||
typedef struct {
|
||||
struct espconn* pCon;
|
||||
uint8_t security;
|
||||
char* host;
|
||||
uint32_t port;
|
||||
ip_addr_t ip;
|
||||
mqtt_state_t mqtt_state;
|
||||
mqtt_connect_info_t connect_info;
|
||||
MqttCallback connectedCb;
|
||||
MqttCallback cmdConnectedCb;
|
||||
MqttCallback disconnectedCb;
|
||||
MqttCallback cmdDisconnectedCb;
|
||||
MqttCallback tcpDisconnectedCb;
|
||||
MqttCallback cmdTcpDisconnectedCb;
|
||||
MqttCallback publishedCb;
|
||||
MqttCallback cmdPublishedCb;
|
||||
MqttDataCallback dataCb;
|
||||
MqttDataCallback cmdDataCb;
|
||||
ETSTimer mqttTimer;
|
||||
uint32_t keepAliveTick;
|
||||
uint32_t reconnectTick;
|
||||
uint32_t sendTimeout;
|
||||
tConnState connState;
|
||||
QUEUE msgQueue;
|
||||
void* user_data;
|
||||
struct espconn* pCon; // socket
|
||||
// connection information
|
||||
char* host; // MQTT server
|
||||
uint16_t port;
|
||||
uint8_t security; // 0=tcp, 1=ssl
|
||||
ip_addr_t ip; // MQTT server IP address
|
||||
mqtt_connect_info_t connect_info; // info to connect/reconnect
|
||||
// protocol state and message assembly
|
||||
tConnState connState; // connection state
|
||||
bool sending; // espconn_send is pending
|
||||
mqtt_connection_t mqtt_connection; // message assembly descriptor
|
||||
PktBuf* msgQueue; // queued outbound messages
|
||||
// TCP input buffer
|
||||
uint8_t* in_buffer;
|
||||
int in_buffer_size; // length allocated
|
||||
int in_buffer_filled; // number of bytes held
|
||||
// outstanding message when we expect an ACK
|
||||
PktBuf* pending_buffer; // buffer sent and awaiting ACK
|
||||
PktBuf* sending_buffer; // buffer sent not awaiting ACK
|
||||
// timer and associated timeout counters
|
||||
ETSTimer mqttTimer; // timer for this connection
|
||||
uint8_t keepAliveTick; // seconds 'til keep-alive is required (0=no k-a)
|
||||
uint8_t keepAliveAckTick; // seconds 'til keep-alive ack is overdue (0=no k-a)
|
||||
uint8_t timeoutTick; // seconds 'til other timeout
|
||||
uint8_t sendTimeout; // value of send timeout setting
|
||||
// callbacks
|
||||
MqttCallback connectedCb;
|
||||
MqttCallback cmdConnectedCb;
|
||||
MqttCallback disconnectedCb;
|
||||
MqttCallback cmdDisconnectedCb;
|
||||
MqttCallback tcpDisconnectedCb;
|
||||
MqttCallback cmdTcpDisconnectedCb;
|
||||
MqttCallback publishedCb;
|
||||
MqttCallback cmdPublishedCb;
|
||||
MqttDataCallback dataCb;
|
||||
MqttDataCallback cmdDataCb;
|
||||
// misc
|
||||
void* user_data;
|
||||
} MQTT_Client;
|
||||
|
||||
#define SEC_NONSSL 0
|
||||
#define SEC_SSL 1
|
||||
// Initialize client data structure
|
||||
void MQTT_Init(MQTT_Client* mqttClient, char* host, uint32 port,
|
||||
uint8_t security, uint8_t sendTimeout,
|
||||
char* client_id, char* client_user, char* client_pass,
|
||||
uint8_t keepAliveTime, uint8_t cleanSession);
|
||||
|
||||
#define MQTT_FLAG_CONNECTED 1
|
||||
#define MQTT_FLAG_READY 2
|
||||
#define MQTT_FLAG_EXIT 4
|
||||
// Set Last Will Topic on client, must be called before MQTT_InitConnection
|
||||
void MQTT_InitLWT(MQTT_Client* mqttClient, char* will_topic, char* will_msg,
|
||||
uint8_t will_qos, uint8_t will_retain);
|
||||
|
||||
#define MQTT_EVENT_TYPE_NONE 0
|
||||
#define MQTT_EVENT_TYPE_CONNECTED 1
|
||||
#define MQTT_EVENT_TYPE_DISCONNECTED 2
|
||||
#define MQTT_EVENT_TYPE_SUBSCRIBED 3
|
||||
#define MQTT_EVENT_TYPE_UNSUBSCRIBED 4
|
||||
#define MQTT_EVENT_TYPE_PUBLISH 5
|
||||
#define MQTT_EVENT_TYPE_PUBLISHED 6
|
||||
#define MQTT_EVENT_TYPE_EXITED 7
|
||||
#define MQTT_EVENT_TYPE_PUBLISH_CONTINUATION 8
|
||||
|
||||
void MQTT_InitConnection(MQTT_Client* mqttClient, char* host, uint32 port, uint8_t security);
|
||||
void MQTT_InitClient(MQTT_Client* mqttClient, char* client_id, char* client_user, char* client_pass, uint8_t keepAliveTime, uint8_t cleanSession);
|
||||
void MQTT_InitLWT(MQTT_Client* mqttClient, char* will_topic, char* will_msg, uint8_t will_qos, uint8_t will_retain);
|
||||
void MQTT_OnConnected(MQTT_Client* mqttClient, MqttCallback connectedCb);
|
||||
void MQTT_OnDisconnected(MQTT_Client* mqttClient, MqttCallback disconnectedCb);
|
||||
void MQTT_OnPublished(MQTT_Client* mqttClient, MqttCallback publishedCb);
|
||||
void MQTT_OnData(MQTT_Client* mqttClient, MqttDataCallback dataCb);
|
||||
bool MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos);
|
||||
// Kick of a persistent connection to the broker, will reconnect anytime conn breaks
|
||||
void MQTT_Connect(MQTT_Client* mqttClient);
|
||||
|
||||
// Kill persistent connection
|
||||
void MQTT_Disconnect(MQTT_Client* mqttClient);
|
||||
bool MQTT_Publish(MQTT_Client* client, const char* topic, const char* data, uint8_t qos, uint8_t retain);
|
||||
|
||||
// Subscribe to a topic
|
||||
bool MQTT_Subscribe(MQTT_Client* client, char* topic, uint8_t qos);
|
||||
|
||||
// Publish a message
|
||||
bool MQTT_Publish(MQTT_Client* client, const char* topic, const char* data,
|
||||
uint8_t qos, uint8_t retain);
|
||||
|
||||
// Callback when connected
|
||||
void MQTT_OnConnected(MQTT_Client* mqttClient, MqttCallback connectedCb);
|
||||
// Callback when disconnected
|
||||
void MQTT_OnDisconnected(MQTT_Client* mqttClient, MqttCallback disconnectedCb);
|
||||
// Callback when publish succeeded
|
||||
void MQTT_OnPublished(MQTT_Client* mqttClient, MqttCallback publishedCb);
|
||||
// Callback when data arrives for subscription
|
||||
void MQTT_OnData(MQTT_Client* mqttClient, MqttDataCallback dataCb);
|
||||
|
||||
#endif /* USER_AT_MQTT_H_ */
|
||||
|
||||
116
mqtt/mqtt_cmd.c
116
mqtt/mqtt_cmd.c
@@ -1,18 +1,18 @@
|
||||
#include <esp8266.h>
|
||||
#include "mqtt.h"
|
||||
#include "mqtt_cmd.h"
|
||||
|
||||
uint32_t connectedCb = 0, disconnectCb = 0, tcpDisconnectedCb = 0, publishedCb = 0, dataCb = 0;
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
void ICACHE_FLASH_ATTR
|
||||
cmdMqttConnectedCb(uint32_t* args) {
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
MqttCmdCb* cb = (MqttCmdCb*)client->user_data;
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("cmdMqttConnectedCb: connectedCb=%p, disconnectedCb=%p, publishedCb=%p, dataCb=%p\n",
|
||||
os_printf("MQTT: Connected 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);
|
||||
}
|
||||
@@ -21,50 +21,42 @@ void ICACHE_FLASH_ATTR
|
||||
cmdMqttTcpDisconnectedCb(uint32_t *args) {
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
MqttCmdCb *cb = (MqttCmdCb*)client->user_data;
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("cmdMqttTcpDisconnectedCb\n");
|
||||
#endif
|
||||
os_printf("MQTT: TCP Disconnected\n");
|
||||
uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->tcpDisconnectedCb, 0, 0);
|
||||
CMD_ResponseEnd(crc);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
void ICACHE_FLASH_ATTR
|
||||
cmdMqttDisconnectedCb(uint32_t* args) {
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
MqttCmdCb* cb = (MqttCmdCb*)client->user_data;
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("cmdMqttDisconnectedCb\n");
|
||||
#endif
|
||||
os_printf("MQTT: Disconnected\n");
|
||||
uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->disconnectedCb, 0, 0);
|
||||
CMD_ResponseEnd(crc);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
void ICACHE_FLASH_ATTR
|
||||
cmdMqttPublishedCb(uint32_t* args) {
|
||||
MQTT_Client* client = (MQTT_Client*)args;
|
||||
MqttCmdCb* cb = (MqttCmdCb*)client->user_data;
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("cmdMqttPublishedCb\n");
|
||||
#endif
|
||||
os_printf("MQTT: Published\n");
|
||||
uint16_t crc = CMD_ResponseStart(CMD_MQTT_EVENTS, cb->publishedCb, 0, 0);
|
||||
CMD_ResponseEnd(crc);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
void ICACHE_FLASH_ATTR
|
||||
cmdMqttDataCb(uint32_t* args, const char* topic, uint32_t topic_len, const char* data, uint32_t data_len) {
|
||||
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);
|
||||
CMD_ResponseEnd(crc);
|
||||
}
|
||||
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
MQTTCMD_Setup(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
CMD_Request(&req, cmd);
|
||||
@@ -75,10 +67,12 @@ MQTTCMD_Setup(CmdPacket *cmd) {
|
||||
// create mqtt client
|
||||
uint8_t clientLen = sizeof(MQTT_Client);
|
||||
MQTT_Client* client = (MQTT_Client*)os_zalloc(clientLen);
|
||||
if (client == NULL)
|
||||
return 0;
|
||||
if (client == NULL) return 0;
|
||||
os_memset(client, 0, clientLen);
|
||||
|
||||
return 0;
|
||||
#if 0
|
||||
|
||||
uint16_t len;
|
||||
uint8_t *client_id, *user_data, *pass_data;
|
||||
uint32_t keepalive, clean_session, cb_data;
|
||||
@@ -109,10 +103,10 @@ MQTTCMD_Setup(CmdPacket *cmd) {
|
||||
|
||||
// get clean session
|
||||
CMD_PopArg(&req, (uint8_t*)&clean_session, 4);
|
||||
#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
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -122,11 +116,11 @@ MQTTCMD_Setup(CmdPacket *cmd) {
|
||||
CMD_PopArg(&req, (uint8_t*)&cb_data, 4);
|
||||
callback->connectedCb = cb_data;
|
||||
CMD_PopArg(&req, (uint8_t*)&cb_data, 4);
|
||||
callback->disconnectedCb = cb_data;
|
||||
callback->disconnectedCb = cb_data;
|
||||
CMD_PopArg(&req, (uint8_t*)&cb_data, 4);
|
||||
callback->publishedCb = cb_data;
|
||||
CMD_PopArg(&req, (uint8_t*)&cb_data, 4);
|
||||
callback->dataCb = cb_data;
|
||||
callback->dataCb = cb_data;
|
||||
|
||||
client->user_data = callback;
|
||||
|
||||
@@ -146,9 +140,10 @@ MQTTCMD_Setup(CmdPacket *cmd) {
|
||||
os_free(pass_data);
|
||||
|
||||
return (uint32_t)client;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
MQTTCMD_Lwt(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
CMD_Request(&req, cmd);
|
||||
@@ -160,11 +155,10 @@ MQTTCMD_Lwt(CmdPacket *cmd) {
|
||||
uint32_t client_ptr;
|
||||
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
|
||||
MQTT_Client* client = (MQTT_Client*)client_ptr;
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("MQTTCMD_Lwt: client ptr=%p\n", (void*)client_ptr);
|
||||
#endif
|
||||
os_printf("MQTT: MQTTCMD_Lwt client ptr=%p\n", (void*)client_ptr);
|
||||
|
||||
uint16_t len;
|
||||
|
||||
|
||||
// get topic
|
||||
if (client->connect_info.will_topic)
|
||||
os_free(client->connect_info.will_topic);
|
||||
@@ -185,37 +179,35 @@ MQTTCMD_Lwt(CmdPacket *cmd) {
|
||||
|
||||
// get qos
|
||||
CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_qos, 4);
|
||||
|
||||
|
||||
// get retain
|
||||
CMD_PopArg(&req, (uint8_t*)&client->connect_info.will_retain, 4);
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("MQTTCMD_Lwt: topic=%s, message=%s, qos=%d, retain=%d\n",
|
||||
|
||||
os_printf("MQTT: 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;
|
||||
}
|
||||
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
MQTTCMD_Connect(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
CMD_Request(&req, cmd);
|
||||
|
||||
if (CMD_GetArgc(&req) != 4)
|
||||
return 0;
|
||||
return 0;
|
||||
|
||||
// get mqtt client
|
||||
uint32_t client_ptr;
|
||||
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
|
||||
MQTT_Client* client = (MQTT_Client*)client_ptr;
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("MQTTCMD_Connect: client ptr=%p\n", (void*)client_ptr);
|
||||
#endif
|
||||
os_printf("MQTT: MQTTCMD_Connect client ptr=%p\n", (void*)client_ptr);
|
||||
|
||||
uint16_t len;
|
||||
|
||||
// get host
|
||||
// get host
|
||||
if (client->host)
|
||||
os_free(client->host);
|
||||
len = CMD_ArgLen(&req);
|
||||
@@ -229,17 +221,17 @@ MQTTCMD_Connect(CmdPacket *cmd) {
|
||||
|
||||
// get security
|
||||
CMD_PopArg(&req, (uint8_t*)&client->security, 4);
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("MQTTCMD_Connect: host=%s, port=%ld, security=%d\n",
|
||||
|
||||
os_printf("MQTT: MQTTCMD_Connect host=%s, port=%d, security=%d\n",
|
||||
client->host,
|
||||
client->port,
|
||||
client->security);
|
||||
#endif
|
||||
|
||||
MQTT_Connect(client);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
MQTTCMD_Disconnect(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
CMD_Request(&req, cmd);
|
||||
@@ -251,15 +243,14 @@ MQTTCMD_Disconnect(CmdPacket *cmd) {
|
||||
uint32_t client_ptr;
|
||||
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
|
||||
MQTT_Client* client = (MQTT_Client*)client_ptr;
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("MQTTCMD_Disconnect: client ptr=%p\n", (void*)client_ptr);
|
||||
#endif
|
||||
os_printf("MQTT: MQTTCMD_Disconnect client ptr=%p\n", (void*)client_ptr);
|
||||
|
||||
// disconnect
|
||||
MQTT_Disconnect(client);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
MQTTCMD_Publish(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
CMD_Request(&req, cmd);
|
||||
@@ -271,9 +262,8 @@ MQTTCMD_Publish(CmdPacket *cmd) {
|
||||
uint32_t client_ptr;
|
||||
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
|
||||
MQTT_Client* client = (MQTT_Client*)client_ptr;
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("MQTTCMD_Publish: client ptr=%p\n", (void*)client_ptr);
|
||||
#endif
|
||||
os_printf("MQTT: MQTTCMD_Publish client ptr=%p\n", (void*)client_ptr);
|
||||
|
||||
uint16_t len;
|
||||
uint8_t *topic, *data;
|
||||
uint32_t qos = 0, retain = 0, data_len;
|
||||
@@ -294,7 +284,7 @@ MQTTCMD_Publish(CmdPacket *cmd) {
|
||||
// TODO: next line not originally present
|
||||
data[len] = 0;
|
||||
|
||||
// get data length
|
||||
// get data length
|
||||
// TODO: this isn't used but we have to pull it off the stack
|
||||
CMD_PopArg(&req, (uint8_t*)&data_len, 4);
|
||||
|
||||
@@ -303,20 +293,20 @@ MQTTCMD_Publish(CmdPacket *cmd) {
|
||||
|
||||
// get retain
|
||||
CMD_PopArg(&req, (uint8_t*)&retain, 4);
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("MQTTCMD_Publish: topic=%s, data_len=%d, qos=%ld, retain=%ld\n",
|
||||
|
||||
os_printf("MQTT: 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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
uint32_t ICACHE_FLASH_ATTR
|
||||
MQTTCMD_Subscribe(CmdPacket *cmd) {
|
||||
CmdRequest req;
|
||||
CMD_Request(&req, cmd);
|
||||
@@ -328,9 +318,8 @@ MQTTCMD_Subscribe(CmdPacket *cmd) {
|
||||
uint32_t client_ptr;
|
||||
CMD_PopArg(&req, (uint8_t*)&client_ptr, 4);
|
||||
MQTT_Client* client = (MQTT_Client*)client_ptr;
|
||||
#ifdef MQTT_CMD_DBG
|
||||
os_printf("MQTTCMD_Subscribe: client ptr=%p\n", (void*)client_ptr);
|
||||
#endif
|
||||
os_printf("MQTT: MQTTCMD_Subscribe client ptr=%p\n", (void*)client_ptr);
|
||||
|
||||
uint16_t len;
|
||||
uint8_t* topic;
|
||||
uint32_t qos = 0;
|
||||
@@ -344,9 +333,8 @@ 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;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#define MODULES_MQTT_CMD_H_
|
||||
|
||||
#include "cmd.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t connectedCb;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include <esp8266.h>
|
||||
#include "mqtt_msg.h"
|
||||
#define MQTT_MAX_FIXED_HEADER_SIZE 3
|
||||
|
||||
@@ -57,7 +58,7 @@ struct
|
||||
uint8_t keepaliveLsb;
|
||||
};
|
||||
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int ICACHE_FLASH_ATTR
|
||||
append_string(mqtt_connection_t* connection, const char* string, int len) {
|
||||
if (connection->message.length + len + 2 > connection->buffer_length)
|
||||
return -1;
|
||||
@@ -70,7 +71,7 @@ append_string(mqtt_connection_t* connection, const char* string, int len) {
|
||||
return len + 2;
|
||||
}
|
||||
|
||||
static uint16_t ICACHE_FLASH_ATTR
|
||||
static uint16_t ICACHE_FLASH_ATTR
|
||||
append_message_id(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
// If message_id is zero then we should assign one, otherwise
|
||||
// we'll use the one supplied by the caller
|
||||
@@ -86,20 +87,20 @@ append_message_id(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
return message_id;
|
||||
}
|
||||
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int ICACHE_FLASH_ATTR
|
||||
init_message(mqtt_connection_t* connection) {
|
||||
connection->message.length = MQTT_MAX_FIXED_HEADER_SIZE;
|
||||
return MQTT_MAX_FIXED_HEADER_SIZE;
|
||||
}
|
||||
|
||||
static mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
static mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
fail_message(mqtt_connection_t* connection) {
|
||||
connection->message.data = connection->buffer;
|
||||
connection->message.length = 0;
|
||||
return &connection->message;
|
||||
}
|
||||
|
||||
static mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
static mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int retain) {
|
||||
int remaining_length = connection->message.length - MQTT_MAX_FIXED_HEADER_SIZE;
|
||||
|
||||
@@ -120,7 +121,7 @@ fini_message(mqtt_connection_t* connection, int type, int dup, int qos, int reta
|
||||
return &connection->message;
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
void ICACHE_FLASH_ATTR
|
||||
mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length) {
|
||||
uint8_t len = sizeof(connection);
|
||||
memset(connection, '\0', len);
|
||||
@@ -128,8 +129,8 @@ mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_le
|
||||
connection->buffer_length = buffer_length;
|
||||
}
|
||||
|
||||
int ICACHE_FLASH_ATTR
|
||||
mqtt_get_total_length(uint8_t* buffer, uint16_t length) {
|
||||
int ICACHE_FLASH_ATTR
|
||||
mqtt_get_total_length(const uint8_t* buffer, uint16_t length) {
|
||||
int i;
|
||||
int totlen = 0;
|
||||
|
||||
@@ -145,8 +146,8 @@ mqtt_get_total_length(uint8_t* buffer, uint16_t length) {
|
||||
return totlen;
|
||||
}
|
||||
|
||||
const char* ICACHE_FLASH_ATTR
|
||||
mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length) {
|
||||
const char* ICACHE_FLASH_ATTR
|
||||
mqtt_get_publish_topic(const uint8_t* buffer, uint16_t* length) {
|
||||
int i;
|
||||
int totlen = 0;
|
||||
int topiclen;
|
||||
@@ -172,8 +173,8 @@ mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length) {
|
||||
return (const char*)(buffer + i);
|
||||
}
|
||||
|
||||
const char* ICACHE_FLASH_ATTR
|
||||
mqtt_get_publish_data(uint8_t* buffer, uint16_t* length) {
|
||||
const char* ICACHE_FLASH_ATTR
|
||||
mqtt_get_publish_data(const uint8_t* buffer, uint16_t* length) {
|
||||
int i;
|
||||
int totlen = 0;
|
||||
int topiclen;
|
||||
@@ -214,8 +215,8 @@ mqtt_get_publish_data(uint8_t* buffer, uint16_t* length) {
|
||||
return (const char*)(buffer + i);
|
||||
}
|
||||
|
||||
uint16_t ICACHE_FLASH_ATTR
|
||||
mqtt_get_id(uint8_t* buffer, uint16_t length) {
|
||||
uint16_t ICACHE_FLASH_ATTR
|
||||
mqtt_get_id(const uint8_t* buffer, uint16_t length) {
|
||||
if (length < 1)
|
||||
return 0;
|
||||
|
||||
@@ -271,7 +272,7 @@ mqtt_get_id(uint8_t* buffer, uint16_t length) {
|
||||
}
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) {
|
||||
struct mqtt_connect_variable_header* variable_header;
|
||||
|
||||
@@ -339,7 +340,7 @@ mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info) {
|
||||
return fini_message(connection, MQTT_MSG_TYPE_CONNECT, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id) {
|
||||
init_message(connection);
|
||||
|
||||
@@ -364,7 +365,7 @@ mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* d
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBLISH, 0, qos, retain);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
init_message(connection);
|
||||
if (append_message_id(connection, message_id) == 0)
|
||||
@@ -372,7 +373,7 @@ mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBACK, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
init_message(connection);
|
||||
if (append_message_id(connection, message_id) == 0)
|
||||
@@ -380,7 +381,7 @@ mqtt_msg_pubrec(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBREC, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
init_message(connection);
|
||||
if (append_message_id(connection, message_id) == 0)
|
||||
@@ -388,7 +389,7 @@ mqtt_msg_pubrel(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBREL, 0, 1, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
init_message(connection);
|
||||
if (append_message_id(connection, message_id) == 0)
|
||||
@@ -396,7 +397,7 @@ mqtt_msg_pubcomp(mqtt_connection_t* connection, uint16_t message_id) {
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PUBCOMP, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, uint16_t* message_id) {
|
||||
init_message(connection);
|
||||
|
||||
@@ -416,7 +417,7 @@ mqtt_msg_subscribe(mqtt_connection_t* connection, const char* topic, int qos, ui
|
||||
return fini_message(connection, MQTT_MSG_TYPE_SUBSCRIBE, 0, 1, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t* message_id) {
|
||||
init_message(connection);
|
||||
|
||||
@@ -432,19 +433,19 @@ mqtt_msg_unsubscribe(mqtt_connection_t* connection, const char* topic, uint16_t*
|
||||
return fini_message(connection, MQTT_MSG_TYPE_UNSUBSCRIBE, 0, 1, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_pingreq(mqtt_connection_t* connection) {
|
||||
init_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PINGREQ, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_pingresp(mqtt_connection_t* connection) {
|
||||
init_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_PINGRESP, 0, 0, 0);
|
||||
}
|
||||
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_message_t* ICACHE_FLASH_ATTR
|
||||
mqtt_msg_disconnect(mqtt_connection_t* connection) {
|
||||
init_message(connection);
|
||||
return fini_message(connection, MQTT_MSG_TYPE_DISCONNECT, 0, 0, 0);
|
||||
|
||||
@@ -30,8 +30,9 @@
|
||||
*/
|
||||
|
||||
#ifndef MQTT_MSG_H
|
||||
#define MQTT_MSG_H
|
||||
#include <esp8266.h>
|
||||
#define MQTT_MSG_H
|
||||
|
||||
#define PROTOCOL_NAMEv311
|
||||
|
||||
enum mqtt_message_type {
|
||||
MQTT_MSG_TYPE_CONNECT = 1,
|
||||
@@ -50,21 +51,22 @@ enum mqtt_message_type {
|
||||
MQTT_MSG_TYPE_DISCONNECT = 14
|
||||
};
|
||||
|
||||
// Descriptor for a serialized MQTT message, this is returned by functions that compose a message
|
||||
// (It's really an MQTT packet in v3.1.1 terminology)
|
||||
typedef struct mqtt_message {
|
||||
uint8_t* data;
|
||||
uint16_t length;
|
||||
|
||||
} mqtt_message_t;
|
||||
|
||||
// Descriptor for a connection with message assembly storage
|
||||
typedef struct mqtt_connection {
|
||||
mqtt_message_t message;
|
||||
|
||||
uint16_t message_id;
|
||||
uint8_t* buffer;
|
||||
uint16_t buffer_length;
|
||||
|
||||
mqtt_message_t message; // resulting message
|
||||
uint16_t message_id; // id of assembled message and memo to calculate next message id
|
||||
uint8_t* buffer; // buffer for assembling messages
|
||||
uint16_t buffer_length; // buffer length
|
||||
} mqtt_connection_t;
|
||||
|
||||
// Descriptor for a connect request
|
||||
typedef struct mqtt_connect_info {
|
||||
char* client_id;
|
||||
char* username;
|
||||
@@ -75,32 +77,40 @@ typedef struct mqtt_connect_info {
|
||||
uint8_t will_qos;
|
||||
uint8_t will_retain;
|
||||
uint8_t clean_session;
|
||||
|
||||
} mqtt_connect_info_t;
|
||||
|
||||
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_type(uint8_t* buffer) {
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_type(const uint8_t* buffer) {
|
||||
return (buffer[0] & 0xf0) >> 4;
|
||||
}
|
||||
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_dup(uint8_t* buffer) {
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_dup(const uint8_t* buffer) {
|
||||
return (buffer[0] & 0x08) >> 3;
|
||||
}
|
||||
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_qos(uint8_t* buffer) {
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_qos(const uint8_t* buffer) {
|
||||
return (buffer[0] & 0x06) >> 1;
|
||||
}
|
||||
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_retain(uint8_t* buffer) {
|
||||
static inline int ICACHE_FLASH_ATTR mqtt_get_retain(const uint8_t* buffer) {
|
||||
return (buffer[0] & 0x01);
|
||||
}
|
||||
|
||||
// Init a connection descriptor
|
||||
void mqtt_msg_init(mqtt_connection_t* connection, uint8_t* buffer, uint16_t buffer_length);
|
||||
int mqtt_get_total_length(uint8_t* buffer, uint16_t length);
|
||||
const char* mqtt_get_publish_topic(uint8_t* buffer, uint16_t* length);
|
||||
const char* mqtt_get_publish_data(uint8_t* buffer, uint16_t* length);
|
||||
uint16_t mqtt_get_id(uint8_t* buffer, uint16_t length);
|
||||
|
||||
// Returns the total length of a message including MQTT fixed header
|
||||
int mqtt_get_total_length(const uint8_t* buffer, uint16_t length);
|
||||
|
||||
// Return pointer to topic, length in in/out param: in=length of buffer, out=length of topic
|
||||
const char* mqtt_get_publish_topic(const uint8_t* buffer, uint16_t* length);
|
||||
|
||||
// Return pointer to data, length in in/out param: in=length of buffer, out=length of data
|
||||
const char* mqtt_get_publish_data(const uint8_t* buffer, uint16_t* length);
|
||||
|
||||
// Return message id
|
||||
uint16_t mqtt_get_id(const uint8_t* buffer, uint16_t length);
|
||||
|
||||
// The following functions construct an outgoing message
|
||||
mqtt_message_t* mqtt_msg_connect(mqtt_connection_t* connection, mqtt_connect_info_t* info);
|
||||
mqtt_message_t* mqtt_msg_publish(mqtt_connection_t* connection, const char* topic, const char* data, int data_length, int qos, int retain, uint16_t* message_id);
|
||||
mqtt_message_t* mqtt_msg_puback(mqtt_connection_t* connection, uint16_t message_id);
|
||||
|
||||
64
mqtt/pktbuf.c
Normal file
64
mqtt/pktbuf.c
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
|
||||
|
||||
#include <esp8266.h>
|
||||
#include "pktbuf.h"
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
PktBuf_Print(PktBuf *buf) {
|
||||
os_printf("PktBuf:");
|
||||
for (int i=-16; i<0; i++)
|
||||
os_printf(" %02X", ((uint8_t*)buf)[i]);
|
||||
os_printf(" %p", buf);
|
||||
for (int i=0; i<16; i++)
|
||||
os_printf(" %02X", ((uint8_t*)buf)[i]);
|
||||
os_printf("\n");
|
||||
os_printf("PktBuf: next=%p len=0x%04x\n",
|
||||
((void**)buf)[-4], ((uint16_t*)buf)[-6]);
|
||||
}
|
||||
|
||||
|
||||
PktBuf * ICACHE_FLASH_ATTR
|
||||
PktBuf_New(uint16_t length) {
|
||||
PktBuf *buf = os_zalloc(length+sizeof(PktBuf));
|
||||
buf->next = NULL;
|
||||
buf->filled = 0;
|
||||
//os_printf("PktBuf_New: %p l=%d->%d d=%p\n",
|
||||
// buf, length, length+sizeof(PktBuf), buf->data);
|
||||
return buf;
|
||||
}
|
||||
|
||||
PktBuf * ICACHE_FLASH_ATTR
|
||||
PktBuf_Push(PktBuf *headBuf, PktBuf *buf) {
|
||||
if (headBuf == NULL) {
|
||||
//os_printf("PktBuf_Push: %p\n", buf);
|
||||
return buf;
|
||||
}
|
||||
PktBuf *h = headBuf;
|
||||
while (h->next != NULL) h = h->next;
|
||||
h->next = buf;
|
||||
//os_printf("PktBuf_Push: %p->..->%p\n", headBuf, buf);
|
||||
return headBuf;
|
||||
}
|
||||
|
||||
PktBuf * ICACHE_FLASH_ATTR
|
||||
PktBuf_Unshift(PktBuf *headBuf, PktBuf *buf) {
|
||||
buf->next = headBuf;
|
||||
//os_printf("PktBuf_Unshift: %p->%p\n", buf, buf->next);
|
||||
return buf;
|
||||
}
|
||||
|
||||
PktBuf * ICACHE_FLASH_ATTR
|
||||
PktBuf_Shift(PktBuf *headBuf) {
|
||||
PktBuf *buf = headBuf->next;
|
||||
headBuf->next = NULL;
|
||||
//os_printf("PktBuf_Shift: (%p)->%p\n", headBuf, buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
PktBuf * ICACHE_FLASH_ATTR
|
||||
PktBuf_ShiftFree(PktBuf *headBuf) {
|
||||
PktBuf *buf = headBuf->next;
|
||||
//os_printf("PktBuf_ShiftFree: (%p)->%p\n", headBuf, buf);
|
||||
os_free(headBuf);
|
||||
return buf;
|
||||
}
|
||||
29
mqtt/pktbuf.h
Normal file
29
mqtt/pktbuf.h
Normal file
@@ -0,0 +1,29 @@
|
||||
// Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
|
||||
|
||||
#ifndef PKTBUF_H
|
||||
#define PKTBUF_H
|
||||
|
||||
typedef struct PktBuf {
|
||||
struct PktBuf *next; // next buffer in chain
|
||||
uint16_t filled; // number of bytes filled in buffer
|
||||
uint8_t data[0]; // data in buffer
|
||||
} PktBuf;
|
||||
|
||||
// Allocate a new packet buffer of given length
|
||||
PktBuf *PktBuf_New(uint16_t length);
|
||||
|
||||
// Append a buffer to the end of a packet buffer queue, returns new head
|
||||
PktBuf *PktBuf_Push(PktBuf *headBuf, PktBuf *buf);
|
||||
|
||||
// Prepend a buffer to the beginning of a packet buffer queue, return new head
|
||||
PktBuf * PktBuf_Unshift(PktBuf *headBuf, PktBuf *buf);
|
||||
|
||||
// Shift first buffer off queue, returns new head (not shifted buffer!)
|
||||
PktBuf *PktBuf_Shift(PktBuf *headBuf);
|
||||
|
||||
// Shift first buffer off queue, free it, return new head
|
||||
PktBuf *PktBuf_ShiftFree(PktBuf *headBuf);
|
||||
|
||||
void PktBuf_Print(PktBuf *buf);
|
||||
|
||||
#endif
|
||||
86
mqtt/proto.c
86
mqtt/proto.c
@@ -1,86 +0,0 @@
|
||||
#include "proto.h"
|
||||
|
||||
int8_t ICACHE_FLASH_ATTR
|
||||
PROTO_Init(PROTO_PARSER* parser, PROTO_PARSE_CALLBACK* completeCallback, uint8_t* buf, uint16_t bufSize) {
|
||||
parser->buf = buf;
|
||||
parser->bufSize = bufSize;
|
||||
parser->dataLen = 0;
|
||||
parser->callback = completeCallback;
|
||||
parser->isEsc = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int8_t ICACHE_FLASH_ATTR
|
||||
PROTO_ParseByte(PROTO_PARSER* parser, uint8_t value) {
|
||||
switch (value) {
|
||||
case 0x7D:
|
||||
parser->isEsc = 1;
|
||||
break;
|
||||
|
||||
case 0x7E:
|
||||
parser->dataLen = 0;
|
||||
parser->isEsc = 0;
|
||||
parser->isBegin = 1;
|
||||
break;
|
||||
|
||||
case 0x7F:
|
||||
if (parser->callback != NULL)
|
||||
parser->callback();
|
||||
parser->isBegin = 0;
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (parser->isBegin == 0) break;
|
||||
|
||||
if (parser->isEsc) {
|
||||
value ^= 0x20;
|
||||
parser->isEsc = 0;
|
||||
}
|
||||
|
||||
if (parser->dataLen < parser->bufSize)
|
||||
parser->buf[parser->dataLen++] = value;
|
||||
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int16_t ICACHE_FLASH_ATTR
|
||||
PROTO_ParseRb(RINGBUF* rb, uint8_t* bufOut, uint16_t* len, uint16_t maxBufLen) {
|
||||
uint8_t c;
|
||||
|
||||
PROTO_PARSER proto;
|
||||
PROTO_Init(&proto, NULL, bufOut, maxBufLen);
|
||||
while (RINGBUF_Get(rb, &c) == 0) {
|
||||
if (PROTO_ParseByte(&proto, c) == 0) {
|
||||
*len = proto.dataLen;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int16_t ICACHE_FLASH_ATTR
|
||||
PROTO_AddRb(RINGBUF* rb, const uint8_t* packet, int16_t len) {
|
||||
uint16_t i = 2;
|
||||
if (RINGBUF_Put(rb, 0x7E) == -1) return -1;
|
||||
while (len--) {
|
||||
switch (*packet) {
|
||||
case 0x7D:
|
||||
case 0x7E:
|
||||
case 0x7F:
|
||||
if (RINGBUF_Put(rb, 0x7D) == -1) return -1;
|
||||
if (RINGBUF_Put(rb, *packet++ ^ 0x20) == -1) return -1;
|
||||
i += 2;
|
||||
break;
|
||||
default:
|
||||
if (RINGBUF_Put(rb, *packet++) == -1) return -1;
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (RINGBUF_Put(rb, 0x7F) == -1) return -1;
|
||||
|
||||
return i;
|
||||
}
|
||||
21
mqtt/proto.h
21
mqtt/proto.h
@@ -1,21 +0,0 @@
|
||||
#ifndef _PROTO_H_
|
||||
#define _PROTO_H_
|
||||
#include <esp8266.h>
|
||||
#include "ringbuf.h"
|
||||
|
||||
typedef void (PROTO_PARSE_CALLBACK)();
|
||||
|
||||
typedef struct {
|
||||
uint8_t* buf;
|
||||
uint16_t bufSize;
|
||||
uint16_t dataLen;
|
||||
uint8_t isEsc;
|
||||
uint8_t isBegin;
|
||||
PROTO_PARSE_CALLBACK* callback;
|
||||
} PROTO_PARSER;
|
||||
|
||||
int8_t PROTO_Init(PROTO_PARSER* parser, PROTO_PARSE_CALLBACK* completeCallback, uint8_t* buf, uint16_t bufSize);
|
||||
int16_t PROTO_AddRb(RINGBUF* rb, const uint8_t* packet, int16_t len);
|
||||
int8_t PROTO_ParseByte(PROTO_PARSER* parser, uint8_t value);
|
||||
int16_t PROTO_ParseRb(RINGBUF* rb, uint8_t* bufOut, uint16_t* len, uint16_t maxBufLen);
|
||||
#endif
|
||||
53
mqtt/queue.c
53
mqtt/queue.c
@@ -1,53 +0,0 @@
|
||||
/* str_queue.c
|
||||
*
|
||||
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "queue.h"
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
QUEUE_Init(QUEUE* queue, int bufferSize) {
|
||||
queue->buf = (uint8_t*)os_zalloc(bufferSize);
|
||||
RINGBUF_Init(&queue->rb, queue->buf, bufferSize);
|
||||
}
|
||||
|
||||
int32_t ICACHE_FLASH_ATTR
|
||||
QUEUE_Puts(QUEUE* queue, uint8_t* buffer, uint16_t len) {
|
||||
return PROTO_AddRb(&queue->rb, buffer, len);
|
||||
}
|
||||
|
||||
int32_t ICACHE_FLASH_ATTR
|
||||
QUEUE_Gets(QUEUE* queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen) {
|
||||
return PROTO_ParseRb(&queue->rb, buffer, len, maxLen);
|
||||
}
|
||||
|
||||
bool ICACHE_FLASH_ATTR
|
||||
QUEUE_IsEmpty(QUEUE* queue) {
|
||||
if (queue->rb.fill_cnt <= 0)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
46
mqtt/queue.h
46
mqtt/queue.h
@@ -1,46 +0,0 @@
|
||||
/* str_queue.h --
|
||||
*
|
||||
* Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Redis nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef USER_QUEUE_H_
|
||||
#define USER_QUEUE_H_
|
||||
#include <esp8266.h>
|
||||
#include "proto.h"
|
||||
#include "ringbuf.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t* buf;
|
||||
RINGBUF rb;
|
||||
} QUEUE;
|
||||
|
||||
void QUEUE_Init(QUEUE* queue, int bufferSize);
|
||||
int32_t QUEUE_Puts(QUEUE* queue, uint8_t* buffer, uint16_t len);
|
||||
int32_t QUEUE_Gets(QUEUE* queue, uint8_t* buffer, uint16_t* len, uint16_t maxLen);
|
||||
bool QUEUE_IsEmpty(QUEUE* queue);
|
||||
#endif /* USER_QUEUE_H_ */
|
||||
@@ -1,63 +0,0 @@
|
||||
#include "ringbuf.h"
|
||||
|
||||
/**
|
||||
* \brief init a RINGBUF object
|
||||
* \param r pointer to a RINGBUF object
|
||||
* \param buf pointer to a byte array
|
||||
* \param size size of buf
|
||||
* \return 0 if successfull, otherwise failed
|
||||
*/
|
||||
int16_t ICACHE_FLASH_ATTR
|
||||
RINGBUF_Init(RINGBUF* r, uint8_t* buf, int32_t size) {
|
||||
if (r == NULL || buf == NULL || size < 2) return -1;
|
||||
|
||||
r->p_o = r->p_r = r->p_w = buf;
|
||||
r->fill_cnt = 0;
|
||||
r->size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief put a character into ring buffer
|
||||
* \param r pointer to a ringbuf object
|
||||
* \param c character to be put
|
||||
* \return 0 if successfull, otherwise failed
|
||||
*/
|
||||
int16_t ICACHE_FLASH_ATTR
|
||||
RINGBUF_Put(RINGBUF* r, uint8_t c) {
|
||||
if (r->fill_cnt >= r->size)return -1; // ring buffer is full, this should be atomic operation
|
||||
|
||||
|
||||
r->fill_cnt++; // increase filled slots count, this should be atomic operation
|
||||
|
||||
|
||||
*r->p_w++ = c; // put character into buffer
|
||||
|
||||
if (r->p_w >= r->p_o + r->size) // rollback if write pointer go pass
|
||||
r->p_w = r->p_o; // the physical boundary
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief get a character from ring buffer
|
||||
* \param r pointer to a ringbuf object
|
||||
* \param c read character
|
||||
* \return 0 if successfull, otherwise failed
|
||||
*/
|
||||
int16_t ICACHE_FLASH_ATTR
|
||||
RINGBUF_Get(RINGBUF* r, uint8_t* c) {
|
||||
if (r->fill_cnt <= 0)return -1; // ring buffer is empty, this should be atomic operation
|
||||
|
||||
|
||||
r->fill_cnt--; // decrease filled slots count
|
||||
|
||||
|
||||
*c = *r->p_r++; // get the character out
|
||||
|
||||
if (r->p_r >= r->p_o + r->size) // rollback if write pointer go pass
|
||||
r->p_r = r->p_o; // the physical boundary
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
#ifndef _RING_BUF_H_
|
||||
#define _RING_BUF_H_
|
||||
|
||||
#include <esp8266.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t* p_o; /**< Original pointer */
|
||||
uint8_t* volatile p_r; /**< Read pointer */
|
||||
uint8_t* volatile p_w; /**< Write pointer */
|
||||
volatile int32_t fill_cnt; /**< Number of filled slots */
|
||||
int32_t size; /**< Buffer size */
|
||||
} RINGBUF;
|
||||
|
||||
int16_t RINGBUF_Init(RINGBUF* r, uint8_t* buf, int32_t size);
|
||||
int16_t RINGBUF_Put(RINGBUF* r, uint8_t c);
|
||||
int16_t RINGBUF_Get(RINGBUF* r, uint8_t* c);
|
||||
#endif
|
||||
12
rest/rest.c
12
rest/rest.c
@@ -154,12 +154,12 @@ rest_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) {
|
||||
|
||||
if(client->ip.addr == 0 && ipaddr->addr != 0) {
|
||||
os_memcpy(client->pCon->proto.tcp->remote_ip, &ipaddr->addr, 4);
|
||||
//if(client->security){
|
||||
// espconn_secure_connect(client->pCon);
|
||||
//}
|
||||
//else {
|
||||
#ifdef CLIENT_SSL_ENABLE
|
||||
if(client->security) {
|
||||
espconn_secure_connect(client->pCon);
|
||||
} else
|
||||
#endif
|
||||
espconn_connect(client->pCon);
|
||||
//}
|
||||
os_printf("REST: connecting...\n");
|
||||
}
|
||||
}
|
||||
@@ -368,6 +368,8 @@ REST_Request(CmdPacket *cmd) {
|
||||
}
|
||||
os_printf("\n");
|
||||
|
||||
//os_printf("REST request: %s", (char*)client->data);
|
||||
|
||||
os_printf("REST: pCon state=%d\n", client->pCon->state);
|
||||
client->pCon->state = ESPCONN_NONE;
|
||||
espconn_regist_connectcb(client->pCon, tcpclient_connect_cb);
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "serled.h"
|
||||
#include "config.h"
|
||||
#include "console.h"
|
||||
#include "slip.h"
|
||||
#include "cmd.h"
|
||||
|
||||
static struct espconn serbridgeConn;
|
||||
@@ -258,6 +259,19 @@ console_process(char *buf, short len) {
|
||||
}
|
||||
}
|
||||
|
||||
// callback with a buffer of characters that have arrived on the uart
|
||||
void ICACHE_FLASH_ATTR
|
||||
serbridgeUartCb(char *buf, short length) {
|
||||
if (!flashConfig.slip_enable || slip_disabled > 0) {
|
||||
//os_printf("SLIP: disabled got %d\n", length);
|
||||
console_process(buf, length);
|
||||
} else {
|
||||
slip_parse_buf(buf, length);
|
||||
}
|
||||
|
||||
serledFlash(50); // short blink on serial LED
|
||||
}
|
||||
|
||||
//callback after the data are sent
|
||||
static void ICACHE_FLASH_ATTR
|
||||
serbridgeSentCb(void *arg) {
|
||||
@@ -273,6 +287,7 @@ serbridgeSentCb(void *arg) {
|
||||
|
||||
// Error callback (it's really poorly named, it's not a "connection reconnected" callback,
|
||||
// it's really a "connection broken, please reconnect" callback)
|
||||
// Note that there is no DisconCb after a ReconCb
|
||||
static void ICACHE_FLASH_ATTR serbridgeReconCb(void *arg, sint8 err) {
|
||||
serbridgeConnData *sbConn = serbridgeFindConnData(arg);
|
||||
if (sbConn == NULL) return;
|
||||
|
||||
@@ -6,4 +6,3 @@ void serledInit(void);
|
||||
void makeGpio(uint8_t pin);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -4,11 +4,10 @@
|
||||
#include "uart.h"
|
||||
#include "crc16.h"
|
||||
#include "serbridge.h"
|
||||
#include "serled.h"
|
||||
#include "console.h"
|
||||
#include "cmd.h"
|
||||
|
||||
uint8_t slip_disabled; // disable slip to allow flashing of attached MCU
|
||||
uint8_t slip_disabled; // temporarily disable slip to allow flashing of attached MCU
|
||||
|
||||
extern void ICACHE_FLASH_ATTR console_process(char *buf, short len);
|
||||
|
||||
@@ -115,18 +114,7 @@ slip_parse_char(char c) {
|
||||
|
||||
// callback with a buffer of characters that have arrived on the uart
|
||||
void ICACHE_FLASH_ATTR
|
||||
serbridgeUartCb(char *buf, short length) {
|
||||
if (slip_disabled > 0) {
|
||||
//os_printf("SLIP: disabled got %d\n", length);
|
||||
console_process(buf, length);
|
||||
for (short i=0; i<length; i++)
|
||||
if (buf[i] == SLIP_START) {
|
||||
os_printf("SLIP: START while disabled=%d\n", slip_disabled);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
slip_parse_buf(char *buf, short length) {
|
||||
// do SLIP parsing
|
||||
for (short i=0; i<length; i++)
|
||||
slip_parse_char(buf[i]);
|
||||
@@ -136,6 +124,5 @@ serbridgeUartCb(char *buf, short length) {
|
||||
slip_process();
|
||||
slip_reset();
|
||||
}
|
||||
|
||||
serledFlash(50); // short blink on serial LED
|
||||
}
|
||||
|
||||
|
||||
6
serial/slip.h
Normal file
6
serial/slip.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef SLIP_H
|
||||
#define SLIP_H
|
||||
|
||||
void slip_parse_buf(char *buf, short length);
|
||||
|
||||
#endif
|
||||
@@ -23,7 +23,7 @@
|
||||
#include "user_interface.h"
|
||||
#include "uart.h"
|
||||
|
||||
#define recvTaskPrio 0
|
||||
#define recvTaskPrio 1
|
||||
#define recvTaskQueueLen 64
|
||||
|
||||
// UartDev is defined and initialized in rom code.
|
||||
|
||||
167
user/user_main.c
167
user/user_main.c
@@ -1,103 +1,64 @@
|
||||
#include <esp8266.h>
|
||||
#include <mqtt.h>
|
||||
#include <cgiwifi.h>
|
||||
#include <json/jsontree.h>
|
||||
#include <json/jsonparse.h>
|
||||
#include "user_json.h"
|
||||
#include "user_funcs.h"
|
||||
#include "cgiwifi.h"
|
||||
#include "mqtt.h"
|
||||
|
||||
MQTT_Client mqttClient;
|
||||
|
||||
typedef struct {
|
||||
uint8_t fallbackStateBits;
|
||||
uint8_t stateBits;
|
||||
uint8_t init;
|
||||
uint8_t fallbackSecondsForBits[8];
|
||||
} LatchState;
|
||||
static ETSTimer mqttTimer;
|
||||
|
||||
static LatchState latch;
|
||||
static int once = 0;
|
||||
static void ICACHE_FLASH_ATTR mqttTimerCb(void *arg) {
|
||||
if (once++ > 0) return;
|
||||
MQTT_Init(&mqttClient, "h.voneicken.com", 1883, 0, 2, "test1", "", "", 10, 1);
|
||||
MQTT_Connect(&mqttClient);
|
||||
MQTT_Subscribe(&mqttClient, "system/time", 0);
|
||||
}
|
||||
|
||||
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
|
||||
wifiStateChangeCb(uint8_t status)
|
||||
{
|
||||
if (status == wifiGotIP) {
|
||||
os_timer_disarm(&mqttTimer);
|
||||
os_timer_setfn(&mqttTimer, mqttTimerCb, NULL);
|
||||
os_timer_arm(&mqttTimer, 15000, 0);
|
||||
}
|
||||
}
|
||||
|
||||
LOCAL int ICACHE_FLASH_ATTR
|
||||
latchGet(struct jsontree_context *js_ctx) {
|
||||
return 0;
|
||||
|
||||
// initialize the custom stuff that goes beyond esp-link
|
||||
void app_init() {
|
||||
wifiAddStateChangeCb(wifiStateChangeCb);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#if 0
|
||||
MQTT_Client mqttClient;
|
||||
|
||||
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
|
||||
void ICACHE_FLASH_ATTR
|
||||
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
|
||||
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 ICACHE_FLASH_ATTR
|
||||
mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) {
|
||||
char *topicBuf = (char*)os_zalloc(topic_len + 1);
|
||||
char *dataBuf = (char*)os_zalloc(data_len + 1);
|
||||
@@ -110,49 +71,11 @@ 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\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_printf("Receive topic: %s, data: %s\n", topicBuf, dataBuf);
|
||||
os_free(topicBuf);
|
||||
os_free(dataBuf);
|
||||
}
|
||||
|
||||
void ICACHE_FLASH_ATTR
|
||||
wifiStateChangeCb(uint8_t status)
|
||||
{
|
||||
if (status == wifiGotIP && mqttClient.connState != TCP_CONNECTING){
|
||||
MQTT_Connect(&mqttClient);
|
||||
}
|
||||
else if (status == wifiIsDisconnected && mqttClient.connState == TCP_CONNECTING){
|
||||
MQTT_Disconnect(&mqttClient);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
MQTT_InitClient(&mqttClient, MQTT_CLIENT_ID, MQTT_USER, MQTT_PASS, MQTT_KEEPALIVE, MQTT_CLSESSION);
|
||||
MQTT_InitLWT(&mqttClient, "/lwt", "offline", 0, 0);
|
||||
@@ -161,4 +84,4 @@ void init() {
|
||||
MQTT_OnDisconnected(&mqttClient, mqttTcpDisconnectedCb);
|
||||
MQTT_OnPublished(&mqttClient, mqttPublishedCb);
|
||||
MQTT_OnData(&mqttClient, mqttDataCb);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user