work on the reporting

Former-commit-id: 22df0fb4780da583ee956c45441fc15e9283eab1
master
Ondřej Hruška 8 years ago
parent daf3d6dee4
commit c620976902
  1. 4
      esphttpclient/httpclient.c
  2. 2
      html/js/all.js
  3. 21
      html/pages/monitoring.tpl
  4. 9
      html_src/js-src/page_mon.js
  5. 2
      html_src/js/all.js
  6. 2
      html_src/js/all.js.map
  7. 21
      html_src/page_monitoring.php
  8. 87
      libesphttpd/core/httpd.c
  9. 12
      libesphttpd/core/httpdespfs.c
  10. 8
      libesphttpd/include/cgiflash.h
  11. 9
      libesphttpd/include/cgiwebsocket.h
  12. 14
      libesphttpd/include/cgiwifi.h
  13. 37
      libesphttpd/include/httpd.h
  14. 6
      libesphttpd/include/httpdespfs.h
  15. 8
      libesphttpd/util/cgiflash.c
  16. 45
      libesphttpd/util/cgiwebsocket.c
  17. 10
      libesphttpd/util/cgiwifi.c
  18. 2
      sbmp
  19. 3
      user/cgi_ping.c
  20. 2
      user/cgi_ping.h
  21. 3
      user/cgi_reset.c
  22. 2
      user/cgi_reset.h
  23. 1
      user/datalink.h
  24. 2
      user/page_about.c
  25. 2
      user/page_about.h
  26. 161
      user/page_monitoring.c
  27. 8
      user/page_monitoring.h
  28. 2
      user/page_status.c
  29. 2
      user/page_status.h
  30. 8
      user/page_waveform.c
  31. 4
      user/page_waveform.h
  32. 135
      user/reporting.c
  33. 19
      user/reporting.h
  34. 4
      user/routes.c
  35. 7
      user/user_main.c

@ -241,8 +241,8 @@ static void FLASH_FN sent_callback(void * arg)
static void FLASH_FN connect_callback(void * arg) static void FLASH_FN connect_callback(void * arg)
{ {
info("Connected!"); info("Connected!");
struct espconn * conn = (struct espconn *)arg; struct espconn *conn = (struct espconn *)arg;
request_args * req = (request_args *)conn->reserve; request_args *req = (request_args *)conn->reserve;
espconn_regist_recvcb(conn, receive_callback); espconn_regist_recvcb(conn, receive_callback);
espconn_regist_sentcb(conn, sent_callback); espconn_regist_sentcb(conn, sent_callback);

File diff suppressed because one or more lines are too long

@ -36,9 +36,12 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<th>Actual&nbsp;distance:</th> <th>Actual&nbsp;state:</th>
<td> <td>
<span id="refdist" class="Valfield">N/A</span> <span class="Valfield">
Δ = <span id="actual-dev">%curDeviation%</span>,
I<sub>rms</sub> = <span id="actual-rms">%curRMS%</span> mA
</span>
<a onclick="page_mon.compareNow()" class="button btn-blue">Measure</a> <a onclick="page_mon.compareNow()" class="button btn-blue">Measure</a>
</td> </td>
</tr> </tr>
@ -47,36 +50,36 @@
<div class="Box"> <div class="Box">
<h2>Reporting</h2> <h2>Reporting</h2>
<form method="POST"> <form action="/mon/config" method="POST">
<table> <table>
<tr> <tr>
<th><label for="rep-on">Reporting:</label></th> <th><label for="rep-on">Reporting:</label></th>
<td> <td>
<input type="checkbox" id="rep-on" name="rep-on" %repEnableCheck%><!-- <input type="checkbox" id="rep-on" name="enabled" value="1" %repEnableCheck%><!--
-->&nbsp;<label for="rep-on">enabled</label> -->&nbsp;<label for="rep-on">enabled</label>
</td> </td>
</tr> </tr>
<tr> <tr>
<th><label for="rep-interval">Interval:</label></th> <th><label for="rep-interval">Interval:</label></th>
<td> <td>
<input type="number" id="rep-interval" style="max-width: 10em" value="%repInterval%"><!-- <input type="number" name="interval" id="rep-interval" style="max-width: 10em" value="%repInterval%"><!--
-->&nbsp;seconds -->&nbsp;seconds
</td> </td>
</tr> </tr>
<tr> <tr>
<th>Service:</th> <th>Service:</th>
<td> <td>
<input type="radio" name="rep-service" value="xively" id="rep-svc-xv" %repSvcCheckXv%>&nbsp;<label for="rep-svc-xv">Xively</label>&nbsp; <input type="radio" name="service" value="xv" id="rep-svc-xv" %repSvcCheckXv%>&nbsp;<label for="rep-svc-xv">Xively</label>&nbsp;
<input type="radio" name="rep-service" value="thingspeak" id="rep-svc-ts" %repSvcCheckTs%>&nbsp;<label for="rep-svc-ts">ThingSpeak</label> <input type="radio" name="service" value="ts" id="rep-svc-ts" %repSvcCheckTs%>&nbsp;<label for="rep-svc-ts">ThingSpeak</label>
</td> </td>
</tr> </tr>
<tr> <tr>
<th><label for="rep-feed">Feed/Channel:</label></th> <th><label for="rep-feed">Feed/Channel:</label></th>
<td><input type="text" name="rep-feed" id="rep-feed" value="%repFeed%"></td> <td><input type="text" name="feed" id="rep-feed" value="%repFeed%"></td>
</tr> </tr>
<tr> <tr>
<th><label for="rep-key">API key:</label></th> <th><label for="rep-key">API key:</label></th>
<td><input type="text" name="rep-key" id="rep-key" value="%repKey%"></td> <td><input type="text" name="key" id="rep-key" value="%repKey%"></td>
</tr> </tr>
<tr> <tr>
<th>&nbsp;</th> <th>&nbsp;</th>

@ -35,14 +35,17 @@ var page_mon = (function() {
// OK // OK
var j = JSON.parse(resp); var j = JSON.parse(resp);
if (j.success) { if (j.success) {
$('#refdist').html(numfmt(j.deviation, 2)); $('#actual-dev').html(numfmt(j.deviation, 2));
$('#actual-rms').html(numfmt(j.rms, 2));
} else { } else {
errorMsg('Capture failed.'); errorMsg('Capture failed.');
$('#refdist').html('--'); $('#actual-dev').html('--');
$('#actual-rms').html('--');
} }
} catch(e) { } catch(e) {
errorMsg(e); errorMsg(e);
$('#refdist').html('--'); $('#actual-dev').html('--');
$('#actual-rms').html('--');
} }
} }
}); });

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -13,9 +13,12 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<th>Actual&nbsp;distance:</th> <th>Actual&nbsp;state:</th>
<td> <td>
<span id="refdist" class="Valfield">N/A</span> <span class="Valfield">
Δ = <span id="actual-dev">%curDeviation%</span>,
I<sub>rms</sub> = <span id="actual-rms">%curRMS%</span> mA
</span>
<a onclick="page_mon.compareNow()" class="button btn-blue">Measure</a> <a onclick="page_mon.compareNow()" class="button btn-blue">Measure</a>
</td> </td>
</tr> </tr>
@ -24,36 +27,36 @@
<div class="Box"> <div class="Box">
<h2>Reporting</h2> <h2>Reporting</h2>
<form method="POST"> <form action="<?=$root?>/mon/config" method="POST">
<table> <table>
<tr> <tr>
<th><label for="rep-on">Reporting:</label></th> <th><label for="rep-on">Reporting:</label></th>
<td> <td>
<input type="checkbox" id="rep-on" name="rep-on" %repEnableCheck%><!-- <input type="checkbox" id="rep-on" name="enabled" value="1" %repEnableCheck%><!--
-->&nbsp;<label for="rep-on">enabled</label> -->&nbsp;<label for="rep-on">enabled</label>
</td> </td>
</tr> </tr>
<tr> <tr>
<th><label for="rep-interval">Interval:</label></th> <th><label for="rep-interval">Interval:</label></th>
<td> <td>
<input type="number" id="rep-interval" style="max-width: 10em" value="%repInterval%"><!-- <input type="number" name="interval" id="rep-interval" style="max-width: 10em" value="%repInterval%"><!--
-->&nbsp;seconds -->&nbsp;seconds
</td> </td>
</tr> </tr>
<tr> <tr>
<th>Service:</th> <th>Service:</th>
<td> <td>
<input type="radio" name="rep-service" value="xively" id="rep-svc-xv" %repSvcCheckXv%>&nbsp;<label for="rep-svc-xv">Xively</label>&nbsp; <input type="radio" name="service" value="xv" id="rep-svc-xv" %repSvcCheckXv%>&nbsp;<label for="rep-svc-xv">Xively</label>&nbsp;
<input type="radio" name="rep-service" value="thingspeak" id="rep-svc-ts" %repSvcCheckTs%>&nbsp;<label for="rep-svc-ts">ThingSpeak</label> <input type="radio" name="service" value="ts" id="rep-svc-ts" %repSvcCheckTs%>&nbsp;<label for="rep-svc-ts">ThingSpeak</label>
</td> </td>
</tr> </tr>
<tr> <tr>
<th><label for="rep-feed">Feed/Channel:</label></th> <th><label for="rep-feed">Feed/Channel:</label></th>
<td><input type="text" name="rep-feed" id="rep-feed" value="%repFeed%"></td> <td><input type="text" name="feed" id="rep-feed" value="%repFeed%"></td>
</tr> </tr>
<tr> <tr>
<th><label for="rep-key">API key:</label></th> <th><label for="rep-key">API key:</label></th>
<td><input type="text" name="rep-key" id="rep-key" value="%repKey%"></td> <td><input type="text" name="key" id="rep-key" value="%repKey%"></td>
</tr> </tr>
<tr> <tr>
<th>&nbsp;</th> <th>&nbsp;</th>

@ -62,7 +62,7 @@ struct HttpdPriv {
//Connection pool //Connection pool
static HttpdConnData *connData[HTTPD_MAX_CONNECTIONS]; static HttpdConnData *connPool[HTTPD_MAX_CONNECTIONS];
//Struct to keep extension->mime data in //Struct to keep extension->mime data in
typedef struct { typedef struct {
@ -118,10 +118,10 @@ const char ICACHE_FLASH_ATTR *httpdGetMimetype(const char *filepath) {
//Looks up the connData info for a specific connection //Looks up the connData info for a specific connection
static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(ConnTypePtr conn, const char *remIp, int remPort) { static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(ConnTypePtr conn, const char *remIp, int remPort) {
for (int i=0; i<HTTPD_MAX_CONNECTIONS; i++) { for (int i=0; i<HTTPD_MAX_CONNECTIONS; i++) {
if (connData[i] && connData[i]->remote_port == remPort && if (connPool[i] && connPool[i]->remote_port == remPort &&
memcmp(connData[i]->remote_ip, remIp, 4) == 0) { memcmp(connPool[i]->remote_ip, remIp, 4) == 0) {
connData[i]->conn=conn; connPool[i]->conn=conn;
return connData[i]; return connPool[i];
} }
} }
//Shouldn't happen. //Shouldn't happen.
@ -146,7 +146,7 @@ static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) {
if (conn->priv!=NULL) free(conn->priv); if (conn->priv!=NULL) free(conn->priv);
if (conn) free(conn); if (conn) free(conn);
for (int i=0; i<HTTPD_MAX_CONNECTIONS; i++) { for (int i=0; i<HTTPD_MAX_CONNECTIONS; i++) {
if (connData[i]==conn) connData[i]=NULL; if (connPool[i]==conn) connPool[i]=NULL;
} }
} }
@ -285,7 +285,7 @@ void ICACHE_FLASH_ATTR httpdRedirect(HttpdConnData *conn, char *newUrl) {
} }
//Use this as a cgi function to redirect one url to another. //Use this as a cgi function to redirect one url to another.
int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) {
if (connData->conn==NULL) { if (connData->conn==NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
@ -295,7 +295,7 @@ int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) {
} }
//Used to spit out a 404 error //Used to spit out a 404 error
static int ICACHE_FLASH_ATTR cgiNotFound(HttpdConnData *connData) { static httpd_cgi_state ICACHE_FLASH_ATTR cgiNotFound(HttpdConnData *connData) {
if (connData->conn==NULL) return HTTPD_CGI_DONE; if (connData->conn==NULL) return HTTPD_CGI_DONE;
httpdStartResponse(connData, 404); httpdStartResponse(connData, 404);
httpdEndHeaders(connData); httpdEndHeaders(connData);
@ -308,7 +308,7 @@ static int ICACHE_FLASH_ATTR cgiNotFound(HttpdConnData *connData) {
//ESP in order to load a HTML page as soon as a phone, tablet etc connects to the ESP. Watch out: //ESP in order to load a HTML page as soon as a phone, tablet etc connects to the ESP. Watch out:
//this will also redirect connections when the ESP is in STA mode, potentially to a hostname that is not //this will also redirect connections when the ESP is in STA mode, potentially to a hostname that is not
//in the 'official' DNS and so will fail. //in the 'official' DNS and so will fail.
int ICACHE_FLASH_ATTR cgiRedirectToHostname(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiRedirectToHostname(HttpdConnData *connData) {
static const char hostFmt[]="http://%s/"; static const char hostFmt[]="http://%s/";
char *buff; char *buff;
int isIP=0; int isIP=0;
@ -345,7 +345,7 @@ int ICACHE_FLASH_ATTR cgiRedirectToHostname(HttpdConnData *connData) {
//Same as above, but will only redirect clients with an IP that is in the range of //Same as above, but will only redirect clients with an IP that is in the range of
//the SoftAP interface. This should preclude clients connected to the STA interface //the SoftAP interface. This should preclude clients connected to the STA interface
//to be redirected to nowhere. //to be redirected to nowhere.
int ICACHE_FLASH_ATTR cgiRedirectApClientToHostname(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiRedirectApClientToHostname(HttpdConnData *connData) {
#ifndef FREERTOS #ifndef FREERTOS
uint32 *remadr; uint32 *remadr;
struct ip_info apip; struct ip_info apip;
@ -588,19 +588,22 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
int i; int i;
char firstLine=0; char firstLine=0;
if (strncmp(h, "GET ", 4)==0) { if (strstarts(h, "GET ")) {
conn->requestType = HTTPD_METHOD_GET; conn->requestType = HTTPD_METHOD_GET;
firstLine=1; firstLine=1;
} else if (strncmp(h, "Host:", 5)==0) { } else if (strstarts(h, "POST ")) {
i=5;
while (h[i]==' ') i++;
conn->hostName=&h[i];
} else if (strncmp(h, "POST ", 5)==0) {
conn->requestType = HTTPD_METHOD_POST; conn->requestType = HTTPD_METHOD_POST;
firstLine=1; firstLine=1;
} else if (strncmp(h, "OPTIONS ", 8)==0) { } else if (strstarts(h, "PUT ")) {
conn->requestType = HTTPD_METHOD_PUT;
firstLine=1;
} else if (strstarts(h, "OPTIONS ")) {
conn->requestType = HTTPD_METHOD_OPTIONS; conn->requestType = HTTPD_METHOD_OPTIONS;
firstLine=1; firstLine=1;
} else if (strstarts(h, "Host:")) {
i=5;
while (h[i]==' ') i++;
conn->hostName=&h[i];
} }
if (firstLine) { if (firstLine) {
@ -630,12 +633,12 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
} else { } else {
conn->getArgs=NULL; conn->getArgs=NULL;
} }
} else if (strncmp(h, "Connection:", 11)==0) { } else if (strstarts(h, "Connection:")) {
i=11; i=11;
//Skip trailing spaces //Skip trailing spaces
while (h[i]==' ') i++; while (h[i]==' ') i++;
if (strncmp(&h[i], "close", 5)==0) conn->priv->flags&=~HFL_CHUNKED; //Don't use chunked conn if (strstarts(&h[i], "close")) conn->priv->flags&=~HFL_CHUNKED; //Don't use chunked conn
} else if (strncmp(h, "Content-Length:", 15)==0) { } else if (strstarts(h, "Content-Length:")) {
i=15; i=15;
//Skip trailing spaces //Skip trailing spaces
while (h[i]==' ') i++; while (h[i]==' ') i++;
@ -652,7 +655,7 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
dbg("Malloc'd buffer for %d + 1 bytes of post data.", conn->post->buffSize); dbg("Malloc'd buffer for %d + 1 bytes of post data.", conn->post->buffSize);
conn->post->buff=(char*)malloc(conn->post->buffSize + 1); conn->post->buff=(char*)malloc(conn->post->buffSize + 1);
conn->post->buffLen=0; conn->post->buffLen=0;
} else if (strncmp(h, "Content-Type: ", 14)==0) { } else if (strstarts(h, "Content-Type: ")) {
if (strstr(h, "multipart/form-data")) { if (strstr(h, "multipart/form-data")) {
// It's multipart form data so let's pull out the boundary for future use // It's multipart form data so let's pull out the boundary for future use
char *b; char *b;
@ -663,7 +666,7 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
dbg("boundary = %s", conn->post->multipartBoundary); dbg("boundary = %s", conn->post->multipartBoundary);
} }
} }
} else if (strncmp(h, "Access-Control-Request-Headers: ", 32)==0) { } else if (strstarts(h, "Access-Control-Request-Headers: ")) {
// CORS crap that needs to be repeated in the response // CORS crap that needs to be repeated in the response
info("CORS preflight request."); info("CORS preflight request.");
@ -783,7 +786,7 @@ int ICACHE_FLASH_ATTR httpdConnectCb(ConnTypePtr conn, char *remIp, int remPort)
int i; int i;
//Find empty conndata in pool //Find empty conndata in pool
for (i=0; i<HTTPD_MAX_CONNECTIONS; i++) if (connData[i]==NULL) break; for (i=0; i<HTTPD_MAX_CONNECTIONS; i++) if (connPool[i]==NULL) break;
info("Conn req from %d.%d.%d.%d:%d, using pool slot %d", remIp[0]&0xff, remIp[1]&0xff, remIp[2]&0xff, remIp[3]&0xff, remPort, i); info("Conn req from %d.%d.%d.%d:%d, using pool slot %d", remIp[0]&0xff, remIp[1]&0xff, remIp[2]&0xff, remIp[3]&0xff, remPort, i);
if (i==HTTPD_MAX_CONNECTIONS) { if (i==HTTPD_MAX_CONNECTIONS) {
error("Aiee, conn pool overflow!"); error("Aiee, conn pool overflow!");
@ -799,24 +802,24 @@ int ICACHE_FLASH_ATTR httpdConnectCb(ConnTypePtr conn, char *remIp, int remPort)
failed_cnt = 0; failed_cnt = 0;
connData[i]=malloc(sizeof(HttpdConnData)); connPool[i]=malloc(sizeof(HttpdConnData));
memset(connData[i], 0, sizeof(HttpdConnData)); memset(connPool[i], 0, sizeof(HttpdConnData));
connData[i]->priv=malloc(sizeof(HttpdPriv)); connPool[i]->priv=malloc(sizeof(HttpdPriv));
memset(connData[i]->priv, 0, sizeof(HttpdPriv)); memset(connPool[i]->priv, 0, sizeof(HttpdPriv));
connData[i]->conn=conn; connPool[i]->conn=conn;
connData[i]->slot=i; connPool[i]->slot=i;
connData[i]->priv->headPos=0; connPool[i]->priv->headPos=0;
connData[i]->post=malloc(sizeof(HttpdPostData)); connPool[i]->post=malloc(sizeof(HttpdPostData));
memset(connData[i]->post, 0, sizeof(HttpdPostData)); memset(connPool[i]->post, 0, sizeof(HttpdPostData));
connData[i]->post->buff=NULL; connPool[i]->post->buff=NULL;
connData[i]->post->buffLen=0; connPool[i]->post->buffLen=0;
connData[i]->post->received=0; connPool[i]->post->received=0;
connData[i]->post->len=-1; connPool[i]->post->len=-1;
connData[i]->hostName=NULL; connPool[i]->hostName=NULL;
connData[i]->remote_port=remPort; connPool[i]->remote_port=remPort;
connData[i]->priv->sendBacklog=NULL; connPool[i]->priv->sendBacklog=NULL;
connData[i]->priv->sendBacklogSize=0; connPool[i]->priv->sendBacklogSize=0;
memcpy(connData[i]->remote_ip, remIp, 4); memcpy(connPool[i]->remote_ip, remIp, 4);
return 1; return 1;
} }
@ -826,7 +829,7 @@ void ICACHE_FLASH_ATTR httpdInit(HttpdBuiltInUrl *fixedUrls, int port) {
int i; int i;
for (i=0; i<HTTPD_MAX_CONNECTIONS; i++) { for (i=0; i<HTTPD_MAX_CONNECTIONS; i++) {
connData[i]=NULL; connPool[i]=NULL;
} }
builtInUrls=fixedUrls; builtInUrls=fixedUrls;

@ -73,7 +73,7 @@ EspFsFile *tryOpenIndex(const char *path)
} }
int ICACHE_FLASH_ATTR serveStaticFile(HttpdConnData *connData, const char* filepath) httpd_cgi_state ICACHE_FLASH_ATTR serveStaticFile(HttpdConnData *connData, const char* filepath)
{ {
EspFsFile *file = connData->cgiData; EspFsFile *file = connData->cgiData;
int len; int len;
@ -153,13 +153,13 @@ int ICACHE_FLASH_ATTR serveStaticFile(HttpdConnData *connData, const char* filep
//This is a catch-all cgi function. It takes the url passed to it, looks up the corresponding //This is a catch-all cgi function. It takes the url passed to it, looks up the corresponding
//path in the filesystem and if it exists, passes the file through. This simulates what a normal //path in the filesystem and if it exists, passes the file through. This simulates what a normal
//webserver would do with static files. //webserver would do with static files.
int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData) httpd_cgi_state cgiEspFsHook(HttpdConnData *connData)
{ {
return serveStaticFile(connData, connData->url); return serveStaticFile(connData, connData->url);
} }
int ICACHE_FLASH_ATTR cgiEspFsFile(HttpdConnData *connData) httpd_cgi_state ICACHE_FLASH_ATTR cgiEspFsFile(HttpdConnData *connData)
{ {
return serveStaticFile(connData, connData->cgiArg); return serveStaticFile(connData, connData->cgiArg);
} }
@ -183,9 +183,9 @@ typedef struct {
char *buff_e; char *buff_e;
} TplData; } TplData;
typedef int (* TplCallback)(HttpdConnData *connData, char *token, void **arg); typedef httpd_cgi_state (* TplCallback)(HttpdConnData *connData, char *token, void **arg);
int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData) httpd_cgi_state ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData)
{ {
TplData *tpd = connData->cgiData; TplData *tpd = connData->cgiData;
int len; int len;
@ -289,7 +289,7 @@ int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData)
tpd->chunk_resume = false; tpd->chunk_resume = false;
int status = ((TplCallback)(connData->cgiArg))(connData, tpd->token, &tpd->tplArg); httpd_cgi_state status = ((TplCallback)(connData->cgiArg))(connData, tpd->token, &tpd->tplArg);
if (status == HTTPD_CGI_MORE) { if (status == HTTPD_CGI_MORE) {
// dbg("Multi-part tpl subst, saving parser state"); // dbg("Multi-part tpl subst, saving parser state");

@ -14,9 +14,9 @@ typedef struct {
char *tagName; char *tagName;
} CgiUploadFlashDef; } CgiUploadFlashDef;
int cgiReadFlash(HttpdConnData *connData); httpd_cgi_state cgiReadFlash(HttpdConnData *connData);
int cgiGetFirmwareNext(HttpdConnData *connData); httpd_cgi_state cgiGetFirmwareNext(HttpdConnData *connData);
int cgiUploadFirmware(HttpdConnData *connData); httpd_cgi_state cgiUploadFirmware(HttpdConnData *connData);
int cgiRebootFirmware(HttpdConnData *connData); httpd_cgi_state cgiRebootFirmware(HttpdConnData *connData);
#endif #endif

@ -27,11 +27,12 @@ struct Websock {
WebsockPriv *priv; WebsockPriv *priv;
}; };
int ICACHE_FLASH_ATTR cgiWebsocket(HttpdConnData *connData); httpd_cgi_state cgiWebsocket(HttpdConnData *connData);
int ICACHE_FLASH_ATTR cgiWebsocketSend(Websock *ws, char *data, int len, int flags); int ICACHE_FLASH_ATTR cgiWebsocketSend(Websock *ws, char *data, int len, int flags);
void ICACHE_FLASH_ATTR cgiWebsocketClose(Websock *ws, int reason); void ICACHE_FLASH_ATTR cgiWebsocketClose(Websock *ws, int reason);
int ICACHE_FLASH_ATTR cgiWebSocketRecv(HttpdConnData *connData, char *data, int len); httpd_cgi_state cgiWebSocketRecv(HttpdConnData *connData, char *data, int len);
int ICACHE_FLASH_ATTR cgiWebsockBroadcast(char *resource, char *data, int len, int flags);
//int ICACHE_FLASH_ATTR cgiWebsockBroadcast(char *resource, char *data, int len, int flags);
#endif
#endif

@ -3,11 +3,11 @@
#include "httpd.h" #include "httpd.h"
int cgiWiFiScan(HttpdConnData *connData); httpd_cgi_state cgiWiFiScan(HttpdConnData *connData);
int tplWlan(HttpdConnData *connData, char *token, void **arg); httpd_cgi_state tplWlan(HttpdConnData *connData, char *token, void **arg);
int cgiWiFi(HttpdConnData *connData); httpd_cgi_state cgiWiFi(HttpdConnData *connData);
int cgiWiFiConnect(HttpdConnData *connData); httpd_cgi_state cgiWiFiConnect(HttpdConnData *connData);
int cgiWiFiSetMode(HttpdConnData *connData); httpd_cgi_state cgiWiFiSetMode(HttpdConnData *connData);
int cgiWiFiConnStatus(HttpdConnData *connData); httpd_cgi_state cgiWiFiConnStatus(HttpdConnData *connData);
#endif #endif

@ -5,26 +5,34 @@
#define HTTPDVER "0.4-based" #define HTTPDVER "0.4-based"
#define HTTPD_CGI_MORE 0 typedef enum {
#define HTTPD_CGI_DONE 1 HTTPD_CGI_MORE = 0,
#define HTTPD_CGI_NOTFOUND 2 HTTPD_CGI_DONE = 1,
#define HTTPD_CGI_AUTHENTICATED 3 HTTPD_CGI_NOTFOUND = 2,
HTTPD_CGI_AUTHENTICATED = 3,
#define HTTPD_METHOD_GET 1 } httpd_cgi_state;
#define HTTPD_METHOD_POST 2
#define HTTPD_METHOD_OPTIONS 3 typedef enum {
HTTPD_METHOD_GET = 1,
HTTPD_METHOD_POST = 2,
HTTPD_METHOD_OPTIONS = 3,
HTTPD_METHOD_PUT = 4,
HTTPD_METHOD_DELETE = 5,
HTTPD_METHOD_PATCH = 6,
HTTPD_METHOD_HEAD = 7,
} http_method;
typedef struct HttpdPriv HttpdPriv; typedef struct HttpdPriv HttpdPriv;
typedef struct HttpdConnData HttpdConnData; typedef struct HttpdConnData HttpdConnData;
typedef struct HttpdPostData HttpdPostData; typedef struct HttpdPostData HttpdPostData;
typedef int (* cgiSendCallback)(HttpdConnData *connData); typedef httpd_cgi_state (* cgiSendCallback)(HttpdConnData *connData);
typedef int (* cgiRecvHandler)(HttpdConnData *connData, char *data, int len); typedef httpd_cgi_state (* cgiRecvHandler)(HttpdConnData *connData, char *data, int len);
//A struct describing a http connection. This gets passed to cgi functions. //A struct describing a http connection. This gets passed to cgi functions.
struct HttpdConnData { struct HttpdConnData {
ConnTypePtr conn; // The TCP connection. Exact type depends on the platform. ConnTypePtr conn; // The TCP connection. Exact type depends on the platform.
char requestType; // One of the HTTPD_METHOD_* values http_method requestType; // method type
char *url; // The URL requested, without hostname or GET arguments char *url; // The URL requested, without hostname or GET arguments
char *getArgs; // The GET arguments for this request, if any. char *getArgs; // The GET arguments for this request, if any.
@ -89,9 +97,10 @@ typedef struct {
int cgiRedirect(HttpdConnData *connData); httpd_cgi_state cgiRedirect(HttpdConnData *connData);
int cgiRedirectToHostname(HttpdConnData *connData); httpd_cgi_state cgiRedirectToHostname(HttpdConnData *connData);
int cgiRedirectApClientToHostname(HttpdConnData *connData); httpd_cgi_state cgiRedirectApClientToHostname(HttpdConnData *connData);
void httpdRedirect(HttpdConnData *conn, char *newUrl); void httpdRedirect(HttpdConnData *conn, char *newUrl);
int httpdUrlDecode(char *val, int valLen, char *ret, int retLen); int httpdUrlDecode(char *val, int valLen, char *ret, int retLen);
int httpdFindArg(char *line, char *arg, char *buff, int buffLen); int httpdFindArg(char *line, char *arg, char *buff, int buffLen);

@ -4,12 +4,12 @@
#include "httpd.h" #include "httpd.h"
/** Catch-all, use in '*' routes */ /** Catch-all, use in '*' routes */
int cgiEspFsHook(HttpdConnData *connData); httpd_cgi_state cgiEspFsHook(HttpdConnData *connData);
/** Template route */ /** Template route */
int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData); httpd_cgi_state ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData);
/** Static file route with the file as the first arg. */ /** Static file route with the file as the first arg. */
int ICACHE_FLASH_ATTR cgiEspFsFile(HttpdConnData *connData); httpd_cgi_state ICACHE_FLASH_ATTR cgiEspFsFile(HttpdConnData *connData);
#endif #endif

@ -43,7 +43,7 @@ static int ICACHE_FLASH_ATTR checkEspfsHeader(void *buf) {
// Cgi to query which firmware needs to be uploaded next // Cgi to query which firmware needs to be uploaded next
int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) {
if (connData->conn==NULL) { if (connData->conn==NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
@ -62,7 +62,7 @@ int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) {
//Cgi that reads the SPI flash. Assumes 512KByte flash. //Cgi that reads the SPI flash. Assumes 512KByte flash.
//ToDo: Figure out real flash size somehow? //ToDo: Figure out real flash size somehow?
int ICACHE_FLASH_ATTR cgiReadFlash(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiReadFlash(HttpdConnData *connData) {
int *pos=(int *)&connData->cgiData; int *pos=(int *)&connData->cgiData;
if (connData->conn==NULL) { if (connData->conn==NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
@ -123,7 +123,7 @@ typedef struct __attribute__((packed)) {
} OtaHeader; } OtaHeader;
int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) {
CgiUploadFlashDef *def=(CgiUploadFlashDef*)connData->cgiArg; CgiUploadFlashDef *def=(CgiUploadFlashDef*)connData->cgiArg;
UploadState *state=(UploadState *)connData->cgiData; UploadState *state=(UploadState *)connData->cgiData;
int len; int len;
@ -302,7 +302,7 @@ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) {
} }
// Handle request to reboot into the new firmware // Handle request to reboot into the new firmware
int ICACHE_FLASH_ATTR cgiRebootFirmware(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiRebootFirmware(HttpdConnData *connData) {
if (connData->conn==NULL) { if (connData->conn==NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;

@ -119,26 +119,27 @@ int ICACHE_FLASH_ATTR cgiWebsocketSend(Websock *ws, char *data, int len, int fla
return r; return r;
} }
//Broadcast data to all websockets at a specific url. Returns the amount of connections sent to.
int ICACHE_FLASH_ATTR cgiWebsockBroadcast(char *resource, char *data, int len, int flags) { ////Broadcast data to all websockets at a specific url. Returns the amount of connections sent to.
//This is majorly broken (and actually, always, it just tended to work because the circumstances //int ICACHE_FLASH_ATTR cgiWebsockBroadcast(char *resource, char *data, int len, int flags) {
//were juuuust right). Because the socket is used outside of the httpd send/receive context, it ////This is majorly broken (and actually, always, it just tended to work because the circumstances
//will not have an associated send buffer. This means httpdSend will write to a dangling pointer! ////were juuuust right). Because the socket is used outside of the httpd send/receive context, it
//Disabled for now. If you really need this, open an issue on github or otherwise poke me and I'll ////will not have an associated send buffer. This means httpdSend will write to a dangling pointer!
//see what I can do. ////Disabled for now. If you really need this, open an issue on github or otherwise poke me and I'll
/* ////see what I can do.
Websock *lw=llStart; ///*
int ret=0; // Websock *lw=llStart;
while (lw!=NULL) { // int ret=0;
if (strcmp(lw->conn->url, resource)==0) { // while (lw!=NULL) {
cgiWebsocketSend(lw, data, len, flags); // if (strcmp(lw->conn->url, resource)==0) {
ret++; // cgiWebsocketSend(lw, data, len, flags);
} // ret++;
lw=lw->priv->next; // }
} // lw=lw->priv->next;
return ret;*/ // }
return 0; // return ret;*/
} // return 0;
//}
void ICACHE_FLASH_ATTR cgiWebsocketClose(Websock *ws, int reason) { void ICACHE_FLASH_ATTR cgiWebsocketClose(Websock *ws, int reason) {
@ -167,7 +168,7 @@ static void ICACHE_FLASH_ATTR websockFree(Websock *ws) {
if (ws->priv) free(ws->priv); if (ws->priv) free(ws->priv);
} }
int ICACHE_FLASH_ATTR cgiWebSocketRecv(HttpdConnData *connData, char *data, int len) { httpd_cgi_state ICACHE_FLASH_ATTR cgiWebSocketRecv(HttpdConnData *connData, char *data, int len) {
int i, j, sl; int i, j, sl;
int r=HTTPD_CGI_MORE; int r=HTTPD_CGI_MORE;
int wasHeaderByte; int wasHeaderByte;
@ -280,7 +281,7 @@ int ICACHE_FLASH_ATTR cgiWebSocketRecv(HttpdConnData *connData, char *data, int
} }
//Websocket 'cgi' implementation //Websocket 'cgi' implementation
int ICACHE_FLASH_ATTR cgiWebsocket(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiWebsocket(HttpdConnData *connData) {
char buff[256]; char buff[256];
int i; int i;
sha1nfo s; sha1nfo s;

@ -130,7 +130,7 @@ static void ICACHE_FLASH_ATTR wifiStartScan() {
//This CGI is called from the bit of AJAX-code in wifi.tpl. It will initiate a //This CGI is called from the bit of AJAX-code in wifi.tpl. It will initiate a
//scan for access points and if available will return the result of an earlier scan. //scan for access points and if available will return the result of an earlier scan.
//The result is embedded in a bit of JSON parsed by the javascript in wifi.tpl. //The result is embedded in a bit of JSON parsed by the javascript in wifi.tpl.
int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) {
int pos=(int)connData->cgiData; int pos=(int)connData->cgiData;
int len; int len;
char buff[256]; char buff[256];
@ -226,7 +226,7 @@ static void ICACHE_FLASH_ATTR reassTimerCb(void *arg) {
//This cgi uses the routines above to connect to a specific access point with the //This cgi uses the routines above to connect to a specific access point with the
//given ESSID using the given password. //given ESSID using the given password.
int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) {
char essid[128]; char essid[128];
char passwd[128]; char passwd[128];
static os_timer_t reassTimer; static os_timer_t reassTimer;
@ -258,7 +258,7 @@ int ICACHE_FLASH_ATTR cgiWiFiConnect(HttpdConnData *connData) {
//This cgi uses the routines above to connect to a specific access point with the //This cgi uses the routines above to connect to a specific access point with the
//given ESSID using the given password. //given ESSID using the given password.
int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
int len; int len;
char buff[64]; char buff[64];
@ -282,7 +282,7 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;
} }
int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) { httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
char buff[256]; char buff[256];
int len; int len;
struct ip_info info; struct ip_info info;
@ -314,7 +314,7 @@ int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
} }
//Template code for the WLAN page. //Template code for the WLAN page.
int ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) { httpd_cgi_state ICACHE_FLASH_ATTR tplWlan(HttpdConnData *connData, char *token, void **arg) {
char buff[256]; char buff[256];
int x; int x;
static struct station_config stconf; static struct station_config stconf;

@ -1 +1 @@
Subproject commit b2fca263f880869744bb086047d394d32e13117d Subproject commit 70e41c91e5daabeb6e39a02df9baeadb3995b700

@ -1,6 +1,6 @@
#include "cgi_ping.h" #include "cgi_ping.h"
int FLASH_FN cgiPing(HttpdConnData *connData) httpd_cgi_state FLASH_FN cgiPing(HttpdConnData *connData)
{ {
if (connData->conn==NULL) { if (connData->conn==NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
@ -8,6 +8,7 @@ int FLASH_FN cgiPing(HttpdConnData *connData)
} }
httpdStartResponse(connData, 200); httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "text/plain");
httpdEndHeaders(connData); httpdEndHeaders(connData);
httpdSend(connData, "pong\n", -1); httpdSend(connData, "pong\n", -1);

@ -6,6 +6,6 @@
// this is used by the UI to check if server is already restarted and working again. // this is used by the UI to check if server is already restarted and working again.
int cgiPing(HttpdConnData *connData); httpd_cgi_state cgiPing(HttpdConnData *connData);
#endif // CGI_PING_H #endif // CGI_PING_H

@ -7,7 +7,7 @@ static void FLASH_FN tmrCb(void *arg)
system_restart(); system_restart();
} }
int FLASH_FN cgiResetDevice(HttpdConnData *connData) httpd_cgi_state FLASH_FN cgiResetDevice(HttpdConnData *connData)
{ {
if (connData->conn==NULL) { if (connData->conn==NULL) {
//Connection aborted. Clean up. //Connection aborted. Clean up.
@ -15,6 +15,7 @@ int FLASH_FN cgiResetDevice(HttpdConnData *connData)
} }
httpdStartResponse(connData, 200); httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "text/plain");
httpdEndHeaders(connData); httpdEndHeaders(connData);
os_timer_disarm(&tmr); os_timer_disarm(&tmr);

@ -4,6 +4,6 @@
#include <esp8266.h> #include <esp8266.h>
#include <httpd.h> #include <httpd.h>
int cgiResetDevice(HttpdConnData *connData); httpd_cgi_state cgiResetDevice(HttpdConnData *connData);
#endif // CGI_RESET_H #endif // CGI_RESET_H

@ -12,6 +12,7 @@
#define DG_REQUEST_COMPARE_REF 43 #define DG_REQUEST_COMPARE_REF 43
extern SBMP_Endpoint *dlnk_ep; extern SBMP_Endpoint *dlnk_ep;
void datalinkInit(void); void datalinkInit(void);

@ -5,7 +5,7 @@
#include "sbmp.h" #include "sbmp.h"
/** "About" page */ /** "About" page */
int FLASH_FN tplAbout(HttpdConnData *connData, char *token, void **arg) httpd_cgi_state FLASH_FN tplAbout(HttpdConnData *connData, char *token, void **arg)
{ {
// arg is unused // arg is unused
(void)arg; (void)arg;

@ -3,6 +3,6 @@
#include <httpd.h> #include <httpd.h>
int tplAbout(HttpdConnData *connData, char *token, void **arg); httpd_cgi_state tplAbout(HttpdConnData *connData, char *token, void **arg);
#endif // PAGE_ABOUT_H #endif // PAGE_ABOUT_H

@ -1,11 +1,124 @@
#include <esp8266.h> #include <esp8266.h>
#include <httpd.h> #include <httpd.h>
#include "page_monitoring.h" #include "page_monitoring.h"
#include "reporting.h"
#include "ftoa.h"
httpd_cgi_state FLASH_FN cgiMonCompare(HttpdConnData *connData)
{
if (connData->conn == NULL) {
//Connection aborted. Clean up.
return HTTPD_CGI_DONE;
}
httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "application/json");
httpdEndHeaders(connData);
// this is semi-async (waits for completion)
bool suc = capture_and_report();
char buf[100];
if (suc && rpt_result.ready) {
// success
sprintf(buf, "{\"success\": true, \"deviation\": ");
my_ftoa(buf+strlen(buf),rpt_result.deviation, 2);
sprintf(buf, ", \"rms\": ");
my_ftoa(buf+strlen(buf),rpt_result.i_rms, 2);
sprintf(buf, "}");
httpdSend(connData, buf, -1);
} else {
httpdSend(connData, "{\"success\": false}", -1);
}
return HTTPD_CGI_DONE;
}
httpd_cgi_state FLASH_FN cgiMonSetRef(HttpdConnData *connData)
{
if (connData->conn == NULL) {
//Connection aborted. Clean up.
return HTTPD_CGI_DONE;
}
httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "application/json");
httpdEndHeaders(connData);
// this is semi-async (waits for completion)
bool suc = capture_reporting_reference();
httpdSend(connData, suc ? "{\"success\": true}" : "{\"success\": false}", -1);
return HTTPD_CGI_DONE;
}
httpd_cgi_state FLASH_FN cgiMonitoringCfg(HttpdConnData *connData)
{
if (connData->conn == NULL) {
//Connection aborted. Clean up.
return HTTPD_CGI_DONE;
}
httpdStartResponse(connData, 200);
httpdHeader(connData, "Content-Type", "application/json");
httpdEndHeaders(connData);
// TODO
HttpdPostData *post = connData->post;
if (post != NULL) {
char buf[64];
int blen;
// enabled=1
blen = httpdFindArg(post->buff, "enabled", buf, 64);
if (blen == -1) {
// wasn't found
rpt_conf.enabled = false;
} else {
rpt_conf.enabled = (buf[0] == '1');
}
// interval=secs
blen = httpdFindArg(post->buff, "enabled", buf, 64);
if (blen != -1) {
rpt_conf.interval = (uint32_t)atoi(buf);
}
// service=xv or ts
blen = httpdFindArg(post->buff, "service", buf, 64);
if (blen != -1) {
rpt_conf.service = (buf[0] == 'x' ? RPT_XIVELY: RPT_THINGSPEAK);
}
// feed
blen = httpdFindArg(post->buff, "feed", buf, 64);
if (blen != -1) {
strcpy(rpt_conf.feed, buf);
}
// key
blen = httpdFindArg(post->buff, "key", buf, 64);
if (blen != -1) {
strcpy(rpt_conf.key, buf);
}
// Save & Apply
reporting_cfg_save();
}
httpdRedirect(connData, "/monitoring");
return HTTPD_CGI_DONE;
}
/** "Monitoring" page - fill form fields */ /** "Monitoring" page - fill form fields */
int FLASH_FN tplMonitoring(HttpdConnData *connData, char *token, void **arg) httpd_cgi_state FLASH_FN tplMonitoring(HttpdConnData *connData, char *token, void **arg)
{ {
// arg is unused
(void)arg; (void)arg;
char buf[20]; char buf[20];
@ -15,24 +128,46 @@ int FLASH_FN tplMonitoring(HttpdConnData *connData, char *token, void **arg)
if (streq(token, "refStored")) { if (streq(token, "refStored")) {
httpdSend(connData, true ? "OK" : "Not set!", -1); // fixme httpdSend(connData, true ? "OK" : "Not set!", -1); // fixme
} else if (streq(token, "curDeviation")) {
// current deviation
if (rpt_result.ready) {
my_ftoa(buf, rpt_result.deviation, 2);
} else {
sprintf(buf, "--");
}
httpdSend(connData, buf, -1);
} else if (streq(token, "curRMS")) {
// current deviation
if (rpt_result.ready) {
my_ftoa(buf, rpt_result.i_rms, 2);
} else {
sprintf(buf, "--");
}
httpdSend(connData, buf, -1);
} else if (streq(token, "repEnableCheck")) { } else if (streq(token, "repEnableCheck")) {
if (true) httpdSend(connData, "checked", -1); // fixme if (rpt_conf.enabled) httpdSend(connData, "checked", -1);
} else if (streq(token, "repInterval")) { } else if (streq(token, "repInterval")) { // interval in seconds
sprintf(buf, "%d", 123); // fixme sprintf(buf, "%d", rpt_conf.interval);
httpdSend(connData, buf, -1); httpdSend(connData, buf, -1);
} else if (streq(token, "repSvcCheckXv")) { // Xively } else if (streq(token, "repSvcCheckXv")) { // Xively checkbox
if (true) httpdSend(connData, "checked", -1); // fixme if (rpt_conf.service == RPT_XIVELY) {
httpdSend(connData, "checked", -1);
}
} else if (streq(token, "repSvcCheckTs")) { // ThingSpeak } else if (streq(token, "repSvcCheckTs")) { // ThingSpeak checkbox
if (true) httpdSend(connData, "checked", -1); // fixme if (rpt_conf.service == RPT_THINGSPEAK) {
httpdSend(connData, "checked", -1);
}
} else if (streq(token, "repFeed")) { } else if (streq(token, "repFeed")) { // reporting feed ID
httpdSend(connData, "null", -1); // fixme httpdSend(connData, rpt_conf.feed, -1);
} else if (streq(token, "repKey")) { } else if (streq(token, "repKey")) { // reporting key
httpdSend(connData, "null", -1); // fixme httpdSend(connData, rpt_conf.key, -1);
} }
return HTTPD_CGI_DONE; return HTTPD_CGI_DONE;

@ -3,6 +3,12 @@
#include <httpd.h> #include <httpd.h>
int tplMonitoring(HttpdConnData *connData, char *token, void **arg); httpd_cgi_state tplMonitoring(HttpdConnData *connData, char *token, void **arg);
httpd_cgi_state cgiMonCompare(HttpdConnData *connData);
httpd_cgi_state cgiMonSetRef(HttpdConnData *connData);
httpd_cgi_state cgiMonitoringCfg(HttpdConnData *connData);
#endif // PAGE_MONITORING_H #endif // PAGE_MONITORING_H

@ -7,7 +7,7 @@
/** System Status page */ /** System Status page */
int FLASH_FN tplSystemStatus(HttpdConnData *connData, char *token, void **arg) httpd_cgi_state FLASH_FN tplSystemStatus(HttpdConnData *connData, char *token, void **arg)
{ {
// arg is unused // arg is unused
(void)arg; (void)arg;

@ -3,6 +3,6 @@
#include <httpd.h> #include <httpd.h>
int tplSystemStatus(HttpdConnData *connData, char *token, void **arg); httpd_cgi_state tplSystemStatus(HttpdConnData *connData, char *token, void **arg);
#endif // PAGE_HOME_H #endif // PAGE_HOME_H

@ -19,22 +19,22 @@ typedef struct {
} tplReadSamplesJSON_state; } tplReadSamplesJSON_state;
static int FLASH_FN tplSamplesJSON(MEAS_FORMAT fmt, HttpdConnData *connData, char *token, void **arg); static httpd_cgi_state FLASH_FN tplSamplesJSON(MEAS_FORMAT fmt, HttpdConnData *connData, char *token, void **arg);
int FLASH_FN tplWaveformJSON(HttpdConnData *connData, char *token, void **arg) httpd_cgi_state FLASH_FN tplWaveformJSON(HttpdConnData *connData, char *token, void **arg)
{ {
return tplSamplesJSON(RAW, connData, token, arg); return tplSamplesJSON(RAW, connData, token, arg);
} }
int FLASH_FN tplFourierJSON(HttpdConnData *connData, char *token, void **arg) httpd_cgi_state FLASH_FN tplFourierJSON(HttpdConnData *connData, char *token, void **arg)
{ {
return tplSamplesJSON(FFT, connData, token, arg); return tplSamplesJSON(FFT, connData, token, arg);
} }
static int FLASH_FN tplSamplesJSON(MEAS_FORMAT fmt, HttpdConnData *connData, char *token, void **arg) static httpd_cgi_state FLASH_FN tplSamplesJSON(MEAS_FORMAT fmt, HttpdConnData *connData, char *token, void **arg)
{ {
char buff[128]; char buff[128];
int len; int len;

@ -3,8 +3,8 @@
#include <httpd.h> #include <httpd.h>
int tplWaveformJSON(HttpdConnData *connData, char *token, void **arg); httpd_cgi_state tplWaveformJSON(HttpdConnData *connData, char *token, void **arg);
int tplFourierJSON(HttpdConnData *connData, char *token, void **arg); httpd_cgi_state tplFourierJSON(HttpdConnData *connData, char *token, void **arg);
#endif // PAGE_WAVEFORM_H #endif // PAGE_WAVEFORM_H

@ -1,6 +1,7 @@
#include "reporting.h" #include "reporting.h"
#include "datalink.h" #include "datalink.h"
#include "serial.h" #include "serial.h"
#include "httpclient.h"
#define RPT_CONF_MAGIC 0x24C595D5 #define RPT_CONF_MAGIC 0x24C595D5
@ -10,94 +11,184 @@ ReportingCfg rpt_conf;
static os_timer_t rpt_tim; static os_timer_t rpt_tim;
/** Timer cb */ /** Timer cb */
static void rpt_tim_cb(void *arg) static void FLASH_FN rpt_tim_cb(void *arg)
{ {
(void)arg; (void)arg;
reporting_send_now(); // send report now...
if (rpt_conf.enabled) {
capture_and_report();
}
} }
/** Stop / start timer & set interval based on rpt conf */ /** Stop / start timer & set interval based on rpt conf */
static void set_timer(void) static FLASH_FN void set_timer(void)
{ {
os_timer_disarm(&rpt_tim); os_timer_disarm(&rpt_tim);
if (rpt_conf.enabled) { if (rpt_conf.enabled) {
os_timer_setfn(&rpt_tim, rpt_tim_cb, NULL); os_timer_setfn(&rpt_tim, rpt_tim_cb, NULL);
os_timer_arm(&rpt_tim, (int)(rpt_conf.interval*1000), 1); os_timer_arm(&rpt_tim, (int)(rpt_conf.interval * 1000), 1);
} }
} }
/** Fix unterminated strings, add magic, etc.. */ /** Fix unterminated strings, add magic, etc.. */
static void normalize_rpt_conf(void) static FLASH_FN void normalize_rpt_conf(void)
{ {
// terminate strings // terminate strings
rpt_conf.feed[sizeof(rpt_conf.feed)-1] = 0; rpt_conf.feed[sizeof(rpt_conf.feed) - 1] = 0;
rpt_conf.key[sizeof(rpt_conf.key)-1] = 0; rpt_conf.key[sizeof(rpt_conf.key) - 1] = 0;
// set magic // set magic
rpt_conf.magic = RPT_CONF_MAGIC; rpt_conf.magic = RPT_CONF_MAGIC;
} }
static FLASH_FN void dump_rpt_conf(void)
{
dbg("Enabled: %d | Interval: %d | Service: %s", rpt_conf.enabled, rpt_conf.interval, (rpt_conf.service == RPT_XIVELY ? "Xively" : "ThingSpeak"));
dbg("Key: %s | Feed: %s", rpt_conf.key, rpt_conf.feed);
}
/** Save reporting config to flash */ /** Save reporting config to flash */
void reporting_save(void) void FLASH_FN reporting_cfg_save(void)
{ {
normalize_rpt_conf(); // fix weirdness normalize_rpt_conf(); // fix weirdness
info("Saving monitoring config");
dump_rpt_conf();
system_param_save_with_protect(0x3D, &rpt_conf, sizeof(ReportingCfg)); system_param_save_with_protect(0x3D, &rpt_conf, sizeof(ReportingCfg));
// start timer for the new interval time // start timer for the new interval time
set_timer(); set_timer();
info("Config saved.");
} }
/** Load the reporting config from flash */ /** Load the reporting config from flash */
void reporting_load(void) void FLASH_FN reporting_cfg_load(void)
{ {
info("Loading monitoring config");
system_param_load(0x3D, 0, &rpt_conf, sizeof(ReportingCfg)); system_param_load(0x3D, 0, &rpt_conf, sizeof(ReportingCfg));
if (rpt_conf.magic != RPT_CONF_MAGIC) { if (rpt_conf.magic != RPT_CONF_MAGIC) {
warn("Config block corrupted, reset to defaults.");
// invalid config, zero out // invalid config, zero out
memset(&rpt_conf, 0, sizeof(ReportingCfg)); memset(&rpt_conf, 0, sizeof(ReportingCfg));
rpt_conf.magic = RPT_CONF_MAGIC; rpt_conf.magic = RPT_CONF_MAGIC;
// save fixed // save fixed
reporting_save(); reporting_cfg_save();
} else {
dump_rpt_conf();
} }
set_timer(); set_timer();
info("Config loaded.");
} }
void compare_ref_cb(SBMP_Endpoint *ep, SBMP_Datagram *dg, void **obj) /** Called when response to Compare Ref is received */
static void FLASH_FN compare_ref_cb(SBMP_Endpoint *ep, SBMP_Datagram *dg, void **obj)
{ {
(void)obj; (void)obj;
sbmp_ep_remove_listener(ep, dg->session); sbmp_ep_remove_listener(ep, dg->session);
info("Measurement complete.");
PayloadParser pp = pp_start(dg->payload, dg->length); PayloadParser pp = pp_start(dg->payload, dg->length);
rpt_result.deviation = pp_float(&pp); rpt_result.deviation = pp_float(&pp);
rpt_result.rms = pp_float(&pp); rpt_result.i_rms = pp_float(&pp);
rpt_result.ready = true; // signal to waiting loop
}
/** Send report from rpt_result */
static void FLASH_FN do_send_report(void)
{
info("Sending report...");
switch (rpt_conf.service) {
case RPT_XIVELY:
// TODO send request
break;
case RPT_THINGSPEAK:
break;
}
} }
/** Immediately send report to xively / thingspeak */ /** Immediately send report to xively / thingspeak */
void reporting_send_now(void) bool FLASH_FN capture_and_report(void)
{ {
info("Starting reporting measurmenet...");
rpt_result.ready = false;
uint16_t sesn; uint16_t sesn;
sbmp_ep_send_message(dlnk_ep, DG_REQUEST_COMPARE_REF, NULL, 0, &sesn, NULL); sbmp_ep_send_message(dlnk_ep, DG_REQUEST_COMPARE_REF, NULL, 0, &sesn, NULL);
sbmp_ep_add_listener(dlnk_ep, sesn, compare_ref_cb, NULL); sbmp_ep_add_listener(dlnk_ep, sesn, compare_ref_cb, NULL);
// poll & wait for response // poll & wait for response
const int timeout = 500; const int timeout = 500;
for (uint32_t i = 0; i < timeout*100; i++) { for (uint32_t i = 0; i < timeout * 100; i++) {
uart_poll(); // can stop measure & start first chunk, if rx offer uart_poll();
// check for closed connection - aborted by peer? if (rpt_result.ready) {
if (meas_is_closed()) { do_send_report();
error("Session closed by peer, readout failed."); return true; // done
return false; // assume already cleaned up
} }
if (meas_chunk_ready()) { os_delay_us(10);
// yay!! system_soft_wdt_feed(); // Feed the dog, or it'll bite.
return true; }
// timeout - remove listener
error("Measure timeout - no resp received.");
sbmp_ep_remove_listener(dlnk_ep, sesn);
return false;
}
static bool capt_ref_done;
static bool capt_ref_success;
/** Callback for "store ref" */
static void FLASH_FN store_ref_cb(SBMP_Endpoint *ep, SBMP_Datagram *dg, void **obj)
{
(void)obj;
sbmp_ep_remove_listener(ep, dg->session);
capt_ref_done = true;
capt_ref_success = (dg->type == DG_SUCCESS);
}
/** Capture reference vector for monitoring */
bool FLASH_FN capture_reporting_reference(void)
{
info("Capturing refernece...");
uint16_t sesn;
sbmp_ep_send_message(dlnk_ep, DG_REQUEST_STORE_REF, NULL, 0, &sesn, NULL);
sbmp_ep_add_listener(dlnk_ep, sesn, store_ref_cb, NULL);
capt_ref_done = false;
capt_ref_success = false;
const int timeout = 500;
for (uint32_t i = 0; i < timeout * 100; i++) {
uart_poll();
if (capt_ref_done) {
return capt_ref_success; // done
} }
os_delay_us(10); os_delay_us(10);
system_soft_wdt_feed(); // Feed the dog, or it'll bite. system_soft_wdt_feed(); // Feed the dog, or it'll bite.
} }
// timeout - remove listener
error("Ref capture timeout - no resp received.");
sbmp_ep_remove_listener(dlnk_ep, sesn);
return false;
} }

@ -5,14 +5,14 @@
typedef struct { typedef struct {
// 0 // 0
bool enabled : 4; bool enabled;
// 4 // 4
uint32_t interval; uint32_t interval;
// 8 // 8
enum { enum {
RPT_XIVELY, RPT_XIVELY,
RPT_THINGSPEAK RPT_THINGSPEAK
} service : 4; } service;
// 12 // 12
char feed[64]; char feed[64];
// 76 // 76
@ -23,23 +23,28 @@ typedef struct {
/** Comapre result is stored here */ /** Comapre result is stored here */
typedef struct { typedef struct {
bool ready : 4; bool ready;
float deviation; float deviation;
float rms; float i_rms;
} ReportingResult; } ReportingResult;
/** Report result */
extern ReportingResult rpt_result; extern ReportingResult rpt_result;
/** Reporting config struct */ /** Reporting config struct */
extern ReportingCfg rpt_conf; extern ReportingCfg rpt_conf;
/** Save reporting config to flash */ /** Save reporting config to flash */
void reporting_save(void); void reporting_cfg_save(void);
/** Load the reporting config from flash */ /** Load the reporting config from flash */
void reporting_load(void); void reporting_cfg_load(void);
/** Immediately send report to xively / thingspeak */ /** Immediately send report to xively / thingspeak */
void reporting_send_now(void); bool capture_and_report(void);
/** Capture reference vector for monitoring */
bool capture_reporting_reference(void);
#endif // REPORTING_H #endif // REPORTING_H

@ -47,6 +47,10 @@ HttpdBuiltInUrl builtInUrls[] = {
ROUTE_TPL_FILE("/measure/raw", tplWaveformJSON, "/json/samples.tpl"), ROUTE_TPL_FILE("/measure/raw", tplWaveformJSON, "/json/samples.tpl"),
ROUTE_TPL_FILE("/measure/fft", tplFourierJSON, "/json/samples.tpl"), ROUTE_TPL_FILE("/measure/fft", tplFourierJSON, "/json/samples.tpl"),
ROUTE_CGI("/mon/compare", cgiMonCompare),
ROUTE_CGI("/mon/setref", cgiMonSetRef),
ROUTE_CGI("/mon/config", cgiMonitoringCfg), // redirects to /monitoring
// --- UI pages --- // --- UI pages ---
// System Status page // System Status page
ROUTE_TPL_FILE("/", tplSystemStatus, "/pages/status.tpl"), ROUTE_TPL_FILE("/", tplSystemStatus, "/pages/status.tpl"),

@ -23,14 +23,14 @@
#include "routes.h" #include "routes.h"
#include "fw_version.h" #include "fw_version.h"
#include "httpclient.h" #include "reporting.h"
extern HttpdBuiltInUrl builtInUrls[]; extern HttpdBuiltInUrl builtInUrls[];
static ETSTimer prSecondTimer; static ETSTimer prSecondTimer;
/** Timer called each second */ /** Timer called each second */
static void ICACHE_FLASH_ATTR prSecondTimerCb(void *arg) static void FLASH_FN prSecondTimerCb(void *arg)
{ {
(void)arg; (void)arg;
@ -112,6 +112,9 @@ void user_init(void)
httpdInit(builtInUrls, 80); httpdInit(builtInUrls, 80);
// start reporting timer
reporting_cfg_load();
printf(LOG_EOL); printf(LOG_EOL);
info("Ready"); info("Ready");
printf(LOG_EOL); printf(LOG_EOL);

Loading…
Cancel
Save