Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/iNavFlight/inav-configurator.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Sherlock <n.sherlock@gmail.com>2015-11-30 10:36:47 +0300
committerNicholas Sherlock <n.sherlock@gmail.com>2015-12-04 05:49:51 +0300
commit4e12db9c5e9c89f086e35ad6c929ff933aeef530 (patch)
treeb693382436a062046c2e510306a27167cbd0ed33
parentb0d0f40c41c9ced19b2738208778f2376f8cc0be (diff)
Convert dataflash tab to a new Blackbox tab with SD card support
-rwxr-xr-x_locales/en/messages.json30
-rw-r--r--images/icons/cf_icon_sdcard.svg83
-rwxr-xr-xjs/data_storage.js16
-rw-r--r--js/gui.js2
-rw-r--r--js/msp.js47
-rwxr-xr-xmain.html12
-rw-r--r--main.js4
-rw-r--r--tabs/dataflash.css221
-rw-r--r--tabs/dataflash.html66
-rw-r--r--tabs/dataflash.js288
-rw-r--r--tabs/onboard_logging.css298
-rw-r--r--tabs/onboard_logging.html141
-rw-r--r--tabs/onboard_logging.js470
13 files changed, 1088 insertions, 590 deletions
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index ff0b4b1e..77a03a0b 100755
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -103,10 +103,10 @@
"message": "CLI"
},
"tabLogging": {
- "message": "Logging"
+ "message": "Tethered Logging"
},
- "tabDataflash": {
- "message": "Dataflash"
+ "tabOnboardLogging": {
+ "message": "Blackbox"
},
"tabAdjustments": {
"message": "Adjustments"
@@ -988,10 +988,30 @@
"message": "Automatically loaded previous log file: <strong>$1</strong>"
},
+ "blackboxNotSupported": {
+ "message": "Your flight controller's firmware does not support Blackbox logging."
+ },
+ "blackboxMaybeSupported": {
+ "message": "Your flight controller's firmware is too old to support this tab, or the Blackbox feature is disabled on the Configuration tab."
+ },
+ "blackboxConfiguration": {
+ "message": "Blackbox configuration"
+ },
+ "blackboxButtonSave": {
+ "message": "Save and reboot"
+ },
+
+ "serialLoggingSupportedNote": {
+ "message": "You can log to an external logging device (such as an OpenLog or compatible clone) by using a serial port. Configure the port on the Ports tab."
+ },
+ "sdcardNote": {
+ "message": "Flight logs can be recorded to your flight controller's onboard SD card slot."
+ },
+
"dataflashNote": {
- "message": "Blackbox flight logs can be recorded to your flight controller's onboard dataflash chip."
+ "message": "Flight logs can be recorded to your flight controller's onboard dataflash chip."
},
- "dataflashNotSupportedNote": {
+ "dataflashNotPresentNote": {
"message": "Your flight controller does not have a compatible dataflash chip available."
},
"dataflashFirmwareUpgradeRequired": {
diff --git a/images/icons/cf_icon_sdcard.svg b/images/icons/cf_icon_sdcard.svg
new file mode 100644
index 00000000..c429edd8
--- /dev/null
+++ b/images/icons/cf_icon_sdcard.svg
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="81.504448mm"
+ height="109.72666mm"
+ viewBox="0 0 288.79529 388.79528"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="cf_icon_sdcard.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#9e9e9e"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.979899"
+ inkscape:cx="62.562956"
+ inkscape:cy="45.52524"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer2"
+ showgrid="true"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ fit-margin-top="1.1"
+ fit-margin-left="1.1"
+ fit-margin-right="1.1"
+ fit-margin-bottom="1.1"
+ inkscape:window-width="1920"
+ inkscape:window-height="1076"
+ inkscape:window-x="0"
+ inkscape:window-y="0"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ type="xygrid"
+ id="grid3336"
+ originx="-168.45952"
+ originy="-373.45953" />
+ <sodipodi:guide
+ position="241.54049,446.54052"
+ orientation="0,1"
+ id="guide3343" />
+ </sodipodi:namedview>
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-168.45951,-290.10742)" />
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="Layer 2"
+ transform="translate(-168.45951,-290.10742)">
+ <path
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 172.85715,294.50506 240,0 40,50 0,330 -280,0 0,-230 10,0 0,-50 -10,0 z"
+ id="path3341"
+ inkscape:connector-curvature="0" />
+ </g>
+</svg>
diff --git a/js/data_storage.js b/js/data_storage.js
index 2d75ed18..b3a7f821 100755
--- a/js/data_storage.js
+++ b/js/data_storage.js
@@ -174,7 +174,23 @@ var _3D = {
var DATAFLASH = {
ready: false,
+ supported: false,
sectors: 0,
totalSize: 0,
usedSize: 0
};
+
+var SDCARD = {
+ supported: false,
+ state: 0,
+ filesystemLastError: 0,
+ freeSizeKB: 0,
+ totalSizeKB: 0,
+};
+
+var BLACKBOX = {
+ supported: false,
+ blackboxDevice: 0,
+ blackboxRateNum: 1,
+ blackboxRateDenom: 1
+};
diff --git a/js/gui.js b/js/gui.js
index 466b35a1..b3b955d2 100644
--- a/js/gui.js
+++ b/js/gui.js
@@ -25,7 +25,7 @@ var GUI_control = function () {
'gps',
'led_strip',
'logging',
- 'dataflash',
+ 'onboard_logging',
'modes',
'motors',
'pid_tuning',
diff --git a/js/msp.js b/js/msp.js
index cfde7dc0..5c42ffed 100644
--- a/js/msp.js
+++ b/js/msp.js
@@ -29,6 +29,10 @@ var MSP_codes = {
MSP_DATAFLASH_ERASE: 72,
MSP_LOOP_TIME: 73,
MSP_SET_LOOP_TIME: 74,
+
+ MSP_SDCARD_SUMMARY: 79,
+ MSP_BLACKBOX_CONFIG: 80,
+ MSP_SET_BLACKBOX_CONFIG: 81,
// Multiwii MSP commands
MSP_IDENT: 100,
@@ -811,13 +815,17 @@ var MSP = {
break;
case MSP_codes.MSP_DATAFLASH_SUMMARY:
if (data.byteLength >= 13) {
- DATAFLASH.ready = (data.getUint8(0) & 1) != 0;
+ var
+ flags = data.getUint8(0);
+ DATAFLASH.ready = (flags & 1) != 0;
+ DATAFLASH.supported = (flags & 2) != 0 || DATAFLASH.ready;
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.supported = false;
DATAFLASH.sectors = 0;
DATAFLASH.totalSize = 0;
DATAFLASH.usedSize = 0;
@@ -829,6 +837,24 @@ var MSP = {
case MSP_codes.MSP_DATAFLASH_ERASE:
console.log("Data flash erase begun...");
break;
+ case MSP_codes.MSP_SDCARD_SUMMARY:
+ var flags = data.getUint8(0);
+
+ SDCARD.supported = (flags & 0x01) != 0;
+ SDCARD.state = data.getUint8(1);
+ SDCARD.filesystemLastError = data.getUint8(2);
+ SDCARD.freeSizeKB = data.getUint32(3, 1);
+ SDCARD.totalSizeKB = data.getUint32(7, 1);
+ break;
+ case MSP_codes.MSP_BLACKBOX_CONFIG:
+ BLACKBOX.supported = (data.getUint8(0) & 1) != 0;
+ BLACKBOX.blackboxDevice = data.getUint8(1);
+ BLACKBOX.blackboxRateNum = data.getUint8(2);
+ BLACKBOX.blackboxRateDenom = data.getUint8(3);
+ break;
+ case MSP_codes.MSP_SET_BLACKBOX_CONFIG:
+ console.log("Blackbox config saved");
+ break;
case MSP_codes.MSP_SET_MODE_RANGE:
console.log('Mode range saved');
break;
@@ -1176,6 +1202,19 @@ MSP.setRawRx = function(channels) {
MSP.send_message(MSP_codes.MSP_SET_RAW_RC, buffer, false);
}
+MSP.sendBlackboxConfiguration = function(onDataCallback) {
+ var
+ message = [
+ BLACKBOX.blackboxDevice & 0xFF,
+ BLACKBOX.blackboxRateNum & 0xFF,
+ BLACKBOX.blackboxRateDenom & 0xFF
+ ];
+
+ MSP.send_message(MSP_codes.MSP_SET_BLACKBOX_CONFIG, message, false, function(response) {
+ onDataCallback();
+ });
+}
+
/**
* 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).
@@ -1438,3 +1477,9 @@ MSP.serialPortFunctionsToMask = function(functions) {
}
return mask;
}
+
+MSP.SDCARD_STATE_NOT_PRESENT = 0;
+MSP.SDCARD_STATE_FATAL = 1;
+MSP.SDCARD_STATE_CARD_INIT = 2;
+MSP.SDCARD_STATE_FS_INIT = 3;
+MSP.SDCARD_STATE_READY = 4;
diff --git a/main.html b/main.html
index 88320b86..e1136e5b 100755
--- a/main.html
+++ b/main.html
@@ -1,4 +1,4 @@
-<!DOCTYPE html>
+<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
@@ -21,7 +21,7 @@
<link type="text/css" rel="stylesheet" href="./tabs/sensors.css" media="all" />
<link type="text/css" rel="stylesheet" href="./tabs/cli.css" media="all" />
<link type="text/css" rel="stylesheet" href="./tabs/logging.css" media="all" />
-<link type="text/css" rel="stylesheet" href="./tabs/dataflash.css" media="all" />
+<link type="text/css" rel="stylesheet" href="./tabs/onboard_logging.css" media="all" />
<link type="text/css" rel="stylesheet" href="./tabs/firmware_flasher.css" media="all" />
<link type="text/css" rel="stylesheet" href="./tabs/adjustments.css" media="all" />
<link type="text/css" rel="stylesheet" href="./tabs/auxiliary.css" media="all" />
@@ -73,7 +73,7 @@
<script type="text/javascript" src="./tabs/sensors.js"></script>
<script type="text/javascript" src="./tabs/cli.js"></script>
<script type="text/javascript" src="./tabs/logging.js"></script>
-<script type="text/javascript" src="./tabs/dataflash.js"></script>
+<script type="text/javascript" src="./tabs/onboard_logging.js"></script>
<script type="text/javascript" src="./tabs/firmware_flasher.js"></script>
<title></title>
</head>
@@ -188,9 +188,9 @@
title="LED Strip"></a></li>
<li class="tab_sensors"><a href="#" i18n="tabRawSensorData" class="tabicon ic_sensors"
title="Sensors"></a></li>
- <li class="tab_logging"><a href="#" i18n="tabLogging" class="tabicon ic_log" title="Logging"></a></li>
- <li class="tab_dataflash"><a href="#" i18n="tabDataflash" class="tabicon ic_data"
- title="Dataflash"></a></li>
+ <li class="tab_logging"><a href="#" i18n="tabLogging" class="tabicon ic_log" title="Tethered Logging"></a></li>
+ <li class="tab_onboard_logging"><a href="#" i18n="tabOnboardLogging" class="tabicon ic_data"
+ title="Onboard Logging"></a></li>
<li class="tab_cli"><a href="#" i18n="tabCLI" class="tabicon ic_cli" title="CLI"></a></li>
<!-- spare icons
<li class=""><a href="#"class="tabicon ic_mission">Mission (spare icon)</a></li>
diff --git a/main.js b/main.js
index 29613a01..970298de 100644
--- a/main.js
+++ b/main.js
@@ -157,8 +157,8 @@ $(document).ready(function () {
case 'logging':
TABS.logging.initialize(content_ready);
break;
- case 'dataflash':
- TABS.dataflash.initialize(content_ready);
+ case 'onboard_logging':
+ TABS.onboard_logging.initialize(content_ready);
break;
case 'cli':
TABS.cli.initialize(content_ready);
diff --git a/tabs/dataflash.css b/tabs/dataflash.css
deleted file mode 100644
index 01ebdb04..00000000
--- a/tabs/dataflash.css
+++ /dev/null
@@ -1,221 +0,0 @@
-.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 .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 .dataflash-progress {
- display: none;
-}
-
-.tab-dataflash .dataflash-contents {
- margin-top: 5px;
- 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;
- box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.20);
- border-radius: 4px;
-}
-
-.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: #59AA29;
- border-radius: 4px;
-}
-
-.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;
- border-radius: 5px;
-}
-
-.tab-dataflash dialog .buttons {
- position: static;
- margin-top: 2em;
- float: left;
-}
-
-.tab-dataflash .buttons a {
- margin-top: 9px;
- margin-bottom: 0px;
- margin-right: 10px;
- background-color: #59aa29;
- border-radius: 3px;
- border: 1px solid #4c8829;
- color: #fff;
- float: left;
- font-family: 'open_sansbold', Arial;
- font-size: 12px;
- text-shadow: 0px 1px rgba(0, 0, 0, 0.25);
- display: block;
- cursor: pointer;
- transition: all ease 0.2s;
- padding: 0px;
- padding-left: 9px;
- padding-right: 9px;
- line-height: 28px;
-}
-
-.tab-dataflash .buttons a:hover {
- background-color: #6ac435;
- border: 1px solid #4d9324;
- text-shadow: 0px 1px rgba(0, 0, 0, 0.25);
- color: #fff;
- transition: all ease 0.2s;
-}
-
-.tab-dataflash .buttons a:active {
- background-color: #4d9324;
- transition: all ease 0.0s;
- box-shadow: inset 0px 1px 5px rgba(0, 0, 0, 0.35);
-}
-
-.tab-dataflash dialog h3 {
- margin-bottom: 0.5em;
-}
-
-.dataflash-confirm-erase .dataflash-erase-progress {
- height: 125px;
- display: none;
- border-radius: 5px;
-}
-
-.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;
-}
-
-@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
- .tab-dataflash table thead tr:first-child {
- font-size: 12px;
- height: 22px;
- }
-} \ No newline at end of file
diff --git a/tabs/dataflash.html b/tabs/dataflash.html
deleted file mode 100644
index eac22fb5..00000000
--- a/tabs/dataflash.html
+++ /dev/null
@@ -1,66 +0,0 @@
-<div class="tab-dataflash toolbar_fixed_bottom">
- <div class="content_wrapper">
- <div class="tab_title" i18n="tabDataflash"></div>
- <div class="cf_doc_version_bt">
- <a id="button-documentation" href="https://github.com/cleanflight/cleanflight/releases" target="_blank"></a>
- </div>
- <div class="require-dataflash">
- <div class="note" style="margin-bottom: 20px;">
- <div class="note_spacer">
- <p i18n="dataflashNote"></p>
- </div>
- </div>
- <dialog class="dataflash-confirm-erase">
- <h3 i18n="dataflashConfirmEraseTitle"></h3>
- <div class="dataflash-confirm-erase-note" i18n="dataflashConfirmEraseNote"></div>
- <div class="dataflash-erase-progress">
- <div class="data-loading">
- <p>Erase in progress, please wait...</p>
- </div>
- </div>
- <div class="buttons">
- <a href="#" class="erase-flash-cancel" i18n="dataflashButtonEraseCancel"></a> <a href="#"
- class="erase-flash-confirm" i18n="dataflashButtonEraseConfirm"></a>
- </div>
- </dialog>
- <dialog class="dataflash-saving">
- <h3 i18n="dataflashSavingTitle"></h3>
- <div class="dataflash-saving-before">
- <div i18n="dataflashSavingNote"></div>
- <progress value="0" min="0" max="100"></progress>
- <div class="buttons">
- <a href="#" class="save-flash-cancel" i18n="dataflashButtonSaveCancel"></a>
- </div>
- </div>
- <div class="dataflash-saving-after">
- <div i18n="dataflashSavingNoteAfter"></div>
- <div class="buttons">
- <a href="#" class="save-flash-dismiss" i18n="dataflashButtonSaveDismiss"></a>
- </div>
- </div>
- </dialog>
- <h3>Dataflash contents</h3>
- <ul class="dataflash-contents">
- <li class="dataflash-used">
- <div class="legend">Used space</div>
- </li>
- <li class="dataflash-free">
- <div class="legend">Free space</div>
- </li>
- </ul>
- </div>
- <div class="require-no-dataflash note">
- <div class="note_spacer">
- <p i18n="require-no-dataflash"></p>
- </div>
- </div>
- </div>
- <div class="content_toolbar">
- <div class="btn erase_btn">
- <a class="erase-flash" href="#" i18n="dataflashButtonErase"></a>
- </div>
- <div class="btn save_btn">
- <a class="save-flash" href="#" i18n="dataflashButtonSaveFile"></a>
- </div>
- </div>
-</div>
diff --git a/tabs/dataflash.js b/tabs/dataflash.js
deleted file mode 100644
index 60e9214e..00000000
--- a/tabs/dataflash.js
+++ /dev/null
@@ -1,288 +0,0 @@
-'use strict';
-
-TABS.dataflash = {
- available: false
-};
-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) {
- TABS.dataflash.available = semver.gte(CONFIG.apiVersion, "1.6.0");
-
- if (!TABS.dataflash.available) {
- load_html();
- return;
- }
-
- MSP.send_message(MSP_codes.MSP_DATAFLASH_SUMMARY, false, false, load_html);
- }
-
- function load_html() {
- $('#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'
- });
- }
-
- $(".btn a.erase-flash, .btn a.save-flash").toggleClass("disabled", DATAFLASH.usedSize == 0);
- }
-
- function create_html() {
-
- // translate to user-selected language
- localize();
-
-
- if (TABS.dataflash.available) {
- var supportsDataflash = DATAFLASH.totalSize > 0;
-
- $(".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();
- } else {
- $(".tab-dataflash .note_spacer").html(chrome.i18n.getMessage('dataflashNotSupportedNote'));
- }
- } else {
- $(".tab-dataflash").removeClass("supported");
- $(".tab-dataflash .note").html(chrome.i18n.getMessage('dataflashFirmwareUpgradeRequired'));
- }
-
-
- GUI.content_ready(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_update_summary(onDone) {
- MSP.send_message(MSP_codes.MSP_DATAFLASH_SUMMARY, false, false, function() {
- update_html();
-
- if (onDone) {
- onDone();
- }
- });
- }
-
- function flash_save_begin() {
- if (GUI.connected_to) {
- // Begin by refreshing the occupied size in case it changed while the tab was open
- flash_update_summary(function() {
- var
- maxBytes = DATAFLASH.usedSize;
-
- prepare_file(function(fileWriter) {
- var
- nextAddress = 0;
-
- show_saving_dialog();
-
- function onChunkRead(chunkAddress, chunkDataView) {
- if (chunkDataView != null) {
- // Did we receive any data?
- if (chunkDataView.byteLength > 0) {
- nextAddress += chunkDataView.byteLength;
-
- $(".dataflash-saving progress").attr("value", nextAddress / maxBytes * 100);
-
- var
- blob = new Blob([chunkDataView]);
-
- fileWriter.onwriteend = function(e) {
- if (saveCancelled || nextAddress >= maxBytes) {
- if (saveCancelled) {
- dismiss_saving_dialog();
- } else {
- mark_saving_dialog_done();
- }
- } else {
- MSP.dataflashRead(nextAddress, onChunkRead);
- }
- };
-
- fileWriter.write(blob);
- } else {
- // A zero-byte block indicates end-of-file, so we're done
- mark_saving_dialog_done();
- }
- } else {
- // There was an error with the received block (address didn't match the one we asked for), retry
- MSP.dataflashRead(nextAddress, onChunkRead);
- }
- }
-
- // Fetch the initial block
- 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) {
- var error = chrome.runtime.lastError;
-
- if (error) {
- console.error(error.message);
-
- if (error.message != "User cancelled") {
- GUI.log(chrome.i18n.getMessage('dataflashFileWriteFailed'));
- }
- 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);
- GUI.log(chrome.i18n.getMessage('dataflashFileWriteFailed'));
- });
- });
- }
-
- function ask_to_erase_flash() {
- eraseCancelled = false;
- $(".dataflash-confirm-erase").removeClass('erasing');
-
- $(".dataflash-confirm-erase")[0].showModal();
- }
-
- function poll_for_erase_completion() {
- flash_update_summary(function() {
- 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
diff --git a/tabs/onboard_logging.css b/tabs/onboard_logging.css
new file mode 100644
index 00000000..25fa7b04
--- /dev/null
+++ b/tabs/onboard_logging.css
@@ -0,0 +1,298 @@
+.tab-onboard_logging .info {
+ margin: 0 0 10px 0;
+ position: relative;
+}
+
+.tab-onboard_logging .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-onboard_logging .properties {
+ margin-top: 10px;
+}
+
+.tab-onboard_logging .dataflash-info {
+ overflow: hidden;
+}
+
+.tab-onboard_logging .dataflash-info dt {
+ float: left;
+ width: 12em;
+ height: 20px;
+ line-height: 20px;
+ font-weight: bold;
+}
+
+.tab-onboard_logging .dataflash-info dd {
+ display: block;
+ height: 20px;
+ line-height: 20px;
+}
+
+.tab-onboard_logging .speed {
+ margin-top: 5px;
+ width: 80px;
+ border: 1px solid silver;
+}
+
+.tab-onboard_logging .info {
+ margin-top: 10px;
+}
+
+.tab-onboard_logging .info dt {
+ float: left;
+ width: 120px;
+ height: 20px;
+ line-height: 20px;
+ font-weight: bold;
+}
+
+.tab-onboard_logging .info dd {
+ display: block;
+ margin-left: 130px;
+ height: 20px;
+ line-height: 20px;
+}
+
+.tab-onboard_logging .buttons {
+ width: calc(100% - 20px);
+ position: absolute;
+ bottom: 10px;
+}
+
+.tab-onboard_logging .dataflash-progress {
+ display: none;
+}
+
+.tab-onboard_logging .dataflash-contents,
+.tab-onboard_logging .sdcard-contents {
+ margin-top: 15px;
+ margin-bottom:26px;
+ border: 1px solid silver;
+ background-color: #eee;
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: flex-start;
+ border-radius: 6px;
+}
+
+.tab-onboard_logging .dataflash-contents li,
+.tab-onboard_logging .sdcard-contents li {
+ height: 26px;
+ position: relative;
+ box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.20);
+ border-radius: 4px;
+}
+
+.tab-onboard_logging .dataflash-contents li div,
+.tab-onboard_logging .sdcard-contents li div {
+ position: absolute;
+ top: 26px;
+ margin-top: 4px;
+ text-align: center;
+ left: 0;
+ right: 0;
+ white-space: nowrap;
+}
+
+.tab-onboard_logging .dataflash-used,
+.tab-onboard_logging .sdcard-other {
+ background-color: #59AA29;
+ border-radius: 4px;
+}
+
+.tab-onboard_logging progress::-webkit-progress-bar {
+ height: 24px;
+ background-color: #eee;
+}
+
+.tab-onboard_logging progress::-webkit-progress-value {
+ background-color: #bcf;
+}
+
+.tab-onboard_logging dialog {
+ width: 40em;
+ border-radius: 5px;
+}
+
+.tab-onboard_logging dialog .buttons {
+ position: static;
+ margin-top: 2em;
+}
+
+.tab-onboard_logging dialog h3 {
+ margin-bottom: 0.5em;
+}
+
+.dataflash-confirm-erase .dataflash-erase-progress {
+ height: 125px;
+ display: none;
+ border-radius: 5px;
+}
+
+.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-onboard_logging 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-present,
+.require-dataflash-supported,
+.require-sdcard-ready,
+.require-sdcard-supported,
+.require-blackbox-supported,
+.require-blackbox-maybe-supported,
+.require-blackbox-unsupported,
+.require-blackbox-config-supported,
+.tab-onboard_logging.dataflash-present .require-dataflash-not-present,
+.tab-onboard_logging.dataflash-supported .require-dataflash-unsupported,
+.tab-onboard_logging.sdcard-supported .require-sdcard-unsupported,
+.tab-onboard_logging.blackbox-config-supported .require-blackbox-config-unsupported {
+ display: none;
+}
+
+.tab-onboard_logging.dataflash-present .require-dataflash-present,
+.tab-onboard_logging.dataflash-supported .require-dataflash-supported,
+.tab-onboard_logging.sdcard-ready .require-sdcard-ready,
+.tab-onboard_logging.sdcard-supported .require-sdcard-supported,
+.tab-onboard_logging.blackbox-supported .require-blackbox-supported,
+.tab-onboard_logging.blackbox-maybe-supported .require-blackbox-maybe-supported,
+.tab-onboard_logging.blackbox-unsupported .require-blackbox-unsupported,
+.tab-onboard_logging.blackbox-config-supported .require-blackbox-config-supported {
+ display: block;
+}
+
+.require-no-dataflash {
+ display: block;
+}
+
+.tab-onboard_logging.supported .require-no-dataflash {
+ display: none;
+}
+
+@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
+ .tab-onboard_logging table thead tr:first-child {
+ font-size: 12px;
+ height: 22px;
+ }
+}
+
+.tab-onboard_logging .line {
+ clear: left;
+}
+.tab-onboard_logging .blackboxRate select,
+.tab-onboard_logging .blackboxDevice select {
+ float: left;
+ width: 180px;
+ height: 20px;
+ margin: 0 10px 5px 0;
+ border: 1px solid silver;
+}
+.tab-onboard_logging .blackboxRate span,
+.tab-onboard_logging .blackboxDevice span {
+ line-height: 20px;
+}
+
+.tab-onboard_logging .sdcard {
+ padding:10px;
+ float:left;
+}
+.tab-onboard_logging .sdcard-status {
+ padding-top: 4px;
+ text-align: center;
+}
+.tab-onboard_logging.sdcard-error .sdcard-icon {
+ background-color: #e60000;
+ border: 1px solid #fe0000;
+}
+.tab-onboard_logging.sdcard-initializing .sdcard-icon {
+ background-color: #64a5f6;
+ border: 1px solid #68a7ff;
+}
+.tab-onboard_logging.sdcard-ready .sdcard-icon {
+ background-color: #56ac1d;
+ border: 1px solid #5bbb1b;
+}
+.tab-onboard_logging .sdcard-icon {
+ box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.35);
+ width: 90px;
+ height: 90px;
+ background-image: url(/images/icons/cf_icon_sdcard.svg);
+ background-position: 21px 20px;
+ background-size: 50px 50px;
+ background-repeat: no-repeat;
+
+ background-color: #808080;
+ border: 1px solid #888888;
+
+ border-radius: 45px;
+}
+
+.tab-onboard_logging .regular-button {
+ margin-top: 8px;
+ margin-bottom: 8px;
+ margin-right: 10px;
+ background-color: #59aa29;
+ border-radius: 3px;
+ border: 1px solid #4c8829;
+ color: #fff;
+ font-family: 'open_sansbold', Arial;
+ font-size: 12px;
+ text-shadow: 0px 1px rgba(0, 0, 0, 0.25);
+ display: inline-block;
+ cursor: pointer;
+ transition: all ease 0.2s;
+ padding: 0px;
+ padding-left: 9px;
+ padding-right: 9px;
+ line-height: 28px;
+}
+.tab-onboard_logging .regular-button:hover {
+ background-color: #6ac435;
+ transition: all ease 0.2s;
+}
+.tab-onboard_logging .regular-button:active {
+ background-color: #4d9324;
+ transition: all ease 0.0s;
+ box-shadow: inset 0px 1px 5px rgba(0, 0, 0, 0.35);
+}
+.tab-onboard_logging .regular-button.disabled {
+ cursor: default;
+ color: #fff;
+ background-color: #AFAFAF;
+ border: 1px solid #AFAFAF;
+ pointer-events: none;
+ text-shadow: none;
+ opacity: 0.5;
+} \ No newline at end of file
diff --git a/tabs/onboard_logging.html b/tabs/onboard_logging.html
new file mode 100644
index 00000000..359f8214
--- /dev/null
+++ b/tabs/onboard_logging.html
@@ -0,0 +1,141 @@
+<div class="tab-onboard_logging toolbar_fixed_bottom">
+ <div class="content_wrapper">
+ <div class="tab_title" i18n="tabOnboardLogging"></div>
+ <div class="cf_doc_version_bt">
+ <a id="button-documentation" href="https://github.com/cleanflight/cleanflight/releases" target="_blank"></a>
+ </div>
+ <div class="require-blackbox-unsupported note">
+ <div class="note_spacer">
+ <p i18n="blackboxNotSupported"></p>
+ </div>
+ </div>
+ <div class="require-blackbox-maybe-supported note">
+ <div class="note_spacer">
+ <p i18n="blackboxMaybeSupported"></p>
+ </div>
+ </div>
+ <div class="require-blackbox-supported">
+ <div class="gui_box grey require-blackbox-config-supported">
+ <div class="gui_box_titlebar">
+ <div class="spacer_box_title" i18n="blackboxConfiguration"></div>
+ </div>
+ <div class="spacer_box">
+ <div class="line blackboxDevice">
+ <select name="blackbox_device">
+ </select>
+ <span>Blackbox logging device</span>
+ </div>
+ <div class="line blackboxRate">
+ <select name="blackbox_rate">
+ </select>
+ <span>Portion of flight loop iterations to log (logging rate)</span>
+ </div>
+ <div class="line">
+ <a href="#" class="save-settings regular-button" i18n="blackboxButtonSave"></a>
+ </div>
+ </div>
+ </div>
+
+ <div class="gui_box grey">
+ <div class="gui_box_titlebar" align="left">
+ <div class="spacer_box_title">
+ Outboard serial logging device
+ </div>
+ </div>
+ <div class="spacer_box">
+ <p i18n="serialLoggingSupportedNote"></p>
+ </div>
+ </div>
+
+ <div class="gui_box grey require-dataflash-supported">
+ <div class="gui_box_titlebar" align="left">
+ <div class="spacer_box_title">
+ Onboard dataflash chip
+ </div>
+ </div>
+ <div class="spacer_box">
+ <div class="require-dataflash-supported">
+ <p i18n="dataflashNote"></p>
+
+ <dialog class="dataflash-confirm-erase">
+ <h3 i18n="dataflashConfirmEraseTitle"></h3>
+ <div class="dataflash-confirm-erase-note" i18n="dataflashConfirmEraseNote"></div>
+ <div class="dataflash-erase-progress">
+ <div class="data-loading">
+ <p>Erase in progress, please wait...</p>
+ </div>
+ </div>
+ <div class="buttons">
+ <a href="#" class="erase-flash-confirm regular-button" i18n="dataflashButtonEraseConfirm"></a>
+ <a href="#" class="erase-flash-cancel regular-button" i18n="dataflashButtonEraseCancel"></a>
+ </div>
+ </dialog>
+
+ <dialog class="dataflash-saving">
+ <h3 i18n="dataflashSavingTitle"></h3>
+ <div class="dataflash-saving-before">
+ <div i18n="dataflashSavingNote"></div>
+ <progress value="0" min="0" max="100"></progress>
+ <div class="buttons">
+ <a href="#" class="save-flash-cancel regular-button" i18n="dataflashButtonSaveCancel"></a>
+ </div>
+ </div>
+ <div class="dataflash-saving-after">
+ <div i18n="dataflashSavingNoteAfter"></div>
+ <div class="buttons">
+ <a href="#" class="save-flash-dismiss regular-button" i18n="dataflashButtonSaveDismiss"></a>
+ </div>
+ </div>
+ </dialog>
+
+ <ul class="dataflash-contents">
+ <li class="dataflash-used">
+ <div class="legend"></div>
+ </li>
+ <li class="dataflash-free">
+ <div class="legend"></div>
+ </li>
+ </ul>
+
+ <div>
+ <a class="regular-button erase-flash" href="#" i18n="dataflashButtonErase"></a>
+ <a class="regular-button save-flash" href="#" i18n="dataflashButtonSaveFile"></a>
+ </div>
+ </div>
+
+ <p class="require-dataflash-not-present" i18n="dataflashNotPresentNote"></p>
+ <p class="require-dataflash-unsupported" i18n="dataflashFirmwareUpgradeRequired"></p>
+ </div>
+ </div>
+ <div class="require-sdcard-supported">
+ <div class="gui_box grey">
+ <div class="gui_box_titlebar" align="left">
+ <div class="spacer_box_title">
+ Onboard SD card
+ </div>
+ </div>
+ <div class="spacer_box">
+ <div class="sdcard">
+ <div class="sdcard-icon"></div>
+ <div class="sdcard-status"></div>
+ </div>
+
+ <p i18n="sdcardNote"></p>
+
+ <div class="require-sdcard-ready">
+ <ul class="sdcard-contents">
+ <li class="sdcard-other">
+ <div class="legend"></div>
+ </li>
+ <li class="sdcard-free">
+ <div class="legend"></div>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
diff --git a/tabs/onboard_logging.js b/tabs/onboard_logging.js
new file mode 100644
index 00000000..d157de0c
--- /dev/null
+++ b/tabs/onboard_logging.js
@@ -0,0 +1,470 @@
+'use strict';
+
+var
+ sdcardTimer;
+
+TABS.onboard_logging = {
+ available: false
+};
+TABS.onboard_logging.initialize = function (callback) {
+ var
+ self = this,
+ saveCancelled, eraseCancelled;
+
+ if (GUI.active_tab != 'onboard_logging') {
+ GUI.active_tab = 'onboard_logging';
+ googleAnalytics.sendAppView('onboard_logging');
+ }
+
+ if (CONFIGURATOR.connectionValid) {
+ // Blackbox was introduced in 1.5.0, dataflash API was introduced in 1.8.0, BLACKBOX/SDCARD MSP APIs in 1.11.0
+ TABS.onboard_logging.available = semver.gte(CONFIG.flightControllerVersion, "1.5.0");
+
+ if (!TABS.onboard_logging.available) {
+ load_html();
+ return;
+ }
+
+ MSP.send_message(MSP_codes.MSP_BF_CONFIG, false, false, function() {
+ if (semver.gte(CONFIG.flightControllerVersion, "1.8.0")) {
+ MSP.send_message(MSP_codes.MSP_DATAFLASH_SUMMARY, false, false, function() {
+ if (semver.gte(CONFIG.flightControllerVersion, "1.11.0")) {
+ MSP.send_message(MSP_codes.MSP_SDCARD_SUMMARY, false, false, function() {
+ MSP.send_message(MSP_codes.MSP_BLACKBOX_CONFIG, false, false, load_html);
+ });
+ } else {
+ load_html();
+ }
+ });
+ } else {
+ load_html();
+ }
+ });
+ }
+
+ function gcd(a, b) {
+ if (b == 0)
+ return a;
+
+ return gcd(b, a % b);
+ }
+
+ function save_to_eeprom() {
+ MSP.send_message(MSP_codes.MSP_EEPROM_WRITE, false, false, reboot);
+ }
+
+ function reboot() {
+ GUI.log(chrome.i18n.getMessage('configurationEepromSaved'));
+
+ GUI.tab_switch_cleanup(function() {
+ MSP.send_message(MSP_codes.MSP_SET_REBOOT, false, false, reinitialize);
+ });
+ }
+
+ function reinitialize() {
+ GUI.log(chrome.i18n.getMessage('deviceRebooting'));
+
+ if (BOARD.find_board_definition(CONFIG.boardIdentifier).vcp) { // VCP-based flight controls may crash old drivers, we catch and reconnect
+ $('a.connect').click();
+ GUI.timeout_add('start_connection',function start_connection() {
+ $('a.connect').click();
+ },2000);
+ } else {
+
+ GUI.timeout_add('waiting_for_bootup', function waiting_for_bootup() {
+ MSP.send_message(MSP_codes.MSP_IDENT, false, false, function () {
+ GUI.log(chrome.i18n.getMessage('deviceReady'));
+ TABS.onboard_logging.initialize(false, $('#content').scrollTop());
+ });
+ },1500); // 1500 ms seems to be just the right amount of delay to prevent data request timeouts
+ }
+ }
+
+ function load_html() {
+ $('#content').load("./tabs/onboard_logging.html", function() {
+ // translate to user-selected language
+ localize();
+
+ var
+ dataflashPresent = DATAFLASH.totalSize > 0,
+ blackboxSupport;
+
+ /*
+ * Pre-1.11.0 firmware supported DATAFLASH API (on targets with SPI flash) but not the BLACKBOX config API.
+ *
+ * The best we can do on those targets is check the BLACKBOX feature bit to identify support for Blackbox instead.
+ */
+ if (BLACKBOX.supported || DATAFLASH.supported
+ || semver.gte(CONFIG.flightControllerVersion, "1.5.0") && semver.lte(CONFIG.flightControllerVersion, "1.10.0") && bit_check(BF_CONFIG.features, 19)) {
+ blackboxSupport = 'yes';
+ } else if (semver.gte(CONFIG.flightControllerVersion, "1.5.0") && semver.lte(CONFIG.flightControllerVersion, "1.10.0")) {
+ blackboxSupport = 'maybe';
+ } else {
+ blackboxSupport = 'no';
+ }
+
+ $(".tab-onboard_logging")
+ .addClass("serial-supported")
+ .toggleClass("dataflash-supported", DATAFLASH.supported)
+ .toggleClass("dataflash-present", dataflashPresent)
+ .toggleClass("sdcard-supported", SDCARD.supported)
+ .toggleClass("blackbox-config-supported", BLACKBOX.supported)
+
+ .toggleClass("blackbox-supported", blackboxSupport == 'yes')
+ .toggleClass("blackbox-maybe-supported", blackboxSupport == 'maybe')
+ .toggleClass("blackbox-unsupported", blackboxSupport == 'no');
+
+ if (dataflashPresent) {
+ // UI hooks
+ $('.tab-onboard_logging a.erase-flash').click(ask_to_erase_flash);
+
+ $('.tab-onboard_logging a.erase-flash-confirm').click(flash_erase);
+ $('.tab-onboard_logging a.erase-flash-cancel').click(flash_erase_cancel);
+
+ $('.tab-onboard_logging a.save-flash').click(flash_save_begin);
+ $('.tab-onboard_logging a.save-flash-cancel').click(flash_save_cancel);
+ $('.tab-onboard_logging a.save-flash-dismiss').click(dismiss_saving_dialog);
+ }
+
+ if (BLACKBOX.supported) {
+ $(".tab-onboard_logging a.save-settings").click(function() {
+ var rate = $(".blackboxRate select").val().split('/');
+
+ BLACKBOX.blackboxRateNum = parseInt(rate[0], 10);
+ BLACKBOX.blackboxRateDenom = parseInt(rate[1], 10);
+ BLACKBOX.blackboxDevice = parseInt($(".blackboxDevice select").val(), 10);
+
+ MSP.sendBlackboxConfiguration(save_to_eeprom);
+ });
+ }
+
+ populateLoggingRates();
+ populateDevices();
+
+ update_html();
+
+ GUI.content_ready(callback);
+ });
+ }
+
+ function populateDevices() {
+ var
+ deviceSelect = $(".blackboxDevice select").empty();
+
+ deviceSelect.append('<option value="0">Serial port</option>');
+ if (DATAFLASH.ready) {
+ deviceSelect.append('<option value="1">On-board dataflash chip</option>');
+ }
+ if (SDCARD.supported) {
+ deviceSelect.append('<option value="2">On-board SD card slot</option>');
+ }
+
+ deviceSelect.val(BLACKBOX.blackboxDevice);
+ }
+
+ function populateLoggingRates() {
+ var
+ userRateGCD = gcd(BLACKBOX.blackboxRateNum, BLACKBOX.blackboxRateDenom),
+ userRate = {num: BLACKBOX.blackboxRateNum / userRateGCD, denom: BLACKBOX.blackboxRateDenom / userRateGCD};
+
+ // Offer a reasonable choice of logging rates (if people want weird steps they can use CLI)
+ var
+ loggingRates = [
+ {num: 1, denom: 32},
+ {num: 1, denom: 16},
+ {num: 1, denom: 8},
+ {num: 1, denom: 5},
+ {num: 1, denom: 4},
+ {num: 1, denom: 3},
+ {num: 1, denom: 2},
+ {num: 2, denom: 3},
+ {num: 3, denom: 4},
+ {num: 4, denom: 5},
+ {num: 7, denom: 8},
+ {num: 1, denom: 1},
+ ],
+ loggingRatesSelect = $(".blackboxRate select");
+
+ var
+ addedCurrentValue = false;
+
+ for (var i = 0; i < loggingRates.length; i++) {
+ if (!addedCurrentValue && userRate.num / userRate.denom <= loggingRates[i].num / loggingRates[i].denom) {
+ if (userRate.num / userRate.denom < loggingRates[i].num / loggingRates[i].denom) {
+ loggingRatesSelect.append('<option value="' + userRate.num + '/' + userRate.denom + '">'
+ + userRate.num + '/' + userRate.denom + ' (' + Math.round(userRate.num / userRate.denom * 100) + '%)</option>');
+ }
+ addedCurrentValue = true;
+ }
+
+ loggingRatesSelect.append('<option value="' + loggingRates[i].num + '/' + loggingRates[i].denom + '">'
+ + loggingRates[i].num + '/' + loggingRates[i].denom + ' (' + Math.round(loggingRates[i].num / loggingRates[i].denom * 100) + '%)</option>');
+
+ }
+ loggingRatesSelect.val(userRate.num + '/' + userRate.denom);
+ }
+
+ function formatFilesizeKilobytes(kilobytes) {
+ if (kilobytes < 1024) {
+ return Math.round(kilobytes) + "kB";
+ }
+
+ var
+ megabytes = kilobytes / 1024,
+ gigabytes;
+
+ if (megabytes < 900) {
+ return megabytes.toFixed(1) + "MB";
+ } else {
+ gigabytes = megabytes / 1024;
+
+ return gigabytes.toFixed(1) + "GB";
+ }
+ }
+
+ function formatFilesizeBytes(bytes) {
+ if (bytes < 1024) {
+ return bytes + "B";
+ }
+ return formatFilesizeKilobytes(bytes / 1024);
+ }
+
+ function update_bar_width(bar, value, total, label, valuesAreKilobytes) {
+ if (value > 0) {
+ bar.css({
+ width: (value / total * 100) + "%",
+ display: 'block'
+ });
+
+ $("div", bar).text((label ? label + " " : "") + (valuesAreKilobytes ? formatFilesizeKilobytes(value) : formatFilesizeBytes(value)));
+ } else {
+ bar.css({
+ display: 'none'
+ });
+ }
+ }
+
+ function update_html() {
+ update_bar_width($(".tab-onboard_logging .dataflash-used"), DATAFLASH.usedSize, DATAFLASH.totalSize, "Used space", false);
+ update_bar_width($(".tab-onboard_logging .dataflash-free"), DATAFLASH.totalSize - DATAFLASH.usedSize, DATAFLASH.totalSize, "Free space", false);
+
+ update_bar_width($(".tab-onboard_logging .sdcard-other"), SDCARD.totalSizeKB - SDCARD.freeSizeKB, SDCARD.totalSizeKB, "Unavailable space", true);
+ update_bar_width($(".tab-onboard_logging .sdcard-free"), SDCARD.freeSizeKB, SDCARD.totalSizeKB, "Free space for logs", true);
+
+ $(".btn a.erase-flash, .btn a.save-flash").toggleClass("disabled", DATAFLASH.usedSize == 0);
+
+ $(".tab-onboard_logging")
+ .toggleClass("sdcard-error", SDCARD.state == MSP.SDCARD_STATE_FATAL)
+ .toggleClass("sdcard-initializing", SDCARD.state == MSP.SDCARD_STATE_CARD_INIT || SDCARD.state == MSP.SDCARD_STATE_FS_INIT)
+ .toggleClass("sdcard-ready", SDCARD.state == MSP.SDCARD_STATE_READY);
+
+ switch (SDCARD.state) {
+ case MSP.SDCARD_STATE_NOT_PRESENT:
+ $(".sdcard-status").text("No card inserted");
+ break;
+ case MSP.SDCARD_STATE_FATAL:
+ $(".sdcard-status").html("Fatal error<br>Reboot to retry");
+ break;
+ case MSP.SDCARD_STATE_READY:
+ $(".sdcard-status").text("Card ready");
+ break;
+ case MSP.SDCARD_STATE_CARD_INIT:
+ $(".sdcard-status").text("Card starting...");
+ break;
+ case MSP.SDCARD_STATE_FS_INIT:
+ $(".sdcard-status").text("Filesystem starting...");
+ break;
+ default:
+ $(".sdcard-status").text("Unknown state " + SDCARD.state);
+ }
+
+ if (SDCARD.supported && !sdcardTimer) {
+ // Poll for changes in SD card status
+ sdcardTimer = setTimeout(function() {
+ sdcardTimer = false;
+ if (CONFIGURATOR.connectionValid) {
+ MSP.send_message(MSP_codes.MSP_SDCARD_SUMMARY, false, false, function() {
+ update_html();
+ });
+ }
+ }, 2000);
+ }
+ }
+
+ // 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_update_summary(onDone) {
+ MSP.send_message(MSP_codes.MSP_DATAFLASH_SUMMARY, false, false, function() {
+ update_html();
+
+ if (onDone) {
+ onDone();
+ }
+ });
+ }
+
+ function flash_save_begin() {
+ if (GUI.connected_to) {
+ // Begin by refreshing the occupied size in case it changed while the tab was open
+ flash_update_summary(function() {
+ var
+ maxBytes = DATAFLASH.usedSize;
+
+ prepare_file(function(fileWriter) {
+ var
+ nextAddress = 0;
+
+ show_saving_dialog();
+
+ function onChunkRead(chunkAddress, chunkDataView) {
+ if (chunkDataView != null) {
+ // Did we receive any data?
+ if (chunkDataView.byteLength > 0) {
+ nextAddress += chunkDataView.byteLength;
+
+ $(".dataflash-saving progress").attr("value", nextAddress / maxBytes * 100);
+
+ var
+ blob = new Blob([chunkDataView]);
+
+ fileWriter.onwriteend = function(e) {
+ if (saveCancelled || nextAddress >= maxBytes) {
+ if (saveCancelled) {
+ dismiss_saving_dialog();
+ } else {
+ mark_saving_dialog_done();
+ }
+ } else {
+ MSP.dataflashRead(nextAddress, onChunkRead);
+ }
+ };
+
+ fileWriter.write(blob);
+ } else {
+ // A zero-byte block indicates end-of-file, so we're done
+ mark_saving_dialog_done();
+ }
+ } else {
+ // There was an error with the received block (address didn't match the one we asked for), retry
+ MSP.dataflashRead(nextAddress, onChunkRead);
+ }
+ }
+
+ // Fetch the initial block
+ 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) {
+ var error = chrome.runtime.lastError;
+
+ if (error) {
+ console.error(error.message);
+
+ if (error.message != "User cancelled") {
+ GUI.log(chrome.i18n.getMessage('dataflashFileWriteFailed'));
+ }
+ 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);
+ GUI.log(chrome.i18n.getMessage('dataflashFileWriteFailed'));
+ });
+ });
+ }
+
+ function ask_to_erase_flash() {
+ eraseCancelled = false;
+ $(".dataflash-confirm-erase").removeClass('erasing');
+
+ $(".dataflash-confirm-erase")[0].showModal();
+ }
+
+ function poll_for_erase_completion() {
+ flash_update_summary(function() {
+ if (CONFIGURATOR.connectionValid && !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.onboard_logging.cleanup = function (callback) {
+ if (sdcardTimer) {
+ clearTimeout(sdcardTimer);
+ sdcardTimer = false;
+ }
+
+ if (callback) {
+ callback();
+ }
+}; \ No newline at end of file