From 5df3f721a2ae8efe1e547fce7073e079d4b8e03b Mon Sep 17 00:00:00 2001
From: nerdCopter <56646290+nerdCopter@users.noreply.github.com>
Date: Tue, 12 Jul 2022 11:34:04 -0500
Subject: [PATCH 01/11] VTX tab (#457)
* VTX tab - WIP - very failing, but somewhere worth saving
* VTX tab - WIP - very failing still
* VTX tab - WIP - very failing still; waitng for data(no error)
* VTX tab - WIP - very failing still; no clue--GUI.interval_add('vtx_pull',//self._DEVICE_STATUS_UPDATE_INTERVAL_NAME,
* VTX tab - WIP - very failing still; no clue--ports.js:110
* VTX tab- reads MSP data, but waiting loop; bunch of console.logs
* VTX tab- reads MSP data, but waiting loop; bunch of console.logs
* VTX tab loads; fails displayInit; needs purge VTX em/messages; need setup vtx.js more like other .js
* VTX tab - vtx table farther. uncaught vtx_band:vtx.js:381. Uncaught VTX_DEVICE_STATUS:vtx.js:46
* VTX tab loads; woot working father than before. need local/en/messages purge. need html purge/rewrite. need vtx.js save. need vtx.js cleanup.
* VTX tab loads; woot working father than before. need local/en/messages purge. need html purge/rewrite. need vtx.js save. need vtx.js cleanup. need tab-cleanup working.
* VTX tab - some locale/en fixes. still need all the prior stuff
* VTX tab - more html cleanup. still need all the prior stuff
* VTX tab - more html cleanup. still need all the prior stuff
* VTX tab - more html/locale/en cleanup. still need all the prior stuff
* VTX tab - more html/locale/en cleanup. still need all the prior stuff
* VTX tab - cleanup/table. still need all the prior stuff and more
* VTX tab - fixed vtx.cleanup. purged vtxtables codes. still needs stuff. needs SAVE and further cleanup of used/unused code.
* VTX tab - cleaned some unused code. still needs stuff. needs SAVE/REFRESH and further cleanup of used/unused code.
* VTX tab - added set MSP, but save click does nothing.
* VTX tab - manual freq toggle
* VTX tab - better channel populate; max band 5
* VTX tab - semicolons; vtx_low_power_disarm not supported in MSP :(
* VTX tab - locale/en power-on-switch
* VTX tab - fixes and debugs and still failing
* VTX tab - should save, does not save proper :((
* VTX tab - more debugs
* VTX tab - fix var and debugs
* VTX tab - fix table ch7
* VTX tab - OMG the fugging old band/channel-->freq encode worksyarn gulp clean ; yarn gulp debug Now need major cleaning and UI simplification
* VTX tab - this work better, moved //initDisplay close bracket }, then set input[id="vtx_frequency_channel"]
* VTX tab - clickable table (no effect yet); code cleanup; remove animation
* VTX tab - fix onload freq tofflee; cleanup css
* VTX tab - an easy vtx table
* VTX tab - locales/en; css cleanup
* VTX tab - css cleanup
* vtx tab - pitmode hide/show logic and required css shanges; comment-out other unsused code
* vtx tab - add BeeSign type
* VTX tab - pitmode pause/refresh again
* VTX tab - comment-out console.log ; cleanup
* VTX tab - fix some Codacy complaints
* VTX tab - fix some Codacy complaints
* VTX tab - fix some Codacy complaints
* VTX tab - prettier vtx tablez
* VTX tab - generically simplify HAM License verbiage
* VTX tab - caps VTX
* VTX tab - add colored freq (out-of-band and modulates o-o-b); fix Codact Complaints; fix verical transform text blocking freq buttons:hover
* VTX tab - fix Codact Complaint
* VTX tab - move tab under OSD
---
locales/en/messages.json | 193 ++++++++++
src/css/main.css | 10 +-
src/css/tabs/vtx.css | 195 ++++++++++
src/js/fc.js | 10 +
src/js/gui.js | 1 +
src/js/main.js | 5 +-
src/js/msp/MSPHelper.js | 33 +-
src/js/tabs/ports.js | 11 +-
src/js/tabs/vtx.js | 359 ++++++++++++++++++
.../VtxDeviceStatus/Rtc6705DeviceStatus.js | 19 +
.../VtxDeviceStatus/SmartAudioDeviceStatus.js | 49 +++
.../VtxDeviceStatus/TrampDeviceStatus.js | 19 +
.../utils/VtxDeviceStatus/VtxDeviceStatus.js | 79 ++++
.../VtxDeviceStatus/VtxDeviceStatusFactory.js | 40 ++
src/main.html | 10 +
src/tabs/vtx.html | 221 +++++++++++
16 files changed, 1250 insertions(+), 4 deletions(-)
create mode 100644 src/css/tabs/vtx.css
create mode 100644 src/js/tabs/vtx.js
create mode 100644 src/js/utils/VtxDeviceStatus/Rtc6705DeviceStatus.js
create mode 100644 src/js/utils/VtxDeviceStatus/SmartAudioDeviceStatus.js
create mode 100644 src/js/utils/VtxDeviceStatus/TrampDeviceStatus.js
create mode 100644 src/js/utils/VtxDeviceStatus/VtxDeviceStatus.js
create mode 100644 src/js/utils/VtxDeviceStatus/VtxDeviceStatusFactory.js
create mode 100644 src/tabs/vtx.html
diff --git a/locales/en/messages.json b/locales/en/messages.json
index ce028db46..ca77d3c3a 100644
--- a/locales/en/messages.json
+++ b/locales/en/messages.json
@@ -5535,5 +5535,198 @@
},
"pidTuningIMUFFilterSettings": {
"message": "Profile independent IMU-F Filter Settings"
+ },
+ "tabVtx": {
+ "message": "Analog VTX"
+ },
+ "COMMENT": {"message": "most these need purge"},
+ "vtxHelp": {
+ "message": "Here you can configure the values for your Video Transmitter if the flight controller and the VTX support it. Set the values manually, or click the chart frequencies then save.",
+ "description": "Introduction message in the VTX tab"
+ },
+ "vtxMessageNotSupported": {
+ "message": "Attention: Your VTX is not configured or not supported. Configuration will only be possible if the VTx is properly soldered to the flight-controller and setup correctly with a protocol like Tramp or SmartAudio in the $t(tabPorts.message) tab.",
+ "description": "Message to show when the VTX is not supported in the VTX tab"
+ },
+ "vtxMessageFactoryBandsNotSupported": {
+ "message": "Attention: The selected VTX type does not support the 'factory' setting for bands, but some of your bands have this setting. Click '$t(vtxButtonSave.message)' to fix this.",
+ "description": "Message to show when the configured VTX type does not support factory bands, but one or more of the configured bands are of this type"
+ },
+ "vtxMessageRequiresHAM": {
+ "message": "Attention: Pilots operating an analog VTX must comply with the governmental regulations. An amateur radio license may be required."
+ },
+ "vtxMessageHardwareModes": {
+ "message": "Other things to consider: Locked, Unlocked, Race-Mode, Free-Mode should all be set by the VTX hardware. EmuFlight does not have access to this."
+ },
+ "vtxMessageAnalogFunny": {
+ "message": "Set up however you want, you're not gonna see anything but lines and static anyways"
+ },
+ "vtxMessageNonMSP": {
+ "message": "CLI-only settings include 'vtx_low_power_disarm', 'vtx_pit_mode_freq', 'vtx_halfduplex' and VTX-Power-on-a-Switch. Configure them as needed in CLI."
+ },
+ "vtxFrequencyChannel": {
+ "message": "Frequency Mode",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxFrequencyChannelHelp": {
+ "message": "If you enable this, the Configurator will let you select a frequency in place of the habitual band/channel. For this to work your VTX must support this feature.",
+ "description": "Help text for the frequency or channel select field of the VTX tab"
+ },
+ "vtxSelectedMode": {
+ "message": "Selected Mode",
+ "description": "Title for the actual mode header of the VTX"
+ },
+ "vtxActualState": {
+ "message": "Current Values",
+ "description": "Title for the actual values header of the VTX"
+ },
+ "vtxType": {
+ "message": "VTX Type",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxType_0": {
+ "message": "Unsupported",
+ "description": "Text for one of the types of the VTX type in VTX tab"
+ },
+ "vtxType_1": {
+ "message": "RTC607",
+ "description": "Text for one of the types of the VTX type in VTX tab"
+ },
+ "vtxType_3": {
+ "message": "SmartAudio",
+ "description": "Text for one of the types of the VTX type in VTX tab"
+ },
+ "vtxType_4": {
+ "message": "Tramp",
+ "description": "Text for one of the types of the VTX type in VTX tab"
+ },
+ "vtxType_5": {
+ "message": "BeeSign",
+ "description": "Text for one of the types of the VTX type in VTX tab"
+ },
+ "vtxType_255": {
+ "message": "Unknown",
+ "description": "Text for one of the types of the VTX type in VTX tab"
+ },
+ "vtxBand": {
+ "message": "Band",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxBandHelp": {
+ "message": "Here, set the band for your VTX",
+ "description": "Help text for the band field of the VTX tab"
+ },
+ "vtxBand_0": {
+ "message": "User",
+ "description": "Text of one of the options for the band field of the VTX tab"
+ },
+ "vtxBand_X": {
+ "message": "Band {{bandName}}",
+ "description": "Text of one of the options for the band field of the VTX tab"
+ },
+ "vtxChannel_0": {
+ "message": "None",
+ "description": "Text of one of the options for the channel field of the VTX tab"
+ },
+ "vtxChannel_X": {
+ "message": "Channel {{channelName}}",
+ "description": "Text of one of the options for the channel field of the VTX tab"
+ },
+ "vtxPower_0": {
+ "message": "None",
+ "description": "Text of one of the options for the power field of the VTX tab"
+ },
+ "vtxPower_X": {
+ "message": "Level {{powerLevel}}",
+ "description": "Text of one of the options for the power field of the VTX tab"
+ },
+ "vtxChannel": {
+ "message": "Channel",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxChannelHelp": {
+ "message": "Here, set the channel for your VTX",
+ "description": "Help text for the channel field of the VTX tab"
+ },
+ "vtxFrequency": {
+ "message": "Frequency",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxFrequencyHelp": {
+ "message": "Here, set the frequency for your VTX if it is supported",
+ "description": "Help text for the frequency field of the VTX tab"
+ },
+ "vtxDeviceReady": {
+ "message": "Device ready",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxPower": {
+ "message": "Power",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxPowerHelp": {
+ "message": "Here, set the operational power level for the VTX. It can be modified if the $t(vtxPitMode.message) or the $t(vtxLowPowerDisarm.message) is enabled",
+ "description": "Help text for the power field of the VTX tab"
+ },
+ "vtxPitMode": {
+ "message": "Pit Mode",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxPitModeHelp": {
+ "message": "When enabled, the VTX enters in a very low power mode to let the quad be on at the bench without disturbing other pilots. Usually the range of this mode is less than 5m.
NOTE: Some protocols, like SmartAudio, can't enable Pit Mode via software after power-up.",
+ "description": "Help text for the pit mode field of the VTX tab"
+ },
+ "vtxPitModeFrequency": {
+ "message": "Pit Mode frequency",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxPitModeFrequencyHelp": {
+ "message": "Frequency at which the Pit Mode changes when enabled.",
+ "description": "Help text for the pit mode field of the VTX tab"
+ },
+ "vtxLowPowerDisarm": {
+ "message": "Low Power Disarm",
+ "description": "Text of one of the fields of the VTX tab"
+ },
+ "vtxLowPowerDisarmHelp": {
+ "message": "When enabled, the VTX uses the lowest available power when disarmed (except if a failsafe has occurred).",
+ "description": "Help text for the low power disarm field of the VTX tab"
+ },
+ "vtxLowPowerDisarmOption_0": {
+ "message": "Off",
+ "description": "One of the options for the Low Power Disarm mode of the VTX"
+ },
+ "vtxLowPowerDisarmOption_1": {
+ "message": "On",
+ "description": "One of the options for the Low Power Disarm mode of the VTX"
+ },
+ "vtxLowPowerDisarmOption_2": {
+ "message": "On until first arm",
+ "description": "One of the options for the Low Power Disarm mode of the VTX"
+ },
+ "vtxButtonSave": {
+ "message": "Save",
+ "description": "Save button in the VTX tab"
+ },
+ "vtxButtonSaved": {
+ "message": "Saved",
+ "description": "Saved action button in the VTX tab"
+ },
+ "vtxButtonRefresh": {
+ "message": "Refresh",
+ "description": "Refresh button in the VTX tab"
+ },
+ "vtxSmartAudioUnlocked": {
+ "message": "{{version}} unlocked",
+ "description": "Indicates if SA device is unlocked"
+ },
+ "vtxTableNameCol": {
+ "message": "Name"
+ },
+ "vtxTableChannelRow": {
+ "message": "Channels"
+ },
+ "vtxTableBandCol": {
+ "message": "Bands"
}
}
diff --git a/src/css/main.css b/src/css/main.css
index c646483b6..d7d5f2bcd 100644
--- a/src/css/main.css
+++ b/src/css/main.css
@@ -830,6 +830,14 @@ li.active .ic_data {
background-image: url(../images/icons/cf_icon_data_white.svg);
}
+.ic_vtx {
+ background-image: url(../images/icons/cf_icon_vtx_grey.svg);
+}
+
+.ic_vtx:hover {
+ background-image: url(../images/icons/cf_icon_vtx_white.svg);
+}
+
.ic_cli {
background-image: url(../images/icons/cf_icon_cli_grey.svg);
}
@@ -1710,7 +1718,7 @@ dialog {
/* fixing padding for all Tabs*/
.tab-setup, .tab-landing, .tab-adjustments, .tab-auxiliary, .tab-cli, .tab-configuration, .tab-failsafe, .tab-firmware_flasher,
- .tab-gps, .tab-help, .tab-led-strip, .tab-logging, .tab-modes, .tab-motors, .tab-pid_tuning, .tab-ports, .tab-receiver,
+.tab-gps, .tab-help, .tab-led-strip, .tab-logging, .tab-modes, .tab-motors, .tab-pid_tuning, .tab-ports, .tab-receiver, .tab-vtx,
.tab-sensors, .tab-servos, .tab-osd, .tab-power {
height: 100%;
position: relative;
diff --git a/src/css/tabs/vtx.css b/src/css/tabs/vtx.css
new file mode 100644
index 000000000..f393ed65e
--- /dev/null
+++ b/src/css/tabs/vtx.css
@@ -0,0 +1,195 @@
+.tab-vtx {
+ height: 100%;
+}
+
+.tab-vtx .cf_table {
+ -webkit-border-horizontal-spacing: 1px;
+}
+
+.tab-vtx .require-support {
+ display: none;
+}
+
+.tab-vtx.supported .require-support {
+ display: block;
+}
+
+.tab-vtx .require-upgrade {
+ display: block;
+}
+
+.tab-vtx.supported .require-upgrade {
+ display: none;
+}
+
+.tab-vtx .columnsWrapper {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ justify-content: space-between;
+}
+
+.tab-vtx .columnsWrapper .leftColumn {
+ width: calc(30%);
+ min-width: 266px; /* anything smaller will word-wrap mode-descriptions */
+}
+
+.tab-vtx .columnsWrapper .rightColumn {
+ flex-shrink: 0;
+ flex-grow: 0;
+ flex-basis: 60%;
+ width: calc(60%);
+ min-width: 540px; /* anything smaller will word-wrap Band Names */
+}
+
+.tab-vtx .leftWrapper {
+ float: left;
+ width: calc(60% - 20px);
+}
+
+.tab-vtx .rightWrapper {
+ float: left;
+ width: calc(60%);
+ max-width: 300px;
+ margin: 0 0 10px 20px;
+}
+
+.tab-vtx input, .tab-vtx select {
+ border: 1px solid var(--subtleAccent);
+ max-width: 100px;
+ background: var(--boxBackground);
+ color: var(--defaultText);
+}
+
+.tab-vtx .number input {
+ width: 55px;
+ padding-left: 3px;
+ height: 20px;
+ line-height: 20px;
+ text-align: left;
+ margin-right: 11px;
+ font-size: 12px;
+ font-weight: normal;
+}
+
+.tab-vtx .gui_box span {
+ font-style: normal;
+ line-height: 19px;
+ color: var(--mutedtext);
+ font-size: 11px;
+}
+
+.tab-vtx .spacer_box .field {
+ margin-bottom: 5px;
+ clear: left;
+ /* padding-bottom: 5px; */ /* because swapped to top borders */
+ padding-top: 5px;
+ width: 100%;
+ float: left;
+}
+
+/* because swapped to top borders */
+.tab-vtx .helpicon {
+ margin-top: 2px;
+}
+
+/* swap this for top borders */
+/*
+.tab-vtx .spacer_box .field:not(:last-child) {
+ border-bottom: 1px solid var(--subtleAccent);
+}
+*/
+
+.tab-vtx .spacer_box .field:not(:first-child) {
+ border-top: 1px solid var(--subtleAccent);
+}
+
+.tab-vtx .select_mode .field > span {
+ margin-right: 10px;
+ display: inline-block;
+ min-width: 100px;
+}
+
+.tab-vtx input.one_digit_input {
+ width: 28px;
+}
+
+.tab-vtx input.frequency_input {
+ width: 48px;
+}
+
+/* not great but good enough - actually overridden by show/hide */
+.tab-vtx input.frequency_input:disabled {
+ color: inherit;
+ background-color: inherit;
+}
+
+.tab-vtx .field_powerlevel_value input, .tab-vtx .field_powerlevel_label input {
+ width: 53px;
+}
+
+.tab-vtx .field_band_name input {
+ width: 71px;
+}
+
+.tab-vtx .field_band_letter input {
+ width: 13px;
+}
+
+.tab-vtx table.outer div.band {
+ width: auto;
+ vertical-align: middle;
+ transform: rotate(-90deg);
+ -webkit-transform: rotate(-90deg); /* Safari/Chrome */
+ -moz-transform: rotate(-90deg); /* Firefox */
+ -o-transform: rotate(-90deg); /* Opera */
+ -ms-transform: rotate(-90deg); /* IE 9 */
+ white-space: nowrap;
+}
+
+.tab-vtx table.outer {
+ border-style: none !important;
+ border-collapse: collapse;
+ width: 100%;
+ text-align: center;
+ padding: 5px;
+}
+
+.tab-vtx table.outer td {
+ padding: 10px 15px 1px 5px; /* top right bottom left */
+}
+
+.tab-vtx table.inner {
+ border-width: 1px 1px 1px 1px !important;
+ border-style: solid;
+ border-collapse: collapse;
+ width: 100%;
+}
+
+.tab-vtx table.inner td { /* tr may work, but don't do th { */
+ border-width: 1px 1px 1px 1px !important;
+ border-style: solid !important;
+ border-collapse: collapse;
+ padding: 5px;
+}
+
+.tab-vtx .freq {
+ background: inherit;
+ color: inherit;
+ padding: 3px;
+}
+
+.tab-vtx .freq:hover {
+ background: #00a3e0;
+ color: white;
+ font-weight: bold;
+ padding: 3px;
+}
+
+.tab-vtx .freq.us_moob:hover {
+ color: orange;
+}
+
+.tab-vtx .freq.us_oob:hover {
+ color: red;
+}
diff --git a/src/js/fc.js b/src/js/fc.js
index eb3e711c9..bfcde2ceb 100644
--- a/src/js/fc.js
+++ b/src/js/fc.js
@@ -61,6 +61,7 @@ var KALMAN_FILTER_CONFIG;
var ADVANCED_TUNING;
var SENSOR_CONFIG;
var COPY_PROFILE;
+var VTX_CONFIG;
var DEFAULT;
var FC = {
@@ -521,6 +522,15 @@ var FC = {
RXFAIL_CONFIG = [];
+ VTX_CONFIG = {
+ vtx_type: 0,
+ vtx_band: 0,
+ vtx_channel: 1,
+ vtx_power: 0,
+ vtx_pit_mode: 0,
+ vtx_frequency: 0,
+ };
+
DEFAULT = {
gyro_lowpass_hz: 100,
gyro_lowpass_dyn_min_hz: 150,
diff --git a/src/js/gui.js b/src/js/gui.js
index 35fb9b0d9..1c750c842 100644
--- a/src/js/gui.js
+++ b/src/js/gui.js
@@ -43,6 +43,7 @@ var GUI_control = function () {
'receiver',
'sensors',
'servos',
+ 'vtx'
];
this.defaultAllowedOSDTabsWhenConnected = [
'setup_osd',
diff --git a/src/js/main.js b/src/js/main.js
index d42b69615..db7b0b8ae 100644
--- a/src/js/main.js
+++ b/src/js/main.js
@@ -348,6 +348,9 @@ function startProcess() {
case 'onboard_logging':
TABS.onboard_logging.initialize(content_ready);
break;
+ case 'vtx':
+ TABS.vtx.initialize(content_ready);
+ break;
case 'cli':
TABS.cli.initialize(content_ready, GUI.nwGui);
break;
@@ -716,7 +719,7 @@ function updateTabList(features) {
$('#tabs ul.mode-connected li.tab_power').hide();
}
- if (semver.gte(CONFIG.apiVersion, "1.42.0")) {
+ if (semver.gte(CONFIG.apiVersion, "1.40.0")) {
$('#tabs ul.mode-connected li.tab_vtx').show();
} else {
$('#tabs ul.mode-connected li.tab_vtx').hide();
diff --git a/src/js/msp/MSPHelper.js b/src/js/msp/MSPHelper.js
index 8ad7bc9aa..d89d21bbc 100644
--- a/src/js/msp/MSPHelper.js
+++ b/src/js/msp/MSPHelper.js
@@ -1528,9 +1528,21 @@ MspHelper.prototype.process_data = function(dataHandler) {
break;
case MSPCodes.MSP_VTX_CONFIG:
+ console.log('MSPCodes.MSP_VTX_CONFIG');
+ if (semver.gte(CONFIG.apiVersion, "1.40.0")) { //is this gte necessary?
+ console.log('VTX_config read MSP > 1.40.0');
+ VTX_CONFIG.vtx_type = data.readU8();
+ VTX_CONFIG.vtx_band = data.readU8();
+ VTX_CONFIG.vtx_channel = data.readU8();
+ VTX_CONFIG.vtx_power = data.readU8();
+ VTX_CONFIG.vtx_pit_mode = data.readU8() !== 0;
+ VTX_CONFIG.vtx_frequency = data.readU16();
+ }
+ //console.log('exit MSPCodes.MSP_VTX_CONFIG');
break;
- case MSPCodes.MSP_SET_VTX_CONFIG:
+ case MSPCodes.MSP_SET_VTX_CONFIG: //will never set in process_data
+ console.log("VTX config set");
break;
case MSPCodes.MSP_SET_NAME:
@@ -2226,6 +2238,25 @@ MspHelper.prototype.crunch = function(code) {
.push8(SENSOR_CONFIG.mag_hardware);
break;
+ case MSPCodes.MSP_SET_VTX_CONFIG:
+ console.log("MSPCodes.MSP_SET_VTX_CONFIG");
+ if (semver.gte(CONFIG.apiVersion, "1.40.0")) { //is this gte necessary?
+ //console.log("%c MSP push: type:"+VTX_CONFIG.vtx_type
+ // +' band:'+VTX_CONFIG.vtx_band
+ // +' chan:'+VTX_CONFIG.vtx_channel
+ // +' pwr:'+VTX_CONFIG.vtx_power
+ // +' pit:'+VTX_CONFIG.vtx_pit_mode
+ // +' freq:'+VTX_CONFIG.vtx_frequency, "color: magenta");
+
+ // two options: encoded BAND/CHANNEL into freq variable -OR- actual frequency
+ // see firmware msp.c:MSP_SET_VTX_CONFIG (line ~1991)
+ // cannot send un-encoded band/channel
+ buffer.push16(VTX_CONFIG.vtx_frequency)
+ .push8(VTX_CONFIG.vtx_power)
+ .push8(VTX_CONFIG.vtx_pit_mode ? 1 : 0);
+ }
+ break;
+
case MSPCodes.MSP_SET_NAME:
var MSP_BUFFER_SIZE = 64;
for (var i = 0; i 0).change(frequencyOrBandChannel); // trigger on toggles
+ $('input[id="vtx_frequency_channel"]').prop('checked',frequencyOrBandChannel); //current status on load
+
+ //console.log('exit initDisplay()');
+}; // initDisplay
+
+ function populateBandSelect() {
+ //console.log('enter populateBandSelect()');
+ const selectBand = $(".field #vtx_band");
+ //selectBand.append(new Option(i18n.getMessage('vtxBand_0'), 0)); //user
+ for (let i = 1; i <= TABS.vtx.MAX_BAND_VALUES; i++) {
+ selectBand.append(new Option(i18n.getMessage('vtxBand_X', {
+ bandName: i
+ }), i));
+ }
+ //console.log('exit populateBandSelect()');
+ };
+
+ function populateChannelSelect() {
+ //console.log('enter populateChannelSelect()');
+ const selectChannel = $(".field #vtx_channel");
+ // const selectedBand = $("#vtx_band").val(); //makes no sense for non-vtxTables
+ selectChannel.empty();
+ //selectChannel.append(new Option(i18n.getMessage('vtxChannel_0'), 0)); //in EmuF, 0 is not possible
+ for (let i = 1; i <= TABS.vtx.MAX_BAND_CHANNELS_VALUES; i++) {
+ selectChannel.append(new Option(i18n.getMessage('vtxChannel_X', {
+ channelName: i
+ }), i));
+ }
+ //console.log('exit populateChannelSelect()');
+ };
+
+ function populatePowerSelect() {
+ //console.log('enter populatePowerSelect()');
+ const selectPower = $(".field #vtx_power");
+ const powerMaxMinValues = getPowerValues(VTX_CONFIG.vtx_type);
+ for (let i = powerMaxMinValues.min; i <= powerMaxMinValues.max; i++) {
+ if (i === 0) {
+ selectPower.append(new Option(i18n.getMessage('vtxPower_0'), 0));
+ } else {
+ selectPower.append(new Option(i18n.getMessage('vtxPower_X', {
+ powerLevel: i
+ }), i));
+ }
+ }
+ //console.log('exit populatePowerSelect()');
+ };
+
+ // Returns the power values min and max depending on the VTX Type
+ function getPowerValues(vtxType) {
+ //console.log('enter getPowerValues()');
+ let powerMinMax = {};
+ switch (vtxType) {
+ case VtxDeviceTypes.VTXDEV_UNSUPPORTED:
+ powerMinMax = {};
+ break;
+ case VtxDeviceTypes.VTXDEV_RTC6705:
+ powerMinMax = {
+ min: 1,
+ max: 3
+ };
+ break;
+ case VtxDeviceTypes.VTXDEV_SMARTAUDIO:
+ powerMinMax = {
+ min: 1,
+ max: 4
+ };
+ break;
+ case VtxDeviceTypes.VTXDEV_TRAMP:
+ powerMinMax = {
+ min: 1,
+ max: 5
+ };
+ break;
+ case VtxDeviceTypes.VTXDEV_UNKNOWN:
+ default:
+ powerMinMax = {
+ min: 0,
+ max: 7
+ };
+ }
+ //console.log('exit getPowerValues()');
+ return powerMinMax;
+ };
+
+ // Save all the values to MSP
+ function save_vtx() {
+ //console.log('enter save_vtx()');
+ self.updating = true;
+ dump_html_to_msp();
+
+ //console.log('save_vtx(): type:'+VTX_CONFIG.vtx_type
+ // +' band:'+VTX_CONFIG.vtx_band
+ // +' chan:'+VTX_CONFIG.vtx_channel
+ // +' pwr:'+VTX_CONFIG.vtx_power
+ // +' pit:'+VTX_CONFIG.vtx_pit_mode
+ // +' freq:'+VTX_CONFIG.vtx_frequency);
+ // Start MSP saving
+ save_vtx_config();
+
+ function save_vtx_config() {
+ //console.log('enter save_vtx_config()');
+ MSP.send_message(MSPCodes.MSP_SET_VTX_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_VTX_CONFIG), false, save_to_eeprom);
+ //console.log('exit save_vtx_config()');
+ };
+
+ function save_to_eeprom() {
+ //console.log('enter save_to_eeprom()');
+ MSP.send_message(MSPCodes.MSP_EEPROM_WRITE, false, false, save_completed); //required to save
+ //console.log('exit save_to_eeprom()');
+ };
+
+ function save_completed() {
+ //console.log('enter save_completed()');
+ GUI.log(i18n.getMessage('configurationEepromSaved'));
+ const oldText = $("#save_button").text();
+ $("#save_button").html(i18n.getMessage('vtxButtonSaved'));
+
+ let saveTimeout = setTimeout(function() {
+ $("#save_button").html(oldText);
+ clearTimeout(saveTimeout);
+ }, 2000);
+
+ TABS.vtx.initialize();
+
+ // if pitmode, then wait and refresh again (is 3000ms enough?)
+ if (VTX_CONFIG.vtx_pit_mode) {
+ //console.log('pitmode true, pause and refresh again due to slow VTX setting');
+ let refreshTimeout = setTimeout(function() {
+ TABS.vtx.initialize();
+ clearTimeout(refreshTimeout);
+ }, 3000);
+ }
+
+ //console.log('exit save_completed()');
+ };
+ //console.log('exit save_vtx()');
+ }
+}; //TABS.vtx.initialize
+
+//modified for EmuF
+function dump_html_to_msp() {
+ //console.log('enter dump_html_to_msp()');
+ // General config
+ const frequencyEnabled = $('input[id="vtx_frequency_channel"]').prop('checked');
+ //console.log('%c manual freq toggle is: '+frequencyEnabled, "color: magenta");
+ if (frequencyEnabled) { //user freq
+ VTX_CONFIG.vtx_frequency = parseInt( $("#vtx_frequency").val() );
+ VTX_CONFIG.vtx_band = 0; //user
+ VTX_CONFIG.vtx_channel = 1; //setting this doesn't really do anything, MSP will retain last saved channel
+ } else { //band/channel
+ VTX_CONFIG.vtx_band = parseInt( $("#vtx_band").val() );
+ VTX_CONFIG.vtx_channel = parseInt( $("#vtx_channel").val() );
+ if (semver.gte(CONFIG.apiVersion, "1.40.0")) { //redundant
+ if (VTX_CONFIG.vtx_band > 0 || VTX_CONFIG.vtx_channel > 0) {
+ VTX_CONFIG.vtx_frequency = (VTX_CONFIG.vtx_band - 1) * 8 + (VTX_CONFIG.vtx_channel - 1);
+ //console.log('%c special old ass encoded freq: '+VTX_CONFIG.vtx_frequency, "color: magenta");
+ }
+ } // else some other semver option that does not yet exist
+ }
+
+ VTX_CONFIG.vtx_power = parseInt($("#vtx_power").val());
+ VTX_CONFIG.vtx_pit_mode = $("#vtx_pit_mode").prop('checked');
+ // VTX_CONFIG.vtx_low_power_disarm = parseInt($("#vtx_low_power_disarm").val()); //no EmuF MSP
+
+ //console.log('dump_html_to_msp(): bnd'+VTX_CONFIG.vtx_band+'/ch'+VTX_CONFIG.vtx_channel+'/frq'+VTX_CONFIG.vtx_frequency+'/lvl'+VTX_CONFIG.vtx_power+'/pm'+VTX_CONFIG.vtx_pit_mode);
+ //console.log('exit dump_html_to_msp()');
+};
+
+TABS.vtx.cleanup = function(callback) {
+ //console.log('enter TABS.vtx.cleanup()');
+ // Add here things that need to be cleaned or closed before leaving the tab
+ if (callback) {
+ callback();
+ }
+ //console.log('exit TABS.vtx.cleanup()');
+};
+
+TABS.vtx.refresh = function(callback) {
+ var self = this;
+ GUI.tab_switch_cleanup(function() {
+ self.initialize();
+ if (callback) {
+ callback();
+ }
+ });
+};
diff --git a/src/js/utils/VtxDeviceStatus/Rtc6705DeviceStatus.js b/src/js/utils/VtxDeviceStatus/Rtc6705DeviceStatus.js
new file mode 100644
index 000000000..2ae2dd014
--- /dev/null
+++ b/src/js/utils/VtxDeviceStatus/Rtc6705DeviceStatus.js
@@ -0,0 +1,19 @@
+'use strict';
+
+class VtxDeviceStatusRtc6705 extends VtxDeviceStatus {
+ constructor(dataView)
+ {
+ super(dataView);
+
+ dataView.readU8(); // custom device status size
+
+ // Read other Tramp VTX device parameters here
+ }
+
+ static get staticDeviceStatusType()
+ {
+ return VtxDeviceTypes.VTXDEV_RTC6705;
+ }
+}
+
+vtxDeviceStatusFactory.registerVtxDeviceStatusClass(VtxDeviceStatusRtc6705);
diff --git a/src/js/utils/VtxDeviceStatus/SmartAudioDeviceStatus.js b/src/js/utils/VtxDeviceStatus/SmartAudioDeviceStatus.js
new file mode 100644
index 000000000..279bbde7c
--- /dev/null
+++ b/src/js/utils/VtxDeviceStatus/SmartAudioDeviceStatus.js
@@ -0,0 +1,49 @@
+'use strict';
+
+class VtxDeviceStatusSmartAudio extends VtxDeviceStatus {
+ constructor(dataView)
+ {
+ super(dataView);
+
+ dataView.readU8(); // custom device status size
+
+ this._version = dataView.readU8();
+ this._mode = dataView.readU8();
+ this._orfreq = dataView.readU16();
+ this._willBootIntoPitMode = Boolean(dataView.readU8());
+ }
+
+ get smartAudioVersion()
+ {
+ const sa = this._version * 100 + this._mode;
+ let result = "";
+
+ switch (this._version) {
+ case 1:
+ result = "1.0";
+ break;
+ case 2:
+ result = "2.0";
+ break;
+ case 3:
+ result = "2.1";
+ break;
+ default:
+ // unknown SA version
+ result = i18n.getMessage("vtxType_255");
+ }
+
+ if (16 == this._mode) {
+ result = i18n.getMessage("vtxSmartAudioUnlocked", {"version": result});
+ }
+
+ return result;
+ }
+
+ static get staticDeviceStatusType()
+ {
+ return VtxDeviceTypes.VTXDEV_SMARTAUDIO;
+ }
+}
+
+vtxDeviceStatusFactory.registerVtxDeviceStatusClass(VtxDeviceStatusSmartAudio);
diff --git a/src/js/utils/VtxDeviceStatus/TrampDeviceStatus.js b/src/js/utils/VtxDeviceStatus/TrampDeviceStatus.js
new file mode 100644
index 000000000..287eec9ca
--- /dev/null
+++ b/src/js/utils/VtxDeviceStatus/TrampDeviceStatus.js
@@ -0,0 +1,19 @@
+'use strict';
+
+class VtxDeviceStatusTramp extends VtxDeviceStatus {
+ constructor(dataView)
+ {
+ super(dataView);
+
+ dataView.readU8(); // custom device status size
+
+ // Read other Tramp VTX device parameters here
+ }
+
+ static get staticDeviceStatusType()
+ {
+ return VtxDeviceTypes.VTXDEV_TRAMP;
+ }
+}
+
+vtxDeviceStatusFactory.registerVtxDeviceStatusClass(VtxDeviceStatusTramp);
diff --git a/src/js/utils/VtxDeviceStatus/VtxDeviceStatus.js b/src/js/utils/VtxDeviceStatus/VtxDeviceStatus.js
new file mode 100644
index 000000000..015a29b15
--- /dev/null
+++ b/src/js/utils/VtxDeviceStatus/VtxDeviceStatus.js
@@ -0,0 +1,79 @@
+'use strict';
+
+const VtxDeviceTypes = {
+ VTXDEV_UNSUPPORTED: 0, // reserved for MSP
+ VTXDEV_RTC6705: 1,
+ // 2 reserved
+ VTXDEV_SMARTAUDIO: 3,
+ VTXDEV_TRAMP: 4,
+ VTXDEV_UNKNOWN: 0xFF,
+};
+
+class VtxDeviceStatus
+{
+ constructor(dataView)
+ {
+ this._deviceIsReady = dataView.readU8();
+ const bandAndChannelAvailable = Boolean(dataView.readU8());
+ this._band = dataView.readU8();
+ this._channel = dataView.readU8();
+
+ if (!bandAndChannelAvailable) {
+ this._band = undefined;
+ this._channel = undefined;
+ }
+
+ const powerIndexAvailable = Boolean(dataView.readU8());
+ this._powerIndex = dataView.readU8();
+
+ if (!powerIndexAvailable) {
+ this._powerIndex = undefined;
+ }
+
+ const frequencyAvailable = Boolean(dataView.readU8());
+ this._frequency = dataView.readU16();
+
+ if (!frequencyAvailable) {
+ this._frequency = undefined;
+ }
+
+ const vtxStatusAvailable = Boolean(dataView.readU8());
+ this._vtxStatus = dataView.readU32(); // pitmode and/or locked
+
+ if (!vtxStatusAvailable) {
+ this._vtxStatus = undefined;
+ }
+
+ this._readPowerLevels(dataView);
+ }
+
+ _readPowerLevels(dataView)
+ {
+ this._levels = [];
+ this._powers = [];
+ const powerLevelCount = dataView.readU8();
+
+ for (let i = 0; i < powerLevelCount; i++)
+ {
+ this._levels.push(dataView.readU16());
+ this._powers.push(dataView.readU16());
+ }
+ }
+
+ get deviceIsReady()
+ {
+ return this._deviceIsReady;
+ }
+
+ // overload this function in subclasses
+ static get staticDeviceStatusType()
+ {
+ return VtxDeviceTypes.VTXDEV_UNKNOWN;
+ }
+
+ get deviceStatusType()
+ {
+ // returns result of overloaded static function "staticDeviceStatusType"
+ return this.constructor.staticDeviceStatusType;
+ }
+}
diff --git a/src/js/utils/VtxDeviceStatus/VtxDeviceStatusFactory.js b/src/js/utils/VtxDeviceStatus/VtxDeviceStatusFactory.js
new file mode 100644
index 000000000..acad76b07
--- /dev/null
+++ b/src/js/utils/VtxDeviceStatus/VtxDeviceStatusFactory.js
@@ -0,0 +1,40 @@
+'use strict';
+
+const vtxDeviceStatusFactory = {
+ _vtxDeviceStatusClasses: [],
+
+ // call this to register a new vtx type like SmartAudio, Tramp or Rtc6705
+ registerVtxDeviceStatusClass: function(vtxDeviceStatusClass)
+ {
+ this._vtxDeviceStatusClasses.push(vtxDeviceStatusClass);
+ },
+
+ createVtxDeviceStatus: function(byteArray)
+ {
+ const dataView = new DataView(byteArray.buffer);
+
+ const vtxTypeIndex = dataView.readU8();
+ const vtxDeviceStatusClass = this._getDeviceStatusClass(vtxTypeIndex);
+
+ return new vtxDeviceStatusClass(dataView);
+ },
+
+ _readVtxType: function(dataView)
+ {
+ return dataView.readU8();
+ },
+
+ _getDeviceStatusClass: function(vtxTypeIndex)
+ {
+ let result = this._vtxDeviceStatusClasses.find(
+ (vtxClass) => {
+ return vtxClass.staticDeviceStatusType === vtxTypeIndex;
+ });
+
+ if (typeof result === 'undefined') {
+ result = VtxDeviceStatus;
+ }
+
+ return result;
+ },
+};
diff --git a/src/main.html b/src/main.html
index b1001140f..e60b96206 100644
--- a/src/main.html
+++ b/src/main.html
@@ -165,6 +165,15 @@
+
+
+
+
+
+
+
+
+
@@ -317,6 +326,7 @@
+
diff --git a/src/tabs/vtx.html b/src/tabs/vtx.html
new file mode 100644
index 000000000..723e7d5ae
--- /dev/null
+++ b/src/tabs/vtx.html
@@ -0,0 +1,221 @@
+