dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
osd_menu.c
Go to the documentation of this file.
1 
16 /*
17  * This program is free software; you can redistribute it and/or modify
18  * it under the terms of the GNU General Public License as published by
19  * the Free Software Foundation; either version 3 of the License, or
20  * (at your option) any later version.
21  *
22  * This program is distributed in the hope that it will be useful, but
23  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25  * for more details.
26  *
27  * You should have received a copy of the GNU General Public License along
28  * with this program; if not, see <http://www.gnu.org/licenses/>
29  *
30  * Additional note on redistribution: The copyright and license notices above
31  * must be maintained in each individual source file that is a derivative work
32  * of this source file; otherwise redistribution is prohibited.
33  */
34 
35 #include "osd_utils.h"
36 #include "onscreendisplay.h"
37 
38 #ifdef OSD_USE_MENU
39 
40 #include "actuatorsettings.h"
41 #include "flightstatus.h"
42 #include "flightbatterystate.h"
43 #include "flightbatterysettings.h"
44 #include "homelocation.h"
45 #include "manualcontrolcommand.h"
46 #include "manualcontrolsettings.h"
47 #include "rgbledsettings.h"
48 #include "stabilizationsettings.h"
49 #include "stateestimation.h"
50 #include "vtxinfo.h"
51 #include "vtxsettings.h"
52 
53 // These are allocated in the VTXConfig module
54 //extern const uint16_t *BAND_5G8_A_FREQS;
55 //extern const uint16_t *BAND_5G8_B_FREQS;
56 //extern const uint16_t *BAND_5G8_E_FREQS;
57 //extern const uint16_t *AIRWAVE_FREQS;
58 //extern const uint16_t *RACEBAND_FREQS;
59 
60 static const uint16_t BAND_5G8_A_FREQS[VTXSETTINGS_BAND_5G8_A_FREQUENCY_MAXOPTVAL + 1] = {
61  [VTXSETTINGS_BAND_5G8_A_FREQUENCY_CH15865] = 5865,
62  [VTXSETTINGS_BAND_5G8_A_FREQUENCY_CH25845] = 5845,
63  [VTXSETTINGS_BAND_5G8_A_FREQUENCY_CH35825] = 5825,
64  [VTXSETTINGS_BAND_5G8_A_FREQUENCY_CH45805] = 5805,
65  [VTXSETTINGS_BAND_5G8_A_FREQUENCY_CH55785] = 5785,
66  [VTXSETTINGS_BAND_5G8_A_FREQUENCY_CH65765] = 5765,
67  [VTXSETTINGS_BAND_5G8_A_FREQUENCY_CH75745] = 5745,
68  [VTXSETTINGS_BAND_5G8_A_FREQUENCY_CH85725] = 5725
69 };
70 
71 static const uint16_t BAND_5G8_B_FREQS[VTXSETTINGS_BAND_5G8_B_FREQUENCY_MAXOPTVAL + 1] = {
72  [VTXSETTINGS_BAND_5G8_B_FREQUENCY_CH15733] = 5733,
73  [VTXSETTINGS_BAND_5G8_B_FREQUENCY_CH25752] = 5752,
74  [VTXSETTINGS_BAND_5G8_B_FREQUENCY_CH35771] = 5771,
75  [VTXSETTINGS_BAND_5G8_B_FREQUENCY_CH45790] = 5790,
76  [VTXSETTINGS_BAND_5G8_B_FREQUENCY_CH55809] = 5809,
77  [VTXSETTINGS_BAND_5G8_B_FREQUENCY_CH65828] = 5828,
78  [VTXSETTINGS_BAND_5G8_B_FREQUENCY_CH75847] = 5847,
79  [VTXSETTINGS_BAND_5G8_B_FREQUENCY_CH85866] = 5866
80 };
81 
82 static const uint16_t BAND_5G8_E_FREQS[VTXSETTINGS_BAND_5G8_E_FREQUENCY_MAXOPTVAL + 1] = {
83  [VTXSETTINGS_BAND_5G8_E_FREQUENCY_CH15705] = 5705,
84  [VTXSETTINGS_BAND_5G8_E_FREQUENCY_CH25685] = 5685,
85  [VTXSETTINGS_BAND_5G8_E_FREQUENCY_CH35665] = 5665,
86  [VTXSETTINGS_BAND_5G8_E_FREQUENCY_CH45645] = 5645,
87  [VTXSETTINGS_BAND_5G8_E_FREQUENCY_CH55885] = 5885,
88  [VTXSETTINGS_BAND_5G8_E_FREQUENCY_CH65905] = 5905,
89  [VTXSETTINGS_BAND_5G8_E_FREQUENCY_CH75925] = 5925,
90  [VTXSETTINGS_BAND_5G8_E_FREQUENCY_CH85945] = 5945
91 };
92 
93 static const uint16_t AIRWAVE_FREQS[VTXSETTINGS_AIRWAVE_FREQUENCY_MAXOPTVAL + 1] = {
94  [VTXSETTINGS_AIRWAVE_FREQUENCY_CH15740] = 5740,
95  [VTXSETTINGS_AIRWAVE_FREQUENCY_CH25760] = 5760,
96  [VTXSETTINGS_AIRWAVE_FREQUENCY_CH35780] = 5780,
97  [VTXSETTINGS_AIRWAVE_FREQUENCY_CH45800] = 5800,
98  [VTXSETTINGS_AIRWAVE_FREQUENCY_CH55820] = 5820,
99  [VTXSETTINGS_AIRWAVE_FREQUENCY_CH65840] = 5840,
100  [VTXSETTINGS_AIRWAVE_FREQUENCY_CH75860] = 5860,
101  [VTXSETTINGS_AIRWAVE_FREQUENCY_CH85880] = 5880
102 };
103 
104 static const uint16_t RACEBAND_FREQS[VTXSETTINGS_RACEBAND_FREQUENCY_MAXOPTVAL + 1] = {
105  [VTXSETTINGS_RACEBAND_FREQUENCY_CH15658] = 5658,
106  [VTXSETTINGS_RACEBAND_FREQUENCY_CH25695] = 5695,
107  [VTXSETTINGS_RACEBAND_FREQUENCY_CH35732] = 5732,
108  [VTXSETTINGS_RACEBAND_FREQUENCY_CH45769] = 5769,
109  [VTXSETTINGS_RACEBAND_FREQUENCY_CH55806] = 5806,
110  [VTXSETTINGS_RACEBAND_FREQUENCY_CH65843] = 5843,
111  [VTXSETTINGS_RACEBAND_FREQUENCY_CH75880] = 5880,
112  [VTXSETTINGS_RACEBAND_FREQUENCY_CH85917] = 5917
113 };
114 
115 static const uint16_t VTX_POWER[VTXSETTINGS_POWER_GLOBAL_MAXOPTVAL + 1] = {
116  [VTXSETTINGS_POWER_25] = 25,
117  [VTXSETTINGS_POWER_200] = 200,
118  [VTXSETTINGS_POWER_500] = 500,
119  [VTXSETTINGS_POWER_800] = 800,
120 };
121 
122 // Events that can be be injected into the FSM and trigger state changes
123 enum menu_fsm_event {
125  FSM_EVENT_UP,
126  FSM_EVENT_DOWN,
127  FSM_EVENT_LEFT,
128  FSM_EVENT_RIGHT,
130 };
131 
132 // FSM States
133 enum menu_fsm_state {
135 /*------------------------------------------------------------------------------------------*/
136 #if defined(USE_STM32F4xx_BRAINFPVRE1)
137  FSM_STATE_MAIN_RE1,
138 #endif
139  FSM_STATE_MAIN_RGBLEDS,
140  FSM_STATE_MAIN_FILTER,
141  FSM_STATE_MAIN_FMODE,
142  FSM_STATE_MAIN_HOMELOC,
143  FSM_STATE_MAIN_PIDRATE,
144  FSM_STATE_MAIN_PIDATT,
145  FSM_STATE_MAIN_STICKLIMITS,
146  FSM_STATE_MAIN_VTX,
147  FSM_STATE_MAIN_STATS,
148  FSM_STATE_MAIN_BATTERY,
149 /*------------------------------------------------------------------------------------------*/
150 #if defined(USE_STM32F4xx_BRAINFPVRE1)
151  FSM_STATE_RE1_IR_PROTOCOL,
152  FSM_STATE_RE1_IR_IDILAP,
153  FSM_STATE_RE1_IR_IDTRACKMATE,
154  FSM_STATE_RE1_SAVEEXIT,
155  FSM_STATE_RE1_EXIT,
156 #endif
157 /*------------------------------------------------------------------------------------------*/
158  FSM_STATE_RGB_DEFAULTCOLOR,
159  FSM_STATE_RGB_RANGECOLOR_BASE,
160  FSM_STATE_RGB_RANGECOLOR_END,
161  FSM_STATE_RGB_SAVEEXIT,
162  FSM_STATE_RGB_EXIT,
163 /*------------------------------------------------------------------------------------------*/
164  FSM_STATE_FILTER_ATT,
165  FSM_STATE_FILTER_NAV,
166  FSM_STATE_FILTER_SAVEEXIT,
167  FSM_STATE_FILTER_EXIT,
168 /*------------------------------------------------------------------------------------------*/
169  FSM_STATE_FMODE_1,
170  FSM_STATE_FMODE_2,
171  FSM_STATE_FMODE_3,
172  FSM_STATE_FMODE_4,
173  FSM_STATE_FMODE_5,
174  FSM_STATE_FMODE_6,
175  FSM_STATE_FMODE_SAVEEXIT,
176  FSM_STATE_FMODE_EXIT,
177 /*------------------------------------------------------------------------------------------*/
178  FSM_STATE_HOMELOC_SET,
179  FSM_STATE_HOMELOC_EXIT,
180 /*------------------------------------------------------------------------------------------*/
181  FSM_STATE_PIDRATE_ROLLP,
182  FSM_STATE_PIDRATE_ROLLI,
183  FSM_STATE_PIDRATE_ROLLD,
184  FSM_STATE_PIDRATE_ROLLILIMIT,
185  FSM_STATE_PIDRATE_PITCHP,
186  FSM_STATE_PIDRATE_PITCHI,
187  FSM_STATE_PIDRATE_PITCHD,
188  FSM_STATE_PIDRATE_PITCHILIMIT,
189  FSM_STATE_PIDRATE_YAWP,
190  FSM_STATE_PIDRATE_YAWI,
191  FSM_STATE_PIDRATE_YAWD,
192  FSM_STATE_PIDRATE_YAWILIMIT,
193  FSM_STATE_PIDRATE_SAVEEXIT,
194  FSM_STATE_PIDRATE_EXIT,
195 /*------------------------------------------------------------------------------------------*/
196  FSM_STATE_PIDATT_ROLLP,
197  FSM_STATE_PIDATT_ROLLI,
198  FSM_STATE_PIDATT_ROLLILIMIT,
199  FSM_STATE_PIDATT_PITCHP,
200  FSM_STATE_PIDATT_PITCHI,
201  FSM_STATE_PIDATT_PITCHILIMIT,
202  FSM_STATE_PIDATT_YAWP,
203  FSM_STATE_PIDATT_YAWI,
204  FSM_STATE_PIDATT_YAWILIMIT,
205  FSM_STATE_PIDATT_SAVEEXIT,
206  FSM_STATE_PIDATT_EXIT,
207 /*------------------------------------------------------------------------------------------*/
208  FSM_STATE_STICKLIMITS_ROLLA,
209  FSM_STATE_STICKLIMITS_PITCHA,
210  FSM_STATE_STICKLIMITS_YAWA,
211  FSM_STATE_STICKLIMITS_ROLLR,
212  FSM_STATE_STICKLIMITS_PITCHR,
213  FSM_STATE_STICKLIMITS_YAWR,
214  FSM_STATE_STICKLIMITS_ROLLEXR,
215  FSM_STATE_STICKLIMITS_PITCHEXR,
216  FSM_STATE_STICKLIMITS_YAWEXR,
217  FSM_STATE_STICKLIMITS_ROLLEXH,
218  FSM_STATE_STICKLIMITS_PITCHEXH,
219  FSM_STATE_STICKLIMITS_YAWEXH,
220  FSM_STATE_STICKLIMITS_MOTORPOWER,
221  FSM_STATE_STICKLIMITS_CAMERATILT,
222  FSM_STATE_STICKLIMITS_SAVEEXIT,
223  FSM_STATE_STICKLIMITS_EXIT,
224 /*------------------------------------------------------------------------------------------*/
225  FSM_STATE_VTX_BAND,
226  FSM_STATE_VTX_CH,
227  FSM_STATE_VTX_POWER,
228  FSM_STATE_VTX_APPLY,
229  FSM_STATE_VTX_SAVEEXIT,
230  FSM_STATE_VTX_EXIT,
231 /*------------------------------------------------------------------------------------------*/
232  FSM_STATE_STATS_EXIT,
233 /*------------------------------------------------------------------------------------------*/
234  FSM_STATE_BATTERY_CAPACITY,
235  FSM_STATE_BATTERY_CELLCOUNT,
236  FSM_STATE_BATTERY_WARNING,
237  FSM_STATE_BATTERY_ALARM,
238  FSM_STATE_BATTERY_WARN_TIME,
239  FSM_STATE_BATTERY_ALARM_TIME,
240  FSM_STATE_BATTERY_SAVEEXIT,
241  FSM_STATE_BATTERY_EXIT,
242 /*------------------------------------------------------------------------------------------*/
243 
245 };
246 
247 #if defined(USE_STM32F4xx_BRAINFPVRE1)
248  static void brainre1_menu(void);
249 #define FSM_STATE_TOP FSM_STATE_MAIN_RE1
250 #else
251 #define FSM_STATE_TOP FSM_STATE_MAIN_RGBLEDS
252 #endif /* defined(USE_STM32F4xx_BRAINFPVRE1) */
253 
254 // Structure for the FSM
255 struct menu_fsm_transition {
256  void (*menu_fn)();
257  enum menu_fsm_state next_state[FSM_EVENT_NUM_EVENTS];
258 };
259 
260 extern uint16_t frame_counter;
261 static enum menu_fsm_state current_state = FSM_STATE_TOP;
262 static enum menu_fsm_event current_event = FSM_EVENT_AUTO;
263 static bool held_long;
264 
265 
266 static void main_menu(void);
267 static void rgbled_menu(void);
268 static void filter_menu(void);
269 static void flightmode_menu(void);
270 static void homeloc_menu(void);
271 static void pidrate_menu(void);
272 static void pidatt_menu(void);
273 static void sticklimits_menu(void);
274 static void vtx_menu();
275 static void stats_menu(void);
276 static void battery_menu(void);
277 
278 
279 
280 // The Menu FSM
281 const static struct menu_fsm_transition menu_fsm[FSM_STATE_NUM_STATES] = {
282 #if defined(USE_STM32F4xx_BRAINFPVRE1)
283  [FSM_STATE_MAIN_RE1] = {
284  .menu_fn = main_menu,
285  .next_state = {
286  [FSM_EVENT_UP] = FSM_STATE_MAIN_BATTERY,
287  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_RGBLEDS,
288  [FSM_EVENT_RIGHT] = FSM_STATE_RE1_IR_PROTOCOL,
289  },
290  },
291 #endif
292  [FSM_STATE_MAIN_RGBLEDS] = {
293  .menu_fn = main_menu,
294  .next_state = {
295  #if defined(USE_STM32F4xx_BRAINFPVRE1)
296  [FSM_EVENT_UP] = FSM_STATE_MAIN_RE1,
297  #else
298  [FSM_EVENT_UP] = FSM_STATE_MAIN_BATTERY,
299  #endif
300  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_FILTER,
301  [FSM_EVENT_RIGHT] = FSM_STATE_RGB_DEFAULTCOLOR,
302  },
303  },
304  [FSM_STATE_MAIN_FILTER] = {
305  .menu_fn = main_menu,
306  .next_state = {
307  [FSM_EVENT_UP] = FSM_STATE_MAIN_RGBLEDS,
308  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_FMODE,
309  [FSM_EVENT_RIGHT] = FSM_STATE_FILTER_ATT,
310  },
311  },
312  [FSM_STATE_MAIN_FMODE] = {
313  .menu_fn = main_menu,
314  .next_state = {
315  [FSM_EVENT_UP] = FSM_STATE_MAIN_FILTER,
316  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_HOMELOC,
317  [FSM_EVENT_RIGHT] = FSM_STATE_FMODE_1,
318  },
319  },
320  [FSM_STATE_MAIN_HOMELOC] = {
321  .menu_fn = main_menu,
322  .next_state = {
323  [FSM_EVENT_UP] = FSM_STATE_MAIN_FMODE,
324  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_PIDRATE,
325  [FSM_EVENT_RIGHT] = FSM_STATE_HOMELOC_SET,
326  },
327  },
328  [FSM_STATE_MAIN_PIDRATE] = {
329  .menu_fn = main_menu,
330  .next_state = {
331  [FSM_EVENT_UP] = FSM_STATE_MAIN_HOMELOC,
332  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_PIDATT,
333  [FSM_EVENT_RIGHT] = FSM_STATE_PIDRATE_ROLLP,
334  },
335  },
336  [FSM_STATE_MAIN_PIDATT] = {
337  .menu_fn = main_menu,
338  .next_state = {
339  [FSM_EVENT_UP] = FSM_STATE_MAIN_PIDRATE,
340  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_STICKLIMITS,
341  [FSM_EVENT_RIGHT] = FSM_STATE_PIDATT_ROLLP,
342  },
343  },
344  [FSM_STATE_MAIN_STICKLIMITS] = {
345  .menu_fn = main_menu,
346  .next_state = {
347  [FSM_EVENT_UP] = FSM_STATE_MAIN_PIDATT,
348  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_VTX,
349  [FSM_EVENT_RIGHT] = FSM_STATE_STICKLIMITS_ROLLA,
350  },
351  },
352  [FSM_STATE_MAIN_VTX] = {
353  .menu_fn = main_menu,
354  .next_state = {
355  [FSM_EVENT_UP] = FSM_STATE_MAIN_STICKLIMITS,
356  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_STATS,
357  [FSM_EVENT_RIGHT] = FSM_STATE_VTX_BAND,
358  },
359  },
360  [FSM_STATE_MAIN_STATS] = {
361  .menu_fn = main_menu,
362  .next_state = {
363  [FSM_EVENT_UP] = FSM_STATE_MAIN_VTX,
364  [FSM_EVENT_DOWN] = FSM_STATE_MAIN_BATTERY,
365  [FSM_EVENT_RIGHT] = FSM_STATE_STATS_EXIT,
366  },
367  },
368  [FSM_STATE_MAIN_BATTERY] = {
369  .menu_fn = main_menu,
370  .next_state = {
371  [FSM_EVENT_UP] = FSM_STATE_MAIN_STATS,
372  [FSM_EVENT_DOWN] = FSM_STATE_TOP,
373  [FSM_EVENT_RIGHT] = FSM_STATE_BATTERY_CAPACITY,
374  },
375  },
376 /*------------------------------------------------------------------------------------------*/
377 #if defined(USE_STM32F4xx_BRAINFPVRE1)
378  [FSM_STATE_RE1_IR_PROTOCOL] = {
379  .menu_fn = brainre1_menu,
380  .next_state = {
381  [FSM_EVENT_UP] = FSM_STATE_RE1_EXIT,
382  [FSM_EVENT_DOWN] = FSM_STATE_RE1_IR_IDILAP,
383  },
384  },
385  [FSM_STATE_RE1_IR_IDILAP] = {
386  .menu_fn = brainre1_menu,
387  .next_state = {
388  [FSM_EVENT_UP] = FSM_STATE_RE1_IR_PROTOCOL,
389  [FSM_EVENT_DOWN] = FSM_STATE_RE1_IR_IDTRACKMATE,
390  },
391  },
392  [FSM_STATE_RE1_IR_IDTRACKMATE] = {
393  .menu_fn = brainre1_menu,
394  .next_state = {
395  [FSM_EVENT_UP] = FSM_STATE_RE1_IR_IDILAP,
396  [FSM_EVENT_DOWN] = FSM_STATE_RE1_SAVEEXIT,
397  },
398  },
399  [FSM_STATE_RE1_SAVEEXIT] = {
400  .menu_fn = brainre1_menu,
401  .next_state = {
402  [FSM_EVENT_UP] = FSM_STATE_RE1_IR_IDTRACKMATE,
403  [FSM_EVENT_DOWN] = FSM_STATE_RE1_EXIT,
404  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_RE1,
405  },
406  },
407  [FSM_STATE_RE1_EXIT] = {
408  .menu_fn = brainre1_menu,
409  .next_state = {
410  [FSM_EVENT_UP] = FSM_STATE_RE1_SAVEEXIT,
411  [FSM_EVENT_DOWN] = FSM_STATE_RE1_IR_PROTOCOL,
412  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_RE1,
413  },
414  },
415 #endif /* defined(USE_STM32F4xx_BRAINFPVRE1) */
416 /*------------------------------------------------------------------------------------------*/
417  [FSM_STATE_RGB_DEFAULTCOLOR] = {
418  .menu_fn = rgbled_menu,
419  .next_state = {
420  [FSM_EVENT_UP] = FSM_STATE_RGB_EXIT,
421  [FSM_EVENT_DOWN] = FSM_STATE_RGB_RANGECOLOR_BASE,
422  },
423  },
424  [FSM_STATE_RGB_RANGECOLOR_BASE] = {
425  .menu_fn = rgbled_menu,
426  .next_state = {
427  [FSM_EVENT_UP] = FSM_STATE_RGB_DEFAULTCOLOR,
428  [FSM_EVENT_DOWN] = FSM_STATE_RGB_RANGECOLOR_END,
429  },
430  },
431  [FSM_STATE_RGB_RANGECOLOR_END] = {
432  .menu_fn = rgbled_menu,
433  .next_state = {
434  [FSM_EVENT_UP] = FSM_STATE_RGB_RANGECOLOR_BASE,
435  [FSM_EVENT_DOWN] = FSM_STATE_RGB_SAVEEXIT,
436  },
437  },
438  [FSM_STATE_RGB_SAVEEXIT] = {
439  .menu_fn = rgbled_menu,
440  .next_state = {
441  [FSM_EVENT_UP] = FSM_STATE_RGB_RANGECOLOR_END,
442  [FSM_EVENT_DOWN] = FSM_STATE_RGB_EXIT,
443  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_RGBLEDS,
444  },
445  },
446  [FSM_STATE_RGB_EXIT] = {
447  .menu_fn = rgbled_menu,
448  .next_state = {
449  [FSM_EVENT_UP] = FSM_STATE_RGB_SAVEEXIT,
450  [FSM_EVENT_DOWN] = FSM_STATE_RGB_DEFAULTCOLOR,
451  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_RGBLEDS,
452  },
453  },
454 /*------------------------------------------------------------------------------------------*/
455  [FSM_STATE_FILTER_ATT] = {
456  .menu_fn = filter_menu,
457  .next_state = {
458  [FSM_EVENT_UP] = FSM_STATE_FILTER_EXIT,
459  [FSM_EVENT_DOWN] = FSM_STATE_FILTER_NAV,
460  },
461  },
462  [FSM_STATE_FILTER_NAV] = {
463  .menu_fn = filter_menu,
464  .next_state = {
465  [FSM_EVENT_UP] = FSM_STATE_FILTER_ATT,
466  [FSM_EVENT_DOWN] = FSM_STATE_FILTER_SAVEEXIT,
467  },
468  },
469  [FSM_STATE_FILTER_SAVEEXIT] = {
470  .menu_fn = filter_menu,
471  .next_state = {
472  [FSM_EVENT_UP] = FSM_STATE_FILTER_NAV,
473  [FSM_EVENT_DOWN] = FSM_STATE_FILTER_EXIT,
474  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_FILTER,
475  },
476  },
477  [FSM_STATE_FILTER_EXIT] = {
478  .menu_fn = filter_menu,
479  .next_state = {
480  [FSM_EVENT_UP] = FSM_STATE_FILTER_SAVEEXIT,
481  [FSM_EVENT_DOWN] = FSM_STATE_FILTER_ATT,
482  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_FILTER,
483  },
484  },
485 /*------------------------------------------------------------------------------------------*/
486  [FSM_STATE_FMODE_1] = {
487  .menu_fn = flightmode_menu,
488  .next_state = {
489  [FSM_EVENT_UP] = FSM_STATE_FMODE_SAVEEXIT,
490  [FSM_EVENT_DOWN] = FSM_STATE_FMODE_2,
491  },
492  },
493  [FSM_STATE_FMODE_2] = {
494  .menu_fn = flightmode_menu,
495  .next_state = {
496  [FSM_EVENT_UP] = FSM_STATE_FMODE_1,
497  [FSM_EVENT_DOWN] = FSM_STATE_FMODE_3,
498  },
499  },
500  [FSM_STATE_FMODE_3] = {
501  .menu_fn = flightmode_menu,
502  .next_state = {
503  [FSM_EVENT_UP] = FSM_STATE_FMODE_2,
504  [FSM_EVENT_DOWN] = FSM_STATE_FMODE_4,
505  },
506  },
507  [FSM_STATE_FMODE_4] = {
508  .menu_fn = flightmode_menu,
509  .next_state = {
510  [FSM_EVENT_UP] = FSM_STATE_FMODE_3,
511  [FSM_EVENT_DOWN] = FSM_STATE_FMODE_5,
512  },
513  },
514  [FSM_STATE_FMODE_5] = {
515  .menu_fn = flightmode_menu,
516  .next_state = {
517  [FSM_EVENT_UP] = FSM_STATE_FMODE_4,
518  [FSM_EVENT_DOWN] = FSM_STATE_FMODE_6,
519  },
520  },
521  [FSM_STATE_FMODE_6] = {
522  .menu_fn = flightmode_menu,
523  .next_state = {
524  [FSM_EVENT_UP] = FSM_STATE_FMODE_5,
525  [FSM_EVENT_DOWN] = FSM_STATE_FMODE_SAVEEXIT,
526  },
527  },
528  [FSM_STATE_FMODE_SAVEEXIT] = {
529  .menu_fn = flightmode_menu,
530  .next_state = {
531  [FSM_EVENT_UP] = FSM_STATE_FMODE_6,
532  [FSM_EVENT_DOWN] = FSM_STATE_FMODE_EXIT,
533  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_FMODE,
534  },
535  },
536  [FSM_STATE_FMODE_EXIT] = {
537  .menu_fn = flightmode_menu,
538  .next_state = {
539  [FSM_EVENT_UP] = FSM_STATE_FMODE_SAVEEXIT,
540  [FSM_EVENT_DOWN] = FSM_STATE_FMODE_1,
541  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_FMODE,
542  },
543  },
544 /*------------------------------------------------------------------------------------------*/
545  [FSM_STATE_HOMELOC_SET] = {
546  .menu_fn = homeloc_menu,
547  .next_state = {
548  [FSM_EVENT_UP] = FSM_STATE_HOMELOC_EXIT,
549  [FSM_EVENT_DOWN] = FSM_STATE_HOMELOC_EXIT,
550  },
551  },
552  [FSM_STATE_HOMELOC_EXIT] = {
553  .menu_fn = homeloc_menu,
554  .next_state = {
555  [FSM_EVENT_UP] = FSM_STATE_HOMELOC_SET,
556  [FSM_EVENT_DOWN] = FSM_STATE_HOMELOC_SET,
557  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_HOMELOC,
558  },
559  },
560 /*------------------------------------------------------------------------------------------*/
561  [FSM_STATE_PIDRATE_ROLLP] = {
562  .menu_fn = pidrate_menu,
563  .next_state = {
564  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_EXIT,
565  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_ROLLI,
566  },
567  },
568  [FSM_STATE_PIDRATE_ROLLI] = {
569  .menu_fn = pidrate_menu,
570  .next_state = {
571  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_ROLLP,
572  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_ROLLD,
573  },
574  },
575  [FSM_STATE_PIDRATE_ROLLD] = {
576  .menu_fn = pidrate_menu,
577  .next_state = {
578  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_ROLLI,
579  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_ROLLILIMIT,
580  },
581  },
582  [FSM_STATE_PIDRATE_ROLLILIMIT] = {
583  .menu_fn = pidrate_menu,
584  .next_state = {
585  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_ROLLD,
586  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_PITCHP,
587  },
588  },
589  [FSM_STATE_PIDRATE_PITCHP] = {
590  .menu_fn = pidrate_menu,
591  .next_state = {
592  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_ROLLD,
593  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_PITCHI,
594  },
595  },
596  [FSM_STATE_PIDRATE_PITCHI] = {
597  .menu_fn = pidrate_menu,
598  .next_state = {
599  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_PITCHP,
600  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_PITCHD,
601  },
602  },
603  [FSM_STATE_PIDRATE_PITCHD] = {
604  .menu_fn = pidrate_menu,
605  .next_state = {
606  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_PITCHI,
607  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_PITCHILIMIT,
608  },
609  },
610  [FSM_STATE_PIDRATE_PITCHILIMIT] = {
611  .menu_fn = pidrate_menu,
612  .next_state = {
613  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_PITCHD,
614  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_YAWP,
615  },
616  },
617  [FSM_STATE_PIDRATE_YAWP] = {
618  .menu_fn = pidrate_menu,
619  .next_state = {
620  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_PITCHD,
621  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_YAWI,
622  },
623  },
624  [FSM_STATE_PIDRATE_YAWI] = {
625  .menu_fn = pidrate_menu,
626  .next_state = {
627  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_YAWP,
628  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_YAWD,
629  },
630  },
631  [FSM_STATE_PIDRATE_YAWD] = {
632  .menu_fn = pidrate_menu,
633  .next_state = {
634  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_YAWI,
635  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_YAWILIMIT,
636  },
637  },
638  [FSM_STATE_PIDRATE_YAWILIMIT] = {
639  .menu_fn = pidrate_menu,
640  .next_state = {
641  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_YAWD,
642  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_SAVEEXIT,
643  },
644  },
645  [FSM_STATE_PIDRATE_SAVEEXIT] = {
646  .menu_fn = pidrate_menu,
647  .next_state = {
648  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_YAWILIMIT,
649  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_EXIT,
650  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_PIDRATE,
651  },
652  },
653  [FSM_STATE_PIDRATE_EXIT] = {
654  .menu_fn = pidrate_menu,
655  .next_state = {
656  [FSM_EVENT_UP] = FSM_STATE_PIDRATE_SAVEEXIT,
657  [FSM_EVENT_DOWN] = FSM_STATE_PIDRATE_ROLLP,
658  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_PIDRATE,
659  },
660  },
661 /*------------------------------------------------------------------------------------------*/
662  [FSM_STATE_PIDATT_ROLLP] = {
663  .menu_fn = pidatt_menu,
664  .next_state = {
665  [FSM_EVENT_UP] = FSM_STATE_PIDATT_EXIT,
666  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_ROLLI,
667  },
668  },
669  [FSM_STATE_PIDATT_ROLLI] = {
670  .menu_fn = pidatt_menu,
671  .next_state = {
672  [FSM_EVENT_UP] = FSM_STATE_PIDATT_ROLLP,
673  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_ROLLILIMIT,
674  },
675  },
676  [FSM_STATE_PIDATT_ROLLILIMIT] = {
677  .menu_fn = pidatt_menu,
678  .next_state = {
679  [FSM_EVENT_UP] = FSM_STATE_PIDATT_ROLLI,
680  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_PITCHP,
681  },
682  },
683  [FSM_STATE_PIDATT_PITCHP] = {
684  .menu_fn = pidatt_menu,
685  .next_state = {
686  [FSM_EVENT_UP] = FSM_STATE_PIDATT_ROLLILIMIT,
687  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_PITCHI,
688  },
689  },
690  [FSM_STATE_PIDATT_PITCHI] = {
691  .menu_fn = pidatt_menu,
692  .next_state = {
693  [FSM_EVENT_UP] = FSM_STATE_PIDATT_PITCHP,
694  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_PITCHILIMIT,
695  },
696  },
697  [FSM_STATE_PIDATT_PITCHILIMIT] = {
698  .menu_fn = pidatt_menu,
699  .next_state = {
700  [FSM_EVENT_UP] = FSM_STATE_PIDATT_PITCHI,
701  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_YAWP,
702  },
703  },
704  [FSM_STATE_PIDATT_YAWP] = {
705  .menu_fn = pidatt_menu,
706  .next_state = {
707  [FSM_EVENT_UP] = FSM_STATE_PIDATT_PITCHILIMIT,
708  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_YAWI,
709  },
710  },
711  [FSM_STATE_PIDATT_YAWI] = {
712  .menu_fn = pidatt_menu,
713  .next_state = {
714  [FSM_EVENT_UP] = FSM_STATE_PIDATT_YAWP,
715  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_YAWILIMIT,
716  },
717  },
718  [FSM_STATE_PIDATT_YAWILIMIT] = {
719  .menu_fn = pidatt_menu,
720  .next_state = {
721  [FSM_EVENT_UP] = FSM_STATE_PIDATT_YAWI,
722  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_SAVEEXIT,
723  },
724  },
725  [FSM_STATE_PIDATT_SAVEEXIT] = {
726  .menu_fn = pidatt_menu,
727  .next_state = {
728  [FSM_EVENT_UP] = FSM_STATE_PIDATT_YAWILIMIT,
729  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_EXIT,
730  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_PIDATT,
731  },
732  },
733  [FSM_STATE_PIDATT_EXIT] = {
734  .menu_fn = pidatt_menu,
735  .next_state = {
736  [FSM_EVENT_UP] = FSM_STATE_PIDATT_SAVEEXIT,
737  [FSM_EVENT_DOWN] = FSM_STATE_PIDATT_ROLLP,
738  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_PIDATT,
739  },
740  },
741 /*------------------------------------------------------------------------------------------*/
742  [FSM_STATE_STICKLIMITS_ROLLA] = {
743  .menu_fn = sticklimits_menu,
744  .next_state = {
745  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_EXIT,
746  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_PITCHA,
747  },
748  },
749  [FSM_STATE_STICKLIMITS_PITCHA] = {
750  .menu_fn = sticklimits_menu,
751  .next_state = {
752  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_ROLLA,
753  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_YAWA,
754  },
755  },
756  [FSM_STATE_STICKLIMITS_YAWA] = {
757  .menu_fn = sticklimits_menu,
758  .next_state = {
759  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_PITCHA,
760  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_ROLLR,
761  },
762  },
763  [FSM_STATE_STICKLIMITS_ROLLR] = {
764  .menu_fn = sticklimits_menu,
765  .next_state = {
766  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_YAWA,
767  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_PITCHR,
768  },
769  },
770  [FSM_STATE_STICKLIMITS_PITCHR] = {
771  .menu_fn = sticklimits_menu,
772  .next_state = {
773  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_ROLLR,
774  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_YAWR,
775  },
776  },
777  [FSM_STATE_STICKLIMITS_YAWR] = {
778  .menu_fn = sticklimits_menu,
779  .next_state = {
780  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_PITCHR,
781  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_ROLLEXR,
782  },
783  },
784  [FSM_STATE_STICKLIMITS_ROLLEXR] = {
785  .menu_fn = sticklimits_menu,
786  .next_state = {
787  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_YAWR,
788  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_PITCHEXR,
789  },
790  },
791  [FSM_STATE_STICKLIMITS_PITCHEXR] = {
792  .menu_fn = sticklimits_menu,
793  .next_state = {
794  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_ROLLEXR,
795  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_YAWEXR,
796  },
797  },
798  [FSM_STATE_STICKLIMITS_YAWEXR] = {
799  .menu_fn = sticklimits_menu,
800  .next_state = {
801  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_PITCHEXR,
802  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_ROLLEXH,
803  },
804  },
805  [FSM_STATE_STICKLIMITS_ROLLEXH] = {
806  .menu_fn = sticklimits_menu,
807  .next_state = {
808  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_YAWEXR,
809  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_PITCHEXH,
810  },
811  },
812  [FSM_STATE_STICKLIMITS_PITCHEXH] = {
813  .menu_fn = sticklimits_menu,
814  .next_state = {
815  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_ROLLEXH,
816  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_YAWEXH,
817  },
818  },
819  [FSM_STATE_STICKLIMITS_YAWEXH] = {
820  .menu_fn = sticklimits_menu,
821  .next_state = {
822  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_PITCHEXH,
823  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_MOTORPOWER,
824  },
825  },
826  [FSM_STATE_STICKLIMITS_MOTORPOWER] = {
827  .menu_fn = sticklimits_menu,
828  .next_state = {
829  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_YAWEXH,
830  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_CAMERATILT,
831  },
832  },
833  [FSM_STATE_STICKLIMITS_CAMERATILT] = {
834  .menu_fn = sticklimits_menu,
835  .next_state = {
836  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_MOTORPOWER,
837  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_SAVEEXIT,
838  },
839  },
840  [FSM_STATE_STICKLIMITS_SAVEEXIT] = {
841  .menu_fn = sticklimits_menu,
842  .next_state = {
843  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_CAMERATILT,
844  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_EXIT,
845  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_STICKLIMITS,
846  },
847  },
848  [FSM_STATE_STICKLIMITS_EXIT] = {
849  .menu_fn = sticklimits_menu,
850  .next_state = {
851  [FSM_EVENT_UP] = FSM_STATE_STICKLIMITS_SAVEEXIT,
852  [FSM_EVENT_DOWN] = FSM_STATE_STICKLIMITS_ROLLA,
853  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_STICKLIMITS,
854  },
855  },
856 /*------------------------------------------------------------------------------------------*/
857  [FSM_STATE_VTX_BAND] = {
858  .menu_fn = vtx_menu,
859  .next_state = {
860  [FSM_EVENT_UP] = FSM_STATE_VTX_EXIT,
861  [FSM_EVENT_DOWN] = FSM_STATE_VTX_CH,
862  },
863  },
864  [FSM_STATE_VTX_CH] = {
865  .menu_fn = vtx_menu,
866  .next_state = {
867  [FSM_EVENT_UP] = FSM_STATE_VTX_BAND,
868  [FSM_EVENT_DOWN] = FSM_STATE_VTX_POWER,
869  },
870  },
871  [FSM_STATE_VTX_POWER] = {
872  .menu_fn = vtx_menu,
873  .next_state = {
874  [FSM_EVENT_UP] = FSM_STATE_VTX_CH,
875  [FSM_EVENT_DOWN] = FSM_STATE_VTX_APPLY,
876  },
877  },
878  [FSM_STATE_VTX_APPLY] = {
879  .menu_fn = vtx_menu,
880  .next_state = {
881  [FSM_EVENT_UP] = FSM_STATE_VTX_POWER,
882  [FSM_EVENT_DOWN] = FSM_STATE_VTX_SAVEEXIT,
883  },
884  },
885  [FSM_STATE_VTX_SAVEEXIT] = {
886  .menu_fn = vtx_menu,
887  .next_state = {
888  [FSM_EVENT_UP] = FSM_STATE_VTX_APPLY,
889  [FSM_EVENT_DOWN] = FSM_STATE_VTX_EXIT,
890  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_VTX,
891  },
892  },
893  [FSM_STATE_VTX_EXIT] = {
894  .menu_fn = vtx_menu,
895  .next_state = {
896  [FSM_EVENT_UP] = FSM_STATE_VTX_SAVEEXIT,
897  [FSM_EVENT_DOWN] = FSM_STATE_VTX_BAND,
898  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_VTX,
899  },
900  },
901 /*------------------------------------------------------------------------------------------*/
902  [FSM_STATE_STATS_EXIT] = {
903  .menu_fn = stats_menu,
904  .next_state = {
905  [FSM_EVENT_UP] = FSM_STATE_STATS_EXIT,
906  [FSM_EVENT_DOWN] = FSM_STATE_STATS_EXIT,
907  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_STATS,
908  },
909  },
910 /*------------------------------------------------------------------------------------------*/
911  [FSM_STATE_BATTERY_CAPACITY] = {
912  .menu_fn = battery_menu,
913  .next_state = {
914  [FSM_EVENT_UP] = FSM_STATE_BATTERY_EXIT,
915  [FSM_EVENT_DOWN] = FSM_STATE_BATTERY_CELLCOUNT,
916  },
917  },
918  [FSM_STATE_BATTERY_CELLCOUNT] = {
919  .menu_fn = battery_menu,
920  .next_state = {
921  [FSM_EVENT_UP] = FSM_STATE_BATTERY_CAPACITY,
922  [FSM_EVENT_DOWN] = FSM_STATE_BATTERY_WARNING,
923  },
924  },
925  [FSM_STATE_BATTERY_WARNING] = {
926  .menu_fn = battery_menu,
927  .next_state = {
928  [FSM_EVENT_UP] = FSM_STATE_BATTERY_CELLCOUNT,
929  [FSM_EVENT_DOWN] = FSM_STATE_BATTERY_ALARM,
930  },
931  },
932  [FSM_STATE_BATTERY_ALARM] = {
933  .menu_fn = battery_menu,
934  .next_state = {
935  [FSM_EVENT_UP] = FSM_STATE_BATTERY_WARNING,
936  [FSM_EVENT_DOWN] = FSM_STATE_BATTERY_WARN_TIME,
937  },
938  },
939  [FSM_STATE_BATTERY_WARN_TIME] = {
940  .menu_fn = battery_menu,
941  .next_state = {
942  [FSM_EVENT_UP] = FSM_STATE_BATTERY_ALARM,
943  [FSM_EVENT_DOWN] = FSM_STATE_BATTERY_ALARM_TIME,
944  },
945  },
946  [FSM_STATE_BATTERY_ALARM_TIME] = {
947  .menu_fn = battery_menu,
948  .next_state = {
949  [FSM_EVENT_UP] = FSM_STATE_BATTERY_WARN_TIME,
950  [FSM_EVENT_DOWN] = FSM_STATE_BATTERY_SAVEEXIT,
951  },
952  },
953  [FSM_STATE_BATTERY_SAVEEXIT] = {
954  .menu_fn = battery_menu,
955  .next_state = {
956  [FSM_EVENT_UP] = FSM_STATE_BATTERY_ALARM,
957  [FSM_EVENT_DOWN] = FSM_STATE_BATTERY_EXIT,
958  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_BATTERY,
959  },
960  },
961  [FSM_STATE_BATTERY_EXIT] = {
962  .menu_fn = battery_menu,
963  .next_state = {
964  [FSM_EVENT_UP] = FSM_STATE_BATTERY_SAVEEXIT,
965  [FSM_EVENT_DOWN] = FSM_STATE_BATTERY_CAPACITY,
966  [FSM_EVENT_RIGHT] = FSM_STATE_MAIN_BATTERY,
967  },
968  },
969 
970 };
971 
972 
973 #define INPUT_THRESHOLD (0.2f)
974 enum menu_fsm_event get_controller_event()
975 {
976  float roll, pitch;
977  ManualControlCommandRollGet(&roll);
978  ManualControlCommandPitchGet(&pitch);
979 
980  // pitch has priority
981  if (pitch < -1 * INPUT_THRESHOLD)
982  return FSM_EVENT_UP;
983  if (pitch > INPUT_THRESHOLD)
984  return FSM_EVENT_DOWN;
985  if (roll < -1 * INPUT_THRESHOLD)
986  return FSM_EVENT_LEFT;
987  if (roll > INPUT_THRESHOLD)
988  return FSM_EVENT_RIGHT;
989 
990  return FSM_EVENT_AUTO;
991 }
992 
993 #define HELD_LONG_THRESHOLD 20
994 void render_osd_menu()
995 {
996  uint8_t tmp;
997  static enum menu_fsm_event last_fsm_event;
998  static uint32_t event_repeats = 0;
999 
1000  if (frame_counter % 6 == 0) {
1001  current_event = get_controller_event();
1002  if (last_fsm_event == current_event) {
1003  event_repeats += 1;
1004  }
1005  else {
1006  event_repeats = 0;
1007  }
1008  last_fsm_event = current_event;
1009  held_long = (event_repeats > HELD_LONG_THRESHOLD);
1010  }
1011  else {
1012  current_event = FSM_EVENT_AUTO;
1013  }
1014 
1015  if (menu_fsm[current_state].menu_fn)
1016  menu_fsm[current_state].menu_fn();
1017 
1018  // transition to the next state, but if it's the first right event (effectively
1019  // debounces the exit from sub-menu to main menu transition)
1020  if ((!event_repeats || current_event != FSM_EVENT_RIGHT) && menu_fsm[current_state].next_state[current_event])
1021  current_state = menu_fsm[current_state].next_state[current_event];
1022 
1023  ManualControlSettingsArmingGet(&tmp);
1024  switch(tmp){
1025  case MANUALCONTROLSETTINGS_ARMING_ROLLLEFTTHROTTLE:
1026  case MANUALCONTROLSETTINGS_ARMING_ROLLRIGHTTHROTTLE:
1027  write_string("Do not use roll for arming.", GRAPHICS_X_MIDDLE, GRAPHICS_BOTTOM - 25, 0, 0, TEXT_VA_TOP, TEXT_HA_CENTER, 0, FONT8X10);
1028  break;
1029  default:
1030  write_string("Use roll and pitch to navigate", GRAPHICS_X_MIDDLE, GRAPHICS_BOTTOM - 25, 0, 0, TEXT_VA_TOP, TEXT_HA_CENTER, 0, FONT8X10);
1031  }
1032 
1033  FlightStatusArmedGet(&tmp);
1034  if (tmp != FLIGHTSTATUS_ARMED_DISARMED)
1036 }
1037 
1038 
1039 #define MENU_LINE_SPACING 11
1040 #define MENU_LINE_Y 40
1041 #define MENU_LINE_X (GRAPHICS_LEFT + 10)
1042 #define MENU_FONT FONT8X10
1043 
1044 void draw_menu_title(char* title)
1045 {
1047 }
1048 
1049 void draw_selected_icon(int x, int y)
1050 {
1052 }
1053 
1054 void main_menu(void)
1055 {
1056  int y_pos = MENU_LINE_Y;
1057 
1058  draw_menu_title("Main Menu");
1059 
1060  for (enum menu_fsm_state s=FSM_STATE_TOP; s <= FSM_STATE_MAIN_BATTERY; s++) {
1061  if (s == current_state) {
1062  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1063  }
1064  switch (s) {
1065 #if defined(USE_STM32F4xx_BRAINFPVRE1)
1066  case FSM_STATE_MAIN_RE1:
1067  write_string("BrainFPV RE1 Settings", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1068  break;
1069 #endif /* defined(USE_STM32F4xx_BRAINFPVRE1) */
1070  case FSM_STATE_MAIN_RGBLEDS:
1071  write_string("RGB LED Settings", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1072  break;
1073  case FSM_STATE_MAIN_FILTER:
1074  write_string("Filter Settings", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1075  break;
1076  case FSM_STATE_MAIN_FMODE:
1077  write_string("Flight Modes", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1078  break;
1079  case FSM_STATE_MAIN_HOMELOC:
1080  write_string("Home Location", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1081  break;
1082  case FSM_STATE_MAIN_PIDRATE:
1083  write_string("PID - Rate", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1084  break;
1085  case FSM_STATE_MAIN_PIDATT:
1086  write_string("PID - Attitude", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1087  break;
1088  case FSM_STATE_MAIN_STICKLIMITS:
1089  write_string("Stick Limits and Expo", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1090  break;
1091  case FSM_STATE_MAIN_VTX:
1092  write_string("Video Transmitter", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1093  break;
1094  case FSM_STATE_MAIN_STATS:
1095  write_string("Flight Statistics", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1096  break;
1097  case FSM_STATE_MAIN_BATTERY:
1098  write_string("Battery Settings", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1099  break;
1100  default:
1101  break;
1102  }
1103  y_pos += MENU_LINE_SPACING;
1104  }
1105 }
1106 
1107 #if defined(USE_STM32F4xx_BRAINFPVRE1)
1108 #include "hwbrainre1.h"
1109 
1110 const char * ir_protocol_names[HWBRAINRE1_IRPROTOCOL_MAXOPTVAL + 1] = {
1111  [HWBRAINRE1_IRPROTOCOL_DISABLED] = "OFF",
1112  [HWBRAINRE1_IRPROTOCOL_ILAP] = "I-Lap",
1113  [HWBRAINRE1_IRPROTOCOL_TRACKMATE] = "Trackmate"
1114 };
1115 
1116 #define MAX_ID_ILAP 9999999
1117 #define MAX_ID_TRACKMATE 0xfff
1118 
1119 // Get the next valid trackmate id
1120 // It seems like the ID has some weird requirements:
1121 // 1st nibble is 0, 2nd nibble is not 0, 1, 8, or F
1122 // 3rd and 4th nibbles are not 0 or F
1123 uint16_t next_valid_trackmateid(uint16_t trackmate_id, int16_t step)
1124 {
1125  uint8_t nibble;
1126  while (1){
1127  trackmate_id += step;
1128  if (trackmate_id > MAX_ID_TRACKMATE) {
1129  if (step > 0) {
1130  trackmate_id = 0;
1131  }
1132  else {
1133  trackmate_id = MAX_ID_TRACKMATE;
1134  }
1135  }
1136  // Test 2nd nibble
1137  nibble = (trackmate_id & 0x0F00) >> 8;
1138  if ((nibble == 0x00) || (nibble == 0x01) || (nibble == 0x08) || (nibble == 0x0F)) {
1139  // step through these quickly
1140  if (step > 0) {
1141  trackmate_id += 256;
1142  }
1143  else {
1144  trackmate_id -= 256;
1145  }
1146  continue;
1147  }
1148  // Test 3rd nibble
1149  nibble = (trackmate_id & 0x00F0) >> 4;
1150  if ((nibble == 0x00) || (nibble == 0x0F)) {
1151  continue;
1152  }
1153  // Test 4th nibble
1154  nibble = trackmate_id & 0x000F;
1155  if ((nibble == 0x00) || (nibble == 0x0F)) {
1156  continue;
1157  }
1158  // We have a valid ID
1159  break;
1160  }
1161 
1162  return trackmate_id;
1163 }
1164 
1165 void brainre1_menu(void)
1166 {
1167  HwBrainRE1Data data;
1168  int y_pos = MENU_LINE_Y;
1169  char tmp_str[100] = {0};
1170  bool data_changed = false;
1171 
1172  HwBrainRE1Get(&data);
1173 
1174  draw_menu_title("BrainFPV RE1 Settings");
1175 
1176  for (enum menu_fsm_state s=FSM_STATE_RE1_IR_PROTOCOL; s <= FSM_STATE_RE1_EXIT; s++) {
1177  if (s == current_state) {
1178  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1179  }
1180  switch (s) {
1181  case FSM_STATE_RE1_IR_PROTOCOL:
1182  sprintf(tmp_str, "IR Transponder Protocol: %s", ir_protocol_names[data.IRProtocol]);
1183  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1184  break;
1185  case FSM_STATE_RE1_IR_IDILAP:
1186  sprintf(tmp_str, "IR Transponder ID I-Lap: %07d", (int)data.IRIDILap);
1187  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1188  break;
1189  case FSM_STATE_RE1_IR_IDTRACKMATE:
1190  sprintf(tmp_str, "IR Transponder ID Trackmate: %04d", (int)data.IRIDTrackmate);
1191  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1192  break;
1193  case FSM_STATE_RE1_SAVEEXIT:
1194  write_string("Save and Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1195  break;
1196  case FSM_STATE_RE1_EXIT:
1197  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1198  break;
1199  default:
1200  break;
1201  }
1202  y_pos += MENU_LINE_SPACING;
1203  }
1204 
1205  switch (current_state) {
1206  case FSM_STATE_RE1_IR_PROTOCOL:
1207  if (current_event == FSM_EVENT_RIGHT) {
1208  if (data.IRProtocol == HWBRAINRE1_IRPROTOCOL_GLOBAL_MAXOPTVAL)
1209  data.IRProtocol = 0;
1210  else
1211  data.IRProtocol += 1;
1212  data_changed = true;
1213  }
1214  if (current_event == FSM_EVENT_LEFT) {
1215  if (data.IRProtocol == 0)
1216  data.IRProtocol = HWBRAINRE1_IRPROTOCOL_GLOBAL_MAXOPTVAL;
1217  else
1218  data.IRProtocol -= 1;
1219  data_changed = true;
1220  }
1221  break;
1222  case FSM_STATE_RE1_IR_IDILAP:
1223  {
1224  int step = held_long ? 1000 : 1;
1225  if (current_event == FSM_EVENT_RIGHT) {
1226  data.IRIDILap += step;
1227  if (data.IRIDILap > MAX_ID_ILAP) {
1228  data.IRIDILap = 0;
1229  }
1230  }
1231  if (current_event == FSM_EVENT_LEFT) {
1232  data.IRIDILap -= step;
1233  if (data.IRIDILap > MAX_ID_ILAP) {
1234  data.IRIDILap = MAX_ID_ILAP;
1235  }
1236  }
1237 
1238  data_changed = true;
1239  }
1240  break;
1241  case FSM_STATE_RE1_IR_IDTRACKMATE:
1242  {
1243  if ((current_event == FSM_EVENT_RIGHT) || (current_event == FSM_EVENT_LEFT)) {
1244  int16_t step = held_long ? 100 : 1;
1245  if (current_event == FSM_EVENT_LEFT) {
1246  step *= -1;
1247  }
1248  data.IRIDTrackmate = next_valid_trackmateid(data.IRIDTrackmate, step);
1249  data_changed = true;
1250  }
1251  }
1252  break;
1253  default:
1254  break;
1255  }
1256 
1257  if (data_changed) {
1258  HwBrainRE1Set(&data);
1259  }
1260 
1261  if ((current_state == FSM_STATE_RE1_SAVEEXIT) && (current_event == FSM_EVENT_RIGHT)) {
1262  // Save and exit
1263  UAVObjSave(HwBrainRE1Handle(), 0);
1264  }
1265 }
1266 #endif /* defined(USE_STM32F4xx_BRAINFPVRE1) */
1267 
1268 
1269 
1270 enum RGBColor {
1271  COLOR_OFF,
1272  COLOR_WHITE,
1273  COLOR_RED,
1274  COLOR_ORANGE,
1275  COLOR_YELLOW,
1276  COLOR_GREEN,
1277  COLOR_AQUA,
1278  COLOR_BLUE,
1279  COLOR_PURPLE,
1280  COLOR_CUSTOM,
1281  COLOR_MAXCOLOR
1282 };
1283 
1284 
1285 const uint8_t RGBLED_COLOR_VALUES[COLOR_MAXCOLOR + 1][3] = {
1286  [COLOR_OFF] = {0, 0, 0},
1287  [COLOR_WHITE] = {255, 255, 255},
1288  [COLOR_RED] = {255, 0, 0},
1289  [COLOR_ORANGE] = {255, 69, 0},
1290  [COLOR_YELLOW] = {255, 255, 0},
1291  [COLOR_GREEN] = {0, 255, 0},
1292  [COLOR_AQUA] = {0, 255, 255},
1293  [COLOR_BLUE] = {0, 0, 255},
1294  [COLOR_PURPLE] = {255, 0, 255},
1295  [COLOR_CUSTOM] = {0, 0, 0}
1296 };
1297 
1298 const char * RGBLED_COLOR_NAMES[COLOR_MAXCOLOR + 1] = {
1299  [COLOR_OFF] = "OFF",
1300  [COLOR_WHITE] = "White",
1301  [COLOR_RED] = "Red",
1302  [COLOR_ORANGE] = "Orange",
1303  [COLOR_YELLOW] = "Yellow",
1304  [COLOR_GREEN] = "Green",
1305  [COLOR_AQUA] = "Aqua",
1306  [COLOR_BLUE] = "Blue",
1307  [COLOR_PURPLE] = "Purple",
1308  [COLOR_CUSTOM] = "Custom"
1309 };
1310 
1311 
1312 enum RGBColor get_color(uint8_t * rgb)
1313 {
1314  enum RGBColor color;
1315  for (color=COLOR_OFF; color<COLOR_MAXCOLOR; color++) {
1316  if ((rgb[0] == RGBLED_COLOR_VALUES[color][0]) && (rgb[1] == RGBLED_COLOR_VALUES[color][1])
1317  && (rgb[2] == RGBLED_COLOR_VALUES[color][2])) {
1318  return color;
1319  }
1320  }
1321  return COLOR_CUSTOM;
1322 }
1323 
1324 enum RGBColor get_next_color(enum RGBColor color)
1325 {
1326  if ((color == COLOR_PURPLE) || (color == COLOR_CUSTOM)) {
1327  return COLOR_OFF;
1328  }
1329  return color + 1;
1330 }
1331 
1332 enum RGBColor get_previous_color(enum RGBColor color)
1333 {
1334  if (color == COLOR_OFF) {
1335  return COLOR_PURPLE;
1336  }
1337  return color - 1;
1338 }
1339 
1340 void rgbled_menu(void)
1341 {
1342  int y_pos = MENU_LINE_Y;
1343  char tmp_str[100] = {0};
1344  bool data_changed = false;
1345 
1346  draw_menu_title("RGB LED Settings");
1347 
1348  if (RGBLEDSettingsHandle()) {
1349  RGBLEDSettingsData data;
1350  RGBLEDSettingsGet(&data);
1351  for (enum menu_fsm_state s=FSM_STATE_RGB_DEFAULTCOLOR; s <= FSM_STATE_RGB_EXIT; s++) {
1352  if (s == current_state) {
1353  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1354  }
1355  switch (s) {
1356  case FSM_STATE_RGB_DEFAULTCOLOR:
1357  sprintf(tmp_str, "Default color: %s", RGBLED_COLOR_NAMES[get_color(data.DefaultColor)]);
1358  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1359  break;
1360  case FSM_STATE_RGB_RANGECOLOR_BASE:
1361  sprintf(tmp_str, "Range color base: %s", RGBLED_COLOR_NAMES[get_color(data.RangeBaseColor)]);
1362  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1363  break;
1364  case FSM_STATE_RGB_RANGECOLOR_END:
1365  sprintf(tmp_str, "Range color end: %s", RGBLED_COLOR_NAMES[get_color(data.RangeEndColor)]);
1366  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1367  break;
1368  case FSM_STATE_RGB_SAVEEXIT:
1369  write_string("Save and Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1370  break;
1371  case FSM_STATE_RGB_EXIT:
1372  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1373  break;
1374  default:
1375  break;
1376  }
1377  y_pos += MENU_LINE_SPACING;
1378  }
1379 
1380  uint8_t * target = NULL;
1381  enum RGBColor color;
1382  switch (current_state) {
1383  case FSM_STATE_RGB_DEFAULTCOLOR:
1384  target = data.DefaultColor;
1385  case FSM_STATE_RGB_RANGECOLOR_BASE:
1386  if (target == NULL) {
1387  target = data.RangeBaseColor;
1388  }
1389  case FSM_STATE_RGB_RANGECOLOR_END:
1390  if (target == NULL) {
1391  target = data.RangeEndColor;
1392  }
1393  if (current_event == FSM_EVENT_RIGHT) {
1394  color = get_next_color(get_color(target));
1395  data_changed = true;
1396  }
1397  if (current_event == FSM_EVENT_LEFT) {
1398  color = get_previous_color(get_color(target));
1399  data_changed = true;
1400  }
1401  break;
1402  default:
1403  break;
1404  }
1405 
1406  if (data_changed) {
1407  if (target != NULL) {
1408  target[0] = RGBLED_COLOR_VALUES[color][0];
1409  target[1] = RGBLED_COLOR_VALUES[color][1];
1410  target[2] = RGBLED_COLOR_VALUES[color][2];
1411  }
1412  RGBLEDSettingsSet(&data);
1413  }
1414 
1415  if ((current_state == FSM_STATE_RGB_SAVEEXIT) && (current_event == FSM_EVENT_RIGHT)) {
1416  // Save and exit
1417  UAVObjSave(RGBLEDSettingsHandle(), 0);
1418  }
1419  }
1420  else {
1421  write_string("RGB LED not supported", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1422  current_state = FSM_STATE_RGB_EXIT;
1423  }
1424 }
1425 
1426 
1427 void filter_menu(void)
1428 {
1429  StateEstimationData data;
1430  int y_pos = MENU_LINE_Y;
1431  int tmp;
1432  char tmp_str[100] = {0};
1433  bool data_changed = false;
1434  const char * att_filter_strings[4] = {
1435  [STATEESTIMATION_ATTITUDEFILTER_COMPLEMENTARY] = "Complementary",
1436  [STATEESTIMATION_ATTITUDEFILTER_COMPLEMENTARYVELCOMPASS] = "Comp+Velcomp",
1437  [STATEESTIMATION_ATTITUDEFILTER_INSINDOOR] = "INSIndoor",
1438  [STATEESTIMATION_ATTITUDEFILTER_INSOUTDOOR] = "INSOutdoor",
1439  };
1440  const char * nav_filter_strings[3] = {
1441  [STATEESTIMATION_NAVIGATIONFILTER_NONE] = "None",
1442  [STATEESTIMATION_NAVIGATIONFILTER_RAW] = "Raw",
1443  [STATEESTIMATION_NAVIGATIONFILTER_INS] = "INS",
1444  };
1445 
1446  draw_menu_title("Filter Settings");
1447  StateEstimationGet(&data);
1448 
1449  for (enum menu_fsm_state s=FSM_STATE_FILTER_ATT; s <= FSM_STATE_FILTER_EXIT; s++) {
1450  if (s == current_state) {
1451  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1452  }
1453  switch (s) {
1454  case FSM_STATE_FILTER_ATT:
1455  sprintf(tmp_str, "Attitude Filter: %s", att_filter_strings[data.AttitudeFilter]);
1456  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1457  break;
1458  case FSM_STATE_FILTER_NAV:
1459  sprintf(tmp_str, "Navigation Filter: %s", nav_filter_strings[data.NavigationFilter]);
1460  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1461  break;
1462  case FSM_STATE_FILTER_SAVEEXIT:
1463  write_string("Save and Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1464  break;
1465  case FSM_STATE_FILTER_EXIT:
1466  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1467  break;
1468  default:
1469  break;
1470  }
1471  y_pos += MENU_LINE_SPACING;
1472  }
1473 
1474  switch (current_state) {
1475  case FSM_STATE_FILTER_ATT:
1476  if (current_event == FSM_EVENT_RIGHT) {
1477  data.AttitudeFilter = ((int)(data.AttitudeFilter) + 1) % NELEMENTS(att_filter_strings);;
1478  data_changed = true;
1479  }
1480  if (current_event == FSM_EVENT_LEFT) {
1481  tmp = (int)(data.AttitudeFilter) - 1;
1482  if (tmp < 0)
1483  tmp = NELEMENTS(att_filter_strings) - 1;
1484  data.AttitudeFilter = tmp;
1485  data_changed = true;
1486  }
1487  break;
1488  case FSM_STATE_FILTER_NAV:
1489  if (current_event == FSM_EVENT_RIGHT) {
1490  data.NavigationFilter = (data.NavigationFilter + 1) % NELEMENTS(nav_filter_strings);
1491  data_changed = true;
1492  }
1493  if (current_event == FSM_EVENT_LEFT) {
1494  tmp = (int)(data.NavigationFilter) - 1;
1495  if (tmp < 0)
1496  tmp = NELEMENTS(nav_filter_strings) - 1;
1497  data.NavigationFilter = tmp;
1498  data_changed = true;
1499  }
1500  break;
1501  default:
1502  break;
1503  }
1504 
1505  if (data_changed) {
1506  StateEstimationSet(&data);
1507  }
1508 
1509  if ((current_state == FSM_STATE_FILTER_SAVEEXIT) && (current_event == FSM_EVENT_RIGHT)) {
1510  // Save and exit
1511  UAVObjSave(StateEstimationHandle(), 0);
1512  }
1513 }
1514 
1515 static const char *nullstrwrap(const char *str)
1516 {
1517  if (str)
1518  return str;
1519 
1520  return "";
1521 }
1522 
1523 void flightmode_menu(void)
1524 {
1525  int y_pos = MENU_LINE_Y;
1526  int tmp;
1527  char tmp_str[100] = {0};
1528  bool data_changed = false;
1529  const char* fmode_strings[] = {
1530  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_MANUAL] = "Manual",
1531  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_ACRO] = "Acro",
1532  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_ACRODYNE] = "AcroDyne",
1533  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_ACROPLUS] = "AcroPlus",
1534  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_LEVELING] = "Leveling",
1535  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_HORIZON] = "Horizon",
1536  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_AXISLOCK] = "Axis Lock",
1537  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_VIRTUALBAR] = "Virtualbar",
1538  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED1] = "Stabilized1",
1539  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED2] = "Stabilized2",
1540  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_STABILIZED3] = "Stabilized3",
1541  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_AUTOTUNE] = "Autotune",
1542  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_ALTITUDEHOLD] = "Altitude Hold",
1543  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_POSITIONHOLD] = "Position Hold",
1544  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_RETURNTOHOME] = "Return to Home",
1545  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_PATHPLANNER] = "Path Planner",
1546  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_TABLETCONTROL] = "Tablet Control",
1547  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_LQG] = "LQG",
1548  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_LQGLEVELING] = "LQG Leveling",
1549  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_FLIPREVERSED] = "Flip Reverse",
1550  [MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_FAILSAFE] = "Failsafe",
1551  };
1552 
1553  uint8_t FlightModePosition[MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_NUMELEM];
1554 
1555  draw_menu_title("Flight Modes");
1556 
1557  ManualControlSettingsFlightModePositionGet(FlightModePosition);
1558  for (enum menu_fsm_state s=FSM_STATE_FMODE_1; s <= FSM_STATE_FMODE_EXIT; s++) {
1559  if (s == current_state) {
1560  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1561  }
1562  switch (s) {
1563  case FSM_STATE_FMODE_1:
1564  sprintf(tmp_str, "Position 1: %s", nullstrwrap(fmode_strings[FlightModePosition[0]]));
1565  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1566  break;
1567  case FSM_STATE_FMODE_2:
1568  sprintf(tmp_str, "Position 2: %s", nullstrwrap(fmode_strings[FlightModePosition[1]]));
1569  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1570  break;
1571  case FSM_STATE_FMODE_3:
1572  sprintf(tmp_str, "Position 3: %s", nullstrwrap(fmode_strings[FlightModePosition[2]]));
1573  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1574  break;
1575  case FSM_STATE_FMODE_4:
1576  sprintf(tmp_str, "Position 4: %s", nullstrwrap(fmode_strings[FlightModePosition[3]]));
1577  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1578  break;
1579  case FSM_STATE_FMODE_5:
1580  sprintf(tmp_str, "Position 5: %s", nullstrwrap(fmode_strings[FlightModePosition[4]]));
1581  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1582  break;
1583  case FSM_STATE_FMODE_6:
1584  sprintf(tmp_str, "Position 6: %s", nullstrwrap(fmode_strings[FlightModePosition[5]]));
1585  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1586  break;
1587  case FSM_STATE_FMODE_SAVEEXIT:
1588  write_string("Save and Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1589  break;
1590  case FSM_STATE_FMODE_EXIT:
1591  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1592  break;
1593  default:
1594  break;
1595  }
1596  y_pos += MENU_LINE_SPACING;
1597  }
1598 
1599  for (int i=0; i < MANUALCONTROLSETTINGS_FLIGHTMODEPOSITION_NUMELEM; i++) {
1600  if (current_state == FSM_STATE_FMODE_1 + i) {
1601  if (current_event == FSM_EVENT_RIGHT) {
1602  FlightModePosition[i] = ((int)(FlightModePosition[i]) + 1) % NELEMENTS(fmode_strings);
1603  data_changed = true;
1604  }
1605  if (current_event == FSM_EVENT_LEFT) {
1606  tmp = (int)(FlightModePosition[i]) -1;
1607  if (tmp < 0)
1608  tmp = NELEMENTS(fmode_strings) - 1;
1609  FlightModePosition[i] = tmp;
1610  data_changed = true;
1611  }
1612 
1613  }
1614  }
1615 
1616  if (data_changed) {
1617  ManualControlSettingsFlightModePositionSet(FlightModePosition);
1618  }
1619 
1620  if ((current_state == FSM_STATE_FMODE_SAVEEXIT) && (current_event == FSM_EVENT_RIGHT)) {
1621  // Save and exit
1622  UAVObjSave(ManualControlSettingsHandle(), 0);
1623  }
1624 }
1625 
1626 
1627 void homeloc_menu(void)
1628 {
1629  int y_pos = MENU_LINE_Y;
1630  char tmp_str[100] = {0};
1631  HomeLocationData data;
1632  uint8_t home_set;
1633 
1634  draw_menu_title("Home Location");
1635 
1636  if (HomeLocationHandle()){
1637  HomeLocationSetGet(&home_set);
1638 
1639  if (home_set == HOMELOCATION_SET_TRUE) {
1640  HomeLocationGet(&data);
1641  sprintf(tmp_str, "Home: %0.5f %0.5f Alt: %0.1fm", (double)data.Latitude / 10000000.0, (double)data.Longitude / 10000000.0, (double)data.Altitude);
1642  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1643  }
1644  else {
1645  write_string("Home: Not Set", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1646  }
1647 
1648  y_pos += MENU_LINE_SPACING;
1649  write_string("Set to current location", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1650  if (current_state == FSM_STATE_HOMELOC_SET) {
1651  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1652  if (current_event == FSM_EVENT_RIGHT) {
1653  home_set = HOMELOCATION_SET_FALSE;
1654  HomeLocationSetSet(&home_set);
1655  }
1656 
1657  }
1658  }
1659  else {
1660  write_string("Home Location not available", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1661  }
1662 
1663  y_pos += MENU_LINE_SPACING;
1664  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1665  if (current_state == FSM_STATE_HOMELOC_EXIT) {
1666  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1667  }
1668 }
1669 
1670 
1671 void draw_hscale(int x1, int x2, int y, float val_min, float val_max, float val)
1672 {
1673  int width = x2 - x1;
1674  int width2;
1675  write_filled_rectangle_lm(x1, y, width, 6, 0, 1);
1676  width2 = LIMIT((float)(width - 2) * (val - val_min) / (val_max - val_min), 0, width - 2);
1677  write_filled_rectangle_lm(x1 + 1, y + 1, width2, 4, 1, 1);
1678 }
1679 
1680 const char * axis_strings[] = {"Roll ",
1681  "Pitch",
1682  "Yaw "};
1683 const char * pid_strings[] = {"P ",
1684  "I ",
1685  "D ",
1686  "I-Lim"};
1687 
1688 void pidrate_menu(void)
1689 {
1690  const float limits_high[] = {.01f, .05f, .01f, 1.f};
1691  const float increments[] = {1e-4f, 1e-4f, 1e-4f, 1e-2f};
1692 
1693  float pid_arr[STABILIZATIONSETTINGS_ROLLRATEPID_NUMELEM];
1694  int y_pos = MENU_LINE_Y;
1695  enum menu_fsm_state my_state = FSM_STATE_PIDRATE_ROLLP;
1696  bool data_changed = false;
1697  char tmp_str[100] = {0};
1698 
1699  draw_menu_title("PID Rate");
1700 
1701  for (int i = 0; i < 3; i++) {
1702  data_changed = false;
1703  switch (i) {
1704  case 0:
1705  StabilizationSettingsRollRatePIDGet(pid_arr);
1706  break;
1707  case 1:
1708  StabilizationSettingsPitchRatePIDGet(pid_arr);
1709  break;
1710  case 2:
1711  StabilizationSettingsYawRatePIDGet(pid_arr);
1712  break;
1713  }
1714  for (int j = 0; j < 4; j++) {
1715  sprintf(tmp_str, "%s %s: %0.6f", axis_strings[i], pid_strings[j], (double)pid_arr[j]);
1716  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1717  float h_lim = ceilf(pid_arr[j] / limits_high[j]) * limits_high[j];
1718  draw_hscale(180, GRAPHICS_RIGHT - 5, y_pos + 2, 0.f, h_lim, pid_arr[j]);
1719  if (my_state == current_state) {
1720  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1721  if (current_event == FSM_EVENT_RIGHT) {
1722  pid_arr[j] = pid_arr[j] + increments[j];
1723  data_changed = true;
1724  }
1725  if (current_event == FSM_EVENT_LEFT) {
1726  pid_arr[j] = MAX(0.f, pid_arr[j] - increments[j]);
1727  data_changed = true;
1728  }
1729  if (data_changed) {
1730  switch (i) {
1731  case 0:
1732  StabilizationSettingsRollRatePIDSet(pid_arr);
1733  break;
1734  case 1:
1735  StabilizationSettingsPitchRatePIDSet(pid_arr);
1736  break;
1737  case 2:
1738  StabilizationSettingsYawRatePIDSet(pid_arr);
1739  break;
1740  }
1741  }
1742  }
1743  y_pos += MENU_LINE_SPACING;
1744  my_state++;
1745  }
1746  }
1747 
1748  write_string("Save and Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1749  if (current_state == FSM_STATE_PIDRATE_SAVEEXIT) {
1750  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1751  if (current_event == FSM_EVENT_RIGHT)
1752  UAVObjSave(StabilizationSettingsHandle(), 0);
1753  }
1754 
1755  y_pos += MENU_LINE_SPACING;
1756  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1757  if (current_state == FSM_STATE_PIDRATE_EXIT) {
1758  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1759  }
1760 }
1761 
1762 const char * pid_strings_att[] = {"P ",
1763  "I ",
1764  "I-Lim"};
1765 void pidatt_menu(void)
1766 {
1767  const float limits_high[] = {20.f, 20.f, 100.f};
1768  const float increments[] = {0.1f, 0.1f, 1.f};
1769 
1770  float pid_arr[STABILIZATIONSETTINGS_ROLLPI_NUMELEM];
1771  int y_pos = MENU_LINE_Y;
1772  enum menu_fsm_state my_state = FSM_STATE_PIDATT_ROLLP;
1773  bool data_changed = false;
1774  char tmp_str[100] = {0};
1775 
1776  draw_menu_title("PID Attitude");
1777 
1778  for (int i = 0; i < 3; i++) {
1779  data_changed = false;
1780  switch (i) {
1781  case 0:
1782  StabilizationSettingsRollPIGet(pid_arr);
1783  break;
1784  case 1:
1785  StabilizationSettingsPitchPIGet(pid_arr);
1786  break;
1787  case 2:
1788  StabilizationSettingsYawPIGet(pid_arr);
1789  break;
1790  }
1791  for (int j = 0; j < 3; j++) {
1792  sprintf(tmp_str, "%s %s: %2.1f", axis_strings[i], pid_strings_att[j], (double)pid_arr[j]);
1793  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1794  float h_lim = ceilf(pid_arr[j] / limits_high[j]) * limits_high[j];
1795  draw_hscale(170, GRAPHICS_RIGHT - 5, y_pos + 2, 0.f, h_lim, pid_arr[j]);
1796  if (my_state == current_state) {
1797  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1798  if (current_event == FSM_EVENT_RIGHT) {
1799  pid_arr[j] = pid_arr[j] + increments[j];
1800  data_changed = true;
1801  }
1802  if (current_event == FSM_EVENT_LEFT) {
1803  pid_arr[j] = MAX(0.f, pid_arr[j] - increments[j]);
1804  data_changed = true;
1805  }
1806  if (data_changed) {
1807  switch (i) {
1808  case 0:
1809  StabilizationSettingsRollPISet(pid_arr);
1810  break;
1811  case 1:
1812  StabilizationSettingsPitchPISet(pid_arr);
1813  break;
1814  case 2:
1815  StabilizationSettingsYawPISet(pid_arr);
1816  break;
1817  }
1818  }
1819  }
1820  y_pos += MENU_LINE_SPACING;
1821  my_state++;
1822  }
1823  }
1824 
1825  write_string("Save and Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1826  if (current_state == FSM_STATE_PIDATT_SAVEEXIT) {
1827  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1828  if (current_event == FSM_EVENT_RIGHT) {
1829  UAVObjSave(StabilizationSettingsHandle(), 0);
1830  }
1831  }
1832 
1833  y_pos += MENU_LINE_SPACING;
1834  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1835  if (current_state == FSM_STATE_PIDATT_EXIT) {
1836  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1837  }
1838 }
1839 
1840 DONT_BUILD_IF(STABILIZATIONSETTINGS_MAXLEVELANGLE_ROLL != 0,
1841  LevelAngleConstantRoll);
1842 DONT_BUILD_IF(STABILIZATIONSETTINGS_MAXLEVELANGLE_PITCH != 1,
1843  LevelAngleConstantPitch);
1844 DONT_BUILD_IF(STABILIZATIONSETTINGS_MAXLEVELANGLE_YAW != 2,
1845  LevelAngleConstantYaw);
1846 
1847 #define MAX_STICK_RATE 1440
1848 void sticklimits_menu(void)
1849 {
1850  int y_pos = MENU_LINE_Y;
1851  enum menu_fsm_state my_state = FSM_STATE_STICKLIMITS_ROLLA;
1852  bool data_changed = false;
1853  char tmp_str[100] = {0};
1854 
1855  draw_menu_title("Stick Limits and Expo");
1856 
1857  uint8_t level_angles[STABILIZATIONSETTINGS_MAXLEVELANGLE_NUMELEM];
1858 
1859  StabilizationSettingsMaxLevelAngleGet(level_angles);
1860 
1861  // Full Stick Angle
1862  for (int i = 0; i < 3; i++) {
1863  data_changed = false;
1864 
1865  uint8_t angle = level_angles[i];
1866 
1867  sprintf(tmp_str, "Max Stick Angle %s: %d", axis_strings[i], angle);
1868  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1869  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 0, 90, angle);
1870  if (my_state == current_state) {
1871  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1872  if (current_event == FSM_EVENT_RIGHT) {
1873  level_angles[i] = MIN(angle + 1, 90);
1874  data_changed = true;
1875  }
1876  if (current_event == FSM_EVENT_LEFT) {
1877  level_angles[i] = MAX((int)angle - 1, 0);
1878  data_changed = true;
1879  }
1880  if (data_changed) {
1881  StabilizationSettingsMaxLevelAngleSet(level_angles);
1882  }
1883  }
1884  my_state++;
1885  y_pos += MENU_LINE_SPACING;
1886  }
1887 
1888  // Rate Limits
1889  {
1890  float rate_arr[STABILIZATIONSETTINGS_MANUALRATE_NUMELEM];
1891  StabilizationSettingsManualRateGet(rate_arr);
1892  data_changed = false;
1893  for (int i = 0; i < 3; i++) {
1894  sprintf(tmp_str, "Max Stick Rate %s: %d", axis_strings[i], (int)rate_arr[i]);
1895  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1896  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 0, MAX_STICK_RATE, rate_arr[i]);
1897  if (my_state == current_state) {
1898  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1899  if (current_event == FSM_EVENT_RIGHT) {
1900  rate_arr[i] = MIN(rate_arr[i] + 10, MAX_STICK_RATE);
1901  data_changed = true;
1902  }
1903  if (current_event == FSM_EVENT_LEFT) {
1904  rate_arr[i] = MAX(rate_arr[i] - 10, 0);
1905  data_changed = true;
1906  }
1907  }
1908  my_state++;
1909  y_pos += MENU_LINE_SPACING;
1910 
1911  }
1912  if (data_changed)
1913  StabilizationSettingsManualRateSet(rate_arr);
1914  }
1915 
1916  // Rate Expo
1917  {
1918  uint8_t expo_arr[STABILIZATIONSETTINGS_RATEEXPO_NUMELEM];
1919  StabilizationSettingsRateExpoGet(expo_arr);
1920  data_changed = false;
1921  for (int i = 0; i < 3; i++) {
1922  sprintf(tmp_str, "Expo Rate %s: %d", axis_strings[i], (int)expo_arr[i]);
1923  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1924  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 0, 100, expo_arr[i]);
1925  if (my_state == current_state) {
1926  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1927  if (current_event == FSM_EVENT_RIGHT) {
1928  expo_arr[i] = MIN(expo_arr[i] + 1, 100);
1929  data_changed = true;
1930  }
1931  if (current_event == FSM_EVENT_LEFT) {
1932  expo_arr[i] = MAX(expo_arr[i] - 1, 0);
1933  data_changed = true;
1934  }
1935  }
1936  my_state++;
1937  y_pos += MENU_LINE_SPACING;
1938 
1939  }
1940  if (data_changed)
1941  StabilizationSettingsRateExpoSet(expo_arr);
1942  }
1943 
1944  // Horizon Expo
1945  {
1946  uint8_t expo_arr[STABILIZATIONSETTINGS_HORIZONEXPO_NUMELEM];
1947  StabilizationSettingsHorizonExpoGet(expo_arr);
1948  data_changed = false;
1949  for (int i = 0; i < 3; i++) {
1950  sprintf(tmp_str, "Expo Horizon %s: %d", axis_strings[i], (int)expo_arr[i]);
1951  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1952  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 0, 100, expo_arr[i]);
1953  if (my_state == current_state) {
1954  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1955  if (current_event == FSM_EVENT_RIGHT) {
1956  expo_arr[i] = MIN(expo_arr[i] + 1, 100);
1957  data_changed = true;
1958  }
1959  if (current_event == FSM_EVENT_LEFT) {
1960  expo_arr[i] = MAX(expo_arr[i] - 1, 0);
1961  data_changed = true;
1962  }
1963  }
1964  my_state++;
1965  y_pos += MENU_LINE_SPACING;
1966 
1967  }
1968  if (data_changed)
1969  StabilizationSettingsHorizonExpoSet(expo_arr);
1970  }
1971 
1972  // Motor power scaling
1973  {
1974  float motor_gain;
1975  ActuatorSettingsMotorInputOutputGainGet(&motor_gain);
1976  motor_gain *= 100;
1977 
1978  data_changed = false;
1979  sprintf(tmp_str, "Motor power scale: %d", (int)motor_gain);
1980  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
1981  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 50, 100, motor_gain);
1982  if (my_state == current_state) {
1983  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
1984  if (current_event == FSM_EVENT_RIGHT) {
1985  motor_gain = MIN(motor_gain + 1, 100);
1986  data_changed = true;
1987  }
1988  if (current_event == FSM_EVENT_LEFT) {
1989  motor_gain = MAX(motor_gain - 1, 50);
1990  data_changed = true;
1991  }
1992  }
1993  my_state++;
1994  y_pos += MENU_LINE_SPACING;
1995 
1996  if (data_changed) {
1997  motor_gain /= 100;
1998  ActuatorSettingsMotorInputOutputGainSet(&motor_gain);
1999  }
2000  }
2001 
2002  // Reprojection Camera Tilt
2003  {
2004  float tilt;
2005  StabilizationSettingsCameraTiltGet(&tilt);
2006  data_changed = false;
2007 
2008  sprintf(tmp_str, "Reproject Camera Tilt: %d", (int)tilt);
2009  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2010  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, -85, 85, tilt);
2011  if (my_state == current_state) {
2012  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2013  if (current_event == FSM_EVENT_RIGHT) {
2014  tilt = MIN(tilt + 1, 85);
2015  data_changed = true;
2016  }
2017  if (current_event == FSM_EVENT_LEFT) {
2018  tilt = MAX(tilt - 1, -85);
2019  data_changed = true;
2020  }
2021  }
2022 
2023  my_state++;
2024  y_pos += MENU_LINE_SPACING;
2025 
2026  if (data_changed)
2027  StabilizationSettingsCameraTiltSet(&tilt);
2028  }
2029 
2030  write_string("Save and Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2031  if (current_state == FSM_STATE_STICKLIMITS_SAVEEXIT) {
2032  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2033  if (current_event == FSM_EVENT_RIGHT) {
2034  UAVObjSave(StabilizationSettingsHandle(), 0);
2035  UAVObjSave(ActuatorSettingsHandle(), 0);
2036  }
2037  }
2038 
2039  y_pos += MENU_LINE_SPACING;
2040  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2041  if (current_state == FSM_STATE_STICKLIMITS_EXIT) {
2042  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2043  }
2044 }
2045 
2046 void vtx_menu()
2047 {
2048  const char *vtx_strings[] = {
2049  [VTXINFO_MODEL_NONE] = "No VTX detected",
2050  [VTXINFO_MODEL_TBSUNIFYPRO5G8] = "TBS Unify Pro 5G8",
2051  [VTXINFO_MODEL_TBSUNIFYPRO5G8HV] = "TBS Unify Pro 5G8 HV",
2052  };
2053 
2054  const char *band_strings[] = {
2055  [VTXSETTINGS_BAND_BAND5G8A] = "A",
2056  [VTXSETTINGS_BAND_BAND5G8B] = "B",
2057  [VTXSETTINGS_BAND_BAND5G8E] = "E",
2058  [VTXSETTINGS_BAND_AIRWAVE] = "Airwave",
2059  [VTXSETTINGS_BAND_RACEBAND] = "Raceband",
2060  };
2061 
2062  // this is a special case, we need a local copy as the user has to use "apply" to set the new settings
2063  static VTXSettingsData settings;
2064  static bool settings_read = false;
2065 
2066  draw_menu_title("Video Transmitter");
2067  int y_pos = MENU_LINE_Y;
2068 
2069  if ((VTXSettingsHandle() == NULL) || (VTXInfoHandle() == NULL)) {
2070  write_string("VTX Config Module not running!", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2071  y_pos += MENU_LINE_SPACING;
2072  current_state = FSM_STATE_VTX_EXIT;
2073  }
2074  else {
2075  VTXInfoData vtxInfo;
2076  VTXInfoGet(&vtxInfo);
2077  char tmp_str[100] = {0};
2078 
2079  if (!settings_read) {
2080  VTXSettingsGet(&settings);
2081  settings_read = true;
2082  }
2083 
2084  y_pos += MENU_LINE_SPACING;
2085  sprintf(tmp_str, "VTX Type: %s", vtx_strings[vtxInfo.Model]);
2086  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2087 
2088  y_pos += 2 * MENU_LINE_SPACING;
2089  write_string("Current:", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2090 
2091  y_pos += MENU_LINE_SPACING;
2092  sprintf(tmp_str, " Frequency: %d MHz", vtxInfo.Frequency);
2093  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2094 
2095  y_pos += MENU_LINE_SPACING;
2096  sprintf(tmp_str, " Power: %d mW", vtxInfo.Power);
2097  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2098 
2099  y_pos += 2 * MENU_LINE_SPACING;
2100  write_string("New:", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2101 
2102  y_pos += MENU_LINE_SPACING;
2103  sprintf(tmp_str, " Band: %s", band_strings[settings.Band]);
2104  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2105  if (current_state == FSM_STATE_VTX_BAND) {
2106  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2107 
2108  if (current_event == FSM_EVENT_RIGHT) {
2109  if (settings.Band == VTXSETTINGS_BAND_MAXOPTVAL) {
2110  settings.Band = 0;
2111  }
2112  else {
2113  settings.Band += 1;
2114  }
2115  }
2116  if (current_event == FSM_EVENT_LEFT) {
2117  if (settings.Band == 0) {
2118  settings.Band = VTXSETTINGS_BAND_MAXOPTVAL;
2119  }
2120  else {
2121  settings.Band -= 1;
2122  }
2123  }
2124  }
2125 
2126  uint8_t *target;
2127  uint8_t max_val;
2128  const uint16_t *band_ptr;
2129  switch(settings.Band) {
2130  case VTXSETTINGS_BAND_BAND5G8A:
2131  band_ptr = BAND_5G8_A_FREQS;
2132  max_val = VTXSETTINGS_BAND_5G8_A_FREQUENCY_MAXOPTVAL;
2133  target = &settings.Band_5G8_A_Frequency;
2134  break;
2135  case VTXSETTINGS_BAND_BAND5G8B:
2136  band_ptr = BAND_5G8_B_FREQS;
2137  max_val = VTXSETTINGS_BAND_5G8_B_FREQUENCY_MAXOPTVAL;
2138  target = &settings.Band_5G8_B_Frequency;
2139  break;
2140  case VTXSETTINGS_BAND_BAND5G8E:
2141  band_ptr = BAND_5G8_E_FREQS;
2142  max_val = VTXSETTINGS_BAND_5G8_E_FREQUENCY_MAXOPTVAL;
2143  target = &settings.Band_5G8_E_Frequency;
2144  break;
2145  case VTXSETTINGS_BAND_AIRWAVE:
2146  band_ptr = AIRWAVE_FREQS;
2147  max_val = VTXSETTINGS_AIRWAVE_FREQUENCY_MAXOPTVAL;
2148  target = &settings.Airwave_Frequency;
2149  break;
2150  default:
2151  case VTXSETTINGS_BAND_RACEBAND:
2152  band_ptr = RACEBAND_FREQS;
2153  max_val = VTXSETTINGS_RACEBAND_FREQUENCY_MAXOPTVAL;
2154  target = &settings.Raceband_Frequency;
2155  break;
2156  }
2157  y_pos += MENU_LINE_SPACING;
2158 
2159  sprintf(tmp_str, " Channel: CH %d %d MHz", *target + 1, band_ptr[*target]);
2160  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2161 
2162  if (current_state == FSM_STATE_VTX_CH) {
2163  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2164 
2165  if (current_event == FSM_EVENT_RIGHT) {
2166  if (*target == max_val) {
2167  *target = 0;
2168  }
2169  else {
2170  *target += 1;
2171  }
2172  }
2173  if (current_event == FSM_EVENT_LEFT) {
2174  if (*target == 0) {
2175  *target = max_val;
2176  }
2177  else {
2178  *target -= 1;
2179  }
2180  }
2181  }
2182 
2183  y_pos += MENU_LINE_SPACING;
2184  sprintf(tmp_str, " Power: %d mW", VTX_POWER[settings.Power]);
2185  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2186 
2187  if (current_state == FSM_STATE_VTX_POWER) {
2188  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2189 
2190  if (current_event == FSM_EVENT_RIGHT) {
2191  if (settings.Power == VTXSETTINGS_POWER_MAXOPTVAL) {
2192  settings.Power = 0;
2193  }
2194  else {
2195  settings.Power += 1;
2196  }
2197  }
2198  if (current_event == FSM_EVENT_LEFT) {
2199  if (settings.Power == 0) {
2200  settings.Power = VTXSETTINGS_POWER_MAXOPTVAL;
2201  }
2202  else {
2203  settings.Power -= 1;
2204  }
2205  }
2206  }
2207  }
2208 
2209  y_pos += 2 * MENU_LINE_SPACING;
2210  write_string("Apply", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2211  if (current_state == FSM_STATE_VTX_APPLY) {
2212  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2213  if (current_event == FSM_EVENT_RIGHT) {
2214  VTXSettingsSet(&settings);
2215  }
2216  }
2217 
2218  y_pos += MENU_LINE_SPACING;
2219  write_string("Save and Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2220  if (current_state == FSM_STATE_VTX_SAVEEXIT) {
2221  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2222  if (current_event == FSM_EVENT_RIGHT) {
2223  VTXSettingsSet(&settings);
2224  UAVObjSave(VTXSettingsHandle(), 0);
2225  settings_read = false;
2226  }
2227  }
2228 
2229  y_pos += MENU_LINE_SPACING;
2230  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2231  if (current_state == FSM_STATE_VTX_EXIT) {
2232  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2233 
2234  if (current_event == FSM_EVENT_RIGHT)
2235  settings_read = false;
2236 
2237  }
2238 
2239 }
2240 
2241 
2242 void stats_menu()
2243 {
2244  int y_pos = render_stats();
2245  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2246  if (current_state == FSM_STATE_STATS_EXIT) {
2247  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2248  }
2249 }
2250 
2251 void battery_menu(void)
2252 {
2253  int y_pos = MENU_LINE_Y;
2254  bool settings_changed = false;
2255  char tmp_str[100] = {0};
2256  static FlightBatterySettingsData batterySettings;
2257  static bool settings_read = false;
2258 
2259 
2260  draw_menu_title("Battery Settings");
2261 
2262  if (FlightBatterySettingsHandle()) {
2263  if (!settings_read) {
2264  FlightBatterySettingsGet(&batterySettings);
2265  settings_read = true;
2266  }
2267 
2268  sprintf(tmp_str, "Capacity (mAh): %d", (int)batterySettings.Capacity );
2269  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2270  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 0, 15000, batterySettings.Capacity);
2271  if (current_state == FSM_STATE_BATTERY_CAPACITY) {
2272  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2273  if (current_event == FSM_EVENT_RIGHT) {
2274  batterySettings.Capacity = MIN(15000, batterySettings.Capacity + 50);
2275  settings_changed = true;
2276  }
2277  else if (current_event == FSM_EVENT_LEFT) {
2278  batterySettings.Capacity = MAX(500, batterySettings.Capacity - 50);
2279  settings_changed = true;
2280  }
2281  }
2282 
2283  y_pos += MENU_LINE_SPACING;
2284  sprintf(tmp_str, "Cell Count : %d", (int)batterySettings.NbCells );
2285  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2286  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 1, 10, batterySettings.NbCells);
2287  if (current_state == FSM_STATE_BATTERY_CELLCOUNT) {
2288  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2289  if (current_event == FSM_EVENT_RIGHT) {
2290  batterySettings.NbCells = MIN(10, batterySettings.NbCells + 1);
2291  settings_changed = true;
2292  }
2293  else if (current_event == FSM_EVENT_LEFT) {
2294  batterySettings.NbCells = MAX(1, batterySettings.NbCells - 1);
2295  settings_changed = true;
2296  }
2297  }
2298 
2299  y_pos += MENU_LINE_SPACING;
2300  sprintf(tmp_str, "Low Cell Warn V: %1.1f", (double) batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] );
2301  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2302  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 0.0f, 4.5f, batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING]);
2303  if (current_state == FSM_STATE_BATTERY_WARNING) {
2304  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2305  if (current_event == FSM_EVENT_RIGHT) {
2306  batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] = MIN(4.5f, batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] + 0.1f);
2307  settings_changed = true;
2308  }
2309  else if (current_event == FSM_EVENT_LEFT) {
2310  batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] = MAX(3.0f, batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] - 0.1f);
2311  settings_changed = true;
2312  }
2313  }
2314 
2315 
2316  y_pos += MENU_LINE_SPACING;
2317  sprintf(tmp_str, "Low Cell Alarm V: %1.1f", (double) batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] );
2318  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2319  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 0.0f, 4.5f, batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM]);
2320  if (current_state == FSM_STATE_BATTERY_ALARM) {
2321  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2322  if (current_event == FSM_EVENT_RIGHT) {
2323  batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] = MIN(4.5f, batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] + 0.1f);
2324  settings_changed = true;
2325  }
2326  else if (current_event == FSM_EVENT_LEFT) {
2327  batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] = MAX(3.0f, batterySettings.CellVoltageThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] - 0.1f);
2328  settings_changed = true;
2329  }
2330  }
2331 
2332 
2333  y_pos += MENU_LINE_SPACING;
2334  sprintf(tmp_str, "Flight Warn Time : %d", batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] );
2335  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2336  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 0, 300, batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING]);
2337  if (current_state == FSM_STATE_BATTERY_WARN_TIME) {
2338  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2339  if (current_event == FSM_EVENT_RIGHT) {
2340  batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] = MIN(4.5f, batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] + 1);
2341  settings_changed = true;
2342  }
2343  else if (current_event == FSM_EVENT_LEFT) {
2344  batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] = MIN(4.5f, batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_WARNING] - 1);
2345  settings_changed = true;
2346  }
2347  }
2348 
2349 
2350  y_pos += MENU_LINE_SPACING;
2351  sprintf(tmp_str, "Flight Alarm Time : %d", batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] );
2352  write_string(tmp_str, MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2353  draw_hscale(225, GRAPHICS_RIGHT - 5, y_pos + 2, 0, 300, batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM]);
2354  if (current_state == FSM_STATE_BATTERY_ALARM_TIME) {
2355  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2356  if (current_event == FSM_EVENT_RIGHT) {
2357  batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] = MIN(4.5f, batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] + 1);
2358  settings_changed = true;
2359  }
2360  else if (current_event == FSM_EVENT_LEFT) {
2361  batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] = MIN(4.5f, batterySettings.FlightTimeThresholds[FLIGHTBATTERYSETTINGS_CELLVOLTAGETHRESHOLDS_ALARM] - 1);
2362  settings_changed = true;
2363  }
2364  }
2365 
2366  if (settings_changed)
2367  FlightBatterySettingsSet(&batterySettings);
2368 
2369 
2370  y_pos += MENU_LINE_SPACING;
2371  write_string("Save and Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2372  if (current_state == FSM_STATE_BATTERY_SAVEEXIT) {
2373  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2374 
2375  if (current_event == FSM_EVENT_RIGHT ) {
2376  UAVObjSave(FlightBatterySettingsHandle(), 0);
2377  settings_read = false;
2378  }
2379  }
2380 
2381  y_pos += MENU_LINE_SPACING;
2382  write_string("Exit", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2383  if (current_state == FSM_STATE_BATTERY_EXIT) {
2384  draw_selected_icon(MENU_LINE_X - 4, y_pos + 4);
2385 
2386  if (current_event == FSM_EVENT_RIGHT)
2387  settings_read = false;
2388  }
2389  }
2390  else {
2391  write_string("Battery module not running", MENU_LINE_X, y_pos, 0, 0, TEXT_VA_TOP, TEXT_HA_LEFT, 0, MENU_FONT);
2392  current_state = FSM_STATE_BATTERY_EXIT;
2393  }
2394 }
2395 
2396 #endif /* OSD_USE_MENU */
2397 
OSD Utility Functions.
static const uint16_t BAND_5G8_A_FREQS[VTXSETTINGS_BAND_5G8_A_FREQUENCY_MAXOPTVAL+1]
Definition: VTXConfig.c:72
void write_string(char *str, int x, int y, int xs, int ys, int va, int ha, int flags, int font)
Definition: osd_utils.c:1344
#define LIMIT(x, l, h)
Definition: osd_utils.h:140
#define TEXT_HA_LEFT
Definition: osd_utils.h:133
int sprintf(char *out, const char *format,...)
uint16_t frame_counter
#define NELEMENTS(x)
Definition: pios.h:192
void draw_image(uint16_t x, uint16_t y, const struct Image *image)
Definition: osd_utils.c:70
#define FONT12X18
Definition: fonts.h:54
struct _msp_pid_item pitch
Definition: msp_messages.h:97
struct _msp_pid_item roll
Definition: msp_messages.h:96
volatile int j
Definition: loadabletest.c:12
static const struct Image image_menu_icon
Definition: images.h:2061
int32_t UAVObjSave(UAVObjHandle obj_handle, uint16_t instId)
static const uint16_t RACEBAND_FREQS[VTXSETTINGS_RACEBAND_FREQUENCY_MAXOPTVAL+1]
Definition: VTXConfig.c:116
uint8_t current_state
Definition: bl_messages.h:138
uint8_t data[XFER_BYTES_PER_PACKET]
Definition: bl_messages.h:129
#define TEXT_HA_CENTER
Definition: osd_utils.h:134
static const uint16_t AIRWAVE_FREQS[VTXSETTINGS_AIRWAVE_FREQUENCY_MAXOPTVAL+1]
Definition: VTXConfig.c:105
static const uint16_t VTX_POWER[VTXSETTINGS_POWER_GLOBAL_MAXOPTVAL+1]
Definition: VTXConfig.c:127
#define MAX(a, b)
Definition: misc_math.h:40
static volatile FlightStatsSettingsData settings
OSD gen module, handles OSD draw. Parts from CL-OSD and SUPEROSD projects.
#define GRAPHICS_RIGHT
Definition: pios_video.h:130
#define GRAPHICS_X_MIDDLE
Definition: pios_video.h:133
uint8_t i
Definition: msp_messages.h:97
#define TEXT_VA_TOP
Definition: osd_utils.h:130
uint16_t height
Definition: images.h:1076
tuple f
Definition: px_mkfw.py:81
int render_stats()
#define MIN(a, b)
Definition: misc_math.h:41
#define DONT_BUILD_IF(COND, MSG)
Definition: morsel.c:206
void render_osd_menu()
#define FONT8X10
Definition: fonts.h:52
static const uint16_t BAND_5G8_E_FREQS[VTXSETTINGS_BAND_5G8_E_FREQUENCY_MAXOPTVAL+1]
Definition: VTXConfig.c:94
static const uint16_t BAND_5G8_B_FREQS[VTXSETTINGS_BAND_5G8_B_FREQUENCY_MAXOPTVAL+1]
Definition: VTXConfig.c:83
void write_filled_rectangle_lm(int x, int y, int width, int height, int lmode, int mmode)
Definition: osd_utils.c:659
#define GRAPHICS_BOTTOM
Definition: pios_video.h:131