readout prototype

master
Ondřej Hruška 8 years ago
parent f4b4aa123c
commit d57d8dd692
  1. 6
      esp_meas.pro
  2. BIN
      html/favicon.ico
  3. 4
      html/json/samples.tpl.json
  4. 14
      html/multipart.tpl
  5. 0
      html/pages/home.tpl.html
  6. 0
      html/pages/wifi.tpl.html
  7. 17
      html/style.css
  8. 5
      html_build.sh
  9. 1
      html_src/package.json
  10. 23
      libesphttpd/core/httpd.c
  11. 2
      libesphttpd/core/httpdespfs.c
  12. 6
      libesphttpd/include/esp8266.h
  13. 2
      libesphttpd/include/httpd.h
  14. 4
      libesphttpd/include/logging.h
  15. 116
      user/cgi.c
  16. 2
      user/cgi.h
  17. 99
      user/routes.c
  18. 8
      user/routes.h
  19. 134
      user/user_main.c

@ -57,7 +57,8 @@ SOURCES += \
sbmp/library/payload_parser.c \ sbmp/library/payload_parser.c \
user/sampling.c \ user/sampling.c \
user/page_home.c \ user/page_home.c \
user/ftoa.c user/ftoa.c \
user/routes.c
HEADERS += \ HEADERS += \
include/uart_hw.h \ include/uart_hw.h \
@ -137,7 +138,8 @@ HEADERS += \
user/timeout.h \ user/timeout.h \
user/sbmp_config.h \ user/sbmp_config.h \
sbmp/library/sbmp_config.example.h \ sbmp/library/sbmp_config.example.h \
user/ftoa.h user/ftoa.h \
user/routes.h
DISTFILES += \ DISTFILES += \
style.astylerc \ style.astylerc \

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

@ -0,0 +1,4 @@
{
"samples": [%values%],
"success": %success%
}

@ -1,14 +0,0 @@
<!DOCTYPE html>
<html>
<head><title>ESP8266 web server</title>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="main">
<h1>Multipart</h1>
<nav>
<ul>
%numbers%
</ul>
</body></html>

@ -1,17 +0,0 @@
body {
background-color: #404040;
font-family: sans-serif;
}
#main {
background-color: #d0d0FF;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
border: 2px solid #000000;
width: 800px;
margin: 0 auto;
padding: 20px
}

@ -21,6 +21,5 @@ find "$BLDDIR" -name "*.map" -delete
mkdir -p "$BLDDIR/pages" mkdir -p "$BLDDIR/pages"
php "$SRCDIR/home.php" > "$BLDDIR/pages/home.tpl" php "$SRCDIR/home.php" > "$BLDDIR/pages/home.tpl.html"
php "$SRCDIR/wifi.php" > "$BLDDIR/pages/wifi.tpl" php "$SRCDIR/wifi.php" > "$BLDDIR/pages/wifi.tpl.html"

@ -73,16 +73,21 @@ typedef struct {
//The mappings from file extensions to mime types. If you need an extra mime type, //The mappings from file extensions to mime types. If you need an extra mime type,
//add it here. //add it here.
static const ICACHE_RODATA_ATTR MimeMap mimeTypes[]={ static const ICACHE_RODATA_ATTR MimeMap mimeTypes[]={
{"htm", "text/htm"}, // html
{"html", "text/html"}, {"html", "text/html"},
{"css", "text/css"},
{"js", "text/javascript"}, {"css", "text/css"},
{"txt", "text/plain"}, {"json", "application/json"},
{"jpg", "image/jpeg"}, {"js", "text/javascript"},
{"jpeg", "image/jpeg"}, {"txt", "text/plain"},
{"png", "image/png"}, {"csv", "text/csv"},
{"svg", "image/svg+xml"},
{NULL, "text/html"}, //default value // images
{"ico", "image/x-icon"},
{"jpg", "image/jpeg"},
{"png", "image/png"},
{"svg", "image/svg+xml"},
{NULL, "text/html"}, //default value
}; };
//Returns a static char* to a mime type for a given url to a file. //Returns a static char* to a mime type for a given url to a file.

@ -194,7 +194,7 @@ int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData)
if (connData->conn == NULL) { if (connData->conn == NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
((TplCallback)(connData->cgiArg))(connData, NULL, &tpd->tplArg); ((TplCallback)(connData->cgiArg))(connData, NULL, &tpd->tplArg); // call the template func with NULL token
espFsClose(tpd->file); espFsClose(tpd->file);
free(tpd); free(tpd);
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;

@ -28,6 +28,12 @@
// this ideally would allow flash arrays, but alas works only for uint32_t // this ideally would allow flash arrays, but alas works only for uint32_t
#define FLASH_DATA ICACHE_RODATA_ATTR STORE_ATTR #define FLASH_DATA ICACHE_RODATA_ATTR STORE_ATTR
#define MIN(a,b) ((a)>(b)?(b):(a))
#define MAX(a,b) ((a)<(b)?(b):(a))
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#include "platform.h" #include "platform.h"
#include "espmissingincludes.h" #include "espmissingincludes.h"
#include "esp_sdk_ver.h" #include "esp_sdk_ver.h"

@ -72,7 +72,7 @@ typedef struct {
#define ROUTE_CGI_ARG(path, handler, arg1) ROUTE_CGI_ARG2(path, handler, arg1, NULL) #define ROUTE_CGI_ARG(path, handler, arg1) ROUTE_CGI_ARG2(path, handler, arg1, NULL)
#define ROUTE_CGI(path, handler) ROUTE_CGI_ARG2(path, handler, NULL, NULL) #define ROUTE_CGI(path, handler) ROUTE_CGI_ARG2(path, handler, NULL, NULL)
#define ROUTE_FILE(path, filepath) ROUTE_CGI_ARG(path, cgiEspFsStaticFile, filepath) #define ROUTE_FILE(path, filepath) ROUTE_CGI_ARG(path, cgiEspFsFile, filepath)
// the argument of a template route is accessible as cgiArg2 on the connData struct. // the argument of a template route is accessible as cgiArg2 on the connData struct.
#define ROUTE_TPL(path, replacer) ROUTE_CGI_ARG(path, cgiEspFsTemplate, replacer) #define ROUTE_TPL(path, replacer) ROUTE_CGI_ARG(path, cgiEspFsTemplate, replacer)

@ -18,9 +18,9 @@
#define banner(fmt, ...) \ #define banner(fmt, ...) \
do { \ do { \
printf("\x1b[32;1m"); \ printf(LOG_EOL "\x1b[32;1m"); \
uptime_print(); \ uptime_print(); \
printf(" [i] "fmt"\x1b[0m"LOG_EOL, ##__VA_ARGS__); \ printf(" [i] "fmt"\x1b[0m" LOG_EOL, ##__VA_ARGS__); \
} while(0) } while(0)

@ -18,70 +18,98 @@ flash as a binary. Also handles the hit counter on the main page.
#include "uptime.h" #include "uptime.h"
#include "datalink.h" #include "datalink.h"
// ---- demonstration of a multi-part substituion in a template ----
// -------------------------------------------------------------------------------
// Read multiple samples from the ADC as JSON
typedef struct { typedef struct {
uint32_t count_remain; uint32_t total_count;
} RandomNumberState; uint32_t done_count;
bool success;
} tplReadSamplesJSON_state;
//Template code for the counter on the index page. int FLASH_FN tplReadSamplesJSON(HttpdConnData *connData, char *token, void **arg)
int FLASH_FN tplMultipart(HttpdConnData *connData, char *token, void **arg)
{ {
char buff20[20];
tplReadSamplesJSON_state *st = *arg;
if (token == NULL) { if (token == NULL) {
if (*arg != NULL) { // end of template, cleanup
free(*arg); if (st != NULL) free(st);
*arg = NULL; // mark as already freed
}
return HTTPD_CGI_DONE; // cleanup return HTTPD_CGI_DONE; // cleanup
} }
if (os_strcmp(token, "numbers") == 0) { if (st == NULL) {
RandomNumberState *rns = *arg; // first call - allocate the struct
char buff[20]; st = malloc(sizeof(tplReadSamplesJSON_state));
*arg = st;
// first call in this substitution
if (rns == NULL) { // check how many samples are requested
//First call to this cgi. Open the file so we can read it. uint16_t count = 1;
rns=(RandomNumberState *)malloc(sizeof(RandomNumberState)); int len = httpdFindArg(connData->getArgs, "count", buff20, sizeof(buff20));
*arg=rns; if (len != -1) count = (uint16_t)atoi(buff20);
if (count > 4096) {
// parse count warn("Requested %d samples, capping at 4096.", count);
uint32_t count = 1; count = 4096;
int len = httpdFindArg(connData->getArgs, "count", buff, sizeof(buff));
if (len==-1) {
// no such get arg
} else {
count = (uint32_t)atoi(buff);
}
rns->count_remain = count;
info("User wants %d numbers.", count);
} }
st->total_count = count;
st->done_count = 0;
st->success = true;
// TODO Start the capture
}
// print the numbers // the "success" field is after the data,
for (int i = 0; i < 100; i++) { // so if readout fails, success can be set to false.
os_sprintf(buff, "<li>%lu\n", os_random());
httpdSend(connData, buff, -1);
if (--rns->count_remain == 0) { if (strcmp(token, "values") == 0) {
break;
if (st->done_count == 0) {
dbg("Delay to simulate readout...");
// 1000 ms delay
for(int i=0;i<1000;i++) {
os_delay_us(1000);
} }
} }
// We are done. // TODO wait for data to be received
if (rns->count_remain == 0) { // on error, terminate and proceed to the "success" field.
free(rns);
*arg = NULL; // mark as already freed u32 chunk = MIN(10, st->total_count - st->done_count); // chunks of 10
return HTTPD_CGI_DONE;
// chunk of data...
for (u32 i = 0; i < chunk; i++, st->done_count++) {
// preceding comma if not the first number
if (st->done_count > 0) {
httpdSend(connData, ", ", 2);
}
// one number
os_sprintf(buff20, "%lu", os_random());
httpdSend(connData, buff20, -1);
} }
return HTTPD_CGI_MORE; // wait for more in this substitution
if (st->done_count < st->total_count)
return HTTPD_CGI_MORE; // more numbers to come
} else if (strcmp(token, "success") == 0) {
// success status
httpdSend(connData, (st->success ? "true" : "false"), -1);
} }
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
// Example of multi-pass generation of a html file
/* /*
// better to put it in the fs... // better to put it in the fs...
@ -121,8 +149,8 @@ int FLASH_FN cgiRandomNumbers(HttpdConnData *connData) {
httpdSend(connData, "<!DOCTYPE html>" httpdSend(connData, "<!DOCTYPE html>"
"<html>" "<html>"
"<head>" "<head>"
" <title>Generated page.</title>" " <title>Generated page.</title>"
" <link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">" " <link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">"
"</head>" "</head>"
"<body>" "<body>"
"<div id=\"main\">" "<div id=\"main\">"

@ -4,6 +4,6 @@
#include <esp8266.h> #include <esp8266.h>
#include "httpd.h" #include "httpd.h"
int tplMultipart(HttpdConnData *connData, char *token, void **arg); int tplReadSamplesJSON(HttpdConnData *connData, char *token, void **arg);
#endif #endif

@ -0,0 +1,99 @@
#include "routes.h"
#include <esp8266.h>
#include <httpd.h>
#include "httpdespfs.h"
#include "cgiwifi.h"
//#include "cgiflash.h"
//#include "auth.h"
//#include "cgiwebsocket.h"
// user files
#include "cgi.h"
#include "page_home.h"
#include "sampling.h"
#define WIFI_PROTECT 0
#if WIFI_PROTECT
static int FLASH_FN myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen);
#endif
/**
* This is the main url->function dispatching data struct.
*
* In short, it's a struct with various URLs plus their handlers. The handlers can
* be 'standard' CGI functions you wrote, or 'special' CGIs requiring an argument.
* They can also be auth-functions. An asterisk will match any url starting with
* everything before the asterisks; "*" matches everything. The list will be
* handled top-down, so make sure to put more specific rules above the more
* general ones. Authorization things (like authBasic) act as a 'barrier' and
* should be placed above the URLs they protect.
*/
HttpdBuiltInUrl builtInUrls[] = {
ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp8266.nonet"), // redirect func for the captive portal
ROUTE_TPL_FILE("/", tplHome, "/pages/home.tpl.html"),
ROUTE_CGI("/acquire.cgi", cgiReadSamples),
// API for measurements
ROUTE_TPL_FILE("/meas/samples.json", tplReadSamplesJSON, "/json/samples.tpl.json"),
#if WIFI_PROTECT
ROUTE_AUTH("/wifi/*", myPassFn),
#endif
ROUTE_REDIRECT("/wifi/", "/wifi"),
ROUTE_TPL_FILE("/wifi", tplWlan, "/pages/wifi.tpl.html"),
ROUTE_CGI("/wifi/scan.cgi", cgiWiFiScan),
ROUTE_CGI("/wifi/connect.cgi", cgiWiFiConnect),
ROUTE_CGI("/wifi/connstatus.cgi", cgiWiFiConnStatus),
ROUTE_CGI("/wifi/setmode.cgi", cgiWiFiSetMode),
ROUTE_FS("*"), //Catch-all cgi function for the filesystem NOTE: unsafe, lets user read templates.
ROUTE_END()
};
#if WIFI_PROTECT
/**
* @brief BasicAuth name/password checking function.
*
* It's invoked by the authBasic() built-in route handler
* until it returns 0. Each time it populates the provided
* name and password buffer.
*
* @param connData : connection context
* @param no : user number (incremented each time it's called)
* @param user : user buffer
* @param userLen : user buffer size
* @param pass : password buffer
* @param passLen : password buffer size
* @return 0 to end, 1 if more users are available.
*/
static int FLASH_FN myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen)
{
(void)connData;
(void)userLen;
(void)passLen;
if (no == 0) {
os_strcpy(user, "admin");
os_strcpy(pass, "s3cr3t");
return 1;
//Add more users this way. Check against incrementing no for each user added.
// } else if (no==1) {
// os_strcpy(user, "user1");
// os_strcpy(pass, "something");
// return 1;
}
return 0;
}
#endif

@ -0,0 +1,8 @@
#ifndef ROUTES_H
#define ROUTES_H
#include <httpd.h>
extern HttpdBuiltInUrl builtInUrls[];
#endif // ROUTES_H

@ -1,4 +1,6 @@
/* /*
* Based on an example project for ESP-HTTPD.
*
* ---------------------------------------------------------------------------- * ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42): * "THE BEER-WARE LICENSE" (Revision 42):
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain * Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
@ -10,33 +12,25 @@
// library headers // library headers
#include <esp8266.h> #include <esp8266.h>
#include "httpd.h" #include "httpd.h"
#include "httpdespfs.h"
#include "cgiwifi.h"
#include "cgiflash.h"
#include "auth.h"
#include "espfs.h" #include "espfs.h"
#include "captdns.h"
#include "webpages-espfs.h" #include "webpages-espfs.h"
#include "cgiwebsocket.h" #include "captdns.h"
// user files
#include "cgi.h"
#include "serial.h" #include "serial.h"
#include "io.h" #include "io.h"
#include "datalink.h" #include "datalink.h"
#include "uart_driver.h"
#include "uptime.h" #include "uptime.h"
#include "routes.h"
#include "page_home.h" extern HttpdBuiltInUrl builtInUrls[];
#include "sampling.h"
#include "sbmp.h" static ETSTimer prSecondTimer;
static ETSTimer prHeapTimer;
/** Timer called each second */ /** Timer called each second */
static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) static void ICACHE_FLASH_ATTR prSecondTimerCb(void *arg)
{ {
(void)arg;
static u8 cnt = 0; static u8 cnt = 0;
static u32 last = 0; static u32 last = 0;
@ -54,41 +48,6 @@ static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg)
} }
/**
* @brief BasicAuth name/password checking function.
*
* It's invoked by the authBasic() built-in route handler
* until it returns 0. Each time it populates the provided
* name and password buffer.
*
* @param connData : connection context
* @param no : user number (incremented each time it's called)
* @param user : user buffer
* @param userLen : user buffer size
* @param pass : password buffer
* @param passLen : password buffer size
* @return 0 to end, 1 if more users are available.
*/
int FLASH_FN myPassFn(HttpdConnData *connData, int no, char *user, int userLen, char *pass, int passLen)
{
(void)connData;
(void)userLen;
(void)passLen;
if (no == 0) {
os_strcpy(user, "admin");
os_strcpy(pass, "s3cr3t");
return 1;
//Add more users this way. Check against incrementing no for each user added.
// } else if (no==1) {
// os_strcpy(user, "user1");
// os_strcpy(pass, "something");
// return 1;
}
return 0;
}
// Some stuff for alternative ESPFS storage methods // Some stuff for alternative ESPFS storage methods
#ifdef ESPFS_POS #ifdef ESPFS_POS
CgiUploadFlashDef uploadParams = { CgiUploadFlashDef uploadParams = {
@ -99,6 +58,7 @@ CgiUploadFlashDef uploadParams = {
}; };
#define INCLUDE_FLASH_FNS #define INCLUDE_FLASH_FNS
#endif #endif
#ifdef OTA_FLASH_SIZE_K #ifdef OTA_FLASH_SIZE_K
CgiUploadFlashDef uploadParams = { CgiUploadFlashDef uploadParams = {
.type = CGIFLASH_TYPE_FW, .type = CGIFLASH_TYPE_FW,
@ -111,56 +71,6 @@ CgiUploadFlashDef uploadParams = {
#endif #endif
/**
* This is the main url->function dispatching data struct.
*
* In short, it's a struct with various URLs plus their handlers. The handlers can
* be 'standard' CGI functions you wrote, or 'special' CGIs requiring an argument.
* They can also be auth-functions. An asterisk will match any url starting with
* everything before the asterisks; "*" matches everything. The list will be
* handled top-down, so make sure to put more specific rules above the more
* general ones. Authorization things (like authBasic) act as a 'barrier' and
* should be placed above the URLs they protect.
*/
static HttpdBuiltInUrl builtInUrls[] = {
ROUTE_CGI_ARG("*", cgiRedirectApClientToHostname, "esp8266.nonet"), // redirect func for the captive portal
ROUTE_TPL_FILE("/", tplHome, "/pages/home.tpl"),
ROUTE_CGI("/acquire.cgi", cgiReadSamples),
ROUTE_TPL_FILE("/multipart", tplMultipart, "/multipart.tpl"),
//Enable the line below to protect the WiFi configuration with an username/password combo.
// ROUTE_AUTH("/wifi/*", myPassFn),
ROUTE_REDIRECT("/wifi/", "/wifi"),
ROUTE_TPL_FILE("/wifi", tplWlan, "/pages/wifi.tpl"),
ROUTE_CGI("/wifi/scan.cgi", cgiWiFiScan),
ROUTE_CGI("/wifi/connect.cgi", cgiWiFiConnect),
ROUTE_CGI("/wifi/connstatus.cgi", cgiWiFiConnStatus),
ROUTE_CGI("/wifi/setmode.cgi", cgiWiFiSetMode),
ROUTE_FS("*"), //Catch-all cgi function for the filesystem
ROUTE_END()
};
//static ETSTimer prTestTimer;
//static void ICACHE_FLASH_ATTR test_timer_task(void *arg) {
// const char * t = "Test\r\n";
// UART_WriteBuffer(0, (uint8_t*)t, strlen(t), 1000);
//}
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
/** /**
* Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done. * Main routine. Initialize stdout, the I/O, filesystem and the webserver and we're done.
*/ */
@ -170,10 +80,10 @@ void user_init(void)
serialInit(); serialInit();
uptime_timer_init(); uptime_timer_init();
banner("\n*** ESP8266 starting, " banner("*** ESP8266 starting ***");
"HTTPD v."HTTPDVER", " info("HTTPD v."HTTPDVER", SBMP v."SBMP_VER", IoT SDK v."STR(ESP_SDK_VERSION));
"SBMP v."SBMP_VER", " printf(LOG_EOL);
"IoT SDK v." STR(ESP_SDK_VERSION)" ***\n");
// reset button etc // reset button etc
ioInit(); ioInit();
@ -196,15 +106,11 @@ void user_init(void)
httpdInit(builtInUrls, 80); httpdInit(builtInUrls, 80);
info("\nReady\n"); printf(LOG_EOL);
info("Ready");
os_timer_disarm(&prHeapTimer); printf(LOG_EOL);
os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL);
os_timer_arm(&prHeapTimer, 1000, 1);
}
os_timer_disarm(&prSecondTimer);
void user_rf_pre_init() os_timer_setfn(&prSecondTimer, prSecondTimerCb, NULL);
{ os_timer_arm(&prSecondTimer, 1000, 1);
//Not needed, but some SDK versions want this defined.
} }

Loading…
Cancel
Save