fixes, added about page

master
Ondřej Hruška 9 years ago
parent a778eb6d64
commit 46d861e0dc
  1. 6
      _web-build_do.sh
  2. 7
      esp_meas.pro
  3. 2
      esp_meas.pro.user
  4. 2
      html/css/app.css
  5. 5
      html/img/cvut.svg
  6. 5
      html/js/all.js
  7. 66
      html/pages/about.tpl
  8. 85
      html/pages/fft.html
  9. 6
      html/pages/status.tpl
  10. 12
      html/pages/wfm.html
  11. 4
      html/pages/wifi.tpl
  12. 6
      html_src/_start.php
  13. 2
      html_src/css/app.css
  14. 2
      html_src/css/app.css.map
  15. 1
      html_src/gulpfile.js
  16. 5
      html_src/img/cvut.svg
  17. 2
      html_src/js-src/lib/chartist.axis-title.js
  18. 71
      html_src/js-src/lib/chartist.js
  19. 25
      html_src/js-src/lib/chartist.zoom.js
  20. 3344
      html_src/js-src/lib/lodash.custom.js
  21. 190
      html_src/js-src/page_waveform.js
  22. 4
      html_src/js-src/page_wifi.js
  23. 32
      html_src/js-src/utils.js
  24. 5
      html_src/js/all.js
  25. 2
      html_src/js/all.js.map
  26. 44
      html_src/page_about.php
  27. 63
      html_src/page_fft.php
  28. 2
      html_src/page_status.php
  29. 11
      html_src/page_waveform.php
  30. 19
      html_src/sass/app.scss
  31. 2
      html_src/sass/form/_buttons.scss
  32. 2
      html_src/sass/layout/_box.scss
  33. 2
      html_src/sass/lib/chartist/_chartist-settings.scss
  34. 4
      html_src/sass/lib/chartist/_chartist.scss
  35. 17
      html_src/sass/pages/_about.scss
  36. 23
      html_src/sass/pages/_wfm.scss
  37. 0
      html_src/x_page_layout.php
  38. 2
      libesphttpd/include/httpd.h
  39. 2
      libesphttpd/include/logging.h
  40. 6
      user/fw_version.h
  41. 35
      user/page_about.c
  42. 8
      user/page_about.h
  43. 8
      user/routes.c
  44. 8
      user/user_main.c

@ -9,6 +9,7 @@ BLDDIR=html
rm -rf "$BLDDIR/pages" rm -rf "$BLDDIR/pages"
rm -rf "$BLDDIR/js" rm -rf "$BLDDIR/js"
rm -rf "$BLDDIR/css" rm -rf "$BLDDIR/css"
rm -rf "$BLDDIR/img"
cd "$SRCDIR" cd "$SRCDIR"
gulp --production gulp --production
@ -16,11 +17,14 @@ cd ..
cp -R "$SRCDIR/css" "$BLDDIR" cp -R "$SRCDIR/css" "$BLDDIR"
cp -R "$SRCDIR/js" "$BLDDIR" cp -R "$SRCDIR/js" "$BLDDIR"
cp -R "$SRCDIR/img" "$BLDDIR"
find "$BLDDIR" -name "*.map" -delete find "$BLDDIR" -name "*.map" -delete
mkdir -p "$BLDDIR/pages" mkdir -p "$BLDDIR/pages"
php "$SRCDIR/page_status.php" > "$BLDDIR/pages/status.tpl" php "$SRCDIR/page_status.php" > "$BLDDIR/pages/status.tpl"
php "$SRCDIR/page_about.php" > "$BLDDIR/pages/about.tpl"
php "$SRCDIR/page_wifi.php" > "$BLDDIR/pages/wifi.tpl" php "$SRCDIR/page_wifi.php" > "$BLDDIR/pages/wifi.tpl"
php "$SRCDIR/page_waveform.php" > "$BLDDIR/pages/waveform.html" # no substitutions, .html allows to gzip it. php "$SRCDIR/page_waveform.php" > "$BLDDIR/pages/wfm.html" # no substitutions, .html allows to gzip it.
php "$SRCDIR/page_fft.php" > "$BLDDIR/pages/fft.html" # same

@ -60,7 +60,8 @@ SOURCES += \
user/page_status.c \ user/page_status.c \
user/page_waveform.c \ user/page_waveform.c \
user/utils.c \ user/utils.c \
sbmp/library/payload_builder.c sbmp/library/payload_builder.c \
user/page_about.c
HEADERS += \ HEADERS += \
include/uart_hw.h \ include/uart_hw.h \
@ -142,7 +143,9 @@ HEADERS += \
user/page_waveform.h \ user/page_waveform.h \
libesphttpd/include/espmissingprotos.h \ libesphttpd/include/espmissingprotos.h \
user/utils.h \ user/utils.h \
sbmp/library/payload_builder.h sbmp/library/payload_builder.h \
user/page_about.h \
user/fw_version.h
DISTFILES += \ DISTFILES += \
style.astylerc \ style.astylerc \

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 3.6.1, 2016-03-29T21:53:03. --> <!-- Written by QtCreator 3.6.1, 2016-03-31T02:51:43. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.8 KiB

File diff suppressed because one or more lines are too long

@ -0,0 +1,66 @@
<!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 analyzer</title>
<link href="/css/app.css" rel="stylesheet">
<script src="/js/all.js"></script>
</head>
<body class="page-about">
<div id="outer">
<nav id="menu">
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div>
<a href="/">Home</a><a href="/wifi">WiFi config</a><a href="/waveform">Waveform</a><a href="/fft">FFT</a><a href="/about" class="selected">About</a></nav>
<div id="content">
<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>&copy; Ondřej Hruška, 2016 &lt;<a href="mailto:ondra@ondrovo.com" target="blank">ondra@ondrovo.com</a>&gt;</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>
<p>
The ESP8266 firmware is based on the amazing <a href="https://github.com/Spritetm/esphttpd" target="blank">esp-httpd</a>
library by Jeroen Domburg.
</p>
<table>
<tr>
<th>Firmware</th>
<td>v%vers_fw%, build <i>%date%</i> at <i>%time%</i></td>
</tr>
<tr>
<th>HTTPD</th>
<td>v%vers_httpd%</td>
</tr>
<tr>
<th>SBMP</th>
<td>v%vers_sbmp%</td>
</tr>
<tr>
<th>IoT SDK</th>
<td>v%vers_sdk%</td>
</tr>
</table>
</div>
</div>
</div>
</body>
</html>

@ -0,0 +1,85 @@
<!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 analyzer</title>
<link href="/css/app.css" rel="stylesheet">
<script src="/js/all.js"></script>
</head>
<body class="page-fft">
<div id="outer">
<nav id="menu">
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div>
<a href="/">Home</a><a href="/wifi">WiFi config</a><a href="/waveform">Waveform</a><a href="/fft" class="selected">FFT</a><a href="/about">About</a></nav>
<div id="content">
<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">Rate <span class="mq-tablet-max" style="font-weight:normal;">(Hz)</span></label>
<input id="freq" type="number" value="4096">
<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="0.5" value="1" min="0">&nbsp;s
<input type="button" id="ar-btn" class="btn-blue narrow" value="Auto">
</div>
</div>
</div>
<script>
$().ready(page_waveform.init('fft'));
</script>
</div>
</div>
</body>
</html>

@ -15,8 +15,8 @@
<body class="page-home"> <body class="page-home">
<div id="outer"> <div id="outer">
<nav id="menu"> <nav id="menu">
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current analyzer</div> <div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div>
<a href="/" class="selected">Home</a><a href="/wifi">WiFi config</a><a href="/waveform">Waveform</a></nav> <a href="/" class="selected">Home</a><a href="/wifi">WiFi config</a><a href="/waveform">Waveform</a><a href="/fft">FFT</a><a href="/about">About</a></nav>
<div id="content"> <div id="content">
<h1>System Status</h1> <h1>System Status</h1>
@ -24,7 +24,6 @@
<div class="Box"> <div class="Box">
<h2>Runtime</h2> <h2>Runtime</h2>
<table> <table>
<tbody>
<tr> <tr>
<th>Uptime:</th> <th>Uptime:</th>
<td id="uptime">%uptime%</td> <td id="uptime">%uptime%</td>
@ -33,7 +32,6 @@
<th>Free heap:</th> <th>Free heap:</th>
<td id="heap">%heap%</td> <td id="heap">%heap%</td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>

@ -15,8 +15,8 @@
<body class="page-waveform"> <body class="page-waveform">
<div id="outer"> <div id="outer">
<nav id="menu"> <nav id="menu">
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current analyzer</div> <div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div>
<a href="/">Home</a><a href="/wifi">WiFi config</a><a href="/waveform" class="selected">Waveform</a></nav> <a href="/">Home</a><a href="/wifi">WiFi config</a><a href="/waveform" class="selected">Waveform</a><a href="/fft">FFT</a><a href="/about">About</a></nav>
<div id="content"> <div id="content">
<h1>Waveform</h1> <h1>Waveform</h1>
@ -41,7 +41,7 @@
<div class="stats invis"> <div class="stats invis">
<table> <table>
<tr> <tr>
<th>#</th> <th>Samples</th>
<td id="stat-count"></td> <td id="stat-count"></td>
</tr> </tr>
<tr> <tr>
@ -57,11 +57,15 @@
<td id="stat-i-rms"></td> <td id="stat-i-rms"></td>
</tr> </tr>
</table> </table>
<div class="ar"><!-- auto reload -->
<input type="number" id="ar-time" step="0.5" value="1" min="0">&nbsp;s
<input type="button" id="ar-btn" class="btn-blue narrow" value="Auto">
</div>
</div> </div>
</div> </div>
<script> <script>
$().ready(page_waveform.init()); $().ready(page_waveform.init('raw'));
</script> </script>
</div> </div>

@ -15,8 +15,8 @@
<body class="page-wifi"> <body class="page-wifi">
<div id="outer"> <div id="outer">
<nav id="menu"> <nav id="menu">
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current analyzer</div> <div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div>
<a href="/">Home</a><a href="/wifi" class="selected">WiFi config</a><a href="/waveform">Waveform</a></nav> <a href="/">Home</a><a href="/wifi" class="selected">WiFi config</a><a href="/waveform">Waveform</a><a href="/fft">FFT</a><a href="/about">About</a></nav>
<div id="content"> <div id="content">
<h1>Wireless Setup</h1> <h1>Wireless Setup</h1>

@ -4,10 +4,10 @@ $menu = [
'home' => [ '/', 'Home' ], 'home' => [ '/', 'Home' ],
'wifi' => [ '/wifi', 'WiFi config' ], 'wifi' => [ '/wifi', 'WiFi config' ],
'waveform' => [ '/waveform', 'Waveform' ], 'waveform' => [ '/waveform', 'Waveform' ],
// 'fft' => [ '/fft', 'FFT' ], 'fft' => [ '/fft', 'FFT' ],
// 'spectrogram' => [ '/spectrogram', 'Spectrogram' ], // 'spectrogram' => [ '/spectrogram', 'Spectrogram' ],
// 'transient' => [ '/transient', 'Power-on transient' ], // 'transient' => [ '/transient', 'Power-on transient' ],
// 'about' => [ '/about', 'Credits & About' ], 'about' => [ '/about', 'About' ],
]; ];
$appname = 'Current analyzer'; $appname = 'Current analyzer';
@ -37,7 +37,7 @@ $appname = 'Current analyzer';
<body class="page-<?=$page?>"> <body class="page-<?=$page?>">
<div id="outer"> <div id="outer">
<nav id="menu"> <nav id="menu">
<div id="brand" onclick="$('#menu').toggleClass('expanded')">Current analyzer</div> <div id="brand" onclick="$('#menu').toggleClass('expanded')">Current Analyser</div>
<?php <?php
// generate the menu // generate the menu
foreach($menu as $k => $m) { foreach($menu as $k => $m) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -24,6 +24,7 @@ elixir(function (mix) {
'js-src/lib/chartist.js', 'js-src/lib/chartist.js',
'js-src/lib/chartist.axis-title.js', 'js-src/lib/chartist.axis-title.js',
'js-src/lib/chartist.zoom.js', 'js-src/lib/chartist.zoom.js',
'js-src/lib/lodash.custom.js',
'js-src/utils.js', 'js-src/utils.js',
'js-src/modal.js', 'js-src/modal.js',
'js-src/app.js', 'js-src/app.js',

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.8 KiB

@ -42,8 +42,6 @@
options = Chartist.extend({}, defaultOptions, options); options = Chartist.extend({}, defaultOptions, options);
console.log(options);
return function ctAxisTitle(chart) { return function ctAxisTitle(chart) {
chart.on('created', function (data) { chart.on('created', function (data) {

@ -253,13 +253,13 @@ var Chartist = {
* @memberof Chartist.Core * @memberof Chartist.Core
* @type {Object} * @type {Object}
*/ */
Chartist.escapingMap = { // Chartist.escapingMap = {
'&': '&amp;', // '&': '&amp;',
'<': '&lt;', // '<': '&lt;',
'>': '&gt;', // '>': '&gt;',
'"': '&quot;', // '"': '&quot;',
'\'': '&#039;' // '\'': '&#039;'
}; // };
/** /**
* This function serializes arbitrary data to a string. In case of data that can't be easily converted to a string, this function will create a wrapper object and serialize the data using JSON.stringify. The outcoming string will always be escaped using Chartist.escapingMap. * This function serializes arbitrary data to a string. In case of data that can't be easily converted to a string, this function will create a wrapper object and serialize the data using JSON.stringify. The outcoming string will always be escaped using Chartist.escapingMap.
@ -278,9 +278,11 @@ var Chartist = {
data = JSON.stringify({data: data}); data = JSON.stringify({data: data});
} }
return Object.keys(Chartist.escapingMap).reduce(function(result, key) { return _.escape(data);
return Chartist.replaceAll(result, key, Chartist.escapingMap[key]);
}, data); // return Object.keys(Chartist.escapingMap).reduce(function(result, key) {
// return Chartist.replaceAll(result, key, Chartist.escapingMap[key]);
// }, data);
}; };
/** /**
@ -295,9 +297,10 @@ var Chartist = {
return data; return data;
} }
data = Object.keys(Chartist.escapingMap).reduce(function(result, key) { // data = Object.keys(Chartist.escapingMap).reduce(function(result, key) {
return Chartist.replaceAll(result, Chartist.escapingMap[key], key); // return Chartist.replaceAll(result, Chartist.escapingMap[key], key);
}, data); // }, data);
data = _.unescape(data);
try { try {
data = JSON.parse(data); data = JSON.parse(data);
@ -770,24 +773,24 @@ var Chartist = {
return bounds; return bounds;
}; };
/** // /**
* Calculate cartesian coordinates of polar coordinates // * Calculate cartesian coordinates of polar coordinates
* // *
* @memberof Chartist.Core // * @memberof Chartist.Core
* @param {Number} centerX X-axis coordinates of center point of circle segment // * @param {Number} centerX X-axis coordinates of center point of circle segment
* @param {Number} centerY X-axis coordinates of center point of circle segment // * @param {Number} centerY X-axis coordinates of center point of circle segment
* @param {Number} radius Radius of circle segment // * @param {Number} radius Radius of circle segment
* @param {Number} angleInDegrees Angle of circle segment in degrees // * @param {Number} angleInDegrees Angle of circle segment in degrees
* @return {{x:Number, y:Number}} Coordinates of point on circumference // * @return {{x:Number, y:Number}} Coordinates of point on circumference
*/ // */
Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) { // Chartist.polarToCartesian = function (centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0; // var angleInRadians = (angleInDegrees - 90) * Math.PI / 180.0;
//
return { // return {
x: centerX + (radius * Math.cos(angleInRadians)), // x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians)) // y: centerY + (radius * Math.sin(angleInRadians))
}; // };
}; // };
/** /**
* Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right * Initialize chart drawing rectangle (area where chart is drawn) x1,y1 = bottom left / x2,y2 = top right
@ -907,8 +910,10 @@ var Chartist = {
positionalData[axis.counterUnits.len] = axisOffset - 10; positionalData[axis.counterUnits.len] = axisOffset - 10;
var lblText = labels[index]; var lblText = labels[index];
//round (!! will break for non-numeric)
lblText = Math.round(+lblText*100)/100; if (_.isNumber(lblText)) {
lblText = Chartist.roundWithPrecision(lblText, 2);
}
if(useForeignObject) { if(useForeignObject) {
// We need to set width and height explicitly to px as span will not expand with width and height being // We need to set width and height explicitly to px as span will not expand with width and height being

@ -189,8 +189,21 @@
var y2 = chartRect.y1 - rect.y; var y2 = chartRect.y1 - rect.y;
var y1 = y2 - rect.height; var y1 = y2 - rect.height;
chart.options.axisX.highLow = { low: project(x1, axisX), high: project(x2, axisX) }; var xLow = project(x1, axisX);
chart.options.axisY.highLow = { low: project(y1, axisY), high: project(y2, axisY) }; var xHigh = project(x2, axisX);
var yLow = project(y1, axisY);
var yHigh = project(y2, axisY);
var explb = chart.options.explicitBounds;
if (!_.isUndefined(explb)) {
if (!_.isUndefined(explb.xLow)) xLow = Math.max(explb.xLow, xLow);
if (!_.isUndefined(explb.xHigh)) xHigh = Math.min(explb.xHigh, xHigh);
if (!_.isUndefined(explb.yLow)) yLow = Math.max(explb.yLow, yLow);
if (!_.isUndefined(explb.yHigh)) yHigh = Math.min(explb.yHigh, yHigh);
}
chart.options.axisX.highLow = {low: xLow, high: xHigh};
chart.options.axisY.highLow = {low: yLow, high: yHigh};
chart.update(chart.data, chart.options); chart.update(chart.data, chart.options);
onZoom && onZoom(chart, reset); onZoom && onZoom(chart, reset);
@ -209,11 +222,11 @@
}; };
function hide(rect) { function hide(rect) {
rect.attr({ style: 'display:none' }); rect.attr({style: 'display:none'});
} }
function show(rect) { function show(rect) {
rect.attr({ style: 'display:block' }); rect.attr({style: 'display:block'});
} }
function getRect(firstPoint, secondPoint) { function getRect(firstPoint, secondPoint) {
@ -248,7 +261,7 @@
point.x = x; point.x = x;
point.y = y; point.y = y;
point = point.matrixTransform(matrix.inverse()); point = point.matrixTransform(matrix.inverse());
return point || { x: 0, y: 0 }; return point || {x: 0, y: 0};
} }
function project(value, axis) { function project(value, axis) {
@ -266,7 +279,7 @@
return Math.log(val) / Math.log(base); return Math.log(val) / Math.log(base);
} }
} (window, document, Chartist)); }(window, document, Chartist));
return Chartist.plugins.zoom; return Chartist.plugins.zoom;
})); }));

File diff suppressed because it is too large Load Diff

@ -2,31 +2,77 @@ var page_waveform = (function () {
var wfm = {}; var wfm = {};
var zoomResetFn; var zoomResetFn;
var dataFormat;
function buildChart(obj, xlabel, ylabel) { var readoutPending = false;
var points = []; var autoReload = false;
obj.samples.forEach(function (a, i) { var autoReloadTime = 1;
points.push({x: i, y: a}); var arTimeout = -1;
});
var zoomSavedX, zoomSavedY;
function buildChart(j) {
// Build the chart // Build the chart
var plugins = [];
var mql = window.matchMedia('screen and (min-width: 544px)'); var mql = window.matchMedia('screen and (min-width: 544px)');
var isPhone = !mql.matches; var isPhone = !mql.matches;
if (!isPhone) { var fft = (j.stats.format == 'FFT');
// larger than phone
plugins.push( 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(j.stats.freq);
$('#stat-i-peak').html(peak);
$('#stat-i-rms').html(j.stats.rms);
$('.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({ Chartist.plugins.ctAxisTitle({
axisX: { axisX: {
axisTitle: xlabel, axisTitle: xLabel,
offset: { offset: {
x: 0, x: 0,
y: 55 y: 55
} }
}, },
axisY: { axisY: {
axisTitle: ylabel, axisTitle: yLabel,
flipText: true, flipText: true,
offset: { offset: {
x: 0, x: 0,
@ -35,17 +81,19 @@ var page_waveform = (function () {
} }
}) })
); );
}
// zoom var xHigh, xLow, yHigh, yLow;
plugins.push(Chartist.plugins.zoom({
resetOnRightMouseBtn:true, if (zoomSavedX) {
onZoom: function(chart, reset) { // we have saved coords of the zoom rect, restore the zoom.
zoomResetFn = reset; xHigh = zoomSavedX.high;
xLow = zoomSavedX.low;
yHigh = zoomSavedY.high;
yLow = zoomSavedY.low;
} else {
yHigh = fft ? undefined : displayPeak;
yLow = fft ? 0 : -displayPeak;
} }
}));
var peak = obj.stats.peak;
new Chartist.Line('#chart', { new Chartist.Line('#chart', {
series: [ series: [
@ -56,7 +104,7 @@ var page_waveform = (function () {
] ]
}, { }, {
showPoint: false, showPoint: false,
// showArea: true, showArea: fft,
fullWidth: true, fullWidth: true,
chartPadding: (isPhone ? {right: 20, bottom: 5, left: 0} : {right: 25, bottom: 30, left: 25}), chartPadding: (isPhone ? {right: 20, bottom: 5, left: 0} : {right: 25, bottom: 30, left: 25}),
series: { series: {
@ -66,22 +114,32 @@ var page_waveform = (function () {
}, },
axisX: { axisX: {
type: Chartist.AutoScaleAxis, type: Chartist.AutoScaleAxis,
onlyInteger: true //onlyInteger: !fft // only for raw
high: xHigh,
low: xLow,
}, },
axisY: { axisY: {
type: Chartist.AutoScaleAxis, type: Chartist.AutoScaleAxis,
//onlyInteger: true //onlyInteger: true
high: peak, high: yHigh,
low: -peak, low: yLow,
},
explicitBounds: {
xLow: 0,
yLow: fft ? 0 : undefined,
xHigh: points[points.length-1].x
}, },
plugins: plugins plugins: plugins
}); });
} }
function onRxData(resp, status) { function onRxData(resp, status) {
readoutPending = false;
if (status != 200) { if (status != 200) {
// bad response if (status != 0) { // 0 = aborted
alert("Request failed."); alert("Request failed.");
}
return; return;
} }
@ -91,46 +149,84 @@ var page_waveform = (function () {
return; return;
} }
j.stats.peak = Math.max(-j.stats.min, j.stats.max); if (autoReload)
arTimeout = setTimeout(requestReload, autoReloadTime);
buildChart(j, 'Sample number', 'Current - mA'); buildChart(j);
$('#stat-count').html(j.stats.count);
$('#stat-f-s').html(j.stats.freq);
$('#stat-i-peak').html(j.stats.peak);
$('#stat-i-rms').html(j.stats.rms);
$('.stats').removeClass('invis');
} }
wfm.init = function() { function requestReload() {
// var resp = { if (readoutPending) return false;
// "samples": [1878, 1883, 1887, 1897, 1906, 1915, 1926, 1940, 1955, 1970, 1982, 1996, 2012, 2026, 2038, 2049],
// "success": true
// };
function loadBtnClick() { readoutPending = true;
var samples = $('#count').val();
var freq = $('#freq').val();
//http://192.168.1.13 //http://192.168.1.13
$().get('/api/raw.json?n='+samples+'&fs='+freq, onRxData, true, true); var url = '/api/{fmt}.json?n={n}&fs={fs}'.format({
fmt: dataFormat,
n: $('#count').val(),
fs: $('#freq').val()
});
$().get(url, onRxData, true, true);
return true;
} }
$('#load').on('click', loadBtnClick); wfm.init = function (format) {
// --- Load data ---
dataFormat = format;
// initial
// requestReload();
$('#count,#freq').on('keyup', function(e) { $('#load').on('click', requestReload);
$('#count,#freq').on('keyup', function (e) {
if (e.which == 13) { if (e.which == 13) {
loadBtnClick(); requestReload();
} }
}); });
// chart zooming // --- zooming ---
$('#chart').on('contextmenu', function(e) {
$('#chart').on('contextmenu', function (e) { // right click on the chart -> reset
zoomResetFn && zoomResetFn(); zoomResetFn && zoomResetFn();
zoomResetFn = null; zoomResetFn = null;
zoomSavedX = null;
zoomSavedY = null;
e.preventDefault(); e.preventDefault();
return false; return false;
}); });
// --- scroll the input box ---
$('input[type=number]').on('mousewheel', function(e) {
var val = +$(this).val();
var step = +($(this).attr('step') || 1);
if(e.wheelDelta > 0) {
val += step;
} else {
val -= step;
}
$(this).val(val);
});
// auto-reload button
$('#ar-btn').on('click', function() {
autoReloadTime = +$('#ar-time').val() * 1000; // ms
autoReload = !autoReload;
if (autoReload) {
requestReload();
} else {
clearTimeout(arTimeout);
}
$('#ar-btn')
.toggleClass('btn-blue')
.toggleClass('btn-red')
.val(autoReload ? 'Stop' : 'Auto');
});
}; };
return wfm; return wfm;

@ -50,7 +50,7 @@ var page_wifi = (function () {
var inner = document.createElement('div'); var inner = document.createElement('div');
var $inner = $(inner).addClass('inner') var $inner = $(inner).addClass('inner')
.htmlAppend('<div class="rssi">{0}</div>'.format(ap.rssi_perc)) .htmlAppend('<div class="rssi">{0}</div>'.format(ap.rssi_perc))
.htmlAppend('<div class="essid" title="{0}">{0}</div>'.format(e(ap.essid))) .htmlAppend('<div class="essid" title="{0}">{0}</div>'.format(_.escape(ap.essid)))
.htmlAppend('<div class="auth">{0}</div>'.format(authStr[ap.enc])); .htmlAppend('<div class="auth">{0}</div>'.format(authStr[ap.enc]));
$item.on('click', function () { $item.on('click', function () {
@ -76,7 +76,7 @@ var page_wifi = (function () {
/** Ask the CGI what APs are visible (async) */ /** Ask the CGI what APs are visible (async) */
function scanAPs() { function scanAPs() {
$().get('/wifi/scan.cgi', onScan, true, true); // no cache, no jsonp $().get('http://192.168.1.13/wifi/scan.cgi', onScan, true, true); // no cache, no jsonp
} }
function rescan(time) { function rescan(time) {

@ -2,32 +2,8 @@ function bool(x) {
return (x === 1 || x === '1' || x === true || x === 'true'); return (x === 1 || x === '1' || x === true || x === 'true');
} }
/** html entities */ /**
function e(x) { * Perform a substitution in the given string.
return String(x)
.replace(/&/g, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
}
/** Returns true if argument is array [] */
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
/** Returns true if argument is object {} */
function isObject(obj) {
return Object.prototype.toString.call(obj) === '[object Object]';
}
/** escape a string to have no special meaning in regex */
function regexEscape(s) {
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
/** Perform a substitution in the given string.
* *
* Arguments - array or list of replacements. * Arguments - array or list of replacements.
* Arguments numeric keys will replace {0}, {1} etc. * Arguments numeric keys will replace {0}, {1} etc.
@ -42,7 +18,7 @@ String.prototype.format = function () {
var repl = arguments; var repl = arguments;
if (arguments.length == 1 && (isArray(arguments[0]) || isObject(arguments[0]))) { if (arguments.length == 1 && (_.isArray(arguments[0]) || _.isObject(arguments[0]))) {
repl = arguments[0]; repl = arguments[0];
} }
@ -55,7 +31,7 @@ String.prototype.format = function () {
} }
// replace all occurrences // replace all occurrences
var pattern = new RegExp(regexEscape(ph), "g"); var pattern = new RegExp(_.escapeRegExp(ph), "g");
out = out.replace(pattern, repl[ph_orig]); out = out.replace(pattern, repl[ph_orig]);
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -0,0 +1,44 @@
<?php $page = 'about'; include "_start.php"; ?>
<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>&copy; Ondřej Hruška, 2016 &lt;<a href="mailto:ondra@ondrovo.com" target="blank">ondra@ondrovo.com</a>&gt;</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>
<p>
The ESP8266 firmware is based on the amazing <a href="https://github.com/Spritetm/esphttpd" target="blank">esp-httpd</a>
library by Jeroen Domburg.
</p>
<table>
<tr>
<th>Firmware</th>
<td>v%vers_fw%, build <i>%date%</i> at <i>%time%</i></td>
</tr>
<tr>
<th>HTTPD</th>
<td>v%vers_httpd%</td>
</tr>
<tr>
<th>SBMP</th>
<td>v%vers_sbmp%</td>
</tr>
<tr>
<th>IoT SDK</th>
<td>v%vers_sdk%</td>
</tr>
</table>
</div>
<?php include "_end.php"; ?>

@ -0,0 +1,63 @@
<?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">Rate <span class="mq-tablet-max" style="font-weight:normal;">(Hz)</span></label>
<input id="freq" type="number" value="4096">
<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="0.5" value="1" min="0">&nbsp;s
<input type="button" id="ar-btn" class="btn-blue narrow" value="Auto">
</div>
</div>
</div>
<script>
$().ready(page_waveform.init('fft'));
</script>
<?php include "_end.php"; ?>

@ -6,7 +6,6 @@ include "_start.php"; ?>
<div class="Box"> <div class="Box">
<h2>Runtime</h2> <h2>Runtime</h2>
<table> <table>
<tbody>
<tr> <tr>
<th>Uptime:</th> <th>Uptime:</th>
<td id="uptime">%uptime%</td> <td id="uptime">%uptime%</td>
@ -15,7 +14,6 @@ include "_start.php"; ?>
<th>Free heap:</th> <th>Free heap:</th>
<td id="heap">%heap%</td> <td id="heap">%heap%</td>
</tr> </tr>
</tbody>
</table> </table>
</div> </div>

@ -1,5 +1,4 @@
<?php $page = 'waveform'; <?php $page = 'waveform'; include "_start.php"; ?>
include "_start.php"; ?>
<h1>Waveform</h1> <h1>Waveform</h1>
@ -23,7 +22,7 @@ include "_start.php"; ?>
<div class="stats invis"> <div class="stats invis">
<table> <table>
<tr> <tr>
<th>#</th> <th>Samples</th>
<td id="stat-count"></td> <td id="stat-count"></td>
</tr> </tr>
<tr> <tr>
@ -39,11 +38,15 @@ include "_start.php"; ?>
<td id="stat-i-rms"></td> <td id="stat-i-rms"></td>
</tr> </tr>
</table> </table>
<div class="ar"><!-- auto reload -->
<input type="number" id="ar-time" step="0.5" value="1" min="0">&nbsp;s
<input type="button" id="ar-btn" class="btn-blue narrow" value="Auto">
</div>
</div> </div>
</div> </div>
<script> <script>
$().ready(page_waveform.init()); $().ready(page_waveform.init('raw'));
</script> </script>
<?php include "_end.php"; ?> <?php include "_end.php"; ?>

@ -45,29 +45,20 @@ $c-form-highlight-a: #28bc65;
@import "pages/wifi"; @import "pages/wifi";
@import "pages/home"; @import "pages/home";
@import "pages/wfm"; @import "pages/wfm";
@import "pages/about";
/*
@include media($tablet-min) { @include media($tablet-min) {
.mq-phone { .mq-phone { display: none; }
display: none;
}
} }
@include media($phone) { @include media($phone) {
.mq-tablet-min { .mq-tablet-min { display: none; }
display: none;
}
} }
*/
@include media($normal-min) { @include media($normal-min) {
.mq-tablet-max { .mq-tablet-max { display: none; }
display: none;
}
} }
@include media($tablet-max) { @include media($tablet-max) {
.mq-normal-min { .mq-normal-min { display: none; }
display: none;
}
} }

@ -55,7 +55,7 @@ input[type="reset"], .btn-red {
@include fancy-btn-colors($btn-red-f, $btn-red-b, $btn-red-fa, $btn-red-ba) @include fancy-btn-colors($btn-red-f, $btn-red-b, $btn-red-fa, $btn-red-ba)
} }
//&.blue {@include fancy-btn-colors($btn-blue-f, $btn-blue-b, $btn-blue-fa, $btn-blue-ba)} &.btn-blue {@include fancy-btn-colors($btn-blue-f, $btn-blue-b, $btn-blue-fa, $btn-blue-ba)}
//&, &.orange {@include fancy-btn-colors($btn-orange-f, $btn-orange-b, $btn-orange-fa, $btn-orange-ba)} //&, &.orange {@include fancy-btn-colors($btn-orange-f, $btn-orange-b, $btn-orange-fa, $btn-orange-ba)}
/* /*

@ -3,7 +3,7 @@
max-width: 900px; max-width: 900px;
margin-top: dist(0); margin-top: dist(0);
padding: dist(-1); padding: dist(-1) dist(0);
@include media($phone) { @include media($phone) {
margin-top: dist(-1); margin-top: dist(-1);

@ -30,7 +30,7 @@ $ct-point-size: 4px !default;
// Line chart point, can be either round or square // Line chart point, can be either round or square
$ct-point-shape: round !default; $ct-point-shape: round !default;
// Area fill transparency between 0 and 1 // Area fill transparency between 0 and 1
$ct-area-opacity: 0.1 !default; $ct-area-opacity: 0.3 !default;
// Bar chart bar width // Bar chart bar width
$ct-bar-width: 10px !default; $ct-bar-width: 10px !default;

@ -207,6 +207,10 @@
@include ct-chart-line($ct-line-width); @include ct-chart-line($ct-line-width);
} }
.ct-with-area .ct-line {
stroke-width: 1px;
}
.ct-area { .ct-area {
@include ct-chart-area(); @include ct-chart-area();
} }

@ -0,0 +1,17 @@
.page-about {
.Box {
padding-left:dist(0);
padding-right:dist(0);
a {font-weight: bold;}
}
#logo {
float:right;
height: 130px;
}
#logo2 {
max-width: 150px;
}
}

@ -11,7 +11,7 @@
align-items: stretch; align-items: stretch;
> div { > div {
margin: dist(-2); margin: dist(-2) dist(-1);
} }
label { label {
@ -19,8 +19,8 @@
font-weight: bold; font-weight: bold;
} }
input { input,select {
width: 150px; width: 6em;
@include media($phone) { @include media($phone) {
width: 100%; width: 100%;
@ -38,6 +38,7 @@
.stats { .stats {
flex: 0 1; flex: 0 1;
position: relative;
@include media($phone) { @include media($phone) {
table { table {
@ -68,5 +69,21 @@
#stat-f-s:after {content: "Hz"} #stat-f-s:after {content: "Hz"}
#stat-i-peak:after {content: "mA"} #stat-i-peak:after {content: "mA"}
#stat-i-rms:after {content: "mA"} #stat-i-rms:after {content: "mA"}
// 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);
}
}
} }
} }

@ -3,7 +3,7 @@
#include <esp8266.h> #include <esp8266.h>
#define HTTPDVER "0.4" #define HTTPDVER "0.4-based"
#define HTTPD_CGI_MORE 0 #define HTTPD_CGI_MORE 0
#define HTTPD_CGI_DONE 1 #define HTTPD_CGI_DONE 1

@ -20,7 +20,7 @@
do { \ do { \
printf(LOG_EOL "\x1b[32;1m"); \ printf(LOG_EOL "\x1b[32;1m"); \
uptime_print(); \ uptime_print(); \
printf(" [i] "fmt"\x1b[0m" LOG_EOL, ##__VA_ARGS__); \ printf(" [i] "fmt"\x1b[0m" LOG_EOL LOG_EOL, ##__VA_ARGS__); \
} while(0) } while(0)

@ -0,0 +1,6 @@
#ifndef FW_VERSION_H
#define FW_VERSION_H
#define FIRMWARE_VERSION "0.1.1"
#endif // FW_VERSION_H

@ -0,0 +1,35 @@
#include <esp8266.h>
#include <httpd.h>
#include "page_about.h"
#include "fw_version.h"
#include "sbmp.h"
/** "About" page */
int 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);
}
return HTTPD_CGI_DONE;
}

@ -0,0 +1,8 @@
#ifndef PAGE_ABOUT_H
#define PAGE_ABOUT_H
#include <httpd.h>
int tplAbout(HttpdConnData *connData, char *token, void **arg);
#endif // PAGE_ABOUT_H

@ -12,6 +12,7 @@
// user files // user files
#include "page_status.h" #include "page_status.h"
#include "page_waveform.h" #include "page_waveform.h"
#include "page_about.h"
#define WIFI_PROTECT 0 #define WIFI_PROTECT 0
@ -45,8 +46,13 @@ HttpdBuiltInUrl builtInUrls[] = {
ROUTE_TPL_FILE("/api/status.json", tplSystemStatus, "/json/status.tpl"), ROUTE_TPL_FILE("/api/status.json", tplSystemStatus, "/json/status.tpl"),
// About
ROUTE_TPL_FILE("/about", tplAbout, "/pages/about.tpl"),
// Waveform page // Waveform page
ROUTE_FILE("/waveform", "/pages/waveform.html"), // static file, html -> can use gzip ROUTE_FILE("/waveform", "/pages/wfm.html"), // static file, html -> can use gzip
// FFT
ROUTE_FILE("/fft", "/pages/fft.html"), // static file, html -> can use gzip
ROUTE_TPL_FILE("/api/raw.json", tplWaveformJSON, "/json/samples.tpl"), ROUTE_TPL_FILE("/api/raw.json", tplWaveformJSON, "/json/samples.tpl"),
ROUTE_TPL_FILE("/api/fft.json", tplFourierJSON, "/json/samples.tpl"), ROUTE_TPL_FILE("/api/fft.json", tplFourierJSON, "/json/samples.tpl"),

@ -21,6 +21,7 @@
#include "datalink.h" #include "datalink.h"
#include "uptime.h" #include "uptime.h"
#include "routes.h" #include "routes.h"
#include "fw_version.h"
extern HttpdBuiltInUrl builtInUrls[]; extern HttpdBuiltInUrl builtInUrls[];
@ -80,11 +81,14 @@ void user_init(void)
serialInit(); serialInit();
uptime_timer_init(); uptime_timer_init();
banner("*** ESP8266 starting ***"); banner("*** AC current analyser - WiFi module ***");
info("(c) Ondrej Hruska, 2016");
info("Katedra mereni FEL CVUT");
info("");
info("Version "FIRMWARE_VERSION", built "__DATE__" at "__TIME__);
info("HTTPD v."HTTPDVER", SBMP v."SBMP_VER", IoT SDK v."STR(ESP_SDK_VERSION)); info("HTTPD v."HTTPDVER", SBMP v."SBMP_VER", IoT SDK v."STR(ESP_SDK_VERSION));
printf(LOG_EOL); printf(LOG_EOL);
// reset button etc // reset button etc
ioInit(); ioInit();

Loading…
Cancel
Save