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 \
user/sampling.c \
user/page_home.c \
user/ftoa.c
user/ftoa.c \
user/routes.c
HEADERS += \
include/uart_hw.h \
@ -137,7 +138,8 @@ HEADERS += \
user/timeout.h \
user/sbmp_config.h \
sbmp/library/sbmp_config.example.h \
user/ftoa.h
user/ftoa.h \
user/routes.h
DISTFILES += \
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"
php "$SRCDIR/home.php" > "$BLDDIR/pages/home.tpl"
php "$SRCDIR/wifi.php" > "$BLDDIR/pages/wifi.tpl"
php "$SRCDIR/home.php" > "$BLDDIR/pages/home.tpl.html"
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,
//add it here.
static const ICACHE_RODATA_ATTR MimeMap mimeTypes[]={
{"htm", "text/htm"},
// html
{"html", "text/html"},
{"css", "text/css"},
{"js", "text/javascript"},
{"txt", "text/plain"},
{"jpg", "image/jpeg"},
{"jpeg", "image/jpeg"},
{"png", "image/png"},
{"svg", "image/svg+xml"},
{NULL, "text/html"}, //default value
{"css", "text/css"},
{"json", "application/json"},
{"js", "text/javascript"},
{"txt", "text/plain"},
{"csv", "text/csv"},
// 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.

@ -194,7 +194,7 @@ int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData)
if (connData->conn == NULL) {
//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);
free(tpd);
return HTTPD_CGI_DONE;

@ -28,6 +28,12 @@
// this ideally would allow flash arrays, but alas works only for uint32_t
#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 "espmissingincludes.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(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.
#define ROUTE_TPL(path, replacer) ROUTE_CGI_ARG(path, cgiEspFsTemplate, replacer)

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

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

@ -4,6 +4,6 @@
#include <esp8266.h>
#include "httpd.h"
int tplMultipart(HttpdConnData *connData, char *token, void **arg);
int tplReadSamplesJSON(HttpdConnData *connData, char *token, void **arg);
#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):
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
@ -10,33 +12,25 @@
// library headers
#include <esp8266.h>
#include "httpd.h"
#include "httpdespfs.h"
#include "cgiwifi.h"
#include "cgiflash.h"
#include "auth.h"
#include "espfs.h"
#include "captdns.h"
#include "webpages-espfs.h"
#include "cgiwebsocket.h"
#include "captdns.h"
// user files
#include "cgi.h"
#include "serial.h"
#include "io.h"
#include "datalink.h"
#include "uart_driver.h"
#include "uptime.h"
#include "routes.h"
#include "page_home.h"
#include "sampling.h"
extern HttpdBuiltInUrl builtInUrls[];
#include "sbmp.h"
static ETSTimer prHeapTimer;
static ETSTimer prSecondTimer;
/** 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 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
#ifdef ESPFS_POS
CgiUploadFlashDef uploadParams = {
@ -99,6 +58,7 @@ CgiUploadFlashDef uploadParams = {
};
#define INCLUDE_FLASH_FNS
#endif
#ifdef OTA_FLASH_SIZE_K
CgiUploadFlashDef uploadParams = {
.type = CGIFLASH_TYPE_FW,
@ -111,56 +71,6 @@ CgiUploadFlashDef uploadParams = {
#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.
*/
@ -170,10 +80,10 @@ void user_init(void)
serialInit();
uptime_timer_init();
banner("\n*** ESP8266 starting, "
"HTTPD v."HTTPDVER", "
"SBMP v."SBMP_VER", "
"IoT SDK v." STR(ESP_SDK_VERSION)" ***\n");
banner("*** ESP8266 starting ***");
info("HTTPD v."HTTPDVER", SBMP v."SBMP_VER", IoT SDK v."STR(ESP_SDK_VERSION));
printf(LOG_EOL);
// reset button etc
ioInit();
@ -196,15 +106,11 @@ void user_init(void)
httpdInit(builtInUrls, 80);
info("\nReady\n");
os_timer_disarm(&prHeapTimer);
os_timer_setfn(&prHeapTimer, prHeapTimerCb, NULL);
os_timer_arm(&prHeapTimer, 1000, 1);
}
printf(LOG_EOL);
info("Ready");
printf(LOG_EOL);
void user_rf_pre_init()
{
//Not needed, but some SDK versions want this defined.
os_timer_disarm(&prSecondTimer);
os_timer_setfn(&prSecondTimer, prSecondTimerCb, NULL);
os_timer_arm(&prSecondTimer, 1000, 1);
}

Loading…
Cancel
Save