continuation of last nights statusbar cleanup.
[kugel-rb.git] / apps / recorder / radio.c
blob8c8c56cb346c7134f33a3dd493e3d0c548d9747c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2003 Linus Nielsen Feltzing
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "config.h"
23 #include <stdio.h>
24 #include <stdbool.h>
25 #include <stdlib.h>
26 #include "sprintf.h"
27 #include "mas.h"
28 #include "settings.h"
29 #include "button.h"
30 #include "status.h"
31 #include "thread.h"
32 #include "mpeg.h"
33 #include "audio.h"
34 #include "mp3_playback.h"
35 #include "ctype.h"
36 #include "file.h"
37 #include "errno.h"
38 #include "string.h"
39 #include "system.h"
40 #include "radio.h"
41 #include "menu.h"
42 #include "misc.h"
43 #include "keyboard.h"
44 #include "screens.h"
45 #include "peakmeter.h"
46 #include "lang.h"
47 #include "font.h"
48 #include "sound_menu.h"
49 #ifdef HAVE_RECORDING
50 #include "recording.h"
51 #endif
52 #include "talk.h"
53 #include "tuner.h"
54 #include "power.h"
55 #include "sound.h"
56 #include "screen_access.h"
57 #include "statusbar.h"
58 #include "splash.h"
59 #include "yesno.h"
60 #include "buttonbar.h"
61 #include "power.h"
62 #include "tree.h"
63 #include "dir.h"
64 #include "action.h"
65 #include "list.h"
66 #include "menus/exported_menus.h"
67 #include "root_menu.h"
68 #include "viewport.h"
70 #if CONFIG_TUNER
72 #if CONFIG_KEYPAD == RECORDER_PAD
73 #define FM_RECORD
74 #define FM_PRESET_ADD
75 #define FM_PRESET_ACTION
76 #define FM_PRESET
77 #define FM_MODE
79 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
80 #define FM_PRESET
81 #define FM_MODE
82 #define FM_NEXT_PRESET
83 #define FM_PREV_PRESET
85 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
86 #define FM_PRESET
87 #define FM_MODE
89 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
90 #define FM_PRESET
91 #define FM_MODE
92 /* This should be removeable if the whole tuning thing is sorted out since
93 proper tuning quiets the screen almost entirely in that extreme measures
94 have to be taken to hear any interference. */
95 #define HAVE_NOISY_IDLE_MODE
97 #elif CONFIG_KEYPAD == ONDIO_PAD
98 #define FM_RECORD_DBLPRE
99 #define FM_RECORD
100 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
101 #define FM_MENU
102 #define FM_PRESET
103 #define FM_STOP
104 #define FM_MODE
105 #define FM_EXIT
106 #define FM_PLAY
108 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
109 #define FM_PRESET
110 #define FM_MODE
111 #endif
113 #define RADIO_SCAN_MODE 0
114 #define RADIO_PRESET_MODE 1
116 static int curr_preset = -1;
117 static int curr_freq; /* current frequency in Hz */
118 static int radio_mode = RADIO_SCAN_MODE;
119 static int search_dir = 0;
121 static int radio_status = FMRADIO_OFF;
122 static bool in_screen = false;
124 #define MAX_PRESETS 64
125 static bool presets_loaded = false, presets_changed = false;
126 static struct fmstation presets[MAX_PRESETS];
128 static char filepreset[MAX_PATH]; /* preset filename variable */
130 static int num_presets = 0; /* The number of presets in the preset list */
132 static void radio_save_presets(void);
133 static int handle_radio_presets(void);
134 static bool radio_menu(void);
135 static int radio_add_preset(void);
136 static int save_preset_list(void);
137 static int load_preset_list(void);
138 static int clear_preset_list(void);
140 static int scan_presets(void *viewports);
142 /* Function to manipulate all yesno dialogues.
143 This function needs the output text as an argument. */
144 static bool yesno_pop(const char* text)
146 int i;
147 const char *lines[]={text};
148 const struct text_message message={lines, 1};
149 bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES);
150 FOR_NB_SCREENS(i)
151 screens[i].clear_viewport();
152 return ret;
155 void radio_init(void)
157 tuner_init();
158 radio_stop();
161 int get_radio_status(void)
163 return radio_status;
166 bool in_radio_screen(void)
168 return in_screen;
171 /* TODO: Move some more of the control functionality to firmware
172 and clean up the mess */
174 /* secret flag for starting paused - prevents unmute */
175 #define FMRADIO_START_PAUSED 0x8000
176 void radio_start(void)
178 const struct fm_region_data *fmr;
179 bool start_paused;
181 if(radio_status == FMRADIO_PLAYING)
182 return;
184 fmr = &fm_region_data[global_settings.fm_region];
186 start_paused = radio_status & FMRADIO_START_PAUSED;
187 /* clear flag before any yielding */
188 radio_status &= ~FMRADIO_START_PAUSED;
190 if(radio_status == FMRADIO_OFF)
191 tuner_power(true);
193 curr_freq = global_status.last_frequency * fmr->freq_step + fmr->freq_min;
195 tuner_set(RADIO_SLEEP, 0); /* wake up the tuner */
197 if(radio_status == FMRADIO_OFF)
199 #ifdef HAVE_RADIO_REGION
200 tuner_set(RADIO_REGION, global_settings.fm_region);
201 #endif
202 tuner_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
205 tuner_set(RADIO_FREQUENCY, curr_freq);
207 #ifdef HAVE_RADIO_MUTE_TIMEOUT
209 unsigned long mute_timeout = current_tick + HZ;
210 if (radio_status != FMRADIO_OFF)
212 /* paused */
213 mute_timeout += HZ;
216 while(!tuner_get(RADIO_STEREO) && !tuner_get(RADIO_TUNED))
218 if(TIME_AFTER(current_tick, mute_timeout))
219 break;
220 yield();
223 #endif
225 /* keep radio from sounding initially */
226 if(!start_paused)
227 tuner_set(RADIO_MUTE, 0);
229 radio_status = FMRADIO_PLAYING;
230 } /* radio_start */
232 void radio_pause(void)
234 if(radio_status == FMRADIO_PAUSED)
235 return;
237 if(radio_status == FMRADIO_OFF)
239 radio_status |= FMRADIO_START_PAUSED;
240 radio_start();
243 tuner_set(RADIO_MUTE, 1);
244 tuner_set(RADIO_SLEEP, 1);
246 radio_status = FMRADIO_PAUSED;
247 } /* radio_pause */
249 void radio_stop(void)
251 if(radio_status == FMRADIO_OFF)
252 return;
254 tuner_set(RADIO_MUTE, 1);
255 tuner_set(RADIO_SLEEP, 1); /* low power mode, if available */
256 radio_status = FMRADIO_OFF;
257 tuner_power(false); /* status update, power off if avail. */
258 } /* radio_stop */
260 bool radio_hardware_present(void)
262 return tuner_get(RADIO_PRESENT);
265 /* Keep freq on the grid for the current region */
266 static int snap_freq_to_grid(int freq)
268 const struct fm_region_data * const fmr =
269 &fm_region_data[global_settings.fm_region];
271 /* Range clamp if out of range or just round to nearest */
272 if (freq < fmr->freq_min)
273 freq = fmr->freq_min;
274 else if (freq > fmr->freq_max)
275 freq = fmr->freq_max;
276 else
277 freq = (freq - fmr->freq_min + fmr->freq_step/2) /
278 fmr->freq_step * fmr->freq_step + fmr->freq_min;
280 return freq;
283 /* Find a matching preset to freq */
284 static int find_preset(int freq)
286 int i;
287 if(num_presets < 1)
288 return -1;
289 for(i = 0;i < MAX_PRESETS;i++)
291 if(freq == presets[i].frequency)
292 return i;
295 return -1;
298 /* Return the closest preset encountered in the search direction with
299 wraparound. */
300 static int find_closest_preset(int freq, int direction)
302 int i;
303 int lowpreset = 0;
304 int highpreset = 0;
305 int closest = -1;
307 if (direction == 0) /* direction == 0 isn't really used */
308 return 0;
310 for (i = 0; i < num_presets; i++)
312 int f = presets[i].frequency;
313 if (f == freq)
314 return i; /* Exact match = stop */
316 /* remember the highest and lowest presets for wraparound */
317 if (f < presets[lowpreset].frequency)
318 lowpreset = i;
319 if (f > presets[highpreset].frequency)
320 highpreset = i;
322 /* find the closest preset in the given direction */
323 if (direction > 0 && f > freq)
325 if (closest < 0 || f < presets[closest].frequency)
326 closest = i;
328 else if (direction < 0 && f < freq)
330 if (closest < 0 || f > presets[closest].frequency)
331 closest = i;
335 if (closest < 0)
337 /* no presets in the given direction */
338 /* wrap around depending on direction */
339 if (direction < 0)
340 closest = highpreset;
341 else
342 closest = lowpreset;
345 return closest;
348 static void remember_frequency(void)
350 const struct fm_region_data * const fmr =
351 &fm_region_data[global_settings.fm_region];
352 global_status.last_frequency = (curr_freq - fmr->freq_min)
353 / fmr->freq_step;
354 status_save();
357 static void next_preset(int direction)
359 if (num_presets < 1)
360 return;
362 if (curr_preset == -1)
363 curr_preset = find_closest_preset(curr_freq, direction);
364 else
365 curr_preset = (curr_preset + direction + num_presets) % num_presets;
367 /* Must stay on the current grid for the region */
368 curr_freq = snap_freq_to_grid(presets[curr_preset].frequency);
370 tuner_set(RADIO_FREQUENCY, curr_freq);
371 remember_frequency();
374 /* Step to the next or previous frequency */
375 static int step_freq(int freq, int direction)
377 const struct fm_region_data * const fmr =
378 &fm_region_data[global_settings.fm_region];
380 freq += direction*fmr->freq_step;
382 /* Wrap first or snapping to grid will not let us on the band extremes */
383 if (freq > fmr->freq_max)
384 freq = direction > 0 ? fmr->freq_min : fmr->freq_max;
385 else if (freq < fmr->freq_min)
386 freq = direction < 0 ? fmr->freq_max : fmr->freq_min;
387 else
388 freq = snap_freq_to_grid(freq);
390 return freq;
393 /* Step to the next or previous station */
394 static void next_station(int direction)
396 if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
398 next_preset(direction);
399 return;
402 curr_freq = step_freq(curr_freq, direction);
404 if (radio_status == FMRADIO_PLAYING)
405 tuner_set(RADIO_MUTE, 1);
407 tuner_set(RADIO_FREQUENCY, curr_freq);
409 if (radio_status == FMRADIO_PLAYING)
410 tuner_set(RADIO_MUTE, 0);
412 curr_preset = find_preset(curr_freq);
413 remember_frequency();
416 /* Ends an in-progress search */
417 static void end_search(void)
419 if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
420 tuner_set(RADIO_MUTE, 0);
421 search_dir = 0;
424 /* Speak a frequency. */
425 static void talk_freq(int freq, bool enqueue)
427 freq /= 10000;
428 talk_number(freq / 100, enqueue);
429 talk_id(LANG_POINT, true);
430 talk_number(freq % 100 / 10, true);
431 if (freq % 10)
432 talk_number(freq % 10, true);
435 /* Speak a preset by number or by spelling its name, depending on settings. */
436 static void talk_preset(int preset, bool fallback, bool enqueue)
438 if (global_settings.talk_file == 1) /* number */
439 talk_number(preset + 1, enqueue);
440 else
441 { /* spell */
442 if(presets[preset].name[0])
443 talk_spell(presets[preset].name, enqueue);
444 else if(fallback)
445 talk_freq(presets[preset].frequency, enqueue);
449 int radio_screen(void)
451 char buf[MAX_PATH];
452 bool done = false;
453 int ret_val = GO_TO_ROOT;
454 int button;
455 int i;
456 bool stereo = false, last_stereo = false;
457 int fh;
458 int top_of_screen = 0;
459 bool update_screen = true;
460 bool screen_freeze = false;
461 bool keep_playing = false;
462 bool talk = false;
463 #ifdef FM_RECORD_DBLPRE
464 int lastbutton = BUTTON_NONE;
465 unsigned long rec_lastclick = 0;
466 #endif
467 #if CONFIG_CODEC != SWCODEC
468 bool have_recorded = false;
469 int timeout = current_tick + HZ/10;
470 unsigned int seconds = 0;
471 unsigned int last_seconds = 0;
472 int hours, minutes;
473 struct audio_recording_options rec_options;
474 #endif /* CONFIG_CODEC != SWCODEC */
475 #ifndef HAVE_NOISY_IDLE_MODE
476 int button_timeout = current_tick + (2*HZ);
477 #endif
478 struct viewport vp[NB_SCREENS];
479 int oldbars = 0, fmbars = VP_SB_ALLSCREENS;
480 #ifdef HAVE_BUTTONBAR
481 struct gui_buttonbar buttonbar;
482 gui_buttonbar_init(&buttonbar);
483 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
484 #endif
486 /* change status to "in screen" */
487 in_screen = true;
489 /* always display status bar in radio screen for now */
490 FOR_NB_SCREENS(i)
491 fmbars |= VP_SB_IGNORE_SETTING(i);
492 oldbars = viewportmanager_set_statusbar(fmbars);
493 FOR_NB_SCREENS(i)
495 viewport_set_defaults(&vp[i], i);
496 #ifdef HAVE_BUTTONBAR
497 if (global_settings.buttonbar)
498 vp[i].height -= BUTTONBAR_HEIGHT;
499 #endif
500 screens[i].set_viewport(&vp[i]);
501 screens[i].stop_scroll();
502 screens[i].clear_viewport();
503 screens[i].update_viewport();
506 fh = font_get(FONT_UI)->height;
508 /* Adjust for font size, trying to center the information vertically */
509 if(fh < 10)
510 top_of_screen = 1;
512 if(num_presets <= 0)
514 memset(presets, 0, sizeof(presets));
515 radio_load_presets(global_settings.fmr_file);
518 if(radio_status == FMRADIO_OFF)
519 audio_stop();
520 #ifndef SIMULATOR
522 #if CONFIG_CODEC != SWCODEC
523 if(rec_create_directory() > 0)
524 have_recorded = true;
526 audio_init_recording(talk_get_bufsize());
528 sound_settings_apply();
529 /* Yes, we use the D/A for monitoring */
530 peak_meter_playback(true);
532 peak_meter_enabled = true;
534 rec_init_recording_options(&rec_options);
535 rec_options.rec_source = AUDIO_SRC_LINEIN;
536 rec_set_recording_options(&rec_options);
538 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
539 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
541 #endif /* CONFIG_CODEC != SWCODEC */
542 #endif /* ndef SIMULATOR */
544 /* turn on radio */
545 #if CONFIG_CODEC == SWCODEC
546 audio_set_input_source(AUDIO_SRC_FMRADIO,
547 (radio_status == FMRADIO_PAUSED) ?
548 SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
549 #else
550 if (radio_status == FMRADIO_OFF)
551 radio_start();
552 #endif
554 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
555 scan_presets(vp);
557 curr_preset = find_preset(curr_freq);
558 if(curr_preset != -1)
559 radio_mode = RADIO_PRESET_MODE;
561 #ifdef HAVE_BUTTONBAR
562 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
563 str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD));
564 #endif
566 #ifndef HAVE_NOISY_IDLE_MODE
567 cpu_idle_mode(true);
568 #endif
570 while(!done)
572 if(search_dir != 0)
574 curr_freq = step_freq(curr_freq, search_dir);
575 update_screen = true;
577 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
579 curr_preset = find_preset(curr_freq);
580 remember_frequency();
581 end_search();
582 talk = true;
585 trigger_cpu_boost();
588 if (!update_screen)
590 cancel_cpu_boost();
593 #if CONFIG_CODEC != SWCODEC
594 /* TODO: Can we timeout at HZ when recording since peaks aren't
595 displayed? This should quiet recordings too. */
596 button = get_action(CONTEXT_FM,
597 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
598 #else
599 button = get_action(CONTEXT_FM,
600 update_screen ? TIMEOUT_NOBLOCK : HZ);
601 #endif
603 #ifndef HAVE_NOISY_IDLE_MODE
604 if (button != ACTION_NONE)
606 cpu_idle_mode(false);
607 button_timeout = current_tick + (2*HZ);
609 #endif
610 switch(button)
612 case ACTION_FM_STOP:
613 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
614 if(audio_status() == AUDIO_STATUS_RECORD)
616 audio_stop();
618 else
619 #endif
621 done = true;
622 if(presets_changed)
624 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
626 if(filepreset[0] == '\0')
627 save_preset_list();
628 else
629 radio_save_presets();
632 /* Clear the preset list on exit. */
633 clear_preset_list();
635 update_screen = true;
636 break;
638 #ifdef FM_RECORD
639 case ACTION_FM_RECORD:
640 #ifdef FM_RECORD_DBLPRE
641 if (lastbutton != ACTION_FM_RECORD_DBLPRE)
643 rec_lastclick = 0;
644 break;
646 if (current_tick - rec_lastclick > HZ/2)
648 rec_lastclick = current_tick;
649 break;
651 #endif /* FM_RECORD_DBLPRE */
652 #ifndef SIMULATOR
653 if(audio_status() == AUDIO_STATUS_RECORD)
655 rec_command(RECORDING_CMD_START_NEWFILE);
656 update_screen = true;
658 else
660 have_recorded = true;
661 rec_command(RECORDING_CMD_START);
662 update_screen = true;
664 #endif /* SIMULATOR */
665 last_seconds = 0;
666 break;
667 #endif /* #ifdef FM_RECORD */
669 case ACTION_FM_EXIT:
670 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
671 if(audio_status() == AUDIO_STATUS_RECORD)
672 audio_stop();
673 #endif
674 keep_playing = true;
675 done = true;
676 ret_val = GO_TO_ROOT;
677 if(presets_changed)
679 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
681 if(filepreset[0] == '\0')
682 save_preset_list();
683 else
684 radio_save_presets();
688 /* Clear the preset list on exit. */
689 clear_preset_list();
691 break;
693 case ACTION_STD_PREV:
694 case ACTION_STD_NEXT:
695 next_station(button == ACTION_STD_PREV ? -1 : 1);
696 end_search();
697 update_screen = true;
698 talk = true;
699 break;
701 case ACTION_STD_PREVREPEAT:
702 case ACTION_STD_NEXTREPEAT:
704 int dir = search_dir;
705 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
706 if (radio_mode != RADIO_SCAN_MODE)
708 next_preset(search_dir);
709 end_search();
710 update_screen = true;
711 talk = true;
713 else if (dir == 0)
715 /* Starting auto scan */
716 tuner_set(RADIO_MUTE, 1);
717 update_screen = true;
719 break;
722 case ACTION_SETTINGS_INC:
723 case ACTION_SETTINGS_INCREPEAT:
724 global_settings.volume++;
725 setvol();
726 update_screen = true;
727 break;
729 case ACTION_SETTINGS_DEC:
730 case ACTION_SETTINGS_DECREPEAT:
731 global_settings.volume--;
732 setvol();
733 update_screen = true;
734 break;
736 case ACTION_FM_PLAY:
737 if (radio_status == FMRADIO_PLAYING)
738 radio_pause();
739 else
740 radio_start();
742 update_screen = true;
743 talk = false;
744 talk_shutup();
745 break;
747 case ACTION_FM_MENU:
748 viewportmanager_set_statusbar(oldbars);
749 radio_menu();
750 curr_preset = find_preset(curr_freq);
751 viewportmanager_set_statusbar(fmbars);
752 FOR_NB_SCREENS(i)
754 screens[i].set_viewport(&vp[i]);
755 screens[i].clear_viewport();
756 screens[i].update_viewport();
757 screens[i].set_viewport(NULL);
759 #ifdef HAVE_BUTTONBAR
760 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
761 str(LANG_PRESET),
762 str(LANG_FM_BUTTONBAR_RECORD));
763 #endif
764 update_screen = true;
765 break;
767 #ifdef FM_PRESET
768 case ACTION_FM_PRESET:
769 if(num_presets < 1)
771 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
772 update_screen = true;
773 FOR_NB_SCREENS(i)
775 screens[i].set_viewport(&vp[i]);
776 screens[i].clear_viewport();
777 screens[i].update_viewport();
778 screens[i].set_viewport(NULL);
781 break;
783 viewportmanager_set_statusbar(oldbars);
784 handle_radio_presets();
785 viewportmanager_set_statusbar(fmbars);
786 FOR_NB_SCREENS(i)
788 screens[i].set_viewport(&vp[i]);
789 screens[i].stop_scroll();
790 screens[i].clear_viewport();
791 screens[i].update_viewport();
792 screens[i].set_viewport(NULL);
794 #ifdef HAVE_BUTTONBAR
795 gui_buttonbar_set(&buttonbar,
796 str(LANG_BUTTONBAR_MENU),
797 str(LANG_PRESET),
798 str(LANG_FM_BUTTONBAR_RECORD));
799 #endif
800 update_screen = true;
801 break;
802 #endif /* FM_PRESET */
804 #ifdef FM_FREEZE
805 case ACTION_FM_FREEZE:
806 if(!screen_freeze)
808 splash(HZ, str(LANG_FM_FREEZE));
809 screen_freeze = true;
811 else
813 update_screen = true;
814 screen_freeze = false;
816 break;
817 #endif /* FM_FREEZE */
819 case SYS_USB_CONNECTED:
820 #if CONFIG_CODEC != SWCODEC
821 /* Only accept USB connection when not recording */
822 if(audio_status() != AUDIO_STATUS_RECORD)
823 #endif
825 default_event_handler(SYS_USB_CONNECTED);
826 screen_freeze = true; /* Cosmetic: makes sure the
827 radio screen doesn't redraw */
828 done = true;
830 break;
832 #ifdef FM_MODE
833 case ACTION_FM_MODE:
834 if(radio_mode == RADIO_SCAN_MODE)
836 /* Force scan mode if there are no presets. */
837 if(num_presets > 0)
838 radio_mode = RADIO_PRESET_MODE;
840 else
841 radio_mode = RADIO_SCAN_MODE;
842 update_screen = true;
843 cond_talk_ids_fq(radio_mode ?
844 LANG_PRESET : LANG_RADIO_SCAN_MODE);
845 talk = true;
846 break;
847 #endif /* FM_MODE */
849 #ifdef FM_NEXT_PRESET
850 case ACTION_FM_NEXT_PRESET:
851 next_preset(1);
852 end_search();
853 update_screen = true;
854 talk = true;
855 break;
856 #endif
858 #ifdef FM_PREV_PRESET
859 case ACTION_FM_PREV_PRESET:
860 next_preset(-1);
861 end_search();
862 update_screen = true;
863 talk = true;
864 break;
865 #endif
867 default:
868 default_event_handler(button);
869 break;
870 } /*switch(button)*/
872 #ifdef FM_RECORD_DBLPRE
873 if (button != ACTION_NONE)
874 lastbutton = button;
875 #endif
877 #if CONFIG_CODEC != SWCODEC
878 peak_meter_peek();
879 #endif
881 if(!screen_freeze)
883 /* Only display the peak meter when not recording */
884 #if CONFIG_CODEC != SWCODEC
885 if(!audio_status())
887 FOR_NB_SCREENS(i)
889 screens[i].set_viewport(&vp[i]);
890 peak_meter_screen(&screens[i],0,
891 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
892 fh);
893 screens[i].update_rect(0,
894 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
895 screens[i].getwidth(), fh);
896 screens[i].set_viewport(NULL);
900 if(TIME_AFTER(current_tick, timeout))
902 timeout = current_tick + HZ;
903 #else /* SWCODEC */
905 #endif /* CONFIG_CODEC == SWCODEC */
907 /* keep "mono" from always being displayed when paused */
908 if (radio_status != FMRADIO_PAUSED)
910 stereo = tuner_get(RADIO_STEREO) &&
911 !global_settings.fm_force_mono;
913 if(stereo != last_stereo)
915 update_screen = true;
916 last_stereo = stereo;
921 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
922 seconds = audio_recorded_time() / HZ;
923 if (update_screen || seconds > last_seconds)
925 last_seconds = seconds;
926 #else
927 if (update_screen)
929 #endif
930 int freq;
932 FOR_NB_SCREENS(i)
934 screens[i].set_viewport(&vp[i]);
937 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
938 curr_preset + 1, presets[curr_preset].name);
940 FOR_NB_SCREENS(i)
941 screens[i].puts_scroll(0, top_of_screen, buf);
943 freq = curr_freq / 10000;
944 snprintf(buf, 128, str(LANG_FM_STATION),
945 freq / 100, freq % 100);
946 FOR_NB_SCREENS(i)
947 screens[i].puts_scroll(0, top_of_screen + 1, buf);
949 snprintf(buf, 128, "%s", stereo?str(LANG_CHANNEL_STEREO):
950 str(LANG_CHANNEL_MONO));
951 FOR_NB_SCREENS(i)
952 screens[i].puts_scroll(0, top_of_screen + 2, buf);
954 snprintf(buf, 128, "%s %s", str(LANG_MODE),
955 radio_mode ? str(LANG_PRESET) :
956 str(LANG_RADIO_SCAN_MODE));
957 FOR_NB_SCREENS(i)
958 screens[i].puts_scroll(0, top_of_screen + 3, buf);
960 #if CONFIG_CODEC != SWCODEC
961 if(audio_status() == AUDIO_STATUS_RECORD)
963 hours = seconds / 3600;
964 minutes = (seconds - (hours * 3600)) / 60;
965 snprintf(buf, 32, "%s %02d:%02d:%02d",
966 str(LANG_RECORDING_TIME),
967 hours, minutes, seconds%60);
968 FOR_NB_SCREENS(i)
969 screens[i].puts_scroll(0, top_of_screen + 4, buf);
971 else
973 if(rec_options.rec_prerecord_time)
975 snprintf(buf, 32, "%s %02d",
976 str(LANG_RECORD_PRERECORD), seconds%60);
977 FOR_NB_SCREENS(i)
978 screens[i].puts_scroll(0, top_of_screen + 4, buf);
981 #endif /* CONFIG_CODEC != SWCODEC */
983 FOR_NB_SCREENS(i)
985 screens[i].update_viewport();
986 screens[i].set_viewport(NULL);
989 #ifdef HAVE_BUTTONBAR
990 gui_buttonbar_draw(&buttonbar);
991 #endif
995 update_screen = false;
997 if (global_settings.talk_file && talk
998 && radio_status == FMRADIO_PAUSED)
1000 talk = false;
1001 bool enqueue = false;
1002 if (radio_mode == RADIO_SCAN_MODE)
1004 talk_freq(curr_freq, enqueue);
1005 enqueue = true;
1007 if (curr_preset >= 0)
1008 talk_preset(curr_preset, radio_mode == RADIO_PRESET_MODE,
1009 enqueue);
1012 #if CONFIG_CODEC != SWCODEC
1013 if(audio_status() & AUDIO_STATUS_ERROR)
1015 done = true;
1017 #endif
1019 #ifndef HAVE_NOISY_IDLE_MODE
1020 if (TIME_AFTER(current_tick, button_timeout))
1022 cpu_idle_mode(true);
1024 #endif
1025 } /*while(!done)*/
1027 #ifndef SIMULATOR
1028 #if CONFIG_CODEC != SWCODEC
1029 if(audio_status() & AUDIO_STATUS_ERROR)
1031 splash(0, str(LANG_DISK_FULL));
1032 FOR_NB_SCREENS(i)
1034 screens[i].set_viewport(&vp[i]);
1035 screens[i].update_viewport();
1036 screens[i].set_viewport(NULL);
1038 audio_error_clear();
1040 while(1)
1042 button = get_action(CONTEXT_FM, TIMEOUT_BLOCK);
1043 if(button == ACTION_FM_STOP)
1044 break;
1048 audio_init_playback();
1049 #endif /* CONFIG_CODEC != SWCODEC */
1051 sound_settings_apply();
1052 #endif /* SIMULATOR */
1054 if(keep_playing)
1056 /* Catch FMRADIO_PLAYING status for the sim. */
1057 #ifndef SIMULATOR
1058 #if CONFIG_CODEC != SWCODEC
1059 /* Enable the Left and right A/D Converter */
1060 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
1061 sound_default(SOUND_RIGHT_GAIN),
1062 AUDIO_GAIN_LINEIN);
1063 mas_codec_writereg(6, 0x4000);
1064 #endif
1065 end_search();
1066 #endif /* SIMULATOR */
1068 else
1070 #if CONFIG_CODEC == SWCODEC
1071 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1072 #else
1073 radio_stop();
1074 #endif
1077 #ifndef HAVE_NOISY_IDLE_MODE
1078 cpu_idle_mode(false);
1079 #endif
1081 viewportmanager_set_statusbar(oldbars);
1082 in_screen = false;
1083 #if CONFIG_CODEC != SWCODEC
1084 return have_recorded;
1085 #else
1086 return false;
1087 #endif
1088 } /* radio_screen */
1090 static void radio_save_presets(void)
1092 int fd;
1093 int i;
1095 fd = creat(filepreset);
1096 if(fd >= 0)
1098 for(i = 0;i < num_presets;i++)
1100 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
1102 close(fd);
1104 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1105 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1106 presets_changed = false;
1108 else
1110 splash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1114 void radio_load_presets(char *filename)
1116 int fd;
1117 int rc;
1118 char buf[128];
1119 char *freq;
1120 char *name;
1121 bool done = false;
1122 int f;
1124 memset(presets, 0, sizeof(presets));
1125 num_presets = 0;
1127 /* No Preset in configuration. */
1128 if(filename[0] == '\0')
1130 filepreset[0] = '\0';
1131 return;
1133 /* Temporary preset, loaded until player shuts down. */
1134 else if(filename[0] == '/')
1135 strncpy(filepreset, filename, sizeof(filepreset));
1136 /* Preset from default directory. */
1137 else
1138 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1139 FMPRESET_PATH, filename);
1141 fd = open_utf8(filepreset, O_RDONLY);
1142 if(fd >= 0)
1144 while(!done && num_presets < MAX_PRESETS)
1146 rc = read_line(fd, buf, 128);
1147 if(rc > 0)
1149 if(settings_parseline(buf, &freq, &name))
1151 f = atoi(freq);
1152 if(f) /* For backwards compatibility */
1154 struct fmstation * const fms = &presets[num_presets];
1155 fms->frequency = f;
1156 strncpy(fms->name, name, MAX_FMPRESET_LEN);
1157 fms->name[MAX_FMPRESET_LEN] = '\0';
1158 num_presets++;
1162 else
1163 done = true;
1165 close(fd);
1167 else /* invalid file name? */
1168 filepreset[0] = '\0';
1170 presets_loaded = num_presets > 0;
1171 presets_changed = false;
1175 static int radio_add_preset(void)
1177 char buf[MAX_FMPRESET_LEN + 1];
1179 if(num_presets < MAX_PRESETS)
1181 buf[0] = '\0';
1183 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1185 struct fmstation * const fms = &presets[num_presets];
1186 strcpy(fms->name, buf);
1187 fms->frequency = curr_freq;
1188 num_presets++;
1189 presets_changed = true;
1190 presets_loaded = num_presets > 0;
1191 return true;
1194 else
1196 splash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1198 return false;
1201 /* needed to know which preset we are edit/delete-ing */
1202 static int selected_preset = -1;
1203 static int radio_edit_preset(void)
1205 char buf[MAX_FMPRESET_LEN + 1];
1207 if (num_presets > 0)
1209 struct fmstation * const fms = &presets[selected_preset];
1211 strcpy(buf, fms->name);
1213 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1215 strcpy(fms->name, buf);
1216 presets_changed = true;
1220 return 1;
1223 static int radio_delete_preset(void)
1225 if (num_presets > 0)
1227 struct fmstation * const fms = &presets[selected_preset];
1229 if (selected_preset >= --num_presets)
1230 selected_preset = num_presets - 1;
1232 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1233 (uintptr_t)fms);
1235 if (curr_preset >= num_presets)
1236 --curr_preset;
1239 /* Don't ask to save when all presets are deleted. */
1240 presets_changed = num_presets > 0;
1242 if (!presets_changed)
1244 /* The preset list will be cleared, switch to Scan Mode. */
1245 radio_mode = RADIO_SCAN_MODE;
1246 curr_preset = -1;
1247 presets_loaded = false;
1250 return 1;
1253 static int load_preset_list(void)
1255 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1258 static int save_preset_list(void)
1260 if(num_presets > 0)
1262 bool bad_file_name = true;
1264 if(!dir_exists(FMPRESET_PATH)) /* Check if there is preset folder */
1265 mkdir(FMPRESET_PATH);
1267 create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
1268 ".fmr", 2 IF_CNFN_NUM_(, NULL));
1270 while(bad_file_name)
1272 if(!kbd_input(filepreset, sizeof(filepreset)))
1274 /* check the name: max MAX_FILENAME (20) chars */
1275 char* p2;
1276 char* p1;
1277 int len;
1278 p1 = strrchr(filepreset, '/');
1279 p2 = p1;
1280 while((p1) && (*p2) && (*p2 != '.'))
1281 p2++;
1282 len = (int)(p2-p1) - 1;
1283 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1285 /* no slash, too long or too short */
1286 splash(HZ, ID2P(LANG_INVALID_FILENAME));
1288 else
1290 /* add correct extension (easier to always write)
1291 at this point, p2 points to 0 or the extension dot */
1292 *p2 = '\0';
1293 strcat(filepreset,".fmr");
1294 bad_file_name = false;
1295 radio_save_presets();
1298 else
1300 /* user aborted */
1301 return false;
1305 else
1306 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
1308 return true;
1311 static int clear_preset_list(void)
1313 /* Clear all the preset entries */
1314 memset(presets, 0, sizeof (presets));
1316 num_presets = 0;
1317 presets_loaded = false;
1318 /* The preset list will be cleared switch to Scan Mode. */
1319 radio_mode = RADIO_SCAN_MODE;
1320 curr_preset = -1;
1322 presets_changed = false; /* Don't ask to save when clearing the list. */
1324 return true;
1327 MENUITEM_FUNCTION(radio_edit_preset_item, MENU_FUNC_CHECK_RETVAL,
1328 ID2P(LANG_FM_EDIT_PRESET),
1329 radio_edit_preset, NULL, NULL, Icon_NOICON);
1330 MENUITEM_FUNCTION(radio_delete_preset_item, MENU_FUNC_CHECK_RETVAL,
1331 ID2P(LANG_FM_DELETE_PRESET),
1332 radio_delete_preset, NULL, NULL, Icon_NOICON);
1333 static int radio_preset_callback(int action,
1334 const struct menu_item_ex *this_item)
1336 if (action == ACTION_STD_OK)
1337 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1338 return action;
1339 (void)this_item;
1341 MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_PRESET),
1342 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
1343 &radio_delete_preset_item);
1344 /* present a list of preset stations */
1345 static char * presets_get_name(int selected_item, void *data,
1346 char *buffer, size_t buffer_len)
1348 (void)data;
1349 struct fmstation *p = &presets[selected_item];
1350 if(p->name[0])
1351 return p->name;
1352 int freq = p->frequency / 10000;
1353 int frac = freq % 100;
1354 freq /= 100;
1355 snprintf(buffer, buffer_len,
1356 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1357 return buffer;
1360 static int presets_speak_name(int selected_item, void * data)
1362 (void)data;
1363 talk_preset(selected_item, true, false);
1364 return 0;
1367 static int handle_radio_presets(void)
1369 struct gui_synclist lists;
1370 int result = 0;
1371 int action = ACTION_NONE;
1372 #ifdef HAVE_BUTTONBAR
1373 struct gui_buttonbar buttonbar;
1374 #endif
1376 if(presets_loaded == false)
1377 return result;
1379 #ifdef HAVE_BUTTONBAR
1380 gui_buttonbar_init(&buttonbar);
1381 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
1382 gui_buttonbar_set(&buttonbar, str(LANG_FM_BUTTONBAR_ADD),
1383 str(LANG_FM_BUTTONBAR_EXIT),
1384 str(LANG_FM_BUTTONBAR_ACTION));
1385 gui_buttonbar_draw(&buttonbar);
1386 #endif
1387 gui_synclist_init(&lists, presets_get_name, NULL, false, 1, NULL);
1388 gui_synclist_set_title(&lists, str(LANG_PRESET), NOICON);
1389 gui_synclist_set_icon_callback(&lists, NULL);
1390 if(global_settings.talk_file)
1391 gui_synclist_set_voice_callback(&lists, presets_speak_name);
1392 gui_synclist_set_nb_items(&lists, num_presets);
1393 gui_synclist_select_item(&lists, curr_preset<0 ? 0 : curr_preset);
1394 gui_synclist_speak_item(&lists);
1396 while (result == 0)
1398 gui_synclist_draw(&lists);
1399 list_do_action(CONTEXT_STD, TIMEOUT_BLOCK,
1400 &lists, &action, LIST_WRAP_UNLESS_HELD);
1401 switch (action)
1403 case ACTION_STD_MENU:
1404 if (radio_add_preset())
1406 gui_synclist_set_nb_items(&lists, num_presets);
1407 gui_synclist_select_item(&lists, num_presets - 1);
1409 break;
1410 case ACTION_STD_CANCEL:
1411 result = 1;
1412 break;
1413 case ACTION_STD_OK:
1414 curr_preset = gui_synclist_get_sel_pos(&lists);
1415 curr_freq = presets[curr_preset].frequency;
1416 next_station(0);
1417 remember_frequency();
1418 result = 1;
1419 break;
1420 case ACTION_F3:
1421 case ACTION_STD_CONTEXT:
1422 selected_preset = gui_synclist_get_sel_pos(&lists);
1423 do_menu(&handle_radio_preset_menu, NULL, NULL, false);
1424 gui_synclist_set_nb_items(&lists, num_presets);
1425 gui_synclist_select_item(&lists, selected_preset);
1426 gui_synclist_speak_item(&lists);
1427 break;
1428 default:
1429 if(default_event_handler(action) == SYS_USB_CONNECTED)
1430 result = 2;
1433 return result - 1;
1436 void toggle_mono_mode(bool mono)
1438 tuner_set(RADIO_FORCE_MONO, mono);
1441 void set_radio_region(int region)
1443 #ifdef HAVE_RADIO_REGION
1444 tuner_set(RADIO_REGION, region);
1445 #endif
1446 next_station(0);
1447 remember_frequency();
1448 (void)region;
1451 MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL);
1452 MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL);
1454 #ifndef FM_MODE
1455 static char* get_mode_text(int selected_item, void * data, char *buffer)
1457 (void)selected_item;
1458 (void)data;
1459 snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE),
1460 radio_mode ? str(LANG_PRESET) :
1461 str(LANG_RADIO_SCAN_MODE));
1462 return buffer;
1464 static int toggle_radio_mode(void)
1466 radio_mode = (radio_mode == RADIO_SCAN_MODE) ?
1467 RADIO_PRESET_MODE : RADIO_SCAN_MODE;
1468 return 0;
1470 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0,
1471 toggle_radio_mode, NULL,
1472 get_mode_text, NULL, NULL, NULL, Icon_NOICON);
1473 #endif
1475 static int scan_presets(void *viewports)
1477 bool do_scan = true;
1478 int i;
1479 struct viewport *vp = (struct viewport *)viewports;
1481 FOR_NB_SCREENS(i)
1482 screens[i].set_viewport(vp?&vp[i]:NULL);
1483 if(num_presets > 0) /* Do that to avoid 2 questions. */
1484 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1486 if(do_scan)
1488 const struct fm_region_data * const fmr =
1489 &fm_region_data[global_settings.fm_region];
1491 curr_freq = fmr->freq_min;
1492 num_presets = 0;
1493 memset(presets, 0, sizeof(presets));
1494 tuner_set(RADIO_MUTE, 1);
1496 while(curr_freq <= fmr->freq_max)
1498 int freq, frac;
1499 if(num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1500 break;
1502 freq = curr_freq / 10000;
1503 frac = freq % 100;
1504 freq /= 100;
1506 splashf(0, str(LANG_FM_SCANNING), freq, frac);
1508 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
1510 /* add preset */
1511 presets[num_presets].name[0] = '\0';
1512 presets[num_presets].frequency = curr_freq;
1513 num_presets++;
1516 curr_freq += fmr->freq_step;
1519 if (radio_status == FMRADIO_PLAYING)
1520 tuner_set(RADIO_MUTE, 0);
1522 presets_changed = true;
1524 FOR_NB_SCREENS(i)
1526 screens[i].clear_viewport();
1527 screens[i].update_viewport();
1530 if(num_presets > 0)
1532 curr_freq = presets[0].frequency;
1533 radio_mode = RADIO_PRESET_MODE;
1534 presets_loaded = true;
1535 next_station(0);
1537 else
1539 /* Wrap it to beginning or we'll be past end of band */
1540 presets_loaded = false;
1541 next_station(1);
1544 return true;
1548 #ifdef HAVE_RECORDING
1550 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1551 #define FM_RECORDING_SCREEN
1552 static int fm_recording_screen(void)
1554 bool ret;
1556 /* switch recording source to FMRADIO for the duration */
1557 int rec_source = global_settings.rec_source;
1558 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1560 ret = recording_screen(true);
1562 /* safe to reset as changing sources is prohibited here */
1563 global_settings.rec_source = rec_source;
1565 return ret;
1568 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1570 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1571 #define FM_RECORDING_SETTINGS
1572 static int fm_recording_settings(void)
1574 bool ret = recording_menu(true);
1576 #if CONFIG_CODEC != SWCODEC
1577 if (!ret)
1579 struct audio_recording_options rec_options;
1580 rec_init_recording_options(&rec_options);
1581 rec_options.rec_source = AUDIO_SRC_LINEIN;
1582 rec_set_recording_options(&rec_options);
1584 #endif
1586 return ret;
1589 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1590 #endif /* HAVE_RECORDING */
1592 #ifdef FM_RECORDING_SCREEN
1593 MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING),
1594 fm_recording_screen, NULL, NULL, Icon_Recording);
1595 #endif
1596 #ifdef FM_RECORDING_SETTINGS
1597 MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS),
1598 fm_recording_settings, NULL, NULL, Icon_Recording);
1599 #endif
1600 #ifndef FM_PRESET
1601 MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET),
1602 handle_radio_presets, NULL, NULL, Icon_NOICON);
1603 #endif
1604 #ifndef FM_PRESET_ADD
1605 MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET),
1606 radio_add_preset, NULL, NULL, Icon_NOICON);
1607 #endif
1610 MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD),
1611 load_preset_list, NULL, NULL, Icon_NOICON);
1612 MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE),
1613 save_preset_list, NULL, NULL, Icon_NOICON);
1614 MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR),
1615 clear_preset_list, NULL, NULL, Icon_NOICON);
1616 MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM,
1617 ID2P(LANG_FM_SCAN_PRESETS),
1618 scan_presets, NULL, NULL, Icon_NOICON);
1620 MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1621 Icon_Radio_screen,
1622 #ifndef FM_PRESET
1623 &radio_presets_item,
1624 #endif
1625 #ifndef FM_PRESET_ADD
1626 &radio_addpreset_item,
1627 #endif
1628 &presetload_item, &presetsave_item, &presetclear_item,
1629 &force_mono,
1630 #ifndef FM_MODE
1631 &radio_mode_item,
1632 #endif
1633 &set_region, &sound_settings,
1634 #ifdef FM_RECORDING_SCREEN
1635 &recscreen_item,
1636 #endif
1637 #ifdef FM_RECORDING_SETTINGS
1638 &recsettings_item,
1639 #endif
1640 &scan_presets_item);
1641 /* main menu of the radio screen */
1642 static bool radio_menu(void)
1644 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1645 MENU_ATTACHED_USB;
1648 #endif