Merge remote-tracking branch 'origin/master' into mmosca-github-build

pull/1930/head
Marcelo Bezerra 7 months ago
commit 02bf14a58e

@ -14,6 +14,9 @@
"options_showProfileParameters": {
"message": "Highlight parameters that change when switching battery or control profiles"
},
"options_cliAutocomplete": {
"message": "Advanced CLI AutoComplete"
},
"options_unit_type": {
"message": "Set how the units render on the configurator only"
},
@ -3593,6 +3596,12 @@
"osdAlarmGFORCE_AXIS_MAX_HELP": {
"message": "The axes g force elements will start blinking when greater than this value"
},
"osdAlarmADSB_MAX_DISTANCE_WARNING": {
"message": "Distance in meters of ADSB aircraft that is displayed"
},
"osdAlarmADSB_MAX_DISTANCE_ALERT": {
"message": "Distance inside which ADSB data flashes for proximity warning"
},
"osd_current_alarm": {
"message": "Current (A)"
},
@ -3632,6 +3641,12 @@
"osd_rssi_dbm_alarm": {
"message": "CRSF RSSI dBm Alarm"
},
"osd_adsb_distance_warning": {
"message": "ADSB distance warning"
},
"osd_adsb_distance_alert": {
"message": "ADSB distance alert"
},
"osd_rssi_dbm_alarm_HELP": {
"message": "RSSI indicator blinks below this value. Range: [-130,0]. Zero disables this alarm."
},

@ -138,6 +138,8 @@ sources.js = [
'./node_modules/openlayers/dist/ol.js',
'./js/libraries/plotly-latest.min.js',
'./js/sitl.js',
'./js/CliAutoComplete.js',
'./node_modules/jquery-textcomplete/dist/jquery.textcomplete.js'
];
sources.receiverCss = [

@ -0,0 +1,554 @@
/**
* Encapsulates the AutoComplete logic
*
* Uses: https://github.com/yuku/jquery-textcomplete
* Check out the docs at https://github.com/yuku/jquery-textcomplete/tree/v1/doc
*/
const CliAutoComplete = {
configEnabled: false,
builder: { state: 'reset', numFails: 0 },
};
CliAutoComplete.isEnabled = function() {
return this.isBuilding() || (this.configEnabled && CONFIG.flightControllerIdentifier === "INAV" && this.builder.state !== 'fail');
};
CliAutoComplete.isBuilding = function() {
return this.builder.state !== 'reset' && this.builder.state !== 'done' && this.builder.state !== 'fail';
};
CliAutoComplete.isOpen = function() {
return $('.cli-textcomplete-dropdown').is(':visible');
};
/**
* @param {boolean} force - Forces AutoComplete to be shown even if the matching strategy has less that minChars input
*/
CliAutoComplete.openLater = function(force) {
const self = this;
setTimeout(function() {
self.forceOpen = !!force;
self.$textarea.textcomplete('trigger');
self.forceOpen = false;
}, 0);
};
CliAutoComplete.setEnabled = function(enable) {
if (this.configEnabled !== enable) {
this.configEnabled = enable;
if (CONFIGURATOR.cliActive && CONFIGURATOR.cliValid) {
// cli is already open
if (this.isEnabled()) {
this.builderStart();
} else if (!this.isEnabled() && !this.isBuilding()) {
this.cleanup();
}
}
}
};
CliAutoComplete.initialize = function($textarea, sendLine, writeToOutput) {
this.$textarea = $textarea;
this.forceOpen = false;
this.sendLine = sendLine;
this.writeToOutput = writeToOutput;
this.cleanup();
};
CliAutoComplete.cleanup = function() {
this.$textarea.textcomplete('destroy');
this.builder.state = 'reset';
this.builder.numFails = 0;
};
CliAutoComplete._builderWatchdogTouch = function() {
const self = this;
this._builderWatchdogStop();
helper.timeout.add('autocomplete_builder_watchdog', function() {
if (self.builder.numFails) {
self.builder.numFails++;
self.builder.state = 'fail';
self.writeToOutput('Failed!<br># ');
$(self).trigger('build:stop');
} else {
// give it one more try
self.builder.state = 'reset';
self.builderStart();
}
}, 3000);
};
CliAutoComplete._builderWatchdogStop = function() {
helper.timeout.remove('autocomplete_builder_watchdog');
};
CliAutoComplete.builderStart = function() {
if (this.builder.state === 'reset') {
this.cache = {
commands: [],
resources: [],
resourcesCount: {},
settings: [],
settingsAcceptedValues: {},
feature: [],
beeper: ['ALL'],
};
this.builder.commandSequence = ['help', 'dump', 'get'];
this.builder.currentSetting = null;
this.builder.sentinel = `# ${Math.random()}`;
this.builder.state = 'init';
this.writeToOutput('<br># Building AutoComplete Cache ... ');
this.sendLine(this.builder.sentinel);
$(this).trigger('build:start');
}
};
CliAutoComplete.builderParseLine = function(line) {
const cache = this.cache;
const builder = this.builder;
this._builderWatchdogTouch();
if (line.indexOf(builder.sentinel) !== -1) {
// got sentinel
const command = builder.commandSequence.shift();
if (command && this.configEnabled) {
// next state
builder.state = `parse-${command}`;
this.sendLine(command);
this.sendLine(builder.sentinel);
} else {
// done
this._builderWatchdogStop();
if (!this.configEnabled) {
// disabled while we were building
this.writeToOutput('Cancelled!<br># ');
this.cleanup();
} else {
cache.settings.sort();
cache.commands.sort();
cache.feature.sort();
cache.beeper.sort();
cache.resources = Object.keys(cache.resourcesCount).sort();
this._initTextcomplete();
this.writeToOutput('Done!<br># ');
builder.state = 'done';
}
$(this).trigger('build:stop');
}
} else {
switch (builder.state) {
case 'parse-help':
const matchHelp = line.match(/^(\w+)/);
if (matchHelp) {
cache.commands.push(matchHelp[1]);
}
break;
case 'parse-dump':
const matchDump = line.match(/^resource\s+(\w+)/i);
if (matchDump) {
const r = matchDump[1].toUpperCase(); // should alread be upper, but to be sure, since we depend on that later
cache.resourcesCount[r] = (cache.resourcesCount[r] || 0) + 1;
} else {
const matchFeatBeep = line.match(/^(feature|beeper)\s+-?(\w+)/i);
if (matchFeatBeep) {
cache[matchFeatBeep[1].toLowerCase()].push(matchFeatBeep[2]);
}
}
break;
case 'parse-get':
const matchGet = line.match(/^(\w+)\s*=/);
if (matchGet) {
// setting name
cache.settings.push(matchGet[1]);
builder.currentSetting = matchGet[1].toLowerCase();
} else {
const matchGetSettings = line.match(/^(.*): (.*)/);
if (matchGetSettings !== null && builder.currentSetting) {
if (matchGetSettings[1].match(/values/i)) {
// Allowed Values
cache.settingsAcceptedValues[builder.currentSetting] = matchGetSettings[2].split(/\s*,\s*/).sort();
} else if (matchGetSettings[1].match(/range|length/i)){
// "Allowed range" or "Array length", store as string hint
cache.settingsAcceptedValues[builder.currentSetting] = matchGetSettings[0];
}
}
}
break;
}
}
};
/**
* Initializes textcomplete with all the autocomplete strategies
*/
CliAutoComplete._initTextcomplete = function() {
let sendOnEnter = false;
const self = this;
const $textarea = this.$textarea;
const cache = self.cache;
let savedMouseoverItemHandler = null;
// helper functions
const highlighter = function(anywhere) {
return function(value, term) {
const anywherePrefix = anywhere ? '': '^';
const termValue = value.replace(new RegExp(`${anywherePrefix}(${term})`, 'gi'), '<b>$1</b>');
return term ? termValue : value;
};
};
const highlighterAnywhere = highlighter(true);
const highlighterPrefix = highlighter(false);
const searcher = function(term, callback, array, minChars, matchPrefix) {
const res = [];
if ((minChars !== false && term.length >= minChars) || self.forceOpen || self.isOpen()) {
term = term.toLowerCase();
for (let i = 0; i < array.length; i++) {
const v = array[i].toLowerCase();
if (matchPrefix && v.startsWith(term) || !matchPrefix && v.indexOf(term) !== -1) {
res.push(array[i]);
}
}
}
callback(res);
if (self.forceOpen && res.length === 1) {
// hacky: if we came here because of Tab and there's only one match
// trigger Tab again, so that textcomplete should immediately select the only result
// instead of showing the menu
$textarea.trigger($.Event('keydown', {keyCode:9}));
}
};
const contexter = function(text) {
const val = $textarea.val();
if (val.length === text.length || val[text.length].match(/\s/)) {
return true;
}
return false; // do not show autocomplete if in the middle of a word
};
const basicReplacer = function(value) {
return `$1${value} `;
};
// end helper functions
// init textcomplete
$textarea.textcomplete([],
{
maxCount: 10000,
debounce: 0,
className: 'cli-textcomplete-dropdown',
placement: 'top',
onKeydown: function(e) {
// some strategies may set sendOnEnter only at the replace stage, thus we call with timeout
// since this handler [onKeydown] is triggered before replace()
if (e.which === 13) {
setTimeout(function() {
if (sendOnEnter) {
// fake "enter" to run the textarea's handler
$textarea.trigger($.Event('keypress', {which:13}));
}
}, 0);
}
},
},
)
.on('textComplete:show', function() {
/**
* The purpose of this code is to disable initially the `mouseover` menu item handler.
* Normally, when the menu pops up, if the mouse cursor is in the same area,
* the `mouseover` event triggers immediately and activates the item under
* the cursor. This might be undesirable when using the keyboard.
*
* Here we save the original `mouseover` handler and remove it on popup show.
* Then add `mousemove` handler. If the mouse moves we consider that mouse interaction
* is desired so we reenable the `mouseover` handler
*/
const textCompleteDropDownElement = $('.textcomplete-dropdown');
if (!savedMouseoverItemHandler) {
// save the original 'mouseover' handeler
try {
savedMouseoverItemHandler = $._data(textCompleteDropDownElement[0], 'events').mouseover[0].handler;
} catch (error) {
console.log(error);
}
if (savedMouseoverItemHandler) {
textCompleteDropDownElement
.off('mouseover') // initially disable it
.off('mousemove') // avoid `mousemove` accumulation if previous show did not trigger `mousemove`
.on('mousemove', '.textcomplete-item', function(e) {
// the mouse has moved so reenable `mouseover`
$(this).parent()
.off('mousemove')
.on('mouseover', '.textcomplete-item', savedMouseoverItemHandler);
// trigger the mouseover handler to select the item under the cursor
savedMouseoverItemHandler(e);
});
}
}
});
// textcomplete autocomplete strategies
// strategy builder helper
const strategy = function(s) {
return $.extend({
template: highlighterAnywhere,
replace: basicReplacer,
context: contexter,
index: 2,
}, s);
};
$textarea.textcomplete('register', [
strategy({ // "command"
match: /^(\s*)(\w*)$/,
search: function(term, callback) {
sendOnEnter = false;
searcher(term, callback, cache.commands, false, true);
},
template: highlighterPrefix,
}),
strategy({ // "get"
match: /^(\s*get\s+)(\w*)$/i,
search: function(term, callback) {
sendOnEnter = true;
searcher(term, function(arr) {
if (term.length > 0 && arr.length > 1) {
// prepend the uncompleted term in the popup
arr = [term].concat(arr);
}
callback(arr);
}, cache.settings, 3);
},
}),
strategy({ // "set"
match: /^(\s*set\s+)(\w*)$/i,
search: function(term, callback) {
sendOnEnter = false;
searcher(term, callback, cache.settings, 3);
},
}),
strategy({ // "set ="
match: /^(\s*set\s+\w*\s*)$/i,
search: function(term, callback) {
sendOnEnter = false;
searcher('', callback, ['='], false);
},
replace: function(value) {
self.openLater();
return basicReplacer(value);
},
}),
strategy({ // "set with value"
match: /^(\s*set\s+(\w+))\s*=\s*(.*)$/i,
search: function(term, callback, match) {
const arr = [];
const settingName = match[2].toLowerCase();
this.isSettingValueArray = false;
this.value = match[3];
sendOnEnter = !!term;
if (settingName in cache.settingsAcceptedValues) {
const val = cache.settingsAcceptedValues[settingName];
if (Array.isArray(val)) {
// setting uses lookup strings
this.isSettingValueArray = true;
sendOnEnter = true;
searcher(term, callback, val, 0);
return;
}
// the settings uses a numeric value.
// Here we use a little trick - we use the autocomplete
// list as kind of a tooltip to display the Accepted Range hint
arr.push(val);
}
callback(arr);
},
replace: function (value) {
if (!this.isSettingValueArray) {
// `value` is the tooltip text, so use the saved match
value = this.value;
}
return `$1 = ${value}`; // cosmetic - make sure we have spaces around the `=`
},
index: 3,
isSettingValueArray: false,
}),
strategy({ // "resource"
match: /^(\s*resource\s+)(\w*)$/i,
search: function(term, callback) {
sendOnEnter = false;
let arr = cache.resources;
arr = ['show'].concat(arr);
searcher(term, callback, arr, 1);
},
replace: function(value) {
if (value in cache.resourcesCount) {
self.openLater();
} else if (value === 'list' || value === 'show') {
sendOnEnter = true;
}
return basicReplacer(value);
},
}),
strategy({ // "resource index"
match: /^(\s*resource\s+(\w+)\s+)(\d*)$/i,
search: function(term, callback, match) {
sendOnEnter = false;
this.savedTerm = term;
callback([`&lt;1-${cache.resourcesCount[match[2].toUpperCase()]}&gt;`]);
},
replace: function() {
if (this.savedTerm) {
self.openLater();
return '$1$3 ';
}
return undefined;
},
context: function(text) {
const matchResource = text.match(/^\s*resource\s+(\w+)\s/i);
// use this strategy only for resources with more than one index
if (matchResource && (cache.resourcesCount[matchResource[1].toUpperCase()] || 0) > 1 ) {
return contexter(text);
}
return false;
},
index: 3,
savedTerm: null,
}),
strategy({ // "resource pin"
match: /^(\s*resource\s+\w+\s+(\d*\s+)?)(\w*)$/i,
search: function(term, callback) {
sendOnEnter = !!term;
if (term) {
if ('none'.startsWith(term)) {
callback(['none']);
} else {
callback(['&lt;pin&gt;']);
}
} else {
callback(['&lt;pin&gt', 'none']);
}
},
template: function(value, term) {
if (value === 'none') {
return highlighterPrefix(value, term);
}
return value;
},
replace: function(value) {
if (value === 'none') {
sendOnEnter = true;
return '$1none ';
}
return undefined;
},
context: function(text) {
const m = text.match(/^\s*resource\s+(\w+)\s+(\d+\s)?/i);
if (m) {
// show pin/none for resources having only one index (it's not needed at the commend line)
// OR having more than one index and the index is supplied at the command line
const count = cache.resourcesCount[m[1].toUpperCase()] || 0;
if (count && (m[2] || count === 1)) {
return contexter(text);
}
}
return false;
},
index: 3,
}),
strategy({ // "feature" and "beeper"
match: /^(\s*(feature|beeper)\s+(-?))(\w*)$/i,
search: function(term, callback, match) {
sendOnEnter = !!term;
let arr = cache[match[2].toLowerCase()];
if (!match[3]) {
arr = ['-', 'list'].concat(arr);
}
searcher(term, callback, arr, 1);
},
replace: function(value) {
if (value === '-') {
self.openLater(true);
return '$1-';
}
return basicReplacer(value);
},
index: 4,
}),
]);
$textarea.textcomplete('register', [
strategy({ // "resource show all", from BF 4.0.0 onwards
match: /^(\s*resource\s+show\s+)(\w*)$/i,
search: function(term, callback) {
sendOnEnter = true;
searcher(term, callback, ['all'], 1, true);
},
template: highlighterPrefix,
}),
]);
// diff command
const diffArgs1 = ["master", "profile", "rates", "all"];
const diffArgs2 = [];
// above 3.4.0
diffArgs2.push("defaults");
diffArgs1.push("hardware");
diffArgs2.push("bare");
diffArgs1.sort();
diffArgs2.sort();
$textarea.textcomplete('register', [
strategy({ // "diff arg1"
match: /^(\s*diff\s+)(\w*)$/i,
search: function(term, callback) {
sendOnEnter = true;
searcher(term, callback, diffArgs1, 1, true);
},
template: highlighterPrefix,
}),
strategy({ // "diff arg1 arg2"
match: /^(\s*diff\s+\w+\s+)(\w*)$/i,
search: function(term, callback) {
sendOnEnter = true;
searcher(term, callback, diffArgs2, 1, true);
},
template: highlighterPrefix,
}),
]);
};

@ -3,7 +3,7 @@
var CONFIGURATOR = {
// all versions are specified and compared using semantic versioning http://semver.org/
'minfirmwareVersionAccepted': '7.0.0',
'maxFirmwareVersionAccepted': '8.0.0', // Condition is < (lt) so we accept all in 7.x branch
'maxFirmwareVersionAccepted': '9.0.0', // Condition is < (lt) so we accept all in 8.x branch
'connectionValid': false,
'connectionValidCliOnly': false,
'cliActive': false,

@ -39,48 +39,44 @@ helper.defaultsDialog = (function () {
value: "DSHOT300"
},
/*
Filtering
Ez Tune setup
*/
{
key: "gyro_main_lpf_hz",
value: 90
key: "ez_enabled",
value: "ON"
},
{
key: "gyro_main_lpf_type",
value: "PT1"
key: "ez_filter_hz",
value: 90
},
{
key: "dterm_lpf_hz",
value: 85
key: "ez_axis_ratio",
value: 116
},
{
key: "dterm_lpf_type",
value: "PT3"
key: "ez_response",
value: 71
},
{
key: "dynamic_gyro_notch_enabled",
value: "ON"
key: "ez_damping",
value: 103
},
{
key: "dynamic_gyro_notch_q",
value: 250
key: "ez_stability",
value: 105
},
{
key: "dynamic_gyro_notch_min_hz",
value: 70
key: "ez_aggressiveness",
value: 100
},
{
key: "setpoint_kalman_enabled",
value: "ON"
key: "ez_rate",
value: 134
},
{
key: "setpoint_kalman_q",
value: 200
key: "ez_expo",
value: 118
},
{
key: "smith_predictor_delay", // Enable Smith Predictor
value: 1.5
},
/*
Mechanics
*/
@ -112,64 +108,6 @@ helper.defaultsDialog = (function () {
key: "antigravity_accelerator",
value: 5
},
/*
Rates
*/
{
key: "rc_yaw_expo",
value: 75
},
{
key: "rc_expo",
value: 75
},
{
key: "roll_rate",
value: 70
},
{
key: "pitch_rate",
value: 70
},
{
key: "yaw_rate",
value: 60
},
/*
PIDs
*/
{
key: "mc_p_pitch",
value: 32
},
{
key: "mc_i_pitch",
value: 90
},
{
key: "mc_d_pitch",
value: 25
},
{
key: "mc_p_roll",
value: 28
},
{
key: "mc_i_roll",
value: 80
},
{
key: "mc_d_roll",
value: 23
},
{
key: "mc_p_yaw",
value: 30
},
{
key: "mc_i_yaw",
value: 80
},
/*
* TPA
*/
@ -192,11 +130,6 @@ helper.defaultsDialog = (function () {
{
key: "failsafe_procedure",
value: "DROP"
},
// Ez Tune
{
key: "ez_filter_hz",
value: 90
}
]
},
@ -227,70 +160,63 @@ helper.defaultsDialog = (function () {
value: "DSHOT300"
},
/*
Filtering
Ez Tune setup
*/
{
key: "gyro_main_lpf_hz",
value: 110
key: "ez_enabled",
value: "ON"
},
{
key: "gyro_main_lpf_type",
value: "PT1"
key: "ez_filter_hz",
value: 110
},
/*
Dynamic gyro LPF
*/
{
key: "gyro_use_dyn_lpf",
value: "ON"
key: "ez_axis_ratio",
value: 110
},
{
key: "gyro_dyn_lpf_min_hz",
value: 85
key: "ez_response",
value: 92
},
{
key: "gyro_dyn_lpf_max_hz",
value: 300
key: "ez_damping",
value: 108
},
{
key: "gyro_dyn_lpf_curve_expo",
value: 3
},
/*
D-term
*/
{
key: "dterm_lpf_hz",
key: "ez_stability",
value: 110
},
{
key: "dterm_lpf_type",
value: "PT3"
key: "ez_aggressiveness",
value: 80
},
{
key: "dynamic_gyro_notch_enabled",
value: "ON"
key: "ez_rate",
value: 134
},
{
key: "dynamic_gyro_notch_q",
value: 250
key: "ez_expo",
value: 118
},
/*
Dynamic gyro LPF
*/
{
key: "dynamic_gyro_notch_min_hz",
value: 100
key: "gyro_use_dyn_lpf",
value: "ON"
},
{
key: "setpoint_kalman_enabled",
value: "ON"
key: "gyro_dyn_lpf_min_hz",
value: 85
},
{
key: "setpoint_kalman_q",
value: 200
key: "gyro_dyn_lpf_max_hz",
value: 300
},
{
key: "smith_predictor_delay", // Enable Smith Predictor
value: 1.5
},
key: "gyro_dyn_lpf_curve_expo",
value: 3
},
/*
Mechanics
*/
@ -322,64 +248,6 @@ helper.defaultsDialog = (function () {
key: "antigravity_accelerator",
value: 5
},
/*
Rates
*/
{
key: "rc_yaw_expo",
value: 75
},
{
key: "rc_expo",
value: 75
},
{
key: "roll_rate",
value: 70
},
{
key: "pitch_rate",
value: 70
},
{
key: "yaw_rate",
value: 60
},
/*
PIDs
*/
{
key: "mc_p_pitch",
value: 40
},
{
key: "mc_i_pitch",
value: 90
},
{
key: "mc_d_pitch",
value: 27
},
{
key: "mc_p_roll",
value: 36
},
{
key: "mc_i_roll",
value: 80
},
{
key: "mc_d_roll",
value: 25
},
{
key: "mc_p_yaw",
value: 35
},
{
key: "mc_i_yaw",
value: 80
},
/*
* TPA
*/
@ -402,11 +270,6 @@ helper.defaultsDialog = (function () {
{
key: "failsafe_procedure",
value: "DROP"
},
// Ez Tune
{
key: "ez_filter_hz",
value: 110
}
]
},
@ -437,52 +300,44 @@ helper.defaultsDialog = (function () {
value: "DSHOT300"
},
/*
Filtering
Ez Tune setup
*/
{
key: "gyro_main_lpf_hz",
value: 90
},
{
key: "gyro_main_lpf_type",
value: "PT1"
},
{
key: "dterm_lpf_hz",
value: 80
key: "ez_enabled",
value: "ON"
},
{
key: "dterm_lpf_type",
value: "PT3"
key: "ez_filter_hz",
value: 90
},
{
key: "dynamic_gyro_notch_enabled",
value: "ON"
key: "ez_axis_ratio",
value: 110
},
{
key: "dynamic_gyro_notch_mode",
value: "3D"
key: "ez_response",
value: 101
},
{
key: "dynamic_gyro_notch_q",
value: 250
key: "ez_damping",
value: 115
},
{
key: "dynamic_gyro_notch_min_hz",
value: 60
key: "ez_stability",
value: 100
},
{
key: "setpoint_kalman_enabled",
value: "ON"
key: "ez_aggressiveness",
value: 100
},
{
key: "setpoint_kalman_q",
value: 200
key: "ez_rate",
value: 134
},
{
key: "smith_predictor_delay", // Enable Smith Predictor
value: 1.5
},
key: "ez_expo",
value: 118
},
/*
Mechanics
*/
@ -514,64 +369,6 @@ helper.defaultsDialog = (function () {
key: "antigravity_accelerator",
value: 5
},
/*
Rates
*/
{
key: "rc_yaw_expo",
value: 75
},
{
key: "rc_expo",
value: 75
},
{
key: "roll_rate",
value: 70
},
{
key: "pitch_rate",
value: 70
},
{
key: "yaw_rate",
value: 60
},
/*
PIDs
*/
{
key: "mc_p_pitch",
value: 44
},
{
key: "mc_i_pitch",
value: 85
},
{
key: "mc_d_pitch",
value: 28
},
{
key: "mc_p_roll",
value: 40
},
{
key: "mc_i_roll",
value: 75
},
{
key: "mc_d_roll",
value: 26
},
{
key: "mc_p_yaw",
value: 40
},
{
key: "mc_i_yaw",
value: 80
},
/*
* TPA
*/
@ -594,11 +391,6 @@ helper.defaultsDialog = (function () {
{
key: "failsafe_procedure",
value: "DROP"
},
// Ez Tune
{
key: "ez_filter_hz",
value: 90
}
]
},

@ -29,6 +29,7 @@ var CONFIG,
MOTOR_DATA,
SERVO_DATA,
GPS_DATA,
ADSB_VEHICLES,
MISSION_PLANNER,
ANALOG,
ARMING_CONFIG,
@ -251,6 +252,12 @@ var FC = {
packetCount: 0
};
ADSB_VEHICLES = {
vehiclesCount: 0,
callsignLength: 0,
vehicles: []
};
MISSION_PLANNER = new WaypointCollection();
ANALOG = {
@ -1236,7 +1243,13 @@ var FC = {
operandType: "Set Flight Parameter",
hasOperand: [true, false],
output: "raw"
},
},
54: {
name: "Mag calibration",
operandType: "Set Flight Parameter",
hasOperand: [false, false],
output: "boolean"
},
}
},
getOperandTypes: function () {

@ -245,5 +245,7 @@ var MSPCodes = {
MSP2_INAV_EZ_TUNE: 0x2070,
MSP2_INAV_EZ_TUNE_SET: 0x2071,
MSP2_INAV_SELECT_MIXER_PROFILE: 0x2080
MSP2_INAV_SELECT_MIXER_PROFILE: 0x2080,
MSP2_ADSB_VEHICLE_LIST: 0x2090,
};

@ -187,6 +187,35 @@ var mspHelper = (function (gui) {
GPS_DATA.eph = data.getUint16(16, true);
GPS_DATA.epv = data.getUint16(18, true);
break;
case MSPCodes.MSP2_ADSB_VEHICLE_LIST:
var byteOffsetCounter = 0;
ADSB_VEHICLES.vehicles = [];
ADSB_VEHICLES.vehiclesCount = data.getUint8(byteOffsetCounter++);
ADSB_VEHICLES.callsignLength = data.getUint8(byteOffsetCounter++);
for(i = 0; i < ADSB_VEHICLES.vehiclesCount; i++){
var vehicle = {callSignByteArray: [], callsign: "", icao: 0, lat: 0, lon: 0, alt: 0, heading: 0, ttl: 0, tslc: 0, emitterType: 0};
for(ii = 0; ii < ADSB_VEHICLES.callsignLength; ii++){
vehicle.callSignByteArray.push(data.getUint8(byteOffsetCounter++));
}
vehicle.callsign = (String.fromCharCode(...vehicle.callSignByteArray)).replace(/[^\x20-\x7E]/g, '');
vehicle.icao = data.getUint32(byteOffsetCounter, true); byteOffsetCounter += 4;
vehicle.lat = data.getInt32(byteOffsetCounter, true); byteOffsetCounter += 4;
vehicle.lon = data.getInt32(byteOffsetCounter, true); byteOffsetCounter += 4;
vehicle.altCM = data.getInt32(byteOffsetCounter, true); byteOffsetCounter += 4;
vehicle.headingDegrees = data.getUint16(byteOffsetCounter, true); byteOffsetCounter += 2;
vehicle.tslc = data.getUint8(byteOffsetCounter++);
vehicle.emitterType = data.getUint8(byteOffsetCounter++);
vehicle.ttl = data.getUint8(byteOffsetCounter++);
ADSB_VEHICLES.vehicles.push(vehicle);
}
break;
case MSPCodes.MSP_ATTITUDE:
SENSOR_DATA.kinematics[0] = data.getInt16(0, true) / 10.0; // x
SENSOR_DATA.kinematics[1] = data.getInt16(2, true) / 10.0; // y

@ -78,6 +78,14 @@ $(document).ready(function () {
// Update CSS on to show highlighing or not
updateProfilesHighlightColours();
});
chrome.storage.local.get('cli_autocomplete', function (result) {
if (typeof result.cliAutocomplete === 'undefined') {
result.cli_autocomplete = 1;
}
globalSettings.cliAutocomplete = result.cli_autocomplete;
CliAutoComplete.setEnabled(globalSettings.cliAutocomplete);
});
// Resets the OSD units used by the unit coversion when the FC is disconnected.
if (!CONFIGURATOR.connectionValid) {
@ -122,10 +130,14 @@ $(document).ready(function () {
//Get saved size and position
chrome.storage.local.get('windowSize', function (result) {
if (result.windowSize) {
win.height = result.windowSize.height;
win.width = result.windowSize.width;
win.x = result.windowSize.x;
win.y = result.windowSize.y;
if (result.windowSize.height <= window.screen.availHeight)
win.height = result.windowSize.height;
if (result.windowSize.width <= window.screen.availWidth)
win.width = result.windowSize.width;
if (result.windowSize.x >= window.screen.availLeft)
win.x = result.windowSize.x;
if (result.windowSize.y >= window.screen.availTop)
win.y = result.windowSize.y;
}
});
@ -367,6 +379,15 @@ $(document).ready(function () {
activeTab.removeClass('active');
activeTab.find('a').click();
});
$('div.cli_autocomplete input').change(function () {
globalSettings.cliAutocomplete = $(this).is(':checked');
chrome.storage.local.set({
'cli_autocomplete': globalSettings.cliAutocomplete
});
CliAutoComplete.setEnabled($(this).is(':checked'));
});
$('#ui-unit-type').val(globalSettings.unitType);
$('#map-provider-type').val(globalSettings.mapProviderType);
@ -374,6 +395,7 @@ $(document).ready(function () {
$('#proxyurl').val(globalSettings.proxyURL);
$('#proxylayer').val(globalSettings.proxyLayer);
$('#showProfileParameters').prop('checked', globalSettings.showProfileParameters);
$('#cliAutocomplete').prop('checked', globalSettings.cliAutocomplete);
// Set the value of the unit type
// none, OSD, imperial, metric

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"minimum_chrome_version": "38",
"version": "7.0.1",
"version": "8.0.0",
"author": "Several",
"name": "INAV - Configurator",
"short_name": "INAV",

2758
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -1,7 +1,7 @@
{
"name": "inav-configurator",
"description": "INAV Configurator",
"version": "7.0.1",
"version": "8.0.0",
"main": "main.html",
"default_locale": "en",
"scripts": {
@ -32,7 +32,8 @@
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"inflection": "1.12.0",
"jquery": "2.1.4",
"jquery": "3.7.1",
"jquery-textcomplete": "^1.8.5",
"jquery-ui-npm": "1.12.0",
"marked": "^0.3.17",
"minimist": "^1.2.8",

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

@ -79,6 +79,24 @@
color: white;
}
.cli-textcomplete-dropdown {
border: 1px solid black;
background-color: #4f4f4f;
border-radius: 5px;
max-height: 50%;
overflow: auto;
list-style: none;
padding: 5px;
margin: 0;
}
.cli-textcomplete-dropdown a {
color: white;
cursor: pointer;
}
.cli-textcomplete-dropdown .active {
background-color: #000000;
}
@media only screen and (max-width: 1055px) , only screen and (max-device-width: 1055px) {
.tab-cli .content_wrapper {

@ -155,7 +155,11 @@
<label for="maxBankAngle"><span data-i18n="maxBankAngle"></span></label>
<div for="maxBankAngle" class="helpicon cf_tip" data-i18n_title="maxBankAngleHelp"></div>
</div>
<div class="number">
<input type="number" id="navManualClimbRate" data-unit="v-cms" data-setting="nav_fw_manual_climb_rate" data-setting-multiplier="1" step="1" min="10" max="2000" />
<label for="navManualClimbRate"><span data-i18n="navManualClimbRate"></span></label>
<div for="navManualClimbRate" class="helpicon cf_tip" data-i18n_title="navManualClimbRateHelp"></div>
</div>
<div class="number">
<input id="maxClimbAngle" type="number" data-unit="deg" data-setting="nav_fw_climb_angle" data-setting-multiplier="1" step="1" min="5" max="80" />
<label for="maxClimbAngle"><span data-i18n="maxClimbAngle"></span></label>
@ -238,6 +242,16 @@
<label for="max-manual-speed"><span data-i18n="posholdMaxManualSpeed"></span></label>
<div for="max-manual-speed" class="helpicon cf_tip" data-i18n_title="posholdMaxManualSpeedHelp"></div>
</div>
<div class="number">
<input type="number" id="navAutoClimbRate" data-unit="v-cms" data-setting="nav_mc_auto_climb_rate" data-setting-multiplier="1" step="1" min="10" max="2000" />
<label for="navAutoClimbRate"><span data-i18n="navAutoClimbRate"></span></label>
<div for="navAutoClimbRate" class="helpicon cf_tip" data-i18n_title="navAutoClimbRateHelp"></div>
</div>
<div class="number">
<input type="number" id="navManualClimbRate" data-unit="v-cms" data-setting="nav_mc_manual_climb_rate" data-setting-multiplier="1" step="1" min="10" max="2000" />
<label for="navManualClimbRate"><span data-i18n="navManualClimbRate"></span></label>
<div for="navManualClimbRate" class="helpicon cf_tip" data-i18n_title="navManualClimbRateHelp"></div>
</div>
<div class="number">
<input id="max-bank-angle" type="number" data-unit="deg" data-setting="nav_mc_bank_angle" data-setting-multiplier="1" step="1" min="15" max="45" />
<label for="max-bank-angle"><span data-i18n="posholdMaxBankAngle"></span></label>
@ -465,17 +479,6 @@
<div class="spacer_box_title" data-i18n="generalNavigationSettings"></div>
</div>
<div class="spacer_box">
<div class="number">
<input type="number" id="navManualClimbRate" data-unit="v-cms" data-setting="nav_manual_climb_rate" data-setting-multiplier="1" step="1" min="10" max="2000" />
<label for="navManualClimbRate"><span data-i18n="navManualClimbRate"></span></label>
<div for="navManualClimbRate" class="helpicon cf_tip" data-i18n_title="navManualClimbRateHelp"></div>
</div>
<div class="number">
<input type="number" id="navAutoClimbRate" data-unit="v-cms" data-setting="nav_auto_climb_rate" data-setting-multiplier="1" step="1" min="10" max="2000" />
<label for="navAutoClimbRate"><span data-i18n="navAutoClimbRate"></span></label>
<div for="navAutoClimbRate" class="helpicon cf_tip" data-i18n_title="navAutoClimbRateHelp"></div>
</div>
<div class="number">
<input type="number" id="navMaxAltitude" data-unit="cm" data-setting="nav_max_altitude" data-setting-multiplier="1" step="1" min="0" max="65000" />

@ -151,6 +151,19 @@ TABS.cli.initialize = function (callback) {
CONFIGURATOR.cliActive = true;
var textarea = $('.tab-cli textarea[name="commands"]');
CliAutoComplete.initialize(textarea, self.sendLine.bind(self), writeToOutput);
$(CliAutoComplete).on('build:start', function() {
textarea
.val('')
.attr('placeholder', chrome.i18n.getMessage('cliInputPlaceholderBuilding'))
.prop('disabled', true);
});
$(CliAutoComplete).on('build:stop', function() {
textarea
.attr('placeholder', chrome.i18n.getMessage('cliInputPlaceholder'))
.prop('disabled', false)
.focus();
});
$('.tab-cli .save').click(function() {
var prefix = 'cli';
@ -266,12 +279,19 @@ TABS.cli.initialize = function (callback) {
if (event.which == tabKeyCode) {
// prevent default tabbing behaviour
event.preventDefault();
const outString = textarea.val();
const lastCommand = outString.split("\n").pop();
const command = getCliCommand(lastCommand, self.cliBuffer);
if (command) {
self.sendAutoComplete(command);
textarea.val('');
if (!CliAutoComplete.isEnabled()) {
const outString = textarea.val();
const lastCommand = outString.split("\n").pop();
const command = getCliCommand(lastCommand, self.cliBuffer);
if (command) {
self.sendAutoComplete(command);
textarea.val('');
}
}
else if (!CliAutoComplete.isOpen() && !CliAutoComplete.isBuilding()) {
// force show autocomplete on Tab
CliAutoComplete.openLater(true);
}
}
});
@ -281,6 +301,10 @@ TABS.cli.initialize = function (callback) {
if (event.which == enterKeyCode) {
event.preventDefault(); // prevent the adding of new line
if (CliAutoComplete.isBuilding()) {
return; // silently ignore commands if autocomplete is still building
}
var out_string = textarea.val();
self.history.add(out_string.trim());
@ -300,6 +324,10 @@ TABS.cli.initialize = function (callback) {
var keyUp = {38: true},
keyDown = {40: true};
if (CliAutoComplete.isOpen()) {
return; // disable history keys if autocomplete is open
}
if (event.keyCode in keyUp) {
textarea.val(self.history.prev());
}
@ -335,7 +363,7 @@ TABS.cli.initialize = function (callback) {
}, 400);
}
}
GUI.content_ready(callback);
});
};
@ -370,6 +398,11 @@ function writeToOutput(text) {
}
function writeLineToOutput(text) {
if (CliAutoComplete.isBuilding()) {
CliAutoComplete.builderParseLine(text);
return; // suppress output if in building state
}
if (text.startsWith("### ERROR: ")) {
writeToOutput('<span class="error_message">' + text + '</span><br>');
} else {
@ -444,7 +477,10 @@ TABS.cli.read = function (readInfo) {
this.cliBuffer += currentChar;
}
this.outputHistory += currentChar;
if (!CliAutoComplete.isBuilding()) {
// do not include the building dialog into the history
this.outputHistory += currentChar;
}
if (this.cliBuffer == 'Rebooting') {
CONFIGURATOR.cliActive = false;
@ -459,7 +495,16 @@ TABS.cli.read = function (readInfo) {
if (!CONFIGURATOR.cliValid && validateText.indexOf('CLI') !== -1) {
GUI.log(chrome.i18n.getMessage('cliEnter'));
CONFIGURATOR.cliValid = true;
validateText = "";
if (CliAutoComplete.isEnabled() && !CliAutoComplete.isBuilding()) {
// start building autoComplete
CliAutoComplete.builderStart();
}
}
// fallback to native autocomplete
if (!CliAutoComplete.isEnabled()) {
setPrompt(removePromptHash(this.cliBuffer));
}
setPrompt(removePromptHash(this.cliBuffer));
@ -498,5 +543,8 @@ TABS.cli.cleanup = function (callback) {
if (callback) callback();
}, 1000); // if we dont allow enough time to reboot, CRC of "first" command sent will fail, keep an eye for this one
CONFIGURATOR.cliActive = false;
CliAutoComplete.cleanup();
$(CliAutoComplete).off();
});
};

@ -9,6 +9,32 @@ TABS.gps.initialize = function (callback) {
googleAnalytics.sendAppView('GPS');
}
// mavlink ADSB_EMITTER_TYPE
const ADSB_VEHICLE_TYPE = {
0: 'adsb_14.png', // ADSB_EMITTER_TYPE_NO_INFO
1: 'adsb_1.png', // ADSB_EMITTER_TYPE_LIGHT
2: 'adsb_1.png', // ADSB_EMITTER_TYPE_SMALL
3: 'adsb_2.png', // ADSB_EMITTER_TYPE_LARGE
4: 'adsb_14.png', // ADSB_EMITTER_TYPE_HIGH_VORTEX_LARGE
5: 'adsb_5.png', // ADSB_EMITTER_TYPE_HEAVY
6: 'adsb_14.png', // ADSB_EMITTER_TYPE_HIGHLY_MANUV
7: 'adsb_13.png', // ADSB_EMITTER_TYPE_ROTOCRAFT
8: 'adsb_14.png', // ADSB_EMITTER_TYPE_UNASSIGNED
9: 'adsb_6.png', // ADSB_EMITTER_TYPE_GLIDER
10: 'adsb_7.png', // ADSB_EMITTER_TYPE_LIGHTER_AIR
11: 'adsb_15.png', // ADSB_EMITTER_TYPE_PARACHUTE
12: 'adsb_1.png', // ADSB_EMITTER_TYPE_ULTRA_LIGHT
13: 'adsb_14.png', // ADSB_EMITTER_TYPE_UNASSIGNED2
14: 'adsb_8.png', // ADSB_EMITTER_TYPE_UAV
15: 'adsb_14.png', // ADSB_EMITTER_TYPE_SPACE
16: 'adsb_14.png', // ADSB_EMITTER_TYPE_UNASSGINED3
17: 'adsb_9.png', // ADSB_EMITTER_TYPE_EMERGENCY_SURFACE
18: 'adsb_10.png', // ADSB_EMITTER_TYPE_SERVICE_SURFACE
19: 'adsb_12.png', // ADSB_EMITTER_TYPE_POINT_OBSTACLE
};
var loadChainer = new MSPChainerClass();
var loadChain = [
@ -58,6 +84,10 @@ TABS.gps.initialize = function (callback) {
let iconGeometry;
let iconFeature;
let vehicleVectorSource;
let vehiclesCursorInitialized = false;
function process_html() {
localize();
@ -131,6 +161,36 @@ TABS.gps.initialize = function (callback) {
view: mapView
});
TABS.gps.toolboxAdsbVehicle = new jBox('Mouse', {
position: {
x: "right",
y: "bottom"
},
offset: {
x: -5,
y: 20,
},
});
mapHandler.on('pointermove', function(evt) {
var feature = mapHandler.forEachFeatureAtPixel(mapHandler.getEventPixel(evt.originalEvent), function(feature, layer) {
return feature;
});
if (feature) {
TABS.gps.toolboxAdsbVehicle.setContent(
`icao: <strong>` + feature.get('name') + `</strong><br />`
+ `lat: <strong>`+ (feature.get('data').lat / 10000000) + `</strong><br />`
+ `lon: <strong>`+ (feature.get('data').lon / 10000000) + `</strong><br />`
+ `ASL: <strong>`+ (feature.get('data').altCM ) / 100 + `m</strong><br />`
+ `heading: <strong>`+ feature.get('data').headingDegrees + `°</strong><br />`
+ `type: <strong>`+ feature.get('data').emitterType + `</strong>`
).open();
}else{
TABS.gps.toolboxAdsbVehicle.close();
}
});
let center = ol.proj.fromLonLat([0, 0]);
mapView.setCenter(center);
mapView.setZoom(2);
@ -221,6 +281,66 @@ TABS.gps.initialize = function (callback) {
iconGeometry.setCoordinates(center);
}
if (semver.gte(CONFIG.flightControllerVersion, "7.1.0")) {
MSP.send_message(MSPCodes.MSP2_ADSB_VEHICLE_LIST, false, false, function () {
//ADSB vehicles
if (vehiclesCursorInitialized) {
vehicleVectorSource.clear();
}
for (let key in ADSB_VEHICLES.vehicles) {
let vehicle = ADSB_VEHICLES.vehicles[key];
if (!vehiclesCursorInitialized) {
vehiclesCursorInitialized = true;
vehicleVectorSource = new ol.source.Vector({});
let vehicleLayer = new ol.layer.Vector({
source: vehicleVectorSource
});
mapHandler.addLayer(vehicleLayer);
}
if (vehicle.lat > 0 && vehicle.lon > 0 && vehicle.ttl > 0) {
let vehicleIconStyle = new ol.style.Style({
image: new ol.style.Icon(({
opacity: 1,
rotation: vehicle.headingDegrees * (Math.PI / 180),
scale: 0.8,
anchor: [0.5, 0.5],
src: '../resources/adsb/' + ADSB_VEHICLE_TYPE[vehicle.emitterType],
})),
text: new ol.style.Text(({
text: vehicle.callsign,
textAlign: 'center',
textBaseline: "bottom",
offsetY: +40,
padding: [2, 2, 2, 2],
backgroundFill: '#444444',
fill: new ol.style.Fill({color: '#ffffff'}),
})),
});
let iconGeometry = new ol.geom.Point(ol.proj.fromLonLat([vehicle.lon / 10000000, vehicle.lat / 10000000]));
let iconFeature = new ol.Feature({
geometry: iconGeometry,
name: vehicle.callsign,
type: 'adsb',
data: vehicle,
});
iconFeature.setStyle(vehicleIconStyle);
vehicleVectorSource.addFeature(iconFeature);
}
}
});
}
}
/*
@ -271,4 +391,7 @@ TABS.gps.initialize = function (callback) {
TABS.gps.cleanup = function (callback) {
if (callback) callback();
if(TABS.gps.toolboxAdsbVehicle){
TABS.gps.toolboxAdsbVehicle.close();
}
};

@ -20,6 +20,11 @@
<input id="showProfileParameters" type="checkbox" />
<label for="showProfileParameters"><span data-i18n="options_showProfileParameters"></span></label>
</div>
<div class="checkbox cli_autocomplete">
<input id="cliAutocomplete" type="checkbox" />
<label for="cliAutocomplete"><span data-i18n="options_cliAutocomplete"></span></label>
</div>
</div>
</div>

@ -242,6 +242,16 @@
<input id="osd_gforce_axis_alarm_max" data-setting="osd_gforce_axis_alarm_max" data-setting-multiplier="1" type="number" data-step="0.1" />
<span data-i18n="osd_gforce_axis_alarm_max"></span>
</label>
<div for="adsb_distance_warning" class="helpicon cf_tip" data-i18n_title="osdAlarmADSB_MAX_DISTANCE_WARNING"></div>
<label for="adsb_distance_warning">
<input id="adsb_distance_warning" data-setting="osd_adsb_distance_warning" data-unit="m" data-setting-multiplier="1" type="number" data-step="1" />
<span data-i18n="osd_adsb_distance_warning"></span>
</label>
<div for="adsb_distance_alert" class="helpicon cf_tip" data-i18n_title="osdAlarmADSB_MAX_DISTANCE_ALERT"></div>
<label for="adsb_distance_alert">
<input id="adsb_distance_alert" data-setting="osd_adsb_distance_alert" data-unit="m" data-setting-multiplier="1" type="number" data-step="1" />
<span data-i18n="osd_adsb_distance_alert"></span>
</label>
</div>
</div>
<div class="gui_box grey dji-hd-container" id="dji_settings">

@ -114,6 +114,7 @@ SYM.FLIGHT_DIST_REMAINING = 0x167;
SYM.GROUND_COURSE = 0xDC;
SYM.ALERT = 0xDD;
SYM.CROSS_TRACK_ERROR = 0xFC;
SYM.ADSB = 0xFD;
SYM.PAN_SERVO_IS_OFFSET_L = 0x1C7;
SYM.ODOMETER = 0X168;
SYM.PILOT_LOGO_SML_L = 0x1D5;
@ -480,6 +481,8 @@ OSD.initData = function () {
imu_temp_alarm_max: null,
baro_temp_alarm_min: null,
baro_temp_alarm_max: null,
adsb_distance_warning: null,
adsb_distance_alert: null,
},
layouts: [],
layout_count: 1, // This needs to be 1 for compatibility with < 2.0
@ -781,6 +784,24 @@ OSD.constants = {
min: -55,
max: 125
},
{
name: 'ADSB_MAX_DISTANCE_WARNING',
field: 'adsb_distance_warning',
step: 1,
unit: "meters",
min: 1,
max: 64000,
min_version: '7.1.0',
},
{
name: 'ADSB_MAX_DISTANCE_ALERT',
field: 'adsb_distance_alert',
step: 1,
unit: "meters",
min: 1,
max: 64000,
min_version: '7.1.0',
},
],
// All display fields, from every version, do not remove elements, only add!
@ -1654,6 +1675,18 @@ OSD.constants = {
min_version: '6.0.0',
preview: FONT.symbol(SYM.GROUND_COURSE) + '245' + FONT.symbol(SYM.DEGREES)
},
{
name: 'ADSB_WARNING_MESSAGE',
id: 147,
min_version: '7.1.0',
preview: FONT.symbol(SYM.ADSB) + '19.25' + FONT.symbol(SYM.DIR_TO_HOME+1) + '2.75',
},
{
name: 'ADSB_INFO',
id: 148,
min_version: '7.1.0',
preview: FONT.symbol(SYM.ADSB) + '2',
},
{
name: 'CROSS TRACK ERROR',
id: 141,
@ -2264,6 +2297,8 @@ OSD.msp = {
result.push16(OSD.data.alarms.imu_temp_alarm_max);
result.push16(OSD.data.alarms.baro_temp_alarm_min);
result.push16(OSD.data.alarms.baro_temp_alarm_max);
result.push16(OSD.data.alarms.adsb_distance_warning);
result.push16(OSD.data.alarms.adsb_distance_alert);
return result;
},
@ -2283,6 +2318,8 @@ OSD.msp = {
OSD.data.alarms.imu_temp_alarm_max = alarms.read16();
OSD.data.alarms.baro_temp_alarm_min = alarms.read16();
OSD.data.alarms.baro_temp_alarm_max = alarms.read16();
OSD.data.alarms.adsb_distance_warning = alarms.read16();
OSD.data.alarms.adsb_distance_alert = alarms.read16();
},
encodePreferences: function() {
@ -2689,7 +2726,7 @@ OSD.GUI.updateFields = function() {
}
$displayFields.append($field);
}
if (groupContainer.find('.display-fields').children().size() > 0) {
if (groupContainer.find('.display-fields').children().length > 0) {
$tmpl.parent().append(groupContainer);
}
}

@ -276,8 +276,8 @@ TABS.ports.initialize = function (callback) {
var selectElementName = 'function-' + column;
var selectElementSelector = 'select[name=' + selectElementName + ']';
select_e = functions_e.find(selectElementSelector);
if (select_e.size() == 0) {
if (select_e.length == 0) {
functions_e.prepend('<span class="function"><select name="' + selectElementName + '" class="' + selectElementName + '" onchange="updateDefaultBaud(\'' + functions_e_id + '\', \'' + column + '\')" /></span>');
select_e = functions_e.find(selectElementSelector);
var disabledText = chrome.i18n.getMessage('portsTelemetryDisabled');

@ -306,7 +306,7 @@ TABS.setup.initialize3D = function () {
camera.aspect = wrapper.width() / wrapper.height();
camera.updateProjectionMatrix();
self.render3D();
this.render3D();
};
$(window).on('resize', this.resize3D);

Loading…
Cancel
Save