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:
authorKonstantin Sharlaimov <konstantin.sharlaimov@gmail.com>2018-12-10 13:37:41 +0300
committerGitHub <noreply@github.com>2018-12-10 13:37:41 +0300
commit08d50f7feec3631592e30cc45e92788966c8a15b (patch)
tree59ea0cc785eab47e82ce1658d7d866579f15365f
parent2a7a2649e02661717123e96ed90ea33cc3b67597 (diff)
parent43da66e2b42c515e5d557376a250a6d024e4b0ff (diff)
Merge pull request #604 from nmaggioni/cli_rebase
Rebase CLI tab on latest CF
-rwxr-xr-x_locales/en/messages.json15
-rw-r--r--js/fc.js9
-rw-r--r--js/helpers.js33
-rw-r--r--js/msp/MSPHelper.js11
-rwxr-xr-xjs/serial_backend.js7
-rw-r--r--src/css/tabs/cli.css17
-rw-r--r--tabs/cli.html9
-rw-r--r--tabs/cli.js314
-rw-r--r--tabs/configuration.js12
9 files changed, 324 insertions, 103 deletions
diff --git a/_locales/en/messages.json b/_locales/en/messages.json
index e2015e8f..ab7a367b 100755
--- a/_locales/en/messages.json
+++ b/_locales/en/messages.json
@@ -1441,6 +1441,21 @@
"cliReboot": {
"message": "CLI reboot detected"
},
+ "cliSaveToFileBtn": {
+ "message": "Save to File"
+ },
+ "cliSaveToFileFailed": {
+ "message": "Failed to save CLI output to file"
+ },
+ "cliSaveToFileAborted": {
+ "message": "Saving CLI output to file was aborted"
+ },
+ "cliSaveToFileCompleted": {
+ "message": "CLI output successfully saved to file"
+ },
+ "cliClearOutputHistoryBtn": {
+ "message": "Clear output history"
+ },
"loggingNote": {
"message": "Data will be logged in this tab <span style=\"color: red\">only</span>, leaving the tab will <span style=\"color: red\">cancel</span> logging and application will return to its normal <strong>\"configurator\"</strong> state.<br /> You are free to select the global update period, data will be written into the log file every <strong>1</strong> second for performance reasons."
diff --git a/js/fc.js b/js/fc.js
index 6e8d5c26..ecf78b96 100644
--- a/js/fc.js
+++ b/js/fc.js
@@ -103,7 +103,8 @@ var FC = {
battery_profile: 0,
uid: [0, 0, 0],
accelerometerTrims: [0, 0],
- armingFlags: 0
+ armingFlags: 0,
+ name: ''
};
BF_CONFIG = {
@@ -567,7 +568,7 @@ var FC = {
features.push(
{bit: 28, group: 'esc-priority', name: 'PWM_OUTPUT_ENABLE', haveTip: true}
);
-
+
/*
* Transponder disabled until not implemented in firmware
*/
@@ -1068,8 +1069,8 @@ var FC = {
return {
0: "Land",
1: "Drop",
- 2: "RTH",
- 3: "Do Nothing",
+ 2: "RTH",
+ 3: "Do Nothing",
}
},
getRcMapLetters: function () {
diff --git a/js/helpers.js b/js/helpers.js
index 9207089d..ecf72651 100644
--- a/js/helpers.js
+++ b/js/helpers.js
@@ -12,4 +12,37 @@ function constrain(input, min, max) {
}
return input;
+}
+
+function zeroPad(value, width) {
+ value = "" + value;
+
+ while (value.length < width) {
+ value = "0" + value;
+ }
+
+ return value;
+}
+
+function generateFilename(prefix, suffix) {
+ var date = new Date();
+ var filename = prefix;
+
+ if (CONFIG) {
+ if (CONFIG.flightControllerIdentifier) {
+ filename = CONFIG.flightControllerIdentifier + '_' + filename;
+ }
+ if (CONFIG.name && CONFIG.name.trim() !== '') {
+ filename = filename + '_' + CONFIG.name.trim().replace(' ', '_');
+ }
+ }
+
+ filename = filename + '_' + date.getFullYear()
+ + zeroPad(date.getMonth() + 1, 2)
+ + zeroPad(date.getDate(), 2)
+ + '_' + zeroPad(date.getHours(), 2)
+ + zeroPad(date.getMinutes(), 2)
+ + zeroPad(date.getSeconds(), 2);
+
+ return filename + '.' + suffix;
} \ No newline at end of file
diff --git a/js/msp/MSPHelper.js b/js/msp/MSPHelper.js
index f22d8be0..8b2c78c7 100644
--- a/js/msp/MSPHelper.js
+++ b/js/msp/MSPHelper.js
@@ -525,7 +525,7 @@ var mspHelper = (function (gui) {
break;
- case MSPCodes.MSP_SET_SERVO_MIX_RULE:
+ case MSPCodes.MSP_SET_SERVO_MIX_RULE:
console.log("Servo mix saved");
break;
@@ -1345,6 +1345,11 @@ var mspHelper = (function (gui) {
console.log('OSD char uploaded');
break;
case MSPCodes.MSP_NAME:
+ CONFIG.name = '';
+ var char;
+ while ((char = data.readU8()) !== null) {
+ CONFIG.name += String.fromCharCode(char);
+ }
break;
case MSPCodes.MSP_SET_NAME:
console.log("Craft name set");
@@ -1420,7 +1425,7 @@ var mspHelper = (function (gui) {
case MSPCodes.MSP2_INAV_SET_MC_BRAKING:
console.log('Braking config saved');
break;
-
+
default:
console.log('Unknown code detected: ' + dataHandler.code);
} else {
@@ -2186,7 +2191,7 @@ var mspHelper = (function (gui) {
// send one at a time, with index
var servoRule = SERVO_RULES.get()[servoIndex];
-
+
buffer.push(servoIndex);
buffer.push(servoRule.getTarget());
buffer.push(servoRule.getInput());
diff --git a/js/serial_backend.js b/js/serial_backend.js
index da2312da..2226d030 100755
--- a/js/serial_backend.js
+++ b/js/serial_backend.js
@@ -306,7 +306,12 @@ function onOpen(openInfo) {
googleAnalytics.sendEvent('Firmware', 'Variant', CONFIG.flightControllerIdentifier + ',' + CONFIG.flightControllerVersion);
GUI.log(chrome.i18n.getMessage('fcInfoReceived', [CONFIG.flightControllerIdentifier, CONFIG.flightControllerVersion]));
if (semver.gte(CONFIG.flightControllerVersion, CONFIGURATOR.firmwareVersionAccepted)) {
- onValidFirmware();
+ mspHelper.getCraftName(function(name) {
+ if (name) {
+ CONFIG.name = name;
+ }
+ onValidFirmware();
+ });
} else {
onInvalidFirmwareVersion();
}
diff --git a/src/css/tabs/cli.css b/src/css/tabs/cli.css
index 52597896..d7f1643d 100644
--- a/src/css/tabs/cli.css
+++ b/src/css/tabs/cli.css
@@ -3,7 +3,7 @@
}
.tab-cli .content_wrapper {
- height: calc(100% - 50px);
+ height: calc(100% - 92px);
}
.tab-cli p {
@@ -56,4 +56,19 @@
.tab-cli .window .wrapper {
white-space: pre-wrap;
+}
+
+.tab-cli .save {
+ color: white;
+}
+
+@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
+
+.tab-cli .content_wrapper {
+ height: calc(100% - 87px);
+}
+.tab-cli .content_toolbar {
+ margin-top: 5px;
+}
+
} \ No newline at end of file
diff --git a/tabs/cli.html b/tabs/cli.html
index 19872413..9a533704 100644
--- a/tabs/cli.html
+++ b/tabs/cli.html
@@ -5,6 +5,7 @@
<p i18n="cliInfo"></p>
</div>
</div>
+
<div class="backdrop">
<div class="window">
<div class="wrapper"></div>
@@ -12,4 +13,10 @@
</div>
<textarea name="commands" i18n_placeholder="cliInputPlaceholder" rows="1" cols="0"></textarea>
</div>
-</div>
+ <div class="content_toolbar">
+ <div class="btn save_btn pull-right">
+ <a class="save" href="#" i18n="cliSaveToFileBtn"></a>
+ <a class="clear" href="#" i18n="cliClearOutputHistoryBtn"></a>
+ </div>
+ </div>
+</div> \ No newline at end of file
diff --git a/tabs/cli.js b/tabs/cli.js
index 82a3d894..0a7a62c7 100644
--- a/tabs/cli.js
+++ b/tabs/cli.js
@@ -1,11 +1,46 @@
'use strict';
/*global chrome*/
TABS.cli = {
- 'validateText': "",
- 'currentLine': "",
- 'sequenceElements': 0
+ lineDelayMs: 15,
+ profileSwitchDelayMs: 100,
+ outputHistory: "",
+ cliBuffer: ""
};
+function removePromptHash(promptText) {
+ return promptText.replace(/^# /, '');
+}
+
+function cliBufferCharsToDelete(command, buffer) {
+ var commonChars = 0;
+ for (var i = 0;i < buffer.length;i++) {
+ if (command[i] === buffer[i]) {
+ commonChars++;
+ } else {
+ break;
+ }
+ }
+
+ return buffer.length - commonChars;
+}
+
+function commandWithBackSpaces(command, buffer, noOfCharsToDelete) {
+ const backspace = String.fromCharCode(127);
+ return backspace.repeat(noOfCharsToDelete) + command.substring(buffer.length - noOfCharsToDelete, command.length);
+}
+
+function getCliCommand(command, cliBuffer) {
+ const buffer = removePromptHash(cliBuffer);
+ const bufferRegex = new RegExp('^' + buffer, 'g');
+ if (command.match(bufferRegex)) {
+ return command.replace(bufferRegex, '');
+ }
+
+ const noOfCharsToDelete = cliBufferCharsToDelete(command, buffer);
+
+ return commandWithBackSpaces(command, buffer, noOfCharsToDelete);
+}
+
TABS.cli.initialize = function (callback) {
var self = this;
@@ -14,12 +49,13 @@ TABS.cli.initialize = function (callback) {
googleAnalytics.sendAppView('CLI');
}
- /*
- * Flush MSP queue as well as all MSP registered callbacks
- */
+ // Flush MSP queue as well as all MSP registered callbacks
helper.mspQueue.flush();
MSP.callbacks_cleanup();
+ self.outputHistory = "";
+ self.cliBuffer = "";
+
$('#content').load("./tabs/cli.html", function () {
// translate to user-selected language
localize();
@@ -28,18 +64,101 @@ TABS.cli.initialize = function (callback) {
var textarea = $('.tab-cli textarea');
+ $('.tab-cli .save').click(function() {
+ var prefix = 'cli';
+ var suffix = 'txt';
+
+ var filename = generateFilename(prefix, suffix);
+
+ var accepts = [{
+ description: suffix.toUpperCase() + ' files', extensions: [suffix],
+ }];
+
+ chrome.fileSystem.chooseEntry({type: 'saveFile', suggestedName: filename, accepts: accepts}, function(entry) {
+ if (chrome.runtime.lastError) {
+ if (chrome.runtime.lastError.message === 'User cancelled') {
+ GUI.log(chrome.i18n.getMessage('cliSaveToFileAborted'));
+ } else {
+ GUI.log(chrome.i18n.getMessage('cliSaveToFileFailed'));
+ console.error(chrome.runtime.lastError.message);
+ }
+ return;
+ }
+
+ if (!entry) {
+ GUI.log(chrome.i18n.getMessage('cliSaveToFileAborted'));
+ return;
+ }
+
+ entry.createWriter(function (writer) {
+ writer.onerror = function (){
+ GUI.log(chrome.i18n.getMessage('cliSaveToFileFailed'));
+ };
+
+ writer.onwriteend = function () {
+ if (self.outputHistory.length > 0 && writer.length === 0) {
+ writer.write(new Blob([self.outputHistory], {type: 'text/plain'}));
+ } else {
+ GUI.log(chrome.i18n.getMessage('cliSaveToFileCompleted'));
+ }
+ };
+
+ writer.truncate(0);
+ }, function (){
+ GUI.log(chrome.i18n.getMessage('cliSaveToFileFailed'));
+ console.error('Failed to get file writer');
+ });
+ });
+ });
+
+$('.tab-cli .clear').click(function() {
+ self.outputHistory = "";
+ $('.tab-cli .window .wrapper').empty();
+ });
+
+ // Tab key detection must be on keydown,
+ // `keypress`/`keyup` happens too late, as `textarea` will have already lost focus.
+ textarea.keydown(function (event) {
+ const tabKeyCode = 9;
+ if (event.which == tabKeyCode) {
+ // prevent default tabbing behaviour
+ event.preventDefault();
+ const outString = textarea.val();
+ const lastCommand = outString.split("\n").pop();
+ const command = getCliCommand(lastCommand, self.cliBuffer);
+ if (command) {
+ self.sendAutoComplete(command);
+ textarea.val('');
+ }
+ }
+ });
+
textarea.keypress(function (event) {
- if (event.which == 13) { // enter
+ const enterKeyCode = 13;
+ if (event.which == enterKeyCode) {
event.preventDefault(); // prevent the adding of new line
var out_string = textarea.val();
- var out_arr = out_string.split("\n");
self.history.add(out_string.trim());
- var timeout_needle = 0;
- for (var i = 0; i < out_arr.length; i++) {
- self.sendSlowly(out_arr, i, timeout_needle++);
- }
+ var outputArray = out_string.split("\n");
+ Promise.reduce(outputArray, function(delay, line, index) {
+ return new Promise(function (resolve) {
+ helper.timeout.add('CLI_send_slowly', function () {
+ var processingDelay = self.lineDelayMs;
+ if (line.toLowerCase().startsWith('profile')) {
+ processingDelay = self.profileSwitchDelayMs;
+ }
+ const isLastCommand = outputArray.length === index + 1;
+ if (isLastCommand && self.cliBuffer) {
+ line = getCliCommand(line, self.cliBuffer);
+ }
+ self.sendLine(line, function () {
+ resolve(processingDelay);
+ });
+ }, delay)
+ })
+ }, 0);
textarea.val('');
}
@@ -84,29 +203,33 @@ TABS.cli.history.add = function (str) {
this.history.push(str);
this.index = this.history.length;
};
+
TABS.cli.history.prev = function () {
if (this.index > 0) this.index -= 1;
return this.history[this.index];
};
+
TABS.cli.history.next = function () {
if (this.index < this.history.length) this.index += 1;
return this.history[this.index - 1];
};
-TABS.cli.sendSlowly = function (out_arr, i, timeout_needle) {
- helper.timeout.add('CLI_send_slowly', function () {
- var bufferOut = new ArrayBuffer(out_arr[i].length + 1);
- var bufView = new Uint8Array(bufferOut);
+const backspaceCode = 8;
+const lineFeedCode = 10;
+const carriageReturnCode = 13;
- for (var c_key = 0; c_key < out_arr[i].length; c_key++) {
- bufView[c_key] = out_arr[i].charCodeAt(c_key);
- }
+function writeToOutput(text) {
+ $('.tab-cli .window .wrapper').append(text);
+ $('.tab-cli .window').scrollTop($('.tab-cli .window .wrapper').height());
+}
- bufView[out_arr[i].length] = 0x0D; // enter (\n)
+function writeLineToOutput(text) {
+ writeToOutput(text + "<br>");
+}
- serial.send(bufferOut);
- }, timeout_needle * 100);
-};
+function setPrompt(text) {
+ $('.tab-cli textarea').val(text);
+}
TABS.cli.read = function (readInfo) {
/* Some info about handling line feeds and carriage return
@@ -117,93 +240,106 @@ TABS.cli.read = function (readInfo) {
MAC only understands CR
Linux and Unix only understand LF
Windows understands (both) CRLF
- Chrome OS currenty unknown
+ Chrome OS currently unknown
*/
var data = new Uint8Array(readInfo.data),
- text = "";
+ validateText = "",
+ sequenceCharsToSkip = 0;
for (var i = 0; i < data.length; i++) {
- if (CONFIGURATOR.cliValid) {
- if (data[i] == 27 || this.sequenceElements > 0) { // ESC + other
- this.sequenceElements++;
+ const currentChar = String.fromCharCode(data[i]);
- // delete previous space
- if (this.sequenceElements == 1) {
- text = text.substring(0, text.length -1);
- }
+ if (!CONFIGURATOR.cliValid) {
+ // try to catch part of valid CLI enter message
+ validateText += currentChar;
+ writeToOutput(currentChar);
+ continue;
+ }
- // Reset
- if (this.sequenceElements >= 5) {
- this.sequenceElements = 0;
- }
- }
+ const escapeSequenceCode = 27;
+ const escapeSequenceCharLength = 3;
+ if (data[i] == escapeSequenceCode && !sequenceCharsToSkip) { // ESC + other
+ sequenceCharsToSkip = escapeSequenceCharLength;
+ }
- if (this.sequenceElements == 0) {
- switch (data[i]) {
- case 10: // line feed
- if (GUI.operating_system != "MacOS") {
- text += "<br />";
- }
- this.currentLine = "";
- break;
- case 13: // carriage return
- if (GUI.operating_system == "MacOS") {
- text += "<br />";
- }
- this.currentLine = "";
- break;
- case 60:
- text += '&lt';
- break;
- case 62:
- text += '&gt';
- break;
-
- default:
- text += String.fromCharCode(data[i]);
- this.currentLine += String.fromCharCode(data[i]);
+ if (sequenceCharsToSkip) {
+ sequenceCharsToSkip--;
+ continue;
+ }
+
+ switch (data[i]) {
+ case lineFeedCode:
+ if (GUI.operating_system === "Windows") {
+ writeLineToOutput(this.cliBuffer);
+ this.cliBuffer = "";
}
- }
- if (this.currentLine == 'Rebooting') {
- CONFIGURATOR.cliActive = false;
- CONFIGURATOR.cliValid = false;
- GUI.log(chrome.i18n.getMessage('cliReboot'));
- GUI.log(chrome.i18n.getMessage('deviceRebooting'));
- GUI.handleReconnect();
- }
- } else {
- // try to catch part of valid CLI enter message
- this.validateText += String.fromCharCode(data[i]);
- text += String.fromCharCode(data[i]);
+ break;
+ case carriageReturnCode:
+ if (GUI.operating_system !== "Windows") {
+ writeLineToOutput(this.cliBuffer);
+ this.cliBuffer = "";
+ }
+ break;
+ case 60:
+ this.cliBuffer += '&lt';
+ break;
+ case 62:
+ this.cliBuffer += '&gt';
+ break;
+ case backspaceCode:
+ this.cliBuffer = this.cliBuffer.slice(0, -1);
+ break;
+
+ default:
+ this.cliBuffer += currentChar;
+ }
+
+ this.outputHistory += currentChar;
+
+ if (this.cliBuffer == 'Rebooting') {
+ CONFIGURATOR.cliActive = false;
+ CONFIGURATOR.cliValid = false;
+ GUI.log(chrome.i18n.getMessage('cliReboot'));
+ GUI.log(chrome.i18n.getMessage('deviceRebooting'));
+ GUI.handleReconnect();
}
+
}
- if (!CONFIGURATOR.cliValid && this.validateText.indexOf('CLI') != -1) {
+ if (!CONFIGURATOR.cliValid && validateText.indexOf('CLI') !== -1) {
GUI.log(chrome.i18n.getMessage('cliEnter'));
CONFIGURATOR.cliValid = true;
- this.validateText = "";
+ validateText = "";
}
- $('.tab-cli .window .wrapper').append(text);
- $('.tab-cli .window').scrollTop($('.tab-cli .window .wrapper').height());
+ setPrompt(removePromptHash(this.cliBuffer));
};
-TABS.cli.cleanup = function (callback) {
- if (!CONFIGURATOR.connectionValid || !CONFIGURATOR.cliValid) {
- if (callback) callback();
- return;
- }
+TABS.cli.sendLine = function (line, callback) {
+ this.send(line + '\n', callback);
+};
- var bufferOut = new ArrayBuffer(5);
+TABS.cli.sendAutoComplete = function (line, callback) {
+ this.send(line + '\t', callback);
+};
+
+TABS.cli.send = function (line, callback) {
+ var bufferOut = new ArrayBuffer(line.length);
var bufView = new Uint8Array(bufferOut);
- bufView[0] = 0x65; // e
- bufView[1] = 0x78; // x
- bufView[2] = 0x69; // i
- bufView[3] = 0x74; // t
- bufView[4] = 0x0D; // enter
+ for (var c_key = 0; c_key < line.length; c_key++) {
+ bufView[c_key] = line.charCodeAt(c_key);
+ }
+
+ serial.send(bufferOut, callback);
+};
- serial.send(bufferOut, function (writeInfo) {
+TABS.cli.cleanup = function (callback) {
+ if (!(CONFIGURATOR.connectionValid && CONFIGURATOR.cliValid && CONFIGURATOR.cliActive)) {
+ if (callback) callback();
+ return;
+ }
+ this.send(getCliCommand('exit\r', this.cliBuffer), function (writeInfo) {
// we could handle this "nicely", but this will do for now
// (another approach is however much more complicated):
// we can setup an interval asking for data lets say every 200ms, when data arrives, callback will be triggered and tab switched
diff --git a/tabs/configuration.js b/tabs/configuration.js
index 35108a8b..f7adfc6a 100644
--- a/tabs/configuration.js
+++ b/tabs/configuration.js
@@ -12,10 +12,14 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
var craftName = null;
var loadCraftName = function(callback) {
- mspHelper.getCraftName(function(name) {
- craftName = name;
+ if (!CONFIG.name || CONFIG.name.trim() === '') {
+ mspHelper.getCraftName(function(name) {
+ craftName = name;
+ callback();
+ });
+ } else {
callback();
- });
+ }
};
var saveCraftName = function(callback) {
@@ -625,7 +629,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) {
$attitudeFrequency.change(function () {
INAV_PID_CONFIG.attitudeTaskFrequency = $attitudeFrequency.val();
});
-
+
if (semver.gte(CONFIG.flightControllerVersion, "1.5.0")) {
var $sensorAcc = $('#sensor-acc'),