diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..d29547895 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,185 @@ +name: Build Configurator +# Don't enable CI on push, just on PR. If you +# are working on the main repo and want to trigger +# a CI build submit a draft PR. +on: pull_request + +jobs: + build-linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup environment + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + run: | + # This is the hash of the commit for the PR + # when the action is triggered by PR, empty otherwise + COMMIT_ID=${{ github.event.pull_request.head.sha }} + # This is the hash of the commit when triggered by push + # but the hash of refs/pull//merge, which is different + # from the hash of the latest commit in the PR, that's + # why we try github.event.pull_request.head.sha first + COMMIT_ID=${COMMIT_ID:-${{ github.sha }}} + BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID}) + VERSION=$(grep version package.json | sed 's/.*"\([0-9][0-9]*.[0-9]*.[0-9]*\)".*/\1/g') + echo "ACTIONS_STEP_DEBUG=true" >> $GITHUB_ENV + echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV + echo "BUILD_NAME=inav-configurator_linux_x64_${VERSION}_${BUILD_SUFFIX}" >> $GITHUB_ENV + - uses: actions/setup-node@v4 + with: + node-version: 20 + check-latest: true + cache: 'npm' + - name: Install dependencies + run: sudo apt-get update && sudo apt-get -y install dpkg fakeroot rpm build-essential libudev-dev + - name: Install deps + uses: nick-fields/retry@v2 + with: + max_attempts: 3 + retry_on: error + command: npm install + timeout_minutes: 10 + - name: Build Linux + run: npm run make + - name: Upload Linux deb + uses: actions/upload-artifact@v3 + with: + name: ${{ env.BUILD_NAME }}_DEB + path: ./out/make/deb/x64/*.deb + - name: Upload Linux rpm + uses: actions/upload-artifact@v3 + with: + name: ${{ env.BUILD_NAME }}_RPM + path: ./out/make/rpm/x64/*.rpm + - name: Upload Linux zip + uses: actions/upload-artifact@v3 + with: + name: ${{ env.BUILD_NAME }}_ZIP + path: ./out/make/zip/linux/x64/*.zip + build-mac: + runs-on: macos-13 + steps: + - uses: actions/checkout@v4 + - name: Setup environment + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + run: | + # This is the hash of the commit for the PR + # when the action is triggered by PR, empty otherwise + COMMIT_ID=${{ github.event.pull_request.head.sha }} + # This is the hash of the commit when triggered by push + # but the hash of refs/pull//merge, which is different + # from the hash of the latest commit in the PR, that's + # why we try github.event.pull_request.head.sha first + COMMIT_ID=${COMMIT_ID:-${{ github.sha }}} + BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID}) + VERSION=$(grep version package.json | sed 's/.*"\([0-9][0-9]*.[0-9]*.[0-9]*\)".*/\1/g') + echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV + echo "BUILD_NAMEx64=inav-configurator_darwin_x64_${VERSION}_${BUILD_SUFFIX}" >> $GITHUB_ENV + echo "BUILD_NAMEarm64=inav-configurator_darwin_arm64_${VERSION}_${BUILD_SUFFIX}" >> $GITHUB_ENV + - uses: actions/setup-node@v4 + with: + node-version: 20 + check-latest: true + cache: 'npm' + # Workaround due to a bug in node-gyp: https://github.com/electron/rebuild/issues/1116 + - name: Install Setuptools + run: python3 -m pip install --break-system-packages setuptools + - name: Install deps + uses: nick-fields/retry@v2 + with: + max_attempts: 3 + retry_on: error + command: npm install + timeout_minutes: 10 + - name: Build MacOS x64 + run: npm run make -- --arch="x64" + - name: Build MacOS arm64 + run: npm run make -- --arch="arm64" + - name: Upload MacOS x64 zip + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_NAMEx64}}_ZIP + path: ./out/make/zip/darwin/x64/*.zip + - name: Upload MacOS x64 dmg + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_NAMEx64}}_DMG + path: ./out/make/*x64*.dmg + - name: Upload MacOS arm64 zip + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_NAMEarm64}}_ZIP + path: ./out/make/zip/darwin/arm64/*.zip + - name: Upload MacOS arm64 dmg + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_NAMEarm64}}_DMG + path: ./out/make/*arm64*.dmg + build-windows: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Install linux utils + run: choco install --force -y awk grep sed + - name: Setup environment + env: + ACTIONS_ALLOW_UNSECURE_COMMANDS: true + run: | + # This is the hash of the commit for the PR + # when the action is triggered by PR, empty otherwise + COMMIT_ID=${{ github.event.pull_request.head.sha }} + # This is the hash of the commit when triggered by push + # but the hash of refs/pull//merge, which is different + # from the hash of the latest commit in the PR, that's + # why we try github.event.pull_request.head.sha first + COMMIT_ID=${COMMIT_ID:-${{ github.sha }}} + BUILD_SUFFIX=ci-$(date '+%Y%m%d')-$(git rev-parse --short ${COMMIT_ID}) + VERSION=$(grep version package.json | sed 's/.*"\([0-9][0-9]*.[0-9]*.[0-9]*\)".*/\1/g') + echo "ACTIONS_STEP_DEBUG=true" >> $GITHUB_ENV + echo "BUILD_SUFFIX=${BUILD_SUFFIX}" >> $GITHUB_ENV + echo "BUILD_NAMEx64=inav-configurator_win32_x64_${VERSION}_${BUILD_SUFFIX}" >> $GITHUB_ENV + echo "BUILD_NAMEia32=inav-configurator_win32_ia32_${VERSION}_${BUILD_SUFFIX}" >> $GITHUB_ENV + shell: bash + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'npm' + - uses: engineerd/configurator@v0.0.10 + with: + name: "Wix Toolset 3.1.4" + url: "https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip" + pathInArchive: "/" + - name: Install deps + uses: nick-fields/retry@v2 + with: + max_attempts: 3 + retry_on: error + command: npm install + timeout_minutes: 10 + - name: Build Win32 x64 + run: npm run make -- --arch="x64" + - name: Build win32 ia32 + run: npm run make -- --arch="ia32" + - name: Upload Windows x64 zip + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_NAMEx64}}_ZIP + path: ./out/make/zip/win32/x64/*.zip + - name: Upload Windows x64 msi + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_NAMEx64}}_MSI + path: ./out/make/wix/x64/*.msi + - name: Upload Windows ia32 zip + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_NAMEia32}}_ZIP + path: ./out/make/zip/win32/ia32/*.zip + - name: Upload Windows ia32 msi + uses: actions/upload-artifact@v4 + with: + name: ${{env.BUILD_NAMEia32}}_MSI + path: ./out/make/wix/ia32/*.msi + \ No newline at end of file diff --git a/.gitignore b/.gitignore index ec45237d6..fc5c7174c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,14 +5,6 @@ npm-debug.log .idea/ npm-debug.log inav-configurator.iml -# Generated scripts and styles -/build -# Used by nw-builder to download runtimes -/cache -# Where we put the final app directory structure -/dist -# Path where the NW.js apps get built -/apps -/.vscode/ -.eslintrc.json -/.project +/out +.eslintrc.json +/.project diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..f8efa898f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Debug Configurator", + "runtimeExecutable": "${workspaceFolder}/node_modules/@electron-forge/cli/script/vscode.sh", + "windows": { + "runtimeExecutable": "${workspaceFolder}/node_modules/@electron-forge/cli/script/vscode.cmd", + + }, + "args": ["--inspect"], + "env": { + "NODE_ENV": "development", + "NODE_PATH": "${workspaceFolder}/js/" + }, + "cwd": "${workspaceFolder}", + "console": "integratedTerminal" + } + ] + } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..889586c40 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,16 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "npm", + "script": "start", + "problemMatcher": [], + "label": "npm: start", + "detail": "node node_modules/gulp/bin/gulp.js build && node node_modules/nw/bin/nw .", + "group": { + "kind": "build", + "isDefault": true + } + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md index d84f356d8..7394edaf8 100644 --- a/README.md +++ b/README.md @@ -18,40 +18,34 @@ everything, the hardware is not working, or you have any other _support_ problem * [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 starts minimized, what should I do? - -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 the `post_install_cleanup.ps1` script that will do the cleaning. (thank you, James Cherrill) - ## Installation -Depending on the target operating system, _INAV Configurator_ is distributed as a _standalone_ application or Chrome App. + _INAV Configurator_ is distributed as a _standalone_ application. ### 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 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 +2. Download Configurator for Windows platform (ia32 or win64 is present) +3. Install + * Extract ZIP archive and run the INAV Configurator app from the unpacked folder + * OR just use the setup program `INAV-Configurator_win32_arch_x.y.z.msi`, **arch** is your computer architecture (ia32 (32bit) or x64 (64bit)), **x.y.z** is the INAV Configurator version number. + +4. 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) -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 +2. Download Configurator for Linux platform (only linux64 is present) + * **.rpm** is the Fedora installation file. Just download and install using `sudo dnf localinstall /path/to/INAV-Configurator_linux_x64-x.y.z.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_linux_x64_x.y.z.deb` or open it with a package manager (e.g. via the File Manager) + * **.zip** is a universal archive. Download and continue with these instructions to install +3. Change to the directory containing the downloaded **zip** 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 +5. Extract **zip** archive ``` -tar -C /tmp/ -xf INAV-Configurator_linuxNN_x.y.z.tar.gz +unzip INAV-Configurator_linux_arch_x.y.z.zip -d /tmp/ ``` - **NN** is the bits of your OS. **x.y.z** is the INAV Configurator version number. + **arch** is your computer architecture (x64, armv7l, ...), **x.y.z** is the INAV Configurator version number. 6. If this is the first time installing INAV Configurator, create a home for its files ``` @@ -73,26 +67,15 @@ 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 the Mac platform -1. Extract ZIP archive -1. Run INAV Configurator +2. Download Configurator for the Mac platform +3. Install + * Extract ZIP archive and run INAV Configurator + * OR use the DMG package for installation ## Building and running INAV Configurator locally (for development) @@ -100,30 +83,39 @@ For local development, the **node.js** build system is used. 1. Install node.js 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. +1. To build the and start the configurator: + - Run `npm start`. + +To build the App run `npm run make` to build for your platform. + +Options: +* Architecture: --arch - Allowed values are: "ia32", "x64", "armv7l", "arm64", "universal", or "mips64el". -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: +See [Electron Forge CLI Documentation](https://www.electronforge.io/cli#options-2) for details -- **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 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. -
`--installer` argument can be added to build installers for a particular OS. NOTE: MacOS Installer can be built with MacOS only. +Note: Not all architectures are available for all platforms. For example, ia32 (32bit) support is not available for Linux. +Tested architectures: +- Windows: x64 and ia32 +- Linux: x64 and armv7l +- MacOS: x64 and arm64 -To build a specific release, use the command `release --platform="win64"` for example. +To build the setup program for windows, you have to install [WiX Toolset V3](https://github.com/wixtoolset/wix3/releases) and add the `bin` folder to you `PATH`, e.g. +```C:\Program Files (x86)\WiX Toolset v3.14\bin``` + +To build deb and rpm packages for Linux, you have to install the following packages: +- Ubuntu/Debian: `dpkg, fakeroot, rpm, build-essential, libudev-dev` +- OpenSuse/Fedora: `dpkg, fakeroot, rpmbuild, systemd-devel, devel-basis (zypper install -t pattern devel_basis), zip` + +Example (note the double -- ): +```npm run make -- --arch="x64"``` ### Running with debug | Inspector -To be able to open Inspector, you will need SDK flavours of NW.js +To be able to open Inspector, set envorinment variable `NODE_ENV` to `develpoment` or set the flag directly when run `npm start`: + +```NODE_ENV=development npm start``` or ```$env:NODE_ENV="development" | npm start``` for Windows PowerShell -`npm install nw@0.61.0 --nwjs_build_type=sdk` +Or use vscode and start a debug session `Debug Configurator` (Just hit F5!) ## Different map providers diff --git a/_config.yml b/_config.yml deleted file mode 100644 index c74188174..000000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-slate \ No newline at end of file diff --git a/assets/linux/inav-configurator.desktop b/assets/linux/inav-configurator.desktop index 40b0c778d..3b8124bcd 100644 --- a/assets/linux/inav-configurator.desktop +++ b/assets/linux/inav-configurator.desktop @@ -2,7 +2,7 @@ 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 +Icon=/opt/inav/inav-configurator/resources/app/assets/linux/icon/inav_icon_128.png Terminal=false Type=Application Categories=Utility \ No newline at end of file diff --git a/assets/windows/background.jpg b/assets/windows/background.jpg new file mode 100644 index 000000000..6e044d5b6 Binary files /dev/null and b/assets/windows/background.jpg differ diff --git a/assets/windows/banner.jpg b/assets/windows/banner.jpg new file mode 100644 index 000000000..66c3f04f8 Binary files /dev/null and b/assets/windows/banner.jpg differ diff --git a/assets/windows/inav_installer.bmp b/assets/windows/inav_installer.bmp deleted file mode 100644 index d65f39407..000000000 Binary files a/assets/windows/inav_installer.bmp and /dev/null differ diff --git a/assets/windows/inav_installer_small.bmp b/assets/windows/inav_installer_small.bmp deleted file mode 100644 index 535303fb4..000000000 Binary files a/assets/windows/inav_installer_small.bmp and /dev/null differ diff --git a/assets/windows/installer.iss b/assets/windows/installer.iss deleted file mode 100644 index 89f56efa7..000000000 --- a/assets/windows/installer.iss +++ /dev/null @@ -1,169 +0,0 @@ -; ------------------------------------------ -; 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; \ No newline at end of file diff --git a/assets/windows/wix.xml b/assets/windows/wix.xml new file mode 100644 index 000000000..acace5f6e --- /dev/null +++ b/assets/windows/wix.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/eventPage.js b/eventPage.js deleted file mode 100755 index 2843cdbf0..000000000 --- a/eventPage.js +++ /dev/null @@ -1,117 +0,0 @@ -/* - If an id is also specified and a window with a matching id has been shown before, the remembered bounds of the window will be used instead. -*/ -'use strict'; - -function startApplication() { - var applicationStartTime = new Date().getTime(); - - chrome.app.window.create('main.html', { - id: 'main-window', - frame: 'chrome', - innerBounds: { - minWidth: 1024, - minHeight: 550 - } - }, function (createdWindow) { - createdWindow.contentWindow.addEventListener('load', function () { - createdWindow.contentWindow.catch_startup_time(applicationStartTime); - }); - - createdWindow.onClosed.addListener(function () { - // automatically close the port when application closes - // save connectionId in separate variable before createdWindow.contentWindow is destroyed - var connectionId = createdWindow.contentWindow.CONFIGURATOR.connection.connectionId, - valid_connection = createdWindow.contentWindow.CONFIGURATOR.connectionValid, - mincommand = createdWindow.contentWindow.MISC.mincommand; - - console.log("EP:" + connectionId); - if (connectionId && valid_connection) { - // code below is handmade MSP message (without pretty JS wrapper), it behaves exactly like MSP.send_message - // sending exit command just in case the cli tab was open. - // reset motors to default (mincommand) - - var bufferOut = new ArrayBuffer(5), - bufView = new Uint8Array(bufferOut); - - bufView[0] = 0x65; // e - bufView[1] = 0x78; // x - bufView[2] = 0x69; // i - bufView[3] = 0x74; // t - bufView[4] = 0x0D; // enter - - chrome.serial.send(connectionId, bufferOut, function () { console.log('Send exit') }); - - setTimeout(function() { - bufferOut = new ArrayBuffer(22); - bufView = new Uint8Array(bufferOut); - var checksum = 0; - - bufView[0] = 36; // $ - bufView[1] = 77; // M - bufView[2] = 60; // < - bufView[3] = 16; // data length - bufView[4] = 214; // MSP_SET_MOTOR - - checksum = bufView[3] ^ bufView[4]; - - for (var i = 0; i < 16; i += 2) { - bufView[i + 5] = mincommand & 0x00FF; - bufView[i + 6] = mincommand >> 8; - - checksum ^= bufView[i + 5]; - checksum ^= bufView[i + 6]; - } - - bufView[5 + 16] = checksum; - - chrome.serial.send(connectionId, bufferOut, function (sendInfo) { - chrome.serial.disconnect(connectionId, function (result) { - console.log('SERIAL: Connection closed - ' + result); - }); - }); - }, 100); - } else if (connectionId) { - chrome.serial.disconnect(connectionId, function (result) { - console.log('SERIAL: Connection closed - ' + result); - }); - } - }); - }); -} - -chrome.app.runtime.onLaunched.addListener(startApplication); - -chrome.runtime.onInstalled.addListener(function (details) { - if (details.reason == 'update') { - var previousVersionArr = details.previousVersion.split('.'), - currentVersionArr = chrome.runtime.getManifest().version.split('.'); - - // only fire up notification sequence when one of the major version numbers changed - if (currentVersionArr[0] > previousVersionArr[0] || currentVersionArr[1] > previousVersionArr[1]) { - chrome.storage.local.get('update_notify', function (result) { - if (result.update_notify === 'undefined' || result.update_notify) { - var manifest = chrome.runtime.getManifest(); - var options = { - priority: 0, - type: 'basic', - title: manifest.name, - message: chrome.i18n.getMessage('notifications_app_just_updated_to_version', [manifest.version]), - iconUrl: '/images/icon_128.png', - buttons: [{'title': chrome.i18n.getMessage('notifications_click_here_to_start_app')}] - }; - - chrome.notifications.create('baseflight_update', options, function (notificationId) { - // empty - }); - } - }); - } - } -}); - -chrome.notifications.onButtonClicked.addListener(function (notificationId, buttonIndex) { - if (notificationId == 'baseflight_update') { - startApplication(); - } -}); \ No newline at end of file diff --git a/forge.config.js b/forge.config.js new file mode 100644 index 000000000..223287f53 --- /dev/null +++ b/forge.config.js @@ -0,0 +1,114 @@ +const path = require('path'); +const fs = require('fs'); + +module.exports = { + packagerConfig: { + executableName: "inav-configurator", + asar: false, + icon: 'images/inav', + ignore: [ + "^(\/\.vscode$)", + "^(\/support$)", + ".gitattributes", + ".gitignore", + "3D_model_creation.md", + "LICENSE", + "MAPPROXY.md", + "package-lock.json", + "README.md", + "inav_icon_128.psd", + ] + }, + hooks: { + // Uniform artifact file names + postMake: async (config, makeResults) => { + makeResults.forEach(result => { + var baseName = `${result.packageJSON.productName.replace(' ', '-')}_${result.platform}_${result.arch}_${result.packageJSON.version}`; + result.artifacts.forEach(artifact => { + var artifactStr = artifact.toString(); + var newPath = path.join(path.dirname(artifactStr), baseName + path.extname(artifactStr)); + fs.renameSync(artifactStr, newPath); + console.log('Artifact: ' + newPath); + }); + }); + } + }, + rebuildConfig: {}, + makers: [ + { + name: '@electron-forge/maker-wix', + config: { + name: "INAV Configurator", + shortName: "INAV", + exe: "inav-configurator", + description: "Configurator for the open source flight controller software INAV.", + programFilesFolderName: "inav-configurator", + shortcutFolderName: "INAV", + manufacturer: "The INAV open source project", + appUserModelId: "com.inav.configurator", + icon: path.join(__dirname, "./assets/windows/inav_installer_icon.ico"), + upgradeCode: "13606ff3-b0bc-4dde-8fac-805bc8aed2f8", + ui : { + enabled: false, + chooseDirectory: true, + images: { + background: path.join(__dirname, "./assets/windows/background.jpg"), + banner: path.join(__dirname, "./assets/windows/banner.jpg") + } + }, + // Standard WiX template appends the unsightly "(Machine - WSI)" to the name, so use our own template + beforeCreate: (msiCreator) => { + return new Promise((resolve, reject) => { + fs.readFile(path.join(__dirname,"./assets/windows/wix.xml"), "utf8" , (err, content) => { + if (err) { + reject (err); + } + msiCreator.wixTemplate = content; + resolve(); + }); + }); + } + } + }, + { + name: '@electron-forge/maker-dmg', + config: { + name: "INAV Configurator", + background: "./assets/osx/dmg-background.png", + icon: "./images/inav.icns" + } + }, + { + name: '@electron-forge/maker-zip', + platforms: ['win32', 'linux', 'darwin'], + }, + { + name: '@electron-forge/maker-deb', + config: { + options: { + name: "inav-configurator", + productName: "INAV Configurator", + categories: ["Utility"], + icon: "./assets/linux/icon/inav_icon_128.png", + description: "Configurator for the open source flight controller software INAV.", + homepage: "https://github.com/inavflight/", + + } + }, + }, + { + name: '@electron-forge/maker-rpm', + config: { + options: { + name: "inav-configurator", + productName: "INAV Configurator", + license: "GPL-3.0", + categories: ["Utility"], + icon: "./assets/linux/icon/inav_icon_128.png", + description: "Configurator for the open source flight controller software INAV.", + homepage: "https://github.com/inavflight/", + } + }, + }, + ], +}; diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index f2e68d805..000000000 --- a/gulpfile.js +++ /dev/null @@ -1,751 +0,0 @@ -'use strict'; - -var child_process = require('child_process'); -var fs = require('fs'); -var path = require('path'); -var minimist = require('minimist'); - -var archiver = require('archiver'); -var del = require('del'); -var NwBuilder = require('nw-builder'); -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* -// must be also present in *output*, whose value indicates -// the filename for the output file which combines the -// contents of the source files. -// -// Keys must be camel cased and end with either 'Css' or -// 'Js' (e.g. someSourcesCss or someSourcesJs). For each -// key, a build task will be generated named by prepending -// 'build-' and converting the key to dash-separated words -// (e.g. someSourcesCss will generate build-some-sources-css). -// -// Tasks with names ending with '-js' will be executed by the -// build-all-js task, while the ones ending with '-css' will -// be done by build-all-css. There's also a build task which -// runs both build-all-css and build-all-js. -// -// The watch task will monitor any files mentioned in the *sources* -// variable and regenerate the corresponding output file when -// they change. -// -// See README.md for details on the other tasks. - -var sources = {}; - -sources.css = [ - './main.css', - './js/libraries/jquery.nouislider.min.css', - './js/libraries/jquery.nouislider.pips.min.css', - './js/libraries/flightindicators.css', - './src/css/tabs/*.css', - './src/css/opensans_webfontkit/fonts.css', - './src/css/font-awesome/css/font-awesome.css', - './src/css/dropdown-lists/css/style_lists.css', - './js/libraries/switchery/switchery.css', - './js/libraries/jbox/jBox.css', - './node_modules/openlayers/dist/ol.css', - './src/css/logic.css', - './src/css/defaults_dialog.css', -]; - -sources.js = [ - './js/libraries/google-analytics-bundle.js', - './node_modules/jquery/dist/jquery.min.js', - './node_modules/jquery-ui-npm/jquery-ui.min.js', - './node_modules/marked/lib/marked.js', - './js/libraries/d3.min.js', - './js/libraries/jquery.nouislider.all.min.js', - './node_modules/three/build/three.min.js', - './node_modules/three/examples/js/loaders/GLTFLoader.js', - './node_modules/three/examples/js/controls/OrbitControls.js', - './js/libraries/nw-dialog.js', - './js/libraries/bundle_xml2js.js', - './js/libraries/Projector.js', - './js/libraries/CanvasRenderer.js', - './js/libraries/jquery.flightindicators.js', - './js/libraries/semver.js', - './js/libraries/jbox/jBox.min.js', - './js/libraries/switchery/switchery.js', - './js/libraries/jquery.ba-throttle-debounce.js', - './js/helpers.js', - './node_modules/inflection/inflection.min.js', - './node_modules/bluebird/js/browser/bluebird.min.js', - './js/injected_methods.js', - './js/intervals.js', - './js/timeouts.js', - './js/pid_controller.js', - './js/simple_smooth_filter.js', - './js/walking_average_filter.js', - './js/gui.js', - './js/msp/MSPCodes.js', - './js/msp/MSPHelper.js', - './js/msp/MSPchainer.js', - './js/port_handler.js', - './js/connection/connection.js', - './js/connection/connectionBle.js', - './js/connection/connectionSerial.js', - './js/connection/connectionTcp.js', - './js/connection/connectionUdp.js', - './js/servoMixRule.js', - './js/motorMixRule.js', - './js/logicCondition.js', - './js/settings.js', - './js/outputMapping.js', - './js/model.js', - './js/serial_backend.js', - './js/data_storage.js', - './js/fc.js', - './js/msp.js', - './js/protocols/stm32.js', - './js/protocols/stm32usbdfu.js', - './js/localization.js', - './js/boards.js', - './js/servoMixerRuleCollection.js', - './js/motorMixerRuleCollection.js', - './js/logicConditionsCollection.js', - './js/logicConditionsStatus.js', - './js/globalVariablesStatus.js', - './js/programmingPid.js', - './js/programmingPidCollection.js', - './js/programmingPidStatus.js', - './js/vtx.js', - './main.js', - './js/tabs.js', - './tabs/*.js', - './js/eventFrequencyAnalyzer.js', - './js/periodicStatusUpdater.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', - './js/defaults_dialog.js', - './js/safehomeCollection.js', - './js/safehome.js', - './js/waypointCollection.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', - './js/fwApproach.js', - './js/fwApproachCollection.js' -]; - -sources.receiverCss = [ - './src/css/tabs/receiver_msp.css', - './src/css/opensans_webfontkit/fonts.css', - './js/libraries/jquery.nouislider.min.css', - './js/libraries/jquery.nouislider.pips.min.css', -]; - -sources.receiverJs = [ - './node_modules/jquery/dist/jquery.min.js', - './node_modules/jquery-ui-npm/jquery-ui.min.js', - './js/libraries/jquery.nouislider.all.min.js', - './tabs/receiver_msp.js' -]; - -sources.debugTraceJs = [ - './js/debug_trace.js' -]; - -sources.hexParserJs = [ - './js/workers/hex_parser.js', -]; - -var output = { - css: 'styles.css', - js: 'script.js', - receiverCss: 'receiver-msp.css', - receiverJs: 'receiver-msp.js', - debugTraceJs: 'debug-trace.js', - hexParserJs: 'hex_parser.js', -}; - - -var outputDir = './build/'; -var distDir = './dist/'; -var appsDir = './apps/'; - -function get_task_name(key) { - return 'build-' + key.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();}); -} - -function getArguments() { - return minimist(process.argv.slice(2)); -} - -function getPlatforms() { - const defaultPlatforms = ['win32', 'win64', 'osx64', 'linux32', 'linux64']; - const platform = getArguments().platform; - if (platform) { - if (defaultPlatforms.indexOf(platform) < 0) { - throw new Error(`Invalid platform "${platform}". Available ones are: ${defaultPlatforms}`) - } - return [platform]; - } - return defaultPlatforms; -} - -function execSync() { - const cmd = arguments[0]; - const args = Array.prototype.slice.call(arguments, 1); - const result = child_process.spawnSync(cmd, args, {stdio: 'inherit'}); - if (result.error) { - throw result.error; - } -} - -// Define build tasks dynamically based on the sources -// and output variables. -var buildCssTasks = []; -var buildJsTasks = []; -(function() { - // Convers fooBarBaz to foo-bar-baz - for (var k in output) { - (function (key) { - var name = get_task_name(key); - if (name.endsWith('-css')) { - buildCssTasks.push(name); - } else if (name.endsWith('-js')) { - buildJsTasks.push(name); - } else { - throw 'Invalid task name: "' + name + '": must end with -css or -js'; - } - gulp.task(name, function() { - return gulp.src(sources[key]) - .pipe(concat(output[key])) - .pipe(gulp.dest(outputDir)); - }); - })(k); - } -})(); - -gulp.task('build-all-js', gulp.parallel(buildJsTasks)) -gulp.task('build-all-css', gulp.parallel(buildCssTasks)); -gulp.task('build', gulp.parallel('build-all-css', 'build-all-js')); - -gulp.task('clean', function() { return del(['./build/**', './dist/**'], {force: true}); }); - -// Real work for dist task. Done in another task to call it via -// run-sequence. -gulp.task('dist-build', gulp.series('build', function() { - var distSources = [ - './package.json', // For NW.js - './manifest.json', // For Chrome app - './eventPage.js', - './*.html', - './tabs/*.html', - './images/**/*', - './_locales/**/*', - './build/*', - './src/css/font-awesome/webfonts/*', - './src/css/opensans_webfontkit/*.{eot,svg,ttf,woff,woff2}', - './resources/*.json', - './resources/models/*', - './resources/osd/analogue/*.mcm', - './resources/motor_order/*.svg', - './resources/sitl/windows/*', - './resources/sitl/linux/*' - ]; - return gulp.src(distSources, { base: '.' }) - .pipe(gulp.dest(distDir)); -})); - -gulp.task('dist', gulp.series('clean', 'dist-build')); - -// Create app directories in ./apps -gulp.task('apps', gulp.series('dist', function(done) { - var builder = new NwBuilder({ - files: './dist/**/*', - buildDir: appsDir, - platforms: getPlatforms(), - flavor: 'normal', - macIcns: './images/inav.icns', - winIco: './images/inav.ico', - version: get_nw_version(), - zip: false - }); - builder.on('log', console.log); - builder.build(function (err) { - if (err) { - console.log("Error building NW apps:" + err); - done(); - return; - } - // Package apps as .zip files - done(); - }); -})); - -function get_nw_version() { - return semver.valid(semver.coerce(require('./package.json').dependencies.nw)); -} - -function get_release_filename_base(platform) { - return 'INAV-Configurator_' + platform; -} - -function get_release_filename(platform, ext, addition = '') { - var pkg = require('./package.json'); - return get_release_filename_base(platform) + addition + '_' + pkg.version + '.' + ext; -} - -function build_win_zip(arch) { - return function build_win_zip_proc(done) { - var pkg = require('./package.json'); - - // 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 } - }); - 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(); - } -} - -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'); - var src = path.join(appsDir, pkg.name, 'osx64', pkg.name + '.app'); - // Check if we want to sign the .app bundle - if (getArguments().codesign) { - // macapptool can be downloaded from - // https://github.com/fiam/macapptool - // - // Make sure the bundle is well formed - execSync('macapptool', '-v', '1', 'fix', src); - // Sign - const codesignArgs = ['macapptool', '-v', '1', 'sign']; - const codesignIdentity = getArguments()['codesign-identity']; - if (codesignIdentity) { - codesignArgs.push('-i', codesignIdentity); - } - 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 } - }); - archive.on('warning', function(err) { throw err; }); - archive.on('error', function(err) { throw err; }); - archive.pipe(output); - archive.directory(src, 'INAV Configurator.app'); - output.on('close', function() { - if (getArguments().notarize) { - console.log('Notarizing ZIP file: ' + zipFilename); - const notarizeArgs = ['xcrun', 'notarytool', 'submit']; - notarizeArgs.push(zipFilename); - 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 ZIP file: ' + zipFilename); - const stapleArgs = ['macapptool', '-v', '1', 'staple']; - stapleArgs.push(zipFilename) - execSync.apply(this, stapleArgs); - } - 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: ['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); - var output = fs.createWriteStream(path.join(appsDir, get_release_filename(dirname, 'tar.gz'))); - var archive = archiver('tar', { - zlib: { level: 9 }, - gzip: true - }); - 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(); - } -} - -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; }))); - -gulp.task('watch', function () { - for(var k in output) { - gulp.watch(sources[k], gulp.series(get_task_name(k))); - } -}); - -gulp.task('default', gulp.series('build')); diff --git a/images/icons/cf_icon_setup_white.svg b/images/icons/cf_icon_setup_white.svg index 7501a9f07..353d09025 100644 --- a/images/icons/cf_icon_setup_white.svg +++ b/images/icons/cf_icon_setup_white.svg @@ -1,16 +1,8 @@ - - - - - - - - - - + + + + + + + + diff --git a/images/inav-installing.gif b/images/inav-installing.gif new file mode 100644 index 000000000..7a8974410 Binary files /dev/null and b/images/inav-installing.gif differ diff --git a/main.html b/index.html old mode 100755 new mode 100644 similarity index 83% rename from main.html rename to index.html index 92c89a58d..4b0d8aec5 --- a/main.html +++ b/index.html @@ -3,9 +3,13 @@ - - - + + + + + + + INAV Configurator @@ -174,6 +178,49 @@

+
    @@ -195,7 +242,7 @@

    • - +
    • @@ -215,11 +262,8 @@

    • -
    • - -
    • - +
    • @@ -295,9 +339,6 @@

-
- -
-
@@ -312,7 +353,7 @@

+
+ + +
+
+
+ + +
+
@@ -510,17 +524,6 @@
-
- - -
-
- -
- - -
-
diff --git a/tabs/advanced_tuning.js b/tabs/advanced_tuning.js index 6c012fbcf..06c195b74 100644 --- a/tabs/advanced_tuning.js +++ b/tabs/advanced_tuning.js @@ -1,18 +1,40 @@ 'use strict'; +const path = require('path'); + +const MSPCodes = require('./../js/msp/MSPCodes'); +const MSP = require('./../js/msp'); +const { GUI, TABS } = require('./../js/gui'); +const FC = require('./../js/fc'); +const Settings = require('./../js/settings'); +const i18n = require('./../js/localization'); + TABS.advanced_tuning = {}; TABS.advanced_tuning.initialize = function (callback) { if (GUI.active_tab != 'advanced_tuning') { GUI.active_tab = 'advanced_tuning'; - googleAnalytics.sendAppView('AdvancedTuning'); } loadHtml(); + function save_to_eeprom() { + console.log('save_to_eeprom'); + MSP.send_message(MSPCodes.MSP_EEPROM_WRITE, false, false, function () { + GUI.log(i18n.getMessage('eepromSaved')); + + GUI.tab_switch_cleanup(function () { + MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, function () { + GUI.log(i18n.getMessage('deviceRebooting')); + GUI.handleReconnect($('.tab_advanced_tuning a')); + }); + }); + }); + } + function loadHtml() { - GUI.load("./tabs/advanced_tuning.html", Settings.processHtml(function () { + GUI.load(path.join(__dirname, "advanced_tuning.html"), Settings.processHtml(function () { if (FC.isAirplane()) { $('.airplaneTuning').show(); @@ -36,22 +58,22 @@ TABS.advanced_tuning.initialize = function (callback) { GUI.simpleBind(); - localize(); + i18n.localize();; // Set up required field warnings - $('#launchIdleThr').keyup(function() { + $('#launchIdleThr').on('keyup', () => { TABS.advanced_tuning.checkRequirements_IdleThrottle(); }); - $('#launchIdleDelay').keyup(function() { + $('#launchIdleDelay').on('keyup', () => { TABS.advanced_tuning.checkRequirements_IdleThrottle(); }); - $('#rthHomeAltitude').keyup(function() { + $('#rthHomeAltitude').on('keyup', () => { TABS.advanced_tuning.checkRequirements_LinearDescent(); }); - $('#rthUseLinearDescent').change(function() { + $('#rthUseLinearDescent').on('change', function () { TABS.advanced_tuning.checkRequirements_LinearDescent(); }); @@ -59,39 +81,15 @@ TABS.advanced_tuning.initialize = function (callback) { TABS.advanced_tuning.checkRequirements_IdleThrottle(); TABS.advanced_tuning.checkRequirements_LinearDescent(); - $('a.save').click(function () { - Settings.saveInputs().then(function () { - var self = this; - MSP.promise(MSPCodes.MSP_EEPROM_WRITE); - var oldText = $(this).text(); - $(this).html("Saved"); - setTimeout(function () { - $(self).html(oldText); - }, 2000); - reboot(); - }); + $('a.save').on('click', function () { + Settings.saveInputs(save_to_eeprom); }); GUI.content_ready(callback); })); } - - function reboot() { - //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('configurationEepromSaved')); - GUI.tab_switch_cleanup(function () { - MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, reinitialize); - }); - } - - function reinitialize() { - //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('deviceRebooting')); - GUI.handleReconnect($('.tab_advanced_tuning a')); - } }; -$incLD = 0; TABS.advanced_tuning.checkRequirements_IdleThrottle = function() { let idleThrottle = $('#launchIdleThr'); diff --git a/tabs/auxiliary.js b/tabs/auxiliary.js index f04852420..7d66e3897 100644 --- a/tabs/auxiliary.js +++ b/tabs/auxiliary.js @@ -1,5 +1,20 @@ 'use strict'; + +const path = require('path'); +const wNumb = require('wnumb/wNumb') +const Store = require('electron-store'); +const store = new Store(); + +const mspHelper = require('./../js/msp/MSPHelper'); +const MSPCodes = require('./../js/msp/MSPCodes'); +const MSP = require('./../js/msp'); +const { GUI, TABS } = require('./../js/gui'); +const FC = require('./../js/fc'); +const adjustBoxNameIfPeripheralWithModeID = require('./../js/peripherals'); +const i18n = require('./../js/localization'); +const interval = require('./../js/intervals'); + var ORIG_AUX_CONFIG_IDS = []; TABS.auxiliary = {}; @@ -7,8 +22,6 @@ TABS.auxiliary = {}; TABS.auxiliary.initialize = function (callback) { GUI.active_tab_ref = this; GUI.active_tab = 'auxiliary'; - googleAnalytics.sendAppView('Auxiliary'); - function get_mode_ranges() { MSP.send_message(MSPCodes.MSP_MODE_RANGES, false, false, get_box_ids); } @@ -18,7 +31,7 @@ TABS.auxiliary.initialize = function (callback) { } function get_rc_data() { - if (SERIAL_CONFIG.ports.length == 0) { + if (FC.SERIAL_CONFIG.ports.length == 0) { MSP.send_message(MSPCodes.MSP_RC, false, false, get_ports_data); } else { MSP.send_message(MSPCodes.MSP_RC, false, false, load_html); @@ -31,7 +44,7 @@ TABS.auxiliary.initialize = function (callback) { function load_html() { sort_modes_for_display(); - GUI.load("./tabs/auxiliary.html", process_html); + GUI.load(path.join(__dirname, "auxiliary.html"), process_html); } MSP.send_message(MSPCodes.MSP_BOXNAMES, false, false, get_mode_ranges); @@ -55,21 +68,21 @@ TABS.auxiliary.initialize = function (callback) { var found = false; var sortedID = 0; - for (i=0; i AUX_CONFIG.length) { - for (i=0; i FC.AUX_CONFIG.length) { + for (let i=0; i { - return new Promise((resolve) => { - helper.timeout.add('CLI_send_slowly', () => { - let processingDelay = TABS.cli.lineDelayMs; - if (line.toLowerCase().startsWith('profile')) { - processingDelay = TABS.cli.profileSwitchDelayMs; - } - const isLastCommand = outputArray.length === index + 1; - if (isLastCommand && TABS.cli.cliBuffer) { - line = getCliCommand(line, TABS.cli.cliBuffer); - } - TABS.cli.sendLine(line, () => { - resolve(processingDelay); - }); - }, delay); - }); - }; + + navigator.clipboard.writeText(text) + .then(onCopySuccessful, onCopyFailed); } TABS.cli.initialize = function (callback) { @@ -117,11 +92,11 @@ TABS.cli.initialize = function (callback) { if (GUI.active_tab != 'cli') { GUI.active_tab = 'cli'; - googleAnalytics.sendAppView('CLI'); } // Flush MSP queue as well as all MSP registered callbacks - helper.mspQueue.flush(); + mspQueue.flush(); + mspDeduplicationQueue.flush(); MSP.callbacks_cleanup(); self.outputHistory = ""; @@ -135,16 +110,35 @@ TABS.cli.initialize = function (callback) { return !(nwGui == null && !navigator.clipboard) })(); + function executeCommands(out_string) { self.history.add(out_string.trim()); var outputArray = out_string.split("\n"); - Promise.reduce(outputArray, sendLinesWithDelay(outputArray), 0); + return outputArray.reduce((p, line, index) => + p.then((delay) => + new Promise((resolve) => { + timeout.add('CLI_send_slowly', () => { + let processingDelay = TABS.cli.lineDelayMs; + if (line.toLowerCase().startsWith('profile')) { + processingDelay = TABS.cli.profileSwitchDelayMs; + } + const isLastCommand = outputArray.length === index + 1; + if (isLastCommand && TABS.cli.cliBuffer) { + line = getCliCommand(line, TABS.cli.cliBuffer); + } + TABS.cli.sendLine(line, () => { + resolve(processingDelay); + }); + }, delay); + }) + ), Promise.resolve(0), + ); } - GUI.load("./tabs/cli.html", function () { + GUI.load(path.join(__dirname, "cli.html"), function () { // translate to user-selected language - localize(); + i18n.localize(); $('.cliDocsBtn').attr('href', globalSettings.docsTreeLocation + 'Settings.md'); @@ -155,80 +149,83 @@ TABS.cli.initialize = function (callback) { $(CliAutoComplete).on('build:start', function() { textarea .val('') - .attr('placeholder', chrome.i18n.getMessage('cliInputPlaceholderBuilding')) + .attr('placeholder', i18n.getMessage('cliInputPlaceholderBuilding')) .prop('disabled', true); }); $(CliAutoComplete).on('build:stop', function() { textarea - .attr('placeholder', chrome.i18n.getMessage('cliInputPlaceholder')) + .attr('placeholder', i18n.getMessage('cliInputPlaceholder')) .prop('disabled', false) .focus(); }); - $('.tab-cli .save').click(function() { - var prefix = 'cli'; - var suffix = 'txt'; - - var filename = generateFilename(prefix, suffix); - - var accepts = [{ - description: suffix.toUpperCase() + ' files', extensions: [suffix], - }]; - - nwdialog.setContext(document); - nwdialog.saveFileDialog(filename, accepts, '', function(result) { - if (!result) { - GUI.log(chrome.i18n.getMessage('cliSaveToFileAborted')); + $('.tab-cli .save').on('click', function () { + + var options = { + filters: [ + { name: 'CLI', extensions: ['cli'] } , + { name: 'TXT', extensions: ['txt'] } + ], + }; + dialog.showSaveDialog(options).then(result => { + if (result.canceled) { + GUI.log(i18n.getMessage('cliSaveToFileAborted')); return; } - const fs = require('fs'); - - fs.writeFile(result, self.outputHistory, (err) => { + + fs.writeFile(result.filePath, self.outputHistory, (err) => { if (err) { - GUI.log(chrome.i18n.getMessage('ErrorWritingFile')); + GUI.log(i18n.getMessage('ErrorWritingFile')); return console.error(err); } - GUI.log(chrome.i18n.getMessage('FileSaved')); + GUI.log(i18n.getMessage('FileSaved')); }); + }).catch (err => { + console.log(err); }); }); - $('.tab-cli .exit').click(function() { + $('.tab-cli .exit').on('click', function () { self.send(getCliCommand('exit\n', TABS.cli.cliBuffer)); }); - $('.tab-cli .savecmd').click(function() { + $('.tab-cli .savecmd').on('click', function () { self.send(getCliCommand('save\n', TABS.cli.cliBuffer)); }); - $('.tab-cli .msc').click(function() { + $('.tab-cli .msc').on('click', function () { self.send(getCliCommand('msc\n', TABS.cli.cliBuffer)); }); - $('.tab-cli .diffall').click(function() { + $('.tab-cli .diffall').on('click', function () { self.outputHistory = ""; $('.tab-cli .window .wrapper').empty(); self.send(getCliCommand('diff all\n', TABS.cli.cliBuffer)); }); - $('.tab-cli .clear').click(function() { + $('.tab-cli .clear').on('click', function () { self.outputHistory = ""; $('.tab-cli .window .wrapper').empty(); }); if (clipboardCopySupport) { - $('.tab-cli .copy').click(function() { + $('.tab-cli .copy').on('click', function () { copyToClipboard(self.outputHistory); }); } else { $('.tab-cli .copy').hide(); } - $('.tab-cli .load').click(function() { - nwdialog.setContext(document); - nwdialog.openFileDialog(".txt", false, '', function(result) { - if (!result) { + $('.tab-cli .load').on('click', function () { + var options = { + filters: [ + { name: 'CLI/TXT', extensions: ['cli', 'txt'] }, + { name: 'ALL', extensions: ['*'] } + ], + }; + dialog.showOpenDialog(options).then( result => { + if (result.canceled) { console.log('No file selected'); return; } @@ -250,36 +247,37 @@ TABS.cli.initialize = function (callback) { closeButton: 'title', animation: false, isolateScroll: false, - title: chrome.i18n.getMessage("cliConfirmSnippetDialogTitle"), + title: i18n.getMessage("cliConfirmSnippetDialogTitle"), content: $('#snippetpreviewcontent'), - onCreated: () => $("#snippetpreviewcontent a.confirm").click(() => executeSnippet()), + onCreated: () => $("#snippetpreviewcontent a.confirm").on('click', executeSnippet), }); } previewArea.val(result); self.GUI.snippetPreviewWindow.open(); } - const fs = require('fs'); - - fs.readFile(result, (err, data) => { - if (err) { - GUI.log(chrome.i18n.getMessage('ErrorReadingFile')); - return console.error(err); - } + if (result.filePaths.length == 1) { + fs.readFile(result.filePaths[0], (err, data) => { + if (err) { + GUI.log(i18n.getMessage('ErrorReadingFile')); + return console.error(err); + } - previewCommands(data); - }); + previewCommands(data); + }); + } + }).catch (err => { + console.log(err); }); }); // Tab key detection must be on keydown, // `keypress`/`keyup` happens too late, as `textarea` will have already lost focus. - textarea.keydown(function (event) { + textarea.on('keydown', function (event) { const tabKeyCode = 9; if (event.which == tabKeyCode) { // prevent default tabbing behaviour event.preventDefault(); - if (!CliAutoComplete.isEnabled()) { const outString = textarea.val(); const lastCommand = outString.split("\n").pop(); @@ -296,7 +294,7 @@ TABS.cli.initialize = function (callback) { } }); - textarea.keypress(function (event) { + textarea.on('keypress', function (event) { const enterKeyCode = 13; if (event.which == enterKeyCode) { event.preventDefault(); // prevent the adding of new line @@ -312,21 +310,20 @@ TABS.cli.initialize = function (callback) { self.outputHistory = ""; $('.tab-cli .window .wrapper').empty(); } else { - var outputArray = out_string.split("\n"); - Promise.reduce(outputArray, sendLinesWithDelay(outputArray), 0); + executeCommands(out_string); } textarea.val(''); } }); - textarea.keyup(function (event) { + textarea.on('keyup', function (event) { var keyUp = {38: true}, keyDown = {40: true}; - if (CliAutoComplete.isOpen()) { - return; // disable history keys if autocomplete is open - } + if (CliAutoComplete.isOpen()) { + return; // disable history keys if autocomplete is open + } if (event.keyCode in keyUp) { textarea.val(self.history.prev()); @@ -340,7 +337,7 @@ TABS.cli.initialize = function (callback) { // give input element user focus textarea.focus(); - helper.timeout.add('enter_cli', function enter_cli() { + timeout.add('enter_cli', function enter_cli() { // Enter CLI mode var bufferOut = new ArrayBuffer(1); var bufView = new Uint8Array(bufferOut); @@ -357,13 +354,13 @@ TABS.cli.initialize = function (callback) { if (CONFIGURATOR.connection.type == ConnectionType.BLE) { let delay = CONFIGURATOR.connection.deviceDescription.delay; if (delay > 0) { - helper.timeout.add('cli_delay', () => { + timeout.add('cli_delay', () => { self.send(getCliCommand("cli_delay " + delay + '\n', TABS.cli.cliBuffer)); - self.send(getCliCommand('# ' + chrome.i18n.getMessage('connectionBleCliEnter') + '\n', TABS.cli.cliBuffer)); + self.send(getCliCommand('# ' + i18n.getMessage('connectionBleCliEnter') + '\n', TABS.cli.cliBuffer)); }, 400); } } - + GUI.content_ready(callback); }); }; @@ -485,15 +482,15 @@ TABS.cli.read = function (readInfo) { if (this.cliBuffer == 'Rebooting') { CONFIGURATOR.cliActive = false; CONFIGURATOR.cliValid = false; - GUI.log(chrome.i18n.getMessage('cliReboot')); - GUI.log(chrome.i18n.getMessage('deviceRebooting')); + GUI.log(i18n.getMessage('cliReboot')); + GUI.log(i18n.getMessage('deviceRebooting')); GUI.handleReconnect(); } } if (!CONFIGURATOR.cliValid && validateText.indexOf('CLI') !== -1) { - GUI.log(chrome.i18n.getMessage('cliEnter')); + GUI.log(i18n.getMessage('cliEnter')); CONFIGURATOR.cliValid = true; if (CliAutoComplete.isEnabled() && !CliAutoComplete.isBuilding()) { @@ -539,7 +536,7 @@ TABS.cli.cleanup = function (callback) { // (another approach is however much more complicated): // we can setup an interval asking for data lets say every 200ms, when data arrives, callback will be triggered and tab switched // we could probably implement this someday - helper.timeout.add('waiting_for_bootup', function waiting_for_bootup() { + timeout.add('waiting_for_bootup', function waiting_for_bootup() { if (callback) callback(); }, 1000); // if we dont allow enough time to reboot, CRC of "first" command sent will fail, keep an eye for this one CONFIGURATOR.cliActive = false; diff --git a/tabs/configuration.html b/tabs/configuration.html index e6d0fd885..40c81f72c 100644 --- a/tabs/configuration.html +++ b/tabs/configuration.html @@ -19,7 +19,7 @@
-
@@ -45,7 +45,7 @@
- @@ -78,7 +78,7 @@
- @@ -108,7 +108,7 @@
- diff --git a/tabs/configuration.js b/tabs/configuration.js index 07d05d30f..713b8b76e 100644 --- a/tabs/configuration.js +++ b/tabs/configuration.js @@ -1,20 +1,32 @@ -/*global chrome,GUI,FC_CONFIG,$,mspHelper,googleAnalytics,ADVANCED_CONFIG,VTX_CONFIG,CONFIG,MSPChainerClass,BOARD_ALIGNMENT,TABS,MISC*/ 'use strict'; +const path = require('path'); + +const MSPChainerClass = require('./../js/msp/MSPchainer'); +const mspHelper = require('./../js/msp/MSPHelper'); +const MSPCodes = require('./../js/msp/MSPCodes'); +const MSP = require('./../js/msp'); +const { GUI, TABS } = require('./../js/gui'); +const FC = require('./../js/fc'); +const interval = require('./../js/intervals'); +const VTX = require('./../js/vtx'); +const i18n = require('./../js/localization'); +const Settings = require('./../js/settings'); +const features = require('./../js/feature_framework'); + TABS.configuration = {}; TABS.configuration.initialize = function (callback, scrollPosition) { if (GUI.active_tab != 'configuration') { GUI.active_tab = 'configuration'; - googleAnalytics.sendAppView('Configuration'); + } var loadChainer = new MSPChainerClass(); var loadChain = [ mspHelper.loadFeatures, - mspHelper.loadArmingConfig, mspHelper.loadSensorAlignment, mspHelper.loadAdvancedConfig, mspHelper.loadVTXConfig, @@ -31,7 +43,6 @@ TABS.configuration.initialize = function (callback, scrollPosition) { var saveChain = [ mspHelper.saveAccTrim, - mspHelper.saveArmingConfig, mspHelper.saveAdvancedConfig, mspHelper.saveVTXConfig, mspHelper.saveCurrentMeterConfig, @@ -41,7 +52,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { ]; function saveSettings(onComplete) { - Settings.saveInputs().then(onComplete); + Settings.saveInputs(onComplete); } saveChainer.setChain(saveChain); @@ -49,7 +60,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { function reboot() { //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('configurationEepromSaved')); + GUI.log(i18n.getMessage('configurationEepromSaved')); GUI.tab_switch_cleanup(function () { MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, reinitialize); @@ -58,12 +69,12 @@ TABS.configuration.initialize = function (callback, scrollPosition) { function reinitialize() { //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('deviceRebooting')); + GUI.log(i18n.getMessage('deviceRebooting')); GUI.handleReconnect($('.tab_configuration a')); } function load_html() { - GUI.load("./tabs/configuration.html", Settings.processHtml(process_html)); + GUI.load(path.join(__dirname, "configuration.html"), Settings.processHtml(process_html)); } function process_html() { @@ -71,20 +82,20 @@ TABS.configuration.initialize = function (callback, scrollPosition) { let i; // generate features - var features = FC.getFeatures(); + var fcFeatures = FC.getFeatures(); var features_e = $('.features'); - for (i = 0; i < features.length; i++) { + for (let i = 0; i < fcFeatures.length; i++) { var row_e, tips = [], feature_tip_html = ''; - if (features[i].showNameInTip) { - tips.push(chrome.i18n.getMessage("manualEnablingTemplate").replace("{name}", features[i].name)); + if (fcFeatures[i].showNameInTip) { + tips.push(i18n.getMessage("manualEnablingTemplate").replace("{name}", fcFeatures[i].name)); } - if (features[i].haveTip) { - tips.push(chrome.i18n.getMessage("feature" + features[i].name + "Tip")); + if (fcFeatures[i].haveTip) { + tips.push(i18n.getMessage("feature" + fcFeatures[i].name + "Tip")); } if (tips.length > 0) { @@ -92,36 +103,36 @@ TABS.configuration.initialize = function (callback, scrollPosition) { } row_e = $('
' + - '' + - '
'); features_e.each(function () { - if ($(this).hasClass(features[i].group)) { + if ($(this).hasClass(fcFeatures[i].group)) { $(this).after(row_e); } }); } - helper.features.updateUI($('.tab-configuration'), FEATURES); + features.updateUI($('.tab-configuration'), FC.FEATURES); // translate to user-selected language - localize(); + i18n.localize();; // VTX var config_vtx = $('.config-vtx'); - if (VTX_CONFIG.device_type != VTX.DEV_UNKNOWN) { + if (FC.VTX_CONFIG.device_type != VTX.DEV_UNKNOWN) { var vtx_band = $('#vtx_band'); vtx_band.empty(); var vtx_no_band_note = $('#vtx_no_band'); - if (VTX_CONFIG.band < VTX.BAND_MIN || VTX_CONFIG.band > VTX.BAND_MAX) { - var noBandName = chrome.i18n.getMessage("configurationNoBand"); + if (FC.VTX_CONFIG.band < VTX.BAND_MIN || FC.VTX_CONFIG.band > VTX.BAND_MAX) { + var noBandName = i18n.getMessage("configurationNoBand"); $('').appendTo(vtx_band); vtx_no_band_note.show(); } else { @@ -130,58 +141,58 @@ TABS.configuration.initialize = function (callback, scrollPosition) { for (var ii = 0; ii < VTX.BANDS.length; ii++) { var band_name = VTX.BANDS[ii].name; var option = $(''); - if (VTX.BANDS[ii].code == VTX_CONFIG.band) { + if (VTX.BANDS[ii].code == FC.VTX_CONFIG.band) { option.prop('selected', true); } option.appendTo(vtx_band); } - vtx_band.change(function () { - VTX_CONFIG.band = parseInt($(this).val()); + vtx_band.on('change', function () { + FC.VTX_CONFIG.band = parseInt($(this).val()); }); var vtx_channel = $('#vtx_channel'); vtx_channel.empty(); for (var ii = VTX.CHANNEL_MIN; ii <= VTX.CHANNEL_MAX; ii++) { var option = $(''); - if (ii == VTX_CONFIG.channel) { + if (ii == FC.VTX_CONFIG.channel) { option.prop('selected', true); } option.appendTo(vtx_channel); } - vtx_channel.change(function () { - VTX_CONFIG.channel = parseInt($(this).val()); + vtx_channel.on('change', function () { + FC.VTX_CONFIG.channel = parseInt($(this).val()); }); var vtx_power = $('#vtx_power'); vtx_power.empty(); - var minPower = VTX.getMinPower(VTX_CONFIG.device_type); - var maxPower = VTX.getMaxPower(VTX_CONFIG.device_type); + var minPower = VTX.getMinPower(FC.VTX_CONFIG.device_type); + var maxPower = VTX.getMaxPower(FC.VTX_CONFIG.device_type); for (var ii = minPower; ii <= maxPower; ii++) { var option = $(''); - if (ii == VTX_CONFIG.power) { + if (ii == FC.VTX_CONFIG.power) { option.prop('selected', true); } option.appendTo(vtx_power); } - vtx_power.change(function () { - VTX_CONFIG.power = parseInt($(this).val()); + vtx_power.on('change', function () { + FC.FC.VTX_CONFIG.power = parseInt($(this).val()); }); var vtx_low_power_disarm = $('#vtx_low_power_disarm'); vtx_low_power_disarm.empty(); for (var ii = VTX.LOW_POWER_DISARM_MIN; ii <= VTX.LOW_POWER_DISARM_MAX; ii++) { - var name = chrome.i18n.getMessage("configurationVTXLowPowerDisarmValue_" + ii); + var name = i18n.getMessage("configurationVTXLowPowerDisarmValue_" + ii); if (!name) { name = ii; } var option = $(''); - if (ii == VTX_CONFIG.low_power_disarm) { + if (ii == FC.VTX_CONFIG.low_power_disarm) { option.prop('selected', true); } option.appendTo(vtx_low_power_disarm); } - vtx_low_power_disarm.change(function () { - VTX_CONFIG.low_power_disarm = parseInt($(this).val()); + vtx_low_power_disarm.on('change', function () { + FC.VTX_CONFIG.low_power_disarm = parseInt($(this).val()); }); config_vtx.show(); @@ -196,35 +207,37 @@ TABS.configuration.initialize = function (callback, scrollPosition) { $('#content').scrollTop((scrollPosition) ? scrollPosition : 0); // fill board alignment - $('input[name="board_align_yaw"]').val((BOARD_ALIGNMENT.yaw / 10.0).toFixed(1)); + $('input[name="board_align_yaw"]').val((FC.BOARD_ALIGNMENT.yaw / 10.0).toFixed(1)); // fill magnetometer //UPDATE: moved to GPS tab and hidden - //$('#mag_declination').val(MISC.mag_declination); + //$('#mag_declination').val(FC.MISC.mag_declination); // fill battery voltage - $('#voltagesource').val(MISC.voltage_source); - $('#cells').val(MISC.battery_cells); - $('#celldetectvoltage').val(MISC.vbatdetectcellvoltage); - $('#mincellvoltage').val(MISC.vbatmincellvoltage); - $('#maxcellvoltage').val(MISC.vbatmaxcellvoltage); - $('#warningcellvoltage').val(MISC.vbatwarningcellvoltage); - $('#voltagescale').val(MISC.vbatscale); + $('#voltagesource').val(FC.MISC.voltage_source); + $('#cells').val(FC.MISC.battery_cells); + $('#celldetectvoltage').val(FC.MISC.vbatdetectcellvoltage); + $('#mincellvoltage').val(FC.MISC.vbatmincellvoltage); + $('#maxcellvoltage').val(FC.MISC.vbatmaxcellvoltage); + $('#warningcellvoltage').val(FC.MISC.vbatwarningcellvoltage); + $('#voltagescale').val(FC.MISC.vbatscale); // fill current - $('#currentscale').val(CURRENT_METER_CONFIG.scale); - $('#currentoffset').val(CURRENT_METER_CONFIG.offset / 10); + $('#currentscale').val(FC.CURRENT_METER_CONFIG.scale); + $('#currentoffset').val(FC.CURRENT_METER_CONFIG.offset / 10); // fill battery capacity - $('#battery_capacity').val(MISC.battery_capacity); - $('#battery_capacity_warning').val(Math.round(MISC.battery_capacity_warning * 100 / MISC.battery_capacity)); - $('#battery_capacity_critical').val(Math.round(MISC.battery_capacity_critical * 100 / MISC.battery_capacity)); - $('#battery_capacity_unit').val(MISC.battery_capacity_unit); + $('#battery_capacity').val(FC.MISC.battery_capacity); + let batCapWarn = Math.round(FC.MISC.battery_capacity_warning * 100 / FC.MISC.battery_capacity); + $('#battery_capacity_warning').val(isNaN(batCapWarn) ? "" : batCapWarn); + let batCapWarnCrit = Math.round(FC.MISC.battery_capacity_critical * 100 / FC.MISC.battery_capacity); + $('#battery_capacity_critical').val(isNaN(batCapWarnCrit) ? "" : batCapWarnCrit); + $('#battery_capacity_unit').val(FC.MISC.battery_capacity_unit); let $i2cSpeed = $('#i2c_speed'), $i2cSpeedInfo = $('#i2c_speed-info'); - $i2cSpeed.change(function () { + $i2cSpeed.on('change', function () { let $this = $(this), value = $this.children("option:selected").text(); @@ -234,7 +247,7 @@ TABS.configuration.initialize = function (callback, scrollPosition) { $i2cSpeedInfo.addClass('info-box'); $i2cSpeedInfo.removeClass('warning-box'); - $i2cSpeedInfo.html(chrome.i18n.getMessage('i2cSpeedSuggested800khz')); + $i2cSpeedInfo.html(i18n.getMessage('i2cSpeedSuggested800khz')); $i2cSpeedInfo.show(); } else if (value == "800KHZ") { @@ -246,59 +259,42 @@ TABS.configuration.initialize = function (callback, scrollPosition) { $i2cSpeedInfo.removeClass('ok-box'); $i2cSpeedInfo.removeClass('info-box'); $i2cSpeedInfo.addClass('warning-box'); - $i2cSpeedInfo.html(chrome.i18n.getMessage('i2cSpeedTooLow')); + $i2cSpeedInfo.html(i18n.getMessage('i2cSpeedTooLow')); $i2cSpeedInfo.show(); } }); - $i2cSpeed.change(); + $i2cSpeed.trigger('change'); - $('a.save').click(function () { + $('a.save').on('click', function () { //UPDATE: moved to GPS tab and hidden - //MISC.mag_declination = parseFloat($('#mag_declination').val()); - - ARMING_CONFIG.auto_disarm_delay = parseInt($('input[name="autodisarmdelay"]').val()); - - MISC.battery_cells = parseInt($('#cells').val()); - MISC.voltage_source = parseInt($('#voltagesource').val()); - MISC.vbatdetectcellvoltage = parseFloat($('#celldetectvoltage').val()); - MISC.vbatmincellvoltage = parseFloat($('#mincellvoltage').val()); - MISC.vbatmaxcellvoltage = parseFloat($('#maxcellvoltage').val()); - MISC.vbatwarningcellvoltage = parseFloat($('#warningcellvoltage').val()); - MISC.vbatscale = parseInt($('#voltagescale').val()); - - MISC.battery_capacity = parseInt($('#battery_capacity').val()); - MISC.battery_capacity_warning = parseInt($('#battery_capacity_warning').val() * MISC.battery_capacity / 100); - MISC.battery_capacity_critical = parseInt($('#battery_capacity_critical').val() * MISC.battery_capacity / 100); - MISC.battery_capacity_unit = $('#battery_capacity_unit').val(); - - googleAnalytics.sendEvent('Setting', 'I2CSpeed', $('#i2c_speed').children("option:selected").text()); - - googleAnalytics.sendEvent('Board', 'Accelerometer', $('#sensor-acc').children("option:selected").text()); - googleAnalytics.sendEvent('Board', 'Magnetometer', $('#sensor-mag').children("option:selected").text()); - googleAnalytics.sendEvent('Board', 'Barometer', $('#sensor-baro').children("option:selected").text()); - googleAnalytics.sendEvent('Board', 'Pitot', $('#sensor-pitot').children("option:selected").text()); - - for (var i = 0; i < features.length; i++) { - var featureName = features[i].name; - if (FC.isFeatureEnabled(featureName, features)) { - googleAnalytics.sendEvent('Setting', 'Feature', featureName); - } - } - - helper.features.reset(); - helper.features.fromUI($('.tab-configuration')); - helper.features.execute(function () { - CURRENT_METER_CONFIG.scale = parseInt($('#currentscale').val()); - CURRENT_METER_CONFIG.offset = Math.round(parseFloat($('#currentoffset').val()) * 10); + //FC.MISC.mag_declination = parseFloat($('#mag_declination').val()); + + FC.MISC.battery_cells = parseInt($('#cells').val()); + FC.MISC.voltage_source = parseInt($('#voltagesource').val()); + FC.MISC.vbatdetectcellvoltage = parseFloat($('#celldetectvoltage').val()); + FC.MISC.vbatmincellvoltage = parseFloat($('#mincellvoltage').val()); + FC.MISC.vbatmaxcellvoltage = parseFloat($('#maxcellvoltage').val()); + FC.MISC.vbatwarningcellvoltage = parseFloat($('#warningcellvoltage').val()); + FC.MISC.vbatscale = parseInt($('#voltagescale').val()); + + FC.MISC.battery_capacity = parseInt($('#battery_capacity').val()); + FC.MISC.battery_capacity_warning = parseInt($('#battery_capacity_warning').val() * FC.MISC.battery_capacity / 100); + FC.MISC.battery_capacity_critical = parseInt($('#battery_capacity_critical').val() * FC.MISC.battery_capacity / 100); + FC.MISC.battery_capacity_unit = $('#battery_capacity_unit').val(); + + features.reset(); + features.fromUI($('.tab-configuration')); + features.execute(function () { + FC.CURRENT_METER_CONFIG.scale = parseInt($('#currentscale').val()); + FC.CURRENT_METER_CONFIG.offset = Math.round(parseFloat($('#currentoffset').val()) * 10); saveChainer.execute(); }); }); - - helper.interval.add('config_load_analog', function () { - $('#batteryvoltage').val([ANALOG.voltage.toFixed(2)]); - $('#batterycurrent').val([ANALOG.amperage.toFixed(2)]); + interval.add('config_load_analog', function () { + $('#batteryvoltage').val([FC.ANALOG.voltage.toFixed(2)]); + $('#batterycurrent').val([FC.ANALOG.amperage.toFixed(2)]); }, 100, true); // 10 fps GUI.content_ready(callback); diff --git a/tabs/debug_trace.html b/tabs/debug_trace.html index a1d031f12..f46969c29 100644 --- a/tabs/debug_trace.html +++ b/tabs/debug_trace.html @@ -1,7 +1,7 @@ Debug Trace - +
diff --git a/tabs/ez_tune.html b/tabs/ez_tune.html deleted file mode 100644 index 6545bbfb7..000000000 --- a/tabs/ez_tune.html +++ /dev/null @@ -1,175 +0,0 @@ - -
-
\ No newline at end of file diff --git a/tabs/ez_tune.js b/tabs/ez_tune.js deleted file mode 100644 index 8128deb5e..000000000 --- a/tabs/ez_tune.js +++ /dev/null @@ -1,161 +0,0 @@ -/*global chrome,helper,mspHelper*/ -'use strict'; - -TABS.ez_tune = { - -}; - -TABS.ez_tune.initialize = function (callback) { - - let loadChainer = new MSPChainerClass(); - - let loadChain = [ - mspHelper.loadEzTune, - ]; - - let EZ_TUNE_PID_RP_DEFAULT = [40, 75, 23, 100]; - let EZ_TUNE_PID_YAW_DEFAULT = [45, 80, 0, 100]; - - loadChain.push(mspHelper.loadRateProfileData); - - loadChainer.setChain(loadChain); - loadChainer.setExitPoint(load_html); - loadChainer.execute(); - - var saveChainer = new MSPChainerClass(); - - var saveChain = [ - mspHelper.saveEzTune, - mspHelper.saveToEeprom - ]; - - saveChainer.setChain(saveChain); - saveChainer.setExitPoint(reboot); - - function reboot() { - //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('configurationEepromSaved')); - GUI.tab_switch_cleanup(function () { - MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, reinitialize); - }); - } - - function reinitialize() { - GUI.log(chrome.i18n.getMessage('deviceRebooting')); - GUI.handleReconnect($('.tab_ez_tune a')); - } - - if (GUI.active_tab != 'ez_tune') { - GUI.active_tab = 'ez_tune'; - googleAnalytics.sendAppView('Ez Tune'); - } - - function load_html() { - GUI.load("./tabs/ez_tune.html", Settings.processHtml(process_html)); - } - - function getYawPidScale(input) { - const normalized = (input - 100) * 0.01; - - return 1.0 + (normalized * 0.5); - } - - function scaleRange(x, srcMin, srcMax, destMin, destMax) { - let a = (destMax - destMin) * (x - srcMin); - let b = srcMax - srcMin; - return ((a / b) + destMin); - } - - function updatePreview() { - - let axisRatio = $('#ez_tune_axis_ratio').val() / 100; - let response = $('#ez_tune_response').val(); - let damping = $('#ez_tune_damping').val(); - let stability = $('#ez_tune_stability').val(); - let aggressiveness = $('#ez_tune_aggressiveness').val(); - let rate = $('#ez_tune_rate').val(); - let expo = $('#ez_tune_expo').val(); - - $('#preview-roll-p').html(Math.floor(EZ_TUNE_PID_RP_DEFAULT[0] * response / 100)); - $('#preview-roll-i').html(Math.floor(EZ_TUNE_PID_RP_DEFAULT[1] * stability / 100)); - $('#preview-roll-d').html(Math.floor(EZ_TUNE_PID_RP_DEFAULT[2] * damping / 100)); - $('#preview-roll-ff').html(Math.floor(EZ_TUNE_PID_RP_DEFAULT[3] * aggressiveness / 100)); - - $('#preview-pitch-p').html(Math.floor(axisRatio * EZ_TUNE_PID_RP_DEFAULT[0] * response / 100)); - $('#preview-pitch-i').html(Math.floor(axisRatio * EZ_TUNE_PID_RP_DEFAULT[1] * stability / 100)); - $('#preview-pitch-d').html(Math.floor(axisRatio * EZ_TUNE_PID_RP_DEFAULT[2] * damping / 100)); - $('#preview-pitch-ff').html(Math.floor(axisRatio * EZ_TUNE_PID_RP_DEFAULT[3] * aggressiveness / 100)); - - $('#preview-yaw-p').html(Math.floor(EZ_TUNE_PID_YAW_DEFAULT[0] * getYawPidScale(response))); - $('#preview-yaw-i').html(Math.floor(EZ_TUNE_PID_YAW_DEFAULT[1] * getYawPidScale(stability))); - $('#preview-yaw-d').html(Math.floor(EZ_TUNE_PID_YAW_DEFAULT[2] * getYawPidScale(damping))); - $('#preview-yaw-ff').html(Math.floor(EZ_TUNE_PID_YAW_DEFAULT[3] * getYawPidScale(aggressiveness))); - - $('#preview-roll-rate').html(Math.floor(scaleRange(rate, 0, 200, 30, 90)) * 10 + " dps"); - $('#preview-pitch-rate').html(Math.floor(scaleRange(rate, 0, 200, 30, 90)) * 10 + " dps"); - $('#preview-yaw-rate').html((Math.floor(scaleRange(rate, 0, 200, 30, 90)) - 10) * 10 + " dps"); - - $('#preview-roll-expo').html(Math.floor(scaleRange(expo, 0, 200, 40, 100)) + "%"); - $('#preview-pitch-expo').html(Math.floor(scaleRange(expo, 0, 200, 40, 100)) + "%"); - $('#preview-yaw-expo').html(Math.floor(scaleRange(expo, 0, 200, 40, 100)) + "%"); - - } - - function process_html() { - localize(); - - helper.tabs.init($('.tab-ez_tune')); - helper.features.updateUI($('.tab-ez_tune'), FEATURES); - - $("#ez_tune_enabled").prop('checked', EZ_TUNE.enabled); - - GUI.sliderize($('#ez_tune_filter_hz'), EZ_TUNE.filterHz, 10, 300); - GUI.sliderize($('#ez_tune_axis_ratio'), EZ_TUNE.axisRatio, 25, 175); - GUI.sliderize($('#ez_tune_response'), EZ_TUNE.response, 0, 200); - GUI.sliderize($('#ez_tune_damping'), EZ_TUNE.damping, 0, 200); - GUI.sliderize($('#ez_tune_stability'), EZ_TUNE.stability, 0, 200); - GUI.sliderize($('#ez_tune_aggressiveness'), EZ_TUNE.aggressiveness, 0, 200); - - GUI.sliderize($('#ez_tune_rate'), EZ_TUNE.rate, 0, 200); - GUI.sliderize($('#ez_tune_expo'), EZ_TUNE.expo, 0, 200); - - - $('.ez-element').on('updated', function () { - updatePreview(); - }); - - updatePreview(); - - GUI.simpleBind(); - - GUI.content_ready(callback); - - $('a.update').on('click', function () { - - if ($("#ez_tune_enabled").is(":checked")) { - EZ_TUNE.enabled = 1; - } else { - EZ_TUNE.enabled = 0; - } - - EZ_TUNE.filterHz = $('#ez_tune_filter_hz').val(); - EZ_TUNE.axisRatio = $('#ez_tune_axis_ratio').val(); - EZ_TUNE.response = $('#ez_tune_response').val(); - EZ_TUNE.damping = $('#ez_tune_damping').val(); - EZ_TUNE.stability = $('#ez_tune_stability').val(); - EZ_TUNE.aggressiveness = $('#ez_tune_aggressiveness').val(); - EZ_TUNE.rate = $('#ez_tune_rate').val(); - EZ_TUNE.expo = $('#ez_tune_expo').val(); - - saveChainer.execute(); - }); - - } - -}; - -TABS.ez_tune.cleanup = function (callback) { - if (callback) { - callback(); - } -}; \ No newline at end of file diff --git a/tabs/failsafe.js b/tabs/failsafe.js index 8afd2d214..05c02b0f9 100644 --- a/tabs/failsafe.js +++ b/tabs/failsafe.js @@ -1,12 +1,21 @@ 'use strict'; +const path = require('path'); + +const mspHelper = require('./../js/msp/MSPHelper'); +const MSPCodes = require('./../js/msp/MSPCodes'); +const MSP = require('./../js/msp'); +const { GUI, TABS } = require('./../js/gui'); +const FC = require('./../js/fc'); +const Settings = require('./../js/settings'); +const i18n = require('./../js/localization'); + TABS.failsafe = {}; TABS.failsafe.initialize = function (callback, scrollPosition) { if (GUI.active_tab != 'failsafe') { GUI.active_tab = 'failsafe'; - googleAnalytics.sendAppView('Failsafe'); } // Can get rid of this when MSPHelper supports strings (fixed in #7734, awaiting merge) @@ -15,11 +24,11 @@ TABS.failsafe.initialize = function (callback, scrollPosition) { } function load_html() { - GUI.load("./tabs/failsafe.html", Settings.processHtml(function() { + GUI.load(path.join(__dirname, "failsafe.html"), Settings.processHtml(function() { GUI.simpleBind(); // translate to user-selected language - localize(); + i18n.localize();; // for some odd reason chrome 38+ changes scroll according to the touched select element // i am guessing this is a bug, since this wasn't happening on 37 @@ -27,7 +36,7 @@ TABS.failsafe.initialize = function (callback, scrollPosition) { $('#content').scrollTop((scrollPosition) ? scrollPosition : 0); // set stage 2 failsafe procedure - $('input[type="radio"].procedure').change(function () { + $('input[type="radio"].procedure').on('change', function () { var element = $(this), checked = element.is(':checked'), id = element.attr('id'); @@ -49,32 +58,32 @@ TABS.failsafe.initialize = function (callback, scrollPosition) { }); // switch (MSPHelper.getSetting('failsafe_procedure')) { // Use once #7734 is merged - switch (FAILSAFE_CONFIG.failsafe_procedure) { + switch (FC.FAILSAFE_CONFIG.failsafe_procedure) { default: case 0: - element = $('input[id="land"]'); + var element = $('input[id="land"]'); element.prop('checked', true); - element.change(); + element.trigger('change'); break; case 1: - element = $('input[id="drop"]'); + var element = $('input[id="drop"]'); element.prop('checked', true); - element.change(); + element.trigger('change'); break; case 2: - element = $('input[id="rth"]'); + var element = $('input[id="rth"]'); element.prop('checked', true); - element.change(); + element.trigger('change'); break; case 3: - element = $('input[id="nothing"]'); + var element = $('input[id="nothing"]'); element.prop('checked', true); - element.change(); + element.trigger('change'); break; } // Adjust Minimum Distance values when checkbox is checked/unchecked - $('#failsafe_use_minimum_distance').change(function() { + $('#failsafe_use_minimum_distance').on('change', function () { if ($(this).is(':checked')) { // No default distance added due to conversions $('#failsafe_min_distance_elements').show(); @@ -98,15 +107,15 @@ TABS.failsafe.initialize = function (callback, scrollPosition) { $('#failsafe_min_distance_procedure_elements').hide(); } - $('a.save').click(function () { + $('a.save').on('click', function () { if ($('input[id="land"]').is(':checked')) { - FAILSAFE_CONFIG.failsafe_procedure = 0; + FC.FAILSAFE_CONFIG.failsafe_procedure = 0; } else if ($('input[id="drop"]').is(':checked')) { - FAILSAFE_CONFIG.failsafe_procedure = 1; + FC.FAILSAFE_CONFIG.failsafe_procedure = 1; } else if ($('input[id="rth"]').is(':checked')) { - FAILSAFE_CONFIG.failsafe_procedure = 2; + FC.FAILSAFE_CONFIG.failsafe_procedure = 2; } else if ($('input[id="nothing"]').is(':checked')) { - FAILSAFE_CONFIG.failsafe_procedure = 3; + FC.FAILSAFE_CONFIG.failsafe_procedure = 3; } MSP.send_message(MSPCodes.MSP_SET_FAILSAFE_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_FAILSAFE_CONFIG), false, savePhaseTwo); @@ -118,29 +127,22 @@ TABS.failsafe.initialize = function (callback, scrollPosition) { load_failssafe_config(); - function savePhaseTwo() { - Settings.saveInputs().then(function () { - var self = this; - MSP.promise(MSPCodes.MSP_EEPROM_WRITE); - setTimeout(function () { - $(self).html(oldText); - }, 2000); - reboot(); - }); - } + function save_to_eeprom() { + console.log('save_to_eeprom'); + MSP.send_message(MSPCodes.MSP_EEPROM_WRITE, false, false, function () { + GUI.log(i18n.getMessage('eepromSaved')); - function reboot() { - //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('configurationEepromSaved')); - GUI.tab_switch_cleanup(function () { - MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, reinitialize); + GUI.tab_switch_cleanup(function () { + MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, function () { + GUI.log(i18n.getMessage('deviceRebooting')); + GUI.handleReconnect($('.tab_failsafe a')); + }); + }); }); } - function reinitialize() { - //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('deviceRebooting')); - GUI.handleReconnect($('.tab_failsafe a')); + function savePhaseTwo() { + Settings.saveInputs(save_to_eeprom); } }; diff --git a/tabs/firmware_flasher.js b/tabs/firmware_flasher.js index f5b2cc5df..a7b7076ac 100755 --- a/tabs/firmware_flasher.js +++ b/tabs/firmware_flasher.js @@ -1,29 +1,50 @@ -/*global $,nwdialog*/ 'use strict'; +const { marked } = require('marked'); +const fs = require('fs'); +const path = require('path'); +const semver = require('semver'); +const { dialog } = require('@electron/remote'); +const Store = require('electron-store'); +const store = new Store(); + +const i18n = require('./../js/localization'); +const { GUI, TABS } = require('./../js/gui'); +const MSP = require('./../js/msp'); +const MSPCodes = require('./../js/msp/MSPCodes') +const FC = require('./../js/fc'); +const { usbDevices, PortHandler } = require('./../js/port_handler'); +const CONFIGURATOR = require('./../js/data_storage'); +const SerialBackend = require('./../js/serial_backend'); +const timeout = require('./../js/timeouts'); +const interval = require('./../js/intervals'); +const mspQueue = require('./../js/serial_queue'); +const mspHelper = require('./../js/msp/MSPHelper'); +const STM32 = require('./../js/protocols/stm32'); +const STM32DFU = require('./../js/protocols/stm32usbdfu'); +const mspDeduplicationQueue = require('./../js/msp/mspDeduplicationQueue'); + TABS.firmware_flasher = {}; TABS.firmware_flasher.initialize = function (callback) { if (GUI.active_tab != 'firmware_flasher') { GUI.active_tab = 'firmware_flasher'; - googleAnalytics.sendAppView('Firmware Flasher'); } - var intel_hex = false, // standard intel hex in string format parsed_hex = false; // parsed raw hex in array format - GUI.load("./tabs/firmware_flasher.html", function () { + GUI.load(path.join(__dirname, "firmware_flasher.html"), function () { // translate to user-selected language - localize(); + i18n.localize(); function enable_load_online_button() { - $(".load_remote_file").text(chrome.i18n.getMessage('firmwareFlasherButtonLoadOnline')).removeClass('disabled'); + $(".load_remote_file").text(i18n.getMessage('firmwareFlasherButtonLoadOnline')).removeClass('disabled'); } function parse_hex(str, callback) { // parsing hex in different thread - var worker = new Worker('./build/hex_parser.js'); + var worker = new Worker('./js/workers/hex_parser.js'); // "callback" worker.onmessage = function (event) { @@ -50,16 +71,16 @@ TABS.firmware_flasher.initialize = function (callback) { }; } - $('input.show_development_releases').click(function() { + $('input.show_development_releases').on('click', function () { let selectedTarget = String($('select[name="board"]').val()); - GUI.log(chrome.i18n.getMessage('selectedTarget') + selectedTarget); + GUI.log(i18n.getMessage('selectedTarget') + selectedTarget); buildBoardOptions(); - GUI.log(chrome.i18n.getMessage('toggledRCs')); + GUI.log(i18n.getMessage('toggledRCs')); if (selectedTarget === "0") { TABS.firmware_flasher.getTarget(); } else { $('select[name="board"] option[value=' + selectedTarget + ']').attr("selected", "selected"); - $('select[name="board"]').change(); + $('select[name="board"]').trigger('change'); } }); @@ -86,8 +107,8 @@ TABS.firmware_flasher.initialize = function (callback) { var versions_e = $('select[name="firmware_version"]').empty(); var showDevReleases = ($('input.show_development_releases').is(':checked')); - boards_e.append($("".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectBoard')))); - versions_e.append($("".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion')))); + boards_e.append($("".format(i18n.getMessage('firmwareFlasherOptionLabelSelectBoard')))); + versions_e.append($("".format(i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion')))); var releases = {}; var sortedTargets = []; @@ -176,23 +197,23 @@ TABS.firmware_flasher.initialize = function (callback) { buildBoardOptions(); // bind events - $('select[name="board"]').change(function() { + $('select[name="board"]').on('change', function () { $("a.load_remote_file").addClass('disabled'); var target = $(this).children("option:selected").text(); if (!GUI.connect_lock) { $('.progress').val(0).removeClass('valid invalid'); - $('span.progressLabel').text(chrome.i18n.getMessage('firmwareFlasherLoadFirmwareFile')); + $('span.progressLabel').text(i18n.getMessage('firmwareFlasherLoadFirmwareFile')); $('div.git_info').slideUp(); $('div.release_info').slideUp(); $('a.flash_firmware').addClass('disabled'); var versions_e = $('select[name="firmware_version"]').empty(); if(target == 0) { - versions_e.append($("".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion')))); + versions_e.append($("".format(i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersion')))); } else { - versions_e.append($("".format(chrome.i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersionFor'), target))); + versions_e.append($("".format(i18n.getMessage('firmwareFlasherOptionLabelSelectFirmwareVersionFor'), target))); } TABS.firmware_flasher.releases[target].forEach(function(descriptor) { @@ -222,9 +243,18 @@ TABS.firmware_flasher.initialize = function (callback) { $('a.load_file').on('click', function () { - nwdialog.setContext(document); - nwdialog.openFileDialog('.hex', function(filename) { - const fs = require('fs'); + var options = { + filters: [ { name: "HEX file", extensions: ['hex'] } ] + }; + dialog.showOpenDialog(options).then(result => { + if (result.canceled) { + return; + } + + let filename; + if (result.filePaths.length == 1) { + filename = result.filePaths[0]; + } $('div.git_info').slideUp(); @@ -243,12 +273,11 @@ TABS.firmware_flasher.initialize = function (callback) { parsed_hex = data; if (parsed_hex) { - googleAnalytics.sendEvent('Flashing', 'Firmware', 'local'); $('a.flash_firmware').removeClass('disabled'); $('span.progressLabel').text('Loaded Local Firmware: (' + parsed_hex.bytes_total + ' bytes)'); } else { - $('span.progressLabel').text(chrome.i18n.getMessage('firmwareFlasherHexCorrupted')); + $('span.progressLabel').text(i18n.getMessage('firmwareFlasherHexCorrupted')); } }); }); @@ -260,7 +289,7 @@ TABS.firmware_flasher.initialize = function (callback) { /** * Lock / Unlock the firmware download button according to the firmware selection dropdown. */ - $('select[name="firmware_version"]').change(function(evt){ + $('select[name="firmware_version"]').on('change', function(evt){ $('div.release_info').slideUp(); $('a.flash_firmware').addClass('disabled'); if (evt.target.value=="0") { @@ -271,10 +300,10 @@ TABS.firmware_flasher.initialize = function (callback) { } }); - $('a.load_remote_file').click(function (evt) { + $('a.load_remote_file').on('click', function () { if ($('select[name="firmware_version"]').val() == "0") { - GUI.log(chrome.i18n.getMessage('noFirmwareSelectedToLoad')); + GUI.log(i18n.getMessage('noFirmwareSelectedToLoad')); return; } @@ -287,7 +316,6 @@ TABS.firmware_flasher.initialize = function (callback) { if (parsed_hex) { var url; - googleAnalytics.sendEvent('Flashing', 'Firmware', 'online'); $('span.progressLabel').html('Loaded Online Firmware: (' + parsed_hex.bytes_total + ' bytes)'); $('a.flash_firmware').removeClass('disabled'); @@ -317,7 +345,7 @@ TABS.firmware_flasher.initialize = function (callback) { var status_e = $('div.release_info .status'); if (summary.status == 'release-candidate') { - $('div.release_info .status').html(chrome.i18n.getMessage('firmwareFlasherReleaseStatusReleaseCandidate')).show(); + $('div.release_info .status').html(i18n.getMessage('firmwareFlasherReleaseStatusReleaseCandidate')).show(); } else { status_e.hide(); } @@ -327,7 +355,7 @@ TABS.firmware_flasher.initialize = function (callback) { $('div.release_info .status').text(summary.status); $('div.release_info .file').text(summary.file).prop('href', summary.url); - var formattedNotes = marked(summary.notes); + var formattedNotes = marked.parse(summary.notes); $('div.release_info .notes').html(formattedNotes); // Make links in the release notes open in a new window $('div.release_info .notes a').each(function () { @@ -337,30 +365,30 @@ TABS.firmware_flasher.initialize = function (callback) { $('div.release_info').slideDown(); } else { - $('span.progressLabel').text(chrome.i18n.getMessage('firmwareFlasherHexCorrupted')); + $('span.progressLabel').text(i18n.getMessage('firmwareFlasherHexCorrupted')); } }); } function failed_to_load() { - $('span.progressLabel').text(chrome.i18n.getMessage('firmwareFlasherFailedToLoadOnlineFirmware')); + $('span.progressLabel').text(i18n.getMessage('firmwareFlasherFailedToLoadOnlineFirmware')); $('a.flash_firmware').addClass('disabled'); enable_load_online_button(); } var summary = $('select[name="firmware_version"] option:selected').data('summary'); if (summary) { // undefined while list is loading or while running offline - $(".load_remote_file").text(chrome.i18n.getMessage('firmwareFlasherButtonLoading')).addClass('disabled'); + $(".load_remote_file").text(i18n.getMessage('firmwareFlasherButtonLoading')).addClass('disabled'); $.get(summary.url, function (data) { enable_load_online_button(); process_hex(data, summary); }).fail(failed_to_load); } else { - $('span.progressLabel').text(chrome.i18n.getMessage('firmwareFlasherFailedToLoadOnlineFirmware')); + $('span.progressLabel').text(i18n.getMessage('firmwareFlasherFailedToLoadOnlineFirmware')); } }); - $('a.flash_firmware').click(function () { + $('a.flash_firmware').on('click', function () { if (!$(this).hasClass('disabled')) { if (!GUI.connect_lock) { // button disabled while flashing is in progress if (parsed_hex != false) { @@ -402,13 +430,13 @@ TABS.firmware_flasher.initialize = function (callback) { STM32.connect(port, baud, parsed_hex, options); } else { console.log('Please select valid serial port'); - GUI.log(chrome.i18n.getMessage('selectValidSerialPort')); + GUI.log(i18n.getMessage('selectValidSerialPort')); } } else { STM32DFU.connect(usbDevices, parsed_hex, options); } } else { - $('span.progressLabel').text(chrome.i18n.getMessage('firmwareFlasherFirmwareNotLoaded')); + $('span.progressLabel').text(i18n.getMessage('firmwareFlasherFirmwareNotLoaded')); } } } @@ -452,39 +480,39 @@ TABS.firmware_flasher.initialize = function (callback) { }); } else { console.log('You don\'t have write permissions for this file, sorry.'); - GUI.log(chrome.i18n.getMessage('writePermissionsForFile')); + GUI.log(i18n.getMessage('writePermissionsForFile')); } }); }); }); }); - chrome.storage.local.get('no_reboot_sequence', function (result) { - if (result.no_reboot_sequence) { - $('input.updating').prop('checked', true); + + if (store.get('no_reboot_sequence', false)) { + $('input.updating').prop('checked', true); + $('.flash_on_connect_wrapper').show(); + } else { + $('input.updating').prop('checked', false); + } + + // bind UI hook so the status is saved on change + $('input.updating').on('change', function () { + var status = $(this).is(':checked'); + + if (status) { $('.flash_on_connect_wrapper').show(); } else { - $('input.updating').prop('checked', false); + $('input.flash_on_connect').prop('checked', false).trigger('change'); + $('.flash_on_connect_wrapper').hide(); } - // bind UI hook so the status is saved on change - $('input.updating').change(function() { - var status = $(this).is(':checked'); - - if (status) { - $('.flash_on_connect_wrapper').show(); - } else { - $('input.flash_on_connect').prop('checked', false).change(); - $('.flash_on_connect_wrapper').hide(); - } - - chrome.storage.local.set({'no_reboot_sequence': status}); - }); - - $('input.updating').change(); + store.set('no_reboot_sequence', status); }); - chrome.storage.local.get('flash_manual_baud', function (result) { + $('input.updating').trigger('change'); + + + store.get('flash_manual_baud', function (result) { if (result.flash_manual_baud) { $('input.flash_manual_baud').prop('checked', true); } else { @@ -492,91 +520,90 @@ TABS.firmware_flasher.initialize = function (callback) { } // bind UI hook so the status is saved on change - $('input.flash_manual_baud').change(function() { + $('input.flash_manual_baud').on('change', function () { var status = $(this).is(':checked'); - chrome.storage.local.set({'flash_manual_baud': status}); + store.set('flash_manual_baud', status); }); - $('input.flash_manual_baud').change(); + $('input.flash_manual_baud').trigger('change'); }); - chrome.storage.local.get('flash_manual_baud_rate', function (result) { - $('#flash_manual_baud_rate').val(result.flash_manual_baud_rate); - - // bind UI hook so the status is saved on change - $('#flash_manual_baud_rate').change(function() { - var baud = parseInt($('#flash_manual_baud_rate').val()); - chrome.storage.local.set({'flash_manual_baud_rate': baud}); - }); + var flash_manual_baud_rate = store.get('flash_manual_baud_rate', ''); + $('#flash_manual_baud_rate').val(flash_manual_baud_rate); - $('input.flash_manual_baud_rate').change(); + // bind UI hook so the status is saved on change + $('#flash_manual_baud_rate').on('change', function () { + var baud = parseInt($('#flash_manual_baud_rate').val()); + store.set('flash_manual_baud_rate', baud); }); - chrome.storage.local.get('flash_on_connect', function (result) { - if (result.flash_on_connect) { - $('input.flash_on_connect').prop('checked', true); - } else { - $('input.flash_on_connect').prop('checked', false); - } - - $('input.flash_on_connect').change(function () { - var status = $(this).is(':checked'); + $('input.flash_manual_baud_rate').trigger('change'); - if (status) { - var catch_new_port = function () { - PortHandler.port_detected('flash_detected_device', function (result) { - var port = result[0]; + + if (store.get('flash_on_connect', false)) { + $('input.flash_on_connect').prop('checked', true); + } else { + $('input.flash_on_connect').prop('checked', false); + } - if (!GUI.connect_lock) { - GUI.log('Detected: ' + port + ' - triggering flash on connect'); - console.log('Detected: ' + port + ' - triggering flash on connect'); + $('input.flash_on_connect').on('change', function () { + var status = $(this).is(':checked'); - // Trigger regular Flashing sequence - helper.timeout.add('initialization_timeout', function () { - $('a.flash_firmware').click(); - }, 100); // timeout so bus have time to initialize after being detected by the system - } else { - GUI.log('Detected ' + port + ' - previous device still flashing, please replug to try again'); - } + if (status) { + var catch_new_port = function () { + PortHandler.port_detected('flash_detected_device', function (result) { + var port = result[0]; - // Since current port_detected request was consumed, create new one - catch_new_port(); - }, false, true); - }; + if (!GUI.connect_lock) { + GUI.log('Detected: ' + port + ' - triggering flash on connect'); + console.log('Detected: ' + port + ' - triggering flash on connect'); - catch_new_port(); - } else { - PortHandler.flush_callbacks(); - } + // Trigger regular Flashing sequence + timeout.add('initialization_timeout', function () { + $('a.flash_firmware').trigger( "click" ); + }, 100); // timeout so bus have time to initialize after being detected by the system + } else { + GUI.log('Detected ' + port + ' - previous device still flashing, please replug to try again'); + } - chrome.storage.local.set({'flash_on_connect': status}); - }).change(); - }); + // Since current port_detected request was consumed, create new one + catch_new_port(); + }, false, true); + }; - chrome.storage.local.get('erase_chip', function (result) { - if (result.erase_chip) { - $('input.erase_chip').prop('checked', true); + catch_new_port(); } else { - $('input.erase_chip').prop('checked', false); + PortHandler.flush_callbacks(); } - // bind UI hook so the status is saved on change - $('input.erase_chip').change(function () { - chrome.storage.local.set({'erase_chip': $(this).is(':checked')}); - }); + store.set('flash_on_connect', status); + }).trigger('change'); + - $('input.erase_chip').change(); + + if (store.get('erase_chip', false)) { + $('input.erase_chip').prop('checked', true); + } else { + $('input.erase_chip').prop('checked', false); + } + // bind UI hook so the status is saved on change + $('input.erase_chip').on('change', function () { + store.set('erase_chip', $(this).is(':checked')); }); + $('input.erase_chip').trigger('change'); + + + $(document).keypress(function (e) { if (e.which == 13) { // enter // Trigger regular Flashing sequence - $('a.flash_firmware').click(); + $('a.flash_firmware').trigger( "click" ); } }); - $('a.auto_select_target').click(function () { + $('a.auto_select_target').on('click', function () { TABS.firmware_flasher.getTarget(); }); @@ -635,14 +662,14 @@ TABS.firmware_flasher.cleanup = function (callback) { }; TABS.firmware_flasher.getTarget = function() { - GUI.log(chrome.i18n.getMessage('automaticTargetSelect')); + GUI.log(i18n.getMessage('automaticTargetSelect')); var selected_baud = parseInt($('#baud').val()); var selected_port = $('#port').find('option:selected').data().isManual ? $('#port-override').val() : String($('#port').val()); if (selected_port !== 'DFU') { - if (selected_port == '0') { - GUI.log(chrome.i18n.getMessage('targetPrefetchFailNoPort')); + if (!selected_port || selected_port == '0') { + GUI.log(i18n.getMessage('targetPrefetchFailNoPort')); } else { console.log('Connecting to: ' + selected_port); GUI.connecting_to = selected_port; @@ -654,7 +681,7 @@ TABS.firmware_flasher.getTarget = function() { } } } else { - GUI.log(chrome.i18n.getMessage('targetPrefetchFailDFU')); + GUI.log(i18n.getMessage('targetPrefetchFailDFU')); } }; @@ -666,27 +693,27 @@ TABS.firmware_flasher.onOpen = function(openInfo) { GUI.connecting_to = false; // save selected port with chrome.storage if the port differs - chrome.storage.local.get('last_used_port', function (result) { - if (result.last_used_port) { - if (result.last_used_port != GUI.connected_to) { - // last used port doesn't match the one found in local db, we will store the new one - chrome.storage.local.set({'last_used_port': GUI.connected_to}); - } - } else { - // variable isn't stored yet, saving - chrome.storage.local.set({'last_used_port': GUI.connected_to}); + var last_used_port = store.get('last_used_port', ''); + if (last_used_port) { + if (last_used_port != GUI.connected_to) { + // last used port doesn't match the one found in local db, we will store the new one + store.set('last_used_port', GUI.connected_to); } - }); + } else { + // variable isn't stored yet, saving + store.set('last_used_port', GUI.connected_to); + } + - chrome.storage.local.set({last_used_bps: CONFIGURATOR.connection.bitrate}); - chrome.storage.local.set({wireless_mode_enabled: $('#wireless-mode').is(":checked")}); + store.set('last_used_bps', CONFIGURATOR.connection.bitrate); + store.set('wireless_mode_enabled', $('#wireless-mode').is(":checked")); - CONFIGURATOR.connection.addOnReceiveListener(read_serial); + CONFIGURATOR.connection.addOnReceiveListener(SerialBackend.read_serial); // disconnect after 10 seconds with error if we don't get IDENT data - helper.timeout.add('connecting', function () { + timeout.add('connecting', function () { if (!CONFIGURATOR.connectionValid) { - GUI.log(chrome.i18n.getMessage('targetPrefetchFail') + chrome.i18n.getMessage('noConfigurationReceived')); + GUI.log(i18n.getMessage('targetPrefetchFail') + i18n.getMessage('noConfigurationReceived')); TABS.firmware_flasher.closeTempConnection(); } @@ -699,35 +726,35 @@ TABS.firmware_flasher.onOpen = function(openInfo) { MSP.protocolVersion = MSP.constants.PROTOCOL_V2; MSP.send_message(MSPCodes.MSP_API_VERSION, false, false, function () { - if (CONFIG.apiVersion === "0.0.0") { - GUI_control.prototype.log("Cannot prefetch target: " + chrome.i18n.getMessage("illegalStateRestartRequired") + ""); + if (FC.CONFIG.apiVersion === "0.0.0") { + GUI_control.prototype.log("Cannot prefetch target: " + i18n.getMessage("illegalStateRestartRequired") + ""); FC.restartRequired = true; return; } MSP.send_message(MSPCodes.MSP_FC_VARIANT, false, false, function () { - if (CONFIG.flightControllerIdentifier == 'INAV') { + if (FC.CONFIG.flightControllerIdentifier == 'INAV') { MSP.send_message(MSPCodes.MSP_FC_VERSION, false, false, function () { - if (semver.lt(CONFIG.flightControllerVersion, "5.0.0")) { - GUI.log(chrome.i18n.getMessage('targetPrefetchFailOld')); + if (semver.lt(FC.CONFIG.flightControllerVersion, "5.0.0")) { + GUI.log(i18n.getMessage('targetPrefetchFailOld')); TABS.firmware_flasher.closeTempConnection(); } else { mspHelper.getCraftName(function(name) { if (name) { - CONFIG.name = name; + FC.CONFIG.name = name; } TABS.firmware_flasher.onValidFirmware(); }); } }); } else { - GUI.log(chrome.i18n.getMessage('targetPrefetchFailNonINAV')); + GUI.log(i18n.getMessage('targetPrefetchFailNonINAV')); TABS.firmware_flasher.closeTempConnection(); } }); }); } else { - GUI.log(chrome.i18n.getMessage('targetPrefetchFail') + chrome.i18n.getMessage('serialPortOpenFail')); + GUI.log(i18n.getMessage('targetPrefetchFail') + i18n.getMessage('serialPortOpenFail')); return; } }; @@ -735,28 +762,28 @@ TABS.firmware_flasher.onOpen = function(openInfo) { TABS.firmware_flasher.onValidFirmware = function() { MSP.send_message(MSPCodes.MSP_BUILD_INFO, false, false, function () { MSP.send_message(MSPCodes.MSP_BOARD_INFO, false, false, function () { - $('select[name="board"] option[value=' + CONFIG.target + ']').attr("selected", "selected"); - GUI.log(chrome.i18n.getMessage('targetPrefetchsuccessful') + CONFIG.target); + $('select[name="board"] option[value=' + FC.CONFIG.target + ']').attr("selected", "selected"); + GUI.log(i18n.getMessage('targetPrefetchsuccessful') + FC.CONFIG.target); TABS.firmware_flasher.closeTempConnection(); - $('select[name="board"]').change(); + $('select[name="board"]').trigger('change'); }); }); }; TABS.firmware_flasher.closeTempConnection = function() { - helper.timeout.killAll(); - helper.interval.killAll(['global_data_refresh', 'msp-load-update']); - helper.mspBalancedInterval.flush(); + timeout.killAll(); + interval.killAll(['global_data_refresh', 'msp-load-update', 'ltm-connection-check']); - helper.mspQueue.flush(); - helper.mspQueue.freeHardLock(); - helper.mspQueue.freeSoftLock(); + mspQueue.flush(); + mspQueue.freeHardLock(); + mspQueue.freeSoftLock(); + mspDeduplicationQueue.flush(); CONFIGURATOR.connection.emptyOutputBuffer(); CONFIGURATOR.connectionValid = false; GUI.connected_to = false; - CONFIGURATOR.connection.disconnect(onClosed); + CONFIGURATOR.connection.disconnect(); MSP.disconnect_cleanup(); }; \ No newline at end of file diff --git a/tabs/gps.html b/tabs/gps.html index d9c5c27e4..a389737fd 100644 --- a/tabs/gps.html +++ b/tabs/gps.html @@ -20,6 +20,14 @@
+
+ + +
+
+ + +
+
- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -125,7 +156,7 @@

- + align_mag_roll, align_mag_pitch, align_mag_yaw

@@ -172,6 +203,13 @@ +
+ CLI:  +
+
+ + +
diff --git a/tabs/magnetometer.js b/tabs/magnetometer.js index 10fc7e162..af8e6a8ba 100644 --- a/tabs/magnetometer.js +++ b/tabs/magnetometer.js @@ -1,5 +1,16 @@ 'use strict'; -/*global chrome,GUI,BOARD_ALIGNMENT,TABS,nwdialog,helper,$*/ + +const path = require('path'); + +const MSPChainerClass = require('./../js/msp/MSPchainer'); +const MSP = require('./../js/msp'); +const MSPCodes = require('./../js/msp/MSPCodes'); +const mspHelper = require('./../js/msp/MSPHelper'); +const FC = require('./../js/fc'); +const { GUI, TABS } = require('./../js/gui'); +const i18n = require('./../js/localization'); +const { mixer } = require('./../js/model'); +const interval = require('./../js/intervals'); TABS.magnetometer = {}; @@ -9,7 +20,6 @@ TABS.magnetometer.initialize = function (callback) { if (GUI.active_tab != 'magnetometer') { GUI.active_tab = 'magnetometer'; - googleAnalytics.sendAppView('MAGNETOMETER'); } self.alignmentConfig = { @@ -26,7 +36,7 @@ TABS.magnetometer.initialize = function (callback) { self.pageElements = {}; self.isSavePreset = true; - self.showMagnetometer = true; + self.elementToShow = 0; //======================== // Load chain // ======================= @@ -36,9 +46,9 @@ TABS.magnetometer.initialize = function (callback) { mspHelper.loadMixerConfig, mspHelper.loadBoardAlignment, function (callback) { - self.boardAlignmentConfig.pitch = Math.round(BOARD_ALIGNMENT.pitch / 10); - self.boardAlignmentConfig.roll = Math.round(BOARD_ALIGNMENT.roll / 10); - self.boardAlignmentConfig.yaw = Math.round(BOARD_ALIGNMENT.yaw / 10); + self.boardAlignmentConfig.pitch = Math.round(FC.BOARD_ALIGNMENT.pitch / 10); + self.boardAlignmentConfig.roll = Math.round(FC.BOARD_ALIGNMENT.roll / 10); + self.boardAlignmentConfig.yaw = Math.round(FC.BOARD_ALIGNMENT.yaw / 10); callback(); }, mspHelper.loadSensorAlignment, @@ -79,16 +89,16 @@ TABS.magnetometer.initialize = function (callback) { var saveChain = [ function (callback) { - BOARD_ALIGNMENT.pitch = self.boardAlignmentConfig.pitch * 10; - BOARD_ALIGNMENT.roll = self.boardAlignmentConfig.roll * 10; - BOARD_ALIGNMENT.yaw = self.boardAlignmentConfig.yaw * 10; + FC.BOARD_ALIGNMENT.pitch = self.boardAlignmentConfig.pitch * 10; + FC.BOARD_ALIGNMENT.roll = self.boardAlignmentConfig.roll * 10; + FC.BOARD_ALIGNMENT.yaw = self.boardAlignmentConfig.yaw * 10; callback(); }, mspHelper.saveBoardAlignment, // Magnetometer alignment function (callback) { let orientation_mag_e = $('select.magalign'); - SENSOR_ALIGNMENT.align_mag = parseInt(orientation_mag_e.val()); + FC.SENSOR_ALIGNMENT.align_mag = parseInt(orientation_mag_e.val()); callback(); }, mspHelper.saveSensorAlignment, @@ -126,7 +136,7 @@ TABS.magnetometer.initialize = function (callback) { function reboot() { //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('configurationEepromSaved')); + GUI.log(i18n.getMessage('configurationEepromSaved')); GUI.tab_switch_cleanup(function () { MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, reinitialize); @@ -134,12 +144,12 @@ TABS.magnetometer.initialize = function (callback) { } function reinitialize() { - GUI.log(chrome.i18n.getMessage('deviceRebooting')); + GUI.log(i18n.getMessage('deviceRebooting')); GUI.handleReconnect($('.tab_magnetometer a')); } function load_html() { - GUI.load("./tabs/magnetometer.html", process_html); + GUI.load(path.join(__dirname, "magnetometer.html"), process_html); } function generateRange(min, max, step) { @@ -151,6 +161,7 @@ TABS.magnetometer.initialize = function (callback) { } function toUpperRange(input, max) { + if (!Number.isFinite(input)) return 0; while (input > max) input -= 360; while (input + 360 <= max) input += 360; return input; @@ -179,7 +190,7 @@ TABS.magnetometer.initialize = function (callback) { return [180, 0, 180]; case 0: //ALIGN_DEFAULT = 0 case 8: //CW270_DEG_FLIP = 5 - default://If not recognized, returns defualt + default://If not recognized, returns default return [180, 0, 270]; } } @@ -215,16 +226,24 @@ TABS.magnetometer.initialize = function (callback) { function updateMagOrientationWithPreset() { if (self.isSavePreset) { - const degrees = getAxisDegreeWithPresetAndBoardOrientation(SENSOR_ALIGNMENT.align_mag); + const degrees = getAxisDegreeWithPresetAndBoardOrientation(FC.SENSOR_ALIGNMENT.align_mag); presetUpdated(degrees); } } + function updateFCCliString() { + var s = " align_board_roll=" + (self.boardAlignmentConfig.roll * 10) + + " align_board_pitch=" + (self.boardAlignmentConfig.pitch * 10) + + " align_board_yaw=" + (self.boardAlignmentConfig.yaw * 10); + self.pageElements.cli_settings_fc.text(s); + } + function updateBoardRollAxis(value) { self.boardAlignmentConfig.roll = Number(value); self.pageElements.board_roll_slider.val(self.boardAlignmentConfig.roll); self.pageElements.orientation_board_roll.val(self.boardAlignmentConfig.roll); updateMagOrientationWithPreset(); + updateFCCliString(); self.render3D(); } @@ -233,6 +252,7 @@ TABS.magnetometer.initialize = function (callback) { self.pageElements.board_pitch_slider.val(self.boardAlignmentConfig.pitch); self.pageElements.orientation_board_pitch.val(self.boardAlignmentConfig.pitch); updateMagOrientationWithPreset(); + updateFCCliString(); self.render3D(); } @@ -241,14 +261,31 @@ TABS.magnetometer.initialize = function (callback) { self.pageElements.board_yaw_slider.val(self.boardAlignmentConfig.yaw); self.pageElements.orientation_board_yaw.val(self.boardAlignmentConfig.yaw); updateMagOrientationWithPreset(); + updateFCCliString(); self.render3D(); } + + function updateMagCliString() { + var fix = 0; + if ( areAnglesZero() ) { + fix = 1; //if all angles are 0, then we have to save yaw = 1 (0.1 deg) to enforce usage of angles, not a usage of preset + } + var names = ['DEFAULT', 'CW0', 'CW90', 'CW180', 'CW270', 'CW0FLIP', 'CW90FLIP', 'CW180FLIP', 'CW270FLIP']; + var s = "align_mag=" + names[FC.SENSOR_ALIGNMENT.align_mag] + + " align_mag_roll=" + (self.isSavePreset ? 0 : self.alignmentConfig.roll * 10) + + " align_mag_pitch=" + (self.isSavePreset ? 0 : self.alignmentConfig.pitch * 10) + + " align_mag_yaw=" + (self.isSavePreset ? 0 : self.alignmentConfig.yaw * 10 + fix); + self.pageElements.cli_settings_mag.text(s); + self.pageElements.comment_sensor_mag_preset.css("display", !self.isSavePreset ? "none" : ""); + self.pageElements.comment_sensor_mag_angles.css("display", self.isSavePreset ? "none" : ""); + } //Called when roll values change function updateRollAxis(value) { self.alignmentConfig.roll = Number(value); self.pageElements.roll_slider.val(self.alignmentConfig.roll); self.pageElements.orientation_mag_roll.val(self.alignmentConfig.roll); + updateMagCliString(); self.render3D(); } @@ -257,6 +294,7 @@ TABS.magnetometer.initialize = function (callback) { self.alignmentConfig.pitch = Number(value); self.pageElements.pitch_slider.val(self.alignmentConfig.pitch); self.pageElements.orientation_mag_pitch.val(self.alignmentConfig.pitch); + updateMagCliString(); self.render3D(); } @@ -265,6 +303,7 @@ TABS.magnetometer.initialize = function (callback) { self.alignmentConfig.yaw = Number(value); self.pageElements.yaw_slider.val(self.alignmentConfig.yaw); self.pageElements.orientation_mag_yaw.val(self.alignmentConfig.yaw); + updateMagCliString(); self.render3D(); } @@ -272,12 +311,16 @@ TABS.magnetometer.initialize = function (callback) { self.isSavePreset = true; self.pageElements.orientation_mag_e.css("opacity", 1); self.pageElements.orientation_mag_e.css("text-decoration", ""); + self.pageElements.align_mag_xxx_e.css("opacity", "0.65"); + self.pageElements.align_mag_xxx_e.css("text-decoration", "line-through"); } function disableSavePreset() { self.isSavePreset = false; self.pageElements.orientation_mag_e.css("opacity", 0.5); self.pageElements.orientation_mag_e.css("text-decoration", "line-through"); + self.pageElements.align_mag_xxx_e.css("opacity", "1"); + self.pageElements.align_mag_xxx_e.css("text-decoration", ""); } @@ -287,12 +330,13 @@ TABS.magnetometer.initialize = function (callback) { updatePitchAxis(degrees[0]); updateRollAxis(degrees[1]); updateYawAxis(degrees[2]); + updateMagCliString(); } function process_html() { - localize(); + i18n.localize();; // initialize 3D self.initialize3D(); @@ -314,19 +358,27 @@ TABS.magnetometer.initialize = function (callback) { self.pageElements.pitch_slider = $('#pitch_slider'); self.pageElements.yaw_slider = $('#yaw_slider'); + self.pageElements.align_mag_xxx_e = $('#align_mag_xxx'); + + self.pageElements.cli_settings_fc = $('#cli_settings_fc'); + self.pageElements.cli_settings_mag = $('#cli_settings_mag'); + + self.pageElements.comment_sensor_mag_preset = $('#comment_sensor_mag_preset'); + self.pageElements.comment_sensor_mag_angles = $('#comment_sensor_mag_angles'); + self.roll_e = $('dd.roll'), self.pitch_e = $('dd.pitch'), self.heading_e = $('dd.heading'); - for (i = 0; i < alignments.length; i++) { + for (let i = 0; i < alignments.length; i++) { self.pageElements.orientation_mag_e.append(''); } - self.pageElements.orientation_mag_e.val(SENSOR_ALIGNMENT.align_mag); + self.pageElements.orientation_mag_e.val(FC.SENSOR_ALIGNMENT.align_mag); if (areAnglesZero()) { //If using a preset, checking if custom values are equal to 0 //Update the slider, but don't save the value until they will be not modified. - const degrees = getAxisDegreeWithPresetAndBoardOrientation(SENSOR_ALIGNMENT.align_mag); + const degrees = getAxisDegreeWithPresetAndBoardOrientation(FC.SENSOR_ALIGNMENT.align_mag); presetUpdated(degrees); } else { @@ -337,15 +389,15 @@ TABS.magnetometer.initialize = function (callback) { } - self.pageElements.orientation_board_roll.change(function () { + self.pageElements.orientation_board_roll.on('change', function () { updateBoardRollAxis(clamp(this, -180, 360)); }); - self.pageElements.orientation_board_pitch.change(function () { + self.pageElements.orientation_board_pitch.on('change', function () { updateBoardPitchAxis(clamp(this, -180, 360)); }); - self.pageElements.orientation_board_yaw.change(function () { + self.pageElements.orientation_board_yaw.on('change', function () { updateBoardYawAxis(clamp(this, -180, 360)); }); @@ -406,9 +458,9 @@ TABS.magnetometer.initialize = function (callback) { }); const elementToShow = $("#element_to_show"); - elementToShow.change(function () { + elementToShow.on('change', function () { const value = parseInt($(this).val()); - self.showMagnetometer = (value == 0); + self.elementToShow = value; self.render3D(); }); @@ -416,33 +468,33 @@ TABS.magnetometer.initialize = function (callback) { return Math.min(Math.max(parseInt($(input).val()), min), max); } - self.pageElements.orientation_mag_e.change(function () { - SENSOR_ALIGNMENT.align_mag = parseInt($(this).val()); - const degrees = getAxisDegreeWithPresetAndBoardOrientation(SENSOR_ALIGNMENT.align_mag); + self.pageElements.orientation_mag_e.on('change', function () { + FC.SENSOR_ALIGNMENT.align_mag = parseInt($(this).val()); + const degrees = getAxisDegreeWithPresetAndBoardOrientation(FC.SENSOR_ALIGNMENT.align_mag); presetUpdated(degrees); }); self.pageElements.orientation_mag_e.on('mousedown', function () { - const degrees = getAxisDegreeWithPresetAndBoardOrientation(SENSOR_ALIGNMENT.align_mag); + const degrees = getAxisDegreeWithPresetAndBoardOrientation(FC.SENSOR_ALIGNMENT.align_mag); presetUpdated(degrees); }); - self.pageElements.orientation_mag_roll.change(function () { + self.pageElements.orientation_mag_roll.on('change', function () { disableSavePreset(); updateRollAxis(clamp(this, -180, 360)); }); - self.pageElements.orientation_mag_pitch.change(function () { + self.pageElements.orientation_mag_pitch.on('change', function () { disableSavePreset(); updatePitchAxis(clamp(this, -180, 360)); }); - self.pageElements.orientation_mag_yaw.change(function () { + self.pageElements.orientation_mag_yaw.on('change', function () { disableSavePreset(); updateYawAxis(clamp(this, -180, 360)); }); - $('a.save').click(function () { + $('a.save').on('click', function () { saveChainer.execute() }); @@ -513,19 +565,16 @@ TABS.magnetometer.initialize = function (callback) { }); function get_fast_data() { - if (helper.mspQueue.shouldDrop()) { - return; - } MSP.send_message(MSPCodes.MSP_ATTITUDE, false, false, function () { - self.roll_e.text(chrome.i18n.getMessage('initialSetupAttitude', [SENSOR_DATA.kinematics[0]])); - self.pitch_e.text(chrome.i18n.getMessage('initialSetupAttitude', [SENSOR_DATA.kinematics[1]])); - self.heading_e.text(chrome.i18n.getMessage('initialSetupAttitude', [SENSOR_DATA.kinematics[2]])); + self.roll_e.text(i18n.getMessage('initialSetupAttitude', [FC.SENSOR_DATA.kinematics[0]])); + self.pitch_e.text(i18n.getMessage('initialSetupAttitude', [FC.SENSOR_DATA.kinematics[1]])); + self.heading_e.text(i18n.getMessage('initialSetupAttitude', [FC.SENSOR_DATA.kinematics[2]])); self.render3D(); }); } - helper.mspBalancedInterval.add('setup_data_pull_fast', 40, 1, get_fast_data); + interval.add('setup_data_pull_fast', get_fast_data, 40); GUI.content_ready(callback); } @@ -543,8 +592,7 @@ TABS.magnetometer.initialize3D = function () { model_file, camera, scene, - gps, - xyz, + magModels, fc, useWebGlRenderer = false; @@ -571,12 +619,12 @@ TABS.magnetometer.initialize3D = function () { // load the model including materials if (useWebGlRenderer) { - if (MIXER_CONFIG.appliedMixerPreset === -1) { + if (FC.MIXER_CONFIG.appliedMixerPreset === -1) { model_file = 'custom'; - GUI_control.prototype.log("" + chrome.i18n.getMessage("mixerNotConfigured") + ""); + GUI_control.prototype.log("" + i18n.getMessage("mixerNotConfigured") + ""); } else { - model_file = helper.mixer.getById(MIXER_CONFIG.appliedMixerPreset).model; + model_file = mixer.getById(FC.MIXER_CONFIG.appliedMixerPreset).model; } } else { @@ -590,11 +638,10 @@ TABS.magnetometer.initialize3D = function () { this.render3D = function () { - if (!gps || !xyz || !fc) + if (!magModels || !fc) return; - gps.visible = self.showMagnetometer; - xyz.visible = !self.showMagnetometer; + magModels.forEach( (m,i) => m.visible = i == self.elementToShow ); fc.visible = true; var magRotation = new THREE.Euler(-THREE.Math.degToRad(self.alignmentConfig.pitch-180), THREE.Math.degToRad(-180 - self.alignmentConfig.yaw), THREE.Math.degToRad(self.alignmentConfig.roll), 'YXZ'); @@ -608,8 +655,7 @@ TABS.magnetometer.initialize3D = function () { matrix.premultiply(matrix1); //preset specifies orientation relative to FC, align_max_xxx specify absolute orientation } */ - gps.rotation.setFromRotationMatrix(matrix); - xyz.rotation.setFromRotationMatrix(matrix); + magModels.forEach( (m,i) => m.rotation.setFromRotationMatrix(matrix) ); fc.rotation.setFromRotationMatrix(matrix1); // draw @@ -623,7 +669,7 @@ TABS.magnetometer.initialize3D = function () { camera.aspect = wrapper.width() / wrapper.height(); camera.updateProjectionMatrix(); - this.render3D(); + self.render3D(); }; $(window).on('resize', this.resize3D); @@ -684,6 +730,11 @@ TABS.magnetometer.initialize3D = function () { const manager = new THREE.LoadingManager(); const loader = new THREE.GLTFLoader(manager); + const magModelNames = ['xyz', 'ak8963c', 'ak8963n', 'ak8975', 'ak8975c', 'bn_880', 'diatone_mamba_m10_pro', 'flywoo_goku_m10_pro_v3', 'foxeer_m10q_120', 'foxeer_m10q_180', 'foxeer_m10q_250', + 'geprc_gep_m10_dq', 'gy271', 'gy273', 'hglrc_m100', 'qmc5883', 'holybro_m9n_micro', 'holybro_m9n_micro', 'ist8308', 'ist8310', 'lis3mdl', + 'mag3110', 'matek_m8q', 'matek_m9n', 'matek_m10q', 'mlx90393', 'mp9250', 'qmc5883', 'flywoo_goku_m10_pro_v3', 'ws_m181']; + magModels = []; + //Load the UAV model loader.load('./resources/models/' + model_file + '.gltf', (obj) => { const model = obj.scene; @@ -693,30 +744,22 @@ TABS.magnetometer.initialize3D = function () { const gpsOffset = getDistanceByModelName(model_file); - //Load the GPS model - loader.load('./resources/models/gps.gltf', (obj) => { - gps = obj.scene; - const scaleFactor = 0.04; - gps.scale.set(scaleFactor, scaleFactor, scaleFactor); - gps.position.set(gpsOffset[0], gpsOffset[1] + 0.5, gpsOffset[2]); - gps.traverse(child => { - if (child.material) child.material.metalness = 0; + magModelNames.forEach( (name, i) => + { + loader.load('./resources/models/' + name + '.gltf', (obj) => { + const gps = obj.scene; + const scaleFactor = i==0 ? 0.03 : 0.04; + gps.scale.set(scaleFactor, scaleFactor, scaleFactor); + gps.position.set(gpsOffset[0], gpsOffset[1] + 0.5, gpsOffset[2]); + gps.traverse(child => { + if (child.material) child.material.metalness = 0; + }); + gps.rotation.y = 3 * Math.PI / 2; + model.add(gps); + magModels[i]=gps; + this.resize3D(); }); - gps.rotation.y = 3 * Math.PI / 2; - model.add(gps); - this.resize3D(); - }); - - //Load the XYZ model - loader.load('./resources/models/xyz.gltf', (obj) => { - xyz = obj.scene; - const scaleFactor = 0.04; - xyz.scale.set(scaleFactor, scaleFactor, scaleFactor); - xyz.position.set(gpsOffset[0], gpsOffset[1] + 0.5, gpsOffset[2]); - xyz.rotation.y = 3 * Math.PI / 2; - model.add(xyz); - this.render3D(); - }); + }); //Load the FC model loader.load('./resources/models/fc.gltf', (obj) => { diff --git a/tabs/mission_control.html b/tabs/mission_control.html index c1f4824be..94c0a9138 100644 --- a/tabs/mission_control.html +++ b/tabs/mission_control.html @@ -19,8 +19,8 @@
diff --git a/tabs/mission_control.js b/tabs/mission_control.js index a9822dd84..1c277977c 100644 --- a/tabs/mission_control.js +++ b/tabs/mission_control.js @@ -1,48 +1,37 @@ 'use strict'; -//////////////////////////////////// -// -// global Parameters definition -// -//////////////////////////////////// - - -// MultiWii NAV Protocol -var MWNP = MWNP || {}; +const path = require('path'); +const fs = require('fs'); +const ol = require('openlayers'); +const xml2js = require('xml2js'); +const Store = require('electron-store'); +const store = new Store(); +const { dialog } = require("@electron/remote"); + +const MSPChainerClass = require('./../js/msp/MSPchainer'); +const mspHelper = require('./../js/msp/MSPHelper'); +const MSPCodes = require('./../js/msp/MSPCodes'); +const MSP = require('./../js/msp'); +const mspQueue = require('./../js/serial_queue'); +const { GUI, TABS } = require('./../js/gui'); +const FC = require('./../js/fc'); +const CONFIGURATOR = require('./../js/data_storage'); +const i18n = require('./../js/localization'); +const { globalSettings } = require('./../js/globalSettings'); +const MWNP = require('./../js/mwnp'); +const Waypoint = require('./../js/waypoint') +const WaypointCollection = require('./../js/waypointCollection'); +const Safehome = require('./../js/safehome'); +const SafehomeCollection = require('./../js/safehomeCollection'); +const { ApproachDirection, FwApproach } = require('./../js/fwApproach'); +const FwApproachCollection = require('./../js/fwApproachCollection'); +const SerialBackend = require('./../js/serial_backend'); +const { distanceOnLine, wrap_360, calculate_new_cooridatnes } = require('./../js/helpers'); +const Plotly = require('./../js/libraries/plotly-latest.min'); +const interval = require('./../js/intervals'); var MAX_NEG_FW_LAND_ALT = -2000; // cm -// WayPoint type -MWNP.WPTYPE = { - WAYPOINT: 1, - POSHOLD_UNLIM: 2, - POSHOLD_TIME: 3, - RTH: 4, - SET_POI: 5, - JUMP: 6, - SET_HEAD: 7, - LAND: 8 -}; - -MWNP.P3 = { - ALT_TYPE: 0, // Altitude (alt) : Relative (to home altitude) (0) or Absolute (AMSL) (1). - USER_ACTION_1: 1, // WP Action 1 - USER_ACTION_2: 2, // WP Action 2 - USER_ACTION_3: 3, // WP Action 3 - USER_ACTION_4: 4, // WP Action 4 -} - -// Reverse WayPoint type dictionary -function swap(dict) { - let rev_dict = {}; - for (let key in dict) { - rev_dict[dict[key]] = key; - } - return rev_dict; -} - -MWNP.WPTYPE.REV = swap(MWNP.WPTYPE); - // Dictionary of Parameter 1,2,3 definition depending on type of action selected (refer to MWNP.WPTYPE) var dictOfLabelParameterPoint = { 1: {parameter1: 'Speed (cm/s)', parameter2: '', parameter3: 'Sea level Ref'}, @@ -80,12 +69,13 @@ TABS.mission_control.initialize = function (callback) { let textFeature; var textGeom; let isOffline = false; - let rthUpdateInterval = 0; + let selectedSafehome; + let $safehomeContentBox; + let $waypointOptionsTableBody; let settings = {speed: 0, alt: 5000, safeRadiusSH: 50, fwApproachAlt: 60, fwLandAlt: 5, maxDistSH: 0, fwApproachLength: 0, fwLoiterRadius: 0, bingDemModel: false}; if (GUI.active_tab != 'mission_control') { GUI.active_tab = 'mission_control'; - googleAnalytics.sendAppView('Mission Control'); } if (CONFIGURATOR.connectionValid) { @@ -117,19 +107,19 @@ TABS.mission_control.initialize = function (callback) { // FC not connected, load page anyway loadHtml(); - if (!FW_APPROACH) { - FW_APPROACH = new FwApproachCollection(); + if (!FC.FW_APPROACH) { + FC.FW_APPROACH = new FwApproachCollection(); } - if (!SAFEHOMES) { - SAFEHOMES = new SafehomeCollection(); + if (!FC.SAFEHOMES) { + FC.SAFEHOMES = new SafehomeCollection(); } - for (let i = 0; i < FW_APPROACH.getMaxFwApproachCount(); i++){ - FW_APPROACH.put(new FwApproach(i)); + for (let i = 0; i < FC.FW_APPROACH.getMaxFwApproachCount(); i++){ + FC.FW_APPROACH.put(new FwApproach(i)); } } function loadHtml() { - GUI.load("./tabs/mission_control.html", process_html); + GUI.load(path.join(__dirname, "mission_control.html"), process_html); } function process_html() { @@ -146,7 +136,6 @@ TABS.mission_control.initialize = function (callback) { } $safehomeContentBox = $('#SafehomeContentBox'); - $waypointOptionsTable = $('.waypointOptionsTable'); $waypointOptionsTableBody = $('#waypointOptionsTableBody'); if (typeof require !== "undefined") { @@ -155,7 +144,7 @@ TABS.mission_control.initialize = function (callback) { setTimeout(initMap, 200); if (!isOffline) { setTimeout(() => { - if (SAFEHOMES.safehomeCount() >= 1) { + if (FC.SAFEHOMES.safehomeCount() >= 1) { updateSelectedShAndFwAp(0); } else { selectedSafehome = null; @@ -169,7 +158,7 @@ TABS.mission_control.initialize = function (callback) { $('#missionMap, #missionControls').hide(); $('#notLoadMap').show(); } - localize(); + i18n.localize(); function get_raw_gps_data() { MSP.send_message(MSPCodes.MSP_RAW_GPS, false, false, get_comp_gps_data); @@ -190,11 +179,11 @@ TABS.mission_control.initialize = function (callback) { function update_gpsTrack() { - let lat = GPS_DATA.lat / 10000000; - let lon = GPS_DATA.lon / 10000000; + let lat = FC.GPS_DATA.lat / 10000000; + let lon = FC.GPS_DATA.lon / 10000000; //Update map - if (GPS_DATA.fix >= 2) { + if (FC.GPS_DATA.fix >= 2) { if (!cursorInitialized) { cursorInitialized = true; @@ -206,7 +195,7 @@ TABS.mission_control.initialize = function (callback) { anchor: [0.5, 0.5], opacity: 1, scale: 0.6, - src: '../images/icons/icon_mission_airplane.png' + src: './images/icons/icon_mission_airplane.png' })) }); @@ -233,7 +222,7 @@ TABS.mission_control.initialize = function (callback) { anchor: [0.5, 1.0], opacity: 1, scale: 0.5, - src: '../images/icons/cf_icon_RTH.png' + src: './images/icons/cf_icon_RTH.png' })) }); @@ -328,28 +317,16 @@ TABS.mission_control.initialize = function (callback) { breadCrumbLS.setCoordinates(coords); } - curPosStyle.getImage().setRotation((SENSOR_DATA.kinematics[2]/360.0) * 6.28318); + curPosStyle.getImage().setRotation((FC.SENSOR_DATA.kinematics[2]/360.0) * 6.28318); //update data text textGeom.setCoordinates(map.getCoordinateFromPixel([0,0])); let tmpText = textStyle.getText(); tmpText.setText(' \n' + - 'H: ' + SENSOR_DATA.kinematics[2] + - '\nAlt: ' + SENSOR_DATA.altitude + - 'm\nSpeed: ' + GPS_DATA.speed + 'cm/s\n' + - 'Dist: ' + GPS_DATA.distanceToHome + 'm'); - - //update RTH every 5th GPS update since it really shouldn't change - if(rthUpdateInterval >= 5) - { - MISSION_PLANNER.bufferPoint.number = -1; //needed to get point 0 which id RTH - MSP.send_message(MSPCodes.MSP_WP, mspHelper.crunch(MSPCodes.MSP_WP), false, function rth_update() { - var coord = ol.proj.fromLonLat([MISSION_PLANNER.bufferPoint.lon, MISSION_PLANNER.bufferPoint.lat]); - rthGeo.setCoordinates(coord); - }); - rthUpdateInterval = 0; - } - rthUpdateInterval++; + 'H: ' + FC.SENSOR_DATA.kinematics[2] + + '\nAlt: ' + FC.SENSOR_DATA.altitude + + 'm\nSpeed: ' + FC.GPS_DATA.speed + 'cm/s\n' + + 'Dist: ' + FC.GPS_DATA.distanceToHome + 'm'); } } @@ -359,19 +336,15 @@ TABS.mission_control.initialize = function (callback) { */ if(!isOffline) { - helper.mspBalancedInterval.add('gps_pull', 200, 3, function gps_update() { + interval.add('gps_pull', function gps_update() { // avoid usage of the GPS commands until a GPS sensor is detected for targets that are compiled without GPS support. - if (!have_sensor(CONFIG.activeSensors, 'gps')) { + if (!SerialBackend.have_sensor(FC.CONFIG.activeSensors, 'gps')) { update_gpsTrack(); return; } - if (helper.mspQueue.shouldDrop()) { - return; - } - get_raw_gps_data(); - }); + }, 200); } GUI.content_ready(callback); @@ -435,8 +408,8 @@ TABS.mission_control.initialize = function (callback) { ////////////////////////////////////////////////////////////////////////////////////////////// // define & init Safehome parameters ////////////////////////////////////////////////////////////////////////////////////////////// - //var SAFEHOMES = new SafehomeCollection(); // TO COMMENT FOR RELEASE : DECOMMENT FOR DEBUG - //SAFEHOMES.inflate(); // TO COMMENT FOR RELEASE : DECOMMENT FOR DEBUG + //var FC.SAFEHOMES = new SafehomeCollection(); // TO COMMENT FOR RELEASE : DECOMMENT FOR DEBUG + //FC.SAFEHOMES.inflate(); // TO COMMENT FOR RELEASE : DECOMMENT FOR DEBUG //var safehomeRangeRadius = 200; //meters //var safehomeSafeRadius = 50; //meters @@ -466,23 +439,21 @@ TABS.mission_control.initialize = function (callback) { // ///////////////////////////////////////////// function loadSettings() { - chrome.storage.local.get('missionPlannerSettings', function (result) { - if (result.missionPlannerSettings) { - if (!result.missionPlannerSettings.fwApproachLength && settings.fwApproachLength) { - result.missionPlannerSettings.fwApproachLength = settings.fwApproachLength; - result.missionPlannerSettings.maxDistSH = settings.maxDistSH; - result.missionPlannerSettings.fwLoiterRadius = settings.fwLoiterRadius; - } - saveSettings(); - settings = result.missionPlannerSettings; + var missionPlannerSettings = store.get('missionPlannerSettings', false); + if (missionPlannerSettings) { + if (!missionPlannerSettings.fwApproachLength && settings.fwApproachLength) { + missionPlannerSettings.fwApproachLength = settings.fwApproachLength; + missionPlannerSettings.maxDistSH = settings.maxDistSH; + missionPlannerSettings.fwLoiterRadius = settings.fwLoiterRadius; } - - refreshSettings(); - }); + saveSettings(); + settings = missionPlannerSettings; + } + refreshSettings(); } function saveSettings() { - chrome.storage.local.set({'missionPlannerSettings': settings}); + store.set('missionPlannerSettings', settings); } function refreshSettings() { @@ -510,7 +481,7 @@ TABS.mission_control.initialize = function (callback) { function checkApproachAltitude(altitude, isSeaLevelRef, sealevel) { if (altitude - (isSeaLevelRef ? sealevel * 100 : 0 ) < 0) { - alert(chrome.i18n.getMessage('MissionPlannerAltitudeChangeReset')); + GUI.alert(i18n.getMessage('MissionPlannerAltitudeChangeReset')); return false; } @@ -520,7 +491,7 @@ TABS.mission_control.initialize = function (callback) { function checkLandingAltitude(altitude, isSeaLevelRef, sealevel) { if (altitude - (isSeaLevelRef ? sealevel * 100 : 0 ) < MAX_NEG_FW_LAND_ALT) { - alert(chrome.i18n.getMessage('MissionPlannerFwLAndingAltitudeChangeReset')); + GUI.alert(i18n.getMessage('MissionPlannerFwLAndingAltitudeChangeReset')); return false; } @@ -528,8 +499,8 @@ TABS.mission_control.initialize = function (callback) { } function updateSafehomeInfo(){ - let freeSamehomes = SAFEHOMES.getMaxSafehomeCount() - SAFEHOMES.safehomeCount() - $('#availableSafehomes').text(freeSamehomes + '/' + SAFEHOMES.getMaxSafehomeCount()); + let freeSamehomes = FC.SAFEHOMES.getMaxSafehomeCount() - FC.SAFEHOMES.safehomeCount() + $('#availableSafehomes').text(freeSamehomes + '/' + FC.SAFEHOMES.getMaxSafehomeCount()); } @@ -537,10 +508,10 @@ TABS.mission_control.initialize = function (callback) { /* * Process safehome on Map */ - SAFEHOMES.get().forEach(safehome => { - addFwApproach(safehome.getLonMap(), safehome.getLatMap(), FW_APPROACH.get()[safehome.getNumber()], safehomeMarkers); + FC.SAFEHOMES.get().forEach(safehome => { + addFwApproach(safehome.getLonMap(), safehome.getLatMap(), FC.FW_APPROACH.get()[safehome.getNumber()], safehomeMarkers); }); - SAFEHOMES.get().forEach(safehome => { + FC.SAFEHOMES.get().forEach(safehome => { addSafehomeCircles(safehome); addSafeHomeMarker(safehome); }); @@ -562,7 +533,7 @@ TABS.mission_control.initialize = function (callback) { anchor: [0.5, 1], opacity: 1, scale: 0.5, - src: '../images/icons/cf_icon_safehome' + (safehome.isUsed() ? '_used' : '')+ '.png' + src: './images/icons/cf_icon_safehome' + (safehome.isUsed() ? '_used' : '')+ '.png' })), text: new ol.style.Text(({ text: String(Number(safehome.getNumber())+1), @@ -793,13 +764,13 @@ TABS.mission_control.initialize = function (callback) { * Process home table UI */ - $(".home-lat").val(HOME.getLatMap()).change(function () { + $(".home-lat").val(HOME.getLatMap()).on('change', function () { HOME.setLat(Math.round(Number($(this).val()) * 10000000)); cleanHomeLayers(); renderHomeOnMap(); }); - $(".home-lon").val(HOME.getLonMap()).change(function () { + $(".home-lon").val(HOME.getLonMap()).on('change', function () { HOME.setLon(Math.round(Number($(this).val()) * 10000000)); cleanHomeLayers(); renderHomeOnMap(); @@ -871,7 +842,7 @@ TABS.mission_control.initialize = function (callback) { anchor: [0.5, 1], opacity: 1, scale: 0.5, - src: '../images/icons/cf_icon_home.png' + src: './images/icons/cf_icon_home.png' })), }); } @@ -1022,7 +993,7 @@ TABS.mission_control.initialize = function (callback) { }); mission.reinit(); - tempMissionData = multimission.get().slice(startWPCount, endWPCount + 1); // copy selected single mission from MM + var tempMissionData = multimission.get().slice(startWPCount, endWPCount + 1); // copy selected single mission from MM let i = 0; tempMissionData.forEach(function (element) { // write mission copy to active map mission mission.put(element); @@ -1052,7 +1023,7 @@ TABS.mission_control.initialize = function (callback) { MMCount ++; } }); - $('#multimissionOptionList').val(MMCount).change(); + $('#multimissionOptionList').val(MMCount).trigger('change'); } function deleteMultimission() { @@ -1095,14 +1066,23 @@ TABS.mission_control.initialize = function (callback) { function fileLoadMultiMissionCheck() { if (singleMissionActive()) { return true; - } else if (confirm(chrome.i18n.getMessage('confirm_overwrite_multimission_file_load_option'))) { - nwdialog.setContext(document); - nwdialog.openFileDialog(function(result) { - loadMissionFile(result); - multimissionCount = 0; - multimission.flush(); - renderMultimissionTable(); - }) + } else if (confirm(i18n.getMessage('confirm_overwrite_multimission_file_load_option'))) { + var options = { + filters: [ { name: "Mission file", extensions: ['mission'] } ] + }; + dialog.showOpenDialog(options).then(result => { + if (result.canceled) { + console.log('No file selected'); + return; + } + + if (result.filePaths.length == 1) { + loadMissionFile(result.filePaths[0]); + multimissionCount = 0; + multimission.flush(); + renderMultimissionTable(); + } + }); } return false; } @@ -1176,7 +1156,7 @@ TABS.mission_control.initialize = function (callback) { anchor: [0.5, 1], opacity: 1, scale: 0.5, - src: '../images/icons/cf_icon_position' + (dictofPointIcon[waypoint.getAction()] != '' ? '_'+dictofPointIcon[waypoint.getAction()] : '') + (isEdit ? '_edit' : '')+ '.png' + src: './images/icons/cf_icon_position' + (dictofPointIcon[waypoint.getAction()] != '' ? '_'+dictofPointIcon[waypoint.getAction()] : '') + (isEdit ? '_edit' : '')+ '.png' })), text: new ol.style.Text(({ text: String(Number(waypoint.getLayerNumber()+1)), @@ -1220,15 +1200,15 @@ TABS.mission_control.initialize = function (callback) { // If one is POI, draw orange line in-between and modulate dashline each time a new POI is defined else if (typeof oldPos !== 'undefined' && activatePoi == true && activateHead != true) { if ((poiList.length % 2) == 0) { - paintLine(oldPos, coord, element.getNumber(), color='#ffb725', lineDash=5); + paintLine(oldPos, coord, element.getNumber(), '#ffb725', 5); } else { - paintLine(oldPos, coord, element.getNumber(), color='#ffb725'); + paintLine(oldPos, coord, element.getNumber(), '#ffb725'); } } // If one is SET_HEAD, draw labelled line in-between with heading value else if (typeof oldPos !== 'undefined' && activatePoi != true && activateHead == true) { - paintLine(oldPos, coord, element.getNumber(), color='#1497f1', lineDash=0, lineText=String(oldHeading)+"°"); + paintLine(oldPos, coord, element.getNumber(), '#1497f1', 0, String(oldHeading)+"°"); } if (element.getEndMission() == 0xA5) { @@ -1245,7 +1225,7 @@ TABS.mission_control.initialize = function (callback) { if (element.getAction() == MWNP.WPTYPE.JUMP) { let jumpWPIndex = multiMissionWPNum + element.getP1(); let coord = ol.proj.fromLonLat([mission.getWaypoint(jumpWPIndex).getLonMap(), mission.getWaypoint(jumpWPIndex).getLatMap()]); - paintLine(oldPos, coord, element.getNumber(), color='#e935d6', lineDash=5, lineText="Repeat x"+(element.getP2() == -1 ? " infinite" : String(element.getP2())), selection=false, arrow=true); + paintLine(oldPos, coord, element.getNumber(), '#e935d6', 5, "Repeat x"+(element.getP2() == -1 ? " infinite" : String(element.getP2())), false, true); } // If classic WPs is defined with a heading = -1, change Boolean for POI to false. If it is defined with a value different from -1, activate Heading boolean else if (element.getAction() == MWNP.WPTYPE.SET_HEAD) { @@ -1269,7 +1249,7 @@ TABS.mission_control.initialize = function (callback) { } } if (element.getAction() == MWNP.WPTYPE.LAND) { - addFwApproach(element.getLonMap(), element.getLatMap(), FW_APPROACH.get()[SAFEHOMES.getMaxSafehomeCount() + element.getMultiMissionIdx()], lines); + addFwApproach(element.getLonMap(), element.getLatMap(), FC.FW_APPROACH.get()[FC.SAFEHOMES.getMaxSafehomeCount() + element.getMultiMissionIdx()], lines); } }); //reset text position @@ -1281,7 +1261,11 @@ TABS.mission_control.initialize = function (callback) { if (disableMarkerEdit) { $('#missionDistance').text('N/A'); } else { - $('#missionDistance').text(lengthMission[lengthMission.length -1] != -1 ? lengthMission[lengthMission.length -1].toFixed(1) : 'infinite'); + if (lengthMission.length >= 1) { + $('#missionDistance').text(lengthMission[lengthMission.length -1].toFixed(1)); + } else { + $('#missionDistance').text('infinite'); + } } } @@ -1321,7 +1305,7 @@ TABS.mission_control.initialize = function (callback) { featureArrow.setStyle( new ol.style.Style({ image: new ol.style.Icon({ - src: '../images/icons/cf_icon_arrow.png', + src: './images/icons/cf_icon_arrow.png', scale: 0.3, anchor: [0.5, 0.5], rotateWithView: true, @@ -1425,7 +1409,7 @@ TABS.mission_control.initialize = function (callback) { } const $safehomeBox = $safehomeContentBox.find('.missionPlannerSafehomeBox:last-child'); - $safehomeBox.find('.spacer_box_title').text(chrome.i18n.getMessage('safehomeEdit') + ' ' + (selectedSafehome.getNumber() + 1)); + $safehomeBox.find('.spacer_box_title').text(i18n.getMessage('safehomeEdit') + ' ' + (selectedSafehome.getNumber() + 1)); $('#safehomeLatitude').val(selectedSafehome.getLatMap()); $('#safehomeLongitude').val(selectedSafehome.getLonMap()); @@ -1479,7 +1463,7 @@ TABS.mission_control.initialize = function (callback) { GUI.fillSelect($row.find(".waypointOptions-action"), waypointOptions, waypointOptions.indexOf(MWNP.WPTYPE.REV[element.getAction()])); - $row.find(".waypointOptions-action").val(waypointOptions.indexOf(MWNP.WPTYPE.REV[element.getAction()])).change(function () { + $row.find(".waypointOptions-action").val(waypointOptions.indexOf(MWNP.WPTYPE.REV[element.getAction()])).on('change', function () { element.setAction(MWNP.WPTYPE[waypointOptions[$(this).val()]]); for (var i = 1; i <= 3; i++) { if (dictOfLabelParameterPoint[element.getAction()]['parameter'+String(i)] != '') { @@ -1498,31 +1482,31 @@ TABS.mission_control.initialize = function (callback) { $row.find(".waypointOptions-number").text(element.getAttachedNumber()+1); - $row.find(".waypointOptions-p1").val((MWNP.WPTYPE.REV[element.getAction()] == "JUMP" ? element.getP1()+1 : element.getP1())).change(function () { + $row.find(".waypointOptions-p1").val((MWNP.WPTYPE.REV[element.getAction()] == "JUMP" ? element.getP1()+1 : element.getP1())).on('change', function () { if (MWNP.WPTYPE.REV[element.getAction()] == "SET_HEAD") { if ($(this).val() >= 360 || ($(this).val() < 0 && $(this).val() != -1)) { $(this).val(-1); - alert(chrome.i18n.getMessage('MissionPlannerHeadSettingsCheck')); + GUI.alert(i18n.getMessage('MissionPlannerHeadSettingsCheck')); } } else if (MWNP.WPTYPE.REV[element.getAction()] == "RTH") { if ($(this).val() != 0 && $(this).val() != 1) { $(this).val(0); - alert(chrome.i18n.getMessage('MissionPlannerRTHSettingsCheck')); + GUI.alert(i18n.getMessage('MissionPlannerRTHSettingsCheck')); } } else if (MWNP.WPTYPE.REV[element.getAction()] == "JUMP") { if ($(this).val() > mission.getNonAttachedList().length || $(this).val() < 1) { $(this).val(1); - alert(chrome.i18n.getMessage('MissionPlannerJumpSettingsCheck')); + GUI.alert(i18n.getMessage('MissionPlannerJumpSettingsCheck')); } else if (mission.getPoiList().length != 0 && mission.getPoiList()) { if (mission.getPoiList().includes(mission.convertJumpNumberToWaypoint(Number($(this).val())-1))) { $(this).val(1); - alert(chrome.i18n.getMessage('MissionPlannerJump3SettingsCheck')); + GUI.alert(i18n.getMessage('MissionPlannerJump3SettingsCheck')); } } } @@ -1532,12 +1516,12 @@ TABS.mission_control.initialize = function (callback) { redrawLayer(); }); - $row.find(".waypointOptions-p2").val(element.getP2()).change(function () { + $row.find(".waypointOptions-p2").val(element.getP2()).on('change', function () { if (MWNP.WPTYPE.REV[element.getAction()] == "JUMP") { if ($(this).val() > 10 || ($(this).val() < 0 && $(this).val() != -1)) { $(this).val(0); - alert(chrome.i18n.getMessage('MissionPlannerJump2SettingsCheck')); + GUI.alert(i18n.getMessage('MissionPlannerJump2SettingsCheck')); } } element.setP2(Number($(this).val())); @@ -1550,7 +1534,7 @@ TABS.mission_control.initialize = function (callback) { }); GUI.switchery(); - localize(); + i18n.localize();; return waypoint; } @@ -1626,7 +1610,7 @@ TABS.mission_control.initialize = function (callback) { var button = document.createElement('button'); button.innerHTML = ' '; - button.style = 'background: url(\'../images/CF_settings_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);'; + button.style = 'background: url(\'./images/CF_settings_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);'; var handleShowSettings = function () { $('#missionPlannerSettings').fadeIn(300); @@ -1658,7 +1642,7 @@ TABS.mission_control.initialize = function (callback) { var button = document.createElement('button'); button.innerHTML = ' '; - button.style = 'background: url(\'../images/icons/cf_icon_safehome_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);'; + button.style = 'background: url(\'./images/icons/cf_icon_safehome_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);'; var handleShowSafehome = function () { $('#missionPlannerSafehome').fadeIn(300); @@ -1693,7 +1677,7 @@ TABS.mission_control.initialize = function (callback) { var button = document.createElement('button'); button.innerHTML = ' '; - button.style = 'background: url(\'../images/icons/cf_icon_elevation_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);'; + button.style = 'background: url(\'./images/icons/cf_icon_elevation_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);'; var handleShowSettings = function () { $('#missionPlannerHome').fadeIn(300); @@ -1725,12 +1709,12 @@ TABS.mission_control.initialize = function (callback) { // * @param {Object=} opt_options Control options. // */ app.PlannerMultiMissionControl = function (opt_options) { - + var options = opt_options || {}; var button = document.createElement('button'); button.innerHTML = ' '; - button.style = 'background: url(\'../images/icons/cf_icon_multimission_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);'; + button.style = 'background: url(\'./images/icons/cf_icon_multimission_white.svg\') no-repeat 1px -1px;background-color: rgba(0,60,136,.5);'; var handleShowSettings = function () { $('#missionPlannerMultiMission').fadeIn(300); @@ -1818,7 +1802,7 @@ TABS.mission_control.initialize = function (callback) { repaintLine4Waypoints(mission); } else if (tempMarker.kind == "safehome") { - let tmpSafehome = SAFEHOMES.get()[tempMarker.number]; + let tmpSafehome = FC.SAFEHOMES.get()[tempMarker.number]; tmpSafehome.setLon(Math.round(coord[0] * 1e7)); tmpSafehome.setLat(Math.round(coord[1] * 1e7)); @@ -1874,7 +1858,7 @@ TABS.mission_control.initialize = function (callback) { mission.getWaypoint(tempMarker.number).setAlt(returnAltitude); if (mission.getWaypoint(tempMarker.number).getAction() == MWNP.WPTYPE.LAND) { - let approach = FW_APPROACH.get()[SAFEHOMES.getMaxSafehomeCount() + mission.getWaypoint(tempMarker.number).getMultiMissionIdx()]; + let approach = FC.FW_APPROACH.get()[FC.SAFEHOMES.getMaxSafehomeCount() + mission.getWaypoint(tempMarker.number).getMultiMissionIdx()]; if (approach.getIsSeaLevelRef()) { if (approach.getElevation() != 0) { approach.setApproachAltAsl(approach.getApproachAltAsl() - approach.getElevation() + elevationAtWP * 100); @@ -1902,8 +1886,8 @@ TABS.mission_control.initialize = function (callback) { } else if (tempMarker.kind == "safehome") { (async () => { - let approach = FW_APPROACH.get()[tempMarker.number]; - let safehome = SAFEHOMES.get()[tempMarker.number]; + let approach = FC.FW_APPROACH.get()[tempMarker.number]; + let safehome = FC.SAFEHOMES.get()[tempMarker.number]; const elevation = await approach.getElevationFromServer(safehome.getLonMap(), safehome.getLatMap(), globalSettings) * 100; $('#safehomeElevation').text(elevation / 100 + " m"); if (approach.getIsSeaLevelRef()) { @@ -1921,10 +1905,11 @@ TABS.mission_control.initialize = function (callback) { return false; }; - var lat = (GPS_DATA ? (GPS_DATA.lat / 10000000) : 0); - var lon = (GPS_DATA ? (GPS_DATA.lon / 10000000) : 0); + var lat = (FC.GPS_DATA ? (FC.GPS_DATA.lat / 10000000) : 0); + var lon = (FC.GPS_DATA ? (FC.GPS_DATA.lon / 10000000) : 0); let mapLayer; + let control_list; if (globalSettings.mapProviderType == 'bing') { mapLayer = new ol.source.BingMaps({ @@ -1991,20 +1976,20 @@ TABS.mission_control.initialize = function (callback) { // save map view settings when user moves it ////////////////////////////////////////////////////////////////////////// map.on('moveend', function (evt) { - chrome.storage.local.set({'missionPlannerLastValues': { + store.set('missionPlannerLastValues', { center: ol.proj.toLonLat(map.getView().getCenter()), zoom: map.getView().getZoom() - }}); + }); }); ////////////////////////////////////////////////////////////////////////// // load map view settings on startup ////////////////////////////////////////////////////////////////////////// - chrome.storage.local.get('missionPlannerLastValues', function (result) { - if (result.missionPlannerLastValues && result.missionPlannerLastValues.center) { - map.getView().setCenter(ol.proj.fromLonLat(result.missionPlannerLastValues.center)); - map.getView().setZoom(result.missionPlannerLastValues.zoom); - } - }); + var missionPlannerLastValues = store.get('missionPlannerLastValues', false); + if (missionPlannerLastValues && missionPlannerLastValues.zoom && missionPlannerLastValues.center) { + map.getView().setCenter(ol.proj.fromLonLat(missionPlannerLastValues.center)); + map.getView().setZoom(missionPlannerLastValues.zoom); + } + ////////////////////////////////////////////////////////////////////////// // Map on-click behavior definition @@ -2021,7 +2006,7 @@ TABS.mission_control.initialize = function (callback) { clearEditForm(); } catch (e) { console.log(e); - GUI.log(chrome.i18n.getMessage('notAWAYPOINT')); + GUI.log(i18n.getMessage('notAWAYPOINT')); } } selectedFeature = map.forEachFeatureAtPixel(evt.pixel, @@ -2036,7 +2021,7 @@ TABS.mission_control.initialize = function (callback) { $("#editMission").hide(); selectedMarker = mission.getWaypoint(tempMarker.number); - selectedFwApproachWp = FW_APPROACH.get()[SAFEHOMES.getMaxSafehomeCount() + selectedMarker.getMultiMissionIdx()]; + selectedFwApproachWp = FC.FW_APPROACH.get()[FC.SAFEHOMES.getMaxSafehomeCount() + selectedMarker.getMultiMissionIdx()]; if (selectedFwApproachWp.getLandHeading1() == 0 && selectedFwApproachWp.getLandHeading1() == 0 && selectedFwApproachWp.getApproachAltAsl() == 0 && selectedFwApproachWp.getLandAltAsl() == 0) { selectedFwApproachWp.setApproachAltAsl(settings.fwApproachAlt * 100); @@ -2134,7 +2119,7 @@ TABS.mission_control.initialize = function (callback) { } else if (selectedFeature && tempMarker.kind == "line" && tempMarker.selection && !disableMarkerEdit) { let tempWpCoord = ol.proj.toLonLat(evt.coordinate); - let tempWp = new Waypoint(tempMarker.number, MWNP.WPTYPE.WAYPOINT, Math.round(tempWpCoord[1] * 10000000), Math.round(tempWpCoord[0] * 10000000), alt=Number(settings.alt), p1=Number(settings.speed)); + let tempWp = new Waypoint(tempMarker.number, MWNP.WPTYPE.WAYPOINT, Math.round(tempWpCoord[1] * 10000000), Math.round(tempWpCoord[0] * 10000000), Number(settings.alt), Number(settings.speed)); tempWp.setMultiMissionIdx(mission.getWaypoint(0).getMultiMissionIdx()); if (homeMarkers.length && HOME.getAlt() != "N/A") { @@ -2167,11 +2152,11 @@ TABS.mission_control.initialize = function (callback) { } else if (!disableMarkerEdit) { let tempWpCoord = ol.proj.toLonLat(evt.coordinate); - let tempWp = new Waypoint(mission.get().length, MWNP.WPTYPE.WAYPOINT, Math.round(tempWpCoord[1] * 10000000), Math.round(tempWpCoord[0] * 10000000), alt=Number(settings.alt), p1=Number(settings.speed)); + let tempWp = new Waypoint(mission.get().length, MWNP.WPTYPE.WAYPOINT, Math.round(tempWpCoord[1] * 10000000), Math.round(tempWpCoord[0] * 10000000), Number(settings.alt), Number(settings.speed)); if (mission.get().length == 0) { tempWp.setMultiMissionIdx(multimissionCount == 0 ? 0 : multimissionCount - 1); - FW_APPROACH.clean(SAFEHOMES.getMaxSafehomeCount() + tempWp.getMultiMissionIdx()); + FC.FW_APPROACH.clean(FC.SAFEHOMES.getMaxSafehomeCount() + tempWp.getMultiMissionIdx()); } else { tempWp.setMultiMissionIdx(mission.getWaypoint(mission.get().length - 1).getMultiMissionIdx()); } @@ -2228,7 +2213,7 @@ TABS.mission_control.initialize = function (callback) { ////////////////////////////////////////////////////////////////////////// // Update Alt display in meters on ALT field keypress up ////////////////////////////////////////////////////////////////////////// - $('#pointAlt').keyup(function(){ + $('#pointAlt').on('keyup', () => { let altitudeMeters = app.ConvertCentimetersToMeters($(this).val()); $('#altitudeInMeters').text(` ${altitudeMeters}m`); }); @@ -2323,7 +2308,7 @@ TABS.mission_control.initialize = function (callback) { let found = false; mission.get().forEach(wp => { if (wp.getAction() == MWNP.WPTYPE.LAND) { - alert(chrome.i18n.getMessage('MissionPlannerOnlyOneLandWp')); + GUI.alert(i18n.getMessage('MissionPlannerOnlyOneLandWp')); found = true; $(event.currentTarget).val(selectedMarker.getAction()); } @@ -2411,8 +2396,8 @@ TABS.mission_control.initialize = function (callback) { $('#pointP3Alt').on('change', function (event) { if (selectedMarker) { - P3Value = selectedMarker.getP3(); - + var P3Value = selectedMarker.getP3(); + if (disableMarkerEdit) { changeSwitchery($('#pointP3Alt'), TABS.mission_control.isBitSet(P3Value, MWNP.P3.ALT_TYPE)); } @@ -2466,7 +2451,7 @@ TABS.mission_control.initialize = function (callback) { const returnAltitude = checkAltElevSanity(false, selectedMarker.getAlt(), elevationAtWP, selectedMarker.getP3()); selectedMarker.setAlt(returnAltitude); $('#pointAlt').val(selectedMarker.getAlt()); - altitudeMeters = app.ConvertCentimetersToMeters(selectedMarker.getAlt()); + let altitudeMeters = app.ConvertCentimetersToMeters(selectedMarker.getAlt()); $('#altitudeInMeters').text(` ${altitudeMeters}m`); $('#wpLandAltM').text(selectedFwApproachWp.getLandAltAsl() / 100 + " m"); @@ -2504,9 +2489,9 @@ TABS.mission_control.initialize = function (callback) { changeSwitchery($('#pointP3UserAction1'), TABS.mission_control.isBitSet(selectedMarker.getP3(), MWNP.P3.USER_ACTION_1)); } - P3Value = TABS.mission_control.setBit(selectedMarker.getP3(), MWNP.P3.USER_ACTION_1, $('#pointP3UserAction1').prop("checked")); + var P3Value = TABS.mission_control.setBit(selectedMarker.getP3(), MWNP.P3.USER_ACTION_1, $('#pointP3UserAction1').prop("checked")); selectedMarker.setP3(P3Value); - + mission.updateWaypoint(selectedMarker); mission.update(singleMissionActive()); redrawLayer(); @@ -2519,7 +2504,7 @@ TABS.mission_control.initialize = function (callback) { changeSwitchery($('#pointP3UserAction2'), TABS.mission_control.isBitSet(selectedMarker.getP3(), MWNP.P3.USER_ACTION_2)); } - P3Value = TABS.mission_control.setBit(selectedMarker.getP3(), MWNP.P3.USER_ACTION_2, $('#pointP3UserAction2').prop("checked")); + var P3Value = TABS.mission_control.setBit(selectedMarker.getP3(), MWNP.P3.USER_ACTION_2, $('#pointP3UserAction2').prop("checked")); selectedMarker.setP3(P3Value); mission.updateWaypoint(selectedMarker); @@ -2533,8 +2518,8 @@ TABS.mission_control.initialize = function (callback) { if (disableMarkerEdit) { changeSwitchery($('#pointP3UserAction3'), TABS.mission_control.isBitSet(selectedMarker.getP3(), MWNP.P3.USER_ACTION_3)); } - - P3Value = TABS.mission_control.setBit(selectedMarker.getP3(), MWNP.P3.USER_ACTION_3, $('#pointP3UserAction3').prop("checked")); + + var P3Value = TABS.mission_control.setBit(selectedMarker.getP3(), MWNP.P3.USER_ACTION_3, $('#pointP3UserAction3').prop("checked")); selectedMarker.setP3(P3Value); mission.updateWaypoint(selectedMarker); @@ -2548,8 +2533,8 @@ TABS.mission_control.initialize = function (callback) { if (disableMarkerEdit) { changeSwitchery($('#pointP3UserAction4'), TABS.mission_control.isBitSet(selectedMarker.getP3(), MWNP.P3.USER_ACTION_4)); } - - P3Value = TABS.mission_control.setBit(selectedMarker.getP3(), MWNP.P3.USER_ACTION_4, $('#pointP3UserAction4').prop("checked")); + + var P3Value = TABS.mission_control.setBit(selectedMarker.getP3(), MWNP.P3.USER_ACTION_4, $('#pointP3UserAction4').prop("checked")); selectedMarker.setP3(P3Value); mission.updateWaypoint(selectedMarker); @@ -2675,7 +2660,7 @@ TABS.mission_control.initialize = function (callback) { } }); - $("[data-role='waypointOptions-add']").click(function () { + $("[data-role='waypointOptions-add']").on('click', function () { if (selectedMarker) { mission.addAttachedFromWaypoint(selectedMarker); renderWaypointOptionsTable(selectedMarker); @@ -2696,16 +2681,16 @@ TABS.mission_control.initialize = function (callback) { $('#addSafehome').on('click', () => { - if (SAFEHOMES.safehomeCount() + 1 > SAFEHOMES.getMaxSafehomeCount()){ - alert(chrome.i18n.getMessage('missionSafehomeMaxSafehomesReached')); + if (FC.SAFEHOMES.safehomeCount() + 1 > FC.SAFEHOMES.getMaxSafehomeCount()){ + GUI.alert(i18n.getMessage('missionSafehomeMaxSafehomesReached')); return; } let mapCenter = map.getView().getCenter(); let midLon = Math.round(ol.proj.toLonLat(mapCenter)[0] * 1e7); let midLat = Math.round(ol.proj.toLonLat(mapCenter)[1] * 1e7); - SAFEHOMES.put(new Safehome(SAFEHOMES.safehomeCount(), 1, midLat, midLon)); - updateSelectedShAndFwAp(SAFEHOMES.safehomeCount() - 1); + FC.SAFEHOMES.put(new Safehome(FC.SAFEHOMES.safehomeCount(), 1, midLat, midLon)); + updateSelectedShAndFwAp(FC.SAFEHOMES.safehomeCount() - 1); renderSafeHomeOptions(); cleanSafehomeLayers(); renderSafehomesOnMap(); @@ -2724,7 +2709,7 @@ TABS.mission_control.initialize = function (callback) { mspHelper.loadSafehomes, mspHelper.loadFwApproach, function() { - if (SAFEHOMES.safehomeCount() >= 1) { + if (FC.SAFEHOMES.safehomeCount() >= 1) { updateSelectedShAndFwAp(0); } else { selectedSafehome = null; @@ -2734,7 +2719,7 @@ TABS.mission_control.initialize = function (callback) { cleanSafehomeLayers(); renderSafehomesOnMap(); updateSafehomeInfo(); - GUI.log(chrome.i18n.getMessage('endGettingSafehomePoints')); + GUI.log(i18n.getMessage('endGettingSafehomePoints')); $('#loadEepromSafehomeButton').removeClass('disabled'); } ]); @@ -2743,7 +2728,7 @@ TABS.mission_control.initialize = function (callback) { $('#saveEepromSafehomeButton').on('click', function() { $(this).addClass('disabled'); - GUI.log(chrome.i18n.getMessage('startSendingSafehomePoints')); + GUI.log(i18n.getMessage('startSendingSafehomePoints')); var saveChainer = new MSPChainerClass(); saveChainer.setChain([ @@ -2751,7 +2736,7 @@ TABS.mission_control.initialize = function (callback) { mspHelper.saveFwApproach, function() { mspHelper.saveToEeprom(); - GUI.log(chrome.i18n.getMessage('endSendingSafehomePoints')); + GUI.log(i18n.getMessage('endSendingSafehomePoints')); $('#saveEepromSafehomeButton').removeClass('disabled'); } ]); @@ -2761,11 +2746,11 @@ TABS.mission_control.initialize = function (callback) { $('#deleteSafehome').on('click', () => { if (selectedSafehome && selectedFwApproachSh) { var shNum = selectedSafehome.getNumber(); - SAFEHOMES.drop(shNum); - FW_APPROACH.clean(shNum); + FC.SAFEHOMES.drop(shNum); + FC.FW_APPROACH.clean(shNum); - if (SAFEHOMES.safehomeCount() > 0) { - updateSelectedShAndFwAp(SAFEHOMES.safehomeCount() - 1); + if (FC.SAFEHOMES.safehomeCount() > 0) { + updateSelectedShAndFwAp(FC.SAFEHOMES.safehomeCount() - 1); } else { selectedSafehome = null; selectedFwApproachSh = null; @@ -2999,7 +2984,7 @@ TABS.mission_control.initialize = function (callback) { }); $('#updateMultimissionButton').on('click', function () { - $('#multimissionOptionList').val('0').change(); + $('#multimissionOptionList').val('0').trigger('change'); }); $('#cancelMultimission').on('click', function () { @@ -3014,13 +2999,13 @@ TABS.mission_control.initialize = function (callback) { // Callback for Remove buttons ///////////////////////////////////////////// $('#removeAllPoints').on('click', function () { - if (markers.length && confirm(chrome.i18n.getMessage('confirm_delete_all_points'))) { + if (markers.length && confirm(i18n.getMessage('confirm_delete_all_points'))) { if (removeAllMultiMissionCheck()) { removeAllWaypoints(); updateMultimissionState(); } - for (let i = SAFEHOMES.getMaxSafehomeCount(); i < FW_APPROACH.getMaxFwApproachCount(); i++) { - FW_APPROACH.clean(i); + for (let i = FC.SAFEHOMES.getMaxSafehomeCount(); i < FC.FW_APPROACH.getMaxFwApproachCount(); i++) { + FC.FW_APPROACH.clean(i); } plotElevation(); } @@ -3029,14 +3014,14 @@ TABS.mission_control.initialize = function (callback) { $('#removePoint').on('click', function () { if (selectedMarker) { if (mission.isJumpTargetAttached(selectedMarker)) { - alert(chrome.i18n.getMessage('MissionPlannerJumpTargetRemoval')); + GUI.alert(i18n.getMessage('MissionPlannerJumpTargetRemoval')); } else if (mission.getAttachedFromWaypoint(selectedMarker) && mission.getAttachedFromWaypoint(selectedMarker).length != 0) { - if (confirm(chrome.i18n.getMessage('confirm_delete_point_with_options'))) { + if (confirm(i18n.getMessage('confirm_delete_point_with_options'))) { mission.getAttachedFromWaypoint(selectedMarker).forEach(function (element) { if (element.getAction() == MWNP.WPTYPE.LAND) { - FW_APPROACH.clean(element.getNumber()); + FC.FW_APPROACH.clean(element.getNumber()); } mission.dropWaypoint(element); @@ -3053,7 +3038,7 @@ TABS.mission_control.initialize = function (callback) { else { mission.dropWaypoint(selectedMarker); if (selectedMarker.getAction() == MWNP.WPTYPE.LAND) { - FW_APPROACH.clean(selectedFwApproachWp.getNumber()); + FC.FW_APPROACH.clean(selectedFwApproachWp.getNumber()); } selectedMarker = null; mission.update(singleMissionActive()); @@ -3071,55 +3056,68 @@ TABS.mission_control.initialize = function (callback) { $('#loadFileMissionButton').on('click', function () { if (!fileLoadMultiMissionCheck()) return; - if (markers.length && !confirm(chrome.i18n.getMessage('confirm_delete_all_points'))) return; - nwdialog.setContext(document); - nwdialog.openFileDialog('.mission', function(result) { - loadMissionFile(result); + if (markers.length && !confirm(i18n.getMessage('confirm_delete_all_points'))) return; + var options = { + filters: [ { name: "Mission file", extensions: ['mission'] } ] + }; + dialog.showOpenDialog(options).then(result => { + if (result.canceled) { + console.log('No file selected'); + return; + } + if (result.filePaths.length == 1) { + loadMissionFile(result.filePaths[0]); + } }) }); $('#saveFileMissionButton').on('click', function () { - nwdialog.setContext(document); - nwdialog.saveFileDialog('', '.mission', function(result) { - saveMissionFile(result); - }) + var options = { + filters: [ { name: "Mission file", extensions: ['mission'] } ] + }; + dialog.showSaveDialog(options).then(result => { + if (result.canceled) { + return; + } + saveMissionFile(result.filePath); + }); }); $('#loadMissionButton').on('click', function () { let message = multimissionCount ? 'confirm_overwrite_multimission_file_load_option' : 'confirm_delete_all_points'; - if ((markers.length || multimissionCount) && !confirm(chrome.i18n.getMessage(message))) return; + if ((markers.length || multimissionCount) && !confirm(i18n.getMessage(message))) return; removeAllWaypoints(); $(this).addClass('disabled'); - GUI.log(chrome.i18n.getMessage('startGetPoint')); + GUI.log(i18n.getMessage('startGetPoint')); getWaypointsFromFC(false); }); $('#saveMissionButton').on('click', function () { if (mission.isEmpty()) { - alert(chrome.i18n.getMessage('no_waypoints_to_save')); + GUI.alert(i18n.getMessage('no_waypoints_to_save')); return; } $(this).addClass('disabled'); - GUI.log(chrome.i18n.getMessage('startSendPoint')); + GUI.log(i18n.getMessage('startSendPoint')); sendWaypointsToFC(false); }); $('#loadEepromMissionButton').on('click', function () { let message = multimissionCount ? 'confirm_overwrite_multimission_file_load_option' : 'confirm_delete_all_points'; - if ((markers.length || multimissionCount) && !confirm(chrome.i18n.getMessage(message))) return; + if ((markers.length || multimissionCount) && !confirm(i18n.getMessage(message))) return; removeAllWaypoints(); $(this).addClass('disabled'); - GUI.log(chrome.i18n.getMessage('startGetPoint')); + GUI.log(i18n.getMessage('startGetPoint')); getWaypointsFromFC(true); }); $('#saveEepromMissionButton').on('click', function () { if (mission.isEmpty()) { - alert(chrome.i18n.getMessage('no_waypoints_to_save')); + GUI.alert(i18n.getMessage('no_waypoints_to_save')); return; } $(this).addClass('disabled'); - GUI.log(chrome.i18n.getMessage('startSendPoint')); + GUI.log(i18n.getMessage('startSendPoint')); sendWaypointsToFC(true); }); @@ -3161,22 +3159,19 @@ TABS.mission_control.initialize = function (callback) { // ///////////////////////////////////////////// function loadMissionFile(filename) { - const fs = require('fs'); - if (!window.xml2js) return GUI.log(chrome.i18n.getMessage('errorReadingFileXml2jsNotFound')); - - for (let i = SAFEHOMES.getMaxSafehomeCount(); i < FW_APPROACH.getMaxFwApproachCount(); i++) { - FW_APPROACH.clean(i); + for (let i = FC.SAFEHOMES.getMaxSafehomeCount(); i < FC.FW_APPROACH.getMaxFwApproachCount(); i++) { + FC.FW_APPROACH.clean(i); } fs.readFile(filename, (err, data) => { if (err) { - GUI.log(chrome.i18n.getMessage('errorReadingFile')); + GUI.log(i18n.getMessage('errorReadingFile')); return console.error(err); } - window.xml2js.Parser({ 'explicitChildren': true, 'preserveChildrenOrder': true }).parseString(data, (err, result) => { + xml2js.Parser({ 'explicitChildren': true, 'preserveChildrenOrder': true }).parseString(data, (err, result) => { if (err) { - GUI.log(chrome.i18n.getMessage('errorParsingFile')); + GUI.log(i18n.getMessage('errorParsingFile')); return console.error(err); } @@ -3285,7 +3280,7 @@ TABS.mission_control.initialize = function (callback) { fwApproach.setIsSeaLevelRef(parseBooleans(node.$[attr]) ? 1 : 0); } } - FW_APPROACH.insert(fwApproach, SAFEHOMES.getMaxSafehomeCount() + idx); + FC.FW_APPROACH.insert(fwApproach, FC.SAFEHOMES.getMaxSafehomeCount() + idx); } } } @@ -3293,7 +3288,7 @@ TABS.mission_control.initialize = function (callback) { } if (missionEndFlagCount > 1) { - if (multimissionCount && !confirm(chrome.i18n.getMessage('confirm_multimission_file_load'))) { + if (multimissionCount && !confirm(i18n.getMessage('confirm_multimission_file_load'))) { mission.flush(); return; } else { @@ -3337,16 +3332,13 @@ TABS.mission_control.initialize = function (callback) { } updateTotalInfo(); let sFilename = String(filename.split('\\').pop().split('/').pop()); - GUI.log(sFilename + chrome.i18n.getMessage('loadedSuccessfully')); + GUI.log(sFilename + i18n.getMessage('loadedSuccessfully')); updateFilename(sFilename); }); }); } function saveMissionFile(filename) { - const fs = require('fs'); - if (!window.xml2js) return GUI.log(chrome.i18n.getMessage('errorWritingFileXml2jsNotFound')); - var center = ol.proj.toLonLat(map.getView().getCenter()); var zoom = map.getView().getZoom(); let multimission = multimissionCount && !singleMissionActive(); @@ -3390,8 +3382,8 @@ TABS.mission_control.initialize = function (callback) { } }); let approachIdx = 0; - for (let i = SAFEHOMES.getMaxSafehomeCount(); i < FW_APPROACH.getMaxFwApproachCount(); i++){ - let approach = FW_APPROACH.get()[i]; + for (let i = FC.SAFEHOMES.getMaxSafehomeCount(); i < FC.FW_APPROACH.getMaxFwApproachCount(); i++){ + let approach = FC.FW_APPROACH.get()[i]; if (approach.getLandHeading1() != 0 || approach.getLandHeading2() != 0) { var item = { $: { 'index': approachIdx, @@ -3408,23 +3400,23 @@ TABS.mission_control.initialize = function (callback) { approachIdx++; } - var builder = new window.xml2js.Builder({ 'rootName': 'mission', 'renderOpts': { 'pretty': true, 'indent': '\t', 'newline': '\n' } }); + var builder = new xml2js.Builder({ 'rootName': 'mission', 'renderOpts': { 'pretty': true, 'indent': '\t', 'newline': '\n' } }); var xml = builder.buildObject(data); xml = xml.replace(/missionitem mission/g, 'meta mission'); fs.writeFile(filename, xml, (err) => { if (err) { - GUI.log(chrome.i18n.getMessage('ErrorWritingFile')); + GUI.log(i18n.getMessage('ErrorWritingFile')); return console.error(err); } let sFilename = String(filename.split('\\').pop().split('/').pop()); - GUI.log(sFilename + chrome.i18n.getMessage('savedSuccessfully')); + GUI.log(sFilename + i18n.getMessage('savedSuccessfully')); updateFilename(sFilename); }); } ///////////////////////////////////////////// // Load/Save FC mission Toolbox - // mission = configurator store, WP number indexed from 0, MISSION_PLANNER = FC NVM store, WP number indexed from 1 + // mission = configurator store, WP number indexed from 0, FC.MISSION_PLANNER = FC NVM store, WP number indexed from 1 ///////////////////////////////////////////// function getWaypointsFromFC(loadEeprom) { @@ -3437,19 +3429,19 @@ TABS.mission_control.initialize = function (callback) { } chain.push(mspHelper.loadWaypoints); chain.push(function() { - GUI.log(chrome.i18n.getMessage('endGetPoint')); + GUI.log(i18n.getMessage('endGetPoint')); if (loadEeprom) { - GUI.log(chrome.i18n.getMessage('eeprom_load_ok')); + GUI.log(i18n.getMessage('eeprom_load_ok')); $('#loadEepromMissionButton').removeClass('disabled'); } else { $('#loadMissionButton').removeClass('disabled'); } - if (!MISSION_PLANNER.getCountBusyPoints()) { - alert(chrome.i18n.getMessage('no_waypoints_to_load')); + if (!FC.MISSION_PLANNER.getCountBusyPoints()) { + GUI.alert(i18n.getMessage('no_waypoints_to_load')); return; } mission.reinit(); - mission.copy(MISSION_PLANNER); + mission.copy(FC.MISSION_PLANNER); mission.update(false, true); /* check multimissions */ @@ -3477,29 +3469,29 @@ TABS.mission_control.initialize = function (callback) { } function sendWaypointsToFC(saveEeprom) { - MISSION_PLANNER.reinit(); - MISSION_PLANNER.copy(mission); - MISSION_PLANNER.update(false, true, true); + FC.MISSION_PLANNER.reinit(); + FC.MISSION_PLANNER.copy(mission); + FC.MISSION_PLANNER.update(false, true, true); let saveChainer = new MSPChainerClass(); saveChainer.setChain([ mspHelper.saveWaypoints, mspHelper.saveFwApproach, function () { - GUI.log(chrome.i18n.getMessage('endSendPoint')); + GUI.log(i18n.getMessage('endSendPoint')); if (saveEeprom) { $('#saveEepromMissionButton').removeClass('disabled'); - GUI.log(chrome.i18n.getMessage('eeprom_saved_ok')); + GUI.log(i18n.getMessage('eeprom_saved_ok')); MSP.send_message(MSPCodes.MSP_WP_MISSION_SAVE, [0], false, setMissionIndex); } else { $('#saveMissionButton').removeClass('disabled'); } - mission.setMaxWaypoints(MISSION_PLANNER.getMaxWaypoints()); - mission.setValidMission(MISSION_PLANNER.getValidMission()); - mission.setCountBusyPoints(MISSION_PLANNER.getCountBusyPoints()); + mission.setMaxWaypoints(FC.MISSION_PLANNER.getMaxWaypoints()); + mission.setValidMission(FC.MISSION_PLANNER.getValidMission()); + mission.setCountBusyPoints(FC.MISSION_PLANNER.getCountBusyPoints()); multimission.setMaxWaypoints(mission.getMaxWaypoints()); updateTotalInfo(); mission.reinit(); - mission.copy(MISSION_PLANNER); + mission.copy(FC.MISSION_PLANNER); mission.update(false, true); refreshLayers(); $('#MPeditPoint').fadeOut(300); @@ -3511,7 +3503,7 @@ TABS.mission_control.initialize = function (callback) { let activeIndex = singleMissionActive() ? 1 : $('#activeNissionIndex').text(); mspHelper.setSetting("nav_wp_multi_mission_index", activeIndex, function () { MSP.send_message(MSPCodes.MSP_EEPROM_WRITE, false, false, function () { - GUI.log(chrome.i18n.getMessage('multimission_active_index_saved_eeprom')); + GUI.log(i18n.getMessage('multimission_active_index_saved_eeprom')); }); }); } @@ -3524,7 +3516,7 @@ TABS.mission_control.initialize = function (callback) { availableWPs = availableWPs - multimission.get().length; } $('#availablePoints').text(availableWPs + '/' + mission.getMaxWaypoints()); - $('#missionValid').html(mission.getValidMission() ? chrome.i18n.getMessage('armingCheckPass') : chrome.i18n.getMessage('armingCheckFail')); + $('#missionValid').html(mission.getValidMission() ? i18n.getMessage('armingCheckPass') : i18n.getMessage('armingCheckFail')); } } @@ -3540,8 +3532,8 @@ TABS.mission_control.initialize = function (callback) { } function updateSelectedShAndFwAp(index) { - selectedSafehome = SAFEHOMES.get()[index]; - selectedFwApproachSh = FW_APPROACH.get()[index]; + selectedSafehome = FC.SAFEHOMES.get()[index]; + selectedFwApproachSh = FC.FW_APPROACH.get()[index]; } /* resetAltitude = true : For selected WPs only. Changes WP Altitude value back to previous value if setting below ground level. @@ -3555,7 +3547,7 @@ TABS.mission_control.initialize = function (callback) { if (AbsAltCheck) { if (checkAltitude < 100 * elevation) { if (resetAltitude) { - alert(chrome.i18n.getMessage('MissionPlannerAltitudeChangeReset')); + GUI.alert(i18n.getMessage('MissionPlannerAltitudeChangeReset')); altitude = selectedMarker.getAlt(); } else { altitude = settings.alt + 100 * elevation; @@ -3566,7 +3558,7 @@ TABS.mission_control.initialize = function (callback) { let elevationAtHome = HOME.getAlt(); if ((checkAltitude / 100 + elevationAtHome) < elevation) { if (resetAltitude) { - alert(chrome.i18n.getMessage('MissionPlannerAltitudeChangeReset')); + GUI.alert(i18n.getMessage('MissionPlannerAltitudeChangeReset')); altitude = selectedMarker.getAlt(); } else { let currentGroundClearance = 100 * Number($('#groundClearanceValueAtWP').text()); @@ -3702,9 +3694,9 @@ TABS.mission_control.setBit = function(bits, bit, value) { // function handleError(evt) { // if (evt.message) { // Chrome sometimes provides this - // alert("error: "+evt.message +" at linenumber: "+evt.lineno+" of file: "+evt.filename); + // GUI.alert("error: "+evt.message +" at linenumber: "+evt.lineno+" of file: "+evt.filename); // } else { - // alert("error: "+evt.type+" from element: "+(evt.srcElement || evt.target)); + // GUI.alert("error: "+evt.type+" from element: "+(evt.srcElement || evt.target)); // } // } diff --git a/tabs/mixer.html b/tabs/mixer.html index cb03f5d42..47539ccf6 100644 --- a/tabs/mixer.html +++ b/tabs/mixer.html @@ -60,10 +60,10 @@
-
1
-
2
-
3
-
4
+ + + +
diff --git a/tabs/mixer.js b/tabs/mixer.js index 61d133106..7e5e9d550 100644 --- a/tabs/mixer.js +++ b/tabs/mixer.js @@ -1,6 +1,19 @@ -/*global $,helper,mspHelper,MSP,GUI,SERVO_RULES,MOTOR_RULES,MIXER_CONFIG,googleAnalytics,LOGIC_CONDITIONS,TABS,ServoMixRule*/ 'use strict'; +const path = require('path'); + +const MSPChainerClass = require('./../js/msp/MSPchainer'); +const mspHelper = require('./../js/msp/MSPHelper'); +const MSPCodes = require('./../js/msp/MSPCodes'); +const MSP = require('./../js/msp'); +const { GUI, TABS } = require('./../js/gui'); +const FC = require('./../js/fc'); +const i18n = require('./../js/localization'); +const { mixer, platform, PLATFORM, INPUT, STABILIZED } = require('./../js/model'); +const Settings = require('./../js/settings'); +const jBox = require('../js/libraries/jBox/jBox.min'); +const interval = require('./../js/intervals'); + TABS.mixer = {}; TABS.mixer.initialize = function (callback, scrollPosition) { @@ -19,7 +32,6 @@ TABS.mixer.initialize = function (callback, scrollPosition) { if (GUI.active_tab != 'mixer') { GUI.active_tab = 'mixer'; - googleAnalytics.sendAppView('Mixer'); } loadChainer.setChain([ @@ -46,12 +58,12 @@ TABS.mixer.initialize = function (callback, scrollPosition) { saveChainer.setExitPoint(reboot); function saveSettings(onComplete) { - Settings.saveInputs().then(onComplete); + Settings.saveInputs(onComplete); } function reboot() { //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('configurationEepromSaved')); + GUI.log(i18n.getMessage('configurationEepromSaved')); GUI.tab_switch_cleanup(function() { MSP.send_message(MSPCodes.MSP_SET_REBOOT, false, false, reinitialize); @@ -60,16 +72,16 @@ TABS.mixer.initialize = function (callback, scrollPosition) { function reinitialize() { //noinspection JSUnresolvedVariable - GUI.log(chrome.i18n.getMessage('deviceRebooting')); + GUI.log(i18n.getMessage('deviceRebooting')); GUI.handleReconnect($('.tab_mixer a')); } function loadHtml() { - GUI.load("./tabs/mixer.html", Settings.processHtml(processHtml)); + GUI.load(path.join(__dirname, "mixer.html"), Settings.processHtml(processHtml)); } function renderOutputTable() { - let outputCount = OUTPUT_MAPPING.getOutputCount(), + let outputCount = FC.OUTPUT_MAPPING.getOutputCount(), $outputRow = $('#output-row'), $functionRow = $('#function-row'); @@ -78,8 +90,8 @@ TABS.mixer.initialize = function (callback, scrollPosition) { for (let i = 1; i <= outputCount; i++) { - let timerId = OUTPUT_MAPPING.getTimerId(i - 1); - let color = OUTPUT_MAPPING.getOutputTimerColor(i - 1); + let timerId = FC.OUTPUT_MAPPING.getTimerId(i - 1); + let color = FC.OUTPUT_MAPPING.getOutputTimerColor(i - 1); $outputRow.append('S' + i + ' (Timer ' + (timerId + 1) + ')'); $functionRow.append('-'); @@ -90,33 +102,33 @@ TABS.mixer.initialize = function (callback, scrollPosition) { } function updateTimerOverride() { - let timers = OUTPUT_MAPPING.getUsedTimerIds(); + let timers = FC.OUTPUT_MAPPING.getUsedTimerIds(); for(let i =0; i < timers.length;++i) { let timerId = timers[i]; - $select = $('#timer-output-' + timerId); + let $select = $('#timer-output-' + timerId); if(!$select) { continue; } - OUTPUT_MAPPING.setTimerOverride(timerId, $select.val()); + FC.OUTPUT_MAPPING.setTimerOverride(timerId, $select.val()); } } function renderTimerOverride() { - let outputCount = OUTPUT_MAPPING.getOutputCount(), + let outputCount = FC.OUTPUT_MAPPING.getOutputCount(), $container = $('#timerOutputsList'), timers = {}; - let usedTimers = OUTPUT_MAPPING.getUsedTimerIds(); + let usedTimers = FC.OUTPUT_MAPPING.getUsedTimerIds(); - for (t of usedTimers) { - var usageMode = OUTPUT_MAPPING.getTimerOverride(t); + for (let t of usedTimers) { + var usageMode = FC.OUTPUT_MAPPING.getTimerOverride(t); $container.append( - '
' + + '
' + '' + '
- +
-
+ +
+ + +
diff --git a/tabs/osd.html b/tabs/osd.html index 062a56ea0..8488bfbd4 100644 --- a/tabs/osd.html +++ b/tabs/osd.html @@ -10,6 +10,15 @@

+ + + + + + + + +
@@ -242,6 +251,16 @@

+
+ +
+
diff --git a/tabs/osd.js b/tabs/osd.js index c24adb28f..c0ce01f56 100644 --- a/tabs/osd.js +++ b/tabs/osd.js @@ -1,6 +1,26 @@ -/*global $,nwdialog*/ 'use strict'; +const inflection = require( 'inflection' ); +const fs = require('fs'); +const path = require('path'); +const semver = require('semver'); +const mapSeries = require('promise-map-series'); +const { dialog } = require("@electron/remote"); +const Store = require('electron-store'); +const store = new Store(); + +const FC = require('./../js/fc'); +const { GUI, TABS } = require('./../js/gui'); +const MSP = require('./../js/msp'); +const MSPCodes = require('./../js/msp/MSPCodes'); +const mspHelper = require('./../js/msp/MSPHelper'); +const Settings = require('./../js/settings'); +const { globalSettings } = require('./../js/globalSettings'); +const { PortHandler } = require('./../js/port_handler'); +const i18n = require('./../js/localization'); +const jBox = require('./../js/libraries/jBox/jBox.min'); + + var SYM = SYM || {}; SYM.LAST_CHAR = 225; // For drawing the font preview SYM.BLANK = 0x20; @@ -114,6 +134,7 @@ SYM.FLIGHT_DIST_REMAINING = 0x167; SYM.GROUND_COURSE = 0xDC; SYM.ALERT = 0xDD; SYM.CROSS_TRACK_ERROR = 0xFC; +SYM.ADSB = 0xFD; SYM.PAN_SERVO_IS_OFFSET_L = 0x1C7; SYM.ODOMETER = 0X168; SYM.PILOT_LOGO_SML_L = 0x1D5; @@ -137,6 +158,8 @@ var video_type = null; var isGuidesChecked = false; var FONT = FONT || {}; +var layout_clipboard = {layout: [], filled: false}; + var FONT = FONT || {}; FONT.initData = function () { if (FONT.data) { @@ -235,13 +258,24 @@ FONT.parseMCMFontFile = function (data) { //noinspection JSUnusedLocalSymbols FONT.openFontFile = function ($preview) { return new Promise(function (resolve) { - - nwdialog.setContext(document); - nwdialog.openFileDialog('.mcm', function(filename) { - const fs = require('fs'); - const fontData = fs.readFileSync(filename, {flag: "r"}); - FONT.parseMCMFontFile(fontData.toString()); - resolve(); + var options = { + filters: [ + { name: 'Font file', extensions: ['mcm'] } + ], + }; + dialog.showOpenDialog(options).then(result => { + if (result.canceled) { + console.log('No file selected'); + return; + } + + if (result.filePaths.length == 1) { + const fontData = fs.readFileSync(result.filePaths[0], {flag: "r"}); + FONT.parseMCMFontFile(fontData.toString()); + resolve(); + } + }).catch (err => { + console.log(err); }); }); }; @@ -480,6 +514,8 @@ OSD.initData = function () { imu_temp_alarm_max: null, baro_temp_alarm_min: null, baro_temp_alarm_max: null, + adsb_distance_warning: null, + adsb_distance_alert: null, }, layouts: [], layout_count: 1, // This needs to be 1 for compatibility with < 2.0 @@ -781,6 +817,24 @@ OSD.constants = { min: -55, max: 125 }, + { + name: 'ADSB_MAX_DISTANCE_WARNING', + field: 'adsb_distance_warning', + step: 1, + unit: "meters", + min: 1, + max: 64000, + min_version: '7.1.0', + }, + { + name: 'ADSB_MAX_DISTANCE_ALERT', + field: 'adsb_distance_alert', + step: 1, + unit: "meters", + min: 1, + max: 64000, + min_version: '7.1.0', + }, ], // All display fields, from every version, do not remove elements, only add! @@ -1654,6 +1708,18 @@ OSD.constants = { min_version: '6.0.0', preview: FONT.symbol(SYM.GROUND_COURSE) + '245' + FONT.symbol(SYM.DEGREES) }, + { + name: 'ADSB_WARNING_MESSAGE', + id: 150, + min_version: '7.1.0', + preview: FONT.symbol(SYM.ADSB) + '19.25' + FONT.symbol(SYM.DIR_TO_HOME+1) + '2.75', + }, + { + name: 'ADSB_INFO', + id: 151, + min_version: '7.1.0', + preview: FONT.symbol(SYM.ADSB) + '2', + }, { name: 'CROSS TRACK ERROR', id: 141, @@ -1927,27 +1993,27 @@ OSD.constants = { preview: 'TEX 0' }, { - name: 'STABILIZED_RC_EXPO', + name: 'STABILIZED.RC_EXPO', id: 64, preview: 'EXP 20' }, { - name: 'STABILIZED_RC_YAW_EXPO', + name: 'STABILIZED.RC_YAW_EXPO', id: 65, preview: 'YEX 20' }, { - name: 'STABILIZED_PITCH_RATE', + name: 'STABILIZED.PITCH_RATE', id: 67, preview: 'SPR 20' }, { - name: 'STABILIZED_ROLL_RATE', + name: 'STABILIZED.ROLL_RATE', id: 68, preview: 'SRR 20' }, { - name: 'STABILIZED_YAW_RATE', + name: 'STABILIZED.YAW_RATE', id: 69, preview: 'SYR 20' }, @@ -2083,7 +2149,7 @@ OSD.is_item_displayed = function(item, group) { if (typeof group.enabled === 'function' && group.enabled() === false) { return false; } - if (item.min_version && !semver.gte(CONFIG.flightControllerVersion, item.min_version)) { + if (item.min_version && !semver.gte(FC.CONFIG.flightControllerVersion, item.min_version)) { return false; } if (typeof item.enabled === 'function' && item.enabled() === false) { @@ -2110,7 +2176,7 @@ OSD.reload = function(callback) { }; MSP.promise(MSPCodes.MSP2_CF_SERIAL_CONFIG).then(function (resp) { - $.each(SERIAL_CONFIG.ports, function(index, port){ + $.each(FC.SERIAL_CONFIG.ports, function(index, port){ if(port.functions.includes('DJI_FPV')) { OSD.data.isDjiHdFpv = true; } @@ -2125,7 +2191,7 @@ OSD.reload = function(callback) { OSD.msp.decodeLayoutCounts(resp); // Get data for all layouts var ids = Array.apply(null, {length: OSD.data.layout_count}).map(Number.call, Number); - var layouts = Promise.mapSeries(ids, function (layoutIndex, ii) { + var layouts = mapSeries(ids, function (layoutIndex, ii) { var data = []; data.push8(layoutIndex); return MSP.promise(MSPCodes.MSP2_INAV_OSD_LAYOUTS, data).then(function (resp) { @@ -2147,7 +2213,7 @@ OSD.reload = function(callback) { }); }); - if(semver.gte(CONFIG.flightControllerVersion, '7.1.0')) + if(semver.gte(FC.CONFIG.flightControllerVersion, '7.1.0')) { MSP.send_message(MSPCodes.MSP2_INAV_CUSTOM_OSD_ELEMENTS); } @@ -2290,6 +2356,8 @@ OSD.msp = { result.push16(OSD.data.alarms.imu_temp_alarm_max); result.push16(OSD.data.alarms.baro_temp_alarm_min); result.push16(OSD.data.alarms.baro_temp_alarm_max); + result.push16(OSD.data.alarms.adsb_distance_warning); + result.push16(OSD.data.alarms.adsb_distance_alert); return result; }, @@ -2309,6 +2377,8 @@ OSD.msp = { OSD.data.alarms.imu_temp_alarm_max = alarms.read16(); OSD.data.alarms.baro_temp_alarm_min = alarms.read16(); OSD.data.alarms.baro_temp_alarm_max = alarms.read16(); + OSD.data.alarms.adsb_distance_warning = alarms.read16(); + OSD.data.alarms.adsb_distance_alert = alarms.read16(); }, encodePreferences: function() { @@ -2484,7 +2554,7 @@ OSD.GUI.preview = { position += overflows_line; } - $('input.' + item_id + '.position').val(position).change(); + $('input.' + item_id + '.position').val(position).trigger('change'); } }; @@ -2548,7 +2618,7 @@ OSD.GUI.updateVideoMode = function() { } } - $videoTypes.change(function () { + $videoTypes.on('change', function () { OSD.data.preferences.video_system = $(this).find(':selected').data('type'); OSD.updateDisplaySize(); OSD.GUI.saveConfig(); @@ -2562,10 +2632,10 @@ OSD.GUI.updateUnits = function() { for (var i = 0; i < OSD.constants.UNIT_TYPES.length; i++) { var unitType = OSD.constants.UNIT_TYPES[i]; - if (unitType.min_version && semver.lt(CONFIG.flightControllerVersion, unitType.min_version)) { + if (unitType.min_version && semver.lt(FC.CONFIG.flightControllerVersion, unitType.min_version)) { continue; } - var name = chrome.i18n.getMessage(unitType.name); + var name = i18n.getMessage(unitType.name); var $option = $(''); $option.attr('value', name); $option.data('type', unitType.value); @@ -2578,7 +2648,7 @@ OSD.GUI.updateUnits = function() { var unitType = OSD.constants.UNIT_TYPES[OSD.data.preferences.units]; var tip; if (unitType.tip) { - tip = chrome.i18n.getMessage(unitType.tip); + tip = i18n.getMessage(unitType.tip); } if (tip) { $unitTip.attr('title', tip); @@ -2588,7 +2658,7 @@ OSD.GUI.updateUnits = function() { } } updateUnitHelp(); - $unitMode.change(function (e) { + $unitMode.on('change', function (e) { var selected = $(this).find(':selected'); OSD.data.preferences.units = selected.data('type'); globalSettings.osdUnits = OSD.data.preferences.units; @@ -2619,9 +2689,9 @@ OSD.GUI.updateFields = function() { var groupContainer = $tmpl.clone().addClass('osd_group').show(); groupContainer.attr('id', group.name); var groupTitleContainer = groupContainer.find('.spacer_box_title'); - var groupTitle = chrome.i18n.getMessage(group.name); + var groupTitle = i18n.getMessage(group.name); groupTitleContainer.text(groupTitle); - var groupHelp = chrome.i18n.getMessage(group.name + '_HELP'); + var groupHelp = i18n.getMessage(group.name + '_HELP'); if (groupHelp) { $('
') .css('margin-top', '1px') @@ -2645,7 +2715,7 @@ OSD.GUI.updateFields = function() { var $field = $('
'); var name = item.name; var nameKey = 'osdElement_' + name; - var nameMessage = chrome.i18n.getMessage(nameKey); + var nameMessage = i18n.getMessage(nameKey); if (nameMessage) { name = nameMessage; } else { @@ -2655,7 +2725,7 @@ OSD.GUI.updateFields = function() { if (searchTerm.length > 0 && !name.toLowerCase().includes(searchTerm.toLowerCase())) { continue; } - var help = chrome.i18n.getMessage(nameKey + '_HELP'); + var help = i18n.getMessage(nameKey + '_HELP'); if (help) { $('
') .css('margin-top', '1px') @@ -2675,7 +2745,7 @@ OSD.GUI.updateFields = function() { $('') .data('item', item) .attr('checked', itemData.isVisible) - .change(function () { + .on('change', function () { var item = $(this).data('item'); var itemData = OSD.data.items[item.id]; var $position = $(this).parent().find('.position.' + item.name); @@ -2704,7 +2774,7 @@ OSD.GUI.updateFields = function() { $('') .data('item', item) .val(itemData.position) - .change($.debounce(250, function (e) { + .on('change', $.debounce(250, function (e) { var item = $(this).data('item'); var itemData = OSD.data.items[item.id]; itemData.position = parseInt($(this).val()); @@ -2715,7 +2785,7 @@ OSD.GUI.updateFields = function() { } $displayFields.append($field); } - if (groupContainer.find('.display-fields').children().size() > 0) { + if (groupContainer.find('.display-fields').children().length > 0) { $tmpl.parent().append(groupContainer); } } @@ -2726,7 +2796,7 @@ OSD.GUI.updateFields = function() { .attr('checked', isGuidesChecked) .on('change', function () { OSD.GUI.updateGuidesView(this.checked); - chrome.storage.local.set({'showOSDGuides': this.checked}); + store.set('showOSDGuides', this.checked); OSD.GUI.updatePreviews(); }) ); @@ -2791,7 +2861,7 @@ OSD.GUI.updateDjiMessageElements = function(on) { }; OSD.GUI.updateGuidesView = function(on) { - isHdZero = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'HDZERO'; + let isHdZero = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'HDZERO'; $('.hd_43_margin_left').toggleClass('hdzero_43_left', (isHdZero && on)) $('.hd_43_margin_right').toggleClass('hdzero_43_right', (isHdZero && on)) $('.hd_3016_box_top').toggleClass('hd_3016_top', (isHdZero && on)) @@ -2799,11 +2869,11 @@ OSD.GUI.updateGuidesView = function(on) { $('.hd_3016_box_left').toggleClass('hd_3016_left', (isHdZero && on)) $('.hd_3016_box_right').toggleClass('hd_3016_right', (isHdZero && on)) - isDJIWTF = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'DJIWTF'; + let isDJIWTF = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'DJIWTF'; $('.hd_43_margin_left').toggleClass('dji_hd_43_left', (isDJIWTF && on)) $('.hd_43_margin_right').toggleClass('dji_hd_43_right', (isDJIWTF && on)) - isAvatar = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'AVATAR'; + let isAvatar = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'AVATAR'; $('.hd_43_margin_left').toggleClass('hd_avatar_43_left', (isAvatar && on)) $('.hd_43_margin_right').toggleClass('hd_avatar_43_right', (isAvatar && on)) $('.hd_avatar_bottom_bar').toggleClass('hd_avatar_bottom', (isAvatar && on)) @@ -2812,13 +2882,13 @@ OSD.GUI.updateGuidesView = function(on) { $('.hd_avatar_storage_box_left').toggleClass('hd_avatar_storagebox_l', (isAvatar && on)) $('.hd_avatar_storage_box_right').toggleClass('hd_avatar_storagebox_r', (isAvatar && on)) - isBfHdCompat = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'BFHDCOMPAT'; + let isBfHdCompat = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'BFHDCOMPAT'; $('.hd_43_margin_left').toggleClass('hd_bfhdcompat_43_left', (isBfHdCompat && on)); $('.hd_43_margin_right').toggleClass('hd_bfhdcompat_43_right', (isBfHdCompat && on)); $('.hd_bfhdcompat_bottom_box').toggleClass('hd_bfhdcompat_bottom', (isBfHdCompat && on)); $('.hd_bfhdcompat_storage_box').toggleClass('hd_bfhdcompat_storagebox', (isBfHdCompat && on)); - isPAL = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'PAL' || OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'AUTO'; + let isPAL = OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'PAL' || OSD.constants.VIDEO_TYPES[OSD.data.preferences.video_system] == 'AUTO'; $('.pal_ntsc_box_bottom').toggleClass('ntsc_bottom', (isPAL && on)) }; @@ -2890,7 +2960,7 @@ OSD.GUI.updatePreviews = function() { OSD.data.preview = []; // clear the buffer - for (i = 0; i < OSD.data.display_size.total; i++) { + for (let i = 0; i < OSD.data.display_size.total; i++) { OSD.data.preview.push([null, ' '.charCodeAt(0)]); }; @@ -2927,7 +2997,7 @@ OSD.GUI.updatePreviews = function() { } var x = 0; var y = 0; - for (i = 0; i < preview.length; i++) { + for (let i = 0; i < preview.length; i++) { var charCode = preview.charCodeAt(i); if (charCode == '\n'.charCodeAt(0)) { x = 0; @@ -2969,7 +3039,7 @@ OSD.GUI.updatePreviews = function() { // artificial horizon if ($('input[name="ARTIFICIAL_HORIZON"]').prop('checked')) { - for (i = 0; i < 9; i++) { + for (let i = 0; i < 9; i++) { OSD.GUI.checkAndProcessSymbolPosition(hudCenterPosition - 4 + i, SYM.AH_BAR9_0 + 4); } } @@ -3001,7 +3071,7 @@ OSD.GUI.updatePreviews = function() { if ($('input[name="HORIZON_SIDEBARS"]').prop('checked')) { var hudwidth = OSD.constants.AHISIDEBARWIDTHPOSITION; var hudheight = OSD.constants.AHISIDEBARHEIGHTPOSITION; - for (i = -hudheight; i <= hudheight; i++) { + for (let i = -hudheight; i <= hudheight; i++) { OSD.GUI.checkAndProcessSymbolPosition(hudCenterPosition - hudwidth + (i * FONT.constants.SIZES.LINE), SYM.AH_DECORATION); OSD.GUI.checkAndProcessSymbolPosition(hudCenterPosition + hudwidth + (i * FONT.constants.SIZES.LINE), SYM.AH_DECORATION); } @@ -3017,7 +3087,7 @@ OSD.GUI.updatePreviews = function() { // render var $preview = $('.display-layout .preview').empty(); var $row = $('
'); - for (i = 0; i < OSD.data.display_size.total;) { + for (let i = 0; i < OSD.data.display_size.total;) { var charCode = OSD.data.preview[i]; var colorStyle = ''; @@ -3042,7 +3112,7 @@ OSD.GUI.updatePreviews = function() { $img.find('img').css('pointer-events', 'none'); if (item && item.positionable !== false) { var nameKey = 'osdElement_' + item.name; - var nameMessage = chrome.i18n.getMessage(nameKey); + var nameMessage = i18n.getMessage(nameKey); if (!nameMessage) { nameMessage = inflection.titleize(item.name); @@ -3069,10 +3139,13 @@ OSD.GUI.updateAll = function() { return; } var layouts = $('.osd_layouts'); + var copy = $('.osd_copy'); + var paste = $('.osd_paste').hide(); + var clear = $('.osd_clear'); if (OSD.data.layout_count > 1) { layouts.empty(); for (var ii = 0; ii < OSD.data.layout_count; ii++) { - var name = ii > 0 ? chrome.i18n.getMessage('osdLayoutAlternative', [ii]) : chrome.i18n.getMessage('osdLayoutDefault'); + var name = ii > 0 ? i18n.getMessage('osdLayoutAlternative', [ii]) : i18n.getMessage('osdLayoutDefault'); var opt = $('
+ +
+
+ +

@@ -101,7 +261,7 @@

-
+
@@ -115,13 +275,20 @@

+
-
- - +
+
+
+ +
+
+ +
+
-