mirror of
https://github.com/iNavFlight/inav-configurator.git
synced 2025-07-13 03:19:54 +03:00
890 lines
No EOL
36 KiB
JavaScript
Executable file
890 lines
No EOL
36 KiB
JavaScript
Executable file
'use strict';
|
|
|
|
const { marked } = require('marked');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const semver = require('semver');
|
|
const { dialog } = require('@electron/remote');
|
|
const Store = require('electron-store');
|
|
const store = new Store();
|
|
|
|
const i18n = require('./../js/localization');
|
|
const { GUI, TABS } = require('./../js/gui');
|
|
const MSP = require('./../js/msp');
|
|
const MSPCodes = require('./../js/msp/MSPCodes')
|
|
const FC = require('./../js/fc');
|
|
const { usbDevices, PortHandler } = require('./../js/port_handler');
|
|
const CONFIGURATOR = require('./../js/data_storage');
|
|
const SerialBackend = require('./../js/serial_backend');
|
|
const timeout = require('./../js/timeouts');
|
|
const interval = require('./../js/intervals');
|
|
const mspQueue = require('./../js/serial_queue');
|
|
const mspHelper = require('./../js/msp/MSPHelper');
|
|
const STM32 = require('./../js/protocols/stm32');
|
|
const STM32DFU = require('./../js/protocols/stm32usbdfu');
|
|
const mspDeduplicationQueue = require('./../js/msp/mspDeduplicationQueue');
|
|
|
|
TABS.firmware_flasher = {};
|
|
TABS.firmware_flasher.initialize = function (callback) {
|
|
|
|
if (GUI.active_tab != 'firmware_flasher') {
|
|
GUI.active_tab = 'firmware_flasher';
|
|
}
|
|
|
|
var intel_hex = false, // standard intel hex in string format
|
|
parsed_hex = false, // parsed raw hex in array format
|
|
fileName = "inav.hex";
|
|
|
|
GUI.load(path.join(__dirname, "firmware_flasher.html"), function () {
|
|
// translate to user-selected language
|
|
i18n.localize();
|
|
|
|
function enable_load_online_button() {
|
|
$(".load_remote_file").text(i18n.getMessage('firmwareFlasherButtonLoadOnline')).removeClass('disabled');
|
|
}
|
|
|
|
function parse_hex(str, callback) {
|
|
// parsing hex in different thread
|
|
var worker = new Worker('./js/workers/hex_parser.js');
|
|
|
|
// "callback"
|
|
worker.onmessage = function (event) {
|
|
callback(event.data);
|
|
};
|
|
|
|
// send data/string over for processing
|
|
worker.postMessage(str);
|
|
}
|
|
|
|
function getReleaseMajor(releaseName) {
|
|
// "name":"inav-9.0.0-dev-20250124-28-d1ef85e82d8aa5bb8b85e518893c8e4f6ab61d6e"
|
|
var releaseNameExpression = /^inav-(\d+)([\d.]+)-(ci|dev)-(\d{4})(\d{2})(\d{2})-(\d+)-(\w+)$/;
|
|
var match = releaseNameExpression.exec(releaseName);
|
|
|
|
if(!match) {
|
|
console.log(releaseName + " not matched");
|
|
//alert(releaseName);
|
|
return 0;
|
|
}
|
|
|
|
return match[1];
|
|
}
|
|
|
|
function parseDevFilename(filename) {
|
|
//var targetFromFilenameExpression = /inav_([\d.]+)?_?([^.]+)\.(.*)/;
|
|
// inav_8.0.0_TUNERCF405_dev-20240617-88fb1d0.hex
|
|
// inav_8.0.0_TUNERCF405_ci-20240617-88fb1d0.hex
|
|
var targetFromFilenameExpression = /^inav_(\d+)([\d.]+)_([A-Za-z0-9_]+)_(ci|dev)-(\d{4})(\d{2})(\d{2})-(\w+)\.(hex)$/;
|
|
var match = targetFromFilenameExpression.exec(filename);
|
|
|
|
if (!match) {
|
|
console.log(filename + " not matched");
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
raw_target: match[3],
|
|
target: match[3].replace("_", " "),
|
|
format: match[9],
|
|
version: match[1]+match[2],
|
|
major: match[1]
|
|
};
|
|
}
|
|
|
|
function parseFilename(filename) {
|
|
//var targetFromFilenameExpression = /inav_([\d.]+)?_?([^.]+)\.(.*)/;
|
|
var targetFromFilenameExpression = /inav_([\d.]+(?:-rc\d+)?)?_?([^.]+)\.(.*)/;
|
|
var match = targetFromFilenameExpression.exec(filename);
|
|
|
|
if (!match) {
|
|
return null;
|
|
}
|
|
|
|
//GUI.log("non dev: match[2]: " + match[2] + " match[3]: " + match[3]);
|
|
|
|
return {
|
|
raw_target: match[2],
|
|
target: match[2].replace("_", " "),
|
|
format: match[3],
|
|
};
|
|
}
|
|
|
|
$('input.show_development_releases').on('click', function () {
|
|
let selectedTarget = String($('select[name="board"]').val());
|
|
GUI.log(i18n.getMessage('selectedTarget') + selectedTarget);
|
|
buildBoardOptions();
|
|
GUI.log(i18n.getMessage('toggledRCs'));
|
|
if (selectedTarget === "0") {
|
|
TABS.firmware_flasher.getTarget();
|
|
} else {
|
|
$('select[name="board"] option[value=' + selectedTarget + ']').attr("selected", "selected");
|
|
$('select[name="board"]').trigger('change');
|
|
}
|
|
});
|
|
|
|
$('.target_search').on('input', function(){
|
|
var searchText = $('.target_search').val().toLocaleLowerCase();
|
|
|
|
$('#board_targets option').each(function(i){
|
|
var target = $(this);
|
|
//alert("Comparing " + searchText + " with " + target.text());
|
|
if (searchText.length > 0 && i !== 0) {
|
|
if (target.text().toLowerCase().includes(searchText) || target.val().toLowerCase().includes(searchText)) {
|
|
target.show();
|
|
} else {
|
|
target.hide();
|
|
}
|
|
} else {
|
|
target.show();
|
|
}
|
|
});
|
|
});
|
|
|
|
var buildBoardOptions = function(releasesData) {
|
|
const start = performance.now();
|
|
var boards_e = $('select[name="board"]').empty();
|
|
var versions_e = $('select[name="firmware_version"]').empty();
|
|
var showDevReleases = ($('input.show_development_releases').is(':checked'));
|
|
|
|
boards_e.append($("<option value='0'>{0}</option>".format(i18n.getMessage('firmwareFlasherOptionLabelSelectBoard'))));
|
|
versions_e.append($("<option value='0'>{0}</option>".format(i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion'))));
|
|
|
|
var releases = {};
|
|
var sortedTargets = [];
|
|
var unsortedTargets = [];
|
|
|
|
TABS.firmware_flasher.releasesData.forEach(function(release){
|
|
release.assets.forEach(function(asset){
|
|
var result = parseFilename(asset.name);
|
|
|
|
if ((!showDevReleases && release.prerelease) || !result) {
|
|
return;
|
|
}
|
|
if($.inArray(result.target, unsortedTargets) == -1) {
|
|
unsortedTargets.push(result.target);
|
|
}
|
|
});
|
|
});
|
|
|
|
if (showDevReleases) {
|
|
var majorCount = {};
|
|
TABS.firmware_flasher.devReleasesData.forEach(function (release) {
|
|
release.assets.forEach(function (asset) {
|
|
var result = parseDevFilename(asset.name);
|
|
|
|
if (result && $.inArray(result.target, unsortedTargets) == -1) {
|
|
unsortedTargets.push(result.target);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
sortedTargets = unsortedTargets.sort();
|
|
|
|
sortedTargets.forEach(function(release) {
|
|
releases[release] = [];
|
|
});
|
|
|
|
TABS.firmware_flasher.releasesData.forEach(function(release){
|
|
|
|
var versionFromTagExpression = /v?(.*)/;
|
|
var matchVersionFromTag = versionFromTagExpression.exec(release.tag_name);
|
|
var version = matchVersionFromTag[1];
|
|
|
|
release.assets.forEach(function(asset){
|
|
var result = parseFilename(asset.name);
|
|
if ((!showDevReleases && release.prerelease) || !result) {
|
|
return;
|
|
}
|
|
|
|
if (result.format != 'hex') {
|
|
return;
|
|
}
|
|
|
|
var date = new Date(release.published_at);
|
|
var formattedDate = "{0}-{1}-{2} {3}:{4}".format(
|
|
date.getFullYear(),
|
|
date.getMonth() + 1,
|
|
date.getDate(),
|
|
date.getUTCHours(),
|
|
date.getMinutes()
|
|
);
|
|
|
|
var descriptor = {
|
|
"releaseUrl": release.html_url,
|
|
"name" : semver.clean(release.name),
|
|
"version" : release.tag_name,
|
|
"url" : asset.browser_download_url,
|
|
"file" : asset.name,
|
|
"raw_target": result.raw_target,
|
|
"target" : result.target,
|
|
"date" : formattedDate,
|
|
"notes" : release.body,
|
|
"status" : release.prerelease ? "release-candidate" : "stable"
|
|
};
|
|
releases[result.target].push(descriptor);
|
|
});
|
|
});
|
|
|
|
if(showDevReleases && TABS.firmware_flasher.devReleasesData) {
|
|
var majorCount = {};
|
|
TABS.firmware_flasher.devReleasesData.forEach(function(release){
|
|
var major = getReleaseMajor(release.name);
|
|
|
|
if (!(major in majorCount)) {
|
|
majorCount[major] = 0;
|
|
}
|
|
|
|
if(majorCount[major] >= 10) {
|
|
return;
|
|
}
|
|
|
|
majorCount[major]++;
|
|
|
|
var versionFromTagExpression = /v?(.*)/;
|
|
var matchVersionFromTag = versionFromTagExpression.exec(release.tag_name);
|
|
var version = matchVersionFromTag[1];
|
|
|
|
release.assets.forEach(function(asset){
|
|
var result = parseDevFilename(asset.name);
|
|
if ((!showDevReleases && release.prerelease) || !result) {
|
|
return;
|
|
}
|
|
|
|
if (result.format != 'hex') {
|
|
return;
|
|
}
|
|
|
|
var date = new Date(release.published_at);
|
|
var formattedDate = "{0}-{1}-{2} {3}:{4}".format(
|
|
date.getFullYear(),
|
|
date.getMonth() + 1,
|
|
date.getDate(),
|
|
date.getUTCHours(),
|
|
date.getMinutes()
|
|
);
|
|
|
|
var descriptor = {
|
|
"releaseUrl": release.html_url,
|
|
"name" : semver.clean(release.name),
|
|
"version" : release.tag_name,
|
|
"url" : asset.browser_download_url,
|
|
"file" : asset.name,
|
|
"raw_target": result.raw_target,
|
|
"target" : result.target,
|
|
"date" : formattedDate,
|
|
"notes" : release.body,
|
|
"status" : release.prerelease ? "nightly" : "stable"
|
|
};
|
|
releases[result.target].push(descriptor);
|
|
});
|
|
});
|
|
}
|
|
|
|
var selectTargets = [];
|
|
Object.keys(releases)
|
|
.sort()
|
|
.forEach(function(target, i) {
|
|
var descriptors = releases[target];
|
|
descriptors.forEach(function(descriptor){
|
|
if($.inArray(target, selectTargets) == -1) {
|
|
selectTargets.push(target);
|
|
var select_e =
|
|
$("<option value='{0}'>{1}</option>".format(
|
|
descriptor.raw_target,
|
|
descriptor.target
|
|
)).data('summary', descriptor);
|
|
boards_e.append(select_e);
|
|
}
|
|
});
|
|
});
|
|
TABS.firmware_flasher.releases = releases;
|
|
const end = performance.now();
|
|
console.log(`buildBoardOptions: ${end - start} ms`)
|
|
return;
|
|
};
|
|
|
|
$.get('https://api.github.com/repos/iNavFlight/inav-nightly/releases?per_page=50', function(releasesData) {
|
|
TABS.firmware_flasher.devReleasesData = releasesData;
|
|
}).fail(function (data){
|
|
TABS.firmware_flasher.devReleasesData = {};
|
|
if (data["responseJSON"]){
|
|
GUI.log("<b>GITHUB Query Failed: <code>{0}</code></b>".format(data["responseJSON"].message));
|
|
}
|
|
$('select[name="board"]').empty().append('<option value="0">Offline</option>');
|
|
$('select[name="firmware_version"]').empty().append('<option value="0">Offline</option>');
|
|
$('a.auto_select_target').addClass('disabled');
|
|
});
|
|
|
|
|
|
$.get('https://api.github.com/repos/iNavFlight/inav/releases?per_page=10', function (releasesData){
|
|
TABS.firmware_flasher.releasesData = releasesData;
|
|
buildBoardOptions(releasesData);
|
|
|
|
// bind events
|
|
$('select[name="board"]').on('change', function () {
|
|
|
|
$("a.load_remote_file").addClass('disabled');
|
|
var target = $(this).children("option:selected").text();
|
|
|
|
if (!GUI.connect_lock) {
|
|
$('.progress').val(0).removeClass('valid invalid');
|
|
$('span.progressLabel').text(i18n.getMessage('firmwareFlasherLoadFirmwareFile'));
|
|
$('div.git_info').slideUp();
|
|
$('div.release_info').slideUp();
|
|
$('a.flash_firmware').addClass('disabled');
|
|
|
|
var versions_e = $('select[name="firmware_version"]').empty();
|
|
if(target == 0) {
|
|
versions_e.append($("<option value='0'>{0}</option>".format(i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion'))));
|
|
} else {
|
|
versions_e.append($("<option value='0'>{0} {1}</option>".format(i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersionFor'), target)));
|
|
}
|
|
|
|
TABS.firmware_flasher.releases[target].forEach(function(descriptor) {
|
|
var select_e =
|
|
$("<option value='{0}'>{0} - {1} - {2} ({3})</option>".format(
|
|
descriptor.version,
|
|
descriptor.target,
|
|
descriptor.date,
|
|
descriptor.status
|
|
)).data('summary', descriptor);
|
|
|
|
versions_e.append(select_e);
|
|
});
|
|
}
|
|
});
|
|
|
|
$('a.auto_select_target').removeClass('disabled');
|
|
TABS.firmware_flasher.getTarget();
|
|
}).fail(function (data){
|
|
if (data["responseJSON"]){
|
|
GUI.log("<b>GITHUB Query Failed: <code>{0}</code></b>".format(data["responseJSON"].message));
|
|
}
|
|
$('select[name="board"]').empty().append('<option value="0">Offline</option>');
|
|
$('select[name="firmware_version"]').empty().append('<option value="0">Offline</option>');
|
|
$('a.auto_select_target').addClass('disabled');
|
|
});
|
|
|
|
$('a.load_file').on('click', function () {
|
|
|
|
var options = {
|
|
filters: [ { name: "HEX file", extensions: ['hex'] } ]
|
|
};
|
|
dialog.showOpenDialog(options).then(result => {
|
|
if (result.canceled) {
|
|
return;
|
|
}
|
|
|
|
let filename;
|
|
if (result.filePaths.length == 1) {
|
|
filename = result.filePaths[0];
|
|
}
|
|
|
|
$('div.git_info').slideUp();
|
|
|
|
console.log('Loading file from: ' + filename);
|
|
|
|
fs.readFile(filename, (err, data) => {
|
|
|
|
if (err) {
|
|
console.log("Error loading local file", err);
|
|
return;
|
|
}
|
|
|
|
console.log('File loaded');
|
|
|
|
parse_hex(data.toString(), function (data) {
|
|
parsed_hex = data;
|
|
|
|
if (parsed_hex) {
|
|
$('a.flash_firmware').removeClass('disabled');
|
|
|
|
$('span.progressLabel').text('Loaded Local Firmware: (' + parsed_hex.bytes_total + ' bytes)');
|
|
} else {
|
|
$('span.progressLabel').text(i18n.getMessage('firmwareFlasherHexCorrupted'));
|
|
}
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
/**
|
|
* Lock / Unlock the firmware download button according to the firmware selection dropdown.
|
|
*/
|
|
$('select[name="firmware_version"]').on('change', function(evt){
|
|
$('div.release_info').slideUp();
|
|
$('a.flash_firmware').addClass('disabled');
|
|
if (evt.target.value=="0") {
|
|
$("a.load_remote_file").addClass('disabled');
|
|
}
|
|
else {
|
|
enable_load_online_button();
|
|
}
|
|
});
|
|
|
|
$('a.load_remote_file').on('click', function () {
|
|
|
|
if ($('select[name="firmware_version"]').val() == "0") {
|
|
GUI.log(i18n.getMessage('noFirmwareSelectedToLoad'));
|
|
return;
|
|
}
|
|
|
|
function process_hex(data, summary) {
|
|
intel_hex = data;
|
|
|
|
parse_hex(intel_hex, function (data) {
|
|
parsed_hex = data;
|
|
|
|
if (parsed_hex) {
|
|
var url;
|
|
|
|
$('span.progressLabel').html('<a class="save_firmware" href="#" title="Save Firmware">Loaded Online Firmware: (' + parsed_hex.bytes_total + ' bytes)</a>');
|
|
|
|
$('a.flash_firmware').removeClass('disabled');
|
|
|
|
if (summary.commit) {
|
|
$.get('https://api.github.com/repos/iNavFlight/inav/commits/' + summary.commit, function (data) {
|
|
var data = data,
|
|
d = new Date(data.commit.author.date),
|
|
offset = d.getTimezoneOffset() / 60,
|
|
date;
|
|
|
|
date = d.getFullYear() + '.' + ('0' + (d.getMonth() + 1)).slice(-2) + '.' + ('0' + (d.getDate())).slice(-2);
|
|
date += ' @ ' + ('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2);
|
|
date += (offset > 0) ? ' GMT+' + offset : ' GMT' + offset;
|
|
|
|
$('div.git_info .committer').text(data.commit.author.name);
|
|
$('div.git_info .date').text(date);
|
|
$('div.git_info .hash').text(data.sha.slice(0, 7)).prop('href', 'https://api.github.com/repos/iNavFlight/inav/commit/' + data.sha);
|
|
|
|
$('div.git_info .message').text(data.commit.message);
|
|
|
|
$('div.git_info').slideDown();
|
|
});
|
|
}
|
|
|
|
$('div.release_info .target').text(summary.target);
|
|
|
|
var status_e = $('div.release_info .status');
|
|
if (summary.status == 'release-candidate') {
|
|
$('div.release_info .status').html(i18n.getMessage('firmwareFlasherReleaseStatusReleaseCandidate')).show();
|
|
} else {
|
|
status_e.hide();
|
|
}
|
|
|
|
$('div.release_info .name').text(summary.name).prop('href', summary.releaseUrl);
|
|
$('div.release_info .date').text(summary.date);
|
|
$('div.release_info .status').text(summary.status);
|
|
$('div.release_info .file').text(summary.file).prop('href', summary.url);
|
|
|
|
var formattedNotes = marked.parse(summary.notes);
|
|
$('div.release_info .notes').html(formattedNotes);
|
|
// Make links in the release notes open in a new window
|
|
$('div.release_info .notes a').each(function () {
|
|
$(this).attr('target', '_blank');
|
|
});
|
|
|
|
$('div.release_info').slideDown();
|
|
|
|
} else {
|
|
$('span.progressLabel').text(i18n.getMessage('firmwareFlasherHexCorrupted'));
|
|
}
|
|
});
|
|
}
|
|
|
|
function failed_to_load() {
|
|
$('span.progressLabel').text(i18n.getMessage('firmwareFlasherFailedToLoadOnlineFirmware'));
|
|
$('a.flash_firmware').addClass('disabled');
|
|
enable_load_online_button();
|
|
}
|
|
|
|
var summary = $('select[name="firmware_version"] option:selected').data('summary');
|
|
if (summary) { // undefined while list is loading or while running offline
|
|
fileName = summary.file;
|
|
$(".load_remote_file").text(i18n.getMessage('firmwareFlasherButtonLoading')).addClass('disabled');
|
|
$.get(summary.url, function (data) {
|
|
enable_load_online_button();
|
|
process_hex(data, summary);
|
|
}).fail(failed_to_load);
|
|
} else {
|
|
$('span.progressLabel').text(i18n.getMessage('firmwareFlasherFailedToLoadOnlineFirmware'));
|
|
}
|
|
});
|
|
|
|
$('a.flash_firmware').on('click', function () {
|
|
if (!$(this).hasClass('disabled')) {
|
|
if (!GUI.connect_lock) { // button disabled while flashing is in progress
|
|
if (parsed_hex != false) {
|
|
var options = {};
|
|
|
|
if ($('input.erase_chip').is(':checked')) {
|
|
options.erase_chip = true;
|
|
}
|
|
|
|
if (String($('div#port-picker #port').val()) != 'DFU') {
|
|
if (String($('div#port-picker #port').val()) != '0') {
|
|
var port = String($('div#port-picker #port').val()),
|
|
baud;
|
|
|
|
switch (GUI.operating_system) {
|
|
case 'Windows':
|
|
case 'MacOS':
|
|
case 'ChromeOS':
|
|
case 'Linux':
|
|
case 'UNIX':
|
|
baud = 921600;
|
|
break;
|
|
|
|
default:
|
|
baud = 115200;
|
|
}
|
|
|
|
if ($('input.updating').is(':checked')) {
|
|
options.no_reboot = true;
|
|
} else {
|
|
options.reboot_baud = parseInt($('div#port-picker #baud').val());
|
|
}
|
|
|
|
if ($('input.flash_manual_baud').is(':checked')) {
|
|
baud = parseInt($('#flash_manual_baud_rate').val());
|
|
}
|
|
|
|
|
|
STM32.connect(port, baud, parsed_hex, options);
|
|
} else {
|
|
console.log('Please select valid serial port');
|
|
GUI.log(i18n.getMessage('selectValidSerialPort'));
|
|
}
|
|
} else {
|
|
STM32DFU.connect(usbDevices, parsed_hex, options);
|
|
}
|
|
} else {
|
|
$('span.progressLabel').text(i18n.getMessage('firmwareFlasherFirmwareNotLoaded'));
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
$(document).on('click', 'span.progressLabel a.save_firmware', function () {
|
|
var options = {
|
|
defaultPath: fileName,
|
|
filters: [ {name: "HEX File", extensions: ['hex'] } ]
|
|
};
|
|
dialog.showSaveDialog(options).then(result => {
|
|
if (result.canceled) {
|
|
return;
|
|
}
|
|
fs.writeFileSync(result.filePath, intel_hex, (err) => {
|
|
if (err) {
|
|
GUI.log(i18n.getMessage('ErrorWritingFile'));
|
|
return console.error(err);
|
|
}
|
|
});
|
|
let sFilename = String(result.filePath.split('\\').pop().split('/').pop());
|
|
GUI.log(sFilename + i18n.getMessage('savedSuccessfully'));
|
|
});
|
|
});
|
|
|
|
|
|
if (store.get('no_reboot_sequence', false)) {
|
|
$('input.updating').prop('checked', true);
|
|
$('.flash_on_connect_wrapper').show();
|
|
} else {
|
|
$('input.updating').prop('checked', false);
|
|
}
|
|
|
|
// bind UI hook so the status is saved on change
|
|
$('input.updating').on('change', function () {
|
|
var status = $(this).is(':checked');
|
|
|
|
if (status) {
|
|
$('.flash_on_connect_wrapper').show();
|
|
} else {
|
|
$('input.flash_on_connect').prop('checked', false).trigger('change');
|
|
$('.flash_on_connect_wrapper').hide();
|
|
}
|
|
|
|
store.set('no_reboot_sequence', status);
|
|
});
|
|
|
|
$('input.updating').trigger('change');
|
|
|
|
|
|
store.get('flash_manual_baud', function (result) {
|
|
if (result.flash_manual_baud) {
|
|
$('input.flash_manual_baud').prop('checked', true);
|
|
} else {
|
|
$('input.flash_manual_baud').prop('checked', false);
|
|
}
|
|
|
|
// bind UI hook so the status is saved on change
|
|
$('input.flash_manual_baud').on('change', function () {
|
|
var status = $(this).is(':checked');
|
|
store.set('flash_manual_baud', status);
|
|
});
|
|
|
|
$('input.flash_manual_baud').trigger('change');
|
|
});
|
|
|
|
var flash_manual_baud_rate = store.get('flash_manual_baud_rate', '');
|
|
$('#flash_manual_baud_rate').val(flash_manual_baud_rate);
|
|
|
|
// bind UI hook so the status is saved on change
|
|
$('#flash_manual_baud_rate').on('change', function () {
|
|
var baud = parseInt($('#flash_manual_baud_rate').val());
|
|
store.set('flash_manual_baud_rate', baud);
|
|
});
|
|
|
|
$('input.flash_manual_baud_rate').trigger('change');
|
|
|
|
|
|
if (store.get('flash_on_connect', false)) {
|
|
$('input.flash_on_connect').prop('checked', true);
|
|
} else {
|
|
$('input.flash_on_connect').prop('checked', false);
|
|
}
|
|
|
|
$('input.flash_on_connect').on('change', function () {
|
|
var status = $(this).is(':checked');
|
|
|
|
if (status) {
|
|
var catch_new_port = function () {
|
|
PortHandler.port_detected('flash_detected_device', function (result) {
|
|
var port = result[0];
|
|
|
|
if (!GUI.connect_lock) {
|
|
GUI.log('Detected: <strong>' + port + '</strong> - triggering flash on connect');
|
|
console.log('Detected: ' + port + ' - triggering flash on connect');
|
|
|
|
// Trigger regular Flashing sequence
|
|
timeout.add('initialization_timeout', function () {
|
|
$('a.flash_firmware').trigger( "click" );
|
|
}, 100); // timeout so bus have time to initialize after being detected by the system
|
|
} else {
|
|
GUI.log('Detected <strong>' + port + '</strong> - previous device still flashing, please replug to try again');
|
|
}
|
|
|
|
// Since current port_detected request was consumed, create new one
|
|
catch_new_port();
|
|
}, false, true);
|
|
};
|
|
|
|
catch_new_port();
|
|
} else {
|
|
PortHandler.flush_callbacks();
|
|
}
|
|
|
|
store.set('flash_on_connect', status);
|
|
}).trigger('change');
|
|
|
|
|
|
|
|
if (store.get('erase_chip', false)) {
|
|
$('input.erase_chip').prop('checked', true);
|
|
} else {
|
|
$('input.erase_chip').prop('checked', false);
|
|
}
|
|
|
|
// bind UI hook so the status is saved on change
|
|
$('input.erase_chip').on('change', function () {
|
|
store.set('erase_chip', $(this).is(':checked'));
|
|
});
|
|
|
|
$('input.erase_chip').trigger('change');
|
|
|
|
|
|
|
|
$(document).keypress(function (e) {
|
|
if (e.which == 13) { // enter
|
|
// Trigger regular Flashing sequence
|
|
$('a.flash_firmware').trigger( "click" );
|
|
}
|
|
});
|
|
|
|
$('a.auto_select_target').on('click', function () {
|
|
TABS.firmware_flasher.getTarget();
|
|
});
|
|
|
|
GUI.content_ready(callback);
|
|
});
|
|
};
|
|
|
|
TABS.firmware_flasher.FLASH_MESSAGE_TYPES = {NEUTRAL : 'NEUTRAL',
|
|
VALID : 'VALID',
|
|
INVALID : 'INVALID',
|
|
ACTION : 'ACTION'};
|
|
|
|
TABS.firmware_flasher.flashingMessage = function(message, type) {
|
|
let self = this;
|
|
|
|
let progressLabel_e = $('span.progressLabel');
|
|
switch (type) {
|
|
case self.FLASH_MESSAGE_TYPES.VALID:
|
|
progressLabel_e.removeClass('invalid actionRequired')
|
|
.addClass('valid');
|
|
break;
|
|
case self.FLASH_MESSAGE_TYPES.INVALID:
|
|
progressLabel_e.removeClass('valid actionRequired')
|
|
.addClass('invalid');
|
|
break;
|
|
case self.FLASH_MESSAGE_TYPES.ACTION:
|
|
progressLabel_e.removeClass('valid invalid')
|
|
.addClass('actionRequired');
|
|
break;
|
|
case self.FLASH_MESSAGE_TYPES.NEUTRAL:
|
|
default:
|
|
progressLabel_e.removeClass('valid invalid actionRequired');
|
|
break;
|
|
}
|
|
if (message != null) {
|
|
progressLabel_e.html(message);
|
|
}
|
|
|
|
return self;
|
|
};
|
|
|
|
TABS.firmware_flasher.flashProgress = function(value) {
|
|
$('.progress').val(value);
|
|
|
|
return this;
|
|
};
|
|
|
|
TABS.firmware_flasher.cleanup = function (callback) {
|
|
PortHandler.flush_callbacks();
|
|
|
|
// unbind "global" events
|
|
$(document).unbind('keypress');
|
|
$(document).off('click', 'span.progressLabel a');
|
|
|
|
if (callback) callback();
|
|
};
|
|
|
|
TABS.firmware_flasher.getTarget = function() {
|
|
GUI.log(i18n.getMessage('automaticTargetSelect'));
|
|
|
|
var selected_baud = parseInt($('#baud').val());
|
|
var selected_port = $('#port').find('option:selected').data().isManual ? $('#port-override').val() : String($('#port').val());
|
|
|
|
if (selected_port !== 'DFU') {
|
|
if (!selected_port || selected_port == '0') {
|
|
GUI.log(i18n.getMessage('targetPrefetchFailNoPort'));
|
|
} else {
|
|
console.log('Connecting to: ' + selected_port);
|
|
GUI.connecting_to = selected_port;
|
|
|
|
if (selected_port == 'tcp' || selected_port == 'udp') {
|
|
CONFIGURATOR.connection.connect($portOverride.val(), {}, TABS.firmware_flasher.onOpen);
|
|
} else {
|
|
CONFIGURATOR.connection.connect(selected_port, {bitrate: selected_baud}, TABS.firmware_flasher.onOpen);
|
|
}
|
|
}
|
|
} else {
|
|
GUI.log(i18n.getMessage('targetPrefetchFailDFU'));
|
|
}
|
|
};
|
|
|
|
TABS.firmware_flasher.onOpen = function(openInfo) {
|
|
if (openInfo) {
|
|
GUI.connected_to = GUI.connecting_to;
|
|
|
|
// reset connecting_to
|
|
GUI.connecting_to = false;
|
|
|
|
// save selected port with chrome.storage if the port differs
|
|
var last_used_port = store.get('last_used_port', '');
|
|
if (last_used_port) {
|
|
if (last_used_port != GUI.connected_to) {
|
|
// last used port doesn't match the one found in local db, we will store the new one
|
|
store.set('last_used_port', GUI.connected_to);
|
|
}
|
|
} else {
|
|
// variable isn't stored yet, saving
|
|
store.set('last_used_port', GUI.connected_to);
|
|
}
|
|
|
|
|
|
store.set('last_used_bps', CONFIGURATOR.connection.bitrate);
|
|
store.set('wireless_mode_enabled', $('#wireless-mode').is(":checked"));
|
|
|
|
CONFIGURATOR.connection.addOnReceiveListener(SerialBackend.read_serial);
|
|
|
|
// disconnect after 10 seconds with error if we don't get IDENT data
|
|
timeout.add('connecting', function () {
|
|
if (!CONFIGURATOR.connectionValid) {
|
|
GUI.log(i18n.getMessage('targetPrefetchFail') + i18n.getMessage('noConfigurationReceived'));
|
|
|
|
TABS.firmware_flasher.closeTempConnection();
|
|
}
|
|
}, 10000);
|
|
|
|
FC.resetState();
|
|
|
|
// request configuration data. Start with MSPv1 and
|
|
// upgrade to MSPv2 if possible.
|
|
MSP.protocolVersion = MSP.constants.PROTOCOL_V2;
|
|
MSP.send_message(MSPCodes.MSP_API_VERSION, false, false, function () {
|
|
|
|
if (FC.CONFIG.apiVersion === "0.0.0") {
|
|
GUI_control.prototype.log("Cannot prefetch target: <span style='color: red; font-weight: bolder'><strong>" + i18n.getMessage("illegalStateRestartRequired") + "</strong></span>");
|
|
FC.restartRequired = true;
|
|
return;
|
|
}
|
|
|
|
MSP.send_message(MSPCodes.MSP_FC_VARIANT, false, false, function () {
|
|
if (FC.CONFIG.flightControllerIdentifier == 'INAV') {
|
|
MSP.send_message(MSPCodes.MSP_FC_VERSION, false, false, function () {
|
|
if (semver.lt(FC.CONFIG.flightControllerVersion, "5.0.0")) {
|
|
GUI.log(i18n.getMessage('targetPrefetchFailOld'));
|
|
TABS.firmware_flasher.closeTempConnection();
|
|
} else {
|
|
mspHelper.getCraftName(function(name) {
|
|
if (name) {
|
|
FC.CONFIG.name = name;
|
|
}
|
|
TABS.firmware_flasher.onValidFirmware();
|
|
});
|
|
}
|
|
});
|
|
} else {
|
|
GUI.log(i18n.getMessage('targetPrefetchFailNonINAV'));
|
|
TABS.firmware_flasher.closeTempConnection();
|
|
}
|
|
});
|
|
});
|
|
} else {
|
|
GUI.log(i18n.getMessage('targetPrefetchFail') + i18n.getMessage('serialPortOpenFail'));
|
|
return;
|
|
}
|
|
};
|
|
|
|
TABS.firmware_flasher.onValidFirmware = function() {
|
|
MSP.send_message(MSPCodes.MSP_BUILD_INFO, false, false, function () {
|
|
MSP.send_message(MSPCodes.MSP_BOARD_INFO, false, false, function () {
|
|
$('select[name="board"] option[value=' + FC.CONFIG.target + ']').attr("selected", "selected");
|
|
GUI.log(i18n.getMessage('targetPrefetchsuccessful') + FC.CONFIG.target);
|
|
|
|
TABS.firmware_flasher.closeTempConnection();
|
|
$('select[name="board"]').trigger('change');
|
|
});
|
|
});
|
|
};
|
|
|
|
TABS.firmware_flasher.closeTempConnection = function() {
|
|
timeout.killAll();
|
|
interval.killAll(['global_data_refresh', 'msp-load-update', 'ltm-connection-check']);
|
|
|
|
mspQueue.flush();
|
|
mspQueue.freeHardLock();
|
|
mspQueue.freeSoftLock();
|
|
mspDeduplicationQueue.flush();
|
|
CONFIGURATOR.connection.emptyOutputBuffer();
|
|
|
|
CONFIGURATOR.connectionValid = false;
|
|
GUI.connected_to = false;
|
|
|
|
CONFIGURATOR.connection.disconnect();
|
|
MSP.disconnect_cleanup();
|
|
}; |