Added services page and moved some things around
pull/72/head
Benjamin Runnels 9 years ago
commit 13bc8019c6
  1. 1
      .gitignore
  2. 31
      Makefile
  3. 14
      esp-link.vcxproj
  4. 105
      esp-link/cgi.c
  5. 14
      esp-link/cgi.h
  6. 53
      esp-link/cgiflash.c
  7. 1
      esp-link/cgiflash.h
  8. 28
      esp-link/cgimqtt.c
  9. 205
      esp-link/cgiservices.c
  10. 15
      esp-link/cgiservices.h
  11. 55
      esp-link/cgiwifi.c
  12. 2
      esp-link/cgiwifi.h
  13. 37
      esp-link/config.c
  14. 17
      esp-link/config.h
  15. 94
      esp-link/main.c
  16. 78
      esp-link/task.c
  17. 20
      esp-link/task.h
  18. 22
      html/console.html
  19. 2
      html/console.js
  20. BIN
      html/favicon.ico
  21. 9
      html/home.html
  22. 18
      html/log.html
  23. 2
      html/mqtt.js
  24. 111
      html/services.html
  25. 74
      html/services.js
  26. 12
      html/ui.js
  27. 8
      html/wifi/wifi.html
  28. 4
      html/wifi/wifi.js
  29. 15
      include/espmissingincludes.h
  30. 2
      include/user_config.h
  31. 4
      serial/serbridge.c
  32. 11
      serial/uart.c
  33. 382
      syslog/syslog.c
  34. 110
      syslog/syslog.h

1
.gitignore vendored

@ -16,4 +16,5 @@ esp-link.sdf
espfs/mkespfsimage/mman-win32/libmman.a
.localhistory/
tools/
local.conf
*.tgz

@ -8,10 +8,12 @@
# `VERBOSE=1 make ...` will print debug info
# `ESP_HOSTNAME=my.esp.example.com make wiflash` is an easy way to override a variable
#
# optional local configuration file
-include local.conf
# Makefile heavily adapted to esp-link and wireless flashing by Thorsten von Eicken
# Lots of work, in particular to support windows, by brunnels
# Original from esphttpd and others...
#VERBOSE=1
# VERBOSE=1
# --------------- toolchain configuration ---------------
@ -63,7 +65,7 @@ LED_SERIAL_PIN ?= 14
CHANGE_TO_STA ?= yes
# Optional Modules
MODULES ?= mqtt rest
MODULES ?= mqtt rest syslog
# --------------- esphttpd config options ---------------
@ -94,6 +96,25 @@ YUI_COMPRESSOR ?= yuicompressor-2.4.8.jar
# -------------- End of config options -------------
ifeq ("$(FLASH_SIZE)","512KB")
# Winbond 25Q40 512KB flash, typ for esp-01 thru esp-11
ESP_SPI_SIZE ?= 0 # 0->512KB
ESP_FLASH_MODE ?= 0 # 0->QIO
ESP_FLASH_FREQ_DIV ?= 0 # 0->40Mhz
ESP_FLASH_MAX ?= 241664 # max bin file for 512KB flash: 236KB
else
# Winbond 25Q32 4MB flash, typ for esp-12
# Here we're using two partitions of approx 0.5MB because that's what's easily available in terms
# of linker scripts in the SDK. Ideally we'd use two partitions of approx 1MB, the remaining 2MB
# cannot be used for code.
ESP_SPI_SIZE ?= 4 # 6->4MB (1MB+1MB) or 4->4MB (512KB+512KB)
ESP_FLASH_MODE ?= 0 # 0->QIO, 2->DIO
ESP_FLASH_FREQ_DIV ?= 15 # 15->80Mhz
ESP_FLASH_MAX ?= 503808 # max bin file for 512KB flash partition: 492KB
#ESP_FLASH_MAX ?= 1028096 # max bin file for 1MB flash partition: 1004KB
endif
HTML_PATH = $(abspath ./html)/
WIFI_PATH = $(HTML_PATH)wifi/
@ -178,6 +199,10 @@ ifneq (,$(findstring rest,$(MODULES)))
CFLAGS += -DREST
endif
ifneq (,$(findstring syslog,$(MODULES)))
CFLAGS += -DSYSLOG
endif
# which modules (subdirectories) of the project to include in compiling
LIBRARIES_DIR = libraries
MODULES += espfs httpd user serial cmd esp-link
@ -335,7 +360,7 @@ flash: all
$(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash -fs $(ET_FS) -ff $(ET_FF) \
0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin \
$(ET_BLANK) $(SDK_BASE)/bin/blank.bin
tools/$(HTML_COMPRESSOR):
$(Q) mkdir -p tools
ifeq ($(OS),Windows_NT)

@ -18,6 +18,7 @@
<ClCompile Include="esp-link\cgimqtt.c" />
<ClCompile Include="esp-link\cgioptiboot.c" />
<ClCompile Include="esp-link\cgipins.c" />
<ClCompile Include="esp-link\cgiservices.c" />
<ClCompile Include="esp-link\cgitcp.c" />
<ClCompile Include="esp-link\cgiwifi.c" />
<ClCompile Include="esp-link\config.c" />
@ -26,6 +27,7 @@
<ClCompile Include="esp-link\mdns.c" />
<ClCompile Include="esp-link\mqtt_client.c" />
<ClCompile Include="esp-link\status.c" />
<ClCompile Include="esp-link\task.c" />
<ClCompile Include="espfs\espfs.c" />
<ClCompile Include="espfs\mkespfsimage\main.c" />
<ClCompile Include="espfs\mkespfsimage\mman-win32\mman.c" />
@ -45,6 +47,7 @@
<ClCompile Include="serial\serled.c" />
<ClCompile Include="serial\slip.c" />
<ClCompile Include="serial\uart.c" />
<ClCompile Include="syslog\syslog.c" />
<ClCompile Include="user\user_main.c" />
</ItemGroup>
<ItemGroup>
@ -54,6 +57,7 @@
<ClInclude Include="esp-link\cgimqtt.h" />
<ClInclude Include="esp-link\cgioptiboot.h" />
<ClInclude Include="esp-link\cgipins.h" />
<ClInclude Include="esp-link\cgiservices.h" />
<ClInclude Include="esp-link\cgitcp.h" />
<ClInclude Include="esp-link\cgiwifi.h" />
<ClInclude Include="esp-link\config.h" />
@ -62,6 +66,7 @@
<ClInclude Include="esp-link\mqtt_client.h" />
<ClInclude Include="esp-link\status.h" />
<ClInclude Include="esp-link\stk500.h" />
<ClInclude Include="esp-link\task.h" />
<ClInclude Include="espfs\espfs.h" />
<ClInclude Include="espfs\espfsformat.h" />
<ClInclude Include="espfs\mkespfsimage\mman-win32\mman.h" />
@ -84,8 +89,10 @@
<ClInclude Include="serial\serled.h" />
<ClInclude Include="serial\slip.h" />
<ClInclude Include="serial\uart.h" />
<ClInclude Include="syslog\syslog.h" />
</ItemGroup>
<ItemGroup>
<None Include=".gitignore" />
<None Include="avrflash" />
<None Include="BOARDS.md" />
<None Include="espmake.cmd" />
@ -99,6 +106,8 @@
<None Include="html\mqtt.html" />
<None Include="html\mqtt.js" />
<None Include="html\pure.css" />
<None Include="html\services.html" />
<None Include="html\services.js" />
<None Include="html\style.css" />
<None Include="html\ui.js" />
<None Include="html\wifi\wifi.html" />
@ -106,6 +115,7 @@
<None Include="Makefile" />
<None Include="README.md" />
<None Include="wiflash" />
<None Include="WINDOWS.md" />
</ItemGroup>
<ItemGroup>
<Text Include="esp-link.log" />
@ -131,8 +141,8 @@
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<NMakeOutput />
<NMakePreprocessorDefinitions>__ets__;_STDINT_H;ICACHE_FLASH;__MINGW32__;__WIN32__;MQTT;REST</NMakePreprocessorDefinitions>
<NMakeIncludeSearchPath>.\rest;.\esp-link;.\mqtt;.\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.5.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include</NMakeIncludeSearchPath>
<NMakePreprocessorDefinitions>__ets__;_STDINT_H;ICACHE_FLASH;__MINGW32__;__WIN32__;MQTT;REST;SYSLOG;FIRMWARE_SIZE</NMakePreprocessorDefinitions>
<NMakeIncludeSearchPath>.\syslog;.\rest;.\esp-link;.\mqtt;.\cmd;.\serial;.\user;.\espfs;.\httpd;.\include;..\esp_iot_sdk_v1.5.0\include;..\xtensa-lx106-elf\xtensa-lx106-elf\include;c:\tools\mingw64\x86_64-w64-mingw32\include;c:\tools\mingw64\lib\gcc\x86_64-w64-mingw32\4.8.3\include</NMakeIncludeSearchPath>
<ExecutablePath />
<ReferencePath />
<LibraryPath />

@ -13,40 +13,39 @@ Some random cgi routines.
* ----------------------------------------------------------------------------
*/
#include <esp8266.h>
#include "cgi.h"
#include "config.h"
void ICACHE_FLASH_ATTR
noCacheHeaders(HttpdConnData *connData, int code) {
#ifdef CGI_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
#else
#define DBG(format, ...) do { } while(0)
#endif
void ICACHE_FLASH_ATTR 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) {
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) {
void ICACHE_FLASH_ATTR errorResponse(HttpdConnData *connData, int code, char *message) {
noCacheHeaders(connData, code);
httpdEndHeaders(connData);
httpdSend(connData, message, -1);
#ifdef CGI_DBG
os_printf("HTTP %d error response: \"%s\"\n", code, message);
#endif
DBG("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
int8_t ICACHE_FLASH_ATTR
getStringArg(HttpdConnData *connData, char *name, char *config, int max_len) {
int8_t 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
@ -55,19 +54,50 @@ getStringArg(HttpdConnData *connData, char *name, char *config, int max_len) {
errorResponse(connData, 400, buff);
return -1;
}
strcpy(config, buff);
os_strcpy(config, buff);
return 1;
}
// look for the HTTP arg 'name' and store it at 'config' as an 8-bit integer
// returns -1 on error, 0 if not found, 1 if found and OK
int8_t ICACHE_FLASH_ATTR
getInt8Arg(HttpdConnData *connData, char *name, int8_t *config) {
int8_t ICACHE_FLASH_ATTR getInt8Arg(HttpdConnData *connData, char *name, int8_t *config) {
char buff[16];
int len = httpdFindArg(connData->getArgs, name, buff, sizeof(buff));
if (len < 0) return 0; // not found, skip
int m = atoi(buff);
if (len > 5 || m < -127 || m > 127) {
os_sprintf(buff, "Value for %s out of range", name);
errorResponse(connData, 400, buff);
return -1;
}
*config = m;
return 1;
}
// look for the HTTP arg 'name' and store it at 'config' as an unsigned 8-bit integer
// returns -1 on error, 0 if not found, 1 if found and OK
int8_t ICACHE_FLASH_ATTR getUInt8Arg(HttpdConnData *connData, char *name, uint8_t *config) {
char buff[16];
int len = httpdFindArg(connData->getArgs, name, buff, sizeof(buff));
if (len < 0) return 0; // not found, skip
int m = atoi(buff);
if (len > 4 || m < 0 || m > 255) {
os_sprintf(buff, "Value for %s out of range", name);
errorResponse(connData, 400, buff);
return -1;
}
*config = m;
return 1;
}
// look for the HTTP arg 'name' and store it at 'config' as an unsigned 16-bit integer
// returns -1 on error, 0 if not found, 1 if found and OK
int8_t ICACHE_FLASH_ATTR getUInt16Arg(HttpdConnData *connData, char *name, uint16_t *config) {
char buff[16];
int len = httpdFindArg(connData->getArgs, name, buff, sizeof(buff));
if (len < 0) return 0; // not found, skip
int m = atoi(buff);
if (len >= 6 || m < -128 || m > 255) {
if (len > 6 || m < 0 || m > 65535) {
os_sprintf(buff, "Value for %s out of range", name);
errorResponse(connData, 400, buff);
return -1;
@ -76,27 +106,27 @@ getInt8Arg(HttpdConnData *connData, char *name, int8_t *config) {
return 1;
}
int8_t ICACHE_FLASH_ATTR
getBoolArg(HttpdConnData *connData, char *name, bool*config) {
char buff[64];
int8_t ICACHE_FLASH_ATTR getBoolArg(HttpdConnData *connData, char *name, bool *config) {
char buff[16];
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) {
if (os_strcmp(buff, "1") == 0 || os_strcmp(buff, "true") == 0) {
*config = true;
return 1;
}
if (strcmp(buff, "0") == 0 || strcmp(buff, "false") == 0) {
}
if (os_strcmp(buff, "0") == 0 || os_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){
uint8_t ICACHE_FLASH_ATTR UTILS_StrToIP(const char* str, void *ip){
/* The count of the number of bytes processed. */
int i;
/* A pointer to the next digit to process. */
@ -133,8 +163,8 @@ UTILS_StrToIP(const char* str, void *ip){
return 1;
}
#define TOKEN(x) (os_strcmp(token, x) == 0)
#if 0
#define TOKEN(x) (os_strcmp(token, x) == 0)
// Handle system information variables and print their value, returns the number of
// characters appended to buff
int ICACHE_FLASH_ATTR printGlobalInfo(char *buff, int buflen, char *token) {
@ -172,16 +202,23 @@ int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) {
os_strncpy(name, flashConfig.hostname, 12);
name[12] = 0;
// construct json response
os_sprintf(buff,
"{\"menu\": [\"Home\", \"/home.html\", "
"\"Wifi\", \"/wifi/wifi.html\","
"\"\xC2\xB5" "C Console\", \"/console.html\", "
os_sprintf(buff,
"{ "
"\"menu\": [ "
"\"Home\", \"/home.html\", "
"\"Wifi\", \"/wifi/wifi.html\", "
"\"&#xb5;C Console\", \"/console.html\", "
"\"Services\", \"/services.html\", "
#ifdef MQTT
"\"REST/MQTT\", \"/mqtt.html\","
"\"REST/MQTT\", \"/mqtt.html\", "
#endif
"\"Debug log\", \"/log.html\" ],\n"
" \"version\": \"%s\","
"\"name\":\"%s\"}", esp_link_version, name);
"\"Debug log\", \"/log.html\""
" ], "
"\"version\": \"%s\", "
"\"name\": \"%s\""
" }",
esp_link_version, name);
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
}

@ -12,16 +12,24 @@ void errorResponse(HttpdConnData *connData, int code, char *message);
// 'max_len' (incl terminating zero), returns -1 on error, 0 if not found, 1 if found
int8_t getStringArg(HttpdConnData *connData, char *name, char *config, int max_len);
// Get the HTTP query-string param 'name' and store it as a int8 value at 'config',
// Get the HTTP query-string param 'name' and store it as a int8_t value at 'config',
// supports signed and unsigned, returns -1 on error, 0 if not found, 1 if found
int8_t getInt8Arg(HttpdConnData *connData, char *name, int8_t *config);
// Get the HTTP query-string param 'name' and store it as a uint8_t value at 'config',
// supports signed and unsigned, returns -1 on error, 0 if not found, 1 if found
int8_t getUInt8Arg(HttpdConnData *connData, char *name, uint8_t *config);
// Get the HTTP query-string param 'name' and store it as a uint16_t value at 'config',
// supports signed and unsigned, returns -1 on error, 0 if not found, 1 if found
int8_t getUInt16Arg(HttpdConnData *connData, char *name, uint16_t *config);
// Get the HTTP query-string param 'name' and store it boolean value at 'config',
// supports 1/true and 0/false, returns -1 on error, 0 if not found, 1 if found
int8_t getBoolArg(HttpdConnData *connData, char *name, bool*config);
int8_t getBoolArg(HttpdConnData *connData, char *name, bool *config);
int cgiMenu(HttpdConnData *connData);
uint8_t UTILS_StrToIP(const char* str, void *ip);
uint8_t UTILS_StrToIP(const char *str, void *ip);
#endif

@ -18,7 +18,12 @@ Some flash handling cgi routines. Used for reading the existing flash and updati
#include <osapi.h>
#include "cgi.h"
#include "cgiflash.h"
#include "espfs.h"
#ifdef CGIFLASH_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
#else
#define DBG(format, ...) do { } while(0)
#endif
// Check that the header of the firmware blob looks like actual firmware...
static char* ICACHE_FLASH_ATTR check_header(void *buf) {
@ -58,10 +63,7 @@ int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) {
httpdEndHeaders(connData);
char *next = id == 1 ? "user1.bin" : "user2.bin";
httpdSend(connData, next, -1);
#ifdef CGIFLASH_DBG
os_printf("Next firmware: %s (got %d)\n", next, id);
#endif
DBG("Next firmware: %s (got %d)\n", next, id);
return HTTPD_CGI_DONE;
}
@ -103,9 +105,7 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) {
// return an error if there is one
if (err != NULL) {
#ifdef CGIFLASH_DBG
os_printf("Error %d: %s\n", code, err);
#endif
DBG("Error %d: %s\n", code, err);
httpdStartResponse(connData, code);
httpdHeader(connData, "Content-Type", "text/plain");
//httpdHeader(connData, "Content-Length", strlen(err)+2);
@ -124,14 +124,12 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) {
// erase next flash block if necessary
if (address % SPI_FLASH_SEC_SIZE == 0){
#ifdef CGIFLASH_DBG
os_printf("Flashing 0x%05x (id=%d)\n", address, 2-id);
#endif
DBG("Flashing 0x%05x (id=%d)\n", address, 2 - id);
spi_flash_erase_sector(address/SPI_FLASH_SEC_SIZE);
}
// Write the data
//os_printf("Writing %d bytes at 0x%05x (%d of %d)\n", connData->post->buffSize, address,
//DBG("Writing %d bytes at 0x%05x (%d of %d)\n", connData->post->buffSize, address,
// connData->post->received, connData->post->len);
spi_flash_write(address, (uint32 *)connData->post->buff, connData->post->buffLen);
@ -150,10 +148,10 @@ static ETSTimer flash_reboot_timer;
int ICACHE_FLASH_ATTR cgiRebootFirmware(HttpdConnData *connData) {
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
if (!canOTA()) {
errorResponse(connData, 400, flash_too_small);
return HTTPD_CGI_DONE;
}
if (!canOTA()) {
errorResponse(connData, 400, flash_too_small);
return HTTPD_CGI_DONE;
}
// sanity-check that the 'next' partition actually contains something that looks like
// valid firmware
@ -161,15 +159,11 @@ int ICACHE_FLASH_ATTR cgiRebootFirmware(HttpdConnData *connData) {
int address = id == 1 ? 4*1024 // either start after 4KB boot partition
: 4*1024 + FIRMWARE_SIZE + 16*1024 + 4*1024; // 4KB boot, fw1, 16KB user param, 4KB reserved
uint32 buf[8];
#ifdef CGIFLASH_DBG
os_printf("Checking %p\n", (void *)address);
#endif
DBG("Checking %p\n", (void *)address);
spi_flash_read(address, buf, sizeof(buf));
char *err = check_header(buf);
if (err != NULL) {
#ifdef CGIFLASH_DBG
os_printf("Error %d: %s\n", 400, err);
#endif
DBG("Error %d: %s\n", 400, err);
httpdStartResponse(connData, 400);
httpdHeader(connData, "Content-Type", "text/plain");
//httpdHeader(connData, "Content-Length", strlen(err)+2);
@ -190,3 +184,18 @@ int ICACHE_FLASH_ATTR cgiRebootFirmware(HttpdConnData *connData) {
os_timer_arm(&flash_reboot_timer, 2000, 1);
return HTTPD_CGI_DONE;
}
int ICACHE_FLASH_ATTR cgiReboot(HttpdConnData *connData) {
if (connData->conn == NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Length", "0");
httpdEndHeaders(connData);
// Schedule a reboot
system_upgrade_flag_set(UPGRADE_FLAG_FINISH);
os_timer_disarm(&flash_reboot_timer);
os_timer_setfn(&flash_reboot_timer, (os_timer_func_t *)system_upgrade_reboot, NULL);
os_timer_arm(&flash_reboot_timer, 2000, 1);
return HTTPD_CGI_DONE;
}

@ -7,5 +7,6 @@ int cgiReadFlash(HttpdConnData *connData);
int cgiGetFirmwareNext(HttpdConnData *connData);
int cgiUploadFirmware(HttpdConnData *connData);
int cgiRebootFirmware(HttpdConnData *connData);
int cgiReboot(HttpdConnData *connData);
#endif

@ -16,6 +16,12 @@ char *mqttState(void) {
#include "mqtt_client.h"
#include "cgimqtt.h"
#ifdef CGIMQTT_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
#else
#define DBG(format, ...) do { } while(0)
#endif
char *mqttState(void) {
return mqtt_states[mqttClient.connState];
}
@ -69,7 +75,6 @@ int ICACHE_FLASH_ATTR cgiMqttGet(HttpdConnData *connData) {
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;
@ -124,17 +129,14 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) {
// if server setting changed, we need to "make it so"
if (mqtt_server) {
#ifdef CGIMQTT_DBG
os_printf("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable);
#endif
DBG("MQTT server settings changed, enable=%d\n", flashConfig.mqtt_enable);
MQTT_Free(&mqttClient); // safe even if not connected
mqtt_client_init();
// if just enable changed we just need to bounce the client
} else if (mqtt_en_chg > 0) {
#ifdef CGIMQTT_DBG
os_printf("MQTT server enable=%d changed\n", flashConfig.mqtt_enable);
#endif
}
else if (mqtt_en_chg > 0) {
DBG("MQTT server enable=%d changed\n", flashConfig.mqtt_enable);
if (flashConfig.mqtt_enable && strlen(flashConfig.mqtt_host) > 0)
MQTT_Reconnect(&mqttClient);
else
@ -152,11 +154,11 @@ int ICACHE_FLASH_ATTR cgiMqttSet(HttpdConnData *connData) {
// 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;
#ifdef CGIMQTT_DBG
if (slip_update > 0) os_printf("SLIP-enable changed: %d\n", flashConfig.slip_enable);
if (slip_update > 0)
DBG("SLIP-enable changed: %d\n", flashConfig.slip_enable);
DBG("Saving config\n");
os_printf("Saving config\n");
#endif
if (configSave()) {
httpdStartResponse(connData, 200);
httpdEndHeaders(connData);
@ -178,4 +180,4 @@ int ICACHE_FLASH_ATTR cgiMqtt(HttpdConnData *connData) {
return HTTPD_CGI_DONE;
}
}
#endif // MQTT
#endif

@ -0,0 +1,205 @@
#include <esp8266.h>
#include "cgiwifi.h"
#include "cgi.h"
#include "config.h"
#include "syslog.h"
#include "sntp.h"
#include "cgimqtt.h"
#ifdef CGISERVICES_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
#else
#define DBG(format, ...) do { } while(0)
#endif
char* rst_codes[7] = {
"normal", "wdt reset", "exception", "soft wdt", "restart", "deep sleep", "external",
};
char* flash_maps[7] = {
"512KB:256/256", "256KB", "1MB:512/512", "2MB:512/512", "4MB:512/512",
"2MB:1024/1024", "4MB:1024/1024"
};
static ETSTimer reassTimer;
// Cgi to update system info (name/description)
int ICACHE_FLASH_ATTR cgiSystemSet(HttpdConnData *connData) {
if (connData->conn == NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
int8_t n = getStringArg(connData, "name", flashConfig.hostname, sizeof(flashConfig.hostname));
int8_t d = getStringArg(connData, "description", flashConfig.sys_descr, sizeof(flashConfig.sys_descr));
if (n < 0 || d < 0) return HTTPD_CGI_DONE; // getStringArg has produced an error response
if (n > 0) {
// schedule hostname change-over
os_timer_disarm(&reassTimer);
os_timer_setfn(&reassTimer, configWifiIP, NULL);
os_timer_arm(&reassTimer, 1000, 0); // 1 second for the response of this request to make it
}
if (configSave()) {
httpdStartResponse(connData, 204);
httpdEndHeaders(connData);
}
else {
httpdStartResponse(connData, 500);
httpdEndHeaders(connData);
httpdSend(connData, "Failed to save config", -1);
}
return HTTPD_CGI_DONE;
}
// Cgi to return various System information
int ICACHE_FLASH_ATTR cgiSystemInfo(HttpdConnData *connData) {
char buff[1024];
if (connData->conn == NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
uint8 part_id = system_upgrade_userbin_check();
uint32_t fid = spi_flash_get_id();
struct rst_info *rst_info = system_get_rst_info();
os_sprintf(buff,
"{ "
"\"name\": \"%s\", "
"\"reset cause\": \"%d=%s\", "
"\"size\": \"%s\", "
"\"id\": \"0x%02lX 0x%04lX\", "
"\"partition\": \"%s\", "
"\"slip\": \"%s\", "
"\"mqtt\": \"%s/%s\", "
"\"baud\": \"%ld\", "
"\"description\": \"%s\""
" }",
flashConfig.hostname,
rst_info->reason,
rst_codes[rst_info->reason],
flash_maps[system_get_flash_size_map()],
fid & 0xff, (fid & 0xff00) | ((fid >> 16) & 0xff),
part_id ? "user2.bin" : "user1.bin",
flashConfig.slip_enable ? "enabled" : "disabled",
flashConfig.mqtt_enable ? "enabled" : "disabled",
mqttState(),
flashConfig.baud_rate,
flashConfig.sys_descr
);
jsonHeader(connData, 200);
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
}
static void ICACHE_FLASH_ATTR cgiServicesSNTPInit() {
if (flashConfig.sntp_server[0]) {
DBG("SNTP timesource set to %s with offset %d\n", flashConfig.sntp_server, flashConfig.timezone_offset);
sntp_stop();
sntp_setservername(0, flashConfig.sntp_server);
sntp_set_timezone(flashConfig.timezone_offset);
sntp_init();
}
}
int ICACHE_FLASH_ATTR cgiServicesInfo(HttpdConnData *connData) {
char buff[1024];
if (connData->conn == NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
os_sprintf(buff,
"{ "
"\"syslog_enable\": \"%s\", "
"\"syslog_host\": \"%s\", "
"\"syslog_minheap\": %d, "
"\"syslog_filter\": %d, "
"\"syslog_showtick\": \"%s\", "
"\"syslog_showdate\": \"%s\", "
"\"timezone_offset\": %d, "
"\"sntp_server\": \"%s\", "
"\"mdns_enable\": \"%s\", "
"\"mdns_servername\": \"%s\""
" }",
flashConfig.syslog_enable ? "enabled" : "disabled",
flashConfig.syslog_host,
flashConfig.syslog_minheap,
flashConfig.syslog_filter,
flashConfig.syslog_showtick ? "enabled" : "disabled",
flashConfig.syslog_showdate ? "enabled" : "disabled",
flashConfig.timezone_offset,
flashConfig.sntp_server,
flashConfig.mdns_enable ? "enabled" : "disabled",
flashConfig.mdns_servername
);
jsonHeader(connData, 200);
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
}
int ICACHE_FLASH_ATTR cgiServicesSet(HttpdConnData *connData) {
if (connData->conn == NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
int8_t syslog = 0;
syslog |= getBoolArg(connData, "syslog_enable", &flashConfig.syslog_enable);
if (syslog < 0) return HTTPD_CGI_DONE;
syslog |= getStringArg(connData, "syslog_host", flashConfig.syslog_host, sizeof(flashConfig.syslog_host));
if (syslog < 0) return HTTPD_CGI_DONE;
syslog |= getUInt16Arg(connData, "syslog_minheap", &flashConfig.syslog_minheap);
if (syslog < 0) return HTTPD_CGI_DONE;
syslog |= getUInt8Arg(connData, "syslog_filter", &flashConfig.syslog_filter);
if (syslog < 0) return HTTPD_CGI_DONE;
syslog |= getBoolArg(connData, "syslog_showtick", &flashConfig.syslog_showtick);
if (syslog < 0) return HTTPD_CGI_DONE;
syslog |= getBoolArg(connData, "syslog_showdate", &flashConfig.syslog_showdate);
if (syslog < 0) return HTTPD_CGI_DONE;
int8_t sntp = 0;
sntp |= getInt8Arg(connData, "timezone_offset", &flashConfig.timezone_offset);
if (sntp < 0) return HTTPD_CGI_DONE;
sntp |= getStringArg(connData, "sntp_server", flashConfig.sntp_server, sizeof(flashConfig.sntp_server));
if (sntp < 0) return HTTPD_CGI_DONE;
int8_t mdns = 0;
mdns |= getBoolArg(connData, "mdns_enable", &flashConfig.mdns_enable);
if (mdns < 0) return HTTPD_CGI_DONE;
mdns |= getStringArg(connData, "mdns_servername", flashConfig.mdns_servername, sizeof(flashConfig.mdns_servername));
if (mdns < 0) return HTTPD_CGI_DONE;
if (syslog > 0) {
if (!flashConfig.syslog_enable) {
flashConfig.syslog_host[0] = '\0';
}
syslog_init(flashConfig.syslog_host);
}
if (sntp > 0) {
cgiServicesSNTPInit();
}
if (mdns > 0) {
espconn_mdns_disable();
if (flashConfig.mdns_enable) {
struct ip_info ipconfig;
wifi_get_ip_info(STATION_IF, &ipconfig);
mdns_started = false;
if (wifiState == wifiGotIP && ipconfig.ip.addr != 0) {
wifiStartMDNS(ipconfig.ip);
}
}
else {
mdns_started = true;
}
}
if (configSave()) {
httpdStartResponse(connData, 204);
httpdEndHeaders(connData);
}
else {
httpdStartResponse(connData, 500);
httpdEndHeaders(connData);
httpdSend(connData, "Failed to save config", -1);
}
return HTTPD_CGI_DONE;
}

@ -0,0 +1,15 @@
#ifndef CGISERVICES_H
#define CGISERVICES_H
#include "httpd.h"
int cgiSystemSet(HttpdConnData *connData);
int cgiSystemInfo(HttpdConnData *connData);
int cgiServicesInfo(HttpdConnData *connData);
int cgiServicesSet(HttpdConnData *connData);
extern char* rst_codes[7];
extern char* flash_maps[7];
#endif // CGISERVICES_H

@ -13,14 +13,12 @@ Cgi/template routines for the /wifi url.
* ----------------------------------------------------------------------------
*/
#include <esp8266.h>
#include "cgiwifi.h"
#include "cgi.h"
#include "status.h"
#include "config.h"
#include "log.h"
#include "sntp.h"
#ifdef CGIWIFI_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
@ -28,8 +26,7 @@ Cgi/template routines for the /wifi url.
#define DBG(format, ...) do { } while(0)
#endif
static void wifiStartMDNS(struct ip_addr);
static void wifiStartSNTP();
bool mdns_started = false;
// ===== wifi status change callbacks
static WifiStateChangeCb wifi_state_change_cb[4];
@ -85,7 +82,6 @@ static void ICACHE_FLASH_ATTR wifiHandleEventCb(System_Event_t *evt) {
IP2STR(&evt->event_info.got_ip.gw));
statusWifiUpdate(wifiState);
wifiStartMDNS(evt->event_info.got_ip.ip);
wifiStartSNTP();
break;
case EVENT_SOFTAPMODE_STACONNECTED:
DBG("Wifi AP: station " MACSTR " joined, AID = %d\n",
@ -104,8 +100,7 @@ static void ICACHE_FLASH_ATTR wifiHandleEventCb(System_Event_t *evt) {
}
}
void ICACHE_FLASH_ATTR
wifiAddStateChangeCb(WifiStateChangeCb cb) {
void ICACHE_FLASH_ATTR wifiAddStateChangeCb(WifiStateChangeCb cb) {
for (int i = 0; i < 4; i++) {
if (wifi_state_change_cb[i] == cb) return;
if (wifi_state_change_cb[i] == NULL) {
@ -116,56 +111,18 @@ wifiAddStateChangeCb(WifiStateChangeCb cb) {
DBG("WIFI: max state change cb count exceeded\n");
}
static bool mdns_started = false;
static ICACHE_FLASH_ATTR
void wifiStartMDNS(struct ip_addr ip) {
void ICACHE_FLASH_ATTR wifiStartMDNS(struct ip_addr ip) {
if (!mdns_started) {
struct mdns_info *mdns_info = (struct mdns_info *)os_zalloc(sizeof(struct mdns_info));
mdns_info->host_name = flashConfig.hostname;
mdns_info->server_name = "arduino"; // service name
mdns_info->server_name = flashConfig.mdns_servername; // service name
mdns_info->server_port = 80; // service port
mdns_info->ipAddr = ip.addr;
espconn_mdns_init(mdns_info);
espconn_mdns_init(mdns_info);
mdns_started = true;
}
}
static bool sntp_started = false;
static ETSTimer sntp_timer;
void ICACHE_FLASH_ATTR
user_check_sntp_stamp(void *arg){
uint32 current_stamp;
current_stamp = sntp_get_current_timestamp();
if (current_stamp == 0){
os_timer_arm(&sntp_timer, 100, 0);
}
else{
os_timer_disarm(&sntp_timer);
os_printf("sntp: %d, %s \n", current_stamp, sntp_get_real_time(current_stamp));
}
}
static ICACHE_FLASH_ATTR
void wifiStartSNTP() {
if (!sntp_started) {
ip_addr_t *addr = (ip_addr_t *)os_zalloc(sizeof(ip_addr_t));
sntp_setservername(0, "us.pool.ntp.org"); // set server 0 by domain name
sntp_setservername(1, "ntp.sjtu.edu.cn"); // set server 1 by domain name
IP4_ADDR(addr, 210, 72, 145, 44);
sntp_setserver(2, addr); // set server 2 by IP address
sntp_init();
os_free(addr);
os_timer_disarm(&sntp_timer);
os_timer_setfn(&sntp_timer, (os_timer_func_t *)user_check_sntp_stamp, NULL);
os_timer_arm(&sntp_timer, 100, 0);
sntp_started = true;
}
}
// ===== wifi scanning
//WiFi access point data
@ -398,7 +355,7 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) {
return HTTPD_CGI_DONE;
}
static bool parse_ip(char *buff, ip_addr_t *ip_ptr) {
static bool ICACHE_FLASH_ATTR 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

@ -16,7 +16,9 @@ int cgiWiFiSpecial(HttpdConnData *connData);
void configWifiIP();
void wifiInit(void);
void wifiAddStateChangeCb(WifiStateChangeCb cb);
void wifiStartMDNS(struct ip_addr);
extern uint8_t wifiState;
extern bool mdns_started;
#endif

@ -9,21 +9,28 @@
FlashConfig flashConfig;
FlashConfig flashDefault = {
33, 0, 0,
MCU_RESET_PIN, MCU_ISP_PIN, LED_CONN_PIN, LED_SERIAL_PIN,
115200,
"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
2, 1, // mqtt_timeout, mqtt_clean_session
1883, 60, // mqtt port, mqtt_keepalive
"\0", "\0", "\0", "\0", "\0", // mqtt host, client_id, user, password, status-topic
"\0", // system description
1, // rx_pullup
.seq = 33, .magic = 0, .crc = 0,
.reset_pin = MCU_RESET_PIN, .isp_pin = MCU_ISP_PIN,
.conn_led_pin = LED_CONN_PIN, .ser_led_pin = LED_SERIAL_PIN,
.baud_rate = 115200,
.hostname = "esp-link\0",
.staticip = 0,
.netmask = 0x00ffffff,
.gateway = 0,
.log_mode = 0,
.swap_uart = 0,
.tcp_enable = 1, .rssi_enable = 0,
.api_key = "",
.slip_enable = 0, .mqtt_enable = 0, .mqtt_status_enable = 0,
.mqtt_timeout = 2, .mqtt_clean_session = 1,
.mqtt_port = 1883, .mqtt_keepalive = 60,
.mqtt_host = "\0", .mqtt_clientid = "\0",
.mqtt_username= "\0", .mqtt_password = "\0", .mqtt_status_topic = "\0",
.sys_descr = "\0",
.rx_pullup = 1,
.mdns_enable = 1, .mdns_servername = "http\0",
.sntp_server = "us.pool.ntp.org\0", .timezone_offset = 0,
.syslog_enable= 0, .syslog_host = "\0", .syslog_minheap = 8192, .syslog_filter = 7, .syslog_showtick = 1, .syslog_showdate = 0,
};
typedef union {

@ -21,10 +21,23 @@ typedef struct {
mqtt_timeout, // MQTT send timeout
mqtt_clean_session; // MQTT clean session
uint16_t mqtt_port, mqtt_keepalive; // MQTT Host port, MQTT Keepalive timer
char mqtt_host[32], mqtt_clientid[48], mqtt_username[32], mqtt_password[32];
char mqtt_status_topic[32];
char mqtt_host[32],
mqtt_clientid[48],
mqtt_username[32],
mqtt_password[32],
mqtt_status_topic[32];
char sys_descr[129]; // system description
int8_t rx_pullup; // internal pull-up on RX pin
uint8_t mdns_enable;
char mdns_servername[32],
sntp_server[32];
int8_t timezone_offset;
uint8_t syslog_enable;
char syslog_host[32];
uint16_t syslog_minheap; // min. heap to allow queuing
uint8_t syslog_filter, // min. severity
syslog_showtick, // show system tick (µs)
syslog_showdate; // populate SYSLOG date field
} FlashConfig;
extern FlashConfig flashConfig;

@ -9,7 +9,6 @@
* ----------------------------------------------------------------------------
*/
#include <esp8266.h>
#include "httpd.h"
#include "httpdespfs.h"
@ -30,9 +29,13 @@
#include "config.h"
#include "log.h"
#include "gpio.h"
#include "syslog.h"
#include "cgiservices.h"
static int ICACHE_FLASH_ATTR cgiSystemInfo(HttpdConnData *connData);
static int ICACHE_FLASH_ATTR cgiSystemSet(HttpdConnData *connData);
#define NOTICE(format, ...) do { \
LOG_NOTICE(format, ## __VA_ARGS__ ); \
os_printf(format "\n", ## __VA_ARGS__); \
} while ( 0 )
/*
This is the main url->function dispatching data struct.
@ -54,6 +57,7 @@ HttpdBuiltInUrl builtInUrls[] = {
{ "/pgm/upload", cgiOptibootData, NULL },
{ "/log/text", ajaxLog, NULL },
{ "/log/dbg", ajaxLogDbg, NULL },
{ "/log/reboot", cgiReboot, NULL },
{ "/console/reset", ajaxConsoleReset, NULL },
{ "/console/baud", ajaxConsoleBaud, NULL },
{ "/console/text", ajaxConsole, NULL },
@ -70,11 +74,12 @@ HttpdBuiltInUrl builtInUrls[] = {
{ "/wifi/special", cgiWiFiSpecial, NULL },
{ "/system/info", cgiSystemInfo, NULL },
{ "/system/update", cgiSystemSet, NULL },
{ "/services/info", cgiServicesInfo, NULL },
{ "/services/update", cgiServicesSet, NULL },
{ "/pins", cgiPins, NULL },
#ifdef MQTT
{ "/mqtt", cgiMqtt, NULL },
#endif
#endif
{ "*", cgiEspFsHook, NULL }, //Catch-all cgi function for the filesystem
{ NULL, NULL, NULL }
};
@ -94,69 +99,6 @@ char* esp_link_version = VERS_STR(VERSION);
// address of espfs binary blob
extern uint32_t _binary_espfs_img_start;
static char *rst_codes[] = {
"normal", "wdt reset", "exception", "soft wdt", "restart", "deep sleep", "external",
};
static char *flash_maps[] = {
"512KB:256/256", "256KB", "1MB:512/512", "2MB:512/512", "4MB:512/512",
"2MB:1024/1024", "4MB:1024/1024"
};
// Cgi to return various System information
static int ICACHE_FLASH_ATTR cgiSystemInfo(HttpdConnData *connData) {
char buff[1024];
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
uint8 part_id = system_upgrade_userbin_check();
uint32_t fid = spi_flash_get_id();
struct rst_info *rst_info = system_get_rst_info();
os_sprintf(buff, "{\"name\": \"%s\", \"reset cause\": \"%d=%s\", "
"\"size\": \"%s\"," "\"id\": \"0x%02lX 0x%04lX\"," "\"partition\": \"%s\","
"\"slip\": \"%s\"," "\"mqtt\": \"%s/%s\"," "\"baud\": \"%ld\","
"\"description\": \"%s\"" "}",
flashConfig.hostname, rst_info->reason, rst_codes[rst_info->reason],
flash_maps[system_get_flash_size_map()], fid & 0xff, (fid&0xff00)|((fid>>16)&0xff),
part_id ? "user2.bin" : "user1.bin",
flashConfig.slip_enable ? "enabled" : "disabled",
flashConfig.mqtt_enable ? "enabled" : "disabled",
mqttState(), flashConfig.baud_rate, flashConfig.sys_descr
);
jsonHeader(connData, 200);
httpdSend(connData, buff, -1);
return HTTPD_CGI_DONE;
}
static ETSTimer reassTimer;
// Cgi to update system info (name/description)
static int ICACHE_FLASH_ATTR cgiSystemSet(HttpdConnData *connData) {
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
int8_t n = getStringArg(connData, "name", flashConfig.hostname, sizeof(flashConfig.hostname));
int8_t d = getStringArg(connData, "description", flashConfig.sys_descr, sizeof(flashConfig.sys_descr));
if (n < 0 || d < 0) return HTTPD_CGI_DONE; // getStringArg has produced an error response
if (n > 0) {
// schedule hostname change-over
os_timer_disarm(&reassTimer);
os_timer_setfn(&reassTimer, configWifiIP, NULL);
os_timer_arm(&reassTimer, 1000, 0); // 1 second for the response of this request to make it
}
if (configSave()) {
httpdStartResponse(connData, 204);
httpdEndHeaders(connData);
} else {
httpdStartResponse(connData, 500);
httpdEndHeaders(connData);
httpdSend(connData, "Failed to save config", -1);
}
return HTTPD_CGI_DONE;
}
extern void app_init(void);
extern void mqtt_client_init(void);
@ -168,7 +110,7 @@ void user_rf_pre_init(void) {
// Main routine to initialize esp-link.
void user_init(void) {
// get the flash config so we know how to init things
//configWipe(); // uncomment to reset the config for testing purposes
// configWipe(); // uncomment to reset the config for testing purposes
bool restoreOk = configRestore();
// init gpio pin registers
gpio_init();
@ -225,18 +167,24 @@ void user_init(void) {
#endif
struct rst_info *rst_info = system_get_rst_info();
os_printf("Reset cause: %d=%s\n", rst_info->reason, rst_codes[rst_info->reason]);
os_printf("exccause=%d epc1=0x%x epc2=0x%x epc3=0x%x excvaddr=0x%x depc=0x%x\n",
NOTICE("Reset cause: %d=%s", rst_info->reason, rst_codes[rst_info->reason]);
NOTICE("exccause=%d epc1=0x%x epc2=0x%x epc3=0x%x excvaddr=0x%x depc=0x%x",
rst_info->exccause, rst_info->epc1, rst_info->epc2, rst_info->epc3,
rst_info->excvaddr, rst_info->depc);
uint32_t fid = spi_flash_get_id();
os_printf("Flash map %s, manuf 0x%02lX chip 0x%04lX\n", flash_maps[system_get_flash_size_map()],
NOTICE("Flash map %s, manuf 0x%02lX chip 0x%04lX", flash_maps[system_get_flash_size_map()],
fid & 0xff, (fid&0xff00)|((fid>>16)&0xff));
NOTICE("** esp-link ready");
//enableSNTP();
os_printf("** esp-link ready\n");
#ifdef MQTT
NOTICE("initializing MQTT");
mqtt_client_init();
#endif
NOTICE("initializing user application");
app_init();
NOTICE("waiting for work to do...");
}

@ -0,0 +1,78 @@
/*
* task.c
*
* Copyright 2015 Susi's Strolch
*
* For license information see projects "License.txt"
*
* Not sure if it's save to use ICACHE_FLASH_ATTR, so we're running from RAM
*/
#undef USRTASK_DBG
#include "esp8266.h"
#include <task.h>
#define MAXUSRTASKS 8
#ifdef USRTASK_DBG
#define DBG_USRTASK(format, ...) os_printf(format, ## __VA_ARGS__)
#else
#define DBG_USRTASK(format, ...) do { } while(0)
#endif
LOCAL os_event_t *_task_queue = NULL; // system_os_task queue
LOCAL os_task_t *usr_task_queue = NULL; // user task queue
// it seems save to run the usr_event_handler from RAM, so no ICACHE_FLASH_ATTR here...
LOCAL void usr_event_handler(os_event_t *e)
{
DBG_USRTASK("usr_event_handler: event %p (sig=%d, par=%p)\n", e, (int)e->sig, (void *)e->par);
if (usr_task_queue[e->sig] == NULL || e->sig < 0 || e->sig >= MAXUSRTASKS) {
os_printf("usr_event_handler: task %d %s\n", (int)e->sig,
usr_task_queue[e->sig] == NULL ? "not registered" : "out of range");
return;
}
(usr_task_queue[e->sig])(e);
}
LOCAL void init_usr_task() {
if (_task_queue == NULL)
_task_queue = (os_event_t *)os_zalloc(sizeof(os_event_t) * _task_queueLen);
if (usr_task_queue == NULL)
usr_task_queue = (os_task_t *)os_zalloc(sizeof(os_task_t) * MAXUSRTASKS);
system_os_task(usr_event_handler, _taskPrio, _task_queue, _task_queueLen);
}
// public functions
bool post_usr_task(uint8_t task, os_param_t par)
{
return system_os_post(_taskPrio, task, par);
}
uint8_t register_usr_task (os_task_t event)
{
int task;
DBG_USRTASK("register_usr_task: %p\n", event);
if (_task_queue == NULL || usr_task_queue == NULL)
init_usr_task();
for (task = 0; task < MAXUSRTASKS; task++) {
if (usr_task_queue[task] == event)
return task; // task already registered - bail out...
}
for (task = 0; task < MAXUSRTASKS; task++) {
if (usr_task_queue[task] == NULL) {
DBG_USRTASK("register_usr_task: assign task #%d\n", task);
usr_task_queue[task] = event;
break;
}
}
return task;
}

@ -0,0 +1,20 @@
/*
* task.h
*
* Copyright 2015 Susi's Strolch
*
* For license information see projects "License.txt"
*
*
*/
#ifndef USRTASK_H
#define USRTASK_H
#define _taskPrio 1
#define _task_queueLen 64
uint8_t register_usr_task (os_task_t event);
bool post_usr_task(uint8_t task, os_param_t par);
#endif

@ -5,7 +5,8 @@
<div class="content flex-fill flex-vbox">
<p>
<a id="reset-button" class="pure-button button-primary" href="#">Reset µC</a>
<a id="reset-button" class="pure-button button-primary" href="#">Reset &#xb5;C</a>
<a id="clear-button" class="pure-button button-primary" href="#">Clear Log</a>
&nbsp;&nbsp;Baud:
<select id="baud-sel" class="pure-button" href="#">
<option value="460800">460800</option>
@ -17,19 +18,6 @@
<option value="19200">19200</option>
<option value="9600">9600</option>
</select>
<!--
&nbsp;&nbsp;Pgm baud:
<select id="baud-pgm" class="pure-button">
<option value="same">same</option>
<option value="460800">460800</option>
<option value="250000">250000</option>
<option value="230400">230400</option>
<option value="115200">115200</option>
<option value="57600">57600</option>
<option value="38400">38400</option>
<option value="19200">19200</option>
<option value="9600">9600</option>
</select> -->
&nbsp;&nbsp;Fmt: 8N1
</p>
<div class="pure-g">
@ -85,6 +73,12 @@
);
});
$("#clear-button").addEventListener("click", function(e) {
e.preventDefault();
var co = $("#console");
co.innerHTML = "";
});
ajaxJson('GET', "/console/baud",
function(data) { $("#baud-sel").value = data.rate; },
function(s, st) { showNotification(st); }

@ -21,7 +21,7 @@ function updateText(resp) {
var delay = 3000;
if (resp != null && resp.len > 0) {
console.log("updateText got", resp.len, "chars at", resp.start);
// console.log("updateText got", resp.len, "chars at", resp.start);
var isScrolledToBottom = el.scrollHeight - el.clientHeight <= el.scrollTop + 1;
//console.log("isScrolledToBottom="+isScrolledToBottom, "scrollHeight="+el.scrollHeight,
// "clientHeight="+el.clientHeight, "scrollTop="+el.scrollTop,

Binary file not shown.

Before

Width:  |  Height:  |  Size: 498 B

After

Width:  |  Height:  |  Size: 874 B

@ -59,20 +59,21 @@
<div id="pin-table" hidden>
<form action="#" id="pinform" class="pure-form pure-form-aligned form-narrow">
<div class="pure-control-group">
<label for="pin-preset">Presets</label><select id="pin-preset" class="pure-button">
<label for="pin-preset">Presets</label>
<select id="pin-preset" class="pure-button">
<option value="" selected disabled></option>
</select></label>
</select>
</div>
<hr>
<div class="pure-control-group">
<label for="pin-reset">Reset</label>
<select id="pin-reset"></select>
<div class="popup">Connect to uC reset pin for programming and reset-uC function</div>
<div class="popup">Connect to &#xb5;C reset pin for programming and reset-&#xb5;C function</div>
</div>
<div class="pure-control-group">
<label for="pin-isp">ISP/Flash</label>
<select id="pin-isp"></select>
<div class="popup">Second signal to program uC.
<div class="popup">Second signal to program &#xb5;C.
AVR:not used, esp8266:gpio2, ARM:ISP</div>
</div>
<div class="pure-control-group">

@ -9,6 +9,8 @@
<div class="pure-g">
<p class="pure-u-1-4">
<a id="refresh-button" class="pure-button button-primary" href="#">Refresh</a>
<a id="reboot-button" class="pure-button button-primary" href="#">Reboot esp-link</a>
<a id="clear-button" class="pure-button button-primary" href="#">Clear Log</a>
</p>
<p class="pure-u-3-4" style="vertical-align: baseline">
UART debug log:
@ -34,6 +36,22 @@
fetchText(100, false);
});
$("#reboot-button").addEventListener("click", function (e) {
e.preventDefault();
var co = $("#console");
co.innerHTML = "";
ajaxSpin('POST', "/log/reboot",
function (resp) { showNotification("esp-link reset"); co.textEnd = 0; },
function (s, st) { showWarning("Error resetting esp-link"); }
);
});
$("#clear-button").addEventListener("click", function (e) {
e.preventDefault();
var co = $("#console");
co.innerHTML = "";
});
["auto", "off", "on0", "on1"].forEach(function(mode) {
bnd($('#dbg-'+mode), "click", function(el) {
ajaxJsonSpin('POST', "/log/dbg?mode="+mode,

@ -44,7 +44,7 @@ function displayMqtt(data) {
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) };
inputs[i].onclick = function () { setMqtt(this.name, this.checked) };
}
}

@ -0,0 +1,111 @@
<div id="main">
<div class="header">
<h1>Services</h1>
</div>
<div class="content">
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<h1>
Syslog
<div id="syslog-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="Syslog-form" class="pure-form" hidden>
<div class="form-horizontal">
<label>Enable syslog</label>
<input type="checkbox" name="syslog_enable"/>
</div>
<br>
<legend>Syslog settings</legend>
<div class="pure-form-stacked">
<label>Syslog Host</label>
<input type="text" name="syslog_host" />
<div class="popup">Use server [hostname:port] as UDP Syslog server</div>
</div>
<div class="pure-form-stacked">
<label>Min Heap</label>
<input type="text" name="syslog_minheap" />
<label>Filter</label>
<select name="syslog_filter" href="#">
<option value="0">EMERG</option>
<option value="1">ALERT</option>
<option value="2">CRIT</option>
<option value="3">ERR</option>
<option value="4">WARNING</option>
<option value="5">NOTICE</option>
<option value="6">INFO</option>
<option value="7">DEBUG</option>
</select>
</div>
<div class="form-horizontal">
<label>Show ESP &#xb5;C Ticker in log message</label>
<input type="checkbox" name="syslog_showtick" />
</div>
<div class="form-horizontal">
<label>Show date in log message</label>
<input type="checkbox" name="syslog_showdate" />
<div class="popup">Synology does a log rotate if timestamp is in the past so disable to prevent this</div>
</div>
<button id="Syslog-button" type="submit" class="pure-button button-primary">
Update syslog settings!
</button>
</form>
</div>
<div class="card">
<h1>
mDNS
<div id="mdns-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="mDNS-form" class="pure-form" hidden>
<div class="form-horizontal">
<input type="checkbox" name="mdns_enable"/>
<label>Enable mDNS</label>
</div>
<br>
<legend>mDNS server settings</legend>
<div class="pure-form-stacked">
<label>Server Name</label>
<input type="text" name="mdns_servername"/>
</div>
<button id="mDNS-button" type="submit" class="pure-button button-primary">
Update mDNS settings!
</button>
</form>
</div>
</div>
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<h1>
SNTP
<div id="sntp-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="SNTP-form" class="pure-form" hidden>
<legend>SNTP server settings</legend>
<div class="pure-form-stacked">
<label>Timezone Offset</label>
<input type="text" name="timezone_offset" />
<label>SNTP Server</label>
<input type="text" name="sntp_server" />
</div>
<button id="SNTP-button" type="submit" class="pure-button button-primary">
Update SNTP settings!
</button>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="services.js"></script>
<script type="text/javascript">
onLoad(function() {
fetchServices();
bnd($("#Syslog-form"), "submit", changeServices);
bnd($("#SNTP-form"), "submit", changeServices);
bnd($("#mDNS-form"), "submit", changeServices);
});
</script>
</body></html>

@ -0,0 +1,74 @@
function changeServices(e) {
e.preventDefault();
var url = "services/update?1=1";
var i, inputs = document.querySelectorAll('#' + e.srcElement.id + ' input');
for (i = 0; i < inputs.length; i++) {
if (inputs[i].type == "checkbox") {
var val = (inputs[i].checked) ? 1 : 0;
url += "&" + inputs[i].name + "=" + val;
}
else
url += "&" + inputs[i].name + "=" + inputs[i].value;
};
hideWarning();
var n = e.srcElement.id.replace("-form", "");
var cb = $("#" + n + "-button");
addClass(cb, 'pure-button-disabled');
ajaxSpin("POST", url, function (resp) {
showNotification(n + " updated");
removeClass(cb, 'pure-button-disabled');
}, function (s, st) {
showWarning("Error: " + st);
removeClass(cb, 'pure-button-disabled');
window.setTimeout(fetchServices, 100);
});
}
function displayServices(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] == "enabled";
} else el.value = data[v];
}
});
$("#syslog-spinner").setAttribute("hidden", "");
$("#sntp-spinner").setAttribute("hidden", "");
$("#mdns-spinner").setAttribute("hidden", "");
$("#Syslog-form").removeAttribute("hidden");
$("#SNTP-form").removeAttribute("hidden");
$("#mDNS-form").removeAttribute("hidden");
var i, inputs = $("input");
for (i = 0; i < inputs.length; i++) {
if (inputs[i].type == "checkbox" && (inputs[i].name == "syslog_enable" || inputs[i].name == "mdns_enable")) { }
inputs[i].onclick = function () { setService(this.name, this.checked) };
}
}
function setService(name, v) {
ajaxSpin("POST", "/services/update?" + name + "=" + (v ? 1 : 0), function () {
var n = name.replace("_enable", "");
n = (n == "syslog") ? "Syslog" : "mDNS";
showNotification(n + " is now " + (v ? "enabled" : "disabled"));
}, function () {
showWarning("Enable/disable failed");
window.setTimeout(fetchServices, 100);
});
}
function fetchServices() {
ajaxJson("GET", "/services/info", displayServices, function () {
window.setTimeout(fetchServices, 1000);
});
}

@ -164,14 +164,14 @@ function ajaxReq(method, url, ok_cb, err_cb) {
if (xhr.readyState != 4) { return; }
clearTimeout(timeout);
if (xhr.status >= 200 && xhr.status < 300) {
console.log("XHR done:", method, url, "->", xhr.status);
// 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);
// console.log("XHR send:", method, url);
try {
xhr.send();
} catch(err) {
@ -244,7 +244,7 @@ onLoad(function() {
// make hamburger button pull out menu
var ml = $('#menuLink'), mm = $('#menu');
bnd(ml, 'click', function (e) {
console.log("hamburger time");
// console.log("hamburger time");
var active = 'active';
e.preventDefault();
toggleClass(l, active);
@ -346,7 +346,7 @@ function makeAjaxInput(klass, field) {
}
var submitEditToClick = function(v) {
console.log("Submit POST "+url+"="+v);
// console.log("Submit POST "+url+"="+v);
ajaxSpin("POST", url+"="+v, function() {
domForEach(eon, function(el){ el.setAttribute('hidden',''); });
eoff.removeAttribute('hidden');
@ -410,7 +410,7 @@ function createPresets(sel) {
function applyPreset(v) {
var pp = pinPresets[v];
if (pp === undefined) return pp;
console.log("apply preset:", v, pp);
// console.log("apply preset:", v, pp);
function setPP(k, v) { $("#pin-"+k).value = v; };
setPP("reset", pp[0]);
setPP("isp", pp[1]);
@ -474,7 +474,7 @@ function setPins(ev) {
sep = "&";
});
url += "&rxpup=" + ($("#pin-rxpup").selected ? "1" : "0");
console.log("set pins: " + url);
// console.log("set pins: " + url);
ajaxSpin("POST", url, function() {
showNotification("Pin assignment changed");
}, function(status, errMsg) {

@ -10,7 +10,7 @@
<div id="wifi-spinner" class="spinner spinner-small"></div>
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>Wifi channel</td><td id="wifi-chan"></td></tr>
<tr><td>Wifi channel</td><td id="wifi-chan"></td></tr>
<tr><td>Configured network</td><td id="wifi-ssid"></td></tr>
<tr><td>Wifi status</td><td id="wifi-status"></td></tr>
<tr><td>Wifi address</td><td id="wifi-ip"></td></tr>
@ -30,8 +30,7 @@
<div id="aps">Scanning... <div class="spinner spinner-small"></div></div>
<label for="opt-hiddenssid">
<input type="radio" name="essid" value="_hidden_ssid_" id="opt-hiddenssid">
<input type="text" id="hidden-ssid" value=""
style="width:auto; display:inline-block; margin-left: 0.7em">
<input type="text" id="hidden-ssid" value="" style="width:auto; display:inline-block; margin-left: 0.7em">
</label>
<label>WiFi password, if applicable:</label>
<input id="wifi-passwd" type="password" name="passwd" placeholder="password">
@ -61,8 +60,7 @@
<label>Gateway (for static IP)</label>
<input id="wifi-gateway" type="text" name="gateway"/>
</div>
<button id="special-button" type="submit"
class="pure-button button-primary">Change!</button>
<button id="special-button" type="submit" class="pure-button button-primary">Change!</button>
</form>
</div></div>
</div>

@ -82,7 +82,7 @@ function scanResult() {
}
function scanAPs() {
console.log("scanning now");
// console.log("scanning now");
if (blockScan) {
scanTimeout = window.setTimeout(scanAPs, 1000);
return;
@ -184,7 +184,7 @@ function changeSpecial(e) {
addClass(cb, 'pure-button-disabled');
ajaxSpin("POST", url, function(resp) {
removeClass(cb, 'pure-button-disabled');
getWifiInfo();
//getWifiInfo(); // it takes 1 second for new settings to be applied
}, function(s, st) {
showWarning("Error: "+st);
removeClass(cb, 'pure-button-disabled');

@ -3,6 +3,10 @@
#include <user_interface.h>
#include <eagle_soc.h>
#include <stdint.h>
#include <c_types.h>
#include <ets_sys.h>
#include <stdarg.h>
//Missing function prototypes in include folders. Gcc will warn on these if we don't define 'em anywhere.
//MOST OF THESE ARE GUESSED! but they seem to work and shut up the compiler.
@ -43,14 +47,17 @@ void ets_update_cpu_frequency(int freqmhz);
#define DEBUG_SDK false
#endif
int ets_vsprintf(char *str, const char *format, va_list argptr);
int ets_vsnprintf(char *buffer, size_t sizeOfBuffer, const char *format, va_list argptr);
int os_snprintf(char *str, size_t size, const char *format, ...) __attribute__((format(printf, 3, 4)));
int os_printf_plus(const char *format, ...) __attribute__((format(printf, 1, 2)));
#undef os_printf
#define os_printf(format, ...) \
system_set_os_print(true); \
os_printf_plus(format, ## __VA_ARGS__); \
system_set_os_print(DEBUG_SDK); // int os_printf(const char *format, ...)
#define os_printf(format, ...) do { \
system_set_os_print(true); \
os_printf_plus(format, ## __VA_ARGS__); \
system_set_os_print(DEBUG_SDK); \
} while (0)
// memory allocation functions are "different" due to memory debugging functionality

@ -31,6 +31,8 @@
#define UART_DBG
#define MDNS_DBG
#define OPTIBOOT_DBG
#define SYSLOG_DBG
#define CGISERVICES_DBG
// If defined, the default hostname for DHCP will include the chip ID to make it unique
#undef CHIP_IN_HOSTNAME

@ -10,6 +10,7 @@
#include "console.h"
#include "slip.h"
#include "cmd.h"
#include "syslog.h"
#define SKIP_AT_RESET
@ -404,11 +405,12 @@ serbridgeConnectCb(void *arg)
#ifdef SERBR_DBG
os_printf("Accept port %d, conn=%p, pool slot %d\n", conn->proto.tcp->local_port, conn, i);
#endif
syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_NOTICE, "esp-link", "Accept port %d, conn=%p, pool slot %d\n", conn->proto.tcp->local_port, conn, i);
if (i==MAX_CONN) {
#ifdef SERBR_DBG
os_printf("Aiee, conn pool overflow!\n");
#endif
syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_WARNING, "esp-link", "Aiee, conn pool overflow!\n");
espconn_disconnect(conn);
return;
}

@ -18,6 +18,7 @@
* Heavily modified and enhanced by Thorsten von Eicken in 2015
*/
#include "esp8266.h"
#include "task.h"
#include "uart.h"
#ifdef UART_DBG
@ -26,14 +27,10 @@
#define DBG_UART(format, ...) do { } while(0)
#endif
#define recvTaskPrio 1
#define recvTaskQueueLen 64
LOCAL uint8_t uart_recvTaskNum;
// UartDev is defined and initialized in rom code.
extern UartDevice UartDev;
os_event_t recvTaskQueue[recvTaskQueueLen];
#define MAX_CB 4
static UartRecv_cb uart_recv_cb[4];
@ -208,7 +205,7 @@ uart0_rx_intr_handler(void *para)
{
//DBG_UART("stat:%02X",*(uint8 *)UART_INT_ENA(uart_no));
ETS_UART_INTR_DISABLE();
system_os_post(recvTaskPrio, 0, 0);
post_usr_task(uart_recvTaskNum, 0);
}
}
@ -284,7 +281,7 @@ uart_init(UartBautRate uart0_br, UartBautRate uart1_br)
// install uart1 putc callback
os_install_putc1((void *)uart0_write_char);
system_os_task(uart_recvTask, recvTaskPrio, recvTaskQueue, recvTaskQueueLen);
uart_recvTaskNum = register_usr_task(uart_recvTask);
}
void ICACHE_FLASH_ATTR

@ -0,0 +1,382 @@
/*
* syslog.c
*
*
* Copyright 2015 Susi's Strolch
*
* For license information see projects "License.txt"
*
*/
#include <esp8266.h>
#include "config.h"
#include "syslog.h"
#include "time.h"
#include "task.h"
extern void * mem_trim(void *m, size_t s); // not well documented...
#ifdef SYSLOG_DBG
#define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
#else
#define DBG(format, ...) do { } while(0)
#endif
#define WIFI_CHK_INTERVAL 1000 // ms to check Wifi statis
static os_timer_t wifi_chk_timer;
static struct espconn syslog_espconn;
static uint32_t syslog_msgid = 1;
static uint8_t syslog_task = 0;
static syslog_host_t syslogHost;
static syslog_entry_t *syslogQueue = NULL;
static enum syslog_state syslogState = SYSLOG_NONE;
static void ICACHE_FLASH_ATTR syslog_add_entry(syslog_entry_t *entry);
static void ICACHE_FLASH_ATTR syslog_chk_wifi_stat(void);
static void ICACHE_FLASH_ATTR syslog_udp_sent_cb(void *arg);
#ifdef SYSLOG_UDP_RECV
static void ICACHE_FLASH_ATTR syslog_udp_recv_cb(void *arg, char *pusrdata, unsigned short length);
#endif
#define syslog_send_udp() post_usr_task(syslog_task,0)
/******************************************************************************
* FunctionName : syslog_chk_wifi_stat
* Description : check whether get ip addr or not
* Parameters : none
* Returns : none
*******************************************************************************/
static void ICACHE_FLASH_ATTR syslog_chk_wifi_stat(void)
{
struct ip_info ipconfig;
DBG("syslog_chk_wifi_stat: state: %d ", syslogState);
//disarm timer first
os_timer_disarm(&wifi_chk_timer);
//try to get ip info of ESP8266 station
wifi_get_ip_info(STATION_IF, &ipconfig);
int wifi_status = wifi_station_get_connect_status();
if (wifi_status == STATION_GOT_IP && ipconfig.ip.addr != 0)
{
if (syslogState == SYSLOG_WAIT) { // waiting for initialization
DBG("connected, initializing UDP socket\n");
syslog_init(flashConfig.syslog_host);
}
} else {
if ((wifi_status == STATION_WRONG_PASSWORD ||
wifi_status == STATION_NO_AP_FOUND ||
wifi_status == STATION_CONNECT_FAIL)) {
syslogState = SYSLOG_ERROR;
os_printf("*** connect failure!!!\n");
} else {
DBG("re-arming timer...\n");
os_timer_setfn(&wifi_chk_timer, (os_timer_func_t *)syslog_chk_wifi_stat, NULL);
os_timer_arm(&wifi_chk_timer, WIFI_CHK_INTERVAL, 0);
}
}
}
static void ICACHE_FLASH_ATTR syslog_udp_send_event(os_event_t *events) {
if (syslogQueue == NULL)
syslogState = SYSLOG_READY;
else {
int res = 0;
syslog_espconn.proto.udp->remote_port = syslogHost.port; // ESP8266 udp remote port
os_memcpy(&syslog_espconn.proto.udp->remote_ip, &syslogHost.addr.addr, 4); // ESP8266 udp remote IP
res = espconn_send(&syslog_espconn, (uint8_t *)syslogQueue->datagram, syslogQueue->datagram_len);
if (res != 0) {
os_printf("syslog_udp_send: error %d\n", res);
}
}
}
/******************************************************************************
* FunctionName : syslog_compose
* Description : compose a syslog_entry_t from va_args
* Parameters : va_args
* Returns : the malloced syslog_entry_t
******************************************************************************/
static syslog_entry_t* ICACHE_FLASH_ATTR syslog_compose(uint8_t facility, uint8_t severity, const char *tag, const char *fmt, ...)
{
syslog_entry_t *se = os_zalloc(sizeof (syslog_entry_t) + 1024); // allow up to 1k datagram
char *p = se->datagram;
uint32_t tick = WDEV_NOW(); // 0 ... 4294.967295s
// The Priority value is calculated by first multiplying the Facility
// number by 8 and then adding the numerical value of the Severity.
p += os_sprintf(p, "<%d> ", facility * 8 + severity);
// strftime doesn't work as expected - or adds 8k overhead.
// so let's do poor man conversion - format is fixed anyway
if (flashConfig.syslog_showdate == 0)
p += os_sprintf(p, "- ");
else {
time_t now = NULL;
struct tm *tp = NULL;
// create timestamp: FULL-DATE "T" PARTIAL-TIME "Z": 'YYYY-mm-ddTHH:MM:SSZ '
// as long as realtime_stamp is 0 we use tick div 10⁶ as date
now = (realtime_stamp == 0) ? (tick / 1000000) : realtime_stamp;
tp = gmtime(&now);
p += os_sprintf(p, "%4d-%02d-%02dT%02d:%02d:%02dZ ",
tp->tm_year + 1900, tp->tm_mon + 1, tp->tm_mday,
tp->tm_hour, tp->tm_min, tp->tm_sec);
}
// add HOSTNAME APP-NAME PROCID MSGID
if (flashConfig.syslog_showtick)
p += os_sprintf(p, "%s %s %lu.%06lu %lu ", flashConfig.hostname, tag, tick / 1000000, tick % 1000000, syslog_msgid++);
else
p += os_sprintf(p, "%s %s - %lu ", flashConfig.hostname, tag, syslog_msgid++);
// append syslog message
va_list arglist;
va_start(arglist, fmt);
p += ets_vsprintf(p, fmt, arglist );
va_end(arglist);
se->datagram_len = p - se->datagram;
se = mem_trim(se, sizeof(syslog_entry_t) + se->datagram_len + 1);
return se;
}
/******************************************************************************
* FunctionName : syslog_add_entry
* Description : add a syslog_entry_t to the syslogQueue
* Parameters : entry: the syslog_entry_t
* Returns : none
******************************************************************************/
static void ICACHE_FLASH_ATTR syslog_add_entry(syslog_entry_t *entry)
{
syslog_entry_t *pse = syslogQueue;
// append msg to syslog_queue
if (pse == NULL)
syslogQueue = entry;
else {
while (pse->next != NULL)
pse = pse->next;
pse->next = entry; // append msg to syslog queue
}
// ensure we have sufficient heap for the rest of the system
if (system_get_free_heap_size() < syslogHost.min_heap_size) {
if (syslogState != SYSLOG_HALTED) {
os_printf("syslog_add_entry: Warning: queue filled up, halted\n");
entry->next = syslog_compose(SYSLOG_FAC_SYSLOG, SYSLOG_PRIO_CRIT, "-", "queue filled up, halted");
if (syslogState == SYSLOG_READY)
syslog_send_udp();
syslogState = SYSLOG_HALTED;
}
}
}
/******************************************************************************
* FunctionName : syslog_sent_cb
* Description : udp sent successfully
* fetch next syslog package, free old message
* Parameters : arg -- Additional argument to pass to the callback function
* Returns : none
******************************************************************************/
static void ICACHE_FLASH_ATTR syslog_udp_sent_cb(void *arg)
{
struct espconn *pespconn = arg;
(void) pespconn;
// datagram is delivered - free and advance queue
syslog_entry_t *pse = syslogQueue;
syslogQueue = syslogQueue -> next;
os_free(pse);
if (syslogQueue != NULL)
syslog_send_udp();
else
syslogState = SYSLOG_READY;
}
/*****************************************************************************
* FunctionName : syslog_recv_cb
* Description : Processing the received udp packet
* Parameters : arg -- Additional argument to pass to the callback function
* pusrdata -- The received data (or NULL when the connection has been closed!)
* length -- The length of received data
* Returns : none
******************************************************************************/
#ifdef SYSLOG_UDP_RECV
static void ICACHE_FLASH_ATTR syslog_udp_recv_cb(void *arg, char *pusrdata, unsigned short length)
{
DBG("syslog_udp_recv_cb: %p, %p, %d\n", arg, pusrdata, length);
}
#endif
/******************************************************************************
*
******************************************************************************/
static void ICACHE_FLASH_ATTR syslog_gethostbyname_cb(const char *name, ip_addr_t *ipaddr, void *arg)
{
struct espconn *pespconn = (struct espconn *)arg;
(void) pespconn;
if (ipaddr != NULL) {
syslogHost.addr.addr = ipaddr->addr;
syslogState = SYSLOG_SENDING;
syslog_send_udp();
} else {
syslogState = SYSLOG_ERROR;
DBG("syslog_gethostbyname_cb: state=SYSLOG_ERROR\n");
}
}
/******************************************************************************
* FunctionName : initSyslog
* Description : Initialize the syslog library
* Parameters : hostname -- the syslog server (host:port)
* host: IP-Addr | hostname
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR syslog_init(char *syslog_server)
{
char host[32], *port = &host[0];
syslog_task = register_usr_task(syslog_udp_send_event);
syslogHost.min_heap_size = flashConfig.syslog_minheap;
syslogHost.port = 514;
syslogState = SYSLOG_WAIT;
os_strncpy(host, syslog_server, 32);
while (*port && *port != ':') // find port delimiter
port++;
if (*port) {
*port++ = '\0';
syslogHost.port = atoi(port);
}
wifi_set_broadcast_if(STATIONAP_MODE); // send UDP broadcast from both station and soft-AP interface
syslog_espconn.type = ESPCONN_UDP;
syslog_espconn.proto.udp = (esp_udp *)os_zalloc(sizeof(esp_udp));
syslog_espconn.proto.udp->local_port = espconn_port(); // set a available port
#ifdef SYSLOG_UDP_RECV
espconn_regist_recvcb(&syslog_espconn, syslog_udp_recv_cb); // register a udp packet receiving callback
#endif
espconn_regist_sentcb(&syslog_espconn, syslog_udp_sent_cb); // register a udp packet sent callback
espconn_create(&syslog_espconn); // create udp
if (UTILS_StrToIP((const char *)host, (void*)&syslogHost.addr)) {
syslogState = SYSLOG_SENDING;
syslog_send_udp();
} else {
static struct espconn espconn_ghbn;
espconn_gethostbyname(&espconn_ghbn, host, &syslogHost.addr, syslog_gethostbyname_cb);
// syslog_send_udp is called by syslog_gethostbyname_cb()
}
#ifdef SYSLOG_UDP_RECV
DBG("syslog_init: host: %s, port: %d, lport: %d, recvcb: %p, sentcb: %p, state: %d\n",
host, syslogHost.port, syslog_espconn.proto.udp->local_port,
syslog_udp_recv_cb, syslog_udp_sent_cb, syslogState );
#else
DBG("syslog_init: host: %s, port: %d, lport: %d, rsentcb: %p, state: %d\n",
host, syslogHost.port, syslog_espconn.proto.udp->local_port,
syslog_udp_sent_cb, syslogState );
#endif
}
/******************************************************************************
* FunctionName : syslog
* Description : compose and queue a new syslog message
* Parameters : facility
* severity
* tag
* message
* ...
*
* SYSLOG-MSG = HEADER SP STRUCTURED-DATA [SP MSG]
HEADER = PRI VERSION SP TIMESTAMP SP HOSTNAME
SP APP-NAME SP PROCID SP MSGID
PRI = "<" PRIVAL ">"
PRIVAL = 1*3DIGIT ; range 0 .. 191
VERSION = NONZERO-DIGIT 0*2DIGIT
HOSTNAME = NILVALUE / 1*255PRINTUSASCII
APP-NAME = NILVALUE / 1*48PRINTUSASCII
PROCID = NILVALUE / 1*128PRINTUSASCII
MSGID = NILVALUE / 1*32PRINTUSASCII
TIMESTAMP = NILVALUE / FULL-DATE "T" FULL-TIME
FULL-DATE = DATE-FULLYEAR "-" DATE-MONTH "-" DATE-MDAY
DATE-FULLYEAR = 4DIGIT
DATE-MONTH = 2DIGIT ; 01-12
DATE-MDAY = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on
; month/year
FULL-TIME = PARTIAL-TIME TIME-OFFSET
PARTIAL-TIME = TIME-HOUR ":" TIME-MINUTE ":" TIME-SECOND
[TIME-SECFRAC]
TIME-HOUR = 2DIGIT ; 00-23
TIME-MINUTE = 2DIGIT ; 00-59
TIME-SECOND = 2DIGIT ; 00-59
TIME-SECFRAC = "." 1*6DIGIT
TIME-OFFSET = "Z" / TIME-NUMOFFSET
TIME-NUMOFFSET = ("+" / "-") TIME-HOUR ":" TIME-MINUTE
STRUCTURED-DATA = NILVALUE / 1*SD-ELEMENT
SD-ELEMENT = "[" SD-ID *(SP SD-PARAM) "]"
SD-PARAM = PARAM-NAME "=" %d34 PARAM-VALUE %d34
SD-ID = SD-NAME
PARAM-NAME = SD-NAME
PARAM-VALUE = UTF-8-STRING ; characters '"', '\' and
; ']' MUST be escaped.
SD-NAME = 1*32PRINTUSASCII
; except '=', SP, ']', %d34 (")
MSG = MSG-ANY / MSG-UTF8
MSG-ANY = *OCTET ; not starting with BOM
MSG-UTF8 = BOM UTF-8-STRING
BOM = %xEF.BB.BF
UTF-8-STRING = *OCTET ; UTF-8 string as specified
; in RFC 3629
OCTET = %d00-255
SP = %d32
PRINTUSASCII = %d33-126
NONZERO-DIGIT = %d49-57
DIGIT = %d48 / NONZERO-DIGIT
NILVALUE = "-"
*
* TIMESTAMP: realtime_clock == 0 ? timertick / 10 : realtime_clock
* HOSTNAME hostname
* APPNAME: ems-esp-link
* PROCID: timertick
* MSGID: NILVALUE
*
* Returns : none
*******************************************************************************/
void ICACHE_FLASH_ATTR syslog(uint8_t facility, uint8_t severity, const char *tag, const char *fmt, ...)
{
DBG("syslog: state=%d ", syslogState);
if (syslogState == SYSLOG_ERROR ||
syslogState == SYSLOG_HALTED)
return;
// compose the syslog message
void *arg = __builtin_apply_args();
void *res = __builtin_apply((void*)syslog_compose, arg, 128);
syslog_entry_t *se = *(syslog_entry_t **)res;
// and append it to the message queue
syslog_add_entry(se);
if (syslogState == SYSLOG_READY) {
syslogState = SYSLOG_SENDING;
syslog_send_udp();
}
if (syslogState == SYSLOG_NONE) {
syslogState = SYSLOG_WAIT;
syslog_chk_wifi_stat(); // fire the timer to check the Wifi connection status
}
}

@ -0,0 +1,110 @@
/*
* syslog.h
*
*
* Copyright 2015 Susi's Strolch
*
* For license information see projects "License.txt"
*
* part of syslog.c - client library
*
*/
#ifndef _SYSLOG_H
#define _SYSLOG_H
#ifdef __cplusplus
extern "C" {
#endif
enum syslog_state {
SYSLOG_NONE, // not initialized
SYSLOG_WAIT, // initialized, waiting for Wifi
SYSLOG_READY, // Wifi established, ready to send
SYSLOG_SENDING, // UDP package on the air
SYSLOG_HALTED, // heap full, discard message
SYSLOG_ERROR,
};
enum syslog_priority {
SYSLOG_PRIO_EMERG, /* system is unusable */
SYSLOG_PRIO_ALERT, /* action must be taken immediately */
SYSLOG_PRIO_CRIT, /* critical conditions */
SYSLOG_PRIO_ERR, /* error conditions */
SYSLOG_PRIO_WARNING, /* warning conditions */
SYSLOG_PRIO_NOTICE, /* normal but significant condition */
SYSLOG_PRIO_INFO, /* informational */
SYSLOG_PRIO_DEBUG, /* debug-level messages */
};
enum syslog_facility {
SYSLOG_FAC_KERN, /* kernel messages */
SYSLOG_FAC_USER, /* random user-level messages */
SYSLOG_FAC_MAIL, /* mail system */
SYSLOG_FAC_DAEMON, /* system daemons */
SYSLOG_FAC_AUTH, /* security/authorization messages */
SYSLOG_FAC_SYSLOG, /* messages generated internally by syslogd */
SYSLOG_FAC_LPR, /* line printer subsystem */
SYSLOG_FAC_NEWS, /* network news subsystem */
SYSLOG_FAC_UUCP, /* UUCP subsystem */
SYSLOG_FAC_CRON, /* clock daemon */
SYSLOG_FAC_AUTHPRIV,/* security/authorization messages (private) */
SYSLOG_FAC_FTP, /* ftp daemon */
SYSLOG_FAC_LOCAL0, /* reserved for local use */
SYSLOG_FAC_LOCAL1, /* reserved for local use */
SYSLOG_FAC_LOCAL2, /* reserved for local use */
SYSLOG_FAC_LOCAL3, /* reserved for local use */
SYSLOG_FAC_LOCAL4, /* reserved for local use */
SYSLOG_FAC_LOCAL5, /* reserved for local use */
SYSLOG_FAC_LOCAL6, /* reserved for local use */
SYSLOG_FAC_LOCAL7, /* reserved for local use */
};
#define MINIMUM_HEAP_SIZE 8192
#define REG_READ(_r) (*(volatile uint32 *)(_r))
#define WDEV_NOW() REG_READ(0x3ff20c00)
extern uint32_t realtime_stamp; // 1sec NTP ticker
typedef struct syslog_host_t syslog_host_t;
struct syslog_host_t {
uint32_t min_heap_size; // minimum allowed heap size when buffering
ip_addr_t addr;
uint16_t port;
};
// buffered syslog event - f.e. if network stack isn't up and running
typedef struct syslog_entry_t syslog_entry_t;
struct syslog_entry_t {
syslog_entry_t *next;
uint16_t datagram_len;
char datagram[];
};
syslog_host_t syslogserver;
void ICACHE_FLASH_ATTR syslog_init(char *syslog_server);
void ICACHE_FLASH_ATTR syslog(uint8_t facility, uint8_t severity, const char tag[], const char message[], ...);
// some convenience macros
#ifdef SYSLOG
// extern char *esp_link_version; // in user_main.c
#define LOG_DEBUG(format, ...) syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_DEBUG, "esp_link", format, ## __VA_ARGS__ )
#define LOG_NOTICE(format, ...) syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_NOTICE, "esp_link", format, ## __VA_ARGS__ )
#define LOG_INFO(format, ...) syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_INFO, "esp_link", format, ## __VA_ARGS__ )
#define LOG_WARN(format, ...) syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_WARNING, "esp_link", format, ## __VA_ARGS__ )
#define LOG_ERR(format, ...) syslog(SYSLOG_FAC_USER, SYSLOG_PRIO_ERR, "esp_link", format, ## __VA_ARGS__ )
#else
#define LOG_DEBUG(format, ...) do { } while(0)
#define LOG_NOTICE(format, ...) do { } while(0)
#define LOG_WARN(format, ...) do { } while(0)
#define LOG_INFO(format, ...) do { } while(0)
#define LOG_ERR(format, ...) do { } while(0)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _SYSLOG_H */
Loading…
Cancel
Save