betaflight-configurator/js/protocols/stm32.js

692 lines
29 KiB
JavaScript
Raw Normal View History

2014-03-08 05:25:15 +00:00
/*
2014-01-28 11:21:35 +00:00
STM32 F103 serial bus seems to properly initialize with quite a huge auto-baud range
From 921600 down to 1200, i don't recommend getting any lower then that
Official "specs" are from 115200 to 1200
popular choices - 921600, 460800, 256000, 230400, 153600, 128000, 115200, 57600, 38400, 28800, 19200
2014-01-28 11:21:35 +00:00
*/
2014-08-09 18:47:07 +00:00
'use strict';
2014-01-28 11:21:35 +00:00
2014-08-14 15:00:32 +00:00
var STM32_protocol = function () {
this.baud;
this.options = {};
this.callback; // ref
2013-12-10 07:19:18 +00:00
this.hex; // ref
this.verify_hex;
2014-03-08 05:25:15 +00:00
this.receive_buffer;
2014-03-08 05:25:15 +00:00
this.bytes_to_read = 0; // ref
this.read_callback; // ref
2014-03-08 05:25:15 +00:00
this.upload_time_start;
this.upload_process_alive;
2014-03-08 05:25:15 +00:00
this.status = {
2014-01-27 22:15:34 +00:00
ACK: 0x79, // y
NACK: 0x1F
};
2014-03-08 05:25:15 +00:00
this.command = {
get: 0x00, // Gets the version and the allowed commands supported by the current version of the bootloader
get_ver_r_protect_s: 0x01, // Gets the bootloader version and the Read Protection status of the Flash memory
get_ID: 0x02, // Gets the chip ID
read_memory: 0x11, // Reads up to 256 bytes of memory starting from an address specified by the application
go: 0x21, // Jumps to user application code located in the internal Flash memory or in SRAM
write_memory: 0x31, // Writes up to 256 bytes to the RAM or Flash memory starting from an address specified by the application
erase: 0x43, // Erases from one to all the Flash memory pages
extended_erase: 0x44, // Erases from one to all the Flash memory pages using two byte addressing mode (v3.0+ usart).
write_protect: 0x63, // Enables the write protection for some sectors
write_unprotect: 0x73, // Disables the write protection for all Flash memory sectors
readout_protect: 0x82, // Enables the read protection
readout_unprotect: 0x92 // Disables the read protection
};
2014-03-08 05:25:15 +00:00
// Erase (x043) and Extended Erase (0x44) are exclusive. A device may support either the Erase command or the Extended Erase command but not both.
this.available_flash_size = 0;
this.page_size = 0;
};
// no input parameters
STM32_protocol.prototype.connect = function (port, baud, hex, options, callback) {
var self = this;
2013-12-10 07:19:18 +00:00
self.hex = hex;
self.baud = baud;
self.callback = callback;
2014-03-08 05:25:15 +00:00
// we will crunch the options here since doing it inside initialization routine would be too late
self.options = {
no_reboot: false,
reboot_baud: false,
erase_chip: false,
flash_slowly: false
};
2014-03-08 05:25:15 +00:00
if (options.no_reboot) {
self.options.no_reboot = true;
} else {
self.options.reboot_baud = options.reboot_baud;
}
2014-03-08 05:25:15 +00:00
if (options.erase_chip) {
self.options.erase_chip = true;
}
2014-03-08 05:25:15 +00:00
if (options.flash_slowly) {
self.options.flash_slowly = true;
self.baud = 115200;
}
if (self.options.no_reboot) {
serial.connect(port, {bitrate: self.baud, parityBit: 'even', stopBits: 'one'}, function (openInfo) {
if (openInfo) {
// we are connected, disabling connect button in the UI
GUI.connect_lock = true;
2014-03-08 05:25:15 +00:00
self.initialize();
} else {
GUI.log('<span style="color: red">Failed</span> to open serial port');
}
});
} else {
2014-08-14 15:00:32 +00:00
serial.connect(port, {bitrate: self.options.reboot_baud}, function (openInfo) {
if (openInfo) {
console.log('Sending ascii "R" to reboot');
// we are connected, disabling connect button in the UI
GUI.connect_lock = true;
var bufferOut = new ArrayBuffer(1);
var bufferView = new Uint8Array(bufferOut);
bufferView[0] = 0x52;
2014-08-14 15:00:32 +00:00
serial.send(bufferOut, function () {
serial.disconnect(function (result) {
if (result) {
serial.connect(port, {bitrate: self.baud, parityBit: 'even', stopBits: 'one'}, function (openInfo) {
if (openInfo) {
self.initialize();
} else {
GUI.connect_lock = false;
GUI.log('<span style="color: red">Failed</span> to open serial port');
}
});
} else {
GUI.connect_lock = false;
}
});
});
} else {
GUI.log('<span style="color: red">Failed</span> to open serial port');
}
});
}
};
// initialize certain variables and start timers that oversee the communication
2014-08-14 15:00:32 +00:00
STM32_protocol.prototype.initialize = function () {
var self = this;
2014-03-08 05:25:15 +00:00
// reset and set some variables before we start
self.receive_buffer = [];
self.verify_hex = [];
2014-03-08 05:25:15 +00:00
self.upload_time_start = new Date().getTime();
self.upload_process_alive = false;
2014-03-08 05:25:15 +00:00
2013-11-16 12:03:42 +00:00
// reset progress bar to initial state
self.progress_bar_e = $('.progress');
self.progress_bar_e.val(0);
self.progress_bar_e.removeClass('valid invalid');
// lock some UI elements TODO needs rework
$('select[name="release"]').prop('disabled', true);
2014-08-14 15:00:32 +00:00
serial.onReceive.addListener(function (info) {
2014-01-18 11:44:51 +00:00
self.read(info);
});
2014-03-08 05:25:15 +00:00
2014-08-14 15:00:32 +00:00
GUI.interval_add('STM32_timeout', function () {
if (self.upload_process_alive) { // process is running
self.upload_process_alive = false;
} else {
console.log('STM32 - timed out, programming failed ...');
2014-08-30 08:30:28 +00:00
$('span.progressLabel').text('STM32 - timed out, programming: FAILED');
self.progress_bar_e.addClass('invalid');
2014-07-16 10:59:12 +00:00
googleAnalytics.sendEvent('Flashing', 'Programming', 'timeout');
2014-03-08 05:25:15 +00:00
// protocol got stuck, clear timer and disconnect
GUI.interval_remove('STM32_timeout');
2014-03-08 05:25:15 +00:00
// exit
self.upload_procedure(99);
}
}, 2000);
2014-03-08 05:25:15 +00:00
self.upload_procedure(1);
};
// no input parameters
// this method should be executed every 1 ms via interval timer
2014-08-14 15:00:32 +00:00
STM32_protocol.prototype.read = function (readInfo) {
// routine that fills the buffer
2014-01-18 11:44:51 +00:00
var data = new Uint8Array(readInfo.data);
2014-03-08 05:25:15 +00:00
2014-01-18 11:44:51 +00:00
for (var i = 0; i < data.length; i++) {
2014-03-08 05:25:15 +00:00
this.receive_buffer.push(data[i]);
2014-01-18 11:44:51 +00:00
}
2014-03-08 05:25:15 +00:00
// routine that fetches data from buffer if statement is true
2014-01-27 22:15:34 +00:00
if (this.receive_buffer.length >= this.bytes_to_read && this.bytes_to_read != 0) {
var data = this.receive_buffer.slice(0, this.bytes_to_read); // bytes requested
this.receive_buffer.splice(0, this.bytes_to_read); // remove read bytes
2014-03-08 05:25:15 +00:00
2014-01-27 22:15:34 +00:00
this.bytes_to_read = 0; // reset trigger
2014-03-08 05:25:15 +00:00
2014-01-27 22:15:34 +00:00
this.read_callback(data);
}
};
// we should always try to consume all "proper" available data while using retrieve
2014-08-14 15:00:32 +00:00
STM32_protocol.prototype.retrieve = function (n_bytes, callback) {
2014-01-27 22:15:34 +00:00
if (this.receive_buffer.length >= n_bytes) {
// data that we need are there, process immediately
var data = this.receive_buffer.slice(0, n_bytes);
this.receive_buffer.splice(0, n_bytes); // remove read bytes
2014-03-08 05:25:15 +00:00
2014-01-27 22:15:34 +00:00
callback(data);
} else {
// still waiting for data, add callback
this.bytes_to_read = n_bytes;
this.read_callback = callback;
}
2014-01-18 11:44:51 +00:00
};
// Array = array of bytes that will be send over serial
// bytes_to_read = received bytes necessary to trigger read_callback
// callback = function that will be executed after received bytes = bytes_to_read
2014-08-14 15:00:32 +00:00
STM32_protocol.prototype.send = function (Array, bytes_to_read, callback) {
// flip flag
this.upload_process_alive = true;
2014-03-08 05:25:15 +00:00
var bufferOut = new ArrayBuffer(Array.length);
var bufferView = new Uint8Array(bufferOut);
2014-03-08 05:25:15 +00:00
// set Array values inside bufferView (alternative to for loop)
bufferView.set(Array);
2014-03-08 05:25:15 +00:00
// update references
this.bytes_to_read = bytes_to_read;
2014-01-27 20:37:42 +00:00
this.read_callback = callback;
2014-03-08 05:25:15 +00:00
2014-01-27 20:37:42 +00:00
// empty receive buffer before next command is out
this.receive_buffer = [];
// send over the actual data
2014-08-14 15:00:32 +00:00
serial.send(bufferOut, function (writeInfo) {});
};
2014-03-08 05:25:15 +00:00
// val = single byte to be verified
// data = response of n bytes from mcu (array)
// result = true/false
2014-08-14 15:00:32 +00:00
STM32_protocol.prototype.verify_response = function (val, data) {
if (val != data[0]) {
console.error('STM32 Communication failed, wrong response, expected: ' + val + ' received: ' + data[0]);
2014-08-30 08:30:28 +00:00
$('span.progressLabel').text('STM32 Communication failed, wrong response, expected: ' + val + ' received: ' + data[0]);
self.progress_bar_e.addClass('invalid');
2014-03-08 05:25:15 +00:00
// disconnect
this.upload_procedure(99);
2014-03-08 05:25:15 +00:00
return false;
}
2014-03-08 05:25:15 +00:00
return true;
};
// input = 16 bit value
// result = true/false
2014-08-14 15:00:32 +00:00
STM32_protocol.prototype.verify_chip_signature = function (signature) {
switch (signature) {
2013-11-15 15:31:16 +00:00
case 0x412: // not tested
2013-11-15 15:17:43 +00:00
console.log('Chip recognized as F1 Low-density');
break;
case 0x410:
console.log('Chip recognized as F1 Medium-density');
this.available_flash_size = 131072;
this.page_size = 1024;
break;
2013-11-15 15:31:16 +00:00
case 0x414: // not tested
2013-11-15 15:17:43 +00:00
console.log('Chip recognized as F1 High-density');
break;
2013-11-15 15:31:16 +00:00
case 0x418: // not tested
2013-11-15 15:17:43 +00:00
console.log('Chip recognized as F1 Connectivity line');
break;
2013-11-15 15:31:16 +00:00
case 0x420: // not tested
2013-11-15 15:17:43 +00:00
console.log('Chip recognized as F1 Medium-density value line');
break;
2013-11-15 15:31:16 +00:00
case 0x428: // not tested
2013-11-15 15:17:43 +00:00
console.log('Chip recognized as F1 High-density value line');
break;
2013-11-15 15:31:16 +00:00
case 0x430: // not tested
2013-11-15 15:17:43 +00:00
console.log('Chip recognized as F1 XL-density value line');
2013-11-15 15:31:16 +00:00
break;
case 0x416: // not tested
console.log('Chip recognized as L1 Medium-density ultralow power');
break;
2013-11-15 15:35:36 +00:00
case 0x436: // not tested
2013-11-15 15:31:16 +00:00
console.log('Chip recognized as L1 High-density ultralow power');
break;
2013-11-15 15:35:36 +00:00
case 0x427: // not tested
2013-11-15 15:31:16 +00:00
console.log('Chip recognized as L1 Medium-density plus ultralow power');
break;
2013-11-15 15:35:36 +00:00
case 0x411: // not tested
2013-11-15 15:31:16 +00:00
console.log('Chip recognized as F2 STM32F2xxxx');
break;
2013-11-15 15:35:36 +00:00
case 0x440: // not tested
2013-11-15 15:31:16 +00:00
console.log('Chip recognized as F0 STM32F051xx');
break;
2013-11-15 15:35:36 +00:00
case 0x444: // not tested
2013-11-15 15:31:16 +00:00
console.log('Chip recognized as F0 STM32F050xx');
break;
2013-11-15 15:35:36 +00:00
case 0x413: // not tested
2013-11-15 15:31:16 +00:00
console.log('Chip recognized as F4 STM32F40xxx/41xxx');
break;
2013-11-15 15:35:36 +00:00
case 0x419: // not tested
2013-11-15 15:31:16 +00:00
console.log('Chip recognized as F4 STM32F427xx/437xx, STM32F429xx/439xx');
break;
2013-11-15 15:35:36 +00:00
case 0x432: // not tested
2013-11-15 15:31:16 +00:00
console.log('Chip recognized as F3 STM32F37xxx, STM32F38xxx');
break;
2013-11-15 15:35:36 +00:00
case 0x422: // not tested
2013-11-15 15:31:16 +00:00
console.log('Chip recognized as F3 STM32F30xxx, STM32F31xxx');
break;
2013-12-10 07:53:53 +00:00
}
2014-03-08 05:25:15 +00:00
if (this.available_flash_size > 0) {
if (this.hex.bytes_total < this.available_flash_size) {
2013-12-10 07:53:53 +00:00
return true;
} else {
console.log('Supplied hex is bigger then flash available on the chip, HEX: ' + this.hex.bytes_total + ' bytes, limit = ' + this.available_flash_size + ' bytes');
2014-03-08 05:25:15 +00:00
return false;
2013-12-10 07:53:53 +00:00
}
2014-03-08 05:25:15 +00:00
}
2013-12-10 07:53:53 +00:00
console.log('Chip NOT recognized: ' + signature);
2014-03-08 05:25:15 +00:00
2013-12-10 07:53:53 +00:00
return false;
};
// first_array = usually hex_to_flash array
// second_array = usually verify_hex array
// result = true/false
2014-08-14 15:00:32 +00:00
STM32_protocol.prototype.verify_flash = function (first_array, second_array) {
for (var i = 0; i < first_array.length; i++) {
if (first_array[i] != second_array[i]) {
console.log('Verification failed on byte: ' + i + ' expected: 0x' + first_array[i].toString(16) + ' received: 0x' + second_array[i].toString(16));
return false;
}
}
2014-03-08 05:25:15 +00:00
console.log('Verification successful, matching: ' + first_array.length + ' bytes');
2014-03-08 05:25:15 +00:00
return true;
};
// step = value depending on current state of upload_procedure
2014-08-14 15:00:32 +00:00
STM32_protocol.prototype.upload_procedure = function (step) {
var self = this;
2014-03-08 05:25:15 +00:00
switch (step) {
case 1:
// initialize serial interface on the MCU side, auto baud rate settings
2014-08-30 08:30:28 +00:00
$('span.progressLabel').text('Contacting bootloader ...');
2013-12-03 20:23:31 +00:00
var send_counter = 0;
2014-08-14 15:00:32 +00:00
GUI.interval_add('stm32_initialize_mcu', function () { // 200 ms interval (just in case mcu was already initialized), we need to break the 2 bytes command requirement
self.send([0x7F], 1, function (reply) {
2014-01-26 23:49:28 +00:00
if (reply[0] == 0x7F || reply[0] == self.status.ACK || reply[0] == self.status.NACK) {
2013-12-03 20:23:31 +00:00
GUI.interval_remove('stm32_initialize_mcu');
console.log('STM32 - Serial interface initialized on the MCU side');
2014-03-08 05:25:15 +00:00
2013-12-03 20:23:31 +00:00
// proceed to next step
self.upload_procedure(2);
} else {
2014-08-30 08:30:28 +00:00
$('span.progressLabel').text('Communication with bootloader failed');
self.progress_bar_e.addClass('invalid');
2013-12-03 20:23:31 +00:00
GUI.interval_remove('stm32_initialize_mcu');
2014-03-08 05:25:15 +00:00
2013-12-03 20:23:31 +00:00
// disconnect
self.upload_procedure(99);
}
});
2014-03-08 05:25:15 +00:00
2013-12-03 20:23:31 +00:00
if (send_counter++ > 3) {
// stop retrying, its too late to get any response from MCU
console.log('STM32 - no response from bootloader, disconnecting');
2014-08-30 08:30:28 +00:00
2014-08-31 13:55:12 +00:00
$('span.progressLabel').text('No response from the bootloader, programming: FAILED');
2014-08-30 08:30:28 +00:00
self.progress_bar_e.addClass('invalid');
2013-12-03 20:23:31 +00:00
GUI.interval_remove('stm32_initialize_mcu');
GUI.interval_remove('STM32_timeout');
// exit
self.upload_procedure(99);
}
}, 250, true);
break;
case 2:
// get version of the bootloader and supported commands
2014-08-14 15:00:32 +00:00
self.send([self.command.get, 0xFF], 2, function (data) { // 0x00 ^ 0xFF
if (self.verify_response(self.status.ACK, data)) {
2014-08-14 15:00:32 +00:00
self.retrieve(data[1] + 1 + 1, function (data) { // data[1] = number of bytes that will follow [ 1 except current and ACKs]
2014-01-27 20:41:32 +00:00
console.log('STM32 - Bootloader version: ' + (parseInt(data[0].toString(16)) / 10).toFixed(1)); // convert dec to hex, hex to dec and add floating point
2014-03-08 05:25:15 +00:00
// proceed to next step
self.upload_procedure(3);
});
}
});
break;
case 3:
// get ID (device signature)
2014-08-14 15:00:32 +00:00
self.send([self.command.get_ID, 0xFD], 2, function (data) { // 0x01 ^ 0xFF
if (self.verify_response(self.status.ACK, data)) {
2014-08-14 15:00:32 +00:00
self.retrieve(data[1] + 1 + 1, function (data) { // data[1] = number of bytes that will follow [ 1 (N = 1 for STM32), except for current byte and ACKs]
var signature = (data[0] << 8) | data[1];
console.log('STM32 - Signature: 0x' + signature.toString(16)); // signature in hex representation
2014-03-08 05:25:15 +00:00
if (self.verify_chip_signature(signature)) {
// proceed to next step
self.upload_procedure(4);
} else {
// disconnect
self.upload_procedure(99);
}
});
}
});
break;
case 4:
// erase memory
2014-08-30 08:30:28 +00:00
$('span.progressLabel').text('Erasing ...');
if (self.options.erase_chip) {
console.log('Executing global chip erase');
2014-08-14 15:00:32 +00:00
self.send([self.command.erase, 0xBC], 1, function (reply) { // 0x43 ^ 0xFF
if (self.verify_response(self.status.ACK, reply)) {
2014-08-14 15:00:32 +00:00
self.send([0xFF, 0x00], 1, function (reply) {
if (self.verify_response(self.status.ACK, reply)) {
console.log('Erasing: done');
// proceed to next step
self.upload_procedure(5);
}
});
}
});
} else {
2014-05-07 06:07:49 +00:00
console.log('Executing local erase (only needed pages)');
2014-08-14 15:00:32 +00:00
self.send([self.command.erase, 0xBC], 1, function (reply) { // 0x43 ^ 0xFF
2014-05-07 06:07:49 +00:00
if (self.verify_response(self.status.ACK, reply)) {
// the bootloader receives one byte that contains N, the number of pages to be erased 1
var max_address = self.hex.data[self.hex.data.length - 1].address + self.hex.data[self.hex.data.length - 1].bytes - 0x8000000,
erase_pages_n = Math.ceil(max_address / self.page_size),
buff = [],
checksum = erase_pages_n - 1;
2014-05-07 06:07:49 +00:00
buff.push(erase_pages_n - 1);
2014-05-07 06:07:49 +00:00
for (var i = 0; i < erase_pages_n; i++) {
buff.push(i);
checksum ^= i;
}
2014-05-07 06:07:49 +00:00
buff.push(checksum);
2014-03-08 05:25:15 +00:00
2014-08-14 15:00:32 +00:00
self.send(buff, 1, function (reply) {
2014-05-07 06:07:49 +00:00
if (self.verify_response(self.status.ACK, reply)) {
console.log('Erasing: done');
// proceed to next step
self.upload_procedure(5);
}
});
}
});
}
break;
case 5:
// upload
console.log('Writing data ...');
2014-08-30 08:30:28 +00:00
$('span.progressLabel').text('Flashing ...');
var blocks = self.hex.data.length - 1,
flashing_block = 0,
address = self.hex.data[flashing_block].address,
bytes_flashed = 0,
bytes_flashed_total = 0; // used for progress bar
2014-03-08 05:25:15 +00:00
2014-08-09 18:47:07 +00:00
var write = function () {
2014-02-09 15:26:18 +00:00
if (bytes_flashed < self.hex.data[flashing_block].bytes) {
var bytes_to_write = ((bytes_flashed + 256) <= self.hex.data[flashing_block].bytes) ? 256 : (self.hex.data[flashing_block].bytes - bytes_flashed);
2014-03-08 05:25:15 +00:00
2014-02-09 15:26:18 +00:00
// console.log('STM32 - Writing to: 0x' + address.toString(16) + ', ' + bytes_to_write + ' bytes');
2014-03-08 05:25:15 +00:00
2014-08-14 15:00:32 +00:00
self.send([self.command.write_memory, 0xCE], 1, function (reply) { // 0x31 ^ 0xFF
if (self.verify_response(self.status.ACK, reply)) {
// address needs to be transmitted as 32 bit integer, we need to bit shift each byte out and then calculate address checksum
2014-02-09 14:56:06 +00:00
var address_arr = [(address >> 24), (address >> 16), (address >> 8), address];
var address_checksum = address_arr[0] ^ address_arr[1] ^ address_arr[2] ^ address_arr[3];
2014-03-08 05:25:15 +00:00
2014-08-14 15:00:32 +00:00
self.send([address_arr[0], address_arr[1], address_arr[2], address_arr[3], address_checksum], 1, function (reply) { // write start address + checksum
if (self.verify_response(self.status.ACK, reply)) {
var array_out = new Array(bytes_to_write + 2); // 2 byte overhead [N, ...., checksum]
array_out[0] = bytes_to_write - 1; // number of bytes to be written (to write 128 bytes, N must be 127, to write 256 bytes, N must be 255)
2014-03-08 05:25:15 +00:00
var checksum = array_out[0];
for (var i = 0; i < bytes_to_write; i++) {
array_out[i + 1] = self.hex.data[flashing_block].data[bytes_flashed]; // + 1 because of the first byte offset
checksum ^= self.hex.data[flashing_block].data[bytes_flashed];
2014-03-08 05:25:15 +00:00
bytes_flashed++;
}
array_out[array_out.length - 1] = checksum; // checksum (last byte in the array_out array)
2014-03-08 05:25:15 +00:00
2014-02-09 15:03:42 +00:00
address += bytes_to_write;
2014-06-08 20:38:58 +00:00
bytes_flashed_total += bytes_to_write;
2014-08-14 15:00:32 +00:00
self.send(array_out, 1, function (reply) {
if (self.verify_response(self.status.ACK, reply)) {
2014-02-09 15:26:18 +00:00
// update progress bar
self.progress_bar_e.val(bytes_flashed_total / (self.hex.bytes_total * 2) * 100);
2014-03-08 05:25:15 +00:00
// flash another page
write();
}
});
}
});
}
});
2014-02-09 15:26:18 +00:00
} else {
// move to another block
if (flashing_block < blocks) {
flashing_block++;
2014-03-08 05:25:15 +00:00
2014-02-09 15:26:18 +00:00
address = self.hex.data[flashing_block].address;
bytes_flashed = 0;
2014-03-08 05:25:15 +00:00
2014-02-09 15:26:18 +00:00
write();
} else {
// all blocks flashed
console.log('Writing: done');
2014-03-08 05:25:15 +00:00
2014-02-09 15:26:18 +00:00
// proceed to next step
self.upload_procedure(6);
}
}
}
2014-03-08 05:25:15 +00:00
// start writing
write();
break;
case 6:
// verify
console.log('Verifying data ...');
2014-08-30 08:30:28 +00:00
$('span.progressLabel').text('Verifying ...');
var blocks = self.hex.data.length - 1,
reading_block = 0,
address = self.hex.data[reading_block].address,
bytes_verified = 0,
bytes_verified_total = 0; // used for progress bar
2014-03-08 05:25:15 +00:00
// initialize arrays
for (var i = 0; i <= blocks; i++) {
self.verify_hex.push([]);
}
2014-03-08 05:25:15 +00:00
2014-08-09 18:47:07 +00:00
var reading = function () {
2014-02-09 15:26:18 +00:00
if (bytes_verified < self.hex.data[reading_block].bytes) {
var bytes_to_read = ((bytes_verified + 256) <= self.hex.data[reading_block].bytes) ? 256 : (self.hex.data[reading_block].bytes - bytes_verified);
2014-03-08 05:25:15 +00:00
2014-02-09 15:26:18 +00:00
// console.log('STM32 - Reading from: 0x' + address.toString(16) + ', ' + bytes_to_read + ' bytes');
2014-03-08 05:25:15 +00:00
2014-08-14 15:00:32 +00:00
self.send([self.command.read_memory, 0xEE], 1, function (reply) { // 0x11 ^ 0xFF
2014-02-09 15:26:18 +00:00
if (self.verify_response(self.status.ACK, reply)) {
var address_arr = [(address >> 24), (address >> 16), (address >> 8), address];
var address_checksum = address_arr[0] ^ address_arr[1] ^ address_arr[2] ^ address_arr[3];
2014-03-08 05:25:15 +00:00
2014-08-14 15:00:32 +00:00
self.send([address_arr[0], address_arr[1], address_arr[2], address_arr[3], address_checksum], 1, function (reply) { // read start address + checksum
2014-02-09 15:26:18 +00:00
if (self.verify_response(self.status.ACK, reply)) {
var bytes_to_read_n = bytes_to_read - 1;
2014-03-08 05:25:15 +00:00
2014-08-14 15:00:32 +00:00
self.send([bytes_to_read_n, (~bytes_to_read_n) & 0xFF], 1, function (reply) { // bytes to be read + checksum XOR(complement of bytes_to_read_n)
2014-02-09 15:26:18 +00:00
if (self.verify_response(self.status.ACK, reply)) {
2014-08-14 15:00:32 +00:00
self.retrieve(bytes_to_read, function (data) {
2014-02-09 15:26:18 +00:00
for (var i = 0; i < data.length; i++) {
self.verify_hex[reading_block].push(data[i]);
}
2014-03-08 05:25:15 +00:00
2014-02-09 15:26:18 +00:00
address += bytes_to_read;
bytes_verified += bytes_to_read;
bytes_verified_total += bytes_to_read;
2014-03-08 05:25:15 +00:00
2014-02-09 15:26:18 +00:00
// update progress bar
2014-03-08 05:25:15 +00:00
self.progress_bar_e.val((self.hex.bytes_total + bytes_verified_total) / (self.hex.bytes_total * 2) * 100);
2014-02-09 15:26:18 +00:00
// verify another page
reading();
});
}
});
}
});
}
});
} else {
// move to another block
if (reading_block < blocks) {
reading_block++;
2014-03-08 05:25:15 +00:00
2014-02-09 15:03:42 +00:00
address = self.hex.data[reading_block].address;
bytes_verified = 0;
2014-03-08 05:25:15 +00:00
reading();
} else {
// all blocks read, verify
2014-03-08 05:25:15 +00:00
var verify = true;
for (var i = 0; i <= blocks; i++) {
verify = self.verify_flash(self.hex.data[i].data, self.verify_hex[i]);
2014-03-08 05:25:15 +00:00
if (!verify) break;
}
2014-03-08 05:25:15 +00:00
if (verify) {
console.log('Programming: SUCCESSFUL');
2014-08-30 08:30:28 +00:00
$('span.progressLabel').text('Programming: SUCCESSFUL');
2014-07-16 10:59:12 +00:00
googleAnalytics.sendEvent('Flashing', 'Programming', 'success');
2014-03-08 05:25:15 +00:00
// update progress bar
self.progress_bar_e.addClass('valid');
2014-03-08 05:25:15 +00:00
// proceed to next step
2014-03-08 05:25:15 +00:00
self.upload_procedure(7);
} else {
console.log('Programming: FAILED');
2014-08-30 08:30:28 +00:00
$('span.progressLabel').text('Programming: FAILED');
2014-07-16 10:59:12 +00:00
googleAnalytics.sendEvent('Flashing', 'Programming', 'fail');
2014-03-08 05:25:15 +00:00
// update progress bar
self.progress_bar_e.addClass('invalid');
2014-03-08 05:25:15 +00:00
// disconnect
2014-03-08 05:25:15 +00:00
self.upload_procedure(99);
}
}
}
}
2014-03-08 05:25:15 +00:00
// start reading
reading();
break;
case 7:
// go
// memory address = 4 bytes, 1st high byte, 4th low byte, 5th byte = checksum XOR(byte 1, byte 2, byte 3, byte 4)
console.log('Sending GO command: 0x8000000');
2014-08-14 15:00:32 +00:00
self.send([self.command.go, 0xDE], 1, function (reply) { // 0x21 ^ 0xFF
if (self.verify_response(self.status.ACK, reply)) {
var gt_address = 0x8000000,
address = [(gt_address >> 24), (gt_address >> 16), (gt_address >> 8), gt_address],
address_checksum = address[0] ^ address[1] ^ address[2] ^ address[3];
2014-03-08 05:25:15 +00:00
2014-08-14 15:00:32 +00:00
self.send([address[0], address[1], address[2], address[3], address_checksum], 1, function (reply) {
if (self.verify_response(self.status.ACK, reply)) {
// disconnect
self.upload_procedure(99);
}
});
}
});
break;
case 99:
// disconnect
GUI.interval_remove('STM32_timeout'); // stop STM32 timeout timer (everything is finished now)
2014-03-08 05:25:15 +00:00
// close connection
2014-08-14 15:00:32 +00:00
serial.disconnect(function (result) {
if (result) { // All went as expected
} else { // Something went wrong
}
2014-03-08 05:25:15 +00:00
PortUsage.reset();
// unlocking connect button
GUI.connect_lock = false;
// unlock some UI elements TODO needs rework
$('select[name="release"]').prop('disabled', false);
// handle timing
var timeSpent = new Date().getTime() - self.upload_time_start;
console.log('Script finished after: ' + (timeSpent / 1000) + ' seconds');
if (self.callback) callback();
});
break;
}
};
// initialize object
var STM32 = new STM32_protocol();