From 75bac26c675a97ccadc9de218b39d4b419757827 Mon Sep 17 00:00:00 2001 From: cTn Date: Thu, 5 Jun 2014 16:08:20 +0200 Subject: [PATCH 01/84] fully dynamic aux channel UI --- main.js | 2 +- tabs/auxiliary_configuration.html | 16 ----- tabs/auxiliary_configuration.js | 107 ++++++++++++++++-------------- 3 files changed, 60 insertions(+), 65 deletions(-) diff --git a/main.js b/main.js index 37af0a8a..6a11f081 100644 --- a/main.js +++ b/main.js @@ -174,7 +174,7 @@ $(document).ready(function() { $("#content").on('keydown', 'input[type="number"]', function(e) { // whitelist all that we need for numeric control if ((e.keyCode >= 96 && e.keyCode <= 105) || (e.keyCode >= 48 && e.keyCode <= 57)) { // allow numpad and standard number keypad - } else if(e.keyCode == 109 || e.keyCode == 189) { // minus on numpad and in standard keyboard + } else if (e.keyCode == 109 || e.keyCode == 189) { // minus on numpad and in standard keyboard } else if (e.keyCode == 8 || e.keyCode == 46) { // backspace and delete } else if (e.keyCode == 190 || e.keyCode == 110) { // allow and decimal point } else if ((e.keyCode >= 37 && e.keyCode <= 40) || e.keyCode == 13) { // allow arrows, enter diff --git a/tabs/auxiliary_configuration.html b/tabs/auxiliary_configuration.html index 9a0eb865..43f4f466 100644 --- a/tabs/auxiliary_configuration.html +++ b/tabs/auxiliary_configuration.html @@ -2,25 +2,9 @@ - - - - - - - - - - - - - - - -
AUX 1AUX 2AUX 3AUX 4
diff --git a/tabs/auxiliary_configuration.js b/tabs/auxiliary_configuration.js index c6be127f..c7ed1adb 100644 --- a/tabs/auxiliary_configuration.js +++ b/tabs/auxiliary_configuration.js @@ -1,3 +1,4 @@ +// TODO: rework box_highlight & update_ui to accept flexible amount of aux channels function tab_initialize_auxiliary_configuration() { ga_tracker.sendAppView('Auxiliary Configuration'); GUI.active_tab = 'auxiliary_configuration'; @@ -5,7 +6,11 @@ function tab_initialize_auxiliary_configuration() { MSP.send_message(MSP_codes.MSP_BOXNAMES, false, false, get_box_data); function get_box_data() { - MSP.send_message(MSP_codes.MSP_BOX, false, false, load_html); + MSP.send_message(MSP_codes.MSP_BOX, false, false, get_rc_data); + } + + function get_rc_data() { + MSP.send_message(MSP_codes.MSP_RC, false, false, load_html); } function load_html() { @@ -13,55 +18,39 @@ function tab_initialize_auxiliary_configuration() { } function process_html() { + // generate heads according to RC count + var table_head = $('table.boxes .heads'); + var main_head = $('table.boxes .main'); + for (var i = 0; i < (RC.active_channels - 4); i++) { + table_head.append('AUX ' + (i + 1) + ''); + + // 3 columns per aux channel (this might be requested to change to 6 in the future, so watch out) + main_head.append('\ + \ + \ + \ + '); + } + // translate to user-selected language localize(); - function box_check(num, pos) { - if (bit_check(num, pos)) { // 1 - return ''; - } else { // 0 - return ''; - } - } - - // val = channel value - // aux_num = position of corresponding aux channel in the html table - function box_highlight(val, aux_num) { - var tr = $('table.boxes .switches'); - var pos = 0; // < 1300 - - if (val > 1300 && val < 1700) { - pos = 1; - } else if (val > 1700) { - pos = 2; - } - - $('td:nth-child(' + aux_num + '), td:nth-child(' + (aux_num + 1) + '), td:nth-child(' + (aux_num + 2) + ')', tr).css('background-color', 'transparent'); - $('td:nth-child(' + (aux_num + pos) + ')', tr).css('background-color', 'orange'); - } - // generate table from the supplied AUX names and AUX data for (var i = 0; i < AUX_CONFIG.length; i++) { - $('.boxes > tbody:last').append( - '' + - '' + AUX_CONFIG[i] + '' + - box_check(AUX_CONFIG_values[i], 0) + - box_check(AUX_CONFIG_values[i], 1) + - box_check(AUX_CONFIG_values[i], 2) + + var line = ''; + line += '' + AUX_CONFIG[i] + ''; - box_check(AUX_CONFIG_values[i], 3) + - box_check(AUX_CONFIG_values[i], 4) + - box_check(AUX_CONFIG_values[i], 5) + + for (var j = 0; j < (RC.active_channels - 4) * 3; j++) { + if (bit_check(AUX_CONFIG_values[i], j)) { + line += ''; + } else { + line += ''; + } + } - box_check(AUX_CONFIG_values[i], 6) + - box_check(AUX_CONFIG_values[i], 7) + - box_check(AUX_CONFIG_values[i], 8) + + line += ''; - box_check(AUX_CONFIG_values[i], 9) + - box_check(AUX_CONFIG_values[i], 10) + - box_check(AUX_CONFIG_values[i], 11) + - '' - ); + $('.boxes > tbody:last').append(line); } // UI Hooks @@ -78,7 +67,7 @@ function tab_initialize_auxiliary_configuration() { needle++; - if (needle >= 12) { // 4 aux * 3 checkboxes = 12 bits per line + if (needle >= (RC.active_channels - 4) * 3) { // 1 aux * 3 checkboxes, 4 AUX = 12 bits per line main_needle++; needle = 0; @@ -110,6 +99,25 @@ function tab_initialize_auxiliary_configuration() { } }); + // val = channel value + // aux_num = position of corresponding aux channel in the html table + var switches_e = $('table.boxes .switches'); + function box_highlight(aux_num, val) { + var pos = 0; // < 1300 + + if (val > 1300 && val < 1700) { + pos = 1; + } else if (val > 1700) { + pos = 2; + } + + var highlight_column = (aux_num * 3) + pos + 2; // +2 to skip name column and index starting on 1 instead of 0 + var erase_columns = (aux_num * 3) + 2; + + $('td:nth-child(n+' + erase_columns + '):nth-child(-n+' + (erase_columns + 2) + ')', switches_e).css('background-color', 'transparent'); + $('td:nth-child(' + highlight_column + ')', switches_e).css('background-color', 'orange'); + } + // data pulling functions used inside interval timer function get_rc_data() { MSP.send_message(MSP_codes.MSP_RC, false, false, update_ui); @@ -126,16 +134,19 @@ function tab_initialize_auxiliary_configuration() { $('td.name').eq(i).addClass('off'); } } + } - box_highlight(RC.channels[4], 2); // aux 1 - box_highlight(RC.channels[5], 5); // aux 2 - box_highlight(RC.channels[6], 8); // aux 3 - box_highlight(RC.channels[7], 11); // aux 4 + for (var i = 0; i < (RC.active_channels - 4); i++) { + box_highlight(i, RC.channels[i + 4]); + } } + // update ui instantly on first load + update_ui(); + // enable data pulling - GUI.interval_add('aux_data_pull', get_rc_data, 50, true); + GUI.interval_add('aux_data_pull', get_rc_data, 50); // status data pulled via separate timer with static speed GUI.interval_add('status_pull', function() { From b09620b6aee3f5b2c71cea6312190d8968c8c3dd Mon Sep 17 00:00:00 2001 From: cTn Date: Sat, 7 Jun 2014 17:54:51 +0200 Subject: [PATCH 02/84] remove obsolete needle, cleanup --- js/data_storage.js | 14 +++++++------- js/msp.js | 6 ++---- tabs/auxiliary_configuration.js | 10 ++++------ 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/js/data_storage.js b/js/data_storage.js index 3af5498a..00c2c4d2 100644 --- a/js/data_storage.js +++ b/js/data_storage.js @@ -38,10 +38,10 @@ var RC_tuning = { throttle_EXPO: 0, }; -var AUX_CONFIG = new Array(); -var AUX_CONFIG_values = new Array(); +var AUX_CONFIG = []; +var AUX_CONFIG_values = []; -var SERVO_CONFIG = new Array(); +var SERVO_CONFIG = []; var SENSOR_DATA = { gyroscope: [0, 0, 0], @@ -70,10 +70,10 @@ var GPS_DATA = { update: 0, // baseflight specific gps stuff - chn: new Array(), - svid: new Array(), - quality: new Array(), - cno: new Array() + chn: [], + svid: [], + quality: [], + cno: [] }; var ANALOG = { diff --git a/js/msp.js b/js/msp.js index fea1fdc6..fb60af29 100644 --- a/js/msp.js +++ b/js/msp.js @@ -283,8 +283,7 @@ MSP.process_data = function(code, message_buffer, message_length) { } break; case MSP_codes.MSP_BOX: - // dump previous data (if there was any) - AUX_CONFIG_values = new Array(); + AUX_CONFIG_values = []; // empty the array as new data is coming in // fill in current data for (var i = 0; i < data.byteLength; i += 2) { // + 2 because uint16_t = 2 bytes @@ -345,8 +344,7 @@ MSP.process_data = function(code, message_buffer, message_length) { console.log(data); break; case MSP_codes.MSP_SERVO_CONF: - // drop previous data - SERVO_CONFIG = []; + SERVO_CONFIG = []; // empty the array as new data is coming in for (var i = 0; i < 56; i += 7) { var arr = { diff --git a/tabs/auxiliary_configuration.js b/tabs/auxiliary_configuration.js index c7ed1adb..4d648a60 100644 --- a/tabs/auxiliary_configuration.js +++ b/tabs/auxiliary_configuration.js @@ -74,13 +74,11 @@ function tab_initialize_auxiliary_configuration() { } }); - // send over the data - var AUX_val_buffer_out = new Array(); - - var needle = 0; + // send over data + var AUX_val_buffer_out = []; for (var i = 0; i < AUX_CONFIG_values.length; i++) { - AUX_val_buffer_out[needle++] = lowByte(AUX_CONFIG_values[i]); - AUX_val_buffer_out[needle++] = highByte(AUX_CONFIG_values[i]); + AUX_val_buffer_out.push(lowByte(AUX_CONFIG_values[i])); + AUX_val_buffer_out.push(highByte(AUX_CONFIG_values[i])); } MSP.send_message(MSP_codes.MSP_SET_BOX, AUX_val_buffer_out, false, save_to_eeprom); From c4e1cf2600d701337ae5979be1ddac09cd14457e Mon Sep 17 00:00:00 2001 From: cTn Date: Sun, 8 Jun 2014 17:16:44 +0200 Subject: [PATCH 03/84] initial (header) work on STM32DFU --- js/data_storage.js | 2 +- js/stm32dfu.js | 82 ++++++++++++++++++++++++++++++++++++++++++++++ main.html | 1 + 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 js/stm32dfu.js diff --git a/js/data_storage.js b/js/data_storage.js index 00c2c4d2..35e55ab8 100644 --- a/js/data_storage.js +++ b/js/data_storage.js @@ -51,7 +51,7 @@ var SENSOR_DATA = { kinematicsX: 0.0, kinematicsY: 0.0, kinematicsZ: 0.0, - debug: [0, 0, 0, 0] + debug: [0, 0, 0, 0] }; var MOTOR_DATA = new Array(8); diff --git a/js/stm32dfu.js b/js/stm32dfu.js new file mode 100644 index 00000000..4c9c4436 --- /dev/null +++ b/js/stm32dfu.js @@ -0,0 +1,82 @@ +/* + USB DFU uses: + control transfers for communicating + recipient is interface + request type is class +*/ + +var STM32DFU_protocol = function() { + this.hex; // ref + this.verify_hex; + + this.handle = null; // connection handle + + this.command = { + 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 + UPLOAD: 0x02, // IN, Requests data transfer from device to Host in order to load content of device internal Flash into a Host file. + GETSTATUS: 0x03, // IN, Requests device to send status report to the Host (including status resulting from the last request execution and the state the device will enter immediately after this request). + CLRSTATUS: 0x04, // OUT, Requests device to clear error status and move to next step + GETSTATE: 0x05, // IN, Requests the device to send only the state it will enter immediately after this request. + ABORT: 0x06 // OUT, Requests device to exit the current state/operation and enter idle state immediately. + }; + + this.status = { + OK: 0x00, // No error condition is present. + errTARGET: 0x01, // File is not targeted for use by this device. + errFILE: 0x02, // File is for this device but fails some vendor-specific verification test + errWRITE: 0x03, // Device is unable to write memory. + errERASE: 0x04, // Memory erase function failed. + errCHECK_ERASED: 0x05, // Memory erase check failed. + errPROG: 0x06, // Program memory function failed. + errVERIFY: 0x07, // Programmed memory failed verification. + errADDRESS: 0x08, // Cannot program memory due to received address that is out of range. + errNOTDONE: 0x09, // Received DFU_DNLOAD with wLength = 0, but device does not think it has all of the data yet. + errFIRMWARE: 0x0A, // Device's firmware is corrupt. It cannot return to run-time (non-DFU) operations. + errVENDOR: 0x0B, // iString indicates a vendor-specific error. + errUSBR: 0x0C, // Device detected unexpected USB reset signaling. + errPOR: 0x0D, // Device detected unexpected power on reset. + errUNKNOWN: 0x0E, // Something went wrong, but the device does not know what it was. + errSTALLEDPKT: 0x0F // Device stalled an unexpected request. + }; + + this.state = { + appIDLE: 0, // Device is running its normal application. + appDETACH: 1, // Device is running its normal application, has received the DFU_DETACH request, and is waiting for a USB reset. + dfuIDLE: 2, // Device is operating in the DFU mode and is waiting for requests. + dfuDNLOAD_SYNC: 3, // Device has received a block and is waiting for the host to solicit the status via DFU_GETSTATUS. + dfuDNBUSY: 4, // Device is programming a control-write block into its nonvolatile memories. + dfuDNLOAD_IDLE: 5, // Device is processing a download operation. Expecting DFU_DNLOAD requests. + dfuMANIFEST_SYNC: 6, // Device has received the final block of firmware from the host and is waiting for receipt of DFU_GETSTATUS to begin the Manifestation phase; or device has completed the Manifestation phase and is waiting for receipt of DFU_GETSTATUS. + dfuMANIFEST: 7, // Device is in the Manifestation phase. (Not all devices will be able to respond to DFU_GETSTATUS when in this state.) + dfuMANIFEST_WAIT_RESET: 8, // Device has programmed its memories and is waiting for a USB reset or a power on reset. (Devices that must enter this state clear bitManifestationTolerant to 0.) + dfuUPLOAD_IDLE: 9, // The device is processing an upload operation. Expecting DFU_UPLOAD requests. + dfuERROR: 10 // An error has occurred. Awaiting the DFU_CLRSTATUS request. + }; +}; + +STM32DFU_protocol.prototype.openDevice = function(callback) { +}; + +STM32DFU_protocol.prototype.closeDevice = function(callback) { +}; + +STM32DFU_protocol.prototype.claimInterface = function(callback) { +}; + +STM32DFU_protocol.prototype.releaseInterface = function(callback) { +}; + +STM32DFU_protocol.prototype.resetDevice = function(callback) { + chrome.usb.resetDevice(this.handle, function(result) { + console.log('Reset Device: ' + result); + + if (callback) callback(); + }); +}; + +STM32DFU_protocol.prototype.controlTransfer = function() { +}; + +// initialize object +var STM32DFU = new STM32DFU_protocol(); \ No newline at end of file diff --git a/main.html b/main.html index 5d857a29..59373e69 100644 --- a/main.html +++ b/main.html @@ -32,6 +32,7 @@ + From 8231c60b3cc51413f5d89e2d32beff1f0c57acd3 Mon Sep 17 00:00:00 2001 From: cTn Date: Sun, 8 Jun 2014 17:42:02 +0200 Subject: [PATCH 04/84] initial implementation of control transfer in/out --- js/stm32dfu.js | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/js/stm32dfu.js b/js/stm32dfu.js index 4c9c4436..97a1fafb 100644 --- a/js/stm32dfu.js +++ b/js/stm32dfu.js @@ -11,7 +11,7 @@ var STM32DFU_protocol = function() { this.handle = null; // connection handle - this.command = { + 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 UPLOAD: 0x02, // IN, Requests data transfer from device to Host in order to load content of device internal Flash into a Host file. @@ -75,7 +75,38 @@ STM32DFU_protocol.prototype.resetDevice = function(callback) { }); }; -STM32DFU_protocol.prototype.controlTransfer = function() { +STM32DFU_protocol.prototype.controlTransfer = function(direction, request, value, interface, length, data, callback) { + if (direction == 'in') { + // data is ignored + chrome.usb.controlTransfer(this.handle, { + 'direction': 'in', + 'recipient': 'interface', + 'requestType': 'class', + 'request': request, + 'value': value, + 'index': interface, + 'length': length + }, callback); + } else { + // length is ignored + if (data) { + var arrayBuf = new ArrayBuffer(data.length); + var arrayBufView = new Uint8Array(arrayBuf); + arrayBufView.set(data); + } else { + var arrayBuf = new ArrayBuffer(0); + } + + chrome.usb.controlTransfer(this.handle, { + 'direction': 'out', + 'recipient': 'interface', + 'requestType': 'class', + 'request': request, + 'value': value, + 'index': interface, + 'data': arrayBuf + }, callback); + } }; // initialize object From cda43ac9bf8d11b374468f139b1637e99e6cbca0 Mon Sep 17 00:00:00 2001 From: cTn Date: Sun, 8 Jun 2014 18:42:31 +0200 Subject: [PATCH 05/84] add additional permissions so we can use USB api --- js/stm32dfu.js | 6 ++++++ manifest.json | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/js/stm32dfu.js b/js/stm32dfu.js index 97a1fafb..dc4a7368 100644 --- a/js/stm32dfu.js +++ b/js/stm32dfu.js @@ -53,6 +53,12 @@ var STM32DFU_protocol = function() { dfuUPLOAD_IDLE: 9, // The device is processing an upload operation. Expecting DFU_UPLOAD requests. dfuERROR: 10 // An error has occurred. Awaiting the DFU_CLRSTATUS request. }; + + this.usbDevices = { + F3DiscoveryDFU: {'vendorId': 1155, 'productId': 57105} + }; + + this.usbPermissions = {permissions: [{'usbDevices': [this.usbDevices.F3DiscoveryDFU]}]}; }; STM32DFU_protocol.prototype.openDevice = function(callback) { diff --git a/manifest.json b/manifest.json index 83da3444..5b48ad14 100644 --- a/manifest.json +++ b/manifest.json @@ -23,6 +23,7 @@ "https://*.github.com/", "https://*.githubusercontent.com/", "serial", + "usb", "storage", "fileSystem", "fileSystem.write", @@ -30,6 +31,12 @@ "notifications" ], + "optional_permissions": [ + {"usbDevices": [ + {"vendorId": 1155, "productId": 57105} + ]} + ], + "icons": { "128": "images/icon_128.png" } From a0582fd79fedd144c7fb0dca9e82e63ddfa53372 Mon Sep 17 00:00:00 2001 From: cTn Date: Sun, 8 Jun 2014 19:32:24 +0200 Subject: [PATCH 06/84] adding request usb permissions UI (DEV only) --- _locales/en/messages.json | 16 ++++++++++++++++ js/gui.js | 1 + js/stm32dfu.js | 6 ------ js/usb.js | 32 ++++++++++++++++++++++++++++++++ main.html | 1 + tabs/default.css | 39 +++++++++++++++++++++++++++++++++++++++ tabs/default.html | 7 +++++++ tabs/default.js | 2 ++ 8 files changed, 98 insertions(+), 6 deletions(-) create mode 100644 js/usb.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 08e8541f..b2823c76 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -112,10 +112,26 @@ "message": "Cycle Time:" }, + "please_grant_usb_permissions": { + "message": "Please click on \"Request Optional Permissions\" button to grant application required USB access" + }, + "usb_permissions_granted": { + "message": "Optional USB permissions granted" + }, + "eeprom_saved_ok": { "message": "EEPROM saved" }, + "default_optional_permissions_head": { + "message": "Optional USB Permissions" + }, + "default_optional_permissions_text": { + "message": "Due to addition of Naze32PRO to the supported hardware family, Configurator requires USB access to allow firmware flashing via DFU" + }, + "default_request_optional_permissions": { + "message": "Request Optional Permissions" + }, "defaultWelcomeText": { "message": "This application is a configuration utility for baseflight, a 32 bit fork of the popular open source RC flight control firmware project MultiWii.

Application supports hardware that run Baseflight exclusively (acro naze, naze, afromini)

Official Resellers & Backers
AbuseMark - International (Japan)
Multirotor Superstore - International (United States)

The firmware source code can be downloaded from here
The newest binary firmware image is available here
" }, diff --git a/js/gui.js b/js/gui.js index 0933c3e6..cdf00f06 100644 --- a/js/gui.js +++ b/js/gui.js @@ -4,6 +4,7 @@ var GUI_control = function() { this.connected_to = false; this.active_tab; this.operating_system; + this.optional_usb_permissions = false; // controlled by usb permissions code this.interval_array = []; this.timeout_array = []; diff --git a/js/stm32dfu.js b/js/stm32dfu.js index dc4a7368..97a1fafb 100644 --- a/js/stm32dfu.js +++ b/js/stm32dfu.js @@ -53,12 +53,6 @@ var STM32DFU_protocol = function() { dfuUPLOAD_IDLE: 9, // The device is processing an upload operation. Expecting DFU_UPLOAD requests. dfuERROR: 10 // An error has occurred. Awaiting the DFU_CLRSTATUS request. }; - - this.usbDevices = { - F3DiscoveryDFU: {'vendorId': 1155, 'productId': 57105} - }; - - this.usbPermissions = {permissions: [{'usbDevices': [this.usbDevices.F3DiscoveryDFU]}]}; }; STM32DFU_protocol.prototype.openDevice = function(callback) { diff --git a/js/usb.js b/js/usb.js new file mode 100644 index 00000000..1134658a --- /dev/null +++ b/js/usb.js @@ -0,0 +1,32 @@ +var usbDevices = { + STM32DFU: {'vendorId': 1155, 'productId': 57105} +}; +var usbPermissions = {permissions: [{'usbDevices': [usbDevices.STM32DFU]}]}; + +function check_usb_permissions(callback) { + chrome.permissions.contains(usbPermissions, function(result) { + if (result) { + GUI.optional_usb_permissions = true; + } else { + console.log('Optional USB permissions: missing'); + GUI.log(chrome.i18n.getMessage('please_grant_usb_permissions')); + + // display optional usb permissions request box + $('div.optional_permissions').show(); + + // UI hooks + document.getElementById("requestOptionalPermissions").addEventListener('click', function() { + chrome.permissions.request(usbPermissions, function(result) { + if (result) { + GUI.log(chrome.i18n.getMessage('usb_permissions_granted')); + $('div.optional_permissions').hide(); + + GUI.optional_usb_permissions = true; + } + }); + }); + } + + if (callback) callback(); + }); +} \ No newline at end of file diff --git a/main.html b/main.html index 59373e69..5be08ece 100644 --- a/main.html +++ b/main.html @@ -25,6 +25,7 @@ + diff --git a/tabs/default.css b/tabs/default.css index 0aea6ddb..259ed23d 100644 --- a/tabs/default.css +++ b/tabs/default.css @@ -8,6 +8,45 @@ width: calc(40% - 10px); } +.tab-default .optional_permissions { + display: none; + + margin-bottom: 10px; + + border: 1px solid silver; +} + .tab-default .optional_permissions .title { + line-height: 20px; + + text-align: center; + font-weight: bold; + color: white; + + border-bottom: 1px solid silver; + background-color: #cd4c4c; + } + .tab-default .optional_permissions p { + padding: 5px; + } + .tab-default .optional_permissions a { + display: block; + float: left; + + height: 28px; + line-height: 28px; + + margin: 0 0 5px 5px; + padding: 0 15px 0 15px; + + text-align: center; + font-weight: bold; + + border: 1px solid silver; + background-color: #ececec; + } + .tab-default .optional_permissions a:hover { + background-color: #dedcdc; + } .welcome { margin-bottom: 10px; diff --git a/tabs/default.html b/tabs/default.html index 616dc8db..548425c2 100644 --- a/tabs/default.html +++ b/tabs/default.html @@ -1,5 +1,12 @@
+
+
+

+

+ +
+
\ No newline at end of file diff --git a/tabs/logging.js b/tabs/logging.js index cc261e0a..5da35654 100644 --- a/tabs/logging.js +++ b/tabs/logging.js @@ -112,6 +112,22 @@ function tab_initialize_logging() { } }); + if (MSP_pass_through) { + $('a.back').show(); + + $('a.back').click(function() { + if (GUI.connected_to) { + $('a.connect').click(); + } else { + GUI.tab_switch_cleanup(function() { + MSP_pass_through = false; + $('#tabs > ul li').removeClass('active'); + tab_initialize_default(); + }); + } + }); + } + chrome.storage.local.get('logging_file_entry', function(result) { if (result.logging_file_entry) { chrome.fileSystem.restoreEntry(result.logging_file_entry, function(entry) { From 19de1e8040e749dcc2888ac3d3c209450d7265d7 Mon Sep 17 00:00:00 2001 From: cTn Date: Fri, 20 Jun 2014 11:55:14 +0200 Subject: [PATCH 33/84] add MSP_ANALOG support to logger --- tabs/logging.html | 1 + tabs/logging.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/tabs/logging.html b/tabs/logging.html index 4f2b9ac3..2fa90fc7 100644 --- a/tabs/logging.html +++ b/tabs/logging.html @@ -7,6 +7,7 @@
3 columns (x, y, z)
one column
7 columns
+
4 columns
8 columns by default
8 columns by default
4 columns
diff --git a/tabs/logging.js b/tabs/logging.js index 5da35654..ced6a921 100644 --- a/tabs/logging.js +++ b/tabs/logging.js @@ -167,6 +167,12 @@ function tab_initialize_logging() { sample += ',' + GPS_DATA.speed; sample += ',' + GPS_DATA.ground_course; break; + case 'MSP_ANALOG': + sample += ',' + ANALOG.voltage; + sample += ',' + ANALOG.amperage; + sample += ',' + ANALOG.mAhdrawn; + sample += ',' + ANALOG.rssi; + break; case 'MSP_RC': for (var chan = 0; chan < RC.active_channels; chan++) { sample += ',' + RC.channels[chan]; @@ -219,6 +225,12 @@ function tab_initialize_logging() { head += ',' + 'gpsSpeed'; head += ',' + 'gpsGroundCourse'; break; + case 'MSP_ANALOG': + head += ',' + 'voltage'; + head += ',' + 'amperage'; + head += ',' + 'mAhdrawn'; + head += ',' + 'rssi'; + break; case 'MSP_RC': for (var chan = 0; chan < RC.active_channels; chan++) { head += ',' + 'RC' + chan; From 8dfec796ee381ab8c7ec9a79b19e4939aaf2adb0 Mon Sep 17 00:00:00 2001 From: cTn Date: Fri, 20 Jun 2014 11:59:53 +0200 Subject: [PATCH 34/84] add error message for not being connected --- _locales/en/messages.json | 3 + tabs/logging.js | 112 ++++++++++++++++++++------------------ 2 files changed, 61 insertions(+), 54 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 7ebb415b..eab1bea3 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -493,6 +493,9 @@ "loggingBack": { "message": "Leave Logging / Disconnect" }, + "loggingErrorNotConnected": { + "message": "You need to connect first" + }, "loggingErrorLogFile": { "message": "Please select log file" }, diff --git a/tabs/logging.js b/tabs/logging.js index ced6a921..4e8795dd 100644 --- a/tabs/logging.js +++ b/tabs/logging.js @@ -40,75 +40,79 @@ function tab_initialize_logging() { $('a.log_file').click(prepare_file); $('a.logging').click(function() { - if (fileEntry != null) { - var clicks = $(this).data('clicks'); + if (GUI.connected_to) { + if (fileEntry != null) { + var clicks = $(this).data('clicks'); - if (!clicks) { - // reset some variables before start - samples = 0; - log_buffer = []; - requested_properties = []; + if (!clicks) { + // reset some variables before start + samples = 0; + log_buffer = []; + requested_properties = []; - $('.properties input:checked').each(function() { - requested_properties.push($(this).prop('name')); - }); + $('.properties input:checked').each(function() { + requested_properties.push($(this).prop('name')); + }); - if (requested_properties.length) { - // print header for the csv file - print_head(); + if (requested_properties.length) { + // print header for the csv file + print_head(); - function poll_data() { - // save current - crunch_data(); + function poll_data() { + // save current + crunch_data(); - // request new - if (!MSP_pass_through) { - for (var i = 0; i < requested_properties.length; i++) { - MSP.send_message(MSP_codes[requested_properties[i]]); + // request new + if (!MSP_pass_through) { + for (var i = 0; i < requested_properties.length; i++) { + MSP.send_message(MSP_codes[requested_properties[i]]); - /* this approach could be used if we want to utilize request time compensation - if (i < requested_properties.length -1) { - MSP.send_message(requested_properties[i]); - } else { - MSP.send_message(requested_properties[i], false, false, poll_data); + /* this approach could be used if we want to utilize request time compensation + if (i < requested_properties.length -1) { + MSP.send_message(requested_properties[i]); + } else { + MSP.send_message(requested_properties[i], false, false, poll_data); + } + */ } - */ } } + + GUI.interval_add('log_data_pull', poll_data, parseInt($('select.speed').val()), true); // refresh rate goes here + GUI.interval_add('flush_data', function() { + if (log_buffer.length) { // only execute when there is actual data to write + if (fileWriter.readyState == 0 || fileWriter.readyState == 2) { + append_to_file(log_buffer.join('\n')); + + $('.samples').text(samples += log_buffer.length); + $('.size').text(chrome.i18n.getMessage('loggingKB', [(fileWriter.length / 1024).toFixed(2)])); + + log_buffer = []; + } else { + console.log('IO having trouble keeping up with the data flow'); + } + } + }, 1000); + + $('.speed').prop('disabled', true); + $(this).text(chrome.i18n.getMessage('loggingStop')); + $(this).data("clicks", !clicks); + } else { + GUI.log(chrome.i18n.getMessage('loggingErrorOneProperty')); } - - GUI.interval_add('log_data_pull', poll_data, parseInt($('select.speed').val()), true); // refresh rate goes here - GUI.interval_add('flush_data', function() { - if (log_buffer.length) { // only execute when there is actual data to write - if (fileWriter.readyState == 0 || fileWriter.readyState == 2) { - append_to_file(log_buffer.join('\n')); - - $('.samples').text(samples += log_buffer.length); - $('.size').text(chrome.i18n.getMessage('loggingKB', [(fileWriter.length / 1024).toFixed(2)])); - - log_buffer = []; - } else { - console.log('IO having trouble keeping up with the data flow'); - } - } - }, 1000); - - $('.speed').prop('disabled', true); - $(this).text(chrome.i18n.getMessage('loggingStop')); - $(this).data("clicks", !clicks); } else { - GUI.log(chrome.i18n.getMessage('loggingErrorOneProperty')); + GUI.interval_remove('log_data_pull'); + GUI.interval_remove('flush_data'); + + $('.speed').prop('disabled', false); + $(this).text(chrome.i18n.getMessage('loggingStart')); + $(this).data("clicks", !clicks); } } else { - GUI.interval_remove('log_data_pull'); - GUI.interval_remove('flush_data'); - - $('.speed').prop('disabled', false); - $(this).text(chrome.i18n.getMessage('loggingStart')); - $(this).data("clicks", !clicks); + GUI.log(chrome.i18n.getMessage('loggingErrorLogFile')); } } else { - GUI.log(chrome.i18n.getMessage('loggingErrorLogFile')); + GUI.log(chrome.i18n.getMessage('loggingErrorNotConnected')); } }); From 8273081fdd8f1b287218d3271818fdcfa5f66159 Mon Sep 17 00:00:00 2001 From: cTn Date: Fri, 20 Jun 2014 12:39:42 +0200 Subject: [PATCH 35/84] moving kinematics data to array --- js/data_storage.js | 4 +--- js/msp.js | 6 +++--- tabs/initial_setup.js | 6 +++--- tabs/logging.js | 6 +++--- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/js/data_storage.js b/js/data_storage.js index 35e55ab8..d97b743f 100644 --- a/js/data_storage.js +++ b/js/data_storage.js @@ -48,9 +48,7 @@ var SENSOR_DATA = { accelerometer: [0, 0, 0], magnetometer: [0, 0, 0], altitude: 0, - kinematicsX: 0.0, - kinematicsY: 0.0, - kinematicsZ: 0.0, + kinematics: [0.0, 0.0, 0.0], debug: [0, 0, 0, 0] }; diff --git a/js/msp.js b/js/msp.js index 5a1e6b4e..4f85954f 100644 --- a/js/msp.js +++ b/js/msp.js @@ -231,9 +231,9 @@ MSP.process_data = function(code, message_buffer, message_length) { GPS_DATA.update = data.getUint8(4); break; case MSP_codes.MSP_ATTITUDE: - SENSOR_DATA.kinematicsX = data.getInt16(0, 1) / 10.0; - SENSOR_DATA.kinematicsY = data.getInt16(2, 1) / 10.0; - SENSOR_DATA.kinematicsZ = data.getInt16(4, 1); + SENSOR_DATA.kinematics[0] = data.getInt16(0, 1) / 10.0; // x + SENSOR_DATA.kinematics[1] = data.getInt16(2, 1) / 10.0; // y + SENSOR_DATA.kinematics[2] = data.getInt16(4, 1); // z break; case MSP_codes.MSP_ALTITUDE: SENSOR_DATA.altitude = parseFloat((data.getInt32(0, 1) / 100.0).toFixed(2)); // correct scale factor diff --git a/tabs/initial_setup.js b/tabs/initial_setup.js index cb5ce0d8..ee0be55c 100644 --- a/tabs/initial_setup.js +++ b/tabs/initial_setup.js @@ -251,9 +251,9 @@ function tab_initialize_initial_setup() { // Update cube var cube = $('div#cube'); - cube.css('-webkit-transform', 'rotateY(' + ((SENSOR_DATA.kinematicsZ * -1.0) - yaw_fix) + 'deg)'); - $('#cubePITCH', cube).css('-webkit-transform', 'rotateX(' + SENSOR_DATA.kinematicsY + 'deg)'); - $('#cubeROLL', cube).css('-webkit-transform', 'rotateZ(' + SENSOR_DATA.kinematicsX + 'deg)'); + cube.css('-webkit-transform', 'rotateY(' + ((SENSOR_DATA.kinematics[2] * -1.0) - yaw_fix) + 'deg)'); + $('#cubePITCH', cube).css('-webkit-transform', 'rotateX(' + SENSOR_DATA.kinematics[1] + 'deg)'); + $('#cubeROLL', cube).css('-webkit-transform', 'rotateZ(' + SENSOR_DATA.kinematics[0] + 'deg)'); } GUI.interval_add('initial_setup_data_pull', get_analog_data, 50, true); diff --git a/tabs/logging.js b/tabs/logging.js index 4e8795dd..7a7ee052 100644 --- a/tabs/logging.js +++ b/tabs/logging.js @@ -155,9 +155,9 @@ function tab_initialize_logging() { sample += ',' + SENSOR_DATA.magnetometer; break; case 'MSP_ATTITUDE': - sample += ',' + SENSOR_DATA.kinematicsX; - sample += ',' + SENSOR_DATA.kinematicsY; - sample += ',' + SENSOR_DATA.kinematicsZ; + sample += ',' + SENSOR_DATA.kinematics[0]; + sample += ',' + SENSOR_DATA.kinematics[1]; + sample += ',' + SENSOR_DATA.kinematics[2]; break; case 'MSP_ALTITUDE': sample += ',' + SENSOR_DATA.altitude; From 61bed4770fd8678220303bd3ce538963bf41e80b Mon Sep 17 00:00:00 2001 From: cTn Date: Fri, 20 Jun 2014 14:29:16 +0200 Subject: [PATCH 36/84] cosmetic change --- js/port_handler.js | 22 +++++++++++----------- js/serial_backend.js | 2 +- js/stm32.js | 2 +- tabs/firmware_flasher.js | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/js/port_handler.js b/js/port_handler.js index 4cb0eb9a..f685b203 100644 --- a/js/port_handler.js +++ b/js/port_handler.js @@ -65,7 +65,7 @@ port_handler.prototype.check = function() { if (port == result.last_used_port) { console.log('Selecting last used port: ' + result.last_used_port); - $('div#port-picker .port select').val(result.last_used_port); + $('div#port-picker #port').val(result.last_used_port); } }); } else { @@ -98,9 +98,9 @@ port_handler.prototype.check = function() { // select / highlight new port, if connected -> select connected port if (!GUI.connected_to) { - $('div#port-picker .port select').val(new_ports[0]); + $('div#port-picker #port').val(new_ports[0]); } else { - $('div#port-picker .port select').val(GUI.connected_to); + $('div#port-picker #port').val(GUI.connected_to); } // start connect procedure (if statement is valid) @@ -143,13 +143,13 @@ port_handler.prototype.check = function() { function check_usb_devices() { chrome.usb.getDevices(usbDevices.STM32DFU, function(result) { if (result.length) { - if (!$("div#port-picker .port select [value='DFU']").length) { - $('div#port-picker .port select').append(''); - $('div#port-picker .port select').val('DFU'); + if (!$("div#port-picker #port [value='DFU']").length) { + $('div#port-picker #port').append(''); + $('div#port-picker #port').val('DFU'); } } else { - if ($("div#port-picker .port select [value='DFU']").length) { - $("div#port-picker .port select [value='DFU']").remove(); + if ($("div#port-picker #port [value='DFU']").length) { + $("div#port-picker #port [value='DFU']").remove(); } } }); @@ -157,14 +157,14 @@ port_handler.prototype.check = function() { }; port_handler.prototype.update_port_select = function(ports) { - $('div#port-picker .port select').html(''); // drop previous one + $('div#port-picker #port').html(''); // drop previous one if (ports.length > 0) { for (var i = 0; i < ports.length; i++) { - $('div#port-picker .port select').append($("
-
+
@@ -69,7 +69,6 @@
-
@@ -92,4 +91,7 @@
+
+ +
\ No newline at end of file From e8c4a03dd541837201693e7c5299a3f404123a15 Mon Sep 17 00:00:00 2001 From: cTn Date: Fri, 4 Jul 2014 20:55:46 +0200 Subject: [PATCH 82/84] moving majority of save buttons to bottom right corner, graph margin plish --- tabs/auxiliary_configuration.css | 8 +++-- tabs/auxiliary_configuration.html | 4 ++- tabs/initial_setup.css | 13 +++---- tabs/logging.css | 7 ++-- tabs/logging.html | 4 +-- tabs/pid_tuning.css | 6 ++++ tabs/pid_tuning.html | 6 ++-- tabs/receiver.css | 59 ++++++++++++++++--------------- tabs/receiver.html | 6 ++-- tabs/receiver.js | 2 +- tabs/sensors.js | 2 +- tabs/servos.css | 6 ++++ tabs/servos.html | 4 ++- 13 files changed, 76 insertions(+), 51 deletions(-) diff --git a/tabs/auxiliary_configuration.css b/tabs/auxiliary_configuration.css index d941e4c4..3a8a3c91 100644 --- a/tabs/auxiliary_configuration.css +++ b/tabs/auxiliary_configuration.css @@ -40,12 +40,16 @@ border: 0; background-color: white; } + .tab-auxiliary_configuration .buttons { + width: calc(100% - 20px); + + position: absolute; + bottom: 10px; + } .tab-auxiliary_configuration .update { display: block; float: right; - margin-top: 10px; - height: 28px; line-height: 28px; diff --git a/tabs/auxiliary_configuration.html b/tabs/auxiliary_configuration.html index 43f4f466..2ef7ddba 100644 --- a/tabs/auxiliary_configuration.html +++ b/tabs/auxiliary_configuration.html @@ -7,5 +7,7 @@ - +
+ +
\ No newline at end of file diff --git a/tabs/initial_setup.css b/tabs/initial_setup.css index aec8c9ed..e4c28fd0 100644 --- a/tabs/initial_setup.css +++ b/tabs/initial_setup.css @@ -309,20 +309,21 @@ margin-left: 100px; } -.tab-initial_setup .buttons { - width: calc(100% - 20px); + .tab-initial_setup .buttons { + width: calc(100% - 20px); - position: absolute; - bottom: 10px; -} + position: absolute; + bottom: 10px; + } .tab-initial_setup .update { display: block; float: right; - width: 80px; height: 28px; line-height: 28px; + padding: 0 15px 0 15px; + text-align: center; font-weight: bold; diff --git a/tabs/logging.css b/tabs/logging.css index a34c4f65..0e752671 100644 --- a/tabs/logging.css +++ b/tabs/logging.css @@ -56,9 +56,9 @@ } .tab-logging .buttons a { display: block; - float: left; + float: right; - margin-right: 10px; + margin-left: 10px; height: 28px; line-height: 28px; @@ -76,7 +76,4 @@ } .tab-logging .buttons .back { display: none; - - float: right; - margin: 0; } \ No newline at end of file diff --git a/tabs/logging.html b/tabs/logging.html index 863f7886..b5cf7ef0 100644 --- a/tabs/logging.html +++ b/tabs/logging.html @@ -33,8 +33,8 @@
- - + +
\ No newline at end of file diff --git a/tabs/pid_tuning.css b/tabs/pid_tuning.css index c450b8a4..b6c7fc06 100644 --- a/tabs/pid_tuning.css +++ b/tabs/pid_tuning.css @@ -73,6 +73,12 @@ float: right; width: calc(40% - 10px); /* - ( "virtual" margin) */ } + .tab-pid_tuning .buttons { + width: calc(100% - 20px); + + position: absolute; + bottom: 10px; + } .tab-pid_tuning .update, .tab-pid_tuning .refresh { display: block; diff --git a/tabs/pid_tuning.html b/tabs/pid_tuning.html index 1803bedc..1dca82b7 100644 --- a/tabs/pid_tuning.html +++ b/tabs/pid_tuning.html @@ -76,11 +76,13 @@ - -
+
+ + +
\ No newline at end of file diff --git a/tabs/receiver.css b/tabs/receiver.css index aa54bb25..fbba80f8 100644 --- a/tabs/receiver.css +++ b/tabs/receiver.css @@ -121,37 +121,9 @@ border: 1px solid silver; } - .tab-receiver .update, - .tab-receiver .refresh { - display: block; - float: right; - - margin-top: 22px; - - height: 28px; - line-height: 28px; - - padding: 0 15px 0 15px; - - text-align: center; - font-weight: bold; - - border: 1px solid silver; - background-color: #ececec; - } - .tab-receiver .refresh { - margin-right: 10px; - } - .tab-receiver .update:hover, - .tab-receiver .refresh:hover { - background-color: #dedcdc; - } .tab-receiver select[name="rx_refresh_rate"] { float: right; - margin-top: 30px; - margin-right: 20px; - border: 1px solid silver; } .tab-receiver #RX_plot { @@ -194,6 +166,37 @@ .tab-receiver #RX_plot .line:nth-child(12) { stroke: #7a6614; } + .tab-receiver .buttons { + width: calc(100% - 20px); + + position: absolute; + bottom: 10px; + } + .tab-receiver .update, + .tab-receiver .refresh { + display: block; + float: right; + + margin-top: 22px; + + height: 28px; + line-height: 28px; + + padding: 0 15px 0 15px; + + text-align: center; + font-weight: bold; + + border: 1px solid silver; + background-color: #ececec; + } + .tab-receiver .refresh { + margin-right: 10px; + } + .tab-receiver .update:hover, + .tab-receiver .refresh:hover { + background-color: #dedcdc; + } /* SVG classes*/ .tab-receiver .grid .tick { diff --git a/tabs/receiver.html b/tabs/receiver.html index f90f5fc5..28418ba8 100644 --- a/tabs/receiver.html +++ b/tabs/receiver.html @@ -22,8 +22,6 @@ - -
@@ -53,4 +51,8 @@ +
+ + +
diff --git a/tabs/receiver.js b/tabs/receiver.js index 2a884ce0..c44b9b50 100644 --- a/tabs/receiver.js +++ b/tabs/receiver.js @@ -178,7 +178,7 @@ function tab_initialize_receiver() { var svg = d3.select("svg"); var RX_plot_e = $('#RX_plot'); - var margin = {top: 20, right: 20, bottom: 10, left: 40}; + var margin = {top: 20, right: 0, bottom: 10, left: 40}; var width, height, widthScale, heightScale; function update_receiver_plot_size() { width = RX_plot_e.width() - margin.left - margin.right; diff --git a/tabs/sensors.js b/tabs/sensors.js index 1bca3963..23a27f5e 100644 --- a/tabs/sensors.js +++ b/tabs/sensors.js @@ -40,7 +40,7 @@ function tab_initialize_sensors() { return sampleNumber + 1; } - var margin = {top: 20, right: 20, bottom: 10, left: 40}; + var margin = {top: 20, right: 10, bottom: 10, left: 40}; function updateGraphHelperSize(helpers) { helpers.width = helpers.targetElement.width() - margin.left - margin.right; helpers.height = helpers.targetElement.height() - margin.top - margin.bottom; diff --git a/tabs/servos.css b/tabs/servos.css index 056adcd7..bbdaa2d3 100644 --- a/tabs/servos.css +++ b/tabs/servos.css @@ -106,6 +106,12 @@ float: left; margin: 0 0 0 5px; } + .tab-servos .buttons { + width: calc(100% - 20px); + + position: absolute; + bottom: 10px; + } .tab-servos .update { display: block; float: right; diff --git a/tabs/servos.html b/tabs/servos.html index 1ad006a5..887e4abc 100644 --- a/tabs/servos.html +++ b/tabs/servos.html @@ -31,6 +31,8 @@
- +
+ +
\ No newline at end of file From 628972d5f2d844307956dc6aed6ab889cf090bae Mon Sep 17 00:00:00 2001 From: cTn Date: Fri, 4 Jul 2014 20:58:55 +0200 Subject: [PATCH 83/84] removing RapidFlash promotion --- main.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/main.js b/main.js index df6dbb79..7ddad3bd 100644 --- a/main.js +++ b/main.js @@ -46,8 +46,6 @@ $(document).ready(function() { break; } - GUI.log('Are you using ESCs with SimonK firmware? Try RapidFlash, our new utility for configuring / flashing / updating firmware.'); - // Tabs var tabs = $('#tabs > ul'); $('a', tabs).click(function() { From 918d02bedc7b5e66d6b0ffdc71029e4c0982e0cf Mon Sep 17 00:00:00 2001 From: cTn Date: Fri, 4 Jul 2014 21:08:33 +0200 Subject: [PATCH 84/84] updating welcome text, manifest version, changelog, release --- _locales/en/messages.json | 2 +- changelog.html | 5 ++++- manifest.json | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 80de9b53..2c94dbe9 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -136,7 +136,7 @@ "message": "Request Optional Permissions" }, "defaultWelcomeText": { - "message": "Welcome to Baseflight - Configurator, utility designed to simplify updating, configuring and tuning of your flight controller. Supporting complete family of Baseflight hardware (acro naze, naze32, naze32pro and afromini).

Official Resellers & Backers
AbuseMark - International (Japan)
Multirotor Superstore - International (United States)

Latest CP210x Drivers can be downloaded from here
" + "message": "Welcome to Baseflight - Configurator, utility designed to simplify updating, configuring and tuning of your flight controller.
Application supports complete family of Baseflight hardware (acro naze, naze32, naze32pro and afromini).

Official Resellers & Backers
AbuseMark - International (Japan)
Multirotor Superstore - International (United States)

Latest CP210x Drivers can be downloaded from here
" }, "defaultChangelogHead": { "message": "Configurator - Changelog" diff --git a/changelog.html b/changelog.html index b69da820..a482fac6 100644 --- a/changelog.html +++ b/changelog.html @@ -1,6 +1,9 @@ -xx.xx.2014 - 0.45 +07.04.2014 - 0.45

- Configurator reached 5000+ users on 07.03.2014
+ - Updated various text notes to make things clearer
+ - UI polish
+ - Various bugfixes

06.27.2014 - 0.44

diff --git a/manifest.json b/manifest.json index 741cb7c3..32fad074 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "minimum_chrome_version": "33", - "version": "0.44.4", + "version": "0.45", "author": "cTn", "name": "Baseflight - Configurator",