From 49741b45a83ec54c06f0f9af8f44fba87b779c77 Mon Sep 17 00:00:00 2001 From: Nicholas Sherlock Date: Fri, 13 Feb 2015 21:05:36 +1300 Subject: [PATCH] Add progress dialogs for flash save and erase --- _locales/en/messages.json | 31 ++++++- js/data_storage.js | 4 +- js/msp.js | 8 +- main.css | 11 +++ tabs/dataflash.css | 108 ++++++++++++++++++++- tabs/dataflash.html | 67 +++++++++++-- tabs/dataflash.js | 191 +++++++++++++++++++++++++++++--------- 7 files changed, 357 insertions(+), 63 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 7efa5fbd87..364d4e4485 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -845,13 +845,42 @@ "message": "Automatically loaded previous log file: $1" }, + "dataflashNote": { + "message": "Blackbox flight logs can be stored on the onboard dataflash chip if your flight controller supports one." + }, "dataflashButtonSaveFile": { "message": "Save flash to file..." }, "dataflashButtonErase": { "message": "Erase flash" }, - + "dataflashConfirmEraseTitle": { + "message": "Confirm dataflash erase" + }, + "dataflashConfirmEraseNote": { + "message": "This will erase any Blackbox logs or other data contained in the dataflash which will take about 20 seconds, are you sure?" + }, + "dataflashSavingTitle": { + "message": "Saving dataflash to file" + }, + "dataflashSavingNote": { + "message": "Saving could take several minutes, please wait." + }, + "dataflashSavingNoteAfter": { + "message": "Save completed! Press \"Ok\" to continue." + }, + "dataflashButtonSaveCancel": { + "message": "Cancel" + }, + "dataflashButtonSaveDismiss": { + "message": "Ok" + }, + "dataflashButtonEraseConfirm": { + "message": "Yes, erase dataflash" + }, + "dataflashButtonEraseCancel": { + "message": "Cancel" + }, "firmwareFlasherReleaseSummaryHead": { "message": "Release info" }, diff --git a/js/data_storage.js b/js/data_storage.js index 1c4e1fbb66..9e397de8c9 100755 --- a/js/data_storage.js +++ b/js/data_storage.js @@ -151,6 +151,8 @@ var MISC = { }; var DATAFLASH = { + ready: false, sectors: 0, - totalSize: 0 + totalSize: 0, + usedSize: 0 }; \ No newline at end of file diff --git a/js/msp.js b/js/msp.js index bb03ecd55c..466266d165 100644 --- a/js/msp.js +++ b/js/msp.js @@ -670,14 +670,16 @@ var MSP = { console.log('Led strip config saved'); break; case MSP_codes.MSP_DATAFLASH_SUMMARY: - DATAFLASH.sectors = data.getUint32(0, 1); - DATAFLASH.totalSize = data.getUint32(4, 1); + DATAFLASH.ready = (data.getUint8(0) & 1) != 0; + DATAFLASH.sectors = data.getUint32(1, 1); + DATAFLASH.totalSize = data.getUint32(5, 1); + DATAFLASH.usedSize = data.getUint32(9, 1); break; case MSP_codes.MSP_DATAFLASH_READ: // No-op, let callback handle it break; case MSP_codes.MSP_DATAFLASH_ERASE: - console.log("Data flash erased"); + console.log("Data flash erase begun..."); break; case MSP_codes.MSP_SET_MODE_RANGE: console.log('Mode range saved'); diff --git a/main.css b/main.css index cc8918d537..c066167726 100755 --- a/main.css +++ b/main.css @@ -353,3 +353,14 @@ input[type="number"]::-webkit-inner-spin-button { text-align: center; font-weight: bold; } + +dialog { + background-color: white; + padding: 1em; + height: auto; + margin: auto auto; + position: absolute; + width: 50%; + border-radius: 5px; + border: 1px solid silver; +} \ No newline at end of file diff --git a/tabs/dataflash.css b/tabs/dataflash.css index 669151b817..50404d5baf 100644 --- a/tabs/dataflash.css +++ b/tabs/dataflash.css @@ -1,12 +1,28 @@ -.tab-dataflash { -} -.tab-dataflash .dataflash-info dd{ - +.tab-dataflash .info { + margin: 0 0 10px 0; + position: relative; } +.tab-dataflash .info .progressLabel { + position: absolute; + width: 100%; + height: 26px; + + top: 0; + left: 0; + + text-align: center; + line-height: 24px; + + color: white; + font-weight: bold; + + /* text-shadow: 1px 0px 2px rgba(0, 0, 0, 0.9);*/ +} .tab-dataflash .note { padding: 5px; border: 1px dashed silver; + margin-bottom: 8px; } .tab-dataflash .properties { margin-top: 10px; @@ -76,6 +92,88 @@ .tab-dataflash .buttons a:hover { background-color: #dedcdc; } -.tab-dataflash .buttons .back { +.tab-dataflash .buttons a.disabled { + cursor: default; + color: #999; + pointer-events: none; +} +.tab-dataflash .dataflash-progress { display: none; +} +.tab-dataflash .dataflash-contents { + margin:9px 16px; + + border:1px solid silver; + background-color:#eee; + + display:flex; + flex-direction:row; + flex-wrap:nowrap; + justify-content:flex-start; + + border-radius:6px; +} +.tab-dataflash .dataflash-contents li { + height:26px; + position:relative; +} +.tab-dataflash .dataflash-contents li div { + position:absolute; + top:26px; + margin-top:4px; + text-align:center; + left: 0; + right: 0; +} +.tab-dataflash .dataflash-used { + background-color:#bcf; +} +.tab-dataflash progress::-webkit-progress-bar { + height:24px; + background-color:#eee; +} +.tab-dataflash progress::-webkit-progress-value { + background-color:#bcf; +} + +.tab-dataflash dialog { + width:40em; +} +.tab-dataflash dialog .buttons { + position:static; + margin-top: 2em; + overflow: hidden; + width:auto; +} +.tab-dataflash dialog h3 { + margin-bottom: 0.5em; +} + +.dataflash-confirm-erase .dataflash-erase-progress { + height:125px; + display:none; +} +.dataflash-confirm-erase.erasing .dataflash-erase-progress { + display:block; +} +.dataflash-confirm-erase.erasing h3, +.dataflash-confirm-erase.erasing .erase-flash-confirm, +.dataflash-confirm-erase.erasing .dataflash-confirm-erase-note { + display:none; +} + +.tab-dataflash progress { + display:block; + width:100%; + margin:1em 0; +} + +.dataflash-saving .dataflash-saving-after { + display:none; +} +.dataflash-saving.done .dataflash-saving-before { + display:none; +} +.dataflash-saving.done .dataflash-saving-after { + display:block; } \ No newline at end of file diff --git a/tabs/dataflash.html b/tabs/dataflash.html index 8b22737104..484372cadc 100644 --- a/tabs/dataflash.html +++ b/tabs/dataflash.html @@ -1,14 +1,63 @@
-

Dataflash

-
-
Capacity (bytes)
-
-
Capacity (sectors)
-
-
+
+
+ + +

+
+
+ +
+
+

Erase in progress, please wait...

+
+
+ +
+ + +
+
+ + +

+
+
+
+ + + +
+ +
+
+
+
+
+ +
+ +
+
+
+ +

Dataflash contents

+ +
- - + +
\ No newline at end of file diff --git a/tabs/dataflash.js b/tabs/dataflash.js index 38d846d320..e2460385fb 100644 --- a/tabs/dataflash.js +++ b/tabs/dataflash.js @@ -2,39 +2,93 @@ TABS.dataflash = {}; TABS.dataflash.initialize = function (callback) { - var self = this; + var + self = this, + saveCancelled, eraseCancelled; if (GUI.active_tab != 'dataflash') { GUI.active_tab = 'dataflash'; googleAnalytics.sendAppView('dataflash'); } - var requested_properties = [], + var + requested_properties = [], samples = 0, requests = 0, log_buffer = []; if (CONFIGURATOR.connectionValid) { MSP.send_message(MSP_codes.MSP_DATAFLASH_SUMMARY, false, false, function() { - $('#content').load("./tabs/dataflash.html", process_html); + $('#content').load("./tabs/dataflash.html", function() { + create_html(); + }); }); } - function process_html() { + function formatFilesize(bytes) { + if (bytes < 1024) { + return bytes + "B"; + } + + var kilobytes = bytes / 1024; + + if (kilobytes < 1024) { + return Math.round(kilobytes) + "kB"; + } + + var megabytes = kilobytes / 1024; + + return megabytes.toFixed(1) + "MB"; + } + + function update_html() { + if (DATAFLASH.usedSize > 0) { + $(".tab-dataflash .dataflash-used").css({ + width: (DATAFLASH.usedSize / DATAFLASH.totalSize * 100) + "%", + display: 'block' + }); + + $(".tab-dataflash .dataflash-used div").text('Used space ' + formatFilesize(DATAFLASH.usedSize)); + } else { + $(".tab-dataflash .dataflash-used").css({ + display: 'none' + }); + } + + if (DATAFLASH.totalSize - DATAFLASH.usedSize > 0) { + $(".tab-dataflash .dataflash-free").css({ + width: ((DATAFLASH.totalSize - DATAFLASH.usedSize) / DATAFLASH.totalSize * 100) + "%", + display: 'block' + }); + $(".tab-dataflash .dataflash-free div").text('Free space ' + formatFilesize(DATAFLASH.totalSize - DATAFLASH.usedSize)); + } else { + $(".tab-dataflash .dataflash-free").css({ + display: 'none' + }); + } + + $(".tab-dataflash a.erase-flash, .tab-dataflash a.save-flash").toggleClass("disabled", DATAFLASH.usedSize == 0); + } + + function create_html() { // translate to user-selected language localize(); - $(".tab-dataflash .dataflash-capacity").text(DATAFLASH.totalSize); - $(".tab-dataflash .dataflash-sectors").text(DATAFLASH.sectors); - // UI hooks - $('.tab-dataflash a.erase_flash').click(erase_flash); - - $('.tab-dataflash a.save_to_file').click(stream_flash_to_file); + $('.tab-dataflash a.erase-flash').click(ask_to_erase_flash); + + $('.tab-dataflash a.erase-flash-confirm').click(flash_erase); + $('.tab-dataflash a.erase-flash-cancel').click(flash_erase_cancel); + $('.tab-dataflash a.save-flash').click(flash_save_begin); + $('.tab-dataflash a.save-flash-cancel').click(flash_save_cancel); + $('.tab-dataflash a.save-flash-dismiss').click(dismiss_saving_dialog); + + update_html(); + if (callback) callback(); } - + // IO related methods function zeroPad(value, width) { value = "" + value; @@ -46,21 +100,60 @@ TABS.dataflash.initialize = function (callback) { return value; } - function stream_flash_to_file() { + function flash_save_cancel() { + saveCancelled = true; + } + + function show_saving_dialog() { + $(".dataflash-saving progress").attr("value", 0); + saveCancelled = false; + $(".dataflash-saving").removeClass("done"); + + $(".dataflash-saving")[0].showModal(); + } + + function dismiss_saving_dialog() { + $(".dataflash-saving")[0].close(); + } + + function mark_saving_dialog_done() { + $(".dataflash-saving").addClass("done"); + } + + function flash_save_begin() { + var + maxBytes = DATAFLASH.usedSize; + if (GUI.connected_to) { prepare_file(function(fileWriter) { var nextAddress = 0; + show_saving_dialog(); + function onChunkRead(chunkAddress, chunkDataView) { // If we didn't get a zero-byte chunk (indicating end-of-file), request more if (chunkDataView.byteLength > 0) { - var blob = new Blob([chunkDataView]); + nextAddress += chunkDataView.byteLength; + + $(".dataflash-saving progress").attr("value", nextAddress / maxBytes * 100); + + var + blob = new Blob([chunkDataView]); fileWriter.write(blob); - - nextAddress += chunkDataView.byteLength; - MSP.dataflashRead(nextAddress, onChunkRead); + + if (saveCancelled || nextAddress >= maxBytes) { + if (saveCancelled) { + dismiss_saving_dialog(); + } else { + mark_saving_dialog_done(); + } + } else { + MSP.dataflashRead(nextAddress, onChunkRead); + } + } else { + mark_saving_dialog_done(); } } @@ -88,41 +181,51 @@ TABS.dataflash.initialize = function (callback) { console.log('Dataflash dump file path: ' + path); }); - prepare_writer(fileEntry, onComplete); - }); - } + fileEntry.createWriter(function (fileWriter) { + fileWriter.onerror = function (e) { + console.error(e); - function prepare_writer(fileEntry, onComplete) { - fileEntry.createWriter(function (fileWriter) { - fileWriter.onerror = function (e) { + // stop logging if the procedure was/is still running + }; + + onComplete(fileWriter); + }, function (e) { + // File is not readable or does not exist! console.error(e); - - // stop logging if the procedure was/is still running - }; - - fileWriter.onwriteend = function () { - }; - - onComplete(fileWriter); - }, function (e) { - // File is not readable or does not exist! - console.error(e); + }); }); } - function erase_flash() { - /* var dialog = $("lol"); - - $("body").append(dialog); - - dialog[0].showModal(); - - TODO modal dialog to confirm erase */ - - MSP.send_message(MSP_codes.MSP_DATAFLASH_ERASE, false, false, function(data) { - + function ask_to_erase_flash() { + eraseCancelled = false; + $(".dataflash-confirm-erase").removeClass('erasing'); + + $(".dataflash-confirm-erase")[0].showModal(); + } + + function poll_for_erase_completion() { + MSP.send_message(MSP_codes.MSP_DATAFLASH_SUMMARY, false, false, function() { + update_html(); + if (!eraseCancelled) { + if (DATAFLASH.ready) { + $(".dataflash-confirm-erase")[0].close(); + } else { + setTimeout(poll_for_erase_completion, 500); + } + } }); } + + function flash_erase() { + $(".dataflash-confirm-erase").addClass('erasing'); + + MSP.send_message(MSP_codes.MSP_DATAFLASH_ERASE, false, false, poll_for_erase_completion); + } + + function flash_erase_cancel() { + eraseCancelled = true; + $(".dataflash-confirm-erase")[0].close(); + } }; TABS.dataflash.cleanup = function (callback) {