parent
2357472b4c
commit
f77caa03f2
@ -0,0 +1,161 @@ |
||||
TEMPLATE = app |
||||
CONFIG += console |
||||
CONFIG -= app_bundle |
||||
CONFIG -= qt |
||||
|
||||
DEFINES = ESPFS_HEATSHRINK HTTPD_MAX_CONNECTIONS=4 __ets__ |
||||
|
||||
INCLUDEPATH = . \ |
||||
esp_iot_sdk_v1.5.2/include \ |
||||
include \ |
||||
user \ |
||||
esphttpclient \ |
||||
libesphttpd/include \ |
||||
libesphttpd/espfs \ |
||||
libesphttpd/core \ |
||||
libesphttpd/lib/heatshrink \ |
||||
sbmp/library \ |
||||
/home/ondra/devel/esp/sdk/esp-open-sdk/xtensa-lx106-elf/xtensa-lx106-elf/include |
||||
|
||||
SOURCES += \ |
||||
libesphttpd/core/auth.c \ |
||||
libesphttpd/core/base64.c \ |
||||
libesphttpd/core/httpd-freertos.c \ |
||||
libesphttpd/core/httpd-nonos.c \ |
||||
libesphttpd/core/httpd.c \ |
||||
libesphttpd/core/httpdespfs.c \ |
||||
libesphttpd/core/sha1.c \ |
||||
libesphttpd/espfs/espfstest/main.c \ |
||||
libesphttpd/espfs/mkespfsimage/heatshrink_encoder.c \ |
||||
libesphttpd/espfs/mkespfsimage/main.c \ |
||||
libesphttpd/espfs/espfs.c \ |
||||
libesphttpd/espfs/heatshrink_decoder.c \ |
||||
libesphttpd/lib/heatshrink/heatshrink.c \ |
||||
libesphttpd/lib/heatshrink/heatshrink_decoder.c \ |
||||
libesphttpd/lib/heatshrink/heatshrink_encoder.c \ |
||||
libesphttpd/lib/heatshrink/test_heatshrink_dynamic.c \ |
||||
libesphttpd/lib/heatshrink/test_heatshrink_dynamic_theft.c \ |
||||
libesphttpd/lib/heatshrink/test_heatshrink_static.c \ |
||||
libesphttpd/mkupgimg/mkupgimg.c \ |
||||
libesphttpd/util/captdns.c \ |
||||
libesphttpd/util/cgiflash.c \ |
||||
libesphttpd/util/cgiwebsocket.c \ |
||||
libesphttpd/util/cgiwifi.c \ |
||||
user/cgi-test.c \ |
||||
user/io.c \ |
||||
user/user_main.c \ |
||||
user/uart_driver.c \ |
||||
sbmp/library/crc32.c \ |
||||
sbmp/library/sbmp_checksum.c \ |
||||
sbmp/library/sbmp_datagram.c \ |
||||
sbmp/library/sbmp_frame.c \ |
||||
sbmp/library/sbmp_session.c \ |
||||
sbmp/library/sbmp_bulk.c \ |
||||
user/datalink.c \ |
||||
user/serial.c \ |
||||
user/uptime.c \ |
||||
sbmp/library/payload_parser.c \ |
||||
user/sampling.c \ |
||||
user/ftoa.c \ |
||||
user/routes.c \ |
||||
user/utils.c \ |
||||
sbmp/library/payload_builder.c \ |
||||
user/cgi_reset.c \ |
||||
user/cgi_ping.c \ |
||||
esphttpclient/test/httpclient_test.c \ |
||||
esphttpclient/httpclient.c \ |
||||
user/wificontrol.c \ |
||||
user/page_home.c \ |
||||
user/pers_cfg.c |
||||
|
||||
HEADERS += \ |
||||
include/uart_hw.h \ |
||||
include/user_config.h \ |
||||
libesphttpd/core/base64.h \ |
||||
libesphttpd/core/httpd-platform.h \ |
||||
libesphttpd/espfs/espfsformat.h \ |
||||
libesphttpd/espfs/heatshrink_config_custom.h \ |
||||
libesphttpd/include/auth.h \ |
||||
libesphttpd/include/captdns.h \ |
||||
libesphttpd/include/cgiflash.h \ |
||||
libesphttpd/include/cgiwebsocket.h \ |
||||
libesphttpd/include/cgiwifi.h \ |
||||
libesphttpd/include/esp8266.h \ |
||||
libesphttpd/include/espfs.h \ |
||||
libesphttpd/include/httpd.h \ |
||||
libesphttpd/include/httpdespfs.h \ |
||||
libesphttpd/include/platform.h \ |
||||
libesphttpd/include/sha1.h \ |
||||
libesphttpd/include/user_config.h \ |
||||
libesphttpd/include/webpages-espfs.h \ |
||||
libesphttpd/lib/heatshrink/greatest.h \ |
||||
libesphttpd/lib/heatshrink/heatshrink_common.h \ |
||||
libesphttpd/lib/heatshrink/heatshrink_config.h \ |
||||
libesphttpd/lib/heatshrink/heatshrink_decoder.h \ |
||||
libesphttpd/lib/heatshrink/heatshrink_encoder.h \ |
||||
user/cgi-test.h \ |
||||
user/io.h \ |
||||
user/uart_register.h \ |
||||
esp_iot_sdk_v1.5.2/include/json/json.h \ |
||||
esp_iot_sdk_v1.5.2/include/json/jsonparse.h \ |
||||
esp_iot_sdk_v1.5.2/include/json/jsontree.h \ |
||||
esp_iot_sdk_v1.5.2/include/airkiss.h \ |
||||
esp_iot_sdk_v1.5.2/include/at_custom.h \ |
||||
esp_iot_sdk_v1.5.2/include/c_types.h \ |
||||
esp_iot_sdk_v1.5.2/include/eagle_soc.h \ |
||||
esp_iot_sdk_v1.5.2/include/esp_sdk_ver.h \ |
||||
esp_iot_sdk_v1.5.2/include/espconn.h \ |
||||
esp_iot_sdk_v1.5.2/include/espnow.h \ |
||||
esp_iot_sdk_v1.5.2/include/ets_sys.h \ |
||||
esp_iot_sdk_v1.5.2/include/gpio.h \ |
||||
esp_iot_sdk_v1.5.2/include/ip_addr.h \ |
||||
esp_iot_sdk_v1.5.2/include/mem.h \ |
||||
esp_iot_sdk_v1.5.2/include/mesh.h \ |
||||
esp_iot_sdk_v1.5.2/include/os_type.h \ |
||||
esp_iot_sdk_v1.5.2/include/osapi.h \ |
||||
esp_iot_sdk_v1.5.2/include/ping.h \ |
||||
esp_iot_sdk_v1.5.2/include/pwm.h \ |
||||
esp_iot_sdk_v1.5.2/include/queue.h \ |
||||
esp_iot_sdk_v1.5.2/include/slc_register.h \ |
||||
esp_iot_sdk_v1.5.2/include/smartconfig.h \ |
||||
esp_iot_sdk_v1.5.2/include/sntp.h \ |
||||
esp_iot_sdk_v1.5.2/include/spi_flash.h \ |
||||
esp_iot_sdk_v1.5.2/include/spi_register.h \ |
||||
esp_iot_sdk_v1.5.2/include/uart_register.h \ |
||||
esp_iot_sdk_v1.5.2/include/upgrade.h \ |
||||
esp_iot_sdk_v1.5.2/include/user_interface.h \ |
||||
user/uart_driver.h \ |
||||
sbmp/library/crc32.h \ |
||||
sbmp/library/sbmp.h \ |
||||
sbmp/library/sbmp_checksum.h \ |
||||
sbmp/library/sbmp_config.h \ |
||||
sbmp/library/sbmp_datagram.h \ |
||||
sbmp/library/sbmp_frame.h \ |
||||
sbmp/library/sbmp_logging.h \ |
||||
sbmp/library/sbmp_session.h \ |
||||
sbmp/library/sbmp_bulk.h \ |
||||
user/datalink.h \ |
||||
user/serial.h \ |
||||
libesphttpd/include/logging.h \ |
||||
user/uptime.h \ |
||||
sbmp/library/payload_parser.h \ |
||||
user/sampling.h \ |
||||
user/sbmp_config.h \ |
||||
sbmp/library/sbmp_config.example.h \ |
||||
user/ftoa.h \ |
||||
user/routes.h \ |
||||
libesphttpd/include/espmissingprotos.h \ |
||||
user/utils.h \ |
||||
sbmp/library/payload_builder.h \ |
||||
user/fw_version.h \ |
||||
user/cgi_reset.h \ |
||||
user/cgi_ping.h \ |
||||
esphttpclient/espmissingincludes.h \ |
||||
esphttpclient/httpclient.h \ |
||||
user/wificontrol.h \ |
||||
user/page_home.h \ |
||||
user/pers_cfg.h |
||||
|
||||
DISTFILES += \ |
||||
style.astylerc \ |
||||
Makefile |
@ -1,167 +0,0 @@ |
||||
TEMPLATE = app |
||||
CONFIG += console |
||||
CONFIG -= app_bundle |
||||
CONFIG -= qt |
||||
|
||||
DEFINES = ESPFS_HEATSHRINK HTTPD_MAX_CONNECTIONS=4 __ets__ |
||||
|
||||
INCLUDEPATH = . \ |
||||
esp_iot_sdk_v1.5.2/include \ |
||||
include \ |
||||
user \ |
||||
esphttpclient \ |
||||
libesphttpd/include \ |
||||
libesphttpd/espfs \ |
||||
libesphttpd/core \ |
||||
libesphttpd/lib/heatshrink \ |
||||
sbmp/library \ |
||||
/home/ondra/devel/esp/sdk/esp-open-sdk/xtensa-lx106-elf/xtensa-lx106-elf/include |
||||
|
||||
SOURCES += \ |
||||
libesphttpd/core/auth.c \ |
||||
libesphttpd/core/base64.c \ |
||||
libesphttpd/core/httpd-freertos.c \ |
||||
libesphttpd/core/httpd-nonos.c \ |
||||
libesphttpd/core/httpd.c \ |
||||
libesphttpd/core/httpdespfs.c \ |
||||
libesphttpd/core/sha1.c \ |
||||
libesphttpd/espfs/espfstest/main.c \ |
||||
libesphttpd/espfs/mkespfsimage/heatshrink_encoder.c \ |
||||
libesphttpd/espfs/mkespfsimage/main.c \ |
||||
libesphttpd/espfs/espfs.c \ |
||||
libesphttpd/espfs/heatshrink_decoder.c \ |
||||
libesphttpd/lib/heatshrink/heatshrink.c \ |
||||
libesphttpd/lib/heatshrink/heatshrink_decoder.c \ |
||||
libesphttpd/lib/heatshrink/heatshrink_encoder.c \ |
||||
libesphttpd/lib/heatshrink/test_heatshrink_dynamic.c \ |
||||
libesphttpd/lib/heatshrink/test_heatshrink_dynamic_theft.c \ |
||||
libesphttpd/lib/heatshrink/test_heatshrink_static.c \ |
||||
libesphttpd/mkupgimg/mkupgimg.c \ |
||||
libesphttpd/util/captdns.c \ |
||||
libesphttpd/util/cgiflash.c \ |
||||
libesphttpd/util/cgiwebsocket.c \ |
||||
libesphttpd/util/cgiwifi.c \ |
||||
user/cgi-test.c \ |
||||
user/io.c \ |
||||
user/user_main.c \ |
||||
user/uart_driver.c \ |
||||
sbmp/library/crc32.c \ |
||||
sbmp/library/sbmp_checksum.c \ |
||||
sbmp/library/sbmp_datagram.c \ |
||||
sbmp/library/sbmp_frame.c \ |
||||
sbmp/library/sbmp_session.c \ |
||||
sbmp/library/sbmp_bulk.c \ |
||||
user/datalink.c \ |
||||
user/serial.c \ |
||||
user/uptime.c \ |
||||
sbmp/library/payload_parser.c \ |
||||
user/sampling.c \ |
||||
user/ftoa.c \ |
||||
user/routes.c \ |
||||
user/page_status.c \ |
||||
user/page_waveform.c \ |
||||
user/utils.c \ |
||||
sbmp/library/payload_builder.c \ |
||||
user/page_about.c \ |
||||
user/cgi_reset.c \ |
||||
user/cgi_ping.c \ |
||||
esphttpclient/test/httpclient_test.c \ |
||||
esphttpclient/httpclient.c \ |
||||
user/page_monitoring.c \ |
||||
user/reporting.c \ |
||||
user/wificontrol.c |
||||
|
||||
HEADERS += \ |
||||
include/uart_hw.h \ |
||||
include/user_config.h \ |
||||
libesphttpd/core/base64.h \ |
||||
libesphttpd/core/httpd-platform.h \ |
||||
libesphttpd/espfs/espfsformat.h \ |
||||
libesphttpd/espfs/heatshrink_config_custom.h \ |
||||
libesphttpd/include/auth.h \ |
||||
libesphttpd/include/captdns.h \ |
||||
libesphttpd/include/cgiflash.h \ |
||||
libesphttpd/include/cgiwebsocket.h \ |
||||
libesphttpd/include/cgiwifi.h \ |
||||
libesphttpd/include/esp8266.h \ |
||||
libesphttpd/include/espfs.h \ |
||||
libesphttpd/include/httpd.h \ |
||||
libesphttpd/include/httpdespfs.h \ |
||||
libesphttpd/include/platform.h \ |
||||
libesphttpd/include/sha1.h \ |
||||
libesphttpd/include/user_config.h \ |
||||
libesphttpd/include/webpages-espfs.h \ |
||||
libesphttpd/lib/heatshrink/greatest.h \ |
||||
libesphttpd/lib/heatshrink/heatshrink_common.h \ |
||||
libesphttpd/lib/heatshrink/heatshrink_config.h \ |
||||
libesphttpd/lib/heatshrink/heatshrink_decoder.h \ |
||||
libesphttpd/lib/heatshrink/heatshrink_encoder.h \ |
||||
user/cgi-test.h \ |
||||
user/io.h \ |
||||
user/uart_register.h \ |
||||
esp_iot_sdk_v1.5.2/include/json/json.h \ |
||||
esp_iot_sdk_v1.5.2/include/json/jsonparse.h \ |
||||
esp_iot_sdk_v1.5.2/include/json/jsontree.h \ |
||||
esp_iot_sdk_v1.5.2/include/airkiss.h \ |
||||
esp_iot_sdk_v1.5.2/include/at_custom.h \ |
||||
esp_iot_sdk_v1.5.2/include/c_types.h \ |
||||
esp_iot_sdk_v1.5.2/include/eagle_soc.h \ |
||||
esp_iot_sdk_v1.5.2/include/esp_sdk_ver.h \ |
||||
esp_iot_sdk_v1.5.2/include/espconn.h \ |
||||
esp_iot_sdk_v1.5.2/include/espnow.h \ |
||||
esp_iot_sdk_v1.5.2/include/ets_sys.h \ |
||||
esp_iot_sdk_v1.5.2/include/gpio.h \ |
||||
esp_iot_sdk_v1.5.2/include/ip_addr.h \ |
||||
esp_iot_sdk_v1.5.2/include/mem.h \ |
||||
esp_iot_sdk_v1.5.2/include/mesh.h \ |
||||
esp_iot_sdk_v1.5.2/include/os_type.h \ |
||||
esp_iot_sdk_v1.5.2/include/osapi.h \ |
||||
esp_iot_sdk_v1.5.2/include/ping.h \ |
||||
esp_iot_sdk_v1.5.2/include/pwm.h \ |
||||
esp_iot_sdk_v1.5.2/include/queue.h \ |
||||
esp_iot_sdk_v1.5.2/include/slc_register.h \ |
||||
esp_iot_sdk_v1.5.2/include/smartconfig.h \ |
||||
esp_iot_sdk_v1.5.2/include/sntp.h \ |
||||
esp_iot_sdk_v1.5.2/include/spi_flash.h \ |
||||
esp_iot_sdk_v1.5.2/include/spi_register.h \ |
||||
esp_iot_sdk_v1.5.2/include/uart_register.h \ |
||||
esp_iot_sdk_v1.5.2/include/upgrade.h \ |
||||
esp_iot_sdk_v1.5.2/include/user_interface.h \ |
||||
user/uart_driver.h \ |
||||
sbmp/library/crc32.h \ |
||||
sbmp/library/sbmp.h \ |
||||
sbmp/library/sbmp_checksum.h \ |
||||
sbmp/library/sbmp_config.h \ |
||||
sbmp/library/sbmp_datagram.h \ |
||||
sbmp/library/sbmp_frame.h \ |
||||
sbmp/library/sbmp_logging.h \ |
||||
sbmp/library/sbmp_session.h \ |
||||
sbmp/library/sbmp_bulk.h \ |
||||
user/datalink.h \ |
||||
user/serial.h \ |
||||
libesphttpd/include/logging.h \ |
||||
user/uptime.h \ |
||||
sbmp/library/payload_parser.h \ |
||||
user/sampling.h \ |
||||
user/sbmp_config.h \ |
||||
sbmp/library/sbmp_config.example.h \ |
||||
user/ftoa.h \ |
||||
user/routes.h \ |
||||
user/page_status.h \ |
||||
user/page_waveform.h \ |
||||
libesphttpd/include/espmissingprotos.h \ |
||||
user/utils.h \ |
||||
sbmp/library/payload_builder.h \ |
||||
user/page_about.h \ |
||||
user/fw_version.h \ |
||||
user/cgi_reset.h \ |
||||
user/cgi_ping.h \ |
||||
esphttpclient/espmissingincludes.h \ |
||||
esphttpclient/httpclient.h \ |
||||
user/page_monitoring.h \ |
||||
user/reporting.h \ |
||||
user/wificontrol.h |
||||
|
||||
DISTFILES += \ |
||||
style.astylerc \ |
||||
Makefile |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,77 +0,0 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<title>About - Current Analyser</title> |
||||
|
||||
<link href="/css/app.css" rel="stylesheet"> |
||||
<script src="/js/all.js"></script> |
||||
<script> |
||||
// server root (or URL) - used for local development with remote AJAX calls |
||||
// (this needs CORS working on the target - which I added to esp-httpd) |
||||
var _root = ""; |
||||
</script> |
||||
</head> |
||||
<body class="page-about"> |
||||
<div id="outer"> |
||||
<nav id="menu"> |
||||
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div> |
||||
<a href="/status">Home</a><a href="/wifi">WiFi config</a><a href="/waveform">Waveform</a><a href="/fft">FFT</a><a href="/spectrogram">Spectrogram</a><a href="/monitoring">Monitoring</a><a href="/about" class="selected">About</a></nav> |
||||
<div id="content"> |
||||
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
||||
|
||||
<h1>About</h1> |
||||
|
||||
<div class="Box"> |
||||
<img src="/img/cvut.svg" id="logo" class="mq-tablet-min"> |
||||
<h2>Current Analyser</h2> |
||||
|
||||
<img src="/img/cvut.svg" id="logo2" class="mq-phone"> |
||||
|
||||
<p>© Ondřej Hruška, 2016 <<a href="mailto:ondra@ondrovo.com" target="blank">ondra@ondrovo.com</a>></p> |
||||
|
||||
<p><a href="http://measure.feld.cvut.cz/" target="blank">Katedra měření, FEL ČVUT</a><br>Department of Measurement, FEE CTU</p> |
||||
</div> |
||||
|
||||
<div class="Box"> |
||||
<h2>Firmware</h2> |
||||
|
||||
<table> |
||||
<tr> |
||||
<th>Firmware</th> |
||||
<td>v%vers_fw%, build <i>%date%</i> at <i>%time%</i></td> |
||||
</tr> |
||||
<tr> |
||||
<th>esp-httpd lib</th> |
||||
<td>v%vers_httpd%</td> |
||||
</tr> |
||||
<tr> |
||||
<th>SBMP lib</th> |
||||
<td>v%vers_sbmp%</td> |
||||
</tr> |
||||
<tr> |
||||
<th>ESP IoT SDK</th> |
||||
<td>v%vers_sdk%</td> |
||||
</tr> |
||||
<tr> |
||||
<th>STM32 firmware</th> |
||||
<td>v%vers_stm%</td> |
||||
</tr> |
||||
</table> |
||||
|
||||
<p> |
||||
The webserver was built using the great <a href="https://github.com/Spritetm/esphttpd" target="blank">esp-httpd</a> |
||||
library by Jeroen Domburg. |
||||
</p> |
||||
</div> |
||||
|
||||
|
||||
<div class="NotifyMsg hidden" id="notif"></div> |
||||
|
||||
</div><!-- content --> |
||||
</div><!-- outer --> |
||||
</body> |
||||
</html> |
@ -1,102 +0,0 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<title>FFT - Current Analyser</title> |
||||
|
||||
<link href="/css/app.css" rel="stylesheet"> |
||||
<script src="/js/all.js"></script> |
||||
<script> |
||||
// server root (or URL) - used for local development with remote AJAX calls |
||||
// (this needs CORS working on the target - which I added to esp-httpd) |
||||
var _root = ""; |
||||
</script> |
||||
</head> |
||||
<body class="page-fft"> |
||||
<div id="outer"> |
||||
<nav id="menu"> |
||||
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div> |
||||
<a href="/status">Home</a><a href="/wifi">WiFi config</a><a href="/waveform">Waveform</a><a href="/fft" class="selected">FFT</a><a href="/spectrogram">Spectrogram</a><a href="/monitoring">Monitoring</a><a href="/about">About</a></nav> |
||||
<div id="content"> |
||||
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
||||
|
||||
<h1>FFT</h1> |
||||
|
||||
<div class="Box center" id="samp-ctrl"> |
||||
<div> |
||||
<label for="count">Bins</label> |
||||
<label for="count" class="select-wrap"> |
||||
<select name="count" id="count"> |
||||
<option value="16">8 |
||||
<option value="32">16 |
||||
<option value="64">32 |
||||
<option value="128">64 |
||||
<option value="256">128 |
||||
<option value="512">256 |
||||
<option value="1024">512 |
||||
<option value="2048" selected>1024 |
||||
</select> |
||||
</label> |
||||
</div> |
||||
<div> |
||||
<label for="freq">f<sub>bw</sub> <span class="mq-normal-min nb">=</span><span class="mq-tablet-max nb">(Hz)</span></label> |
||||
<input id="freq" type="number" value="2048"> |
||||
<span class="mq-normal-min">Hz</span> |
||||
</div> |
||||
<div> |
||||
<a id="load" class="button btn-green">Load</a> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box medium chartbox"> |
||||
<div id="chart" class="ct-chart ct-wide ct-with-area"></div> |
||||
<div class="stats invis"> |
||||
<table> |
||||
<tr> |
||||
<th>Samples</th> |
||||
<td id="stat-count"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>f<sub>s</sub></th> |
||||
<td id="stat-f-s"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>I<sub>peak</sub></th> |
||||
<td id="stat-i-peak"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>I<sub>RMS</sub></th> |
||||
<td id="stat-i-rms"></td> |
||||
</tr> |
||||
</table> |
||||
<div class="ar"><!-- auto reload --> |
||||
<input type="number" id="ar-time" step="100" value="1000" min="0"> ms |
||||
<input type="button" id="ar-btn" class="btn-blue narrow" value="Auto"> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box chartexport hidden"> |
||||
Copy: |
||||
<a data-sep="space">1·2·3</a> |
||||
<a data-sep="comma">1,2,3</a> |
||||
<a data-sep="newline">1↵2↵3</a> |
||||
<a data-sep="csv">CSV</a> |
||||
<br> |
||||
<textarea id="copybox" class="hidden" readonly onfocus="this.select();" onmouseup="return false"></textarea> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_waveform.init('fft')); |
||||
</script> |
||||
|
||||
|
||||
<div class="NotifyMsg hidden" id="notif"></div> |
||||
|
||||
</div><!-- content --> |
||||
</div><!-- outer --> |
||||
</body> |
||||
</html> |
@ -0,0 +1,49 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<title>Home - WiFi Demo</title> |
||||
|
||||
<link href="/css/app.css" rel="stylesheet"> |
||||
<script src="/js/all.js"></script> |
||||
<script> |
||||
// server root (or URL) - used for local development with remote AJAX calls |
||||
// (this needs CORS working on the target - which I added to esp-httpd) |
||||
var _root = ""; |
||||
</script> |
||||
</head> |
||||
<body class="page-home"> |
||||
<div id="outer"> |
||||
<nav id="menu"> |
||||
<div id="brand" onclick="$('#menu').toggleClass('expanded')">WiFi Demo</div> |
||||
<a href="/home" class="selected">Home</a><a href="/wifi">WiFi config</a></nav> |
||||
<div id="content"> |
||||
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
||||
|
||||
<h1>Home</h1> |
||||
|
||||
<div class="Box"> |
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus cum eius molestias nesciunt nihil sequi? Laboriosam molestiae nesciunt |
||||
quis! Aut eius esse in laudantium obcaecati possimus quis repudiandae tenetur velit.</p> |
||||
</div> |
||||
|
||||
<div class="Box"> |
||||
<h2>Firmware</h2> |
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus cum eius molestias nesciunt nihil sequi? Laboriosam molestiae nesciunt |
||||
quis! Aut eius esse in laudantium obcaecati possimus quis repudiandae tenetur velit.</p> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_home.init); |
||||
</script> |
||||
|
||||
|
||||
<div class="NotifyMsg hidden" id="notif"></div> |
||||
|
||||
</div><!-- content --> |
||||
</div><!-- outer --> |
||||
</body> |
||||
</html> |
@ -1,102 +0,0 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<title>Monitoring - Current Analyser</title> |
||||
|
||||
<link href="/css/app.css" rel="stylesheet"> |
||||
<script src="/js/all.js"></script> |
||||
<script> |
||||
// server root (or URL) - used for local development with remote AJAX calls |
||||
// (this needs CORS working on the target - which I added to esp-httpd) |
||||
var _root = ""; |
||||
</script> |
||||
</head> |
||||
<body class="page-monitoring"> |
||||
<div id="outer"> |
||||
<nav id="menu"> |
||||
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div> |
||||
<a href="/status">Home</a><a href="/wifi">WiFi config</a><a href="/waveform">Waveform</a><a href="/fft">FFT</a><a href="/spectrogram">Spectrogram</a><a href="/monitoring" class="selected">Monitoring</a><a href="/about">About</a></nav> |
||||
<div id="content"> |
||||
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
||||
|
||||
<h1>Monitoring & Reporting</h1> |
||||
|
||||
<div class="Box"> |
||||
<h2>Status</h2> |
||||
<table> |
||||
<tr> |
||||
<th>Reference:</th> |
||||
<td> |
||||
<span id="hasref" class="Valfield">%refStored%</span> |
||||
<a onclick="page_mon.captureRef()" class="button btn-green">Capture</a> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th>Status:</th> |
||||
<td> |
||||
<span class="Valfield" style="vertical-align:middle;"> |
||||
Δ = <span id="actual-dev">%curDeviation%</span><br> |
||||
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> |
||||
</table> |
||||
</div> |
||||
|
||||
<div class="Box"> |
||||
<h2>Reporting</h2> |
||||
<form action="/mon/config" method="POST"> |
||||
<table> |
||||
<tr> |
||||
<th><label for="rep-on">Reporting:</label></th> |
||||
<td> |
||||
<input type="checkbox" id="rep-on" name="enabled" value="1" %rep_en%><!-- |
||||
--> <label for="rep-on">enabled</label> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th><label for="rep-interval">Interval:</label></th> |
||||
<td> |
||||
<input type="number" name="interval" id="rep-interval" style="max-width: 10em" value="%repInterval%"><!-- |
||||
--> seconds |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th>Service:</th> |
||||
<td> |
||||
<input type="radio" name="service" value="xv" id="rep-svc-xv" %svc_xv%> <label for="rep-svc-xv">Xively</label> |
||||
<input type="radio" name="service" value="ts" id="rep-svc-ts" %svc_ts%> <label for="rep-svc-ts">ThingSpeak</label> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th><label for="rep-key">API key:</label></th> |
||||
<td><input type="text" name="key" id="rep-key" value="%repKey%"></td> |
||||
</tr> |
||||
<tr class="xv-only"> |
||||
<th><label for="rep-feed">Feed ID:</label></th> |
||||
<td><input type="text" name="feed" id="rep-feed" value="%repFeed%"></td> |
||||
</tr> |
||||
<tr> |
||||
<th> </th> |
||||
<td><input type="submit" value="Save changes"></td> |
||||
</tr> |
||||
</table> |
||||
</form> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_mon.init); |
||||
</script> |
||||
|
||||
|
||||
<div class="NotifyMsg hidden" id="notif"></div> |
||||
|
||||
</div><!-- content --> |
||||
</div><!-- outer --> |
||||
</body> |
||||
</html> |
@ -1,79 +0,0 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<title>Spectrogram - Current Analyser</title> |
||||
|
||||
<link href="/css/app.css" rel="stylesheet"> |
||||
<script src="/js/all.js"></script> |
||||
<script> |
||||
// server root (or URL) - used for local development with remote AJAX calls |
||||
// (this needs CORS working on the target - which I added to esp-httpd) |
||||
var _root = ""; |
||||
</script> |
||||
</head> |
||||
<body class="page-spectrogram"> |
||||
<div id="outer"> |
||||
<nav id="menu"> |
||||
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div> |
||||
<a href="/status">Home</a><a href="/wifi">WiFi config</a><a href="/waveform">Waveform</a><a href="/fft">FFT</a><a href="/spectrogram" class="selected">Spectrogram</a><a href="/monitoring">Monitoring</a><a href="/about">About</a></nav> |
||||
<div id="content"> |
||||
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
||||
|
||||
<h1>Spectrogram</h1> |
||||
|
||||
<div class="Box center" id="samp-ctrl"> |
||||
<div> |
||||
<label for="count">Bins</label> |
||||
<label for="count" class="select-wrap"> |
||||
<select name="count" id="count"> |
||||
<option value="16">8 |
||||
<option value="32">16 |
||||
<option value="64">32 |
||||
<option value="128">64 |
||||
<option value="256">128 |
||||
<option value="512">256 |
||||
<option value="1024" selected>512 |
||||
<option value="2048">1024 |
||||
</select> |
||||
</label> |
||||
</div> |
||||
<div id="tile-cfg"> |
||||
<label for="tile-x">Tile</label> |
||||
<input id="tile-x" type="number" min=1 step=1 value=4> |
||||
× |
||||
<input id="tile-y" type="number" min=1 step=1 value=1> |
||||
</div> |
||||
<div> |
||||
<label for="freq">f<sub>bw</sub> <span class="mq-normal-min nb">=</span><span class="mq-tablet-max nb">(Hz)</span></label> |
||||
<input id="freq" type="number" value="2048"> |
||||
<span class="mq-normal-min">Hz</span> |
||||
</div> |
||||
<div> |
||||
<label for="interval">Interval <span class="mq-tablet-max" style="font-weight:normal;">(ms)</span></label> |
||||
<input id="interval" type="number" value="0" step=100 min=0> |
||||
<span class="mq-normal-min">ms</span> |
||||
</div> |
||||
<div> |
||||
<a id="go-btn" class="button btn-green">Start</a> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box center"> |
||||
<canvas id="sg" width=860 height=530></canvas> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_spectrogram.init()); |
||||
</script> |
||||
|
||||
|
||||
<div class="NotifyMsg hidden" id="notif"></div> |
||||
|
||||
</div><!-- content --> |
||||
</div><!-- outer --> |
||||
</body> |
||||
</html> |
@ -1,128 +0,0 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<title>Home - Current Analyser</title> |
||||
|
||||
<link href="/css/app.css" rel="stylesheet"> |
||||
<script src="/js/all.js"></script> |
||||
<script> |
||||
// server root (or URL) - used for local development with remote AJAX calls |
||||
// (this needs CORS working on the target - which I added to esp-httpd) |
||||
var _root = ""; |
||||
</script> |
||||
</head> |
||||
<body class="page-home"> |
||||
<div id="outer"> |
||||
<nav id="menu"> |
||||
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div> |
||||
<a href="/status" class="selected">Home</a><a href="/wifi">WiFi config</a><a href="/waveform">Waveform</a><a href="/fft">FFT</a><a href="/spectrogram">Spectrogram</a><a href="/monitoring">Monitoring</a><a href="/about">About</a></nav> |
||||
<div id="content"> |
||||
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
||||
|
||||
<h1>System Status</h1> |
||||
|
||||
<div class="Box"> |
||||
<h2>Runtime</h2> |
||||
<table> |
||||
<tr> |
||||
<th>Uptime:</th> |
||||
<td id="uptime">%uptime%</td> |
||||
</tr> |
||||
<tr> |
||||
<th>Free heap:</th> |
||||
<td id="heap">%heap%</td> |
||||
</tr> |
||||
<tr> |
||||
<th></th> |
||||
<td><a onclick="page_status.trigReset()" class="button btn-red">Restart system</a></td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
|
||||
<div class="Box"> |
||||
<h2>WiFi</h2> |
||||
<table> |
||||
<tr> |
||||
<th>WiFi mode:</th> |
||||
<td id="wmode">%wifiMode%</td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
|
||||
<!-- WiFi info is read & updated using AJAX --> |
||||
|
||||
<div class="Box sta-only" style="display:none"> |
||||
<h2>WiFi Station</h2> |
||||
<table> |
||||
<tr> |
||||
<th>SSID:</th> |
||||
<td id="staSSID"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>RSSI:</th> |
||||
<td> |
||||
<span id="staRSSIperc"></span>, |
||||
<span id="staRSSI"></span> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th>MAC:</th> |
||||
<td id="staMAC"></td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
|
||||
<div class="Box ap-only" style="display:none"> |
||||
<h2>WiFi AP</h2> |
||||
<table> |
||||
<tr> |
||||
<th>SSID:</th> |
||||
<td id="apSSID"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>Hidden:</th> |
||||
<td id="apHidden"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>Auth. mode:</th> |
||||
<td id="apAuth"></td> |
||||
</tr> |
||||
<tr class="ap-auth-only"> |
||||
<th>Password:</th> |
||||
<td id="apPwd"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>Channel:</th> |
||||
<td id="apChan"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>MAC:</th> |
||||
<td id="apMAC"></td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
|
||||
<div class="Modal hidden no-close" id="reset-modal"> |
||||
<div class="Dialog center"> |
||||
<h2>The device has been reset.</h2> |
||||
<p class="ap-only">If you're connected to the AP, you'll have to re-connect.</p> |
||||
<p>This dialog should close when the restart is complete, please wait around 15 seconds..</p> |
||||
<p><a onclick="location.reload()" class="button btn-blue">Reload the page</a></p> |
||||
</div> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_status.init); |
||||
</script> |
||||
|
||||
|
||||
<div class="NotifyMsg hidden" id="notif"></div> |
||||
|
||||
</div><!-- content --> |
||||
</div><!-- outer --> |
||||
</body> |
||||
</html> |
@ -1,91 +0,0 @@ |
||||
<!doctype html> |
||||
<html> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<title>Waveform - Current Analyser</title> |
||||
|
||||
<link href="/css/app.css" rel="stylesheet"> |
||||
<script src="/js/all.js"></script> |
||||
<script> |
||||
// server root (or URL) - used for local development with remote AJAX calls |
||||
// (this needs CORS working on the target - which I added to esp-httpd) |
||||
var _root = ""; |
||||
</script> |
||||
</head> |
||||
<body class="page-waveform"> |
||||
<div id="outer"> |
||||
<nav id="menu"> |
||||
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div> |
||||
<a href="/status">Home</a><a href="/wifi">WiFi config</a><a href="/waveform" class="selected">Waveform</a><a href="/fft">FFT</a><a href="/spectrogram">Spectrogram</a><a href="/monitoring">Monitoring</a><a href="/about">About</a></nav> |
||||
<div id="content"> |
||||
<img src="/img/loader.gif" alt="Loading…" id="loader"> |
||||
|
||||
<h1>Waveform</h1> |
||||
|
||||
<div class="Box center" id="samp-ctrl"> |
||||
<div> |
||||
<label for="count">Samples</label> |
||||
<input id="count" type="number" value="500"> |
||||
</div> |
||||
<div> |
||||
<label for="freq">f<sub>s</sub> <span class="mq-normal-min nb">=</span><span class="mq-tablet-max nb">(Hz)</span></label> |
||||
<input id="freq" type="number" value="2048"> |
||||
<span class="mq-normal-min">Hz</span> |
||||
</div> |
||||
<div> |
||||
<a id="load" class="button btn-green">Load</a> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box medium chartbox"> |
||||
<div id="chart" class="ct-chart ct-wide"></div> |
||||
<div class="stats invis"> |
||||
<table> |
||||
<tr> |
||||
<th>Samples</th> |
||||
<td id="stat-count"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>f<sub>s</sub></th> |
||||
<td id="stat-f-s"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>I<sub>peak</sub></th> |
||||
<td id="stat-i-peak"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>I<sub>RMS</sub></th> |
||||
<td id="stat-i-rms"></td> |
||||
</tr> |
||||
</table> |
||||
<div class="ar"><!-- auto reload --> |
||||
<input type="number" id="ar-time" step="100" value="1000" min="0"> ms |
||||
<input type="button" id="ar-btn" class="btn-blue narrow" value="Auto"> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box chartexport hidden"> |
||||
Copy: |
||||
<a data-sep="space">1·2·3</a> |
||||
<a data-sep="comma">1,2,3</a> |
||||
<a data-sep="newline">1↵2↵3</a> |
||||
<a data-sep="csv">CSV</a> |
||||
<br> |
||||
<textarea id="copybox" class="hidden" readonly onfocus="this.select();" onmouseup="return false"></textarea> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_waveform.init('raw')); |
||||
</script> |
||||
|
||||
|
||||
<div class="NotifyMsg hidden" id="notif"></div> |
||||
|
||||
</div><!-- content --> |
||||
</div><!-- outer --> |
||||
</body> |
||||
</html> |
File diff suppressed because one or more lines are too long
@ -0,0 +1,11 @@ |
||||
/** Wifi page */ |
||||
var page_home = (function () { |
||||
var home = {}; |
||||
|
||||
/** Set up the Home page */ |
||||
home.init = function () { |
||||
//
|
||||
}; |
||||
|
||||
return home; |
||||
})(); |
@ -1,91 +0,0 @@ |
||||
var page_mon = (function() { |
||||
var mon = {}; |
||||
|
||||
function updRefInfoField(ok) { |
||||
$('#hasref').html(ok ? 'OK' : 'Not set!'); |
||||
} |
||||
|
||||
/** Capture reference & save to flash */ |
||||
mon.captureRef = function() { |
||||
$().get(_root + '/mon/setref', function(resp, status) { |
||||
if (status != 200) { |
||||
// bad response
|
||||
errorMsg('Operation failed.'); |
||||
} else { |
||||
try { |
||||
// OK
|
||||
var j = JSON.parse(resp); |
||||
updRefInfoField(j.success); |
||||
} catch(e) { |
||||
errorMsg(e); |
||||
updRefInfoField(false); |
||||
} |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
/** Capture waveform and compare with reference */ |
||||
mon.compareNow = function() { |
||||
$().get(_root + '/mon/compare', function(resp, status) { |
||||
if (status != 200) { |
||||
// bad response
|
||||
errorMsg('Operation failed.'); |
||||
} else { |
||||
try { |
||||
// OK
|
||||
var j = JSON.parse(resp); |
||||
if (j.success) { |
||||
$('#actual-dev').html(numfmt(j.deviation, 2)); |
||||
$('#actual-rms').html(numfmt(j.rms, 2)); |
||||
} else { |
||||
throw 'Capture failed.'; |
||||
} |
||||
} catch(e) { |
||||
errorMsg(e); |
||||
$('#actual-dev').html('--'); |
||||
$('#actual-rms').html('--'); |
||||
} |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
function updateXvOnly() { |
||||
// is xively
|
||||
var isXv = $('#rep-svc-xv')[0].checked; |
||||
|
||||
if (isXv) { |
||||
$('.xv-only').removeClass('hidden'); |
||||
} else { |
||||
$('.xv-only').addClass('hidden'); |
||||
} |
||||
} |
||||
|
||||
mon.init = function() { |
||||
updateXvOnly(); |
||||
|
||||
$('#rep-svc-xv,#rep-svc-ts').on('change', updateXvOnly); |
||||
|
||||
setInterval(function() { |
||||
$().get(_root + '/mon/status', function(resp, status) { |
||||
if (status == 200) { |
||||
try { |
||||
// OK
|
||||
var j = JSON.parse(resp); |
||||
if (j.success) { |
||||
$('#actual-dev').html(numfmt(j.deviation, 2)); |
||||
$('#actual-rms').html(numfmt(j.rms, 2)); |
||||
} else { |
||||
console.error('Capture failed.'); |
||||
} |
||||
} catch(e) { |
||||
errorMsg(e); |
||||
$('#actual-dev').html('--'); |
||||
$('#actual-rms').html('--'); |
||||
} |
||||
} |
||||
}); |
||||
}, 10000); |
||||
}; |
||||
|
||||
return mon; |
||||
})(); |
@ -1,356 +0,0 @@ |
||||
var page_spectrogram = (function () { |
||||
var sg = {}; |
||||
|
||||
var ctx; |
||||
|
||||
// drawing area
|
||||
var plot = { |
||||
x:50, |
||||
y:10, |
||||
w:740,//860 total
|
||||
h:512, |
||||
dx: 1, // bin
|
||||
dy: 1 |
||||
}; |
||||
|
||||
var opts = { |
||||
interval: 0, |
||||
sampCount: 0, |
||||
freq:0 |
||||
}; |
||||
|
||||
var interval = 1000; |
||||
var running = false; |
||||
var readTimeout; // timer
|
||||
var readoutPending; |
||||
var readXhr; |
||||
|
||||
var lastLoadMs; |
||||
var lastMarkMs; |
||||
var lastMark10s; |
||||
|
||||
var colormap = [ |
||||
/* [val, r, g, b] */ |
||||
[0.00, 0, 0, 0], |
||||
[0.10, 41, 17, 41], |
||||
[0.25, 34, 17, 78], |
||||
[0.6, 17, 30, 105], |
||||
[1.0, 17, 57, 126], |
||||
[1.2, 17, 84, 128], |
||||
[1.3, 17, 111, 115], |
||||
[1.4, 17, 134, 96], |
||||
[1.5, 17, 155, 71], |
||||
[1.6, 68, 194, 17], |
||||
[1.75, 111, 209, 17], |
||||
[1.84, 180, 213, 17], |
||||
[1.90, 223, 217, 86], |
||||
[1.97, 248, 222, 176], |
||||
[1.99, 255, 237, 222], |
||||
[2.00, 255, 255, 255], |
||||
]; |
||||
|
||||
function val2color(val) { |
||||
var x1, x2, c1, c2; |
||||
|
||||
val = Math.log10(1+val); |
||||
|
||||
if (val > 2) val = 2; |
||||
if (val < 0) val = 0; |
||||
|
||||
for (var i = 0; i < colormap.length; i++) { |
||||
var c = colormap[i]; |
||||
var point = c[0]; |
||||
if (val >= point) { |
||||
x1 = point; |
||||
c1 = c; |
||||
} |
||||
|
||||
if (val <= point) { |
||||
x2 = point; |
||||
c2 = c; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
var rate = ((val - x1)/(x2 - x1)); |
||||
if (x1 == x2) rate=0; |
||||
|
||||
var r = Math.round((c1[1] + (c2[1] - c1[1])*rate)); |
||||
var g = Math.round((c1[2] + (c2[2] - c1[2])*rate)); |
||||
var b = Math.round((c1[3] + (c2[3] - c1[3])*rate)); |
||||
return 'rgb('+r+','+g+','+b+')'; |
||||
} |
||||
|
||||
function shiftSg() { |
||||
var imageData = ctx.getImageData(plot.x+plot.dx, plot.y, plot.w-plot.dx, plot.h+10); |
||||
|
||||
ctx.fillStyle = 'black'; |
||||
ctx.fillRect(plot.x, plot.y, plot.w, plot.h); |
||||
ctx.clearRect(plot.x, plot.y+plot.h+1, plot.w, 10); // clear the second marks box
|
||||
|
||||
ctx.putImageData(imageData, plot.x, plot.y); |
||||
} |
||||
|
||||
function drawSg(col) { |
||||
shiftSg(); |
||||
|
||||
var bc = opts.sampCount/2; |
||||
for (var i = 0; i < bc; i++) { |
||||
// resolve color from the value
|
||||
var clr; |
||||
|
||||
if (i*plot.dy > plot.h) { |
||||
break; |
||||
} |
||||
|
||||
if (i > col.length) { |
||||
clr = '#000'; |
||||
} else { |
||||
clr = val2color(col[i]); |
||||
} |
||||
ctx.fillStyle = clr; |
||||
|
||||
var tx = plot.x+plot.w-plot.dx; |
||||
var ty = plot.y+plot.h-(i+1)*plot.dy; |
||||
var tw = plot.dx; |
||||
var th = plot.dy; |
||||
|
||||
if (ty<plot.y) { |
||||
th -= plot.y-ty; |
||||
ty = plot.y; |
||||
} |
||||
|
||||
ctx.fillRect(tx, ty, tw, th); |
||||
} |
||||
|
||||
// mark every 10 s
|
||||
//console.log('remain',msElapsed(lastMarkMs));
|
||||
if (msElapsed(lastMarkMs) >= 950) { |
||||
lastMarkMs = msNow(); |
||||
|
||||
var long = false; |
||||
if (msElapsed(lastMark10s) > 9500) { |
||||
long = true; |
||||
lastMark10s = msNow(); |
||||
} |
||||
|
||||
ctx.strokeStyle = 'white'; |
||||
ctx.beginPath(); |
||||
ctx.moveTo(plot.x+plot.w-.5, plot.y+plot.h+1); |
||||
ctx.lineTo(plot.x+plot.w-.5, plot.y+plot.h+1+(long?6:2)); |
||||
ctx.stroke(); |
||||
} |
||||
} |
||||
|
||||
|
||||
function onRxData(resp, status) { |
||||
readoutPending = false; |
||||
if (status == 200) { |
||||
try { |
||||
var j = JSON.parse(resp); |
||||
if (j.success) { |
||||
// display
|
||||
drawSg(j.samples); |
||||
} else { |
||||
errorMsg("Sampling failed.", 1000); |
||||
} |
||||
} catch(e) { |
||||
errorMsg(e); |
||||
} |
||||
} else { |
||||
errorMsg("Request failed.", 1000); |
||||
} |
||||
|
||||
if (running) |
||||
readTimeout = setTimeout(requestData, Math.max(0, opts.interval - msElapsed(lastLoadMs))); // TODO should actually compute time remaining, this adds interval to the request time.
|
||||
} |
||||
|
||||
function requestData() { |
||||
if (readoutPending) { |
||||
errorMsg("Request already pending - aborting."); |
||||
readXhr.abort(); |
||||
} |
||||
readoutPending = true; |
||||
lastLoadMs = msNow(); |
||||
|
||||
var fs = opts.freq; |
||||
var n = opts.sampCount; |
||||
var url = _root+'/measure/fft?n='+n+'&fs='+fs; |
||||
|
||||
readXhr = $().get(url, onRxData, estimateLoadTime(fs,n)); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
function drawLegend() { |
||||
var gap = 8; |
||||
var barW = 10; |
||||
var barH = plot.h-12; |
||||
var barY = plot.y+6; |
||||
var barX = plot.x - gap - barW; |
||||
var vStep = (100 / barH); |
||||
for (var i = 0; i < barH; i++) { |
||||
var c1 = val2color(i * vStep); |
||||
var c2 = val2color((i + 1) * vStep); |
||||
|
||||
var y = Math.floor(barY + barH - (i + 1)); |
||||
|
||||
var gradient = ctx.createLinearGradient(0, y + 1, 0, y); |
||||
gradient.addColorStop(0, c1); |
||||
gradient.addColorStop(1, c2); |
||||
ctx.fillStyle = gradient; |
||||
|
||||
ctx.fillRect(barX, y, barW, 1); |
||||
} |
||||
|
||||
// border
|
||||
ctx.strokeStyle = '#000'; |
||||
ctx.strokeRect(barX-.5, barY-.5, barW+1, barH+1); |
||||
|
||||
vStep = (100 / barH); |
||||
ctx.font = '12px sans-serif'; |
||||
ctx.fillStyle = 'white'; |
||||
ctx.textAlign = 'right'; |
||||
for (var i = 0; i <= plot.h; i+=barH/10) { |
||||
ctx.fillText(Math.round(i*vStep)+"", plot.x - gap - barW - gap, barY+barH-i+3); |
||||
} |
||||
} |
||||
|
||||
function drawAxis() { |
||||
var gap = 8; |
||||
var rX0 = plot.x+plot.w; |
||||
var rX = rX0+gap; |
||||
var rY = plot.y; |
||||
var rH = plot.h; |
||||
var rW = 70; |
||||
ctx.clearRect(rX0+.5, rY-10, rW, rH+20); |
||||
|
||||
var perBin = (opts.freq/2) / (opts.sampCount/2); |
||||
|
||||
var totalBins = (plot.h / plot.dy); |
||||
var totalHz = totalBins*perBin; |
||||
|
||||
//console.log("perbin=",perBin,"totalBins=",totalBins,"totalHz=",totalHz);
|
||||
|
||||
var step; |
||||
|
||||
// get the best step size
|
||||
var steps = [10, 25, 50]; |
||||
var multiplier = 1; |
||||
var suc = false; |
||||
do { |
||||
for (var i = 0; i < steps.length; i++) { |
||||
if ((totalHz / (steps[i] * multiplier)) <= 21) { |
||||
step = (steps[i] * multiplier); |
||||
suc = true; |
||||
break; |
||||
} |
||||
} |
||||
if (suc) break; |
||||
multiplier *= 10; |
||||
} while (true); |
||||
|
||||
step = step/perBin; |
||||
|
||||
// every step-th bin has a label
|
||||
ctx.font = '12px sans-serif'; |
||||
ctx.fillStyle = 'white'; |
||||
ctx.strokeStyle = 'white'; |
||||
ctx.textAlign = 'left'; |
||||
|
||||
// labels and dashes
|
||||
for(var i = 0; i <= totalBins+step; i+= step) { |
||||
if (i >= totalBins) { |
||||
var dist = i - totalBins; |
||||
if (dist > step/2) break;// make sure not too close
|
||||
i = totalBins; |
||||
} |
||||
|
||||
var hz = i*(totalHz/totalBins); |
||||
if (hz>=1000000) hz = numfmt(hz/1e6,2)+'M'; |
||||
else if (hz>=1000) hz = numfmt(hz/1e3,2)+'k'; |
||||
else hz = numfmt(hz,1); |
||||
|
||||
var yy = Math.round(rY+rH-(plot.dy*i)); |
||||
ctx.fillText(hz, rX, yy+4); |
||||
|
||||
ctx.beginPath(); |
||||
ctx.moveTo(rX0, yy+.5); |
||||
ctx.lineTo(rX0+gap/2, yy+.5); |
||||
ctx.stroke(); |
||||
|
||||
if (i >= totalBins) break; |
||||
} |
||||
|
||||
// Hz label
|
||||
ctx.font = '16px sans-serif'; |
||||
ctx.save(); |
||||
ctx.translate(rX0+50, plot.y+plot.h/2); |
||||
ctx.rotate(Math.PI/2); |
||||
ctx.textAlign = "center"; |
||||
ctx.fillText("Frequency - [Hz]", 0, 0); |
||||
ctx.restore(); |
||||
} |
||||
|
||||
function readOpts() { |
||||
opts.interval = +$('#interval').val(); // ms
|
||||
opts.freq = +$('#freq').val()*2; |
||||
opts.sampCount = +$('#count').val(); |
||||
|
||||
plot.dx = +$('#tile-x').val(); |
||||
plot.dy = +$('#tile-y').val(); |
||||
} |
||||
|
||||
function clearSgArea() { |
||||
ctx.fillStyle = '#000'; |
||||
ctx.fillRect(plot.x, plot.y, plot.w, plot.h); |
||||
ctx.strokeStyle = 'white'; |
||||
ctx.strokeRect(plot.x-.5, plot.y-.5, plot.w+1, plot.h+1); |
||||
} |
||||
|
||||
sg.init = function () { |
||||
var canvas = $('#sg')[0]; |
||||
ctx = canvas.getContext('2d'); |
||||
|
||||
// CLS
|
||||
clearSgArea(); |
||||
readOpts(); |
||||
drawLegend(); |
||||
drawAxis(); |
||||
lastMarkMs = msNow()-10000; |
||||
lastMark10s = msNow()-10000; |
||||
|
||||
// update tile size on bin count selection
|
||||
$('#count').on('change', function() { |
||||
var count = +$('#count').val(); |
||||
var tile = Math.max(1, plot.h/(count/2)); |
||||
|
||||
$('#tile-x').val(Math.max(4, tile)); // use width 4 for smaller by default (rolls more nicely)
|
||||
$('#tile-y').val(tile); |
||||
}); |
||||
|
||||
// chain Y with X
|
||||
$('#tile-y').on('change', function() { |
||||
$('#tile-x').val(Math.max(4,$(this).val())); |
||||
}); |
||||
|
||||
$('#go-btn').on('click', function() { |
||||
running = !running; |
||||
if (running) { |
||||
readOpts(); |
||||
drawAxis(); |
||||
|
||||
requestData(); |
||||
} else { |
||||
clearTimeout(readTimeout); |
||||
} |
||||
|
||||
$('#go-btn') |
||||
.toggleClass('btn-green') |
||||
.toggleClass('btn-red') |
||||
.html(running ? 'Stop' : 'Start'); |
||||
}); |
||||
}; |
||||
|
||||
return sg; |
||||
})(); |
@ -1,88 +0,0 @@ |
||||
var page_status = (function() { |
||||
var st = {}; |
||||
st.j = {}; |
||||
|
||||
var updateTime = 10000; |
||||
|
||||
var updateInhibited = false; |
||||
|
||||
st.trigReset = function() { |
||||
var modal_sel = '#reset-modal'; |
||||
$().get(_root + '/system/reset', function(resp, status) { |
||||
if (status == 200) { |
||||
|
||||
modal.show(modal_sel); |
||||
updateInhibited = true; |
||||
|
||||
var ping_i = setInterval(function() { |
||||
$().get(_root+'/system/ping', function(resp, code){ |
||||
if (code == 200) { |
||||
// device is ready
|
||||
modal.hide(modal_sel); |
||||
requestUpdate(); |
||||
clearInterval(ping_i); |
||||
updateInhibited = false; |
||||
} |
||||
}, {timeout: 500}); |
||||
}, 1000); |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
function onUpdate(resp, status) { |
||||
if (status != 200) { |
||||
// bad response
|
||||
errorMsg('Update failed.'); |
||||
} else { |
||||
try { |
||||
// OK
|
||||
var j = JSON.parse(resp); |
||||
st.j = j; // store for global access
|
||||
|
||||
$('.sta-only').toggle(j.sta); |
||||
$('.ap-only').toggle(j.ap); |
||||
|
||||
$('#uptime').html(j.uptime); |
||||
$('#heap').html(j.heap + " bytes"); |
||||
$('#wmode').html(j.wifiMode); |
||||
|
||||
if (j.sta) { |
||||
$('#staSSID').html(j.sta.SSID); |
||||
$('#staRSSIperc').html(j.sta.RSSIperc); |
||||
$('#staRSSI').html(j.sta.RSSI); |
||||
$('#staMAC').html(j.sta.MAC); |
||||
} |
||||
|
||||
if (j.ap) { |
||||
$('#apSSID').html(j.ap.SSID); |
||||
$('#apHidden').html(j.ap.hidden ? "Yes" : "No"); |
||||
$('#apAuth').html(j.ap.auth); |
||||
|
||||
// hide the password row if auth is Open
|
||||
$('.ap-auth-only').toggle(j.ap.auth != 'Open'); |
||||
|
||||
$('#apPwd').html(j.ap.pwd); |
||||
$('#apChan').html(j.ap.chan); |
||||
$('#apMAC').html(j.ap.MAC); |
||||
} |
||||
// chip ID & macs don't change
|
||||
} catch(e) { |
||||
errorMsg(e); |
||||
} |
||||
} |
||||
|
||||
if (!updateInhibited) { |
||||
setTimeout(requestUpdate, updateTime); |
||||
} |
||||
} |
||||
|
||||
function requestUpdate() { |
||||
$().get(_root+'/system/status', onUpdate); |
||||
} |
||||
|
||||
st.init = function() { |
||||
requestUpdate(); |
||||
}; |
||||
|
||||
return st; |
||||
})(); |
@ -1,271 +0,0 @@ |
||||
var page_waveform = (function () { |
||||
var wfm = {}; |
||||
|
||||
var zoomResetFn; |
||||
var dataFormat; |
||||
|
||||
var readoutPending = false; |
||||
var autoReload = false; |
||||
var autoReloadTime = 1; |
||||
var arTimeout = -1; |
||||
|
||||
var lastLoadMs; |
||||
|
||||
var zoomSavedX, zoomSavedY; |
||||
|
||||
var readXhr; // read xhr
|
||||
|
||||
var lastObj = null; // samples are stored here
|
||||
|
||||
var opts = { |
||||
count: 0, // sample count
|
||||
freq: 0 // sampling freq
|
||||
}; |
||||
|
||||
function buildChart(j) { |
||||
// Build the chart
|
||||
var mql = window.matchMedia('screen and (min-width: 544px)'); |
||||
var isPhone = !mql.matches; |
||||
|
||||
var fft = (j.stats.format == 'FFT'); |
||||
|
||||
var xLabel, yLabel; |
||||
if (fft) { |
||||
xLabel = 'Frequency - [ Hz ]'; |
||||
yLabel = 'Magnitude - [ mA ]'; |
||||
} else { |
||||
xLabel = 'Sample time - [ ms ]'; |
||||
yLabel = 'Current - [ mA ]'; |
||||
} |
||||
|
||||
var peak = Math.max(-j.stats.min, j.stats.max); |
||||
var displayPeak = Math.max(peak, 10); |
||||
|
||||
// Sidebar
|
||||
|
||||
$('#stat-count').html(j.stats.count); |
||||
$('#stat-f-s').html(numfmt(j.stats.freq, 2)); |
||||
$('#stat-i-peak').html(numfmt(peak, 2)); |
||||
$('#stat-i-rms').html(numfmt(j.stats.rms, 2)); |
||||
$('.stats').removeClass('invis'); |
||||
|
||||
// --- chart ---
|
||||
|
||||
// Generate point entries
|
||||
// add synthetic properties
|
||||
var step = fft ? (j.stats.freq/j.stats.count) : (1000/j.stats.freq); |
||||
var points = _.map(j.samples, function (a, i) { |
||||
return { |
||||
x: i * step, |
||||
y: a |
||||
}; |
||||
}); |
||||
|
||||
var plugins = [ |
||||
Chartist.plugins.zoom({ |
||||
resetOnRightMouseBtn: true, |
||||
onZoom: function (chart, reset) { |
||||
zoomResetFn = reset; |
||||
|
||||
zoomSavedX = chart.options.axisX.highLow; |
||||
zoomSavedY = chart.options.axisY.highLow; |
||||
} |
||||
}) |
||||
]; |
||||
|
||||
if (!isPhone) plugins.push( // larger than phone
|
||||
Chartist.plugins.ctAxisTitle({ |
||||
axisX: { |
||||
axisTitle: xLabel, |
||||
offset: { |
||||
x: 0, |
||||
y: 55 |
||||
} |
||||
}, |
||||
axisY: { |
||||
axisTitle: yLabel, |
||||
flipText: true, |
||||
offset: { |
||||
x: 0, |
||||
y: 15 |
||||
} |
||||
} |
||||
}) |
||||
); |
||||
|
||||
var xHigh, xLow, yHigh, yLow; |
||||
|
||||
if (zoomSavedX) { |
||||
// we have saved coords of the zoom rect, restore the zoom.
|
||||
xHigh = zoomSavedX.high; |
||||
xLow = zoomSavedX.low; |
||||
yHigh = zoomSavedY.high; |
||||
yLow = zoomSavedY.low; |
||||
} else { |
||||
yHigh = fft ? undefined : displayPeak; |
||||
yLow = fft ? 0 : -displayPeak; |
||||
} |
||||
|
||||
new Chartist.Line('#chart', { |
||||
series: [ |
||||
{ |
||||
name: 'a', |
||||
data: points |
||||
}, |
||||
] |
||||
}, { |
||||
showPoint: false, |
||||
showArea: fft, |
||||
fullWidth: true, |
||||
chartPadding: (isPhone ? {right: 20, bottom: 5, left: 0} : {right: 25, bottom: 30, left: 25}), |
||||
series: { |
||||
'a': { |
||||
lineSmooth: Chartist.Interpolation.monotoneCubic() |
||||
} |
||||
}, |
||||
axisX: { |
||||
type: Chartist.AutoScaleAxis, |
||||
//onlyInteger: !fft // only for raw
|
||||
high: xHigh, |
||||
low: xLow, |
||||
}, |
||||
axisY: { |
||||
type: Chartist.AutoScaleAxis, |
||||
//onlyInteger: true
|
||||
high: yHigh, |
||||
low: yLow, |
||||
}, |
||||
explicitBounds: { |
||||
xLow: 0, |
||||
yLow: fft ? 0 : undefined, |
||||
xHigh: points[points.length-1].x |
||||
}, |
||||
plugins: plugins |
||||
}); |
||||
} |
||||
|
||||
function onRxData(resp, status) { |
||||
readoutPending = false; |
||||
|
||||
if (status != 200) { |
||||
errorMsg("Request failed.", 1000); |
||||
} else { |
||||
var j = JSON.parse(resp); |
||||
if (!j.success) { |
||||
errorMsg("Sampling failed.", 1000); |
||||
} else { |
||||
$('.chartexport').removeClass('hidden'); |
||||
lastObj = j; |
||||
buildChart(j); |
||||
} |
||||
} |
||||
|
||||
if (autoReload) |
||||
arTimeout = setTimeout(requestReload, Math.max(0, autoReloadTime - msElapsed(lastLoadMs))); |
||||
} |
||||
|
||||
function readInputs() { |
||||
opts.count = $('#count').val(); |
||||
opts.freq = $('#freq').val() * (dataFormat == 'fft' ? 2 : 1); // bw 2x -> f_s
|
||||
} |
||||
|
||||
function requestReload() { |
||||
if (readoutPending) { |
||||
errorMsg("Request already pending - aborting."); |
||||
readXhr.abort(); |
||||
} |
||||
|
||||
readoutPending = true; |
||||
lastLoadMs = msNow(); |
||||
|
||||
var n = opts.count; |
||||
var fs = opts.freq; |
||||
var url = _root+'/measure/'+dataFormat+'?n='+n+'&fs='+fs; |
||||
readXhr = $().get(url, onRxData, estimateLoadTime(fs,n)); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
function toggleAutoReload() { |
||||
autoReloadTime = +$('#ar-time').val(); // ms
|
||||
|
||||
readInputs(); |
||||
|
||||
autoReload = !autoReload; |
||||
if (autoReload) { |
||||
requestReload(); |
||||
} else { |
||||
clearTimeout(arTimeout); |
||||
} |
||||
|
||||
$('#ar-btn') |
||||
.toggleClass('btn-blue') |
||||
.toggleClass('btn-red') |
||||
.val(autoReload ? 'Stop' : 'Auto'); |
||||
} |
||||
|
||||
wfm.init = function (format) { |
||||
// --- Load data ---
|
||||
dataFormat = format; |
||||
|
||||
function onLoadClick() { |
||||
readInputs(); |
||||
requestReload(); |
||||
} |
||||
|
||||
$('#load').on('click', onLoadClick); |
||||
|
||||
$('.chartexport a').on('click', function() { |
||||
var sep = $(this).data('sep'); |
||||
var str = ''; |
||||
|
||||
var isFft = (dataFormat == 'fft'); |
||||
var csvStep = isFft ? (lastObj.stats.freq/lastObj.stats.count) : (1000/lastObj.stats.freq); |
||||
var csvPlaces = isFft ? 3 : 2; |
||||
|
||||
switch (sep) { |
||||
case 'space': str = lastObj.samples.join(' '); break; |
||||
case 'comma': str = lastObj.samples.join(','); break; |
||||
case 'newline': str = lastObj.samples.join('\n'); break; |
||||
|
||||
case 'csv': |
||||
str = _.map(lastObj.samples, function (a, i) { |
||||
return numfmt(i * csvStep, csvPlaces) + "," + a; |
||||
}).join('\n'); |
||||
break; |
||||
} |
||||
|
||||
if (!copyToClipboard(str)) { |
||||
var $cb = $('#copybox'); |
||||
$cb.removeClass('hidden'); |
||||
$cb.val(str); |
||||
} else { |
||||
infoMsg('Copy success!'); |
||||
} |
||||
}); |
||||
|
||||
$('#count,#freq').on('keyup', function (e) { |
||||
if (e.which == 13) { |
||||
onLoadClick(); |
||||
} |
||||
}); |
||||
|
||||
// --- zooming ---
|
||||
|
||||
$('#chart').on('contextmenu', function (e) { // right click on the chart -> reset
|
||||
zoomResetFn && zoomResetFn(); |
||||
zoomResetFn = null; |
||||
|
||||
zoomSavedX = null; |
||||
zoomSavedY = null; |
||||
|
||||
e.preventDefault(); |
||||
return false; |
||||
}); |
||||
|
||||
// auto-reload button
|
||||
$('#ar-btn').on('click', toggleAutoReload); |
||||
}; |
||||
|
||||
return wfm; |
||||
})(); |
File diff suppressed because one or more lines are too long
@ -1 +0,0 @@ |
||||
0648559aed5a9ec1d478b445839bdb807ced7fc5 |
@ -1,48 +0,0 @@ |
||||
<?php $page = 'about'; include "_start.php"; ?> |
||||
|
||||
<h1>About</h1> |
||||
|
||||
<div class="Box"> |
||||
<img src="/img/cvut.svg" id="logo" class="mq-tablet-min"> |
||||
<h2><?= e($appname) ?></h2>
|
||||
|
||||
<img src="/img/cvut.svg" id="logo2" class="mq-phone"> |
||||
|
||||
<p>© Ondřej Hruška, 2016 <<a href="mailto:ondra@ondrovo.com" target="blank">ondra@ondrovo.com</a>></p> |
||||
|
||||
<p><a href="http://measure.feld.cvut.cz/" target="blank">Katedra měření, FEL ČVUT</a><br>Department of Measurement, FEE CTU</p> |
||||
</div> |
||||
|
||||
<div class="Box"> |
||||
<h2>Firmware</h2> |
||||
|
||||
<table> |
||||
<tr> |
||||
<th>Firmware</th> |
||||
<td>v%vers_fw%, build <i>%date%</i> at <i>%time%</i></td> |
||||
</tr> |
||||
<tr> |
||||
<th>esp-httpd lib</th> |
||||
<td>v%vers_httpd%</td> |
||||
</tr> |
||||
<tr> |
||||
<th>SBMP lib</th> |
||||
<td>v%vers_sbmp%</td> |
||||
</tr> |
||||
<tr> |
||||
<th>ESP IoT SDK</th> |
||||
<td>v%vers_sdk%</td> |
||||
</tr> |
||||
<tr> |
||||
<th>STM32 firmware</th> |
||||
<td>v%vers_stm%</td> |
||||
</tr> |
||||
</table> |
||||
|
||||
<p> |
||||
The webserver was built using the great <a href="https://github.com/Spritetm/esphttpd" target="blank">esp-httpd</a> |
||||
library by Jeroen Domburg. |
||||
</p> |
||||
</div> |
||||
|
||||
<?php include "_end.php"; ?> |
@ -1,73 +0,0 @@ |
||||
<?php $page = 'fft'; include "_start.php"; ?> |
||||
|
||||
<h1>FFT</h1> |
||||
|
||||
<div class="Box center" id="samp-ctrl"> |
||||
<div> |
||||
<label for="count">Bins</label> |
||||
<label for="count" class="select-wrap"> |
||||
<select name="count" id="count"> |
||||
<option value="16">8 |
||||
<option value="32">16 |
||||
<option value="64">32 |
||||
<option value="128">64 |
||||
<option value="256">128 |
||||
<option value="512">256 |
||||
<option value="1024">512 |
||||
<option value="2048" selected>1024 |
||||
</select> |
||||
</label> |
||||
</div> |
||||
<div> |
||||
<label for="freq">f<sub>bw</sub> <span class="mq-normal-min nb">=</span><span class="mq-tablet-max nb">(Hz)</span></label> |
||||
<input id="freq" type="number" value="2048"> |
||||
<span class="mq-normal-min">Hz</span> |
||||
</div> |
||||
<div> |
||||
<a id="load" class="button btn-green">Load</a> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box medium chartbox"> |
||||
<div id="chart" class="ct-chart ct-wide ct-with-area"></div> |
||||
<div class="stats invis"> |
||||
<table> |
||||
<tr> |
||||
<th>Samples</th> |
||||
<td id="stat-count"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>f<sub>s</sub></th> |
||||
<td id="stat-f-s"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>I<sub>peak</sub></th> |
||||
<td id="stat-i-peak"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>I<sub>RMS</sub></th> |
||||
<td id="stat-i-rms"></td> |
||||
</tr> |
||||
</table> |
||||
<div class="ar"><!-- auto reload --> |
||||
<input type="number" id="ar-time" step="100" value="1000" min="0"> ms |
||||
<input type="button" id="ar-btn" class="btn-blue narrow" value="Auto"> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box chartexport hidden"> |
||||
Copy: |
||||
<a data-sep="space">1·2·3</a> |
||||
<a data-sep="comma">1,2,3</a> |
||||
<a data-sep="newline">1↵2↵3</a> |
||||
<a data-sep="csv">CSV</a> |
||||
<br> |
||||
<textarea id="copybox" class="hidden" readonly onfocus="this.select();" onmouseup="return false"></textarea> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_waveform.init('fft')); |
||||
</script> |
||||
|
||||
<?php include "_end.php"; ?> |
@ -0,0 +1,21 @@ |
||||
<?php $page = 'home'; |
||||
include "_start.php"; ?> |
||||
|
||||
<h1>Home</h1> |
||||
|
||||
<div class="Box"> |
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus cum eius molestias nesciunt nihil sequi? Laboriosam molestiae nesciunt |
||||
quis! Aut eius esse in laudantium obcaecati possimus quis repudiandae tenetur velit.</p> |
||||
</div> |
||||
|
||||
<div class="Box"> |
||||
<h2>Firmware</h2> |
||||
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusamus cum eius molestias nesciunt nihil sequi? Laboriosam molestiae nesciunt |
||||
quis! Aut eius esse in laudantium obcaecati possimus quis repudiandae tenetur velit.</p> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_home.init); |
||||
</script> |
||||
|
||||
<?php include "_end.php"; ?> |
@ -1,73 +0,0 @@ |
||||
<?php $page = 'monitoring'; include "_start.php"; ?> |
||||
|
||||
<h1>Monitoring & Reporting</h1> |
||||
|
||||
<div class="Box"> |
||||
<h2>Status</h2> |
||||
<table> |
||||
<tr> |
||||
<th>Reference:</th> |
||||
<td> |
||||
<span id="hasref" class="Valfield">%refStored%</span> |
||||
<a onclick="page_mon.captureRef()" class="button btn-green">Capture</a> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th>Status:</th> |
||||
<td> |
||||
<span class="Valfield" style="vertical-align:middle;"> |
||||
Δ = <span id="actual-dev">%curDeviation%</span><br> |
||||
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> |
||||
</table> |
||||
</div> |
||||
|
||||
<div class="Box"> |
||||
<h2>Reporting</h2> |
||||
<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="enabled" value="1" %rep_en%><!-- |
||||
--> <label for="rep-on">enabled</label> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th><label for="rep-interval">Interval:</label></th> |
||||
<td> |
||||
<input type="number" name="interval" id="rep-interval" style="max-width: 10em" value="%repInterval%"><!-- |
||||
--> seconds |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th>Service:</th> |
||||
<td> |
||||
<input type="radio" name="service" value="xv" id="rep-svc-xv" %svc_xv%> <label for="rep-svc-xv">Xively</label> |
||||
<input type="radio" name="service" value="ts" id="rep-svc-ts" %svc_ts%> <label for="rep-svc-ts">ThingSpeak</label> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th><label for="rep-key">API key:</label></th> |
||||
<td><input type="text" name="key" id="rep-key" value="%repKey%"></td> |
||||
</tr> |
||||
<tr class="xv-only"> |
||||
<th><label for="rep-feed">Feed ID:</label></th> |
||||
<td><input type="text" name="feed" id="rep-feed" value="%repFeed%"></td> |
||||
</tr> |
||||
<tr> |
||||
<th> </th> |
||||
<td><input type="submit" value="Save changes"></td> |
||||
</tr> |
||||
</table> |
||||
</form> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_mon.init); |
||||
</script> |
||||
|
||||
<?php include "_end.php"; ?> |
@ -1,50 +0,0 @@ |
||||
<?php $page = 'spectrogram'; include "_start.php"; ?> |
||||
|
||||
<h1>Spectrogram</h1> |
||||
|
||||
<div class="Box center" id="samp-ctrl"> |
||||
<div> |
||||
<label for="count">Bins</label> |
||||
<label for="count" class="select-wrap"> |
||||
<select name="count" id="count"> |
||||
<option value="16">8 |
||||
<option value="32">16 |
||||
<option value="64">32 |
||||
<option value="128">64 |
||||
<option value="256">128 |
||||
<option value="512">256 |
||||
<option value="1024" selected>512 |
||||
<option value="2048">1024 |
||||
</select> |
||||
</label> |
||||
</div> |
||||
<div id="tile-cfg"> |
||||
<label for="tile-x">Tile</label> |
||||
<input id="tile-x" type="number" min=1 step=1 value=4> |
||||
× |
||||
<input id="tile-y" type="number" min=1 step=1 value=1> |
||||
</div> |
||||
<div> |
||||
<label for="freq">f<sub>bw</sub> <span class="mq-normal-min nb">=</span><span class="mq-tablet-max nb">(Hz)</span></label> |
||||
<input id="freq" type="number" value="2048"> |
||||
<span class="mq-normal-min">Hz</span> |
||||
</div> |
||||
<div> |
||||
<label for="interval">Interval <span class="mq-tablet-max" style="font-weight:normal;">(ms)</span></label> |
||||
<input id="interval" type="number" value="0" step=100 min=0> |
||||
<span class="mq-normal-min">ms</span> |
||||
</div> |
||||
<div> |
||||
<a id="go-btn" class="button btn-green">Start</a> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box center"> |
||||
<canvas id="sg" width=860 height=530></canvas> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_spectrogram.init()); |
||||
</script> |
||||
|
||||
<?php include "_end.php"; ?> |
@ -1,99 +0,0 @@ |
||||
<?php $page = 'home'; include "_start.php"; ?> |
||||
|
||||
<h1>System Status</h1> |
||||
|
||||
<div class="Box"> |
||||
<h2>Runtime</h2> |
||||
<table> |
||||
<tr> |
||||
<th>Uptime:</th> |
||||
<td id="uptime">%uptime%</td> |
||||
</tr> |
||||
<tr> |
||||
<th>Free heap:</th> |
||||
<td id="heap">%heap%</td> |
||||
</tr> |
||||
<tr> |
||||
<th></th> |
||||
<td><a onclick="page_status.trigReset()" class="button btn-red">Restart system</a></td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
|
||||
<div class="Box"> |
||||
<h2>WiFi</h2> |
||||
<table> |
||||
<tr> |
||||
<th>WiFi mode:</th> |
||||
<td id="wmode">%wifiMode%</td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
|
||||
<!-- WiFi info is read & updated using AJAX --> |
||||
|
||||
<div class="Box sta-only" style="display:none"> |
||||
<h2>WiFi Station</h2> |
||||
<table> |
||||
<tr> |
||||
<th>SSID:</th> |
||||
<td id="staSSID"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>RSSI:</th> |
||||
<td> |
||||
<span id="staRSSIperc"></span>, |
||||
<span id="staRSSI"></span> |
||||
</td> |
||||
</tr> |
||||
<tr> |
||||
<th>MAC:</th> |
||||
<td id="staMAC"></td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
|
||||
<div class="Box ap-only" style="display:none"> |
||||
<h2>WiFi AP</h2> |
||||
<table> |
||||
<tr> |
||||
<th>SSID:</th> |
||||
<td id="apSSID"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>Hidden:</th> |
||||
<td id="apHidden"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>Auth. mode:</th> |
||||
<td id="apAuth"></td> |
||||
</tr> |
||||
<tr class="ap-auth-only"> |
||||
<th>Password:</th> |
||||
<td id="apPwd"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>Channel:</th> |
||||
<td id="apChan"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>MAC:</th> |
||||
<td id="apMAC"></td> |
||||
</tr> |
||||
</table> |
||||
</div> |
||||
|
||||
<div class="Modal hidden no-close" id="reset-modal"> |
||||
<div class="Dialog center"> |
||||
<h2>The device has been reset.</h2> |
||||
<p class="ap-only">If you're connected to the AP, you'll have to re-connect.</p> |
||||
<p>This dialog should close when the restart is complete, please wait around 15 seconds..</p> |
||||
<p><a onclick="location.reload()" class="button btn-blue">Reload the page</a></p> |
||||
</div> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_status.init); |
||||
</script> |
||||
|
||||
<?php include "_end.php"; ?> |
@ -1,62 +0,0 @@ |
||||
<?php $page = 'waveform'; include "_start.php"; ?> |
||||
|
||||
<h1>Waveform</h1> |
||||
|
||||
<div class="Box center" id="samp-ctrl"> |
||||
<div> |
||||
<label for="count">Samples</label> |
||||
<input id="count" type="number" value="500"> |
||||
</div> |
||||
<div> |
||||
<label for="freq">f<sub>s</sub> <span class="mq-normal-min nb">=</span><span class="mq-tablet-max nb">(Hz)</span></label> |
||||
<input id="freq" type="number" value="2048"> |
||||
<span class="mq-normal-min">Hz</span> |
||||
</div> |
||||
<div> |
||||
<a id="load" class="button btn-green">Load</a> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box medium chartbox"> |
||||
<div id="chart" class="ct-chart ct-wide"></div> |
||||
<div class="stats invis"> |
||||
<table> |
||||
<tr> |
||||
<th>Samples</th> |
||||
<td id="stat-count"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>f<sub>s</sub></th> |
||||
<td id="stat-f-s"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>I<sub>peak</sub></th> |
||||
<td id="stat-i-peak"></td> |
||||
</tr> |
||||
<tr> |
||||
<th>I<sub>RMS</sub></th> |
||||
<td id="stat-i-rms"></td> |
||||
</tr> |
||||
</table> |
||||
<div class="ar"><!-- auto reload --> |
||||
<input type="number" id="ar-time" step="100" value="1000" min="0"> ms |
||||
<input type="button" id="ar-btn" class="btn-blue narrow" value="Auto"> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<div class="Box chartexport hidden"> |
||||
Copy: |
||||
<a data-sep="space">1·2·3</a> |
||||
<a data-sep="comma">1,2,3</a> |
||||
<a data-sep="newline">1↵2↵3</a> |
||||
<a data-sep="csv">CSV</a> |
||||
<br> |
||||
<textarea id="copybox" class="hidden" readonly onfocus="this.select();" onmouseup="return false"></textarea> |
||||
</div> |
||||
|
||||
<script> |
||||
$().ready(page_waveform.init('raw')); |
||||
</script> |
||||
|
||||
<?php include "_end.php"; ?> |
@ -1,17 +0,0 @@ |
||||
.page-about { |
||||
.Box { |
||||
padding-left:dist(0); |
||||
padding-right:dist(0); |
||||
|
||||
a {font-weight: bold;} |
||||
} |
||||
|
||||
#logo { |
||||
float:right; |
||||
height: 130px; |
||||
} |
||||
|
||||
#logo2 { |
||||
max-width: 150px; |
||||
} |
||||
} |
@ -1,11 +1,17 @@ |
||||
.page-home #staRSSIperc:after { |
||||
padding-left: dist(-4); |
||||
content: '%'; |
||||
font-size: fsize(-1); |
||||
} |
||||
.page-about { |
||||
.Box { |
||||
padding-left:dist(0); |
||||
padding-right:dist(0); |
||||
|
||||
a {font-weight: bold;} |
||||
} |
||||
|
||||
#logo { |
||||
float:right; |
||||
height: 130px; |
||||
} |
||||
|
||||
.page-home #staRSSI:after { |
||||
padding-left: dist(-4); |
||||
content: 'dBm'; |
||||
font-size: fsize(-1); |
||||
#logo2 { |
||||
max-width: 150px; |
||||
} |
||||
} |
||||
|
@ -1,101 +0,0 @@ |
||||
#samp-ctrl { |
||||
display: flex; |
||||
padding: dist(-2); |
||||
|
||||
flex-direction: row; |
||||
@include media($phone) { |
||||
flex-direction: column; |
||||
} |
||||
|
||||
justify-content: center; |
||||
align-items: stretch; |
||||
|
||||
> div { |
||||
margin: dist(-2) dist(-1); |
||||
} |
||||
|
||||
label { |
||||
line-height: 1.8; |
||||
font-weight: bold; |
||||
} |
||||
|
||||
input,select { |
||||
width: 6em; |
||||
|
||||
@include media($phone) { |
||||
width: 100%; |
||||
} |
||||
} |
||||
|
||||
// -- spectrogram -- |
||||
|
||||
#tile-cfg input { |
||||
width: 3em; |
||||
} |
||||
|
||||
#interval { |
||||
width: 4.5em; |
||||
} |
||||
} |
||||
|
||||
.Box.chartbox { |
||||
display: flex; |
||||
flex-direction: row; |
||||
|
||||
@include media($phone) { |
||||
flex-direction: column; |
||||
} |
||||
|
||||
.stats { |
||||
flex: 0 1; |
||||
position: relative; |
||||
|
||||
@include media($phone) { |
||||
table { |
||||
margin: 0 auto; |
||||
} // center the table |
||||
|
||||
td,th { |
||||
width: 50%; |
||||
} |
||||
} |
||||
|
||||
th,td { |
||||
@include nowrap; |
||||
} |
||||
|
||||
th sub { font-weight: normal;} |
||||
|
||||
td { |
||||
min-width: 100px; |
||||
} |
||||
|
||||
td:after { |
||||
font-size: 90%; |
||||
padding-left: .5em; |
||||
} |
||||
|
||||
//#stat-count |
||||
#stat-f-s:after {content: "Hz"} |
||||
#stat-i-peak:after {content: "mA"} |
||||
#stat-i-rms:after {content: "mA"} |
||||
|
||||
padding-bottom: 50px; |
||||
|
||||
// auto reload box |
||||
.ar { |
||||
position: absolute; |
||||
bottom:dist(-2); |
||||
width:100%; |
||||
text-align: center; |
||||
|
||||
input[type=number] { |
||||
width: 4em; |
||||
} |
||||
|
||||
input[type=button] { |
||||
margin-left: dist(-2); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -1,71 +0,0 @@ |
||||
<?php $page='home'; include "_start.php"; ?> |
||||
|
||||
<h1>Heading sdfsd sdfsd</h1> |
||||
|
||||
<div class="Box">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium et fugit, labore molestiae provident veniam. Architecto deserunt eos esse fuga, hic inventore maxime minima natus non quas quibusdam sunt suscipit.</div> |
||||
|
||||
<div class="Box wide"><b>This is a wide box for like a graph or whatever.</b><br> |
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aliquid asperiores consectetur debitis deleniti dicta dignissimos dolores eveniet exercitationem ipsa iste necessitatibus nemo, odit pariatur provident repellat ullam ut veniam vero!</div> |
||||
|
||||
<div class="Box">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur aut commodi culpa et fugit laboriosam, minus praesentium recusandae ullam voluptates. Alias culpa, cupiditate ducimus est id ipsum optio quam voluptate!</div> |
||||
|
||||
<div class="Box">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur ex rerum tempore voluptates? Accusamus corporis, dolorem enim <a href="#">This is a link</a>. ipsum molestiae molestias non odit perspiciatis repellendus sint, soluta, tempore tenetur vitae voluptate!</div> |
||||
|
||||
|
||||
<div class="Box"> |
||||
<form action="#"> |
||||
<div class="Row"> |
||||
<label for="xoxo">Text</label> |
||||
<input id="xoxo" name="xoxo" type="text" value="I'm a text input"> |
||||
</div> |
||||
<div class="Row checkbox"> |
||||
<div class="checkbox-wrap"><input id="aa" name="aa" type="checkbox" value=asdf"></div> |
||||
<label for="aa">Checkbox</label> |
||||
</div> |
||||
<div class="Row"> |
||||
<label for="sss">Number</label> |
||||
<input id="sss" name="sss" type="number" value="123"> |
||||
</div> |
||||
<div class="Row"> |
||||
<label for="sss">Password</label> |
||||
<input id="sss" name="sss" type="password" value="123"> |
||||
</div> |
||||
<div class="Row"> |
||||
<label for="sss">Yo textarea</label> |
||||
<textarea>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Alias aperiam assumenda blanditiis, commodi cumque debitis harum in inventore ipsum iusto laudantium minima molestias nam nemo nihil nulla perferendis, porro vel?</textarea> |
||||
</div> |
||||
<div class="Row buttons"> |
||||
<div class="spacer"></div> |
||||
<input type="submit" value="Send"> |
||||
<input type="reset" value="Clear"> |
||||
</div> |
||||
<div class="Row checkbox"> |
||||
<div class="checkbox-wrap"><input id="aa" name="aa" type="checkbox" value=asdf"></div> |
||||
<label for="aa">Checkbox</label> |
||||
</div> |
||||
<div class="Row"> |
||||
<label for="sss">Select!!</label> |
||||
<label for="sdsd" class="select-wrap"> |
||||
<select name="sdsd" id="sdsd"> |
||||
<option value="sdfsf">sfsdf</option> |
||||
<option value="fff">fff</option> |
||||
<option value="dddd">dddddd</option> |
||||
</select> |
||||
</label> |
||||
</div> |
||||
</form> |
||||
</div> |
||||
|
||||
|
||||
|
||||
<div class="Box">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur aut commodi culpa et fugit laboriosam, minus praesentium recusandae ullam voluptates. Alias culpa, cupiditate ducimus est id ipsum optio quam voluptate!</div> |
||||
|
||||
<div class="Box">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur aut commodi culpa et fugit laboriosam, minus praesentium recusandae ullam voluptates. Alias culpa, cupiditate ducimus est id ipsum optio quam voluptate!</div> |
||||
|
||||
<div class="Box">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur aut commodi culpa et fugit laboriosam, minus praesentium recusandae ullam voluptates. Alias culpa, cupiditate ducimus est id ipsum optio quam voluptate!</div> |
||||
|
||||
<div class="Box">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur aut commodi culpa et fugit laboriosam, minus praesentium recusandae ullam voluptates. Alias culpa, cupiditate ducimus est id ipsum optio quam voluptate!</div> |
||||
|
||||
<div class="Box">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur aut commodi culpa et fugit laboriosam, minus praesentium recusandae ullam voluptates. Alias culpa, cupiditate ducimus est id ipsum optio quam voluptate!</div> |
||||
|
||||
<?php include "_end.php"; ?> |
@ -1,83 +0,0 @@ |
||||
#include <esp8266.h> |
||||
#include <httpd.h> |
||||
#include "page_about.h" |
||||
#include "fw_version.h" |
||||
#include "sbmp.h" |
||||
#include "datalink.h" |
||||
#include "serial.h" |
||||
|
||||
static bool stm_vers_loaded = false; |
||||
static char stm_vers_buf[10]; |
||||
|
||||
static void readVersionCB(SBMP_Endpoint *ep, SBMP_Datagram *dg, void** arg) |
||||
{ |
||||
(void)ep; |
||||
(void)arg; |
||||
|
||||
if (dg->type != DG_SUCCESS) { |
||||
error("Response to REQUEST_VERSION not SUCCESS."); |
||||
return; |
||||
} |
||||
|
||||
sprintf(stm_vers_buf, "%d.%d.%d", dg->payload[0], dg->payload[1], dg->payload[2]); |
||||
stm_vers_loaded = true; |
||||
} |
||||
|
||||
|
||||
/** "About" page */ |
||||
httpd_cgi_state FLASH_FN tplAbout(HttpdConnData *connData, char *token, void **arg) |
||||
{ |
||||
// arg is unused
|
||||
(void)arg; |
||||
|
||||
if (token == NULL) return HTTPD_CGI_DONE; |
||||
|
||||
if (streq(token, "vers_fw")) { |
||||
httpdSend(connData, FIRMWARE_VERSION, -1); |
||||
|
||||
} else if (streq(token, "date")) { |
||||
httpdSend(connData, __DATE__, -1); |
||||
|
||||
} else if (streq(token, "time")) { |
||||
httpdSend(connData, __TIME__, -1); |
||||
|
||||
} else if (streq(token, "vers_httpd")) { |
||||
httpdSend(connData, HTTPDVER, -1); |
||||
|
||||
} else if (streq(token, "vers_sbmp")) { |
||||
httpdSend(connData, SBMP_VER, -1); |
||||
|
||||
} else if (streq(token, "vers_sdk")) { |
||||
httpdSend(connData, STR(ESP_SDK_VERSION), -1); |
||||
|
||||
} else if (streq(token, "vers_stm")) { |
||||
|
||||
if (stm_vers_loaded) { |
||||
httpdSend(connData, stm_vers_buf, -1); |
||||
} else { |
||||
|
||||
uint16_t sesn; |
||||
sbmp_ep_send_message(dlnk_ep, DG_REQUEST_STM_VERSION, NULL, 0, &sesn, NULL); |
||||
sbmp_ep_add_listener(dlnk_ep, sesn, readVersionCB, NULL); |
||||
|
||||
sprintf(stm_vers_buf, "???"); |
||||
|
||||
// poll & wait for response
|
||||
const int timeout = 100; |
||||
for (uint32_t i = 0; i < timeout * 100; i++) { |
||||
uart_poll(); |
||||
|
||||
if (stm_vers_loaded) { |
||||
break; |
||||
} |
||||
|
||||
os_delay_us(10); |
||||
system_soft_wdt_feed(); // Feed the dog, or it'll bite.
|
||||
} |
||||
|
||||
httpdSend(connData, stm_vers_buf, -1); // send to view
|
||||
} |
||||
} |
||||
|
||||
return HTTPD_CGI_DONE; |
||||
} |
@ -0,0 +1,23 @@ |
||||
#include <esp8266.h> |
||||
#include <httpd.h> |
||||
#include "fw_version.h" |
||||
#include "sbmp.h" |
||||
#include "datalink.h" |
||||
#include "serial.h" |
||||
|
||||
|
||||
/** "Home" page */ |
||||
httpd_cgi_state FLASH_FN tplHome(HttpdConnData *connData, char *token, void **arg) |
||||
{ |
||||
// arg is unused
|
||||
(void)arg; |
||||
(void)connData; |
||||
|
||||
if (token == NULL) return HTTPD_CGI_DONE; |
||||
|
||||
// if (streq(token, "vers_fw")) {
|
||||
// httpdSend(connData, FIRMWARE_VERSION, -1);
|
||||
// }
|
||||
|
||||
return HTTPD_CGI_DONE; |
||||
} |
@ -1,189 +0,0 @@ |
||||
#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) 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(false); |
||||
|
||||
char buf[100]; |
||||
|
||||
if (suc && rpt_result.ready) { |
||||
// success
|
||||
char *bb = buf; |
||||
bb += sprintf(bb, "{\"success\": true, \"deviation\": "); |
||||
bb += my_ftoa(bb,rpt_result.deviation, 2); |
||||
bb += sprintf(bb, ", \"rms\": "); |
||||
bb += my_ftoa(bb,rpt_result.i_rms, 2); |
||||
bb += sprintf(bb, "}"); |
||||
|
||||
httpdSend(connData, buf, -1); |
||||
} else { |
||||
httpdSend(connData, "{\"success\": false}", -1); |
||||
} |
||||
|
||||
return HTTPD_CGI_DONE; |
||||
} |
||||
|
||||
/** This is an automated poll for current state, to update the display (measured by reporting func) */ |
||||
httpd_cgi_state FLASH_FN cgiMonStatus(HttpdConnData *connData) |
||||
{ |
||||
if (connData->conn == NULL) return HTTPD_CGI_DONE; |
||||
|
||||
httpdStartResponse(connData, 200); |
||||
httpdHeader(connData, "Content-Type", "application/json"); |
||||
httpdEndHeaders(connData); |
||||
|
||||
char buf[100]; |
||||
|
||||
if (rpt_result.ready) { |
||||
// success
|
||||
char *bb = buf; |
||||
bb += sprintf(bb, "{\"success\": true, \"deviation\": "); |
||||
bb += my_ftoa(bb,rpt_result.deviation, 2); |
||||
bb += sprintf(bb, ", \"rms\": "); |
||||
bb += my_ftoa(bb,rpt_result.i_rms, 2); |
||||
bb += sprintf(bb, "}"); |
||||
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) 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) return HTTPD_CGI_DONE; |
||||
|
||||
// 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, "interval", 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 */ |
||||
httpd_cgi_state FLASH_FN tplMonitoring(HttpdConnData *connData, char *token, void **arg) |
||||
{ |
||||
(void)arg; |
||||
|
||||
char buf[20]; |
||||
|
||||
if (token == NULL) return HTTPD_CGI_DONE; |
||||
|
||||
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, "rep_en")) { |
||||
if (rpt_conf.enabled) httpdSend(connData, "checked", -1); |
||||
|
||||
} else if (streq(token, "repInterval")) { // interval in seconds
|
||||
sprintf(buf, "%d", rpt_conf.interval); |
||||
httpdSend(connData, buf, -1); |
||||
|
||||
} else if (streq(token, "svc_xv")) { // Xively checkbox
|
||||
if (rpt_conf.service == RPT_XIVELY) { |
||||
httpdSend(connData, "checked", -1); |
||||
} |
||||
|
||||
} else if (streq(token, "svc_ts")) { // ThingSpeak checkbox
|
||||
if (rpt_conf.service == RPT_THINGSPEAK) { |
||||
httpdSend(connData, "checked", -1); |
||||
} |
||||
|
||||
} else if (streq(token, "repFeed")) { // reporting feed ID
|
||||
httpdSend(connData, rpt_conf.feed, -1); |
||||
|
||||
} else if (streq(token, "repKey")) { // reporting key
|
||||
httpdSend(connData, rpt_conf.key, -1); |
||||
} |
||||
|
||||
return HTTPD_CGI_DONE; |
||||
} |
@ -1,15 +0,0 @@ |
||||
#ifndef PAGE_MONITORING_H |
||||
#define PAGE_MONITORING_H |
||||
|
||||
#include <httpd.h> |
||||
|
||||
httpd_cgi_state tplMonitoring(HttpdConnData *connData, char *token, void **arg); |
||||
|
||||
httpd_cgi_state cgiMonCompare(HttpdConnData *connData); |
||||
httpd_cgi_state cgiMonStatus(HttpdConnData *connData); // same result as "compare", but doesn't measure anything
|
||||
|
||||
httpd_cgi_state cgiMonSetRef(HttpdConnData *connData); |
||||
|
||||
httpd_cgi_state cgiMonitoringCfg(HttpdConnData *connData); |
||||
|
||||
#endif // PAGE_MONITORING_H
|
@ -1,159 +0,0 @@ |
||||
#include <esp8266.h> |
||||
#include <httpd.h> |
||||
#include "page_status.h" |
||||
#include "uptime.h" |
||||
|
||||
#include "utils.h" |
||||
|
||||
|
||||
/** System Status page */ |
||||
httpd_cgi_state FLASH_FN tplSystemStatus(HttpdConnData *connData, char *token, void **arg) |
||||
{ |
||||
// arg is unused
|
||||
(void)arg; |
||||
|
||||
struct station_config stconf; |
||||
struct softap_config apconf; |
||||
|
||||
char buff[300]; |
||||
u8 mac[6]; |
||||
int rssi; |
||||
|
||||
// empty string if no token matches
|
||||
buff[0] = 0; |
||||
|
||||
if (token == NULL) return HTTPD_CGI_DONE; |
||||
|
||||
|
||||
// {
|
||||
// "uptime": "00:01:1200:01:12",
|
||||
// "heap": 3391233912,
|
||||
// "wifiMode": "ClientClient",
|
||||
// "sta": null,
|
||||
// "ap": {"SSID": "ESP_D58987", "pwd": "", "MAC": "1a:fe:34:d5:89:87", "chan": 1, "hidden": false, "auth": Open, }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
int opmode = wifi_get_opmode(); |
||||
bool is_sta = (opmode == STATION_MODE || opmode == STATIONAP_MODE); |
||||
bool is_ap = (opmode == SOFTAP_MODE || opmode == STATIONAP_MODE); |
||||
|
||||
if (streq(token, "uptime")) { |
||||
// Uptime
|
||||
uptime_str(buff); |
||||
|
||||
} else if (streq(token, "heap")) { |
||||
// Free heap
|
||||
sprintf(buff, "%u", system_get_free_heap_size()); |
||||
|
||||
} else if (streq(token, "wifiMode")) { |
||||
// WiFi mode
|
||||
strcpy(buff, opmode2str(opmode)); |
||||
|
||||
} else if (streq(token, "staInfo")) { |
||||
if (!is_sta) { |
||||
strcpy(buff, "null"); |
||||
} else { |
||||
// AP info
|
||||
wifi_station_get_config(&stconf); |
||||
wifi_get_macaddr(STATION_IF, mac); |
||||
rssi = wifi_station_get_rssi(); |
||||
|
||||
sprintf(buff, |
||||
"{" |
||||
"\"SSID\": \"%s\", " |
||||
"\"RSSI\": %d, " |
||||
"\"RSSIperc\": %d, " |
||||
"\"MAC\": \""MACSTR"\"" |
||||
"}", |
||||
stconf.ssid, |
||||
rssi, |
||||
rssi2perc(rssi), |
||||
MAC2STR(mac) |
||||
); |
||||
} |
||||
|
||||
} else if (streq(token, "apInfo")) { |
||||
if (!is_ap) { |
||||
strcpy(buff, "null"); |
||||
} else { |
||||
wifi_softap_get_config(&apconf); |
||||
wifi_get_macaddr(SOFTAP_IF, mac); |
||||
|
||||
// AP info
|
||||
sprintf(buff, |
||||
"{" |
||||
"\"SSID\": \"%s\", " |
||||
"\"pwd\": \"%s\", " |
||||
"\"MAC\": \""MACSTR"\", " |
||||
"\"chan\": %d, " |
||||
"\"hidden\": %s, " |
||||
"\"auth\": \"%s\"" |
||||
"}", |
||||
apconf.ssid, |
||||
apconf.password, |
||||
MAC2STR(mac), |
||||
apconf.channel, |
||||
apconf.ssid_hidden ? "true" : "false", |
||||
auth2str(apconf.authmode) |
||||
); |
||||
} |
||||
|
||||
/*} else if (streq(token, "staSSID")) {
|
||||
// Station SSID (if in station mode)
|
||||
if (!is_sta) { |
||||
strcpy(buff, "N/A"); |
||||
} else { |
||||
strcpy(buff, (char*)stconf.ssid); |
||||
} |
||||
|
||||
} else if (streq(token, "staRSSI")) { |
||||
// Signal strength if in Station mode
|
||||
if (!is_sta) { |
||||
strcpy(buff, "0"); |
||||
} else { |
||||
rssi = wifi_station_get_rssi(); |
||||
sprintf(buff, "%d", rssi); |
||||
} |
||||
|
||||
} else if (streq(token, "staRSSIperc")) { |
||||
// Signal strength if in Station mode
|
||||
if (!is_sta) { |
||||
strcpy(buff, "0"); |
||||
} else { |
||||
rssi = wifi_station_get_rssi(); |
||||
sprintf(buff, "%d", rssi2perc(rssi)); |
||||
} |
||||
|
||||
} else if (streq(token, "staMAC")) { |
||||
// Station MAC addr
|
||||
wifi_get_macaddr(STATION_IF, mac); |
||||
sprintf(buff, MACSTR, MAC2STR(mac)); |
||||
|
||||
} else if (streq(token, "apMAC")) { |
||||
// SoftAP MAC addr
|
||||
wifi_get_macaddr(SOFTAP_IF, mac); |
||||
sprintf(buff, MACSTR, MAC2STR(mac)); |
||||
|
||||
} else if (streq(token, "chipID")) { |
||||
// Chip serial number
|
||||
sprintf(buff, "%08x", system_get_chip_id());*/ |
||||
} |
||||
|
||||
httpdSend(connData, buff, -1); |
||||
|
||||
return HTTPD_CGI_DONE; |
||||
} |
||||
|
||||
/*
|
||||
"sta": { |
||||
"SSID": "%staSSID%", |
||||
"RSSI": %staRSSI%, |
||||
"RSSIperc": %staRSSIperc%, |
||||
"MAC": "%staMAC%" |
||||
}, |
||||
"ap": { |
||||
"MAC": "%apMAC%" |
||||
}, |
||||
*/ |
@ -1,8 +0,0 @@ |
||||
#ifndef PAGE_HOME_H |
||||
#define PAGE_HOME_H |
||||
|
||||
#include <httpd.h> |
||||
|
||||
httpd_cgi_state tplSystemStatus(HttpdConnData *connData, char *token, void **arg); |
||||
|
||||
#endif // PAGE_HOME_H
|
@ -1,191 +0,0 @@ |
||||
#include <esp8266.h> |
||||
#include <httpd.h> |
||||
#include "page_waveform.h" |
||||
|
||||
#include "ftoa.h" |
||||
#include "sampling.h" |
||||
#include "serial.h" |
||||
#include "payload_parser.h" |
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
|
||||
// Read multiple samples from the ADC as JSON
|
||||
|
||||
typedef struct { |
||||
uint16_t total_count; |
||||
uint16_t done_count; |
||||
uint32_t freq; |
||||
bool success; |
||||
} tplReadSamplesJSON_state; |
||||
|
||||
|
||||
static httpd_cgi_state FLASH_FN tplSamplesJSON(MEAS_FORMAT fmt, HttpdConnData *connData, char *token, void **arg); |
||||
|
||||
|
||||
httpd_cgi_state FLASH_FN tplWaveformJSON(HttpdConnData *connData, char *token, void **arg) |
||||
{ |
||||
return tplSamplesJSON(RAW, connData, token, arg); |
||||
} |
||||
|
||||
|
||||
httpd_cgi_state FLASH_FN tplFourierJSON(HttpdConnData *connData, char *token, void **arg) |
||||
{ |
||||
return tplSamplesJSON(FFT, connData, token, arg); |
||||
} |
||||
|
||||
|
||||
static httpd_cgi_state FLASH_FN tplSamplesJSON(MEAS_FORMAT fmt, HttpdConnData *connData, char *token, void **arg) |
||||
{ |
||||
char buff[128]; |
||||
int len; |
||||
|
||||
tplReadSamplesJSON_state *st = *arg; |
||||
|
||||
if (token == NULL) { |
||||
// end of template, or connection closed.
|
||||
if (st != NULL) free(st); |
||||
|
||||
// make sure resources are freed
|
||||
if (!meas_is_closed()) { |
||||
meas_close(); |
||||
} |
||||
|
||||
return HTTPD_CGI_DONE; // cleanup
|
||||
} |
||||
|
||||
if (st == NULL) { |
||||
// first call - allocate the struct
|
||||
st = malloc(sizeof(tplReadSamplesJSON_state)); |
||||
*arg = st; |
||||
|
||||
// check how many samples are requested
|
||||
uint16_t count = 1; |
||||
len = httpdFindArg(connData->getArgs, "n", buff, sizeof(buff)); |
||||
if (len != -1) count = (uint16_t)atoi(buff); |
||||
if (count == 0) { |
||||
error("Count == 0"); |
||||
st->success = false; |
||||
return HTTPD_CGI_DONE; |
||||
} |
||||
|
||||
uint32_t freq = 0; |
||||
len = httpdFindArg(connData->getArgs, "fs", buff, sizeof(buff)); |
||||
if (len != -1) freq = (uint32_t)atoi(buff); |
||||
if (freq == 0) { |
||||
error("Freq == 0"); |
||||
st->success = false; |
||||
return HTTPD_CGI_DONE; |
||||
} |
||||
|
||||
st->total_count = count; |
||||
st->done_count = 0; |
||||
|
||||
st->freq = freq; |
||||
|
||||
// --- REQUEST THE DATA ---
|
||||
// This actually asks the STM32 over SBMP to start the ADC DMA,
|
||||
// and we'll wait for the data to arrive.
|
||||
st->success = meas_request_data(fmt, count, freq); |
||||
if (!st->success) { |
||||
error("Failed to start sampling"); |
||||
} |
||||
} |
||||
|
||||
// the "success" field is after the data,
|
||||
// so if readout fails, success can be set to false.
|
||||
|
||||
if (strcmp(token, "values") == 0) { |
||||
if (!st->success) { |
||||
// failed to start sampling
|
||||
return HTTPD_CGI_DONE; |
||||
} |
||||
|
||||
// Wait for a chunk
|
||||
|
||||
uint8_t *chunk = NULL; |
||||
uint16_t chunk_len = 0; |
||||
|
||||
// 10 secs or 100 ms - longer wait for intial data.
|
||||
|
||||
if (!meas_wait_for_chunk()) { |
||||
// meas session was already closed.
|
||||
st->success = false; |
||||
return HTTPD_CGI_DONE; |
||||
} |
||||
|
||||
chunk = meas_get_chunk(&chunk_len); |
||||
|
||||
PayloadParser pp = pp_start(chunk, chunk_len); |
||||
|
||||
// chunk of data...
|
||||
for (; pp.ptr < pp.len; st->done_count++) { |
||||
// preceding comma if not the first number
|
||||
if (st->done_count > 0) { |
||||
httpdSend(connData, ", ", 2); |
||||
} |
||||
|
||||
float samp = pp_float(&pp); |
||||
my_ftoa(buff, samp, 3); |
||||
httpdSend(connData, buff, -1); |
||||
} |
||||
|
||||
// wait for more data in this % tag
|
||||
if (!meas_is_last_chunk()) { |
||||
meas_request_next_chunk(); |
||||
return HTTPD_CGI_MORE; // more numbers to come
|
||||
} else { |
||||
// we're done
|
||||
meas_close(); |
||||
return HTTPD_CGI_DONE; |
||||
} |
||||
|
||||
} else if (strcmp(token, "stats") == 0) { |
||||
|
||||
// the STATS json block
|
||||
if (!st->success) { |
||||
httpdSend(connData, "null", 4); |
||||
} else { |
||||
// no %f in sprintf :(
|
||||
|
||||
MeasStats *stats = meas_get_stats(); |
||||
httpdSend(connData, "{", 1); |
||||
|
||||
sprintf(buff, "\"count\": %d, ", stats->count); |
||||
httpdSend(connData, buff, -1); |
||||
|
||||
httpdSend(connData, "\"freq\": ", -1); |
||||
my_ftoa(buff, stats->freq, 3); |
||||
httpdSend(connData, buff, -1); |
||||
|
||||
httpdSend(connData, ", \"min\": ", -1); |
||||
my_ftoa(buff, stats->min, 3); |
||||
httpdSend(connData, buff, -1); |
||||
|
||||
httpdSend(connData, ", \"max\": ", -1); |
||||
my_ftoa(buff, stats->max, 3); |
||||
httpdSend(connData, buff, -1); |
||||
|
||||
httpdSend(connData, ", \"rms\": ", -1); |
||||
my_ftoa(buff, stats->rms, 3); |
||||
httpdSend(connData, buff, -1); |
||||
|
||||
if (fmt == FFT) { |
||||
// ... maybe something special for fft ...
|
||||
} |
||||
|
||||
sprintf(buff, ", \"format\": \"%s\"", fmt == RAW ? "RAW" : fmt == FFT ? "FFT" : "UNKNOWN"); |
||||
httpdSend(connData, buff, -1); |
||||
|
||||
httpdSend(connData, "}", 1); |
||||
} |
||||
|
||||
} else if (strcmp(token, "success") == 0) { |
||||
// success status
|
||||
httpdSend(connData, (st->success ? "true" : "false"), -1); |
||||
} |
||||
|
||||
return HTTPD_CGI_DONE; |
||||
} |
||||
|
||||
|
||||
|
@ -1,10 +0,0 @@ |
||||
#ifndef PAGE_WAVEFORM_H |
||||
#define PAGE_WAVEFORM_H |
||||
|
||||
#include <httpd.h> |
||||
|
||||
httpd_cgi_state tplWaveformJSON(HttpdConnData *connData, char *token, void **arg); |
||||
|
||||
httpd_cgi_state tplFourierJSON(HttpdConnData *connData, char *token, void **arg); |
||||
|
||||
#endif // PAGE_WAVEFORM_H
|
@ -0,0 +1,40 @@ |
||||
#include "pers_cfg.h" |
||||
#include "datalink.h" |
||||
#include "serial.h" |
||||
#include "httpclient.h" |
||||
#include "ftoa.h" |
||||
|
||||
#define RPT_CONF_MAGIC 0x24C595D5 |
||||
|
||||
PersistentCfg pers_conf; |
||||
|
||||
/** Save reporting config to flash */ |
||||
void FLASH_FN persistent_cfg_save(void) |
||||
{ |
||||
info("Saving persistent user config"); |
||||
|
||||
system_param_save_with_protect(0x3D, &pers_conf, sizeof(PersistentCfg)); |
||||
|
||||
info("Config saved."); |
||||
} |
||||
|
||||
/** Load the reporting config from flash */ |
||||
void FLASH_FN persistent_cfg_load(void) |
||||
{ |
||||
info("Loading persistent user config"); |
||||
|
||||
system_param_load(0x3D, 0, &pers_conf, sizeof(PersistentCfg)); |
||||
|
||||
if (pers_conf.magic != RPT_CONF_MAGIC) { |
||||
warn("Config block corrupted, reset to defaults."); |
||||
|
||||
// invalid config, zero out
|
||||
memset(&pers_conf, 0, sizeof(PersistentCfg)); |
||||
pers_conf.magic = RPT_CONF_MAGIC; |
||||
|
||||
// save fixed
|
||||
persistent_cfg_save(); |
||||
} |
||||
|
||||
info("Config loaded."); |
||||
} |
@ -0,0 +1,23 @@ |
||||
#ifndef REPORTING_H |
||||
#define REPORTING_H |
||||
|
||||
#include <esp8266.h> |
||||
|
||||
typedef struct { |
||||
|
||||
// ...
|
||||
|
||||
uint32_t magic; |
||||
} PersistentCfg; |
||||
|
||||
|
||||
/** Reporting config struct */ |
||||
extern PersistentCfg pers_conf; |
||||
|
||||
/** Save reporting config to flash */ |
||||
void persistent_cfg_save(void); |
||||
|
||||
/** Load the reporting config from flash */ |
||||
void persistent_cfg_load(void); |
||||
|
||||
#endif // REPORTING_H
|
@ -1,259 +0,0 @@ |
||||
#include "reporting.h" |
||||
#include "datalink.h" |
||||
#include "serial.h" |
||||
#include "httpclient.h" |
||||
#include "ftoa.h" |
||||
|
||||
#define RPT_CONF_MAGIC 0x24C595D5 |
||||
|
||||
ReportingResult rpt_result; |
||||
ReportingCfg rpt_conf; |
||||
|
||||
static os_timer_t rpt_tim; |
||||
|
||||
/** Timer cb */ |
||||
static void FLASH_FN rpt_tim_cb(void *arg) |
||||
{ |
||||
(void)arg; |
||||
// send report now...
|
||||
if (rpt_conf.enabled) { |
||||
capture_and_report(true); |
||||
} |
||||
} |
||||
|
||||
/** Stop / start timer & set interval based on rpt conf */ |
||||
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); |
||||
} |
||||
} |
||||
|
||||
/** Fix unterminated strings, add magic, etc.. */ |
||||
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; |
||||
// 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 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 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_cfg_save(); |
||||
} else { |
||||
dump_rpt_conf(); |
||||
} |
||||
|
||||
set_timer(); |
||||
|
||||
info("Config loaded."); |
||||
} |
||||
|
||||
/** 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."); |
||||
|
||||
rpt_result.success = (dg->type == DG_SUCCESS); |
||||
|
||||
if (dg->type == DG_SUCCESS) { |
||||
PayloadParser pp = pp_start(dg->payload, dg->length); |
||||
rpt_result.deviation = pp_float(&pp); |
||||
rpt_result.i_rms = pp_float(&pp); |
||||
} else { |
||||
error("FAIL resp from sbmp."); |
||||
} |
||||
|
||||
rpt_result.ready = true; // signal to waiting loop
|
||||
} |
||||
|
||||
|
||||
/** Send report from rpt_result */ |
||||
static void FLASH_FN do_send_report(void) |
||||
{ |
||||
info("Sending report..."); |
||||
|
||||
char buf[100]; |
||||
char *bb = buf; |
||||
|
||||
char url_buf[200]; |
||||
char hdrs_buf[100]; |
||||
|
||||
switch (rpt_conf.service) { |
||||
case RPT_XIVELY: |
||||
bb += sprintf(bb, "deviation,"); |
||||
bb += my_ftoa(bb, rpt_result.deviation, 2); |
||||
bb += sprintf(bb, "\nI_rms,"); |
||||
bb += my_ftoa(bb, rpt_result.i_rms, 2); |
||||
|
||||
// URL
|
||||
// We technically could use HTTPS, but it's not tested and probably buggy as hell
|
||||
sprintf(url_buf, "http://api.xively.com/v2/feeds/%s.csv", rpt_conf.feed); |
||||
|
||||
// Key
|
||||
sprintf(hdrs_buf, "X-ApiKey: %s\r\n", rpt_conf.key); |
||||
|
||||
http_put(url_buf, buf, hdrs_buf, http_callback_showstatus); |
||||
|
||||
break; |
||||
|
||||
case RPT_THINGSPEAK: |
||||
bb += sprintf(bb, "key=%s", rpt_conf.key); |
||||
bb += sprintf(bb, "&field1="); |
||||
bb += my_ftoa(bb, rpt_result.deviation, 2); |
||||
bb += sprintf(bb, "&field2="); |
||||
bb += my_ftoa(bb, rpt_result.i_rms, 2); |
||||
|
||||
http_post("http://api.thingspeak.com/update", buf, NULL, http_callback_showstatus); |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
|
||||
/** Immediately send report to xively / thingspeak */ |
||||
bool FLASH_FN capture_and_report(bool do_report) |
||||
{ |
||||
info("Starting reporting measurmenet..."); |
||||
|
||||
if (rpt_result.busy) { |
||||
error("Capture busy."); |
||||
return false; |
||||
} |
||||
|
||||
if (do_report) { |
||||
// don't report in AP mode
|
||||
WIFI_MODE mode = wifi_get_opmode(); |
||||
if (mode != STATION_MODE && mode != STATIONAP_MODE) { |
||||
warn("Not in station mode, cannot report."); |
||||
do_report = false; |
||||
} |
||||
} |
||||
|
||||
rpt_result.ready = false; |
||||
rpt_result.busy = true; |
||||
|
||||
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(); |
||||
|
||||
if (rpt_result.ready) { |
||||
if (rpt_result.success && do_report) { |
||||
do_send_report(); |
||||
} |
||||
|
||||
rpt_result.busy = false; |
||||
return true; // done
|
||||
} |
||||
|
||||
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); |
||||
|
||||
rpt_result.busy = false; |
||||
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 reference..."); |
||||
|
||||
if (rpt_result.busy) { |
||||
error("Capture busy."); |
||||
return false; |
||||
} |
||||
rpt_result.busy = true; |
||||
|
||||
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) { |
||||
rpt_result.busy = false; |
||||
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); |
||||
rpt_result.busy = false; |
||||
return false; |
||||
} |
@ -1,52 +0,0 @@ |
||||
#ifndef REPORTING_H |
||||
#define REPORTING_H |
||||
|
||||
#include <esp8266.h> |
||||
|
||||
typedef struct { |
||||
// 0
|
||||
bool enabled; |
||||
// 4
|
||||
uint32_t interval; |
||||
// 8
|
||||
enum { |
||||
RPT_XIVELY, |
||||
RPT_THINGSPEAK |
||||
} service; |
||||
// 12
|
||||
char feed[64]; |
||||
// 76
|
||||
char key[64]; |
||||
// 80
|
||||
uint32_t magic; |
||||
} ReportingCfg; |
||||
|
||||
/** Comapre result is stored here */ |
||||
typedef struct { |
||||
bool ready; |
||||
bool success; |
||||
bool busy; |
||||
float deviation; |
||||
float i_rms; |
||||
} ReportingResult; |
||||
|
||||
/** Report result */ |
||||
extern ReportingResult rpt_result; |
||||
|
||||
/** Reporting config struct */ |
||||
extern ReportingCfg rpt_conf; |
||||
|
||||
|
||||
/** Save reporting config to flash */ |
||||
void reporting_cfg_save(void); |
||||
|
||||
/** Load the reporting config from flash */ |
||||
void reporting_cfg_load(void); |
||||
|
||||
/** Immediately capture & send report to xively / thingspeak (or dont send - just for view) */ |
||||
bool capture_and_report(bool do_report); |
||||
|
||||
/** Capture reference vector for monitoring */ |
||||
bool capture_reporting_reference(void); |
||||
|
||||
#endif // REPORTING_H
|
@ -1,277 +0,0 @@ |
||||
#include <esp8266.h> |
||||
#include <sbmp.h> |
||||
|
||||
#include "datalink.h" |
||||
#include "sampling.h" |
||||
#include "serial.h" |
||||
|
||||
// The buffer is big enough for 256 data bytes - 4*64
|
||||
|
||||
// chunk size for bulk transfer (must be multiple of 4 - length of uint32 / float)
|
||||
// NOTE: If too large, strange errors can occur (problem with the underlying UART FIFO at high speed)
|
||||
// the FIFO has 128 bytes, and should accomodate ideally the whole frame.
|
||||
#define CHUNK_LEN 100 |
||||
|
||||
|
||||
// Only one readout can happen at a time.
|
||||
|
||||
static struct { |
||||
bool waiting_for_measure; /*!< Still waiting for first data packet */ |
||||
bool pending; /*!< Flag that data is currently being read */ |
||||
uint16_t sesn; /*!< SBMP session of the readout sequence */ |
||||
bool chunk_ready; /*!< Chunk was received and is ready for reading */ |
||||
uint8_t received_chunk[CHUNK_LEN]; /*!< Copy of the latest received chunk of data */ |
||||
uint16_t received_chunk_size; /*!< Size of the chunk in latest_chunk_copy */ |
||||
|
||||
uint32_t est_sampling_time; /*!< Estimated time in millis before data is captured and readout starts */ |
||||
|
||||
uint32_t pos; |
||||
uint32_t total; |
||||
|
||||
MEAS_FORMAT format; /*!< Requested data format */ |
||||
|
||||
// --- data stats ---
|
||||
MeasStats stats; |
||||
} rd; |
||||
|
||||
|
||||
bool FLASH_FN meas_is_closed(void) |
||||
{ |
||||
return !rd.pending; |
||||
} |
||||
|
||||
|
||||
uint32_t FLASH_FN meas_estimate_duration(uint32_t count, uint32_t freq) |
||||
{ |
||||
return (uint32_t)((count*1000.0f) / freq) + SAMP_RD_TMEO; |
||||
} |
||||
|
||||
/** Wait for one chunk, with possible retries */ |
||||
bool FLASH_FN meas_wait_for_chunk(void) |
||||
{ |
||||
for (int retry_count = 0; retry_count < SAMP_RD_RETRY_COUNT; retry_count++) { |
||||
uint32_t timeout = (rd.waiting_for_measure ? rd.est_sampling_time: SAMP_RD_TMEO); |
||||
// dbg("Chunk read total timeout = %d ms", timeout);
|
||||
|
||||
for (uint32_t i = 0; i < timeout*100; i++) { |
||||
uart_poll(); // can stop measure & start first chunk, if rx offer
|
||||
|
||||
// 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 (meas_chunk_ready()) { |
||||
// yay!!
|
||||
return true; |
||||
} |
||||
|
||||
os_delay_us(10); |
||||
system_soft_wdt_feed(); // Feed the dog, or it'll bite.
|
||||
} |
||||
|
||||
// Data still not Rx
|
||||
if (rd.waiting_for_measure) { |
||||
|
||||
// only one try in this case
|
||||
error("Sampling aborted due to timeout (no data offered)"); |
||||
sbmp_bulk_abort(dlnk_ep, rd.sesn); // send abort msg
|
||||
meas_close(); // close
|
||||
return false; |
||||
|
||||
} else { |
||||
warn("Data chunk not rx in time."); |
||||
dbg("Requesting again (try %d of %d).", retry_count+1, SAMP_RD_RETRY_COUNT); |
||||
|
||||
sbmp_bulk_request(dlnk_ep, rd.pos, CHUNK_LEN, rd.sesn); |
||||
} |
||||
} |
||||
|
||||
error("Retry count exhausted!"); |
||||
sbmp_bulk_abort(dlnk_ep, rd.sesn); |
||||
meas_close(); |
||||
return false; |
||||
} |
||||
|
||||
/** request next chunk */ |
||||
void FLASH_FN meas_request_next_chunk(void) |
||||
{ |
||||
if (!rd.pending) return; |
||||
rd.chunk_ready = false; // invalidate the current chunk, so waiting for chunk is possible.
|
||||
sbmp_bulk_request(dlnk_ep, rd.pos, CHUNK_LEN, rd.sesn); |
||||
} |
||||
|
||||
/** Check if chunk ready to be read */ |
||||
bool FLASH_FN meas_chunk_ready(void) |
||||
{ |
||||
return rd.pending && rd.chunk_ready; |
||||
} |
||||
|
||||
/**
|
||||
* @brief Get received chunk. NULL if none. |
||||
* |
||||
* The array is valid until next chunk is requested. |
||||
* Chunk length in bytes is stored in the argument. |
||||
*/ |
||||
uint8_t FLASH_FN *meas_get_chunk(uint16_t *chunk_len) |
||||
{ |
||||
if (!rd.pending) { |
||||
warn("Meas not pending, cant get chunk"); |
||||
return NULL; |
||||
} |
||||
if (!rd.chunk_ready) { |
||||
warn("Rx chunk not ready"); |
||||
return NULL; |
||||
} |
||||
|
||||
*chunk_len = rd.received_chunk_size; |
||||
return rd.received_chunk; |
||||
} |
||||
|
||||
/** Check if this was the last chunk */ |
||||
bool FLASH_FN meas_is_last_chunk(void) |
||||
{ |
||||
return rd.pos >= rd.total; |
||||
} |
||||
|
||||
/** Terminate the readout. */ |
||||
void FLASH_FN meas_close(void) |
||||
{ |
||||
if (!rd.pending) return; // ignore this call
|
||||
|
||||
sbmp_ep_remove_listener(dlnk_ep, rd.sesn); |
||||
rd.pending = false; |
||||
|
||||
info("Transfer closed."); |
||||
} |
||||
|
||||
MeasStats FLASH_FN *meas_get_stats(void) |
||||
{ |
||||
return &rd.stats; |
||||
} |
||||
|
||||
static void FLASH_FN request_data_sesn_listener(SBMP_Endpoint *ep, SBMP_Datagram *dg, void **obj) |
||||
{ |
||||
(void)obj; |
||||
|
||||
// dbg("Received msg in session %d, dg type %d", dg->session, dg->type);
|
||||
|
||||
PayloadParser pp; |
||||
switch (dg->type) { |
||||
case DG_BULK_OFFER:// Data ready notification
|
||||
// data is ready to be read
|
||||
pp = pp_start(dg->payload, dg->length); |
||||
|
||||
rd.pos = 0; |
||||
rd.total = pp_u32(&pp); |
||||
rd.waiting_for_measure = false; // "pending" flag remains set
|
||||
|
||||
// --- here start the user data (common) ---
|
||||
rd.stats.count = pp_u32(&pp); |
||||
rd.stats.freq = pp_float(&pp); |
||||
rd.stats.min = pp_float(&pp); |
||||
rd.stats.max = pp_float(&pp); |
||||
rd.stats.rms = pp_float(&pp); |
||||
// --- user data end ---
|
||||
|
||||
if (rd.format == FFT) { |
||||
// TODO read extra FFT stats ??
|
||||
} |
||||
|
||||
info("Offered %d bytes of data, starting readout.", rd.total); |
||||
|
||||
// request first chunk
|
||||
sbmp_bulk_request(ep, rd.pos, CHUNK_LEN, dg->session); |
||||
break; |
||||
|
||||
case DG_BULK_DATA: // data received
|
||||
// Process the received data
|
||||
memcpy(rd.received_chunk, dg->payload, dg->length); |
||||
rd.chunk_ready = true; |
||||
rd.received_chunk_size = dg->length; |
||||
|
||||
// move the pointer for next request
|
||||
rd.pos += dg->length; |
||||
|
||||
// --- Now we wait for the CGI func to retrieve the chunk and send it to the browser. ---
|
||||
|
||||
if (rd.pos >= rd.total) { |
||||
info("Transfer is complete."); |
||||
// transfer complete
|
||||
|
||||
// ask peer to release the buffer & go idle
|
||||
sbmp_bulk_abort(ep, dg->session); |
||||
} |
||||
break; |
||||
|
||||
case DG_BULK_ABORT: // Peer resets the readout
|
||||
// this is unlikely
|
||||
warn("Bulk transfer aborted by peer."); |
||||
goto cleanup; |
||||
} |
||||
|
||||
return; |
||||
|
||||
cleanup: |
||||
// remove the listener
|
||||
meas_close(); |
||||
} |
||||
|
||||
|
||||
bool FLASH_FN meas_request_data(MEAS_FORMAT format, uint16_t count, uint32_t freq) |
||||
{ |
||||
bool suc = false; |
||||
|
||||
info("Requesting data capture - %d samples @ %d Hz, fmt %d.", count, freq, format); |
||||
|
||||
if (rd.pending) { |
||||
warn("Acquire request already in progress; shouldn't happen, IGNORING"); |
||||
} |
||||
|
||||
if (sbmp_ep_handshake_status(dlnk_ep) != SBMP_HSK_SUCCESS) { |
||||
error("Hsk status not SUCCESS, can't request data."); |
||||
return false; |
||||
} |
||||
|
||||
// clean up
|
||||
rd.chunk_ready = false; |
||||
rd.pos = 0; |
||||
rd.total = 0; |
||||
rd.pending = true; |
||||
rd.format = format; |
||||
memset(&rd.stats, 0, sizeof(MeasStats)); // clear the stats obj
|
||||
|
||||
rd.est_sampling_time = meas_estimate_duration(count, freq); |
||||
|
||||
// start a message
|
||||
uint16_t sesn = 0; |
||||
suc = sbmp_ep_start_message(dlnk_ep, format, sizeof(uint16_t)+sizeof(uint32_t), &sesn); // format enum matches the message types
|
||||
if (!suc) goto fail; |
||||
|
||||
// register the session listener
|
||||
suc = sbmp_ep_add_listener(dlnk_ep, sesn, request_data_sesn_listener, NULL); |
||||
if (!suc) { |
||||
// discard the unfinished outgoing packet
|
||||
sbmp_frm_reset_tx(&dlnk_ep->frm); |
||||
goto fail; |
||||
} |
||||
|
||||
rd.sesn = sesn; |
||||
rd.waiting_for_measure = true; // waiting for acquisition module to start sending data
|
||||
|
||||
// request N values
|
||||
sbmp_ep_send_u16(dlnk_ep, count); |
||||
|
||||
// at freq F
|
||||
sbmp_ep_send_u32(dlnk_ep, freq); |
||||
|
||||
dbg("Request sent, session nr %d", sesn); |
||||
|
||||
return true; |
||||
|
||||
fail: |
||||
rd.waiting_for_measure = false; |
||||
rd.pending = false; |
||||
return false; |
||||
} |
@ -1,75 +0,0 @@ |
||||
#ifndef SAMPLING_H |
||||
#define SAMPLING_H |
||||
|
||||
#include <esp8266.h> |
||||
#include <httpd.h> |
||||
#include "datalink.h" |
||||
|
||||
// ms
|
||||
#define SAMP_RD_TMEO 300 |
||||
#define SAMP_RD_RETRY_COUNT 3 |
||||
#define SAMP_RD_TMEO_TOTAL (SAMP_RD_TMEO*SAMP_RD_RETRY_COUNT+200) |
||||
|
||||
typedef struct { |
||||
uint32_t count; |
||||
float freq; // actual frequency - not exact due to the prescaller limitations
|
||||
float min; |
||||
float max; |
||||
float rms; |
||||
} MeasStats; |
||||
|
||||
typedef enum { |
||||
RAW = DG_REQUEST_RAW, // same as the SBMP packet numbers used to request it
|
||||
FFT = DG_REQUEST_FFT |
||||
} MEAS_FORMAT; |
||||
|
||||
|
||||
/**
|
||||
* Reading procedure |
||||
* ----------------- |
||||
* |
||||
* 1. meas_request_data(count) |
||||
* 2. wait for meas_chunk_ready() == true |
||||
* 3. meas_get_chunk() to read the chunk last received |
||||
* 4. if meas_is_last_chunk(), call meas_close() and DONE. |
||||
* 5. meas_request_next_chunk() to get more data, goto 2 |
||||
* |
||||
* Waiting should have a timeout, if data not received, return error status to client. |
||||
*/ |
||||
|
||||
/** Estimate time needed for sampling (with some space) */ |
||||
uint32_t meas_estimate_duration(uint32_t count,uint32_t freq); |
||||
|
||||
/** Request data from the sampling module. Count - number of samples. */ |
||||
bool meas_request_data(MEAS_FORMAT format, uint16_t count, uint32_t freq); // TODO specify what kind of data - currently direct samples.
|
||||
|
||||
/** request next chunk */ |
||||
void meas_request_next_chunk(void); |
||||
|
||||
/** Check if chunk ready to be read */ |
||||
bool meas_chunk_ready(void); |
||||
|
||||
/** Check if closed (if data was expected, this means the peer aborted the transaction) */ |
||||
bool meas_is_closed(void); |
||||
|
||||
/** Get the stats struct */ |
||||
MeasStats *meas_get_stats(void); |
||||
|
||||
/**
|
||||
* @brief Get received chunk. NULL if none. |
||||
* |
||||
* The array is valid until next chunk is requested. |
||||
* Chunk length in bytes is stored in the argument. |
||||
*/ |
||||
uint8_t *meas_get_chunk(uint16_t *chunk_len); |
||||
|
||||
/** Check if this was the last chunk */ |
||||
bool meas_is_last_chunk(void); |
||||
|
||||
/** Terminate the readout. */ |
||||
void meas_close(void); |
||||
|
||||
/** Wait for one chunk, with possible retries. True = chunk ready, false = failed. */ |
||||
bool meas_wait_for_chunk(void); |
||||
|
||||
#endif // SAMPLING_H
|
Loading…
Reference in new issue