1
0
Fork 0
mirror of https://github.com/betaflight/betaflight-configurator.git synced 2025-07-23 00:05:22 +03:00

Added flasing of Unified Targets from configurations.

This commit is contained in:
mikeller 2019-08-14 01:41:14 +12:00
parent e2c6cfae0f
commit 1079a854aa
3 changed files with 190 additions and 48 deletions

110
src/js/ConfigInserter.js Normal file
View file

@ -0,0 +1,110 @@
'use strict';
var ConfigInserter = function () {
}
const CUSTOM_DEFAULTS_POINTER_ADDRESS = 0x08002800;
const BLOCK_SIZE = 16384;
function seek(firmware, address) {
var index = 0;
for (; index < firmware.data.length && address >= firmware.data[index].address + firmware.data[index].bytes; index++);
var result = {
lineIndex: index
};
if (firmware.data[index] && address >= firmware.data[index].address) {
result.byteIndex = address - firmware.data[index].address;
}
return result;
}
function readUint32(firmware, index) {
var result = 0;
for (var position = 0; position < 4; position++) {
result += firmware.data[index.lineIndex].data[index.byteIndex++] << (8 * position);
if (index.byteIndex >= firmware.data[index.lineIndex].bytes) {
index.lineIndex++;
index.byteIndex = 0;
}
}
return result;
}
function getCustomDefaultsArea(firmware) {
var result = {};
var index = seek(firmware, CUSTOM_DEFAULTS_POINTER_ADDRESS);
if (index.byteIndex === undefined) {
return;
}
var result = {};
result.startAddress = readUint32(firmware, index);
result.endAddress = readUint32(firmware, index);
return result;
}
function generateData(firmware, input, startAddress) {
var address = startAddress;
var index = seek(firmware, address);
if (index.byteIndex !== undefined) {
throw new Error('Configuration area in firmware not free.');
}
var inputIndex = 0;
while (inputIndex < input.length) {
var remaining = input.length - inputIndex;
var line = {
address: address,
bytes: BLOCK_SIZE > remaining ? remaining : BLOCK_SIZE,
data: []
};
if (firmware.data[index.lineIndex] && (line.address + line.bytes) > firmware.data[index.lineIndex].address) {
throw new Error("Aborting data generation, free area too small.");
}
for (var i = 0; i < line.bytes; i++) {
line.data.push(input.charCodeAt(inputIndex++));
}
address = address + line.bytes;
firmware.data.splice(index.lineIndex++, 0, line);
}
firmware.bytes_total += input.length;
}
function microtime() {
var now = new Date().getTime() / 1000;
return now;
}
ConfigInserter.prototype.insertConfig = function (firmware, input) {
var time_parsing_start = microtime(); // track time
var customDefaultsArea = getCustomDefaultsArea(firmware);
if (!customDefaultsArea || customDefaultsArea.endAddress - customDefaultsArea.startAddress === 0) {
return false;
} else if (input.length >= customDefaultsArea.endAddress - customDefaultsArea.startAddress) {
throw new Error(`Custom defaults area too small (${customDefaultsArea.endAddress - customDefaultsArea.startAddress} bytes), ${input.length + 1} bytes needed.`);
}
generateData(firmware, input, customDefaultsArea.startAddress);
console.log('Custom defaults inserted in: ' + (microtime() - time_parsing_start).toFixed(4) + ' seconds.');
return true;
}

View file

@ -15,8 +15,9 @@ TABS.firmware_flasher.initialize = function (callback) {
} }
var intel_hex = false, // standard intel hex in string format var intel_hex = false; // standard intel hex in string format
parsed_hex = false; // parsed raw hex in array format var parsed_hex = false; // parsed raw hex in array format
var targetConfig; // the Unified Target configuration to be spliced into the configuration
/** /**
* Change boldness of firmware option depending on cache status * Change boldness of firmware option depending on cache status
@ -365,7 +366,15 @@ TABS.firmware_flasher.initialize = function (callback) {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHANNEL, undefined); analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHANNEL, undefined);
analytics.setFirmwareData(analytics.DATA.FIRMWARE_SOURCE, 'file'); analytics.setFirmwareData(analytics.DATA.FIRMWARE_SOURCE, 'file');
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: [{description: 'HEX files', extensions: ['hex']}]}, function (fileEntry) { chrome.fileSystem.chooseEntry({
type: 'openFile',
accepts: [
{
description: 'target files',
extensions: ['hex', 'config']
}
]
}, function (fileEntry) {
if (chrome.runtime.lastError) { if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message); console.error(chrome.runtime.lastError.message);
@ -383,28 +392,30 @@ TABS.firmware_flasher.initialize = function (callback) {
var reader = new FileReader(); var reader = new FileReader();
reader.onloadend = function(e) { reader.onloadend = function(e) {
if (e.total != 0 && e.total == e.loaded) { if (e.total != 0 && e.total == e.loaded) {
console.log('File loaded (' + e.loaded + ')'); console.log('File loaded (' + e.loaded + ')');
intel_hex = e.target.result; if (file.name.split('.').pop() === "hex") {
intel_hex = e.target.result;
analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHECKSUM, objectHash.sha1(intel_hex)); analytics.setFirmwareData(analytics.DATA.FIRMWARE_CHECKSUM, objectHash.sha1(intel_hex));
parse_hex(intel_hex, function (data) { parse_hex(intel_hex, function (data) {
parsed_hex = data; parsed_hex = data;
if (parsed_hex) { if (parsed_hex) {
analytics.setFirmwareData(analytics.DATA.FIRMWARE_SIZE, parsed_hex.bytes_total); analytics.setFirmwareData(analytics.DATA.FIRMWARE_SIZE, parsed_hex.bytes_total);
self.enableFlashing(true); self.enableFlashing(true);
self.flashingMessage(i18n.getMessage('firmwareFlasherFirmwareLocalLoaded', parsed_hex.bytes_total), self.FLASH_MESSAGE_TYPES.NEUTRAL); self.flashingMessage(i18n.getMessage('firmwareFlasherFirmwareLocalLoaded', parsed_hex.bytes_total), self.FLASH_MESSAGE_TYPES.NEUTRAL);
} else { } else {
self.flashingMessage('firmwareFlasherHexCorrupted', self.FLASH_MESSAGE_TYPES.INVALID); self.flashingMessage('firmwareFlasherHexCorrupted', self.FLASH_MESSAGE_TYPES.INVALID);
} }
}); });
} else {
targetConfig = e.target.result;
}
} }
}; };
@ -473,46 +484,66 @@ TABS.firmware_flasher.initialize = function (callback) {
} }
}); });
function flashFirmware(firmware) {
var options = {};
var eraseAll = false;
if ($('input.erase_chip').is(':checked')) {
options.erase_chip = true;
eraseAll = true
}
analytics.setFirmwareData(analytics.DATA.FIRMWARE_ERASE_ALL, eraseAll.toString());
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;
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());
}
analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing');
STM32.connect(port, baud, firmware, options);
} else {
console.log('Please select valid serial port');
GUI.log(i18n.getMessage('firmwareFlasherNoValidPort'));
}
} else {
analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing');
STM32DFU.connect(usbDevices, firmware, options);
}
}
$('a.flash_firmware').click(function () { $('a.flash_firmware').click(function () {
if (!$(this).hasClass('disabled')) { if (!$(this).hasClass('disabled')) {
if (!GUI.connect_lock) { // button disabled while flashing is in progress if (!GUI.connect_lock) { // button disabled while flashing is in progress
if (parsed_hex != false) { if (parsed_hex != false) {
var options = {}; try {
if (targetConfig && !parsed_hex.configInserted) {
var configInserter = new ConfigInserter();
var eraseAll = false; if (configInserter.insertConfig(parsed_hex, targetConfig)) {
if ($('input.erase_chip').is(':checked')) { parsed_hex.configInserted = true;
options.erase_chip = true;
eraseAll = true
}
analytics.setFirmwareData(analytics.DATA.FIRMWARE_ERASE_ALL, eraseAll.toString());
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;
baud = 115200;
if ($('input.updating').is(':checked')) {
options.no_reboot = true;
} else { } else {
options.reboot_baud = parseInt($('div#port-picker #baud').val()); console.log('Firmware does not support custom defaults.');
targetConfig = undefined;
} }
if ($('input.flash_manual_baud').is(':checked')) {
baud = parseInt($('#flash_manual_baud_rate').val());
}
analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing');
STM32.connect(port, baud, parsed_hex, options);
} else {
console.log('Please select valid serial port');
GUI.log(i18n.getMessage('firmwareFlasherNoValidPort'));
} }
} else {
analytics.sendEvent(analytics.EVENT_CATEGORIES.FIRMWARE, 'Flashing');
STM32DFU.connect(usbDevices, parsed_hex, options); flashFirmware(parsed_hex);
} catch (e) {
console.log(`Flashing failed: ${e.message}`);
} }
} else { } else {
$('span.progressLabel').attr('i18n','firmwareFlasherFirmwareNotLoaded').removeClass('i18n-replaced'); $('span.progressLabel').attr('i18n','firmwareFlasherFirmwareNotLoaded').removeClass('i18n-replaced');

View file

@ -168,6 +168,7 @@
<script type="text/javascript" src="./node_modules/jquery-textcomplete/dist/jquery.textcomplete.min.js"></script> <script type="text/javascript" src="./node_modules/jquery-textcomplete/dist/jquery.textcomplete.min.js"></script>
<script type="text/javascript" src="./js/CliAutoComplete.js"></script> <script type="text/javascript" src="./js/CliAutoComplete.js"></script>
<script type="text/javascript" src="./js/DarkTheme.js"></script> <script type="text/javascript" src="./js/DarkTheme.js"></script>
<script type="text/javascript" src="./js/ConfigInserter.js"></script>
<title i18n="windowTitle"></title> <title i18n="windowTitle"></title>
</head> </head>
<body> <body>