diff --git a/FSBrowser.ino b/FSBrowser.ino index 53471ce..7ad7739 100644 --- a/FSBrowser.ino +++ b/FSBrowser.ino @@ -198,20 +198,25 @@ void handleFileList() { static void sendCommand(String cmd) { - Serial.print("\n"); - delay(1); - while(Serial.available()) - Serial.read(); //flush all previous output Serial.print(cmd); Serial.print("\n"); - Serial.readStringUntil('\n'); //consume echo + + char c; + uint32_t timeout = millis(); + do { + if(Serial.available() > 0) + c = Serial.read(); + } while (millis() - timeout < 256 && c != '\n'); } static void handleCommand() { - const int cmdBufSize = 128; if(!server.hasArg("cmd")) {server.send(500, "text/plain", "BAD ARGS"); return;} - String cmd = server.arg("cmd").substring(0, cmdBufSize); + //const int cmdBufSize = 128; + //String cmd = server.arg("cmd").substring(0, cmdBufSize); + + sendCommand(server.arg("cmd")); + int repeat = 0; char buffer[255]; size_t len = 0; @@ -219,22 +224,7 @@ static void handleCommand() { if (server.hasArg("repeat")) repeat = server.arg("repeat").toInt(); - - if (!fastUart && fastUartAvailable) - { - sendCommand("fastuart"); - if (Serial.readString().startsWith("OK")) - { - Serial.begin(921600); - fastUart = true; - } - else - { - fastUartAvailable = false; - } - } - - sendCommand(cmd); + do { memset(buffer,0,sizeof(buffer)); len = Serial.readBytes(buffer, sizeof(buffer) - 1); @@ -247,8 +237,8 @@ static void handleCommand() { Serial.readBytes(buffer, 1); //consume "!" } } while (len > 0); - server.sendHeader("Access-Control-Allow-Origin","*"); - server.send(200, "text/json", output); + //server.sendHeader("Access-Control-Allow-Origin","*"); + server.send(200, "text/plain", output); } static uint32_t crc32_word(uint32_t Crc, uint32_t Data) @@ -291,7 +281,10 @@ static void handleUpdate() if (step == -1) { int c; - sendCommand("reset"); + char b[128]; + + Serial.print("reset\n"); + Serial.readBytesUntil('t', b, sizeof(b) - 1); //echo -> reset if (fastUart) { @@ -299,6 +292,8 @@ static void handleUpdate() fastUart = false; fastUartAvailable = true; //retry after reboot } + Serial.setTimeout(1000); //default + do { c = Serial.read(); } while (c != 'S' && c != '2'); @@ -394,6 +389,10 @@ static void handleWifi() static void handleBaud() { + if (server.hasArg("timeout")) { + Serial.setTimeout(server.arg("timeout").toInt()); + } + if (fastUart) server.send(200, "text/html", "fastUart on"); else @@ -412,6 +411,24 @@ void setup(void){ Serial.setTimeout(100); SPIFFS.begin(); + Serial.print("\n"); + while(Serial.available()) + Serial.read(); //flush all previous output + + if (!fastUart && fastUartAvailable) + { + sendCommand("fastuart"); + if (Serial.readString().startsWith("OK")) + { + Serial.begin(921600); + fastUart = true; + } + else + { + fastUartAvailable = false; + } + } + //WIFI INIT #ifdef WIFI_IS_OFF_AT_BOOT enableWiFiAtBootTime(); @@ -587,8 +604,6 @@ void setup(void){ swd.debugHaltOnReset(0); swd.debugReset(); - server.sendContent(""); //end stream - } else { server.send(200, "text/plain", "SWD Error"); } @@ -603,7 +618,6 @@ void setup(void){ } else if (server.hasArg("flash")) { addr = 0x08001000; addrEnd = 0x0801ffff; - //addrEnd = 0x080011ff; //Quick Debug } else if (server.hasArg("ram")) { addr = 0x20000000; addrEnd = 0x200003ff; //Note: Read is limited to 0x200003ff but you can write to higher portion of RAM @@ -624,8 +638,6 @@ void setup(void){ addrNext += (addrCount * 4); //step = count * 4 bytes in int32 word } while (addrNext <= addrEnd); - server.sendContent(""); //end stream - } else { server.send(200, "text/plain", "SWD Error"); } @@ -665,8 +677,6 @@ void setup(void){ addrNext++; } while (addrNext <= addrEnd); - server.sendContent(""); //end stream - } else { server.send(200, "text/plain", "SWD Error"); } @@ -755,7 +765,6 @@ void setup(void){ fs.close(); SPIFFS.remove("/" + filename); - server.sendContent(""); //end stream digitalWrite(LED_BUILTIN, HIGH); //OFF } else { server.send(200, "text/plain", "File Error"); diff --git a/gauge.min.js.gz b/gauge.min.js.gz index a8753f0..c4b0e44 100644 Binary files a/gauge.min.js.gz and b/gauge.min.js.gz differ diff --git a/gauges.html b/gauges.html index c4736e3..6b6ed91 100644 --- a/gauges.html +++ b/gauges.html @@ -22,7 +22,7 @@ --> -
Use binary files (stm32_sine/foc.bin) for updating inverter firmware. Upload any other file for updating this web interface.
Use binary files (stm32_loader.bin, stm32_sine/foc.bin) for updating inverter bootloader/firmware.
+ +Scroll pages: Limit data points to: Burst length: +Chart delay (ms): +Auto scroll:
Copyright 2018 Johannes Huebner dev@johanneshuebner.com
Charting by chart.js
Gauges by Mykhailo Stadnyk
diff --git a/index.js b/index.js index 90fa3d8..1ff2a57 100644 --- a/index.js +++ b/index.js @@ -18,6 +18,7 @@ * */ var chart; +var chartPages = 0; var items = {}; var stop; var imgid = 0; @@ -37,9 +38,9 @@ function generateChart() chart = new Chart("canvas", { type: "line", options: { - animation: { - duration: 0 - }, + responsive: true, + maintainAspectRatio: false, + animation: false, scales: { 'y-axis-0': { type: "linear", @@ -50,7 +51,7 @@ function generateChart() type: "linear", display: true, position: "right", - gridLines: { drawOnChartArea: false } + grid: { drawOnChartArea: false } } } } }); @@ -64,7 +65,7 @@ function parameterSubmit() document.getElementById("loader0").style.visibility = "hidden"; document.getElementById("parameters_json").value = JSON.stringify(values); document.getElementById("paramdb").submit(); - }, true); + }, true, 0); } function checkSubscribedParameterSet() @@ -260,7 +261,7 @@ function updateTables() if (document.getElementById("autorefresh").checked) updateTables(); - }); + }, false, 0); } /** @brief Adds row to a table @@ -398,8 +399,30 @@ function showLog() window.open(req); } -function fileSelected() +/** @brief export chart as image */ +function exportChartImage() { + var render = chart.canvas.toDataURL('image/png', 1.0); + var d = new Date(); + + var data = atob(render.substring('data:image/png;base64,'.length)), + asArray = new Uint8Array(data.length); + + for (var i = 0, len = data.length; i < len; ++i) { + asArray[i] = data.charCodeAt(i); + } + var blob = new Blob([asArray.buffer], { type: 'image/png' }); + + var url = URL.createObjectURL(blob); + var a = document.createElement('a'); + a.href = url; + a.download = 'chart ' + d.getDate() + '-' + (d.getMonth() + 1) + '-' + d.getFullYear() + ' ' + (d.getHours() % 12 || 12) + '-' + d.getMinutes() + ' ' + (d.getHours() >= 12 ? 'pm' : 'am') + '.png'; + document.body.appendChild(a); + a.click(); + setTimeout(function () { + document.body.removeChild(a); + window.URL.revokeObjectURL(url); + }, 0); } /** @brief uploads file to web server, if bin-file uploaded, starts a firmware upgrade */ @@ -467,7 +490,6 @@ function uploadSWDFile() var xhr = new XMLHttpRequest(); xhr.seenBytes = 0; xhr.seenTotalPages = 0; - xhr.onreadystatechange = function() { if(xhr.readyState == 3) { var data = xhr.response.substr(xhr.seenBytes); @@ -508,11 +530,11 @@ function uploadSWDFile() function runUpdate(step,file) { var xmlhttp=new XMLHttpRequest(); - xmlhttp.onload = function() + xmlhttp.responseType = "json"; + xmlhttp.onload = function() { step++; - var result = JSON.parse(this.responseText); - var totalPages = result.pages; + var totalPages = this.response.pages; var progress = Math.round(100 * step / totalPages); document.getElementById("bar").style.width = progress + "%"; document.getElementById("bar").innerHTML = "" + progress + "%
"; @@ -531,27 +553,45 @@ function startPlot() items = getPlotItems(); var colours = [ 'rgb(255, 99, 132)', 'rgb(54, 162, 235)', 'rgb(255, 159, 64)', 'rgb(153, 102, 255)', 'rgb(255, 205, 86)', 'rgb(75, 192, 192)' ]; + chart.config.data.labels = new Array(); chart.config.data.datasets = new Array(); for (var signalIdx = 0; signalIdx < items.names.length; signalIdx++) { + var yAxisKey = items.names[signalIdx]; var newDataset = { label: items.names[signalIdx], data: [], borderColor: colours[signalIdx % colours.length], backgroundColor: colours[signalIdx % colours.length], - fill: false, pointRadius: 0, - yAxisID: items.axes[signalIdx] + yAxisID: items.axes[signalIdx], + normalized: true }; chart.config.data.datasets.push(newDataset); } - - time = 0; + chart.update(); stop = false; document.getElementById("pauseButton").disabled = false; - acquire(); + + //Scroll Chart Reset + var chartArea = document.getElementById("chartArea"); + var chartAreaWrapper = document.getElementById("chartAreaWrapper"); + chartArea.style.width = chartAreaWrapper.clientWidth + "px"; + + var chartDelay = document.getElementById('chartDelay').value; + serialTimeout(chartDelay); + + if (items.names.length) acquire(); +} + +/** @brief changes Serial.setTimeout() in esp8266 */ +function serialTimeout(value) +{ + var xmlhttp = new XMLHttpRequest(); + xmlhttp.open("GET", "/baud?timeout=" + (value / 2), true); + xmlhttp.send(); } /** @brief Stop plotting */ @@ -578,35 +618,59 @@ function pauseResumePlot() } } +/** @brief chart stream results, loop needs to be as efficient as possible */ function acquire() { if (stop) return; - if (!items.names.length) return; - var burstLength = document.getElementById('burstLength').value; - var maxValues = document.getElementById('maxValues').value; + + burstLength = document.getElementById('burstLength').value; + maxPages = document.getElementById('maxPages').value; + maxValues = document.getElementById('maxValues').value; + autoScroll = document.getElementById('autoScroll').checked; inverter.getValues(items.names, burstLength, - function(values) + function(values) { - for (var i = 0; i < burstLength; i++) + var d = new Date(); + chart.config.data.labels.push(d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds()); + for (var i = 1; i < burstLength; i++) { - chart.config.data.labels.push(time); - time++; + chart.config.data.labels.push(""); } - chart.config.data.labels.splice(0, Math.max(chart.config.data.labels.length - maxValues, 0)); + var count = 0; for (var name in values) { var data = chart.config.data.datasets.find(function(element) { return element.label == name }).data; - + for (var i = 0; i < values[name].length; i++) { - data.push(values[name][i]) - data.splice(0, Math.max(data.length - maxValues, 0)); + data.push(values[name][i]); } + count++; } chart.update(); + + //Scroll Chart + var dataPoints = String(chart.config.data.labels.length / maxValues)[0]; + if(chartPages != dataPoints) + { + chartPages = dataPoints; + //console.log(chartPages); + var chartArea = document.getElementById("chartArea"); + var chartAreaWrapper = document.getElementById("chartAreaWrapper"); + var chartAreaWidth = chartAreaWrapper.clientWidth + chart.width; + chartArea.style.width = chartAreaWidth + "px"; + if(autoScroll) + chartAreaWrapper.scrollLeft = chartAreaWidth; + + if(chartPages >= maxPages) { + data.splice(0, maxValues); + chart.config.data.labels.splice(0, maxValues); + chartPages--; + } + } acquire(); }); } diff --git a/inverter.js b/inverter.js index 3809956..fa908b5 100644 --- a/inverter.js +++ b/inverter.js @@ -38,10 +38,11 @@ var inverter = { xmlhttp.send(); }, - getParamList: function(replyFunc, includeHidden) + getParamList: function(replyFunc, includeHidden, loop) { var cmd = includeHidden ? "json hidden" : "json"; + if(loop < 3) { //at maximum speed json can get corrupted, try a few times inverter.sendCmd(cmd, function(reply) { var params = {}; try { @@ -55,9 +56,10 @@ var inverter = { if (name == "version") inverter.firmwareVersion = parseFloat(param.value); } - } catch(ex) {} + } catch(ex) { inverter.getParamList(replyFunc, includeHidden, loop+1) } if (replyFunc) replyFunc(params); }); + } }, getValues: function(items, repeat, replyFunc) diff --git a/log.html b/log.html index 84be475..01ba40e 100644 --- a/log.html +++ b/log.html @@ -22,7 +22,7 @@ --> -