Merge pull request #6382 from mikeller/fix_smartport_delay
[betaflight.git] / src / main / cms / cms_menu_vtx_smartaudio.c
blobec6abbd956808e94ae92ef6a25994902e80d2410
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 <ctype.h>
24 #include <string.h>
26 #include "platform.h"
28 #if defined(USE_CMS) && defined(USE_VTX_SMARTAUDIO)
30 #include "common/printf.h"
31 #include "common/utils.h"
33 #include "cms/cms.h"
34 #include "cms/cms_types.h"
35 #include "cms/cms_menu_vtx_smartaudio.h"
37 #include "drivers/vtx_common.h"
39 #include "fc/config.h"
41 #include "io/vtx_string.h"
42 #include "io/vtx_smartaudio.h"
43 #include "io/vtx.h"
45 // Interface to CMS
47 // Operational Model and RF modes (CMS)
49 #define SACMS_OPMODEL_UNDEF 0 // Not known yet
50 #define SACMS_OPMODEL_FREE 1 // Freestyle model: Power up transmitting
51 #define SACMS_OPMODEL_RACE 2 // Race model: Power up in pit mode
53 uint8_t saCmsOpmodel = SACMS_OPMODEL_UNDEF;
55 #define SACMS_TXMODE_NODEF 0
56 #define SACMS_TXMODE_PIT_OUTRANGE 1
57 #define SACMS_TXMODE_PIT_INRANGE 2
58 #define SACMS_TXMODE_ACTIVE 3
60 uint8_t saCmsRFState; // RF state; ACTIVE, PIR, POR XXX Not currently used
62 uint8_t saCmsBand = 0;
63 uint8_t saCmsChan = 0;
64 uint8_t saCmsPower = 0;
66 // Frequency derived from channel table (used for reference in band/channel mode)
67 uint16_t saCmsFreqRef = 0;
69 uint16_t saCmsDeviceFreq = 0;
71 uint8_t saCmsDeviceStatus = 0;
72 uint8_t saCmsPower;
73 uint8_t saCmsPitFMode; // Undef(0), In-Range(1) or Out-Range(2)
75 uint8_t saCmsFselMode; // Channel(0) or User defined(1)
76 uint8_t saCmsFselModeNew; // Channel(0) or User defined(1)
78 uint16_t saCmsORFreq = 0; // POR frequency
79 uint16_t saCmsORFreqNew; // POR frequency
81 uint16_t saCmsUserFreq = 0; // User defined frequency
82 uint16_t saCmsUserFreqNew; // User defined frequency
84 void saCmsUpdate(void)
86 // XXX Take care of pit mode update somewhere???
87 if (saCmsOpmodel == SACMS_OPMODEL_UNDEF) {
88 // This is a first valid response to GET_SETTINGS.
89 saCmsOpmodel = (saDevice.mode & SA_MODE_GET_PITMODE) ? SACMS_OPMODEL_RACE : SACMS_OPMODEL_FREE;
91 saCmsFselMode = (saDevice.mode & SA_MODE_GET_FREQ_BY_FREQ) ? 1 : 0;
93 saCmsBand = vtxSettingsConfig()->band;
94 saCmsChan = vtxSettingsConfig()->channel;
95 saCmsFreqRef = vtxSettingsConfig()->freq;
96 saCmsDeviceFreq = saCmsFreqRef;
98 if ((saDevice.mode & SA_MODE_GET_PITMODE) == 0) {
99 saCmsRFState = SACMS_TXMODE_ACTIVE;
100 } else if (saDevice.mode & SA_MODE_GET_IN_RANGE_PITMODE) {
101 saCmsRFState = SACMS_TXMODE_PIT_INRANGE;
102 } else {
103 saCmsRFState = SACMS_TXMODE_PIT_OUTRANGE;
106 saCmsPower = vtxSettingsConfig()->power;
108 // if user-freq mode then track possible change
109 if (saCmsFselMode && vtxSettingsConfig()->freq) {
110 saCmsUserFreq = vtxSettingsConfig()->freq;
113 saCmsFselModeNew = saCmsFselMode; //init mode for menu
116 saUpdateStatusString();
119 char saCmsStatusString[31] = "- -- ---- ---";
120 // m bc ffff ppp
121 // 0123456789012
123 static long saCmsConfigOpmodelByGvar(displayPort_t *, const void *self);
124 static long saCmsConfigPitFModeByGvar(displayPort_t *, const void *self);
125 static long saCmsConfigBandByGvar(displayPort_t *, const void *self);
126 static long saCmsConfigChanByGvar(displayPort_t *, const void *self);
127 static long saCmsConfigPowerByGvar(displayPort_t *, const void *self);
129 void saUpdateStatusString(void)
131 if (saDevice.version == 0)
132 return;
134 // XXX These should be done somewhere else
135 if (saCmsDeviceStatus == 0 && saDevice.version != 0)
136 saCmsDeviceStatus = saDevice.version;
137 if (saCmsORFreq == 0 && saDevice.orfreq != 0)
138 saCmsORFreq = saDevice.orfreq;
139 if (saCmsUserFreq == 0 && saDevice.freq != 0)
140 saCmsUserFreq = saDevice.freq;
142 if (saDevice.version == 2) {
143 if (saDevice.mode & SA_MODE_GET_OUT_RANGE_PITMODE)
144 saCmsPitFMode = 1;
145 else
146 saCmsPitFMode = 0;
149 saCmsStatusString[0] = "-FR"[saCmsOpmodel];
151 if (saCmsFselMode == 0) {
152 saCmsStatusString[2] = "ABEFR"[saDevice.channel / 8];
153 saCmsStatusString[3] = '1' + (saDevice.channel % 8);
154 } else {
155 saCmsStatusString[2] = 'U';
156 saCmsStatusString[3] = 'F';
159 if ((saDevice.mode & SA_MODE_GET_PITMODE)
160 && (saDevice.mode & SA_MODE_GET_OUT_RANGE_PITMODE))
161 tfp_sprintf(&saCmsStatusString[5], "%4d", saDevice.orfreq);
162 else if (saDevice.mode & SA_MODE_GET_FREQ_BY_FREQ)
163 tfp_sprintf(&saCmsStatusString[5], "%4d", saDevice.freq);
164 else
165 tfp_sprintf(&saCmsStatusString[5], "%4d",
166 vtx58frequencyTable[saDevice.channel / 8][saDevice.channel % 8]);
168 saCmsStatusString[9] = ' ';
170 if (saDevice.mode & SA_MODE_GET_PITMODE) {
171 saCmsStatusString[10] = 'P';
172 if (saDevice.mode & SA_MODE_GET_IN_RANGE_PITMODE) {
173 saCmsStatusString[11] = 'I';
174 } else {
175 saCmsStatusString[11] = 'O';
177 saCmsStatusString[12] = 'R';
178 saCmsStatusString[13] = 0;
179 } else {
180 tfp_sprintf(&saCmsStatusString[10], "%3d", (saDevice.version == 2) ? saPowerTable[saDevice.power].rfpower : saPowerTable[saDacToPowerIndex(saDevice.power)].rfpower);
184 void saCmsResetOpmodel()
186 // trigger data refresh in 'saCmsUpdate()'
187 saCmsOpmodel = SACMS_OPMODEL_UNDEF;
190 static long saCmsConfigBandByGvar(displayPort_t *pDisp, const void *self)
192 UNUSED(pDisp);
193 UNUSED(self);
195 if (saDevice.version == 0) {
196 // Bounce back; not online yet
197 saCmsBand = 0;
198 return 0;
201 if (saCmsBand == 0) {
202 // Bouce back, no going back to undef state
203 saCmsBand = 1;
204 return 0;
207 if ((saCmsOpmodel == SACMS_OPMODEL_FREE) && !saDeferred)
208 saSetBandAndChannel(saCmsBand - 1, saCmsChan - 1);
210 saCmsFreqRef = vtx58frequencyTable[saCmsBand - 1][saCmsChan - 1];
212 return 0;
215 static long saCmsConfigChanByGvar(displayPort_t *pDisp, const void *self)
217 UNUSED(pDisp);
218 UNUSED(self);
220 if (saDevice.version == 0) {
221 // Bounce back; not online yet
222 saCmsChan = 0;
223 return 0;
226 if (saCmsChan == 0) {
227 // Bounce back; no going back to undef state
228 saCmsChan = 1;
229 return 0;
232 if ((saCmsOpmodel == SACMS_OPMODEL_FREE) && !saDeferred)
233 saSetBandAndChannel(saCmsBand - 1, saCmsChan - 1);
235 saCmsFreqRef = vtx58frequencyTable[saCmsBand - 1][saCmsChan - 1];
237 return 0;
240 static long saCmsConfigPowerByGvar(displayPort_t *pDisp, const void *self)
242 UNUSED(pDisp);
243 UNUSED(self);
245 if (saDevice.version == 0) {
246 // Bounce back; not online yet
247 saCmsPower = 0;
248 return 0;
251 if (saCmsPower == 0) {
252 // Bouce back; no going back to undef state
253 saCmsPower = 1;
254 return 0;
257 if (saCmsOpmodel == SACMS_OPMODEL_FREE && !saDeferred) {
258 vtxSettingsConfigMutable()->power = saCmsPower;
261 return 0;
264 static long saCmsConfigPitFModeByGvar(displayPort_t *pDisp, const void *self)
266 UNUSED(pDisp);
267 UNUSED(self);
269 if (saDevice.version == 1) {
270 // V1 device doesn't support PIT mode; bounce back.
271 saCmsPitFMode = 0;
272 return 0;
275 dprintf(("saCmsConfigPitFmodeByGbar: saCmsPitFMode %d\r\n", saCmsPitFMode));
277 if (saCmsPitFMode == 0) {
278 // Bounce back
279 saCmsPitFMode = 1;
280 return 0;
283 if (saCmsPitFMode == 1) {
284 saSetMode(SA_MODE_SET_IN_RANGE_PITMODE);
285 } else {
286 saSetMode(SA_MODE_SET_OUT_RANGE_PITMODE);
289 return 0;
292 static long saCmsConfigFreqModeByGvar(displayPort_t *pDisp, const void *self); // Forward
294 static long saCmsConfigOpmodelByGvar(displayPort_t *pDisp, const void *self)
296 UNUSED(pDisp);
297 UNUSED(self);
299 if (saDevice.version == 1) {
300 if (saCmsOpmodel != SACMS_OPMODEL_FREE)
301 saCmsOpmodel = SACMS_OPMODEL_FREE;
302 return 0;
305 uint8_t opmodel = saCmsOpmodel;
307 dprintf(("saCmsConfigOpmodelByGvar: opmodel %d\r\n", opmodel));
309 if (opmodel == SACMS_OPMODEL_FREE) {
310 // VTX should power up transmitting.
311 // Turn off In-Range and Out-Range bits
312 saSetMode(0);
313 } else if (opmodel == SACMS_OPMODEL_RACE) {
314 // VTX should power up in pit mode.
315 // Default PitFMode is in-range to prevent users without
316 // out-range receivers from getting blinded.
317 saCmsPitFMode = 0;
318 saCmsConfigPitFModeByGvar(pDisp, self);
320 // Direct frequency mode is not available in RACE opmodel
321 saCmsFselModeNew = 0;
322 saCmsConfigFreqModeByGvar(pDisp, self);
323 } else {
324 // Trying to go back to unknown state; bounce back
325 saCmsOpmodel = SACMS_OPMODEL_UNDEF + 1;
328 return 0;
331 #ifdef USE_EXTENDED_CMS_MENUS
332 static const char * const saCmsDeviceStatusNames[] = {
333 "OFFL",
334 "ONL V1",
335 "ONL V2",
338 static OSD_TAB_t saCmsEntOnline = { &saCmsDeviceStatus, 2, saCmsDeviceStatusNames };
340 static OSD_Entry saCmsMenuStatsEntries[] = {
341 { "- SA STATS -", OME_Label, NULL, NULL, 0 },
342 { "STATUS", OME_TAB, NULL, &saCmsEntOnline, DYNAMIC },
343 { "BAUDRATE", OME_UINT16, NULL, &(OSD_UINT16_t){ &sa_smartbaud, 0, 0, 0 }, DYNAMIC },
344 { "SENT", OME_UINT16, NULL, &(OSD_UINT16_t){ &saStat.pktsent, 0, 0, 0 }, DYNAMIC },
345 { "RCVD", OME_UINT16, NULL, &(OSD_UINT16_t){ &saStat.pktrcvd, 0, 0, 0 }, DYNAMIC },
346 { "BADPRE", OME_UINT16, NULL, &(OSD_UINT16_t){ &saStat.badpre, 0, 0, 0 }, DYNAMIC },
347 { "BADLEN", OME_UINT16, NULL, &(OSD_UINT16_t){ &saStat.badlen, 0, 0, 0 }, DYNAMIC },
348 { "CRCERR", OME_UINT16, NULL, &(OSD_UINT16_t){ &saStat.crc, 0, 0, 0 }, DYNAMIC },
349 { "OOOERR", OME_UINT16, NULL, &(OSD_UINT16_t){ &saStat.ooopresp, 0, 0, 0 }, DYNAMIC },
350 { "BACK", OME_Back, NULL, NULL, 0 },
351 { NULL, OME_END, NULL, NULL, 0 }
354 static CMS_Menu saCmsMenuStats = {
355 #ifdef CMS_MENU_DEBUG
356 .GUARD_text = "XSAST",
357 .GUARD_type = OME_MENU,
358 #endif
359 .onEnter = NULL,
360 .onExit = NULL,
361 .entries = saCmsMenuStatsEntries
363 #endif /* USE_EXTENDED_CMS_MENUS */
365 static OSD_TAB_t saCmsEntBand = { &saCmsBand, VTX_SMARTAUDIO_BAND_COUNT, vtx58BandNames };
367 static OSD_TAB_t saCmsEntChan = { &saCmsChan, VTX_SMARTAUDIO_CHANNEL_COUNT, vtx58ChannelNames };
369 static OSD_TAB_t saCmsEntPower = { &saCmsPower, VTX_SMARTAUDIO_POWER_COUNT, saPowerNames};
371 static OSD_UINT16_t saCmsEntFreqRef = { &saCmsFreqRef, 5600, 5900, 0 };
373 static const char * const saCmsOpmodelNames[] = {
374 "----",
375 "FREE",
376 "RACE",
379 static const char * const saCmsFselModeNames[] = {
380 "CHAN",
381 "USER"
384 static const char * const saCmsPitFModeNames[] = {
385 "---",
386 "PIR",
387 "POR"
390 static OSD_TAB_t saCmsEntPitFMode = { &saCmsPitFMode, 1, saCmsPitFModeNames };
392 static long sacms_SetupTopMenu(void); // Forward
394 static long saCmsConfigFreqModeByGvar(displayPort_t *pDisp, const void *self)
396 UNUSED(pDisp);
397 UNUSED(self);
399 // if trying to do user frequency mode in RACE opmodel then
400 // revert because user-freq only available in FREE opmodel
401 if (saCmsFselModeNew != 0 && saCmsOpmodel != SACMS_OPMODEL_FREE) {
402 saCmsFselModeNew = 0;
405 // don't call 'saSetBandAndChannel()' / 'saSetFreq()' here,
406 // wait until SET / 'saCmsCommence()' is activated
408 sacms_SetupTopMenu();
410 return 0;
413 static long saCmsCommence(displayPort_t *pDisp, const void *self)
415 UNUSED(pDisp);
416 UNUSED(self);
418 const vtxSettingsConfig_t prevSettings = {
419 .band = vtxSettingsConfig()->band,
420 .channel = vtxSettingsConfig()->channel,
421 .freq = vtxSettingsConfig()->freq,
422 .power = vtxSettingsConfig()->power,
423 .lowPowerDisarm = vtxSettingsConfig()->lowPowerDisarm,
425 vtxSettingsConfig_t newSettings = prevSettings;
427 if (saCmsOpmodel == SACMS_OPMODEL_RACE) {
428 // Race model
429 // Setup band, freq and power.
431 newSettings.band = saCmsBand;
432 newSettings.channel = saCmsChan;
433 newSettings.freq = vtx58_Bandchan2Freq(saCmsBand, saCmsChan);
434 // If in pit mode, cancel it.
436 if (saCmsPitFMode == 0)
437 saSetMode(SA_MODE_CLR_PITMODE|SA_MODE_SET_IN_RANGE_PITMODE);
438 else
439 saSetMode(SA_MODE_CLR_PITMODE|SA_MODE_SET_OUT_RANGE_PITMODE);
440 } else {
441 // Freestyle model
442 // Setup band and freq / user freq
443 if (saCmsFselModeNew == 0) {
444 newSettings.band = saCmsBand;
445 newSettings.channel = saCmsChan;
446 newSettings.freq = vtx58_Bandchan2Freq(saCmsBand, saCmsChan);
447 } else {
448 saSetMode(0); //make sure FREE mode is setup
449 newSettings.band = 0;
450 newSettings.freq = saCmsUserFreq;
454 newSettings.power = saCmsPower;
456 if (memcmp(&prevSettings, &newSettings, sizeof(vtxSettingsConfig_t))) {
457 vtxSettingsConfigMutable()->band = newSettings.band;
458 vtxSettingsConfigMutable()->channel = newSettings.channel;
459 vtxSettingsConfigMutable()->power = newSettings.power;
460 vtxSettingsConfigMutable()->freq = newSettings.freq;
461 saveConfigAndNotify();
464 return MENU_CHAIN_BACK;
467 static long saCmsSetPORFreqOnEnter(void)
469 if (saDevice.version == 1)
470 return MENU_CHAIN_BACK;
472 saCmsORFreqNew = saCmsORFreq;
474 return 0;
477 static long saCmsSetPORFreq(displayPort_t *pDisp, const void *self)
479 UNUSED(pDisp);
480 UNUSED(self);
482 saSetPitFreq(saCmsORFreqNew);
484 return 0;
487 static char *saCmsORFreqGetString(void)
489 static char pbuf[5];
491 tfp_sprintf(pbuf, "%4d", saCmsORFreq);
493 return pbuf;
496 static char *saCmsUserFreqGetString(void)
498 static char pbuf[5];
500 tfp_sprintf(pbuf, "%4d", saCmsUserFreq);
502 return pbuf;
505 static long saCmsSetUserFreqOnEnter(void)
507 saCmsUserFreqNew = saCmsUserFreq;
509 return 0;
512 static long saCmsConfigUserFreq(displayPort_t *pDisp, const void *self)
514 UNUSED(pDisp);
515 UNUSED(self);
517 saCmsUserFreq = saCmsUserFreqNew;
519 return MENU_CHAIN_BACK;
522 static OSD_Entry saCmsMenuPORFreqEntries[] = {
523 { "- POR FREQ -", OME_Label, NULL, NULL, 0 },
525 { "CUR FREQ", OME_UINT16, NULL, &(OSD_UINT16_t){ &saCmsORFreq, 5000, 5999, 0 }, DYNAMIC },
526 { "NEW FREQ", OME_UINT16, NULL, &(OSD_UINT16_t){ &saCmsORFreqNew, 5000, 5999, 1 }, 0 },
527 { "SET", OME_Funcall, saCmsSetPORFreq, NULL, 0 },
529 { "BACK", OME_Back, NULL, NULL, 0 },
530 { NULL, OME_END, NULL, NULL, 0 }
533 static CMS_Menu saCmsMenuPORFreq =
535 #ifdef CMS_MENU_DEBUG
536 .GUARD_text = "XSAPOR",
537 .GUARD_type = OME_MENU,
538 #endif
539 .onEnter = saCmsSetPORFreqOnEnter,
540 .onExit = NULL,
541 .entries = saCmsMenuPORFreqEntries,
544 static OSD_Entry saCmsMenuUserFreqEntries[] = {
545 { "- USER FREQ -", OME_Label, NULL, NULL, 0 },
547 { "CUR FREQ", OME_UINT16, NULL, &(OSD_UINT16_t){ &saCmsUserFreq, 5000, 5999, 0 }, DYNAMIC },
548 { "NEW FREQ", OME_UINT16, NULL, &(OSD_UINT16_t){ &saCmsUserFreqNew, 5000, 5999, 1 }, 0 },
549 { "SET", OME_Funcall, saCmsConfigUserFreq, NULL, 0 },
551 { "BACK", OME_Back, NULL, NULL, 0 },
552 { NULL, OME_END, NULL, NULL, 0 }
555 static CMS_Menu saCmsMenuUserFreq =
557 #ifdef CMS_MENU_DEBUG
558 .GUARD_text = "XSAUFQ",
559 .GUARD_type = OME_MENU,
560 #endif
561 .onEnter = saCmsSetUserFreqOnEnter,
562 .onExit = NULL,
563 .entries = saCmsMenuUserFreqEntries,
566 static OSD_TAB_t saCmsEntFselMode = { &saCmsFselModeNew, 1, saCmsFselModeNames };
568 static OSD_Entry saCmsMenuConfigEntries[] = {
569 { "- SA CONFIG -", OME_Label, NULL, NULL, 0 },
571 { "OP MODEL", OME_TAB, saCmsConfigOpmodelByGvar, &(OSD_TAB_t){ &saCmsOpmodel, 2, saCmsOpmodelNames }, DYNAMIC },
572 { "FSEL MODE", OME_TAB, saCmsConfigFreqModeByGvar, &saCmsEntFselMode, DYNAMIC },
573 { "PIT FMODE", OME_TAB, saCmsConfigPitFModeByGvar, &saCmsEntPitFMode, 0 },
574 { "POR FREQ", OME_Submenu, (CMSEntryFuncPtr)saCmsORFreqGetString, &saCmsMenuPORFreq, OPTSTRING },
575 #ifdef USE_EXTENDED_CMS_MENUS
576 { "STATX", OME_Submenu, cmsMenuChange, &saCmsMenuStats, 0 },
577 #endif /* USE_EXTENDED_CMS_MENUS */
579 { "BACK", OME_Back, NULL, NULL, 0 },
580 { NULL, OME_END, NULL, NULL, 0 }
583 static CMS_Menu saCmsMenuConfig = {
584 #ifdef CMS_MENU_DEBUG
585 .GUARD_text = "XSACFG",
586 .GUARD_type = OME_MENU,
587 #endif
588 .onEnter = NULL,
589 .onExit = NULL,
590 .entries = saCmsMenuConfigEntries
593 static OSD_Entry saCmsMenuCommenceEntries[] = {
594 { "CONFIRM", OME_Label, NULL, NULL, 0 },
596 { "YES", OME_Funcall, saCmsCommence, NULL, 0 },
598 { "BACK", OME_Back, NULL, NULL, 0 },
599 { NULL, OME_END, NULL, NULL, 0 }
602 static CMS_Menu saCmsMenuCommence = {
603 #ifdef CMS_MENU_DEBUG
604 .GUARD_text = "XVTXCOM",
605 .GUARD_type = OME_MENU,
606 #endif
607 .onEnter = NULL,
608 .onExit = NULL,
609 .entries = saCmsMenuCommenceEntries,
612 static OSD_Entry saCmsMenuFreqModeEntries[] = {
613 { "- SMARTAUDIO -", OME_Label, NULL, NULL, 0 },
615 { "", OME_Label, NULL, saCmsStatusString, DYNAMIC },
616 { "FREQ", OME_Submenu, (CMSEntryFuncPtr)saCmsUserFreqGetString, &saCmsMenuUserFreq, OPTSTRING },
617 { "POWER", OME_TAB, saCmsConfigPowerByGvar, &saCmsEntPower, 0 },
618 { "SET", OME_Submenu, cmsMenuChange, &saCmsMenuCommence, 0 },
619 { "CONFIG", OME_Submenu, cmsMenuChange, &saCmsMenuConfig, 0 },
621 { "BACK", OME_Back, NULL, NULL, 0 },
622 { NULL, OME_END, NULL, NULL, 0 }
625 static OSD_Entry saCmsMenuChanModeEntries[] =
627 { "- SMARTAUDIO -", OME_Label, NULL, NULL, 0 },
629 { "", OME_Label, NULL, saCmsStatusString, DYNAMIC },
630 { "BAND", OME_TAB, saCmsConfigBandByGvar, &saCmsEntBand, 0 },
631 { "CHAN", OME_TAB, saCmsConfigChanByGvar, &saCmsEntChan, 0 },
632 { "(FREQ)", OME_UINT16, NULL, &saCmsEntFreqRef, DYNAMIC },
633 { "POWER", OME_TAB, saCmsConfigPowerByGvar, &saCmsEntPower, 0 },
634 { "SET", OME_Submenu, cmsMenuChange, &saCmsMenuCommence, 0 },
635 { "CONFIG", OME_Submenu, cmsMenuChange, &saCmsMenuConfig, 0 },
637 { "BACK", OME_Back, NULL, NULL, 0 },
638 { NULL, OME_END, NULL, NULL, 0 }
641 static OSD_Entry saCmsMenuOfflineEntries[] =
643 { "- VTX SMARTAUDIO -", OME_Label, NULL, NULL, 0 },
645 { "", OME_Label, NULL, saCmsStatusString, DYNAMIC },
646 #ifdef USE_EXTENDED_CMS_MENUS
647 { "STATX", OME_Submenu, cmsMenuChange, &saCmsMenuStats, 0 },
648 #endif /* USE_EXTENDED_CMS_MENUS */
650 { "BACK", OME_Back, NULL, NULL, 0 },
651 { NULL, OME_END, NULL, NULL, 0 }
654 CMS_Menu cmsx_menuVtxSmartAudio; // Forward
656 static long sacms_SetupTopMenu(void)
658 if (saCmsDeviceStatus) {
659 if (saCmsFselModeNew == 0)
660 cmsx_menuVtxSmartAudio.entries = saCmsMenuChanModeEntries;
661 else
662 cmsx_menuVtxSmartAudio.entries = saCmsMenuFreqModeEntries;
663 } else {
664 cmsx_menuVtxSmartAudio.entries = saCmsMenuOfflineEntries;
667 return 0;
670 CMS_Menu cmsx_menuVtxSmartAudio = {
671 #ifdef CMS_MENU_DEBUG
672 .GUARD_text = "XVTXSA",
673 .GUARD_type = OME_MENU,
674 #endif
675 .onEnter = sacms_SetupTopMenu,
676 .onExit = NULL,
677 .entries = saCmsMenuOfflineEntries,
680 #endif // CMS