diff --git a/locales/en/messages.json b/locales/en/messages.json index fa4a6544..78a0768b 100644 --- a/locales/en/messages.json +++ b/locales/en/messages.json @@ -6,6 +6,14 @@ "message": "Betaflight Configurator", "description": "Title of the application window, usually not translated" }, + "yes": { + "message": "Yes", + "description": "General Yes message to be used across the application" + }, + "no": { + "message": "No", + "description": "General No message to be used across the application" + }, "error": { "message": "Error: {{errorMessage}}" }, @@ -280,6 +288,9 @@ "tabOsd": { "message": "OSD" }, + "tabVtx": { + "message": "Video Transmitter" + }, "tabPower": { "message": "Power & Battery" }, @@ -3840,12 +3851,6 @@ "osdSetupCameraConnected": { "message": "Camera Connected" }, - "osdSetupCameraConnectedValueYes": { - "message": "Yes" - }, - "osdSetupCameraConnectedValueNo": { - "message": "No" - }, "osdSetupResetText": { "message": "Reset OSD to default" @@ -4720,6 +4725,215 @@ "message": "Saved" }, + "vtxHelp": { + "message": "You can configure here the values for your Video Trasmitter (VTX). You can consult and configure the values of the transmission including the VTX Tables if the flight controller and the VTX support it", + "description": "Introduction message in the VTX tab" + }, + "vtxMessageNotSupported": { + "message": "Attention: Your VTX is not configured or not supported. So you can't modify the VTX values from here. This will only be possible if the flight controller is attached to the VTX using some protocol like Tramp or SmartAudio and is correctly configured in the $t(tabPorts.message) tab if needed.", + "description": "Message to show when the VTX is not supported in the VTX tab" + }, + "vtxMessageTableNotConfigured": { + "message": "Attention: You need to configure and save FIRST the VTX Table at the bottom before you can make use of the $t(vtxSelectedMode.message) fields.", + "description": "Message to show when the VTX is not supported in the VTX tab" + }, + "vtxFrequencyChannel": { + "message": "Enter frequency directly", + "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_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": "You can select here the band for your VTX", + "description": "Help text for the band field of the VTX tab" + }, + "vtxBand_0": { + "message": "None", + "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": "You can select here 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": "You can select here 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": "This is the power selected 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" + }, + "vtxTable": { + "message": "VTX Table", + "description": "Text of the header of the VTX Table element in the VTX tab" + }, + "vtxTablePowerLevels": { + "message": "Number of power levels", + "description": "Text of one of the fields of the VTX Table element in the VTX tab" + }, + "vtxTablePowerLevelsHelp": { + "message": "This defines the number of power levels supported by your VTX", + "description": "Help for the number of power levels field of the VTX Table element in the VTX tab" + }, + "vtxTablePowerLevelsTableHelp": { + "message": "This table represents the different values of power that can be used for the VTX. They are divided into two:
- $t(vtxTablePowerLevelsValue.message): each power level requires a value that is defined by the hardware manufacturer. Ask your manufacturer for the correct value or consult the Betaflight wiki of VTX Tables to grab some samples.
- $t(vtxTablePowerLevelsLabel.message): you can put here the label you want for each power level value. It can be numbers (25, 200, 600, 1.2), letters (OFF, MIN, MAX) or a mix of them.

You must configure only the power levels that are legal at your contry.", + "description": "Help for the table of power levels (value-label) that appears in the VTX tab" + }, + "vtxTablePowerLevelsValue": { + "message": "Value", + "description": "Text of one of the fields of the VTX Table element in the VTX tab" + }, + "vtxTablePowerLevelsLabel": { + "message": "Label", + "description": "Text of one of the fields of the VTX Table element in the VTX tab" + }, + "vtxTableBands": { + "message": "Number of bands", + "description": "Text of one of the fields of the VTX Table element in the VTX tab" + }, + "vtxTableChannels": { + "message": "Number of channels by band", + "description": "Text of one of the fields of the VTX Table element in the VTX tab" + }, + "vtxTableBandsChannelsHelp": { + "message": "This defines the number of bands and the number of channels by band that you that you want for your VTX.", + "description": "Help for the number of bands and channels field of the VTX Table element in the VTX tab" + }, + "vtxTableBandTitleName": { + "message": "Name", + "description": "Text of one of the titles of the VTX Table element in the VTX tab" + }, + "vtxTableBandTitleLetter": { + "message": "Letter", + "description": "Text of one of the titles of the VTX Table element in the VTX tab" + }, + "vtxTableBandTitleFactory": { + "message": "Factory", + "description": "Text of one of the titles of the VTX Table element in the VTX tab" + }, + "vtxTableBandsChannelsTableHelp": { + "message": "This table represents all the frequencies that can be used for your VTX. You can have several bands and for each band you must configure:
- $t(vtxTableBandTitleName.message): Name that you want to assign to this band, like BOSCAM_A, FATSHARK or RACEBAND.
- $t(vtxTableBandTitleLetter.message): Short letter that references the band.
- $t(vtxTableBandTitleFactory.message): This indicates if it is a factory band. If enabled Betaflight sends to the VTX a band and channel number. The VTX will then use its built-in frequency table and the frequencies configured here are only to show the value in the OSD and other places. If it is not enabled, then Betaflight will send to the VTX the real frequency configured here.
- Frequencies: Frequencies for this band.

Remember that not all frequencies are legal at your country. You must put a value of zero to each frequency index that you are not allowed to use to disable it.", + "description": "Help for the table of bands-channels that appears in the VTX tab" + }, + "vtxButtonSave": { + "message": "Save", + "description": "Save button in the VTX tab" + }, + "vtxButtonSaved": { + "message": "Saved", + "description": "Saved action button in the VTX tab" + }, + "mainHelpArmed": { "message": "Motor Arming" }, diff --git a/src/css/main.css b/src/css/main.css index 139faad4..445818f9 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -876,6 +876,15 @@ li.active .ic_transponder { background-image: url(../images/icons/icon_osd_white.svg); } +.ic_vtx { + background-image: url(../images/icons/cf_icon_vtx_grey.svg); + background-position-y: 4px; +} + +.ic_vtx:hover, li.active .ic_osd { + background-image: url(../images/icons/cf_icon_vtx_white.svg); +} + .ic_power { background-image: url(../images/icons/cf_icon_power_grey.svg); background-position-y: 9px; @@ -1481,9 +1490,12 @@ dialog { .cf_table td { border: 0px; - border-bottom: solid 1px var(--subtleAccent); padding-top: 2px; padding-bottom: 5px; +} + +.cf_table tr:not(:last-child) td { + border-bottom: solid 1px var(--subtleAccent); border-style: dotted; } diff --git a/src/css/tabs/vtx.css b/src/css/tabs/vtx.css new file mode 100644 index 00000000..2f688500 --- /dev/null +++ b/src/css/tabs/vtx.css @@ -0,0 +1,125 @@ +.tab-vtx { + height: 100%; +} + +.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 .leftWrapper { + float: left; + width:calc(60% - 20px) +} + +.tab-vtx .rightWrapper { + float: left; + width: calc(30% - 0px); + max-width: 300px; + margin: 0 0 10px 20px; +} + +.tab-vtx input , .tab-vtx select { + border: 1px solid var(--subtleAccent); + border-radius: 3px; + max-width: 100px; + +} + +.tab-vtx .number input { + width: 55px; + padding-left: 3px; + height: 20px; + line-height: 20px; + text-align: left; + border-radius: 3px; + margin-right: 11px; + font-size: 12px; + font-weight: normal; +} + +.tab-vtx .gui_box span { + font-style: normal; + font-family: 'open_sansregular', Arial; + line-height: 19px; + color: var(--mutedtext); + font-size: 11px; +} + +.tab-vtx .spacer_box .field { + margin-bottom: 5px; + clear: left; + padding-bottom: 5px; + width: 100%; + float: left; +} + +.tab-vtx .spacer_box .field:not(:last-child) { + border-bottom: 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; +} + +.tab-vtx .vtx_table_box { + min-width: 750px +} + +.tab-vtx .table_vtx_bands tr:first-child td, .tab-vtx .table_vtx_powerlevels tr:first-child td { + text-align: center; +} + + +.tab-vtx .table_vtx_bands td, .tab-vtx .table_vtx_powerlevels td { + padding: 0px 1px; + text-align: center; +} + +.tab-vtx .table_vtx_bands input, .tab-vtx .table_vtx_powerlevels input { + display: block; + margin: 0 auto; +} + +.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 .vtx_table_bands_table span table, .tab-vtx .vtx_table_powerlevels_table span table { + float: left; +} + +#tab-vtx-templates { + display: none; +} \ No newline at end of file diff --git a/src/js/fc.js b/src/js/fc.js index be3a3a64..c943956b 100644 --- a/src/js/fc.js +++ b/src/js/fc.js @@ -58,6 +58,9 @@ var FILTER_CONFIG; var ADVANCED_TUNING; var SENSOR_CONFIG; var COPY_PROFILE; +var VTX_CONFIG; +var VTXTABLE_BAND; +var VTXTABLE_POWERLEVEL; var DEFAULT; var FC = { @@ -483,6 +486,37 @@ var FC = { RXFAIL_CONFIG = []; + VTX_CONFIG = { + vtx_type: 0, + vtx_band: 0, + vtx_channel: 0, + vtx_power: 0, + vtx_pit_mode: false, + vtx_frequency: 0, + vtx_device_ready: false, + vtx_low_power_disarm: 0, + vtx_pit_mode_frequency: 0, + vtx_table_available: false, + vtx_table_bands: 0, + vtx_table_channels: 0, + vtx_table_powerlevels: 0, + vtx_table_clear: false, + }; + + VTXTABLE_BAND = { + vtxtable_band_number: 0, + vtxtable_band_name: '', + vtxtable_band_letter: '', + vtxtable_band_is_factory_band: false, + vtxtable_band_frequencies: [], + }; + + VTXTABLE_POWERLEVEL = { + vtxtable_powerlevel_number: 0, + vtxtable_powerlevel_value: 0, + vtxtable_powerlevel_label: 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 4de1126c..b4f9fd55 100644 --- a/src/js/gui.js +++ b/src/js/gui.js @@ -42,6 +42,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 3abe0bc4..e1dd7bd1 100644 --- a/src/js/main.js +++ b/src/js/main.js @@ -248,6 +248,9 @@ function startProcess() { case 'osd': TABS.osd.initialize(content_ready); break; + case 'vtx': + TABS.vtx.initialize(content_ready); + break; case 'power': TABS.power.initialize(content_ready); break; @@ -632,48 +635,33 @@ function isExpertModeEnabled() { } function updateTabList(features) { + + if (isExpertModeEnabled()) { + $('#tabs ul.mode-connected li.tab_failsafe').show(); + $('#tabs ul.mode-connected li.tab_adjustments').show(); + $('#tabs ul.mode-connected li.tab_servos').show(); + $('#tabs ul.mode-connected li.tab_sensors').show(); + $('#tabs ul.mode-connected li.tab_logging').show(); + } else { + $('#tabs ul.mode-connected li.tab_failsafe').hide(); + $('#tabs ul.mode-connected li.tab_adjustments').hide(); + $('#tabs ul.mode-connected li.tab_servos').hide(); + $('#tabs ul.mode-connected li.tab_sensors').hide(); + $('#tabs ul.mode-connected li.tab_logging').hide(); + } + if (features.isEnabled('GPS') && isExpertModeEnabled()) { $('#tabs ul.mode-connected li.tab_gps').show(); } else { $('#tabs ul.mode-connected li.tab_gps').hide(); } - if (isExpertModeEnabled()) { - $('#tabs ul.mode-connected li.tab_failsafe').show(); - } else { - $('#tabs ul.mode-connected li.tab_failsafe').hide(); - } - - if (isExpertModeEnabled()) { - $('#tabs ul.mode-connected li.tab_adjustments').show(); - } else { - $('#tabs ul.mode-connected li.tab_adjustments').hide(); - } - - if (isExpertModeEnabled()) { - $('#tabs ul.mode-connected li.tab_servos').show(); - } else { - $('#tabs ul.mode-connected li.tab_servos').hide(); - } - if (features.isEnabled('LED_STRIP')) { $('#tabs ul.mode-connected li.tab_led_strip').show(); } else { $('#tabs ul.mode-connected li.tab_led_strip').hide(); } - if (isExpertModeEnabled()) { - $('#tabs ul.mode-connected li.tab_sensors').show(); - } else { - $('#tabs ul.mode-connected li.tab_sensors').hide(); - } - - if (isExpertModeEnabled()) { - $('#tabs ul.mode-connected li.tab_logging').show(); - } else { - $('#tabs ul.mode-connected li.tab_logging').hide(); - } - if (features.isEnabled('TRANSPONDER')) { $('#tabs ul.mode-connected li.tab_transponder').show(); } else { @@ -691,6 +679,13 @@ function updateTabList(features) { } else { $('#tabs ul.mode-connected li.tab_power').hide(); } + + if (semver.gte(CONFIG.apiVersion, "1.42.0")) { + $('#tabs ul.mode-connected li.tab_vtx').show(); + } else { + $('#tabs ul.mode-connected li.tab_vtx').hide(); + } + } function zeroPad(value, width) { diff --git a/src/js/msp/MSPCodes.js b/src/js/msp/MSPCodes.js index 4152a171..eeadb375 100644 --- a/src/js/msp/MSPCodes.js +++ b/src/js/msp/MSPCodes.js @@ -112,6 +112,9 @@ var MSPCodes = { MSP_COMPASS_CONFIG: 133, MSP_GPS_RESCUE: 135, + MSP_VTXTABLE_BAND: 137, + MSP_VTXTABLE_POWERLEVEL: 138, + MSP_STATUS_EX: 150, MSP_UID: 160, @@ -148,6 +151,9 @@ var MSPCodes = { MSP_SET_COMPASS_CONFIG: 224, MSP_SET_GPS_RESCUE: 225, + MSP_SET_VTXTABLE_BAND: 227, + MSP_SET_VTXTABLE_POWERLEVEL: 228, + MSP_MODE_RANGES_EXTRA: 238, MSP_SET_ACC_TRIM: 239, MSP_ACC_TRIM: 240, diff --git a/src/js/msp/MSPHelper.js b/src/js/msp/MSPHelper.js index ad3bb8ce..1a93aa71 100644 --- a/src/js/msp/MSPHelper.js +++ b/src/js/msp/MSPHelper.js @@ -1300,9 +1300,78 @@ MspHelper.prototype.process_data = function(dataHandler) { TRANSPONDER.data.push(data.readU8()); } break; + case MSPCodes.MSP_SET_TRANSPONDER_CONFIG: console.log("Transponder config saved"); break; + + case MSPCodes.MSP_VTX_CONFIG: + + 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(); + VTX_CONFIG.vtx_device_ready = data.readU8() != 0; + VTX_CONFIG.vtx_low_power_disarm = data.readU8(); + + if (semver.gte(CONFIG.apiVersion, "1.42.0")) { + VTX_CONFIG.vtx_pit_mode_frequency = data.readU16(); + VTX_CONFIG.vtx_table_available = data.readU8() != 0; + VTX_CONFIG.vtx_table_bands = data.readU8(); + VTX_CONFIG.vtx_table_channels = data.readU8(); + VTX_CONFIG.vtx_table_powerlevels = data.readU8(); + VTX_CONFIG.vtx_table_clear = false; + } + break; + + case MSPCodes.MSP_SET_VTX_CONFIG: + console.log("VTX config sent"); + break; + + case MSPCodes.MSP_VTXTABLE_BAND: + + VTXTABLE_BAND.vtxtable_band_number = data.readU8(); + + let bandNameLength = data.readU8(); + VTXTABLE_BAND.vtxtable_band_name = ''; + for (let i = 0; i < bandNameLength; i++) { + VTXTABLE_BAND.vtxtable_band_name += String.fromCharCode(data.readU8()); + } + + VTXTABLE_BAND.vtxtable_band_letter = String.fromCharCode(data.readU8()); + VTXTABLE_BAND.vtxtable_band_is_factory_band = data.readU8() != 0; + + let bandFrequenciesLength = data.readU8(); + VTXTABLE_BAND.vtxtable_band_frequencies = []; + for (let i = 0; i < bandFrequenciesLength; i++) { + VTXTABLE_BAND.vtxtable_band_frequencies.push(data.readU16()); + } + + break; + + case MSPCodes.MSP_SET_VTXTABLE_BAND: + console.log("VTX band sent"); + break; + + case MSPCodes.MSP_VTXTABLE_POWERLEVEL: + + VTXTABLE_POWERLEVEL.vtxtable_powerlevel_number = data.readU8(); + VTXTABLE_POWERLEVEL.vtxtable_powerlevel_value = data.readU16(); + + let powerLabelLength = data.readU8(); + VTXTABLE_POWERLEVEL.vtxtable_powerlevel_label = ''; + for (let i = 0; i < powerLabelLength; i++) { + VTXTABLE_POWERLEVEL.vtxtable_powerlevel_label += String.fromCharCode(data.readU8()); + } + + break; + + case MSPCodes.MSP_SET_VTXTABLE_POWERLEVEL: + console.log("VTX powerlevel sent"); + break; + case MSPCodes.MSP_SET_MODE_RANGE: console.log('Mode range saved'); break; @@ -1358,10 +1427,6 @@ MspHelper.prototype.process_data = function(dataHandler) { case MSPCodes.MSP_OSD_CHAR_WRITE: console.log('OSD char uploaded'); break; - case MSPCodes.MSP_VTX_CONFIG: - break; - case MSPCodes.MSP_SET_VTX_CONFIG: - break; case MSPCodes.MSP_SET_NAME: console.log('Name set'); break; @@ -1919,6 +1984,58 @@ MspHelper.prototype.crunch = function(code) { } break; + + case MSPCodes.MSP_SET_VTX_CONFIG: + + buffer.push16(VTX_CONFIG.vtx_frequency) + .push8(VTX_CONFIG.vtx_power) + .push8(VTX_CONFIG.vtx_pit_mode ? 1 : 0) + .push8(VTX_CONFIG.vtx_low_power_disarm); + + if (semver.gte(CONFIG.apiVersion, "1.42.0")) { + buffer.push16(VTX_CONFIG.vtx_pit_mode_frequency) + .push8(VTX_CONFIG.vtx_band) + .push8(VTX_CONFIG.vtx_channel) + .push16(VTX_CONFIG.vtx_frequency) + .push8(VTX_CONFIG.vtx_table_bands) + .push8(VTX_CONFIG.vtx_table_channels) + .push8(VTX_CONFIG.vtx_table_powerlevels) + .push8(VTX_CONFIG.vtx_table_clear ? 1 : 0); + } + + break; + + case MSPCodes.MSP_SET_VTXTABLE_POWERLEVEL: + + buffer.push8(VTXTABLE_POWERLEVEL.vtxtable_powerlevel_number) + .push16(VTXTABLE_POWERLEVEL.vtxtable_powerlevel_value); + + buffer.push8(VTXTABLE_POWERLEVEL.vtxtable_powerlevel_label.length); + for (let i = 0; i < VTXTABLE_POWERLEVEL.vtxtable_powerlevel_label.length; i++) { + buffer.push8(VTXTABLE_POWERLEVEL.vtxtable_powerlevel_label.charCodeAt(i)); + } + + break; + + case MSPCodes.MSP_SET_VTXTABLE_BAND: + + buffer.push8(VTXTABLE_BAND.vtxtable_band_number); + + buffer.push8(VTXTABLE_BAND.vtxtable_band_name.length); + for (let i = 0; i < VTXTABLE_BAND.vtxtable_band_name.length; i++) { + buffer.push8(VTXTABLE_BAND.vtxtable_band_name.charCodeAt(i)); + } + + buffer.push8(VTXTABLE_BAND.vtxtable_band_letter.charCodeAt(0)) + .push8(VTXTABLE_BAND.vtxtable_band_is_factory_band ? 1 : 0); + + buffer.push8(VTXTABLE_BAND.vtxtable_band_frequencies.length); + for (let i = 0; i < VTXTABLE_BAND.vtxtable_band_frequencies.length; i++) { + buffer.push16(VTXTABLE_BAND.vtxtable_band_frequencies[i]); + } + + break; + default: return false; } diff --git a/src/js/tabs/setup_osd.js b/src/js/tabs/setup_osd.js index 632b7f94..799b199f 100644 --- a/src/js/tabs/setup_osd.js +++ b/src/js/tabs/setup_osd.js @@ -55,7 +55,7 @@ TABS.setup_osd.initialize = function (callback) { element.text(osdVideoMode); element = $('.camera-connected'); - element.text(OSD_VIDEO_STATE.camera_connected ? i18n.getMessage('osdSetupCameraConnectedValueYes') : i18n.getMessage('osdSetupCameraConnectedValueNo')); + element.text(OSD_VIDEO_STATE.camera_connected ? i18n.getMessage('yes') : i18n.getMessage('No')); }); */ } diff --git a/src/js/tabs/vtx.js b/src/js/tabs/vtx.js new file mode 100644 index 00000000..ccd520a4 --- /dev/null +++ b/src/js/tabs/vtx.js @@ -0,0 +1,563 @@ +'use strict'; + +TABS.vtx = { + supported: false, + MAX_POWERLEVEL_VALUES: 8, + MAX_BAND_VALUES: 8, + MAX_BAND_CHANNELS_VALUES: 8, + VTXTABLE_BAND_LIST: [], + VTXTABLE_POWERLEVEL_LIST: [], +}; + +TABS.vtx.initialize = function (callback) { + + if (GUI.active_tab != 'vtx') { + GUI.active_tab = 'vtx'; + } + + this.supported = semver.gte(CONFIG.apiVersion, "1.42.0"); + + if (!this.supported) { + load_html(); + } else { + read_vtx_config(load_html); + } + + function load_html() { + $('#content').load("./tabs/vtx.html", process_html); + } + + function process_html() { + initDisplay(); + + // translate to user-selected language + i18n.localizePage(); + + GUI.content_ready(callback); + } + + // Read all the MSP data needed by the tab + function read_vtx_config(callback_after_msp) { + + vtx_config(); + + function vtx_config() { + MSP.send_message(MSPCodes.MSP_VTX_CONFIG, false, false, vtxtable_bands); + } + + function vtxtable_bands() { + + // Simulation of static variable + if (typeof vtxtable_bands.counter === 'undefined') { + TABS.vtx.VTXTABLE_BAND_LIST = []; + vtxtable_bands.counter = 1; + } else { + TABS.vtx.VTXTABLE_BAND_LIST.push(Object.assign({}, VTXTABLE_BAND)); + vtxtable_bands.counter++; + } + + let buffer = []; + buffer.push8(vtxtable_bands.counter); + + if (vtxtable_bands.counter <= VTX_CONFIG.vtx_table_bands) { + MSP.send_message(MSPCodes.MSP_VTXTABLE_BAND, buffer, false, vtxtable_bands); + } else { + vtxtable_bands.counter = undefined; + vtxtable_powerlevels(); + } + + } + + function vtxtable_powerlevels() { + + // Simulation of static variable + if (typeof vtxtable_powerlevels.counter === 'undefined') { + TABS.vtx.VTXTABLE_POWERLEVEL_LIST = []; + vtxtable_powerlevels.counter = 1; + } else { + TABS.vtx.VTXTABLE_POWERLEVEL_LIST.push(Object.assign({}, VTXTABLE_POWERLEVEL)); + vtxtable_powerlevels.counter++; + } + + let buffer = []; + buffer.push8(vtxtable_powerlevels.counter); + + if (vtxtable_powerlevels.counter <= VTX_CONFIG.vtx_table_powerlevels) { + MSP.send_message(MSPCodes.MSP_VTXTABLE_POWERLEVEL, buffer, false, vtxtable_powerlevels); + } else { + vtxtable_powerlevels.counter = undefined; + callback_after_msp(); + } + } + } + + // Prepares all the UI elements, the MSP command has been executed before + function initDisplay() { + + if (!TABS.vtx.supported) { + $(".tab-vtx").removeClass("supported"); + return; + } + + $(".tab-vtx").addClass("supported"); + + // Load all the dynamic elements + loadPowerLevelsTemplate(); + loadBandsChannelsTemplate(); + populateBandSelect(); + populatePowerSelect(); + + $(".uppercase").keyup(function(){ + this.value = this.value.toUpperCase().trim(); + }); + + // Supported? + let vtxSupported = VTX_CONFIG.vtx_type != 0 && VTX_CONFIG.vtx_type != 255; + let vtxTableNotConfigured = vtxSupported && VTX_CONFIG.vtx_table_available && (VTX_CONFIG.vtx_table_bands == 0 || + VTX_CONFIG.vtx_table_channels == 0 || + VTX_CONFIG.vtx_table_powerlevels == 0); + + $(".vtx_supported").toggle(vtxSupported); + $(".vtx_not_supported").toggle(!vtxSupported); + $(".vtx_table_available").toggle(vtxSupported && VTX_CONFIG.vtx_table_available); + $(".vtx_table_not_configured").toggle(vtxTableNotConfigured); + + // Insert actual values in the fields + // Values of the selected mode + $("#vtx_frequency").val(VTX_CONFIG.vtx_frequency); + $("#vtx_band").val(VTX_CONFIG.vtx_band); + + $("#vtx_band").change(populateChannelSelect).change(); + + $("#vtx_channel").val(VTX_CONFIG.vtx_channel); + if (VTX_CONFIG.vtx_table_available) { + $("#vtx_channel").attr("max", VTX_CONFIG.vtx_table_channels); + } + + $("#vtx_power").val(VTX_CONFIG.vtx_power); + $("#vtx_pit_mode").prop('checked', VTX_CONFIG.vtx_pit_mode); + $("#vtx_pit_mode_frequency").val(VTX_CONFIG.vtx_pit_mode_frequency); + $("#vtx_low_power_disarm").val(VTX_CONFIG.vtx_low_power_disarm); + + // Values of the current values + let yesMessage = i18n.getMessage("yes"); + let noMessage = i18n.getMessage("no"); + + $("#vtx_device_ready_description").text(VTX_CONFIG.vtx_device_ready ? yesMessage : noMessage); + $("#vtx_type_description").text(i18n.getMessage("vtxType_" + VTX_CONFIG.vtx_type)); + $("#vtx_channel_description").text(VTX_CONFIG.vtx_channel); + $("#vtx_frequency_description").text(VTX_CONFIG.vtx_frequency); + $("#vtx_pit_mode_description").text(VTX_CONFIG.vtx_pit_mode ? yesMessage : noMessage); + $("#vtx_pit_mode_frequency_description").text(VTX_CONFIG.vtx_pit_mode_frequency); + $("#vtx_low_power_disarm_description").text(i18n.getMessage("vtxLowPowerDisarmOption_" + VTX_CONFIG.vtx_low_power_disarm)); + + if (VTX_CONFIG.vtx_band == 0) { + $("#vtx_band_description").text(i18n.getMessage("vtxBand_0")); + } else { + if (VTX_CONFIG.vtx_table_available && TABS.vtx.VTXTABLE_BAND_LIST[VTX_CONFIG.vtx_band - 1]) { + let bandName = TABS.vtx.VTXTABLE_BAND_LIST[VTX_CONFIG.vtx_band - 1].vtxtable_band_name; + if (bandName.trim() === '') { + bandName = VTX_CONFIG.vtx_band; + } + $("#vtx_band_description").text(bandName); + } else { + $("#vtx_band_description").text(VTX_CONFIG.vtx_band); + } + } + + if (VTX_CONFIG.vtx_power == 0) { + $("#vtx_power_description").text(i18n.getMessage("vtxPower_0")); + } else { + if (VTX_CONFIG.vtx_table_available) { + let powerLevel = TABS.vtx.VTXTABLE_POWERLEVEL_LIST[VTX_CONFIG.vtx_power - 1].vtxtable_powerlevel_label; + if (powerLevel.trim() === '') { + powerLevel = i; + } + $("#vtx_power_description").text(powerLevel); + } else { + let levelText = i18n.getMessage('vtxPower_X', {powerLevel: VTX_CONFIG.vtx_power}); + $("#vtx_power_description").text(levelText); + } + } + + $("#vtx_table_powerlevels").val(VTX_CONFIG.vtx_table_powerlevels); + + // Populate power levels + for (let i = 1; i <= TABS.vtx.VTXTABLE_POWERLEVEL_LIST.length; i++) { + $("#vtx_table_powerlevels_" + i).val(TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value); + $("#vtx_table_powerlabels_" + i).val(TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label); + } + + $("#vtx_table_bands").val(VTX_CONFIG.vtx_table_bands); + $("#vtx_table_channels").val(VTX_CONFIG.vtx_table_channels); + + // Populate VTX Table + for (let i = 1; i <= TABS.vtx.VTXTABLE_BAND_LIST.length; i++) { + $("#vtx_table_band_name_" + i).val(TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name); + $("#vtx_table_band_letter_" + i).val(TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter); + $("#vtx_table_band_factory_" + i).prop("checked",TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band); + for (let j = 1; j <= TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies.length; j++) { + $("#vtx_table_band_channel_" + i + "_" + j).val(TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies[j - 1]); + } + } + + // Actions and other + function frequencyOrBandChannel() { + + let frequencyEnabled = $(this).prop('checked'); + + if (frequencyEnabled) { + $(".field.vtx_channel").slideUp(100, function() { + $(".field.vtx_band").slideUp(100, function() { + $(".field.vtx_frequency").slideDown(100); + }); + }); + + } else { + $(".field.vtx_frequency").slideUp(100, function() { + $(".field.vtx_band").slideDown(100,function() { + $(".field.vtx_channel").slideDown(100); + }); + }); + } + } + + $("#vtx_frequency_channel").prop('checked', VTX_CONFIG.vtx_band == 0 && VTX_CONFIG.vtx_frequency > 0) + .change(frequencyOrBandChannel) + .change(); + + function showHidePowerlevels() { + let powerlevelsValue = $(this).val(); + + for (let i = 1; i <= TABS.vtx.MAX_POWERLEVEL_VALUES; i++) { + $(".vtx_table_powerlevels_table td:nth-child(" + i +")").toggle(i <= powerlevelsValue); + } + } + + $("#vtx_table_powerlevels").change(showHidePowerlevels).change(); + + function showHideBands() { + let bandsValue = $(this).val(); + + for (let i = 1; i <= TABS.vtx.MAX_BAND_VALUES; i++) { + $(".vtx_table_bands_table tr:nth-child(" + (i + 1) +")").toggle(i <= bandsValue); + } + } + + $("#vtx_table_bands").change(showHideBands).change(); + + function showHideBandChannels() { + let channelsValue = $(this).val(); + + for (let i = 1; i <= TABS.vtx.MAX_BAND_CHANNELS_VALUES; i++) { + $(".vtx_table_bands_table td:nth-child(" + (i + 3) +")").toggle(i <= channelsValue); + } + } + + $("#vtx_table_channels").change(showHideBandChannels).change(); + + /*** Helper functions */ + + function loadPowerLevelsTemplate() { + + // Power levels title + let powerlevelstitle_e = $(".vtx_table_powerlevels_table .vtx_table_powerlevels_title"); + + for (let i = 1; i <= TABS.vtx.MAX_POWERLEVEL_VALUES; i++) { + powerlevelstitle_e.append("" + i + ""); + } + + // Power levels + let powerlevelsrow_e = $(".vtx_table_powerlevels_table .vtx_table_powerlevels_values"); + + let powervalues_e = $("#tab-vtx-templates #tab-vtx-powerlevel-values td"); + for (let i = 1; i <= TABS.vtx.MAX_POWERLEVEL_VALUES; i++) { + let newPowerValues_e = powervalues_e.clone(); + $(newPowerValues_e).find('input').attr('id', 'vtx_table_powerlevels_' + i); + powerlevelsrow_e.append(newPowerValues_e); + } + powerlevelsrow_e.append("" + i18n.getMessage('vtxTablePowerLevelsValue') + ""); + + // Power labels + let powerlabelsrow_e = $(".vtx_table_powerlevels_table .vtx_table_powerlevels_labels"); + + let powerlabels_e = $("#tab-vtx-templates #tab-vtx-powerlevel-labels td"); + for (let i = 1; i <= TABS.vtx.MAX_POWERLEVEL_VALUES; i++) { + let newPowerLabels_e = powerlabels_e.clone(); + $(newPowerLabels_e).find('input').attr('id', 'vtx_table_powerlabels_' + i); + powerlabelsrow_e.append(newPowerLabels_e); + } + powerlabelsrow_e.append("" + i18n.getMessage('vtxTablePowerLevelsLabel') + ""); + } + + function loadBandsChannelsTemplate() { + let bandstable_e = $(".vtx_table_bands_table tbody"); + + // Title + let title_e = $("#tab-vtx-templates #tab-vtx-bands-title tr"); + + for (let i = 1; i <= TABS.vtx.MAX_BAND_VALUES; i++) { + title_e.append("" + i + ""); + } + bandstable_e.append(title_e); + + // Bands + let band_e = $("#tab-vtx-templates #tab-vtx-bands tr"); + let channel_e = $("#tab-vtx-templates #tab-vtx-channels td"); + for (let i = 1; i <= TABS.vtx.MAX_BAND_VALUES; i++) { + let newBand_e = band_e.clone(); + $(newBand_e).find('#vtx_table_band_name').attr('id', 'vtx_table_band_name_' + i); + $(newBand_e).find('#vtx_table_band_letter').attr('id', 'vtx_table_band_letter_' + i); + $(newBand_e).find('#vtx_table_band_factory').attr('id', 'vtx_table_band_factory_' + i); + + // Channels + let newChannel_e; + for (let j = 1; j <= TABS.vtx.MAX_BAND_CHANNELS_VALUES; j++) { + newChannel_e = channel_e.clone(); + $(newChannel_e).find('input').attr('id', 'vtx_table_band_channel_' + i + '_' + j); + + newBand_e.append(newChannel_e); + } + + // Append to the end an index of the band + newBand_e.append("" + i18n.getMessage("vtxBand_X", {bandName: i}) + "") + + bandstable_e.append(newBand_e); + } + } + + function populateBandSelect() { + + let selectBand = $(".field #vtx_band"); + + selectBand.append(new Option(i18n.getMessage('vtxBand_0'), 0)) + if (VTX_CONFIG.vtx_table_available) { + for (let i = 1; i <= VTX_CONFIG.vtx_table_bands; i++) { + let bandName = TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name; + if (bandName.trim() === '') { + bandName = i18n.getMessage('vtxBand_X', {bandName: i}); + } + selectBand.append(new Option(bandName, i)); + } + } else { + for (let i = 1; i <= TABS.vtx.MAX_BAND_VALUES; i++) { + selectBand.append(new Option(i18n.getMessage('vtxBand_X', {bandName: i}), i)); + } + } + } + + function populateChannelSelect() { + + let selectChannel = $(".field #vtx_channel"); + let selectedBand = $("#vtx_band").val(); + + selectChannel.empty(); + + selectChannel.append(new Option(i18n.getMessage('vtxChannel_0'), 0)) + if (VTX_CONFIG.vtx_table_available) { + if (TABS.vtx.VTXTABLE_BAND_LIST[selectedBand - 1]) { + for (let i = 1; i <= TABS.vtx.VTXTABLE_BAND_LIST[selectedBand - 1].vtxtable_band_frequencies.length; i++) { + let channelName = TABS.vtx.VTXTABLE_BAND_LIST[selectedBand - 1].vtxtable_band_frequencies[i - 1]; + if (channelName > 0) { + selectChannel.append(new Option(i18n.getMessage('vtxChannel_X', {channelName: i}), i)); + } + } + } + } else { + for (let i = 1; i <= TABS.vtx.MAX_BAND_CHANNELS_VALUES; i++) { + selectBand.append(new Option(i18n.getMessage('vtxChannel_X', {channelName: i}), i)); + } + } + } + + function populatePowerSelect() { + let selectPower = $(".field #vtx_power"); + + if (VTX_CONFIG.vtx_table_available) { + selectPower.append(new Option(i18n.getMessage('vtxPower_0'), 0)) + for (let i = 1; i <= VTX_CONFIG.vtx_table_powerlevels; i++) { + let powerLevel = TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label; + if (powerLevel.trim() === '') { + powerLevel = i18n.getMessage('vtxPower_X', {powerLevel: i}); + } + selectPower.append(new Option(powerLevel, i)); + } + } else { + let 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', {bandName: i}), i)); + } + } + } + } + + // Returns the power values min and max depending on the VTX Type + function getPowerValues(vtxType) { + + let powerMinMax = {}; + + if (VTX_CONFIG.vtx_table_available) { + powerMinMax = {min: 1, max: VTX_CONFIG.vtx_table_powerlevels} + } else { + + switch (vtxType) { + + case 0: // Unsupported + powerMinMax = {}; + break; + + case 1: // RTC6705 + powerMinMax = {min: 1, max: 3}; + break; + + case 3: // SmartAudio + powerMinMax = {min: 1, max: 4}; + break; + + case 4: // Tramp + powerMinMax = {min: 1, max: 5}; + break; + + case 255: // Unknown + default: + powerMinMax = {min: 0, max: 7}; + } + } + return powerMinMax; + } + + // Save function + $('a.save').click(function () { + save_vtx(); + }); + + } + + // Save all the values from the tab to MSP + function save_vtx() { + + // General config + let frequencyEnabled = $("#vtx_frequency_channel").prop('checked'); + if (frequencyEnabled) { + VTX_CONFIG.vtx_frequency = parseInt($("#vtx_frequency").val()); + VTX_CONFIG.vtx_band = 0; + VTX_CONFIG.vtx_channel = 0; + } else { + VTX_CONFIG.vtx_band = parseInt($("#vtx_band").val()); + VTX_CONFIG.vtx_channel = parseInt($("#vtx_channel").val()); + VTX_CONFIG.vtx_frequency = 0; + if (semver.lt(CONFIG.apiVersion, "1.42.0")) { + if (VTX_CONFIG.vtx_band > 0 || VTX_CONFIG.vtx_channel > 0) { + VTX_CONFIG.vtx_frequency = (band - 1) * 8 + (channel - 1); + } + } + } + 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()); + VTX_CONFIG.vtx_table_clear = true; + + // Power levels + VTX_CONFIG.vtx_table_powerlevels = parseInt($("#vtx_table_powerlevels").val()); + + TABS.vtx.VTXTABLE_POWERLEVEL_LIST = []; + for (let i = 1; i <= VTX_CONFIG.vtx_table_powerlevels; i++) { + TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1] = {}; + TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_number = i; + TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_value = parseInt($("#vtx_table_powerlevels_" + i).val()); + TABS.vtx.VTXTABLE_POWERLEVEL_LIST[i - 1].vtxtable_powerlevel_label = $("#vtx_table_powerlabels_" + i).val(); + } + + // Bands and channels + VTX_CONFIG.vtx_table_bands = parseInt($("#vtx_table_bands").val()); + VTX_CONFIG.vtx_table_channels = parseInt($("#vtx_table_channels").val()); + TABS.vtx.VTXTABLE_BAND_LIST = []; + for (let i = 1; i <= VTX_CONFIG.vtx_table_bands; i++) { + TABS.vtx.VTXTABLE_BAND_LIST[i - 1] = {}; + TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_number = i; + TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_name = $("#vtx_table_band_name_" + i).val(); + TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_letter = $("#vtx_table_band_letter_" + i).val(); + TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_is_factory_band = $("#vtx_table_band_factory_" + i).prop('checked'); + + TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies = []; + for (let j = 1; j <= VTX_CONFIG.vtx_table_channels; j++) { + TABS.vtx.VTXTABLE_BAND_LIST[i - 1].vtxtable_band_frequencies.push(parseInt($("#vtx_table_band_channel_" + i + "_" + j).val())); + } + } + + // Start MSP saving + save_vtx_config(); + + function save_vtx_config() { + MSP.send_message(MSPCodes.MSP_SET_VTX_CONFIG, mspHelper.crunch(MSPCodes.MSP_SET_VTX_CONFIG), false, save_vtx_powerlevels); + } + + function save_vtx_powerlevels() { + + // Simulation of static variable + if (typeof save_vtx_powerlevels.counter === 'undefined') { + save_vtx_powerlevels.counter = 0; + } else { + save_vtx_powerlevels.counter++; + } + + + if (save_vtx_powerlevels.counter < VTX_CONFIG.vtx_table_powerlevels) { + VTXTABLE_POWERLEVEL = Object.assign({}, TABS.vtx.VTXTABLE_POWERLEVEL_LIST[save_vtx_powerlevels.counter]); + MSP.send_message(MSPCodes.MSP_SET_VTXTABLE_POWERLEVEL, mspHelper.crunch(MSPCodes.MSP_SET_VTXTABLE_POWERLEVEL), false, save_vtx_powerlevels); + } else { + save_vtx_powerlevels.counter = undefined; + save_vtx_bands(); + } + } + + function save_vtx_bands() { + + // Simulation of static variable + if (typeof save_vtx_bands.counter === 'undefined') { + save_vtx_bands.counter = 0; + } else { + save_vtx_bands.counter++; + } + + + if (save_vtx_bands.counter < VTX_CONFIG.vtx_table_bands) { + VTXTABLE_BAND = Object.assign({}, TABS.vtx.VTXTABLE_BAND_LIST[save_vtx_bands.counter]); + MSP.send_message(MSPCodes.MSP_SET_VTXTABLE_BAND, mspHelper.crunch(MSPCodes.MSP_SET_VTXTABLE_BAND), false, save_vtx_bands); + } else { + save_vtx_bands.counter = undefined; + save_to_eeprom(); + } + } + + function save_to_eeprom() { + MSP.send_message(MSPCodes.MSP_EEPROM_WRITE, false, false, save_completed); + } + + function save_completed() { + GUI.log(i18n.getMessage('configurationEepromSaved')); + + var oldText = $("#save_button").text(); + $("#save_button").html(i18n.getMessage('vtxButtonSaved')); + setTimeout(function () { + $("#save_button").html(oldText); + }, 2000); + + TABS.vtx.initialize(); + } + } +}; + +TABS.vtx.cleanup = function (callback) { + + // Add here things that need to be cleaned or closed before leaving the tab + this.VTXTABLE_BAND_LIST = []; + this.VTXTABLE_POWERLEVEL_LIST = []; + + if (callback) { + callback(); + } +}; diff --git a/src/main.html b/src/main.html index 24420676..61870d4c 100644 --- a/src/main.html +++ b/src/main.html @@ -29,6 +29,7 @@ + @@ -163,6 +164,7 @@ + @@ -322,6 +324,7 @@
  • +
  • diff --git a/src/tabs/vtx.html b/src/tabs/vtx.html new file mode 100644 index 00000000..05ad3977 --- /dev/null +++ b/src/tabs/vtx.html @@ -0,0 +1,329 @@ +
    +
    + +
    +
    +
    + +
    +
    + +
    +

    +

    + +
    +
    +
    + +
    +
    +
    + + + + + + + + + +
    +
    + +
    + +
    +
    +
    + +
    + +
    + + + +
    +
    + +
    + +
    +
    +
    + +
    + +
    + + + + + + + + +
    +
    + +
    + + + + + +
    +
    + +
    + +
    + +
    + + + +
    + +
    +
    + +
    + +
    +
    + +
    + +
    + +
    + +
    + +
    + + + + +
    +
    + +
    + + + + +
    +
    + +
    + + + + + + +
    +
    + +
    + + + + + + + +
    +
    + +
    + + + + +
    +
    + + + +
    \ No newline at end of file