mirror of
https://github.com/iNavFlight/inav-configurator.git
synced 2025-07-13 19:40:22 +03:00
Merge pull request #1738 from Scavanger/SITL-Integration
SITL integration
This commit is contained in:
commit
448d9dc3ba
26 changed files with 6597 additions and 5710 deletions
|
@ -139,8 +139,124 @@
|
|||
"tabAuxiliary": {
|
||||
"message": "Modes"
|
||||
},
|
||||
|
||||
"serialPortOpened": {
|
||||
"tabSitl": {
|
||||
"message" : "SITL"
|
||||
},
|
||||
"sitlDemoMode": {
|
||||
"message": "Demo Mode"
|
||||
},
|
||||
"sitlResetDemoModeData": {
|
||||
"message": "Reset Demo Mode"
|
||||
},
|
||||
"sitlOSNotSupported": {
|
||||
"message": "SITL is not supported on this operating system."
|
||||
},
|
||||
"sitlOptions": {
|
||||
"message": "SITL Options"
|
||||
},
|
||||
"sitlEnableSim": {
|
||||
"message": "Enable simulator"
|
||||
},
|
||||
"sitlSimulator": {
|
||||
"message": "Simulator"
|
||||
},
|
||||
"sitlUseImu": {
|
||||
"message": "Use IMU"
|
||||
},
|
||||
"sitlSimIP": {
|
||||
"message" : "Simulator IP"
|
||||
},
|
||||
"sitlPort": {
|
||||
"message" : "Simulator Port"
|
||||
},
|
||||
"sitlChannelMap": {
|
||||
"message": "Channel Mapping"
|
||||
},
|
||||
"sitlSimInput": {
|
||||
"message": "Simulator Input"
|
||||
},
|
||||
"sitlInavOutput": {
|
||||
"message": "INAV Output"
|
||||
},
|
||||
"sitlLog": {
|
||||
"message": "Log"
|
||||
},
|
||||
"sitlStart": {
|
||||
"message": "Start"
|
||||
},
|
||||
"sitlStop": {
|
||||
"message": "Stop"
|
||||
},
|
||||
"sitlStopped": {
|
||||
"message": "SITL stopped\n"
|
||||
},
|
||||
"sitlProfiles": {
|
||||
"message": "SITL Profiles"
|
||||
},
|
||||
"sitlNew": {
|
||||
"message": "New"
|
||||
},
|
||||
"sitlSave": {
|
||||
"message": "Save"
|
||||
},
|
||||
"sitlDelete": {
|
||||
"message": "Delete"
|
||||
},
|
||||
"sitlNewProfile": {
|
||||
"message": "New SITL Profile"
|
||||
},
|
||||
"sitlEnterName": {
|
||||
"message": "(Profile name)"
|
||||
},
|
||||
"sitlProfileExists": {
|
||||
"message": "A profile with this name already exists."
|
||||
},
|
||||
"sitlStdProfileCantDeleted": {
|
||||
"message": "SITL standard profile can't be deleted."
|
||||
},
|
||||
"sitlSerialToTCP": {
|
||||
"message": "Serial to TCP (UART)"
|
||||
},
|
||||
"sitlSerialProtocoll": {
|
||||
"message": "Preset for RX Protocoll"
|
||||
},
|
||||
"sitlSerialStopbits": {
|
||||
"message": "Stopbits"
|
||||
},
|
||||
"sitlSerialPort": {
|
||||
"message": "Serial port"
|
||||
},
|
||||
"sitlSerialTCPPort": {
|
||||
"message": "TCP port"
|
||||
},
|
||||
"sitlSerialParity": {
|
||||
"message": "Parity"
|
||||
},
|
||||
"sitlSerialTcpEnable": {
|
||||
"message": "Enable"
|
||||
},
|
||||
"sitlHelp": {
|
||||
"message": "SITL (Software in the loop) allows to run INAV completely in software on the PC without using a flight controller and simulate complete FPV flights. For this, INAV is compiled with a normal PC compiler. The sensors are replaced by data provided by a simulator.<br/>Currently supported are:<br/><ul><li><a href=\"https://www.realflight.com\" target=\"_blank\">RealFlight</a><br/></li><li><a href=\"https://www.x-plane.com\" target=\"_blank\">X-Plane</a></li></ul>"
|
||||
},
|
||||
"sitlProfilesHelp": {
|
||||
"message": "Profiles are saved locally. The profiles contain not only all data of this tab, but also the configuration file (\"EEPROM\") of INAV itself."
|
||||
},
|
||||
"sitlEnableSimulatorHelp": {
|
||||
"message": "If this option is deactivated, only the Configurator can be used. Useful to configure INAV without having to start the simulator."
|
||||
},
|
||||
"sitlUseImuHelp": {
|
||||
"message": "Use IMU sensor data from the simulator instead of using attitude data from the simulator directly (Experimental, not recommended)."
|
||||
},
|
||||
"sitlIpHelp": {
|
||||
"message": "IP address of the computer on which the simulator is running. If the simulator is running on the same computer, leave it at \"127.0.0.1"
|
||||
},
|
||||
"sitlPortHelp": {
|
||||
"message": "Port number of the interface of the simulator. Note: The RealFlight port is fixed and cannot be changed."
|
||||
},
|
||||
"sitlSer2TcpHelp": {
|
||||
"message": "Devices with a UART interface can be used with SITL via a serial to USB interface. Especially intended for serial receivers to use the full number of channels. "
|
||||
},
|
||||
"serialPortOpened": {
|
||||
"message": "MSP connection <span style=\"color: #37a8db\">successfully</span> opened with ID: $1"
|
||||
},
|
||||
"serialPortOpenFail": {
|
||||
|
|
|
@ -136,6 +136,7 @@ sources.js = [
|
|||
'./js/waypoint.js',
|
||||
'./node_modules/openlayers/dist/ol.js',
|
||||
'./js/libraries/plotly-latest.min.js',
|
||||
'./js/sitl.js',
|
||||
];
|
||||
|
||||
sources.receiverCss = [
|
||||
|
@ -252,6 +253,8 @@ gulp.task('dist-build', gulp.series('build', function() {
|
|||
'./resources/models/*',
|
||||
'./resources/osd/analogue/*.mcm',
|
||||
'./resources/motor_order/*.svg',
|
||||
'./resources/sitl/windows/*',
|
||||
'./resources/sitl/linux/*'
|
||||
];
|
||||
return gulp.src(distSources, { base: '.' })
|
||||
.pipe(gulp.dest(distDir));
|
||||
|
@ -268,7 +271,8 @@ gulp.task('apps', gulp.series('dist', function(done) {
|
|||
flavor: 'normal',
|
||||
macIcns: './images/inav.icns',
|
||||
winIco: './images/inav.ico',
|
||||
version: get_nw_version()
|
||||
version: get_nw_version(),
|
||||
zip: false
|
||||
});
|
||||
builder.on('log', console.log);
|
||||
builder.build(function (err) {
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 141.7 141.7" enable-background="new 0 0 141.7 141.7" xml:space="preserve">
|
||||
width="283.46px" height="141.73px" viewBox="0 0 283.46 141.73" enable-background="new 0 0 283.46 141.73" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#FFFFFF" d="M137.9,36.3c-0.1-1.2-0.9-2.2-2-2.6c-1.1-0.4-2.4-0.1-3.2,0.7l-17.4,17.4l-19.3-6.1l-6.1-19.3l17.4-17.4
|
||||
c0.9-0.9,1.1-2.1,0.7-3.2c-0.4-1.1-1.4-1.9-2.6-2C94.7,2.7,84.3,6.5,76.8,14c-10.3,10.3-13,25.3-8.2,38c-0.5,0.4-1,0.9-1.6,1.4
|
||||
L9,108.3c0,0,0,0-0.1,0.1c-6.8,6.8-6.8,18,0,24.8c6.8,6.8,17.9,6.8,24.7-0.1c0,0,0.1-0.1,0.1-0.1l54.4-58.6c0.5-0.5,1-1,1.4-1.6
|
||||
c12.8,4.8,27.8,2.1,38-8.2C135,57.2,138.8,46.9,137.9,36.3z M24.9,125.8c-2.5,2.5-6.6,2.5-9.1,0c-2.5-2.5-2.5-6.6,0-9.1
|
||||
c2.5-2.5,6.6-2.5,9.1,0C27.4,119.2,27.4,123.3,24.9,125.8z"/>
|
||||
<circle fill="#999999" cx="141.73" cy="100.25" r="5.271"/>
|
||||
<path fill="#999999" d="M160.347,114.468h-37.234c0.025,7.52-4.19,12.583-9.941,16.749h57.114
|
||||
C163.099,126.682,160.447,120.906,160.347,114.468z"/>
|
||||
<path fill="#999999" d="M213.125,6H70.336c-2.261,0-4.104,1.843-4.104,4.104v94.594c0,2.262,1.843,4.104,4.104,4.104h142.789
|
||||
c2.262,0,4.104-1.844,4.104-4.104V10.104C217.228,7.843,215.386,6,213.125,6z M141.73,105.521c-2.912,0-5.271-2.359-5.271-5.271
|
||||
s2.359-5.271,5.271-5.271s5.272,2.359,5.272,5.271S144.642,105.521,141.73,105.521z M208.515,88.036
|
||||
c0,1.99-1.633,3.624-3.623,3.624H78.581c-1.99,0-3.625-1.634-3.625-3.624V17.354c-0.012-1.991,1.622-3.625,3.625-3.625h126.311
|
||||
c2.002,0,3.623,1.634,3.623,3.625V88.036z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 934 B After Width: | Height: | Size: 1.2 KiB |
16
images/icons/cf_icon_sitl_grey.svg
Normal file
16
images/icons/cf_icon_sitl_grey.svg
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="141.7px" height="141.7px" viewBox="0 0 141.7 141.7" enable-background="new 0 0 141.7 141.7" xml:space="preserve">
|
||||
<g>
|
||||
<circle fill="#9A9999" cx="70.85" cy="102.911" r="4.754"/>
|
||||
<path fill="#9A9999" d="M87.639,115.732H54.062c0.021,6.782-3.779,11.349-8.966,15.105h51.508
|
||||
C90.122,126.748,87.729,121.538,87.639,115.732z"/>
|
||||
<path fill="#9A9999" d="M135.235,17.913H6.465c-2.039,0-3.701,1.663-3.701,3.702v85.308c0,2.04,1.662,3.7,3.701,3.7h128.771
|
||||
c2.039,0,3.701-1.662,3.701-3.7V21.615C138.937,19.576,137.274,17.913,135.235,17.913z M70.85,107.665
|
||||
c-2.626,0-4.754-2.128-4.754-4.754c0-2.627,2.128-4.755,4.754-4.755c2.628,0,4.756,2.128,4.756,4.755
|
||||
C75.605,105.537,73.478,107.665,70.85,107.665z M131.079,91.896c0,1.795-1.474,3.269-3.27,3.269H13.9
|
||||
c-1.796,0-3.269-1.474-3.269-3.269V28.153c-0.011-1.795,1.462-3.269,3.269-3.269H127.81c1.807,0,3.27,1.474,3.27,3.269V91.896z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
16
images/icons/cf_icon_sitl_white.svg
Normal file
16
images/icons/cf_icon_sitl_white.svg
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Ebene_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="141.7px" height="141.7px" viewBox="0 0 141.7 141.7" enable-background="new 0 0 141.7 141.7" xml:space="preserve">
|
||||
<g>
|
||||
<circle fill="#FFFFFF" cx="70.85" cy="102.911" r="4.754"/>
|
||||
<path fill="#FFFFFF" d="M87.639,115.732H54.062c0.021,6.782-3.779,11.349-8.966,15.105h51.508
|
||||
C90.122,126.748,87.729,121.538,87.639,115.732z"/>
|
||||
<path fill="#FFFFFF" d="M135.235,17.913H6.465c-2.039,0-3.701,1.663-3.701,3.702v85.308c0,2.04,1.662,3.7,3.701,3.7h128.771
|
||||
c2.039,0,3.701-1.662,3.701-3.7V21.615C138.937,19.576,137.274,17.913,135.235,17.913z M70.85,107.665
|
||||
c-2.626,0-4.754-2.128-4.754-4.754c0-2.627,2.128-4.755,4.754-4.755c2.628,0,4.756,2.128,4.756,4.755
|
||||
C75.605,105.537,73.478,107.665,70.85,107.665z M131.079,91.896c0,1.795-1.474,3.269-3.27,3.269H13.9
|
||||
c-1.796,0-3.269-1.474-3.269-3.269V28.153c-0.011-1.795,1.462-3.269,3.269-3.269H127.81c1.807,0,3.27,1.474,3.27,3.269V91.896z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
BIN
images/inav.ico
BIN
images/inav.ico
Binary file not shown.
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 44 KiB |
3
js/fc.js
3
js/fc.js
|
@ -596,7 +596,8 @@ var FC = {
|
|||
'NMEA',
|
||||
'UBLOX',
|
||||
'UBLOX7',
|
||||
'MSP'
|
||||
'MSP',
|
||||
'FAKE'
|
||||
];
|
||||
},
|
||||
getGpsBaudRates: function () {
|
||||
|
|
|
@ -14,6 +14,7 @@ var GUI_control = function () {
|
|||
'landing',
|
||||
'firmware_flasher',
|
||||
'mission_control',
|
||||
'sitl',
|
||||
'help'
|
||||
];
|
||||
this.defaultAllowedTabsWhenConnected = [
|
||||
|
|
|
@ -69,7 +69,7 @@ PortHandler.check = function () {
|
|||
chrome.storage.local.get('last_used_port', function (result) {
|
||||
// if last_used_port was set, we try to select it
|
||||
if (result.last_used_port) {
|
||||
if (result.last_used_port == "ble" || result.last_used_port == "tcp" || result.last_used_port == "udp") {
|
||||
if (result.last_used_port == "ble" || result.last_used_port == "tcp" || result.last_used_port == "udp" || result.last_used_port == "sitl" || result.last_used_port == "sitl-demo") {
|
||||
$('#port').val(result.last_used_port);
|
||||
} else {
|
||||
current_ports.forEach(function(port) {
|
||||
|
@ -184,6 +184,8 @@ PortHandler.update_port_select = function (ports) {
|
|||
$('div#port-picker #port').append($("<option/>", {value: 'ble', text: 'BLE', data: {isBle: true}}));
|
||||
$('div#port-picker #port').append($("<option/>", {value: 'tcp', text: 'TCP', data: {isTcp: true}}));
|
||||
$('div#port-picker #port').append($("<option/>", {value: 'udp', text: 'UDP', data: {isUdp: true}}));
|
||||
$('div#port-picker #port').append($("<option/>", {value: 'sitl', text: 'SITL', data: {isSitl: true}}));
|
||||
$('div#port-picker #port').append($("<option/>", {value: 'sitl-demo', text: 'Demo mode', data: {isSitl: true}}));
|
||||
};
|
||||
|
||||
PortHandler.port_detected = function(name, code, timeout, ignore_timeout) {
|
||||
|
|
|
@ -5,7 +5,8 @@ $(document).ready(function () {
|
|||
|
||||
var $port = $('#port'),
|
||||
$baud = $('#baud'),
|
||||
$portOverride = $('#port-override');
|
||||
$portOverride = $('#port-override'),
|
||||
isDemoRunning = false;
|
||||
|
||||
/*
|
||||
* Handle "Wireless" mode with strict queueing of messages
|
||||
|
@ -89,14 +90,14 @@ $(document).ready(function () {
|
|||
$('#port-override-label').text("Port");
|
||||
}
|
||||
|
||||
if (selected_port.data().isDFU || selected_port.data().isBle || selected_port.data().isTcp || selected_port.data().isUdp) {
|
||||
if (selected_port.data().isDFU || selected_port.data().isBle || selected_port.data().isTcp || selected_port.data().isUdp || selected_port.data().isSitl) {
|
||||
$baud.hide();
|
||||
}
|
||||
else {
|
||||
$baud.show();
|
||||
}
|
||||
|
||||
if (selected_port.data().isBle || selected_port.data().isTcp || selected_port.data().isUdp) {
|
||||
if (selected_port.data().isBle || selected_port.data().isTcp || selected_port.data().isUdp || selected_port.data().isSitl) {
|
||||
$('.tab_firmware_flasher').hide();
|
||||
} else {
|
||||
$('.tab_firmware_flasher').show();
|
||||
|
@ -104,7 +105,7 @@ $(document).ready(function () {
|
|||
var type = ConnectionType.Serial;
|
||||
if (selected_port.data().isBle) {
|
||||
type = ConnectionType.BLE;
|
||||
} else if (selected_port.data().isTcp) {
|
||||
} else if (selected_port.data().isTcp || selected_port.data().isSitl) {
|
||||
type = ConnectionType.TCP;
|
||||
} else if (selected_port.data().isUdp) {
|
||||
type = ConnectionType.UDP;
|
||||
|
@ -150,10 +151,24 @@ $(document).ready(function () {
|
|||
|
||||
if (selected_port == 'tcp' || selected_port == 'udp') {
|
||||
CONFIGURATOR.connection.connect($portOverride.val(), {}, onOpen);
|
||||
} else if (selected_port == 'sitl') {
|
||||
CONFIGURATOR.connection.connect("127.0.0.1:5760", {}, onOpen);
|
||||
} else if (selected_port == 'sitl-demo') {
|
||||
if (SITLProcess.isRunning) {
|
||||
SITLProcess.stop();
|
||||
}
|
||||
SITLProcess.start("demo.bin");
|
||||
this.isDemoRunning = true;
|
||||
CONFIGURATOR.connection.connect("127.0.0.1:5760", {}, onOpen);
|
||||
} else {
|
||||
CONFIGURATOR.connection.connect(selected_port, {bitrate: selected_baud}, onOpen);
|
||||
}
|
||||
} else {
|
||||
if (this.isDemoRunning) {
|
||||
SITLProcess.stop();
|
||||
this.isDemoRunning = false;
|
||||
}
|
||||
|
||||
var wasConnected = CONFIGURATOR.connectionValid;
|
||||
|
||||
helper.timeout.killAll();
|
||||
|
|
270
js/sitl.js
Normal file
270
js/sitl.js
Normal file
|
@ -0,0 +1,270 @@
|
|||
'use strict'
|
||||
|
||||
const { spawn } = require('node:child_process');
|
||||
const pathMod = require('path');
|
||||
const { chmod, rm } = require('node:fs');
|
||||
|
||||
const serialRXProtocolls = [
|
||||
{
|
||||
name : "SBus",
|
||||
baudrate: 100000,
|
||||
stopBits: "Two",
|
||||
parity: "Even"
|
||||
},
|
||||
{
|
||||
name : "SBus Fast",
|
||||
baudrate: 200000,
|
||||
stopBits: "Two",
|
||||
parity: "Even"
|
||||
},
|
||||
{
|
||||
name : "Crossfire/Ghost",
|
||||
baudrate: 420000,
|
||||
stopBits: "One",
|
||||
parity: "None"
|
||||
},
|
||||
{
|
||||
name : "FPort/IBus/Spektrum/SRXL2/SUMD",
|
||||
baudrate: 115200,
|
||||
stopBits: "One",
|
||||
parity: "None"
|
||||
},
|
||||
{
|
||||
name : "JETI EX Bus",
|
||||
baudrate: 125000,
|
||||
stopBits: "One",
|
||||
parity: "None"
|
||||
},
|
||||
];
|
||||
|
||||
var Ser2TCP = {
|
||||
|
||||
isRunning: false,
|
||||
process: null,
|
||||
portsList: [],
|
||||
stopPolling: false,
|
||||
|
||||
getProtocolls: function() {
|
||||
return serialRXProtocolls;
|
||||
},
|
||||
|
||||
start: function(comPort, serialPortOptions, ipAddress, tcpPort, callback) {
|
||||
|
||||
if (this.isRunning)
|
||||
this.stop();
|
||||
|
||||
var path;
|
||||
if (GUI.operating_system == 'Windows') {
|
||||
path = './resources/sitl/windows/Ser2TCP.exe'
|
||||
} else if (GUI.operating_system == 'Linux') {
|
||||
path = './resources/sitl/linux/ser2TCP'
|
||||
chmod(path, 0o755, (err) => {
|
||||
if (err)
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
var protocoll = serialRXProtocolls.find(proto => {
|
||||
return proto.name == serialPortOptions.protocollName;
|
||||
});
|
||||
|
||||
var args = [];
|
||||
if (protocoll && protocoll.name != "manual") {
|
||||
args.push(`--comport=${comPort}`)
|
||||
args.push(`--baudrate=${protocoll.baudrate}`);
|
||||
args.push(`--stopbits=${protocoll.stopBits}`)
|
||||
args.push(`--parity=${protocoll.parity}`)
|
||||
args.push(`--ip=${ipAddress}`);
|
||||
args.push(`--tcpport=${tcpPort}`);
|
||||
} else {
|
||||
args.push(`--comport=${comPort}`)
|
||||
args.push(`--baudrate${proserialPortOptionstocoll.baudrate}`);
|
||||
args.push(`--stopbits=${protserialPortOptionsocoll.stopBits}`)
|
||||
args.push(`--parity=${serialPortOptions.parity}`)
|
||||
args.push(`--ip=${ipAddress}`);
|
||||
args.push(`--tcpport=${tcpPort}`);
|
||||
}
|
||||
|
||||
var opts = undefined;
|
||||
if (GUI.operating_system == 'Linux')
|
||||
opts = { useShell: true };
|
||||
|
||||
this.process = spawn(path, args, opts);
|
||||
this.isRunning = true;
|
||||
|
||||
this.process.stdout.on('data', (data) => {
|
||||
if (callback)
|
||||
callback(data);
|
||||
});
|
||||
|
||||
this.process.stderr.on('data', (data) => {
|
||||
if (callback)
|
||||
callback(data);
|
||||
});
|
||||
|
||||
this.process.on('error', (error) => {
|
||||
if (callback)
|
||||
callback(error);
|
||||
this.isRunning = false;
|
||||
});
|
||||
|
||||
this.process.on('exit', () => {
|
||||
if (this.isRunning)
|
||||
this.spawn(path, args, callback);
|
||||
});
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (this.isRunning) {
|
||||
this.isRunning = false;
|
||||
this.process.kill();
|
||||
}
|
||||
},
|
||||
|
||||
getDevices: function(callback) {
|
||||
chrome.serial.getDevices((devices_array) => {
|
||||
var devices = [];
|
||||
devices_array.forEach((device) => {
|
||||
|
||||
if (GUI.operating_system == 'Windows') {
|
||||
var m = device.path.match(/COM\d?\d/g)
|
||||
if (m)
|
||||
devices.push(m[0]);
|
||||
} else
|
||||
devices.push(device.displayName);
|
||||
});
|
||||
callback(devices);
|
||||
});
|
||||
},
|
||||
|
||||
pollSerialPorts: function(callback) {
|
||||
this.getDevices(devices => {
|
||||
if (!this.arraysEqual(this.portsList, devices)) {
|
||||
this.portsList = devices;
|
||||
if (callback)
|
||||
callback(this.portsList);
|
||||
}
|
||||
|
||||
});
|
||||
if (!this.stopPolling) {
|
||||
setTimeout(() => { this.pollSerialPorts(callback) }, 250);
|
||||
} else {
|
||||
this.stopPolling = false;
|
||||
}
|
||||
},
|
||||
|
||||
resetPortsList: function() {
|
||||
this.portsList = [];
|
||||
},
|
||||
|
||||
stopPollSerialPorts: function()
|
||||
{
|
||||
this.stopPolling = true;
|
||||
},
|
||||
|
||||
arraysEqual: function(a, b) {
|
||||
if (a === b) return true;
|
||||
if (a == null || b == null) return false;
|
||||
if (a.length !== b.length) return false;
|
||||
|
||||
for (var i = 0; i < a.length; ++i) {
|
||||
if (a[i] !== b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var SITLProcess = {
|
||||
|
||||
spawn : null,
|
||||
isRunning: false,
|
||||
process: null,
|
||||
|
||||
deleteEepromFile(filename) {
|
||||
rm(`${nw.App.dataPath}/${filename}`, error => {
|
||||
if (error) {
|
||||
GUI.log(`Unable to reset Demo mode: ${error.message}`);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
start: function(eepromFileName, sim, useIMU, simIp, simPort, channelMap, callback) {
|
||||
|
||||
if (this.isRunning)
|
||||
this.stop();
|
||||
|
||||
var sitlExePath, eepromPath;
|
||||
if (GUI.operating_system == 'Windows') {
|
||||
sitlExePath = './resources/sitl/windows/inav_SITL.exe'
|
||||
eepromPath = `${nw.App.dataPath}\\${eepromFileName}`
|
||||
} else if (GUI.operating_system == 'Linux') {
|
||||
sitlExePath = './resources/sitl/linux/inav_SITL';
|
||||
eepromPath = `${nw.App.dataPath}/${eepromFileName}`
|
||||
chmod(sitlExePath, 0o755, err => {
|
||||
if (err)
|
||||
console.log(err);
|
||||
});
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
var args = [];
|
||||
args.push(`--path=${eepromPath}`);
|
||||
|
||||
if (sim) {
|
||||
args.push(`--sim=${sim}`);
|
||||
if (useIMU)
|
||||
args.push("--useimu")
|
||||
|
||||
if (simIp)
|
||||
args.push(`--simip=${simIp}`);
|
||||
|
||||
if (simPort)
|
||||
args.push(`--simport=${simPort}`);
|
||||
|
||||
if (channelMap)
|
||||
args.push(`--chanmap=${channelMap}`)
|
||||
}
|
||||
this.spawn(sitlExePath, args, callback);
|
||||
},
|
||||
|
||||
spawn: function(path, args, callback) {
|
||||
|
||||
var opts = undefined;
|
||||
if (GUI.operating_system == 'Linux')
|
||||
opts = { useShell: true };
|
||||
|
||||
this.process = spawn(path, args, opts);
|
||||
this.isRunning = true;
|
||||
|
||||
this.process.stdout.on('data', (data) => {
|
||||
if (callback)
|
||||
callback(data);
|
||||
});
|
||||
|
||||
this.process.stderr.on('data', (data) => {
|
||||
if (callback)
|
||||
callback(data);
|
||||
});
|
||||
|
||||
this.process.on('error', (error) => {
|
||||
if (callback)
|
||||
callback(error);
|
||||
this.isRunning = false;
|
||||
});
|
||||
|
||||
this.process.on('exit', () => {
|
||||
if (this.isRunning)
|
||||
this.spawn(path, args, callback);
|
||||
});
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
if (this.isRunning) {
|
||||
this.isRunning = false;
|
||||
this.process.kill();
|
||||
}
|
||||
}
|
||||
};
|
12
main.css
12
main.css
|
@ -885,6 +885,18 @@ li.active .ic_flasher {
|
|||
background-image: url("../images/icons/cf_icon_flasher_white.svg");
|
||||
}
|
||||
|
||||
.ic_sitl {
|
||||
background-image: url("../images/icons/cf_icon_sitl_grey.svg");
|
||||
}
|
||||
|
||||
.ic_sitl:hover {
|
||||
background-image: url("../images/icons/cf_icon_sitl_white.svg");
|
||||
}
|
||||
|
||||
li.active .ic_sitl {
|
||||
background-image: url("../images/icons/cf_icon_sitl_white.svg");
|
||||
}
|
||||
|
||||
.ic_calibration {
|
||||
background-image: url(../images/icons/cf_icon_cal_grey.svg);
|
||||
}
|
||||
|
|
|
@ -178,6 +178,9 @@
|
|||
<li class="tab_firmware_flasher">
|
||||
<a href="#" data-i18n="tabFirmwareFlasher" class="tabicon ic_flasher" title="Firmware Flasher"></a>
|
||||
</li>
|
||||
<li class="tab_sitl">
|
||||
<a href="#" data-i18n="tabSitl" class="tabicon ic_sitl" title="SITL"></a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="mode-connected">
|
||||
<li class="tab_setup">
|
||||
|
|
6
main.js
6
main.js
|
@ -223,6 +223,9 @@ $(document).ready(function () {
|
|||
case 'firmware_flasher':
|
||||
TABS.firmware_flasher.initialize(content_ready);
|
||||
break;
|
||||
case 'sitl':
|
||||
TABS.sitl.initialize(content_ready);
|
||||
break;
|
||||
case 'auxiliary':
|
||||
TABS.auxiliary.initialize(content_ready);
|
||||
break;
|
||||
|
@ -412,6 +415,9 @@ $(document).ready(function () {
|
|||
});
|
||||
globalSettings.proxyLayer = $(this).val();
|
||||
});
|
||||
$('#demoModeReset').on('click', () => {
|
||||
SITLProcess.deleteEepromFile('demo.bin');
|
||||
});
|
||||
function close_and_cleanup(e) {
|
||||
if (e.type == 'click' && !$.contains($('div#options-window')[0], e.target) || e.type == 'keyup' && e.keyCode == 27) {
|
||||
$(document).unbind('click keyup', close_and_cleanup);
|
||||
|
|
11029
package-lock.json
generated
11029
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -36,7 +36,7 @@
|
|||
"jquery-ui-npm": "1.12.0",
|
||||
"marked": "^0.3.17",
|
||||
"minimist": "^1.2.0",
|
||||
"nw": "^0.61.0",
|
||||
"nw": "^0.61.0-sdk",
|
||||
"nw-dialog": "^1.0.7",
|
||||
"openlayers": "^4.6.5",
|
||||
"plotly": "^1.0.6",
|
||||
|
@ -45,12 +45,12 @@
|
|||
"xml2js": "^0.4.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@quanle94/innosetup": "^6.0.2",
|
||||
"gulp-debian": "^0.1.9",
|
||||
"gulp-rename": "^2.0.0",
|
||||
"nw-builder": "^3.5.7",
|
||||
"rpm-builder": "^1.2.1",
|
||||
"semver": "6.3.0",
|
||||
"@quanle94/innosetup": "^6.0.2"
|
||||
"semver": "6.3.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"appdmg": "^0.6.2"
|
||||
|
|
BIN
resources/sitl/linux/Ser2TCP
Normal file
BIN
resources/sitl/linux/Ser2TCP
Normal file
Binary file not shown.
BIN
resources/sitl/linux/inav_SITL
Normal file
BIN
resources/sitl/linux/inav_SITL
Normal file
Binary file not shown.
BIN
resources/sitl/linux/libSystem.IO.Ports.Native.so
Normal file
BIN
resources/sitl/linux/libSystem.IO.Ports.Native.so
Normal file
Binary file not shown.
BIN
resources/sitl/windows/Ser2TCP.exe
Normal file
BIN
resources/sitl/windows/Ser2TCP.exe
Normal file
Binary file not shown.
BIN
resources/sitl/windows/cygwin1.dll
Normal file
BIN
resources/sitl/windows/cygwin1.dll
Normal file
Binary file not shown.
BIN
resources/sitl/windows/inav_SITL.exe
Normal file
BIN
resources/sitl/windows/inav_SITL.exe
Normal file
Binary file not shown.
86
src/css/tabs/sitl.css
Normal file
86
src/css/tabs/sitl.css
Normal file
|
@ -0,0 +1,86 @@
|
|||
.tab-sitl input {
|
||||
width: 111px;
|
||||
padding-left: 3px;
|
||||
height: 18px;
|
||||
line-height: 20px;
|
||||
text-align: left;
|
||||
border: 1px solid silver;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.tab-sitl .simIP span {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.map-table td, .map-table th {
|
||||
padding: 2px;
|
||||
height: 2.5em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tab-sitl .switchery {
|
||||
margin-right: 68px !important;
|
||||
}
|
||||
|
||||
.map-table thead tr {
|
||||
border-left: 1px solid #e4e4e4;
|
||||
border-right: 1px solid #e4e4e4;
|
||||
background-color: #828885;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.map-table tr:nth-child(even) td,
|
||||
.map-table tr:nth-child(even) th {
|
||||
background-color: #ebe7e7;
|
||||
}
|
||||
|
||||
|
||||
.sitlNumber {
|
||||
margin-left: 14px;
|
||||
}
|
||||
|
||||
.map-table {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.tab-sitl .leftWrapper {
|
||||
float: left;
|
||||
width: calc(50% - 20px);
|
||||
}
|
||||
|
||||
.tab-sitl .rightWrapper {
|
||||
float: left;
|
||||
width: calc(50% - 0px);
|
||||
margin: 0 0 10px 20px;
|
||||
}
|
||||
|
||||
.sitlProfile_box {
|
||||
padding: 10px;
|
||||
margin-bottom: 3px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.sitlProfile_select {
|
||||
float:left;
|
||||
padding-top: 2px;
|
||||
padding-right: 10px
|
||||
}
|
||||
|
||||
.default_btn.sitlnarrow {
|
||||
width: auto;
|
||||
margin-bottom: 0;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.default_btn.sitlnarrow a {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
#sitlLog {
|
||||
resize: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box
|
||||
}
|
|
@ -67,5 +67,15 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-section gui_box grey">
|
||||
<div class="gui_box_titlebar">
|
||||
<div class="spacer_box_title" data-i18n="sitlDemoMode"></div>
|
||||
</div>
|
||||
<div class="spacer_box settings">
|
||||
<div class="default_btn" style="float: none; width: 200px;">
|
||||
<a id="demoModeReset" href="#" i18n="sitlResetDemoModeData"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
157
tabs/sitl.html
Normal file
157
tabs/sitl.html
Normal file
|
@ -0,0 +1,157 @@
|
|||
<div class="tab-sitl toolbar_fixed_bottom">
|
||||
<div class="content_wrapper">
|
||||
<div class="tab_title" data-i18n="tabSitl">SITL</div>
|
||||
<div class="note" style="margin-bottom: 20px;">
|
||||
<div class="note_spacer">
|
||||
<p data-i18n="sitlHelp"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="leftWrapper">
|
||||
<div class="gui_box grey">
|
||||
<div class="gui_box_titlebar">
|
||||
<div class="spacer_box_title" data-i18n="sitlProfiles"></div>
|
||||
<div class="helpicon cf_tip" data-i18n_title="sitlProfilesHelp"></div>
|
||||
</div>
|
||||
<div class="sitlProfile_box">
|
||||
<div class="sitlProfile_select">
|
||||
<select id="sitlProfile"></select>
|
||||
</div>
|
||||
<div class="default_btn sitlnarrow">
|
||||
<a id="sitlProfileNew" href="#" i18n="sitlNew"></a>
|
||||
</div>
|
||||
<div class="default_btn sitlnarrow">
|
||||
<a id="sitlProfileSave" href="#" i18n="sitlSave"></a>
|
||||
</div>
|
||||
<div class="default_btn sitlnarrow">
|
||||
<a id="sitlProfileDelete" href="#" i18n="sitlDelete"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="config-section gui_box grey">
|
||||
<div class="gui_box_titlebar">
|
||||
<div class="spacer_box_title" data-i18n="sitlOptions"></div>
|
||||
</div>
|
||||
<div class="spacer_box">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="sitlEnableSim" class="toggle" data-live="true">
|
||||
<label for="enableSim"><span data-i18n="sitlEnableSim"></span></label>
|
||||
<div class="helpicon cf_tip" data-i18n_title="sitlEnableSimulatorHelp"></div>
|
||||
</div>
|
||||
<div class="select">
|
||||
<select id="simulator"></select>
|
||||
<label for="simulator"> <span data-i18n="sitlSimulator"></span></label>
|
||||
</div>
|
||||
<div class="number">
|
||||
<input type="text" id="simIP" data-setting="simip" data-live="true" />
|
||||
<label for="simIP" class="sitlNumber"><span data-i18n="sitlSimIP"></span></label>
|
||||
<div class="helpicon cf_tip" data-i18n_title="sitlIpHelp"></div>
|
||||
</div>
|
||||
<div class="number">
|
||||
<input type="number" id="simPort" data-setting-multiplier="1" step="1" min="1" max="64500" />
|
||||
<label for="sitlPort" class="sitlNumber"><span data-i18n="sitlPort"></span></label>
|
||||
<div class="helpicon cf_tip" data-i18n_title="sitlPortHelp"></div>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="sitlUseImu" class="sitlUseImu toggle" data-live="true">
|
||||
<label for="sitlUseImu"><span data-i18n="sitlUseImu"></span></label>
|
||||
<div class="helpicon cf_tip" data-i18n_title="sitlUseImuHelp"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="gui_box grey">
|
||||
<div class="gui_box_titlebar">
|
||||
<div class="spacer_box_title" data-i18n="sitlLog"></div>
|
||||
</div>
|
||||
<div class="spacer_box">
|
||||
<textarea readonly id="sitlLog" rows="25"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="rightWrapper">
|
||||
<div class="gui_box grey">
|
||||
<div class="gui_box_titlebar">
|
||||
<div class="spacer_box_title" data-i18n="sitlChannelMap"></div>
|
||||
</div>
|
||||
<div class="spacer_box">
|
||||
<table id="channelMap-table" class="map-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 100px" data-i18n="sitlSimInput"></th>
|
||||
<th style="width: 100px" data-i18n="sitlInavOutput"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="mapTableBody">
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="config-section gui_box grey">
|
||||
<div class="gui_box_titlebar">
|
||||
<div class="spacer_box_title" data-i18n="sitlSerialToTCP"></div>
|
||||
<div class="helpicon cf_tip" data-i18n_title="sitlSer2TcpHelp"></div>
|
||||
</div>
|
||||
<div class="spacer_box">
|
||||
<div class="checkbox">
|
||||
<input type="checkbox" id="serialTcpEnable" class="toggle" data-live="true">
|
||||
<label for="serialTcpEnable"><span data-i18n="sitlSerialTcpEnable"></span></label>
|
||||
</div>
|
||||
<span id="serialTcpOptions">
|
||||
<div class="select">
|
||||
<select id="sitlSerialPort"></select>
|
||||
<label for="sitlSerialPort"> <span data-i18n="sitlSerialPort"></span></label>
|
||||
</div>
|
||||
<div class="select">
|
||||
<select id="serialTCPPort">
|
||||
<option value="5760">5760 (UART1)</option>
|
||||
<option value="5761">5761 (UART2)</option>
|
||||
<option value="5762">5762 (UART3)</option>
|
||||
<option value="5763">5763 (UART4)</option>
|
||||
<option value="5764">5764 (UART5)</option>
|
||||
<option value="5765">5765 (UART6)</option>
|
||||
<option value="5766">5766 (UART7)</option>
|
||||
<option value="5767">5767 (UART8)</option>
|
||||
</select>
|
||||
<label for="serialTCPPort"> <span data-i18n="sitlSerialTCPPort"></span></label>
|
||||
</div>
|
||||
<div class="select">
|
||||
<select id="serialProtocoll"></select>
|
||||
<label for="serialProtocoll"> <span data-i18n="sitlSerialProtocoll"></span></label>
|
||||
</div>
|
||||
<div class="number">
|
||||
<input type="number" id="sitlBaud" class="sitlBaud" data-setting-multiplier="1" step="1" min="1" max="256000" />
|
||||
<label for="sitlBaud" class="sitlNumber"><span data-i18n="configurationGPSBaudrate"></span></label>
|
||||
</div>
|
||||
<div class="select">
|
||||
<select id="serialStopbits">
|
||||
<option value="None">0</option>
|
||||
<option value="One">1</option>
|
||||
<option value="OnePointFive">1.5</option>
|
||||
<option value="Two">2</option>
|
||||
</select>
|
||||
<label for="serialStopbits"> <span data-i18n="sitlSerialStopbits"></span></label>
|
||||
</div>
|
||||
<div class="select">
|
||||
<select id="serialParity">
|
||||
<option value="None">None</option>
|
||||
<option value="Even">Even</option>
|
||||
<option value="Mark">Mark</option>
|
||||
<option value="Odd">Odd</option>
|
||||
<option value="Space">Space</option>
|
||||
</select>
|
||||
<label for="serialParity"> <span data-i18n="sitlSerialParity"></span></label>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content_toolbar" style="position: unset;">
|
||||
<div class="btn">
|
||||
<a class="sitlStop disabled" href="#" i18n="sitlStop"></a>
|
||||
</div>
|
||||
<div class="btn">
|
||||
<a class="sitlStart" href="#" i18n="sitlStart"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
521
tabs/sitl.js
Normal file
521
tabs/sitl.js
Normal file
|
@ -0,0 +1,521 @@
|
|||
'use strict'
|
||||
|
||||
const localhost = "127.0.0.1"
|
||||
|
||||
const simulators = [
|
||||
{
|
||||
name: "X-Plane",
|
||||
port: 49001,
|
||||
isPortFixed: false,
|
||||
inputChannels: 4,
|
||||
fixedChanMap: ["Throttle", "Roll", "Pitch", "Yaw" ]
|
||||
},
|
||||
{
|
||||
name: "RealFlight",
|
||||
port: 18083,
|
||||
isPortFixed: true,
|
||||
inputChannels: 12,
|
||||
fixedChanMap: false
|
||||
}
|
||||
];
|
||||
|
||||
const stdProfiles = [
|
||||
{
|
||||
name: "[Standard] X-Plane",
|
||||
sim: "X-Plane",
|
||||
eepromFileName: "standard-x-plane.bin",
|
||||
isStdProfile: true,
|
||||
simEnabeld: true,
|
||||
port: 49001,
|
||||
ip: "127.0.0.1",
|
||||
useImu: false,
|
||||
channelMap: [ 1, 15, 13, 16],
|
||||
useSerialTcp: true,
|
||||
comPort: "",
|
||||
tcpPort: 5762,
|
||||
serialProtocol: "SBus",
|
||||
baudrate: false,
|
||||
stopbits: false,
|
||||
parity: false
|
||||
},
|
||||
{
|
||||
name: "[Standard] RealFlight Flying Wing",
|
||||
sim: "RealFlight",
|
||||
eepromFileName: "standard-realflight.bin",
|
||||
isStdProfile: true,
|
||||
simEnabeld: true,
|
||||
port: 49001,
|
||||
ip: "127.0.0.1",
|
||||
useImu: false,
|
||||
channelMap: [ 1, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
useSerialTcp: true,
|
||||
comPort: "",
|
||||
tcpPort: 5762,
|
||||
serialProtocol: "SBus",
|
||||
baudrate: false,
|
||||
stopbits: false,
|
||||
parity: false
|
||||
|
||||
}
|
||||
];
|
||||
|
||||
var SITL_LOG = "";
|
||||
|
||||
TABS.sitl = {};
|
||||
TABS.sitl.initialize = (callback) => {
|
||||
|
||||
if (GUI.active_tab != 'sitl') {
|
||||
GUI.active_tab = 'sitl';
|
||||
googleAnalytics.sendAppView('SITL');
|
||||
}
|
||||
|
||||
if (GUI.active_tab != 'sitl') {
|
||||
GUI.active_tab = 'sitl';
|
||||
googleAnalytics.sendAppView('SITL');
|
||||
}
|
||||
|
||||
GUI.load("./tabs/sitl.html", function () {
|
||||
localize();
|
||||
|
||||
var os = GUI.operating_system;
|
||||
if (os != 'Windows' && os != 'Linux') {
|
||||
|
||||
$('.content_wrapper').find('*').remove();
|
||||
$('.content_wrapper').append(`<h2>${chrome.i18n.getMessage('sitlOSNotSupported')}</h2>`);
|
||||
|
||||
GUI.content_ready(callback);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
var currentSim, currentProfile, profiles;
|
||||
var mapping = new Array(28).fill(0);
|
||||
var serialProtocolls = Ser2TCP.getProtocolls();
|
||||
var sim_e = $('#simulator');
|
||||
var enableSim_e = $('#sitlEnableSim');
|
||||
var port_e = $('#simPort');
|
||||
var simIp_e = $('#simIP');
|
||||
var useImu_e = $('#sitlUseImu');
|
||||
var profiles_e = $('#sitlProfile');
|
||||
var profileSaveBtn_e = $('#sitlProfileSave');
|
||||
var profileNewBtn_e = $('#sitlProfileNew');
|
||||
var profileDeleteBtn_e = $('#sitlProfileDelete');
|
||||
var serialPorts_e = $('#sitlSerialPort');
|
||||
var serialTcpEnable = $('#serialTcpEnable')
|
||||
var tcpPort_e = $('#serialTCPPort');
|
||||
var protocollPreset_e = $('#serialProtocoll');
|
||||
var baudRate_e = $('#sitlBaud');
|
||||
var stopBits_e = $('#serialStopbits');
|
||||
var parity_e = $('#serialParity');
|
||||
var serialTcpEable_e = $('#serialTcpEnable');
|
||||
|
||||
if (SITLProcess.isRunning) {
|
||||
$('.sitlStart').addClass('disabled');
|
||||
$('.sitlStop').removeClass('disabled');
|
||||
} else {
|
||||
$('.sitlStop').addClass('disabled');
|
||||
$('.sitlStart').removeClass('disabled');
|
||||
}
|
||||
|
||||
$('#sitlLog').val(SITL_LOG);
|
||||
$('#sitlLog').animate({scrollTop: $('#sitlLog').scrollHeight}, "fast");
|
||||
|
||||
profiles = stdProfiles.slice(0);
|
||||
chrome.storage.local.get('sitlProfiles', (result) => {
|
||||
if(result.sitlProfiles)
|
||||
profiles.push(...result.sitlProfiles);
|
||||
|
||||
initElements(true);
|
||||
});
|
||||
|
||||
Ser2TCP.resetPortsList();
|
||||
Ser2TCP.pollSerialPorts(ports => {
|
||||
serialPorts_e.find('*').remove();
|
||||
ports.forEach(port => {
|
||||
serialPorts_e.append(`<option value="${port}">${port}</option>`)
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
enableSim_e.on('change', () => {
|
||||
currentProfile.simEnabeld = enableSim_e.is(':checked');
|
||||
});
|
||||
|
||||
sim_e.on('change', () => {
|
||||
updateSim();
|
||||
});
|
||||
|
||||
profiles_e.on('change', () => {
|
||||
updateCurrentProfile();
|
||||
});
|
||||
|
||||
port_e.on('change', () => {
|
||||
if (!currentSim.isPortFixed) {
|
||||
var port = parseInt(port_e.val());
|
||||
if (port != NaN)
|
||||
currentProfile.port = parseInt(port_e.val());
|
||||
}
|
||||
});
|
||||
|
||||
simIp_e.on('change', () => {
|
||||
currentProfile.ip = simIp_e.val();
|
||||
});
|
||||
|
||||
useImu_e.on('change', () => {
|
||||
currentProfile.useImu = useImu_e.is(':checked');
|
||||
});
|
||||
|
||||
$('.sitlStart').on('click', ()=> {
|
||||
$('.sitlStart').addClass('disabled');
|
||||
$('.sitlStop').removeClass('disabled');
|
||||
|
||||
var sim, simPort, simIp, channelMap = "";
|
||||
|
||||
if (enableSim_e.is(':checked')) {
|
||||
switch(currentSim.name) {
|
||||
case 'X-Plane':
|
||||
sim = 'xp';
|
||||
break;
|
||||
case 'RealFlight':
|
||||
sim = 'rf'
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (port_e.val() !== "") {
|
||||
simPort = port_e.val();
|
||||
}
|
||||
|
||||
if (simIp_e.val() !== "") {
|
||||
simIp = simIp_e.val();
|
||||
}
|
||||
|
||||
const zeroPad = (num, places) => String(num).padStart(places, '0');
|
||||
|
||||
for (let i = 0; i < currentSim.inputChannels; i++) {
|
||||
var inavChan = mapping[i];
|
||||
if (inavChan == 0) {
|
||||
continue;
|
||||
} else if (inavChan < 13) {
|
||||
channelMap += `M${zeroPad(inavChan, 2)}-${zeroPad(i + 1, 2)},`;
|
||||
} else {
|
||||
channelMap += `S${zeroPad(inavChan - 12, 2)}-${zeroPad(i + 1, 2)},`;
|
||||
}
|
||||
}
|
||||
channelMap = channelMap.substring(0, channelMap.length - 1);
|
||||
|
||||
var serialOptions;
|
||||
var selectedProtocoll = protocollPreset_e.find(':selected').val();
|
||||
if (selectedProtocoll == "manual") {
|
||||
serialOptions = {
|
||||
protocollName: "manual",
|
||||
bitrate: currentProfile.baudrate,
|
||||
stopBits: currentProfile.stopBits,
|
||||
parityBit: currentProfile.parity
|
||||
}
|
||||
} else {;
|
||||
serialOptions = {
|
||||
protocollName: selectedProtocoll
|
||||
}
|
||||
}
|
||||
|
||||
SITLProcess.start(currentProfile.eepromFileName, sim, useImu_e.is(':checked'), simIp, simPort, channelMap, result => {
|
||||
|
||||
appendLog(result);
|
||||
if (serialTcpEnable.is(':checked') && result == `[SIM] Connection with ${currentProfile.sim} successfully established.\n`) {
|
||||
Ser2TCP.start(serialPorts_e.val(), serialOptions, currentProfile.ip, currentProfile.tcpPort, result => {
|
||||
appendLog(`[Serial2TCP] ${result}`);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.sitlStop').on('click', ()=> {
|
||||
$('.sitlStop').addClass('disabled');
|
||||
$('.sitlStart').removeClass('disabled');
|
||||
Ser2TCP.stop();
|
||||
SITLProcess.stop();
|
||||
appendLog(chrome.i18n.getMessage('sitlStopped'));
|
||||
});
|
||||
|
||||
profileSaveBtn_e.on('click', () => {
|
||||
saveProfiles();
|
||||
});
|
||||
|
||||
profileNewBtn_e.on('click', () => {
|
||||
var name = prompt(chrome.i18n.getMessage('sitlNewProfile'), chrome.i18n.getMessage('sitlEnterName'));
|
||||
if (!name)
|
||||
return;
|
||||
|
||||
if (profiles.find(e => { return e.name == name })) {
|
||||
alert(chrome.i18n.getMessage('sitlProfileExists'))
|
||||
return;
|
||||
}
|
||||
var eerpromName = name.replace(/[^a-z0-9]/gi, '_').toLowerCase() + ".bin";
|
||||
var profile = {
|
||||
name: name,
|
||||
sim: "RealFlight",
|
||||
isStdProfile: false,
|
||||
simEnabeld: true,
|
||||
eepromFileName: eerpromName,
|
||||
port: 49001,
|
||||
ip: "127.0.0.1",
|
||||
useImu: false,
|
||||
channelMap: [ 1, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
useSerialTcp: true,
|
||||
tcpPort: 5762,
|
||||
serialProtocol: "SBus",
|
||||
baudrate: false,
|
||||
stopbits: false,
|
||||
parity: false
|
||||
}
|
||||
profiles.push(profile);
|
||||
profiles_e.append(`<option value="${name}">${name}</option>`)
|
||||
profiles_e.val(name);
|
||||
updateCurrentProfile();
|
||||
saveProfiles();
|
||||
});
|
||||
|
||||
profileDeleteBtn_e.on('click', () => {
|
||||
|
||||
if (currentProfile.isStdProfile) {
|
||||
alert(chrome.i18n.getMessage('sitlStdProfileCantDeleted'));
|
||||
return;
|
||||
}
|
||||
|
||||
var selected = profiles_e.find(':selected').val();
|
||||
profiles = profiles.filter(profile => {
|
||||
return profile.name != selected;
|
||||
});
|
||||
|
||||
SITLProcess.deleteEepromFile(currentProfile.eepromFileName);
|
||||
profiles_e.find('*').remove();
|
||||
|
||||
initElements(false);
|
||||
saveProfiles();
|
||||
});
|
||||
|
||||
serialTcpEable_e.on('change', () => {
|
||||
currentProfile.useSerialTcp = serialTcpEable_e.is(':checked');
|
||||
});
|
||||
|
||||
protocollPreset_e.on('change', () => {
|
||||
var selectedProtocoll = protocollPreset_e.find(':selected').val();
|
||||
|
||||
var protocoll = serialProtocolls.find(protocoll => {
|
||||
return protocoll.name == selectedProtocoll;
|
||||
});
|
||||
|
||||
if (selectedProtocoll != 'manual'){
|
||||
baudRate_e.prop('disabled', true);
|
||||
baudRate_e.val(protocoll.baudrate);
|
||||
stopBits_e.prop('disabled', true);
|
||||
stopBits_e.val(protocoll.stopBits);
|
||||
parity_e.prop('disabled', true);
|
||||
parity_e.val(protocoll.parity);
|
||||
|
||||
} else {
|
||||
baudRate_e.prop('disabled', false);
|
||||
baudRate_e.val('');
|
||||
stopBits_e.prop('disabled', false);
|
||||
stopBits_e.val('');
|
||||
parity_e.prop('disabled', false);
|
||||
parity_e.val('');
|
||||
}
|
||||
|
||||
currentProfile.serialProtocol = selectedProtocoll;
|
||||
});
|
||||
|
||||
serialPorts_e.on('change', () => {
|
||||
currentProfile.comPort = serialPorts_e.val();
|
||||
});
|
||||
|
||||
tcpPort_e.on('change', () => {
|
||||
currentProfile.tcpPort = parseInt(tcpPort_e.val());
|
||||
});
|
||||
|
||||
baudRate_e.on('change', () => {
|
||||
var baud = parseInt(baudRate_e.val());
|
||||
if (baud != NaN)
|
||||
currentProfile.baudrate = baud
|
||||
});
|
||||
|
||||
stopBits_e.on('change', () => {
|
||||
currentProfile.stopBits = stopBits_e.val();
|
||||
});
|
||||
|
||||
parity_e.on('change', () => {
|
||||
currentProfile.parity = parity_e.val();
|
||||
});
|
||||
|
||||
function initElements(init)
|
||||
{
|
||||
profiles.forEach(profile => {
|
||||
profiles_e.append(`<option value="${profile.name}">${profile.name}</option>`)
|
||||
});
|
||||
|
||||
if (init) {
|
||||
simulators.forEach(simulator => {
|
||||
sim_e.append(`<option value="${simulator.name}">${simulator.name}</option>`)
|
||||
});
|
||||
|
||||
protocollPreset_e.append('<option value="manual">Manual</option>');
|
||||
serialProtocolls.forEach(protocoll => {
|
||||
protocollPreset_e.append(`<option value="${protocoll.name}">${protocoll.name}</option>`);
|
||||
});
|
||||
|
||||
chrome.storage.local.get('sitlLastProfile', (result) => {
|
||||
if (result.sitlLastProfile) {
|
||||
var element = profiles.find(profile => {
|
||||
return profile.name == result.sitlLastProfile;
|
||||
});
|
||||
|
||||
if (element)
|
||||
profiles_e.val(element.name).trigger('change');
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
updateCurrentProfile();
|
||||
}
|
||||
|
||||
function saveProfiles() {
|
||||
var profilesToSave = [];
|
||||
profiles.forEach(profile => {
|
||||
if (!profile.isStdProfile)
|
||||
profilesToSave.push(profile);
|
||||
});
|
||||
|
||||
chrome.storage.local.set({
|
||||
'sitlProfiles': profilesToSave
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function updateSim() {
|
||||
simulators.forEach(simulator => {
|
||||
if (simulator.name == sim_e.find(':selected').text()) {
|
||||
currentSim = simulator;
|
||||
currentProfile.sim = currentSim.name;
|
||||
if (currentSim.isPortFixed) {
|
||||
port_e.val(currentSim.port).trigger('change');
|
||||
} else {
|
||||
port_e.val(currentProfile.port);
|
||||
}
|
||||
port_e.prop('disabled', simulator.isPortFixed);
|
||||
|
||||
renderChanMapTable();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function updateCurrentProfile() {
|
||||
var selected = profiles_e.find(':selected').val();
|
||||
var selectedIndex = profiles.findIndex(element => {
|
||||
return element.name == selected;
|
||||
});
|
||||
currentProfile = profiles[selectedIndex];
|
||||
|
||||
if (currentProfile.isStdProfile) {
|
||||
currentProfile = structuredClone(stdProfiles.find((profile) => {
|
||||
return profile.sim == currentProfile.sim;
|
||||
}));
|
||||
}
|
||||
|
||||
protocollPreset_e.val(currentProfile.serialProtocol);
|
||||
if (currentProfile.serialProtocol == "manual")
|
||||
{
|
||||
baudRate_e.val(currentProfile.baudrate);
|
||||
baudRate_e.prop('disabled', false);
|
||||
stopBits_e.val(currentProfile.stopBits);
|
||||
stopBits_e.prop('disabled', false);
|
||||
parity_e.val(currentProfile.parity);
|
||||
parity_e.prop('disabled', false);
|
||||
} else {
|
||||
var protocoll = serialProtocolls.find(protocoll => {
|
||||
return protocoll.name == currentProfile.serialProtocol;
|
||||
});
|
||||
baudRate_e.prop('disabled', true);
|
||||
baudRate_e.val(protocoll.baudrate);
|
||||
stopBits_e.prop('disabled', true);
|
||||
stopBits_e.val(protocoll.stopBits);
|
||||
parity_e.prop('disabled', true);
|
||||
parity_e.val(protocoll.parity);
|
||||
}
|
||||
|
||||
if (currentProfile.comPort != "")
|
||||
serialPorts_e.val(currentProfile.comPort);
|
||||
|
||||
enableSim_e.prop('checked', currentProfile.simEnabeld).trigger('change');
|
||||
serialTcpEable_e.prop('checked', currentProfile.useSerialTcp).trigger('change');
|
||||
tcpPort_e.val(currentProfile.tcpPort);
|
||||
mapping = currentProfile.channelMap;
|
||||
sim_e.val(currentProfile.sim);
|
||||
updateSim();
|
||||
simIp_e.val(currentProfile.ip).trigger('change');
|
||||
useImu_e.prop('checked', currentProfile.useImu).trigger('change');
|
||||
|
||||
chrome.storage.local.set({
|
||||
'sitlLastProfile': selected
|
||||
});
|
||||
}
|
||||
|
||||
function renderChanMapTable()
|
||||
{
|
||||
var mapTableBody = $('.mapTableBody');
|
||||
mapTableBody.find('*').remove();
|
||||
for (let i = 0; i < currentSim.inputChannels; i++) {
|
||||
|
||||
var output;
|
||||
if (currentSim.fixedChanMap) {
|
||||
output = currentSim.fixedChanMap[i];
|
||||
} else {
|
||||
output = i + 1;
|
||||
}
|
||||
|
||||
mapTableBody.append("<tr><td>" + output + "</td><td><select data-out=\"" + i + "\" class=\"inavChannel\"\"></select></td></td>");
|
||||
const row = mapTableBody.find('tr:last');
|
||||
GUI.fillSelect(row.find(".inavChannel"), getInavChannels(), mapping[i]);
|
||||
|
||||
row.find(".inavChannel").val(mapping[i]).on('change', (sender) => {
|
||||
mapping[$(sender.target).data('out')] = parseInt($(sender.target).val());
|
||||
chrome.storage.local.set({'sitlMapping': mapping});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getInavChannels() {
|
||||
var channels = [];
|
||||
for (var i = 0; i <= 12; i++) {
|
||||
if (i == 0)
|
||||
channels.push("None");
|
||||
else
|
||||
channels.push("Motor " + i);
|
||||
}
|
||||
|
||||
for (var i = 1; i <= 16; i++) {
|
||||
if (i == 0)
|
||||
channels.push("None");
|
||||
else
|
||||
channels.push("Servo " + i);
|
||||
}
|
||||
return channels;
|
||||
}
|
||||
|
||||
function appendLog(message){
|
||||
SITL_LOG += message;
|
||||
$('#sitlLog').val(SITL_LOG);
|
||||
$('#sitlLog').animate({scrollTop: $('#sitlLog')[0].scrollHeight}, "fast");
|
||||
}
|
||||
|
||||
GUI.content_ready(callback);
|
||||
});
|
||||
};
|
||||
|
||||
TABS.sitl.cleanup = (callback) => {
|
||||
Ser2TCP.stopPollSerialPorts();
|
||||
if (callback)
|
||||
callback();
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue