Browse Source

work on the reporting

Former-commit-id: 22df0fb4780da583ee956c45441fc15e9283eab1
master
Ondřej Hruška 6 years ago
parent
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

4
esphttpclient/httpclient.c

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

2
html/js/all.js

File diff suppressed because one or more lines are too long

21
html/pages/monitoring.tpl

@ -36,9 +36,12 @@
</td>
</tr>
<tr>
<th>Actual&nbsp;distance:</th>
<th>Actual&nbsp;state:</th>
<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>
</td>
</tr>
@ -47,36 +50,36 @@
<div class="Box">
<h2>Reporting</h2>
<form method="POST">
<form action="/mon/config" method="POST">
<table>
<tr>
<th><label for="rep-on">Reporting:</label></th>
<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>
</td>
</tr>
<tr>
<th><label for="rep-interval">Interval:</label></th>
<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
</td>
</tr>
<tr>
<th>Service:</th>
<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="rep-service" value="thingspeak" id="rep-svc-ts" %repSvcCheckTs%>&nbsp;<label for="rep-svc-ts">ThingSpeak</label>
<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="service" value="ts" id="rep-svc-ts" %repSvcCheckTs%>&nbsp;<label for="rep-svc-ts">ThingSpeak</label>
</td>
</tr>
<tr>
<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>
<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>
<th>&nbsp;</th>

9
html_src/js-src/page_mon.js

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

2
html_src/js/all.js

File diff suppressed because one or more lines are too long

2
html_src/js/all.js.map

File diff suppressed because one or more lines are too long

21
html_src/page_monitoring.php

@ -13,9 +13,12 @@
</td>
</tr>
<tr>
<th>Actual&nbsp;distance:</th>
<th>Actual&nbsp;state:</th>
<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>
</td>
</tr>
@ -24,36 +27,36 @@
<div class="Box">
<h2>Reporting</h2>
<form method="POST">
<form action="<?=$root?>/mon/config" method="POST">
<table>
<tr>
<th><label for="rep-on">Reporting:</label></th>
<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>
</td>
</tr>
<tr>
<th><label for="rep-interval">Interval:</label></th>
<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
</td>
</tr>
<tr>
<th>Service:</th>
<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="rep-service" value="thingspeak" id="rep-svc-ts" %repSvcCheckTs%>&nbsp;<label for="rep-svc-ts">ThingSpeak</label>
<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="service" value="ts" id="rep-svc-ts" %repSvcCheckTs%>&nbsp;<label for="rep-svc-ts">ThingSpeak</label>
</td>
</tr>
<tr>
<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>
<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>
<th>&nbsp;</th>

87
libesphttpd/core/httpd.c

@ -62,7 +62,7 @@ struct HttpdPriv {
//Connection pool
static HttpdConnData *connData[HTTPD_MAX_CONNECTIONS];
static HttpdConnData *connPool[HTTPD_MAX_CONNECTIONS];
//Struct to keep extension->mime data in
typedef struct {
@ -118,10 +118,10 @@ const char ICACHE_FLASH_ATTR *httpdGetMimetype(const char *filepath) {
//Looks up the connData info for a specific connection
static HttpdConnData ICACHE_FLASH_ATTR *httpdFindConnData(ConnTypePtr conn, const char *remIp, int remPort) {
for (int i=0; i<HTTPD_MAX_CONNECTIONS; i++) {
if (connData[i] && connData[i]->remote_port == remPort &&
memcmp(connData[i]->remote_ip, remIp, 4) == 0) {
connData[i]->conn=conn;
return connData[i];
if (connPool[i] && connPool[i]->remote_port == remPort &&
memcmp(connPool[i]->remote_ip, remIp, 4) == 0) {
connPool[i]->conn=conn;
return connPool[i];
}
}
//Shouldn't happen.
@ -146,7 +146,7 @@ static void ICACHE_FLASH_ATTR httpdRetireConn(HttpdConnData *conn) {
if (conn->priv!=NULL) free(conn->priv);
if (conn) free(conn);
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.
int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) {
httpd_cgi_state ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) {
if (connData->conn==NULL) {
//Connection aborted. Clean up.
return HTTPD_CGI_DONE;
@ -295,7 +295,7 @@ int ICACHE_FLASH_ATTR cgiRedirect(HttpdConnData *connData) {
}
//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;
httpdStartResponse(connData, 404);
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:
//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.
int ICACHE_FLASH_ATTR cgiRedirectToHostname(HttpdConnData *connData) {
httpd_cgi_state ICACHE_FLASH_ATTR cgiRedirectToHostname(HttpdConnData *connData) {
static const char hostFmt[]="http://%s/";
char *buff;
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
//the SoftAP interface. This should preclude clients connected to the STA interface
//to be redirected to nowhere.
int ICACHE_FLASH_ATTR cgiRedirectApClientToHostname(HttpdConnData *connData) {
httpd_cgi_state ICACHE_FLASH_ATTR cgiRedirectApClientToHostname(HttpdConnData *connData) {
#ifndef FREERTOS
uint32 *remadr;
struct ip_info apip;
@ -588,19 +588,22 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
int i;
char firstLine=0;
if (strncmp(h, "GET ", 4)==0) {
if (strstarts(h, "GET ")) {
conn->requestType = HTTPD_METHOD_GET;
firstLine=1;
} else if (strncmp(h, "Host:", 5)==0) {
i=5;
while (h[i]==' ') i++;
conn->hostName=&h[i];
} else if (strncmp(h, "POST ", 5)==0) {
} else if (strstarts(h, "POST ")) {
conn->requestType = HTTPD_METHOD_POST;
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;
firstLine=1;
} else if (strstarts(h, "Host:")) {
i=5;
while (h[i]==' ') i++;
conn->hostName=&h[i];
}
if (firstLine) {
@ -630,12 +633,12 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
} else {
conn->getArgs=NULL;
}
} else if (strncmp(h, "Connection:", 11)==0) {
} else if (strstarts(h, "Connection:")) {
i=11;
//Skip trailing spaces
while (h[i]==' ') i++;
if (strncmp(&h[i], "close", 5)==0) conn->priv->flags&=~HFL_CHUNKED; //Don't use chunked conn
} else if (strncmp(h, "Content-Length:", 15)==0) {
if (strstarts(&h[i], "close")) conn->priv->flags&=~HFL_CHUNKED; //Don't use chunked conn
} else if (strstarts(h, "Content-Length:")) {
i=15;
//Skip trailing spaces
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);
conn->post->buff=(char*)malloc(conn->post->buffSize + 1);
conn->post->buffLen=0;
} else if (strncmp(h, "Content-Type: ", 14)==0) {
} else if (strstarts(h, "Content-Type: ")) {
if (strstr(h, "multipart/form-data")) {
// It's multipart form data so let's pull out the boundary for future use
char *b;
@ -663,7 +666,7 @@ static void ICACHE_FLASH_ATTR httpdParseHeader(char *h, HttpdConnData *conn) {
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
info("CORS preflight request.");
@ -783,7 +786,7 @@ int ICACHE_FLASH_ATTR httpdConnectCb(ConnTypePtr conn, char *remIp, int remPort)
int i;
//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);
if (i==HTTPD_MAX_CONNECTIONS) {
error("Aiee, conn pool overflow!");
@ -799,24 +802,24 @@ int ICACHE_FLASH_ATTR httpdConnectCb(ConnTypePtr conn, char *remIp, int remPort)
failed_cnt = 0;
connData[i]=malloc(sizeof(HttpdConnData));
memset(connData[i], 0, sizeof(HttpdConnData));
connData[i]->priv=malloc(sizeof(HttpdPriv));
memset(connData[i]->priv, 0, sizeof(HttpdPriv));
connData[i]->conn=conn;
connData[i]->slot=i;
connData[i]->priv->headPos=0;
connData[i]->post=malloc(sizeof(HttpdPostData));
memset(connData[i]->post, 0, sizeof(HttpdPostData));
connData[i]->post->buff=NULL;
connData[i]->post->buffLen=0;
connData[i]->post->received=0;
connData[i]->post->len=-1;
connData[i]->hostName=NULL;
connData[i]->remote_port=remPort;
connData[i]->priv->sendBacklog=NULL;
connData[i]->priv->sendBacklogSize=0;
memcpy(connData[i]->remote_ip, remIp, 4);
connPool[i]=malloc(sizeof(HttpdConnData));
memset(connPool[i], 0, sizeof(HttpdConnData));
connPool[i]->priv=malloc(sizeof(HttpdPriv));
memset(connPool[i]->priv, 0, sizeof(HttpdPriv));
connPool[i]->conn=conn;
connPool[i]->slot=i;
connPool[i]->priv->headPos=0;
connPool[i]->post=malloc(sizeof(HttpdPostData));
memset(connPool[i]->post, 0, sizeof(HttpdPostData));
connPool[i]->post->buff=NULL;
connPool[i]->post->buffLen=0;
connPool[i]->post->received=0;
connPool[i]->post->len=-1;
connPool[i]->hostName=NULL;
connPool[i]->remote_port=remPort;
connPool[i]->priv->sendBacklog=NULL;
connPool[i]->priv->sendBacklogSize=0;
memcpy(connPool[i]->remote_ip, remIp, 4);
return 1;
}
@ -826,7 +829,7 @@ void ICACHE_FLASH_ATTR httpdInit(HttpdBuiltInUrl *fixedUrls, int port) {
int i;
for (i=0; i<HTTPD_MAX_CONNECTIONS; i++) {
connData[i]=NULL;
connPool[i]=NULL;
}
builtInUrls=fixedUrls;

12
libesphttpd/core/httpdespfs.c

@ -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;
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
//path in the filesystem and if it exists, passes the file through. This simulates what a normal
//webserver would do with static files.
int ICACHE_FLASH_ATTR cgiEspFsHook(HttpdConnData *connData)
httpd_cgi_state cgiEspFsHook(HttpdConnData *connData)
{
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);
}
@ -183,9 +183,9 @@ typedef struct {
char *buff_e;
} 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;
int len;
@ -289,7 +289,7 @@ int ICACHE_FLASH_ATTR cgiEspFsTemplate(HttpdConnData *connData)
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) {
// dbg("Multi-part tpl subst, saving parser state");

8
libesphttpd/include/cgiflash.h

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

9
libesphttpd/include/cgiwebsocket.h

@ -27,11 +27,12 @@ struct Websock {
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);
void ICACHE_FLASH_ATTR cgiWebsocketClose(Websock *ws, int reason);
int ICACHE_FLASH_ATTR cgiWebSocketRecv(HttpdConnData *connData, char *data, int len);
int ICACHE_FLASH_ATTR cgiWebsockBroadcast(char *resource, char *data, int len, int flags);
httpd_cgi_state cgiWebSocketRecv(HttpdConnData *connData, char *data, int len);
//int ICACHE_FLASH_ATTR cgiWebsockBroadcast(char *resource, char *data, int len, int flags);
#endif
#endif

14
libesphttpd/include/cgiwifi.h

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

37
libesphttpd/include/httpd.h

@ -5,26 +5,34 @@
#define HTTPDVER "0.4-based"
#define HTTPD_CGI_MORE 0
#define HTTPD_CGI_DONE 1
#define HTTPD_CGI_NOTFOUND 2
#define HTTPD_CGI_AUTHENTICATED 3
#define HTTPD_METHOD_GET 1
#define HTTPD_METHOD_POST 2
#define HTTPD_METHOD_OPTIONS 3
typedef enum {
HTTPD_CGI_MORE = 0,
HTTPD_CGI_DONE = 1,
HTTPD_CGI_NOTFOUND = 2,
HTTPD_CGI_AUTHENTICATED = 3,
} httpd_cgi_state;
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 HttpdConnData HttpdConnData;
typedef struct HttpdPostData HttpdPostData;
typedef int (* cgiSendCallback)(HttpdConnData *connData);
typedef int (* cgiRecvHandler)(HttpdConnData *connData, char *data, int len);
typedef httpd_cgi_state (* cgiSendCallback)(HttpdConnData *connData);
typedef httpd_cgi_state (* cgiRecvHandler)(HttpdConnData *connData, char *data, int len);
//A struct describing a http connection. This gets passed to cgi functions.
struct HttpdConnData {
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 *getArgs; // The GET arguments for this request, if any.
@ -89,9 +97,10 @@ typedef struct {
int cgiRedirect(HttpdConnData *connData);
int cgiRedirectToHostname(HttpdConnData *connData);
int cgiRedirectApClientToHostname(HttpdConnData *connData);
httpd_cgi_state cgiRedirect(HttpdConnData *connData);
httpd_cgi_state cgiRedirectToHostname(HttpdConnData *connData);
httpd_cgi_state cgiRedirectApClientToHostname(HttpdConnData *connData);
void httpdRedirect(HttpdConnData *conn, char *newUrl);
int httpdUrlDecode(char *val, int valLen, char *ret, int retLen);
int httpdFindArg(char *line, char *arg, char *buff, int buffLen);

6
libesphttpd/include/httpdespfs.h

@ -4,12 +4,12 @@
#include "httpd.h"
/** Catch-all, use in '*' routes */
int cgiEspFsHook(HttpdConnData *connData);
httpd_cgi_state cgiEspFsHook(HttpdConnData *connData);
/** 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. */
int ICACHE_FLASH_ATTR cgiEspFsFile(HttpdConnData *connData);
httpd_cgi_state ICACHE_FLASH_ATTR cgiEspFsFile(HttpdConnData *connData);
#endif

8
libesphttpd/util/cgiflash.c

@ -43,7 +43,7 @@ static int ICACHE_FLASH_ATTR checkEspfsHeader(void *buf) {
// 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) {
//Connection aborted. Clean up.
return HTTPD_CGI_DONE;
@ -62,7 +62,7 @@ int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) {
//Cgi that reads the SPI flash. Assumes 512KByte flash.
//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;
if (connData->conn==NULL) {
//Connection aborted. Clean up.
@ -123,7 +123,7 @@ typedef struct __attribute__((packed)) {
} OtaHeader;
int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) {
httpd_cgi_state ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) {
CgiUploadFlashDef *def=(CgiUploadFlashDef*)connData->cgiArg;
UploadState *state=(UploadState *)connData->cgiData;
int len;
@ -302,7 +302,7 @@ static void ICACHE_FLASH_ATTR resetTimerCb(void *arg) {
}
// 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) {
//Connection aborted. Clean up.
return HTTPD_CGI_DONE;

45
libesphttpd/util/cgiwebsocket.c

@ -119,26 +119,27 @@ int ICACHE_FLASH_ATTR cgiWebsocketSend(Websock *ws, char *data, int len, int fla
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) {
//This is majorly broken (and actually, always, it just tended to work because the circumstances
//were juuuust right). Because the socket is used outside of the httpd send/receive context, it
//will not have an associated send buffer. This means httpdSend will write to a dangling pointer!
//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;
while (lw!=NULL) {
if (strcmp(lw->conn->url, resource)==0) {
cgiWebsocketSend(lw, data, len, flags);
ret++;
}
lw=lw->priv->next;
}
return ret;*/
return 0;
}
////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) {
////This is majorly broken (and actually, always, it just tended to work because the circumstances
////were juuuust right). Because the socket is used outside of the httpd send/receive context, it
////will not have an associated send buffer. This means httpdSend will write to a dangling pointer!
////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;
// while (lw!=NULL) {
// if (strcmp(lw->conn->url, resource)==0) {
// cgiWebsocketSend(lw, data, len, flags);
// ret++;
// }
// lw=lw->priv->next;
// }
// return ret;*/
// return 0;
//}
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);
}
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 r=HTTPD_CGI_MORE;
int wasHeaderByte;
@ -280,7 +281,7 @@ int ICACHE_FLASH_ATTR cgiWebSocketRecv(HttpdConnData *connData, char *data, int
}
//Websocket 'cgi' implementation
int ICACHE_FLASH_ATTR cgiWebsocket(HttpdConnData *connData) {
httpd_cgi_state ICACHE_FLASH_ATTR cgiWebsocket(HttpdConnData *connData) {
char buff[256];
int i;
sha1nfo s;

10
libesphttpd/util/cgiwifi.c

@ -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
//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.
int ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) {
httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiScan(HttpdConnData *connData) {
int pos=(int)connData->cgiData;
int len;
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
//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 passwd[128];
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
//given ESSID using the given password.
int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
int len;
char buff[64];
@ -282,7 +282,7 @@ int ICACHE_FLASH_ATTR cgiWiFiSetMode(HttpdConnData *connData) {
return HTTPD_CGI_DONE;
}
int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
httpd_cgi_state ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
char buff[256];
int len;
struct ip_info info;
@ -314,7 +314,7 @@ int ICACHE_FLASH_ATTR cgiWiFiConnStatus(HttpdConnData *connData) {
}
//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];
int x;
static struct station_config stconf;

2
sbmp

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

3
user/cgi_ping.c

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

2
user/cgi_ping.h

@ -6,6 +6,6 @@
// 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

3
user/cgi_reset.c

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

2
user/cgi_reset.h

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

1
user/datalink.h

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

2
user/page_about.c

@ -5,7 +5,7 @@
#include "sbmp.h"
/** "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
(void)arg;

2
user/page_about.h

@ -3,6 +3,6 @@
#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

161
user/page_monitoring.c

@ -1,11 +1,124 @@
#include <esp8266.h>
#include <httpd.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 */
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;
char buf[20];
@ -15,24 +128,46 @@ int FLASH_FN tplMonitoring(HttpdConnData *connData, char *token, void **arg)
if (streq(token, "refStored")) {
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")) {
if (true) httpdSend(connData, "checked", -1); // fixme
if (rpt_conf.enabled) httpdSend(connData, "checked", -1);
} else if (streq(token, "repInterval")) {
sprintf(buf, "%d", 123); // fixme
} else if (streq(token, "repInterval")) { // interval in seconds
sprintf(buf, "%d", rpt_conf.interval);
httpdSend(connData, buf, -1);
} else if (streq(token, "repSvcCheckXv")) { // Xively
if (true) httpdSend(connData, "checked", -1); // fixme
} else if (streq(token, "repSvcCheckXv")) { // Xively checkbox
if (rpt_conf.service == RPT_XIVELY) {
httpdSend(connData, "checked", -1);
}
} else if (streq(token, "repSvcCheckTs")) { // ThingSpeak
if (true) httpdSend(connData, "checked", -1); // fixme
} else if (streq(token, "repSvcCheckTs")) { // ThingSpeak checkbox
if (rpt_conf.service == RPT_THINGSPEAK) {
httpdSend(connData, "checked", -1);
}
} else if (streq(token, "repFeed")) {
httpdSend(connData, "null", -1); // fixme
} else if (streq(token, "repFeed")) { // reporting feed ID
httpdSend(connData, rpt_conf.feed, -1);
} else if (streq(token, "repKey")) {
httpdSend(connData, "null", -1); // fixme
} else if (streq(token, "repKey")) { // reporting key
httpdSend(connData, rpt_conf.key, -1);
}
return HTTPD_CGI_DONE;

8
user/page_monitoring.h

@ -3,6 +3,12 @@
#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

2
user/page_status.c

@ -7,7 +7,7 @@
/** 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
(void)arg;

2
user/page_status.h

@ -3,6 +3,6 @@
#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

8
user/page_waveform.c

@ -19,22 +19,22 @@ typedef struct {
} 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);
}
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);
}
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];
int len;

4
user/page_waveform.h

@ -3,8 +3,8 @@
#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

135
user/reporting.c

@ -1,6 +1,7 @@
#include "reporting.h"
#include "datalink.h"
#include "serial.h"
#include "httpclient.h"
#define RPT_CONF_MAGIC 0x24C595D5
@ -10,94 +11,184 @@ ReportingCfg rpt_conf;
static os_timer_t rpt_tim;
/** Timer cb */
static void rpt_tim_cb(void *arg)
static void FLASH_FN rpt_tim_cb(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 */
static void set_timer(void)
static FLASH_FN void set_timer(void)
{
os_timer_disarm(&rpt_tim);
if (rpt_conf.enabled) {
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.. */
static void normalize_rpt_conf(void)
static FLASH_FN void normalize_rpt_conf(void)
{
// terminate strings
rpt_conf.feed[sizeof(rpt_conf.feed)-1] = 0;
rpt_conf.key[sizeof(rpt_conf.key)-1] = 0;
rpt_conf.feed[sizeof(rpt_conf.feed) - 1] = 0;
rpt_conf.key[sizeof(rpt_conf.key) - 1] = 0;
// set 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 */
void reporting_save(void)
void FLASH_FN reporting_cfg_save(void)
{
normalize_rpt_conf(); // fix weirdness
info("Saving monitoring config");
dump_rpt_conf();
system_param_save_with_protect(0x3D, &rpt_conf, sizeof(ReportingCfg));
// start timer for the new interval time
set_timer();
info("Config saved.");
}
/** 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));
if (rpt_conf.magic != RPT_CONF_MAGIC) {
warn("Config block corrupted, reset to defaults.");
// invalid config, zero out
memset(&rpt_conf, 0, sizeof(ReportingCfg));
rpt_conf.magic = RPT_CONF_MAGIC;
// save fixed
reporting_save();
reporting_cfg_save();
} else {
dump_rpt_conf();
}
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;
sbmp_ep_remove_listener(ep, dg->session);
info("Measurement complete.");
PayloadParser pp = pp_start(dg->payload, dg->length);
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 */
void reporting_send_now(void)
bool FLASH_FN capture_and_report(void)
{
info("Starting reporting measurmenet...");
rpt_result.ready = false;
uint16_t sesn;
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);
// poll & wait for response
const int timeout = 500;
for (uint32_t i = 0; i < timeout*100; i++) {
uart_poll(); // can stop measure & start first chunk, if rx offer
for (uint32_t i = 0; i < timeout * 100; i++) {
uart_poll();
// check for closed connection - aborted by peer?
if (meas_is_closed()) {
error("Session closed by peer, readout failed.");
return false; // assume already cleaned up
if (rpt_result.ready) {
do_send_report();
return true; // done
}
if (meas_chunk_ready()) {
// yay!!
return true;
os_delay_us(10);
system_soft_wdt_feed(); // Feed the dog, or it'll bite.
}
// 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);
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;
}

19
user/reporting.h

@ -5,14 +5,14 @@
typedef struct {
// 0
bool enabled : 4;
bool enabled;
// 4
uint32_t interval;
// 8
enum {
RPT_XIVELY,
RPT_THINGSPEAK
} service : 4;
} service;
// 12
char feed[64];
// 76
@ -23,23 +23,28 @@ typedef struct {
/** Comapre result is stored here */
typedef struct {
bool ready : 4;
bool ready;
float deviation;
float rms;
float i_rms;
} ReportingResult;
/** Report result */
extern ReportingResult rpt_result;
/** Reporting config struct */
extern ReportingCfg rpt_conf;
/** Save reporting config to flash */
void reporting_save(void);
void reporting_cfg_save(void);
/** Load the reporting config from flash */
void reporting_load(void);
void reporting_cfg_load(void);
/** 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

4
user/routes.c

@ -47,6 +47,10 @@ HttpdBuiltInUrl builtInUrls[] = {
ROUTE_TPL_FILE("/measure/raw", tplWaveformJSON, "/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 ---
// System Status page
ROUTE_TPL_FILE("/", tplSystemStatus, "/pages/status.tpl"),

7
user/user_main.c

@ -23,14 +23,14 @@
#include "routes.h"
#include "fw_version.h"
#include "httpclient.h"
#include "reporting.h"
extern HttpdBuiltInUrl builtInUrls[];
static ETSTimer prSecondTimer;
/** Timer called each second */