Created
September 20, 2016 08:38
-
-
Save tracernz/1100ca6d589f430f6a4c123248040a27 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- 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