Moved 'config.[ch]' into the 'config/' directory.
[betaflight.git] / src / main / io / vtx.c
blobd7393e1e5ebadf83945f7b52ced30db6d2a3eb38
1 /*
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)
8 * any later version.
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/>.
21 #include <stdint.h>
22 #include <string.h>
24 #include "platform.h"
26 #if defined(USE_VTX_COMMON)
28 #include "cli/cli.h"
30 #include "common/maths.h"
31 #include "common/time.h"
33 #include "drivers/vtx_common.h"
34 #if defined(USE_VTX_RTC6705)
35 #include "drivers/vtx_rtc6705.h"
36 #endif
37 #include "drivers/vtx_table.h"
39 #include "config/config.h"
40 #include "fc/rc_modes.h"
41 #include "fc/runtime_config.h"
43 #include "flight/failsafe.h"
45 #include "io/vtx_control.h"
47 #include "pg/pg.h"
48 #include "pg/pg_ids.h"
50 #include "vtx.h"
53 PG_REGISTER_WITH_RESET_FN(vtxSettingsConfig_t, vtxSettingsConfig, PG_VTX_SETTINGS_CONFIG, 0);
55 void pgResetFn_vtxSettingsConfig(vtxSettingsConfig_t *vtxSettingsConfig)
57 #ifdef USE_VTX_TABLE
58 vtxSettingsConfig->band = 0;
59 vtxSettingsConfig->channel = 0;
60 vtxSettingsConfig->power = 0;
61 vtxSettingsConfig->freq = 0;
62 #else
63 vtxSettingsConfig->freq = VTX_TABLE_DEFAULT_FREQ;
64 vtxSettingsConfig->band = VTX_TABLE_DEFAULT_BAND;
65 vtxSettingsConfig->channel = VTX_TABLE_DEFAULT_CHANNEL;
66 vtxSettingsConfig->power = VTX_TABLE_DEFAULT_POWER;
67 #endif
68 vtxSettingsConfig->pitModeFreq = VTX_TABLE_DEFAULT_PITMODE_FREQ;
69 vtxSettingsConfig->lowPowerDisarm = VTX_LOW_POWER_DISARM_OFF;
72 typedef enum {
73 VTX_PARAM_POWER = 0,
74 VTX_PARAM_BANDCHAN,
75 VTX_PARAM_PITMODE,
76 VTX_PARAM_CONFIRM,
77 VTX_PARAM_COUNT
78 } vtxScheduleParams_e;
80 void vtxInit(void)
82 bool settingsUpdated = false;
84 vtxDevice_t *vtxDevice = vtxCommonDevice();
86 if (!vtxDevice) {
87 // If a device is not registered, we don't have any table to refer.
88 // Don't manipulate settings and just return in this case.
89 return;
92 // sync frequency in parameter group when band/channel are specified
93 const uint16_t freq = vtxCommonLookupFrequency(vtxDevice, vtxSettingsConfig()->band, vtxSettingsConfig()->channel);
94 if (vtxSettingsConfig()->band && freq != vtxSettingsConfig()->freq) {
95 vtxSettingsConfigMutable()->freq = freq;
96 settingsUpdated = true;
99 #if defined(VTX_SETTINGS_FREQCMD)
100 // constrain pit mode frequency
101 if (vtxSettingsConfig()->pitModeFreq) {
102 const uint16_t constrainedPitModeFreq = MAX(vtxSettingsConfig()->pitModeFreq, VTX_TABLE_MIN_USER_FREQ);
103 if (constrainedPitModeFreq != vtxSettingsConfig()->pitModeFreq) {
104 vtxSettingsConfigMutable()->pitModeFreq = constrainedPitModeFreq;
105 settingsUpdated = true;
108 #endif
110 if (settingsUpdated) {
111 saveConfigAndNotify();
115 // Once refactoring for RTC6705 to handle pit mode properly and remove the requirement
116 // for having a 0 value in the vtxtable power levels is completed then this function will
117 // no longer be required and the VTX_TABLE_LOW_POWER_INDEX value can always be used.
118 static uint8_t vtxGetMinimumPowerIndex(void)
120 const vtxDevice_t *vtxDevice = vtxCommonDevice();
121 vtxDevType_e vtxType = VTXDEV_UNKNOWN;
122 if (vtxDevice) {
123 vtxType = vtxCommonGetDeviceType(vtxDevice);
125 switch (vtxType) {
126 #if defined(USE_VTX_RTC6705)
127 case VTXDEV_RTC6705:
128 // special handling for rtc6705 which has the low power setting in index 2
129 return VTX_RTC6705_DEFAULT_POWER_INDEX;
130 #endif
131 default:
132 return VTX_TABLE_LOW_POWER_INDEX;
136 STATIC_UNIT_TESTED vtxSettingsConfig_t vtxGetSettings(void)
138 vtxSettingsConfig_t settings = {
139 .band = vtxSettingsConfig()->band,
140 .channel = vtxSettingsConfig()->channel,
141 .power = vtxSettingsConfig()->power,
142 .freq = vtxSettingsConfig()->freq,
143 .pitModeFreq = vtxSettingsConfig()->pitModeFreq,
144 .lowPowerDisarm = vtxSettingsConfig()->lowPowerDisarm,
147 #if defined(VTX_SETTINGS_FREQCMD)
148 if (IS_RC_MODE_ACTIVE(BOXVTXPITMODE) && settings.pitModeFreq) {
149 settings.band = 0;
150 settings.freq = settings.pitModeFreq;
151 settings.power = vtxGetMinimumPowerIndex();
153 #endif
155 if (!ARMING_FLAG(ARMED) && !failsafeIsActive() &&
156 (settings.lowPowerDisarm == VTX_LOW_POWER_DISARM_ALWAYS ||
157 (settings.lowPowerDisarm == VTX_LOW_POWER_DISARM_UNTIL_FIRST_ARM && !ARMING_FLAG(WAS_EVER_ARMED)))) {
158 settings.power = vtxGetMinimumPowerIndex();
161 return settings;
164 static bool vtxProcessBandAndChannel(vtxDevice_t *vtxDevice)
166 if (!ARMING_FLAG(ARMED)) {
167 uint8_t vtxBand;
168 uint8_t vtxChan;
169 if (vtxCommonGetBandAndChannel(vtxDevice, &vtxBand, &vtxChan)) {
170 const vtxSettingsConfig_t settings = vtxGetSettings();
171 if (vtxBand != settings.band || vtxChan != settings.channel) {
172 vtxCommonSetBandAndChannel(vtxDevice, settings.band, settings.channel);
173 return true;
177 return false;
180 #if defined(VTX_SETTINGS_FREQCMD)
181 static bool vtxProcessFrequency(vtxDevice_t *vtxDevice)
183 if (!ARMING_FLAG(ARMED)) {
184 uint16_t vtxFreq;
185 if (vtxCommonGetFrequency(vtxDevice, &vtxFreq)) {
186 const vtxSettingsConfig_t settings = vtxGetSettings();
187 if (vtxFreq != settings.freq) {
188 vtxCommonSetFrequency(vtxDevice, settings.freq);
189 return true;
193 return false;
195 #endif
197 static bool vtxProcessPower(vtxDevice_t *vtxDevice)
199 uint8_t vtxPower;
200 if (vtxCommonGetPowerIndex(vtxDevice, &vtxPower)) {
201 const vtxSettingsConfig_t settings = vtxGetSettings();
202 if (vtxPower != settings.power) {
203 vtxCommonSetPowerByIndex(vtxDevice, settings.power);
204 return true;
207 return false;
210 static bool vtxProcessPitMode(vtxDevice_t *vtxDevice)
212 static bool prevPmSwitchState = false;
214 unsigned vtxStatus;
215 if (!ARMING_FLAG(ARMED) && vtxCommonGetStatus(vtxDevice, &vtxStatus)) {
216 bool currPmSwitchState = IS_RC_MODE_ACTIVE(BOXVTXPITMODE);
218 if (currPmSwitchState != prevPmSwitchState) {
219 prevPmSwitchState = currPmSwitchState;
221 if (currPmSwitchState) {
222 #if defined(VTX_SETTINGS_FREQCMD)
223 if (vtxSettingsConfig()->pitModeFreq) {
224 return false;
226 #endif
227 if (!(vtxStatus & VTX_STATUS_PIT_MODE)) {
228 vtxCommonSetPitMode(vtxDevice, true);
230 return true;
232 } else {
233 if (vtxStatus & VTX_STATUS_PIT_MODE) {
234 vtxCommonSetPitMode(vtxDevice, false);
236 return true;
242 return false;
245 static bool vtxProcessStateUpdate(vtxDevice_t *vtxDevice)
247 const vtxSettingsConfig_t vtxSettingsState = vtxGetSettings();
248 vtxSettingsConfig_t vtxState = vtxSettingsState;
250 if (vtxSettingsState.band) {
251 vtxCommonGetBandAndChannel(vtxDevice, &vtxState.band, &vtxState.channel);
252 #if defined(VTX_SETTINGS_FREQCMD)
253 } else {
254 vtxCommonGetFrequency(vtxDevice, &vtxState.freq);
255 #endif
258 vtxCommonGetPowerIndex(vtxDevice, &vtxState.power);
260 return (bool)memcmp(&vtxSettingsState, &vtxState, sizeof(vtxSettingsConfig_t));
263 void vtxUpdate(timeUs_t currentTimeUs)
265 static uint8_t currentSchedule = 0;
267 if (cliMode) {
268 return;
271 vtxDevice_t *vtxDevice = vtxCommonDevice();
272 if (vtxDevice) {
273 // Check input sources for config updates
274 vtxControlInputPoll();
276 const uint8_t startingSchedule = currentSchedule;
277 bool vtxUpdatePending = false;
278 do {
279 switch (currentSchedule) {
280 case VTX_PARAM_POWER:
281 vtxUpdatePending = vtxProcessPower(vtxDevice);
282 break;
283 case VTX_PARAM_BANDCHAN:
284 if (vtxGetSettings().band) {
285 vtxUpdatePending = vtxProcessBandAndChannel(vtxDevice);
286 #if defined(VTX_SETTINGS_FREQCMD)
287 } else {
288 vtxUpdatePending = vtxProcessFrequency(vtxDevice);
289 #endif
291 break;
292 case VTX_PARAM_PITMODE:
293 vtxUpdatePending = vtxProcessPitMode(vtxDevice);
294 break;
295 case VTX_PARAM_CONFIRM:
296 vtxUpdatePending = vtxProcessStateUpdate(vtxDevice);
297 break;
298 default:
299 break;
301 currentSchedule = (currentSchedule + 1) % VTX_PARAM_COUNT;
302 } while (!vtxUpdatePending && currentSchedule != startingSchedule);
304 if (!ARMING_FLAG(ARMED) || vtxUpdatePending) {
305 vtxCommonProcess(vtxDevice, currentTimeUs);
310 #endif