From 902da2f91dd9889c3d359695223c9bdb9e1beb5b Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Sun, 9 Nov 2014 00:46:12 +0000 Subject: [PATCH] Add 'Adjustments' tab. Cleanup 'Auxilary' tab code. Rename other tabs to have shorter titles. --- _locales/en/messages.json | 112 ++++++++++++- js/data_storage.js | 1 + js/msp.js | 26 +++ main.html | 15 +- main.js | 5 +- tabs/adjustments.css | 125 ++++++++++++++ tabs/adjustments.html | 94 +++++++++++ tabs/adjustments.js | 266 ++++++++++++++++++++++++++++++ tabs/auxiliary_configuration.css | 4 +- tabs/auxiliary_configuration.html | 2 +- tabs/auxiliary_configuration.js | 21 ++- 11 files changed, 643 insertions(+), 28 deletions(-) create mode 100644 tabs/adjustments.css create mode 100644 tabs/adjustments.html create mode 100644 tabs/adjustments.js diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 97486a96..980ad92f 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -36,30 +36,33 @@ "message": "Initial Setup" }, "tab2": { - "message": "PID Tuning" + "message": "PID" }, "tab3": { "message": "Receiver" }, "tab4": { - "message": "Auxiliary Configuration" + "message": "Auxiliary" }, "tab5": { - "message": "Servos" + "message": "Adjustments" }, "tab6": { - "message": "GPS" + "message": "Servos" }, "tab7": { - "message": "Motor Testing" + "message": "GPS" }, "tab8": { - "message": "Raw Sensor Data" + "message": "Motors" }, "tab9": { - "message": "CLI" + "message": "Sensors" }, "tab10": { + "message": "CLI" + }, + "tab11": { "message": "Logging" }, @@ -370,6 +373,101 @@ "message": "EEPROM saved" }, + "adjustmentsHelp": { + "message": "Configure adjustment switches. See the 'in-flight adjustments' section of the manual for details. The changes that adjustment functions make are not saved automatically. There are 4 slots. Each switch used to concurrently make adjustments requires exclusive use of a slot." + }, + "adjustmentsExamples": { + "message": "Examples" + }, + "adjustmentsExample1": { + "message": "Use Slot 1 and a 3POS switch on AUX1 to select between Pitch/Roll P, I and D and another 3POS switch on AUX2 to increase or decrease the value when held up or down." + }, + "adjustmentsExample2": { + "message": "Use Slot 2 and a 3POS switch on AUX4 to select enable Rate Profile Selection via the same 3POS switch on the same channel." + }, + "adjustmentsColumnEnable": { + "message": "If enabled" + }, + "adjustmentsColumnUsingSlot": { + "message": "using slot" + }, + "adjustmentsColumnWhenChannel": { + "message": "when channel" + }, + "adjustmentsColumnIsInRange": { + "message": "is in range" + }, + "adjustmentsColumnThenApplyFunction": { + "message": "then apply" + }, + "adjustmentsColumnViaChannel": { + "message": "via channel" + }, + "adjustmentsSlot0": { + "message": "Slot 1" + }, + "adjustmentsSlot1": { + "message": "Slot 2" + }, + "adjustmentsSlot2": { + "message": "Slot 3" + }, + "adjustmentsSlot3": { + "message": "Slot 4" + }, + "adjustmentsMin": { + "message": "Min" + }, + "adjustmentsMax": { + "message": "Max" + }, + "adjustmentsFunction0": { + "message": "No changes" + }, + "adjustmentsFunction1": { + "message": "RC Rate Adjustment" + }, + "adjustmentsFunction2": { + "message": "RC Expo Adjustment" + }, + "adjustmentsFunction3": { + "message": "Throttle Expo Adjustment" + }, + "adjustmentsFunction4": { + "message": "Pitch & Roll Rate Adjustment" + }, + "adjustmentsFunction5": { + "message": "Yaw Rate Adjustment" + }, + "adjustmentsFunction6": { + "message": "Pitch P Adjustment" + }, + "adjustmentsFunction7": { + "message": "Pitch I Adjustment" + }, + "adjustmentsFunction8": { + "message": "Pitch D Adjustment" + }, + "adjustmentsFunction9": { + "message": "Yaw P Adjustment" + }, + "adjustmentsFunction10": { + "message": "Yaw I Adjustment" + }, + "adjustmentsFunction11": { + "message": "Yaw D Adjustment" + }, + "adjustmentsFunction12": { + "message": "Rate Profile Selection" + }, + "adjustmentsSave": { + "message": "Save" + }, + "adjustmentsEepromSaved": { + "message": "EEPROM saved" + }, + + "servosModel": { "message": "Model:" }, diff --git a/js/data_storage.js b/js/data_storage.js index 17eb9510..8fdb5c74 100644 --- a/js/data_storage.js +++ b/js/data_storage.js @@ -54,6 +54,7 @@ var AUX_CONFIG = []; var AUX_CONFIG_IDS = []; var MODE_RANGES = []; +var ADJUSTMENT_RANGES = []; var SERVO_CONFIG = []; diff --git a/js/msp.js b/js/msp.js index 3dca7b92..75542caf 100644 --- a/js/msp.js +++ b/js/msp.js @@ -9,6 +9,9 @@ var MSP_codes = { MSP_SET_CHANNEL_FORWARDING: 33, MSP_MODE_RANGES: 34, MSP_SET_MODE_RANGE: 35, + MSP_ADJUSTMENT_RANGES: 52, + MSP_SET_ADJUSTMENT_RANGE: 53, + // Multiwii MSP commands MSP_IDENT: 100, @@ -321,6 +324,26 @@ MSP.process_data = function(code, message_buffer, message_length) { MODE_RANGES.push(modeRange); } break; + case MSP_codes.MSP_ADJUSTMENT_RANGES: + ADJUSTMENT_RANGES = []; // empty the array as new data is coming in + + var adjustmentRangeCount = data.byteLength / 6; // 6 bytes per item. + + var offset = 0; + for (var i = 0; offset < data.byteLength && i < adjustmentRangeCount; i++) { + var adjustmentRange = { + slotIndex: data.getUint8(offset++, 1), + auxChannelIndex: data.getUint8(offset++, 1), + range: { + start: 900 + (data.getUint8(offset++, 1) * 25), + end: 900 + (data.getUint8(offset++, 1) * 25) + }, + adjustmentFunction: data.getUint8(offset++, 1), + auxSwitchChannelIndex: data.getUint8(offset++, 1) + }; + ADJUSTMENT_RANGES.push(adjustmentRange); + } + break; case MSP_codes.MSP_MISC: // 22 bytes MISC.PowerTrigger1 = data.getInt16(0, 1); MISC.minthrottle = data.getUint16(2, 1); // 0-2000 @@ -407,6 +430,9 @@ MSP.process_data = function(code, message_buffer, message_length) { case MSP_codes.MSP_SET_MODE_RANGE: console.log('Mode range saved'); break; + case MSP_codes.MSP_SET_ADJUSTMENT_RANGE: + console.log('Adjustment range saved'); + break; case MSP_codes.MSP_SET_BOX: console.log('AUX Configuration saved'); break; diff --git a/main.html b/main.html index ec8a9a9a..37c4eec4 100644 --- a/main.html +++ b/main.html @@ -13,6 +13,7 @@ + @@ -46,6 +47,7 @@ + @@ -108,12 +110,13 @@
  • -
  • -
  • -
  • -
  • -
  • -
  • +
  • +
  • +
  • +
  • +
  • +
  • +
  • diff --git a/main.js b/main.js index ca8fbe7e..4fcfac1d 100644 --- a/main.js +++ b/main.js @@ -94,6 +94,9 @@ $(document).ready(function () { case 'tab_auxiliary_configuration': TABS.auxiliary_configuration.initialize(content_ready); break; + case 'tab_adjustments': + TABS.adjustments.initialize(content_ready); + break; case 'tab_servos': TABS.servos.initialize(content_ready); break; @@ -270,4 +273,4 @@ function bytesToSize(bytes) { } return bytes; -} \ No newline at end of file +} diff --git a/tabs/adjustments.css b/tabs/adjustments.css new file mode 100644 index 00000000..caea58c1 --- /dev/null +++ b/tabs/adjustments.css @@ -0,0 +1,125 @@ +.tab-adjustments { +} + +#tab-adjustments-templates { + display: none; +} + +.tab-adjustments .help { + padding: 10px; + background-color: #ffcb18; + margin-bottom: 10px; +} + +.tab-adjustments .help p { + padding-bottom: 5px; +} + +.tab-adjustments .help li { + list-style-type: decimal; + margin-left: 20px; +} + +.tab-adjustments .adjustments { + width: 100%; + border-spacing: 0px; +} + +.tab-adjustments .adjustments thead td { + text-align: center; + white-space: nowrap; + padding: 10px 10px; + background-color: #61B665; + +} + +.tab-adjustments .adjustment { + background-color: #ececec; +} + +.tab-adjustments .adjustment:nth-child(odd) { + background-color: #ffffff; +} + +.tab-adjustments .adjustment select { + outline: 1px solid silver; +} + +.tab-adjustments .adjustment td { + text-align: center; +} + +.tab-adjustments .adjustment .info { + width: 5%; + height: 80px; +} + +.tab-adjustments .adjustment .info .enabling { + white-space: nowrap; +} + +.tab-adjustments .adjustment .channelInfo { + width: 5%; + padding: 0px 10px; +} + +.tab-adjustments .adjustment .channelInfo .limits { + padding: 10px 0px; +} + +.tab-adjustments .adjustment .range { + width: 65%; + padding: 0px 20px; +} + +.tab-adjustments .adjustment .range .channel-slider { + margin-top: -28px; +} + +.tab-adjustments .adjustment .range .marker { + position: absolute; + left: 50%; + top: 27px; + height: 13px; + width: 6px; + margin-left: -3px; +} + +.tab-adjustments .adjustment .functionSelection { + width: 5%; +} + +.tab-adjustments .adjustment .adjustmentSlot { + width: 5%; +} + +.tab-adjustments .adjustment .functionSwitchChannel { + width: 5%; +} + +.tab-adjustments > .buttons { + width: calc(100% - 20px); + + margin-top: 10px; + bottom: 10px; +} + +.tab-adjustments > .buttons a { + float: right; + height: 28px; + line-height: 28px; + padding: 0 15px 0 15px; + display: block; +} + +.tab-adjustments .buttons a { + text-align: center; + font-weight: bold; + + border: 1px solid silver; + background-color: #ececec; +} + +.tab-adjustments .buttons a:hover { + background-color: #dedcdc; +} \ No newline at end of file diff --git a/tabs/adjustments.html b/tabs/adjustments.html new file mode 100644 index 00000000..65ef2737 --- /dev/null +++ b/tabs/adjustments.html @@ -0,0 +1,94 @@ +
    +
    +

    +

    +
      +
    • +
    • +
    +
    + + + + + + + + + + + + + +
    + + + + + +
    + +
    + +
    +
    + +
    + + + + + + + + + + + +
    +
    + +
    +
    +
    + +
    +
    +

    :

    +

    :

    +
    +
    +
    +
    +
    +
    + + + + + +
    +
    diff --git a/tabs/adjustments.js b/tabs/adjustments.js new file mode 100644 index 00000000..6ff9cf1d --- /dev/null +++ b/tabs/adjustments.js @@ -0,0 +1,266 @@ +'use strict'; + +TABS.adjustments = {}; +TABS.adjustments.initialize = function (callback) { + GUI.active_tab_ref = this; + GUI.active_tab = 'adjustments'; + googleAnalytics.sendAppView('Adjustments'); + + function get_adjustment_ranges() { + MSP.send_message(MSP_codes.MSP_ADJUSTMENT_RANGES, false, false, get_box_ids); + } + + function get_box_ids() { + MSP.send_message(MSP_codes.MSP_BOXIDS, false, false, get_rc_data); + } + + function get_rc_data() { + MSP.send_message(MSP_codes.MSP_RC, false, false, load_html); + } + + function load_html() { + $('#content').load("./tabs/adjustments.html", process_html); + } + + MSP.send_message(MSP_codes.MSP_BOXNAMES, false, false, get_adjustment_ranges); + + function addAdjustment(adjustmentIndex, adjustmentRange, auxChannelCount) { + + var template = $('#tab-adjustments-templates .adjustments .adjustment'); + var newAdjustment = template.clone(); + + $(newAdjustment).attr('id', 'adjustment-' + adjustmentIndex); + $(newAdjustment).data('index', adjustmentIndex); + + // + // update selected slot + // + + var channelList = $(newAdjustment).find('.adjustmentSlot .slot'); + channelList.val(adjustmentRange.slotIndex); + + // + // populate source channel select box + // + + var channelList = $(newAdjustment).find('.channelInfo .channel'); + var channelOptionTemplate = $(channelList).find('option'); + channelOptionTemplate.remove(); + for (var channelIndex = 0; channelIndex < auxChannelCount; channelIndex++) { + var channelOption = channelOptionTemplate.clone(); + channelOption.text('AUX ' + (channelIndex + 1)); + channelOption.val(channelIndex); + channelList.append(channelOption); + } + channelList.val(adjustmentRange.auxChannelIndex); + + // + // update selected function + // + + var channelList = $(newAdjustment).find('.functionSelection .function'); + channelList.val(adjustmentRange.adjustmentFunction); + + // + // populate function channel select box + // + + var channelList = $(newAdjustment).find('.functionSwitchChannel .channel'); + var channelOptionTemplate = $(channelList).find('option'); + channelOptionTemplate.remove(); + for (var channelIndex = 0; channelIndex < auxChannelCount; channelIndex++) { + var channelOption = channelOptionTemplate.clone(); + channelOption.text('AUX ' + (channelIndex + 1)); + channelOption.val(channelIndex); + channelList.append(channelOption); + } + channelList.val(adjustmentRange.auxSwitchChannelIndex); + + // + // configure range + // + + var channel_range = { + 'min': [ 900 ], + 'max': [ 2100 ] + }; + + var rangeValues = [900, 2100]; // select the full range by default + if (adjustmentRange.range != undefined) { + rangeValues = [adjustmentRange.range.start, adjustmentRange.range.end]; + } + + var rangeElement = $(newAdjustment).find('.range'); + + $(rangeElement).find('.channel-slider').noUiSlider({ + start: rangeValues, + behaviour: 'snap-drag', + step: 25, + connect: true, + range: channel_range, + format: wNumb({ + decimals: 0, + }) + }); + + var elementName = '#adjustment-' + adjustmentIndex; + $(newAdjustment).find('.channel-slider').Link('lower').to($(newAdjustment).find('.lowerLimitValue')); + $(newAdjustment).find('.channel-slider').Link('upper').to($(newAdjustment).find('.upperLimitValue')); + + $(rangeElement).find(".pips-channel-range").noUiSlider_pips({ + mode: 'values', + values: [900, 1000, 1200, 1400, 1500, 1600, 1800, 2000, 2100], + density: 4, + stepped: true + }); + + // + // add the enable/disable behavior + // + + var enableElement = $(newAdjustment).find('.enable'); + $(enableElement).data('adjustmentElement', newAdjustment); + $(enableElement).change(function() { + var adjustmentElement = $(this).data('adjustmentElement'); + if ($(this).prop("checked")) { + $(adjustmentElement).find(':input').prop("disabled", false); + $(adjustmentElement).find('.channel-slider').removeAttr("disabled"); + } else { + $(adjustmentElement).find(':input').prop("disabled", true); + $(adjustmentElement).find('.channel-slider').attr("disabled", "disabled"); + } + + // keep this element enabled + $(this).prop("disabled", false); + }); + + var isEnabled = (adjustmentRange.range.start != adjustmentRange.range.end); + $(enableElement).prop("checked", isEnabled).change(); + + return newAdjustment; + } + + function process_html() { + + var auxChannelCount = RC.active_channels - 4; + + var modeTableBodyElement = $('.tab-adjustments .adjustments tbody') + for (var adjustmentIndex = 0; adjustmentIndex < ADJUSTMENT_RANGES.length; adjustmentIndex++) { + var newAdjustment = addAdjustment(adjustmentIndex, ADJUSTMENT_RANGES[adjustmentIndex], auxChannelCount); + modeTableBodyElement.append(newAdjustment); + } + + // translate to user-selected language + localize(); + + // UI Hooks + $('a.save').click(function () { + + // update internal data structures based on current UI elements + var requiredAdjustmentRangeCount = ADJUSTMENT_RANGES.length; + + ADJUSTMENT_RANGES = []; + + var defaultAdjustmentRange = { + slotIndex: 0, + auxChannelIndex: 0, + range: { + start: 900, + end: 900 + }, + adjustmentFunction: 0, + auxSwitchChannelIndex: 0 + }; + + $('.adjustments .adjustment').each(function () { + var adjustmentElement = $(this); + + if ($(adjustmentElement).find('.enable').prop("checked")) { + var rangeValues = $(this).find('.range .channel-slider').val(); + var adjustmentRange = { + slotIndex: parseInt($(this).find('.adjustmentSlot .slot').val()), + auxChannelIndex: parseInt($(this).find('.channelInfo .channel').val()), + range: { + start: rangeValues[0], + end: rangeValues[1] + }, + adjustmentFunction: parseInt($(this).find('.functionSelection .function').val()), + auxSwitchChannelIndex: parseInt($(this).find('.functionSwitchChannel .channel').val()), + }; + ADJUSTMENT_RANGES.push(adjustmentRange); + } else { + ADJUSTMENT_RANGES.push(defaultAdjustmentRange); + } + }); + + for (var adjustmentRangeIndex = ADJUSTMENT_RANGES.length; adjustmentRangeIndex < requiredAdjustmentRangeCount; adjustmentRangeIndex++) { + ADJUSTMENT_RANGES.push(defaultAdjustmentRange); + } + + // + // send data to FC + // + + var nextFunction = send_next_adjustment_range; + + var adjustmentRangeIndex = 0; + + send_next_adjustment_range(); + + + function send_next_adjustment_range() { + + 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); + + // prepare for next iteration + adjustmentRangeIndex++; + if (adjustmentRangeIndex == requiredAdjustmentRangeCount) { + nextFunction = save_to_eeprom; + + } + MSP.send_message(MSP_codes.MSP_SET_ADJUSTMENT_RANGE, ADJUSTMENT_val_buffer_out, false, nextFunction); + } + + function save_to_eeprom() { + MSP.send_message(MSP_codes.MSP_EEPROM_WRITE, false, false, function () { + GUI.log(chrome.i18n.getMessage('adjustmentsEepromSaved')); + }); + } + + }); + + // data pulling functions used inside interval timer + function get_rc_data() { + MSP.send_message(MSP_codes.MSP_RC, false, false, update_ui); + } + + function update_ui() { + } + + // update ui instantly on first load + update_ui(); + + // enable data pulling + GUI.interval_add('aux_data_pull', get_rc_data, 50); + + // status data pulled via separate timer with static speed + GUI.interval_add('status_pull', function () { + MSP.send_message(MSP_codes.MSP_STATUS); + }, 250, true); + + if (callback) callback(); + } +}; + +TABS.adjustments.cleanup = function (callback) { + if (callback) callback(); +}; \ No newline at end of file diff --git a/tabs/auxiliary_configuration.css b/tabs/auxiliary_configuration.css index 2cc930d6..cf0bfe34 100644 --- a/tabs/auxiliary_configuration.css +++ b/tabs/auxiliary_configuration.css @@ -18,7 +18,7 @@ .tab-auxiliary_configuration .mode.on:nth-child(odd) .info { background: #BAE2BC; - } +} .tab-auxiliary_configuration .mode.off .info { background: #E86969; @@ -28,7 +28,7 @@ background: #E7AEAE; } -#templates { +#tab-auxiliary_configuration-templates { display: none; } diff --git a/tabs/auxiliary_configuration.html b/tabs/auxiliary_configuration.html index e38b6406..4a7f427a 100644 --- a/tabs/auxiliary_configuration.html +++ b/tabs/auxiliary_configuration.html @@ -11,7 +11,7 @@ -
    +
    diff --git a/tabs/auxiliary_configuration.js b/tabs/auxiliary_configuration.js index 73c2e9a4..5e22eca5 100644 --- a/tabs/auxiliary_configuration.js +++ b/tabs/auxiliary_configuration.js @@ -25,7 +25,7 @@ TABS.auxiliary_configuration.initialize = function (callback) { MSP.send_message(MSP_codes.MSP_BOXNAMES, false, false, get_mode_ranges); function createMode(modeIndex, modeId) { - var modeTemplate = $('#templates .mode'); + var modeTemplate = $('#tab-auxiliary_configuration-templates .mode'); var newMode = modeTemplate.clone(); var modeName = AUX_CONFIG[modeIndex]; @@ -43,7 +43,7 @@ TABS.auxiliary_configuration.initialize = function (callback) { function configureRangeTemplate(auxChannelCount) { - var rangeTemplate = $('#templates .range'); + var rangeTemplate = $('#tab-auxiliary_configuration-templates .range'); var channelList = $(rangeTemplate).find('.channel'); var channelOptionTemplate = $(channelList).find('option'); @@ -54,7 +54,7 @@ TABS.auxiliary_configuration.initialize = function (callback) { channelOption.val(channelIndex); channelList.append(channelOption); } - channelList.select(0); + channelList.val(0); } function addRangeToMode(modeElement, auxChannelIndex, range) { @@ -72,11 +72,11 @@ TABS.auxiliary_configuration.initialize = function (callback) { var rangeIndex = $(modeElement).find('.range').length; - var range = $('#templates .range').clone(); - range.attr('id', 'mode-' + modeIndex + '-range-' + rangeIndex); + var rangeElement = $('#tab-auxiliary_configuration-templates .range').clone(); + rangeElement.attr('id', 'mode-' + modeIndex + '-range-' + rangeIndex); modeElement.find('.ranges').append(range); - $(range).find('.channel-slider').noUiSlider({ + $(rangeElement).find('.channel-slider').noUiSlider({ start: rangeValues, behaviour: 'snap-drag', step: 25, @@ -91,7 +91,7 @@ TABS.auxiliary_configuration.initialize = function (callback) { $(elementName + ' .channel-slider').Link('lower').to($(elementName + ' .lowerLimitValue')); $(elementName + ' .channel-slider').Link('upper').to($(elementName + ' .upperLimitValue')); - $(range).find(".pips-channel-range").noUiSlider_pips({ + $(rangeElement).find(".pips-channel-range").noUiSlider_pips({ mode: 'values', values: [900, 1000, 1200, 1400, 1500, 1600, 1800, 2000, 2100], density: 4, @@ -110,8 +110,6 @@ TABS.auxiliary_configuration.initialize = function (callback) { } function process_html() { - - $('.boxes').hide(); var auxChannelCount = RC.active_channels - 4; @@ -180,7 +178,6 @@ TABS.auxiliary_configuration.initialize = function (callback) { MODE_RANGES = []; $('.modes .mode').each(function () { - //var _this = this; var modeElement = $(this); var modeId = modeElement.data('id'); @@ -210,8 +207,10 @@ TABS.auxiliary_configuration.initialize = function (callback) { }; MODE_RANGES.push(defaultModeRange); } - + + // // send data to FC + // var nextFunction = send_next_mode_range;