diff --git a/_locales/en/messages.json b/_locales/en/messages.json index bd6eb305..a9876707 100755 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -957,6 +957,18 @@ "pidTuningYawRate": { "message": "YAW rate" }, + "pidTuningMaxRollAngle": { + "message": "Max. ROLL angle" + }, + "pidTuningMaxRollAngleHelp": { + "message": "Maximum ROLL angle in ANGLE mode. This also constrains the maximum bank in navigation modes." + }, + "pidTuningMaxPitchAngle": { + "message": "Max. PITCH angle" + }, + "pidTuningMaxPitchAngleHelp": { + "message": "Maximum PITCH angle in ANGLE mode. This also constrains the maximum climb and dive in navigation modes." + }, "pidTuningManualRollRate": { "message": "Manual ROLL rate" }, @@ -2176,8 +2188,8 @@ "dtermNotchCutoffHelp": { "message": "Defines band of filter.

Has to be kept below notch filter frequency." }, - "positionHoldConfiguration": { - "message": "Basic Navigation Settings" + "multiRotorNavigationConfiguration": { + "message": "Multirotor Navigation Settings" }, "userControlMode": { "message": "User Control Mode" @@ -2195,7 +2207,10 @@ "message": "Max. ALTHOLD climb rate [cm/s]" }, "posholdMaxBankAngle": { - "message": "Multirotor max. banking angle [deg]" + "message": "Multirotor max. banking angle [degrees]" + }, + "posholdMaxBankAngleHelp": { + "message": "Maximum banking angle in navigation modes. Constrained by maximum ROLL angle in PID tuning tab." }, "posholdHoverThrottle": { "message": "Hover throttle" @@ -2300,22 +2315,34 @@ "message": "Max. throttle" }, "maxBankAngle": { - "message": "Max. bank angle" + "message": "Max. bank angle [degrees]" + }, + "maxBankAngleHelp": { + "message": "Maximum banking angle in navigation modes. Constrained by maximum ROLL angle in PID tuning tab." }, "maxClimbAngle": { - "message": "Max. climb angle" + "message": "Max. climb angle [degrees]" + }, + "maxClimbAngleHelp": { + "message": "Maximum climb angle in navigation modes. Constrained by maximum PITCH angle in PID tuning tab." }, "maxDiveAngle": { - "message": "Max. dive angle" + "message": "Max. dive angle [degrees]" + }, + "maxDiveAngleHelp": { + "message": "Maximum dive angle in navigation modes. Constrained by maximum PITCH angle in PID tuning tab." }, "pitchToThrottle": { "message": "Pitch to throttle ratio" }, + "pitchToThrottleHelp": { + "message": "In navigation modes, each degree of climb will add this many units to the cruise throttle. Conversely, each degree of diving will substract from it." + }, "loiterRadius": { "message": "Loiter radius [cm]" }, - "fixedWingConfiguration": { - "message": "Fixed Wing Settings" + "fixedWingNavigationConfiguration": { + "message": "Fixed Wing Navigation Settings" }, "osdLayoutDefault": { "message": "Default Layout" diff --git a/js/fc.js b/js/fc.js index 30704caf..af04a9f6 100644 --- a/js/fc.js +++ b/js/fc.js @@ -54,7 +54,8 @@ var CONFIG, DEBUG_TRACE, MIXER_CONFIG, BATTERY_CONFIG, - OUTPUT_MAPPING; + OUTPUT_MAPPING, + SETTINGS; var FC = { MAX_SERVO_RATE: 125, @@ -508,6 +509,8 @@ var FC = { RXFAIL_CONFIG = []; OUTPUT_MAPPING = new OutputMappingCollection(); + + SETTINGS = {}; }, getOutputUsages: function() { return { diff --git a/js/injected_methods.js b/js/injected_methods.js index 5bce5a18..9521f744 100644 --- a/js/injected_methods.js +++ b/js/injected_methods.js @@ -89,4 +89,16 @@ DataView.prototype.read32 = function() { } else { return null; } +}; + +DataView.prototype.readString = function() { + var s = ""; + while (this.byteLength > this.offset) { + var c = this.readU8(); + if (!c) { + break; + } + s += String.fromCharCode(c); + } + return s; }; \ No newline at end of file diff --git a/js/msp/MSPCodes.js b/js/msp/MSPCodes.js index a13d0720..a040eaeb 100644 --- a/js/msp/MSPCodes.js +++ b/js/msp/MSPCodes.js @@ -161,6 +161,9 @@ var MSPCodes = { MSP2_COMMON_MOTOR_MIXER: 0x1005, MSP2_COMMON_SET_MOTOR_MIXER: 0x1006, + MSP2_COMMON_SETTING_INFO: 0x1007, + MSP2_COMMON_PG_LIST: 0x1008, + MSPV2_INAV_STATUS: 0x2000, MSPV2_INAV_OPTICAL_FLOW: 0x2001, MSPV2_INAV_ANALOG: 0x2002, diff --git a/js/msp/MSPHelper.js b/js/msp/MSPHelper.js index 3e9406dc..e85d6bf6 100644 --- a/js/msp/MSPHelper.js +++ b/js/msp/MSPHelper.js @@ -1347,6 +1347,8 @@ var mspHelper = (function (gui) { break; case MSPCodes.MSPV2_SETTING: break; + case MSPCodes.MSP2_COMMON_SETTING_INFO: + break; case MSPCodes.MSPV2_SET_SETTING: console.log("Setting set"); break; @@ -2859,12 +2861,66 @@ var mspHelper = (function (gui) { }; self._getSetting = function (name) { + if (semver.lt(CONFIG.flightControllerVersion, '2.0.0')) { + return self._getLegacySetting(name); + } + if (SETTINGS[name]) { + return Promise.resolve(SETTINGS[name]); + } + var data = []; + self._encodeSettingReference(name, null, data); + return MSP.promise(MSPCodes.MSP2_COMMON_SETTING_INFO, data).then(function (result) { + const MODE_LOOKUP = 1 << 6; + var settingTypes = { + 0: "uint8_t", + 1: "int8_t", + 2: "uint16_t", + 3: "int16_t", + 4: "uint32_t", + 5: "float", + 6: "string", + }; + var setting = {}; + // Discard PG ID + result.data.readU16(); + + var type = result.data.readU8(); + setting.type = settingTypes[type]; + if (!setting.type) { + console.log("Unknown setting type " + type + " for setting '" + name + "'"); + return null; + } + // Discard section + result.data.readU8(); + setting.mode = result.data.readU8(); + setting.min = result.data.read32(); + setting.max = result.data.readU32(); + + setting.index = result.data.readU16(); + + // Discard profile info + result.data.readU8(); + result.data.readU8(); + + if (setting.mode == MODE_LOOKUP) { + var values = []; + for (var ii = setting.min; ii <= setting.max; ii++) { + values.push(result.data.readString()); + } + setting.table = {values: values}; + } + SETTINGS[name] = setting; + return setting; + }); + } + + + self._getLegacySetting = function (name) { var promise; - if (this._settings) { - promise = Promise.resolve(this._settings); + if (SETTINGS) { + promise = Promise.resolve(SETTINGS); } else { promise = new Promise(function (resolve, reject) { - var $this = this; $.ajax({ url: chrome.runtime.getURL('/resources/settings.json'), dataType: 'json', @@ -2872,7 +2928,7 @@ var mspHelper = (function (gui) { reject(error); }, success: function (data) { - $this._settings = data; + SETTINGS = data; resolve(data); } }); @@ -2883,19 +2939,24 @@ var mspHelper = (function (gui) { }); }; - self._encodeSettingName = function (name, data) { - for (var ii = 0; ii < name.length; ii++) { - data.push(name.charCodeAt(ii)); + self._encodeSettingReference = function (name, index, data) { + if (Number.isInteger(index)) { + data.push8(0); + data.push16(index); + } else { + for (var ii = 0; ii < name.length; ii++) { + data.push(name.charCodeAt(ii)); + } + data.push(0); } - data.push(0); }; - self.getSetting = function (name, callback) { + self.getSetting = function (name) { var $this = this; return this._getSetting(name).then(function (setting) { var data = []; - $this._encodeSettingName(name, data); - MSP.send_message(MSPCodes.MSPV2_SETTING, data, false, function (resp) { + $this._encodeSettingReference(name, setting.index, data); + return MSP.promise(MSPCodes.MSPV2_SETTING, data).then(function (resp) { var value; switch (setting.type) { case "uint8_t": @@ -2925,15 +2986,12 @@ var mspHelper = (function (gui) { if (setting.table) { value = setting.table.values[value]; } - if (callback) { - callback(value, setting); - } + return {setting: setting, value: value}; }); }); }; self.encodeSetting = function (name, value) { - var $this = this; return this._getSetting(name).then(function (setting) { if (setting.table) { var found = false; @@ -2949,7 +3007,7 @@ var mspHelper = (function (gui) { } } var data = []; - $this._encodeSettingName(name, data); + self._encodeSettingReference(name, setting.index, data); switch (setting.type) { case "uint8_t": case "int8_t": @@ -2975,9 +3033,38 @@ var mspHelper = (function (gui) { }); }; - self.setSetting = function (name, value, callback) { + self.setSetting = function (name, value) { this.encodeSetting(name, value).then(function (data) { - MSP.send_message(MSPCodes.MSPV2_SET_SETTING, data, false, callback); + return MSP.promise(MSPCodes.MSPV2_SET_SETTING, data); + }); + }; + + self.configureSettingInputs = function() { + var inputs = []; + $('input[data-setting!=""][data-setting]').each(function() { + inputs.push($(this)); + }); + return Promise.mapSeries(inputs, function (input, ii) { + var settingName = input.data("setting"); + return self.getSetting(settingName).then(function (s) { + var multiplier = parseFloat(input.data('setting-multiplier') || 1); + input.attr("step", 1 / multiplier); + input.attr("min", s.setting.min / multiplier); + input.attr("max", s.setting.max / multiplier); + input.val((s.value / multiplier).toFixed(Math.log10(multiplier))); + }); + }); + }; + + self.saveSettingsInputs = function() { + var inputs = []; + $('input[data-setting!=""][data-setting]').each(function() { + inputs.push($(this)); + }); + return Promise.mapSeries(inputs, function (input, ii) { + var settingName = input.data("setting"); + var multiplier = parseFloat(input.data('setting-multiplier') || 1); + return self.setSetting(settingName, parseFloat(input.val()) * multiplier); }); }; @@ -3032,13 +3119,7 @@ var mspHelper = (function (gui) { self.getCraftName = function(callback) { if (semver.gt(CONFIG.flightControllerVersion, "1.8.0")) { MSP.send_message(MSPCodes.MSP_NAME, false, false, function(resp) { - var name = ""; - for (var ii = 0; ii < resp.data.byteLength; ii++) { - var c = resp.data.readU8(); - if (c != 0) { - name += String.fromCharCode(c); - } - } + var name = resp.data.readString(); if (callback) { callback(name); } @@ -3091,6 +3172,31 @@ var mspHelper = (function (gui) { } else { callback(); } + }; + + self.loadParameterGroups = function(callback) { + if (semver.gte(CONFIG.flightControllerVersion, "2.0.0")) { + MSP.send_message(MSPCodes.MSP2_COMMON_PG_LIST, false, false, function (resp) { + var groups = []; + while (resp.data.offset < resp.data.byteLength) { + var id = resp.data.readU16(); + var start = resp.data.readU16(); + var end = resp.data.readU16(); + groups.push({id: id, start: start, end: end}); + } + if (callback) { + callback(groups); + } + }); + } else if (callback) { + callback(); + } + }; + + self.processHtml = function(callback) { + return function() { + self.configureSettingInputs().then(callback); + }; } return self; diff --git a/tabs/advanced_tuning.html b/tabs/advanced_tuning.html index 8620b5a1..9309779a 100644 --- a/tabs/advanced_tuning.html +++ b/tabs/advanced_tuning.html @@ -5,7 +5,7 @@
-
+
@@ -41,6 +41,7 @@ +
@@ -215,7 +216,7 @@
-
+
@@ -245,6 +246,7 @@ +
@@ -252,6 +254,7 @@ +
@@ -259,6 +262,7 @@ +
@@ -266,6 +270,7 @@ +
diff --git a/tabs/advanced_tuning.js b/tabs/advanced_tuning.js index d92839d8..63b3b52e 100644 --- a/tabs/advanced_tuning.js +++ b/tabs/advanced_tuning.js @@ -97,7 +97,6 @@ TABS.advanced_tuning.initialize = function (callback) { RTH_AND_LAND_CONFIG.rthAltControlMode = $rthAltControlMode.val(); }); GUI.fillSelect($rthAllowLanding, FC.getRthAllowLanding(), RTH_AND_LAND_CONFIG.rthAllowLanding); - console.log("VAL", RTH_AND_LAND_CONFIG.rthAllowLanding); $rthAllowLanding.val(RTH_AND_LAND_CONFIG.rthAllowLanding); $rthAllowLanding.change(function () { RTH_AND_LAND_CONFIG.rthAllowLanding = $rthAllowLanding.val(); @@ -148,4 +147,4 @@ TABS.advanced_tuning.initialize = function (callback) { TABS.advanced_tuning.cleanup = function (callback) { if (callback) callback(); -}; \ No newline at end of file +}; diff --git a/tabs/pid_tuning.html b/tabs/pid_tuning.html index 515cb44e..8b767c53 100755 --- a/tabs/pid_tuning.html +++ b/tabs/pid_tuning.html @@ -167,6 +167,20 @@ degrees per second + + + + degrees +
+ + + + + + degrees +
+ + diff --git a/tabs/pid_tuning.js b/tabs/pid_tuning.js index a48ed738..14395deb 100755 --- a/tabs/pid_tuning.js +++ b/tabs/pid_tuning.js @@ -33,7 +33,7 @@ TABS.pid_tuning.initialize = function (callback) { } function load_html() { - $('#content').load("./tabs/pid_tuning.html", process_html); + $('#content').load("./tabs/pid_tuning.html", mspHelper.processHtml(process_html)); } function pid_and_rc_to_form() { @@ -243,7 +243,11 @@ TABS.pid_tuning.initialize = function (callback) { } function saveFilterConfig() { - MSP.send_message(MSPCodes.MSP_SET_FILTER_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_FILTER_CONFIG), false, save_to_eeprom); + MSP.send_message(MSPCodes.MSP_SET_FILTER_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_FILTER_CONFIG), false, saveSettings); + } + + function saveSettings() { + mspHelper.saveSettingsInputs().then(save_to_eeprom); } function save_to_eeprom() { diff --git a/tabs/profiles.js b/tabs/profiles.js index 41af971a..ac72ec29 100644 --- a/tabs/profiles.js +++ b/tabs/profiles.js @@ -622,9 +622,7 @@ TABS.profiles.initialize = function (callback, scrollPosition) { var settings = presets.settings.get(currentPreset.type); Object.keys(settings).forEach(function(key, ii) { var value = settings[key]; - promises[key] = mspHelper.encodeSetting(key, value).then(function(data) { - return MSP.promise(MSPCodes.MSPV2_SET_SETTING, data); - }); + promises[key] = mspHelper.setSetting(name, value); }); } Promise.props(promises).then(function () {