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/>.
26 #if defined(USE_VTX_COMMON)
28 #include "common/maths.h"
29 #include "common/time.h"
31 #include "drivers/vtx_common.h"
33 #include "fc/config.h"
34 #include "fc/rc_modes.h"
35 #include "fc/runtime_config.h"
37 #include "flight/failsafe.h"
40 #include "io/vtx_string.h"
41 #include "io/vtx_control.h"
43 #include "interface/cli.h"
46 #include "pg/pg_ids.h"
49 PG_REGISTER_WITH_RESET_TEMPLATE(vtxSettingsConfig_t
, vtxSettingsConfig
, PG_VTX_SETTINGS_CONFIG
, 0);
51 PG_RESET_TEMPLATE(vtxSettingsConfig_t
, vtxSettingsConfig
,
52 .band
= VTX_SETTINGS_DEFAULT_BAND
,
53 .channel
= VTX_SETTINGS_DEFAULT_CHANNEL
,
54 .power
= VTX_SETTINGS_DEFAULT_POWER
,
55 .freq
= VTX_SETTINGS_DEFAULT_FREQ
,
56 .pitModeFreq
= VTX_SETTINGS_DEFAULT_PITMODE_FREQ
,
57 .lowPowerDisarm
= VTX_LOW_POWER_DISARM_OFF
,
66 } vtxScheduleParams_e
;
70 bool settingsUpdated
= false;
72 // sync frequency in parameter group when band/channel are specified
73 const uint16_t freq
= vtxCommonLookupFrequency(vtxCommonDevice(), vtxSettingsConfig()->band
, vtxSettingsConfig()->channel
);
74 if (vtxSettingsConfig()->band
&& freq
!= vtxSettingsConfig()->freq
) {
75 vtxSettingsConfigMutable()->freq
= freq
;
76 settingsUpdated
= true;
79 #if defined(VTX_SETTINGS_FREQCMD)
80 // constrain pit mode frequency
81 if (vtxSettingsConfig()->pitModeFreq
) {
82 const uint16_t constrainedPitModeFreq
= MAX(vtxSettingsConfig()->pitModeFreq
, VTX_SETTINGS_MIN_USER_FREQ
);
83 if (constrainedPitModeFreq
!= vtxSettingsConfig()->pitModeFreq
) {
84 vtxSettingsConfigMutable()->pitModeFreq
= constrainedPitModeFreq
;
85 settingsUpdated
= true;
90 if (settingsUpdated
) {
91 saveConfigAndNotify();
95 STATIC_UNIT_TESTED vtxSettingsConfig_t
vtxGetSettings(void)
97 vtxSettingsConfig_t settings
= {
98 .band
= vtxSettingsConfig()->band
,
99 .channel
= vtxSettingsConfig()->channel
,
100 .power
= vtxSettingsConfig()->power
,
101 .freq
= vtxSettingsConfig()->freq
,
102 .pitModeFreq
= vtxSettingsConfig()->pitModeFreq
,
103 .lowPowerDisarm
= vtxSettingsConfig()->lowPowerDisarm
,
106 #if defined(VTX_SETTINGS_FREQCMD)
107 if (IS_RC_MODE_ACTIVE(BOXVTXPITMODE
) && settings
.pitModeFreq
) {
109 settings
.freq
= settings
.pitModeFreq
;
110 settings
.power
= VTX_SETTINGS_DEFAULT_POWER
;
114 if (!ARMING_FLAG(ARMED
) && !failsafeIsActive() &&
115 (settings
.lowPowerDisarm
== VTX_LOW_POWER_DISARM_ALWAYS
||
116 (settings
.lowPowerDisarm
== VTX_LOW_POWER_DISARM_UNTIL_FIRST_ARM
&& !ARMING_FLAG(WAS_EVER_ARMED
)))) {
117 settings
.power
= VTX_SETTINGS_DEFAULT_POWER
;
123 static bool vtxProcessBandAndChannel(vtxDevice_t
*vtxDevice
)
125 if(!ARMING_FLAG(ARMED
)) {
128 if (vtxCommonGetBandAndChannel(vtxDevice
, &vtxBand
, &vtxChan
)) {
129 const vtxSettingsConfig_t settings
= vtxGetSettings();
130 if (vtxBand
!= settings
.band
|| vtxChan
!= settings
.channel
) {
131 vtxCommonSetBandAndChannel(vtxDevice
, settings
.band
, settings
.channel
);
139 #if defined(VTX_SETTINGS_FREQCMD)
140 static bool vtxProcessFrequency(vtxDevice_t
*vtxDevice
)
142 if(!ARMING_FLAG(ARMED
)) {
144 if (vtxCommonGetFrequency(vtxDevice
, &vtxFreq
)) {
145 const vtxSettingsConfig_t settings
= vtxGetSettings();
146 if (vtxFreq
!= settings
.freq
) {
147 vtxCommonSetFrequency(vtxDevice
, settings
.freq
);
156 static bool vtxProcessPower(vtxDevice_t
*vtxDevice
)
159 if (vtxCommonGetPowerIndex(vtxDevice
, &vtxPower
)) {
160 const vtxSettingsConfig_t settings
= vtxGetSettings();
161 if (vtxPower
!= settings
.power
) {
162 vtxCommonSetPowerByIndex(vtxDevice
, settings
.power
);
169 static bool vtxProcessPitMode(vtxDevice_t
*vtxDevice
)
171 static bool prevPmSwitchState
= false;
174 if (!ARMING_FLAG(ARMED
) && vtxCommonGetPitMode(vtxDevice
, &pitOnOff
)) {
175 bool currPmSwitchState
= IS_RC_MODE_ACTIVE(BOXVTXPITMODE
);
177 if (currPmSwitchState
!= prevPmSwitchState
) {
178 prevPmSwitchState
= currPmSwitchState
;
180 if (currPmSwitchState
) {
181 #if defined(VTX_SETTINGS_FREQCMD)
182 if (vtxSettingsConfig()->pitModeFreq
) {
187 vtxCommonSetPitMode(vtxDevice
, true);
193 vtxCommonSetPitMode(vtxDevice
, false);
204 static bool vtxProcessStateUpdate(vtxDevice_t
*vtxDevice
)
206 const vtxSettingsConfig_t vtxSettingsState
= vtxGetSettings();
207 vtxSettingsConfig_t vtxState
= vtxSettingsState
;
209 if (vtxSettingsState
.band
) {
210 vtxCommonGetBandAndChannel(vtxDevice
, &vtxState
.band
, &vtxState
.channel
);
211 #if defined(VTX_SETTINGS_FREQCMD)
213 vtxCommonGetFrequency(vtxDevice
, &vtxState
.freq
);
217 vtxCommonGetPowerIndex(vtxDevice
, &vtxState
.power
);
219 return (bool)memcmp(&vtxSettingsState
, &vtxState
, sizeof(vtxSettingsConfig_t
));
222 void vtxUpdate(timeUs_t currentTimeUs
)
224 static uint8_t currentSchedule
= 0;
230 vtxDevice_t
*vtxDevice
= vtxCommonDevice();
232 // Check input sources for config updates
233 vtxControlInputPoll();
235 const uint8_t startingSchedule
= currentSchedule
;
236 bool vtxUpdatePending
= false;
238 switch (currentSchedule
) {
239 case VTX_PARAM_POWER
:
240 vtxUpdatePending
= vtxProcessPower(vtxDevice
);
242 case VTX_PARAM_BANDCHAN
:
243 if (vtxGetSettings().band
) {
244 vtxUpdatePending
= vtxProcessBandAndChannel(vtxDevice
);
245 #if defined(VTX_SETTINGS_FREQCMD)
247 vtxUpdatePending
= vtxProcessFrequency(vtxDevice
);
251 case VTX_PARAM_PITMODE
:
252 vtxUpdatePending
= vtxProcessPitMode(vtxDevice
);
254 case VTX_PARAM_CONFIRM
:
255 vtxUpdatePending
= vtxProcessStateUpdate(vtxDevice
);
260 currentSchedule
= (currentSchedule
+ 1) % VTX_PARAM_COUNT
;
261 } while (!vtxUpdatePending
&& currentSchedule
!= startingSchedule
);
263 if (!ARMING_FLAG(ARMED
) || vtxUpdatePending
) {
264 vtxCommonProcess(vtxDevice
, currentTimeUs
);