diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 7275ff4eab..969a1a0adb 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -102,7 +102,9 @@ "tabLogging": { "message": "Logging" }, - + "tabDataflash": { + "message": "Dataflash" + }, "tabAdjustments": { "message": "Adjustments" }, @@ -846,6 +848,45 @@ "message": "Automatically loaded previous log file: $1" }, + "dataflashNote": { + "message": "Blackbox flight logs can be recorded to your flight controller's onboard dataflash chip." + }, + "dataflashNotSupportedNote": { + "message": "Your flight controller does not have a compatible dataflash chip available." + }, + "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 31be24de8f..343a96583f 100755 --- a/js/data_storage.js +++ b/js/data_storage.js @@ -149,3 +149,10 @@ var MISC = { vbatmaxcellvoltage: 0, vbatwarningcellvoltage: 0 }; + +var DATAFLASH = { + ready: false, + sectors: 0, + totalSize: 0, + usedSize: 0 +}; diff --git a/js/gui.js b/js/gui.js index f6007a9b58..89fab7d761 100644 --- a/js/gui.js +++ b/js/gui.js @@ -25,6 +25,7 @@ var GUI_control = function () { 'gps', 'led_strip', 'logging', + 'dataflash', 'modes', 'motors', 'pid_tuning', diff --git a/js/msp.js b/js/msp.js index d772710e31..1fea8bb3e8 100644 --- a/js/msp.js +++ b/js/msp.js @@ -22,6 +22,9 @@ var MSP_codes = { MSP_SONAR: 58, MSP_PID_CONTROLLER: 59, MSP_SET_PID_CONTROLLER: 60, + MSP_DATAFLASH_SUMMARY: 70, + MSP_DATAFLASH_READ: 71, + MSP_DATAFLASH_ERASE: 72, // Multiwii MSP commands MSP_IDENT: 100, @@ -671,8 +674,26 @@ var MSP = { case MSP_codes.MSP_SET_LED_STRIP_CONFIG: console.log('Led strip config saved'); break; - - + case MSP_codes.MSP_DATAFLASH_SUMMARY: + if (data.byteLength >= 13) { + 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); + } else { + // Firmware version too old to support MSP_DATAFLASH_SUMMARY + DATAFLASH.ready = false; + DATAFLASH.sectors = 0; + DATAFLASH.totalSize = 0; + DATAFLASH.usedSize = 0; + } + break; + case MSP_codes.MSP_DATAFLASH_READ: + // No-op, let callback handle it + break; + case MSP_codes.MSP_DATAFLASH_ERASE: + console.log("Data flash erase begun..."); + break; case MSP_codes.MSP_SET_MODE_RANGE: console.log('Mode range saved'); break; @@ -798,6 +819,9 @@ var MSP = { } }; +/** + * Encode the request body for the MSP request with the given code and return it as an array of bytes. + */ MSP.crunch = function (code) { var buffer = []; @@ -959,6 +983,27 @@ MSP.crunch = function (code) { return buffer; }; +/** + * Send a request to read a block of data from the dataflash at the given address and pass that address and a dataview + * of the returned data to the given callback (or null for the data if an error occured). + */ +MSP.dataflashRead = function(address, onDataCallback) { + MSP.send_message(MSP_codes.MSP_DATAFLASH_READ, [address & 0xFF, (address >> 8) & 0xFF, (address >> 16) & 0xFF, (address >> 24) & 0xFF], + false, function(response) { + var chunkAddress = response.data.getUint32(0, 1); + + // Verify that the address of the memory returned matches what the caller asked for + if (chunkAddress == address) { + /* Strip that address off the front of the reply and deliver it separately so the caller doesn't have to + * figure out the reply format: + */ + onDataCallback(address, new DataView(response.data.buffer, response.data.byteOffset + 4, response.data.buffer.byteLength - 4)); + } else { + // Report error + onDataCallback(address, null); + } + }); +} ; MSP.sendModeRanges = function(onCompleteCallback) { var nextFunction = send_next_mode_range; 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/main.html b/main.html index 3ffd777881..432ef9c89e 100755 --- a/main.html +++ b/main.html @@ -23,6 +23,7 @@ + @@ -70,6 +71,7 @@ + @@ -148,6 +150,7 @@
  • +
  • diff --git a/main.js b/main.js index 374f4cdc24..fa3d54b656 100755 --- a/main.js +++ b/main.js @@ -153,6 +153,9 @@ $(document).ready(function () { case 'logging': TABS.logging.initialize(content_ready); break; + case 'dataflash': + TABS.dataflash.initialize(content_ready); + break; case 'cli': TABS.cli.initialize(content_ready); break; diff --git a/resources/motor_order/airplane.svg b/resources/motor_order/airplane.svg index 7a6a596aee..a97ea0f741 100644 --- a/resources/motor_order/airplane.svg +++ b/resources/motor_order/airplane.svg @@ -1,73 +1,73 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/atail_quad.svg b/resources/motor_order/atail_quad.svg index 74641eb83e..63b93848c7 100644 --- a/resources/motor_order/atail_quad.svg +++ b/resources/motor_order/atail_quad.svg @@ -1,44 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/bicopter.svg b/resources/motor_order/bicopter.svg index 95b2ca75f6..6d866dc7d2 100644 --- a/resources/motor_order/bicopter.svg +++ b/resources/motor_order/bicopter.svg @@ -1,52 +1,52 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/flying_wing.svg b/resources/motor_order/flying_wing.svg index 638f120d9a..4636539898 100644 --- a/resources/motor_order/flying_wing.svg +++ b/resources/motor_order/flying_wing.svg @@ -1,55 +1,55 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/hex_p.svg b/resources/motor_order/hex_p.svg index 03830b8dc6..eab82b7c83 100644 --- a/resources/motor_order/hex_p.svg +++ b/resources/motor_order/hex_p.svg @@ -1,58 +1,58 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/hex_x.svg b/resources/motor_order/hex_x.svg index ae28e35732..4e3a02d782 100644 --- a/resources/motor_order/hex_x.svg +++ b/resources/motor_order/hex_x.svg @@ -1,58 +1,58 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/octo_flat_p.svg b/resources/motor_order/octo_flat_p.svg index 7dc6460ecd..5b880729c6 100644 --- a/resources/motor_order/octo_flat_p.svg +++ b/resources/motor_order/octo_flat_p.svg @@ -1,72 +1,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/octo_flat_x.svg b/resources/motor_order/octo_flat_x.svg index 4031ab796d..9493a4b284 100644 --- a/resources/motor_order/octo_flat_x.svg +++ b/resources/motor_order/octo_flat_x.svg @@ -1,72 +1,72 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/octo_x8.svg b/resources/motor_order/octo_x8.svg index 236b3cf269..8e28d09573 100644 --- a/resources/motor_order/octo_x8.svg +++ b/resources/motor_order/octo_x8.svg @@ -1,76 +1,76 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/quad_p.svg b/resources/motor_order/quad_p.svg index 7424e1b359..25609e84ec 100644 --- a/resources/motor_order/quad_p.svg +++ b/resources/motor_order/quad_p.svg @@ -1,44 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/quad_x.svg b/resources/motor_order/quad_x.svg index de045e366d..7ae53a0bdc 100644 --- a/resources/motor_order/quad_x.svg +++ b/resources/motor_order/quad_x.svg @@ -1,44 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/tri.svg b/resources/motor_order/tri.svg index 8f30f934a5..5ff940c8f7 100644 --- a/resources/motor_order/tri.svg +++ b/resources/motor_order/tri.svg @@ -1,51 +1,51 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/vtail_quad.svg b/resources/motor_order/vtail_quad.svg index 654fa68695..6ec31ef664 100644 --- a/resources/motor_order/vtail_quad.svg +++ b/resources/motor_order/vtail_quad.svg @@ -1,44 +1,44 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/y4.svg b/resources/motor_order/y4.svg index 6edfcfa2ca..5f7a539fa2 100644 --- a/resources/motor_order/y4.svg +++ b/resources/motor_order/y4.svg @@ -1,45 +1,45 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/motor_order/y6.svg b/resources/motor_order/y6.svg index ef1ee8013d..b830dd46b4 100644 --- a/resources/motor_order/y6.svg +++ b/resources/motor_order/y6.svg @@ -1,61 +1,61 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tabs/dataflash.css b/tabs/dataflash.css new file mode 100644 index 0000000000..a6885d53a8 --- /dev/null +++ b/tabs/dataflash.css @@ -0,0 +1,192 @@ +.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; +} +.tab-dataflash .dataflash-info { + overflow:hidden; +} +.tab-dataflash .dataflash-info dt { + float: left; + width: 12em; + height: 20px; + line-height: 20px; + + font-weight: bold; +} +.tab-dataflash .dataflash-info dd { + display: block; + height: 20px; + line-height: 20px; +} +.tab-dataflash .speed { + margin-top: 5px; + width: 80px; + + border: 1px solid silver; +} +.tab-dataflash .info { + margin-top: 10px; +} +.tab-dataflash .info dt { + float: left; + width: 120px; + height: 20px; + line-height: 20px; + + font-weight: bold; +} +.tab-dataflash .info dd { + display: block; + margin-left: 130px; + height: 20px; + line-height: 20px; +} +.tab-dataflash .buttons { + width: calc(100% - 20px); + + position: absolute; + bottom: 10px; +} +.tab-dataflash .buttons a { + display: block; + float: right; + + margin-left: 10px; + + height: 28px; + line-height: 28px; + + padding: 0 15px 0 15px; + + text-align: center; + font-weight: bold; + + border: 1px solid silver; + background-color: #ececec; +} +.tab-dataflash .buttons a:hover { + background-color: #dedcdc; +} +.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; +} + +.require-dataflash { + display:none; +} +.tab-dataflash.supported .require-dataflash { + display:block; +} +.require-no-dataflash { + display:block; +} +.tab-dataflash.supported .require-no-dataflash { + display:none; +} \ No newline at end of file diff --git a/tabs/dataflash.html b/tabs/dataflash.html new file mode 100644 index 0000000000..a3a391a471 --- /dev/null +++ b/tabs/dataflash.html @@ -0,0 +1,66 @@ +
    +
    +
    +
    + + +

    +
    +
    + +
    +
    +

    Erase in progress, please wait...

    +
    +
    + +
    + + +
    +
    + + +

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

    Dataflash contents

    + + +
    + + +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/tabs/dataflash.js b/tabs/dataflash.js new file mode 100644 index 0000000000..90980c5c7e --- /dev/null +++ b/tabs/dataflash.js @@ -0,0 +1,240 @@ +'use strict'; + +TABS.dataflash = {}; +TABS.dataflash.initialize = function (callback) { + var + self = this, + saveCancelled, eraseCancelled; + + if (GUI.active_tab != 'dataflash') { + GUI.active_tab = 'dataflash'; + googleAnalytics.sendAppView('dataflash'); + } + + 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", function() { + create_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() { + var + supportsDataflash = DATAFLASH.totalSize > 0; + + // translate to user-selected language + localize(); + + $(".tab-dataflash").toggleClass("supported", supportsDataflash); + + if (supportsDataflash) { + // UI hooks + $('.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; + + while (value.length < width) { + value = "0" + value; + } + + return value; + } + + 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) { + nextAddress += chunkDataView.byteLength; + + $(".dataflash-saving progress").attr("value", nextAddress / maxBytes * 100); + + var + blob = new Blob([chunkDataView]); + + fileWriter.write(blob); + + if (saveCancelled || nextAddress >= maxBytes) { + if (saveCancelled) { + dismiss_saving_dialog(); + } else { + mark_saving_dialog_done(); + } + } else { + MSP.dataflashRead(nextAddress, onChunkRead); + } + } else { + mark_saving_dialog_done(); + } + } + + MSP.dataflashRead(nextAddress, onChunkRead); + }); + } + } + + function prepare_file(onComplete) { + var + date = new Date(), + filename = 'blackbox_log_' + date.getFullYear() + '-' + zeroPad(date.getMonth() + 1, 2) + '-' + + zeroPad(date.getDate(), 2) + '_' + zeroPad(date.getHours(), 2) + zeroPad(date.getMinutes(), 2) + + zeroPad(date.getSeconds(), 2); + + chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: filename, + accepts: [{extensions: ['TXT']}]}, function(fileEntry) { + if (!fileEntry) { + console.log('No file selected'); + return; + } + + // echo/console log path specified + chrome.fileSystem.getDisplayPath(fileEntry, function(path) { + console.log('Dataflash dump file path: ' + path); + }); + + fileEntry.createWriter(function (fileWriter) { + fileWriter.onerror = function (e) { + console.error(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); + }); + }); + } + + 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) { + if (callback) callback(); +}; \ No newline at end of file