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)
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/>.
25 #include <drivers/vtx_table.h>
29 #if defined(USE_CMS) && defined(USE_VTX_SMARTAUDIO)
31 #include "common/printf.h"
32 #include "common/utils.h"
35 #include "cms/cms_types.h"
36 #include "cms/cms_menu_vtx_smartaudio.h"
38 #include "drivers/vtx_common.h"
40 #include "config/config.h"
42 #include "io/vtx_smartaudio.h"
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;
74 uint8_t saCmsPitFMode
; // Undef(0), In-Range(1) or Out-Range(2)
76 uint8_t saCmsFselMode
; // Channel(0) or User defined(1)
77 uint8_t saCmsFselModeNew
; // Channel(0) or User defined(1)
79 uint16_t saCmsORFreq
= 0; // POR frequency
80 uint16_t saCmsORFreqNew
; // POR frequency
82 uint16_t saCmsUserFreq
= 0; // User defined frequency
83 uint16_t saCmsUserFreqNew
; // User defined frequency
85 void saCmsUpdate(void)
87 // XXX Take care of pit mode update somewhere???
88 if (saCmsOpmodel
== SACMS_OPMODEL_UNDEF
) {
89 // This is a first valid response to GET_SETTINGS.
90 saCmsOpmodel
= saDevice
.willBootIntoPitMode
? SACMS_OPMODEL_RACE
: SACMS_OPMODEL_FREE
;
92 saCmsFselMode
= (saDevice
.mode
& SA_MODE_GET_FREQ_BY_FREQ
) && vtxSettingsConfig()->band
== 0 ? 1 : 0;
94 saCmsBand
= vtxSettingsConfig()->band
;
95 saCmsChan
= vtxSettingsConfig()->channel
;
96 saCmsFreqRef
= vtxSettingsConfig()->freq
;
97 saCmsDeviceFreq
= saCmsFreqRef
;
99 if ((saDevice
.mode
& SA_MODE_GET_PITMODE
) == 0) {
100 saCmsRFState
= SACMS_TXMODE_ACTIVE
;
101 } else if (saDevice
.mode
& SA_MODE_GET_IN_RANGE_PITMODE
) {
102 saCmsRFState
= SACMS_TXMODE_PIT_INRANGE
;
104 saCmsRFState
= SACMS_TXMODE_PIT_OUTRANGE
;
107 saCmsPower
= vtxSettingsConfig()->power
;
109 // if user-freq mode then track possible change
110 if (saCmsFselMode
&& vtxSettingsConfig()->freq
) {
111 saCmsUserFreq
= vtxSettingsConfig()->freq
;
114 saCmsFselModeNew
= saCmsFselMode
; //init mode for menu
117 saUpdateStatusString();
120 char saCmsStatusString
[31] = "- -- ---- ---";
124 static const void *saCmsConfigOpmodelByGvar(displayPort_t
*, const void *self
);
125 static const void *saCmsConfigPitFModeByGvar(displayPort_t
*, const void *self
);
126 static const void *saCmsConfigBandByGvar(displayPort_t
*, const void *self
);
127 static const void *saCmsConfigChanByGvar(displayPort_t
*, const void *self
);
128 static const void *saCmsConfigPowerByGvar(displayPort_t
*, const void *self
);
129 static const void *saCmsConfigPitByGvar(displayPort_t
*, const void *self
);
131 void saUpdateStatusString(void)
133 if (saDevice
.version
== 0)
136 // XXX These should be done somewhere else
137 if (saCmsDeviceStatus
== 0 && saDevice
.version
!= 0)
138 saCmsDeviceStatus
= saDevice
.version
;
139 if (saCmsORFreq
== 0 && saDevice
.orfreq
!= 0)
140 saCmsORFreq
= saDevice
.orfreq
;
141 if (saCmsUserFreq
== 0 && saDevice
.freq
!= 0)
142 saCmsUserFreq
= saDevice
.freq
;
144 if (saDevice
.version
== 2) {
145 if (saDevice
.mode
& SA_MODE_GET_OUT_RANGE_PITMODE
)
149 } else if (saDevice
.version
== 3) {
150 saCmsPitFMode
= 1;//V2.1 only supports PIR
153 const vtxDevice_t
*device
= vtxCommonDevice();
155 saCmsStatusString
[0] = "-FR"[saCmsOpmodel
];
157 if (saCmsFselMode
== 0) {
160 vtxCommonGetBandAndChannel(device
, &band
, &channel
);
161 saCmsStatusString
[2] = vtxCommonLookupBandLetter(device
, band
);
162 saCmsStatusString
[3] = vtxCommonLookupChannelName(device
, channel
)[0];
164 saCmsStatusString
[2] = 'U';
165 saCmsStatusString
[3] = 'F';
168 if ((saDevice
.mode
& SA_MODE_GET_PITMODE
)
169 && (saDevice
.mode
& SA_MODE_GET_OUT_RANGE_PITMODE
)) {
170 tfp_sprintf(&saCmsStatusString
[5], "%4d", saDevice
.orfreq
);
173 vtxCommonGetFrequency(device
, &freq
);
174 tfp_sprintf(&saCmsStatusString
[5], "%4d", freq
);
177 saCmsStatusString
[9] = ' ';
179 if (saDevice
.mode
& SA_MODE_GET_PITMODE
) {
181 saCmsStatusString
[10] = 'P';
182 if (saDevice
.mode
& SA_MODE_GET_OUT_RANGE_PITMODE
) {
183 saCmsStatusString
[11] = 'O';
185 saCmsStatusString
[11] = 'I';
187 saCmsStatusString
[12] = 'R';
188 saCmsStatusString
[13] = 0;
191 uint8_t powerIndex
= 0;
192 bool powerFound
= vtxCommonGetPowerIndex(device
, &powerIndex
);
193 tfp_sprintf(&saCmsStatusString
[10], "%s", powerFound
? vtxCommonLookupPowerName(device
, powerIndex
) : "???");
196 if (vtxTableBandCount
== 0 || vtxTablePowerLevels
== 0) {
197 strncpy(saCmsStatusString
, "PLEASE CONFIGURE VTXTABLE", sizeof(saCmsStatusString
));
201 void saCmsResetOpmodel(void)
203 // trigger data refresh in 'saCmsUpdate()'
204 saCmsOpmodel
= SACMS_OPMODEL_UNDEF
;
207 static const void *saCmsConfigBandByGvar(displayPort_t
*pDisp
, const void *self
)
212 if (saDevice
.version
== 0) {
213 // Bounce back; not online yet
218 if (saCmsBand
== 0) {
219 // Bouce back, no going back to undef state
224 if ((saCmsOpmodel
== SACMS_OPMODEL_FREE
) && !saDeferred
) {
225 vtxCommonSetBandAndChannel(vtxCommonDevice(), saCmsBand
, saCmsChan
);
228 saCmsFreqRef
= vtxCommonLookupFrequency(vtxCommonDevice(), saCmsBand
, saCmsChan
);
233 static const void *saCmsConfigChanByGvar(displayPort_t
*pDisp
, const void *self
)
238 if (saDevice
.version
== 0) {
239 // Bounce back; not online yet
244 if (saCmsChan
== 0) {
245 // Bounce back; no going back to undef state
250 if ((saCmsOpmodel
== SACMS_OPMODEL_FREE
) && !saDeferred
) {
251 vtxCommonSetBandAndChannel(vtxCommonDevice(), saCmsBand
, saCmsChan
);
254 saCmsFreqRef
= vtxCommonLookupFrequency(vtxCommonDevice(), saCmsBand
, saCmsChan
);
259 static const void *saCmsConfigPitByGvar(displayPort_t
*pDisp
, const void *self
)
264 dprintf(("saCmsConfigPitByGvar: saCmsPit %d\r\n", saCmsPit
));
266 if (saDevice
.version
== 0) {
267 // Bounce back; not online yet
272 if (saCmsPit
== 0) {//trying to go back to undef state; bounce back
276 if (saDevice
.power
!= saCmsPower
) {//we can't change both power and pit mode at once
277 saCmsPower
= saDevice
.power
;
283 static const void *saCmsConfigPowerByGvar(displayPort_t
*pDisp
, const void *self
)
288 if (saDevice
.version
== 0) {
289 // Bounce back; not online yet
294 if (saCmsPower
== 0) {
295 // Bouce back; no going back to undef state
300 if (saCmsPit
> 0 && saCmsPit
!= 1 ) {
304 if (saCmsOpmodel
== SACMS_OPMODEL_FREE
&& !saDeferred
) {
305 vtxSettingsConfigMutable()->power
= saCmsPower
;
307 dprintf(("saCmsConfigPowerByGvar: power index is now %d\r\n", saCmsPower
));
312 static const void *saCmsConfigPitFModeByGvar(displayPort_t
*pDisp
, const void *self
)
317 if (saDevice
.version
== 1) {
318 // V1 device doesn't support PIT mode; bounce back.
322 if (saDevice
.version
>= 3) {
323 // V2.1 device only supports PIR mode. and setting any flag immediately enables pit mode.
324 //therefore: bounce back.
329 dprintf(("saCmsConfigPitFmodeByGbar: saCmsPitFMode %d\r\n", saCmsPitFMode
));
331 if (saCmsPitFMode
== 0) {
337 if (saCmsPitFMode
== 1) {
338 saSetMode(SA_MODE_SET_IN_RANGE_PITMODE
);
340 saSetMode(SA_MODE_SET_OUT_RANGE_PITMODE
);
346 static const void *saCmsConfigFreqModeByGvar(displayPort_t
*pDisp
, const void *self
); // Forward
348 static const void *saCmsConfigOpmodelByGvar(displayPort_t
*pDisp
, const void *self
)
353 if (saDevice
.version
== 1) {
354 if (saCmsOpmodel
!= SACMS_OPMODEL_FREE
)
355 saCmsOpmodel
= SACMS_OPMODEL_FREE
;
359 uint8_t opmodel
= saCmsOpmodel
;
361 dprintf(("saCmsConfigOpmodelByGvar: opmodel %d\r\n", opmodel
));
363 if (opmodel
== SACMS_OPMODEL_FREE
) {
364 // VTX should power up transmitting.
365 // Turn off In-Range and Out-Range bits
367 } else if (opmodel
== SACMS_OPMODEL_RACE
) {
368 // VTX should power up in pit mode.
369 // Default PitFMode is in-range to prevent users without
370 // out-range receivers from getting blinded.
372 saCmsConfigPitFModeByGvar(pDisp
, self
);
373 if (saDevice
.version
>= 3) {
374 saSetMode(SA_MODE_SET_IN_RANGE_PITMODE
| ((saDevice
.mode
& SA_MODE_GET_PITMODE
) ? 0 : SA_MODE_CLR_PITMODE
));
377 // Direct frequency mode is not available in RACE opmodel
378 saCmsFselModeNew
= 0;
379 saCmsConfigFreqModeByGvar(pDisp
, self
);
381 // Trying to go back to unknown state; bounce back
382 saCmsOpmodel
= SACMS_OPMODEL_UNDEF
+ 1;
388 #ifdef USE_EXTENDED_CMS_MENUS
389 static const char * const saCmsDeviceStatusNames
[] = {
396 static OSD_TAB_t saCmsEntOnline
= { &saCmsDeviceStatus
, 3, saCmsDeviceStatusNames
};
398 static const OSD_Entry saCmsMenuStatsEntries
[] = {
399 { "- SA STATS -", OME_Label
, NULL
, NULL
},
400 { "STATUS", OME_TAB
| DYNAMIC
, NULL
, &saCmsEntOnline
},
401 { "BAUDRATE", OME_UINT16
| DYNAMIC
, NULL
, &(OSD_UINT16_t
){ &sa_smartbaud
, 0, 0, 0 } },
402 { "SENT", OME_UINT16
| DYNAMIC
, NULL
, &(OSD_UINT16_t
){ &saStat
.pktsent
, 0, 0, 0 } },
403 { "RCVD", OME_UINT16
| DYNAMIC
, NULL
, &(OSD_UINT16_t
){ &saStat
.pktrcvd
, 0, 0, 0 } },
404 { "BADPRE", OME_UINT16
| DYNAMIC
, NULL
, &(OSD_UINT16_t
){ &saStat
.badpre
, 0, 0, 0 } },
405 { "BADLEN", OME_UINT16
| DYNAMIC
, NULL
, &(OSD_UINT16_t
){ &saStat
.badlen
, 0, 0, 0 } },
406 { "CRCERR", OME_UINT16
| DYNAMIC
, NULL
, &(OSD_UINT16_t
){ &saStat
.crc
, 0, 0, 0 } },
407 { "OOOERR", OME_UINT16
| DYNAMIC
, NULL
, &(OSD_UINT16_t
){ &saStat
.ooopresp
, 0, 0, 0 } },
408 { "BACK", OME_Back
, NULL
, NULL
},
409 { NULL
, OME_END
, NULL
, NULL
}
412 static CMS_Menu saCmsMenuStats
= {
413 #ifdef CMS_MENU_DEBUG
414 .GUARD_text
= "XSAST",
415 .GUARD_type
= OME_MENU
,
419 .onDisplayUpdate
= NULL
,
420 .entries
= saCmsMenuStatsEntries
422 #endif /* USE_EXTENDED_CMS_MENUS */
424 static OSD_TAB_t saCmsEntBand
;
425 static OSD_TAB_t saCmsEntChan
;
426 static OSD_TAB_t saCmsEntPower
;
428 static void saCmsInitNames(void)
430 saCmsEntBand
.val
= &saCmsBand
;
431 saCmsEntBand
.max
= vtxTableBandCount
;
432 saCmsEntBand
.names
= vtxTableBandNames
;
434 saCmsEntChan
.val
= &saCmsChan
;
435 saCmsEntChan
.max
= vtxTableChannelCount
;
436 saCmsEntChan
.names
= vtxTableChannelNames
;
438 saCmsEntPower
.val
= &saCmsPower
;
439 saCmsEntPower
.max
= vtxTablePowerLevels
;
440 saCmsEntPower
.names
= vtxTablePowerLabels
;
443 static OSD_UINT16_t saCmsEntFreqRef
= { &saCmsFreqRef
, 5600, 5900, 0 };
445 static const char * const saCmsOpmodelNames
[] = {
451 static const char * const saCmsFselModeNames
[] = {
456 static const char * const saCmsPitFModeNames
[] = {
462 static const char * const saCmsPitNames
[] = {
468 static OSD_TAB_t saCmsEntPitFMode
= { &saCmsPitFMode
, 1, saCmsPitFModeNames
};
469 static OSD_TAB_t saCmsEntPit
= {&saCmsPit
, 2, saCmsPitNames
};
471 static const void *sacms_SetupTopMenu(displayPort_t
*pDisp
); // Forward
473 static const void *saCmsConfigFreqModeByGvar(displayPort_t
*pDisp
, const void *self
)
478 // if trying to do user frequency mode in RACE opmodel then
479 // revert because user-freq only available in FREE opmodel
480 if (saCmsFselModeNew
!= 0 && saCmsOpmodel
!= SACMS_OPMODEL_FREE
) {
481 saCmsFselModeNew
= 0;
484 // don't call 'saSetBandAndChannel()' / 'saSetFreq()' here,
485 // wait until SET / 'saCmsCommence()' is activated
487 sacms_SetupTopMenu(pDisp
);
492 static const void *saCmsCommence(displayPort_t
*pDisp
, const void *self
)
494 const vtxSettingsConfig_t prevSettings
= {
495 .band
= vtxSettingsConfig()->band
,
496 .channel
= vtxSettingsConfig()->channel
,
497 .freq
= vtxSettingsConfig()->freq
,
498 .power
= vtxSettingsConfig()->power
,
499 .lowPowerDisarm
= vtxSettingsConfig()->lowPowerDisarm
,
501 vtxSettingsConfig_t newSettings
= prevSettings
;
503 if (saCmsOpmodel
== SACMS_OPMODEL_RACE
) {
505 // Setup band, freq and power.
507 newSettings
.band
= saCmsBand
;
508 newSettings
.channel
= saCmsChan
;
509 newSettings
.freq
= vtxCommonLookupFrequency(vtxCommonDevice(), saCmsBand
, saCmsChan
);
512 // Setup band and freq / user freq
513 if (saCmsFselModeNew
== 0) {
514 newSettings
.band
= saCmsBand
;
515 newSettings
.channel
= saCmsChan
;
516 newSettings
.freq
= vtxCommonLookupFrequency(vtxCommonDevice(), saCmsBand
, saCmsChan
);
518 saSetMode(0); //make sure FREE mode is setup
519 newSettings
.band
= 0;
520 newSettings
.freq
= saCmsUserFreq
;
524 if (newSettings
.power
== saCmsPower
&& saCmsPit
> 0) {
525 vtxCommonSetPitMode(vtxCommonDevice(), saCmsPit
== 2);
527 newSettings
.power
= saCmsPower
;
529 if (memcmp(&prevSettings
, &newSettings
, sizeof(vtxSettingsConfig_t
))) {
530 vtxSettingsConfigMutable()->band
= newSettings
.band
;
531 vtxSettingsConfigMutable()->channel
= newSettings
.channel
;
532 vtxSettingsConfigMutable()->power
= newSettings
.power
;
533 vtxSettingsConfigMutable()->freq
= newSettings
.freq
;
534 saveConfigAndNotify();
537 cmsMenuExit(pDisp
, self
);
539 return MENU_CHAIN_BACK
;
542 static const void *saCmsSetPORFreqOnEnter(displayPort_t
*pDisp
)
546 if (saDevice
.version
== 1)
547 return MENU_CHAIN_BACK
;
549 saCmsORFreqNew
= saCmsORFreq
;
554 static const void *saCmsSetPORFreq(displayPort_t
*pDisp
, const void *self
)
559 saSetPitFreq(saCmsORFreqNew
);
564 static const char *saCmsORFreqGetString(displayPort_t
*pDisp
, const void *self
)
571 tfp_sprintf(pbuf
, "%4d", saCmsORFreq
);
576 static const char *saCmsUserFreqGetString(displayPort_t
*pDisp
, const void *self
)
583 tfp_sprintf(pbuf
, "%4d", saCmsUserFreq
);
588 static const void *saCmsSetUserFreqOnEnter(displayPort_t
*pDisp
)
592 saCmsUserFreqNew
= saCmsUserFreq
;
597 static const void *saCmsConfigUserFreq(displayPort_t
*pDisp
, const void *self
)
602 saCmsUserFreq
= saCmsUserFreqNew
;
604 return MENU_CHAIN_BACK
;
607 static const OSD_Entry saCmsMenuPORFreqEntries
[] = {
608 { "- POR FREQ -", OME_Label
, NULL
, NULL
},
610 { "CUR FREQ", OME_UINT16
| DYNAMIC
, NULL
, &(OSD_UINT16_t
){ &saCmsORFreq
, 5000, 5999, 0 } },
611 { "NEW FREQ", OME_UINT16
, NULL
, &(OSD_UINT16_t
){ &saCmsORFreqNew
, 5000, 5999, 1 } },
612 { "SAVE", OME_Funcall
, saCmsSetPORFreq
, NULL
},
614 { "BACK", OME_Back
, NULL
, NULL
},
615 { NULL
, OME_END
, NULL
, NULL
}
618 static CMS_Menu saCmsMenuPORFreq
=
620 #ifdef CMS_MENU_DEBUG
621 .GUARD_text
= "XSAPOR",
622 .GUARD_type
= OME_MENU
,
624 .onEnter
= saCmsSetPORFreqOnEnter
,
626 .onDisplayUpdate
= NULL
,
627 .entries
= saCmsMenuPORFreqEntries
,
630 static const OSD_Entry saCmsMenuUserFreqEntries
[] = {
631 { "- USER FREQ -", OME_Label
, NULL
, NULL
},
633 { "CUR FREQ", OME_UINT16
| DYNAMIC
, NULL
, &(OSD_UINT16_t
){ &saCmsUserFreq
, 5000, 5999, 0 } },
634 { "NEW FREQ", OME_UINT16
, NULL
, &(OSD_UINT16_t
){ &saCmsUserFreqNew
, 5000, 5999, 1 } },
635 { "SAVE", OME_Funcall
, saCmsConfigUserFreq
, NULL
},
637 { "BACK", OME_Back
, NULL
, NULL
},
638 { NULL
, OME_END
, NULL
, NULL
}
641 static CMS_Menu saCmsMenuUserFreq
=
643 #ifdef CMS_MENU_DEBUG
644 .GUARD_text
= "XSAUFQ",
645 .GUARD_type
= OME_MENU
,
647 .onEnter
= saCmsSetUserFreqOnEnter
,
649 .onDisplayUpdate
= NULL
,
650 .entries
= saCmsMenuUserFreqEntries
,
653 static OSD_TAB_t saCmsEntFselMode
= { &saCmsFselModeNew
, 1, saCmsFselModeNames
};
655 static const OSD_Entry saCmsMenuConfigEntries
[] = {
656 { "- SA CONFIG -", OME_Label
, NULL
, NULL
},
658 { "OP MODEL", OME_TAB
| DYNAMIC
, saCmsConfigOpmodelByGvar
, &(OSD_TAB_t
){ &saCmsOpmodel
, 2, saCmsOpmodelNames
} },
659 { "FSEL MODE", OME_TAB
| DYNAMIC
, saCmsConfigFreqModeByGvar
, &saCmsEntFselMode
},
660 { "PIT FMODE", OME_TAB
, saCmsConfigPitFModeByGvar
, &saCmsEntPitFMode
},
661 { "POR FREQ", OME_Submenu
| OPTSTRING
, (CMSEntryFuncPtr
)saCmsORFreqGetString
, &saCmsMenuPORFreq
},
662 #ifdef USE_EXTENDED_CMS_MENUS
663 { "STATX", OME_Submenu
, cmsMenuChange
, &saCmsMenuStats
},
664 #endif /* USE_EXTENDED_CMS_MENUS */
666 { "BACK", OME_Back
, NULL
, NULL
},
667 { NULL
, OME_END
, NULL
, NULL
}
670 static CMS_Menu saCmsMenuConfig
= {
671 #ifdef CMS_MENU_DEBUG
672 .GUARD_text
= "XSACFG",
673 .GUARD_type
= OME_MENU
,
677 .onDisplayUpdate
= NULL
,
678 .entries
= saCmsMenuConfigEntries
681 static const OSD_Entry saCmsMenuCommenceEntries
[] = {
682 { "CONFIRM", OME_Label
, NULL
, NULL
},
684 { "YES", OME_OSD_Exit
, saCmsCommence
, (void *)CMS_EXIT
},
686 { "NO", OME_Back
, NULL
, NULL
},
687 { NULL
, OME_END
, NULL
, NULL
}
690 static CMS_Menu saCmsMenuCommence
= {
691 #ifdef CMS_MENU_DEBUG
692 .GUARD_text
= "XVTXCOM",
693 .GUARD_type
= OME_MENU
,
697 .onDisplayUpdate
= NULL
,
698 .entries
= saCmsMenuCommenceEntries
,
701 static const OSD_Entry saCmsMenuFreqModeEntries
[] = {
702 { "- SMARTAUDIO -", OME_Label
, NULL
, NULL
},
704 { "", OME_Label
| DYNAMIC
, NULL
, saCmsStatusString
},
705 { "FREQ", OME_Submenu
| OPTSTRING
, (CMSEntryFuncPtr
)saCmsUserFreqGetString
, &saCmsMenuUserFreq
},
706 { "POWER", OME_TAB
| DYNAMIC
, saCmsConfigPowerByGvar
, &saCmsEntPower
},
707 { "PIT", OME_TAB
| DYNAMIC
, saCmsConfigPitByGvar
, &saCmsEntPit
},
708 { "SAVE&EXIT", OME_Submenu
, cmsMenuChange
, &saCmsMenuCommence
},
709 { "CONFIG", OME_Submenu
, cmsMenuChange
, &saCmsMenuConfig
},
711 { "BACK", OME_Back
, NULL
, NULL
},
712 { NULL
, OME_END
, NULL
, NULL
}
715 static const OSD_Entry saCmsMenuChanModeEntries
[] =
717 { "- SMARTAUDIO -", OME_Label
, NULL
, NULL
},
719 { "", OME_Label
| DYNAMIC
, NULL
, saCmsStatusString
},
720 { "BAND", OME_TAB
, saCmsConfigBandByGvar
, &saCmsEntBand
},
721 { "CHAN", OME_TAB
, saCmsConfigChanByGvar
, &saCmsEntChan
},
722 { "(FREQ)", OME_UINT16
| DYNAMIC
, NULL
, &saCmsEntFreqRef
},
723 { "POWER", OME_TAB
| DYNAMIC
, saCmsConfigPowerByGvar
, &saCmsEntPower
},
724 { "PIT", OME_TAB
| DYNAMIC
, saCmsConfigPitByGvar
, &saCmsEntPit
},
725 { "SAVE&EXIT", OME_Submenu
, cmsMenuChange
, &saCmsMenuCommence
},
726 { "CONFIG", OME_Submenu
, cmsMenuChange
, &saCmsMenuConfig
},
728 { "BACK", OME_Back
, NULL
, NULL
},
729 { NULL
, OME_END
, NULL
, NULL
}
732 static const OSD_Entry saCmsMenuOfflineEntries
[] =
734 { "- VTX SMARTAUDIO -", OME_Label
, NULL
, NULL
},
736 { "", OME_Label
| DYNAMIC
, NULL
, saCmsStatusString
},
737 #ifdef USE_EXTENDED_CMS_MENUS
738 { "STATX", OME_Submenu
, cmsMenuChange
, &saCmsMenuStats
},
739 #endif /* USE_EXTENDED_CMS_MENUS */
741 { "BACK", OME_Back
, NULL
, NULL
},
742 { NULL
, OME_END
, NULL
, NULL
}
745 CMS_Menu cmsx_menuVtxSmartAudio
; // Forward
747 static const void *sacms_SetupTopMenu(displayPort_t
*pDisp
)
751 if (saCmsDeviceStatus
) {
752 if (saCmsFselModeNew
== 0)
753 cmsx_menuVtxSmartAudio
.entries
= saCmsMenuChanModeEntries
;
755 cmsx_menuVtxSmartAudio
.entries
= saCmsMenuFreqModeEntries
;
757 cmsx_menuVtxSmartAudio
.entries
= saCmsMenuOfflineEntries
;
765 CMS_Menu cmsx_menuVtxSmartAudio
= {
766 #ifdef CMS_MENU_DEBUG
767 .GUARD_text
= "XVTXSA",
768 .GUARD_type
= OME_MENU
,
770 .onEnter
= sacms_SetupTopMenu
,
772 .onDisplayUpdate
= NULL
,
773 .entries
= saCmsMenuOfflineEntries
,