2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
22 #if defined(USE_SPEKTRUM_VTX_CONTROL) && defined(USE_VTX_COMMON)
26 #include "config/config.h"
27 #include "drivers/vtx_common.h"
30 #include "io/spektrum_vtx_control.h"
32 // We can not use the common set/get-frequncy API.
33 // Some VTX devices do not support it.
34 //#define USE_VTX_COMMON_FREQ_API
36 #ifdef USE_VTX_COMMON_FREQ_API
37 const uint16_t SpektrumVtxfrequencyTable
[SPEKTRUM_VTX_BAND_COUNT
][SPEKTRUM_VTX_CHAN_COUNT
] =
39 { 5740, 5760, 5780, 5800, 5820, 5840, 5860, 5880 }, // FatShark
40 { 5658, 5695, 5732, 5769, 5806, 5843, 5880, 5917 }, // RaceBand
41 { 5705, 5685, 5665, 5645, 5885, 5905, 5925, 5945 }, // Boscam E
42 { 5733, 5752, 5771, 5790, 5809, 5828, 5847, 5866 }, // Boscam B
43 { 5865, 5845, 5825, 5805, 5785, 5765, 5745, 5725 }, // Boscam A
46 // Translation table, Spektrum bands to BF internal vtx_common bands
47 const uint8_t spek2commonBand
[SPEKTRUM_VTX_BAND_COUNT
]= {
56 // RF Power Index translation tables. No generic power API available.....
59 // Tramp "---", 25, 200, 400. 600 mW
60 const uint8_t vtxTrampPi
[SPEKTRUM_VTX_POWER_COUNT
] = {
61 // Spektrum Spec Tx menu Tx sends To VTX Watt
62 VTX_TRAMP_POWER_OFF
, // Off INHIBIT 0 0 -
63 VTX_TRAMP_POWER_OFF
, // 1 - 14mW - - - -
64 VTX_TRAMP_POWER_25
, // 15 - 25mW 15 - 25mW 2 1 25mW
65 VTX_TRAMP_POWER_100
, // 26 - 99mW 26 - 99mW 3 2 100mW Slightly outside range
66 VTX_TRAMP_POWER_200
, // 100 - 299mW 100 - 200mW 4 3 200mW
67 VTX_TRAMP_POWER_400
, // 300 - 600mW 300 - 600mW 5 4 400mW
68 VTX_TRAMP_POWER_600
, // 601 - max 601+ mW 6 5 600mW Slightly outside range
69 VTX_TRAMP_POWER_200
// Manual - - - -
71 #endif // USE_VTX_TRAMP
72 //todo: enable pit mode where appropriate, for all protcols
73 #ifdef USE_VTX_RTC6705
74 // RTC6705 "---", 25 or 200 mW
75 const uint8_t vtxRTC6705Pi
[SPEKTRUM_VTX_POWER_COUNT
] = {
76 VTX_6705_POWER_25
, // Off
77 VTX_6705_POWER_25
, // 1 - 14mW
78 VTX_6705_POWER_25
, // 15 - 25mW
79 VTX_6705_POWER_25
, // 26 - 99mW
80 VTX_6705_POWER_200
, // 100 - 299mW
81 VTX_6705_POWER_200
, // 300 - 600mW
82 VTX_6705_POWER_200
, // 601 - max
83 VTX_6705_POWER_200
// Manual
85 #endif //USE_VTX_RTC6705
87 #ifdef USE_VTX_SMARTAUDIO
88 // SmartAudio "---", 25, 200, 500. 800 mW
89 const uint8_t vtxSaPi
[SPEKTRUM_VTX_POWER_COUNT
] = {
90 VTX_SA_POWER_OFF
, // Off
91 VTX_SA_POWER_OFF
, // 1 - 14mW
92 VTX_SA_POWER_25
, // 15 - 25mW
93 VTX_SA_POWER_25
, // 26 - 99mW
94 VTX_SA_POWER_200
, // 100 - 299mW
95 VTX_SA_POWER_500
, // 300 - 600mW
96 VTX_SA_POWER_800
, // 601 - max
97 VTX_SA_POWER_200
// Manual
99 #endif // USE_VTX_SMARTAUDIO
101 uint8_t convertSpektrumVtxPowerIndex(uint8_t sPower
)
103 uint8_t devicePower
= 0;
105 const vtxDevice_t
*vtxDevice
= vtxCommonDevice();
106 switch (vtxCommonGetDeviceType(vtxDevice
)) {
107 #ifdef USE_VTX_RTC6705
109 devicePower
= vtxRTC6705Pi
[sPower
];
111 #endif // USE_VTX_RTC6705
113 #ifdef USE_VTX_SMARTAUDIO
114 case VTXDEV_SMARTAUDIO
:
115 devicePower
= vtxSaPi
[sPower
];
117 #endif // USE_VTX_SMARTAUDIO
121 devicePower
= vtxTrampPi
[sPower
];
123 #endif // USE_VTX_TRAMP
126 case VTXDEV_UNSUPPORTED
:
134 #ifdef USE_SPEKTRUM_REGION_CODES
135 // Just a global SpektrumRegion for now, To save VTX ctrl input to VTX tm output.
136 // Would need a PG item to survive power cycle. Not really used so let it be as is.
137 uint8_t SpektrumRegion
= SPEKTRUM_VTX_REGION_NONE
;
140 // Mark an inital invalid VTX ctrl frame to force first VTX settings cheange to actually come from Tx/Rx.
141 static uint32_t vtxControl_ipc
= ~(SPEKTRUM_VTX_CONTROL_FRAME
);
143 // ############ RX task ######################
144 void spektrumHandleVtxControl(uint32_t vtxCntrl
)
146 vtxControl_ipc
= vtxCntrl
;
148 // ###########################################
151 // ############ VTX_CONTROL task #############
152 void spektrumVtxControl(void)
154 static uint32_t prevVtxControl
=0;
157 // Check for invalid VTX ctrl frames
158 if ((vtxControl_ipc
& SPEKTRUM_VTX_CONTROL_FRAME_MASK
) != SPEKTRUM_VTX_CONTROL_FRAME
) return;
160 vtxControl
= vtxControl_ipc
;
163 if (prevVtxControl
== vtxControl
) return;
164 prevVtxControl
= vtxControl
;
166 spektrumVtx_t vtx
= {
167 .pitMode
= (vtxControl
& SPEKTRUM_VTX_PIT_MODE_MASK
) >> SPEKTRUM_VTX_PIT_MODE_SHIFT
,
168 .region
= (vtxControl
& SPEKTRUM_VTX_REGION_MASK
) >> SPEKTRUM_VTX_REGION_SHIFT
,
169 .power
= (vtxControl
& SPEKTRUM_VTX_POWER_MASK
) >> SPEKTRUM_VTX_POWER_SHIFT
,
170 .band
= (vtxControl
& SPEKTRUM_VTX_BAND_MASK
) >> SPEKTRUM_VTX_BAND_SHIFT
,
171 .channel
= (vtxControl
& SPEKTRUM_VTX_CHANNEL_MASK
) >> SPEKTRUM_VTX_CHANNEL_SHIFT
,
172 #ifdef USE_SPEKTRUM_REGION_CODES
173 .region
= (vtxControl
& SPEKTRUM_VTX_REGION_MASK
) >> SPEKTRUM_VTX_REGION_SHIFT
;
177 const vtxSettingsConfig_t prevSettings
= {
178 .band
= vtxSettingsConfig()->band
,
179 .channel
= vtxSettingsConfig()->channel
,
180 .freq
= vtxSettingsConfig()->freq
,
181 .power
= vtxSettingsConfig()->power
,
182 .lowPowerDisarm
= vtxSettingsConfig()->lowPowerDisarm
,
184 vtxSettingsConfig_t newSettings
= prevSettings
;
186 vtxDevice_t
*vtxDevice
= vtxCommonDevice();
188 #ifdef USE_VTX_COMMON_FREQ_API
189 uint16_t freq
= SpektrumVtxfrequencyTable
[vtx
.band
][vtx
.channel
];
190 if (prevSettings
.freq
!= freq
) {
191 newSettings
.band
= VTX_COMMON_BAND_USER
;
192 newSettings
.channel
= vtx
.channel
;
193 newSettings
.freq
= freq
;
196 // Convert to the internal Common Band index
197 const uint8_t band
= spek2commonBand
[vtx
.band
];
198 const uint8_t channel
= vtx
.channel
+1; // 0 based to 1 based
199 if ((prevSettings
.band
!= band
) || (prevSettings
.channel
!= channel
)) {
200 newSettings
.band
= band
;
201 newSettings
.channel
= channel
;
202 newSettings
.freq
= vtxCommonLookupFrequency(vtxDevice
, band
, channel
);
205 // Seems to be no unified internal VTX API standard for power levels/indexes, VTX device brand specific.
206 const uint8_t power
= convertSpektrumVtxPowerIndex(vtx
.power
);
207 if (prevSettings
.power
!= power
) {
208 newSettings
.power
= power
;
210 // Everyone seems to agree on what PIT ON/OFF means
211 unsigned vtxCurrentStatus
;
212 if (vtxCommonGetStatus(vtxDevice
, &vtxCurrentStatus
)) {
213 if ((vtxCurrentStatus
& VTX_STATUS_PIT_MODE
) != vtx
.pitMode
) {
214 vtxCommonSetPitMode(vtxDevice
, vtx
.pitMode
);
219 if (memcmp(&prevSettings
,&newSettings
,sizeof(vtxSettingsConfig_t
))) {
220 vtxSettingsConfigMutable()->band
= newSettings
.band
;
221 vtxSettingsConfigMutable()->channel
= newSettings
.channel
;
222 vtxSettingsConfigMutable()->power
= newSettings
.power
;
223 vtxSettingsConfigMutable()->freq
= newSettings
.freq
;
224 saveConfigAndNotify();
226 #ifdef USE_SPEKTRUM_REGION_CODES
228 SpektrumRegion
= vtx
.region
;
233 #endif // USE_SPEKTRUM_VTX_CONTROL && USE_VTX_COMMON