diff --git a/js/stm32.js b/js/stm32.js
new file mode 100644
index 0000000000..b82592aab6
--- /dev/null
+++ b/js/stm32.js
@@ -0,0 +1,455 @@
+var STM32_protocol = function() {
+ this.hex_to_flash; // data to flash
+
+ this.receive_buffer;
+
+ this.bytes_to_read = 0; // ref
+ this.read_callback; // ref
+
+ this.flashing_memory_address;
+ this.verify_memory_address;
+
+ this.bytes_flashed;
+ this.bytes_verified;
+
+ this.verify_hex = new Array();
+
+ this.upload_time_start;
+
+ this.steps_executed;
+ this.steps_executed_last;
+
+ this.status = {
+ ACK: 0x79,
+ NACK: 0x1F
+ };
+
+ 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
+ };
+
+ // Erase (x043) and Extended Erase (0x44) are exclusive. A device may support either the Erase command or the Extended Erase command but not both.
+};
+
+// no input parameters
+STM32_protocol.prototype.connect = function() {
+ var self = this;
+
+ selected_port = String($('div#port-picker .port select').val());
+
+ if (selected_port != '0') {
+ // parity and stopbit properties should be in chrome v30 or v31
+ chrome.serial.open(selected_port, {bitrate: 115200, parityBit: 'evenparity', stopBit: 'onestopbit'}, function(openInfo) {
+ connectionId = openInfo.connectionId;
+
+ if (connectionId != -1) {
+ console.log('Connection was opened with ID: ' + connectionId);
+
+ // we are connected, disabling connect button in the UI
+ GUI.connect_lock = true;
+
+ // start the upload procedure
+ self.initialize();
+ }
+ });
+ } else {
+ console.log('Please select valid serial port');
+ }
+};
+
+// initialize certain variables and start timers that oversee the communication
+STM32_protocol.prototype.initialize = function() {
+ var self = this;
+
+ // reset and set some variables before we start
+ self.receive_buffer = [];
+
+ self.flashing_memory_address = 0x08000000;
+ self.verify_memory_address = 0x08000000;
+
+ self.bytes_flashed = 0;
+ self.bytes_verified = 0;
+
+ self.verify_hex = [];
+
+ self.upload_time_start = microtime();
+
+ self.steps_executed = 0;
+ self.steps_executed_last = 0;
+
+ GUI.interval_add('firmware_uploader_read', function() {
+ self.read();
+ }, 1, true);
+
+ GUI.interval_add('STM32_timeout', function() {
+ if (self.steps_executed > self.steps_executed_last) { // process is running
+ self.steps_executed_last = self.steps_executed;
+ } else {
+ console.log('STM32 - timed out, programming failed ...');
+
+ // protocol got stuck, clear timer and disconnect
+ GUI.interval_remove('STM32_timeout');
+
+ // exit
+ self.upload_procedure(99);
+ }
+ }, 1000);
+
+ // there seems to be 2 unwanted bytes in the parsed array, we will drop them now (WHY ???)
+ this.hex_to_flash.shift();
+ this.hex_to_flash.shift();
+
+ // first step
+ self.upload_procedure(1);
+};
+
+// no input parameters
+// this method should be executed every 1 ms via interval timer
+STM32_protocol.prototype.read = function() {
+ var self = this;
+
+ // routine that fills the buffer
+ chrome.serial.read(connectionId, 128, function(readInfo) {
+ if (readInfo && readInfo.bytesRead > 0) {
+ var data = new Uint8Array(readInfo.data);
+
+ for (var i = 0; i < data.length; i++) {
+ self.receive_buffer.push(data[i]);
+ }
+ }
+ });
+
+ // routine that fetches data from buffer if statement is true
+ if (self.receive_buffer.length >= self.bytes_to_read && self.bytes_to_read != 0) {
+ var data = self.receive_buffer.slice(0, self.bytes_to_read); // bytes requested
+ self.receive_buffer.splice(0, self.bytes_to_read); // remove read bytes
+
+ self.bytes_to_read = 0; // reset trigger
+
+ self.read_callback(data);
+ }
+};
+
+// 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
+STM32_protocol.prototype.send = function(Array, bytes_to_read, callback) {
+ var bufferOut = new ArrayBuffer(Array.length);
+ var bufferView = new Uint8Array(bufferOut);
+
+ // set Array values inside bufferView (alternative to for loop)
+ bufferView.set(Array);
+
+ // update references
+ this.bytes_to_read = bytes_to_read;
+ this.read_callback = callback;
+
+ // send over the actual data
+ chrome.serial.write(connectionId, bufferOut, function(writeInfo) {});
+};
+
+// val = single byte to be verified
+// data = response of n bytes from mcu (array)
+// result = true/false
+STM32_protocol.prototype.verify_response = function(val, data) {
+ if (val != data[0]) {
+ console.log('STM32 Communication failed, wrong response, expected: ' + val + ' received: ' + data[0]);
+
+ // disconnect
+ this.upload_procedure(99);
+
+ return false;
+ }
+
+ return true;
+};
+
+// input = 16 bit value
+// result = true/false
+STM32_protocol.prototype.verify_chip_signature = function(signature) {
+ switch (signature) {
+ case 0x412:
+ // low density
+ return false;
+ break;
+ case 0x410:
+ // medium density
+ console.log('Chip recognized as F1 Medium-density');
+
+ return true;
+ break;
+ case 0x414:
+ // high density
+ return false
+ break;
+ case 0x418:
+ // connectivity line
+ return false;
+ break;
+ case 0x420:
+ // medium density value line
+ return false;
+ break;
+ case 0x428:
+ // high density value line
+ return false;
+ break;
+ case 0x430:
+ // XL density
+ return false;
+ break;
+ default:
+ return false;
+ };
+};
+
+// first_array = usually hex_to_flash array
+// second_array = usually verify_hex array
+// result = true/false
+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;
+ }
+ }
+
+ console.log('Verification successful, matching: ' + first_array.length + ' bytes');
+
+ return true;
+};
+
+// step = value depending on current state of upload_procedure
+STM32_protocol.prototype.upload_procedure = function(step) {
+ var self = this;
+ self.steps_executed++;
+
+ switch (step) {
+ case 1:
+ // initialize serial interface on the MCU side, auto baud rate settings
+ self.send([0x7F], 1, function(reply) {
+ if (self.verify_response(self.status.ACK, reply)) {
+ console.log('STM32 - Serial interface initialized on the MCU side');
+
+ // proceed to next step
+ self.upload_procedure(2);
+ }
+ });
+ break;
+ case 2:
+ // get version of the bootloader and supported commands
+ self.send([self.command.get, 0xFF], 2, function(data) { // 0x00 ^ 0xFF
+ if (self.verify_response(self.status.ACK, data)) {
+ self.send([], data[1] + 2, function(data) { // data[1] = number of bytes that will follow (should be 12 + ack)
+ console.log('STM32 - Bootloader version: ' + (parseInt(data[0].toString(16)) / 10).toFixed(1)); // convert dec to hex, hex to dec and add floating point
+
+ // proceed to next step
+ self.upload_procedure(3);
+ });
+ }
+ });
+ break;
+ case 3:
+ // get ID (device signature)
+ self.send([self.command.get_ID, 0xFD], 2, function(data) { // 0x01 ^ 0xFF
+ if (self.verify_response(self.status.ACK, data)) {
+ self.send([], data[1] + 2, function(data) { // data[1] = number of bytes that will follow (should be 1 + ack), its 2 + ack, WHY ???
+ var signature = (data[0] << 8) | data[1];
+ console.log('STM32 - Signature: 0x' + signature.toString(16)); // signature in hex representation
+
+ if (self.verify_chip_signature(signature)) {
+ // proceed to next step
+ self.upload_procedure(4);
+ } else {
+ console.log('Chip not supported, sorry :-(');
+
+ // disconnect
+ self.upload_procedure(99);
+ }
+ });
+ }
+ });
+ break;
+ case 4:
+ // erase memory
+ console.log('Executing global chip erase');
+
+ self.send([self.command.erase, 0xBC], 1, function(reply) { // 0x43 ^ 0xFF
+ if (self.verify_response(self.status.ACK, reply)) {
+ self.send([0xFF, 0x00], 1, function(reply) {
+ if (self.verify_response(self.status.ACK, reply)) {
+ console.log('Erasing: done');
+ console.log('Writing data ...');
+
+ // proceed to next step
+ self.upload_procedure(5);
+ }
+ });
+ }
+ });
+ break;
+ case 5:
+ // upload
+ if (self.bytes_flashed < self.hex_to_flash.length) {
+ if ((self.bytes_flashed + 256) <= self.hex_to_flash.length) {
+ var data_length = 256;
+ } else {
+ var data_length = self.hex_to_flash.length - self.bytes_flashed;
+ }
+
+ console.log('STM32 - Writing to: 0x' + self.flashing_memory_address.toString(16) + ', ' + data_length + ' bytes');
+
+ 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
+ var address = [(self.flashing_memory_address >> 24), (self.flashing_memory_address >> 16) & 0xFF, (self.flashing_memory_address >> 8) & 0xFF, (self.flashing_memory_address & 0xFF)];
+ var address_checksum = address[0] ^ address[1] ^ address[2] ^ address[3];
+
+ self.send([address[0], address[1], address[2], address[3], address_checksum], 1, function(reply) { // write start address + checksum
+ if (self.verify_response(self.status.ACK, reply)) {
+ var array_out = new Array(data_length + 2); // 2 byte overhead [N, ...., checksum]
+ array_out[0] = data_length - 1; // number of bytes to be written (to write 128 bytes, N must be 127, to write 256 bytes, N must be 255)
+
+ var checksum = array_out[0];
+ for (var i = 0; i < data_length; i++) {
+ array_out[i + 1] = self.hex_to_flash[self.bytes_flashed]; // + 1 because of the first byte offset
+ checksum ^= self.hex_to_flash[self.bytes_flashed];
+
+ self.bytes_flashed++;
+ self.flashing_memory_address++;
+ }
+
+ array_out[array_out.length - 1] = checksum; // checksum (last byte in the array_out array)
+
+ self.send(array_out, 1, function(reply) {
+ if (self.verify_response(self.status.ACK, reply)) {
+ // flash another page
+ self.upload_procedure(5);
+ }
+ });
+ }
+ });
+ }
+ });
+
+ } else {
+ console.log('Writing: done');
+ console.log('Verifying data ...');
+
+ // proceed to next step
+ self.upload_procedure(6);
+ }
+ break;
+ case 6:
+ // verify
+ if (self.bytes_verified < self.hex_to_flash.length) {
+ if ((self.bytes_verified + 256) <= self.hex_to_flash.length) {
+ var data_length = 256;
+ } else {
+ var data_length = self.hex_to_flash.length - self.bytes_verified;
+ }
+
+ console.log('STM32 - Reading from: 0x' + self.verify_memory_address.toString(16) + ', ' + data_length + ' bytes');
+
+ self.send([self.command.read_memory, 0xEE], 1, function(reply) { // 0x11 ^ 0xFF
+ if (self.verify_response(self.status.ACK, reply)) {
+ var address = [(self.verify_memory_address >> 24), (self.verify_memory_address >> 16) & 0x00FF, (self.verify_memory_address >> 8) & 0x00FF, (self.verify_memory_address & 0x00FF)];
+ var address_checksum = address[0] ^ address[1] ^ address[2] ^ address[3];
+
+ self.send([address[0], address[1], address[2], address[3], address_checksum], 1, function(reply) { // read start address + checksum
+ if (self.verify_response(self.status.ACK, reply)) {
+ var bytes_to_read_n = data_length - 1;
+
+ 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)
+ if (self.verify_response(self.status.ACK, reply)) {
+ self.send([], data_length, function(data) {
+ for (var i = 0; i < data.length; i++) {
+ self.verify_hex.push(data[i]);
+ self.bytes_verified++;
+ }
+
+ self.verify_memory_address += data_length;
+
+ // verify another page
+ self.upload_procedure(6);
+ });
+ }
+ });
+ }
+ });
+ }
+ });
+ } else {
+ var result = self.verify_flash(self.hex_to_flash, self.verify_hex);
+
+ if (result) {
+ console.log('Verifying: done');
+ console.log('Programming: SUCCESSFUL');
+
+ // proceed to next step
+ self.upload_procedure(7);
+ } else {
+ console.log('Verifying: failed');
+ console.log('Programming: FAILED');
+
+ // disconnect
+ self.upload_procedure(99);
+ }
+ }
+ 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');
+
+ self.send([self.command.go, 0xDE], 1, function(reply) { // 0x21 ^ 0xFF
+ if (self.verify_response(self.status.ACK, reply)) {
+ self.send([0x08, 0x00, 0x00, 0x00, 0x08], 1, function(reply) {
+ if (self.verify_response(self.status.ACK, reply)) {
+ // disconnect
+ self.upload_procedure(99);
+ }
+ });
+ }
+ });
+ break;
+ case 99:
+ // disconnect
+ GUI.interval_remove('firmware_uploader_read'); // stop reading serial
+ GUI.interval_remove('STM32_timeout'); // stop STM32 timeout timer (everything is finished now)
+
+ console.log('Script finished after: ' + (microtime() - self.upload_time_start).toFixed(4) + ' seconds');
+ console.log('Script finished after: ' + self.steps_executed + ' steps');
+
+ // close connection
+ chrome.serial.close(connectionId, function(result) {
+ if (result) { // All went as expected
+ console.log('Connection closed successfully.');
+
+ connectionId = -1; // reset connection id
+ } else { // Something went wrong
+ if (connectionId > 0) {
+ console.log('There was an error that happened during "connection-close" procedure');
+ }
+ }
+
+ // unlocking connect button
+ GUI.connect_lock = false;
+ });
+ break;
+ }
+};
+
+// initialize object
+var STM32 = new STM32_protocol();
\ No newline at end of file
diff --git a/main.html b/main.html
index 715da9e672..d65bb3624d 100644
--- a/main.html
+++ b/main.html
@@ -17,6 +17,7 @@
+
diff --git a/tabs/default.js b/tabs/default.js
index 3452e6e363..c8866dd453 100644
--- a/tabs/default.js
+++ b/tabs/default.js
@@ -9,5 +9,8 @@ function tab_initialize_default() {
$('a.firmware_flasher').click(function() {
tab_initialize_firmware_flasher();
});
+
+ // temporary
+ tab_initialize_firmware_flasher();
});
}
\ No newline at end of file
diff --git a/tabs/firmware_flasher.js b/tabs/firmware_flasher.js
index e3635fa6dc..e26625bff3 100644
--- a/tabs/firmware_flasher.js
+++ b/tabs/firmware_flasher.js
@@ -43,7 +43,9 @@ function tab_initialize_firmware_flasher() {
$('a.flash_firmware').click(function() {
if (raw_hex != false) {
+ STM32.hex_to_flash = raw_hex.slice(0);
+ STM32.connect();
}
});
});