mirror of
https://github.com/betaflight/betaflight-configurator.git
synced 2025-07-23 16:25:22 +03:00
Feat/vite build (#3292)
feat: vite based web build * configure vitejs build * add web serial option
This commit is contained in:
parent
172cb0bee9
commit
ff4b62d7e2
15 changed files with 723 additions and 54 deletions
|
@ -280,6 +280,11 @@ function processPackage(done, gitRevision, isReleaseBuild) {
|
||||||
|
|
||||||
// remove gulp-appdmg from the package.json we're going to write
|
// remove gulp-appdmg from the package.json we're going to write
|
||||||
delete pkg.optionalDependencies['gulp-appdmg'];
|
delete pkg.optionalDependencies['gulp-appdmg'];
|
||||||
|
// keeping this package in `package.json` for some reason
|
||||||
|
// breaks the nwjs builds. This is not really needed for
|
||||||
|
// nwjs nor it's imported anywhere at runtime ¯\_(ツ)_/¯
|
||||||
|
// this probably can go away if we fully move to pwa.
|
||||||
|
delete pkg.dependencies['@vitejs/plugin-vue2'];
|
||||||
|
|
||||||
pkg.gitRevision = gitRevision;
|
pkg.gitRevision = gitRevision;
|
||||||
if (!isReleaseBuild) {
|
if (!isReleaseBuild) {
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
"main": "main.html",
|
"main": "main.html",
|
||||||
"chromium-args": "--disable-features=nw2",
|
"chromium-args": "--disable-features=nw2",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
"start": "run-script-os",
|
"start": "run-script-os",
|
||||||
"start:default": "NODE_ENV=development NW_PRE_ARGS=--load-extension='./node_modules/nw-vue-devtools-prebuilt/extension' gulp debug",
|
"start:default": "NODE_ENV=development NW_PRE_ARGS=--load-extension='./node_modules/nw-vue-devtools-prebuilt/extension' gulp debug",
|
||||||
"start:windows": "set NODE_ENV=development && set NW_PRE_ARGS=--load-extension='./node_modules/nw-vue-devtools-prebuilt/extension' && gulp debug",
|
"start:windows": "set NODE_ENV=development && set NW_PRE_ARGS=--load-extension='./node_modules/nw-vue-devtools-prebuilt/extension' && gulp debug",
|
||||||
|
@ -54,6 +55,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^5.13.0",
|
"@fortawesome/fontawesome-free": "^5.13.0",
|
||||||
"@panter/vue-i18next": "^0.15.2",
|
"@panter/vue-i18next": "^0.15.2",
|
||||||
|
"@vitejs/plugin-vue2": "^2.2.0",
|
||||||
"bonjour": "^3.5.0",
|
"bonjour": "^3.5.0",
|
||||||
"crypto-es": "^1.2.7",
|
"crypto-es": "^1.2.7",
|
||||||
"d3": "^7.8.2",
|
"d3": "^7.8.2",
|
||||||
|
@ -136,7 +138,8 @@
|
||||||
"appdmg": "^0.6.4"
|
"appdmg": "^0.6.4"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"jquery": "3.6.3"
|
"jquery": "3.6.3",
|
||||||
|
"libxmljs2": "0.32.0"
|
||||||
},
|
},
|
||||||
"husky": {
|
"husky": {
|
||||||
"hooks": {
|
"hooks": {
|
||||||
|
|
342
src/index.html
Normal file
342
src/index.html
Normal file
|
@ -0,0 +1,342 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
|
<meta name="author" content="cTn"/>
|
||||||
|
|
||||||
|
<script type="module" src="./src/js/utils/common.js"></script>
|
||||||
|
<script type="module" src="./src/js/browserMain.js"></script>
|
||||||
|
|
||||||
|
<title></title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="main-wrapper">
|
||||||
|
<div id="background"></div>
|
||||||
|
<div id="side_menu_swipe"></div>
|
||||||
|
<div class="headerbar">
|
||||||
|
<div id="menu_btn">
|
||||||
|
<em class="fas fa-bars"></em>
|
||||||
|
</div>
|
||||||
|
<betaflight-logo
|
||||||
|
:configurator-version="CONFIGURATOR.getDisplayVersion()"
|
||||||
|
:firmware-version="FC.CONFIG.flightControllerVersion"
|
||||||
|
:firmware-id="FC.CONFIG.flightControllerIdentifier"
|
||||||
|
:hardware-id="FC.CONFIG.hardwareName"
|
||||||
|
></betaflight-logo>
|
||||||
|
<div id="port-picker">
|
||||||
|
<div id="port-override-option">
|
||||||
|
<label for="port-override">
|
||||||
|
<span i18n="portOverrideText">Port:</span>
|
||||||
|
<input id="port-override" type="text" value="/dev/rfcomm0"/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="firmware-virtual-option">
|
||||||
|
<div class="dropdown dropdown-dark">
|
||||||
|
<select id="firmware-version-dropdown" class="dropdown-select" i18n_title="virtualMSPVersion"></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="portsinput" style="display: none">
|
||||||
|
<div class="dropdown dropdown-dark">
|
||||||
|
<select class="dropdown-select" id="port" i18n_title="firmwareFlasherManualPort">
|
||||||
|
<option value="loading" i18n="serialPortLoading">Loading</option>
|
||||||
|
<!-- port list gets generated here -->
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div id="auto-connect-and-baud">
|
||||||
|
<div id="auto-connect-switch">
|
||||||
|
<label>
|
||||||
|
<input class="auto_connect togglesmall" type="checkbox"/>
|
||||||
|
<span class="auto_connect" i18n="autoConnect"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div id="baudselect">
|
||||||
|
<div class="dropdown dropdown-dark">
|
||||||
|
<select class="dropdown-select" id="baud" i18n_title="firmwareFlasherBaudRate">
|
||||||
|
<option value="1000000">1000000</option>
|
||||||
|
<option value="500000">500000</option>
|
||||||
|
<option value="250000">250000</option>
|
||||||
|
<option value="115200" selected="selected">115200</option>
|
||||||
|
<option value="57600">57600</option>
|
||||||
|
<option value="38400">38400</option>
|
||||||
|
<option value="28800">28800</option>
|
||||||
|
<option value="19200">19200</option>
|
||||||
|
<option value="14400">14400</option>
|
||||||
|
<option value="9600">9600</option>
|
||||||
|
<option value="4800">4800</option>
|
||||||
|
<option value="2400">2400</option>
|
||||||
|
<option value="1200">1200</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="header-wrapper">
|
||||||
|
<div id="quad-status_wrapper">
|
||||||
|
<battery-icon
|
||||||
|
:voltage="FC.ANALOG.voltage"
|
||||||
|
:vbatmincellvoltage="FC.BATTERY_CONFIG.vbatmincellvoltage"
|
||||||
|
:vbatmaxcellvoltage="FC.BATTERY_CONFIG.vbatmaxcellvoltage"
|
||||||
|
:vbatwarningcellvoltage="FC.BATTERY_CONFIG.vbatwarningcellvoltage"
|
||||||
|
:batteryState="FC.BATTERY_STATE?.batteryState"
|
||||||
|
>
|
||||||
|
</battery-icon>
|
||||||
|
<battery-legend
|
||||||
|
:voltage="FC.ANALOG.voltage"
|
||||||
|
:vbatmaxcellvoltage="FC.BATTERY_CONFIG.vbatmaxcellvoltage"
|
||||||
|
></battery-legend>
|
||||||
|
<div class="bottomStatusIcons">
|
||||||
|
<div class="armedicon cf_tip" i18n_title="mainHelpArmed"></div>
|
||||||
|
<div class="failsafeicon cf_tip" i18n_title="mainHelpFailsafe"></div>
|
||||||
|
<div class="linkicon cf_tip" i18n_title="mainHelpLink"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="sensor-status" class="sensor_state mode-connected">
|
||||||
|
<ul>
|
||||||
|
<li class="gyro" i18n_title="sensorStatusGyro">
|
||||||
|
<div class="gyroicon" i18n="sensorStatusGyroShort"></div>
|
||||||
|
</li>
|
||||||
|
<li class="accel" i18n_title="sensorStatusAccel">
|
||||||
|
<div class="accicon" i18n="sensorStatusAccelShort"></div>
|
||||||
|
</li>
|
||||||
|
<li class="mag" i18n_title="sensorStatusMag">
|
||||||
|
<div class="magicon" i18n="sensorStatusMagShort"></div>
|
||||||
|
</li>
|
||||||
|
<li class="baro" i18n_title="sensorStatusBaro">
|
||||||
|
<div class="baroicon" i18n="sensorStatusBaroShort"></div>
|
||||||
|
</li>
|
||||||
|
<li class="gps" i18n_title="sensorStatusGPS">
|
||||||
|
<div class="gpsicon" i18n="sensorStatusGPSShort"></div>
|
||||||
|
</li>
|
||||||
|
<li class="sonar" i18n_title="sensorStatusSonar">
|
||||||
|
<div class="sonaricon" i18n="sensorStatusSonarShort"></div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div id="dataflash_wrapper_global">
|
||||||
|
<div class="noflash_global" align="center" i18n="sensorDataFlashNotFound"></div>
|
||||||
|
<ul class="dataflash-contents_global">
|
||||||
|
<li class="dataflash-free_global">
|
||||||
|
<div class="legend" i18n="sensorDataFlashFreeSpace"></div>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div id="expertMode" align="center">
|
||||||
|
<label>
|
||||||
|
<input name="expertModeCheckbox" class="togglesmall" type="checkbox"/>
|
||||||
|
<span i18n="expertMode"></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="header_btns">
|
||||||
|
<div class="open_firmware_flasher" id="flashbutton">
|
||||||
|
<div class="firmware_b">
|
||||||
|
<a class="flash disabled" href="#"></a>
|
||||||
|
</div>
|
||||||
|
<div class="flash_state" i18n="flashTab"></div>
|
||||||
|
</div>
|
||||||
|
<div class="connect_controls" id="connectbutton">
|
||||||
|
<div class="connect_b">
|
||||||
|
<a class="connect disabled" href="#"></a>
|
||||||
|
</div>
|
||||||
|
<div class="connect_state" i18n="connect"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="reveal_btn">
|
||||||
|
<em class="fas fa-ellipsis-v"></em>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="log">
|
||||||
|
<div class="logswitch">
|
||||||
|
<a href="#" id="showlog" i18n="logActionShow"></a>
|
||||||
|
</div>
|
||||||
|
<div id="scrollicon"></div>
|
||||||
|
<div class="wrapper"></div>
|
||||||
|
</div>
|
||||||
|
<div id="tab-content-container">
|
||||||
|
<div class="tab_container">
|
||||||
|
<betaflight-logo
|
||||||
|
:configurator-version="CONFIGURATOR.getDisplayVersion()"
|
||||||
|
:firmware-version="FC.CONFIG.flightControllerVersion"
|
||||||
|
:firmware-id="FC.CONFIG.flightControllerIdentifier"
|
||||||
|
:hardware-id="FC.CONFIG.hardwareName"
|
||||||
|
></betaflight-logo>
|
||||||
|
<div id="tabs">
|
||||||
|
<ul class="mode-disconnected">
|
||||||
|
<li class="tab_landing" id="tab_landing"><a href="#" i18n="tabLanding" class="tabicon ic_welcome" i18n_title="tabLanding"></a>
|
||||||
|
</li>
|
||||||
|
<li class="tab_changelog"><a href="#" class="tabicon ic_help" i18n="tabChangelog"></a></li>
|
||||||
|
<li class="tab_privacy_policy"><a href="#" class="tabicon ic_help" i18n="tabPrivacyPolicy"></a></li>
|
||||||
|
<li class="tab_help" id="tab_help"><a href="#" i18n="tabHelp" class="tabicon ic_help"
|
||||||
|
i18n_title="tabHelp"></a></li>
|
||||||
|
<li class="tab_options" id="tab_options"><a href="#" i18n="tabOptions" class="tabicon ic_config" i18n_title="tabOptions"></a>
|
||||||
|
</li>
|
||||||
|
<li class="tab_firmware_flasher" id="tabFirmware"><a href="#" i18n="tabFirmwareFlasher" class="tabicon ic_flasher"
|
||||||
|
i18n_title="tabFirmwareFlasher"></a></li>
|
||||||
|
</ul>
|
||||||
|
<ul class="mode-connected">
|
||||||
|
<li class="tab_setup"><a href="#" i18n="tabSetup" class="tabicon ic_setup" i18n_title="tabSetup"></a></li>
|
||||||
|
<li class="tab_setup_osd"><a href="#" i18n="tabSetupOSD" class="tabicon ic_setup" i18n_title="tabSetupOSD"></a></li>
|
||||||
|
|
||||||
|
<li class="tab_ports"><a href="#" i18n="tabPorts" class="tabicon ic_ports" i18n_title="tabPorts"></a></li>
|
||||||
|
<li class="tab_configuration"><a href="#" i18n="tabConfiguration" class="tabicon ic_config"
|
||||||
|
i18n_title="tabConfiguration"></a></li>
|
||||||
|
<li class="tab_power"><a href="#" i18n="tabPower" class="tabicon ic_power"
|
||||||
|
i18n_title="tabPower"></a></li>
|
||||||
|
<li class="tab_failsafe"><a href="#" i18n="tabFailsafe" class="tabicon ic_failsafe"
|
||||||
|
i18n_title="tabFailsafe"></a></li>
|
||||||
|
<li class="tab_presets">
|
||||||
|
<a href="#" i18n="tabPresets" class="tabicon ic_wizzard" i18n_title="tabPresets"></a>
|
||||||
|
</li>
|
||||||
|
<li class="tab_pid_tuning"><a href="#" i18n="tabPidTuning" class="tabicon ic_pid"
|
||||||
|
i18n_title="tabPidTuning"></a></li>
|
||||||
|
<li class="tab_receiver"><a href="#" i18n="tabReceiver" class="tabicon ic_rx" i18n_title="tabReceiver"></a></li>
|
||||||
|
<li class="tab_auxiliary"><a href="#" i18n="tabAuxiliary" class="tabicon ic_modes" i18n_title="tabAuxiliary"></a>
|
||||||
|
</li>
|
||||||
|
<li class="tab_adjustments"><a href="#" i18n="tabAdjustments" class="tabicon ic_adjust"
|
||||||
|
i18n_title="tabAdjustments"></a></li>
|
||||||
|
<li class="tab_servos"><a href="#" i18n="tabServos" class="tabicon ic_servo" i18n_title="tabServos"></a></li>
|
||||||
|
<li class="tab_gps"><a href="#" i18n="tabGPS" class="tabicon ic_gps" i18n_title="tabGPS"></a></li>
|
||||||
|
<li class="tab_motors"><a href="#" i18n="tabMotorTesting" class="tabicon ic_motor" i18n_title="tabMotorTesting"></a>
|
||||||
|
</li>
|
||||||
|
<li class="tab_osd"><a href="#" i18n="tabOsd" class="tabicon ic_osd" i18n_title="tabOsd"></a></li>
|
||||||
|
<li class="tab_vtx"><a href="#" i18n="tabVtx" class="tabicon ic_vtx" i18n_title="tabVtx"></a></li>
|
||||||
|
<li class="tab_transponder"><a href="#" i18n="tabTransponder" class="tabicon ic_transponder"
|
||||||
|
i18n_title="tabTransponder"></a></li>
|
||||||
|
<li class="tab_led_strip"><a href="#" i18n="tabLedStrip" class="tabicon ic_led" i18n_title="tabLedStrip"></a>
|
||||||
|
</li>
|
||||||
|
<li class="tab_sensors"><a href="#" i18n="tabRawSensorData" class="tabicon ic_sensors"
|
||||||
|
i18n_title="tabRawSensorData"></a></li>
|
||||||
|
<li class="tab_logging"><a href="#" i18n="tabLogging" class="tabicon ic_log"
|
||||||
|
i18n_title="tabLogging"></a></li>
|
||||||
|
<li class="tab_onboard_logging"><a href="#" i18n="tabOnboardLogging" class="tabicon ic_data"
|
||||||
|
i18n_title="tabOnboardLogging"></a></li>
|
||||||
|
<!-- spare icons
|
||||||
|
<li class=""><a href="#"class="tabicon ic_mission">Mission (spare icon)</a></li>
|
||||||
|
<li class=""><a href="#"class="tabicon ic_advanced">Advanced (spare icon)</a></li>
|
||||||
|
<li class=""><a href="#"class="tabicon ic_wizzard">Wizzard (spare icon)</a></li>
|
||||||
|
-->
|
||||||
|
</ul>
|
||||||
|
<ul class="mode-connected mode-connected-cli">
|
||||||
|
<li class="tab_cli">
|
||||||
|
<a href="#" i18n="tabCLI" class="tabicon ic_cli" i18n_title="tabCLI"></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="clear-both"></div>
|
||||||
|
</div>
|
||||||
|
<div id="content"></div>
|
||||||
|
</div>
|
||||||
|
<status-bar
|
||||||
|
:port-usage-down="PortUsage.port_usage_down"
|
||||||
|
:port-usage-up="PortUsage.port_usage_up"
|
||||||
|
:packet-error="MSP.packet_error"
|
||||||
|
:i2c-error="FC.CONFIG.i2cError"
|
||||||
|
:cycle-time="FC.CONFIG.cycleTime"
|
||||||
|
:cpu-load="FC.CONFIG.cpuload"
|
||||||
|
|
||||||
|
:configurator-version="CONFIGURATOR.getDisplayVersion()"
|
||||||
|
:firmware-version="FC.CONFIG.flightControllerVersion"
|
||||||
|
:firmware-id="FC.CONFIG.flightControllerIdentifier"
|
||||||
|
:hardware-id="FC.CONFIG.hardwareName"
|
||||||
|
></status-bar>
|
||||||
|
<div id="cache">
|
||||||
|
<div class="data-loading">
|
||||||
|
<p>Waiting for data ...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<dialog class="dialogConfiguratorUpdate">
|
||||||
|
<h3 i18n="noticeTitle"></h3>
|
||||||
|
<div class="content">
|
||||||
|
<div class="dialogConfiguratorUpdate-content" style="margin-top: 10px"></div>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="#" class="dialogConfiguratorUpdate-websitebtn regular-button" i18n="configuratorUpdateWebsite"></a>
|
||||||
|
<a href="#" class="dialogConfiguratorUpdate-closebtn regular-button" i18n="close"></a>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog class="dialogConnectWarning">
|
||||||
|
<h3 i18n="warningTitle"></h3>
|
||||||
|
<div class="content">
|
||||||
|
<div class="dialogConnectWarning-content" style="margin-top: 10px"></div>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="#" class="dialogConnectWarning-closebtn regular-button" i18n="close"></a>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog id="dialogResetToCustomDefaults">
|
||||||
|
<h3 i18n="noticeTitle"></h3>
|
||||||
|
<div class="content">
|
||||||
|
<div id="dialogResetToCustomDefaults-content" i18n="resetToCustomDefaultsDialog"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="buttons">
|
||||||
|
<a href="#" id="dialogResetToCustomDefaults-acceptbtn" class="regular-button" i18n="resetToCustomDefaultsAccept"></a>
|
||||||
|
</span>
|
||||||
|
<span class="buttons">
|
||||||
|
<a href="#" id="dialogResetToCustomDefaults-cancelbtn" class="regular-button" i18n="cancel"></a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog id="dialogReportProblems">
|
||||||
|
<h3 i18n="warningTitle"></h3>
|
||||||
|
<div class="content">
|
||||||
|
<div id="dialogReportProblems-header" i18n="reportProblemsDialogHeader"></div>
|
||||||
|
<ul id="dialogReportProblems-list">
|
||||||
|
<!-- List elements added dynamically -->
|
||||||
|
</ul>
|
||||||
|
<div id="dialogReportProblems-footer" i18n="reportProblemsDialogFooter"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span class="buttons">
|
||||||
|
<a href="#" id="dialogReportProblems-closebtn" class="regular-button" i18n="close"></a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<ul class="hidden"> <!-- Sonar says so -->
|
||||||
|
<li id="dialogReportProblems-listItemTemplate" class="dialogReportProblems-listItem"></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<dialog class="dialogError">
|
||||||
|
<h3 i18n="errorTitle"></h3>
|
||||||
|
<div class="content">
|
||||||
|
<div class="dialogError-content" style="margin-top: 10px"></div>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="#" class="dialogError-closebtn regular-button" i18n="close"></a>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog class="dialogYesNo">
|
||||||
|
<h3 class="dialogYesNoTitle"></h3>
|
||||||
|
<div class="dialogYesNoContent"></div>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="#" class="dialogYesNo-yesButton regular-button"></a>
|
||||||
|
<a href="#" class="dialogYesNo-noButton regular-button"></a>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog class="dialogWait">
|
||||||
|
<div class="data-loading"></div>
|
||||||
|
<h3 class="dialogWaitTitle"></h3>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="#" class="dialogWait-cancelButton regular-button" i18n="cancel"></a>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
|
||||||
|
<dialog class="dialogInformation">
|
||||||
|
<h3 class="dialogInformationTitle"></h3>
|
||||||
|
<div class="dialogInformationContent"></div>
|
||||||
|
<div class="buttons">
|
||||||
|
<a href="#" class="dialogInformation-confirmButton regular-button"></a>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
<!-- CORDOVA_INCLUDE cordova.js -->
|
||||||
|
</body>
|
||||||
|
</html>
|
54
src/js/browserMain.js
Normal file
54
src/js/browserMain.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
import '../js/jqueryPlugins';
|
||||||
|
import "jbox/dist/jBox.min.css";
|
||||||
|
import "../../libraries/jquery.nouislider.min.css";
|
||||||
|
import "../../libraries/jquery.nouislider.pips.min.css";
|
||||||
|
import "../../libraries/flightindicators.css";
|
||||||
|
|
||||||
|
import "../css/theme.css";
|
||||||
|
import "../css/main.less";
|
||||||
|
import "../css/tabs/static_tab.less";
|
||||||
|
import "../css/tabs/landing.less";
|
||||||
|
import "../css/tabs/setup.less";
|
||||||
|
import "../css/tabs/help.less";
|
||||||
|
import "../css/tabs/ports.less";
|
||||||
|
import "../css/tabs/configuration.less";
|
||||||
|
import "../css/tabs/pid_tuning.less";
|
||||||
|
import "../css/tabs/receiver.less";
|
||||||
|
import "../css/tabs/servos.less";
|
||||||
|
import "../css/tabs/gps.less";
|
||||||
|
import "../css/tabs/motors.less";
|
||||||
|
import "../css/tabs/led_strip.less";
|
||||||
|
import "../css/tabs/sensors.less";
|
||||||
|
import "../css/tabs/cli.less";
|
||||||
|
import "../tabs/presets/presets.less";
|
||||||
|
// TODO: for some reason can't resolve these less files
|
||||||
|
// import "../tabs/presets/TitlePanel/PresetTitlePanel.less";
|
||||||
|
import "../tabs/presets/DetailedDialog/PresetsDetailedDialog.less";
|
||||||
|
// TODO: for some reason can't resolve these less files
|
||||||
|
// import "../tabs/presets/SourcesDialog/SourcesDialog.less";
|
||||||
|
// import "../tabs/presets/SourcesDialog/SourcePanel.less";
|
||||||
|
import "../css/tabs/logging.less";
|
||||||
|
import "../css/tabs/onboard_logging.less";
|
||||||
|
import "../css/tabs/firmware_flasher.less";
|
||||||
|
import "../css/tabs/adjustments.less";
|
||||||
|
import "../css/tabs/auxiliary.less";
|
||||||
|
import "../css/tabs/failsafe.less";
|
||||||
|
import "../css/tabs/osd.less";
|
||||||
|
import "../css/tabs/vtx.less";
|
||||||
|
import "../css/tabs/power.less";
|
||||||
|
import "../css/tabs/transponder.less";
|
||||||
|
import "../css/tabs/privacy_policy.less";
|
||||||
|
import "../css/tabs/options.less";
|
||||||
|
import "../css/opensans_webfontkit/fonts.css";
|
||||||
|
import "../css/dropdown-lists/css/style_lists.css";
|
||||||
|
import "switchery-latest/dist/switchery.min.css";
|
||||||
|
import "../css/switchery_custom.less";
|
||||||
|
import "@fortawesome/fontawesome-free/css/all.css";
|
||||||
|
import "../components/MotorOutputReordering/Styles.css";
|
||||||
|
import "../css/select2_custom.less";
|
||||||
|
import "select2/dist/css/select2.min.css";
|
||||||
|
import "multiple-select/dist/multiple-select.min.css";
|
||||||
|
import "../components/EscDshotDirection/Styles.css";
|
||||||
|
import "../css/dark-theme.less";
|
||||||
|
|
||||||
|
import "./main";
|
|
@ -50,11 +50,13 @@ function useGlobalNodeFunctions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function readConfiguratorVersionMetadata() {
|
function readConfiguratorVersionMetadata() {
|
||||||
|
if (GUI.isNWJS()) {
|
||||||
const manifest = chrome.runtime.getManifest();
|
const manifest = chrome.runtime.getManifest();
|
||||||
CONFIGURATOR.productName = manifest.productName;
|
CONFIGURATOR.productName = manifest.productName;
|
||||||
CONFIGURATOR.version = manifest.version;
|
CONFIGURATOR.version = manifest.version;
|
||||||
CONFIGURATOR.gitRevision = manifest.gitRevision;
|
CONFIGURATOR.gitRevision = manifest.gitRevision;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function cleanupLocalStorage() {
|
function cleanupLocalStorage() {
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,9 @@ MdnsDiscovery.initialize = function() {
|
||||||
|
|
||||||
reinit();
|
reinit();
|
||||||
} else {
|
} else {
|
||||||
|
if(typeof require === 'undefined') {
|
||||||
|
return 'not implemented';
|
||||||
|
}
|
||||||
const bonjour = require('bonjour')();
|
const bonjour = require('bonjour')();
|
||||||
|
|
||||||
self.mdnsBrowser.browser = bonjour.find({ type: 'http' }, service => {
|
self.mdnsBrowser.browser = bonjour.find({ type: 'http' }, service => {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import GUI from "./gui.js";
|
import GUI from "./gui.js";
|
||||||
import CONFIGURATOR from "./data_storage.js";
|
import CONFIGURATOR from "./data_storage.js";
|
||||||
import serial from "./serial.js";
|
import serialNWJS from "./serial.js";
|
||||||
|
import serialWeb from "./webSerial.js";
|
||||||
|
|
||||||
|
const serial = import.meta.env ? serialWeb : serialNWJS;
|
||||||
|
|
||||||
const MSP = {
|
const MSP = {
|
||||||
symbols: {
|
symbols: {
|
||||||
|
@ -66,7 +69,7 @@ const MSP = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = new Uint8Array(readInfo.data);
|
const data = new Uint8Array(readInfo.data ?? readInfo);
|
||||||
|
|
||||||
for (const chunk of data) {
|
for (const chunk of data) {
|
||||||
switch (this.state) {
|
switch (this.state) {
|
||||||
|
@ -304,14 +307,14 @@ const MSP = {
|
||||||
return bufferOut;
|
return bufferOut;
|
||||||
},
|
},
|
||||||
send_message(code, data, callback_sent, callback_msp, doCallbackOnError) {
|
send_message(code, data, callback_sent, callback_msp, doCallbackOnError) {
|
||||||
if (code === undefined || !serial.connectionId || CONFIGURATOR.virtualMode) {
|
const connected = import.meta.env ? serial.connected : serial.connectionId;
|
||||||
|
if (code === undefined || !connected || CONFIGURATOR.virtualMode) {
|
||||||
if (callback_msp) {
|
if (callback_msp) {
|
||||||
callback_msp();
|
callback_msp();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if request already exists in the queue
|
|
||||||
let requestExists = false;
|
let requestExists = false;
|
||||||
for (const instance of this.callbacks) {
|
for (const instance of this.callbacks) {
|
||||||
if (instance.code === code) {
|
if (instance.code === code) {
|
||||||
|
@ -321,6 +324,12 @@ const MSP = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (import.meta.env && (code === undefined || !serial.connectionInfo)) {
|
||||||
|
console.log('ERROR: code undefined or no connectionId');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const bufferOut = code <= 254 ? this.encode_message_v1(code, data) : this.encode_message_v2(code, data);
|
const bufferOut = code <= 254 ? this.encode_message_v1(code, data) : this.encode_message_v2(code, data);
|
||||||
|
|
||||||
const obj = {
|
const obj = {
|
||||||
|
@ -374,7 +383,7 @@ const MSP = {
|
||||||
},
|
},
|
||||||
callbacks_cleanup() {
|
callbacks_cleanup() {
|
||||||
for (const callback of this.callbacks) {
|
for (const callback of this.callbacks) {
|
||||||
clearInterval(callback.timer);
|
clearTimeout(callback.timer);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.callbacks = [];
|
this.callbacks = [];
|
||||||
|
|
|
@ -29,6 +29,12 @@ const PortHandler = new function () {
|
||||||
PortHandler.initialize = function () {
|
PortHandler.initialize = function () {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
|
// currently web build doesn't need port handler,
|
||||||
|
// so just bail out.
|
||||||
|
if (import.meta.env) {
|
||||||
|
return 'not implemented';
|
||||||
|
}
|
||||||
|
|
||||||
const portPickerElementSelector = "div#port-picker #port";
|
const portPickerElementSelector = "div#port-picker #port";
|
||||||
self.portPickerElement = $(portPickerElementSelector);
|
self.portPickerElement = $(portPickerElementSelector);
|
||||||
self.selectList = document.querySelector(portPickerElementSelector);
|
self.selectList = document.querySelector(portPickerElementSelector);
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { gui_log } from "./gui_log";
|
||||||
import inflection from "inflection";
|
import inflection from "inflection";
|
||||||
import PortHandler from "./port_handler";
|
import PortHandler from "./port_handler";
|
||||||
import { checkChromeRuntimeError } from "./utils/common";
|
import { checkChromeRuntimeError } from "./utils/common";
|
||||||
|
import { serialDevices } from './serial_devices';
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
|
||||||
const serial = {
|
const serial = {
|
||||||
|
@ -23,14 +24,7 @@ const serial = {
|
||||||
transmitting: false,
|
transmitting: false,
|
||||||
outputBuffer: [],
|
outputBuffer: [],
|
||||||
|
|
||||||
serialDevices: [
|
serialDevices,
|
||||||
{'vendorId': 1027, 'productId': 24577}, // FT232R USB UART
|
|
||||||
{'vendorId': 1155, 'productId': 22336}, // STM Electronics Virtual COM Port
|
|
||||||
{'vendorId': 4292, 'productId': 60000}, // CP210x
|
|
||||||
{'vendorId': 4292, 'productId': 60001}, // CP210x
|
|
||||||
{'vendorId': 4292, 'productId': 60002}, // CP210x
|
|
||||||
{'vendorId': 0x2e3c, 'productId': 0x5740}, // AT32 VCP
|
|
||||||
],
|
|
||||||
|
|
||||||
connect: function (path, options, callback) {
|
connect: function (path, options, callback) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
|
@ -11,7 +11,6 @@ import MSPCodes from "./msp/MSPCodes";
|
||||||
import PortUsage from "./port_usage";
|
import PortUsage from "./port_usage";
|
||||||
import PortHandler from "./port_handler";
|
import PortHandler from "./port_handler";
|
||||||
import CONFIGURATOR, { API_VERSION_1_45, API_VERSION_1_46 } from "./data_storage";
|
import CONFIGURATOR, { API_VERSION_1_45, API_VERSION_1_46 } from "./data_storage";
|
||||||
import serial from "./serial";
|
|
||||||
import UI_PHONES from "./phones_ui";
|
import UI_PHONES from "./phones_ui";
|
||||||
import { bit_check } from './bit.js';
|
import { bit_check } from './bit.js';
|
||||||
import { sensor_status, have_sensor } from "./sensor_helpers";
|
import { sensor_status, have_sensor } from "./sensor_helpers";
|
||||||
|
@ -25,6 +24,11 @@ import CryptoES from "crypto-es";
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import BuildApi from "./BuildApi";
|
import BuildApi from "./BuildApi";
|
||||||
|
|
||||||
|
import serialNWJS from "./serial.js";
|
||||||
|
import serialWeb from "./webSerial.js";
|
||||||
|
|
||||||
|
const serial = import.meta.env ? serialWeb : serialNWJS;
|
||||||
|
|
||||||
let mspHelper;
|
let mspHelper;
|
||||||
let connectionTimestamp;
|
let connectionTimestamp;
|
||||||
let clicks = false;
|
let clicks = false;
|
||||||
|
@ -64,8 +68,19 @@ export function initializeSerialBackend() {
|
||||||
GUI.updateManualPortVisibility();
|
GUI.updateManualPortVisibility();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('div.connect_controls a.connect').click(function () {
|
|
||||||
if (!GUI.connect_lock) { // GUI control overrides the user control
|
$("div.connect_controls a.connect").on('click', function () {
|
||||||
|
|
||||||
|
const selectedPort = $('div#port-picker #port option:selected');
|
||||||
|
let portName;
|
||||||
|
if (selectedPort.data().isManual) {
|
||||||
|
portName = $('#port-override').val();
|
||||||
|
} else {
|
||||||
|
portName = String($('div#port-picker #port').val());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!GUI.connect_lock) {
|
||||||
|
// GUI control overrides the user control
|
||||||
|
|
||||||
const toggleStatus = function () {
|
const toggleStatus = function () {
|
||||||
clicks = !clicks;
|
clicks = !clicks;
|
||||||
|
@ -76,13 +91,6 @@ export function initializeSerialBackend() {
|
||||||
const selected_baud = parseInt($('div#port-picker #baud').val());
|
const selected_baud = parseInt($('div#port-picker #baud').val());
|
||||||
const selectedPort = $('div#port-picker #port option:selected');
|
const selectedPort = $('div#port-picker #port option:selected');
|
||||||
|
|
||||||
let portName;
|
|
||||||
if (selectedPort.data().isManual) {
|
|
||||||
portName = $('#port-override').val();
|
|
||||||
} else {
|
|
||||||
portName = String($('div#port-picker #port').val());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (selectedPort.data().isDFU) {
|
if (selectedPort.data().isDFU) {
|
||||||
$('select#baud').hide();
|
$('select#baud').hide();
|
||||||
} else if (portName !== '0') {
|
} else if (portName !== '0') {
|
||||||
|
@ -94,16 +102,27 @@ export function initializeSerialBackend() {
|
||||||
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', true);
|
$('div#port-picker #port, div#port-picker #baud, div#port-picker #delay').prop('disabled', true);
|
||||||
$('div.connect_controls div.connect_state').text(i18n.getMessage('connecting'));
|
$('div.connect_controls div.connect_state').text(i18n.getMessage('connecting'));
|
||||||
|
|
||||||
|
const baudRate = parseInt($('div#port-picker #baud').val());
|
||||||
if (selectedPort.data().isVirtual) {
|
if (selectedPort.data().isVirtual) {
|
||||||
CONFIGURATOR.virtualMode = true;
|
CONFIGURATOR.virtualMode = true;
|
||||||
CONFIGURATOR.virtualApiVersion = $('#firmware-version-dropdown :selected').val();
|
CONFIGURATOR.virtualApiVersion = $('#firmware-version-dropdown :selected').val();
|
||||||
|
|
||||||
serial.connect('virtual', {}, onOpenVirtual);
|
serial.connect('virtual', {}, onOpenVirtual);
|
||||||
|
} else if (import.meta.env) {
|
||||||
|
serial.addEventListener('connect', (event) => {
|
||||||
|
onOpen(event.detail);
|
||||||
|
toggleStatus();
|
||||||
|
});
|
||||||
|
serial.connect({ baudRate });
|
||||||
} else {
|
} else {
|
||||||
serial.connect(portName, {bitrate: selected_baud}, onOpen);
|
serial.connect(
|
||||||
|
portName,
|
||||||
|
{ bitrate: selected_baud },
|
||||||
|
onOpen,
|
||||||
|
);
|
||||||
|
toggleStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleStatus();
|
|
||||||
} else {
|
} else {
|
||||||
if ($('div#flashbutton a.flash_state').hasClass('active') && $('div#flashbutton a.flash').hasClass('active')) {
|
if ($('div#flashbutton a.flash_state').hasClass('active') && $('div#flashbutton a.flash').hasClass('active')) {
|
||||||
$('div#flashbutton a.flash_state').removeClass('active');
|
$('div#flashbutton a.flash_state').removeClass('active');
|
||||||
|
@ -287,7 +306,11 @@ function onOpen(openInfo) {
|
||||||
result = getConfig('expertMode')?.expertMode ?? false;
|
result = getConfig('expertMode')?.expertMode ?? false;
|
||||||
$('input[name="expertModeCheckbox"]').prop('checked', result).trigger('change');
|
$('input[name="expertModeCheckbox"]').prop('checked', result).trigger('change');
|
||||||
|
|
||||||
|
if(import.meta.env) {
|
||||||
|
serial.addEventListener('receive', (e) => read_serial(e.detail.buffer));
|
||||||
|
} else {
|
||||||
serial.onReceive.addListener(read_serial);
|
serial.onReceive.addListener(read_serial);
|
||||||
|
}
|
||||||
setConnectionTimeout();
|
setConnectionTimeout();
|
||||||
FC.resetState();
|
FC.resetState();
|
||||||
mspHelper = new MspHelper();
|
mspHelper = new MspHelper();
|
||||||
|
|
15
src/js/serial_devices.js
Normal file
15
src/js/serial_devices.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
export const serialDevices = [
|
||||||
|
{ vendorId: 1027, productId: 24577 }, // FT232R USB UART
|
||||||
|
{ vendorId: 1155, productId: 22336 }, // STM Electronics Virtual COM Port
|
||||||
|
{ vendorId: 4292, productId: 60000 }, // CP210x
|
||||||
|
{ vendorId: 4292, productId: 60001 }, // CP210x
|
||||||
|
{ vendorId: 4292, productId: 60002 }, // CP210x
|
||||||
|
{ vendorId: 0x2e3c, productId: 0x5740 }, // AT32 VCP
|
||||||
|
];
|
||||||
|
|
||||||
|
export const webSerialDevices = serialDevices.map(
|
||||||
|
({ vendorId, productId }) => ({
|
||||||
|
usbVendorId: vendorId,
|
||||||
|
usbProductId: productId,
|
||||||
|
}),
|
||||||
|
);
|
|
@ -1,6 +1,10 @@
|
||||||
import windowWatcherUtil from "../utils/window_watchers";
|
import windowWatcherUtil from "../utils/window_watchers";
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
|
|
||||||
|
// This is a hack to get the i18n var of the parent, but the i18n.localizePage not works
|
||||||
|
// It seems than when node opens a new window, the module "context" is different, so the i18n var is not initialized
|
||||||
|
const i18n = opener.i18n;
|
||||||
|
|
||||||
const css_dark = [
|
const css_dark = [
|
||||||
'/css/dark-theme.css',
|
'/css/dark-theme.css',
|
||||||
];
|
];
|
||||||
|
@ -201,10 +205,6 @@ $(window).on("mouseup", function(e) {
|
||||||
|
|
||||||
windowWatcherUtil.bindWatchers(window, watchers);
|
windowWatcherUtil.bindWatchers(window, watchers);
|
||||||
|
|
||||||
// This is a hack to get the i18n var of the parent, but the i18n.localizePage not works
|
|
||||||
// It seems than when node opens a new window, the module "context" is different, so the i18n var is not initialized
|
|
||||||
const i18n = opener.i18n;
|
|
||||||
|
|
||||||
localizePage();
|
localizePage();
|
||||||
localizeAxisNames();
|
localizeAxisNames();
|
||||||
|
|
||||||
|
|
156
src/js/webSerial.js
Normal file
156
src/js/webSerial.js
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
import { webSerialDevices } from "./serial_devices";
|
||||||
|
|
||||||
|
async function* streamAsyncIterable(stream) {
|
||||||
|
const reader = stream.getReader();
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
const { done, value } = await reader.read();
|
||||||
|
if (done) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
yield value;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
reader.releaseLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class WebSerial extends EventTarget {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.connected = false;
|
||||||
|
this.openRequested = false;
|
||||||
|
this.openCanceled = false;
|
||||||
|
this.transmitting = false;
|
||||||
|
this.connectionInfo = null;
|
||||||
|
|
||||||
|
this.bitrate = 0;
|
||||||
|
this.bytesSent = 0;
|
||||||
|
this.bytesReceived = 0;
|
||||||
|
this.failed = 0;
|
||||||
|
|
||||||
|
this.logHead = "SERIAL: ";
|
||||||
|
|
||||||
|
this.port = null;
|
||||||
|
this.reader = null;
|
||||||
|
this.writer = null;
|
||||||
|
|
||||||
|
this.connect = this.connect.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect(options) {
|
||||||
|
this.openRequested = true;
|
||||||
|
this.port = await navigator.serial.requestPort({
|
||||||
|
filters: webSerialDevices,
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.port.open(options);
|
||||||
|
const connectionInfo = this.port.getInfo();
|
||||||
|
this.connectionInfo = connectionInfo;
|
||||||
|
this.writer = this.port.writable.getWriter();
|
||||||
|
|
||||||
|
if (connectionInfo && !this.openCanceled) {
|
||||||
|
this.connected = true;
|
||||||
|
this.connectionId = connectionInfo.connectionId;
|
||||||
|
this.bitrate = options.baudrate;
|
||||||
|
this.bytesReceived = 0;
|
||||||
|
this.bytesSent = 0;
|
||||||
|
this.failed = 0;
|
||||||
|
this.openRequested = false;
|
||||||
|
|
||||||
|
this.addEventListener("receive", (info) => {
|
||||||
|
this.bytesReceived += info.detail.byteLength;
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${this.logHead} Connection opened with ID: ${connectionInfo.connectionId}, Baud: ${options.baudRate}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("connect", { detail: connectionInfo }),
|
||||||
|
);
|
||||||
|
// Check if we need the helper function or could polyfill
|
||||||
|
// the stream async iterable interface:
|
||||||
|
// https://web.dev/streams/#asynchronous-iteration
|
||||||
|
|
||||||
|
for await (let value of streamAsyncIterable(this.port.readable)) {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent("receive", { detail: value }),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (connectionInfo && this.openCanceled) {
|
||||||
|
this.connectionId = connectionInfo.connectionId;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${this.logHead} Connection opened with ID: ${connectionInfo.connectionId}, but request was canceled, disconnecting`,
|
||||||
|
);
|
||||||
|
// some bluetooth dongles/dongle drivers really doesn't like to be closed instantly, adding a small delay
|
||||||
|
setTimeout(() => {
|
||||||
|
this.openRequested = false;
|
||||||
|
this.openCanceled = false;
|
||||||
|
this.disconnect(() => {
|
||||||
|
this.dispatchEvent(new CustomEvent("connect", { detail: false }));
|
||||||
|
});
|
||||||
|
}, 150);
|
||||||
|
} else if (this.openCanceled) {
|
||||||
|
console.log(
|
||||||
|
`${this.logHead} Connection didn't open and request was canceled`,
|
||||||
|
);
|
||||||
|
this.openRequested = false;
|
||||||
|
this.openCanceled = false;
|
||||||
|
this.dispatchEvent(new CustomEvent("connect", { detail: false }));
|
||||||
|
} else {
|
||||||
|
this.openRequested = false;
|
||||||
|
console.log(`${this.logHead} Failed to open serial port`);
|
||||||
|
this.dispatchEvent(new CustomEvent("connect", { detail: false }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async disconnect() {
|
||||||
|
this.connected = false;
|
||||||
|
|
||||||
|
if (this.port) {
|
||||||
|
this.transmitting = false;
|
||||||
|
if (this.writer) {
|
||||||
|
await this.writer.close();
|
||||||
|
this.writer = null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.port.close();
|
||||||
|
this.port = null;
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
`${this.logHead}Connection with ID: ${this.connectionId} closed, Sent: ${this.bytesSent} bytes, Received: ${this.bytesReceived} bytes`,
|
||||||
|
);
|
||||||
|
|
||||||
|
this.connectionId = false;
|
||||||
|
this.bitrate = 0;
|
||||||
|
this.dispatchEvent(new CustomEvent("disconnect"));
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
console.error(
|
||||||
|
`${this.logHead}Failed to close connection with ID: ${this.connectionId} closed, Sent: ${this.bytesSent} bytes, Received: ${this.bytesReceived} bytes`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.openCanceled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async send(data) {
|
||||||
|
// TODO: previous serial implementation had a buffer of 100, do we still need it with streams?
|
||||||
|
if (this.writer) {
|
||||||
|
await this.writer.write(data);
|
||||||
|
this.bytesSent += data.byteLength;
|
||||||
|
} else {
|
||||||
|
console.error(
|
||||||
|
`${this.logHead}Failed to send data, serial port not open`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
bytesSent: this.bytesSent,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default new WebSerial();
|
|
@ -1,13 +1,65 @@
|
||||||
/// <reference types="vitest" />
|
/// <reference types="vitest" />
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from "vite";
|
||||||
|
import vue from "@vitejs/plugin-vue2";
|
||||||
|
import path from "node:path";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is plugin to work around the file structure required nwjs.
|
||||||
|
* In future this can be dropped if we restructure folder structure
|
||||||
|
* to be more web friendly.
|
||||||
|
* @returns {import('vite').Plugin}
|
||||||
|
*/
|
||||||
|
function serveLocalesPlugin() {
|
||||||
|
return {
|
||||||
|
name: "serve-locales",
|
||||||
|
configureServer(server) {
|
||||||
|
return () => {
|
||||||
|
server.middlewares.use((req, res, next) => {
|
||||||
|
if (req.url.startsWith("/locales/")) {
|
||||||
|
// Extract the file path from the URL
|
||||||
|
const filePath = req.url.replace(/^\/locales\//, "");
|
||||||
|
const absolutePath = path.resolve(
|
||||||
|
process.cwd(),
|
||||||
|
"locales",
|
||||||
|
filePath,
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const fileContents = readFileSync(
|
||||||
|
absolutePath,
|
||||||
|
"utf-8",
|
||||||
|
);
|
||||||
|
res.end(fileContents);
|
||||||
|
} catch (e) {
|
||||||
|
// If file not found or any other error, pass to the next middleware
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
test: {
|
test: {
|
||||||
// NOTE: this is a replacement location for karma tests.
|
// NOTE: this is a replacement location for karma tests.
|
||||||
// moving forward we should colocate tests with the
|
// moving forward we should colocate tests with the
|
||||||
// code they test.
|
// code they test.
|
||||||
include: ['test/**/*.test.{js,mjs,cjs}'],
|
include: ["test/**/*.test.{js,mjs,cjs}"],
|
||||||
environment: 'jsdom',
|
environment: "jsdom",
|
||||||
setupFiles: ['test/setup.js'],
|
setupFiles: ["test/setup.js"],
|
||||||
|
root: '.',
|
||||||
|
},
|
||||||
|
plugins: [vue(), serveLocalesPlugin()],
|
||||||
|
root: "./src",
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
"/src": path.resolve(process.cwd(), "src"),
|
||||||
|
'vue': path.resolve(__dirname, 'node_modules/vue/dist/vue.esm.js'),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
33
yarn.lock
33
yarn.lock
|
@ -1653,10 +1653,10 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
cross-spawn "^7.0.1"
|
cross-spawn "^7.0.1"
|
||||||
|
|
||||||
"@mapbox/node-pre-gyp@^1.0.5":
|
"@mapbox/node-pre-gyp@^1.0.10":
|
||||||
version "1.0.9"
|
version "1.0.11"
|
||||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz#09a8781a3a036151cdebbe8719d6f8b25d4058bc"
|
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa"
|
||||||
integrity sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==
|
integrity sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
detect-libc "^2.0.0"
|
detect-libc "^2.0.0"
|
||||||
https-proxy-agent "^5.0.0"
|
https-proxy-agent "^5.0.0"
|
||||||
|
@ -2982,6 +2982,11 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@vitejs/plugin-vue2@^2.2.0":
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue2/-/plugin-vue2-2.2.0.tgz#7453207197d6ac2b7023cedc7133b142c604c356"
|
||||||
|
integrity sha512-1km7zEuZ/9QRPvzXSjikbTYGQPG86Mq1baktpC4sXqsXlb02HQKfi+fl8qVS703JM7cgm24Ga9j+RwKmvFn90A==
|
||||||
|
|
||||||
"@vue/compiler-core@3.2.33":
|
"@vue/compiler-core@3.2.33":
|
||||||
version "3.2.33"
|
version "3.2.33"
|
||||||
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.33.tgz#e915d59cce85898f5c5cfebe4c09e539278c3d59"
|
resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.33.tgz#e915d59cce85898f5c5cfebe4c09e539278c3d59"
|
||||||
|
@ -10385,14 +10390,14 @@ levn@~0.3.0:
|
||||||
prelude-ls "~1.1.2"
|
prelude-ls "~1.1.2"
|
||||||
type-check "~0.3.2"
|
type-check "~0.3.2"
|
||||||
|
|
||||||
libxmljs2@^0.29.0:
|
libxmljs2@0.32.0, libxmljs2@^0.29.0:
|
||||||
version "0.29.0"
|
version "0.32.0"
|
||||||
resolved "https://registry.yarnpkg.com/libxmljs2/-/libxmljs2-0.29.0.tgz#4d44efc7998d9c0d938e174226cf625a8ebf630d"
|
resolved "https://registry.yarnpkg.com/libxmljs2/-/libxmljs2-0.32.0.tgz#408e35c54a5ad5e0366bc8299ba20ed35224d0d9"
|
||||||
integrity sha512-g9PvujoUGRHBp2R7Z49pKklMdAucayepGSJajfpzl+JlGRO1lHfWWH1KQcwqoylO524G9Mu9pO74ZaQ11fi0/w==
|
integrity sha512-DuvKfSQZeUzw0A4UWZXfcBpr3VqlcJY1b3aw99PxTiX3T5t1rEO4gSpobNrP9S74LIhyDKaAs/lphuErV+n+7w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@mapbox/node-pre-gyp" "^1.0.5"
|
"@mapbox/node-pre-gyp" "^1.0.10"
|
||||||
bindings "~1.5.0"
|
bindings "~1.5.0"
|
||||||
nan "~2.15.0"
|
nan "~2.17.0"
|
||||||
|
|
||||||
lie@~3.3.0:
|
lie@~3.3.0:
|
||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
|
@ -11386,10 +11391,10 @@ nan@^2.12.1, nan@^2.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
||||||
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
||||||
|
|
||||||
nan@~2.15.0:
|
nan@~2.17.0:
|
||||||
version "2.15.0"
|
version "2.17.0"
|
||||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
|
resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
|
||||||
integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==
|
integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==
|
||||||
|
|
||||||
nanoid@^2.1.0:
|
nanoid@^2.1.0:
|
||||||
version "2.1.4"
|
version "2.1.4"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue