1
0
Fork 0
mirror of https://github.com/iNavFlight/inav-configurator.git synced 2025-07-16 04:45:18 +03:00

Merge branch 'master' into dzikuvx-new-servo-frames

This commit is contained in:
Pawel Spychalski (DzikuVx) 2024-04-06 10:01:54 +02:00
commit d6b6c34ef9
28 changed files with 3968 additions and 1287 deletions

View file

@ -850,7 +850,7 @@
"message": "External PWM servo driver"
},
"featurePWM_SERVO_DRIVERTip": {
"message": "Use external PCA9685 PMW driver to connect up to 16 servos to flight controller. PCA9685 has to be connected to enable this feature."
"message": "Use external PCA9685 PWM driver to connect up to 16 servos to flight controller. PCA9685 has to be connected to enable this feature."
},
"featureRSSI_ADCTip": {
"message": "RSSI is a measurement of signal strength and is very handy so you know when your aircraft is going out of range or if it is suffering RF interference."
@ -2999,8 +2999,8 @@
"posholdHoverThrottle": {
"message": "Hover throttle"
},
"posholdHoverMidThrottle": {
"message": "Use mid. throttle for ALTHOLD"
"navmcAltholdThrottle": {
"message": "Stick position for althold hover"
},
"mcWpSlowdown": {
"message": "Slow down when approaching waypoint"
@ -3377,6 +3377,54 @@
"fixedWingNavigationConfiguration": {
"message": "Fixed Wing Navigation Settings"
},
"fixedWingLandingConfiguration": {
"message": "Fixed Wing Landing Settings"
},
"MissionPlannerOnlyOneLandWp": {
"message": "You can set only one LAND Waypoint per mission."
},
"fwLandApproachLength" : {
"message": "Final approach length"
},
"fwLandApproachLengthHelp": {
"message": "Length of the final approach, also includes the glide and intercept phase. This is the length from the safe home point to the final turn point."
},
"fwLandFinalApproachPitch2throttle": {
"message": "Modifier for pitch to throttle ratio at final approach"
},
"fwLandFinalApproachPitch2throttleHelp": {
"message": "This value is multiplied by the \"pitch to throttle ratio\" value during the final approach. Allows the velocity to be reduced."
},
"fwLandGlideAlt" : {
"message": "Initial altitude of the glide phase"
},
"fwLandGlideAltHelp" : {
"message": "At this altitude (measured from the altitude of the landing point) the engine is switched off and the aircraft glides from here."
},
"fwLandFlareAlt" : {
"message": "Initial altitude of the flare phase"
},
"fwLandFlareAltHelp" : {
"message": "At this altitude (measured from the altitude of the landing point) the last phase of landing is executed."
},
"fwLandGlidePitch" : {
"message": "Pitch value for glide phase"
},
"fwLandGlidePitchHelp" : {
"message": "This pitch angle is held during the glide phase."
},
"fwLandFlarePitch" : {
"message": "Pitch value for flare phase"
},
"fwLandFlarePitchHelp" : {
"message": "This pitch angle is held during the flare phase."
},
"fwLandMaxTailwind": {
"message": "Max. tailwind"
},
"fwLandMaxTailwindHelp": {
"message": "This value is used when no headwind landing is possible and wind speeds below this value are ignored (inaccuracies in INAV wind measurement)."
},
"osd_unsupported_msg1": {
"message": "Your flight controller isn't responding to OSD commands. This probably means that it does not have an integrated OSD."
},
@ -3461,6 +3509,12 @@
"osd_hud_settings": {
"message": "Heads up Display settings"
},
"osd_custom_element_settings": {
"message": "Custom OSD elements"
},
"custom_element": {
"message": "Custom element"
},
"osd_hud_settings_HELP": {
"message": "This section allows tweaking the behavior of HUD elements."
},
@ -4331,6 +4385,12 @@
"SafehomeSafeRadius": {
"message": "Safe Radius (m):"
},
"SafehomeFwAppraoch": {
"message": "FW Approach:"
},
"safehomeEdit": {
"message": "Edit Safehome"
},
"missionTitleHide": {
"message": "Hide"
},
@ -4361,6 +4421,9 @@
"missionTitleSaveEepromMission": {
"message": "Save Eeprom mission"
},
"missionTitleDelete": {
"message": "Delete"
},
"missionTitleRemoveAll": {
"message": "Remove all"
},
@ -4385,6 +4448,60 @@
"missionTitlEditMission": {
"message": "Edit Mission"
},
"MissionPlannerFwLAndingAltitudeChangeReset": {
"message": "Altitude below min land altitude. Change ignored"
},
"missionWpType": {
"message": "Type:"
},
"missionWpLat": {
"message": "Lat:"
},
"missionWpLon": {
"message": "Lon:"
},
"missionSeaLevelRef": {
"message": "Sea level Ref: "
},
"missionElevation": {
"message": "Elevation (m):"
},
"missionNA": {
"message": "N/A"
},
"missionGroundDist": {
"message": "Grd Dist (m):"
},
"missionParameter1": {
"message": "Parameter 1:"
},
"missionParameter2": {
"message": "Parameter 2:"
},
"missionUserActions": {
"message": "User Actions:"
},
"missionFwLandingSettings": {
"message": "Fixed Wing landing settings:"
},
"missionFwApproachAlt": {
"message": "Approach Alt: (cm):"
},
"missionFwLandAlt": {
"message": "Land Alt: (cm):"
},
"missionFwApproachDir": {
"message": "Approach direction:"
},
"missionFwLandHeading1": {
"message": "Heading 1: (deg):"
},
"missionFwLandHeading2": {
"message": "Heading 2: (deg):"
},
"missionExclusive": {
"message": "Excl."
},
"missionRTHsettingsTitle": {
"message": "RTH settings"
},
@ -4400,6 +4517,12 @@
"missionSafehomeHead": {
"message": "Safe Home manager"
},
"missionSafehomeAvailableSafehomes" : {
"message": "Available Safehomes:"
},
"missionSafehomeMaxSafehomesReached": {
"message": "Maximum number of safehomes reached."
},
"missionMultiMissionHead": {
"message": "Multi Missions"
},
@ -4721,12 +4844,6 @@
"itermRelaxHelp": {
"message": "Defines Iterm relaxation algorithm activation. PR mean it's active on Roll and Pitch axis. PRY is active also on Yaw."
},
"gyro_main_lpf_type": {
"message": "Gyro LPF type"
},
"gyro_main_lpf_type_help": {
"message": "BIQUAD offers better noise attenuation for a price of higher delay. PT1 has lower attenuation but offers lower delay."
},
"dterm_lpf_type": {
"message": "D-term LPF type"
},
@ -4914,10 +5031,10 @@
"message": "Illegal state. Restart required."
},
"motor_direction_inverted": {
"message": "Normal motor direction / Props In configuration"
"message": "Normal motor direction / Props-in configuration"
},
"motor_direction_isInverted": {
"message": "Reversed motor direction / Props Out configuration"
"message": "Reversed motor direction / Props-out configuration"
},
"motor_direction_inverted_hint": {
"message": "Enable if the motor direction is reversed and the props are mounted in the opposite direction."

View file

@ -142,6 +142,8 @@ sources.js = [
'./js/sitl.js',
'./js/CliAutoComplete.js',
'./node_modules/jquery-textcomplete/dist/jquery.textcomplete.js',
'./js/fwApproach.js',
'./js/fwApproachCollection.js',
'./js/ltmDecoder.js',
'./js/groundstation.js'
];
@ -410,18 +412,39 @@ gulp.task('release-osx64', function(done) {
archive.directory(src, 'INAV Configurator.app');
output.on('close', function() {
if (getArguments().notarize) {
console.log('Notarizing DMG file: ' + zipFilename);
const notarizeArgs = ['macapptool', '-v', '1', 'notarize'];
console.log('Notarizing ZIP file: ' + zipFilename);
const notarizeArgs = ['xcrun', 'notarytool', 'submit'];
notarizeArgs.push(zipFilename);
const notarizationUsername = getArguments()['notarization-username'];
if (notarizationUsername) {
notarizeArgs.push('-u', notarizationUsername)
notarizeArgs.push('--apple-id', notarizationUsername)
} else {
throw new Error('Missing notarization username');
}
const notarizationPassword = getArguments()['notarization-password'];
if (notarizationPassword) {
notarizeArgs.push('-p', notarizationPassword)
notarizeArgs.push('--password', notarizationPassword)
} else {
throw new Error('Missing notarization password');
}
const notarizationTeamId = getArguments()['notarization-team-id'];
if (notarizationTeamId) {
notarizeArgs.push('--team-id', notarizationTeamId)
} else {
throw new Error('Missing notarization Team ID');
}
notarizeArgs.push('--wait');
const notarizationWebhook = getArguments()['notarization-webhook'];
if (notarizationWebhook) {
notarizeArgs.push('--webhook', notarizationWebhook);
}
notarizeArgs.push(zipFilename)
execSync.apply(this, notarizeArgs);
console.log('Stapling ZIP file: ' + zipFilename);
const stapleArgs = ['macapptool', '-v', '1', 'staple'];
stapleArgs.push(zipFilename)
execSync.apply(this, stapleArgs);
}
done();
});
@ -587,7 +610,7 @@ function release_deb(arch) {
`xdg-desktop-menu install ${LINUX_INSTALL_DIR}/${metadata.name}/${metadata.name}.desktop`,
],
prerm: [`xdg-desktop-menu uninstall ${metadata.name}.desktop`],
depends: ['libgconf-2-4', 'libatomic1'],
depends: ['libatomic1'],
changelog: [],
_target: `${LINUX_INSTALL_DIR}/${metadata.name}`,
_out: appsDir,

View file

@ -433,10 +433,6 @@ helper.defaultsDialog = (function () {
key: "d_boost_max",
value: 1
},
{
key: "gyro_main_lpf_type",
value: "BIQUAD"
},
{
key: "dynamic_gyro_notch_enabled",
value: "ON"
@ -642,10 +638,6 @@ helper.defaultsDialog = (function () {
key: "d_boost_max",
value: 1
},
{
key: "gyro_main_lpf_type",
value: "BIQUAD"
},
{
key: "dynamic_gyro_notch_enabled",
value: "ON"
@ -831,10 +823,6 @@ helper.defaultsDialog = (function () {
key: "gyro_main_lpf_hz",
value: 10
},
{
key: "gyro_main_lpf_type",
value: "BIQUAD"
},
{
key: "motor_pwm_protocol",
value: "STANDARD"

View file

@ -65,7 +65,10 @@ var CONFIG,
BOARD_ALIGNMENT,
CURRENT_METER_CONFIG,
FEATURES,
RATE_DYNAMICS;
RATE_DYNAMICS,
FW_APPROACH,
OSD_CUSTOM_ELEMENTS;
var FC = {
restartRequired: false,
@ -565,6 +568,15 @@ var FC = {
rate: null,
expo: null
};
FW_APPROACH = new FwApproachCollection();
OSD_CUSTOM_ELEMENTS = {
settings: {customElementsCount: 0, customElementTextSize: 0},
items: [],
};
},
getOutputUsages: function() {
return {
@ -1307,7 +1319,8 @@ var FC = {
37: "Rangefinder [cm]",
38: "Active MixerProfile",
39: "MixerTransition Active",
40: "Yaw [deg]"
40: "Yaw [deg]",
41: "FW Land State"
}
},
3: {

107
js/fwApproach.js Normal file
View file

@ -0,0 +1,107 @@
/*global $*/
'use strict';
const ApproachDirection = Object.freeze({
LEFT: 0,
RIGHT: 1,
})
let FwApproach = function (number, approachAltAsl = 0, landAltAsl = 0, approachDirection = 0, landHeading1 = 0, landHeading2 = 0, isSeaLevelRef = 0, elevation = 0) {
var self = {};
self.getNumber = function () {
return number;
};
self.setNumber = function (data) {
number = data;
};
self.getApproachAltAsl = function () {
return approachAltAsl;
}
self.setApproachAltAsl = function (data) {
approachAltAsl = data;
}
self.getLandAltAsl = function () {
return landAltAsl;
}
self.setLandAltAsl = function (data) {
landAltAsl = data;
}
self.getApproachDirection = function () {
return approachDirection;
}
self.setApproachDirection = function (data) {
approachDirection = data;
}
self.getLandHeading1 = function () {
return landHeading1;
}
self.setLandHeading1 = function (data) {
landHeading1 = data;
}
self.getLandHeading2 = function () {
return landHeading2;
}
self.setLandHeading2 = function (data) {
landHeading2 = data;
}
self.getIsSeaLevelRef = function () {
return isSeaLevelRef;
}
self.setIsSeaLevelRef = function (data) {
isSeaLevelRef = data;
}
self.getElevation = function() {
return elevation;
}
self.setElevation = function (data) {
elevation = data;
}
self.cleanup = function () {
approachAltAsl = 0;
landAltAsl = 0;
approachDirection = 0;
landHeading1 = 0;
landHeading2 = 0;
isSeaLevelRef = 0;
elevation = 0
};
self.getElevationFromServer = async function (lon, lat, globalSettings) {
let elevation = "N/A";
if (globalSettings.mapProviderType == 'bing') {
let elevationEarthModel = $('#elevationEarthModel').prop("checked") ? "ellipsoid" : "sealevel";
const response = await fetch('http://dev.virtualearth.net/REST/v1/Elevation/List?points='+lat+','+lon+'&heights='+elevationEarthModel+'&key='+globalSettings.mapApiKey);
const myJson = await response.json();
elevation = myJson.resourceSets[0].resources[0].elevations[0];
}
else {
const response = await fetch('https://api.opentopodata.org/v1/aster30m?locations='+lat+','+lon);
const myJson = await response.json();
if (myJson.status == "OK" && myJson.results[0].elevation != null) {
elevation = myJson.results[0].elevation;
}
}
return elevation;
}
return self;
};

View file

@ -0,0 +1,92 @@
'use strict';
let FwApproachCollection = function () {
let self = {},
data = [],
maxFwApproachCount = 17;
self.setMaxFwApproachCount = function (value) {
maxFwApproachCount = value;
};
self.getMaxFwApproachCount = function () {
return maxFwApproachCount;
}
self.put = function (element) {
element.setNumber(data.length);
data.push(element);
};
self.get = function () {
return data;
};
self.clean = function (index){
data[index].cleanup();
};
self.flush = function () {
data = [];
};
self.isEmpty = () => {
return data.length == 0;
};
self.fwApproachCount = () => {
return data.length;
}
self.drop = (idx) => {
data.forEach(f => {
if (f.getNumber() >= idx) {
f.setNumber(f.getNumber() - 1);
}
});
data.splice(idx, 1);
}
self.insert = (fwApprach, idx) => {
data.forEach(f => {
if (f.getNumber() >= idx) {
f.setNumber(f.getNumber() + 1);
}
});
data.splice(idx, 0, fwApprach);
}
self.updateFwApproach = function(newFwApproach) {
data[newFwApproach.getNumber()] = newFwApproach;
};
self.extractBuffer = function(fwApproachId) {
let buffer = [];
let fwApproach = data[fwApproachId];
if (fwApproachId < self.fwApproachCount()) {
buffer.push(fwApproach.getNumber()); // sbufReadU8(src); // number
buffer.push(specificByte(fwApproach.getApproachAltAsl(), 0));
buffer.push(specificByte(fwApproach.getApproachAltAsl(), 1));
buffer.push(specificByte(fwApproach.getApproachAltAsl(), 2));
buffer.push(specificByte(fwApproach.getApproachAltAsl(), 3));
buffer.push(specificByte(fwApproach.getLandAltAsl(), 0));
buffer.push(specificByte(fwApproach.getLandAltAsl(), 1));
buffer.push(specificByte(fwApproach.getLandAltAsl(), 2));
buffer.push(specificByte(fwApproach.getLandAltAsl(), 3));
buffer.push(fwApproach.getApproachDirection());
buffer.push(specificByte(fwApproach.getLandHeading1(), 0));
buffer.push(specificByte(fwApproach.getLandHeading1(), 1));
buffer.push(specificByte(fwApproach.getLandHeading2(), 0));
buffer.push(specificByte(fwApproach.getLandHeading2(), 1));
buffer.push(fwApproach.getIsSeaLevelRef());
} else {
buffer = Array(15).fill(0);
buffer[0] = safehomeId;
}
return buffer;
}
return self;
};

View file

@ -1,6 +1,7 @@
/*global $*/
'use strict';
function checkChromeRuntimeError() {
if (chrome.runtime.lastError) {
console.error(
@ -65,3 +66,51 @@ function scaleRangeInt(x, srcMin, srcMax, destMin, destMax) {
let b = srcMax - srcMin;
return Math.round((a / b) + destMin);
}
function distanceOnLine(start, end, distance)
{
var vx = end[0] - start[0];
var vy = end[1] - start[1];
var mag = Math.sqrt(vx * vx + vy * vy);
vx /= mag;
vy /= mag;
var px = start[0] + vx * (mag + distance);
var py = start[1] + vy * (mag + distance);
return [px, py];
}
function wrap_360(angle)
{
if (angle >= 360)
angle -= 360;
if (angle < 0)
angle += 360;
return angle;
}
function rad2Deg(rad)
{
return rad * (180 / Math.PI);
}
function deg2Rad(deg)
{
return deg * (Math.PI / 180);
}
function calculate_new_cooridatnes(coord, bearing, distance)
{
var lat = deg2Rad(coord.lat);
var lon = deg2Rad(coord.lon);
bearing = deg2Rad(bearing);
var delta = distance / 637100000; // Earth radius in cm
var latNew = Math.asin(Math.sin(lat) * Math.cos(delta) + Math.cos(lat) * Math.sin(delta) * Math.cos(bearing));
var lonNew = lon + Math.atan2(Math.sin(bearing) * Math.sin(delta) * Math.cos(lat), Math.cos(delta) - Math.sin(lat) * Math.sin(lat));
return {
lat: rad2Deg(latNew),
lon: rad2Deg(lonNew),
}
}

View file

@ -226,6 +226,9 @@ var MSPCodes = {
MSP2_INAV_LED_STRIP_CONFIG_EX: 0x2048,
MSP2_INAV_SET_LED_STRIP_CONFIG_EX: 0x2049,
MSP2_INAV_FW_APPROACH: 0x204A,
MSP2_INAV_SET_FW_APPROACH: 0x204B,
MSP2_INAV_RATE_DYNAMICS: 0x2060,
MSP2_INAV_SET_RATE_DYNAMICS: 0x2061,
@ -235,4 +238,8 @@ var MSPCodes = {
MSP2_INAV_SELECT_MIXER_PROFILE: 0x2080,
MSP2_ADSB_VEHICLE_LIST: 0x2090,
MSP2_INAV_CUSTOM_OSD_ELEMENTS: 0x2100,
MSP2_INAV_SET_CUSTOM_OSD_ELEMENTS: 0x2101,
};

View file

@ -1425,6 +1425,9 @@ var mspHelper = (function (gui) {
case MSPCodes.MSP2_INAV_SELECT_BATTERY_PROFILE:
console.log('Battery profile selected');
break;
case MSPCodes.MSP2_INAV_SET_CUSTOM_OSD_ELEMENTS:
console.log('OSD custom elements preferences saved');
break;
case MSPCodes.MSPV2_INAV_OUTPUT_MAPPING:
OUTPUT_MAPPING.flush();
for (i = 0; i < data.byteLength; ++i)
@ -1492,17 +1495,37 @@ var mspHelper = (function (gui) {
}
break;
case MSPCodes.MSP2_INAV_SAFEHOME:
SAFEHOMES.put(new Safehome(
let safehome = new Safehome(
data.getUint8(0),
data.getUint8(1),
data.getInt32(2, true),
data.getInt32(6, true)
));
data.getInt32(6, true),
);
if (safehome.getEnabled()) {
SAFEHOMES.put(safehome);
}
break;
case MSPCodes.MSP2_INAV_SET_SAFEHOME:
console.log('Safehome points saved');
break;
case MSPCodes.MSP2_INAV_FW_APPROACH:
FW_APPROACH.put(new FwApproach(
data.getUint8(0),
data.getInt32(1, true),
data.getInt32(5, true),
data.getUint8(9, true),
data.getInt16(10, true),
data.getInt16(12, true),
data.getUint8(14, true),
));
break;
case MSPCodes.MSP2_INAV_SET_FW_APPROACH:
console.log('FW Approach saved');
break;
case MSPCodes.MSP2_INAV_RATE_DYNAMICS:
RATE_DYNAMICS.sensitivityCenter = data.getUint8(0);
RATE_DYNAMICS.sensitivityEnd = data.getUint8(1);
@ -1532,6 +1555,54 @@ var mspHelper = (function (gui) {
console.log('EzTune settings saved');
break;
case MSPCodes.MSP2_INAV_CUSTOM_OSD_ELEMENTS:
OSD_CUSTOM_ELEMENTS.items = [];
var index = 0;
if(data.byteLength == 0){
OSD_CUSTOM_ELEMENTS.settings.customElementsCount = 0;
OSD_CUSTOM_ELEMENTS.settings.customElementTextSize = 0;
return;
}
OSD_CUSTOM_ELEMENTS.settings.customElementsCount = data.getUint8(index++);
OSD_CUSTOM_ELEMENTS.settings.customElementTextSize = data.getUint8(index++);
for (i = 0; i < OSD_CUSTOM_ELEMENTS.settings.customElementsCount; i++){
var customElement = {
customElementItems: [],
customElementVisibility: {type: 0, value: 0},
customElementText: [],
};
for (let ii = 0; ii < OSD_CUSTOM_ELEMENTS.settings.customElementsCount; ii++){
var customElementPart = {type: 0, value: 0,};
customElementPart.type = data.getUint8(index++);
customElementPart.value = data.getUint16(index, true);
index += 2;
customElement.customElementItems.push(customElementPart);
}
customElement.customElementVisibility.type = data.getUint8(index++);
customElement.customElementVisibility.value = data.getUint16(index, true);
index += 2;
for (let ii = 0; ii < OSD_CUSTOM_ELEMENTS.settings.customElementTextSize; ii++){
var char = data.getUint8(index++);
if(char === 0){
index += (OSD_CUSTOM_ELEMENTS.settings.customElementTextSize - 1) - ii;
break;
}
customElement.customElementText[ii] = char;
}
customElement.customElementText = String.fromCharCode(...customElement.customElementText);
OSD_CUSTOM_ELEMENTS.items.push(customElement)
}
break;
default:
console.log('Unknown code detected: ' + dataHandler.code);
} else {
@ -2442,6 +2513,10 @@ var mspHelper = (function (gui) {
}
};
self.loadOsdCustomElements = function (callback) {
MSP.send_message(MSPCodes.MSP2_INAV_CUSTOM_OSD_ELEMENTS, false, false, callback);
}
self.sendModeRanges = function (onCompleteCallback) {
var nextFunction = send_next_mode_range;
@ -2759,7 +2834,7 @@ var mspHelper = (function (gui) {
MSP.send_message(MSPCodes.MSP2_INAV_TIMER_OUTPUT_MODE, false, false, callback);
}
self.sendTimerOutputModes = function(onCompleteCallback) {
self.sendTimerOutputModes = function(callback) {
var nextFunction = send_next_output_mode;
var idIndex = 0;
@ -2784,7 +2859,7 @@ var mspHelper = (function (gui) {
// prepare for next iteration
idIndex++;
if (idIndex == overrideIds.length) {
nextFunction = onCompleteCallback;
nextFunction = callback;
}
MSP.send_message(MSPCodes.MSP2_INAV_SET_TIMER_OUTPUT_MODE, buffer, false, nextFunction);
@ -3017,6 +3092,37 @@ var mspHelper = (function (gui) {
};
};
self.loadFwApproach = function (callback) {
FW_APPROACH.flush();
let id = 0;
MSP.send_message(MSPCodes.MSP2_INAV_FW_APPROACH, [id], false, nextFwApproach);
function nextFwApproach() {
id++;
if (id < FW_APPROACH.getMaxFwApproachCount() - 1) {
MSP.send_message(MSPCodes.MSP2_INAV_FW_APPROACH, [id], false, nextFwApproach);
}
else {
MSP.send_message(MSPCodes.MSP2_INAV_FW_APPROACH, [id], false, callback);
}
};
};
self.saveFwApproach = function (callback) {
let id = 0;
MSP.send_message(MSPCodes.MSP2_INAV_SET_FW_APPROACH, FW_APPROACH.extractBuffer(id), false, nextFwApproach);
function nextFwApproach() {
id++;
if (id < FW_APPROACH.getMaxFwApproachCount() - 1) {
MSP.send_message(MSPCodes.MSP2_INAV_SET_FW_APPROACH, FW_APPROACH.extractBuffer(id), false, nextFwApproach);
}
else {
MSP.send_message(MSPCodes.MSP2_INAV_SET_FW_APPROACH, FW_APPROACH.extractBuffer(id), false, callback);
}
};
};
self._getSetting = function (name) {
if (SETTINGS[name]) {
return Promise.resolve(SETTINGS[name]);
@ -3132,8 +3238,7 @@ var mspHelper = (function (gui) {
return this._getSetting(name).then(function (setting) {
if (!setting) {
console.log("Setting invalid: " + name);
return null;
throw 'Invalid setting';
}
if (setting.table && !Number.isInteger(value)) {
@ -3183,11 +3288,10 @@ var mspHelper = (function (gui) {
self.setSetting = function (name, value, callback) {
this.encodeSetting(name, value).then(function (data) {
if (data) {
return MSP.promise(MSPCodes.MSPV2_SET_SETTING, data).then(callback);
} else {
return Promise.resolve().then(callback);
}
}).catch(error => {
console.log("Invalid setting: " + name);
return new Promise(callback);
});
};

View file

@ -15,6 +15,7 @@ let SafehomeCollection = function () {
}
self.put = function (element) {
element.setNumber(data.length);
data.push(element);
};
@ -30,67 +31,31 @@ let SafehomeCollection = function () {
data = [];
};
self.inflate = function () {
while (self.hasFreeSlots()) {
self.put(new Safehome(data.length, 0, 0, 0));
}
self.isEmpty = () => {
return data.length == 0;
};
self.hasFreeSlots = function () {
return data.length < self.getMaxSafehomeCount();
};
self.isSafehomeConfigured = function(safehomeId) {
for (let safehomeIndex in data) {
if (data.hasOwnProperty(safehomeIndex)) {
let safehome = data[safehomeIndex];
if (safehome.getNumber() == safehomeId && safehome.isUsed()) {
return true;
}
}
}
return false;
};
self.getNumberOfConfiguredSafehome = function () {
let count = 0;
for (let i = 0; i < self.getMaxSafehomeCount(); i ++) {
if (self.isSafehomeConfigured(i)) {
count++;
}
}
return count;
};
self.getUsedSafehomeIndexes = function () {
let out = [];
for (let safehomeIndex in data) {
if (data.hasOwnProperty(safehomeIndex)) {
let safehome = data[safehomeIndex];
out.push(safehome.getNumber());
}
self.safehomeCount = () => {
return data.length;
}
let unique = [...new Set(out)];
return unique.sort(function(a, b) {
return a-b;
self.drop = (idx) => {
data.forEach(safehome => {
if (safehome.getNumber() >= idx) {
safehome.setNumber(safehome.getNumber() - 1);
}
});
data.splice(idx, 1);
}
self.getSafehome = function(safehomeId) {
for (let safehomeIndex in data) {
if (data.hasOwnProperty(safehomeIndex)) {
let safehome = data[safehomeIndex];
if (safehome.getNumber() == safehomeId ) {
return safehome;
self.insert = (safehome, idx) => {
data.forEach(s => {
if (s.getNumber() >= idx) {
s.setNumber(s.getNumber() + 1);
}
});
data.splice(idx, 0, safehome);
}
}
};
self.updateSafehome = function(newSafehome) {
data[newSafehome.getNumber()] = newSafehome;
@ -98,9 +63,10 @@ let SafehomeCollection = function () {
self.extractBuffer = function(safehomeId) {
let buffer = [];
let safehome = self.getSafehome(safehomeId);
let safehome = data[safehomeId];
if (safehomeId < self.safehomeCount()) {
buffer.push(safehome.getNumber()); // sbufReadU8(src); // number
buffer.push(safehome.getEnabled()); // sbufReadU8(src); // action
buffer.push(1);
buffer.push(specificByte(safehome.getLat(), 0)); // sbufReadU32(src); // lat
buffer.push(specificByte(safehome.getLat(), 1));
buffer.push(specificByte(safehome.getLat(), 2));
@ -109,6 +75,10 @@ let SafehomeCollection = function () {
buffer.push(specificByte(safehome.getLon(), 1));
buffer.push(specificByte(safehome.getLon(), 2));
buffer.push(specificByte(safehome.getLon(), 3));
} else {
buffer = Array(10).fill(0);
buffer[0] = safehomeId;
}
return buffer;
}

View file

@ -61,6 +61,8 @@ var Settings = (function () {
if (input.prop('tagName') == 'SELECT' || s.setting.table) {
if (input.attr('type') == 'checkbox') {
input.prop('checked', s.value > 0);
} else if (input.attr('type') == 'radio') {
input.prop( 'checked', s.value == input.attr('value') );
} else {
input.empty();
let option = null;
@ -515,6 +517,10 @@ var Settings = (function () {
if (setting.table) {
if (input.attr('type') == 'checkbox') {
value = input.prop('checked') ? 1 : 0;
} else if (input.attr('type') == 'radio') {
if (input.prop('checked')) {
value = parseInt(input.val());
}
} else {
value = parseInt(input.val());
}

View file

@ -1,7 +1,7 @@
/*global $*/
'use strict';
let Waypoint = function (number, action, lat, lon, alt=0, p1=0, p2=0, p3=0, endMission=0, isUsed=true, isAttached=false, attachedId="") {
let Waypoint = function (number, action, lat, lon, alt=0, p1=0, p2=0, p3=0, endMission=0, isUsed=true, isAttached=false, attachedId="", multiMissionIdx = 0) {
var self = {};
let layerNumber = "undefined";
@ -136,6 +136,14 @@ let Waypoint = function (number, action, lat, lon, alt=0, p1=0, p2=0, p3=0, endM
attachedNumber = data;
};
self.setMultiMissionIdx = function(data) {
multiMissionIdx = data;
}
self.getMultiMissionIdx = function() {
return multiMissionIdx;
}
self.getElevation = async function (globalSettings) {
let elevation = "N/A";
if (globalSettings.mapProviderType == 'bing') {

View file

@ -442,7 +442,7 @@ let WaypointCollection = function () {
let elevation = "N/A";
if (globalSettings.mapProviderType == 'bing') {
let elevationEarthModel = $('#elevationEarthModel').prop("checked") ? "sealevel" : "ellipsoid";
let elevationEarthModel = $('#elevationEarthModel').prop("checked") ? "ellipsoid" : "sealevel";
if (point2measure.length >1) {
const response = await fetch('http://dev.virtualearth.net/REST/v1/Elevation/Polyline?points='+point2measure+'&heights='+elevationEarthModel+'&samples='+String(samples+1)+'&key='+globalSettings.mapApiKey);

14
main.js
View file

@ -79,7 +79,7 @@ $(document).ready(function () {
updateProfilesHighlightColours();
});
chrome.storage.local.get('cli_autocomplete', function (result) {
if (typeof result.cliAutocomplete === 'undefined') {
if (typeof result.cli_autocomplete === 'undefined') {
result.cli_autocomplete = 1;
}
globalSettings.cliAutocomplete = result.cli_autocomplete;
@ -130,14 +130,14 @@ $(document).ready(function () {
//Get saved size and position
chrome.storage.local.get('windowSize', function (result) {
if (result.windowSize) {
if (result.windowSize.height <= window.screen.availHeight)
if (result.windowSize.height >= window.screen.availHeight && result.windowSize.width >= window.screen.availWidth) {
win.maximize();
} else {
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;
win.x = Math.max(result.windowSize.x, window.screen.availLeft);
win.y = Math.max(result.windowSize.y, window.screen.availTop);
}
}
});

2780
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -37,7 +37,7 @@
"jquery-ui-npm": "1.12.0",
"marked": "^0.3.17",
"minimist": "^1.2.0",
"nw": "^0.61.0-sdk",
"nw": "^0.61.0",
"nw-dialog": "^1.0.7",
"openlayers": "^4.6.5",
"plotly": "^1.0.6",

Binary file not shown.

Binary file not shown.

View file

@ -236,10 +236,17 @@
margin-bottom: 5px;
margin-left: 5px;
}
.tab-mission-control .point-label {
width: 80px;
display: inline-block;
}
.tab-mission-control .point-label-safehome {
width: 120px;
display: inline-block;
}
.tab-mission-control .point-radio input{
width: 25px;
padding-left: 3px;
@ -511,7 +518,6 @@
.tab-mission-control .fill{
border:none;
border-bottom:5px dotted #88CC3E;
display:inline-block;
width:20px;
}
@ -519,9 +525,6 @@
.tab-mission-control .textLegend{
margin:2px;
}
.tab-mission-control .valueLegend{
float:right;
}
.tab-mission-control .userActionContainer {
display: inline-block;

View file

@ -720,3 +720,17 @@ button {
.tab-osd .unit_wrapper {
vertical-align: top;
}
.osdCustomElement_main_table {
width: 100%;
table-layout: fixed;
max-width: 400px;
}
.osdCustomElement_main_table td{
max-width: 80px;
}
.osdCustomElement_main_table select, .osdCustomElement_main_table input{
width: 100% !important;
}

View file

@ -68,6 +68,49 @@
</div>
</div>
<div class="config-section gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" data-i18n="fixedWingLandingConfiguration"></div>
</div>
<div class="spacer_box">
<div class="number">
<input id="fwLandApproachLength" type="number" data-unit="cm" data-setting="nav_fw_land_approach_length" data-setting-multiplier="1" step="1" min="100" max="100000" />
<label for="fwLandApproachLength"><span data-i18n="fwLandApproachLength"></span></label>
<div for="fwLandApproachLength" class="helpicon cf_tip" data-i18n_title="fwLandApproachLengthHelp"></div>
</div>
<div class="number">
<input id="fwLandFinalApproachPitch2throttle" type="number" data-unit="percent" data-setting="nav_fw_land_final_approach_pitch2throttle_mod" data-setting-multiplier="1" step="1" min="100" max="400" />
<label for="fwLandFinalApproachPitch2throttle"><span data-i18n="fwLandFinalApproachPitch2throttle"></span></label>
<div for="fwLandFinalApproachPitch2throttle" class="helpicon cf_tip" data-i18n_title="fwLandFinalApproachPitch2throttleHelp"></div>
</div>
<div class="number">
<input id="fwLandGlideAlt" type="number" data-unit="cm" data-setting="nav_fw_land_glide_alt" data-setting-multiplier="1" step="1" min="100" max="5000" />
<label for="fwLandGlideAlt"><span data-i18n="fwLandGlideAlt"></span></label>
<div for="fwLandGlideAlt" class="helpicon cf_tip" data-i18n_title="fwLandGlideAltHelp"></div>
</div>
<div class="number">
<input id="fwLandFlareAlt" type="number" data-unit="cm" data-setting="nav_fw_land_flare_alt" data-setting-multiplier="1" step="1" min="0" max="10000" />
<label for="fwLandFlareAlt"><span data-i18n="fwLandFlareAlt"></span></label>
<div for="fwLandFlareAlt" class="helpicon cf_tip" data-i18n_title="fwLandFlareAltHelp"></div>
</div>
<div class="number">
<input id="fwLandGlidePitch" type="number" data-unit="deg" data-setting="nav_fw_land_glide_pitch" data-setting-multiplier="1" step="1" min="0" max="45" />
<label for="fwLandGlidePitch"><span data-i18n="fwLandGlidePitch"></span></label>
<div for="fwLandGlidePitch" class="helpicon cf_tip" data-i18n_title="fwLandGlidePitchHelp"></div>
</div>
<div class="number">
<input id="fwLandFlarePitch" type="number" data-unit="deg" data-setting="nav_fw_land_flare_pitch" data-setting-multiplier="1" step="1" min="0" max="45" />
<label for="fwLandFlarePitch"><span data-i18n="fwLandFlarePitch"></span></label>
<div for="fwLandFlarePitch" class="helpicon cf_tip" data-i18n_title="fwLandFlarePitchHelp"></div>
</div>
<div class="number">
<input id="fwLandMaxTailwind" type="number" data-unit="cms" data-setting="nav_fw_land_max_tailwind" data-setting-multiplier="1" step="1" min="0" max="3000" />
<label for="fwLandMaxTailwind"><span data-i18n="fwLandMaxTailwind"></span></label>
<div for="fwLandMaxTailwind" class="helpicon cf_tip" data-i18n_title="fwLandMaxTailwindHelp"></div>
</div>
</div>
</div>
<div class="config-section gui_box grey">
<div class="gui_box_titlebar">
<div class="spacer_box_title" data-i18n="powerConfiguration"></div>
@ -257,10 +300,12 @@
<label for="max-bank-angle"><span data-i18n="posholdMaxBankAngle"></span></label>
<div for="max-bank-angle" class="helpicon cf_tip" data-i18n_title="posholdMaxBankAngleHelp"></div>
</div>
<div class="checkbox">
<input type="checkbox" class="toggle update_preview" id="use-mid-throttle" data-setting="nav_use_midthr_for_althold" data-live="true" />
<label for="use-mid-throttle"><span data-i18n="posholdHoverMidThrottle"></span></label>
<div class="select">
<select id="nav-mc-althold-throttle" data-setting="nav_mc_althold_throttle"></select>
<label for="nav-mc-althold-throttle"><span data-i18n="navmcAltholdThrottle"></span></label>
</div>
<div class="number">
<input id="hover-throttle" type="number" data-unit="us" data-setting="nav_mc_hover_thr" data-setting-multiplier="1" step="1" min="1000" max="2000" />
<label for="hover-throttle"><span data-i18n="posholdHoverThrottle"></span></label>

View file

@ -86,6 +86,14 @@
<label class="point-label" for="MPdefaultSafeRangeSH" data-i18n="missionDefaultSafeRangeSH"></label>
<input id="MPdefaultSafeRangeSH" type="text" value="0" required>
</div>
<div class="point">
<label class="point-label" for="MPdefaultFwApproachAlt">FW Approach Alt (m): </label>
<input id="MPdefaultFwApproachAlt" type="text" value="0" required>
</div>
<div class="point">
<label class="point-label" for="MPdefaultLandAlt">FW Land Alt (m): </label>
<input id="MPdefaultLandAlt" type="text" value="0" required>
</div>
</div>
</div>
@ -167,7 +175,7 @@
</div>
<div class="point" id="elevationEarthModelclass" style="display: none">
<label class="spacer_box_title" for="elevationEarthModel" data-i18n="missionEllipsoidEarthDEMModel"></label>
<input id="elevationEarthModel" type="checkbox" value="0" class="togglemedium" required>
<input id="elevationEarthModel" type="checkbox" value="0" class="togglemedium" checked required>
</div>
</div>
@ -178,39 +186,96 @@
<div id="showHideSafehomeButton">
<a class="ic_hide" href="#" i18n_title="missionTitleHide"></a>
</div>
<a id="cancelSafehome" class="ic_cancel" href="#" i18n_title="missionTitleCancel"></a>
<a id="cancelSafehome" class="ic_cancel" href="#" title="Cancel"></a>
<a id="addSafehome" class="ic_add" href="#" i18n_title="missionTitleAdd"></a>
<a id="saveEepromSafehomeButton" class="ic_save2Eprom" href="#" i18n_title="missionTitleSaveEepromSafehome"></a>
<a id="loadEepromSafehomeButton" class="ic_loadFromEprom" href="#" i18n_title="missionTitleLoadEepromSafehome"></a>
</div>
</div>
<div class="spacer" id="SafehomeContent">
<div>
<table class="safehomesTable">
<thead>
<tr>
<th style="width: 40px" data-i18n="SafehomeSelected"></th>
<th style="width: 40px" data-i18n="SafehomeId"></th>
<th style="width: 60px" data-i18n="SafehomeEnabled"></th>
<th style="width: 140px" data-i18n="SafehomeLat"></th>
<th style="width: 140px" data-i18n="SafehomeLon"></th>
</tr>
</thead>
<tbody id="safehomesTableBody">
</tbody>
</table>
<div style="padding-bottom: 2px;">
<span data-i18n="missionSafehomeAvailableSafehomes"></span>
<span id="availableSafehomes"></span>
</div>
<div id="SafehomeContentBox" style="display: none;">
<div class="gui_box grey missionPlannerSafehomeBox">
<div class="gui_box_titlebar">
<div class="spacer_box_title" data-i18n="safehomeEdit"></div>
<div class="btnMenu btnMenuIcon">
<div class="btnMenu-danger">
<a id="deleteSafehome" class="ic_removeAll" href="#" i18n_title="missionTitleDelete"></a>
</div>
</div>
</div>
<div class="spacer" id="safehomeSingelContent">
<div class="point">
<label class="point-label-safehome" for="safeHomeLatitude" data-i18n="gpsLat"></label>
<input type="number" id="safehomeLatitude"></input>
</div>
<div class="point">
<label class="point-label-safehome" for="safehomeLongitude" data-i18n="gpsLon"></label>
<input type="number" id="safehomeLongitude"></input>
</div>
<div class="point">
<span style="font-weight: bold" data-i18n="missionFwLandingSettings"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="safehomeSeaLevelRef" data-i18n="missionSeaLevelRef"></label>
<input id="safehomeSeaLevelRef" type="checkbox" value="0" class="togglemedium" required>
</div>
<div class="point">
<label class="point-label-safehome" for="safehomeApproachAlt" data-i18n="missionFwApproachAlt"></label>
<input type="number" id="safehomeApproachAlt"></input>
<span id="safehomeApproachAltM"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="safehomeLandAlt" data-i18n="missionFwLandAlt"></label>
<input type="number" id="safehomeLandAlt"></input>
<span id="safehomeLandAltM"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="safehomeElevation" data-i18n="missionElevation"></label>
<span id="safehomeElevation"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="geozoneApproachDirection" data-i18n="missionFwApproachDir"></label>
<select name="zoneAction" id="geozoneApproachDirection">
<option value="0">Left</option>
<option value="1">Right</option>
</select>
</div>
<div class="point">
<label class="point-label-safehome" for="safehomeLandHeading1" data-i18n="missionFwLandHeading1"></label>
<input type="number" id="safehomeLandHeading1"></input>
<input id="safehomeLandHeading1Excl" type="checkbox" value="0" class="togglemedium" required>
<span data-i18n="missionExclusive"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="safehomeLandHeading2" data-i18n="missionFwLandHeading2"></label>
<input type="number" id="safehomeLandHeading2"></input>
<input id="safehomeLandHeading2Excl" type="checkbox" value="0" class="togglemedium" required>
<span data-i18n="missionExclusive"></span>
</div>
</div>
</div>
</div>
<hr>
<div class="spacer" id="safehomeLegend">
<span><b data-i18n="SafehomeLegend"></b></span>
<div class="legendItem">
<span class="fill" style="border-bottom-color:#900C3F"></span>
<span class="fill" style="border-bottom:5px dotted #900C3F;"></span>
<span class="textLegend" data-i18n="SafehomeMaxDistance"></span>
<span id="safeHomeMaxDistance" class="valueLegend"></span>
<span id="safeHomeMaxDistance"></span>
</div>
<div class="legendItem">
<span class="fill"></span>
<span class="fill" style="border-bottom:5px dotted #88CC3E;"></span>
<span class="textLegend" data-i18n="SafehomeSafeRadius"></span>
<span id="SafeHomeSafeDistance" class="valueLegend"></span>
<span id="SafeHomeSafeDistance"></span>
</div>
<div class="legendItem">
<span class="fill" style="border-bottom:5px solid #f78a05;border-top:5px solid #0025a1;"></span>
<span class="textLegend" data-i18n="SafehomeFwAppraoch"></span>
<span id="SafeHomeSafeDistance"></span>
</div>
</div>
</div>
@ -234,7 +299,7 @@
<div class="spacer" id="WPeditContent">
<input type="hidden" name="pointNumber" value="">
<div class="point">
<label class="point-label" for="pointType">Type: </label>
<label class="point-label" for="pointType" data-i18n="missionWpType"></label>
<select name="type" id="pointType">
<!--<option value="1">Home</option>-->
<option value="1">Waypoint</option>
@ -248,39 +313,39 @@
</select>
</div>
<div class="point">
<label class="point-label" for="pointLat">Lat: </label>
<label class="point-label" for="pointLat" data-i18n="missionWpLat"></label>
<input id="pointLat" type="text" value="0.0" required>
</div>
<div class="point">
<label class="point-label" for="pointLon">Lon: </label>
<label class="point-label" for="pointLon" data-i18n="missionWpLon"></label>
<input id="pointLon" type="text" value="0.0" required>
</div>
<div class="point">
<label class="point-label" for="pointAlt">Alt (cm): </label>
<label class="point-label" for="pointAlt" data-i18n="missionDefaultPointAlt"></label>
<input id="pointAlt" type="text" value="0" required><span id="altitudeInMeters"></span>
</div>
<div class="point" id="pointP3class" style="display: none">
<label class="point-label" for="pointP3Alt">Sea level Ref: </label>
<label class="point-label" for="pointP3Alt" data-i18n="missionSeaLevelRef"></label>
<input id="pointP3Alt" type="checkbox" value="0" class="togglemedium" checked required>
</div>
<div class="point" id="elevationAtWP" style="display: none">
<label class="point-label">Elevation (m): </label>
<span id="elevationValueAtWP">N/A</span>
<label class="point-label" data-i18n="missionElevation"></label>
<span id="elevationValueAtWP" data-i18n="missionNA"></span>
</div>
<div class="point" id="groundClearanceAtWP" style="display: none">
<label class="point-label">Grd Dist (m): </label>
<span id="groundClearanceValueAtWP">N/A</span>
<label class="point-label" data-i18n="missionGroundDist"></label>
<span id="groundClearanceValueAtWP" data-i18n="missionNA"></span>
</div>
<div class="point" id="pointP1class" style="display: none">
<label class="point-label" for="pointP1">Parameter 1: </label>
<label class="point-label" for="pointP1" data-i18n="missionParameter1"></label>
<input id="pointP1" type="text" value="0" required>
</div>
<div class="point" id="pointP2class" style="display: none">
<label class="point-label" for="pointP2">Parameter 2: </label>
<label class="point-label" for="pointP2" data-i18n="missionParameter1"></label>
<input id="pointP2" type="text" value="0" required>
</div>
<div class="point" id="pointP3UserActionClass" style="display: none">
<label class="point-label" for="pointP3UserAction">User Actions: </label>
<label class="point-label" for="pointP3UserAction" data-i18n="missionUserActions"></label>
<div class="userActionContainer">1 <input id="pointP3UserAction1" type="checkbox" value="0" class="togglemedium" checked required></div>
<div class="userActionContainer">2 <input id="pointP3UserAction2" type="checkbox" value="0" class="togglemedium" checked required></div>
<div class="userActionContainer">3 <input id="pointP3UserAction3" type="checkbox" value="0" class="togglemedium" checked required></div>
@ -305,7 +370,74 @@
</tbody>
</table>
</div>
<div id="wpFwLanding" style="display: none;">
<div class="point">
<span style="font-weight: bold" data-i18n="missionFwLandingSettings"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="wpApproachAlt" data-i18n="missionFwApproachAlt"></label>
<input type="number" id="wpApproachAlt"></input>
<span id="wpApproachAltM"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="wpLandAlt" data-i18n="missionFwLandAlt"></label>
<input type="number" id="wpLandAlt"></input>
<span id="wpLandAltM"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="wpApproachDirection" data-i18n="missionFwApproachDir"></label>
<select name="wpApproachDirection" id="wpApproachDirection">
<option value="0">Left</option>
<option value="1">Right</option>
</select>
</div>
<div class="point">
<label class="point-label-safehome" for="wpLandHeading1" data-i18n="missionFwLandHeading1"></label>
<input type="number" id="wpLandHeading1"></input>
<input id="wpLandHeading1Excl" type="checkbox" value="0" class="togglemedium" checked required>
<span data-i18n="missionExclusive"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="wpLandHeading2" data-i18n="missionFwLandHeading1"></label>
<input type="number" id="wpLandHeading2"></input>
<input id="wpLandHeading2Excl" type="checkbox" value="0" class="togglemedium" checked required>
<span data-i18n="missionExclusive"></span>
</div>
</div>
<div id="wpFwLanding" style="display: none;">
<div class="point">
<span style="font-weight: bold" data-i18n="missionFwLandingSettings"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="wpApproachAlt" data-i18n="missionFwApproachAlt"></label>
<input type="number" id="wpApproachAlt"></input>
<span id="wpApproachAltM"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="wpLandAlt" data-i18n="missionFwLandAlt"></label>
<input type="number" id="wpLandAlt"></input>
<span id="wpLandAltM"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="wpApproachDirection" data-i18n="missionFwApproachDir"></label>
<select name="wpApproachDirection" id="wpApproachDirection">
<option value="0">Left</option>
<option value="1">Right</option>
</select>
</div>
<div class="point">
<label class="point-label-safehome" for="wpLandHeading1" data-i18n="missionFwLandHeading1"></label>
<input type="number" id="wpLandHeading1"></input>
<input id="wpLandHeading1Excl" type="checkbox" value="0" class="togglemedium" checked required>
<span data-i18n="missionExclusive"></span>
</div>
<div class="point">
<label class="point-label-safehome" for="wpLandHeading2" data-i18n="missionFwLandHeading1"></label>
<input type="number" id="wpLandHeading2"></input>
<input id="wpLandHeading2Excl" type="checkbox" value="0" class="togglemedium" checked required>
<span data-i18n="missionExclusive"></span>
</div>
</div>
<!-- <div class="point-radio" id="pointOptionclass" style="display: none">
<div class="radio-line">
<input type="radio" id="Options_None" name="Options" value="None" checked>
@ -332,7 +464,6 @@
<input id="Options_HeadingHead" type="text" value="-1" required><br>
</div>
</div> -->
</div>
</div>
</div>

File diff suppressed because it is too large Load diff

View file

@ -15,11 +15,26 @@
<span data-i18n="platformType"></span>
</label>
</div>
<div class="checkbox">
<input id="motor_direction_inverted" type="checkbox" class="toggle" data-setting="motor_direction_inverted" />
<label for="motor_direction_inverted"><span data-i18n="motor_direction_inverted"></span></label>
<div class="radio">
<fieldset>
<legend>Motor direction</legend>
<label for="motor_direction_normal">
<input id="motor_direction_normal" name="motor_direction_inverted" type="radio"
value="0" data-setting="motor_direction_inverted" class="left" />
<span data-i18n="motor_direction_inverted"></span>
</label><br class="clear-both"/>
<label class="checkbox-inline">
<input id="motor_direction_inverted" name="motor_direction_inverted" type="radio"
value="1" data-setting="motor_direction_inverted" class="left"/>
<span data-i18n="motor_direction_isInverted"></span>
</span></label>
<div class="helpicon cf_tip" data-i18n_title="motor_direction_inverted_hint"></div>
</fieldset>
</div>
<div class="checkbox">
<input id="mixer_pid_profile_linking" type="checkbox" class="toggle" data-setting="mixer_pid_profile_linking" />
<label for="mixer_pid_profile_linking"><span data-i18n="mixer_pid_profile_linking"></span></label>

View file

@ -641,25 +641,17 @@ TABS.mixer.initialize = function (callback, scrollPosition) {
});
const updateMotorDirection = function () {
let motorDirectionCheckbox = $("#motor_direction_inverted");
const isReversed = motorDirectionCheckbox.is(":checked") && (MIXER_CONFIG.platformType == PLATFORM_MULTIROTOR || MIXER_CONFIG.platformType == PLATFORM_TRICOPTER);
let motorDirectionCheckbox = $('input[name=motor_direction_inverted]:checked');
const isReversed = motorDirectionCheckbox.val() == 1 && (MIXER_CONFIG.platformType == PLATFORM_MULTIROTOR || MIXER_CONFIG.platformType == PLATFORM_TRICOPTER);
const path = './resources/motor_order/'
+ currentMixerPreset.image + (isReversed ? "_reverse" : "") + '.svg';
$('.mixerPreview img').attr('src', path);
if (MIXER_CONFIG.platformType == PLATFORM_MULTIROTOR || MIXER_CONFIG.platformType == PLATFORM_TRICOPTER) {
if (isReversed) {
motorDirectionCheckbox.parent().find("label span").html(chrome.i18n.getMessage("motor_direction_isInverted"));
} else {
motorDirectionCheckbox.parent().find("label span").html(chrome.i18n.getMessage("motor_direction_inverted"));
}
}
renderServoOutputImage();
};
$("#motor_direction_inverted").change(updateMotorDirection);
$("input[name=motor_direction_inverted]").change(updateMotorDirection);
$platformSelect.find("*").remove();

View file

@ -326,6 +326,16 @@
</label>
</div>
</div>
<div class="gui_box grey custom-element-container">
<div class="gui_box_titlebar">
<div class="spacer_box_title" data-i18n="osd_custom_element_settings"></div>
</div>
<div class="spacer_box settings" id="osdCustomElements"></div>
</div>
<div class="gui_box grey pan-servo-container">
<div class="gui_box_titlebar">
<div for="osd_pan_servo_settings" class="helpicon cf_tip" data-i18n_title="osd_pan_servo_settings_HELP"></div>
@ -435,6 +445,12 @@
<a class="flash_font active" data-i18n="osd_font_upload"></a>
</div>
</div>
<div id="fonttypeselectorcontent" style="display:none; width:712px;">
<div class="font-picker" style="margin-bottom: 10px;">
<h1 class="tab_title">Font:</h1>
<div class="content_wrapper font-preview"></div>
</div>
</div>
<div class="clear-both"></div>
</div>
</div>

View file

@ -341,7 +341,7 @@ FONT.preview = function ($el) {
$el.empty();
for (var i = 1; i <= SYM.LAST_CHAR; i++) {
var url = FONT.data.character_image_urls[i];
$el.append('<img src="' + url + '" title="0x' + i.toString(16) + '"></img> ');
$el.append('<img src="' + url + '" title="0x' + i.toString(16) + ' (' + i.toString(10) + ') "></img> ');
}
};
@ -1865,7 +1865,28 @@ OSD.constants = {
id: 116,
positionable: true,
preview: 'G3:30126'
}
},
{
name: 'CUSTOM ELEMENT 1',
id: 147,
min_version: '7.1.0',
positionable: true,
preview: "CE_1",
},
{
name: 'CUSTOM ELEMENT 2',
id: 148,
min_version: '7.1.0',
positionable: true,
preview: "CE_2",
},
{
name: 'CUSTOM ELEMENT 3',
id: 149,
min_version: '7.1.0',
positionable: true,
preview: "CE_3",
},
]
},
{
@ -2158,6 +2179,11 @@ OSD.reload = function(callback) {
});
});
});
if(semver.gte(CONFIG.flightControllerVersion, '7.1.0'))
{
MSP.send_message(MSPCodes.MSP2_INAV_CUSTOM_OSD_ELEMENTS);
}
};
OSD.updateSelectedLayout = function(new_layout) {
@ -3397,9 +3423,265 @@ TABS.osd.initialize = function (callback) {
usePitot = (SENSOR_CONFIG.pitot != 0);
GUI.content_ready(callback);
});
if(semver.gte(CONFIG.flightControllerVersion, '7.1.0')) {
mspHelper.loadOsdCustomElements(createCustomElements);
}
}));
};
function createCustomElements(){
if(OSD_CUSTOM_ELEMENTS.settings.customElementsCount == 0){
$('.custom-element-container').remove();
return;
}
var customElementsContainer = $('#osdCustomElements');
for(var i = 0; i < OSD_CUSTOM_ELEMENTS.settings.customElementsCount; i++){
var label = $('<label>');
var customElementTable = $('<table>').addClass('osdCustomElement_main_table');
var customElementRowType = $('<tr>').data('row', i);
var customElementRowValue = $('<tr>').data('row', i);
var customElementLabel = $('<tr>');
for(var ii = 0; ii < 3; ii++){
var select = $('<select>').addClass('osdCustomElement-' + i + '-part-' + ii + '-type').data('valueCellClass', 'osdCustomElement-' + i + '-part-' + ii + '-value').html(`
<option value="0">none</option>
<option data-value="text" value="1">Text</option>
<option data-value="ico" value="2">Icon Static</option>
<option data-value="ico_gv" value="3">Icon Global Variable</option>
<option data-value="gv" value="4">Global Variable 00000</option>
<option data-value="gv" value="5">Global Variable 000.00</option>
<option data-value="gv" value="6">Global Variable 000</option>
<option data-value="gv" value="7">Global Variable 0.0</option>
`);
customElementRowType.append($('<td>').append(select));
customElementRowValue.append($('<td>').addClass('osdCustomElement-' + i + '-part-' + ii + '-value').append(
$('<input>').addClass('value').addClass('text').attr('type', 'text').attr('maxlength', OSD_CUSTOM_ELEMENTS.settings.customElementTextSize).hide()
).append(
$('<input>').addClass('value').addClass('ico').attr('min', 1).attr('max', 255).hide()
).append(
$('<select>').addClass('value').addClass('ico_gv').html(getGVoptions()).hide()
).append(
$('<select>').addClass('value').addClass('gv').html(getGVoptions()).hide()
));
select.change(function(){
var dataValue = $(this).find(':selected').data('value');
var valueBlock = $('.' + $(this).data('valueCellClass'))
valueBlock.find('.value').hide();
valueBlock.find('.' + dataValue).show();
});
}
var selectVisibility = $('<select>').addClass('osdCustomElement-' + i + '-visibility-type').data('valueCellClass', 'osdCustomElement-' + i + '-visibility-value').html(`
<option value="0">always</option>
<option data-value="gv" value="1">Global Variable</option>
<option data-value="lc" value="2">Logic Condition</option>
`);
customElementRowType.append($('<td>').append(selectVisibility));
customElementRowValue.append($('<td>').addClass('osdCustomElement-' + i + '-visibility-value').append(
$('<select>').addClass('value').addClass('gv').html(getGVoptions()).hide()
).append(
$('<select>').addClass('value').addClass('lc').html(getLCoptions()).hide()
));
selectVisibility.change(function(){
var dataValue = $(this).find(':selected').data('value');
var valueBlock = $('.' + $(this).data('valueCellClass'))
valueBlock.find('.value').hide();
valueBlock.find('.' + dataValue).show();
});
customElementLabel.append($('<td>').attr('colspan', 2).append($('<span>').html(chrome.i18n.getMessage("custom_element") + ' ' + (i + 1))));
customElementTable.append(customElementRowType).append(customElementRowValue).append(customElementLabel);
label.append(customElementTable);
customElementsContainer.append(label);
}
fillCustomElementsValues();
customElementsInitCallback();
}
function fillCustomElementsValues() {
for (var i = 0; i < OSD_CUSTOM_ELEMENTS.settings.customElementsCount; i++) {
for (var ii = 0; ii < 3; ii++) {
$('.osdCustomElement-' + i + '-part-' + ii + '-type').val(OSD_CUSTOM_ELEMENTS.items[i].customElementItems[ii].type).trigger('change');
var valueCell = $('.osdCustomElement-' + i + '-part-' + ii + '-value');
switch (OSD_CUSTOM_ELEMENTS.items[i].customElementItems[ii].type){
case 1:
valueCell.find('.text').val(OSD_CUSTOM_ELEMENTS.items[i].customElementText).trigger('change');
break;
case 2:
valueCell.find('.ico').val(OSD_CUSTOM_ELEMENTS.items[i].customElementItems[ii].value).trigger('change');
break;
case 3:
valueCell.find('.ico_gv').val(OSD_CUSTOM_ELEMENTS.items[i].customElementItems[ii].value).trigger('change');
break;
case 4:
case 5:
case 6:
case 7:
valueCell.find('.gv').val(OSD_CUSTOM_ELEMENTS.items[i].customElementItems[ii].value).trigger('change');
break;
}
}
$('.osdCustomElement-' + i + '-visibility-type').val(OSD_CUSTOM_ELEMENTS.items[i].customElementVisibility.type).trigger('change');
var valueVisibilityCell = $('.osdCustomElement-' + i + '-visibility-value');
switch (OSD_CUSTOM_ELEMENTS.items[i].customElementVisibility.type){
case 1:
valueVisibilityCell.find('.gv').val(OSD_CUSTOM_ELEMENTS.items[i].customElementVisibility.value).trigger('change');
break;
case 2:
valueVisibilityCell.find('.lc').val(OSD_CUSTOM_ELEMENTS.items[i].customElementVisibility.value).trigger('change');
break;
}
customElementNormaliseRow(i);
customElementDisableNonValidOptionsRow(i);
}
}
function customElementsInitCallback() {
var callback = function(){
var row = $(this).closest('tr').data('row');
customElementNormaliseRow(row);
customElementDisableNonValidOptionsRow(row);
MSP.promise(MSPCodes.MSP2_INAV_SET_CUSTOM_OSD_ELEMENTS, customElementGetDataForRow(row));
};
var customElements = $('#osdCustomElements')
customElements.find('input, select').change(callback);
customElements.find('input').keyup(callback);
}
function customElementNormaliseRow(row){
for(var i = 0; i < 3; i++){
var elementType = $('.osdCustomElement-' + row + '-part-' + i + '-type');
var valueCell = $('.' + elementType.data('valueCellClass'));
switch (parseInt(elementType.val())){
case 1:
valueCell.find('.text').val(valueCell.find('.text').val().toUpperCase());
valueCell.find('.text').val(valueCell.find('.text').val().replace(/[^A-Z0-9!.\* ]/g, ""));
break;
case 2:
valueCell.find('.ico').val(valueCell.find('.ico').val() > 255 ? 255 : valueCell.find('.ico').val());
valueCell.find('.ico').val(valueCell.find('.ico').val() < 1 ? 1 : valueCell.find('.ico').val());
}
}
}
function customElementDisableNonValidOptionsRow(row){
var selectedTextIndex = false;
for(let i = 0; i < 3; i++){
let elementType = $('.osdCustomElement-' + row + '-part-' + i + '-type');
if(parseInt(elementType.val()) === 1)
{
selectedTextIndex = i;
break;
}
}
for(let i = 0; i < 3; i++){
let elementType = $('.osdCustomElement-' + row + '-part-' + i + '-type');
if(i !== selectedTextIndex && selectedTextIndex !== false){
elementType.find('option[value="1"]').attr('disabled', 'disabled');
}else{
elementType.find('option[value="1"]').removeAttr('disabled');
}
}
}
function customElementGetDataForRow(row){
var data = [];
data.push8(row);
var text = "";
for(var ii = 0; ii < 3; ii++){
var elementType = $('.osdCustomElement-' + row + '-part-' + ii + '-type');
var valueCell = $('.' + elementType.data('valueCellClass'));
var partValue = 0;
switch (parseInt(elementType.val())){
case 1:
text = valueCell.find('.text').val();
break;
case 2:
partValue = parseInt(valueCell.find('.ico').val());
break;
case 3:
partValue = parseInt(valueCell.find('.ico_gv').find(':selected').val());
break;
case 4:
case 5:
case 6:
case 7:
partValue = parseInt(valueCell.find('.gv').find(':selected').val());
break;
}
data.push8(parseInt(elementType.val()));
data.push16(partValue);
}
var elementVisibilityType = $('.osdCustomElement-' + row + '-visibility-type');
var valueVisibilityCell = $('.' + elementVisibilityType.data('valueCellClass'));
var visibilityValue = null;
switch (parseInt(elementVisibilityType.val())){
case 1:
visibilityValue = parseInt(valueVisibilityCell.find('.gv').find(':selected').val());
break;
case 2:
visibilityValue = parseInt(valueVisibilityCell.find('.lc').find(':selected').val());
break;
}
data.push8(parseInt(elementVisibilityType.val()));
data.push16(visibilityValue);
for(var i = 0; i < OSD_CUSTOM_ELEMENTS.settings.customElementTextSize; i++){
if(i < text.length){
data.push8(text.charCodeAt(i))
}else{
data.push8(0);
}
}
return data;
}
function getGVoptions(){
var result = '';
for(var i = 0; i < 8; i++){
result += `<option value="` + i + `">GV `+i+`</option>`;
}
return result;
}
function getLCoptions(){
var result = '';
for(var i = 0; i < 64; i++){
result += `<option value="` + i + `">LC `+i+`</option>`;
}
return result;
}
function refreshOSDSwitchIndicators() {
let group = OSD.constants.ALL_DISPLAY_GROUPS.filter(function(e) {
return e.name == "osdGroupSwitchIndicators";
@ -3421,7 +3703,7 @@ function refreshOSDSwitchIndicators() {
}
OSD.GUI.updatePreviews();
};
}
function updatePilotAndCraftNames() {
let foundPilotName = ($('#pilot_name').val() == undefined);

View file

@ -30,7 +30,6 @@ TABS.outputs.initialize = function (callback) {
mspHelper.loadMotorMixRules,
mspHelper.loadServoMixRules,
mspHelper.loadMixerConfig,
mspHelper.loadServoMixRules,
mspHelper.loadServoConfiguration,
mspHelper.loadOutputMapping,
mspHelper.loadRcData,