1
0
Fork 0
mirror of https://github.com/iNavFlight/inav-configurator.git synced 2025-07-23 16:25:19 +03:00

Merge branch 'master' into dzikuvx-wizard

This commit is contained in:
Pawel Spychalski (DzikuVx) 2024-03-23 13:23:43 +01:00
commit 341f2bb9d8
3375 changed files with 283533 additions and 275991 deletions

View file

@ -175,13 +175,13 @@ https://hub.docker.com/r/yagajs/mapproxy/ Docker image (untested)
base: GLOBAL_MERCATOR
origin: ul
```
1. You can use any map provider that is compatible with MapProxy, and once you zoom in on the region you will be flying in, the map tiles will be cached for offline use. You can test this by disabling your internet connection and browsing the demo url in a browser
1. You can use any map provider that is compatible with MapProxy, and once you zoom in on the region you will be flying in, the map tiles will be cached for offline use. You can test this by disabling your internet connection and browsing the demo URL in a browser
https://wiki.openstreetmap.org/wiki/WMS#OSM_WMS_Servers OpenStreetMap WSM servers
https://lpdaac.usgs.gov/data_access/web_map_services_wms # USGS currently has 400+ WMS layers
* You can use QGIS to browse different provieders and pick the maps you like for your iNav layers
* You can use QGIS to browse different providers and pick the maps you like for your iNav layers
https://qgis.org/en/site/
* There are many government and public wms providers available in different regions worldwide
* There are many government and public WMS providers available in different regions worldwide

120
README.md
View file

@ -1,88 +1,121 @@
# INAV Configurator
INAV Configurator is a crossplatform configuration tool for the [INAV](https://github.com/iNavFlight/inav) flight control system.
INAV Configurator is a cross-platform configuration tool for the [INAV](https://github.com/iNavFlight/inav) flight control system.
It runs as an app within Google Chrome and allows you to configure the INAV software running on any supported INAV target.
Various types of aircraft are supported by the tool and by INAV, e.g. quadcopters, hexacopters, octocopters and fixed-wing aircraft.
Various types of aircraft are supported by the tool and by INAV, e.g. quadcopters, hexacopters, octocopters, and fixed-wing aircraft.
# Support
INAV Configurator comes `as is`, without any warranty and support from authors. If you found a bug, please create an issue on [GitHub](https://github.com/iNavFlight/inav-configurator/issues).
INAV Configurator comes `as is`, without any warranty and support from the authors. If you find a bug, please create an issue on [GitHub](https://github.com/iNavFlight/inav-configurator/issues).
GitHub issue tracker is reserved for bugs and other technical problems. If you do not know how to setup
everything, hardware is not working or have any other _support_ problem, please consult:
The GitHub issue tracker is reserved for bugs and other technical problems. If you do not know how to set up
everything, the hardware is not working, or you have any other _support_ problem, please consult:
* [INAV Discord Server](https://discord.gg/peg2hhbYwN)
* [INAV Official on Facebook](https://www.facebook.com/groups/INAVOfficial)
* [RC Groups Support](https://www.rcgroups.com/forums/showthread.php?2495732-Cleanflight-iNav-(navigation-rewrite)-project)
* [INAV Official on Telegram](https://t.me/INAVFlight)
## INAV Configurator start minimized, what should I do?
## INAV Configurator starts minimized, what should I do?
You have to remove `C:\Users%Your_UserNname%\AppData\Local\inav-configurator` folder and all its content.
You have to remove the `C:\Users%Your_UserName%\AppData\Local\inav-configurator` folder and all its content.
[https://www.youtube.com/watch?v=XMoULyiFDp4](https://www.youtube.com/watch?v=XMoULyiFDp4)
Alternatively, on Windows with PowerShell you can use `post_install_cleanup.ps1` script that will do the cleaning. (thank you James Cherrill)
Alternatively, on Windows with PowerShell, you can use the `post_install_cleanup.ps1` script that will do the cleaning. (thank you, James Cherrill)
## Installation
Depending on target operating system, _INAV Configurator_ is distributed as _standalone_ application or Chrome App.
Depending on the target operating system, _INAV Configurator_ is distributed as a _standalone_ application or Chrome App.
### Windows
1. Visit [release page](https://github.com/iNavFlight/inav-configurator/releases)
1. Download Configurator for Windows platform (win32 or win64 is present)
1. Extract ZIP archive
1. Run INAV Configurator app from unpacked folder
1. Configurator is not signed, so you have to allow Windows to run untrusted application. There might be a monit for it during first run
1. Run the INAV Configurator app from the unpacked folder
1. Configurator is not signed, so you have to allow Windows to run untrusted applications. There might be a monit for it during the first run
### Linux
1. Visit [release page](https://github.com/iNavFlight/inav-configurator/releases)
1. Download Configurator for Linux platform (linux32 and linux64 are present)
1. Extract tar.gz archive
1. Make the following files executable:
* inav-configurator `chmod +x inav-configurator`
* (5.0.0+) chrome_crashpad_handler `chmod +x chrome_crashpad_handler`
1. Run INAV Configurator app from unpacked folder
2. Download Configurator for Linux platform (linux32 and linux64 are present)
* **.rpm** is the Fedora installation file. Just download and install using `sudo dnf localinstall /path/to/INAV-Configurator_linux64-x.y.z-x86_64.rpm` or open it with a package manager (e.g. via Files)
* **.deb** is the Debian/Ubuntu installation file. Just download and install using `sudo apt install /path/to/INAV-Configurator_linux64_x.y.z.deb` or open it with a package manager (e.g. via the File Manager)
* **.tar.gz** is a universal archive. Download and continue with these instructions to install
3. Change to the directory containing the downloaded **tar.gz** file
4. download [this](https://raw.githubusercontent.com/iNavFlight/inav-configurator/master/assets/linux/inav-configurator.desktop) file to the same directory. Its filename should be `inav-configurator.desktop`.
5. Extract **tar.gz** archive
```
tar -C /tmp/ -xf INAV-Configurator_linuxNN_x.y.z.tar.gz
```
**NN** is the bits of your OS. **x.y.z** is the INAV Configurator version number.
On some Linux distros, you may be missing `libatomic`, a `NW.JS` (specially `libnode.so`) dependency. If so, please install `libatomic` using your distro's package manager, e.g:
6. If this is the first time installing INAV Configurator, create a home for its files
```
sudo mkdir /opt/inav
sudo chown $USER /opt/inav
```
7. Move the temporary files into their home
```
mv /tmp/INAV\ Configurator /opt/inav/inav-configurator
```
8. Update the application icon.
```
sudo mkdir /opt/inav/inav-configurator/icon
sudo cp /opt/inav/inav-configurator/images/inav_icon_128.png /opt/inav/inav-configurator/icon
```
9. As a one-off, move the desktop file into the applications directory
```
sudo mv inav-configurator.desktop /usr/share/applications/
```
10. Make the following files executable:
* inav-configurator `chmod +x /opt/inav/inav-configurator/inav-configurator`
* (5.0.0+) chrome_crashpad_handler `chmod +x /opt/inav/inav-configurator/chrome_crashpad_handler`
11. Run the INAV Configurator app from the unpacked folder `/opt/inav/inav-configurator/inav-configurator`
#### Notes
On some Linux distros, you may be missing `libatomic` and/or `NW.JS` (especially `libnode.so`) dependencies. If so, please install `libatomic` using your distro's package manager, e.g:
* Arch Linux: `sudo pacman -S --needed libatomic_ops`
* Debian / Ubuntu: `sudo apt install libatomic1`
* Fedora: `sudo dnf install libatomic`
1. Don't forget to add your user to the dialout group "sudo usermod -aG dialout YOUR_USERNAME" for serial access
2. If you have 3D model animation problems, enable "Override software rendering list" in Chrome flags chrome://flags/#ignore-gpu-blacklist
### Mac
1. Visit [release page](https://github.com/iNavFlight/inav-configurator/releases)
1. Download Configurator for Mac platform
1. Download Configurator for the Mac platform
1. Extract ZIP archive
1. Run INAV Configurator
1. Configurator is not signed, so you have to allow Mac to run untrusted application. There might be a monit for it during first run
## Building and running INAV Configurator locally (for development or Linux users)
## Building and running INAV Configurator locally (for development)
For local development, **node.js** build system is used.
For local development, the **node.js** build system is used.
1. Install node.js
1. From project folder run `npm install`
1. From the project folder run `npm install`
1. To build the JS and CSS files and start the configurator:
- With NW.js: Run `npm start`.
- With Chrome: Run `npm run gulp`. Then open `chrome://extensions`, enable
the `Developer mode`, click on the `Load unpacked extension...` button and select the `inav-configurator` directory.
the `Developer mode`, click on the `Load unpacked extension...` button, and select the `inav-configurator` directory.
Other tasks are also defined in `gulpfile.js`. To run a task, use `node ./node_modules/gulp/bin/gulp.js task-name`. Available ones are:
- **build**: Generate JS and CSS output files used by the configurator from their sources. It must be run whenever changes are made to any `.js` or `.css` files in order to have those changes appear
in the configurator. If new files are added, they must be included in `gulpfile.js`. See the comments at the top of `gulpfile.js` to learn how to do so. See also the `watch` task.
- **watch**: Watch JS and CSS sources for changes and run the `build` task whenever they're edited.
- **dist**: Create a distribution of the app (valid for packaging both as a Chrome app or a NW.js app)
- **dist**: Create a distribution of the app (valid for packaging both as a Chrome app or NW.js app)
in the `./dist/` directory.
- **release**: Create NW.js apps for each supported platform (win32, osx64 and linux64) in the `./apps`
directory. Running this task on macOS or Linux requires Wine, since it's needed to set the icon
for the Windows app. If you don't have Wine installed you can create a release by running the **release-only-linux** task.
directory. Running this task on macOS or Linux requires Wine since it's needed to set the icon
for the Windows app. If you don't have Wine installed, you can create a release by running the **release-only-Linux** task.
<br>`--installer` argument can be added to build installers for a particular OS. NOTE: MacOS Installer can be built with MacOS only.
To build a specific release, use the command `release --platform="win64"` for example.
@ -94,17 +127,17 @@ To be able to open Inspector, you will need SDK flavours of NW.js
## Different map providers
INAV Configurator 2.1 allows to choose between OpenStreetMap, Bing Maps, and MapProxy map providers.
INAV Configurator is shipped **WITHOUT** API key for Bing Maps. That means: every user who wants to use Bing Maps has to create own account, agree to all _Terms and Conditions_ required by Bing Maps and configure INAV Configuerator by himself.
INAV Configurator 2.1 allows you to choose between OpenStreetMap, Bing Maps (Aerial View), and MapProxy map providers.
INAV Configurator is shipped **WITHOUT** API key for Bing Maps. That means: every user who wants to use Bing Maps has to create their own account, agree to all _Terms and Conditions_ required by Bing Maps, and configure INAV Configurator by himself.
### How to choose Map provider
### How to choose a Map provider
1. Click **Settings** icon in the top-right corner of INAV Configurator
1. Choose provider: OpenStreetMap, Bing, or MapProxy
1. Choose a provider: OpenStreetMap, Bing, or MapProxy
1. In the case of Bing Maps, you have to provide your own, personal, generated by you, Bing Maps API key
1. For MapProxy, you need to provide a server URL and layer name to be used
### How to get Bing Maps API key
### How to get the Bing Maps API key
1. Go to the Bing Maps Dev Center at [https://www.bingmapsportal.com/](https://www.bingmapsportal.com/).
* If you have a Bing Maps account, sign in with the Microsoft account that you used to create the account or create a new one. For new accounts, follow the instructions in [Creating a Bing Maps Account](https://msdn.microsoft.com/library/gg650598.aspx).
@ -112,18 +145,22 @@ INAV Configurator is shipped **WITHOUT** API key for Bing Maps. That means: ever
1. Select the option to create a new key.
1. Provide the following information to create a key:
1. Application name: Required. The name of the application.
1. Application URL: The URL of the application. This is an optional field which is useful in helping you remember the purpose of that key in the future.
1. Application URL: The URL of the application. This is an optional field that is useful in helping you remember the purpose of that key in the future.
1. Key type: Required. Select the key type that you want to create. You can find descriptions of key and application types here.
1. Application type: Required. Select the application type that best represents the application that will use this key. You can find descriptions of key and application types [here](https://www.microsoft.com/maps/create-a-bing-maps-key.aspx).
1. Click the **Create** button. The new key displays in the list of available keys. Use this key to authenticate your Bing Maps application as described in the documentation for the Bing Maps API you are using.
1. Click the **Create** button. The new key is displayed in the list of available keys. Use this key to authenticate your Bing Maps application as described in the documentation for the Bing Maps API you are using.
### How to setup a MapProxy server for offline caching and mission planning
1. Follow process described in [MAPPROXY.md](MAPPROXY.md)
1. Test your MapProxy server in web browser, eg: http://192.168.145.20/inavmapproxy/
### How to set up a MapProxy server for offline caching and mission planning
1. Follow the process described in [MAPPROXY.md](MAPPROXY.md)
1. Test your MapProxy server in a web browser, eg: http://192.168.145.20/inavmapproxy/
1. Once you have a working MapProxy server choose MapProxy as your map provider
1. Enter MapProxy service URL, eg: http://192.168.145.20/inavmapproxy/service?
1. Enter MapProxy service layer (inav_layer if configured from MAPPROXY.md)
1. Once completed, you can zoom in on area you will be flying in while connected to the internet in either GPS or Mission Control tab to save the cache for offline use
1. Once completed, you can zoom in on the area you will be flying in while connected to the internet in either the GPS or Mission Control tab to save the cache for offline use
## Font Customisation
INAV provides the font images so that custom fonts can be created for your personal preference. This is the case for both analogue and digital fonts. The resources can be found in the [osd](/resources/osd) folder. Within the **analogue** and **digital** subfolders, you will find information on compiling your own fonts. There is also an [INAV Character Map](/resources/osd/INAV%20Character%20Map.md) document. This contains previews of all the character images in the fonts and the appropriate variable names within the firmware and Configurator. There are tools for compiling the [analogue](https://github.com/fiam/max7456tool) and [digital](https://github.com/MrD-RC/hdosd-font-tool) fonts. New font submissions via pull requests are welcome.
## Notes
@ -131,18 +168,13 @@ INAV Configurator is shipped **WITHOUT** API key for Bing Maps. That means: ever
Make sure Settings -> System -> "User hardware acceleration when available" is checked to achieve the best performance
### Linux users
1. Dont forget to add your user into dialout group "sudo usermod -aG dialout YOUR_USERNAME" for serial access
2. If you have 3D model animation problems, enable "Override software rendering list" in Chrome flags chrome://flags/#ignore-gpu-blacklist
## Issue trackers
For INAV configurator issues raise them here
https://github.com/iNavFlight/inav-configurator/issues
For INAV firmware issues raise them here
For INAV firmware issues, raise them here
https://github.com/iNavFlight/inav/issues

File diff suppressed because it is too large Load diff

23
assets/linux/copyright Normal file
View file

@ -0,0 +1,23 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: INAV Configurator
Source: https://github.com/iNavFlight/inav-configurator
Files: *
Copyright: Copyright 2022 The INAV open source project
License: GPL-3
License: GPL-3
This program is free software: you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation, either version 3 of the License, or (at your option) any later
version.
.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>.
.
On Debian systems, the complete text of the GNU General Public License
can be found in `/usr/share/common-licenses/GPL-3'.

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

View file

@ -0,0 +1,8 @@
[Desktop Entry]
Name=INAV Configurator
Comment=Crossplatform configuration tool for the INAV flight control system
Exec=/opt/inav/inav-configurator/inav-configurator
Icon=/opt/inav/inav-configurator/icon/inav_icon_128.png
Terminal=false
Type=Application
Categories=Utility

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -0,0 +1,169 @@
; ------------------------------------------
; Installer for INAV
; ------------------------------------------
; It receives from the command line with /D the parameters:
; version
; archName
; archAllowed
; archInstallIn64bit
; sourceFolder
; targetFolder
#define ApplicationName "INAV Configurator"
#define CompanyName "The INAV open source project"
#define CompanyUrl "https://github.com/iNavFlight/inav"
#define ExecutableFileName "inav-configurator.exe"
#define GroupName "INAV"
#define InstallerFileName "INAV-Configurator_" + archName + "_" + version
#define SourcePath "..\..\" + sourceFolder + "\inav-configurator\" + archName
#define TargetFolderName "INAV-Configurator"
#define UpdatesUrl "https://github.com/iNavFlight/inav-configurator/releases"
[CustomMessages]
AppName=inav-configurator
LaunchProgram=Start {#ApplicationName}
[Files]
Source: "{#SourcePath}\*"; DestDir: "{app}"; Flags: recursesubdirs
[Icons]
; Programs group
Name: "{group}\{#ApplicationName}"; Filename: "{app}\{#ExecutableFileName}";
; Desktop icon
Name: "{autodesktop}\{#ApplicationName}"; Filename: "{app}\{#ExecutableFileName}";
; Non admin users, uninstall icon
Name: "{group}\Uninstall {#ApplicationName}"; Filename: "{uninstallexe}"; Check: not IsAdminInstallMode
[Languages]
; English default, it must be first
Name: "en"; MessagesFile: "compiler:Default.isl"
; Official languages
;Name: "ca"; MessagesFile: "compiler:Languages\Catalan.isl"
;Name: "da"; MessagesFile: "compiler:Languages\Danish.isl"
;Name: "de"; MessagesFile: "compiler:Languages\German.isl"
;Name: "es"; MessagesFile: "compiler:Languages\Spanish.isl"
;Name: "fr"; MessagesFile: "compiler:Languages\French.isl"
;Name: "it"; MessagesFile: "compiler:Languages\Italian.isl"
;Name: "ja"; MessagesFile: "compiler:Languages\Japanese.isl"
;Name: "nl"; MessagesFile: "compiler:Languages\Dutch.isl"
;Name: "pt"; MessagesFile: "compiler:Languages\Portuguese.isl"
;Name: "pl"; MessagesFile: "compiler:Languages\Polish.isl"
;Name: "ru"; MessagesFile: "compiler:Languages\Russian.isl"
; Not official. Sometimes not updated to latest version (strings missing)
;Name: "ga"; MessagesFile: "unofficial_inno_languages\Galician.isl"
;Name: "eu"; MessagesFile: "unofficial_inno_languages\Basque.isl"
;Name: "hr"; MessagesFile: "unofficial_inno_languages\Croatian.isl"
;Name: "hu"; MessagesFile: "unofficial_inno_languages\Hungarian.isl"
;Name: "id"; MessagesFile: "unofficial_inno_languages\Indonesian.isl"
;Name: "ko"; MessagesFile: "unofficial_inno_languages\Korean.isl"
;Name: "lv"; MessagesFile: "unofficial_inno_languages\Latvian.isl"
;Name: "sv"; MessagesFile: "unofficial_inno_languages\Swedish.isl"
;Name: "zh_CN"; MessagesFile: "unofficial_inno_languages\ChineseSimplified.isl"
;Name: "zh_TW"; MessagesFile: "unofficial_inno_languages\ChineseTraditional.isl"
; Not available
; pt_BR (Portuguese Brasileiro)
[Run]
; Add a checkbox to start the app after installed
Filename: {app}\{cm:AppName}.exe; Description: {cm:LaunchProgram,{cm:AppName}}; Flags: nowait postinstall skipifsilent
[Setup]
AppId=2e5662ca-1fb3-8f1e-a7e1-e390add7a19d
AppName={#ApplicationName}
AppPublisher={#CompanyName}
AppPublisherURL={#CompanyUrl}
AppUpdatesURL={#UpdatesUrl}
AppVersion={#version}
ArchitecturesAllowed={#archAllowed}
ArchitecturesInstallIn64BitMode={#archInstallIn64bit}
Compression=lzma2
DefaultDirName={autopf}\{#GroupName}\{#TargetFolderName}
DefaultGroupName={#GroupName}\{#ApplicationName}
LicenseFile=..\..\LICENSE
MinVersion=6.2
OutputBaseFilename={#InstallerFileName}
OutputDir=..\..\{#targetFolder}\
PrivilegesRequiredOverridesAllowed=commandline dialog
SetupIconFile=inav_installer_icon.ico
ShowLanguageDialog=yes
SolidCompression=yes
UninstallDisplayIcon={app}\{#ExecutableFileName}
UninstallDisplayName={#ApplicationName}
WizardImageFile=inav_installer.bmp
WizardSmallImageFile=inav_installer_small.bmp
WizardStyle=modern
[Code]
function GetOldNsisUninstallerPath(): String;
var
RegKey: String;
begin
Result := '';
// Look into the different registry entries: win32, win64 and without user rights
if not RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\INAV Configurator', 'UninstallString', Result) then
begin
if not RegQueryStringValue(HKLM, 'SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\INAV Configurator', 'UninstallString', Result) then
begin
RegQueryStringValue(HKCU, 'SOFTWARE\INAV\INAV Configurator', 'UninstallString', Result)
end;
end;
end;
function GetQuietUninstallerPath(): String;
var
RegKey: String;
begin
Result := '';
RegKey := Format('%s\%s_is1', ['Software\Microsoft\Windows\CurrentVersion\Uninstall', '{#emit SetupSetting("AppId")}']);
if not RegQueryStringValue(HKEY_LOCAL_MACHINE, RegKey, 'QuietUninstallString', Result) then
begin
RegQueryStringValue(HKEY_CURRENT_USER, RegKey, 'QuietUninstallString', Result);
end;
end;
function InitializeSetup(): Boolean;
var
ResultCode: Integer;
ParameterStr : String;
UninstPath : String;
begin
Result := True;
// Check if the application is already installed by the old NSIS installer, and uninstall it
UninstPath := GetOldNsisUninstallerPath();
// Found, start uninstall
if UninstPath <> '' then
begin
UninstPath := RemoveQuotes(UninstPath);
// Add this parameter to not return until uninstall finished. The drawback is that the uninstaller file is not deleted
ParameterStr := '_?=' + ExtractFilePath(UninstPath);
if Exec(UninstPath, ParameterStr, '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
// Delete the unistaller file and empty folders. Not deleting the files.
DeleteFile(UninstPath);
DelTree(ExtractFilePath(UninstPath), True, False, True);
end
else begin
Result := False;
MsgBox('Error uninstalling old Configurator ' + SysErrorMessage(ResultCode) + '.', mbError, MB_OK);
end;
end
else begin
// Search for new Inno Setup installations
UninstPath := GetQuietUninstallerPath();
if UninstPath <> '' then
begin
if not Exec('>', UninstPath, '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
Result := False;
MsgBox('Error uninstalling Configurator ' + SysErrorMessage(ResultCode) + '.', mbError, MB_OK);
end;
end;
end;
end;

View file

@ -13,6 +13,8 @@ var semver = require('semver');
var gulp = require('gulp');
var concat = require('gulp-concat');
const commandExistsSync = require('command-exists').sync;
// Each key in the *sources* variable must be an array of
// the source files that will be combined into a single
// file and stored in *outputDir*. Each key in *sources*
@ -124,6 +126,7 @@ sources.js = [
'./js/serial_queue.js',
'./js/msp_balanced_interval.js',
'./tabs/advanced_tuning.js',
'./tabs/ez_tune.js',
'./js/peripherals.js',
'./js/appUpdater.js',
'./js/feature_framework.js',
@ -135,6 +138,9 @@ sources.js = [
'./js/waypoint.js',
'./node_modules/openlayers/dist/ol.js',
'./js/libraries/plotly-latest.min.js',
'./js/sitl.js',
'./js/CliAutoComplete.js',
'./node_modules/jquery-textcomplete/dist/jquery.textcomplete.js'
];
sources.receiverCss = [
@ -249,8 +255,10 @@ gulp.task('dist-build', gulp.series('build', function() {
'./src/css/opensans_webfontkit/*.{eot,svg,ttf,woff,woff2}',
'./resources/*.json',
'./resources/models/*',
'./resources/osd/*.mcm',
'./resources/osd/analogue/*.mcm',
'./resources/motor_order/*.svg',
'./resources/sitl/windows/*',
'./resources/sitl/linux/*'
];
return gulp.src(distSources, { base: '.' })
.pipe(gulp.dest(distDir));
@ -267,7 +275,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) {
@ -285,29 +294,23 @@ function get_nw_version() {
return semver.valid(semver.coerce(require('./package.json').dependencies.nw));
}
function get_release_filename(platform, ext) {
var pkg = require('./package.json');
return 'INAV-Configurator_' + platform + '_' + pkg.version + '.' + ext;
function get_release_filename_base(platform) {
return 'INAV-Configurator_' + platform;
}
gulp.task('release-win32', function() {
function get_release_filename(platform, ext, addition = '') {
var pkg = require('./package.json');
var src = path.join(appsDir, pkg.name, 'win32');
var output = fs.createWriteStream(path.join(appsDir, get_release_filename('win32', 'zip')));
var archive = archiver('zip', {
zlib: { level: 9 }
});
archive.on('warning', function(err) { throw err; });
archive.on('error', function(err) { throw err; });
archive.pipe(output);
archive.directory(src, 'INAV Configurator');
return archive.finalize();
});
return get_release_filename_base(platform) + addition + '_' + pkg.version + '.' + ext;
}
gulp.task('release-win64', function() {
function build_win_zip(arch) {
return function build_win_zip_proc(done) {
var pkg = require('./package.json');
var src = path.join(appsDir, pkg.name, 'win64');
var output = fs.createWriteStream(path.join(appsDir, get_release_filename('win64', 'zip')));
// Create ZIP
console.log(`Creating ${arch} ZIP file...`);
var src = path.join(appsDir, pkg.name, arch);
var output = fs.createWriteStream(path.join(appsDir, get_release_filename(arch, 'zip')));
var archive = archiver('zip', {
zlib: { level: 9 }
});
@ -316,7 +319,54 @@ gulp.task('release-win64', function() {
archive.pipe(output);
archive.directory(src, 'INAV Configurator');
return archive.finalize();
});
}
}
function build_win_iss(arch) {
return function build_win_iss_proc(done) {
if (!getArguments().installer) {
done();
return null;
}
// Create Installer
console.log(`Creating ${arch} Installer...`);
const innoSetup = require('@quanle94/innosetup');
const APPS_DIR = './apps/';
const pkg = require('./package.json');
// Parameters passed to the installer script
const parameters = [];
// Extra parameters to replace inside the iss file
parameters.push(`/Dversion=${pkg.version}`);
parameters.push(`/DarchName=${arch}`);
parameters.push(`/DarchAllowed=${(arch === 'win32') ? 'x86 x64' : 'x64'}`);
parameters.push(`/DarchInstallIn64bit=${(arch === 'win32') ? '' : 'x64'}`);
parameters.push(`/DsourceFolder=${APPS_DIR}`);
parameters.push(`/DtargetFolder=${APPS_DIR}`);
// Show only errors in console
parameters.push(`/Q`);
// Script file to execute
parameters.push("assets/windows/installer.iss");
innoSetup(parameters, {},
function(error) {
if (error != null) {
console.error(`Installer for platform ${arch} finished with error ${error}`);
} else {
console.log(`Installer for platform ${arch} finished`);
}
done();
});
}
}
gulp.task('release-win32', gulp.series(build_win_zip('win32'), build_win_iss('win32')));
gulp.task('release-win64', gulp.series(build_win_zip('win64'), build_win_iss('win64')));
gulp.task('release-osx64', function(done) {
var pkg = require('./package.json');
@ -337,8 +387,16 @@ gulp.task('release-osx64', function(done) {
codesignArgs.push('-e', 'entitlements.plist');
codesignArgs.push(src)
execSync.apply(this, codesignArgs);
// Check if the bundle is signed
const codesignCheckArgs = [ 'codesign', '-vvv', '--deep', '--strict', src ];
execSync.apply(this, codesignCheckArgs);
}
// 'old' .zip mode
if (!getArguments().installer) {
const zipFilename = path.join(appsDir, get_release_filename('macOS', 'zip'));
console.log('Creating ZIP file: ' + zipFilename);
var output = fs.createWriteStream(zipFilename);
var archive = archiver('zip', {
zlib: { level: 9 }
@ -349,6 +407,7 @@ 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'];
const notarizationUsername = getArguments()['notarization-username'];
if (notarizationUsername) {
@ -364,10 +423,281 @@ gulp.task('release-osx64', function(done) {
done();
});
archive.finalize();
}
// 'new' .dmg mode
else {
const appdmg = require('appdmg');
var target = path.join(appsDir, get_release_filename('macOS', 'dmg'));
console.log('Creating DMG file: ' + target);
var basepath = path.join(appsDir, pkg.name, 'osx64');
console.log('Base path: ' + basepath);
if (fs.existsSync(target)) {
fs.unlinkSync(target);
}
var specs = {};
specs["title"] = "INAV Configurator";
specs["contents"] = [
{ "x": 448, "y": 342, "type": "link", "path": "/Applications" },
{ "x": 192, "y": 344, "type": "file", "path": pkg.name + ".app", "name": "INAV Configurator.app" },
];
specs["background"] = path.join(__dirname, 'assets/osx/dmg-background.png');
specs["format"] = "UDZO";
specs["window"] = {
"size": {
"width": 638,
"height": 479,
}
};
const codesignIdentity = getArguments()['codesign-identity'];
if (getArguments().codesign) {
specs['code-sign'] = {
'signing-identity': codesignIdentity,
}
}
const ee = appdmg({
target: target,
basepath: basepath,
specification: specs,
});
ee.on('progress', function(info) {
//console.log(info);
});
ee.on('error', function(err) {
console.log(err);
});
ee.on('finish', function() {
if (getArguments().codesign) {
// Check if the bundle is signed
const codesignCheckArgs = [ 'codesign', '-vvv', '--deep', '--strict', target ];
execSync.apply(this, codesignCheckArgs);
}
if (getArguments().notarize) {
console.log('Notarizing DMG file: ' + target);
const notarizeArgs = ['xcrun', 'notarytool', 'submit'];
notarizeArgs.push(target);
const notarizationUsername = getArguments()['notarization-username'];
if (notarizationUsername) {
notarizeArgs.push('--apple-id', notarizationUsername)
} else {
throw new Error('Missing notarization username');
}
const notarizationPassword = getArguments()['notarization-password'];
if (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);
}
execSync.apply(this, notarizeArgs);
console.log('Stapling DMG file: ' + target);
const stapleArgs = ['xcrun', 'stapler', 'staple'];
stapleArgs.push(target);
execSync.apply(this, stapleArgs);
console.log('Checking DMG file: ' + target);
const checkArgs = ['spctl', '-vvv', '--assess', '--type', 'install', target];
execSync.apply(this, checkArgs);
}
done();
});
}
});
function post_build(arch, folder) {
return function post_build_linux(done) {
if ((arch === 'linux32') || (arch === 'linux64')) {
const metadata = require('./package.json');
// Copy Ubuntu launcher scripts to destination dir
const launcherDir = path.join(folder, metadata.name, arch);
console.log(`Copy Ubuntu launcher scripts to ${launcherDir}`);
return gulp.src('assets/linux/**')
.pipe(gulp.dest(launcherDir));
}
return done();
}
}
// Create the dir directory, with write permissions
function createDirIfNotExists(dir) {
fs.mkdir(dir, '0775', function(err) {
if (err && err.code !== 'EEXIST') {
throw err;
}
});
}
function release_deb(arch) {
return function release_deb_proc(done) {
if (!getArguments().installer) {
done();
return null;
}
// Check if dpkg-deb exists
if (!commandExistsSync('dpkg-deb')) {
console.warn(`dpkg-deb command not found, not generating deb package for ${arch}`);
done();
return null;
}
const deb = require('gulp-debian');
const LINUX_INSTALL_DIR = '/opt/inav';
const metadata = require('./package.json');
console.log(`Generating deb package for ${arch}`);
return gulp.src([path.join(appsDir, metadata.name, arch, '*')])
.pipe(deb({
package: metadata.name,
version: metadata.version,
section: 'base',
priority: 'optional',
architecture: getLinuxPackageArch('deb', arch),
maintainer: metadata.author,
description: metadata.description,
preinst: [`rm -rf ${LINUX_INSTALL_DIR}/${metadata.name}`],
postinst: [
`chown root:root ${LINUX_INSTALL_DIR}`,
`chown -R root:root ${LINUX_INSTALL_DIR}/${metadata.name}`,
`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'],
changelog: [],
_target: `${LINUX_INSTALL_DIR}/${metadata.name}`,
_out: appsDir,
_copyright: 'assets/linux/copyright',
_clean: true,
}));
}
}
function post_release_deb(arch) {
return function post_release_linux_deb(done) {
if (!getArguments().installer) {
done();
return null;
}
if ((arch === 'linux32') || (arch === 'linux64')) {
var rename = require("gulp-rename");
const metadata = require('./package.json');
const renameFrom = path.join(appsDir, metadata.name + '_' + metadata.version + '_' + getLinuxPackageArch('.deb', arch) + '.deb');
const renameTo = path.join(appsDir, get_release_filename_base(arch) + '_' + metadata.version + '.deb');
// Rename .deb build to common naming
console.log(`Renaming .deb installer ${renameFrom} to ${renameTo}`);
return gulp.src(renameFrom)
.pipe(rename(renameTo))
.pipe(gulp.dest("."));
}
return done();
}
}
function release_rpm(arch) {
return function release_rpm_proc(done) {
if (!getArguments().installer) {
done();
return null;
}
// Check if rpmbuild exists
if (!commandExistsSync('rpmbuild')) {
console.warn(`rpmbuild command not found, not generating rpm package for ${arch}`);
done();
return;
}
const buildRpm = require('rpm-builder');
const NAME_REGEX = /-/g;
const LINUX_INSTALL_DIR = '/opt/inav';
const metadata = require('./package.json');
console.log(`Generating rpm package for ${arch}`);
// The buildRpm does not generate the folder correctly, manually
createDirIfNotExists(appsDir);
const options = {
name: get_release_filename_base(arch), // metadata.name,
version: metadata.version.replace(NAME_REGEX, '_'), // RPM does not like release candidate versions
buildArch: getLinuxPackageArch('rpm', arch),
vendor: metadata.author,
summary: metadata.description,
license: 'GNU General Public License v3.0',
requires: ['libatomic1'],
prefix: '/opt',
files: [{
cwd: path.join(appsDir, metadata.name, arch),
src: '*',
dest: `${LINUX_INSTALL_DIR}/${metadata.name}`,
}],
postInstallScript: [`xdg-desktop-menu install ${LINUX_INSTALL_DIR}/${metadata.name}/${metadata.name}.desktop`],
preUninstallScript: [`xdg-desktop-menu uninstall ${metadata.name}.desktop`],
tempDir: path.join(appsDir, `tmp-rpm-build-${arch}`),
keepTemp: false,
verbose: false,
rpmDest: appsDir,
execOpts: { maxBuffer: 1024 * 1024 * 16 },
};
buildRpm(options, function(err) {
if (err) {
console.error(`Error generating rpm package: ${err}`);
}
done();
});
}
}
function getLinuxPackageArch(type, arch) {
let packArch;
switch (arch) {
case 'linux32':
packArch = 'i386';
break;
case 'linux64':
if (type === 'rpm') {
packArch = 'x86_64';
} else {
packArch = 'amd64';
}
break;
default:
console.error(`Package error, arch: ${arch}`);
process.exit(1);
break;
}
return packArch;
}
function releaseLinux(bits) {
return function() {
console.log(`Generating zip package for linux${bits}`);
var dirname = 'linux' + bits;
var pkg = require('./package.json');
var src = path.join(appsDir, pkg.name, dirname);
@ -384,8 +714,8 @@ function releaseLinux(bits) {
}
}
gulp.task('release-linux32', releaseLinux(32));
gulp.task('release-linux64', releaseLinux(64));
gulp.task('release-linux32', gulp.series(releaseLinux(32), post_build('linux32', appsDir), release_deb('linux32'), post_release_deb('linux32')));
gulp.task('release-linux64', gulp.series(releaseLinux(64), post_build('linux64', appsDir), release_deb('linux64'), post_release_deb('linux64'), release_rpm('linux64')));
// Create distributable .zip files in ./apps
gulp.task('release', gulp.series('apps', getPlatforms().map(function(v) { return 'release-' + v; })));

View file

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

Before After
Before After

View 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

View 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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Before After
Before After

554
js/CliAutoComplete.js Normal file
View file

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

View file

@ -5,7 +5,7 @@ var appUpdater = appUpdater || {};
appUpdater.checkRelease = function (currVersion) {
var modalStart;
$.get('https://api.github.com/repos/iNavFlight/inav-configurator/releases', function (releaseData) {
GUI.log('Loaded release information from GitHub.');
GUI.log(chrome.i18n.getMessage('loadedReleaseInfo'));
//Git return sorted list, 0 - last release
let newVersion = releaseData[0].tag_name;
@ -15,7 +15,7 @@ appUpdater.checkRelease = function (currVersion) {
GUI.log(newVersion, chrome.runtime.getManifest().version);
GUI.log(currVersion);
GUI.log('New version available!');
GUI.log(chrome.i18n.getMessage('newVersionAvailable'));
modalStart = new jBox('Modal', {
width: 400,
height: 200,

View file

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

View file

@ -102,10 +102,13 @@ helper.defaultsDialog = (function (data) {
};
privateScope.saveAndReboot = function () {
GUI.tab_switch_cleanup(function () {
MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, function () {
//noinspection JSUnresolvedVariable
if (typeof savingDefaultsModal !== 'undefined') {
savingDefaultsModal.close();
}
GUI.log(chrome.i18n.getMessage('deviceRebooting'));
GUI.handleReconnect();
});
@ -132,39 +135,96 @@ helper.defaultsDialog = (function (data) {
};
privateScope.setSettings = function (selectedDefaultPreset) {
var currentControlProfile = parseInt($("#profilechange").val());
var currentBatteryProfile = parseInt($("#batteryprofilechange").val());
var controlProfileSettings = [];
var batterySettings = [];
var miscSettings = [];
selectedDefaultPreset.settings.forEach(input => {
if (FC.isControlProfileParameter(input.key)) {
controlProfileSettings.push(input);
} else if (FC.isBatteryProfileParameter(input.key)) {
batterySettings.push(input);
} else {
miscSettings.push(input);
}
});
//Save analytics
googleAnalytics.sendEvent('Setting', 'Defaults', selectedDefaultPreset.title);
Promise.mapSeries(selectedDefaultPreset.settings, function (input, ii) {
return mspHelper.getSetting(input.key);
}).then(function () {
Promise.mapSeries(selectedDefaultPreset.settings, function (input, ii) {
return mspHelper.setSetting(input.key, input.value);
}).then(function () {
// If default preset is associated to a mixer, apply the mixer as well
var settingsChainer = MSPChainerClass();
var chain = [];
miscSettings.forEach(input => {
chain.push(function (callback) {
mspHelper.setSetting(input.key, input.value, callback);
});
});
for (var i = 0; i < 3; i++ ) {
chain.push(function (callback) {
MSP.send_message(MSPCodes.MSP_SELECT_SETTING, [i], false, callback);
});
controlProfileSettings.forEach(input => {
chain.push(function (callback) {
mspHelper.setSetting(input.key, input.value, callback);
});
});
}
for (var i = 0; i < 3; i++ ) {
chain.push(function (callback) {
MSP.send_message(MSPCodes.MSP2_INAV_SELECT_BATTERY_PROFILE, [i], false, callback);
});
batterySettings.forEach(input => {
chain.push(function (callback) {
mspHelper.setSetting(input.key, input.value, callback);
});
});
}
// Set Mixers
if (selectedDefaultPreset.mixerToApply) {
let currentMixerPreset = helper.mixer.getById(selectedDefaultPreset.mixerToApply);
helper.mixer.loadServoRules(currentMixerPreset);
helper.mixer.loadMotorRules(currentMixerPreset);
MIXER_CONFIG.platformType = currentMixerPreset.platform;
MIXER_CONFIG.appliedMixerPreset = selectedDefaultPreset.mixerToApply;
MIXER_CONFIG.motorStopOnLow = (currentMixerPreset.motorStopOnLow === true) ? true : false;
MIXER_CONFIG.hasFlaps = (currentMixerPreset.hasFlaps === true) ? true : false;
SERVO_RULES.cleanup();
SERVO_RULES.inflate();
MOTOR_RULES.cleanup();
MOTOR_RULES.inflate();
mspHelper.sendServoMixer(function () {
mspHelper.sendMotorMixer(function () {
privateScope.finalize(selectedDefaultPreset);
})
});
} else {
privateScope.finalize(selectedDefaultPreset);
chain = chain.concat([
mspHelper.saveMixerConfig,
mspHelper.sendServoMixer,
mspHelper.sendMotorMixer
]);
}
})
chain.push(function (callback) {
MSP.send_message(MSPCodes.MSP_SELECT_SETTING, [currentControlProfile], false, callback);
});
};
chain.push(function (callback) {
MSP.send_message(MSPCodes.MSP2_INAV_SELECT_BATTERY_PROFILE, [currentBatteryProfile], false, callback);
});
settingsChainer.setChain(chain);
settingsChainer.setExitPoint(function () {
privateScope.finalize(selectedDefaultPreset);
});
settingsChainer.execute();
}
privateScope.onPresetClick = function (event) {
savingDefaultsModal = new jBox('Modal', {

View file

@ -2,22 +2,8 @@ var helper = helper || {};
helper.defaultsDialogData = [
{
"title": 'Test',
"id": 17,
"notRecommended": false,
"reboot": true,
"mixerToApply": 3,
"wizardPages": ['receiver', 'outputs', 'gps', 'filters', 'pids'],
"settings": [
{
key: "model_preview_type",
value: 3
}
]
},
{
"title": 'Mini Quad with 3"-7" propellers',
"id": 2,
"title": 'Mini Quad with 3" propellers',
"id": 6,
"notRecommended": false,
"reboot": true,
"mixerToApply": 3,
@ -43,55 +29,43 @@ helper.defaultsDialogData = [
value: "DSHOT300"
},
/*
Filtering
Ez Tune setup
*/
{
key: "gyro_main_lpf_hz",
value: 110
},
{
key: "gyro_main_lpf_type",
value: "PT1"
},
{
key: "dterm_lpf_hz",
value: 110
},
{
key: "dterm_lpf_type",
value: "PT3"
},
{
key: "dterm_lpf2_hz",
value: 0
},
{
key: "dterm_lpf2_type",
value: "PT1"
},
{
key: "dynamic_gyro_notch_enabled",
key: "ez_enabled",
value: "ON"
},
{
key: "dynamic_gyro_notch_q",
value: 250
key: "ez_filter_hz",
value: 90
},
{
key: "dynamic_gyro_notch_min_hz",
value: 120
key: "ez_axis_ratio",
value: 116
},
{
key: "setpoint_kalman_enabled",
value: "ON"
key: "ez_response",
value: 71
},
{
key: "setpoint_kalman_q",
value: 200
key: "ez_damping",
value: 103
},
{
key: "smith_predictor_delay", // Enable Smith Predictor
value: 1.5
key: "ez_stability",
value: 105
},
{
key: "ez_aggressiveness",
value: 100
},
{
key: "ez_rate",
value: 134
},
{
key: "ez_expo",
value: 118
},
/*
Mechanics
@ -110,11 +84,11 @@ helper.defaultsDialogData = [
},
{
key: "d_boost_min",
value: 0.8
value: 1.0
},
{
key: "d_boost_max",
value: 1.2
value: 1.0
},
{
key: "antigravity_gain",
@ -125,63 +99,145 @@ helper.defaultsDialogData = [
value: 5
},
/*
Rates
* TPA
*/
{
key: "rc_yaw_expo",
value: 75
key: "tpa_rate",
value: 20
},
{
key: "rc_expo",
value: 75
key: "tpa_breakpoint",
value: 1200
},
{
key: "roll_rate",
value: 70
key: "platform_type",
value: "MULTIROTOR"
},
{
key: "pitch_rate",
value: 70
key: "applied_defaults",
value: 6
},
{
key: "yaw_rate",
value: 60
key: "failsafe_procedure",
value: "DROP"
}
]
},
{
"title": 'Mini Quad with 5" propellers',
"id": 2,
"notRecommended": false,
"reboot": true,
"mixerToApply": 3,
"settings": [
{
key: "model_preview_type",
value: 3
},
/*
PIDs
System
*/
{
key: "mc_p_pitch",
value: 44
key: "gyro_hardware_lpf",
value: "256HZ"
},
{
key: "mc_i_pitch",
value: 75
key: "looptime",
value: 500
},
{
key: "mc_d_pitch",
value: 25
key: "motor_pwm_protocol",
value: "DSHOT300"
},
/*
Ez Tune setup
*/
{
key: "ez_enabled",
value: "ON"
},
{
key: "mc_p_roll",
value: 40
key: "ez_filter_hz",
value: 110
},
{
key: "mc_i_roll",
value: 60
key: "ez_axis_ratio",
value: 110
},
{
key: "mc_d_roll",
value: 23
key: "ez_response",
value: 92
},
{
key: "mc_p_yaw",
value: 35
key: "ez_damping",
value: 108
},
{
key: "mc_i_yaw",
key: "ez_stability",
value: 110
},
{
key: "ez_aggressiveness",
value: 80
},
{
key: "ez_rate",
value: 134
},
{
key: "ez_expo",
value: 118
},
/*
Dynamic gyro LPF
*/
{
key: "gyro_use_dyn_lpf",
value: "ON"
},
{
key: "gyro_dyn_lpf_min_hz",
value: 85
},
{
key: "gyro_dyn_lpf_max_hz",
value: 300
},
{
key: "gyro_dyn_lpf_curve_expo",
value: 3
},
/*
Mechanics
*/
{
key: "airmode_type",
value: "THROTTLE_THRESHOLD"
},
{
key: "airmode_throttle_threshold",
value: 1150
},
{
key: "mc_iterm_relax",
value: "RP"
},
{
key: "d_boost_min",
value: 1.0
},
{
key: "d_boost_max",
value: 1.0
},
{
key: "antigravity_gain",
value: 2
},
{
key: "antigravity_accelerator",
value: 5
},
/*
* TPA
*/
@ -207,6 +263,127 @@ helper.defaultsDialogData = [
}
]
},
{
"title": 'Mini Quad with 7" propellers',
"id": 5,
"notRecommended": false,
"reboot": true,
"mixerToApply": 3,
"settings": [
{
key: "model_preview_type",
value: 3
},
/*
System
*/
{
key: "gyro_hardware_lpf",
value: "256HZ"
},
{
key: "looptime",
value: 500
},
{
key: "motor_pwm_protocol",
value: "DSHOT300"
},
/*
Ez Tune setup
*/
{
key: "ez_enabled",
value: "ON"
},
{
key: "ez_filter_hz",
value: 90
},
{
key: "ez_axis_ratio",
value: 110
},
{
key: "ez_response",
value: 101
},
{
key: "ez_damping",
value: 115
},
{
key: "ez_stability",
value: 100
},
{
key: "ez_aggressiveness",
value: 100
},
{
key: "ez_rate",
value: 134
},
{
key: "ez_expo",
value: 118
},
/*
Mechanics
*/
{
key: "airmode_type",
value: "THROTTLE_THRESHOLD"
},
{
key: "airmode_throttle_threshold",
value: 1150
},
{
key: "mc_iterm_relax",
value: "RPY"
},
{
key: "d_boost_min",
value: 0.8
},
{
key: "d_boost_max",
value: 1.2
},
{
key: "antigravity_gain",
value: 2
},
{
key: "antigravity_accelerator",
value: 5
},
/*
* TPA
*/
{
key: "tpa_rate",
value: 20
},
{
key: "tpa_breakpoint",
value: 1200
},
{
key: "platform_type",
value: "MULTIROTOR"
},
{
key: "applied_defaults",
value: 5
},
{
key: "failsafe_procedure",
value: "DROP"
}
]
},
{
"title": 'Airplane with a Tail',
"notRecommended": false,
@ -266,6 +443,10 @@ helper.defaultsDialogData = [
key: "motor_pwm_protocol",
value: "STANDARD"
},
{
key: "ahrs_inertia_comp_method",
value: "ADAPTIVE"
},
{
key: "throttle_idle",
value: 5.0
@ -292,19 +473,23 @@ helper.defaultsDialogData = [
},
{
key: "nav_fw_pos_z_p",
value: 15
value: 25
},
{
key: "nav_fw_pos_z_d",
key: "nav_fw_pos_z_i",
value: 5
},
{
key: "nav_fw_pos_z_d",
value: 8
},
{
key: "nav_fw_pos_xy_p",
value: 60
value: 55
},
{
key: "fw_turn_assist_pitch_gain",
value: 0.5
value: 0.4
},
{
key: "max_angle_inclination_rll",
@ -348,7 +533,7 @@ helper.defaultsDialogData = [
},
{
key: "fw_p_yaw",
value: 20
value: 50
},
{
key: "fw_i_yaw",
@ -356,19 +541,11 @@ helper.defaultsDialogData = [
},
{
key: "fw_d_yaw",
value: 0
value: 20
},
{
key: "fw_ff_yaw",
value: 100
},
{
key: "imu_acc_ignore_rate",
value: 9
},
{
key: "imu_acc_ignore_slope",
value: 5
value: 255
},
{
key: "airmode_type",
@ -391,25 +568,35 @@ helper.defaultsDialogData = [
value: 5000
},
{
key: "failsafe_mission",
value: "ON"
key: "nav_wp_radius",
value: 800
},
{
key: "nav_wp_radius",
key: "nav_wp_max_safe_distance",
value: 500
},
{
key: "nav_fw_launch_max_angle",
value: 45
},
{
key: "nav_fw_launch_motor_delay",
value: 100
},
{
key: "nav_fw_launch_max_altitude",
value: 5000
},
],
"features": [
{
bit: 4, // Enable MOTOR_STOP
state: true
}
]
key: "nav_fw_launch_climb_angle",
value: 25
},
],
},
{
"title": 'Airplane without a Tail (Wing, Delta, etc)',
"notRecommended": false,
"id": 3,
"id": 4,
"reboot": true,
"mixerToApply": 8,
"settings": [
@ -423,7 +610,7 @@ helper.defaultsDialogData = [
},
{
key: "applied_defaults",
value: 3
value: 4
},
{
key: "gyro_hardware_lpf",
@ -465,6 +652,10 @@ helper.defaultsDialogData = [
key: "motor_pwm_protocol",
value: "STANDARD"
},
{
key: "ahrs_inertia_comp_method",
value: "ADAPTIVE"
},
{
key: "throttle_idle",
value: 5.0
@ -491,19 +682,23 @@ helper.defaultsDialogData = [
},
{
key: "nav_fw_pos_z_p",
value: 15
value: 35
},
{
key: "nav_fw_pos_z_d",
key: "nav_fw_pos_z_i",
value: 5
},
{
key: "nav_fw_pos_z_d",
value: 10
},
{
key: "nav_fw_pos_xy_p",
value: 60
value: 70
},
{
key: "fw_turn_assist_pitch_gain",
value: 0.2
value: 0.3
},
{
key: "max_angle_inclination_rll",
@ -561,14 +756,6 @@ helper.defaultsDialogData = [
key: "fw_ff_yaw",
value: 100
},
{
key: "imu_acc_ignore_rate",
value: 9
},
{
key: "imu_acc_ignore_slope",
value: 5
},
{
key: "airmode_type",
value: "STICK_CENTER_ONCE"
@ -590,20 +777,30 @@ helper.defaultsDialogData = [
value: 5000
},
{
key: "failsafe_mission",
value: "ON"
key: "nav_wp_radius",
value: 1000
},
{
key: "nav_wp_radius",
key: "nav_wp_max_safe_distance",
value: 500
},
{
key: "nav_fw_launch_max_angle",
value: 75
},
{
key: "nav_fw_launch_motor_delay",
value: 100
},
{
key: "nav_fw_launch_max_altitude",
value: 5000
},
],
"features": [
{
bit: 4, // Enable MOTOR_STOP
state: true
}
]
key: "nav_fw_launch_climb_angle",
value: 25
},
],
},
{
"title": 'Rovers & Boats',
@ -645,8 +842,8 @@ helper.defaultsDialogData = [
value: "ROVER"
},
{
key: "nav_wp_safe_distance",
value: 50000
key: "nav_wp_max_safe_distance",
value: 500
},
{
key: "nav_fw_loiter_radius",

186
js/fc.js
View file

@ -29,6 +29,7 @@ var CONFIG,
MOTOR_DATA,
SERVO_DATA,
GPS_DATA,
ADSB_VEHICLES,
MISSION_PLANNER,
ANALOG,
ARMING_CONFIG,
@ -64,7 +65,8 @@ var CONFIG,
SAFEHOMES,
BOARD_ALIGNMENT,
CURRENT_METER_CONFIG,
FEATURES;
FEATURES,
RATE_DYNAMICS;
var FC = {
restartRequired: false,
@ -92,8 +94,7 @@ var FC = {
gpsHwStatus: 0,
rangeHwStatus: 0,
speedHwStatus: 0,
flowHwStatus: 0,
imu2HwStatus: 0
flowHwStatus: 0
};
SENSOR_CONFIG = {
@ -118,8 +119,9 @@ var FC = {
i2cError: 0,
activeSensors: 0,
mode: [],
profile: 0,
battery_profile: 0,
mixer_profile: -1,
profile: -1,
battery_profile: -1,
uid: [0, 0, 0],
accelerometerTrims: [0, 0],
armingFlags: 0,
@ -196,6 +198,7 @@ var FC = {
MIXER_CONFIG = {
yawMotorDirection: 0,
yawJumpPreventionLimit: 0,
motorStopOnLow: false,
platformType: -1,
hasFlaps: false,
appliedMixerPreset: -1,
@ -249,6 +252,12 @@ var FC = {
packetCount: 0
};
ADSB_VEHICLES = {
vehiclesCount: 0,
callsignLength: 0,
vehicles: []
};
MISSION_PLANNER = new WaypointCollection();
ANALOG = {
@ -541,6 +550,27 @@ var FC = {
SETTINGS = {};
SAFEHOMES = new SafehomeCollection();
RATE_DYNAMICS = {
sensitivityCenter: null,
sensitivityEnd: null,
correctionCenter: null,
correctionEnd: null,
weightCenter: null,
weightEnd: null
};
EZ_TUNE = {
enabled: null,
filterHz: null,
axisRatio: null,
response: null,
damping: null,
stability: null,
aggressiveness: null,
rate: null,
expo: null
};
},
getOutputUsages: function() {
return {
@ -555,7 +585,6 @@ var FC = {
getFeatures: function () {
var features = [
{bit: 1, group: 'batteryVoltage', name: 'VBAT'},
{bit: 4, group: 'other', name: 'MOTOR_STOP'},
{bit: 6, group: 'other', name: 'SOFTSERIAL', haveTip: true, showNameInTip: true},
{bit: 7, group: 'other', name: 'GPS', haveTip: true},
{bit: 10, group: 'other', name: 'TELEMETRY', showNameInTip: true},
@ -594,13 +623,10 @@ var FC = {
},
getGpsProtocols: function () {
return [
'NMEA',
'UBLOX',
'I2C-NAV',
'DJI NAZA',
'UBLOX7',
'MTK',
'MSP'
'MSP',
'FAKE'
];
},
getGpsBaudRates: function () {
@ -619,6 +645,7 @@ var FC = {
'North American WAAS',
'Japanese MSAS',
'Indian GAGAN',
'SouthPAN (AU/NZ)',
'Disabled'
];
},
@ -767,6 +794,24 @@ var FC = {
return retVal;
},
getAccelerometerCalibrated: function () {
var calibrated = true;
var flagNames = FC.getArmingFlags();
if (CALIBRATION_DATA.accGain.X === 4096 && CALIBRATION_DATA.accGain.Y === 4096 && CALIBRATION_DATA.accGain.Z === 4096 &&
CALIBRATION_DATA.accZero.X === 0 && CALIBRATION_DATA.accZero.Y === 0 && CALIBRATION_DATA.accZero.Z === 0
) {
calibrated = false;
}
if ((calibrated) && flagNames.hasOwnProperty(13)) {
if (bit_check(CONFIG.armingFlags, 13)) {
calibrated = false;
}
}
return calibrated;
},
getUserControlMode: function () {
return [
"Attitude",
@ -865,6 +910,7 @@ var FC = {
'GVAR 5', // 35
'GVAR 6', // 36
'GVAR 7', // 37
'Mixer Transition', // 38
];
},
getServoMixInputName: function (input) {
@ -892,19 +938,19 @@ var FC = {
output: "boolean"
},
1: {
name: "Equal",
name: "Equal (A = B)",
operandType: "Comparison",
hasOperand: [true, true],
output: "boolean"
},
2: {
name: "Greater Than",
name: "Greater Than (A > B)",
operandType: "Comparison",
hasOperand: [true, true],
output: "boolean"
},
3: {
name: "Lower Than",
name: "Lower Than (A < B)",
operandType: "Comparison",
hasOperand: [true, true],
output: "boolean"
@ -1162,6 +1208,48 @@ var FC = {
hasOperand: [true, true],
output: "boolean"
},
47: {
name: "Edge",
operandType: "Logic Switches",
hasOperand: [true, true],
output: "boolean"
},
48: {
name: "Delay",
operandType: "Logic Switches",
hasOperand: [true, true],
output: "boolean"
},
49: {
name: "Timer",
operandType: "Logic Switches",
hasOperand: [true, true],
output: "boolean"
},
50: {
name: "Delta (|A| >= B)",
operandType: "Comparison",
hasOperand: [true, true],
output: "boolean"
},
51: {
name: "Approx Equals (A ~ B)",
operandType: "Comparison",
hasOperand: [true, true],
output: "boolean"
},
52: {
name: "LED Pin PWM",
operandType: "Set Flight Parameter",
hasOperand: [true, false],
output: "raw"
},
54: {
name: "Mag calibration",
operandType: "Set Flight Parameter",
hasOperand: [false, false],
output: "boolean"
},
}
},
getOperandTypes: function () {
@ -1208,24 +1296,24 @@ var FC = {
20: "Is Controlling Position",
21: "Is Emergency Landing",
22: "Is RTH",
23: "Is WP",
24: "Is Landing",
25: "Is Failsafe",
26: "Stabilized Roll",
27: "Stabilized Pitch",
28: "Stabilized Yaw",
29: "Current Waypoint Index",
30: "Current Waypoint Action",
31: "3D home distance [m]",
32: "CRSF LQ",
33: "CRSF SNR",
34: "GPS Valid Fix",
35: "Loiter Radius [cm]",
36: "Active Profile",
37: "Battery cells",
38: "AGL status [0/1]",
39: "AGL [cm]",
40: "Rangefinder [cm]",
23: "Is Landing",
24: "Is Failsafe",
25: "Stabilized Roll",
26: "Stabilized Pitch",
27: "Stabilized Yaw",
28: "3D home distance [m]",
29: "CRSF LQ",
30: "CRSF SNR",
31: "GPS Valid Fix",
32: "Loiter Radius [cm]",
33: "Active PIDProfile",
34: "Battery cells",
35: "AGL status [0/1]",
36: "AGL [cm]",
37: "Rangefinder [cm]",
38: "Active MixerProfile",
39: "MixerTransition Active",
40: "Yaw [deg]"
}
},
3: {
@ -1243,13 +1331,18 @@ var FC = {
7: "Horizon",
8: "Air",
9: "USER 1",
10: "USER 2"
10: "USER 2",
11: "Course Hold",
12: "USER 3",
13: "USER 4",
14: "Acro",
15: "Waypoint Mission",
}
},
4: {
name: "Logic Condition",
type: "range",
range: [0, 31],
range: [0, (LOGIC_CONDITIONS.getMaxLogicConditionCount()-1)],
default: 0
},
5: {
@ -1263,7 +1356,28 @@ var FC = {
type: "range",
range: [0, 3],
default: 0
},
7: {
name: "Waypoints",
type: "dictionary",
default: 0,
values: {
0: "Is WP",
1: "Current Waypoint Index",
2: "Current Waypoint Action",
3: "Next Waypoint Action",
4: "Distance to next Waypoint [m]",
5: "Distance from last Waypoint [m]",
6: "Current WP has User Action 1",
7: "Current WP has User Action 2",
8: "Current WP has User Action 3",
9: "Current WP has User Action 4",
10: "Next WP has User Action 1",
11: "Next WP has User Action 2",
12: "Next WP has User Action 3",
13: "Next WP has User Action 4",
}
},
}
},
getBatteryProfileParameters: function () {
@ -1282,7 +1396,6 @@ var FC = {
'throttle_idle',
'turtle_mode_power_factor',
'failsafe_throttle',
'fw_min_throttle_down_pitch',
'nav_mc_hover_thr',
'nav_fw_cruise_thr',
'nav_fw_min_thr',
@ -1339,11 +1452,8 @@ var FC = {
'max_angle_inclination_pit',
'dterm_lpf_hz',
'dterm_lpf_type',
'dterm_lpf2_hz',
'dterm_lpf2_type',
'yaw_lpf_hz',
'fw_iterm_throw_limit',
'fw_loiter_direction',
'fw_reference_airspeed',
'fw_turn_assist_yaw_gain',
'fw_turn_assist_pitch_gain',

187
js/gui.js
View file

@ -14,6 +14,7 @@ var GUI_control = function () {
'landing',
'firmware_flasher',
'mission_control',
'sitl',
'help'
];
this.defaultAllowedTabsWhenConnected = [
@ -40,7 +41,8 @@ var GUI_control = function () {
'advanced_tuning',
'mission_control',
'mixer',
'programming'
'programming',
'ez_tune'
];
this.allowedTabs = this.defaultAllowedTabsWhenDisconnected;
@ -51,6 +53,17 @@ var GUI_control = function () {
else if (navigator.appVersion.indexOf("Linux") != -1) this.operating_system = "Linux";
else if (navigator.appVersion.indexOf("X11") != -1) this.operating_system = "UNIX";
else this.operating_system = "Unknown";
this.colorTable = [
"#8ecae6",
"#2a9d8f",
"#e9c46a",
"#f4a261",
"#e76f51",
"#ef476f",
"#ffc300"
];
};
// message = string
@ -202,14 +215,61 @@ GUI_control.prototype.content_ready = function (callback) {
};
GUI_control.prototype.updateStatusBar = function() {
var armingFlags = {
'ARMED':(1 << 2),
//'WAS_EVER_ARMED':(1 << 3),
'SIMULATOR_MODE':(1 << 4),
'ARMING_DISABLED_FAILSAFE_SYSTEM':(1 << 7),
'ARMING_DISABLED_NOT_LEVEL':(1 << 8),
'ARMING_DISABLED_SENSORS_CALIBRATING':(1 << 9),
'ARMING_DISABLED_SYSTEM_OVERLOADED':(1 << 10),
'ARMING_DISABLED_NAVIGATION_UNSAFE':(1 << 11),
'ARMING_DISABLED_COMPASS_NOT_CALIBRATED':(1 << 12),
'ARMING_DISABLED_ACCELEROMETER_NOT_CALIBRATED':(1 << 13),
'ARMING_DISABLED_ARM_SWITCH':(1 << 14),
'ARMING_DISABLED_HARDWARE_FAILURE':(1 << 15),
'ARMING_DISABLED_BOXFAILSAFE':(1 << 16),
'ARMING_DISABLED_BOXKILLSWITCH':(1 << 17),
'ARMING_DISABLED_RC_LINK':(1 << 18),
'ARMING_DISABLED_THROTTLE':(1 << 19),
'ARMING_DISABLED_CLI':(1 << 20),
'ARMING_DISABLED_CMS_MENU':(1 << 21),
'ARMING_DISABLED_OSD_MENU':(1 << 22),
'ARMING_DISABLED_ROLLPITCH_NOT_CENTERED':(1 << 23),
'ARMING_DISABLED_SERVO_AUTOTRIM':(1 << 24),
'ARMING_DISABLED_OOM':(1 << 25),
'ARMING_DISABLED_INVALID_SETTING':(1 << 26),
'ARMING_DISABLED_PWM_OUTPUT_ERROR':(1 << 27),
'ARMING_DISABLED_NO_PREARM':(1 << 28),
'ARMING_DISABLED_DSHOT_BEEPER':(1 << 29),
'ARMING_DISABLED_LANDING_DETECTED':(1 << 30),
};
var activeArmFlags = [];
for(var i=0;i<32;i++) {
var checkBit = (1 << i);
if(Object.values(armingFlags).includes(checkBit) && (checkBit & CONFIG.armingFlags)) {
activeArmFlags.push(Object.keys(armingFlags)[Object.values(armingFlags).indexOf(checkBit)]);
}
}
$('span.i2c-error').text(CONFIG.i2cError);
$('span.cycle-time').text(CONFIG.cycleTime);
$('span.cpu-load').text(chrome.i18n.getMessage('statusbar_cpu_load', [CONFIG.cpuload]));
$('span.arming-flags').text(activeArmFlags.length ? activeArmFlags.join(', ') : '-');
};
GUI_control.prototype.updateProfileChange = function() {
GUI_control.prototype.updateProfileChange = function(refresh) {
$('#mixerprofilechange').val(CONFIG.mixer_profile);
$('#profilechange').val(CONFIG.profile);
$('#batteryprofilechange').val(CONFIG.battery_profile);
if (refresh) {
GUI.log(chrome.i18n.getMessage('loadedMixerProfile', [CONFIG.mixer_profile + 1]));
GUI.log(chrome.i18n.getMessage('pidTuning_LoadedProfile', [CONFIG.profile + 1]));
GUI.log(chrome.i18n.getMessage('loadedBatteryProfile', [CONFIG.battery_profile + 1]));
updateActivatedTab();
}
};
GUI_control.prototype.fillSelect = function ($element, values, currentValue, unit) {
@ -279,11 +339,27 @@ GUI_control.prototype.renderOperandValue = function ($container, operandMetadata
$t.append('<option value="' + i + '">' + i + '</option>');
}
} else if (operandMetadata.type == "dictionary") {
for (let k in operandMetadata.values) {
if (operandMetadata.values.hasOwnProperty(k)) {
$t.append('<option value="' + k + '">' + operandMetadata.values[k] + '</option>');
let operandValues = [];
for (let j in operandMetadata.values) {
if (operandMetadata.values.hasOwnProperty(j)) {
operandValues[parseInt(j,10)] = {
id: parseInt(j, 10),
name: operandMetadata.values[j],
};
}
}
operandValues.sort((a, b) => {
let ovAN = a.name.toLowerCase(),
ovBN = b.name.toLowerCase();
return (ovAN < ovBN) ? -1 : 1;
});
operandValues.forEach( val => {
$t.append('<option value="' + val.id + '">' + val.name + '</option>');
});
}
$t.val(value);
@ -300,20 +376,117 @@ GUI_control.prototype.renderOperandValue = function ($container, operandMetadata
* @param {function} onChange
* @param {boolean} withAlways
*/
GUI_control.prototype.renderLogicConditionSelect = function ($container, logicConditions, current, onChange, withAlways) {
GUI_control.prototype.renderLogicConditionSelect = function ($container, logicConditions, current, onChange, withAlways, onlyEnabled) {
let $select = $container.append('<select class="mix-rule-condition">').find("select"),
lcCount = logicConditions.getCount();
option = "";
if (withAlways) {
$select.append('<option value="-1">Always</option>')
}
for (let i = 0; i < lcCount ; i++) {
$select.append('<option value="' + i + '">Logic Condition ' + i + ' </option>');
if (!onlyEnabled || i === current || (logicConditions.isEnabled(i))) {
option = '<option';
if (i === current && !logicConditions.isEnabled(i)) {
option+= ' class="lc_disabled"';
}
option+= ' value="' + i + '">Logic Condition ' + i + ' </option>';
$select.append(option);
}
}
$select.val(current).change(onChange);
}
GUI_control.prototype.sliderize = function ($input, value, min, max) {
let scaledMax;
let scaledMin;
let scalingThreshold;
if ($input.data('normal-max')) {
scaledMax = max * 2;
scalingThreshold = Math.round(scaledMax * 0.8);
scaledMin = min *2;
} else {
scaledMax = max;
scaledMin = min;
scalingThreshold = scaledMax;
}
let $range = $('<input type="range" min="' + scaledMin + '" max="' + scaledMax + '" value="' + value + '"/>');
if ($input.data('step')) {
$range.attr('step', $input.data('step'));
}
$range.css({
'display': 'block',
'flex-grow': 100,
'margin-left': '1em',
'margin-right': '1em',
});
$input.attr('min', min);
$input.attr('max', max);
$input.val(parseInt(value));
$input.css({
'width': 'auto',
'min-width': '75px',
});
$input.parent().css({
'display': 'flex',
'width': '100%'
});
$range.insertAfter($input);
$input.parent().find('.helpicon').css({
'top': '5px',
'left': '-10px'
});
/*
* Update slider to input
*/
$range.on('input', function() {
let val = $(this).val();
let normalMax = parseInt($input.data('normal-max'));
if (normalMax) {
if (val <= scalingThreshold) {
val = scaleRangeInt(val, scaledMin, scalingThreshold, min, normalMax);
} else {
val = scaleRangeInt(val, scalingThreshold + 1, scaledMax, normalMax + 1, max);
}
}
$input.val(val);
$input.trigger('updated');
});
$input.on('change', function() {
let val = $(this).val();
let newVal;
let normalMax = parseInt($input.data('normal-max'));
if (normalMax) {
if (val <= normalMax) {
newVal = scaleRangeInt(val, min, normalMax, scaledMin, scalingThreshold);
} else {
newVal = scaleRangeInt(val, normalMax + 1, max, scalingThreshold + 1, scaledMax);
}
} else {
newVal = val;
}
$range.val(newVal);
$input.trigger('updated');
});
$input.trigger('change');
};
// initialize object into GUI variable
var GUI = new GUI_control();

View file

@ -42,8 +42,9 @@ function generateFilename(prefix, suffix) {
if (CONFIG) {
if (CONFIG.flightControllerIdentifier) {
filename = CONFIG.flightControllerIdentifier + '_' + filename;
filename = CONFIG.flightControllerIdentifier + '_' + CONFIG.flightControllerVersion + "_" + filename;
}
if (CONFIG.name && CONFIG.name.trim() !== '') {
filename = filename + '_' + CONFIG.name.trim().replace(' ', '_');
}

View file

@ -221,6 +221,7 @@ let LogicCondition = function (enabled, activatorId, operation, operandAType, op
LOGIC_CONDITIONS,
self.getActivatorId,
self.onActivatorChange,
true,
true
);
} else {

View file

@ -28,6 +28,10 @@ let LogicConditionsCollection = function () {
return data.length
};
self.isEnabled = function (lcID) {
return data[lcID].getEnabled();
}
self.open = function () {
self.render();
$container.show();

View file

@ -32,6 +32,12 @@ const INPUT_STABILIZED_ROLL = 0,
INPUT_GIMBAL_PITCH = 12,
INPUT_GIMBAL_ROLL = 13,
INPUT_FEATURE_FLAPS = 14;
STABILIZED_ROLL_POSITIVE = 23;
STABILIZED_ROLL_NEGATIVE = 24;
STABILIZED_PITCH_POSITIVE = 25;
STABILIZED_PITCH_NEGATIVE = 26;
STABILIZED_YAW_POSITIVE = 27;
STABILIZED_YAW_NEGATIVE = 28;
const
PLATFORM_MULTIROTOR = 0,
@ -344,6 +350,7 @@ const mixerList = [
enabled: true,
legacy: true,
platform: PLATFORM_AIRPLANE,
motorStopOnLow: true,
motorMixer: [
new MotorMixRule(1.0, 0.0, 0.0, 0.0),
],
@ -367,6 +374,7 @@ const mixerList = [
enabled: true,
legacy: false,
platform: PLATFORM_AIRPLANE,
motorStopOnLow: true,
motorMixer: [
new MotorMixRule(1.0, 0.0, 0.0, 0.1),
new MotorMixRule(1.0, 0.0, 0.0, -0.1)
@ -393,6 +401,7 @@ const mixerList = [
enabled: true,
legacy: true,
platform: PLATFORM_AIRPLANE,
motorStopOnLow: true,
hasFlaps: true,
motorMixer: [
new MotorMixRule(1.0, 0.0, 0.0, 0.0),
@ -421,6 +430,7 @@ const mixerList = [
enabled: true,
legacy: false,
platform: PLATFORM_AIRPLANE,
motorStopOnLow: true,
hasFlaps: true,
motorMixer: [
new MotorMixRule(1.0, 0.0, 0.0, 0.3),
@ -450,6 +460,7 @@ const mixerList = [
enabled: true,
legacy: false,
platform: PLATFORM_AIRPLANE,
motorStopOnLow: true,
hasFlaps: true,
motorMixer: [
new MotorMixRule(1.0, 0.0, 0.0, 0.0),
@ -480,6 +491,7 @@ const mixerList = [
enabled: true,
legacy: false,
platform: PLATFORM_AIRPLANE,
motorStopOnLow: true,
hasFlaps: true,
motorMixer: [
new MotorMixRule(1.0, 0.0, 0.0, 0.3),
@ -510,6 +522,7 @@ const mixerList = [
enabled: true,
legacy: false,
platform: PLATFORM_AIRPLANE,
motorStopOnLow: true,
motorMixer: [
new MotorMixRule(1.0, 0.0, 0.0, 0.0),
],
@ -536,6 +549,7 @@ const mixerList = [
legacy: false,
platform: PLATFORM_AIRPLANE,
hasFlaps: true,
motorStopOnLow: true,
motorMixer: [
new MotorMixRule(1.0, 0.0, 0.0, 0.0),
],
@ -562,6 +576,7 @@ const mixerList = [
enabled: false,
legacy: true,
platform: PLATFORM_AIRPLANE,
motorStopOnLow: true,
motorMixer: [],
servoMixer: []
}, // 24

View file

@ -6,7 +6,7 @@ var MotorMixRule = function (throttle, roll, pitch, yaw) {
var self = {};
self.fromMsp = function (mspThrottle, mspRoll, mspPitch, mspYaw) {
throttle = mspThrottle / 1000;
throttle = Math.round(((mspThrottle / 1000) - 2) * 1000) / 1000;
roll = Math.round(((mspRoll / 1000) - 2) * 1000) / 1000;
pitch = Math.round(((mspPitch / 1000) - 2) * 1000) / 1000;
yaw = Math.round(((mspYaw / 1000) - 2) * 1000) / 1000;
@ -17,11 +17,11 @@ var MotorMixRule = function (throttle, roll, pitch, yaw) {
};
self.getThrottle = function () {
return constrain(parseFloat(throttle, 10), 0, 1);
return constrain(parseFloat(throttle, 10), -2, 2);
};
self.getThrottleForMsp = function () {
return self.getThrottle() * 1000;
return (self.getThrottle()+2) * 1000;
};
self.setThrottle = function (data) {

View file

@ -5,6 +5,7 @@ var MotorMixerRuleCollection = function () {
let self = {},
data = [],
inactiveData = [],
maxMotorCount = 8;
self.setMotorCount = function (value) {
@ -16,7 +17,11 @@ var MotorMixerRuleCollection = function () {
};
self.put = function (element) {
if (data.length < self.getMotorCount()){
data.push(element);
}else{
inactiveData.push(element); //store the data for mixer_profile 2
}
};
self.get = function () {
@ -30,18 +35,25 @@ var MotorMixerRuleCollection = function () {
self.flush = function () {
data = [];
inactiveData = [];
};
self.cleanup = function () {
var tmpData = [];
var tmpInactiveData = [];
data.forEach(function (element) {
if (element.isUsed()) {
tmpData.push(element);
}
});
inactiveData.forEach(function (element) {
if (element.isUsed()) {
tmpInactiveData.push(element);
}
});
data = tmpData;
inactiveData = tmpInactiveData;
};
self.inflate = function () {
@ -55,7 +67,7 @@ var MotorMixerRuleCollection = function () {
};
self.getNumberOfConfiguredMotors = function () {
return data.length;
return data.length > inactiveData.length ? data.length : inactiveData.length;
};
return self;

View file

@ -73,7 +73,7 @@ var MSP = {
ledDirectionLetters: ['n', 'e', 's', 'w', 'u', 'd'], // in LSB bit order
ledFunctionLetters: ['i', 'w', 'f', 'a', 't', 'r', 'c', 'g', 's', 'b', 'l'], // in LSB bit order
ledBaseFunctionLetters: ['c', 'f', 'a', 'l', 's', 'g', 'r', 'h'], // in LSB bit
ledOverlayLetters: ['t', 'o', 'b', 'n', 'i', 'w'], // in LSB bit
ledOverlayLetters: ['t', 'o', 'b', 'n', 'i', 'w', 'e'], // in LSB bit
last_received_timestamp: null,
analog_last_received_timestamp: null,

View file

@ -180,6 +180,11 @@ var MSPCodes = {
MSPV2_INAV_SET_RATE_PROFILE: 0x2008,
MSPV2_INAV_AIR_SPEED: 0x2009,
MSPV2_INAV_OUTPUT_MAPPING: 0x200A,
MSP2_INAV_MC_BRAKING: 0x200B,
MSP2_INAV_SET_MC_BRAKING: 0x200C,
MSPV2_INAV_OUTPUT_MAPPING_EXT: 0x200D,
MSP2_INAV_TIMER_OUTPUT_MODE: 0x200E,
MSP2_INAV_SET_TIMER_OUTPUT_MODE: 0x200F,
MSP2_INAV_MIXER: 0x2010,
MSP2_INAV_SET_MIXER: 0x2011,
@ -191,9 +196,6 @@ var MSPCodes = {
MSP2_INAV_OSD_PREFERENCES: 0x2016,
MSP2_INAV_OSD_SET_PREFERENCES: 0x2017,
MSP2_INAV_MC_BRAKING: 0x200B,
MSP2_INAV_SET_MC_BRAKING: 0x200C,
MSP2_INAV_SELECT_BATTERY_PROFILE: 0x2018,
MSP2_INAV_DEBUG: 0x2019,
@ -217,6 +219,7 @@ var MSPCodes = {
MSP2_INAV_SET_PROGRAMMING_PID: 0x2029,
MSP2_INAV_PROGRAMMING_PID_STATUS: 0x202A,
MSP2_PID: 0x2030,
MSP2_SET_PID: 0x2031,
@ -231,5 +234,18 @@ var MSPCodes = {
MSP2_INAV_SAFEHOME: 0x2038,
MSP2_INAV_SET_SAFEHOME: 0x2039,
MSP2_INAV_LOGIC_CONDITIONS_SINGLE: 0x203B
MSP2_INAV_LOGIC_CONDITIONS_SINGLE: 0x203B,
MSP2_INAV_LED_STRIP_CONFIG_EX: 0x2048,
MSP2_INAV_SET_LED_STRIP_CONFIG_EX: 0x2049,
MSP2_INAV_RATE_DYNAMICS: 0x2060,
MSP2_INAV_SET_RATE_DYNAMICS: 0x2061,
MSP2_INAV_EZ_TUNE: 0x2070,
MSP2_INAV_EZ_TUNE_SET: 0x2071,
MSP2_INAV_SELECT_MIXER_PROFILE: 0x2080,
MSP2_ADSB_VEHICLE_LIST: 0x2090,
};

View file

@ -42,9 +42,9 @@ var mspHelper = (function (gui) {
'GSM_SMS': 19,
'FRSKY_OSD': 20,
'DJI_FPV': 21,
'SBUS_OUTPUT': 22,
'SMARTPORT_MASTER': 23,
'IMU2': 24,
'HDZERO_VTX': 25,
'MSP_DISPLAYPORT': 25,
};
// Required for MSP_DEBUGMSG because console.log() doesn't allow omitting
@ -69,6 +69,7 @@ var mspHelper = (function (gui) {
color;
if (!dataHandler.unsupported || dataHandler.unsupported) switch (dataHandler.code) {
case MSPCodes.MSPV2_INAV_STATUS:
let profile_changed = false;
CONFIG.cycleTime = data.getUint16(offset, true);
offset += 2;
CONFIG.i2cError = data.getUint16(offset, true);
@ -77,13 +78,28 @@ var mspHelper = (function (gui) {
offset += 2;
CONFIG.cpuload = data.getUint16(offset, true);
offset += 2;
profile_byte = data.getUint8(offset++)
CONFIG.profile = profile_byte & 0x0F;
CONFIG.battery_profile = (profile_byte & 0xF0) >> 4;
let profile = profile_byte & 0x0F;
profile_changed |= (profile !== CONFIG.profile) && (CONFIG.profile !==-1);
CONFIG.profile = profile;
let battery_profile = (profile_byte & 0xF0) >> 4;
profile_changed |= (battery_profile !== CONFIG.battery_profile) && (CONFIG.battery_profile !==-1);
CONFIG.battery_profile = battery_profile;
CONFIG.armingFlags = data.getUint32(offset, true);
offset += 4;
//As there are 8 bytes for mspBoxModeFlags (number of bytes is actually variable)
//read mixer profile as the last byte in the the message
profile_byte = data.getUint8(dataHandler.message_length_expected - 1);
let mixer_profile = profile_byte & 0x0F;
profile_changed |= (mixer_profile !== CONFIG.mixer_profile) && (CONFIG.mixer_profile !==-1);
CONFIG.mixer_profile = mixer_profile;
gui.updateStatusBar();
gui.updateProfileChange();
gui.updateProfileChange(profile_changed);
break;
case MSPCodes.MSP_ACTIVEBOXES:
@ -104,7 +120,6 @@ var mspHelper = (function (gui) {
SENSOR_STATUS.rangeHwStatus = data.getUint8(6);
SENSOR_STATUS.speedHwStatus = data.getUint8(7);
SENSOR_STATUS.flowHwStatus = data.getUint8(8);
SENSOR_STATUS.imu2HwStatus = data.getUint8(9);
sensor_status_ex(SENSOR_STATUS);
break;
@ -172,6 +187,35 @@ var mspHelper = (function (gui) {
GPS_DATA.eph = data.getUint16(16, true);
GPS_DATA.epv = data.getUint16(18, true);
break;
case MSPCodes.MSP2_ADSB_VEHICLE_LIST:
var byteOffsetCounter = 0;
ADSB_VEHICLES.vehicles = [];
ADSB_VEHICLES.vehiclesCount = data.getUint8(byteOffsetCounter++);
ADSB_VEHICLES.callsignLength = data.getUint8(byteOffsetCounter++);
for(i = 0; i < ADSB_VEHICLES.vehiclesCount; i++){
var vehicle = {callSignByteArray: [], callsign: "", icao: 0, lat: 0, lon: 0, alt: 0, heading: 0, ttl: 0, tslc: 0, emitterType: 0};
for(ii = 0; ii < ADSB_VEHICLES.callsignLength; ii++){
vehicle.callSignByteArray.push(data.getUint8(byteOffsetCounter++));
}
vehicle.callsign = (String.fromCharCode(...vehicle.callSignByteArray)).replace(/[^\x20-\x7E]/g, '');
vehicle.icao = data.getUint32(byteOffsetCounter, true); byteOffsetCounter += 4;
vehicle.lat = data.getInt32(byteOffsetCounter, true); byteOffsetCounter += 4;
vehicle.lon = data.getInt32(byteOffsetCounter, true); byteOffsetCounter += 4;
vehicle.altCM = data.getInt32(byteOffsetCounter, true); byteOffsetCounter += 4;
vehicle.headingDegrees = data.getUint16(byteOffsetCounter, true); byteOffsetCounter += 2;
vehicle.tslc = data.getUint8(byteOffsetCounter++);
vehicle.emitterType = data.getUint8(byteOffsetCounter++);
vehicle.ttl = data.getUint8(byteOffsetCounter++);
ADSB_VEHICLES.vehicles.push(vehicle);
}
break;
case MSPCodes.MSP_ATTITUDE:
SENSOR_DATA.kinematics[0] = data.getInt16(0, true) / 10.0; // x
SENSOR_DATA.kinematics[1] = data.getInt16(2, true) / 10.0; // y
@ -777,6 +821,18 @@ var mspHelper = (function (gui) {
CONFIG.boardIdentifier = identifier;
CONFIG.boardVersion = data.getUint16(offset, 1);
offset += 2;
if (semver.gt(CONFIG.flightControllerVersion, "4.1.0")) {
CONFIG.osdUsed = data.getUint8(offset++);
CONFIG.commCompatability = data.getUint8(offset++);
let targetNameLen = data.getUint8(offset++);
let targetName = "";
targetNameLen += offset;
for (offset = offset; offset < targetNameLen; offset++) {
targetName += String.fromCharCode(data.getUint8(offset));
}
CONFIG.target = targetName;
}
break;
case MSPCodes.MSP_SET_CHANNEL_FORWARDING:
@ -797,7 +853,7 @@ var mspHelper = (function (gui) {
msp_baudrate: BAUD_RATES[data.getUint8(offset + 5)],
sensors_baudrate: BAUD_RATES[data.getUint8(offset + 6)],
telemetry_baudrate: BAUD_RATES[data.getUint8(offset + 7)],
blackbox_baudrate: BAUD_RATES[data.getUint8(offset + 8)]
peripherals_baudrate: BAUD_RATES[data.getUint8(offset + 8)]
};
offset += bytesPerPort;
@ -1018,9 +1074,66 @@ var mspHelper = (function (gui) {
}
}
break;
case MSPCodes.MSP2_INAV_LED_STRIP_CONFIG_EX:
//noinspection JSUndeclaredVariable
LED_STRIP = [];
var ledCount = data.byteLength / 5;
var directionMask,
directions,
directionLetterIndex,
functions,
led;
for (i = 0; offset < data.byteLength && i < ledCount; i++) {
var mask = data.getUint32(offset, 1);
offset += 4;
var extra = data.getUint8(offset, 1);
offset++;
var functionId = (mask >> 8) & 0xFF;
functions = [];
for (var baseFunctionLetterIndex = 0; baseFunctionLetterIndex < MSP.ledBaseFunctionLetters.length; baseFunctionLetterIndex++) {
if (functionId == baseFunctionLetterIndex) {
functions.push(MSP.ledBaseFunctionLetters[baseFunctionLetterIndex]);
break;
}
}
var overlayMask = (mask >> 16) & 0xFF;
for (var overlayLetterIndex = 0; overlayLetterIndex < MSP.ledOverlayLetters.length; overlayLetterIndex++) {
if (bit_check(overlayMask, overlayLetterIndex)) {
functions.push(MSP.ledOverlayLetters[overlayLetterIndex]);
}
}
directionMask = (mask >> 28) & 0xF | ((extra & 0x3) << 4);
directions = [];
for (directionLetterIndex = 0; directionLetterIndex < MSP.ledDirectionLetters.length; directionLetterIndex++) {
if (bit_check(directionMask, directionLetterIndex)) {
directions.push(MSP.ledDirectionLetters[directionLetterIndex]);
}
}
led = {
y: (mask) & 0xF,
x: (mask >> 4) & 0xF,
functions: functions,
color: (mask >> 24) & 0xF,
directions: directions,
parameters: (extra >> 2) & 0x3F
};
LED_STRIP.push(led);
}
break;
case MSPCodes.MSP_SET_LED_STRIP_CONFIG:
console.log('Led strip config saved');
break;
case MSPCodes.MSP2_INAV_SET_LED_STRIP_CONFIG_EX:
console.log('Led strip extended config saved');
break;
case MSPCodes.MSP_LED_COLORS:
//noinspection JSUndeclaredVariable
@ -1386,7 +1499,8 @@ var mspHelper = (function (gui) {
break;
case MSPCodes.MSP2_INAV_MIXER:
MIXER_CONFIG.yawMotorDirection = data.getInt8(0);
MIXER_CONFIG.yawJumpPreventionLimit = data.getUint16(1, true);
MIXER_CONFIG.yawJumpPreventionLimit = data.getUint8(1, true);
MIXER_CONFIG.motorStopOnLow = data.getUint8(2, true);
MIXER_CONFIG.platformType = data.getInt8(3);
MIXER_CONFIG.hasFlaps = data.getInt8(4);
MIXER_CONFIG.appliedMixerPreset = data.getInt16(5, true);
@ -1412,10 +1526,38 @@ var mspHelper = (function (gui) {
case MSPCodes.MSP2_INAV_OSD_SET_PREFERENCES:
console.log('OSD preferences saved');
break;
case MSPCodes.MSP2_INAV_SELECT_BATTERY_PROFILE:
console.log('Battery profile selected');
break;
case MSPCodes.MSPV2_INAV_OUTPUT_MAPPING:
OUTPUT_MAPPING.flush();
for (i = 0; i < data.byteLength; ++i)
OUTPUT_MAPPING.put(data.getUint8(i));
OUTPUT_MAPPING.put({
'timerId': i,
'usageFlags': data.getUint8(i)});
break;
case MSPCodes.MSPV2_INAV_OUTPUT_MAPPING_EXT:
OUTPUT_MAPPING.flush();
for (i = 0; i < data.byteLength; i += 2) {
timerId = data.getUint8(i);
usageFlags = data.getUint8(i + 1);
OUTPUT_MAPPING.put(
{
'timerId': timerId,
'usageFlags': usageFlags
});
}
break;
case MSPCodes.MSP2_INAV_TIMER_OUTPUT_MODE:
if(data.byteLength > 2) {
OUTPUT_MAPPING.flushTimerOverrides();
}
for (i = 0; i < data.byteLength; i += 2) {
timerId = data.getUint8(i);
outputMode = data.getUint8(i + 1);
OUTPUT_MAPPING.setTimerOverride(timerId, outputMode);
}
break;
case MSPCodes.MSP2_INAV_MC_BRAKING:
@ -1465,6 +1607,35 @@ var mspHelper = (function (gui) {
console.log('Safehome points saved');
break;
case MSPCodes.MSP2_INAV_RATE_DYNAMICS:
RATE_DYNAMICS.sensitivityCenter = data.getUint8(0);
RATE_DYNAMICS.sensitivityEnd = data.getUint8(1);
RATE_DYNAMICS.correctionCenter = data.getUint8(2);
RATE_DYNAMICS.correctionEnd = data.getUint8(3);
RATE_DYNAMICS.weightCenter = data.getUint8(4);
RATE_DYNAMICS.weightEnd = data.getUint8(5);
break;
case MSPCodes.MSP2_INAV_SET_RATE_DYNAMICS:
console.log('Rate dynamics saved');
break;
case MSPCodes.MSP2_INAV_EZ_TUNE:
EZ_TUNE.enabled = data.getUint8(0);
EZ_TUNE.filterHz = data.getUint16(1, true);
EZ_TUNE.axisRatio = data.getUint8(3);
EZ_TUNE.response = data.getUint8(4);
EZ_TUNE.damping = data.getUint8(5);
EZ_TUNE.stability = data.getUint8(6);
EZ_TUNE.aggressiveness = data.getUint8(7);
EZ_TUNE.rate = data.getUint8(8);
EZ_TUNE.expo = data.getUint8(9);
break;
case MSPCodes.MSP2_INAV_EZ_TUNE_SET:
console.log('EzTune settings saved');
break;
default:
console.log('Unknown code detected: ' + dataHandler.code);
} else {
@ -1772,7 +1943,7 @@ var mspHelper = (function (gui) {
buffer.push(BAUD_RATES.indexOf(serialPort.msp_baudrate));
buffer.push(BAUD_RATES.indexOf(serialPort.sensors_baudrate));
buffer.push(BAUD_RATES.indexOf(serialPort.telemetry_baudrate));
buffer.push(BAUD_RATES.indexOf(serialPort.blackbox_baudrate));
buffer.push(BAUD_RATES.indexOf(serialPort.peripherals_baudrate));
}
break;
@ -2062,8 +2233,8 @@ var mspHelper = (function (gui) {
case MSPCodes.MSP2_INAV_SET_MIXER:
buffer.push(MIXER_CONFIG.yawMotorDirection);
buffer.push(lowByte(MIXER_CONFIG.yawJumpPreventionLimit));
buffer.push(highByte(MIXER_CONFIG.yawJumpPreventionLimit));
buffer.push(MIXER_CONFIG.yawJumpPreventionLimit);
buffer.push(MIXER_CONFIG.motorStopOnLow);
buffer.push(MIXER_CONFIG.platformType);
buffer.push(MIXER_CONFIG.hasFlaps);
buffer.push(lowByte(MIXER_CONFIG.appliedMixerPreset));
@ -2092,6 +2263,31 @@ var mspHelper = (function (gui) {
buffer.push(BRAKING_CONFIG.bankAngle);
break;
case MSPCodes.MSP2_INAV_SET_RATE_DYNAMICS:
buffer.push(RATE_DYNAMICS.sensitivityCenter);
buffer.push(RATE_DYNAMICS.sensitivityEnd);
buffer.push(RATE_DYNAMICS.correctionCenter);
buffer.push(RATE_DYNAMICS.correctionEnd);
buffer.push(RATE_DYNAMICS.weightCenter);
buffer.push(RATE_DYNAMICS.weightEnd);
break;
case MSPCodes.MSP2_INAV_EZ_TUNE_SET:
buffer.push(EZ_TUNE.enabled);
buffer.push(lowByte(EZ_TUNE.filterHz));
buffer.push(highByte(EZ_TUNE.filterHz));
buffer.push(EZ_TUNE.axisRatio);
buffer.push(EZ_TUNE.response);
buffer.push(EZ_TUNE.damping);
buffer.push(EZ_TUNE.stability);
buffer.push(EZ_TUNE.aggressiveness);
buffer.push(EZ_TUNE.rate);
buffer.push(EZ_TUNE.expo);
console.log(buffer);
break;
default:
return false;
}
@ -2599,11 +2795,12 @@ var mspHelper = (function (gui) {
buffer.push(ledIndex);
var mask = 0;
var extra = 0;
/*
ledDirectionLetters: ['n', 'e', 's', 'w', 'u', 'd'], // in LSB bit order
ledFunctionLetters: ['i', 'w', 'f', 'a', 't', 'r', 'c', 'g', 's', 'b', 'l'], // in LSB bit order
ledBaseFunctionLetters: ['c', 'f', 'a', 'l', 's', 'g', 'r', 'h'], // in LSB bit
ledOverlayLetters: ['t', 'o', 'b', 'n', 'i', 'w'], // in LSB bit
ledOverlayLetters: ['t', 'o', 'b', 'n', 'i', 'w', 'e'], // in LSB bit
*/
mask |= (led.y << 0);
@ -2621,29 +2818,32 @@ var mspHelper = (function (gui) {
bitIndex = MSP.ledOverlayLetters.indexOf(led.functions[overlayLetterIndex]);
if (bitIndex >= 0) {
mask |= bit_set(mask, bitIndex + 12);
mask |= bit_set(mask, bitIndex + 16);
}
}
mask |= (led.color << 18);
mask |= (led.color << 24);
for (directionLetterIndex = 0; directionLetterIndex < led.directions.length; directionLetterIndex++) {
bitIndex = MSP.ledDirectionLetters.indexOf(led.directions[directionLetterIndex]);
if (bitIndex >= 0) {
mask |= bit_set(mask, bitIndex + 22);
if(bitIndex < 4) {
mask |= bit_set(mask, bitIndex + 28);
} else {
extra |= bit_set(extra, bitIndex - 4);
}
}
}
}
mask |= (0 << 28); // parameters
extra |= (0 << 2); // parameters
buffer.push(specificByte(mask, 0));
buffer.push(specificByte(mask, 1));
buffer.push(specificByte(mask, 2));
buffer.push(specificByte(mask, 3));
buffer.push(specificByte(extra, 0));
// prepare for next iteration
ledIndex++;
@ -2651,7 +2851,7 @@ var mspHelper = (function (gui) {
nextFunction = onCompleteCallback;
}
MSP.send_message(MSPCodes.MSP_SET_LED_STRIP_CONFIG, buffer, false, nextFunction);
MSP.send_message(MSPCodes.MSP2_INAV_SET_LED_STRIP_CONFIG_EX, buffer, false, nextFunction);
}
};
@ -2749,6 +2949,47 @@ var mspHelper = (function (gui) {
MSP.send_message(MSPCodes.MSPV2_INAV_OUTPUT_MAPPING, false, false, callback);
};
self.loadOutputMappingExt = function (callback) {
MSP.send_message(MSPCodes.MSPV2_INAV_OUTPUT_MAPPING_EXT, false, false, callback);
};
self.loadTimerOutputModes = function(callback) {
MSP.send_message(MSPCodes.MSP2_INAV_TIMER_OUTPUT_MODE, false, false, callback);
}
self.sendTimerOutputModes = function(onCompleteCallback) {
var nextFunction = send_next_output_mode;
var idIndex = 0;
var overrideIds = OUTPUT_MAPPING.getUsedTimerIds();
if (overrideIds.length == 0) {
onCompleteCallback();
} else {
send_next_output_mode();
}
function send_next_output_mode() {
var timerId = overrideIds[idIndex];
var outputMode = OUTPUT_MAPPING.getTimerOverride(timerId);
var buffer = [];
buffer.push(timerId);
buffer.push(outputMode);
// prepare for next iteration
idIndex++;
if (idIndex == overrideIds.length) {
nextFunction = onCompleteCallback;
}
MSP.send_message(MSPCodes.MSP2_INAV_SET_TIMER_OUTPUT_MODE, buffer, false, nextFunction);
}
}
self.loadBatteryConfig = function (callback) {
MSP.send_message(MSPCodes.MSPV2_BATTERY_CONFIG, false, false, callback);
};
@ -2932,7 +3173,7 @@ var mspHelper = (function (gui) {
if (waypointId < MISSION_PLANNER.getCountBusyPoints()) {
MSP.send_message(MSPCodes.MSP_WP, [waypointId], false, loadWaypoint);
} else {
GUI.log('Receive time: ' + (new Date().getTime() - startTime) + 'ms');
GUI.log(chrome.i18n.getMessage('ReceiveTime') + (new Date().getTime() - startTime) + 'ms');
MSP.send_message(MSPCodes.MSP_WP, [waypointId], false, callback);
}
};
@ -2954,7 +3195,7 @@ var mspHelper = (function (gui) {
};
function endMission() {
GUI.log('Send time: ' + (new Date().getTime() - startTime) + 'ms');
GUI.log(chrome.i18n.getMessage('SendTime') + (new Date().getTime() - startTime) + 'ms');
MSP.send_message(MSPCodes.MSP_WP_GETINFO, false, false, callback);
}
};
@ -3103,6 +3344,12 @@ var mspHelper = (function (gui) {
self.encodeSetting = function (name, value) {
return this._getSetting(name).then(function (setting) {
if (!setting) {
console.log("Setting invalid: " + name);
return null;
}
if (setting.table && !Number.isInteger(value)) {
var found = false;
for (var ii = 0; ii < setting.table.values.length; ii++) {
@ -3150,7 +3397,11 @@ 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);
}
});
};
@ -3190,6 +3441,15 @@ var mspHelper = (function (gui) {
MSP.send_message(MSPCodes.MSP_MOTOR, false, false, callback);
};
self.getTarget = function(callback) {
MSP.send_message(MSPCodes.MSP_FC_VERSION, false, false, function(resp){
var target = resp.data.readString();
if (callback) {
callback(target);
}
});
}
self.getCraftName = function (callback) {
MSP.send_message(MSPCodes.MSP_NAME, false, false, function (resp) {
var name = resp.data.readString();
@ -3232,6 +3492,22 @@ var mspHelper = (function (gui) {
MSP.send_message(MSPCodes.MSP2_INAV_SET_MC_BRAKING, mspHelper.crunch(MSPCodes.MSP2_INAV_SET_MC_BRAKING), false, callback);
};
self.loadRateDynamics = function (callback) {
MSP.send_message(MSPCodes.MSP2_INAV_RATE_DYNAMICS, false, false, callback);
}
self.saveRateDynamics = function (callback) {
MSP.send_message(MSPCodes.MSP2_INAV_SET_RATE_DYNAMICS, mspHelper.crunch(MSPCodes.MSP2_INAV_SET_RATE_DYNAMICS), false, callback);
}
self.loadEzTune = function (callback) {
MSP.send_message(MSPCodes.MSP2_INAV_EZ_TUNE, false, false, callback);
}
self.saveEzTune = function (callback) {
MSP.send_message(MSPCodes.MSP2_INAV_EZ_TUNE_SET, mspHelper.crunch(MSPCodes.MSP2_INAV_EZ_TUNE_SET), false, callback);
}
self.loadParameterGroups = function (callback) {
MSP.send_message(MSPCodes.MSP2_COMMON_PG_LIST, false, false, function (resp) {
var groups = [];

View file

@ -3,22 +3,63 @@
let OutputMappingCollection = function () {
let self = {},
data = [];
data = [],
timerOverrides = {};
const TIM_USE_ANY = 0;
const TIM_USE_PPM = 0;
const TIM_USE_PWM = 1;
const TIM_USE_MC_MOTOR = 2; // Multicopter motor output
const TIM_USE_MC_SERVO = 3; // Multicopter servo output (i.e. TRI)
const TIM_USE_MC_CHNFW = 4; // Deprecated and not used after removal of CHANNEL_FORWARDING feature
const TIM_USE_FW_MOTOR = 5;
const TIM_USE_FW_SERVO = 6;
const TIM_USE_MOTOR = 2; // Motor output
const TIM_USE_SERVO = 3; // Servo output (i.e. TRI)
//const TIM_USE_MC_CHNFW = 4; // Deprecated and not used after removal of CHANNEL_FORWARDING feature
//const TIM_USE_FW_MOTOR = 5;
//const TIM_USE_FW_SERVO = 6;
const TIM_USE_LED = 24;
const TIM_USE_BEEPER = 25;
const OUTPUT_TYPE_MOTOR = 0;
const OUTPUT_TYPE_SERVO = 1;
self.TIMER_OUTPUT_MODE_AUTO = 0;
self.TIMER_OUTPUT_MODE_MOTORS = 1;
self.TIMER_OUTPUT_MODE_SERVOS = 2;
self.flushTimerOverrides = function() {
timerOverrides = {};
}
self.setTimerOverride = function (timer, outputMode) {
timerOverrides[timer] = outputMode;
}
self.getTimerOverride = function (timer) {
return timerOverrides[timer];
}
self.getTimerColor = function (timer) {
let timerIndex = OUTPUT_MAPPING.getUsedTimerIds().indexOf(String(timer));
return GUI.colorTable[timerIndex % GUI.colorTable.length];
}
self.getOutputTimerColor = function (output) {
let timerId = OUTPUT_MAPPING.getTimerId(output);
return self.getTimerColor(timerId);
}
self.getUsedTimerIds = function (timer) {
let used = {};
let outputCount = self.getOutputCount();
for (let i = 0; i < outputCount; ++i) {
let timerId = self.getTimerId(i);
used[timerId] = 1;
}
return Object.keys(used).sort((a, b) => a - b);
}
function getTimerMap(isMR, motors, servos) {
let timerMap = [],
motorsToGo = motors,
@ -27,24 +68,13 @@ let OutputMappingCollection = function () {
for (let i = 0; i < data.length; i++) {
timerMap[i] = null;
if (isMR) {
if (servosToGo > 0 && bit_check(data[i], TIM_USE_MC_SERVO)) {
if (servosToGo > 0 && bit_check(data[i]['usageFlags'], TIM_USE_SERVO)) {
servosToGo--;
timerMap[i] = OUTPUT_TYPE_SERVO;
} else if (motorsToGo > 0 && bit_check(data[i], TIM_USE_MC_MOTOR)) {
} else if (motorsToGo > 0 && bit_check(data[i]['usageFlags'], TIM_USE_MOTOR)) {
motorsToGo--;
timerMap[i] = OUTPUT_TYPE_MOTOR;
}
} else {
if (servosToGo > 0 && bit_check(data[i], TIM_USE_FW_SERVO)) {
servosToGo--;
timerMap[i] = OUTPUT_TYPE_SERVO;
} else if (motorsToGo > 0 && bit_check(data[i], TIM_USE_FW_MOTOR)) {
motorsToGo--;
timerMap[i] = OUTPUT_TYPE_MOTOR;
}
}
}
return timerMap;
@ -70,7 +100,6 @@ let OutputMappingCollection = function () {
outputMap[i] = "Servo " + servos[currentServoIndex];
currentServoIndex++;
}
}
return outputMap;
@ -89,10 +118,8 @@ let OutputMappingCollection = function () {
for (let i = 0; i < data.length; i++) {
if (
bit_check(data[i], TIM_USE_MC_MOTOR) ||
bit_check(data[i], TIM_USE_MC_SERVO) ||
bit_check(data[i], TIM_USE_FW_MOTOR) ||
bit_check(data[i], TIM_USE_FW_SERVO)
bit_check(data[i]['usageFlags'], TIM_USE_MOTOR) ||
bit_check(data[i]['usageFlags'], TIM_USE_SERVO)
) {
retVal++;
};
@ -104,10 +131,8 @@ let OutputMappingCollection = function () {
function getFirstOutputOffset() {
for (let i = 0; i < data.length; i++) {
if (
bit_check(data[i], TIM_USE_MC_MOTOR) ||
bit_check(data[i], TIM_USE_MC_SERVO) ||
bit_check(data[i], TIM_USE_FW_MOTOR) ||
bit_check(data[i], TIM_USE_FW_SERVO)
bit_check(data[i]['usageFlags'], TIM_USE_MOTOR) ||
bit_check(data[i]['usageFlags'], TIM_USE_SERVO)
) {
return i;
}
@ -115,6 +140,10 @@ let OutputMappingCollection = function () {
return 0;
}
function getTimerId(outputIndex) {
return data[outputIndex]['timerId'];
}
function getOutput(servoIndex, bit) {
let offset = getFirstOutputOffset();
@ -122,7 +151,7 @@ let OutputMappingCollection = function () {
let lastFound = 0;
for (let i = offset; i < data.length; i++) {
if (bit_check(data[i], bit)) {
if (bit_check(data[i]['usageFlags'], bit)) {
if (lastFound == servoIndex) {
return i - offset + 1;
} else {
@ -134,12 +163,16 @@ let OutputMappingCollection = function () {
return null;
}
self.getTimerId = function(outputIndex) {
return getTimerId(outputIndex)
}
self.getFwServoOutput = function (servoIndex) {
return getOutput(servoIndex, TIM_USE_FW_SERVO);
return getOutput(servoIndex, TIM_USE_SERVO);
};
self.getMrServoOutput = function (index) {
return getOutput(index, TIM_USE_MC_SERVO);
return getOutput(index, TIM_USE_SERVO);
};
return self;

View file

@ -23,10 +23,15 @@ function adjustBoxNameIfPeripheralWithModeID(modeId, defaultName) {
case 41: // BOXCAMERA3
return "CAMERA CHANGE MODE";
default:
return defaultName;
break;
}
}
if (modeId === 11) {
if (FC.isAirplane()) {
return "NAV LOITER";
}
}
return defaultName;
}

View file

@ -1,7 +1,10 @@
'use strict';
var usbDevices = {
STM32DFU: {'vendorId': 1155, 'productId': 57105}
filters: [
{'vendorId': 1155, 'productId': 57105},
{'vendorId': 11836, 'productId': 57105}
]
};
var PortHandler = new function () {
@ -19,7 +22,16 @@ PortHandler.initialize = function () {
PortHandler.check = function () {
var self = this;
ConnectionSerial.getDevices(function(current_ports) {
ConnectionSerial.getDevices(function(all_ports) {
// filter out ports that are not serial
let current_ports = [];
for (var i = 0; i < all_ports.length; i++) {
if (all_ports[i].indexOf(':') === -1) {
current_ports.push(all_ports[i]);
}
}
// port got removed or initial_ports wasn't initialized yet
if (self.array_difference(self.initial_ports, current_ports).length > 0 || !self.initial_ports) {
var removed_ports = self.array_difference(self.initial_ports, current_ports);
@ -66,7 +78,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) {
@ -152,7 +164,7 @@ PortHandler.check = function () {
};
PortHandler.check_usb_devices = function (callback) {
chrome.usb.getDevices(usbDevices.STM32DFU, function (result) {
chrome.usb.getDevices(usbDevices, function (result) {
if (result.length) {
if (!$("div#port-picker #port [value='DFU']").length) {
$('div#port-picker #port').append($('<option/>', {value: "DFU", text: "DFU", data: {isDFU: true}}));
@ -166,7 +178,7 @@ PortHandler.check_usb_devices = function (callback) {
self.dfu_available = false;
}
if(callback) callback(self.dfu_available);
if (callback) callback(self.dfu_available);
});
};
@ -181,6 +193,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) {

View file

@ -81,7 +81,7 @@ STM32_protocol.prototype.connect = function (port, baud, hex, options, callback)
self.initialize();
} else {
GUI.log('<span style="color: red">Failed</span> to open serial port');
GUI.log(chrome.i18n.getMessage('failedToOpenSerialPort'));
}
});
} else {
@ -108,14 +108,14 @@ STM32_protocol.prototype.connect = function (port, baud, hex, options, callback)
retries++;
if (retries > maxRetries) {
clearInterval(interval);
GUI.log('<span style="color: red">Failed</span> to flash ' + port);
GUI.log(chrome.i18n.getMessage('failedToFlash') + port);
}
}
// Check for DFU devices
PortHandler.check_usb_devices(function(dfu_available) {
if (dfu_available) {
clearInterval(interval);
STM32DFU.connect(usbDevices.STM32DFU, hex, options);
STM32DFU.connect(usbDevices, hex, options);
return;
}
// Check for the serial port
@ -145,7 +145,7 @@ STM32_protocol.prototype.connect = function (port, baud, hex, options, callback)
});
});
} else {
GUI.log('<span style="color: red">Failed</span> to open serial port');
GUI.log(chrome.i18n.getMessage('failedToOpenSerialPort'));
}
});
}

View file

@ -336,6 +336,8 @@ STM32DFU_protocol.prototype.getChipInfo = function (_interface, callback) {
// H750 SPRacing H7 EXST: "@External Flash /0x90000000/998*128Kg,1*128Kg,4*128Kg,21*128Ka"
// H750 SPRacing H7 EXST: "@External Flash /0x90000000/1001*128Kg,3*128Kg,20*128Ka" - Early BL firmware with incorrect string, treat as above.
// AT32F435: "@Internal Flash /0x08000000/512*002Kg,@Option byte /0x1FFFC000/01*512 g"
// H750 Partitions: Flash, Config, Firmware, 1x BB Management block + x BB Replacement blocks)
if (str == "@External Flash /0x90000000/1001*128Kg,3*128Kg,20*128Ka") {
str = "@External Flash /0x90000000/998*128Kg,1*128Kg,4*128Kg,21*128Ka";
@ -617,6 +619,11 @@ STM32DFU_protocol.prototype.upload_procedure = function (step) {
});
break;
case 1:
// workaroud for AT32
if (typeof self.chipInfo.option_bytes === "undefined" && typeof self.chipInfo.option_byte !== "undefined") {
self.chipInfo.option_bytes = self.chipInfo.option_byte;
}
if (typeof self.chipInfo.option_bytes === "undefined") {
console.log('Failed to detect option bytes');
self.cleanup();

View file

@ -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();
@ -242,6 +257,7 @@ function onValidFirmware()
$('#tabs ul.mode-connected .tab_setup a').click();
updateEzTuneTabVisibility(true);
updateFirmwareVersion();
});
});
@ -464,7 +480,6 @@ function sensor_status_ex(hw_status)
sensor_status_update_icon('.sonar', '.sonaricon', hw_status.rangeHwStatus);
sensor_status_update_icon('.airspeed', '.airspeedicon', hw_status.speedHwStatus);
sensor_status_update_icon('.opflow', '.opflowicon', hw_status.flowHwStatus);
sensor_status_update_icon('.imu2', '.imu2icon', hw_status.imu2HwStatus);
}
function sensor_status_update_icon(sensId, sensIconId, status)
@ -499,8 +514,7 @@ function sensor_status_hash(hw_status)
hw_status.gpsHwStatus +
hw_status.rangeHwStatus +
hw_status.speedHwStatus +
hw_status.flowHwStatus +
hw_status.imu2HwStatus;
hw_status.flowHwStatus;
}
/**
@ -523,7 +537,6 @@ function sensor_status(sensors_detected) {
SENSOR_STATUS.rangeHwStatus = have_sensor(sensors_detected, 'sonar') ? 1 : 0;
SENSOR_STATUS.speedHwStatus = have_sensor(sensors_detected, 'airspeed') ? 1 : 0;
SENSOR_STATUS.flowHwStatus = have_sensor(sensors_detected, 'opflow') ? 1 : 0;
SENSOR_STATUS.imu2HwStatus = have_sensor(sensors_detected, 'imu2') ? 1 : 0;
sensor_status_ex(SENSOR_STATUS);
}

View file

@ -5,6 +5,7 @@ let ServoMixerRuleCollection = function () {
let self = {},
data = [],
inactiveData = [],
maxServoCount = 16;
self.setServoCount = function (value) {
@ -20,7 +21,11 @@ let ServoMixerRuleCollection = function () {
}
self.put = function (element) {
if (data.length < self.getServoRulesCount()) {
data.push(element);
}else{
inactiveData.push(element); //store the data for mixer_profile 2
}
};
self.get = function () {
@ -34,18 +39,24 @@ let ServoMixerRuleCollection = function () {
self.flush = function () {
data = [];
inactiveData = [];
};
self.cleanup = function () {
var tmpData = [];
var tmpInactiveData = [];
data.forEach(function (element) {
if (element.isUsed()) {
tmpData.push(element);
}
});
inactiveData.forEach(function (element) {
if (element.isUsed()) {
tmpInactiveData.push(element);
}
});
data = tmpData;
inactiveData = tmpInactiveData;
};
self.inflate = function () {
@ -69,6 +80,15 @@ let ServoMixerRuleCollection = function () {
}
}
}
for (let ruleIndex in inactiveData) {
if (inactiveData.hasOwnProperty(ruleIndex)) {
let rule = inactiveData[ruleIndex];
if (rule.getTarget() == servoId && rule.isUsed()) {
return true;
}
}
}
return false;
};
@ -106,12 +126,17 @@ let ServoMixerRuleCollection = function () {
out.push(rule.getTarget());
}
}
for (let ruleIndex in inactiveData) {
if (inactiveData.hasOwnProperty(ruleIndex)) {
let rule = inactiveData[ruleIndex];
out.push(rule.getTarget());
}
}
let unique = [...new Set(out)];
return unique.sort(function(a, b) {
return a-b;
});
let minIndex = Math.min(...out);
let maxIndex = Math.max(...out);
return Array.from({ length: maxIndex - minIndex + 1 }, (_, index) => minIndex + index);
}
self.getNextUnusedIndex = function() {

View file

@ -3,6 +3,24 @@
var Settings = (function () {
let self = {};
self.fillSelectOption = function(s, ii) {
var name = (s.setting.table ? s.setting.table.values[ii] : null);
if (name) {
var localizedName = chrome.i18n.getMessage(name);
if (localizedName) {
name = localizedName;
}
} else {
// Fallback to the number itself
name = ii;
}
var option = $('<option/>').attr('value', ii).text(name);
if (ii == s.value) {
option.prop('selected', true);
}
return option;
}
self.configureInputs = function() {
var inputs = [];
$('[data-setting!=""][data-setting]').each(function() {
@ -45,130 +63,49 @@ var Settings = (function () {
input.prop('checked', s.value > 0);
} else {
input.empty();
for (var ii = s.setting.min; ii <= s.setting.max; ii++) {
var name = (s.setting.table ? s.setting.table.values[ii] : null);
if (name) {
var localizedName = chrome.i18n.getMessage(name);
if (localizedName) {
name = localizedName;
let option = null;
if (input.data('setting-invert-select') === true) {
for (var ii = s.setting.max; ii >= s.setting.min; ii--) {
option = null;
option = self.fillSelectOption(s, ii);
option.appendTo(input);
}
} else {
// Fallback to the number itself
name = ii;
}
var option = $('<option/>').attr('value', ii).text(name);
if (ii == s.value) {
option.prop('selected', true);
}
for (var ii = s.setting.min; ii <= s.setting.max; ii++) {
option = null;
option = self.fillSelectOption(s, ii);
option.appendTo(input);
}
}
}
} else if (s.setting.type == 'string') {
input.val(s.value);
input.attr('maxlength', s.setting.max);
} else if (input.data('presentation') == 'range') {
let scaledMax;
let scaledMin;
let scalingThreshold;
if (input.data('normal-max')) {
scaledMax = s.setting.max * 2;
scalingThreshold = Math.round(scaledMax * 0.8);
scaledMin = s.setting.min *2;
} else {
scaledMax = s.setting.max;
scaledMin = s.setting.min;
scalingThreshold = scaledMax;
}
let $range = $('<input type="range" min="' + scaledMin + '" max="' + scaledMax + '" value="' + s.value + '"/>');
if (input.data('step')) {
$range.attr('step', input.data('step'));
}
$range.css({
'display': 'block',
'flex-grow': 100,
'margin-left': '1em',
'margin-right': '1em',
});
input.attr('min', s.setting.min);
input.attr('max', s.setting.max);
input.val(parseInt(s.value));
input.css({
'width': 'auto',
'min-width': '75px',
});
input.parent().css({
'display': 'flex',
'width': '100%'
});
$range.insertAfter(input);
input.parent().find('.helpicon').css({
'top': '5px',
'left': '-10px'
});
/*
* Update slider to input
*/
$range.on('input', function() {
let val = $(this).val();
let normalMax = parseInt(input.data('normal-max'));
if (normalMax) {
if (val <= scalingThreshold) {
val = scaleRangeInt(val, scaledMin, scalingThreshold, s.setting.min, normalMax);
} else {
val = scaleRangeInt(val, scalingThreshold + 1, scaledMax, normalMax + 1, s.setting.max);
}
}
input.val(val);
});
input.on('change', function() {
let val = $(this).val();
let newVal;
let normalMax = parseInt(input.data('normal-max'));
if (normalMax) {
if (val <= normalMax) {
newVal = scaleRangeInt(val, s.setting.min, normalMax, scaledMin, scalingThreshold);
} else {
newVal = scaleRangeInt(val, normalMax + 1, s.setting.max, scalingThreshold + 1, scaledMax);
}
} else {
newVal = val;
}
$range.val(newVal);
});
input.trigger('change');
GUI.sliderize(input, s.value, s.setting.min, s.setting.max);
} else if (s.setting.type == 'float') {
input.attr('type', 'number');
let dataStep = input.data("step");
if (dataStep !== undefined) {
input.attr('step', dataStep);
} else {
input.attr('step', "0.01");
if (typeof dataStep === 'undefined') {
dataStep = self.countDecimals(s.value);
dataStep = 1 / Math.pow(10, dataStep);
input.data("step", dataStep);
}
input.attr('step', dataStep);
input.attr('min', s.setting.min);
input.attr('max', s.setting.max);
input.val(s.value.toFixed(2));
input.val(s.value.toFixed(self.countDecimals(dataStep)));
} else {
var multiplier = parseFloat(input.data('setting-multiplier') || 1);
input.data("step", 1);
input.val((s.value / multiplier).toFixed(Math.log10(multiplier)));
input.attr('type', 'number');
if (typeof s.setting.min !== 'undefined' && s.setting.min !== null) {
@ -233,18 +170,25 @@ var Settings = (function () {
const oldValue = element.val();
//display names for the units
const unitDisplayDames = {
// Display names for the units
const unitDisplayNames = {
// Misc
'us' : "uS",
'cw' : 'cW',
'percent' : '%',
'cmss' : 'cm/s/s',
// Time
'us' : "uS",
'msec' : 'ms',
'msec-nc' : 'ms', // Milliseconds, but not converted.
'dsec' : 'ds',
'sec' : 's',
'mins' : 'm',
'hours' : 'h',
'tzmins' : 'm',
'tzhours' : 'hh:mm',
// Angles
'centideg' : 'centi&deg;',
'centideg-deg' : 'centi&deg;', // Centidegrees, but always converted to degrees by default
'deg' : '&deg;',
'decideg' : 'deci&deg;',
'decideg-lrg' : 'deci&deg;', // Decidegrees, but always converted to degrees by default
@ -274,6 +218,53 @@ var Settings = (function () {
'nm' : 'NM'
}
// Hover full descriptions for the units
const unitExpandedNames = {
// Misc
'cw' : 'CentiWatts',
'percent' : 'Percent',
'cmss' : 'Centimetres per second, per second',
// Time
'us' : "Microseconds",
'msec' : 'Milliseconds',
'msec-nc' : 'Milliseconds',
'dsec' : 'Deciseconds',
'sec' : 'Seconds',
'mins' : 'Minutes',
'hours' : 'Hours',
'tzmins' : 'Minutes',
'tzhours' : 'Hours:Minutes',
// Angles
'centideg' : 'CentiDegrees',
'centideg-deg' : 'CentiDegrees',
'deg' : 'Degrees',
'decideg' : 'DeciDegrees',
'decideg-lrg' : 'DeciDegrees',
// Rotational speed
'degps' : 'Degrees per second',
'decadegps' : 'DecaDegrees per second',
// Temperature
'decidegc' : 'DeciDegrees Celsius',
'degc' : 'Degrees Celsius',
'degf' : 'Degrees Fahrenheit',
// Speed
'cms' : 'Centimetres per second',
'v-cms' : 'Centimetres per second',
'ms' : 'Metres per second',
'kmh' : 'Kilometres per hour',
'mph' : 'Miles per hour',
'hftmin' : 'Hundred feet per minute',
'fts' : 'Feet per second',
'kt' : 'Knots',
// Distance
'cm' : 'Centimetres',
'm' : 'Metres',
'km' : 'Kilometres',
'm-lrg' : 'Metres',
'ft' : 'Feet',
'mi' : 'Miles',
'nm' : 'Nautical Miles'
}
// Ensure we can do conversions
if (!inputUnit || !oldValue || !element) {
@ -309,12 +300,27 @@ var Settings = (function () {
'hftmin' : 50.8,
'fts' : 30.48
},
'msec-nc' : {
'msec-nc' : 1
},
'msec' : {
'sec' : 1000
},
'dsec' : {
'sec' : 10
},
'mins' : {
'hours' : 60
},
'tzmins' : {
'tzhours' : 'TZHOURS'
},
'centideg' : {
'deg' : 0.1
},
'centideg-deg' : {
'deg' : 0.1
},
'decideg' : {
'deg' : 10
},
@ -340,7 +346,11 @@ var Settings = (function () {
'v-cms' : 'fts',
'msec' : 'sec',
'dsec' : 'sec',
'mins' : 'hours',
'tzmins' : 'tzhours',
'decadegps' : 'degps',
'centideg' : 'deg',
'centideg-deg' : 'deg',
'decideg' : 'deg',
'decideg-lrg' : 'deg',
'decidegc' : 'degf',
@ -353,7 +363,11 @@ var Settings = (function () {
'v-cms' : 'ms',
'msec' : 'sec',
'dsec' : 'sec',
'mins' : 'hours',
'tzmins' : 'tzhours',
'decadegps' : 'degps',
'centideg' : 'deg',
'centideg-deg' : 'deg',
'decideg' : 'deg',
'decideg-lrg' : 'deg',
'decidegc' : 'degc',
@ -365,10 +379,14 @@ var Settings = (function () {
'cms' : 'mph',
'v-cms' : 'ms',
'decadegps' : 'degps',
'centideg' : 'deg',
'centideg-deg' : 'deg',
'decideg' : 'deg',
'decideg-lrg' : 'deg',
'msec' : 'sec',
'dsec' : 'sec',
'mins' : 'hours',
'tzmins' : 'tzhours',
'decidegc' : 'degc',
},
3:{ //UK
@ -377,11 +395,15 @@ var Settings = (function () {
'm-lrg' : 'mi',
'cms' : 'mph',
'v-cms' : 'fts',
'decadegps' : 'degpd',
'decadegps' : 'degps',
'centideg' : 'deg',
'centideg-deg' : 'deg',
'decideg' : 'deg',
'decideg-lrg' : 'deg',
'msec' : 'sec',
'dsec' : 'sec',
'mins' : 'hours',
'tzmins' : 'tzhours',
'decidegc' : 'degc',
},
4: { //General aviation
@ -391,15 +413,22 @@ var Settings = (function () {
'cms': 'kt',
'v-cms' : 'hftmin',
'decadegps' : 'degps',
'centideg' : 'deg',
'centideg-deg' : 'deg',
'decideg' : 'deg',
'decideg-lrg' : 'deg',
'msec' : 'sec',
'dsec' : 'sec',
'mins' : 'hours',
'tzmins' : 'tzhours',
'decidegc' : 'degc',
},
default: { //show base units
'decadegps' : 'degps',
'decideg-lrg' : 'deg',
'centideg' : 'deg',
'centideg-deg' : 'deg',
'tzmins' : 'tzhours',
}
};
@ -423,43 +452,51 @@ var Settings = (function () {
const multiplier = multiObj.multiplier;
const unitName = multiObj.unitName;
let decimalPlaces = 0;
// Update the step, min, and max; as we have the multiplier here.
if (element.attr('type') == 'number') {
let step = element.attr('step') || 1;
let decimalPlaces = 0;
let step = parseFloat(element.attr('step')) || 1;
step = step / multiplier;
if (step < 1) {
decimalPlaces = step.toString().length - step.toString().indexOf(".") - 1;
if (parseInt(step.toString().slice(-1)) > 1 ) {
decimalPlaces--;
if (multiplier !== 1) {
decimalPlaces = Math.min(Math.ceil(multiplier / 100), 3);
// Add extra decimal place for non-integer conversions.
if (multiplier % 1 != 0 && decimalPlaces < 3) {
decimalPlaces++;
}
step = 1 / Math.pow(10, decimalPlaces);
}
element.attr('step', step.toFixed(decimalPlaces));
if (multiplier != 'FAHREN') {
element.attr('min', (element.attr('min') / multiplier).toFixed(decimalPlaces));
element.attr('max', (element.attr('max') / multiplier).toFixed(decimalPlaces));
if (multiplier !== 'FAHREN' && multiplier !== 'TZHOURS' && multiplier !== 1) {
element.data('default-min', element.attr('min'));
element.data('default-max', element.attr('max'));
element.attr('min', (parseFloat(element.attr('min')) / multiplier).toFixed(decimalPlaces));
element.attr('max', (parseFloat(element.attr('max')) / multiplier).toFixed(decimalPlaces));
}
}
// Update the input with a new formatted unit
let newValue = "";
if (multiplier == 'FAHREN') {
element.attr('min', toFahrenheit(element.attr('min')).toFixed(2));
element.attr('max', toFahrenheit(element.attr('max')).toFixed(2));
newValue = toFahrenheit(oldValue).toFixed(2);
if (multiplier === 'FAHREN') {
element.attr('min', toFahrenheit(element.attr('min')).toFixed(decimalPlaces));
element.attr('max', toFahrenheit(element.attr('max')).toFixed(decimalPlaces));
newValue = toFahrenheit(oldValue).toFixed(decimalPlaces);
} else if (multiplier === 'TZHOURS') {
element.attr('type', 'text');
element.removeAttr('step');
element.attr('pattern', '([0-9]{2}|[-,0-9]{3}):([0-9]{2})');
let hours = Math.floor(oldValue/60);
let mins = oldValue - (hours*60);
newValue = ((hours < 0) ? padZeros(hours, 3) : padZeros(hours, 2)) + ':' + padZeros(mins, 2);
} else {
const convertedValue = Number((oldValue / multiplier).toFixed(2));
newValue = Number.isInteger(convertedValue) ? Math.round(convertedValue) : convertedValue;
newValue = Number((oldValue / multiplier)).toFixed(decimalPlaces);
}
element.val(newValue);
element.data('setting-multiplier', multiplier);
// Now wrap the input in a display that shows the unit
element.wrap(`<div data-unit="${unitDisplayDames[unitName]}" class="unit_wrapper unit"></div>`);
element.wrap(`<div data-unit="${unitDisplayNames[unitName]}" title="${unitExpandedNames[unitName]}" class="unit_wrapper unit"></div>`);
function toFahrenheit(decidegC) {
return (decidegC / 10) * 1.8 + 32;
@ -487,14 +524,57 @@ var Settings = (function () {
var multiplier = input.data('setting-multiplier') || 1;
if (multiplier == 'FAHREN') {
value = Math.round(((parseFloat(input.val())-32) / 1.8) * 10);
} else if (multiplier === 'TZHOURS') {
let inputTZ = input.val().split(':');
value = (parseInt(inputTZ[0]) * 60) + parseInt(inputTZ[1]);
if (value > parseInt(input.attr('max'))) {
value = parseInt(input.attr('max'));
}
if (value < parseInt(input.attr('min'))) {
value = parseInt(input.attr('min'));
}
} else {
multiplier = parseFloat(multiplier);
let precision = input.data("step") || 1; // data-step is always based on the default firmware units.
precision = self.countDecimals(precision);
if (precision === 0) {
value = Math.round(parseFloat(input.val()) * multiplier);
} else {
value = Math.round((parseFloat(input.val()) * multiplier) * Math.pow(10, precision)) / Math.pow(10, precision);
}
if (value > parseInt(input.data('default-max'))) {
value = parseInt(input.data('default-max'));
}
if (value < parseInt(input.data('default-min'))) {
value = parseInt(input.data('default-min'));
}
}
}
return mspHelper.setSetting(settingName, value);
};
self.countDecimals = function(value) {
let text = value.toString()
// verify if number 0.000005 is represented as "5e-6"
if (text.indexOf('e-') > -1) {
let [base, trail] = text.split('e-');
let deg = parseInt(trail, 10);
return deg;
}
// count decimals for number in representation like "0.123456"
if (Math.floor(value) !== value) {
return value.toString().split(".")[1].length || 0;
}
return 0;
};
self.saveInputs = function() {
var inputs = [];
$('[data-setting!=""][data-setting]').each(function() {
@ -533,7 +613,7 @@ var Settings = (function () {
}
if (typeof dataSettingName !== "undefined" && dataSettingName !== "") {
helpIcon.wrap('<a class="helpiconLink" href="https://github.com/iNavFlight/inav/blob/master/docs/Settings.md#' + dataSettingName + '" target="_blank"></a>');
helpIcon.wrap('<a class="helpiconLink" href="' + globalSettings.docsTreeLocation + 'Settings.md#' + dataSettingName + '" target="_blank"></a>');
}
}

270
js/sitl.js Normal file
View 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 {
if (device.displayName != null) {
var m = device.path.match(/\/dev\/.*/)
if (m)
devices.push(m[0]);
}
}
});
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;
});
},
stop: function() {
if (this.isRunning) {
this.isRunning = false;
this.process.kill();
}
}
};

View file

@ -139,7 +139,7 @@ let Waypoint = function (number, action, lat, lon, alt=0, p1=0, p2=0, p3=0, endM
self.getElevation = async function (globalSettings) {
let elevation = "N/A";
if (globalSettings.mapProviderType == 'bing') {
let elevationEarthModel = $('#elevationEarthModel').prop("checked") ? "sealevel" : "ellipsoid";
let elevationEarthModel = $('#elevationEarthModel').prop("checked") ? "ellipsoid" : "sealevel";
const response = await fetch('http://dev.virtualearth.net/REST/v1/Elevation/List?points='+self.getLatMap()+','+self.getLonMap()+'&heights='+elevationEarthModel+'&key='+globalSettings.mapApiKey);
const myJson = await response.json();

View file

@ -360,7 +360,8 @@ let WaypointCollection = function () {
}
altPoint2measure.push(self.getWaypoint(nStart).getAlt());
namePoint2measure.push(self.getWaypoint(nStart).getLayerNumber()+1);
refPoint2measure.push(self.getWaypoint(nStart).getP3());
let useAbsoluteAlt = (self.getWaypoint(nStart).getP3() & (1 << 0));
refPoint2measure.push(useAbsoluteAlt);
nStart++;
}
else if (self.getWaypoint(nStart).getAction() == MWNP.WPTYPE.JUMP) {

View file

@ -60,6 +60,10 @@ a.disabled {
transition: none;
}
.inputRequiredWarning {
border: 3px solid #d40000 !important;
}
.cf_doc_version_bt a {
padding: 1px 9px 1px 9px;
margin-top: -45px;
@ -322,27 +326,6 @@ input[type="number"]::-webkit-inner-spin-button {
color: #d40000;
}
.imu2icon {
background: url("../images/icons/sensor_imu2_off.png") no-repeat -5px 2px;
background-size: 40px;
height: 30px;
margin-top: 3px;
width: 100%;
padding-top: 40px;
color: #4f4f4f;
text-align: center;
}
.imu2icon.active {
background-image: url("../images/icons/sensor_imu2_on.png");
color: #818181;
}
.imu2icon.error {
background-image: url("../images/icons/sensor_imu2_error.png");
color: #d40000;
}
.magicon {
background: url("../images/icons/sensor_mag_off.png") no-repeat -5px 2px;
background-size: 42px;
@ -906,6 +889,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);
}
@ -1648,7 +1643,7 @@ dialog {
/* fixing padding for all Tabs*/
.tab-setup, .tab-landing, .tab-adjustments, .tab-auxiliary, .tab-cli, .tab-configuration, .tab-failsafe, .tab-onboard_logging,
.tab-firmware_flasher, .tab-gps, .tab-magnetometer, .tab-help, .tab-led-strip, .tab-logging, .tab-modes, .tab-motors, .tab-pid_tuning,
.tab-ports, .tab-receiver, .tab-sensors, .tab-servos, .tab-osd, .tab-calibration {
.tab-ports, .tab-receiver, .tab-sensors, .tab-servos, .tab-osd, .tab-calibration, .tab-ez_tune {
height: 100%;
position: relative;
}
@ -1690,7 +1685,7 @@ dialog {
color: white;
font-size: 10px;
margin-top: 20px;
width: 269px;
width: 410px;
float: right;
margin-right: 10px;
line-height: 12px;
@ -1705,6 +1700,15 @@ dialog {
}
#mixer_profile_change {
color: white;
margin-top: 16px;
width: 130px;
float: left;
margin-right: 10px;
line-height: 12px;
}
#profile_change {
color: white;
margin-top: 16px;
@ -2010,6 +2014,10 @@ select {
padding: 1px;
}
.lc_disabled {
color: #aaa;
}
.ic_osd {
background-image: url("../images/icons/icon_osd.svg");
background-position-y: 4px;
@ -2276,3 +2284,11 @@ ol li {
.controlProfileHighlightActive {
background-color: #d5ebfe !important ;
}
.no-border {
border: none !important;
}
.bold {
font-weight: bold;
}

View file

@ -27,11 +27,11 @@
<div class="headerbar">
<div id="logo">
<div class="logo_text">
CONFIGURATOR
<span i18n="mainLogoText"></span>
<div class="version"></div>
</div>
<div class="logo_text_firmware">
FC FIRMWARE
<span i18n="mainLogoTextFirmware"></span>
<div class="firmware_version"></div>
</div>
</div>
@ -46,15 +46,14 @@
</div>
<div id="portsinput">
<div class="portsinput__row">
<div id="port-override-option"
class="portsinput__top-element portsinput__top-element--port-override">
<label id="port-override-label" for="port-override">Port: </label>
<div id="port-override-option" class="portsinput__top-element portsinput__top-element--port-override">
<label id="port-override-label" for="port-override" i18n="mainPortOverrideLabel"></label>
<input id="port-override" type="text" value="/dev/rfcomm0" />
</div>
<div class="dropdown dropdown-dark portsinput__top-element">
<!--suppress HtmlFormInputWithoutLabel -->
<select class="dropdown-select" id="port" title="Port">
<option value="manual">Manual</option>
<option value="manual" i18n="mainManual"></option>
<!-- port list gets generated here -->
</select>
</div>
@ -86,20 +85,30 @@
</div>
<div class="header-wrapper">
<div id="dataflash_wrapper_global">
<div class="noflash_global" align="center">No dataflash <br>chip found</div>
<div class="noflash_global" align="center" i18n="sensorDataFlashNotFound"></div>
<ul class="dataflash-contents_global">
<li class="dataflash-free_global">
<div class="legend">Dataflash: free space</div>
<div class="legend" i18n="sensorDataFlashFreeSpace"></div>
</li>
</ul>
<div id="mixer_profile_change">
<div class="dropdown dropdown-dark">
<form name="mixer-profile-change" id="mixer-profile-change">
<select class="dropdown-select" id="mixerprofilechange">
<option value="0" i18n="mixerProfile1"></option>
<option value="1" i18n="mixerProfile2"></option>
</select>
</form>
</div>
</div>
<div id="profile_change">
<div class="dropdown dropdown-dark">
<form name="profile-change" id="profile-change">
<!--suppress HtmlFormInputWithoutLabel -->
<select class="dropdown-select" id="profilechange">
<option value="0">Profile 1</option>
<option value="1">Profile 2</option>
<option value="2">Profile 3</option>
<option value="0" i18n="sensorProfile1"></option>
<option value="1" i18n="sensorProfile2"></option>
<option value="2" i18n="sensorProfile3"></option>
</select>
</form>
</div>
@ -109,9 +118,9 @@
<form name="battery-profile-change" id="battery-profile-change">
<!--suppress HtmlFormInputWithoutLabel -->
<select class="dropdown-select" id="batteryprofilechange">
<option value="0">Battery profile 1</option>
<option value="1">Battery profile 2</option>
<option value="2">Battery profile 3</option>
<option value="0" i18n="sensorBatteryProfile1"></option>
<option value="1" i18n="sensorBatteryProfile2"></option>
<option value="2" i18n="sensorBatteryProfile3"></option>
</select>
</form>
</div>
@ -119,32 +128,30 @@
</div>
<div id="sensor-status" class="sensor_state mode-connected">
<ul>
<li class="gyro" title="Gyroscope">
<div class="gyroicon">Gyro</div>
<li class="gyro" i18n_title="sensorStatusGyro">
<div class="gyroicon" i18n="sensorStatusGyroShort"></div>
</li>
<li class="accel" title="Accelerometer">
<div class="accicon">Accel</div>
<li class="accel" i18n_title="sensorStatusAccel">
<div class="accicon" i18n="sensorStatusAccelShort"></div>
</li>
<li class="mag" title="Magnetometer">
<div class="magicon">Mag</div>
<li class="mag" i18n_title="sensorStatusMag">
<div class="magicon" i18n="sensorStatusMagShort"></div>
</li>
<li class="baro" title="Barometer">
<div class="baroicon">Baro</div>
<li class="baro" i18n_title="sensorStatusBaro">
<div class="baroicon" i18n="sensorStatusBaroShort"></div>
</li>
<li class="gps" title="GPS">
<div class="gpsicon">GPS</div>
<li class="gps" i18n_title="sensorStatusGPS">
<div class="gpsicon" i18n="sensorStatusGPSShort"></div>
</li>
<li class="opflow" title="Optical flow">
<div class="opflowicon">Flow</div>
<li class="opflow" i18n_title="sensorOpticalFlow">
<div class="opflowicon" i18n="sensorOpticalFlowShort"></div>
</li>
<li class="sonar" title="Sonar / Range finder">
<div class="sonaricon">Sonar</div>
<li class="sonar" i18n_title="sensorStatusSonar">
<div class="sonaricon" i18n="sensorStatusSonarShort"></div>
</li>
<li class="airspeed" title="Airspeed">
<div class="airspeedicon">Speed</div>
</li>
<li class="imu2" title="IMU2">
<div class="imu2icon">IMU2</div>
<li class="airspeed" i18n_title="sensorAirspeed">
<div class="airspeedicon" i18n="sensorAirspeedShort"></div>
</li>
</ul>
</div>
@ -154,7 +161,7 @@
<div class="battery-status"></div>
</div>
</div>
<div class="battery-legend">Battery voltage</div>
<div class="battery-legend" i18n="sensorBatteryVoltage"></div>
<div class="bottomStatusIcons">
<div class="armedicon cf_tip" data-i18n_title="mainHelpArmed"></div>
<div class="failsafeicon cf_tip" data-i18n_title="mainHelpFailsafe"></div>
@ -166,7 +173,7 @@
<div class="clear-both"></div>
<div id="log">
<div class="logswitch">
<a href="#" id="showlog">Show Log</a>
<a href="#" id="showlog" i18n="mainShowLog"></a>
</div>
<div id="scrollicon"></div>
<div class="wrapper"></div>
@ -189,6 +196,9 @@
<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">
@ -212,6 +222,9 @@
<li class="tab_failsafe">
<a href="#" data-i18n="tabFailsafe" class="tabicon ic_failsafe" title="Failsafe"></a>
</li>
<li class="tab_ez_tune">
<a href="#" data-i18n="tabEzTune" class="tabicon ic_wizzard"></a>
</li>
<li class="tab_pid_tuning">
<a href="#" data-i18n="tabPidTuning" class="tabicon ic_pid" title="PID Tuning"></a>
</li>
@ -260,8 +273,7 @@
<a href="#" data-i18n="tabCLI" class="tabicon ic_cli" title="CLI"></a>
</li>
<!--<li class=""><a href="#" class="tabicon ic_advanced">Advanced (spare icon)</a></li>-->
<!--<li class=""><a href="#" class="tabicon ic_wizzard">Wizzard (spare icon)</a></li>-->
<!-- <li class=""><a href="#" class="tabicon ic_advanced">Advanced (spare icon)</a></li> -->
</ul>
</div>
<div class="clear-both"></div>
@ -295,13 +307,16 @@
<div>
<span id="drop-rate"> </span>
</div>
<div>
<span data-i18n="statusbar_arming_flags"></span> <span class="arming-flags">-</span>
</div>
<div class="version">
<!-- configuration version generated here -->
</div>
</div>
<div id="cache">
<div class="data-loading">
<p>Waiting for data ...</p>
<p i18n="waitingForData"></p>
</div>
</div>
</div>

112
main.js
View file

@ -25,11 +25,15 @@ let globalSettings = {
unitType: null,
// Used to convert units within the UI
osdUnits: null,
// Map
mapProviderType: null,
mapApiKey: null,
proxyURL: null,
proxyLayer: null,
// Show colours for profiles
showProfileParameters: null,
// tree target for documents
docsTreeLocation: 'master',
};
$(document).ready(function () {
@ -74,6 +78,14 @@ $(document).ready(function () {
// Update CSS on to show highlighing or not
updateProfilesHighlightColours();
});
chrome.storage.local.get('cli_autocomplete', function (result) {
if (typeof result.cliAutocomplete === 'undefined') {
result.cli_autocomplete = 1;
}
globalSettings.cliAutocomplete = result.cli_autocomplete;
CliAutoComplete.setEnabled(globalSettings.cliAutocomplete);
});
// Resets the OSD units used by the unit coversion when the FC is disconnected.
if (!CONFIGURATOR.connectionValid) {
@ -81,9 +93,9 @@ $(document).ready(function () {
}
// alternative - window.navigator.appVersion.match(/Chrome\/([0-9.]*)/)[1];
GUI.log('Running - OS: <strong>' + GUI.operating_system + '</strong>, ' +
GUI.log(chrome.i18n.getMessage('getRunningOS') + GUI.operating_system + '</strong>, ' +
'Chrome: <strong>' + window.navigator.appVersion.replace(/.*Chrome\/([0-9.]*).*/, "$1") + '</strong>, ' +
'Configurator: <strong>' + chrome.runtime.getManifest().version + '</strong>');
chrome.i18n.getMessage('getConfiguratorVersion') + chrome.runtime.getManifest().version + '</strong>');
$('#status-bar .version').text(chrome.runtime.getManifest().version);
$('#logo .version').text(chrome.runtime.getManifest().version);
@ -118,9 +130,13 @@ $(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)
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;
}
});
@ -219,6 +235,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;
@ -294,6 +313,9 @@ $(document).ready(function () {
case 'cli':
TABS.cli.initialize(content_ready);
break;
case 'ez_tune':
TABS.ez_tune.initialize(content_ready);
break;
default:
console.log('Tab not found:' + tab);
@ -357,6 +379,15 @@ $(document).ready(function () {
activeTab.removeClass('active');
activeTab.find('a').click();
});
$('div.cli_autocomplete input').change(function () {
globalSettings.cliAutocomplete = $(this).is(':checked');
chrome.storage.local.set({
'cli_autocomplete': globalSettings.cliAutocomplete
});
CliAutoComplete.setEnabled($(this).is(':checked'));
});
$('#ui-unit-type').val(globalSettings.unitType);
$('#map-provider-type').val(globalSettings.mapProviderType);
@ -364,6 +395,7 @@ $(document).ready(function () {
$('#proxyurl').val(globalSettings.proxyURL);
$('#proxylayer').val(globalSettings.proxyLayer);
$('#showProfileParameters').prop('checked', globalSettings.showProfileParameters);
$('#cliAutocomplete').prop('checked', globalSettings.cliAutocomplete);
// Set the value of the unit type
// none, OSD, imperial, metric
@ -408,6 +440,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);
@ -530,18 +565,30 @@ $(document).ready(function () {
state = true;
}
$(this).text(state ? 'Hide Log' : 'Show Log');
$(this).html(state ? chrome.i18n.getMessage("mainHideLog") : chrome.i18n.getMessage("mainShowLog"));
$(this).data('state', state);
});
var mixerprofile_e = $('#mixerprofilechange');
mixerprofile_e.change(function () {
var mixerprofile = parseInt($(this).val());
MSP.send_message(MSPCodes.MSP2_INAV_SELECT_MIXER_PROFILE, [mixerprofile], false, function () {
GUI.log(chrome.i18n.getMessage('loadedMixerProfile', [mixerprofile + 1]));
MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, function () {
GUI.log(chrome.i18n.getMessage('deviceRebooting'));
GUI.handleReconnect();
});
});
});
var profile_e = $('#profilechange');
profile_e.change(function () {
var profile = parseInt($(this).val());
MSP.send_message(MSPCodes.MSP_SELECT_SETTING, [profile], false, function () {
GUI.log(chrome.i18n.getMessage('pidTuning_LoadedProfile', [profile + 1]));
updateActivatedTab();
});
});
@ -551,7 +598,6 @@ $(document).ready(function () {
var batteryprofile = parseInt($(this).val());
MSP.send_message(MSPCodes.MSP2_INAV_SELECT_BATTERY_PROFILE, [batteryprofile], false, function () {
GUI.log(chrome.i18n.getMessage('loadedBatteryProfile', [batteryprofile + 1]));
updateActivatedTab();
});
});
});
@ -649,6 +695,21 @@ String.prototype.format = function () {
});
};
function padZeros(val, length) {
let str = val.toString();
if (str.length < length) {
if (str.charAt(0) === '-') {
str = "-0" + str.substring(1);
str = padZeros(str, length);
} else {
str = padZeros("0" + str, length);
}
}
return str;
}
function updateActivatedTab() {
var activeTab = $('#tabs > ul li.active');
activeTab.removeClass('active');
@ -657,8 +718,47 @@ function updateActivatedTab() {
function updateFirmwareVersion() {
if (CONFIGURATOR.connectionValid) {
$('#logo .firmware_version').text(CONFIG.flightControllerVersion);
$('#logo .firmware_version').text(CONFIG.flightControllerVersion + " [" + CONFIG.target + "]");
globalSettings.docsTreeLocation = 'https://github.com/iNavFlight/inav/blob/' + CONFIG.flightControllerVersion + '/docs/';
// If this is a master branch firmware, this will find a 404 as there is no tag tree. So default to master for docs.
$.ajax({
url : globalSettings.docsTreeLocation + 'Settings.md',
method: "HEAD",
statusCode: {
404: function() {
globalSettings.docsTreeLocation = 'https://github.com/iNavFlight/inav/blob/master/docs/';
}
}
});
} else {
$('#logo .firmware_version').text(chrome.i18n.getMessage('fcNotConnected'));
globalSettings.docsTreeLocation = 'https://github.com/iNavFlight/inav/blob/master/docs/';
}
}
function updateEzTuneTabVisibility(loadMixerConfig) {
let useEzTune = true;
if (CONFIGURATOR.connectionValid) {
if (loadMixerConfig) {
mspHelper.loadMixerConfig(function() {
if (MIXER_CONFIG.platformType == PLATFORM_MULTIROTOR || MIXER_CONFIG.platformType == PLATFORM_TRICOPTER) {
$('.tab_ez_tune').removeClass("is-hidden");
} else {
$('.tab_ez_tune').addClass("is-hidden");
useEzTune = false;
}
});
} else {
if (MIXER_CONFIG.platformType == PLATFORM_MULTIROTOR || MIXER_CONFIG.platformType == PLATFORM_TRICOPTER) {
$('.tab_ez_tune').removeClass("is-hidden");
} else {
$('.tab_ez_tune').addClass("is-hidden");
useEzTune = false;
}
}
}
return useEzTune;
}

View file

@ -1,7 +1,7 @@
{
"manifest_version": 2,
"minimum_chrome_version": "38",
"version": "5.0.0",
"version": "8.0.0",
"author": "Several",
"name": "INAV - Configurator",
"short_name": "INAV",
@ -47,7 +47,8 @@
"notifications",
"alwaysOnTopWindows",
{"usbDevices": [
{"vendorId": 1155, "productId": 57105}
{"vendorId": 1155, "productId": 57105},
{"vendorId": 11836, "productId": 57105}
]}
],

13809
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
{
"name": "inav-configurator",
"description": "INAV Configurator",
"version": "5.0.0",
"version": "8.0.0",
"main": "main.html",
"default_locale": "en",
"scripts": {
@ -25,17 +25,19 @@
"dependencies": {
"archiver": "^2.0.3",
"bluebird": "3.4.1",
"command-exists": "^1.2.8",
"del": "^3.0.0",
"fs": "0.0.1-security",
"graceful-fs": "^4.2.0",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"inflection": "1.12.0",
"jquery": "2.1.4",
"jquery": "3.7.1",
"jquery-textcomplete": "^1.8.5",
"jquery-ui-npm": "1.12.0",
"marked": "^0.3.17",
"minimist": "^1.2.0",
"nw": "^0.61.0",
"nw": "^0.61.0-sdk",
"nw-dialog": "^1.0.7",
"openlayers": "^4.6.5",
"plotly": "^1.0.6",
@ -44,7 +46,14 @@
"xml2js": "^0.4.19"
},
"devDependencies": {
"nw-builder": "^3.5.7",
"@quanle94/innosetup": "^6.0.2",
"gulp-debian": "^0.1.9",
"gulp-rename": "^2.0.0",
"nw-builder": "3.8.6",
"rpm-builder": "^1.2.1",
"semver": "6.3.0"
},
"optionalDependencies": {
"appdmg": "^0.6.2"
}
}

BIN
resources/adsb/adsb_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

BIN
resources/adsb/adsb_10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 962 B

BIN
resources/adsb/adsb_11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 982 B

BIN
resources/adsb/adsb_12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

BIN
resources/adsb/adsb_13.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/adsb/adsb_14.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
resources/adsb/adsb_15.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

BIN
resources/adsb/adsb_2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 B

BIN
resources/adsb/adsb_3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
resources/adsb/adsb_4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
resources/adsb/adsb_5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
resources/adsb/adsb_6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 821 B

BIN
resources/adsb/adsb_7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
resources/adsb/adsb_8.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 919 B

BIN
resources/adsb/adsb_9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

6903
resources/models/fc.gltf Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,44 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Public domain (CC-BY-SA if you or your laws insist), generated by Jonathan Hudson's svg_model_motors.rb -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200pt" height="200pt" viewBox="0 0 200 200" version="1.1">
<defs>
<g>
<symbol overflow="visible" id="glyph0-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph0-1">
<path style="stroke:none;" d="M 2.679688 -13.863281 L 2.679688 -15.75 C 4.457031 -15.921875 5.695312 -16.210938 6.398438 -16.617188 C 7.101562 -17.023438 7.625 -17.984375 7.96875 -19.496094 L 9.914062 -19.496094 L 9.914062 0 L 7.289062 0 L 7.289062 -13.863281 Z M 2.679688 -13.863281 "/>
</symbol>
<symbol overflow="visible" id="glyph0-2">
<path style="stroke:none;" d="M 1.921875 -4.402344 C 2.527344 -5.652344 3.710938 -6.785156 5.46875 -7.804688 L 8.09375 -9.324219 C 9.269531 -10.007812 10.09375 -10.589844 10.570312 -11.074219 C 11.316406 -11.832031 11.6875 -12.695312 11.6875 -13.671875 C 11.6875 -14.8125 11.347656 -15.714844 10.664062 -16.386719 C 9.980469 -17.054688 9.070312 -17.390625 7.929688 -17.390625 C 6.242188 -17.390625 5.078125 -16.753906 4.429688 -15.476562 C 4.082031 -14.792969 3.890625 -13.84375 3.855469 -12.632812 L 1.351562 -12.632812 C 1.378906 -14.335938 1.695312 -15.726562 2.296875 -16.804688 C 3.363281 -18.699219 5.246094 -19.648438 7.945312 -19.648438 C 10.1875 -19.648438 11.824219 -19.039062 12.859375 -17.828125 C 13.894531 -16.617188 14.410156 -15.265625 14.410156 -13.78125 C 14.410156 -12.214844 13.859375 -10.875 12.757812 -9.761719 C 12.117188 -9.113281 10.972656 -8.332031 9.324219 -7.410156 L 7.453125 -6.371094 C 6.558594 -5.878906 5.855469 -5.410156 5.34375 -4.960938 C 4.433594 -4.167969 3.859375 -3.289062 3.625 -2.324219 L 14.3125 -2.324219 L 14.3125 0 L 0.875 0 C 0.964844 -1.6875 1.316406 -3.152344 1.921875 -4.402344 Z M 1.921875 -4.402344 "/>
</symbol>
<symbol overflow="visible" id="glyph0-3">
<path style="stroke:none;" d="M 2.234375 -1.375 C 1.191406 -2.644531 0.671875 -4.191406 0.671875 -6.015625 L 3.242188 -6.015625 C 3.351562 -4.75 3.585938 -3.828125 3.953125 -3.253906 C 4.589844 -2.222656 5.742188 -1.710938 7.410156 -1.710938 C 8.703125 -1.710938 9.742188 -2.054688 10.527344 -2.75 C 11.3125 -3.441406 11.703125 -4.335938 11.703125 -5.429688 C 11.703125 -6.777344 11.289062 -7.71875 10.464844 -8.257812 C 9.640625 -8.796875 8.496094 -9.0625 7.027344 -9.0625 C 6.863281 -9.0625 6.695312 -9.0625 6.527344 -9.058594 C 6.359375 -9.054688 6.1875 -9.046875 6.015625 -9.039062 L 6.015625 -11.210938 C 6.269531 -11.183594 6.484375 -11.164062 6.65625 -11.15625 C 6.832031 -11.148438 7.019531 -11.140625 7.21875 -11.140625 C 8.140625 -11.140625 8.894531 -11.289062 9.488281 -11.578125 C 10.527344 -12.089844 11.046875 -13 11.046875 -14.3125 C 11.046875 -15.289062 10.699219 -16.042969 10.007812 -16.570312 C 9.316406 -17.097656 8.507812 -17.363281 7.585938 -17.363281 C 5.945312 -17.363281 4.8125 -16.816406 4.183594 -15.722656 C 3.835938 -15.121094 3.640625 -14.265625 3.59375 -13.152344 L 1.164062 -13.152344 C 1.164062 -14.609375 1.453125 -15.851562 2.039062 -16.871094 C 3.039062 -18.695312 4.804688 -19.605469 7.328125 -19.605469 C 9.324219 -19.605469 10.867188 -19.160156 11.960938 -18.273438 C 13.054688 -17.382812 13.601562 -16.097656 13.601562 -14.410156 C 13.601562 -13.207031 13.28125 -12.230469 12.632812 -11.484375 C 12.230469 -11.019531 11.710938 -10.65625 11.074219 -10.390625 C 12.105469 -10.109375 12.910156 -9.5625 13.488281 -8.757812 C 14.066406 -7.949219 14.355469 -6.964844 14.355469 -5.796875 C 14.355469 -3.929688 13.742188 -2.40625 12.507812 -1.230469 C 11.277344 -0.0546875 9.535156 0.53125 7.273438 0.53125 C 4.957031 0.53125 3.277344 -0.101562 2.234375 -1.375 Z M 2.234375 -1.375 "/>
</symbol>
<symbol overflow="visible" id="glyph0-4">
<path style="stroke:none;" d="M 9.257812 -6.929688 L 9.257812 -15.804688 L 2.980469 -6.929688 Z M 9.296875 0 L 9.296875 -4.785156 L 0.710938 -4.785156 L 0.710938 -7.191406 L 9.679688 -19.632812 L 11.757812 -19.632812 L 11.757812 -6.929688 L 14.640625 -6.929688 L 14.640625 -4.785156 L 11.757812 -4.785156 L 11.757812 0 Z M 9.296875 0 "/>
</symbol>
</g>
</defs>
<g id="surface11">
<path style="fill:none;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(72.941176%,72.941176%,72.941176%);stroke-opacity:1;stroke-miterlimit:10;" d="M 40 40 L 160 160 M 40 160 L 160 40 "/>
<path style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;" d="M 188 160 C 188 175.464844 175.464844 188 160 188 C 144.535156 188 132 175.464844 132 160 C 132 144.535156 144.535156 132 160 132 C 175.464844 132 188 144.535156 188 160 M 179.800781 179.800781 L 177.785156 163 M 179.800781 179.800781 L 196.601562 179.800781 "/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="153" y="167"/>
</g>
<path style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;" d="M 188 40 C 188 55.464844 175.464844 68 160 68 C 144.535156 68 132 55.464844 132 40 C 132 24.535156 144.535156 12 160 12 C 175.464844 12 188 24.535156 188 40 M 179.800781 20.199219 L 177.785156 37 M 179.800781 20.199219 L 196.601562 20.199219 "/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-2" x="153" y="47"/>
</g>
<path style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;" d="M 68 160 C 68 175.464844 55.464844 188 40 188 C 24.535156 188 12 175.464844 12 160 C 12 144.535156 24.535156 132 40 132 C 55.464844 132 68 144.535156 68 160 M 20.199219 179.800781 L 22.214844 163 M 20.199219 179.800781 L 3.398438 179.800781 "/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="33" y="167"/>
</g>
<path style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;" d="M 68 40 C 68 55.464844 55.464844 68 40 68 C 24.535156 68 12 55.464844 12 40 C 12 24.535156 24.535156 12 40 12 C 55.464844 12 68 24.535156 68 40 M 20.199219 20.199219 L 22.214844 37 M 20.199219 20.199219 L 3.398438 20.199219 "/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-4" x="33" y="47"/>
</g>
<path style="fill:none;stroke-width:12;stroke-linecap:butt;stroke-linejoin:bevel;stroke:rgb(98.039216%,2.745098%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100 80 L 100 120 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.039216%,2.745098%,0%);fill-opacity:1;" d="M 100 75 L 85 90 L 115 90 L 100 75 "/>
</g>
<svg
width="200pt"
height="200pt"
viewBox="0 0 200 200"
version="1.1"
id="svg52"
sodipodi:docname="quad_x.svg"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview54"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="pt"
showgrid="false"
inkscape:zoom="3.165"
inkscape:cx="133.17536"
inkscape:cy="133.49131"
inkscape:window-width="1850"
inkscape:window-height="1016"
inkscape:window-x="1990"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="g45" />
<defs
id="defs19">
<g
id="g17">
<symbol
overflow="visible"
id="glyph0-0">
<path
style="stroke:none;"
d=""
id="path2" />
</symbol>
<symbol
overflow="visible"
id="glyph0-1">
<path
style="stroke:none;"
d="M 2.679688 -13.863281 L 2.679688 -15.75 C 4.457031 -15.921875 5.695312 -16.210938 6.398438 -16.617188 C 7.101562 -17.023438 7.625 -17.984375 7.96875 -19.496094 L 9.914062 -19.496094 L 9.914062 0 L 7.289062 0 L 7.289062 -13.863281 Z M 2.679688 -13.863281 "
id="path5" />
</symbol>
<symbol
overflow="visible"
id="glyph0-2">
<path
style="stroke:none;"
d="M 1.921875 -4.402344 C 2.527344 -5.652344 3.710938 -6.785156 5.46875 -7.804688 L 8.09375 -9.324219 C 9.269531 -10.007812 10.09375 -10.589844 10.570312 -11.074219 C 11.316406 -11.832031 11.6875 -12.695312 11.6875 -13.671875 C 11.6875 -14.8125 11.347656 -15.714844 10.664062 -16.386719 C 9.980469 -17.054688 9.070312 -17.390625 7.929688 -17.390625 C 6.242188 -17.390625 5.078125 -16.753906 4.429688 -15.476562 C 4.082031 -14.792969 3.890625 -13.84375 3.855469 -12.632812 L 1.351562 -12.632812 C 1.378906 -14.335938 1.695312 -15.726562 2.296875 -16.804688 C 3.363281 -18.699219 5.246094 -19.648438 7.945312 -19.648438 C 10.1875 -19.648438 11.824219 -19.039062 12.859375 -17.828125 C 13.894531 -16.617188 14.410156 -15.265625 14.410156 -13.78125 C 14.410156 -12.214844 13.859375 -10.875 12.757812 -9.761719 C 12.117188 -9.113281 10.972656 -8.332031 9.324219 -7.410156 L 7.453125 -6.371094 C 6.558594 -5.878906 5.855469 -5.410156 5.34375 -4.960938 C 4.433594 -4.167969 3.859375 -3.289062 3.625 -2.324219 L 14.3125 -2.324219 L 14.3125 0 L 0.875 0 C 0.964844 -1.6875 1.316406 -3.152344 1.921875 -4.402344 Z M 1.921875 -4.402344 "
id="path8" />
</symbol>
<symbol
overflow="visible"
id="glyph0-3">
<path
style="stroke:none;"
d="M 2.234375 -1.375 C 1.191406 -2.644531 0.671875 -4.191406 0.671875 -6.015625 L 3.242188 -6.015625 C 3.351562 -4.75 3.585938 -3.828125 3.953125 -3.253906 C 4.589844 -2.222656 5.742188 -1.710938 7.410156 -1.710938 C 8.703125 -1.710938 9.742188 -2.054688 10.527344 -2.75 C 11.3125 -3.441406 11.703125 -4.335938 11.703125 -5.429688 C 11.703125 -6.777344 11.289062 -7.71875 10.464844 -8.257812 C 9.640625 -8.796875 8.496094 -9.0625 7.027344 -9.0625 C 6.863281 -9.0625 6.695312 -9.0625 6.527344 -9.058594 C 6.359375 -9.054688 6.1875 -9.046875 6.015625 -9.039062 L 6.015625 -11.210938 C 6.269531 -11.183594 6.484375 -11.164062 6.65625 -11.15625 C 6.832031 -11.148438 7.019531 -11.140625 7.21875 -11.140625 C 8.140625 -11.140625 8.894531 -11.289062 9.488281 -11.578125 C 10.527344 -12.089844 11.046875 -13 11.046875 -14.3125 C 11.046875 -15.289062 10.699219 -16.042969 10.007812 -16.570312 C 9.316406 -17.097656 8.507812 -17.363281 7.585938 -17.363281 C 5.945312 -17.363281 4.8125 -16.816406 4.183594 -15.722656 C 3.835938 -15.121094 3.640625 -14.265625 3.59375 -13.152344 L 1.164062 -13.152344 C 1.164062 -14.609375 1.453125 -15.851562 2.039062 -16.871094 C 3.039062 -18.695312 4.804688 -19.605469 7.328125 -19.605469 C 9.324219 -19.605469 10.867188 -19.160156 11.960938 -18.273438 C 13.054688 -17.382812 13.601562 -16.097656 13.601562 -14.410156 C 13.601562 -13.207031 13.28125 -12.230469 12.632812 -11.484375 C 12.230469 -11.019531 11.710938 -10.65625 11.074219 -10.390625 C 12.105469 -10.109375 12.910156 -9.5625 13.488281 -8.757812 C 14.066406 -7.949219 14.355469 -6.964844 14.355469 -5.796875 C 14.355469 -3.929688 13.742188 -2.40625 12.507812 -1.230469 C 11.277344 -0.0546875 9.535156 0.53125 7.273438 0.53125 C 4.957031 0.53125 3.277344 -0.101562 2.234375 -1.375 Z M 2.234375 -1.375 "
id="path11" />
</symbol>
<symbol
overflow="visible"
id="glyph0-4">
<path
style="stroke:none;"
d="M 9.257812 -6.929688 L 9.257812 -15.804688 L 2.980469 -6.929688 Z M 9.296875 0 L 9.296875 -4.785156 L 0.710938 -4.785156 L 0.710938 -7.191406 L 9.679688 -19.632812 L 11.757812 -19.632812 L 11.757812 -6.929688 L 14.640625 -6.929688 L 14.640625 -4.785156 L 11.757812 -4.785156 L 11.757812 0 Z M 9.296875 0 "
id="path14" />
</symbol>
</g>
</defs>
<g
id="surface11">
<path
style="fill:none;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(72.941176%,72.941176%,72.941176%);stroke-opacity:1;stroke-miterlimit:10;"
d="M 40 40 L 160 160 M 40 160 L 160 40 "
id="path21" />
<path
style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;"
d="M 188 160 C 188 175.464844 175.464844 188 160 188 C 144.535156 188 132 175.464844 132 160 C 132 144.535156 144.535156 132 160 132 C 175.464844 132 188 144.535156 188 160 M 179.800781 179.800781 L 177.785156 163 M 179.800781 179.800781 L 196.601562 179.800781 "
id="path23" />
<g
style="fill:rgb(0%,0%,0%);fill-opacity:1;"
id="g27" />
<path
style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;"
d="M 188 40 C 188 55.464844 175.464844 68 160 68 C 144.535156 68 132 55.464844 132 40 C 132 24.535156 144.535156 12 160 12 C 175.464844 12 188 24.535156 188 40 M 179.800781 20.199219 L 177.785156 37 M 179.800781 20.199219 L 196.601562 20.199219 "
id="path29" />
<g
style="fill:rgb(0%,0%,0%);fill-opacity:1;"
id="g33" />
<path
style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;"
d="M 68 160 C 68 175.464844 55.464844 188 40 188 C 24.535156 188 12 175.464844 12 160 C 12 144.535156 24.535156 132 40 132 C 55.464844 132 68 144.535156 68 160 M 20.199219 179.800781 L 22.214844 163 M 20.199219 179.800781 L 3.398438 179.800781 "
id="path35" />
<path
style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;"
d="M 68 40 C 68 55.464844 55.464844 68 40 68 C 24.535156 68 12 55.464844 12 40 C 12 24.535156 24.535156 12 40 12 C 55.464844 12 68 24.535156 68 40 M 20.199219 20.199219 L 22.214844 37 M 20.199219 20.199219 L 3.398438 20.199219 "
id="path41" />
<g
style="fill:rgb(0%,0%,0%);fill-opacity:1;"
id="g45" />
<path
style="fill:none;stroke-width:12;stroke-linecap:butt;stroke-linejoin:bevel;stroke:rgb(98.039216%,2.745098%,0%);stroke-opacity:1;stroke-miterlimit:10;"
d="M 100 80 L 100 120 "
id="path47" />
<path
style=" stroke:none;fill-rule:nonzero;fill:rgb(98.039216%,2.745098%,0%);fill-opacity:1;"
d="M 100 75 L 85 90 L 115 90 L 100 75 "
id="path49" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

Before After
Before After

View file

@ -8,10 +8,9 @@
version="1.1"
id="svg52"
sodipodi:docname="quad_x_reverse.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
@ -25,14 +24,14 @@
inkscape:document-units="pt"
showgrid="false"
inkscape:zoom="1.1269514"
inkscape:cx="-5.3240981"
inkscape:cy="231.15459"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:cx="-4.8804234"
inkscape:cy="231.1546"
inkscape:window-width="1850"
inkscape:window-height="1016"
inkscape:window-x="1990"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg52" />
inkscape:current-layer="g862" />
<defs
id="defs19">
<g
@ -89,62 +88,18 @@
style="fill:none;stroke:#37a8db;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1"
d="m 188,160 c 0,-15.46484 -12.53516,-28 -28,-28 -15.46484,0 -28,12.53516 -28,28 0,15.46484 12.53516,28 28,28 15.46484,0 28,-12.53516 28,-28 M 179.80078,140.19922 177.78516,157 m 2.01562,-16.80078 h 16.80078"
id="path23" />
<g
style="fill:#000000;fill-opacity:1"
id="g27">
<use
xlink:href="#glyph0-1"
x="153"
y="167"
id="use25"
width="100%"
height="100%" />
</g>
<path
style="fill:none;stroke:#37a8db;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1"
d="m 188,40 c 0,-15.464844 -12.53516,-28 -28,-28 -15.46484,0 -28,12.535156 -28,28 0,15.464844 12.53516,28 28,28 15.46484,0 28,-12.535156 28,-28 M 179.80078,59.800781 177.78516,43 m 2.01562,16.800781 h 16.80078"
id="path29" />
<g
style="fill:#000000;fill-opacity:1"
id="g33">
<use
xlink:href="#glyph0-2"
x="153"
y="47"
id="use31"
width="100%"
height="100%" />
</g>
<path
style="fill:none;stroke:#37a8db;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1"
d="m 68,160 c 0,-15.46484 -12.535156,-28 -28,-28 -15.464844,0 -28,12.53516 -28,28 0,15.46484 12.535156,28 28,28 15.464844,0 28,-12.53516 28,-28 M 20.199219,140.19922 22.214844,157 M 20.199219,140.19922 H 3.398438"
id="path35" />
<g
style="fill:#000000;fill-opacity:1"
id="g39">
<use
xlink:href="#glyph0-3"
x="33"
y="167"
id="use37"
width="100%"
height="100%" />
</g>
<path
style="fill:none;stroke:#37a8db;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1"
d="M 68,40 C 68,24.535156 55.464844,12 40,12 24.535156,12 12,24.535156 12,40 12,55.464844 24.535156,68 40,68 55.464844,68 68,55.464844 68,40 M 20.199219,59.800781 22.214844,43 M 20.199219,59.800781 H 3.398438"
id="path41" />
<g
style="fill:#000000;fill-opacity:1"
id="g45">
<use
xlink:href="#glyph0-4"
x="33"
y="47"
id="use43"
width="100%"
height="100%" />
</g>
<path
style="fill:none;stroke:#fa0500;stroke-width:12;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-opacity:1"
d="m 100,80 v 40"

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Before After
Before After

View file

@ -1,51 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Public domain (CC-BY-SA if you or your laws insist), generated by Jonathan Hudson's svg_model_motors.rb -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200pt" height="200pt" viewBox="0 0 200 200" version="1.1">
<defs>
<g>
<symbol overflow="visible" id="glyph0-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph0-1">
<path style="stroke:none;" d="M 2.679688 -13.863281 L 2.679688 -15.75 C 4.457031 -15.921875 5.695312 -16.210938 6.398438 -16.617188 C 7.101562 -17.023438 7.625 -17.984375 7.96875 -19.496094 L 9.914062 -19.496094 L 9.914062 0 L 7.289062 0 L 7.289062 -13.863281 Z M 2.679688 -13.863281 "/>
</symbol>
<symbol overflow="visible" id="glyph0-2">
<path style="stroke:none;" d="M 1.921875 -4.402344 C 2.527344 -5.652344 3.710938 -6.785156 5.46875 -7.804688 L 8.09375 -9.324219 C 9.269531 -10.007812 10.09375 -10.589844 10.570312 -11.074219 C 11.316406 -11.832031 11.6875 -12.695312 11.6875 -13.671875 C 11.6875 -14.8125 11.347656 -15.714844 10.664062 -16.386719 C 9.980469 -17.054688 9.070312 -17.390625 7.929688 -17.390625 C 6.242188 -17.390625 5.078125 -16.753906 4.429688 -15.476562 C 4.082031 -14.792969 3.890625 -13.84375 3.855469 -12.632812 L 1.351562 -12.632812 C 1.378906 -14.335938 1.695312 -15.726562 2.296875 -16.804688 C 3.363281 -18.699219 5.246094 -19.648438 7.945312 -19.648438 C 10.1875 -19.648438 11.824219 -19.039062 12.859375 -17.828125 C 13.894531 -16.617188 14.410156 -15.265625 14.410156 -13.78125 C 14.410156 -12.214844 13.859375 -10.875 12.757812 -9.761719 C 12.117188 -9.113281 10.972656 -8.332031 9.324219 -7.410156 L 7.453125 -6.371094 C 6.558594 -5.878906 5.855469 -5.410156 5.34375 -4.960938 C 4.433594 -4.167969 3.859375 -3.289062 3.625 -2.324219 L 14.3125 -2.324219 L 14.3125 0 L 0.875 0 C 0.964844 -1.6875 1.316406 -3.152344 1.921875 -4.402344 Z M 1.921875 -4.402344 "/>
</symbol>
<symbol overflow="visible" id="glyph0-3">
<path style="stroke:none;" d="M 2.234375 -1.375 C 1.191406 -2.644531 0.671875 -4.191406 0.671875 -6.015625 L 3.242188 -6.015625 C 3.351562 -4.75 3.585938 -3.828125 3.953125 -3.253906 C 4.589844 -2.222656 5.742188 -1.710938 7.410156 -1.710938 C 8.703125 -1.710938 9.742188 -2.054688 10.527344 -2.75 C 11.3125 -3.441406 11.703125 -4.335938 11.703125 -5.429688 C 11.703125 -6.777344 11.289062 -7.71875 10.464844 -8.257812 C 9.640625 -8.796875 8.496094 -9.0625 7.027344 -9.0625 C 6.863281 -9.0625 6.695312 -9.0625 6.527344 -9.058594 C 6.359375 -9.054688 6.1875 -9.046875 6.015625 -9.039062 L 6.015625 -11.210938 C 6.269531 -11.183594 6.484375 -11.164062 6.65625 -11.15625 C 6.832031 -11.148438 7.019531 -11.140625 7.21875 -11.140625 C 8.140625 -11.140625 8.894531 -11.289062 9.488281 -11.578125 C 10.527344 -12.089844 11.046875 -13 11.046875 -14.3125 C 11.046875 -15.289062 10.699219 -16.042969 10.007812 -16.570312 C 9.316406 -17.097656 8.507812 -17.363281 7.585938 -17.363281 C 5.945312 -17.363281 4.8125 -16.816406 4.183594 -15.722656 C 3.835938 -15.121094 3.640625 -14.265625 3.59375 -13.152344 L 1.164062 -13.152344 C 1.164062 -14.609375 1.453125 -15.851562 2.039062 -16.871094 C 3.039062 -18.695312 4.804688 -19.605469 7.328125 -19.605469 C 9.324219 -19.605469 10.867188 -19.160156 11.960938 -18.273438 C 13.054688 -17.382812 13.601562 -16.097656 13.601562 -14.410156 C 13.601562 -13.207031 13.28125 -12.230469 12.632812 -11.484375 C 12.230469 -11.019531 11.710938 -10.65625 11.074219 -10.390625 C 12.105469 -10.109375 12.910156 -9.5625 13.488281 -8.757812 C 14.066406 -7.949219 14.355469 -6.964844 14.355469 -5.796875 C 14.355469 -3.929688 13.742188 -2.40625 12.507812 -1.230469 C 11.277344 -0.0546875 9.535156 0.53125 7.273438 0.53125 C 4.957031 0.53125 3.277344 -0.101562 2.234375 -1.375 Z M 2.234375 -1.375 "/>
</symbol>
<symbol overflow="visible" id="glyph1-0">
<path style="stroke:none;" d=""/>
</symbol>
<symbol overflow="visible" id="glyph1-1">
<path style="stroke:none;" d="M 2.234375 -3.703125 C 2.269531 -3.050781 2.425781 -2.523438 2.695312 -2.117188 C 3.210938 -1.355469 4.121094 -0.976562 5.421875 -0.976562 C 6.003906 -0.976562 6.535156 -1.058594 7.015625 -1.226562 C 7.941406 -1.550781 8.40625 -2.128906 8.40625 -2.960938 C 8.40625 -3.585938 8.210938 -4.03125 7.820312 -4.296875 C 7.425781 -4.558594 6.804688 -4.785156 5.960938 -4.976562 L 4.40625 -5.328125 C 3.390625 -5.558594 2.671875 -5.808594 2.25 -6.085938 C 1.519531 -6.566406 1.15625 -7.28125 1.15625 -8.234375 C 1.15625 -9.265625 1.511719 -10.113281 2.226562 -10.773438 C 2.941406 -11.433594 3.949219 -11.765625 5.257812 -11.765625 C 6.460938 -11.765625 7.484375 -11.476562 8.324219 -10.894531 C 9.164062 -10.3125 9.585938 -9.386719 9.585938 -8.109375 L 8.125 -8.109375 C 8.046875 -8.722656 7.878906 -9.195312 7.625 -9.523438 C 7.152344 -10.121094 6.347656 -10.421875 5.210938 -10.421875 C 4.292969 -10.421875 3.636719 -10.230469 3.234375 -9.84375 C 2.832031 -9.457031 2.632812 -9.011719 2.632812 -8.5 C 2.632812 -7.9375 2.867188 -7.527344 3.335938 -7.265625 C 3.644531 -7.097656 4.339844 -6.890625 5.421875 -6.640625 L 7.03125 -6.273438 C 7.808594 -6.097656 8.40625 -5.855469 8.828125 -5.546875 C 9.558594 -5.011719 9.921875 -4.230469 9.921875 -3.210938 C 9.921875 -1.941406 9.460938 -1.03125 8.535156 -0.484375 C 7.609375 0.0625 6.535156 0.335938 5.3125 0.335938 C 3.886719 0.335938 2.769531 -0.0273438 1.960938 -0.757812 C 1.152344 -1.480469 0.757812 -2.464844 0.773438 -3.703125 Z M 2.234375 -3.703125 "/>
</symbol>
<symbol overflow="visible" id="glyph1-2">
<path style="stroke:none;" d="M 1.53125 -7.921875 L 1.53125 -9 C 2.546875 -9.097656 3.253906 -9.265625 3.65625 -9.496094 C 4.058594 -9.726562 4.355469 -10.277344 4.554688 -11.140625 L 5.664062 -11.140625 L 5.664062 0 L 4.164062 0 L 4.164062 -7.921875 Z M 1.53125 -7.921875 "/>
</symbol>
</g>
</defs>
<g id="surface6">
<path style="fill:none;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke:rgb(72.941176%,72.941176%,72.941176%);stroke-opacity:1;stroke-miterlimit:10;" d="M 40 40 L 160 40 M 100 40 L 100 160 "/>
<path style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;" d="M 128 160 C 128 175.464844 115.464844 188 100 188 C 84.535156 188 72 175.464844 72 160 C 72 144.535156 84.535156 132 100 132 C 115.464844 132 128 144.535156 128 160 M 80.199219 140.199219 L 80.199219 123.398438 M 80.199219 140.199219 L 97 142.214844 "/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-1" x="93" y="167"/>
</g>
<path style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;" d="M 188 40 C 188 55.464844 175.464844 68 160 68 C 144.535156 68 132 55.464844 132 40 C 132 24.535156 144.535156 12 160 12 C 175.464844 12 188 24.535156 188 40 M 140.199219 20.199219 L 140.199219 3.398438 M 140.199219 20.199219 L 157 22.214844 "/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-2" x="153" y="47"/>
</g>
<path style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(55,168,219);stroke-opacity:1;stroke-miterlimit:10;" d="M 68 40 C 68 55.464844 55.464844 68 40 68 C 24.535156 68 12 55.464844 12 40 C 12 24.535156 24.535156 12 40 12 C 55.464844 12 68 24.535156 68 40 M 59.800781 20.199219 L 57.785156 37 M 59.800781 20.199219 L 76.601562 20.199219 "/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph0-3" x="33" y="47"/>
</g>
<path style="fill:none;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke:rgb(0%,0%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 140 140 L 168 140 L 168 168 L 140 168 Z M 140 140 "/>
<g style="fill:rgb(0%,0%,0%);fill-opacity:1;">
<use xlink:href="#glyph1-1" x="144" y="160"/>
<use xlink:href="#glyph1-2" x="154.671875" y="160"/>
</g>
<path style="fill:none;stroke-width:12;stroke-linecap:butt;stroke-linejoin:bevel;stroke:rgb(98.039216%,2.745098%,0%);stroke-opacity:1;stroke-miterlimit:10;" d="M 100 70 L 100 110 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(98.039216%,2.745098%,0%);fill-opacity:1;" d="M 100 65 L 85 80 L 115 80 L 100 65 "/>
</g>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;">
<g id="surface6">
<path d="M40,40L160,40M100,40L100,160" style="fill:none;fill-rule:nonzero;stroke:rgb(185,185,185);stroke-width:28px;"/>
<path d="M128,160C128,175.465 115.465,188 100,188C84.535,188 72,175.465 72,160C72,144.535 84.535,132 100,132C115.465,132 128,144.535 128,160M80.199,140.199L80.199,123.398M80.199,140.199L97,142.215" style="fill:none;fill-rule:nonzero;stroke:rgb(55,168,219);stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;"/>
<g id="glyph0-1" transform="matrix(1,0,0,1,93,167)">
<g>
<path d="M2.68,-13.863L2.68,-15.75C4.457,-15.922 5.695,-16.211 6.398,-16.617C7.102,-17.023 7.625,-17.984 7.969,-19.496L9.914,-19.496L9.914,0L7.289,0L7.289,-13.863L2.68,-13.863Z" style="fill-rule:nonzero;"/>
</g>
</g>
<path d="M188,40C188,55.465 175.465,68 160,68C144.535,68 132,55.465 132,40C132,24.535 144.535,12 160,12C175.465,12 188,24.535 188,40M140.199,20.199L140.199,3.398M140.199,20.199L157,22.215" style="fill:none;fill-rule:nonzero;stroke:rgb(55,168,219);stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;"/>
<g id="glyph0-2" transform="matrix(1,0,0,1,153,47)">
<g>
<path d="M1.922,-4.402C2.527,-5.652 3.711,-6.785 5.469,-7.805L8.094,-9.324C9.27,-10.008 10.094,-10.59 10.57,-11.074C11.316,-11.832 11.688,-12.695 11.688,-13.672C11.688,-14.813 11.348,-15.715 10.664,-16.387C9.98,-17.055 9.07,-17.391 7.93,-17.391C6.242,-17.391 5.078,-16.754 4.43,-15.477C4.082,-14.793 3.891,-13.844 3.855,-12.633L1.352,-12.633C1.379,-14.336 1.695,-15.727 2.297,-16.805C3.363,-18.699 5.246,-19.648 7.945,-19.648C10.188,-19.648 11.824,-19.039 12.859,-17.828C13.895,-16.617 14.41,-15.266 14.41,-13.781C14.41,-12.215 13.859,-10.875 12.758,-9.762C12.117,-9.113 10.973,-8.332 9.324,-7.41L7.453,-6.371C6.559,-5.879 5.855,-5.41 5.344,-4.961C4.434,-4.168 3.859,-3.289 3.625,-2.324L14.313,-2.324L14.313,0L0.875,0C0.965,-1.688 1.316,-3.152 1.922,-4.402Z" style="fill-rule:nonzero;"/>
</g>
</g>
<g transform="matrix(0.0166389,-0.999862,-0.999862,-0.0166389,80.5581,80.9602)">
<path d="M68,40C68,55.465 55.465,68 40,68C24.535,68 12,55.465 12,40C12,24.535 24.535,12 40,12C55.465,12 68,24.535 68,40M59.801,20.199L57.785,37M59.801,20.199L76.602,20.199" style="fill:none;fill-rule:nonzero;stroke:rgb(55,168,219);stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;"/>
</g>
<g id="glyph0-3" transform="matrix(1,0,0,1,33,47)">
<g>
<path d="M2.234,-1.375C1.191,-2.645 0.672,-4.191 0.672,-6.016L3.242,-6.016C3.352,-4.75 3.586,-3.828 3.953,-3.254C4.59,-2.223 5.742,-1.711 7.41,-1.711C8.703,-1.711 9.742,-2.055 10.527,-2.75C11.313,-3.441 11.703,-4.336 11.703,-5.43C11.703,-6.777 11.289,-7.719 10.465,-8.258C9.641,-8.797 8.496,-9.063 7.027,-9.063C6.863,-9.063 6.695,-9.063 6.527,-9.059C6.359,-9.055 6.188,-9.047 6.016,-9.039L6.016,-11.211C6.27,-11.184 6.484,-11.164 6.656,-11.156C6.832,-11.148 7.02,-11.141 7.219,-11.141C8.141,-11.141 8.895,-11.289 9.488,-11.578C10.527,-12.09 11.047,-13 11.047,-14.313C11.047,-15.289 10.699,-16.043 10.008,-16.57C9.316,-17.098 8.508,-17.363 7.586,-17.363C5.945,-17.363 4.813,-16.816 4.184,-15.723C3.836,-15.121 3.641,-14.266 3.594,-13.152L1.164,-13.152C1.164,-14.609 1.453,-15.852 2.039,-16.871C3.039,-18.695 4.805,-19.605 7.328,-19.605C9.324,-19.605 10.867,-19.16 11.961,-18.273C13.055,-17.383 13.602,-16.098 13.602,-14.41C13.602,-13.207 13.281,-12.23 12.633,-11.484C12.23,-11.02 11.711,-10.656 11.074,-10.391C12.105,-10.109 12.91,-9.563 13.488,-8.758C14.066,-7.949 14.355,-6.965 14.355,-5.797C14.355,-3.93 13.742,-2.406 12.508,-1.23C11.277,-0.055 9.535,0.531 7.273,0.531C4.957,0.531 3.277,-0.102 2.234,-1.375Z" style="fill-rule:nonzero;"/>
</g>
</g>
<rect x="140" y="140" width="28" height="28" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;"/>
<g>
<g id="glyph1-1" transform="matrix(1,0,0,1,144,160)">
<path d="M2.234,-3.703C2.27,-3.051 2.426,-2.523 2.695,-2.117C3.211,-1.355 4.121,-0.977 5.422,-0.977C6.004,-0.977 6.535,-1.059 7.016,-1.227C7.941,-1.551 8.406,-2.129 8.406,-2.961C8.406,-3.586 8.211,-4.031 7.82,-4.297C7.426,-4.559 6.805,-4.785 5.961,-4.977L4.406,-5.328C3.391,-5.559 2.672,-5.809 2.25,-6.086C1.52,-6.566 1.156,-7.281 1.156,-8.234C1.156,-9.266 1.512,-10.113 2.227,-10.773C2.941,-11.434 3.949,-11.766 5.258,-11.766C6.461,-11.766 7.484,-11.477 8.324,-10.895C9.164,-10.313 9.586,-9.387 9.586,-8.109L8.125,-8.109C8.047,-8.723 7.879,-9.195 7.625,-9.523C7.152,-10.121 6.348,-10.422 5.211,-10.422C4.293,-10.422 3.637,-10.23 3.234,-9.844C2.832,-9.457 2.633,-9.012 2.633,-8.5C2.633,-7.938 2.867,-7.527 3.336,-7.266C3.645,-7.098 4.34,-6.891 5.422,-6.641L7.031,-6.273C7.809,-6.098 8.406,-5.855 8.828,-5.547C9.559,-5.012 9.922,-4.23 9.922,-3.211C9.922,-1.941 9.461,-1.031 8.535,-0.484C7.609,0.063 6.535,0.336 5.313,0.336C3.887,0.336 2.77,-0.027 1.961,-0.758C1.152,-1.48 0.758,-2.465 0.773,-3.703L2.234,-3.703Z" style="fill-rule:nonzero;"/>
</g>
<g id="glyph1-2" transform="matrix(1,0,0,1,154.672,160)">
<path d="M1.531,-7.922L1.531,-9C2.547,-9.098 3.254,-9.266 3.656,-9.496C4.059,-9.727 4.355,-10.277 4.555,-11.141L5.664,-11.141L5.664,0L4.164,0L4.164,-7.922L1.531,-7.922Z" style="fill-rule:nonzero;"/>
</g>
</g>
<path d="M100,70L100,110" style="fill:none;fill-rule:nonzero;stroke:rgb(250,6,0);stroke-width:12px;stroke-linecap:butt;stroke-linejoin:bevel;"/>
<path d="M100,65L85,80L115,80L100,65" style="fill:rgb(250,6,0);fill-rule:nonzero;"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8 KiB

After

Width:  |  Height:  |  Size: 6 KiB

Before After
Before After

View file

@ -1,177 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Public domain (CC-BY-SA if you or your laws insist), generated by Jonathan Hudson's svg_model_motors.rb -->
<svg
width="200pt"
height="200pt"
viewBox="0 0 200 200"
version="1.1"
id="svg60"
sodipodi:docname="tri_reverse.svg"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview62"
pagecolor="#505050"
bordercolor="#eeeeee"
borderopacity="1"
inkscape:pageshadow="0"
inkscape:pageopacity="0"
inkscape:pagecheckerboard="0"
inkscape:document-units="pt"
showgrid="false"
inkscape:zoom="3.1875"
inkscape:cx="133.33333"
inkscape:cy="108.39216"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg60" />
<defs
id="defs25">
<g
id="g23">
<symbol
overflow="visible"
id="glyph0-0">
<path
style="stroke:none;"
d=""
id="path2" />
</symbol>
<symbol
overflow="visible"
id="glyph0-1">
<path
style="stroke:none;"
d="M 2.679688 -13.863281 L 2.679688 -15.75 C 4.457031 -15.921875 5.695312 -16.210938 6.398438 -16.617188 C 7.101562 -17.023438 7.625 -17.984375 7.96875 -19.496094 L 9.914062 -19.496094 L 9.914062 0 L 7.289062 0 L 7.289062 -13.863281 Z M 2.679688 -13.863281 "
id="path5" />
</symbol>
<symbol
overflow="visible"
id="glyph0-2">
<path
style="stroke:none;"
d="M 1.921875 -4.402344 C 2.527344 -5.652344 3.710938 -6.785156 5.46875 -7.804688 L 8.09375 -9.324219 C 9.269531 -10.007812 10.09375 -10.589844 10.570312 -11.074219 C 11.316406 -11.832031 11.6875 -12.695312 11.6875 -13.671875 C 11.6875 -14.8125 11.347656 -15.714844 10.664062 -16.386719 C 9.980469 -17.054688 9.070312 -17.390625 7.929688 -17.390625 C 6.242188 -17.390625 5.078125 -16.753906 4.429688 -15.476562 C 4.082031 -14.792969 3.890625 -13.84375 3.855469 -12.632812 L 1.351562 -12.632812 C 1.378906 -14.335938 1.695312 -15.726562 2.296875 -16.804688 C 3.363281 -18.699219 5.246094 -19.648438 7.945312 -19.648438 C 10.1875 -19.648438 11.824219 -19.039062 12.859375 -17.828125 C 13.894531 -16.617188 14.410156 -15.265625 14.410156 -13.78125 C 14.410156 -12.214844 13.859375 -10.875 12.757812 -9.761719 C 12.117188 -9.113281 10.972656 -8.332031 9.324219 -7.410156 L 7.453125 -6.371094 C 6.558594 -5.878906 5.855469 -5.410156 5.34375 -4.960938 C 4.433594 -4.167969 3.859375 -3.289062 3.625 -2.324219 L 14.3125 -2.324219 L 14.3125 0 L 0.875 0 C 0.964844 -1.6875 1.316406 -3.152344 1.921875 -4.402344 Z M 1.921875 -4.402344 "
id="path8" />
</symbol>
<symbol
overflow="visible"
id="glyph0-3">
<path
style="stroke:none;"
d="M 2.234375 -1.375 C 1.191406 -2.644531 0.671875 -4.191406 0.671875 -6.015625 L 3.242188 -6.015625 C 3.351562 -4.75 3.585938 -3.828125 3.953125 -3.253906 C 4.589844 -2.222656 5.742188 -1.710938 7.410156 -1.710938 C 8.703125 -1.710938 9.742188 -2.054688 10.527344 -2.75 C 11.3125 -3.441406 11.703125 -4.335938 11.703125 -5.429688 C 11.703125 -6.777344 11.289062 -7.71875 10.464844 -8.257812 C 9.640625 -8.796875 8.496094 -9.0625 7.027344 -9.0625 C 6.863281 -9.0625 6.695312 -9.0625 6.527344 -9.058594 C 6.359375 -9.054688 6.1875 -9.046875 6.015625 -9.039062 L 6.015625 -11.210938 C 6.269531 -11.183594 6.484375 -11.164062 6.65625 -11.15625 C 6.832031 -11.148438 7.019531 -11.140625 7.21875 -11.140625 C 8.140625 -11.140625 8.894531 -11.289062 9.488281 -11.578125 C 10.527344 -12.089844 11.046875 -13 11.046875 -14.3125 C 11.046875 -15.289062 10.699219 -16.042969 10.007812 -16.570312 C 9.316406 -17.097656 8.507812 -17.363281 7.585938 -17.363281 C 5.945312 -17.363281 4.8125 -16.816406 4.183594 -15.722656 C 3.835938 -15.121094 3.640625 -14.265625 3.59375 -13.152344 L 1.164062 -13.152344 C 1.164062 -14.609375 1.453125 -15.851562 2.039062 -16.871094 C 3.039062 -18.695312 4.804688 -19.605469 7.328125 -19.605469 C 9.324219 -19.605469 10.867188 -19.160156 11.960938 -18.273438 C 13.054688 -17.382812 13.601562 -16.097656 13.601562 -14.410156 C 13.601562 -13.207031 13.28125 -12.230469 12.632812 -11.484375 C 12.230469 -11.019531 11.710938 -10.65625 11.074219 -10.390625 C 12.105469 -10.109375 12.910156 -9.5625 13.488281 -8.757812 C 14.066406 -7.949219 14.355469 -6.964844 14.355469 -5.796875 C 14.355469 -3.929688 13.742188 -2.40625 12.507812 -1.230469 C 11.277344 -0.0546875 9.535156 0.53125 7.273438 0.53125 C 4.957031 0.53125 3.277344 -0.101562 2.234375 -1.375 Z M 2.234375 -1.375 "
id="path11" />
</symbol>
<symbol
overflow="visible"
id="glyph1-0">
<path
style="stroke:none;"
d=""
id="path14" />
</symbol>
<symbol
overflow="visible"
id="glyph1-1">
<path
style="stroke:none;"
d="M 2.234375 -3.703125 C 2.269531 -3.050781 2.425781 -2.523438 2.695312 -2.117188 C 3.210938 -1.355469 4.121094 -0.976562 5.421875 -0.976562 C 6.003906 -0.976562 6.535156 -1.058594 7.015625 -1.226562 C 7.941406 -1.550781 8.40625 -2.128906 8.40625 -2.960938 C 8.40625 -3.585938 8.210938 -4.03125 7.820312 -4.296875 C 7.425781 -4.558594 6.804688 -4.785156 5.960938 -4.976562 L 4.40625 -5.328125 C 3.390625 -5.558594 2.671875 -5.808594 2.25 -6.085938 C 1.519531 -6.566406 1.15625 -7.28125 1.15625 -8.234375 C 1.15625 -9.265625 1.511719 -10.113281 2.226562 -10.773438 C 2.941406 -11.433594 3.949219 -11.765625 5.257812 -11.765625 C 6.460938 -11.765625 7.484375 -11.476562 8.324219 -10.894531 C 9.164062 -10.3125 9.585938 -9.386719 9.585938 -8.109375 L 8.125 -8.109375 C 8.046875 -8.722656 7.878906 -9.195312 7.625 -9.523438 C 7.152344 -10.121094 6.347656 -10.421875 5.210938 -10.421875 C 4.292969 -10.421875 3.636719 -10.230469 3.234375 -9.84375 C 2.832031 -9.457031 2.632812 -9.011719 2.632812 -8.5 C 2.632812 -7.9375 2.867188 -7.527344 3.335938 -7.265625 C 3.644531 -7.097656 4.339844 -6.890625 5.421875 -6.640625 L 7.03125 -6.273438 C 7.808594 -6.097656 8.40625 -5.855469 8.828125 -5.546875 C 9.558594 -5.011719 9.921875 -4.230469 9.921875 -3.210938 C 9.921875 -1.941406 9.460938 -1.03125 8.535156 -0.484375 C 7.609375 0.0625 6.535156 0.335938 5.3125 0.335938 C 3.886719 0.335938 2.769531 -0.0273438 1.960938 -0.757812 C 1.152344 -1.480469 0.757812 -2.464844 0.773438 -3.703125 Z M 2.234375 -3.703125 "
id="path17" />
</symbol>
<symbol
overflow="visible"
id="glyph1-2">
<path
style="stroke:none;"
d="M 1.53125 -7.921875 L 1.53125 -9 C 2.546875 -9.097656 3.253906 -9.265625 3.65625 -9.496094 C 4.058594 -9.726562 4.355469 -10.277344 4.554688 -11.140625 L 5.664062 -11.140625 L 5.664062 0 L 4.164062 0 L 4.164062 -7.921875 Z M 1.53125 -7.921875 "
id="path20" />
</symbol>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;">
<path id="path27" d="M40,40L160,40M100,40L100,160" style="fill:none;fill-rule:nonzero;stroke:rgb(184,184,184);stroke-width:28px;"/>
<path id="path29" d="M72,160C72,175.465 84.535,188 100,188C115.465,188 128,175.465 128,160C128,144.535 115.465,132 100,132C84.535,132 72,144.535 72,160M119.801,140.199L119.801,123.398M119.801,140.199L103,142.215" style="fill:none;fill-rule:nonzero;stroke:rgb(55,168,219);stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;"/>
<g id="use31" transform="matrix(1,0,0,1,93,167)">
<g id="g33">
<g id="use311" serif:id="use31">
<path id="path5" d="M2.68,-13.863L2.68,-15.75C4.457,-15.922 5.695,-16.211 6.398,-16.617C7.102,-17.023 7.625,-17.984 7.969,-19.496L9.914,-19.496L9.914,0L7.289,0L7.289,-13.863L2.68,-13.863Z" style="fill-rule:nonzero;"/>
</g>
</defs>
<path
style="fill:none;stroke:#b8b8b8;stroke-width:28;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-opacity:1"
d="m 40,40 h 120 m -60,0 v 120"
id="path27" />
<path
style="fill:none;stroke:#37a8db;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1"
d="m 72,160 c 0,15.46484 12.53516,28 28,28 15.46484,0 28,-12.53516 28,-28 0,-15.46484 -12.53516,-28 -28,-28 -15.46484,0 -28,12.53516 -28,28 m 47.80078,-19.80078 v -16.80078 m 0,16.80078 L 103,142.21484"
id="path29" />
<g
style="fill:#000000;fill-opacity:1"
id="g33">
<use
xlink:href="#glyph0-1"
x="93"
y="167"
id="use31"
width="100%"
height="100%" />
</g>
<path
style="fill:none;stroke:#37a8db;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1"
d="m 132,40 c 0,15.464844 12.53516,28 28,28 15.46484,0 28,-12.535156 28,-28 0,-15.464844 -12.53516,-28 -28,-28 -15.46484,0 -28,12.535156 -28,28 M 179.80078,20.199219 V 3.398438 m 0,16.800781 L 163,22.214844"
id="path35-4" />
<g
style="fill:#000000;fill-opacity:1"
id="g39">
<use
xlink:href="#glyph0-2"
x="153"
y="47"
id="use37"
width="100%"
height="100%" />
</g>
<path
style="fill:none;stroke:#37a8db;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1"
d="m 11.807447,40 c 0,15.464844 12.535157,28 28.000001,28 15.464844,0 28,-12.535156 28,-28 0,-15.464844 -12.535156,-28 -28,-28 C 24.342604,12 11.807447,24.535156 11.807447,40 M 20.006667,20.199219 22.022292,37 M 20.006667,20.199219 H 3.2058824"
id="path41-0" />
<g
style="fill:#000000;fill-opacity:1"
id="g45">
<use
xlink:href="#glyph0-3"
x="33"
y="47"
id="use43"
width="100%"
height="100%" />
<path id="path35-4" d="M132,40C132,55.465 144.535,68 160,68C175.465,68 188,55.465 188,40C188,24.535 175.465,12 160,12C144.535,12 132,24.535 132,40M179.801,20.199L179.801,3.398M179.801,20.199L163,22.215" style="fill:none;fill-rule:nonzero;stroke:rgb(55,168,219);stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;"/>
<g id="use37" transform="matrix(1,0,0,1,153,47)">
<g id="g39">
<g id="use371" serif:id="use37">
<path id="path8" d="M1.922,-4.402C2.527,-5.652 3.711,-6.785 5.469,-7.805L8.094,-9.324C9.27,-10.008 10.094,-10.59 10.57,-11.074C11.316,-11.832 11.688,-12.695 11.688,-13.672C11.688,-14.813 11.348,-15.715 10.664,-16.387C9.98,-17.055 9.07,-17.391 7.93,-17.391C6.242,-17.391 5.078,-16.754 4.43,-15.477C4.082,-14.793 3.891,-13.844 3.855,-12.633L1.352,-12.633C1.379,-14.336 1.695,-15.727 2.297,-16.805C3.363,-18.699 5.246,-19.648 7.945,-19.648C10.188,-19.648 11.824,-19.039 12.859,-17.828C13.895,-16.617 14.41,-15.266 14.41,-13.781C14.41,-12.215 13.859,-10.875 12.758,-9.762C12.117,-9.113 10.973,-8.332 9.324,-7.41L7.453,-6.371C6.559,-5.879 5.855,-5.41 5.344,-4.961C4.434,-4.168 3.859,-3.289 3.625,-2.324L14.313,-2.324L14.313,0L0.875,0C0.965,-1.688 1.316,-3.152 1.922,-4.402Z" style="fill-rule:nonzero;"/>
</g>
<path
style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-opacity:1"
d="m 140,140 h 28 v 28 h -28 z m 0,0"
id="path47" />
<g
style="fill:#000000;fill-opacity:1"
id="g53">
<use
xlink:href="#glyph1-1"
x="144"
y="160"
id="use49"
width="100%"
height="100%" />
<use
xlink:href="#glyph1-2"
x="154.67188"
y="160"
id="use51"
width="100%"
height="100%" />
</g>
<path
style="fill:none;stroke:#fa0500;stroke-width:12;stroke-linecap:butt;stroke-linejoin:bevel;stroke-miterlimit:10;stroke-opacity:1"
d="m 100,70 v 40"
id="path55" />
<path
style="fill:#fa0500;fill-opacity:1;fill-rule:nonzero;stroke:none"
d="M 100,65 85,80 h 30 L 100,65"
id="path57" />
</g>
<g id="path41-0" transform="matrix(0.00137106,0.999999,0.999999,-0.00137106,1.45802,0.54821)">
<path d="M11.807,40C11.807,55.465 24.343,68 39.807,68C55.272,68 67.807,55.465 67.807,40C67.807,24.535 55.272,12 39.807,12C24.343,12 11.807,24.535 11.807,40M20.007,20.199L22.022,37M20.007,20.199L3.206,20.199" style="fill:none;fill-rule:nonzero;stroke:rgb(55,168,219);stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;"/>
</g>
<g id="use43" transform="matrix(1,0,0,1,33,47)">
<g id="g45">
<g id="use431" serif:id="use43">
<path id="path11" d="M2.234,-1.375C1.191,-2.645 0.672,-4.191 0.672,-6.016L3.242,-6.016C3.352,-4.75 3.586,-3.828 3.953,-3.254C4.59,-2.223 5.742,-1.711 7.41,-1.711C8.703,-1.711 9.742,-2.055 10.527,-2.75C11.313,-3.441 11.703,-4.336 11.703,-5.43C11.703,-6.777 11.289,-7.719 10.465,-8.258C9.641,-8.797 8.496,-9.063 7.027,-9.063C6.863,-9.063 6.695,-9.063 6.527,-9.059C6.359,-9.055 6.188,-9.047 6.016,-9.039L6.016,-11.211C6.27,-11.184 6.484,-11.164 6.656,-11.156C6.832,-11.148 7.02,-11.141 7.219,-11.141C8.141,-11.141 8.895,-11.289 9.488,-11.578C10.527,-12.09 11.047,-13 11.047,-14.313C11.047,-15.289 10.699,-16.043 10.008,-16.57C9.316,-17.098 8.508,-17.363 7.586,-17.363C5.945,-17.363 4.813,-16.816 4.184,-15.723C3.836,-15.121 3.641,-14.266 3.594,-13.152L1.164,-13.152C1.164,-14.609 1.453,-15.852 2.039,-16.871C3.039,-18.695 4.805,-19.605 7.328,-19.605C9.324,-19.605 10.867,-19.16 11.961,-18.273C13.055,-17.383 13.602,-16.098 13.602,-14.41C13.602,-13.207 13.281,-12.23 12.633,-11.484C12.23,-11.02 11.711,-10.656 11.074,-10.391C12.105,-10.109 12.91,-9.563 13.488,-8.758C14.066,-7.949 14.355,-6.965 14.355,-5.797C14.355,-3.93 13.742,-2.406 12.508,-1.23C11.277,-0.055 9.535,0.531 7.273,0.531C4.957,0.531 3.277,-0.102 2.234,-1.375Z" style="fill-rule:nonzero;"/>
</g>
</g>
</g>
<rect id="path47" x="140" y="140" width="28" height="28" style="fill:none;fill-rule:nonzero;stroke:black;stroke-width:3px;stroke-linecap:butt;stroke-linejoin:miter;"/>
<g id="g53">
<g id="use49" transform="matrix(1,0,0,1,144,160)">
<path id="path17" d="M2.234,-3.703C2.27,-3.051 2.426,-2.523 2.695,-2.117C3.211,-1.355 4.121,-0.977 5.422,-0.977C6.004,-0.977 6.535,-1.059 7.016,-1.227C7.941,-1.551 8.406,-2.129 8.406,-2.961C8.406,-3.586 8.211,-4.031 7.82,-4.297C7.426,-4.559 6.805,-4.785 5.961,-4.977L4.406,-5.328C3.391,-5.559 2.672,-5.809 2.25,-6.086C1.52,-6.566 1.156,-7.281 1.156,-8.234C1.156,-9.266 1.512,-10.113 2.227,-10.773C2.941,-11.434 3.949,-11.766 5.258,-11.766C6.461,-11.766 7.484,-11.477 8.324,-10.895C9.164,-10.313 9.586,-9.387 9.586,-8.109L8.125,-8.109C8.047,-8.723 7.879,-9.195 7.625,-9.523C7.152,-10.121 6.348,-10.422 5.211,-10.422C4.293,-10.422 3.637,-10.23 3.234,-9.844C2.832,-9.457 2.633,-9.012 2.633,-8.5C2.633,-7.938 2.867,-7.527 3.336,-7.266C3.645,-7.098 4.34,-6.891 5.422,-6.641L7.031,-6.273C7.809,-6.098 8.406,-5.855 8.828,-5.547C9.559,-5.012 9.922,-4.23 9.922,-3.211C9.922,-1.941 9.461,-1.031 8.535,-0.484C7.609,0.063 6.535,0.336 5.313,0.336C3.887,0.336 2.77,-0.027 1.961,-0.758C1.152,-1.48 0.758,-2.465 0.773,-3.703L2.234,-3.703Z" style="fill-rule:nonzero;"/>
</g>
<g id="use51" transform="matrix(1,0,0,1,154.672,160)">
<path id="path20" d="M1.531,-7.922L1.531,-9C2.547,-9.098 3.254,-9.266 3.656,-9.496C4.059,-9.727 4.355,-10.277 4.555,-11.141L5.664,-11.141L5.664,0L4.164,0L4.164,-7.922L1.531,-7.922Z" style="fill-rule:nonzero;"/>
</g>
</g>
<path id="path55" d="M100,70L100,110" style="fill:none;fill-rule:nonzero;stroke:rgb(250,5,0);stroke-width:12px;stroke-linecap:butt;stroke-linejoin:bevel;"/>
<path id="path57" d="M100,65L85,80L115,80L100,65" style="fill:rgb(250,5,0);fill-rule:nonzero;"/>
</svg>

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Before After
Before After

View file

@ -1 +0,0 @@
/*.png

View file

@ -0,0 +1,330 @@
# Characters
| Preview | Firmware Variable | Configurator Variable | Description | Decimal ID | HEX ID |
|--------------------------------------------------------------------|----------------------------|------------------------------|---------------------------------------|------------|--------------|
| ![None](/resources/osd/digital/default/24x36/000.png) | SYM_NONE | | Completely transparent icon | 000 | 0x00 |
| ![RSSI](/resources/osd/digital/default/24x36/001.png) | SYM_RSSI | SYM.RSSI | RSSI Icon | 001 | 0x01 |
| ![LQ](/resources/osd/digital/default/24x36/002.png) | SYM_LQ | SYM.LQ | LQ Icon | 002 | 0x02 |
| ![Latitude](/resources/osd/digital/default/24x36/003.png) | SYM_LAT | SYM.LAT | Latitude | 003 | 0x03 |
| ![Longitude](/resources/osd/digital/default/24x36/004.png) | SYM_LON | SYM.LON | Longitude | 004 | 0x04 |
| ![Azimuth](/resources/osd/digital/default/24x36/005.png) | SYM_AZIMUTH | SYM.AZIMUTH | Azimuth | 005 | 0x05 |
| ![Telemetry](/resources/osd/digital/default/24x36/006.png) | SYM_TELEMETRY_0 | | Antenna tracking Telemetry | 006 | 0x06 |
| ![Telemetry](/resources/osd/digital/default/24x36/007.png) | SYM_TELEMETRY_1 | | Antenna tracking Telemetry | 007 | 0x07 |
| ![Satellites](/resources/osd/digital/default/24x36/008-009.png) | SYM_SAT_L | SYM.GPS_SAT1 | Satellites Icon, left side | 008 | 0x08 |
| | SYM_SAT_R | SYM.GPS_SAT2 | Satellites Icon, right side | 009 | 0x09 |
| ![Near Home](/resources/osd/digital/default/24x36/010.png) | SYM_HOME_NEAR | | Icon shown at home point | 010 | 0x0A |
| ![Degrees](/resources/osd/digital/default/24x36/011.png) | SYM_DEGREES | SYM.DEGREES | Degree symbol | 011 | 0x0B |
| ![Heading](/resources/osd/digital/default/24x36/012.png) | SYM_HEADING | SYM.HEADING | Heading symbol | 012 | 0x0C |
| ![Map Scale](/resources/osd/digital/default/24x36/013.png) | SYM_SCALE | SYM.SCALE | Map scale symbol | 013 | 0x0D |
| ![HDOP](/resources/osd/digital/default/24x36/014-015.png) | SYM_HDP_L | SYM.GPS_HDP1 | HDOP icon, left side | 014 | 0x0E |
| | SYM_HDP_R | SYM.GPS_HDP2 | HDOP icon, right side | 015 | 0x0F |
| ![Home](/resources/osd/digital/default/24x36/016.png) | SYM_HOME | SYM.HOME | Home icon | 016 | 0x10 |
| ![RSSI 2](/resources/osd/digital/default/24x36/017.png) | SYM_2RSS | SYM.RSS2 | RSSI 2 icon | 017 | 0x11 |
| ![Decibel](/resources/osd/digital/default/24x36/018.png) | SYM_DB | SYM.DB | Decibel icon | 018 | 0x12 |
| ![Decibel per mW](/resources/osd/digital/default/24x36/019.png) | SYM_DBM | SYM.DBM | Decibel per milliwatt icon | 019 | 0x13 |
| ![SNR](/resources/osd/digital/default/24x36/020.png) | SYM_SNR | SYM.SNR | Signal to Noise Ratio icon | 020 | 0x14 |
| ![AHI up arrow](/resources/osd/digital/default/24x36/021.png) | SYM_AH_DECORATION_UP | SYM.AH_DECORATION_UP | AHi up arrow | 021 | 0x15 |
| ![AHI down arrow](/resources/osd/digital/default/24x36/022.png) | SYM_AH_DECORATION_DOWN | | AHI down arrow | 022 | 0x16 |
| ![Direction](/resources/osd/digital/default/24x36/023.png) | SYM_DECORATION | SYM.DECORATION | Direction little arrows | 023 - 030 | 0x17 - 0x1E |
| ![Direction](/resources/osd/digital/default/24x36/024.png) | | | | 024 | 0x18 |
| ![Direction](/resources/osd/digital/default/24x36/025.png) | | | | 025 | 0x19 |
| ![Direction](/resources/osd/digital/default/24x36/026.png) | | | | 026 | 0x1A |
| ![Direction](/resources/osd/digital/default/24x36/027.png) | | | | 027 | 0x1B |
| ![Direction](/resources/osd/digital/default/24x36/028.png) | | | | 028 | 0x1C |
| ![Direction](/resources/osd/digital/default/24x36/029.png) | | | | 029 | 0x1D |
| ![Direction](/resources/osd/digital/default/24x36/030.png) | | | | 030 | 0x1E |
| ![Volts](/resources/osd/digital/default/24x36/031.png) | SYM_VOLT | SYM.VOLT | Volts symbol | 031 | 0x1F |
| ![Blank](/resources/osd/digital/default/24x36/032.png) | SYM_BLANK _*_ | SYM.BLANK | Empty | 032 | 0x20 |
| ![Exclamation](/resources/osd/digital/default/24x36/033.png) | _ASCII_ _*_ | | ! | 033 | 0x21 |
| ![Ah per Km](/resources/osd/digital/default/24x36/034.png) | SYM_AH_KM | | Ah per Km | 034 | 0x22 |
| ![Hash](/resources/osd/digital/default/24x36/035.png) | _ASCII_ _*_ | | # | 035 | 0x23 |
| ![Ah per Mile](/resources/osd/digital/default/24x36/036.png) | SYM_AH_MI | | Ah per Mile | 036 | 0x24 |
| ![Percent](/resources/osd/digital/default/24x36/037.png) | _ASCII_ _*_ | | % | 037 | 0x25 |
| ![Ampersand](/resources/osd/digital/default/24x36/038.png) | _ASCII_ _*_ | | & | 038 | 0x26 |
| ![VTX Power](/resources/osd/digital/default/24x36/039.png) | SYM_VTX_POWER | SYM.VTX_POWER | VTx Power | 039 | 0x27 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/040.png) | _ASCII_ _*_ | | Symbols and numbers | 040 - 062 | 0x28 - 0x3E |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/041.png) | _ASCII_ _*_ | | | 041 | 0x29 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/042.png) | _ASCII_ _*_ | | | 042 | 0x2A |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/043.png) | _ASCII_ _*_ | | | 043 | 0x2B |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/044.png) | _ASCII_ _*_ | | | 044 | 0x2C |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/045.png) | _ASCII_ _*_ | | | 045 | 0x2D |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/046.png) | _ASCII_ _*_ | | | 046 | 0x2E |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/047.png) | _ASCII_ _*_ | | | 047 | 0x2F |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/048.png) | _ASCII_ _*_ | | | 048 | 0x30 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/049.png) | _ASCII_ _*_ | | | 049 | 0x31 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/050.png) | _ASCII_ _*_ | | | 050 | 0x32 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/051.png) | _ASCII_ _*_ | | | 051 | 0x33 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/052.png) | _ASCII_ _*_ | | | 052 | 0x34 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/053.png) | _ASCII_ _*_ | | | 053 | 0x35 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/054.png) | _ASCII_ _*_ | | | 054 | 0x36 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/055.png) | _ASCII_ _*_ | | | 055 | 0x37 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/056.png) | _ASCII_ _*_ | | | 056 | 0x38 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/057.png) | _ASCII_ _*_ | | | 057 | 0x39 |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/058.png) | _ASCII_ _*_ | | | 058 | 0x3A |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/059.png) | _ASCII_ _*_ | | | 059 | 0x3B |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/060.png) | _ASCII_ _*_ | | | 060 | 0x3C |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/061.png) | _ASCII_ _*_ | | | 061 | 0x3D |
| ![ASCII Numbers](/resources/osd/digital/default/24x36/062.png) | _ASCII_ _*_ | | | 062 | 0x3E |
| ![Ah/Nautical Mile](/resources/osd/digital/default/24x36/063.png) | SYM_AH_NM | SYM.AH_NM | Ah per Nautical Mile | 063 | 0x3F |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/064.png) | _ASCII_ _*_ | | Alphabet and symbols | 064 - 095 | 0x40 - 0x5F |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/065.png) | _ASCII_ _*_ | | | 065 | 0x41 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/066.png) | _ASCII_ _*_ | | | 066 | 0x42 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/067.png) | _ASCII_ _*_ | | | 067 | 0x43 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/068.png) | _ASCII_ _*_ | | | 068 | 0x44 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/069.png) | _ASCII_ _*_ | | | 069 | 0x45 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/070.png) | _ASCII_ _*_ | | | 070 | 0x46 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/071.png) | _ASCII_ _*_ | | | 071 | 0x47 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/072.png) | _ASCII_ _*_ | | | 072 | 0x48 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/073.png) | _ASCII_ _*_ | | | 073 | 0x49 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/074.png) | _ASCII_ _*_ | | | 074 | 0x4A |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/075.png) | _ASCII_ _*_ | | | 075 | 0x4B |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/076.png) | _ASCII_ _*_ | | | 076 | 0x4C |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/077.png) | _ASCII_ _*_ | | | 077 | 0x4D |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/078.png) | _ASCII_ _*_ | | | 078 | 0x4E |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/079.png) | _ASCII_ _*_ | | | 079 | 0x4F |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/080.png) | _ASCII_ _*_ | | | 080 | 0x50 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/081.png) | _ASCII_ _*_ | | | 081 | 0x51 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/082.png) | _ASCII_ _*_ | | | 082 | 0x52 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/083.png) | _ASCII_ _*_ | | | 083 | 0x53 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/084.png) | _ASCII_ _*_ | | | 084 | 0x54 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/085.png) | _ASCII_ _*_ | | | 085 | 0x55 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/086.png) | _ASCII_ _*_ | | | 086 | 0x56 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/087.png) | _ASCII_ _*_ | | | 087 | 0x57 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/088.png) | _ASCII_ _*_ | | | 088 | 0x58 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/089.png) | _ASCII_ _*_ | | | 089 | 0x59 |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/090.png) | _ASCII_ _*_ | | | 090 | 0x5A |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/091.png) | _ASCII_ _*_ | | | 091 | 0x5B |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/092.png) | _ASCII_ _*_ | | | 092 | 0x5C |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/093.png) | _ASCII_ _*_ | | | 093 | 0x5D |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/094.png) | _ASCII_ _*_ | | | 094 | 0x5E |
| ![ASCII Alphabet](/resources/osd/digital/default/24x36/095.png) | _ASCII_ _*_ | | | 095 | 0x5F |
| ![mAh per NM](/resources/osd/digital/default/24x36/096-097.png) | SYM_MAH_NM_0 | SYM.MAH_NM_0 | mAh per Nautical mile, left side | 096 | 0x60 |
| | SYM_MAH_NM_1 | SYM.MAH_NM_1 | mAh per Nautical mile, right side | 097 | 0x61 |
| ![milliOhm](/resources/osd/digital/default/24x36/098.png) | SYM_MILLIOHM | SYM.MILLIOHM | MilliOhm symbol | 098 | 0x62 |
| ![Battery Full](/resources/osd/digital/default/24x36/099.png) | SYM_BATT_FULL | SYM.BATT | Battery full | 099 | 0x63 |
| ![Battery 83%](/resources/osd/digital/default/24x36/100.png) | SYM_BATT_5 | | Battery ~83% | 100 | 0x64 |
| ![Battery 67%](/resources/osd/digital/default/24x36/101.png) | SYM_BATT_4 | | Battery ~67% | 101 | 0x65 |
| ![Battery 50%](/resources/osd/digital/default/24x36/102.png) | SYM_BATT_3 | | Battery ~50% | 102 | 0x66 |
| ![Battery 34%](/resources/osd/digital/default/24x36/103.png) | SYM_BATT_2 | | Battery ~34% | 103 | 0x67 |
| ![Battery 17%](/resources/osd/digital/default/24x36/104.png) | SYM_BATT_1 | | Battery ~17% | 104 | 0x68 |
| ![Battery Empty](/resources/osd/digital/default/24x36/105.png) | SYM_BATT_EMPTY | | Battery EMPTY | 105 | 0x69 |
| ![Amps](/resources/osd/digital/default/24x36/106.png) | SYM_AMP | SYM.AMP | Amps symbol | 106 | 0x6A |
| ![mAh per Km](/resources/osd/digital/default/24x36/107-108.png) | SYM_MAH_KM_0 | SYM.MAH_KM_0 | mAh per Kilometre, left side | 107 | 0x6B |
| | SYM_MAH_KM_1 | SYM.MAH_KM_1 | mAh per Kilometre, right side | 108 | 0x6C |
| ![Watt hours](/resources/osd/digital/default/24x36/109.png) | SYM_WH | SYM.WH | Watthours symbol | 109 | 0x6D |
| ![Wh per Km](/resources/osd/digital/default/24x36/110.png) | SYM_WH_KM | SYM.WH_KM | Watthours per Kilometre | 110 | 0x6E |
| ![Wh per Mile](/resources/osd/digital/default/24x36/111.png) | SYM_WH_MI | SYM.WH_MI | Watthours per Mile | 111 | 0x6F |
| ![Wh per NM](/resources/osd/digital/default/24x36/112.png) | SYM_WH_NM | SYM.WH_NM | Watthours per Nautical Mile | 112 | 0x70 |
| ![Watts](/resources/osd/digital/default/24x36/113.png) | SYM_WATT | SYM.WATT | Watts symbol | 113 | 0x71 |
| ![milliWatts](/resources/osd/digital/default/24x36/114.png) | SYM_MW | SYM.MW | Milliwatts symbol | 114 | 0x72 |
| ![kiloWatts](/resources/osd/digital/default/24x36/115.png) | SYM_KILOWATT | | Kilowatts symbol | 115 | 0x73 |
| ![Feet](/resources/osd/digital/default/24x36/116.png) | SYM_FT | | Feet symbol | 116 | 0x74 |
| ![Trip Distance](/resources/osd/digital/default/24x36/117.png) | SYM_TRIP_DIST | SYM.TRIP_DIST | Trip distance | 117 | 0x75 |
| ![Total Distance](/resources/osd/digital/default/24x36/117.png) | SYM_TOTAL | | Total distance | 117 | 0x75 |
| ![Alitiude Metres](/resources/osd/digital/default/24x36/118.png) | SYM_ALT_M | SYM.ALT_M | Alitiude in Metres | 118 | 0x76 |
| ![Altitude Km](/resources/osd/digital/default/24x36/119.png) | SYM_ALT_KM | | Altitude in Kilometres | 119 | 0x77 |
| ![Altitude Ft](/resources/osd/digital/default/24x36/120.png) | SYM_ALT_FT | SYM.ALT_FT | Altitude in Feet | 120 | 0x78 |
| ![Altitude kFt](/resources/osd/digital/default/24x36/121.png) | SYM_ALT_KFT | | Altitude in thousand Feet | 121 | 0x79 |
| ![Distance Metres](/resources/osd/digital/default/24x36/122.png) | SYM_DIST_M | | Distance in Metres | 122 | 0x7A |
| ![ASCII (-)](/resources/osd/digital/default/24x36/123.png) | _ASCII_ _*_ | | Bracket symbols | 123 - 125 | 0x7B - 0x7D |
| ![ASCII (-)](/resources/osd/digital/default/24x36/124.png) | _ASCII_ _*_ | | | 124 | 0x7C |
| ![ASCII (-)](/resources/osd/digital/default/24x36/125.png) | _ASCII_ _*_ | | | 125 | 0x7D |
| ![Distance Km](/resources/osd/digital/default/24x36/126.png) | SYM_DIST_KM | SYM.DIST_KM | Distance in Kilometres | 126 | 0x7E |
| ![Distance Feet](/resources/osd/digital/default/24x36/127.png) | SYM_DIST_FT | | Distance in Feet | 127 | 0x7F |
| ![Distance Miles](/resources/osd/digital/default/24x36/128.png) | SYM_DIST_MI | SYM.DIST_MI | Distance in Miles | 128 | 0x80 |
| ![Distance N Miles](/resources/osd/digital/default/24x36/129.png) | SYM_DIST_NM | SYM.DIST_NM | Distance in Nautical Miles | 129 | 0x81 |
| ![Metres](/resources/osd/digital/default/24x36/130.png) | SYM_M | SYM.M | Metres symbol | 130 | 0x82 |
| ![Kilometres](/resources/osd/digital/default/24x36/131.png) | SYM_KM | | Kilometres symbol | 131 | 0x83 |
| ![Miles](/resources/osd/digital/default/24x36/132.png) | SYM_MI | SYM.MI | Miles symbol | 132 | 0x84 |
| ![Nautical Miles](/resources/osd/digital/default/24x36/133.png) | SYM_NM | SYM.NM | Nautical Miles symbol | 133 | 0x85 |
| ![Horiz Wind Speed](/resources/osd/digital/default/24x36/134.png) | SYM_WIND_HORIZONTAL | SYM.WIND_SPEED_HORIZONTAL | Horizontal wind speed | 134 | 0x86 |
| ![Vert Wind Speed](/resources/osd/digital/default/24x36/135.png) | SYM_WIND_VERTICAL | SYM.WIND_SPEED_VERITCAL | Vertical wind speed | 135 | 0x87 |
| ![3D Speed Km/h](/resources/osd/digital/default/24x36/136.png) | SYM_3D_KMH | SYM.KMH_3D | 3D speed in Kilometres per Hour | 136 | 0x88 |
| ![3D Speed MPH](/resources/osd/digital/default/24x36/137.png) | SYM_3D_MPH | SYM.MPH_3D | 3D speed in Miles per Hour | 137 | 0x89 |
| ![3D Speed Knots](/resources/osd/digital/default/24x36/138.png) | SYM_3D_KT | SYM.KT_3D | 3D speed in Knots | 138 | 0x8A |
| ![RPM](/resources/osd/digital/default/24x36/139.png) | SYM_RPM | SYM.RPM | Revolutions per Minute symbol | 139 | 0x8B |
| ![Air](/resources/osd/digital/default/24x36/140.png) | SYM_AIR | SYM.AIR | Air: Prefix for airspeed sensor | 140 | 0x8C |
| ![Feet per Second](/resources/osd/digital/default/24x36/141.png) | SYM_FTS | SYM.FT_S | Feet per Second | 141 | 0x8D |
| ![100 ft/min](/resources/osd/digital/default/24x36/142.png) | SYM_100FTM | SYM.HUND_FTM | 100 Feet per Minute | 142 | 0x8E |
| ![Metres/Second](/resources/osd/digital/default/24x36/143.png) | SYM_MS | SYM.M_S | Metres per Second | 143 | 0x8F |
| ![Kilometres/hour](/resources/osd/digital/default/24x36/144.png) | SYM_KMH | SYM.KMH | Kilometres per Hour | 144 | 0x90 |
| ![Miles per Hour](/resources/osd/digital/default/24x36/145.png) | SYM_MPH | SYM.MPH | Miles per Hour | 145 | 0x91 |
| ![Knots](/resources/osd/digital/default/24x36/146.png) | SYM_KT | SYM.KT | Knots | 146 | 0x92 |
| ![mAh/mile](/resources/osd/digital/default/24x36/147-148.png) | SYM_MAH_MI_0 | SYM.MAH_MI_0 | mAh per Mile, left side | 147 | 0x93 |
| | SYM_MAH_MI_1 | SYM.MAH_MI_1 | mAh per Mile, right side | 148 | 0x94 |
| ![Throttle symbol](/resources/osd/digital/default/24x36/149.png) | SYM_THR | SYM.THR | Throttle symbol | 149 | 0x95 |
| ![Temp Fahrenheit](/resources/osd/digital/default/24x36/150.png) | SYM_TEMP_F | SYM.TEMP_F | Fahrenheit symbol | 150 | 0x96 |
| ![Temp Celsius](/resources/osd/digital/default/24x36/151.png) | SYM_TEMP_C | SYM.TEMP_C | Celsius symbol | 151 | 0x97 |
| ![Home Point map](/resources/osd/digital/default/24x36/152.png) | _reserved or old ?_ | | Home point map | 152 | 0x98 |
| ![mAh](/resources/osd/digital/default/24x36/153.png) | SYM_MAH | SYM.MAH | mAh sysmbol | 153 | 0x99 |
| ![On Hours](/resources/osd/digital/default/24x36/154.png) | SYM_ON_H | | On hours | 154 | 0x9A |
| ![Flying Hours](/resources/osd/digital/default/24x36/155.png) | SYM_FLY_H | | Flying hours | 155 | 0x9B |
| ![Glide slope](/resources/osd/digital/default/24x36/156.png) | SYM_GLIDESLOPE | SYM.GLIDESLOPE | Glide slope | 156 | 0x9C |
| ![Waypoint](/resources/osd/digital/default/24x36/157.png) | SYM_WAYPOINT | | Waypoint | 157 | 0x9D |
| ![On Minutes](/resources/osd/digital/default/24x36/158.png) | SYM_ON_M | SYM.ON_M | On minutes | 158 | 0x9E |
| ![Flying Minutes](/resources/osd/digital/default/24x36/159.png) | SYM_FLY_M | SYM.FLY_M | Flying minutes | 159 | 0x9F |
| ![Clock](/resources/osd/digital/default/24x36/160.png) | SYM_CLOCK | SYM.CLOCK | Clock | 160 | 0xA0 |
| ![Numbers .](/resources/osd/digital/default/24x36/161.png) | SYM_ZERO_HALF_TRAILING_DOT | SYM.ZERO_HALF_TRAILING_DOT | Numbers with trailing dots | 161 - 170 | 0xA1 - 0xAA |
| ![Numbers .](/resources/osd/digital/default/24x36/162.png) | | | | 162 | 0xA2 |
| ![Numbers .](/resources/osd/digital/default/24x36/163.png) | | | | 163 | 0xA3 |
| ![Numbers .](/resources/osd/digital/default/24x36/164.png) | | | | 164 | 0xA4 |
| ![Numbers .](/resources/osd/digital/default/24x36/165.png) | | | | 165 | 0xA5 |
| ![Numbers .](/resources/osd/digital/default/24x36/166.png) | | | | 166 | 0xA6 |
| ![Numbers .](/resources/osd/digital/default/24x36/167.png) | | | | 167 | 0xA7 |
| ![Numbers .](/resources/osd/digital/default/24x36/168.png) | | | | 168 | 0xA8 |
| ![Numbers .](/resources/osd/digital/default/24x36/169.png) | | | | 169 | 0xA9 |
| ![Numbers .](/resources/osd/digital/default/24x36/170.png) | | | | 170 | 0xAA |
| ![AutoThrottle](/resources/osd/digital/default/24x36/171-172.png) | SYM_AUTO_THR0 | | Auto-throttle symbol, left side | 171 | 0xAB |
| | SYM_AUTO_THR1 | | Auto-throttle symbol, right side | 172 | 0xAC |
| ![Roll Left](/resources/osd/digital/default/24x36/173.png) | SYM_ROLL_LEFT | SYM.ROLL_LEFT | roll left symbol | 173 | 0xAD |
| ![Roll level](/resources/osd/digital/default/24x36/174.png) | SYM_ROLL_LEVEL | SYM.ROLL_LEVEL | roll level symbol | 174 | 0xAE |
| ![Roll Right](/resources/osd/digital/default/24x36/175.png) | SYM_ROLL_RIGHT | SYM.ROLL_RIGHT | roll right symbol | 175 | 0xAF |
| ![Pitch Up](/resources/osd/digital/default/24x36/176.png) | SYM_PITCH_UP | SYM.PITCH_UP | Pitch up symbol | 176 | 0xB0 |
| ![. Numbers](/resources/osd/digital/default/24x36/177.png) | SYM_ZERO_HALF_LEADING_DOT | SYM.ZERO_HALF_LEADING_DOT | Numbers with leading dots | 177 - 186 | 0xB1 - 0xBA |
| ![. Numbers](/resources/osd/digital/default/24x36/178.png) | | | | 178 | 0xB2 |
| ![. Numbers](/resources/osd/digital/default/24x36/179.png) | | | | 179 | 0xB3 |
| ![. Numbers](/resources/osd/digital/default/24x36/180.png) | | | | 180 | 0xB4 |
| ![. Numbers](/resources/osd/digital/default/24x36/181.png) | | | | 181 | 0xB5 |
| ![. Numbers](/resources/osd/digital/default/24x36/182.png) | | | | 182 | 0xB6 |
| ![. Numbers](/resources/osd/digital/default/24x36/183.png) | | | | 183 | 0xB7 |
| ![. Numbers](/resources/osd/digital/default/24x36/184.png) | | | | 184 | 0xB8 |
| ![. Numbers](/resources/osd/digital/default/24x36/185.png) | | | | 185 | 0xB9 |
| ![. Numbers](/resources/osd/digital/default/24x36/186.png) | | | | 186 | 0xBA |
| ![Pitch Down](/resources/osd/digital/default/24x36/187.png) | SYM_PITCH_DOWN | SYM.PITCH_DOWN | Pitch down symbol | 187 | 0xBB |
| ![G-Force](/resources/osd/digital/default/24x36/188.png) | SYM_GFORCE | SYM.GFORCE | Gforce (all axis) | 188 | 0xBC |
| ![G-Force X](/resources/osd/digital/default/24x36/189.png) | SYM_GFORCE_X | SYM.GFORCE_X | Gforce X | 189 | 0xBD |
| ![G-Force Y](/resources/osd/digital/default/24x36/190.png) | SYM_GFORCE_Y | SYM.GFORCE_Y | Gforce Y | 190 | 0xBE |
| ![G-Force Z](/resources/osd/digital/default/24x36/191.png) | SYM_GFORCE_Z | SYM.GFORCE_Z | Gforce Z | 191 | 0xBF |
| ![Baro temp](/resources/osd/digital/default/24x36/192.png) | SYM_BARO_TEMP | SYM.BARO_TEMP | Barometer temperature | 192 | 0xC0 |
| ![IMU temp](/resources/osd/digital/default/24x36/193.png) | SYM_IMU_TEMP | SYM.IMU_TEMP | IMU temperature | 193 | 0xC1 |
| ![Temperature](/resources/osd/digital/default/24x36/194.png) | SYM_TEMP | SYM.TEMP | Thermometer symbol **First symbol** | 194 | 0xC2 |
| ![ESC temp](/resources/osd/digital/default/24x36/195.png) | SYM_ESC_TEMP | SYM.ESC_TEMPERATURE | ESC temperature | 195 | 0xC3 |
| ![ESC temp](/resources/osd/digital/default/24x36/196.png) | | | | 196 | 0xC4 |
| ![ESC temp](/resources/osd/digital/default/24x36/197.png) | | | | 197 | 0xC5 |
| ![ESC temp](/resources/osd/digital/default/24x36/198.png) | | | | 198 | 0xC6 |
| ![ESC temp](/resources/osd/digital/default/24x36/199.png) | | | | 199 | 0xC7 |
| ![Heading N](/resources/osd/digital/default/24x36/200.png) | SYM_HEADING_N | SYM.HEADING_N | Heading graph North | 200 | 0xC8 |
| ![Heading S](/resources/osd/digital/default/24x36/201.png) | SYM_HEADING_S | SYM.HEADING_S | Heading graph South | 201 | 0xC9 |
| ![Heading E](/resources/osd/digital/default/24x36/202.png) | SYM_HEADING_E | SYM.HEADING_E | Heading graph East | 202 | 0xCA |
| ![Heading W](/resources/osd/digital/default/24x36/203.png) | SYM_HEADING_W | SYM.HEADING_W | Heading graph West | 203 | 0xCB |
| ![Heading divider](/resources/osd/digital/default/24x36/204.png) | SYM_HEADING_DIVIDED_LINE | SYM.HEADING_DIVIDED_LINE | Heading graphic | 204 | 0xCC |
| ![Heading line](/resources/osd/digital/default/24x36/205.png) | SYM_HEADING_LINE | SYM.HEADING_LINE | Heading graphic | 205 | 0xCD |
| ![Max](/resources/osd/digital/default/24x36/206.png) | SYM_MAX | SYM.MAX | Max icon | 206 | 0xCE |
| ![Profile](/resources/osd/digital/default/24x36/207.png) | SYM_PROFILE | SYM.PROFILE | Profile icon | 207 | 0xCF |
| ![Switch low](/resources/osd/digital/default/24x36/208.png) | SYM_SWITCH_INDICATOR_LOW | N/A | Switch: down | 208 | 0xD0 |
| ![Switch mid](/resources/osd/digital/default/24x36/209.png) | SYM_SWITCH_INDICATOR_LOW | N/A | Switch: middle | 209 | 0xD1 |
| ![Switch high](/resources/osd/digital/default/24x36/210.png) | SYM_SWITCH_INDICATOR_LOW | SYM.SWITCH_INDICATOR_HIGH | Switch: up | 210 | 0xD2 |
| ![Amp hours](/resources/osd/digital/default/24x36/211.png) | SYM_AH | SYM.AHI | Amp Hours icon | 211 | 0xD3 |
| ![Glide distance](/resources/osd/digital/default/24x36/212.png) | SYM_GLIDE_DIST | SYM.GLIDE_DIST | Glide Distance | 212 | 0xD4 |
| ![Glide time](/resources/osd/digital/default/24x36/213.png) | SYM_GLIDE_MINS | SYM.GLIDE_MINS | Glide Time Mins | 213 | 0xD5 |
| ![Climb eff Ft](/resources/osd/digital/default/24x36/214-215.png) | SYM_AH_V_FT_0 | SYM.AH_V_FT_0 | Climb efficiency: imperial L side | 214 | 0xD6 |
| | SYM_AH_V_FT_1 | SYM.AH_V_FT_1 | Climb efficiency: imperial R side | 215 | 0xD7 |
| ![Climb eff M](/resources/osd/digital/default/24x36/216-217.png) | SYM_AH_V_M_0 | SYM.AH_V_M_0 | Climb efficiency: metric L side | 216 | 0xD8 |
| | SYM_AH_V_M_1 | SYM.AH_V_M_1 | Climb efficiency: metric R side | 217 | 0xD9 |
| ![Flight mins rem](/resources/osd/digital/default/24x36/218.png) | SYM_FLIGHT_MINS_REMAINING | SYM.FLIGHT_MINS_REMAINING | Flight time (mins) remaining | 218 | 0xDA |
| ![Flight hours rem](/resources/osd/digital/default/24x36/219.png) | SYM_FLIGHT_HOURS_REMAINING | | Flight time (hours) remaining | 219 | 0xDB |
| ![Ground course](/resources/osd/digital/default/24x36/220.png) | SYM_GROUND_COURSE | SYM.GROUND_COURSE | Ground course | 220 | 0xDC |
| ![Alert](/resources/osd/digital/default/24x36/221.png) | SYM_ALERT | SYM.ALERT | General Alert | 221 | 0xDD |
| ![Terrain follow](/resources/osd/digital/default/24x36/251.png) | SYM_TERRAIN_FOLLOWING | SYM.TERRAIN_FOLLOWING | Terrain following | 251 | 0xFB |
| ![Cross track err](/resources/osd/digital/default/24x36/252.png) | SYM_CROSS_TRACK_ERROR | SYM.CROSS_TRACK_ERROR | Cross track error | 252 | 0xFC |
| ![ADSB](/resources/osd/digital/default/24x36/253.png) | SYM_ADSB | SYM.ADSB | ADSB | 253 | 0xFD |
| ![Blackbox](/resources/osd/digital/default/24x36/254.png) | SYM_BLACKBOX | SYM.BLACKBOX | Blackbox | 254 | 0xFE |
| | | | | | |
| ![INAV Logo](/resources/osd/digital/default/24x36/257_296.png) | SYM_LOGO_START | | INAV Logo | 257 - 296 | 0x101 - 0x128 |
| ![AH left arrow](/resources/osd/digital/default/24x36/300.png) | SYM_AH_LEFT | SYM.AH_LEFT | AHI Arrow left | 300 | 0x12C |
| ![AH right arrow](/resources/osd/digital/default/24x36/301.png) | SYM_AH_RIGHT | SYM.AH_RIGHT | AHI Arrow right | 301 | 0x12D |
| ![AH scroll sides](/resources/osd/digital/default/24x36/302.png) | SYM_AH_DECORATION_MIN | | AHI Scrolling graphics | 302 - 307 | 0x12E - 0x133 |
| ![AH scroll sides](/resources/osd/digital/default/24x36/303.png) | | | | 303 | 0x12F |
| ![AH scroll sides](/resources/osd/digital/default/24x36/304.png) | | | | 304 | 0x130 |
| ![AH scroll sides](/resources/osd/digital/default/24x36/305.png) | SYM_AH_DECORATION | SYM.AH_DECORATION | AHI Scrolling graphics | 305 | 0x131 |
| ![AH scroll sides](/resources/osd/digital/default/24x36/306.png) | | | | 306 | 0x132 |
| ![AH scroll sides](/resources/osd/digital/default/24x36/307.png) | SYM_AH_DECORATION_MAX | | AHI Scrolling graphics | 307 | 0x133 |
| ![Crosshair left](/resources/osd/digital/default/24x36/314.png) | SYM_AH_CH_LEFT | SYM.AH_CENTER_LINE | Crosshair left | 314 | 0x13A |
| ![Crosshair right](/resources/osd/digital/default/24x36/315.png) | SYM_AH_CH_RIGHT | SYM.AH_CENTER_LINE_RIGHT | Crosshair right | 315 | 0x13B |
| ![Dir arrow 0°](/resources/osd/digital/default/24x36/316.png) | SYM_ARROW_UP | SYM.DIR_TO_HOME | Direction arrow 0° | 316 | 0x13C |
| ![Dir arrow 22.5°](/resources/osd/digital/default/24x36/317.png) | SYM_ARROW_2 | | Direction arrow 22.5° | 317 | 0x13D |
| ![Dir arrow 45°](/resources/osd/digital/default/24x36/318.png) | SYM_ARROW_3 | | Direction arrow 45° | 318 | 0x13E |
| ![Dir arrow 67.5°](/resources/osd/digital/default/24x36/319.png) | SYM_ARROW_4 | | Direction arrow 67.5° | 319 | 0x13F |
| ![Dir arrow 90°](/resources/osd/digital/default/24x36/320.png) | SYM_ARROW_RIGHT | | Direction arrow 90° | 320 | 0x140 |
| ![Dir arrow 112.5°](/resources/osd/digital/default/24x36/321.png) | SYM_ARROW_6 | | Direction arrow 112.5° | 321 | 0x141 |
| ![Dir arrow 135°](/resources/osd/digital/default/24x36/322.png) | SYM_ARROW_7 | | Direction arrow 135° | 322 | 0x142 |
| ![Dir arrow 157.5°](/resources/osd/digital/default/24x36/323.png) | SYM_ARROW_8 | | Direction arrow 157.5° | 323 | 0x143 |
| ![Dir arrow 180°](/resources/osd/digital/default/24x36/324.png) | SYM_ARROW_DOWN | | Direction arrow 180° | 324 | 0x144 |
| ![Dir arrow 202.5°](/resources/osd/digital/default/24x36/325.png) | SYM_ARROW_10 | | Direction arrow 202.5° | 325 | 0x145 |
| ![Dir arrow 225°](/resources/osd/digital/default/24x36/326.png) | SYM_ARROW_11 | | Direction arrow 225° | 326 | 0x146 |
| ![Dir arrow 247.5°](/resources/osd/digital/default/24x36/327.png) | SYM_ARROW_12 | | Direction arrow 247.5° | 327 | 0x147 |
| ![Dir arrow 270°](/resources/osd/digital/default/24x36/328.png) | SYM_ARROW_LEFT | | Direction arrow 270° | 328 | 0x148 |
| ![Dir arrow 292.5°](/resources/osd/digital/default/24x36/329.png) | SYM_ARROW_14 | | Direction arrow 292.5° | 329 | 0x149 |
| ![Dir arrow 315°](/resources/osd/digital/default/24x36/330.png) | SYM_ARROW_15 | | Direction arrow 315° | 330 | 0x14A |
| ![Dir arrow 337.5°](/resources/osd/digital/default/24x36/331.png) | SYM_ARROW_16 | | Direction arrow 337.5° | 331 | 0x14B |
| ![AHI](/resources/osd/digital/default/24x36/332.png) | SYM_AH_H_START | SYM.AH_BAR9_0 | Horizontal AHI | 332 - 340 | 0x14C - 0x154 |
| ![AHI](/resources/osd/digital/default/24x36/333.png) | | | Horizontal AHI | 333 | 0x14D |
| ![AHI](/resources/osd/digital/default/24x36/334.png) | | | Horizontal AHI | 334 | 0x14E |
| ![AHI](/resources/osd/digital/default/24x36/335.png) | | | Horizontal AHI | 335 | 0x14F |
| ![AHI](/resources/osd/digital/default/24x36/336.png) | | | Horizontal AHI | 336 | 0x150 |
| ![AHI](/resources/osd/digital/default/24x36/337.png) | | | Horizontal AHI | 337 | 0x151 |
| ![AHI](/resources/osd/digital/default/24x36/338.png) | | | Horizontal AHI | 338 | 0x152 |
| ![AHI](/resources/osd/digital/default/24x36/339.png) | | | Horizontal AHI | 339 | 0x153 |
| ![AHI](/resources/osd/digital/default/24x36/340.png) | | | Horizontal AHI | 340 | 0x154 |
| ![Vario 2 up](/resources/osd/digital/default/24x36/341.png) | SYM_VARIO_UP_2A | SYM.VARIO_UP_2A | Vario up up | 341 | 0x155 |
| ![Vario 1 up](/resources/osd/digital/default/24x36/342.png) | SYM_VARIO_UP_1A | | Vario up | 342 | 0x156 |
| ![Vario 1 down](/resources/osd/digital/default/24x36/343.png) | SYM_VARIO_DOWN_1A | | Vario down | 343 | 0x157 |
| ![Vario 2 down](/resources/osd/digital/default/24x36/344.png) | SYM_VARIO_DOWN_2A | | Vario down down | 344 | 0x158 |
| ![Altitude](/resources/osd/digital/default/24x36/345.png) | SYM_ALT | | Altitude symbol | 345 | 0x159 |
| ![Vertical AHI](/resources/osd/digital/default/24x36/346.png) | SYM_AH_V_START | | Vertical AHI | 346 - 351 | 0x15A - 0x159 |
| ![Vertical AHI](/resources/osd/digital/default/24x36/347.png) | | | | 347 | 0x15B |
| ![Vertical AHI](/resources/osd/digital/default/24x36/348.png) | | | | 348 | 0x15C |
| ![Vertical AHI](/resources/osd/digital/default/24x36/349.png) | | | | 349 | 0x15D |
| ![Vertical AHI](/resources/osd/digital/default/24x36/350.png) | | | | 350 | 0x15E |
| ![Vertical AHI](/resources/osd/digital/default/24x36/351.png) | | | | 351 | 0x15F |
| ![HUD Signal lost](/resources/osd/digital/default/24x36/352.png) | SYM_HUD_SIGNAL_0 | | HUD signal lost icon | 352 | 0x160 |
| ![HUD Signal 25%](/resources/osd/digital/default/24x36/353.png) | SYM_HUD_SIGNAL_1 | | HUD signal 25% icon | 353 | 0x161 |
| ![HUD Signal 50%](/resources/osd/digital/default/24x36/354.png) | SYM_HUD_SIGNAL_2 | | HUD signal 50% icon | 354 | 0x162 |
| ![HUD Signal 75%](/resources/osd/digital/default/24x36/355.png) | SYM_HUD_SIGNAL_3 | | HUD signal 75% icon | 355 | 0x163 |
| ![HUD Signal 100%](/resources/osd/digital/default/24x36/356.png) | SYM_HUD_SIGNAL_4 | | HUD signal 100% icon | 356 | 0x164 |
| ![Home distance](/resources/osd/digital/default/24x36/357.png) | SYM_HOME_DIST | | Home distance icon | 357 | 0x165 |
| ![Crosshair centre](/resources/osd/digital/default/24x36/358.png) | SYM_AH_CH_CENTER | SYM.AH_CROSSHAIRS | Default crosshair centre | 358 | 0x166 |
| ![Flight dist rem](/resources/osd/digital/default/24x36/359.png) | SYM_FLIGHT_DIST_REMAINING | SYM.FLIGHT_DIST_REMAINING | Flight distance remaining | 359 | 0x167 |
| ![Odometer](/resources/osd/digital/default/24x36/360.png) | SYM_ODOMETER | SYM.ODOMETER | Odometer (total aircraft distance) | 360 | 0x168 |
| ![Crosshair 3](/resources/osd/digital/default/24x36/400_402.png) | SYM_AH_CH_TYPE3 | SYM.AH_CROSSHAIRS | Crosshair type 3 | 400 - 402 | 0x190 - 0x192 |
| ![Crosshair 4](/resources/osd/digital/default/24x36/403_405.png) | SYM_AH_CH_TYPE4 | SYM.AH_CROSSHAIRS | Crosshair type 4 | 403 - 405 | 0x193 - 0x195 |
| ![Crosshair 5](/resources/osd/digital/default/24x36/406_408.png) | SYM_AH_CH_TYPE5 | SYM.AH_CROSSHAIRS | Crosshair type 5 | 406 - 408 | 0x196 - 0x198 |
| ![Crosshair 6](/resources/osd/digital/default/24x36/409_411.png) | SYM_AH_CH_TYPE6 | SYM.AH_CROSSHAIRS | Crosshair type 6 | 409 - 411 | 0x199 - 0x19B |
| ![Crosshair 7](/resources/osd/digital/default/24x36/412_414.png) | SYM_AH_CH_TYPE7 | SYM.AH_CROSSHAIRS | Crosshair type 7 | 412 - 414 | 0x19C - 0x19E |
| ![Crosshair 8](/resources/osd/digital/default/24x36/415_417.png) | SYM_AH_CH_TYPE8 | SYM.AH_CROSSHAIRS | Crosshair type 8 | 415 - 417 | 0x19F - 0x1A1 |
| ![Crosshair 9](/resources/osd/digital/default/24x36/418_422.png) | SYM_AH_CH_AIRCRAFT0 | SYM.AH_AIRCRAFT0 | Aircraft crosshair left | 418 | 0x1A2 |
| | SYM_AH_CH_AIRCRAFT1 | SYM.AH_AIRCRAFT1 | Aircraft crosshair | 419 | 0x1A3 |
| | SYM_AH_CH_AIRCRAFT2 | SYM.AH_AIRCRAFT2 | Aircraft crosshair centre | 420 | 0x1A4 |
| | SYM_AH_CH_AIRCRAFT3 | SYM.AH_AIRCRAFT3 | Aircraft crosshair | 421 | 0x1A5 |
| | SYM_AH_CH_AIRCRAFT4 | SYM.AH_AIRCRAFT4 | Aircraft crosshair right | 422 | 0x1A6 |
| ![HUD Arrows L1](/resources/osd/digital/default/24x36/430.png) | SYM_HUD_ARROWS_L1 | | 1 arrow left | 430 | 0x1AE |
| ![HUD Arrows L2](/resources/osd/digital/default/24x36/431.png) | SYM_HUD_ARROWS_L2 | | 2 arrows left | 431 | 0x1AF |
| ![HUD Arrows L3](/resources/osd/digital/default/24x36/432.png) | SYM_HUD_ARROWS_L3 | | 3 arrows left | 432 | 0x1B0 |
| ![HUD Arrows R1](/resources/osd/digital/default/24x36/433.png) | SYM_HUD_ARROWS_R1 | | 1 arrow right | 433 | 0x1B1 |
| ![HUD Arrows R2](/resources/osd/digital/default/24x36/434.png) | SYM_HUD_ARROWS_R2 | | 2 arrows right | 434 | 0x1B2 |
| ![HUD Arrows R3](/resources/osd/digital/default/24x36/435.png) | SYM_HUD_ARROWS_R3 | | 3 arrows right | 435 | 0x1B3 |
| ![HUD Arrows U1](/resources/osd/digital/default/24x36/436.png) | SYM_HUD_ARROWS_U1 | | 1 arrow up | 436 | 0x1B4 |
| ![HUD Arrows U2](/resources/osd/digital/default/24x36/437.png) | SYM_HUD_ARROWS_U2 | | 2 arrows up | 437 | 0x1B5 |
| ![HUD Arrows U3](/resources/osd/digital/default/24x36/438.png) | SYM_HUD_ARROWS_U3 | | 3 arrows up | 438 | 0x1B6 |
| ![HUD Arrows D1](/resources/osd/digital/default/24x36/439.png) | SYM_HUD_ARROWS_D1 | | 1 arrow down | 439 | 0x1B7 |
| ![HUD Arrows D2](/resources/osd/digital/default/24x36/440.png) | SYM_HUD_ARROWS_D2 | | 2 arrows down | 440 | 0x1B8 |
| ![HUD Arrows D3](/resources/osd/digital/default/24x36/441.png) | SYM_HUD_ARROWS_D3 | | 3 arrows down | 441 | 0x1B9 |
| ![Cardinal S](/resources/osd/digital/default/24x36/442.png) | SYM_HUD_CARDINAL | | Cardinal indicators | 442 - 453 | 0x1BA - 0x1C5 |
| ![Cardinal S](/resources/osd/digital/default/24x36/443.png) | | | | 443 | 0x1BB |
| ![Cardinal S](/resources/osd/digital/default/24x36/444.png) | | | | 444 | 0x1BC |
| ![Cardinal S](/resources/osd/digital/default/24x36/445.png) | | | | 445 | 0x1BD |
| ![Cardinal S](/resources/osd/digital/default/24x36/446.png) | | | | 446 | 0x1BE |
| ![Cardinal S](/resources/osd/digital/default/24x36/447.png) | | | | 447 | 0x1BF |
| ![Cardinal S](/resources/osd/digital/default/24x36/448.png) | | | | 448 | 0x1C0 |
| ![Cardinal S](/resources/osd/digital/default/24x36/449.png) | | | | 449 | 0x1C1 |
| ![Cardinal S](/resources/osd/digital/default/24x36/450.png) | | | | 450 | 0x1C2 |
| ![Cardinal S](/resources/osd/digital/default/24x36/451.png) | | | | 451 | 0x1C3 |
| ![Cardinal S](/resources/osd/digital/default/24x36/452.png) | | | | 452 | 0x1C4 |
| ![Cardinal S](/resources/osd/digital/default/24x36/453.png) | | | | 453 | 0x1C5 |
| ![Pan centred](/resources/osd/digital/default/24x36/454.png) | SYM_SERVO_PAN_IS_CENTRED | | Pan servo is centred | 454 | 0x1C6 |
| ![Pan Left](/resources/osd/digital/default/24x36/455.png) | SYM_SERVO_PAN_IS_OFFSET_L | SYM.PAN_SERVO_IS_OFFSET_L | Pan servo is moved to the left | 455 | 0x1C7 |
| ![Pan Right](/resources/osd/digital/default/24x36/456.png) | SYM_SERVO_PAN_IS_OFFSET_R | | Pan servo is moved to the right | 456 | 0x1C8 |
| ![Pilot Logo S](/resources/osd/digital/default/24x36/469_471.png) | SYM_PILOT_LOGO_SML_L | SYM.PILOT_LOGO_SML_L | Small Pilot logo | 469 - 471 | 0x1D5 - 0x1D7 |
| ![Pilot Logo L](/resources/osd/digital/default/24x36/472_511.png) | SYM_PILOT_LOGO_LRG_START | | Large Pilot logo | 472 - 511 | 0x1D5 - 0x1D7 |
_*_ Do not change the IDs of these characters

View file

@ -3,7 +3,10 @@
This directory contains one directory per font. In each
directory, each character is named `%d%d%d.png`, where
the digits represent the decimal character number found
in the filename without the extension.
in the filename without the extension. All characters
must be in the `default` font directory. If characters
missing from alternate font directories, the default
version of the character will be used.
Don't alter the `.mcm` files directly, those should be
only modified by altering the `.png` files found in its

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

Before

Width:  |  Height:  |  Size: 216 B

After

Width:  |  Height:  |  Size: 216 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 238 B

After

Width:  |  Height:  |  Size: 238 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 230 B

After

Width:  |  Height:  |  Size: 230 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 231 B

After

Width:  |  Height:  |  Size: 231 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 239 B

After

Width:  |  Height:  |  Size: 239 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 180 B

After

Width:  |  Height:  |  Size: 180 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 160 B

After

Width:  |  Height:  |  Size: 160 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 452 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 201 B

After

Width:  |  Height:  |  Size: 201 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 242 B

After

Width:  |  Height:  |  Size: 242 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 227 B

After

Width:  |  Height:  |  Size: 227 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 324 B

After

Width:  |  Height:  |  Size: 324 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 272 B

After

Width:  |  Height:  |  Size: 272 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 234 B

After

Width:  |  Height:  |  Size: 234 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 255 B

After

Width:  |  Height:  |  Size: 255 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 250 B

After

Width:  |  Height:  |  Size: 250 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 259 B

After

Width:  |  Height:  |  Size: 259 B

Before After
Before After

Some files were not shown because too many files have changed in this diff Show more