From fa3ce5716b5efac7af6f595b2493b6672ccf54bb Mon Sep 17 00:00:00 2001 From: Mauro Mombelli Date: Tue, 28 Apr 2015 10:13:58 +0200 Subject: [PATCH 01/55] Increase range because some analog servo As the issue #170, but in the correct branch --- tabs/servos.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tabs/servos.js b/tabs/servos.js index 46b7ca85..24a2ed42 100644 --- a/tabs/servos.js +++ b/tabs/servos.js @@ -91,9 +91,9 @@ TABS.servos.initialize = function (callback) { $('div.tab-servos table.fields').append('\ \ ' + name + '\ - \ - \ - \ + \ + \ + \ ' + servoCheckbox + '\ \ ' + name + '\ @@ -318,4 +318,4 @@ TABS.servos.initialize = function (callback) { TABS.servos.cleanup = function (callback) { if (callback) callback(); -}; \ No newline at end of file +}; From 17d525352fd17eda67860d2fdc554b0381bb20f8 Mon Sep 17 00:00:00 2001 From: tricopterY Date: Tue, 26 May 2015 16:28:58 +1000 Subject: [PATCH 02/55] Allow FC loop time change via Configuration Tab --- .gitignore | 1 + _locales/en/messages.json | 3 +++ changelog.html | 1 + tabs/configuration.css | 22 +++++++++++++++++++++- tabs/configuration.html | 9 ++++++++- tabs/configuration.js | 32 +++++++++++++++++++++++++++++--- 6 files changed, 63 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index d04edac2..bfcb31dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .DS_store +nbproject/ diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 962b09ad..ba2925ac 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -499,6 +499,9 @@ "configurationBatteryMultiwiiCurrent": { "message": "Enable support for legacy Multiwii MSP current output" }, + "configurationLoopTimeHead": { + "message": "Flight Controller Loop Time" + }, "configurationGPS": { "message": "GPS" }, diff --git a/changelog.html b/changelog.html index ea2cc733..52af57e2 100644 --- a/changelog.html +++ b/changelog.html @@ -1,5 +1,6 @@ 2015.05.23 - 0.65.0 - cleanflight

+ - Configuration tab supports setting FC loop time - Requires 1.8.0 firmware.
- Support flashing of the SPRacingF3.
- Support manual baud rate configuration for flashing.

diff --git a/tabs/configuration.css b/tabs/configuration.css index f32be360..2d8c7434 100644 --- a/tabs/configuration.css +++ b/tabs/configuration.css @@ -154,7 +154,27 @@ .tab-configuration .disarm .checkbox span { margin-left: 15px; } - +.tab-configuration .cycles { + border-bottom: 1px solid #dddddd; + margin-top: 16px; +} +.tab-configuration .block { + float: left; + display: block; + border: 1px solid silver; +} +.tab-configuration .block .head { + display: block; + text-align: center; + line-height: 20px; + font-weight: bold; + border-bottom: 1px solid silver; + background-color: #ececec; +} +.tab-configuration .block.looptime { + width: 200px; + margin-top: 11px; +} .tab-configuration .save { display: block; float: right; diff --git a/tabs/configuration.html b/tabs/configuration.html index 6dfde182..c049a4a7 100644 --- a/tabs/configuration.html +++ b/tabs/configuration.html @@ -233,7 +233,14 @@ - + +
diff --git a/tabs/configuration.js b/tabs/configuration.js index 962f5120..b1ae7d86 100644 --- a/tabs/configuration.js +++ b/tabs/configuration.js @@ -36,7 +36,11 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } function load_arming_config() { - MSP.send_message(MSP_codes.MSP_ARMING_CONFIG, false, false, load_html); + MSP.send_message(MSP_codes.MSP_ARMING_CONFIG, false, false, load_loop_time); + } + + function load_loop_time() { + MSP.send_message(MSP_codes.MSP_LOOP_TIME, false, false, load_html); } function load_html() { @@ -256,7 +260,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { // fill magnetometer $('input[name="mag_declination"]').val(MISC.mag_declination); - //fill motor disarm params + //fill motor disarm params and FC loop time if(semver.gte(CONFIG.apiVersion, "1.8.0")) { $('input[name="autodisarmdelay"]').val(ARMING_CONFIG.auto_disarm_delay); $('input[name="disarmkillswitch"]').prop('checked', ARMING_CONFIG.disarm_kill_switch); @@ -265,6 +269,15 @@ TABS.configuration.initialize = function (callback, scrollPosition) { $('div.disarmdelay').show(); else $('div.disarmdelay').hide(); + + // fill FC loop time + $('input[name="looptime"]').val(FC_CONFIG.loopTime); + if(FC_CONFIG.loopTime > 0) + $('span.looptimehz').text(parseFloat((1/FC_CONFIG.loopTime)*1000*1000).toFixed(0) + ' Cycles per Sec'); + else + $('span.looptimehz').text('Maximum Cycles per Sec'); + + $('div.cycles').show(); } // fill throttle @@ -287,6 +300,14 @@ TABS.configuration.initialize = function (callback, scrollPosition) { // UI hooks + $('input[name="looptime"]').change(function() { + FC_CONFIG.loopTime = parseInt($('input[name="looptime"]').val()); + if(FC_CONFIG.loopTime > 0) + $('span.looptimehz').text(parseFloat((1/FC_CONFIG.loopTime)*1000*1000).toFixed(0) + ' Cycles per Sec'); + else + $('span.looptimehz').text('Maximum Cycles per Sec'); + }); + $('input[type="checkbox"].feature', features_e).change(function () { var element = $(this), index = element.data('bit'), @@ -338,6 +359,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { if(semver.gte(CONFIG.apiVersion, "1.8.0")) { ARMING_CONFIG.auto_disarm_delay = parseInt($('input[name="autodisarmdelay"]').val()); ARMING_CONFIG.disarm_kill_switch = ~~$('input[name="disarmkillswitch"]').is(':checked'); // ~~ boolean to decimal conversion + FC_CONFIG.loopTime = parseInt($('input[name="looptime"]').val()); } MISC.minthrottle = parseInt($('input[name="minthrottle"]').val()); @@ -373,7 +395,11 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } function save_arming_config() { - MSP.send_message(MSP_codes.MSP_SET_ARMING_CONFIG, MSP.crunch(MSP_codes.MSP_SET_ARMING_CONFIG), false, save_to_eeprom); + MSP.send_message(MSP_codes.MSP_SET_ARMING_CONFIG, MSP.crunch(MSP_codes.MSP_SET_ARMING_CONFIG), false, save_looptime_config); + } + + function save_looptime_config() { + MSP.send_message(MSP_codes.MSP_SET_LOOP_TIME, MSP.crunch(MSP_codes.MSP_SET_LOOP_TIME), false, save_to_eeprom); } function save_to_eeprom() { From bc6d8513eae7f126f7b49439ce0c95bc6cb4ab69 Mon Sep 17 00:00:00 2001 From: Kyle Christensen Date: Tue, 26 May 2015 18:22:48 -0400 Subject: [PATCH 03/55] Fix typo in firmware flasher --- tabs/firmware_flasher.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tabs/firmware_flasher.js b/tabs/firmware_flasher.js index e2df84c0..a7e7e940 100755 --- a/tabs/firmware_flasher.js +++ b/tabs/firmware_flasher.js @@ -39,7 +39,7 @@ TABS.firmware_flasher.initialize = function (callback) { var showDevReleases = ($('input.show_development_releases').is(':checked')); releases_e.append($("".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectFirmware')))); - var releaseDescritpors = []; + var releaseDescriptors = []; TABS.firmware_flasher.releases.forEach(function(release){ release.assets.forEach(function(asset){ var targetFromFilenameExpression = /.*_(.*)\.(.*)/; @@ -81,11 +81,11 @@ TABS.firmware_flasher.initialize = function (callback) { "status" : release.prerelease ? "release-candidate" : "stable" }; - releaseDescritpors.push(descriptor); + releaseDescriptors.push(descriptor); }); }); - releaseDescritpors.sort(function(o1,o2){ + releaseDescriptors.sort(function(o1,o2){ // compare versions descending var cmpVal = semver(o2.version).compare(semver(o1.version)); if (cmpVal == 0){ @@ -96,7 +96,7 @@ TABS.firmware_flasher.initialize = function (callback) { }); var optionIndex = 1; - releaseDescritpors.forEach(function(descriptor){ + releaseDescriptors.forEach(function(descriptor){ var select_e = $("".format( optionIndex++, From dae3c3b2cf408d7d917142e1edaf31c12b8443d3 Mon Sep 17 00:00:00 2001 From: Nicholas Sherlock Date: Mon, 22 Jun 2015 22:39:32 +1200 Subject: [PATCH 04/55] Update used flash size before save begins so that new data is not missed --- tabs/dataflash.js | 106 ++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 47 deletions(-) diff --git a/tabs/dataflash.js b/tabs/dataflash.js index 898001d7..b8f87280 100644 --- a/tabs/dataflash.js +++ b/tabs/dataflash.js @@ -146,53 +146,66 @@ TABS.dataflash.initialize = function (callback) { $(".dataflash-saving").addClass("done"); } - function flash_save_begin() { - var - maxBytes = DATAFLASH.usedSize; - - if (GUI.connected_to) { - prepare_file(function(fileWriter) { - var - nextAddress = 0; - - show_saving_dialog(); - - function onChunkRead(chunkAddress, chunkDataView) { - if (chunkDataView != null) { - // Did we receive any data? - if (chunkDataView.byteLength > 0) { - nextAddress += chunkDataView.byteLength; - - $(".dataflash-saving progress").attr("value", nextAddress / maxBytes * 100); + function flash_update_summary(onDone) { + MSP.send_message(MSP_codes.MSP_DATAFLASH_SUMMARY, false, false, function() { + update_html(); + + if (onDone) { + onDone(); + } + }); + } - var - blob = new Blob([chunkDataView]); - - fileWriter.onwriteend = function(e) { - if (saveCancelled || nextAddress >= maxBytes) { - if (saveCancelled) { - dismiss_saving_dialog(); - } else { - mark_saving_dialog_done(); - } - } else { - MSP.dataflashRead(nextAddress, onChunkRead); - } - }; - - fileWriter.write(blob); - } else { - // A zero-byte block indicates end-of-file, so we're done - mark_saving_dialog_done(); - } - } else { - // There was an error with the received block (address didn't match the one we asked for), retry - MSP.dataflashRead(nextAddress, onChunkRead); - } - } + function flash_save_begin() { + if (GUI.connected_to) { + // Begin by refreshing the occupied size in case it changed while the tab was open + flash_update_summary(function() { + var + maxBytes = DATAFLASH.usedSize; - // Fetch the initial block - MSP.dataflashRead(nextAddress, onChunkRead); + prepare_file(function(fileWriter) { + var + nextAddress = 0; + + show_saving_dialog(); + + function onChunkRead(chunkAddress, chunkDataView) { + if (chunkDataView != null) { + // Did we receive any data? + if (chunkDataView.byteLength > 0) { + nextAddress += chunkDataView.byteLength; + + $(".dataflash-saving progress").attr("value", nextAddress / maxBytes * 100); + + var + blob = new Blob([chunkDataView]); + + fileWriter.onwriteend = function(e) { + if (saveCancelled || nextAddress >= maxBytes) { + if (saveCancelled) { + dismiss_saving_dialog(); + } else { + mark_saving_dialog_done(); + } + } else { + MSP.dataflashRead(nextAddress, onChunkRead); + } + }; + + fileWriter.write(blob); + } else { + // A zero-byte block indicates end-of-file, so we're done + mark_saving_dialog_done(); + } + } else { + // There was an error with the received block (address didn't match the one we asked for), retry + MSP.dataflashRead(nextAddress, onChunkRead); + } + } + + // Fetch the initial block + MSP.dataflashRead(nextAddress, onChunkRead); + }); }); } } @@ -246,8 +259,7 @@ TABS.dataflash.initialize = function (callback) { } function poll_for_erase_completion() { - MSP.send_message(MSP_codes.MSP_DATAFLASH_SUMMARY, false, false, function() { - update_html(); + flash_update_summary(function() { if (!eraseCancelled) { if (DATAFLASH.ready) { $(".dataflash-confirm-erase")[0].close(); From 438dc8d46d6c083d15e64e7230b284485bd5c241 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Sun, 28 Jun 2015 22:30:36 +0100 Subject: [PATCH 05/55] Some changes required for the 'custom-servo-mixers' cleanflight branch. TODO - Support old version of MSP_SERVO_CONF --- js/model.js | 47 ++++++++++++++++++++++++----------------------- js/msp.js | 21 ++++++++++++++++++--- 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/js/model.js b/js/model.js index 98f62ebd..163e6ae5 100644 --- a/js/model.js +++ b/js/model.js @@ -2,27 +2,28 @@ // generate mixer var mixerList = [ - {name: 'Tricopter', model: 'tricopter', image: 'tri'}, - {name: 'Quad +', model: 'quad_x', image: 'quad_p'}, - {name: 'Quad X', model: 'quad_x', image: 'quad_x'}, - {name: 'Bicopter', model: 'custom', image: 'bicopter'}, - {name: 'Gimbal', model: 'custom', image: 'custom'}, - {name: 'Y6', model: 'y6', image: 'y6'}, - {name: 'Hex +', model: 'hex_plus', image: 'hex_p'}, - {name: 'Flying Wing', model: 'custom', image: 'flying_wing'}, - {name: 'Y4', model: 'y4', image: 'y4'}, - {name: 'Hex X', model: 'hex_x', image: 'hex_x'}, - {name: 'Octo X8', model: 'custom', image: 'octo_x8'}, - {name: 'Octo Flat +', model: 'custom', image: 'octo_flat_p'}, - {name: 'Octo Flat X', model: 'custom', image: 'octo_flat_x'}, - {name: 'Airplane', model: 'custom', image: 'airplane'}, - {name: 'Heli 120', model: 'custom', image: 'custom'}, - {name: 'Heli 90', model: 'custom', image: 'custom'}, - {name: 'V-tail Quad', model: 'quad_vtail', image: 'vtail_quad'}, - {name: 'Hex H', model: 'custom', image: 'custom'}, - {name: 'PPM to SERVO', model: 'custom', image: 'custom'}, - {name: 'Dualcopter', model: 'custom', image: 'custom'}, - {name: 'Singlecopter', model: 'custom', image: 'custom'}, - {name: 'A-tail Quad', model: 'quad_atail', image: 'atail_quad'}, - {name: 'Custom', model: 'custom', image: 'custom'} + {name: 'Tricopter', model: 'tricopter', image: 'tri'}, + {name: 'Quad +', model: 'quad_x', image: 'quad_p'}, + {name: 'Quad X', model: 'quad_x', image: 'quad_x'}, + {name: 'Bicopter', model: 'custom', image: 'bicopter'}, + {name: 'Gimbal', model: 'custom', image: 'custom'}, + {name: 'Y6', model: 'y6', image: 'y6'}, + {name: 'Hex +', model: 'hex_plus', image: 'hex_p'}, + {name: 'Flying Wing', model: 'custom', image: 'flying_wing'}, + {name: 'Y4', model: 'y4', image: 'y4'}, + {name: 'Hex X', model: 'hex_x', image: 'hex_x'}, + {name: 'Octo X8', model: 'custom', image: 'octo_x8'}, + {name: 'Octo Flat +', model: 'custom', image: 'octo_flat_p'}, + {name: 'Octo Flat X', model: 'custom', image: 'octo_flat_x'}, + {name: 'Airplane', model: 'custom', image: 'airplane'}, + {name: 'Heli 120', model: 'custom', image: 'custom'}, + {name: 'Heli 90', model: 'custom', image: 'custom'}, + {name: 'V-tail Quad', model: 'quad_vtail', image: 'vtail_quad'}, + {name: 'Hex H', model: 'custom', image: 'custom'}, + {name: 'PPM to SERVO', model: 'custom', image: 'custom'}, + {name: 'Dualcopter', model: 'custom', image: 'custom'}, + {name: 'Singlecopter', model: 'custom', image: 'custom'}, + {name: 'A-tail Quad', model: 'quad_atail', image: 'atail_quad'}, + {name: 'Custom', model: 'custom', image: 'custom'}, + {name: 'Custom Airplane', model: 'custom', image: 'custom'} ]; diff --git a/js/msp.js b/js/msp.js index c6e8d3a6..48609ce6 100644 --- a/js/msp.js +++ b/js/msp.js @@ -447,13 +447,16 @@ var MSP = { case MSP_codes.MSP_SERVO_CONF: SERVO_CONFIG = []; // empty the array as new data is coming in - if (data.byteLength % 7 == 0) { - for (var i = 0; i < data.byteLength; i += 7) { + if (data.byteLength % 13 == 0) { + for (var i = 0; i < data.byteLength; i += 13) { var arr = { 'min': data.getInt16(i, 1), 'max': data.getInt16(i + 2, 1), 'middle': data.getInt16(i + 4, 1), - 'rate': data.getInt8(i + 6) + 'rate': data.getInt8(i + 6), + 'angleAtMin': data.getInt8(i + 7), + 'angleAtMax': data.getInt8(i + 8), + 'reversedChannels': data.getInt32(i + 9) }; SERVO_CONFIG.push(arr); @@ -1047,6 +1050,18 @@ MSP.crunch = function (code) { buffer.push(highByte(SERVO_CONFIG[i].middle)); buffer.push(lowByte(SERVO_CONFIG[i].rate)); + + if (semver.gte(CONFIG.apiVersion, "1.11.0")) { + buffer.push(SERVO_CONFIG[i].angleAtMin); + buffer.push(SERVO_CONFIG[i].angleAtMax); + } + + if (semver.gte(CONFIG.apiVersion, "1.12.0")) { + buffer.push(specificByte(SERVO_CONFIG[i].reversedChannels, 0)); + buffer.push(specificByte(SERVO_CONFIG[i].reversedChannels, 1)); + buffer.push(specificByte(SERVO_CONFIG[i].reversedChannels, 2)); + buffer.push(specificByte(SERVO_CONFIG[i].reversedChannels, 3)); + } } break; case MSP_codes.MSP_SET_CHANNEL_FORWARDING: From 4e41f46523e6a6379823f67ecf27f82b5c92be00 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Sun, 28 Jun 2015 23:19:03 +0100 Subject: [PATCH 06/55] First cut of support for custom airplane and tricopter on servos tab. --- js/model.js | 4 +++- tabs/servos.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/js/model.js b/js/model.js index 163e6ae5..b30f8b9f 100644 --- a/js/model.js +++ b/js/model.js @@ -25,5 +25,7 @@ var mixerList = [ {name: 'Singlecopter', model: 'custom', image: 'custom'}, {name: 'A-tail Quad', model: 'quad_atail', image: 'atail_quad'}, {name: 'Custom', model: 'custom', image: 'custom'}, - {name: 'Custom Airplane', model: 'custom', image: 'custom'} + {name: 'Custom Airplane', model: 'custom', image: 'custom'}, + {name: 'Custom Tricopter', model: 'custom', image: 'custom'} + ]; diff --git a/tabs/servos.js b/tabs/servos.js index 46b7ca85..fbc61667 100644 --- a/tabs/servos.js +++ b/tabs/servos.js @@ -205,10 +205,11 @@ TABS.servos.initialize = function (callback) { $('div.tab-servos table.fields tr:not(:first)').remove(); var model = $('div.tab-servos strong.model'); - var supported_models = [1, 4, 5, 8, 14, 20, 21]; + var supported_models = [1, 4, 5, 8, 14, 20, 21, 24, 25]; switch (CONFIG.multiType) { case 1: // TRI + case 25: // CUSTOM_TRI // looking ok so far model.text('TRI'); @@ -249,6 +250,7 @@ TABS.servos.initialize = function (callback) { process_servos('Right Wing', '', 4, false); break; case 14: // Airplane + case 24: // Custom_Airplane model.text('Airplane'); // rate From 58bcbe876cf73e1169882fe7cca51e82f117af21 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 29 Jun 2015 03:32:42 +0100 Subject: [PATCH 07/55] Allow gimbal servos to be configured when enabled. --- tabs/servos.js | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/tabs/servos.js b/tabs/servos.js index fbc61667..d31191e5 100644 --- a/tabs/servos.js +++ b/tabs/servos.js @@ -281,19 +281,18 @@ TABS.servos.initialize = function (callback) { default: model.text(chrome.i18n.getMessage('servosModelNoSupport')); - - // implementation of feature servo_tilt - if (AUX_CONFIG.indexOf('CAMSTAB') > -1 || AUX_CONFIG.indexOf('CAMTRIG') > -1) { - // Gimbal on - // needs to be verified - model.text('Gimbal / Tilt Servos'); - - // rate - process_servos('Pitch Servo', '', 0, 2); - process_servos('Roll Servo', '', 1, 2); - } } + // implementation of feature servo_tilt + if (AUX_CONFIG.indexOf('CAMSTAB') > -1 || AUX_CONFIG.indexOf('CAMTRIG') > -1) { + // Gimbal on + // needs to be verified + + // rate + process_servos('Pitch Servo', '', 0, 2); + process_servos('Roll Servo', '', 1, 2); + } + // UI hooks for dynamically generated elements $('table.directions select, table.directions input, table.fields select, table.fields input').change(function () { if ($('div.live input').is(':checked')) { From 4203413b749595c254ad3f00ce0d1cf35ea2b9cc Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 29 Jun 2015 03:33:17 +0100 Subject: [PATCH 08/55] Escape < and > characters from the cli. --- tabs/cli.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tabs/cli.js b/tabs/cli.js index 24d7aa64..df8f3ebc 100644 --- a/tabs/cli.js +++ b/tabs/cli.js @@ -141,6 +141,13 @@ TABS.cli.read = function (readInfo) { text += "
"; } break; + case 60: + text += '<'; + break; + case 62: + text += '>'; + break; + default: text += String.fromCharCode(data[i]); } From cb12833b37130b90248d42b1c5739d47a5c6c5bd Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Sun, 12 Jul 2015 20:44:04 +0100 Subject: [PATCH 09/55] Bump version. --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 6dfac358..ba921616 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "manifest_version": 2, "minimum_chrome_version": "38", - "version": "0.65.0", + "version": "0.66.0", "author": "Hydra", "name": "Cleanflight - Configurator", "short_name": "cleanflight", From d8c41fb3c709f8c1f151fccfbe1da610071edd46 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Sun, 12 Jul 2015 20:44:43 +0100 Subject: [PATCH 10/55] Show channel forwarding feature if available. --- tabs/configuration.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tabs/configuration.js b/tabs/configuration.js index 962f5120..86cce852 100644 --- a/tabs/configuration.js +++ b/tabs/configuration.js @@ -73,7 +73,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { {bit: 3, group: 'rxMode', mode: 'group', name: 'RX_SERIAL', description: 'Serial-based receiver (SPEKSAT, SBUS, SUMD)'}, {bit: 4, group: 'esc', name: 'MOTOR_STOP', description: 'Don\'t spin the motors when armed'}, {bit: 5, group: 'other', name: 'SERVO_TILT', description: 'Servo gimbal'}, - {bit: 6, group: 'other', name: 'SOFTSERIAL', description: 'Enable CPU based serial ports (configure port scenario first)'}, + {bit: 6, group: 'other', name: 'SOFTSERIAL', description: 'Enable CPU based serial ports'}, {bit: 7, group: 'gps', name: 'GPS', description: 'GPS (configure port scenario first)'}, {bit: 8, group: 'rxFailsafe', name: 'FAILSAFE', description: 'Failsafe settings on RX signal loss'}, {bit: 9, group: 'other', name: 'SONAR', description: 'Sonar'}, @@ -88,6 +88,12 @@ TABS.configuration.initialize = function (callback, scrollPosition) { {bit: 18, group: 'esc', name: 'ONESHOT125', description: 'ONESHOT ESC support (disconnect ESCs, remove props)'}, {bit: 19, group: 'other', name: 'BLACKBOX', description: 'Blackbox flight data recorder'} ]; + + if (semver.gte(CONFIG.apiVersion, "1.12.0")) { + features.push( + {bit: 20, group: 'other', name: 'CHANNEL_FORWARDING', description: 'Forward aux channels to remaining servo outputs'} + ); + } var radioGroups = []; From c0138f5f8250f0e19e853008b701b4a9f5eb35ed Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Sun, 12 Jul 2015 21:35:25 +0100 Subject: [PATCH 11/55] Sprinkle some help for common causes of error to reduce burned on developers and community. --- _locales/en/messages.json | 24 +++++++++++++++++++----- tabs/configuration.html | 9 +++++++++ tabs/ports.html | 5 +++++ tabs/receiver.css | 6 ++++++ tabs/receiver.html | 4 ++++ 5 files changed, 43 insertions(+), 5 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 962b09ad..cf9456fe 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -211,7 +211,7 @@ "message": "Request Optional Permissions" }, "defaultWelcomeText": { - "message": "Welcome to Cleanflight - Configurator, a utility designed to simplify updating, configuring and tuning of your flight controller.

The application supports all hardware that can run cleanflight (SPRacingF3, Vortex, Sparky, CC3D/EVO, Air Hero 32, Flip32/+/Deluxe, CJMCU Microquad, Chebuzz F3, STM32F3Discovery, Hermit, Naze32 Tricopter Frame, Skyline32, Naze/32/Mini/Pro/Blackbox etc)

The firmware source code can be downloaded from here
The newest binary firmware image is available here

Latest CP210x Drivers can be downloaded from here
" + "message": "Welcome to Cleanflight - Configurator, a utility designed to simplify updating, configuring and tuning of your flight controller.

The application supports all hardware that can run cleanflight (SPRacingF3, Vortex, Sparky, CC3D/EVO, Air Hero 32, Flip32/+/Deluxe, CJMCU Microquad, Chebuzz F3, STM32F3Discovery, Hermit, Naze32 Tricopter Frame, Skyline32, Naze/32/Mini/Pro/Blackbox etc)

The firmware source code can be downloaded from here
The newest binary firmware image is available here, development builds available here

Latest CP210x Drivers can be downloaded from here
" }, "defaultContributingHead": { "message": "Contributing" @@ -426,6 +426,10 @@ "configurationFeaturesHelp": { "message": "Note: Not all combinations of features are valid. When the flight controller firmware detects invalid feature combinations conflicting features will be disabled.
Note: Configure serial ports before enabling the features that will use the ports." }, + + "configurationSerialRXHelp": { + "message": "Note: Rememer to configure a Serial Port (via Ports tab) and choose a Serial Receiver Provider when using RX_SERIAL feature." + }, "configurationBoardAlignment": { "message": "Board Alignment" @@ -511,6 +515,10 @@ "configurationGPSubxSbas": { "message": "Ground Assistance Type" }, + "configurationGPSHelp": { + "message": "Note: Rememer to configure a Serial Port (via Ports tab) when using GPS feature." + }, + "configurationSerialRX": { "message": "Serial Receiver Provider" }, @@ -522,7 +530,10 @@ }, "portsHelp": { - "message": "Configure serial ports. Note: not all combinations are valid. When the flight controller firmware detects this the serial port configuration will be reset." + "message": "Note: not all combinations are valid. When the flight controller firmware detects this the serial port configuration will be reset." + }, + "portsMSPHelp": { + "message": "Note: Do NOT disable MSP on the first serial port unless you know what you are doing. You may have to reflash and erase your configuration if you do." }, "portsFirmwareUpgradeRequired": { "message": "Firmware upgrade required. Serial port configurations of firmware < 1.8.0 is not supported." @@ -613,6 +624,9 @@ "message": "EEPROM saved" }, + "receiverHelp": { + "message": "Please read receiver chapter of the documentation. Configure serial port (if required), receiver mode (serial/ppm/pwm), provider (for serial receivers), bind receiver, set channel map, configure channel endpoints/range on TX so that all channels go from ~1000 to ~2000. Set midpoint (default 1500), trim channels to 1500, configure stick deadband, verify behaviour when TX is off or out of range.
IMPORTANT: Before flying read failsafe chapter of documentation and configure failsafe." + }, "receiverThrottleMid": { "message": "Throttle MID" }, @@ -1042,7 +1056,7 @@ "message": "Attempt to flash the board automatically (triggered by newly detected serial port)" }, "firmwareFlasherFullChipErase": { - "message": "Full Chip Erase" + "message": "Full chip erase" }, "firmwareFlasherFullChipEraseDescription": { "message": "Wipes all configuration data currently stored on the board" @@ -1054,7 +1068,7 @@ "message": "Flash most recent (untested) development firmware" }, "firmwareFlasherManualBaud": { - "message": "Manual Baud Rate" + "message": "Manual baud rate" }, "firmwareFlasherManualBaudDescription": { "message": "Manual selection of baud rate for boards that don't support the default speed or for flashing via bluetooth." @@ -1099,7 +1113,7 @@ "message": "Warning" }, "firmwareFlasherWarningText": { - "message": "Please do not try to flash non-cleanflight hardware with this firmware flasher (it wont work).
Do not disconnect the board or turn off your computer while flashing.

Note: STM32 bootloader is stored in ROM, it cannot be bricked.
Note: Auto-Connect is always disabled while you are inside firmware flasher.
Note: This can wipe your configuration including but not limited to PIDs, Auxiliary, and FEATURES. Make sure you have a backup.
" + "message": "Please do not try to flash non-cleanflight hardware with this firmware flasher.
Do not disconnect the board or turn off your computer while flashing.

Note: STM32 bootloader is stored in ROM, it cannot be bricked.
Note: Auto-Connect is always disabled while you are inside firmware flasher.
Note: Make sure you have a backup; some upgrades/downgrades will wipe your configuration.
Note: If you have problems flashing try disconnecting all cables from your FC.

Note: If you have lost comminication with your board then power off the board, jumper the bootloader pins, power on, enable 'No reboot sequence', enable 'Full chip erase', re-flash, then power off, remove bootloader jumper, power on and connect (For all firmware except OPBL firmware)." }, "firmwareFlasherButtonLeave": { "message": "Leave Firmware Flasher" diff --git a/tabs/configuration.html b/tabs/configuration.html index 6dfde182..4428f99a 100644 --- a/tabs/configuration.html +++ b/tabs/configuration.html @@ -127,6 +127,10 @@ +
+

+
+
@@ -275,6 +279,11 @@ + +
+

+
+
diff --git a/tabs/ports.html b/tabs/ports.html index 15362f98..09fed270 100644 --- a/tabs/ports.html +++ b/tabs/ports.html @@ -18,6 +18,11 @@
+ +
+

+
+
diff --git a/tabs/receiver.css b/tabs/receiver.css index 91d2b7b9..fe1a3c4f 100644 --- a/tabs/receiver.css +++ b/tabs/receiver.css @@ -3,6 +3,12 @@ .tab-receiver input[type="number"]::-webkit-inner-spin-button { border: 0; } +.tab-receiver .help { + padding: 10px; + background-color: #ffcb18; + margin-bottom: 10px; +} + .tab-receiver .bars { float: left; width: 45%; diff --git a/tabs/receiver.html b/tabs/receiver.html index 196f4c04..f562050c 100644 --- a/tabs/receiver.html +++ b/tabs/receiver.html @@ -1,5 +1,9 @@
+
+

+
+
From 1cb64130ccc7e1571ab854ee07f1b18d1f220769 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 13 Jul 2015 00:02:58 +0100 Subject: [PATCH 12/55] update servo tab on configurator 1) work around 1.9.0 MSP buffer size bug. 2) support updated API for 1.12 (CF >= 1.10.0) --- js/backup_restore.js | 54 +++++++++-- js/data_storage.js | 1 + js/msp.js | 220 +++++++++++++++++++++++++++++++------------ tabs/servos.js | 53 ++++++++--- 4 files changed, 250 insertions(+), 78 deletions(-) diff --git a/js/backup_restore.js b/js/backup_restore.js index e7a31c47..ddd6e9ac 100644 --- a/js/backup_restore.js +++ b/js/backup_restore.js @@ -30,12 +30,21 @@ function configuration_backup(callback) { MSP_codes.MSP_PID, MSP_codes.MSP_RC_TUNING, MSP_codes.MSP_ACC_TRIM, - MSP_codes.MSP_SERVO_CONF, - MSP_codes.MSP_CHANNEL_FORWARDING, + MSP_codes.MSP_SERVO_CONFIGURATIONS, MSP_codes.MSP_MODE_RANGES, MSP_codes.MSP_ADJUSTMENT_RANGES ]; + function update_profile_specific_data_list() { + if (semver.lt(CONFIG.apiVersion, "1.12.0")) { + profileSpecificData.push(MSP_codes.MSP_CHANNEL_FORWARDING); + } else { + profileSpecificData.push(MSP_codes.MSP_SERVO_RULES); + } + } + + update_profile_specific_data_list(); + function fetch_specific_data() { var fetchingProfile = 0, codeKey = 0; @@ -54,6 +63,7 @@ function configuration_backup(callback) { 'RC': jQuery.extend(true, {}, RC_tuning), 'AccTrim': jQuery.extend(true, [], CONFIG.accelerometerTrims), 'ServoConfig': jQuery.extend(true, [], SERVO_CONFIG), + 'ServoRules': jQuery.extend(true, [], SERVO_RULES), 'ModeRanges': jQuery.extend(true, [], MODE_RANGES), 'AdjustmentRanges': jQuery.extend(true, [], ADJUSTMENT_RANGES) }); @@ -428,6 +438,31 @@ function configuration_restore(callback) { } } + if (semver.lt(migratedVersion, '0.66.0')) { + // api 1.12 updated servo configuration protocol and added servo mixer rules + for (var profileIndex = 0; i < configuration.profiles.length; i++) { + + if (semver.eq(configuration.apiVersion, '1.10.0')) { + // drop two unused servo configurations + while (configuration.profiles[profileIndex].ServoConfig.length > 8) { + configuration.profiles[profileIndex].ServoConfig.pop(); + } + } + for (var i = 0; i < configuration.profiles[profileIndex].ServoConfig.length; i++) { + var servoConfig = profiles[profileIndex].ServoConfig; + servoConfig[i].angleAtMin = 90; + servoConfig[i].angleAtMax = 90; + servoConfig[i].reversedInputSources = 0; + } + + configuration.profiles[profileIndex].ServoRules = []; + } + + migratedVersion = '0.66.0'; + + appliedMigrationsCount++; + } + if (appliedMigrationsCount > 0) { GUI.log(chrome.i18n.getMessage('configMigrationSuccessful', [appliedMigrationsCount])); } @@ -444,9 +479,7 @@ function configuration_restore(callback) { MSP_codes.MSP_SET_PID_CONTROLLER, MSP_codes.MSP_SET_PID, MSP_codes.MSP_SET_RC_TUNING, - MSP_codes.MSP_SET_ACC_TRIM, - MSP_codes.MSP_SET_SERVO_CONF, - MSP_codes.MSP_SET_CHANNEL_FORWARDING + MSP_codes.MSP_SET_ACC_TRIM ]; MSP.send_message(MSP_codes.MSP_STATUS, false, false, function () { @@ -472,6 +505,7 @@ function configuration_restore(callback) { RC_tuning = configuration.profiles[profile].RC; CONFIG.accelerometerTrims = configuration.profiles[profile].AccTrim; SERVO_CONFIG = configuration.profiles[profile].ServoConfig; + SERVO_RULES = configuration.profiles[profile].ServoRules; MODE_RANGES = configuration.profiles[profile].ModeRanges; ADJUSTMENT_RANGES = configuration.profiles[profile].AdjustmentRanges; } @@ -501,6 +535,14 @@ function configuration_restore(callback) { }); } + function upload_servo_mix_rules() { + MSP.sendServoMixRules(upload_servo_configuration); + } + + function upload_servo_configuration() { + MSP.sendServoConfigurations(upload_mode_ranges); + } + function upload_mode_ranges() { MSP.sendModeRanges(upload_adjustment_ranges); } @@ -510,7 +552,7 @@ function configuration_restore(callback) { } // start uploading load_objects(0); - upload_mode_ranges(); + upload_servo_configuration(); } function upload_unique_data() { diff --git a/js/data_storage.js b/js/data_storage.js index cc51e03b..dae77ca0 100755 --- a/js/data_storage.js +++ b/js/data_storage.js @@ -86,6 +86,7 @@ var MODE_RANGES = []; var ADJUSTMENT_RANGES = []; var SERVO_CONFIG = []; +var SERVO_RULES = []; var SERIAL_CONFIG = { ports: [], diff --git a/js/msp.js b/js/msp.js index 48609ce6..f325b6de 100644 --- a/js/msp.js +++ b/js/msp.js @@ -51,7 +51,7 @@ var MSP_codes = { MSP_PIDNAMES: 117, MSP_WP: 118, MSP_BOXIDS: 119, - MSP_SERVO_CONF: 120, + MSP_SERVO_CONFIGURATIONS: 120, MSP_SET_RAW_RC: 200, MSP_SET_RAW_GPS: 201, @@ -65,10 +65,13 @@ var MSP_codes = { MSP_SET_WP: 209, MSP_SELECT_SETTING: 210, MSP_SET_HEAD: 211, - MSP_SET_SERVO_CONF: 212, + MSP_SET_SERVO_CONFIGURATION: 212, MSP_SET_MOTOR: 214, // MSP_BIND: 240, + + MSP_SERVO_MIX_RULES: 241, + MSP_SET_SERVO_MIX_RULE: 242, MSP_EEPROM_WRITE: 250, @@ -80,7 +83,7 @@ var MSP_codes = { MSP_ACC_TRIM: 240, // get acc angle trim values MSP_SET_ACC_TRIM: 239, // set acc angle trim values MSP_GPS_SV_INFO: 164, // get Signal Strength - + // Additional private MSP for baseflight configurator (yes thats us \o/) MSP_RX_MAP: 64, // get channel map (also returns number of channels total) MSP_SET_RX_MAP: 65, // set rc map, numchannels to set comes from MSP_RX_MAP @@ -444,22 +447,48 @@ var MSP = { AUX_CONFIG_IDS.push(data.getUint8(i)); } break; - case MSP_codes.MSP_SERVO_CONF: + case MSP_codes.MSP_SERVO_MIX_RULES: + break; + + case MSP_codes.MSP_SERVO_CONFIGURATIONS: SERVO_CONFIG = []; // empty the array as new data is coming in - if (data.byteLength % 13 == 0) { - for (var i = 0; i < data.byteLength; i += 13) { - var arr = { - 'min': data.getInt16(i, 1), - 'max': data.getInt16(i + 2, 1), - 'middle': data.getInt16(i + 4, 1), - 'rate': data.getInt8(i + 6), - 'angleAtMin': data.getInt8(i + 7), - 'angleAtMax': data.getInt8(i + 8), - 'reversedChannels': data.getInt32(i + 9) - }; - - SERVO_CONFIG.push(arr); + if (semver.gte(CONFIG.apiVersion, "1.12.0")) { + if (data.byteLength % 14 == 0) { + for (var i = 0; i < data.byteLength; i += 14) { + var arr = { + 'min': data.getInt16(i + 0, 1), + 'max': data.getInt16(i + 2, 1), + 'middle': data.getInt16(i + 4, 1), + 'rate': data.getInt8(i + 6), + 'angleAtMin': data.getUint8(i + 7), + 'angleAtMax': data.getUint8(i + 8), + 'indexOfChannelToForward': data.getInt8(i + 9), + 'reversedInputSources': data.getUint32(i + 10) + }; + + SERVO_CONFIG.push(arr); + } + } + } else { + if (data.byteLength % 7 == 0) { + for (var i = 0; i < data.byteLength; i += 7) { + var arr = { + 'min': data.getInt16(i + 0, 1), + 'max': data.getInt16(i + 2, 1), + 'middle': data.getInt16(i + 4, 1), + 'rate': data.getInt8(i + 6) + }; + + SERVO_CONFIG.push(arr); + } + } + + if (semver.eq(CONFIG.apiVersion, '1.10.0')) { + // drop two unused servo configurations due to MSP rx buffer to small) + while (SERVO_CONFIG.length > 8) { + SERVO_CONFIG.pop(); + } } } break; @@ -493,7 +522,7 @@ var MSP = { case MSP_codes.MSP_SELECT_SETTING: console.log('Profile selected'); break; - case MSP_codes.MSP_SET_SERVO_CONF: + case MSP_codes.MSP_SET_SERVO_CONFIGURATION: console.log('Servo Configuration saved'); break; case MSP_codes.MSP_EEPROM_WRITE: @@ -1038,32 +1067,6 @@ MSP.crunch = function (code) { buffer.push(MISC.vbatmaxcellvoltage * 10); buffer.push(MISC.vbatwarningcellvoltage * 10); break; - case MSP_codes.MSP_SET_SERVO_CONF: - for (var i = 0; i < SERVO_CONFIG.length; i++) { - buffer.push(lowByte(SERVO_CONFIG[i].min)); - buffer.push(highByte(SERVO_CONFIG[i].min)); - - buffer.push(lowByte(SERVO_CONFIG[i].max)); - buffer.push(highByte(SERVO_CONFIG[i].max)); - - buffer.push(lowByte(SERVO_CONFIG[i].middle)); - buffer.push(highByte(SERVO_CONFIG[i].middle)); - - buffer.push(lowByte(SERVO_CONFIG[i].rate)); - - if (semver.gte(CONFIG.apiVersion, "1.11.0")) { - buffer.push(SERVO_CONFIG[i].angleAtMin); - buffer.push(SERVO_CONFIG[i].angleAtMax); - } - - if (semver.gte(CONFIG.apiVersion, "1.12.0")) { - buffer.push(specificByte(SERVO_CONFIG[i].reversedChannels, 0)); - buffer.push(specificByte(SERVO_CONFIG[i].reversedChannels, 1)); - buffer.push(specificByte(SERVO_CONFIG[i].reversedChannels, 2)); - buffer.push(specificByte(SERVO_CONFIG[i].reversedChannels, 3)); - } - } - break; case MSP_codes.MSP_SET_CHANNEL_FORWARDING: for (var i = 0; i < SERVO_CONFIG.length; i++) { var out = SERVO_CONFIG[i].indexOfChannelToForward; @@ -1143,7 +1146,102 @@ MSP.dataflashRead = function(address, onDataCallback) { onDataCallback(address, null); } }); -} ; +}; + +MSP.sendServoMixRules = function(onCompleteCallback) { + // TODO implement + onCompleteCallback(); +}; + +MSP.sendServoConfigurations = function(onCompleteCallback) { + var nextFunction = send_next_servo_configuration; + + var servoIndex = 0; + + if (SERVO_CONFIG.length == 0) { + onCompleteCallback(); + } + + nextFunction(); + + function send_next_servo_configuration() { + + var buffer = []; + + if (semver.lt(CONFIG.apiVersion, "1.12.0")) { + // send all in one go + // 1.9.0 had a bug where the MSP input buffer was too small, limit to 8. + for (var i = 0; i < SERVO_CONFIG.length && i < 8; i++) { + buffer.push(lowByte(SERVO_CONFIG[i].min)); + buffer.push(highByte(SERVO_CONFIG[i].min)); + + buffer.push(lowByte(SERVO_CONFIG[i].max)); + buffer.push(highByte(SERVO_CONFIG[i].max)); + + buffer.push(lowByte(SERVO_CONFIG[i].middle)); + buffer.push(highByte(SERVO_CONFIG[i].middle)); + + buffer.push(lowByte(SERVO_CONFIG[i].rate)); + } + + nextFunction = send_channel_forwarding; + } else { + // send one at a time, with index + + var servoConfiguration = SERVO_CONFIG[servoIndex]; + + buffer.push(servoIndex); + + buffer.push(lowByte(servoConfiguration.min)); + buffer.push(highByte(servoConfiguration.min)); + + buffer.push(lowByte(servoConfiguration.max)); + buffer.push(highByte(servoConfiguration.max)); + + buffer.push(lowByte(servoConfiguration.middle)); + buffer.push(highByte(servoConfiguration.middle)); + + buffer.push(lowByte(servoConfiguration.rate)); + + buffer.push(servoConfiguration.angleAtMin); + buffer.push(servoConfiguration.angleAtMax); + + var out = servoConfiguration.indexOfChannelToForward; + if (out == undefined) { + out = 255; // Cleanflight defines "CHANNEL_FORWARDING_DISABLED" as "(uint8_t)0xFF" + } + buffer.push(out); + + buffer.push(specificByte(servoConfiguration.reversedInputSources, 0)); + buffer.push(specificByte(servoConfiguration.reversedInputSources, 1)); + buffer.push(specificByte(servoConfiguration.reversedInputSources, 2)); + buffer.push(specificByte(servoConfiguration.reversedInputSources, 3)); + + // prepare for next iteration + servoIndex++; + if (servoIndex == SERVO_CONFIG.length) { + nextFunction = onCompleteCallback; + } + } + MSP.send_message(MSP_codes.MSP_SET_SERVO_CONFIGURATION, buffer, false, nextFunction); + } + + function send_channel_forwarding() { + var buffer = []; + + for (var i = 0; i < SERVO_CONFIG.length; i++) { + var out = SERVO_CONFIG[i].indexOfChannelToForward; + if (out == undefined) { + out = 255; // Cleanflight defines "CHANNEL_FORWARDING_DISABLED" as "(uint8_t)0xFF" + } + buffer.push(out); + } + + nextFunction = onCompleteCallback; + + MSP.send_message(MSP_codes.MSP_SET_CHANNEL_FORWARDING, buffer, false, nextFunction); + } +}; MSP.sendModeRanges = function(onCompleteCallback) { var nextFunction = send_next_mode_range; @@ -1161,12 +1259,12 @@ MSP.sendModeRanges = function(onCompleteCallback) { var modeRange = MODE_RANGES[modeRangeIndex]; - var AUX_val_buffer_out = []; - AUX_val_buffer_out.push(modeRangeIndex); - AUX_val_buffer_out.push(modeRange.id); - AUX_val_buffer_out.push(modeRange.auxChannelIndex); - AUX_val_buffer_out.push((modeRange.range.start - 900) / 25); - AUX_val_buffer_out.push((modeRange.range.end - 900) / 25); + var buffer = []; + buffer.push(modeRangeIndex); + buffer.push(modeRange.id); + buffer.push(modeRange.auxChannelIndex); + buffer.push((modeRange.range.start - 900) / 25); + buffer.push((modeRange.range.end - 900) / 25); // prepare for next iteration modeRangeIndex++; @@ -1174,7 +1272,7 @@ MSP.sendModeRanges = function(onCompleteCallback) { nextFunction = onCompleteCallback; } - MSP.send_message(MSP_codes.MSP_SET_MODE_RANGE, AUX_val_buffer_out, false, nextFunction); + MSP.send_message(MSP_codes.MSP_SET_MODE_RANGE, buffer, false, nextFunction); } }; @@ -1194,14 +1292,14 @@ MSP.sendAdjustmentRanges = function(onCompleteCallback) { var adjustmentRange = ADJUSTMENT_RANGES[adjustmentRangeIndex]; - var ADJUSTMENT_val_buffer_out = []; - ADJUSTMENT_val_buffer_out.push(adjustmentRangeIndex); - ADJUSTMENT_val_buffer_out.push(adjustmentRange.slotIndex); - ADJUSTMENT_val_buffer_out.push(adjustmentRange.auxChannelIndex); - ADJUSTMENT_val_buffer_out.push((adjustmentRange.range.start - 900) / 25); - ADJUSTMENT_val_buffer_out.push((adjustmentRange.range.end - 900) / 25); - ADJUSTMENT_val_buffer_out.push(adjustmentRange.adjustmentFunction); - ADJUSTMENT_val_buffer_out.push(adjustmentRange.auxSwitchChannelIndex); + var buffer = []; + buffer.push(adjustmentRangeIndex); + buffer.push(adjustmentRange.slotIndex); + buffer.push(adjustmentRange.auxChannelIndex); + buffer.push((adjustmentRange.range.start - 900) / 25); + buffer.push((adjustmentRange.range.end - 900) / 25); + buffer.push(adjustmentRange.adjustmentFunction); + buffer.push(adjustmentRange.auxSwitchChannelIndex); // prepare for next iteration adjustmentRangeIndex++; @@ -1209,7 +1307,7 @@ MSP.sendAdjustmentRanges = function(onCompleteCallback) { nextFunction = onCompleteCallback; } - MSP.send_message(MSP_codes.MSP_SET_ADJUSTMENT_RANGE, ADJUSTMENT_val_buffer_out, false, nextFunction); + MSP.send_message(MSP_codes.MSP_SET_ADJUSTMENT_RANGE, buffer, false, nextFunction); } }; diff --git a/tabs/servos.js b/tabs/servos.js index d31191e5..d8d3b930 100644 --- a/tabs/servos.js +++ b/tabs/servos.js @@ -15,15 +15,25 @@ TABS.servos.initialize = function (callback) { googleAnalytics.sendAppView('Servos'); } - function get_servo_conf_data() { - MSP.send_message(MSP_codes.MSP_SERVO_CONF, false, false, get_channel_forwarding_data); + function get_servo_configurations() { + MSP.send_message(MSP_codes.MSP_SERVO_CONFIGURATIONS, false, false, get_servo_mix_rules); } - function get_channel_forwarding_data() { - MSP.send_message(MSP_codes.MSP_CHANNEL_FORWARDING, false, false, get_rc_data); + function get_servo_mix_rules() { + MSP.send_message(MSP_codes.MSP_SERVO_MIX_RULES, false, false, get_channel_forwarding); } - function get_rc_data() { + function get_channel_forwarding() { + var nextFunction = get_rc_data; + + if (semver.lt(CONFIG.apiVersion, "1.12.0")) { + MSP.send_message(MSP_codes.MSP_CHANNEL_FORWARDING, false, false, nextFunction); + } else { + nextFunction(); + } + } + + function get_rc_data() { MSP.send_message(MSP_codes.MSP_RC, false, false, get_boxnames_data); } @@ -35,7 +45,7 @@ TABS.servos.initialize = function (callback) { $('#content').load("./tabs/servos.html", process_html); } - MSP.send_message(MSP_codes.MSP_IDENT, false, false, get_servo_conf_data); + MSP.send_message(MSP_codes.MSP_IDENT, false, false, get_servo_configurations); function process_html() { @@ -104,10 +114,12 @@ TABS.servos.initialize = function (callback) { - // translate to user-selected language - localize(); + // translate to user-selected language + localize(); - $('div.tab-servos table.fields tr:last td.channel input').eq(SERVO_CONFIG[obj].indexOfChannelToForward).prop('checked', true); + if (SERVO_CONFIG[obj].indexOfChannelToForward >= 0) { + $('div.tab-servos table.fields tr:last td.channel input').eq(SERVO_CONFIG[obj].indexOfChannelToForward).prop('checked', true); + } if (directions == true) { $('div.tab-servos table.fields tr:last td.direction input:first').prop('checked', bit_check(SERVO_CONFIG[obj].rate, 0)); @@ -146,7 +158,7 @@ TABS.servos.initialize = function (callback) { }); } - function servos_update(save_to_eeprom) { + function servos_update(save_configuration_to_eeprom) { // update bitfields $('div.tab-servos table.directions tr:not(".main")').each(function () { var info = $('select', this).data('info'); @@ -188,9 +200,27 @@ TABS.servos.initialize = function (callback) { } }); + // + // send data to FC + // + MSP.sendServoConfigurations(send_servo_mixer_rules); + + function send_servo_mixer_rules() { + MSP.sendServoConfigurations(save_to_eeprom); + } + + function save_to_eeprom() { + if (save_configuration_to_eeprom) { + MSP.send_message(MSP_codes.MSP_EEPROM_WRITE, false, false, function () { + GUI.log(chrome.i18n.getMessage('servosEepromSave')); + }); + } + } + + /* MSP.send_message(MSP_codes.MSP_SET_CHANNEL_FORWARDING, MSP.crunch(MSP_codes.MSP_SET_CHANNEL_FORWARDING), false, function () { MSP.send_message(MSP_codes.MSP_SET_SERVO_CONF, MSP.crunch(MSP_codes.MSP_SET_SERVO_CONF), false, function () { - if (save_to_eeprom) { + if (save_configuration_to_eeprom) { // Save changes to EEPROM MSP.send_message(MSP_codes.MSP_EEPROM_WRITE, false, false, function () { GUI.log(chrome.i18n.getMessage('servosEepromSave')); @@ -198,6 +228,7 @@ TABS.servos.initialize = function (callback) { } }); }); + */ } From 687c0f1a8499aa43ea19bffe964b204a27aa00c2 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 13 Jul 2015 02:01:19 +0100 Subject: [PATCH 13/55] Remove legacy servo configuration which originated from the overloaded use of the servo 'rate'. All servos are free to be configured regardless of whether the mixer actually uses those servos. --- _locales/en/messages.json | 15 +-- js/backup_restore.js | 9 +- js/msp.js | 6 +- tabs/ports.css | 4 +- tabs/servos.css | 19 +++- tabs/servos.html | 15 +-- tabs/servos.js | 232 +++++++------------------------------- 7 files changed, 76 insertions(+), 224 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index cf9456fe..4db47410 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -805,15 +805,13 @@ }, - "servosModel": { - "message": "Model:" + "servosFirmwareUpgradeRequired": { + "message": "Servos requires firmware >= 1.10.0." }, + "servosChangeDirection": { "message": "Change Direction in TX To Match" }, - "servosGyroAccelDirection": { - "message": "Gyroscope / Accelerometer Direction" - }, "servosName": { "message": "Name" }, @@ -826,8 +824,8 @@ "servosMax": { "message": "MAX" }, - "servosDirection": { - "message": "Direction" + "servosDirectionAndRate": { + "message": "Direction and rate" }, "servosLiveMode": { "message": "Enable Live mode:" @@ -835,9 +833,6 @@ "servosButtonSave": { "message": "Save" }, - "servosModelNoSupport": { - "message": "This model doesn't support servos" - }, "servosNormal": { "message": "Normal" }, diff --git a/js/backup_restore.js b/js/backup_restore.js index ddd6e9ac..52029243 100644 --- a/js/backup_restore.js +++ b/js/backup_restore.js @@ -448,13 +448,20 @@ function configuration_restore(callback) { configuration.profiles[profileIndex].ServoConfig.pop(); } } + for (var i = 0; i < configuration.profiles[profileIndex].ServoConfig.length; i++) { var servoConfig = profiles[profileIndex].ServoConfig; + servoConfig[i].angleAtMin = 90; servoConfig[i].angleAtMax = 90; servoConfig[i].reversedInputSources = 0; + + // set the rate to 0 if an invalid value is detected. + if (servoConfig[i].rate < -100 || servoConfig[i].rate > 100) { + servoConfig[i].rate = 0; + } } - + configuration.profiles[profileIndex].ServoRules = []; } diff --git a/js/msp.js b/js/msp.js index f325b6de..49676381 100644 --- a/js/msp.js +++ b/js/msp.js @@ -477,7 +477,11 @@ var MSP = { 'min': data.getInt16(i + 0, 1), 'max': data.getInt16(i + 2, 1), 'middle': data.getInt16(i + 4, 1), - 'rate': data.getInt8(i + 6) + 'rate': data.getInt8(i + 6), + 'angleAtMin': 90, + 'angleAtMax': 90, + 'indexOfChannelToForward': undefined, + 'reversedInputSources': 0 }; SERVO_CONFIG.push(arr); diff --git a/tabs/ports.css b/tabs/ports.css index e29583ab..cca6c065 100644 --- a/tabs/ports.css +++ b/tabs/ports.css @@ -71,13 +71,13 @@ border: 1px dashed silver; margin-bottom: 8px; } -.require-support { +.tab-ports .require-support { display:none; } .tab-ports.supported .require-support { display:block; } -.require-upgrade { +.tab-ports .require-upgrade { display:block; } .tab-ports.supported .require-upgrade { diff --git a/tabs/servos.css b/tabs/servos.css index d1ddefa0..319047f0 100644 --- a/tabs/servos.css +++ b/tabs/servos.css @@ -3,10 +3,6 @@ .tab-servos input[type="number"]::-webkit-inner-spin-button { border: 0; } -.tab-servos .supported_wrapper, -.tab-servos .direction_wrapper { - display: none; -} .tab-servos .title { margin-top: 10px; @@ -129,4 +125,17 @@ } .tab-servos .update:hover { background-color: #dedcdc; -} \ No newline at end of file +} + +.tab-servos .require-support { + display:none; +} +.tab-servos.supported .require-support { + display:block; +} +.tab-servos .require-upgrade { + display:block; +} +.tab-servos.supported .require-upgrade { + display:none; +} diff --git a/tabs/servos.html b/tabs/servos.html index fd53aa04..00e9218f 100644 --- a/tabs/servos.html +++ b/tabs/servos.html @@ -1,6 +1,5 @@
- -
+
@@ -14,15 +13,6 @@
CH4
-
-
- - - - - -
-
@@ -30,4 +20,7 @@
+ +
+
\ No newline at end of file diff --git a/tabs/servos.js b/tabs/servos.js index d8d3b930..2ed1f188 100644 --- a/tabs/servos.js +++ b/tabs/servos.js @@ -1,9 +1,3 @@ -/* Please don't take code in this file very seriously !!! - - I was "kinda" forced to write this implementation "this way" because the Servo code implementation - from multiwii is so horrible, obstructive and non dynamic, not to mention it doesn't make any sense - that there was just no other way around this then hardcoding/implementing each model separately. -*/ 'use strict'; TABS.servos = {}; @@ -46,9 +40,17 @@ TABS.servos.initialize = function (callback) { } MSP.send_message(MSP_codes.MSP_IDENT, false, false, get_servo_configurations); - - function process_html() { - + + function update_ui() { + + if (semver.lt(CONFIG.apiVersion, "1.12.0")) { + + $(".tab-servos").removeClass("supported"); + return; + } + + $(".tab-servos").addClass("supported"); + var servoCheckbox = ''; var servoHeader = ''; for (var i = 0; i < RC.active_channels-4; i++) { @@ -56,47 +58,19 @@ TABS.servos.initialize = function (callback) { A' + (i+1) + '\ '; } - servoHeader = servoHeader + ''; + servoHeader = servoHeader + ''; for (var i = 0; i < RC.active_channels; i++) { servoCheckbox = servoCheckbox + '\ \ '; } - - $('div.tab-servos table.fields tr.main').append(servoHeader); - function process_directions(name, obj, bitpos) { - $('div.direction_wrapper').show(); - - var val; - - $('div.tab-servos table.directions').append('\ - \ - ' + name + '\ - \ - \ - \ - \ - '); - - if (bit_check(SERVO_CONFIG[obj].rate, bitpos)) val = 1; - else val = 0; - - $('div.tab-servos table.directions tr:last select').val(val); - $('div.tab-servos table.directions tr:last select').data('info', {'obj': obj, 'bitpos': bitpos}); - } - - function process_servos(name, alternate, obj, directions) { + function process_servos(name, alternate, obj) { $('div.supported_wrapper').show(); - - $('div.tab-servos table.fields').append('\ \ @@ -106,46 +80,28 @@ TABS.servos.initialize = function (callback) { \ ' + servoCheckbox + '\ \ - ' + name + '\ - ' + alternate + '\ \ \ '); - - - // translate to user-selected language - localize(); - if (SERVO_CONFIG[obj].indexOfChannelToForward >= 0) { $('div.tab-servos table.fields tr:last td.channel input').eq(SERVO_CONFIG[obj].indexOfChannelToForward).prop('checked', true); } - if (directions == true) { - $('div.tab-servos table.fields tr:last td.direction input:first').prop('checked', bit_check(SERVO_CONFIG[obj].rate, 0)); - $('div.tab-servos table.fields tr:last td.direction input:last').prop('checked', bit_check(SERVO_CONFIG[obj].rate, 1)); - } else if (directions == 2) { - // removing checkboxes - $('div.tab-servos table.fields tr:last td.direction').html(''); + // adding select box and generating options + $('div.tab-servos table.fields tr:last td.direction').append('\ + \ + '); - // adding select box and generating options - $('div.tab-servos table.fields tr:last td.direction').append('\ - \ - '); + var select = $('div.tab-servos table.fields tr:last td.direction select'); - var select = $('div.tab-servos table.fields tr:last td.direction select'); - - for (var i = 100; i > -101; i--) { - select.append(''); - } - - // select current rate - select.val(SERVO_CONFIG[obj].rate); - } else { - // removing checkboxes - $('div.tab-servos table.fields tr:last td.direction').html(''); + for (var i = 100; i > -101; i--) { + select.append(''); } + // select current rate + select.val(SERVO_CONFIG[obj].rate); + $('div.tab-servos table.fields tr:last').data('info', {'obj': obj}); // UI hooks @@ -159,17 +115,6 @@ TABS.servos.initialize = function (callback) { } function servos_update(save_configuration_to_eeprom) { - // update bitfields - $('div.tab-servos table.directions tr:not(".main")').each(function () { - var info = $('select', this).data('info'); - var val = parseInt($('select', this).val()); - - // in this stage we need to know which bitfield and which bitposition needs to be flipped - if (val) SERVO_CONFIG[info.obj].rate = bit_set(SERVO_CONFIG[info.obj].rate, info.bitpos); - else SERVO_CONFIG[info.obj].rate = bit_clear(SERVO_CONFIG[info.obj].rate, info.bitpos); - }); - - // update the rest $('div.tab-servos table.fields tr:not(".main")').each(function () { var info = $(this).data('info'); @@ -187,17 +132,8 @@ TABS.servos.initialize = function (callback) { SERVO_CONFIG[info.obj].min = parseInt($('.min input', this).val()); SERVO_CONFIG[info.obj].max = parseInt($('.max input', this).val()); - // update rate if direction fields exist - if ($('.direction input', this).length) { - if ($('.direction input:first', this).is(':checked')) SERVO_CONFIG[info.obj].rate = bit_set(SERVO_CONFIG[info.obj].rate, 0); - else SERVO_CONFIG[info.obj].rate = bit_clear(SERVO_CONFIG[info.obj].rate, 0); - - if ($('.direction input:last', this).is(':checked')) SERVO_CONFIG[info.obj].rate = bit_set(SERVO_CONFIG[info.obj].rate, 1); - else SERVO_CONFIG[info.obj].rate = bit_clear(SERVO_CONFIG[info.obj].rate, 1); - } else if ($('.direction select', this).length) { - var val = parseInt($('.direction select', this).val()); - SERVO_CONFIG[info.obj].rate = val; - } + var val = parseInt($('.direction select', this).val()); + SERVO_CONFIG[info.obj].rate = val; }); // @@ -217,113 +153,15 @@ TABS.servos.initialize = function (callback) { } } - /* - MSP.send_message(MSP_codes.MSP_SET_CHANNEL_FORWARDING, MSP.crunch(MSP_codes.MSP_SET_CHANNEL_FORWARDING), false, function () { - MSP.send_message(MSP_codes.MSP_SET_SERVO_CONF, MSP.crunch(MSP_codes.MSP_SET_SERVO_CONF), false, function () { - if (save_configuration_to_eeprom) { - // Save changes to EEPROM - MSP.send_message(MSP_codes.MSP_EEPROM_WRITE, false, false, function () { - GUI.log(chrome.i18n.getMessage('servosEepromSave')); - }); - } - }); - }); - */ - } // drop previous table $('div.tab-servos table.fields tr:not(:first)').remove(); - var model = $('div.tab-servos strong.model'); - var supported_models = [1, 4, 5, 8, 14, 20, 21, 24, 25]; - - switch (CONFIG.multiType) { - case 1: // TRI - case 25: // CUSTOM_TRI - // looking ok so far - model.text('TRI'); - - process_directions('YAW', 5, 0); - - process_servos('Yaw Servo', '', 5, false); - break; - case 4: // BI - // looking ok so far - model.text('BI'); - - process_directions('L YAW', 4, 1); - process_directions('R YAW', 5, 1); - process_directions('L NICK', 4, 0); - process_directions('R NICK', 5, 0); - - process_servos('Left Servo', '', 4, false); - process_servos('Right Servo', '', 5, false); - break; - case 5: // Gimbal - // needs to be verified - model.text('Gimbal'); - - // rate - process_servos('Pitch Servo', '', 0, 2); - process_servos('Roll Servo', '', 1, 2); - break; - case 8: // Flying Wing - // looking ok so far - model.text('Flying Wing'); - - process_directions('L ROLL', 3, 1); - process_directions('R ROLL', 4, 1); - process_directions('L NICK', 3, 0); - process_directions('R NICK', 4, 0); - - process_servos('Left Wing', '', 3, false); - process_servos('Right Wing', '', 4, false); - break; - case 14: // Airplane - case 24: // Custom_Airplane - model.text('Airplane'); - - // rate - process_servos('Wing 1', '', 3, 2); - process_servos('Wing 2', '', 4, 2); - process_servos('Rudd', '', 5, 2); - process_servos('Elev', '', 6, 2); - break; - case 20: // Dualcopter - // looking ok so far - model.text('Dualcopter'); - - process_directions('PITCH', 4, 0); - process_directions('ROLL', 5, 0); - - process_servos('Roll', '', 5, false); - process_servos('Nick', '', 4, false); - break; - case 21: // Singlecopter - // looking ok so far - model.text('Singlecopter'); - - process_servos('Right', 'R YAW', 3, true); - process_servos('Left', 'L YAW', 4, true); - process_servos('Front', 'F YAW', 5, true); - process_servos('Rear', 'YAW', 6, true); - break; - - default: - model.text(chrome.i18n.getMessage('servosModelNoSupport')); + for (var servoIndex = 0; servoIndex < 8; servoIndex++) { + process_servos('Servo ' + servoIndex, '', servoIndex, false); } - // implementation of feature servo_tilt - if (AUX_CONFIG.indexOf('CAMSTAB') > -1 || AUX_CONFIG.indexOf('CAMTRIG') > -1) { - // Gimbal on - // needs to be verified - - // rate - process_servos('Pitch Servo', '', 0, 2); - process_servos('Roll Servo', '', 1, 2); - } - // UI hooks for dynamically generated elements $('table.directions select, table.directions input, table.fields select, table.fields input').change(function () { if ($('div.live input').is(':checked')) { @@ -331,14 +169,20 @@ TABS.servos.initialize = function (callback) { GUI.timeout_add('servos_update', servos_update, 10); } }); - + $('a.update').click(function () { - // standard check for supported_models + custom implementation for feature servo_tilt - if (supported_models.indexOf(CONFIG.multiType) != -1 || AUX_CONFIG.indexOf('CAMSTAB') > -1 || AUX_CONFIG.indexOf('CAMTRIG') > -1) { - servos_update(true); - } + servos_update(true); }); + + } + function process_html() { + + update_ui(); + + // translate to user-selected language + localize(); + // status data pulled via separate timer with static speed GUI.interval_add('status_pull', function () { MSP.send_message(MSP_codes.MSP_STATUS); From b1eb21cb78462eef7c01da70e342d039cc15685e Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 13 Jul 2015 02:09:24 +0100 Subject: [PATCH 14/55] Bump date. --- js/data_storage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/data_storage.js b/js/data_storage.js index dae77ca0..85dd9035 100755 --- a/js/data_storage.js +++ b/js/data_storage.js @@ -1,7 +1,7 @@ 'use strict'; var CONFIGURATOR = { - 'releaseDate': 1432389468227, // new Date().getTime() - Sat May 23 2015 14:57:54 GMT+0100 (BST) + 'releaseDate': 1436749724786, // new Date().getTime() - Mon Jul 13 2015 02:08:27 GMT+0100 // all versions are specified and compared using semantic versioning http://semver.org/ 'apiVersionAccepted': '1.2.0', From 12048ac7c1d3e35a2811aea64e449dd4ef425684 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 13 Jul 2015 02:31:14 +0100 Subject: [PATCH 15/55] Update links and sponsors. --- _locales/en/messages.json | 2 +- tabs/landing.html | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 4db47410..5a18ef93 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -211,7 +211,7 @@ "message": "Request Optional Permissions" }, "defaultWelcomeText": { - "message": "Welcome to Cleanflight - Configurator, a utility designed to simplify updating, configuring and tuning of your flight controller.

The application supports all hardware that can run cleanflight (SPRacingF3, Vortex, Sparky, CC3D/EVO, Air Hero 32, Flip32/+/Deluxe, CJMCU Microquad, Chebuzz F3, STM32F3Discovery, Hermit, Naze32 Tricopter Frame, Skyline32, Naze/32/Mini/Pro/Blackbox etc)

The firmware source code can be downloaded from here
The newest binary firmware image is available here, development builds available here

Latest CP210x Drivers can be downloaded from here
" + "message": "Welcome to Cleanflight - Configurator, a utility designed to simplify updating, configuring and tuning of your flight controller.

The application supports all hardware that can run cleanflight (SPRacingF3, Vortex, Sparky, DoDo, CC3D/EVO, Air Hero 32, Flip32/+/Deluxe, DragonFly32, CJMCU Microquad, Chebuzz F3, STM32F3Discovery, Hermit, Naze32 Tricopter Frame, Skyline32, Naze/32/Mini/Pro/Blackbox etc)

The firmware source code can be downloaded from here
The newest binary firmware image is available here, development builds available here

Latest CP210x Drivers can be downloaded from here
" }, "defaultContributingHead": { "message": "Contributing" diff --git a/tabs/landing.html b/tabs/landing.html index 635f5e12..6184c4b6 100644 --- a/tabs/landing.html +++ b/tabs/landing.html @@ -60,6 +60,9 @@

OverSkyRC

+

+ • Multi Rotor Mania
+

From ee27327c67a71ba48fd2f49a9a4e7dbd8f6203a7 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 13 Jul 2015 02:31:23 +0100 Subject: [PATCH 16/55] Update changelog. --- changelog.html | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/changelog.html b/changelog.html index ea2cc733..09720a49 100644 --- a/changelog.html +++ b/changelog.html @@ -1,3 +1,9 @@ +2015.05.23 - 1.0.0 - cleanflight +

+ - Update servo configuration (requires firmware >= 1.10.0).
+ - Add some notes and help messages for common issues.
+ - Update sponsors panel and add links to new boards.
+

2015.05.23 - 0.65.0 - cleanflight

- Support flashing of the SPRacingF3.
@@ -23,10 +29,10 @@

2015.03.29 - 0.63.0 - cleanflight

- - Configuration tab supports auto_disarm_delay and disarm_kill_switch - Requires 1.8.0 firmware.
- - PID Tuning tab allows TPA Breakpoint changes - Requires 1.8.0 firmware.
- - Corrected Artificial Horizon Pitch/Roll views.
- - Changed logging time stamp to include date stamp.
+ - Configuration tab supports auto_disarm_delay and disarm_kill_switch (requires firmware >= 1.8.0).
+ - PID Tuning tab allows TPA Breakpoint changes (requires firmware >= 1.8.0).
+ - Correct Artificial Horizon Pitch/Roll views.
+ - Change logging time stamp to include date stamp.
- Support new firmware 1.8 serial port configuration.
- Move documentation and help to new tab.
- Add contributing section to welcome tab.
@@ -38,7 +44,7 @@ 2015.02.26 - 0.62.0 - cleanflight

- Add flight indicators to setup screen tab.
- - Add dataflash tab. Requires 1.8.0 firmware.
+ - Add dataflash tab (requires firmware >= 1.8.0)..
- Add Cleanflight logos.
- Fix loading online flash files - github moved them to amazon aws.
- Fix to fallback 3D model.
@@ -46,7 +52,7 @@

2015.02.03 - 0.61.0 - cleanflight

- - Support changing PID controller - there new PID controllers in 1.7.0 firmware.
+ - Support changing PID controller - three new PID controllers in 1.7.0 firmware.
- Support for LED thrust ring.
- Support for LED colors.
- Support for displaying sonar sensor reading on the sensors tab.
@@ -54,21 +60,21 @@ - New Logo. (Tom McCullough)
- New 3D models (AkFreak).
- Update presentation of LEDs that have multiple functions.
- - Added Documentation and Support panels to welcome tab.
+ - Add Documentation and Support panels to welcome tab.
- Add support for backup and restore of LED strip configuration.
- Fix for disappearing tabs in chrome 41 beta.
- Various other minor improvements.

2015.01.08 - 0.60.0 - cleanflight

- - Add LED strip tab for LED configuration - requires v1.6.0 firmware to save.
+ - Add LED strip tab for LED configuration (requires firmware >= 1.6.0)..
- Replace motor order images (stronnag)

2015.01.08 - 0.59.1 - cleanflight

- - Add support for Blackbox flight recorder feature (requires v1.5.0 firmware).
+ - Add support for Blackbox flight recorder feature (requires firmware >= 1.5.0).
- Update RSSI channel section to allow any channel.
- - Implemented configuration migration to aid with backwards compatibility.
+ - Implement configuration migration to aid with backwards compatibility.
- Allow CLI access when connecting firmware with an out-of-date API.
- Support 'release candidate' and 'stable' releases.

@@ -88,7 +94,7 @@ 2014.12.06 - 0.57.1 - cleanflight

- Latest firmware required.
- - Merged latest baseflight configurator changes.
+ - Merge latest baseflight configurator changes.
- Added support for choosing and downloading firmware via the github relases API.
- Added Armattan Quads as a sponsor.
- Various UI tweaks.
@@ -96,17 +102,17 @@ 2014.12.06 - 0.57

- Firmware flasher now contains firmware builds picker
- - Implemented new and experimental review mechanism
+ - Implement new and experimental review mechanism
- Support for new A-tail Quad craft type
- Firmware flasher flashing speed optimizations
- - Added specific 3D models for atail/vtail quad (norem)
+ - Add specific 3D models for atail/vtail quad (norem)
- Major bugfix for stuck UI after delayed port open procedure
- Bugfix for GPS distance to home not displaying
- Bugfix for backup/restore misbehaving (mostly on OSX)

2014.11.04 - 0.56

- - Added hex plus, hex X, tri, y4, y6 3D models (jef79m)
+ - Add hex plus, hex X, tri, y4, y6 3D models (jef79m)
- Bugfix for battery voltage saving sequence
- Bugfix for fetching development firmware

@@ -116,9 +122,9 @@ - Minimum accepted firmware version set to 2.31
- Support for flashing development firmware
- Setup tab performance improvements, faster 3D model
- - Strongly improved amount of data stored in backups
- - Improved flash on connect in firmware flasher
- - Rearranged texts and options in firmware flasher
+ - Strongly improve amount of data stored in backups
+ - Improve flash on connect in firmware flasher
+ - Rearrange texts and options in firmware flasher
- Bugfix for corrupted minimum window size on Windows 7
- Bugfix for incorrect date & time in firmware flasher
- Bugfix for port handler firing before port being initialized
From fb467116590caeda37ac3d013b1e37b8b09e201a Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 13 Jul 2015 19:07:39 +0100 Subject: [PATCH 17/55] Cleanup looptime configuration. --- _locales/en/messages.json | 13 +++++++-- changelog.html | 1 - tabs/configuration.css | 28 +++++-------------- tabs/configuration.html | 59 ++++++++++++++++++++++++--------------- tabs/configuration.js | 23 +++++++++------ 5 files changed, 68 insertions(+), 56 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index ebcfd294..91e33056 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -503,9 +503,18 @@ "configurationBatteryMultiwiiCurrent": { "message": "Enable support for legacy Multiwii MSP current output" }, - "configurationLoopTimeHead": { + "configurationSystem": { + "message": "System configuration" + }, + "configurationLoopTime": { "message": "Flight Controller Loop Time" }, + "configurationCalculatedCyclesSec": { + "message": "Cycles/Sec (Hz)" + }, + "configurationLoopTimeHelp": { + "message": "Note: Changing this may require PID re-tuning." + }, "configurationGPS": { "message": "GPS" }, @@ -519,7 +528,7 @@ "message": "Ground Assistance Type" }, "configurationGPSHelp": { - "message": "Note: Rememer to configure a Serial Port (via Ports tab) when using GPS feature." + "message": "Note: Remember to configure a Serial Port (via Ports tab) when using GPS feature." }, "configurationSerialRX": { diff --git a/changelog.html b/changelog.html index 4a5df904..09720a49 100644 --- a/changelog.html +++ b/changelog.html @@ -6,7 +6,6 @@

2015.05.23 - 0.65.0 - cleanflight

- - Configuration tab supports setting FC loop time - Requires 1.8.0 firmware.
- Support flashing of the SPRacingF3.
- Support manual baud rate configuration for flashing.

diff --git a/tabs/configuration.css b/tabs/configuration.css index 2d8c7434..fe48e434 100644 --- a/tabs/configuration.css +++ b/tabs/configuration.css @@ -99,6 +99,13 @@ border: 1px solid silver; } + +.tab-configuration .number input.disabled { + width: 50px; + padding: 0px 5px; + background-color: #ececec; +} + .tab-configuration .number span { margin-left: 10px; line-height: 20px; @@ -154,27 +161,6 @@ .tab-configuration .disarm .checkbox span { margin-left: 15px; } -.tab-configuration .cycles { - border-bottom: 1px solid #dddddd; - margin-top: 16px; -} -.tab-configuration .block { - float: left; - display: block; - border: 1px solid silver; -} -.tab-configuration .block .head { - display: block; - text-align: center; - line-height: 20px; - font-weight: bold; - border-bottom: 1px solid silver; - background-color: #ececec; -} -.tab-configuration .block.looptime { - width: 200px; - margin-top: 11px; -} .tab-configuration .save { display: block; float: right; diff --git a/tabs/configuration.html b/tabs/configuration.html index 1a82b07c..a53226a0 100644 --- a/tabs/configuration.html +++ b/tabs/configuration.html @@ -131,19 +131,6 @@

-
- - - - - - - - - - - -
@@ -163,8 +150,6 @@ - -
@@ -205,7 +190,7 @@
-
+
@@ -238,14 +223,41 @@ - +
+ +
+
+
+ + + + + + + + + + +
+ +
+
+
+ +
+
+ +
+

+
+
@@ -307,6 +319,7 @@
+
diff --git a/tabs/configuration.js b/tabs/configuration.js index ade7a696..1e5f5e55 100644 --- a/tabs/configuration.js +++ b/tabs/configuration.js @@ -49,6 +49,17 @@ TABS.configuration.initialize = function (callback, scrollPosition) { MSP.send_message(MSP_codes.MSP_IDENT, false, false, load_config); + function recalculate_cycles_sec() { + var looptime = $('input[name="looptime"]').val(); + + var message = 'Max'; + if (looptime > 0) { + message = parseFloat((1 / looptime) * 1000 * 1000).toFixed(0); + } + + $('input[name="looptimehz"]').val(message); + } + function process_html() { // translate to user-selected language localize(); @@ -278,10 +289,8 @@ TABS.configuration.initialize = function (callback, scrollPosition) { // fill FC loop time $('input[name="looptime"]').val(FC_CONFIG.loopTime); - if(FC_CONFIG.loopTime > 0) - $('span.looptimehz').text(parseFloat((1/FC_CONFIG.loopTime)*1000*1000).toFixed(0) + ' Cycles per Sec'); - else - $('span.looptimehz').text('Maximum Cycles per Sec'); + + recalculate_cycles_sec(); $('div.cycles').show(); } @@ -307,11 +316,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { // UI hooks $('input[name="looptime"]').change(function() { - FC_CONFIG.loopTime = parseInt($('input[name="looptime"]').val()); - if(FC_CONFIG.loopTime > 0) - $('span.looptimehz').text(parseFloat((1/FC_CONFIG.loopTime)*1000*1000).toFixed(0) + ' Cycles per Sec'); - else - $('span.looptimehz').text('Maximum Cycles per Sec'); + recalculate_cycles_sec(); }); $('input[type="checkbox"].feature', features_e).change(function () { From 56a209a1e8ef01a6db9ea234cb74ae2209fa8d49 Mon Sep 17 00:00:00 2001 From: ProDrone Date: Sun, 5 Jul 2015 00:21:14 +0200 Subject: [PATCH 18/55] Detect and register unsupported message error from FC --- js/msp.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/js/msp.js b/js/msp.js index 49676381..8415d8c9 100644 --- a/js/msp.js +++ b/js/msp.js @@ -105,6 +105,7 @@ var MSP = { callbacks: [], packet_error: 0, + unsupported: 0, ledDirectionLetters: ['n', 'e', 's', 'w', 'u', 'd'], // in LSB bit order ledFunctionLetters: ['i', 'w', 'f', 'a', 't', 'r', 'c'], // in LSB bit order @@ -141,10 +142,14 @@ var MSP = { } break; case 2: // direction (should be >) + this.unsupported = 0; if (data[i] == 62) { // > this.message_direction = 1; - } else { // < + } else if (data[i] == 60) { // < this.message_direction = 0; + } else if (data[i] == 33) { // ! + // FC reports unsupported message error + this.unsupported = 1; } this.state++; From 717025cbdea195cbf6f34841e41e9c5038f23341 Mon Sep 17 00:00:00 2001 From: ProDrone Date: Sun, 5 Jul 2015 00:40:50 +0200 Subject: [PATCH 19/55] Skip and log unsupported messages --- js/msp.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/js/msp.js b/js/msp.js index 8415d8c9..2d2b4915 100644 --- a/js/msp.js +++ b/js/msp.js @@ -210,7 +210,7 @@ var MSP = { process_data: function (code, message_buffer, message_length) { var data = new DataView(message_buffer, 0); // DataView (allowing us to view arrayBuffer as struct/union) - switch (code) { + if (!this.unsupported) switch (code) { case MSP_codes.MSP_IDENT: console.log('Using deprecated msp command: MSP_IDENT'); // Deprecated @@ -839,6 +839,8 @@ var MSP = { default: console.log('Unknown code detected: ' + code); + } else { + console.log('FC reports unsupported message error: ' + code); } // trigger callbacks, cleanup/remove callback after trigger From fa3888a9d851febbc75dfbda65aef392647c5098 Mon Sep 17 00:00:00 2001 From: Nicholas Sherlock Date: Thu, 20 Aug 2015 12:14:33 +1200 Subject: [PATCH 20/55] Fix rounding of floating point values in crunch() (rc_rate, pids, etc) --- js/msp.js | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/js/msp.js b/js/msp.js index 49676381..286fcc55 100644 --- a/js/msp.js +++ b/js/msp.js @@ -980,43 +980,43 @@ MSP.crunch = function (code) { case 7: case 8: case 9: - buffer.push(parseInt(PIDs[i][0] * 10)); - buffer.push(parseInt(PIDs[i][1] * 1000)); + buffer.push(Math.round(PIDs[i][0] * 10)); + buffer.push(Math.round(PIDs[i][1] * 1000)); buffer.push(parseInt(PIDs[i][2])); break; case 4: - buffer.push(parseInt(PIDs[i][0] * 100)); - buffer.push(parseInt(PIDs[i][1] * 100)); + buffer.push(Math.round(PIDs[i][0] * 100)); + buffer.push(Math.round(PIDs[i][1] * 100)); buffer.push(parseInt(PIDs[i][2])); break; case 5: case 6: - buffer.push(parseInt(PIDs[i][0] * 10)); - buffer.push(parseInt(PIDs[i][1] * 100)); - buffer.push(parseInt(PIDs[i][2] * 1000)); + buffer.push(Math.round(PIDs[i][0] * 10)); + buffer.push(Math.round(PIDs[i][1] * 100)); + buffer.push(Math.round(PIDs[i][2] * 1000)); break; } } break; case MSP_codes.MSP_SET_RC_TUNING: - buffer.push(parseInt(RC_tuning.RC_RATE * 100)); - buffer.push(parseInt(RC_tuning.RC_EXPO * 100)); + buffer.push(Math.round(RC_tuning.RC_RATE * 100)); + buffer.push(Math.round(RC_tuning.RC_EXPO * 100)); if (semver.lt(CONFIG.apiVersion, "1.7.0")) { - buffer.push(parseInt(RC_tuning.roll_pitch_rate * 100)); + buffer.push(Math.round(RC_tuning.roll_pitch_rate * 100)); } else { - buffer.push(parseInt(RC_tuning.roll_rate * 100)); - buffer.push(parseInt(RC_tuning.pitch_rate * 100)); + buffer.push(Math.round(RC_tuning.roll_rate * 100)); + buffer.push(Math.round(RC_tuning.pitch_rate * 100)); } - buffer.push(parseInt(RC_tuning.yaw_rate * 100)); - buffer.push(parseInt(RC_tuning.dynamic_THR_PID * 100)); - buffer.push(parseInt(RC_tuning.throttle_MID * 100)); - buffer.push(parseInt(RC_tuning.throttle_EXPO * 100)); + buffer.push(Math.round(RC_tuning.yaw_rate * 100)); + buffer.push(Math.round(RC_tuning.dynamic_THR_PID * 100)); + buffer.push(Math.round(RC_tuning.throttle_MID * 100)); + buffer.push(Math.round(RC_tuning.throttle_EXPO * 100)); if (semver.gte(CONFIG.apiVersion, "1.7.0")) { buffer.push(lowByte(RC_tuning.dynamic_THR_breakpoint)); buffer.push(highByte(RC_tuning.dynamic_THR_breakpoint)); } if (semver.gte(CONFIG.apiVersion, "1.10.0")) { - buffer.push(parseInt(RC_tuning.RC_YAW_EXPO * 100)); + buffer.push(Math.round(RC_tuning.RC_YAW_EXPO * 100)); } break; // Disabled, cleanflight does not use MSP_SET_BOX. @@ -1064,12 +1064,12 @@ MSP.crunch = function (code) { buffer.push(MISC.multiwiicurrentoutput); buffer.push(MISC.rssi_channel); buffer.push(MISC.placeholder2); - buffer.push(lowByte(MISC.mag_declination * 10)); - buffer.push(highByte(MISC.mag_declination * 10)); + buffer.push(lowByte(Math.round(MISC.mag_declination * 10))); + buffer.push(highByte(Math.round(MISC.mag_declination * 10))); buffer.push(MISC.vbatscale); - buffer.push(MISC.vbatmincellvoltage * 10); - buffer.push(MISC.vbatmaxcellvoltage * 10); - buffer.push(MISC.vbatwarningcellvoltage * 10); + buffer.push(Math.round(MISC.vbatmincellvoltage * 10)); + buffer.push(Math.round(MISC.vbatmaxcellvoltage * 10)); + buffer.push(Math.round(MISC.vbatwarningcellvoltage * 10)); break; case MSP_codes.MSP_SET_CHANNEL_FORWARDING: for (var i = 0; i < SERVO_CONFIG.length; i++) { From ef0c6378775a6c74f973961b353886e4e88b467f Mon Sep 17 00:00:00 2001 From: Nicholas Sherlock Date: Thu, 23 Jul 2015 12:54:34 +1200 Subject: [PATCH 21/55] Add control sticks for MSP Rx, suitable for debugging CF without a Tx --- _locales/en/messages.json | 41 ++++++++- js/msp.js | 16 ++++ tabs/receiver.css | 2 + tabs/receiver.html | 1 + tabs/receiver.js | 37 +++++++- tabs/receiver_msp.css | 109 +++++++++++++++++++++++ tabs/receiver_msp.html | 71 +++++++++++++++ tabs/receiver_msp.js | 182 ++++++++++++++++++++++++++++++++++++++ 8 files changed, 455 insertions(+), 4 deletions(-) create mode 100644 tabs/receiver_msp.css create mode 100644 tabs/receiver_msp.html create mode 100644 tabs/receiver_msp.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 91e33056..741ea82a 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -672,6 +672,9 @@ "receiverButtonRefresh": { "message": "Refresh" }, + "receiverButtonSticks": { + "message": "Control sticks" + }, "receiverDataRefreshed": { "message": "RC Tuning data refreshed" }, @@ -1146,5 +1149,41 @@ }, "ledStripEepromSaved": { "message": "EEPROM saved" + }, + "controlAxisRoll": { + "message": "Roll" + }, + "controlAxisPitch": { + "message": "Pitch" + }, + "controlAxisYaw": { + "message": "Yaw" + }, + "controlAxisThrottle": { + "message": "Throttle" + }, + "controlAxisAux1": { + "message": "AUX 1" + }, + "controlAxisAux2": { + "message": "AUX 2" + }, + "controlAxisAux3": { + "message": "AUX 3" + }, + "controlAxisAux4": { + "message": "AUX 4" + }, + "controlAxisAux5": { + "message": "AUX 5" + }, + "controlAxisAux6": { + "message": "AUX 6" + }, + "controlAxisAux7": { + "message": "AUX 7" + }, + "controlAxisAux8": { + "message": "AUX 8" } -} +} \ No newline at end of file diff --git a/js/msp.js b/js/msp.js index 49676381..e2232272 100644 --- a/js/msp.js +++ b/js/msp.js @@ -1130,6 +1130,22 @@ MSP.crunch = function (code) { return buffer; }; +/** + * Set raw Rx values over MSP protocol. + * + * Channels is an array of 16-bit unsigned integer channel values to be sent. 8 channels is probably the maximum. + */ +MSP.setRawRx = function(channels) { + var buffer = []; + + for (var i = 0; i < channels.length; i++) { + buffer.push(specificByte(channels[i], 0)); + buffer.push(specificByte(channels[i], 1)); + } + + MSP.send_message(MSP_codes.MSP_SET_RAW_RC, buffer, false); +} + /** * Send a request to read a block of data from the dataflash at the given address and pass that address and a dataview * of the returned data to the given callback (or null for the data if an error occured). diff --git a/tabs/receiver.css b/tabs/receiver.css index fe1a3c4f..9c7c6903 100644 --- a/tabs/receiver.css +++ b/tabs/receiver.css @@ -299,6 +299,7 @@ position: absolute; bottom: 10px; } +.tab-receiver .sticks, .tab-receiver .update, .tab-receiver .refresh { display: block; @@ -317,6 +318,7 @@ border: 1px solid silver; background-color: #ececec; } +.tab-receiver .sticks, .tab-receiver .refresh { margin-right: 10px; } diff --git a/tabs/receiver.html b/tabs/receiver.html index f562050c..f20c8a98 100644 --- a/tabs/receiver.html +++ b/tabs/receiver.html @@ -86,5 +86,6 @@
+
diff --git a/tabs/receiver.js b/tabs/receiver.js index 0efb5f18..9e08e321 100644 --- a/tabs/receiver.js +++ b/tabs/receiver.js @@ -18,7 +18,12 @@ TABS.receiver.initialize = function (callback) { } function get_rc_map() { - MSP.send_message(MSP_codes.MSP_RX_MAP, false, false, load_html); + MSP.send_message(MSP_codes.MSP_RX_MAP, false, false, load_config); + } + + // Fetch features so we can check if RX_MSP is enabled: + function load_config() { + MSP.send_message(MSP_codes.MSP_BF_CONFIG, false, false, load_html); } function load_html() { @@ -52,7 +57,12 @@ TABS.receiver.initialize = function (callback) { }); // generate bars - var bar_names = ['Roll', 'Pitch', 'Yaw', 'Throttle'], + var bar_names = [ + chrome.i18n.getMessage('controlAxisRoll'), + chrome.i18n.getMessage('controlAxisPitch'), + chrome.i18n.getMessage('controlAxisYaw'), + chrome.i18n.getMessage('controlAxisThrottle') + ], bar_container = $('.tab-receiver .bars'), aux_index = 1; @@ -61,7 +71,7 @@ TABS.receiver.initialize = function (callback) { if (i < bar_names.length) { name = bar_names[i]; } else { - name = 'AUX ' + aux_index++; + name = chrome.i18n.getMessage("controlAxisAux" + (aux_index++)); } bar_container.append('\ @@ -302,6 +312,27 @@ TABS.receiver.initialize = function (callback) { MSP.send_message(MSP_codes.MSP_SET_RC_TUNING, MSP.crunch(MSP_codes.MSP_SET_RC_TUNING), false, save_rc_map); }); + + $("a.sticks").click(function() { + var + windowWidth = 370, + windowHeight = 510; + + chrome.app.window.create("/tabs/receiver_msp.html", { + id: "receiver_msp", + innerBounds: { + minWidth: windowWidth, minHeight: windowHeight, + width: windowWidth, height: windowHeight, + maxWidth: windowWidth, maxHeight: windowHeight + } + }, function(createdWindow) { + // Give the window a callback it can use to access our MSP object to send to CF + createdWindow.contentWindow.setRawRx = MSP.setRawRx; + }); + }); + + // Only show the MSP control sticks if the MSP Rx feature is enabled + $("a.sticks").toggle(bit_check(BF_CONFIG.features, 14 /* RX_MSP */)); $('select[name="rx_refresh_rate"]').change(function () { var plot_update_rate = parseInt($(this).val(), 10); diff --git a/tabs/receiver_msp.css b/tabs/receiver_msp.css new file mode 100644 index 00000000..29ecf158 --- /dev/null +++ b/tabs/receiver_msp.css @@ -0,0 +1,109 @@ +body { + font-family: 'Segoe UI', Tahoma, sans-serif; + font-size: 12px; + color: #303030; + margin: 10px; +} + +.control-gimbals { + /* A generous padding around the window edges ensures that we continue to receive mousemove events (since + * cursor stays in the window for longer) + */ + padding:25px; + padding-bottom:0; + text-align:center; +} + +.control-gimbal { + position:relative; + width:120px; + height:120px; + background-color:#eee; + margin-left:1em; + margin-right:1em; + margin-bottom:2em; + display:inline-block; + border-radius:5px; + + cursor:pointer; +} + +.crosshair { + display:block; + position:absolute; + background-color:#ddd; +} + +.crosshair-vert { + width:1px; + height:100%; + left:50%; +} + +.crosshair-horz { + height:1px; + width:100%; + top:50%; +} + +.gimbal-label { + display:block; + position:absolute; + text-align:center; +} + +.gimbal-label-horz { + top:calc(100% + 0.5em); + width:100%; +} + +.gimbal-label-vert { + transform:rotate(-90deg); + /*transform-origin:0% 100%;*/ + top:calc(50% - 0.5em); + width:100%; + left:calc(-50% - 1em); +} + +.control-stick { + background-color:rgba(255,50,50,1.0); + width:20px; + height:20px; + margin-left:-10px; + margin-top:-10px; + display:block; + border-radius:100%; + position:absolute; + + cursor:pointer; +} + +.control-slider { + margin:20px; +} + +.tooltip { + position: absolute; + left: calc(100% + 24px); + top: 0; +} + +.control-slider .slider { + margin-left:50px; + margin-right:50px; +} + +.slider-label { + position:absolute; + text-align:right; + width:40px; + left:-65px; +} + +.button-enable { + padding:0.5em; + font-size:110%; + margin-left:auto; + margin-right:auto; + display:block; +} \ No newline at end of file diff --git a/tabs/receiver_msp.html b/tabs/receiver_msp.html new file mode 100644 index 00000000..fb1a5482 --- /dev/null +++ b/tabs/receiver_msp.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + +
+
+ + + + + +
+ +
+
+
+ + + + + +
+
+
+
+ +
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+

+ These sticks allow Cleanflight to be armed and tested without a transmitter or receiver being + present. However, this feature is not intended for flight and propellers must not be attached. +

+

+ This feature does not guarantee reliable control of your craft. Serious injury is likely to + result if propellers are left on. +

+ +
+ + \ No newline at end of file diff --git a/tabs/receiver_msp.js b/tabs/receiver_msp.js new file mode 100644 index 00000000..91fd9c24 --- /dev/null +++ b/tabs/receiver_msp.js @@ -0,0 +1,182 @@ +"use strict"; + +var + CHANNEL_MIN_VALUE = 1000, + CHANNEL_MID_VALUE = 1500, + CHANNEL_MAX_VALUE = 2000, + + // What's the index of each channel in the MSP channel list? + channelMSPIndexes = { + roll: 0, + pitch: 1, + yaw: 2, + throttle: 3, + aux1: 4, + aux2: 5, + aux3: 6, + aux4: 7, + }, + + // Set reasonable initial stick positions (Mode 2) + stickValues = { + throttle: CHANNEL_MIN_VALUE, + pitch: CHANNEL_MID_VALUE, + roll: CHANNEL_MID_VALUE, + yaw: CHANNEL_MID_VALUE, + aux1: CHANNEL_MIN_VALUE, + aux2: CHANNEL_MIN_VALUE, + aux3: CHANNEL_MIN_VALUE, + aux4: CHANNEL_MIN_VALUE + }, + + // First the vertical axis, then the horizontal: + gimbals = [ + ["throttle", "yaw"], + ["pitch", "roll"], + ], + + gimbalElems, + sliderElems, + + enableTX = false; + +function transmitChannels() { + var + channelValues = [0, 0, 0, 0, 0, 0, 0, 0]; + + if (!enableTX) { + return; + } + + for (var stickName in stickValues) { + channelValues[channelMSPIndexes[stickName]] = stickValues[stickName]; + } + + // Callback given to us by the window creator so we can have it send data over MSP for us: + window.setRawRx(channelValues); +} + +function stickPortionToChannelValue(portion) { + portion = Math.min(Math.max(portion, 0.0), 1.0); + + return Math.round(portion * (CHANNEL_MAX_VALUE - CHANNEL_MIN_VALUE) + CHANNEL_MIN_VALUE); +} + +function channelValueToStickPortion(channel) { + return (channel - CHANNEL_MIN_VALUE) / (CHANNEL_MAX_VALUE - CHANNEL_MIN_VALUE); +} + +function updateControlPositions() { + for (var stickName in stickValues) { + var + stickValue = stickValues[stickName]; + + // Look for the gimbal which corresponds to this stick name + for (var gimbalIndex in gimbals) { + var + gimbal = gimbals[gimbalIndex], + gimbalElem = gimbalElems.get(gimbalIndex), + gimbalSize = $(gimbalElem).width(), + stickElem = $(".control-stick", gimbalElem); + + if (gimbal[0] == stickName) { + stickElem.css('top', (1.0 - channelValueToStickPortion(stickValue)) * gimbalSize + "px"); + break; + } else if (gimbal[1] == stickName) { + stickElem.css('left', channelValueToStickPortion(stickValue) * gimbalSize + "px"); + break; + } + } + } +} + +function handleGimbalMouseDrag(e) { + var + gimbal = $(gimbalElems.get(e.data.gimbalIndex)), + gimbalOffset = gimbal.offset(), + gimbalSize = gimbal.width(); + + stickValues[gimbals[e.data.gimbalIndex][0]] = stickPortionToChannelValue(1.0 - (e.pageY - gimbalOffset.top) / gimbalSize); + stickValues[gimbals[e.data.gimbalIndex][1]] = stickPortionToChannelValue((e.pageX - gimbalOffset.left) / gimbalSize); + + updateControlPositions(); +} + +function localizeAxisNames() { + for (var gimbalIndex in gimbals) { + var + gimbal = gimbalElems.get(gimbalIndex); + + $(".gimbal-label-vert", gimbal).text(chrome.i18n.getMessage("controlAxis" + gimbals[gimbalIndex][0])); + $(".gimbal-label-horz", gimbal).text(chrome.i18n.getMessage("controlAxis" + gimbals[gimbalIndex][1])); + } + + for (var sliderIndex = 0; sliderIndex < 4; sliderIndex++) { + $(".slider-label", sliderElems.get(sliderIndex)).text(chrome.i18n.getMessage("controlAxisAux" + (sliderIndex + 1))); + } +} + +$(document).ready(function() { + $(".button-enable").click(function() { + var + shrinkHeight = $(".warning").height(); + + $(".warning").slideUp("short", function() { + chrome.app.window.current().innerBounds.minHeight -= shrinkHeight; + chrome.app.window.current().innerBounds.height -= shrinkHeight; + chrome.app.window.current().innerBounds.maxHeight -= shrinkHeight; + }); + + enableTX = true; + }); + + gimbalElems = $(".control-gimbal"); + sliderElems = $(".control-slider"); + + gimbalElems.each(function(gimbalIndex) { + $(this).on('mousedown', {gimbalIndex: gimbalIndex}, function(e) { + if (e.which == 1) { // Only move sticks on left mouse button + handleGimbalMouseDrag(e); + + $(window).on('mousemove', {gimbalIndex: gimbalIndex}, handleGimbalMouseDrag); + } + }); + }); + + $(".slider", sliderElems).each(function(sliderIndex) { + var + initialValue = stickValues["aux" + (sliderIndex + 1)]; + + $(this) + .noUiSlider({ + start: initialValue, + range: { + min: CHANNEL_MIN_VALUE, + max: CHANNEL_MAX_VALUE + } + }).on('slide change set', function(e, value) { + value = Math.round(parseFloat(value)); + + stickValues["aux" + (sliderIndex + 1)] = value; + + $(".tooltip", this).text(value); + }); + + $(this).append('
'); + + $(".tooltip", this).text(initialValue); + }); + + /* + * Mouseup handler needs to be bound to the window in order to receive mouseup if mouse leaves window. + */ + $(window).mouseup(function(e) { + $(this).off('mousemove', handleGimbalMouseDrag); + }); + + localizeAxisNames(); + + updateControlPositions(); + + setInterval(transmitChannels, 100); +}); \ No newline at end of file From e4d87c3ae24b18287287522e264a03c9600596af Mon Sep 17 00:00:00 2001 From: Nicholas Sherlock Date: Tue, 1 Sep 2015 03:34:57 +1200 Subject: [PATCH 22/55] Fix initialisation of sonar and altitude sensor fields on sensor tab --- tabs/sensors.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tabs/sensors.js b/tabs/sensors.js index 08423115..6ebcaea0 100644 --- a/tabs/sensors.js +++ b/tabs/sensors.js @@ -14,7 +14,8 @@ TABS.sensors.initialize = function (callback) { SENSOR_DATA.accelerometer[i] = 0; SENSOR_DATA.gyroscope[i] = 0; SENSOR_DATA.magnetometer[i] = 0; - SENSOR_DATA.sonar[i] = 0; + SENSOR_DATA.sonar = 0; + SENSOR_DATA.altitude = 0; SENSOR_DATA.debug[i] = 0; } } From d5593089df6bc55540525c47e3b4507714942017 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Wed, 9 Sep 2015 20:03:26 +0100 Subject: [PATCH 23/55] Fixing version number in changelog to match manifest.json. --- changelog.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.html b/changelog.html index 09720a49..a32269c8 100644 --- a/changelog.html +++ b/changelog.html @@ -1,4 +1,4 @@ -2015.05.23 - 1.0.0 - cleanflight +2015.05.23 - 0.66.0 - cleanflight

- Update servo configuration (requires firmware >= 1.10.0).
- Add some notes and help messages for common issues.
From ac000a77684239fe3142f6c9e7f9669b1f9fd0be Mon Sep 17 00:00:00 2001 From: Patrick Forringer Date: Sat, 19 Sep 2015 14:53:54 -0500 Subject: [PATCH 24/55] make rate charts taller so curve is easier to see --- tabs/receiver.css | 6 +++--- tabs/receiver.html | 4 ++-- tabs/receiver.js | 27 ++++++++++++++++----------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/tabs/receiver.css b/tabs/receiver.css index 91d2b7b9..08eea235 100644 --- a/tabs/receiver.css +++ b/tabs/receiver.css @@ -218,7 +218,7 @@ margin: 0 10px 10px 0; width: 220px; - height: 58px; + height: 120px; border: 1px solid silver; } @@ -226,7 +226,7 @@ margin: 0 10px 0 0; width: 220px; - height: 58px; + height: 120px; border: 1px solid silver; } @@ -334,4 +334,4 @@ fill: none; stroke: #000; shape-rendering: crispEdges; -} \ No newline at end of file +} diff --git a/tabs/receiver.html b/tabs/receiver.html index 196f4c04..405ef32d 100644 --- a/tabs/receiver.html +++ b/tabs/receiver.html @@ -53,10 +53,10 @@

- +
- +
diff --git a/tabs/receiver.js b/tabs/receiver.js index 0efb5f18..fbb0cd42 100644 --- a/tabs/receiver.js +++ b/tabs/receiver.js @@ -1,6 +1,9 @@ 'use strict'; -TABS.receiver = {}; +TABS.receiver = { + rateChartHeight: 120 +}; + TABS.receiver.initialize = function (callback) { var self = this; @@ -38,11 +41,11 @@ TABS.receiver.initialize = function (callback) { $('.tunings .rate input[name="rate"]').val(RC_tuning.RC_RATE.toFixed(2)); $('.tunings .rate input[name="expo"]').val(RC_tuning.RC_EXPO.toFixed(2)); $('.tunings .yaw_rate input[name="yaw_expo"]').val(RC_tuning.RC_YAW_EXPO.toFixed(2)); - + if (semver.lt(CONFIG.apiVersion, "1.10.0")) { $('.tunings .yaw_rate input[name="yaw_expo"]').hide(); } - + chrome.storage.local.get('rx_refresh_rate', function (result) { if (result.rx_refresh_rate) { $('select[name="rx_refresh_rate"]').val(result.rx_refresh_rate).change(); @@ -176,6 +179,8 @@ TABS.receiver.initialize = function (callback) { $('select[name="rssi_channel"]').val(MISC.rssi_channel); + var rateHeight = TABS.receiver.rateChartHeight; + // UI Hooks // curves $('.tunings .throttle input').on('input change', function () { @@ -201,14 +206,14 @@ TABS.receiver.initialize = function (callback) { var midx = 220 * mid, midxl = midx * 0.5, midxr = (((220 - midx) * 0.5) + midx), - midy = 58 - (midx * (58 / 220)), - midyl = 58 - ((58 - midy) * 0.5 *(expo + 1)), + midy = rateHeight - (midx * (rateHeight / 220)), + midyl = rateHeight - ((rateHeight - midy) * 0.5 *(expo + 1)), midyr = (midy / 2) * (expo + 1); // draw - context.clearRect(0, 0, 220, 58); + context.clearRect(0, 0, 220, rateHeight); context.beginPath(); - context.moveTo(0, 58); + context.moveTo(0, rateHeight); context.quadraticCurveTo(midxl, midyl, midx, midy); context.moveTo(midx, midy); context.quadraticCurveTo(midxr, midyr, 220, 0); @@ -237,13 +242,13 @@ TABS.receiver.initialize = function (callback) { } // math magic by englishman - var ratey = 58 * rate; + var ratey = rateHeight * rate; // draw - context.clearRect(0, 0, 220, 58); + context.clearRect(0, 0, 220, rateHeight); context.beginPath(); - context.moveTo(0, 58); - context.quadraticCurveTo(110, 58 - ((ratey / 2) * (1 - expo)), 220, 58 - ratey); + context.moveTo(0, rateHeight); + context.quadraticCurveTo(110, rateHeight - ((ratey / 2) * (1 - expo)), 220, rateHeight - ratey); context.lineWidth = 2; context.stroke(); }, 0); From b7921de5283ba1d4bb0c331c4983b92b841f1eec Mon Sep 17 00:00:00 2001 From: Nicholas Sherlock Date: Fri, 25 Sep 2015 00:12:06 +1200 Subject: [PATCH 25/55] Have the command sticks disappear when disconnecting or switch to CLI --- tabs/receiver.js | 11 +++++++++-- tabs/receiver_msp.js | 7 +++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tabs/receiver.js b/tabs/receiver.js index 9e08e321..019c3465 100644 --- a/tabs/receiver.js +++ b/tabs/receiver.js @@ -326,8 +326,15 @@ TABS.receiver.initialize = function (callback) { maxWidth: windowWidth, maxHeight: windowHeight } }, function(createdWindow) { - // Give the window a callback it can use to access our MSP object to send to CF - createdWindow.contentWindow.setRawRx = MSP.setRawRx; + // Give the window a callback it can use to send the channels (otherwise it can't see those objects) + createdWindow.contentWindow.setRawRx = function(channels) { + if (CONFIGURATOR.connectionValid && GUI.active_tab != 'cli') { + MSP.setRawRx(channels); + return true; + } else { + return false; + } + } }); }); diff --git a/tabs/receiver_msp.js b/tabs/receiver_msp.js index 91fd9c24..2cb2c353 100644 --- a/tabs/receiver_msp.js +++ b/tabs/receiver_msp.js @@ -53,7 +53,10 @@ function transmitChannels() { } // Callback given to us by the window creator so we can have it send data over MSP for us: - window.setRawRx(channelValues); + if (!window.setRawRx(channelValues)) { + // MSP connection has gone away + chrome.app.window.current().close(); + } } function stickPortionToChannelValue(portion) { @@ -178,5 +181,5 @@ $(document).ready(function() { updateControlPositions(); - setInterval(transmitChannels, 100); + setInterval(transmitChannels, 50); }); \ No newline at end of file From e3e28a3c37174109fcd53627ebabfddce34afd35 Mon Sep 17 00:00:00 2001 From: Nicholas Sherlock Date: Fri, 25 Sep 2015 00:59:54 +1200 Subject: [PATCH 26/55] Make joystick window always-on-top to avoid Chrome scheduling penalty Chrome severely reduces the interval of setInterval() calls when a window is completely hidden (e.g. behind the main Configurator window). This causes rx loss / failsafe detection to trigger when using the RX_MSP joysticks --- manifest.json | 3 ++- tabs/receiver.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/manifest.json b/manifest.json index ba921616..3051e9bd 100644 --- a/manifest.json +++ b/manifest.json @@ -31,7 +31,8 @@ "fileSystem", "fileSystem.write", "fileSystem.retainEntries", - "notifications" + "notifications", + "alwaysOnTopWindows" ], "optional_permissions": [ diff --git a/tabs/receiver.js b/tabs/receiver.js index 019c3465..3c104b08 100644 --- a/tabs/receiver.js +++ b/tabs/receiver.js @@ -324,7 +324,8 @@ TABS.receiver.initialize = function (callback) { minWidth: windowWidth, minHeight: windowHeight, width: windowWidth, height: windowHeight, maxWidth: windowWidth, maxHeight: windowHeight - } + }, + alwaysOnTop: true }, function(createdWindow) { // Give the window a callback it can use to send the channels (otherwise it can't see those objects) createdWindow.contentWindow.setRawRx = function(channels) { From 4d959d7b93abd0be6c7f46fbe0ccdfffd8854f9e Mon Sep 17 00:00:00 2001 From: "Austin St. Aubin" Date: Tue, 29 Sep 2015 23:36:07 -0500 Subject: [PATCH 27/55] Edits for adding Roll, Pitch, and Heading to Setup Page --- _locales/en/messages.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 91e33056..b793f5b2 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -372,8 +372,8 @@ "initialSetupModel": { "message": "Model: $1" }, - "initialSetupHeading": { - "message": "Heading: $1 deg" + "initialSetupAttitude": { + "message": "$1 deg" }, "initialSetupAccelCalibStarted": { "message": "Accelerometer calibration started" @@ -426,7 +426,7 @@ "configurationFeaturesHelp": { "message": "Note: Not all combinations of features are valid. When the flight controller firmware detects invalid feature combinations conflicting features will be disabled.
Note: Configure serial ports before enabling the features that will use the ports." }, - + "configurationSerialRXHelp": { "message": "Note: Rememer to configure a Serial Port (via Ports tab) and choose a Serial Receiver Provider when using RX_SERIAL feature." }, @@ -460,7 +460,7 @@ }, "configurationDisarmKillSwitch": { "message": "Disarm motors regardless of throttle value (When arming via AUX channel)" - }, + }, "configurationThrottleMinimum": { "message": "Minimum Throttle" }, @@ -509,7 +509,7 @@ "configurationLoopTime": { "message": "Flight Controller Loop Time" }, - "configurationCalculatedCyclesSec": { + "configurationCalculatedCyclesSec": { "message": "Cycles/Sec (Hz)" }, "configurationLoopTimeHelp": { From 53f99760c7272a9545fb3744eb55871f146b5472 Mon Sep 17 00:00:00 2001 From: "Austin St. Aubin" Date: Tue, 29 Sep 2015 23:37:53 -0500 Subject: [PATCH 28/55] Formatting changes to add Roll, Pitch & Heading --- tabs/setup.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tabs/setup.html b/tabs/setup.html index 9168ebf7..837a7859 100644 --- a/tabs/setup.html +++ b/tabs/setup.html @@ -25,7 +25,13 @@
- +
+
+
Heading:
 
+
Pitch:
 
+
Roll:
 
+
+
From f62cf8defb68554d1536ee5fe00f47aac2c66bd7 Mon Sep 17 00:00:00 2001 From: "Austin St. Aubin" Date: Tue, 29 Sep 2015 23:38:23 -0500 Subject: [PATCH 29/55] Code edit to add Roll, Pitch & Heading --- tabs/setup.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tabs/setup.js b/tabs/setup.js index 875d1a47..5602d79d 100644 --- a/tabs/setup.js +++ b/tabs/setup.js @@ -47,8 +47,13 @@ TABS.setup.initialize = function (callback) { // initialize 3D self.initialize3D(); + // set roll in interactive block + $('span.roll').text(chrome.i18n.getMessage('initialSetupAttitude', [0])); + // set pitch in interactive block + $('span.pitch').text(chrome.i18n.getMessage('initialSetupAttitude', [0])); // set heading in interactive block - $('span.heading').text(chrome.i18n.getMessage('initialSetupheading', [0])); + $('span.heading').text(chrome.i18n.getMessage('initialSetupAttitude', [0])); + // check if we have magnetometer if (!bit_check(CONFIG.activeSensors, 2)) { @@ -151,7 +156,9 @@ TABS.setup.initialize = function (callback) { gpsSats_e = $('.gpsSats'), gpsLat_e = $('.gpsLat'), gpsLon_e = $('.gpsLon'), - heading_e = $('span.heading'); + roll_e = $('dd.roll'), + pitch_e = $('dd.pitch'), + heading_e = $('dd.heading'); function get_slow_data() { MSP.send_message(MSP_codes.MSP_STATUS); @@ -175,7 +182,9 @@ TABS.setup.initialize = function (callback) { function get_fast_data() { MSP.send_message(MSP_codes.MSP_ATTITUDE, false, false, function () { - heading_e.text(chrome.i18n.getMessage('initialSetupheading', [SENSOR_DATA.kinematics[2]])); + roll_e.text(chrome.i18n.getMessage('initialSetupAttitude', [SENSOR_DATA.kinematics[0]])); + pitch_e.text(chrome.i18n.getMessage('initialSetupAttitude', [SENSOR_DATA.kinematics[1]])); + heading_e.text(chrome.i18n.getMessage('initialSetupAttitude', [SENSOR_DATA.kinematics[2]])); self.render3D(); self.updateInstruments(); }); From cf3d8ae798a03b26268129726ba28d55b74fa4fb Mon Sep 17 00:00:00 2001 From: "Austin St. Aubin" Date: Tue, 29 Sep 2015 23:40:12 -0500 Subject: [PATCH 30/55] Formatting changes to add Roll, Pitch, and Heading to Setup Tab --- tabs/setup.css | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/tabs/setup.css b/tabs/setup.css index f5b3fc64..81a7fbfc 100644 --- a/tabs/setup.css +++ b/tabs/setup.css @@ -68,12 +68,23 @@ border: 1px solid silver; background-color: white; } -.tab-setup #interactive_block .heading { +.tab-setup #interactive_block .attitude { float: right; - height: 15px; + margin: 10px 10px 0px 0px +} - margin: 10px 10px 0 0; - font-weight: bold; +.tab-setup #interactive_block .attitude dt { + float: left; + width: 64px; + font-weight: 700; + text-align: right +} + +.tab-setup #interactive_block .attitude dd { + display: block; + margin-left: 64px; + width: 64px; + text-align: right } .tab-setup #interactive_block a.reset { position: absolute; From eeb45e63df492987db99d4493c2da7b0ac890b86 Mon Sep 17 00:00:00 2001 From: "Austin St. Aubin" Date: Tue, 29 Sep 2015 23:45:53 -0500 Subject: [PATCH 31/55] Formatting Fixes --- _locales/en/messages.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index b793f5b2..1ad53f05 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -426,7 +426,7 @@ "configurationFeaturesHelp": { "message": "Note: Not all combinations of features are valid. When the flight controller firmware detects invalid feature combinations conflicting features will be disabled.
Note: Configure serial ports before enabling the features that will use the ports." }, - + "configurationSerialRXHelp": { "message": "Note: Rememer to configure a Serial Port (via Ports tab) and choose a Serial Receiver Provider when using RX_SERIAL feature." }, @@ -460,7 +460,7 @@ }, "configurationDisarmKillSwitch": { "message": "Disarm motors regardless of throttle value (When arming via AUX channel)" - }, + }, "configurationThrottleMinimum": { "message": "Minimum Throttle" }, @@ -509,7 +509,7 @@ "configurationLoopTime": { "message": "Flight Controller Loop Time" }, - "configurationCalculatedCyclesSec": { + "configurationCalculatedCyclesSec": { "message": "Cycles/Sec (Hz)" }, "configurationLoopTimeHelp": { From 55531741cdf8760aea7e2beda60f436e54913d6e Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Fri, 2 Oct 2015 19:10:50 +0100 Subject: [PATCH 32/55] Update script for vtail mixer. --- support/svg_model_motors.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/support/svg_model_motors.rb b/support/svg_model_motors.rb index 97ee4f17..e2aea439 100755 --- a/support/svg_model_motors.rb +++ b/support/svg_model_motors.rb @@ -315,10 +315,10 @@ def render_vtail m.draw_body 100,180,140,160 m.draw_body 100,180,60,160 m.end_body - m.draw_circle 140,160,"1",Model::CW,Model::SE - m.draw_circle 160,40,"2",Model::CCW,Model::NE - m.draw_circle 60,160,"3",Model::CCW,Model::SW - m.draw_circle 40,40,"4",Model::CW,Model::NW + m.draw_circle 140,160,"1",Model::CCW,Model::SE + m.draw_circle 160,40,"2",Model::CW,Model::NE + m.draw_circle 60,160,"3",Model::CW,Model::SW + m.draw_circle 40,40,"4",Model::CCW,Model::NW m.draw_dirn m.close end From b698169d20101d36a2f9189f5216caa76e16d746 Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Fri, 2 Oct 2015 21:01:08 +0100 Subject: [PATCH 33/55] Prepare for release --- js/data_storage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/data_storage.js b/js/data_storage.js index 85dd9035..2be98490 100755 --- a/js/data_storage.js +++ b/js/data_storage.js @@ -1,7 +1,7 @@ 'use strict'; var CONFIGURATOR = { - 'releaseDate': 1436749724786, // new Date().getTime() - Mon Jul 13 2015 02:08:27 GMT+0100 + 'releaseDate': 1443815435720, // new Date().getTime() - Fri Oct 02 2015 20:50:49 GMT+0100 (GMT Daylight Time) // all versions are specified and compared using semantic versioning http://semver.org/ 'apiVersionAccepted': '1.2.0', From ddeaceaf60d93c5afaad669b04669f1a6345adaa Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Fri, 2 Oct 2015 21:01:35 +0100 Subject: [PATCH 34/55] Bump jQuery libraries. --- js/libraries/jquery-2.1.3.min.js | 4 ---- js/libraries/jquery-2.1.3.min.map | 1 - js/libraries/jquery-2.1.4.min.js | 4 ++++ js/libraries/jquery-2.1.4.min.map | 1 + js/libraries/jquery-ui-1.11.4.min.js | 13 +++++++++++++ main.html | 4 ++-- 6 files changed, 20 insertions(+), 7 deletions(-) delete mode 100644 js/libraries/jquery-2.1.3.min.js delete mode 100644 js/libraries/jquery-2.1.3.min.map create mode 100644 js/libraries/jquery-2.1.4.min.js create mode 100644 js/libraries/jquery-2.1.4.min.map create mode 100644 js/libraries/jquery-ui-1.11.4.min.js diff --git a/js/libraries/jquery-2.1.3.min.js b/js/libraries/jquery-2.1.3.min.js deleted file mode 100644 index 25714ed2..00000000 --- a/js/libraries/jquery-2.1.3.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v2.1.3 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ -!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.3",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)+1>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=hb(),z=hb(),A=hb(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N=M.replace("w","w#"),O="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+N+"))|)"+L+"*\\]",P=":("+M+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+O+")*)|.*)\\)|)",Q=new RegExp(L+"+","g"),R=new RegExp("^"+L+"+|((?:^|[^\\\\])(?:\\\\.)*)"+L+"+$","g"),S=new RegExp("^"+L+"*,"+L+"*"),T=new RegExp("^"+L+"*([>+~]|"+L+")"+L+"*"),U=new RegExp("="+L+"*([^\\]'\"]*?)"+L+"*\\]","g"),V=new RegExp(P),W=new RegExp("^"+N+"$"),X={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+O),PSEUDO:new RegExp("^"+P),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+K+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+L+"?|("+L+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},eb=function(){m()};try{H.apply(E=I.call(v.childNodes),v.childNodes),E[v.childNodes.length].nodeType}catch(fb){H={apply:E.length?function(a,b){G.apply(a,I.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function gb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],k=b.nodeType,"string"!=typeof a||!a||1!==k&&9!==k&&11!==k)return d;if(!e&&p){if(11!==k&&(f=_.exec(a)))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return H.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName)return H.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=1!==k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+rb(o[l]);w=ab.test(a)&&pb(b.parentNode)||b,x=o.join(",")}if(x)try{return H.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function hb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ib(a){return a[u]=!0,a}function jb(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function kb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function lb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||C)-(~a.sourceIndex||C);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function nb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function ob(a){return ib(function(b){return b=+b,ib(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function pb(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=gb.support={},f=gb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=gb.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=g.documentElement,e=g.defaultView,e&&e!==e.top&&(e.addEventListener?e.addEventListener("unload",eb,!1):e.attachEvent&&e.attachEvent("onunload",eb)),p=!f(g),c.attributes=jb(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=jb(function(a){return a.appendChild(g.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(g.getElementsByClassName),c.getById=jb(function(a){return o.appendChild(a).id=u,!g.getElementsByName||!g.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(g.querySelectorAll))&&(jb(function(a){o.appendChild(a).innerHTML="",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+L+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+L+"*(?:value|"+K+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),jb(function(a){var b=g.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+L+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&jb(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",P)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===g||a.ownerDocument===v&&t(v,a)?-1:b===g||b.ownerDocument===v&&t(v,b)?1:k?J(k,a)-J(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,h=[a],i=[b];if(!e||!f)return a===g?-1:b===g?1:e?-1:f?1:k?J(k,a)-J(k,b):0;if(e===f)return lb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?lb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},g):n},gb.matches=function(a,b){return gb(a,null,null,b)},gb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return gb(b,n,null,[a]).length>0},gb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},gb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&D.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},gb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},gb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=gb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=gb.selectors={cacheLength:50,createPseudo:ib,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||gb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&gb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+L+")"+a+"("+L+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=gb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(Q," ")+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||gb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ib(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=J(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ib(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?ib(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ib(function(a){return function(b){return gb(a,b).length>0}}),contains:ib(function(a){return a=a.replace(cb,db),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ib(function(a){return W.test(a||"")||gb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:ob(function(){return[0]}),last:ob(function(a,b){return[b-1]}),eq:ob(function(a,b,c){return[0>c?c+b:c]}),even:ob(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:ob(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:ob(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:ob(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function sb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function tb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function ub(a,b,c){for(var d=0,e=b.length;e>d;d++)gb(a,b[d],c);return c}function vb(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function wb(a,b,c,d,e,f){return d&&!d[u]&&(d=wb(d)),e&&!e[u]&&(e=wb(e,f)),ib(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||ub(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:vb(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=vb(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?J(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=vb(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):H.apply(g,r)})}function xb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=sb(function(a){return a===b},h,!0),l=sb(function(a){return J(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];f>i;i++)if(c=d.relative[a[i].type])m=[sb(tb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return wb(i>1&&tb(m),i>1&&rb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&xb(a.slice(i,e)),f>e&&xb(a=a.slice(e)),f>e&&rb(a))}m.push(c)}return tb(m)}function yb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=F.call(i));s=vb(s)}H.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&gb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?ib(f):f}return h=gb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=xb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,yb(e,d)),f.selector=a}return f},i=gb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&pb(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&rb(j),!a)return H.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&pb(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=jb(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),jb(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||kb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&jb(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||kb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),jb(function(a){return null==a.getAttribute("disabled")})||kb(K,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),gb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+K.uid++}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c) -},removeData:function(a,b){M.remove(a,b)},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthx",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*\s*$/g,ib={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("