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 @@