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

Auto merged - #2485 at Sat, 26 Jun 2021 00:43:00 GMT

Verify board from firmware before flashing
This commit is contained in:
J Blackman 2021-06-26 10:43:00 +10:00 committed by GitHub
commit 31603a2e05
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 181 additions and 28 deletions

View file

@ -170,6 +170,11 @@ PortHandler.detectPort = function(currentPorts) {
}
});
// Signal board verification
if (GUI.active_tab === 'firmware_flasher') {
TABS.firmware_flasher.boardNeedsVerification = true;
}
// auto-connect if enabled
if (GUI.auto_connect && !GUI.connecting_to && !GUI.connected_to) {
// start connect procedure. We need firmware flasher protection over here

View file

@ -92,7 +92,7 @@ STM32_protocol.prototype.connect = function (port, baud, hex, options, callback)
var startFlashing = function() {
// refresh device list
PortHandler.check_usb_devices(function(dfu_available) {
if(dfu_available) {
if (dfu_available) {
STM32DFU.connect(usbDevices, hex, options);
} else {
serial.connect(self.port, {bitrate: self.baud, parityBit: 'even', stopBits: 'one'}, function (openInfo) {
@ -107,6 +107,16 @@ STM32_protocol.prototype.connect = function (port, baud, hex, options, callback)
});
};
const onDisconnect = disconnectionResult => {
if (disconnectionResult) {
// delay to allow board to boot in bootloader mode
// required to detect if a DFU device appears
setTimeout(startFlashing, 1000);
} else {
GUI.connect_lock = false;
}
};
var legacyRebootAndFlash = function() {
serial.connect(self.port, {bitrate: self.options.reboot_baud}, function (openInfo) {
if (!openInfo) {
@ -124,15 +134,7 @@ STM32_protocol.prototype.connect = function (port, baud, hex, options, callback)
bufferView[0] = 0x52;
serial.send(bufferOut, function () {
serial.disconnect(function (disconnectionResult) {
if (disconnectionResult) {
// delay to allow board to boot in bootloader mode
// required to detect if a DFU device appears
setTimeout(startFlashing, 1000);
} else {
GUI.connect_lock = false;
}
});
serial.disconnect(disconnectionResult => onDisconnect(disconnectionResult));
});
});
};
@ -151,7 +153,7 @@ STM32_protocol.prototype.connect = function (port, baud, hex, options, callback)
} else {
console.log('Looking for capabilities via MSP');
MSP.send_message(MSPCodes.MSP_BOARD_INFO, false, false, function () {
MSP.send_message(MSPCodes.MSP_BOARD_INFO, false, false, () => {
var rebootMode = 0; // FIRMWARE
if (bit_check(FC.CONFIG.targetCapabilities, FC.TARGET_CAPABILITIES_FLAGS.HAS_FLASH_BOOTLOADER)) {
// Board has flash bootloader
@ -164,25 +166,36 @@ STM32_protocol.prototype.connect = function (port, baud, hex, options, callback)
rebootMode = 1; // MSP_REBOOT_BOOTLOADER_ROM;
}
var buffer = [];
buffer.push8(rebootMode);
MSP.send_message(MSPCodes.MSP_SET_REBOOT, buffer, function() {
const selectedBoard = TABS.firmware_flasher.selectedBoard;
const connectedBoard = FC.CONFIG.boardName ? FC.CONFIG.boardName : 'UNKNOWN';
// if firmware doesn't flush MSP/serial send buffers and gracefully shutdown VCP connections we won't get a reply, so don't wait for it.
function reboot() {
const buffer = [];
buffer.push8(rebootMode);
MSP.send_message(MSPCodes.MSP_SET_REBOOT, buffer, () => {
self.msp_connector.disconnect(function (disconnectionResult) {
if (disconnectionResult) {
// delay to allow board to boot in bootloader mode
// required to detect if a DFU device appears
setTimeout(startFlashing, 1000);
} else {
GUI.connect_lock = false;
}
});
// if firmware doesn't flush MSP/serial send buffers and gracefully shutdown VCP connections we won't get a reply, so don't wait for it.
self.msp_connector.disconnect(disconnectionResult => onDisconnect(disconnectionResult));
}, () => console.log('Reboot request received by device'));
}
function onAbort() {
GUI.connect_lock = false;
rebootMode = 0;
console.log('User cancelled because selected target does not match verified board');
reboot();
TABS.firmware_flasher.refresh();
}
if (selectedBoard !== connectedBoard) {
TABS.firmware_flasher.showDialogVerifyBoard(selectedBoard, connectedBoard, onAbort, reboot);
} else {
reboot();
}
}, function () {
console.log('Reboot request recevied by device');
});
});
}
};

View file

@ -18,6 +18,10 @@ const serial = {
connect: function (path, options, callback) {
const self = this;
const testUrl = path.match(/^tcp:\/\/([A-Za-z0-9\.-]+)(?:\:(\d+))?$/);
if (self.connectionId || self.connected) {
console.warn('We already connected. Aborting', self.connectionId, self.connected);
return;
}
if (testUrl) {
self.connectTcp(testUrl[1], testUrl[2], options, callback);
} else if (path === 'virtual') {

View file

@ -7,6 +7,7 @@ const firmware_flasher = {
gitHubApi: new GitHubApi(),
localFirmwareLoaded: false,
selectedBoard: undefined,
boardNeedsVerification: false,
intel_hex: undefined, // standard intel hex in string format
parsed_hex: undefined, // parsed raw hex in array format
unifiedTarget: {}, // the Unified Target configuration to be spliced into the configuration
@ -316,6 +317,8 @@ firmware_flasher.initialize = function (callback) {
$('select[name="board"]').val(boardReleases ? result.selected_board : 0).trigger('change');
}
});
verifyBoard();
}
const buildTypes = [
@ -535,7 +538,7 @@ firmware_flasher.initialize = function (callback) {
$("a.load_remote_file").addClass('disabled');
const target = $(this).val();
if (!GUI.connect_lock) {
if (!GUI.connect_lock && target) {
if (TABS.firmware_flasher.selectedBoard !== target) {
// We're sure the board actually changed
if (self.isConfigLocal) {
@ -766,6 +769,68 @@ firmware_flasher.initialize = function (callback) {
}
}
function verifyBoard() {
if (!$('option:selected', portPickerElement).data().isDFU) {
function onFinishClose() {
MSP.clearListeners();
GUI.connect_lock = false;
}
function onClose() {
serial.disconnect(onFinishClose);
MSP.disconnect_cleanup();
}
function onFinish() {
const board = FC.CONFIG.boardName;
if (board) {
$('select[name="board"]').val(board).trigger('change');
GUI.log(i18n.getMessage('firmwareFlasherBoardVerificationSuccess', {boardName: board}));
} else {
GUI.log(i18n.getMessage('firmwareFlasherBoardVerificationFail'));
}
onClose();
}
function getBoard() {
console.log(`Requesting board information`);
MSP.send_message(MSPCodes.MSP_API_VERSION, false, false, () => MSP.send_message(MSPCodes.MSP_BOARD_INFO, false, false, onFinish));
}
function onConnect(openInfo) {
if (openInfo) {
GUI.connect_lock = true;
serial.onReceive.addListener(data => MSP.read(data));
const mspHelper = new MspHelper();
MSP.listen(mspHelper.process_data.bind(mspHelper));
getBoard();
} else {
console.dir('Failed to open connection:', openInfo);
}
}
// Can only verify if not in DFU mode.
if (String(portPickerElement.val()) !== '0') {
const port = String(portPickerElement.val());
let baud = 115200;
if ($('input.flash_manual_baud').is(':checked')) {
baud = parseInt($('#flash_manual_baud_rate').val());
}
console.log('Query board information to preselect right firmware');
if (!(serial.connected || serial.connectionId)) {
serial.connect(port, {bitrate: baud}, onConnect);
} else {
console.warn('Attempting to connect while there still is a connection', serial.connected, serial.connectionId);
serial.disconnect();
}
} else {
console.log('Please select valid serial port');
GUI.log(i18n.getMessage('firmwareFlasherNoValidPort'));
}
}
}
ConfigStorage.get('erase_chip', function (result) {
if (result.erase_chip) {
$('input.erase_chip').prop('checked', true);
@ -1015,6 +1080,13 @@ firmware_flasher.initialize = function (callback) {
if ($('option:selected', this).data().isDFU) {
exitDfuElement.removeClass('disabled');
} else {
// Porthandler resets board on port detect
if (self.boardNeedsVerification) {
// reset to prevent multiple calls
self.boardNeedsVerification = false;
verifyBoard();
}
$("a.load_remote_file").removeClass('disabled');
$("a.load_file").removeClass('disabled');
exitDfuElement.addClass('disabled');
@ -1241,6 +1313,37 @@ firmware_flasher.enableFlashing = function (enabled) {
}
};
firmware_flasher.refresh = function (callback) {
const self = this;
GUI.tab_switch_cleanup(function() {
self.initialize();
if (callback) {
callback();
}
});
};
firmware_flasher.showDialogVerifyBoard = function (selected, verified, onAbort, onAccept) {
const dialogVerifyBoard = $('#dialog-verify-board')[0];
$('#dialog-verify-board-content').html(i18n.getMessage('firmwareFlasherVerifyBoard', {selected_board: selected, verified_board: verified}));
if (!dialogVerifyBoard.hasAttribute('open')) {
dialogVerifyBoard.showModal();
$('#dialog-verify-board-abort-confirmbtn').click(function() {
ConfigStorage.set({'selected_board': FC.CONFIG.boardName});
dialogVerifyBoard.close();
onAbort();
});
$('#dialog-verify-board-continue-confirmbtn').click(function() {
dialogVerifyBoard.close();
onAccept();
});
}
};
firmware_flasher.FLASH_MESSAGE_TYPES = {
NEUTRAL : 'NEUTRAL',
VALID : 'VALID',