Merge pull request #11198 from SteveCEvans/sce_rc2
[betaflight.git] / src / main / io / vtx_control.c
blob8f7b74d1eb5657677537765248c75b15da40f45b
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 <stdbool.h>
22 #include <stdint.h>
23 #include <drivers/vtx_table.h>
25 #include "platform.h"
27 #if defined(USE_VTX_CONTROL) && defined(USE_VTX_COMMON)
29 #include "common/maths.h"
31 #include "config/config_eeprom.h"
33 #include "drivers/buttons.h"
34 #include "drivers/light_led.h"
35 #include "drivers/time.h"
36 #include "drivers/vtx_common.h"
38 #include "config/config.h"
39 #include "fc/runtime_config.h"
41 #include "io/spektrum_vtx_control.h"
42 #include "io/vtx.h"
43 #include "io/vtx_control.h"
45 #include "osd/osd.h"
47 #include "pg/pg.h"
48 #include "pg/pg_ids.h"
51 PG_REGISTER_WITH_RESET_TEMPLATE(vtxConfig_t, vtxConfig, PG_VTX_CONFIG, 1);
53 PG_RESET_TEMPLATE(vtxConfig_t, vtxConfig,
54 // .vtxChannelActivationConditions = { 0 },
55 .halfDuplex = true
58 static uint8_t locked = 0;
61 void vtxControlInit(void)
63 // NOTHING TO DO
66 void vtxControlInputPoll(void)
68 // Check variuos input sources for VTX config updates
69 #if defined(USE_SPEKTRUM_VTX_CONTROL)
70 // Get VTX updates
71 spektrumVtxControl();
72 #endif
75 static void vtxUpdateBandAndChannel(uint8_t bandStep, uint8_t channelStep)
77 if (ARMING_FLAG(ARMED)) {
78 locked = 1;
81 if (!locked && vtxCommonDevice()) {
82 vtxSettingsConfigMutable()->band += bandStep;
83 vtxSettingsConfigMutable()->channel += channelStep;
87 void vtxIncrementBand(void)
89 vtxUpdateBandAndChannel(+1, 0);
92 void vtxDecrementBand(void)
94 vtxUpdateBandAndChannel(-1, 0);
97 void vtxIncrementChannel(void)
99 vtxUpdateBandAndChannel(0, +1);
102 void vtxDecrementChannel(void)
104 vtxUpdateBandAndChannel(0, -1);
107 void vtxUpdateActivatedChannel(void)
109 if (ARMING_FLAG(ARMED)) {
110 locked = 1;
113 if (vtxCommonDevice()) {
114 static uint8_t lastIndex = -1;
116 for (uint8_t index = 0; index < MAX_CHANNEL_ACTIVATION_CONDITION_COUNT; index++) {
117 const vtxChannelActivationCondition_t *vtxChannelActivationCondition = &vtxConfig()->vtxChannelActivationConditions[index];
119 if (isRangeActive(vtxChannelActivationCondition->auxChannelIndex, &vtxChannelActivationCondition->range)
120 && index != lastIndex) {
121 lastIndex = index;
123 if (!locked) {
124 if (vtxChannelActivationCondition->band > 0) {
125 vtxSettingsConfigMutable()->band = vtxChannelActivationCondition->band;
127 if (vtxChannelActivationCondition->channel > 0) {
128 vtxSettingsConfigMutable()->channel = vtxChannelActivationCondition->channel;
132 if (vtxChannelActivationCondition->power > 0) {
133 vtxSettingsConfigMutable()->power = vtxChannelActivationCondition->power;
135 break;
141 void vtxCycleBandOrChannel(const uint8_t bandStep, const uint8_t channelStep)
143 const vtxDevice_t *vtxDevice = vtxCommonDevice();
144 if (vtxDevice) {
145 uint8_t band = 0, channel = 0;
147 const bool haveAllNeededInfo = vtxCommonGetBandAndChannel(vtxDevice, &band, &channel);
148 if (!haveAllNeededInfo) {
149 return;
152 int newChannel = channel + channelStep;
153 if (newChannel > vtxTableChannelCount) {
154 newChannel = 1;
155 } else if (newChannel < 1) {
156 newChannel = vtxTableChannelCount;
159 int newBand = band + bandStep;
160 if (newBand > vtxTableBandCount) {
161 newBand = 1;
162 } else if (newBand < 1) {
163 newBand = vtxTableBandCount;
166 vtxSettingsConfigMutable()->band = newBand;
167 vtxSettingsConfigMutable()->channel = newChannel;
171 void vtxCyclePower(const uint8_t powerStep)
173 const vtxDevice_t *vtxDevice = vtxCommonDevice();
174 if (vtxDevice) {
175 uint8_t power = 0;
176 const bool haveAllNeededInfo = vtxCommonGetPowerIndex(vtxDevice, &power);
177 if (!haveAllNeededInfo) {
178 return;
181 int newPower = power + powerStep;
182 if (newPower >= vtxTablePowerLevels) {
183 newPower = 1;
184 } else if (newPower < 0) {
185 newPower = vtxTablePowerLevels;
188 vtxSettingsConfigMutable()->power = newPower;
193 * Allow VTX channel/band/rf power/on-off and save via a single button.
195 * The LED1 flashes a set number of times, followed by a short pause, one per second. The amount of flashes decreases over time while
196 * the button is held to indicate the action that will be performed upon release.
197 * The actions are ordered by most-frequently used action. i.e. you change channel more frequently than band.
199 * The vtx settings can be changed while the VTX is OFF.
200 * If the VTX is OFF when the settings are saved the VTX will be OFF on the next boot, likewise
201 * If the VTX is ON when the settings are saved the VTX will be ON on the next boot.
203 * Future: It would be nice to re-use the code in statusindicator.c and blink-codes but target a different LED instead of the simple timed
204 * behaviour of the LED1 here.
206 * Future: Blink out the state after changing it.
208 void handleVTXControlButton(void)
210 #if defined(USE_VTX_RTC6705) && defined(BUTTON_A_PIN)
211 bool buttonWasPressed = false;
212 const timeMs_t start = millis();
213 timeMs_t ledToggleAt = start;
214 bool ledEnabled = false;
215 uint8_t flashesDone = 0;
217 uint8_t actionCounter = 0;
218 bool buttonHeld;
219 while ((buttonHeld = buttonAPressed())) {
220 const timeMs_t end = millis();
222 int32_t diff = cmp32(end, start);
223 if (diff > 25 && diff <= 1000) {
224 actionCounter = 4;
225 } else if (diff > 1000 && diff <= 3000) {
226 actionCounter = 3;
227 } else if (diff > 3000 && diff <= 5000) {
228 actionCounter = 2;
229 } else if (diff > 5000) {
230 actionCounter = 1;
233 if (actionCounter) {
235 diff = cmp32(ledToggleAt, end);
237 if (diff < 0) {
238 ledEnabled = !ledEnabled;
240 const uint8_t updateDuration = 60;
242 ledToggleAt = end + updateDuration;
244 if (ledEnabled) {
245 LED1_ON;
246 } else {
247 LED1_OFF;
248 flashesDone++;
251 if (flashesDone == actionCounter) {
252 ledToggleAt += (1000 - ((flashesDone * updateDuration) * 2));
253 flashesDone = 0;
256 buttonWasPressed = true;
260 if (!buttonWasPressed) {
261 return;
264 LED1_OFF;
266 switch (actionCounter) {
267 case 4:
268 vtxCycleBandOrChannel(0, +1);
269 break;
270 case 3:
271 vtxCycleBandOrChannel(+1, 0);
272 break;
273 case 2:
274 vtxCyclePower(+1);
275 break;
276 case 1:
277 saveConfigAndNotify();
278 break;
280 #endif
283 #endif