Skip to content

Instantly share code, notes, and snippets.

@tracernz
Created September 20, 2016 08:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tracernz/1100ca6d589f430f6a4c123248040a27 to your computer and use it in GitHub Desktop.
Save tracernz/1100ca6d589f430f6a4c123248040a27 to your computer and use it in GitHub Desktop.
--- stm32usbdfu.js 2016-07-12 08:28:18.000000000 +1200
+++ rfbl.js 2016-07-12 08:28:18.000000000 +1200
@@ -10,13 +10,15 @@
*/
'use strict';
-var STM32DFU_protocol = function () {
+var RFBL_protocol = function () {
this.callback; // ref
this.hex; // ref
this.verify_hex;
this.handle = null; // connection handle
+ this.connectionId = null;
+
this.request = {
DETACH: 0x00, // OUT, Requests the device to leave DFU mode and enter the application.
DNLOAD: 0x01, // OUT, Requests data transfer from Host to the device in order to load them into device internal Flash. Includes also erase commands
@@ -63,7 +65,8 @@
this.flash_layout = { 'start_address': 0, 'total_size': 0, 'sectors': []};
};
-STM32DFU_protocol.prototype.connect = function (device, hex, options, callback) {
+RFBL_protocol.prototype.connect = function (device, hex, options, callback) {
+
var self = this;
self.hex = hex;
self.callback = callback;
@@ -85,9 +88,9 @@
self.progress_bar_e.val(0);
self.progress_bar_e.removeClass('valid invalid');
- chrome.usb.getDevices(device, function (result) {
+ chrome.hid.getDevices(device, function (result) {
if (result.length) {
- console.log('USB DFU detected with ID: ' + result[0].device);
+ console.log('USB HID RFBL detected with ID: ' + result[0].deviceId);
self.openDevice(result[0]);
} else {
@@ -97,7 +100,7 @@
});
};
-STM32DFU_protocol.prototype.checkChromeError = function() {
+RFBL_protocol.prototype.checkChromeError = function() {
if (chrome.runtime.lastError) {
if(chrome.runtime.lastError.message)
console.log(chrome.runtime.lastError.message);
@@ -110,12 +113,13 @@
return false;
}
-STM32DFU_protocol.prototype.openDevice = function (device) {
+RFBL_protocol.prototype.openDevice = function (device) {
var self = this;
- chrome.usb.openDevice(device, function (handle) {
+ var deviceId = device.deviceId;
+ chrome.hid.connect(deviceId, function (handle) {
if(self.checkChromeError()) {
- console.log('Failed to open USB device!');
+ console.log('Failed to open RFBL!');
GUI.log(chrome.i18n.getMessage('usbDeviceOpenFail'));
if(GUI.operating_system === 'Linux') {
GUI.log(chrome.i18n.getMessage('usbDeviceUdevNotice'));
@@ -123,15 +127,23 @@
return;
}
- self.handle = handle;
+ if (!handle) {
+ GUI.log("Unable to connect to device.");
+ }
- GUI.log(chrome.i18n.getMessage('usbDeviceOpened', handle.handle.toString()));
- console.log('Device opened with Handle ID: ' + handle.handle);
- self.claimInterface(0);
+ console.log("Connected to "+JSON.stringify(handle.connectionId));
+ GUI.log('Successfully connected to RFBL');
+
+ self.handle = handle;
+ self.connectionId = handle.connectionId;
+console.log("Connected to "+JSON.stringify(self.connectionId));
+ GUI.log(chrome.i18n.getMessage('usbDeviceOpened', self.connectionId.toString()));
+ console.log('Device opened with Handle ID: ' + self.connectionId);
+ self.upload_procedure(1);
});
};
-STM32DFU_protocol.prototype.closeDevice = function () {
+RFBL_protocol.prototype.closeDevice = function () {
var self = this;
chrome.usb.closeDevice(this.handle, function closed() {
@@ -147,17 +159,7 @@
});
};
-STM32DFU_protocol.prototype.claimInterface = function (interfaceNumber) {
- var self = this;
-
- chrome.usb.claimInterface(this.handle, interfaceNumber, function claimed() {
- console.log('Claimed interface: ' + interfaceNumber);
-
- self.upload_procedure(1);
- });
-};
-
-STM32DFU_protocol.prototype.releaseInterface = function (interfaceNumber) {
+RFBL_protocol.prototype.releaseInterface = function (interfaceNumber) {
var self = this;
chrome.usb.releaseInterface(this.handle, interfaceNumber, function released() {
@@ -167,7 +169,7 @@
});
};
-STM32DFU_protocol.prototype.resetDevice = function (callback) {
+RFBL_protocol.prototype.resetDevice = function (callback) {
chrome.usb.resetDevice(this.handle, function (result) {
console.log('Reset Device: ' + result);
@@ -175,7 +177,7 @@
});
};
-STM32DFU_protocol.prototype.getString = function (index, callback) {
+RFBL_protocol.prototype.getString = function (index, callback) {
var self = this;
chrome.usb.controlTransfer(self.handle, {
@@ -203,7 +205,7 @@
});
}
-STM32DFU_protocol.prototype.getInterfaceDescriptor = function (_interface, callback) {
+RFBL_protocol.prototype.getInterfaceDescriptor = function (_interface, callback) {
var self = this;
chrome.usb.controlTransfer(this.handle, {
@@ -238,7 +240,7 @@
});
}
-STM32DFU_protocol.prototype.getFlashInfo = function (_interface, callback) {
+RFBL_protocol.prototype.getFlashInfo = function (_interface, callback) {
var self = this;
self.getInterfaceDescriptor(0, function (descriptor, resultCode) {
@@ -254,8 +256,7 @@
}
// F303: "@Internal Flash /0x08000000/128*0002Kg"
- // F405: "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg"
- // F411: "@Internal Flash /0x08000000/04*016Kg,01*064Kg,03*128Kg"
+ // F407: "@Internal Flash /0x08000000/04*016Kg,01*064Kg,07*128Kg"
// split main into [location, start_addr, sectors]
var tmp1 = str.split('/');
if (tmp1.length != 3 || !tmp1[0].startsWith("@Internal Flash")) {
@@ -320,7 +321,7 @@
});
}
-STM32DFU_protocol.prototype.controlTransfer = function (direction, request, value, _interface, length, data, callback) {
+RFBL_protocol.prototype.controlTransfer = function (direction, request, value, _interface, length, data, callback) {
var self = this;
if (direction == 'in') {
@@ -372,7 +373,7 @@
};
// routine calling DFU_CLRSTATUS until device is in dfuIDLE state
-STM32DFU_protocol.prototype.clearStatus = function (callback) {
+RFBL_protocol.prototype.clearStatus = function (callback) {
var self = this;
function check_status() {
@@ -394,7 +395,7 @@
check_status();
};
-STM32DFU_protocol.prototype.loadAddress = function (address, callback) {
+RFBL_protocol.prototype.loadAddress = function (address, callback) {
var self = this;
self.controlTransfer('out', self.request.DNLOAD, 0, 0, 0, [0x21, address, (address >> 8), (address >> 16), (address >> 24)], function () {
@@ -423,7 +424,7 @@
// first_array = usually hex_to_flash array
// second_array = usually verify_hex array
// result = true/false
-STM32DFU_protocol.prototype.verify_flash = function (first_array, second_array) {
+RFBL_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));
@@ -436,137 +437,234 @@
return true;
};
-STM32DFU_protocol.prototype.upload_procedure = function (step) {
+RFBL_protocol.prototype.dec_to_char_arr = function (b) {
+
+ var carray = new Uint8Array(4);
+ b = b.toString(16);
+ //convert to hex
+ //split hex into array
+ b = b.split("");
+ b.reverse();
+ var catfish = 0;
+ while (catfish < 8) {
+ if (b[catfish] == undefined) {
+ b[catfish] = 0;
+ }
+ if (b[catfish] == null) {
+ b[catfish] = 0;
+ }
+ console.info("catfish" + catfish + " " + b[catfish]);
+ catfish++;
+ }
+ console.info(JSON.stringify(b));
+ carray[0] = parseInt(b[7] + b[6], 16);
+ carray[1] = parseInt(b[5] + b[4], 16);
+ carray[2] = parseInt(b[3] + b[2], 16);
+ carray[3] = parseInt(b[1] + b[0], 16);
+ return carray;
+
+};
+
+RFBL_protocol.prototype.text_to_char_arr = function (b) {
+
+ var carray = new Uint8Array(4);
+ b = b.replace(/\\x([a-fA-F0-9]{2})/g, function(match, capture) {
+ return String.fromCharCode(parseInt(capture, 16));
+ });
+ for (var i = 0; i < b.length && i < carray.length; ++i) {
+ if (b.charCodeAt(i) > 255) {
+ throw "I am not smart enough to decode non-ASCII data.";
+ }
+ carray[i] = b.charCodeAt(i);
+ }
+ return carray;
+
+};
+
+var ok4n = false;
+var packet_size = 63;
+var fw_size = 60;
+RFBL_protocol.prototype.upload_procedure = function (step) {
var self = this;
switch (step) {
case 1:
- self.getFlashInfo(0, function (flash, resultCode) {
- if (resultCode != 0) {
- console.log('Failed to detect chip flash info, resultCode: ' + resultCode);
- self.upload_procedure(99);
- } else {
- self.flash_layout = flash;
- self.available_flash_size = flash.total_size - (self.hex.start_linear_address - flash.start_address);
-
- GUI.log(chrome.i18n.getMessage('dfu_device_flash_info', (flash.total_size / 1024).toString()));
-
- if (self.hex.bytes_total > self.available_flash_size) {
- GUI.log(chrome.i18n.getMessage('dfu_error_image_size',
- [(self.hex.bytes_total / 1024.0).toFixed(1),
- (self.available_flash_size / 1024.0).toFixed(1)]));
- self.upload_procedure(99);
- } else {
- self.clearStatus(function () {
- self.upload_procedure(2);
- });
- }
- }
- });
+ var i = 0;
+ var r_id = 2;
+ var bytes = new Uint8Array(packet_size);
+
+ var temp_arr = self.text_to_char_arr("RFBL");
+ bytes[0] = temp_arr[0];
+ bytes[1] = temp_arr[1];
+ bytes[2] = temp_arr[2];
+ bytes[3] = temp_arr[3];
+ temp_arr = self.text_to_char_arr("CCCC");
+ bytes[4] = temp_arr[3];
+ bytes[5] = 5;
+
+ temp_arr = self.text_to_char_arr("FWSZ");
+ bytes[6] = temp_arr[0];
+ bytes[7] = temp_arr[1];
+ bytes[8] = temp_arr[2];
+ bytes[9] = temp_arr[3];
+ temp_arr = self.dec_to_char_arr(self.hex.bytes_total);
+ bytes[10] = temp_arr[0];
+ bytes[11] = temp_arr[1];
+ bytes[12] = temp_arr[2];
+ bytes[13] = temp_arr[3];
+console.info("FWSZ: " + self.hex.bytes_total);
+ temp_arr = self.text_to_char_arr("FWTP");
+ bytes[14] = temp_arr[0];
+ bytes[15] = temp_arr[1];
+ bytes[16] = temp_arr[2];
+ bytes[17] = temp_arr[3];
+ temp_arr = self.text_to_char_arr("RFFW");
+ bytes[18] = temp_arr[0];
+ bytes[19] = temp_arr[1];
+ bytes[20] = temp_arr[2];
+ bytes[21] = temp_arr[3];
+
+ temp_arr = self.text_to_char_arr("FWMD");
+ bytes[22] = temp_arr[0];
+ bytes[23] = temp_arr[1];
+ bytes[24] = temp_arr[2];
+ bytes[25] = temp_arr[3];
+ temp_arr = self.text_to_char_arr("AUTO");
+ bytes[26] = temp_arr[0];
+ bytes[27] = temp_arr[1];
+ bytes[28] = temp_arr[2];
+ bytes[29] = temp_arr[3];
+
+ temp_arr = self.text_to_char_arr("FWER");
+ bytes[30] = temp_arr[0];
+ bytes[31] = temp_arr[1];
+ bytes[32] = temp_arr[2];
+ bytes[33] = temp_arr[3];
+ temp_arr = self.text_to_char_arr("FWCF");
+ bytes[34] = temp_arr[0];
+ bytes[35] = temp_arr[1];
+ bytes[36] = temp_arr[2];
+ bytes[37] = temp_arr[3];
+
+ i = 38;
+ while (i <= packet_size - 1) {
+ bytes[i] = 0;
+ i++;
+ }
+ bytes[packet_size - 1] = 1;
+
+ //GUI.log("Connected to " + this.connectionId);
+ chrome.hid.send(this.connectionId, r_id, bytes.buffer, function() {
+ });
+
+ console.log('Erasing ...');
+ $('span.progressLabel').text('Preparing for Awesomeness!...');
+
+ chrome.hid.receive(this.connectionId, function(reportId, data) {
+ console.info(new Uint8Array(data));
+ self.upload_procedure(2);
+ });
break;
+
case 2:
- // erase
- if (self.options.erase_chip) {
- // full chip erase
- console.log('Executing global chip erase');
- $('span.progressLabel').text('Erasing ...');
- self.controlTransfer('out', self.request.DNLOAD, 0, 0, 0, [0x41], function () {
- self.controlTransfer('in', self.request.GETSTATUS, 0, 0, 6, 0, function (data) {
- if (data[4] == self.state.dfuDNBUSY) { // completely normal
- var delay = data[1] | (data[2] << 8) | (data[3] << 16);
+ console.log('Writing data ...');
+ $('span.progressLabel').text('Flashing Awesomeness!...');
- setTimeout(function () {
- self.controlTransfer('in', self.request.GETSTATUS, 0, 0, 6, 0, function (data) {
- if (data[4] == self.state.dfuDNLOAD_IDLE) {
- self.upload_procedure(4);
- } else {
- console.log('Failed to execute global chip erase');
- self.upload_procedure(99);
- }
- });
- }, delay);
- } else {
- console.log('Failed to initiate global chip erase');
- self.upload_procedure(99);
- }
- });
- });
- } else {
- // local erase
+ var blocks = self.hex.data.length - 1;
+ var flashing_block = 0;
+ var address = self.hex.data[flashing_block].address;
- // find out which pages to erase
- var erase_pages = [];
- for (var i = 0; i < self.flash_layout.sectors.length; i++) {
- for (var j = 0; j < self.flash_layout.sectors[i].num_pages; j++) {
- var page_start = self.flash_layout.sectors[i].start_address + j * self.flash_layout.sectors[i].page_size;
- var page_end = page_start + self.flash_layout.sectors[i].page_size - 1;
- for (var k = 0; k < self.hex.data.length; k++) {
- var starts_in_page = self.hex.data[k].address >= page_start && self.hex.data[k].address <= page_end;
- var end_address = self.hex.data[k].address + self.hex.data[k].bytes - 1;
- var ends_in_page = end_address >= page_start && end_address <= page_end;
- var spans_page = self.hex.data[k].address < page_start && end_address > page_end;
- if (starts_in_page || ends_in_page || spans_page) {
- var idx = erase_pages.findIndex(function (element, index, array) {
- return element.sector == i && element.page == j;
- });
- if (idx == -1)
- erase_pages.push({'sector': i, 'page': j});
- }
- }
- }
- }
+ var bytes_flashed = 0;
+ var bytes_flashed_total = 0; // used for progress bar
- $('span.progressLabel').text('Erasing ...');
- console.log('Executing local chip erase');
+ //break;
+ var write2 = function (connectionId) {
+ var r_id = 2;
+ var fw_size_left = fw_size;
+ var bytes = new Uint8Array(packet_size);
- var page = 0;
- var total_erased = 0; // bytes
+ if (bytes_flashed < self.hex.data[flashing_block].bytes) {
+ var bytes_to_write = ((bytes_flashed + fw_size) <= self.hex.data[flashing_block].bytes) ? fw_size : (self.hex.data[flashing_block].bytes - bytes_flashed);
- var erase_page = function() {
- var page_addr = erase_pages[page].page * self.flash_layout.sectors[erase_pages[page].sector].page_size +
- self.flash_layout.sectors[erase_pages[page].sector].start_address;
- var cmd = [0x41, page_addr & 0xff, (page_addr >> 8) & 0xff, (page_addr >> 16) & 0xff, (page_addr >> 24) & 0xff];
- total_erased += self.flash_layout.sectors[erase_pages[page].sector].page_size;
- console.log('Erasing. sector ' + erase_pages[page].sector +
- ', page ' + erase_pages[page].page + ' @ 0x' + page_addr.toString(16));
+ var data_to_flash = self.hex.data[flashing_block].data.slice(bytes_flashed, bytes_flashed + bytes_to_write);
- self.controlTransfer('out', self.request.DNLOAD, 0, 0, 0, cmd, function () {
- self.controlTransfer('in', self.request.GETSTATUS, 0, 0, 6, 0, function (data) {
- if (data[4] == self.state.dfuDNBUSY) { // completely normal
- var delay = data[1] | (data[2] << 8) | (data[3] << 16);
+ for (var i = 0; i < data_to_flash.length && i < data_to_flash.length; ++i) {
+ bytes[i] = data_to_flash[i];
+ }
+
+ fw_size_left = fw_size;
+ while (fw_size_left <= packet_size - 1) {
+ bytes[fw_size_left] = 0;
+ fw_size_left++;
+ }
+ bytes[packet_size - 1] = 1; //add a tail
- setTimeout(function () {
- self.controlTransfer('in', self.request.GETSTATUS, 0, 0, 6, 0, function (data) {
- if (data[4] == self.state.dfuDNLOAD_IDLE) {
- // update progress bar
- self.progress_bar_e.val((page + 1) / erase_pages.length * 100);
- page++;
+ address += bytes_to_write;
+ bytes_flashed += bytes_to_write;
+ bytes_flashed_total += bytes_to_write;
- if(page == erase_pages.length) {
- console.log("Erase: complete");
- GUI.log(chrome.i18n.getMessage('dfu_erased_kilobytes', (total_erased / 1024).toString()));
- self.upload_procedure(4);
- }
- else
- erase_page();
- } else {
- console.log('Failed to erase page 0x' + page_addr.toString(16));
- self.upload_procedure(99);
- }
- });
- }, delay);
- } else {
- console.log('Failed to initiate page erase, page 0x' + page_addr.toString(16));
- self.upload_procedure(99);
- }
- });
- });
- };
+ self.progress_bar_e.val(bytes_flashed_total / (self.hex.bytes_total * 1) * 100);
+
+ console.info(JSON.stringify(bytes));
+
+ chrome.hid.send(connectionId, r_id, bytes.buffer, function() {
+ write2(connectionId);
+ });
+
+ } else {
+ if (flashing_block < blocks) {
+ // move to another block
+ flashing_block++;
+
+ address = self.hex.data[flashing_block].address;
+ bytes_flashed = 0;
+ wBlockNum = 2;
+
+ write2(connectionId);
+ } else {
+ // all blocks flashed
+ // Reboot RFBL into RFFW
+ GUI.log('Writing: done');
+
+ var bytes = new Uint8Array(packet_size);
+
+ var temp_arr = self.text_to_char_arr("RFBL");
+ bytes[0] = temp_arr[0];
+ bytes[1] = temp_arr[1];
+ bytes[2] = temp_arr[2];
+ bytes[3] = temp_arr[3];
+ temp_arr = self.text_to_char_arr("CCCC");
+ bytes[4] = temp_arr[3];
+ bytes[5] = 3;
+
+ i = 6;
+ while (i <= packet_size - 1) {
+ bytes[i] = 0;
+ i++;
+ }
+ bytes[packet_size - 1] = 1;
+
+ chrome.hid.send(connectionId, r_id, bytes.buffer, function() {
+ GUI.log('Booting into Awesomeness!... after an impressive light show!!!');
+ });
+
+ var delay = 5000;
+ setTimeout(function () {
+ chrome.hid.send(connectionId, r_id, bytes.buffer, function() {
+ GUI.log('Booting into Awesomeness!');
+ });
+ }, delay);
+
+
+ // proceed to next step
+ //self.upload_procedure(5);
+ }
+ }
+ }
+
+ write2(this.connectionId);
- // start
- erase_page();
- }
break;
case 4:
@@ -768,4 +866,4 @@
};
// initialize object
-var STM32DFU = new STM32DFU_protocol();
\ No newline at end of file
+var RFBLHID = new RFBL_protocol();
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment