Add Winbond W25Q512J support (#14036)
[betaflight.git] / src / main / io / vtx_control.c
blob45a63d67289e12adce6a2ba80d64d3bdd2ecba5e
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"
50 PG_REGISTER_WITH_RESET_TEMPLATE(vtxConfig_t, vtxConfig, PG_VTX_CONFIG, 1);
52 PG_RESET_TEMPLATE(vtxConfig_t, vtxConfig,
53 // .vtxChannelActivationConditions = { 0 },
54 .halfDuplex = true
57 static uint8_t locked = 0;
59 void vtxControlInit(void)
61 // NOTHING TO DO
64 void vtxControlInputPoll(void)
66 // Check variuos input sources for VTX config updates
67 #if defined(USE_SPEKTRUM_VTX_CONTROL)
68 // Get VTX updates
69 spektrumVtxControl();
70 #endif
73 static void vtxUpdateBandAndChannel(uint8_t bandStep, uint8_t channelStep)
75 if (ARMING_FLAG(ARMED)) {
76 locked = 1;
79 if (!locked && vtxCommonDevice()) {
80 vtxSettingsConfigMutable()->band += bandStep;
81 vtxSettingsConfigMutable()->channel += channelStep;
85 void vtxIncrementBand(void)
87 vtxUpdateBandAndChannel(+1, 0);
90 void vtxDecrementBand(void)
92 vtxUpdateBandAndChannel(-1, 0);
95 void vtxIncrementChannel(void)
97 vtxUpdateBandAndChannel(0, +1);
100 void vtxDecrementChannel(void)
102 vtxUpdateBandAndChannel(0, -1);
105 void vtxUpdateActivatedChannel(void)
107 if (ARMING_FLAG(ARMED)) {
108 locked = 1;
111 if (vtxCommonDevice()) {
112 static uint8_t lastIndex = -1;
114 for (uint8_t index = 0; index < MAX_CHANNEL_ACTIVATION_CONDITION_COUNT; index++) {
115 const vtxChannelActivationCondition_t *vtxChannelActivationCondition = &vtxConfig()->vtxChannelActivationConditions[index];
117 if (isRangeActive(vtxChannelActivationCondition->auxChannelIndex, &vtxChannelActivationCondition->range)
118 && index != lastIndex) {
119 lastIndex = index;
121 if (!locked) {
122 if (vtxChannelActivationCondition->band > 0) {
123 vtxSettingsConfigMutable()->band = vtxChannelActivationCondition->band;
125 if (vtxChannelActivationCondition->channel > 0) {
126 vtxSettingsConfigMutable()->channel = vtxChannelActivationCondition->channel;
130 if (vtxChannelActivationCondition->power > 0) {
131 vtxSettingsConfigMutable()->power = vtxChannelActivationCondition->power;
133 break;
139 void vtxCycleBandOrChannel(const uint8_t bandStep, const uint8_t channelStep)
141 const vtxDevice_t *vtxDevice = vtxCommonDevice();
142 if (vtxDevice) {
143 uint8_t band = 0, channel = 0;
145 const bool haveAllNeededInfo = vtxCommonGetBandAndChannel(vtxDevice, &band, &channel);
146 if (!haveAllNeededInfo) {
147 return;
150 int newChannel = channel + channelStep;
151 if (newChannel > vtxTableChannelCount) {
152 newChannel = 1;
153 } else if (newChannel < 1) {
154 newChannel = vtxTableChannelCount;
157 int newBand = band + bandStep;
158 if (newBand > vtxTableBandCount) {
159 newBand = 1;
160 } else if (newBand < 1) {
161 newBand = vtxTableBandCount;
164 vtxSettingsConfigMutable()->band = newBand;
165 vtxSettingsConfigMutable()->channel = newChannel;
169 void vtxCyclePower(const uint8_t powerStep)
171 const vtxDevice_t *vtxDevice = vtxCommonDevice();
172 if (vtxDevice) {
173 uint8_t power = 0;
174 const bool haveAllNeededInfo = vtxCommonGetPowerIndex(vtxDevice, &power);
175 if (!haveAllNeededInfo) {
176 return;
179 int newPower = power + powerStep;
180 if (newPower >= vtxTablePowerLevels) {
181 newPower = 1;
182 } else if (newPower < 0) {
183 newPower = vtxTablePowerLevels;
186 vtxSettingsConfigMutable()->power = newPower;
191 * Allow VTX channel/band/rf power/on-off and save via a single button.
193 * The LED1 flashes a set number of times, followed by a short pause, one per second. The amount of flashes decreases over time while
194 * the button is held to indicate the action that will be performed upon release.
195 * The actions are ordered by most-frequently used action. i.e. you change channel more frequently than band.
197 * The vtx settings can be changed while the VTX is OFF.
198 * If the VTX is OFF when the settings are saved the VTX will be OFF on the next boot, likewise
199 * If the VTX is ON when the settings are saved the VTX will be ON on the next boot.
201 * 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
202 * behaviour of the LED1 here.
204 * Future: Blink out the state after changing it.
206 void handleVTXControlButton(void)
208 #if defined(USE_VTX_RTC6705) && defined(BUTTON_A_PIN)
209 bool buttonWasPressed = false;
210 const timeMs_t start = millis();
211 timeMs_t ledToggleAt = start;
212 bool ledEnabled = false;
213 uint8_t flashesDone = 0;
215 uint8_t actionCounter = 0;
216 bool buttonHeld;
217 while ((buttonHeld = buttonAPressed())) {
218 const timeMs_t end = millis();
220 int32_t diff = cmp32(end, start);
221 if (diff > 25 && diff <= 1000) {
222 actionCounter = 4;
223 } else if (diff > 1000 && diff <= 3000) {
224 actionCounter = 3;
225 } else if (diff > 3000 && diff <= 5000) {
226 actionCounter = 2;
227 } else if (diff > 5000) {
228 actionCounter = 1;
231 if (actionCounter) {
233 diff = cmp32(ledToggleAt, end);
235 if (diff < 0) {
236 ledEnabled = !ledEnabled;
238 const uint8_t updateDuration = 60;
240 ledToggleAt = end + updateDuration;
242 if (ledEnabled) {
243 LED1_ON;
244 } else {
245 LED1_OFF;
246 flashesDone++;
249 if (flashesDone == actionCounter) {
250 ledToggleAt += (1000 - ((flashesDone * updateDuration) * 2));
251 flashesDone = 0;
254 buttonWasPressed = true;
258 if (!buttonWasPressed) {
259 return;
262 LED1_OFF;
264 switch (actionCounter) {
265 case 4:
266 vtxCycleBandOrChannel(0, +1);
267 break;
268 case 3:
269 vtxCycleBandOrChannel(+1, 0);
270 break;
271 case 2:
272 vtxCyclePower(+1);
273 break;
274 case 1:
275 saveConfigAndNotify();
276 break;
278 #endif
281 #endif