FS#10365 - Optional debug output for albumart.c
[kugel-rb.git] / apps / recorder / radio.c
blob68c45c4f0190120fad4d3a240999cc4f0497ca19
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 "general.h"
38 #include "errno.h"
39 #include "string.h"
40 #include "system.h"
41 #include "radio.h"
42 #include "menu.h"
43 #include "misc.h"
44 #include "keyboard.h"
45 #include "screens.h"
46 #include "peakmeter.h"
47 #include "lang.h"
48 #include "font.h"
49 #include "sound_menu.h"
50 #ifdef HAVE_RECORDING
51 #include "recording.h"
52 #endif
53 #include "talk.h"
54 #include "tuner.h"
55 #include "power.h"
56 #include "sound.h"
57 #include "screen_access.h"
58 #include "splash.h"
59 #include "yesno.h"
60 #include "buttonbar.h"
61 #include "tree.h"
62 #include "dir.h"
63 #include "action.h"
64 #include "list.h"
65 #include "menus/exported_menus.h"
66 #include "root_menu.h"
67 #include "viewport.h"
69 #if CONFIG_TUNER
71 #if CONFIG_KEYPAD == RECORDER_PAD
72 #define FM_RECORD
73 #define FM_PRESET_ADD
74 #define FM_PRESET_ACTION
75 #define FM_PRESET
76 #define FM_MODE
78 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
79 #define FM_PRESET
80 #define FM_MODE
81 #define FM_NEXT_PRESET
82 #define FM_PREV_PRESET
84 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
85 #define FM_PRESET
86 #define FM_MODE
88 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
89 #define FM_PRESET
90 #define FM_MODE
91 /* This should be removeable if the whole tuning thing is sorted out since
92 proper tuning quiets the screen almost entirely in that extreme measures
93 have to be taken to hear any interference. */
94 #define HAVE_NOISY_IDLE_MODE
96 #elif CONFIG_KEYPAD == ONDIO_PAD
97 #define FM_RECORD_DBLPRE
98 #define FM_RECORD
99 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
100 #define FM_MENU
101 #define FM_PRESET
102 #define FM_STOP
103 #define FM_MODE
104 #define FM_EXIT
105 #define FM_PLAY
107 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
108 #define FM_PRESET
109 #define FM_MODE
111 #elif (CONFIG_KEYPAD == COWOND2_PAD)
112 #define FM_MENU
113 #define FM_PRESET
114 #define FM_STOP
115 #define FM_MODE
116 #define FM_EXIT
117 #define FM_PLAY
118 #endif
120 #define RADIO_SCAN_MODE 0
121 #define RADIO_PRESET_MODE 1
123 static int curr_preset = -1;
124 static int curr_freq; /* current frequency in Hz */
125 static int radio_mode = RADIO_SCAN_MODE;
126 static int search_dir = 0;
128 static int radio_status = FMRADIO_OFF;
129 static bool in_screen = false;
131 #define MAX_PRESETS 64
132 static bool presets_loaded = false, presets_changed = false;
133 static struct fmstation presets[MAX_PRESETS];
135 static char filepreset[MAX_PATH]; /* preset filename variable */
137 static int num_presets = 0; /* The number of presets in the preset list */
139 static void radio_save_presets(void);
140 static int handle_radio_presets(void);
141 static bool radio_menu(void);
142 static int radio_add_preset(void);
143 static int save_preset_list(void);
144 static int load_preset_list(void);
145 static int clear_preset_list(void);
147 static int scan_presets(void *viewports);
149 /* Function to manipulate all yesno dialogues.
150 This function needs the output text as an argument. */
151 static bool yesno_pop(const char* text)
153 int i;
154 const char *lines[]={text};
155 const struct text_message message={lines, 1};
156 bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES);
157 FOR_NB_SCREENS(i)
158 screens[i].clear_viewport();
159 return ret;
162 void radio_init(void)
164 tuner_init();
165 radio_stop();
168 int get_radio_status(void)
170 return radio_status;
173 bool in_radio_screen(void)
175 return in_screen;
178 /* TODO: Move some more of the control functionality to firmware
179 and clean up the mess */
181 /* secret flag for starting paused - prevents unmute */
182 #define FMRADIO_START_PAUSED 0x8000
183 void radio_start(void)
185 const struct fm_region_data *fmr;
186 bool start_paused;
188 if(radio_status == FMRADIO_PLAYING)
189 return;
191 fmr = &fm_region_data[global_settings.fm_region];
193 start_paused = radio_status & FMRADIO_START_PAUSED;
194 /* clear flag before any yielding */
195 radio_status &= ~FMRADIO_START_PAUSED;
197 if(radio_status == FMRADIO_OFF)
198 tuner_power(true);
200 curr_freq = global_status.last_frequency * fmr->freq_step + fmr->freq_min;
202 tuner_set(RADIO_SLEEP, 0); /* wake up the tuner */
204 if(radio_status == FMRADIO_OFF)
206 #ifdef HAVE_RADIO_REGION
207 tuner_set(RADIO_REGION, global_settings.fm_region);
208 #endif
209 tuner_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
212 tuner_set(RADIO_FREQUENCY, curr_freq);
214 #ifdef HAVE_RADIO_MUTE_TIMEOUT
216 unsigned long mute_timeout = current_tick + HZ;
217 if (radio_status != FMRADIO_OFF)
219 /* paused */
220 mute_timeout += HZ;
223 while(!tuner_get(RADIO_STEREO) && !tuner_get(RADIO_TUNED))
225 if(TIME_AFTER(current_tick, mute_timeout))
226 break;
227 yield();
230 #endif
232 /* keep radio from sounding initially */
233 if(!start_paused)
234 tuner_set(RADIO_MUTE, 0);
236 radio_status = FMRADIO_PLAYING;
237 } /* radio_start */
239 void radio_pause(void)
241 if(radio_status == FMRADIO_PAUSED)
242 return;
244 if(radio_status == FMRADIO_OFF)
246 radio_status |= FMRADIO_START_PAUSED;
247 radio_start();
250 tuner_set(RADIO_MUTE, 1);
251 tuner_set(RADIO_SLEEP, 1);
253 radio_status = FMRADIO_PAUSED;
254 } /* radio_pause */
256 void radio_stop(void)
258 if(radio_status == FMRADIO_OFF)
259 return;
261 tuner_set(RADIO_MUTE, 1);
262 tuner_set(RADIO_SLEEP, 1); /* low power mode, if available */
263 radio_status = FMRADIO_OFF;
264 tuner_power(false); /* status update, power off if avail. */
265 } /* radio_stop */
267 bool radio_hardware_present(void)
269 return tuner_get(RADIO_PRESENT);
272 /* Keep freq on the grid for the current region */
273 static int snap_freq_to_grid(int freq)
275 const struct fm_region_data * const fmr =
276 &fm_region_data[global_settings.fm_region];
278 /* Range clamp if out of range or just round to nearest */
279 if (freq < fmr->freq_min)
280 freq = fmr->freq_min;
281 else if (freq > fmr->freq_max)
282 freq = fmr->freq_max;
283 else
284 freq = (freq - fmr->freq_min + fmr->freq_step/2) /
285 fmr->freq_step * fmr->freq_step + fmr->freq_min;
287 return freq;
290 /* Find a matching preset to freq */
291 static int find_preset(int freq)
293 int i;
294 if(num_presets < 1)
295 return -1;
296 for(i = 0;i < MAX_PRESETS;i++)
298 if(freq == presets[i].frequency)
299 return i;
302 return -1;
305 /* Return the closest preset encountered in the search direction with
306 wraparound. */
307 static int find_closest_preset(int freq, int direction)
309 int i;
310 int lowpreset = 0;
311 int highpreset = 0;
312 int closest = -1;
314 if (direction == 0) /* direction == 0 isn't really used */
315 return 0;
317 for (i = 0; i < num_presets; i++)
319 int f = presets[i].frequency;
320 if (f == freq)
321 return i; /* Exact match = stop */
323 /* remember the highest and lowest presets for wraparound */
324 if (f < presets[lowpreset].frequency)
325 lowpreset = i;
326 if (f > presets[highpreset].frequency)
327 highpreset = i;
329 /* find the closest preset in the given direction */
330 if (direction > 0 && f > freq)
332 if (closest < 0 || f < presets[closest].frequency)
333 closest = i;
335 else if (direction < 0 && f < freq)
337 if (closest < 0 || f > presets[closest].frequency)
338 closest = i;
342 if (closest < 0)
344 /* no presets in the given direction */
345 /* wrap around depending on direction */
346 if (direction < 0)
347 closest = highpreset;
348 else
349 closest = lowpreset;
352 return closest;
355 static void remember_frequency(void)
357 const struct fm_region_data * const fmr =
358 &fm_region_data[global_settings.fm_region];
359 global_status.last_frequency = (curr_freq - fmr->freq_min)
360 / fmr->freq_step;
361 status_save();
364 static void next_preset(int direction)
366 if (num_presets < 1)
367 return;
369 if (curr_preset == -1)
370 curr_preset = find_closest_preset(curr_freq, direction);
371 else
372 curr_preset = (curr_preset + direction + num_presets) % num_presets;
374 /* Must stay on the current grid for the region */
375 curr_freq = snap_freq_to_grid(presets[curr_preset].frequency);
377 tuner_set(RADIO_FREQUENCY, curr_freq);
378 remember_frequency();
381 /* Step to the next or previous frequency */
382 static int step_freq(int freq, int direction)
384 const struct fm_region_data * const fmr =
385 &fm_region_data[global_settings.fm_region];
387 freq += direction*fmr->freq_step;
389 /* Wrap first or snapping to grid will not let us on the band extremes */
390 if (freq > fmr->freq_max)
391 freq = direction > 0 ? fmr->freq_min : fmr->freq_max;
392 else if (freq < fmr->freq_min)
393 freq = direction < 0 ? fmr->freq_max : fmr->freq_min;
394 else
395 freq = snap_freq_to_grid(freq);
397 return freq;
400 /* Step to the next or previous station */
401 static void next_station(int direction)
403 if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
405 next_preset(direction);
406 return;
409 curr_freq = step_freq(curr_freq, direction);
411 if (radio_status == FMRADIO_PLAYING)
412 tuner_set(RADIO_MUTE, 1);
414 tuner_set(RADIO_FREQUENCY, curr_freq);
416 if (radio_status == FMRADIO_PLAYING)
417 tuner_set(RADIO_MUTE, 0);
419 curr_preset = find_preset(curr_freq);
420 remember_frequency();
423 /* Ends an in-progress search */
424 static void end_search(void)
426 if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
427 tuner_set(RADIO_MUTE, 0);
428 search_dir = 0;
431 /* Speak a frequency. */
432 static void talk_freq(int freq, bool enqueue)
434 freq /= 10000;
435 talk_number(freq / 100, enqueue);
436 talk_id(LANG_POINT, true);
437 talk_number(freq % 100 / 10, true);
438 if (freq % 10)
439 talk_number(freq % 10, true);
442 /* Speak a preset by number or by spelling its name, depending on settings. */
443 static void talk_preset(int preset, bool fallback, bool enqueue)
445 if (global_settings.talk_file == 1) /* number */
446 talk_number(preset + 1, enqueue);
447 else
448 { /* spell */
449 if(presets[preset].name[0])
450 talk_spell(presets[preset].name, enqueue);
451 else if(fallback)
452 talk_freq(presets[preset].frequency, enqueue);
456 int radio_screen(void)
458 char buf[MAX_PATH];
459 bool done = false;
460 int ret_val = GO_TO_ROOT;
461 int button;
462 int i;
463 bool stereo = false, last_stereo = false;
464 int fh;
465 int top_of_screen = 0;
466 bool update_screen = true;
467 bool screen_freeze = false;
468 bool keep_playing = false;
469 bool talk = false;
470 #ifdef FM_RECORD_DBLPRE
471 int lastbutton = BUTTON_NONE;
472 unsigned long rec_lastclick = 0;
473 #endif
474 #if CONFIG_CODEC != SWCODEC
475 bool have_recorded = false;
476 int timeout = current_tick + HZ/10;
477 unsigned int seconds = 0;
478 unsigned int last_seconds = 0;
479 int hours, minutes;
480 struct audio_recording_options rec_options;
481 #endif /* CONFIG_CODEC != SWCODEC */
482 #ifndef HAVE_NOISY_IDLE_MODE
483 int button_timeout = current_tick + (2*HZ);
484 #endif
485 struct viewport vp[NB_SCREENS];
486 int oldbars = 0, fmbars = VP_SB_ALLSCREENS;
487 #ifdef HAVE_BUTTONBAR
488 struct gui_buttonbar buttonbar;
489 gui_buttonbar_init(&buttonbar);
490 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
491 #endif
493 /* change status to "in screen" */
494 in_screen = true;
496 /* always display status bar in radio screen for now */
497 FOR_NB_SCREENS(i)
498 fmbars |= VP_SB_IGNORE_SETTING(i);
499 oldbars = viewportmanager_set_statusbar(fmbars);
500 FOR_NB_SCREENS(i)
502 viewport_set_defaults(&vp[i], i);
503 #ifdef HAVE_BUTTONBAR
504 if (global_settings.buttonbar)
505 vp[i].height -= BUTTONBAR_HEIGHT;
506 #endif
507 screens[i].set_viewport(&vp[i]);
508 screens[i].stop_scroll();
509 screens[i].clear_viewport();
510 screens[i].update_viewport();
513 fh = font_get(FONT_UI)->height;
515 /* Adjust for font size, trying to center the information vertically */
516 if(fh < 10)
517 top_of_screen = 1;
519 if(num_presets <= 0)
521 radio_load_presets(global_settings.fmr_file);
524 if(radio_status == FMRADIO_OFF)
525 audio_stop();
526 #ifndef SIMULATOR
528 #if CONFIG_CODEC != SWCODEC
529 if(rec_create_directory() > 0)
530 have_recorded = true;
532 audio_init_recording(talk_get_bufsize());
534 sound_settings_apply();
535 /* Yes, we use the D/A for monitoring */
536 peak_meter_playback(true);
538 peak_meter_enabled = true;
540 rec_init_recording_options(&rec_options);
541 rec_options.rec_source = AUDIO_SRC_LINEIN;
542 rec_set_recording_options(&rec_options);
544 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
545 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
547 #endif /* CONFIG_CODEC != SWCODEC */
548 #endif /* ndef SIMULATOR */
550 /* turn on radio */
551 #if CONFIG_CODEC == SWCODEC
552 audio_set_input_source(AUDIO_SRC_FMRADIO,
553 (radio_status == FMRADIO_PAUSED) ?
554 SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
555 #else
556 if (radio_status == FMRADIO_OFF)
557 radio_start();
558 #endif
560 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
561 scan_presets(vp);
563 curr_preset = find_preset(curr_freq);
564 if(curr_preset != -1)
565 radio_mode = RADIO_PRESET_MODE;
567 #ifdef HAVE_BUTTONBAR
568 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
569 str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD));
570 #endif
572 #ifndef HAVE_NOISY_IDLE_MODE
573 cpu_idle_mode(true);
574 #endif
576 while(!done)
578 if(search_dir != 0)
580 curr_freq = step_freq(curr_freq, search_dir);
581 update_screen = true;
583 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
585 curr_preset = find_preset(curr_freq);
586 remember_frequency();
587 end_search();
588 talk = true;
591 trigger_cpu_boost();
594 if (!update_screen)
596 cancel_cpu_boost();
599 #if CONFIG_CODEC != SWCODEC
600 /* TODO: Can we timeout at HZ when recording since peaks aren't
601 displayed? This should quiet recordings too. */
602 button = get_action(CONTEXT_FM,
603 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
604 #else
605 button = get_action(CONTEXT_FM,
606 update_screen ? TIMEOUT_NOBLOCK : HZ);
607 #endif
609 #ifndef HAVE_NOISY_IDLE_MODE
610 if (button != ACTION_NONE)
612 cpu_idle_mode(false);
613 button_timeout = current_tick + (2*HZ);
615 #endif
616 switch(button)
618 case ACTION_FM_STOP:
619 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
620 if(audio_status() == AUDIO_STATUS_RECORD)
622 audio_stop();
624 else
625 #endif
627 done = true;
628 if(presets_changed)
630 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
632 if(filepreset[0] == '\0')
633 save_preset_list();
634 else
635 radio_save_presets();
638 /* Clear the preset list on exit. */
639 clear_preset_list();
641 update_screen = true;
642 break;
644 #ifdef FM_RECORD
645 case ACTION_FM_RECORD:
646 #ifdef FM_RECORD_DBLPRE
647 if (lastbutton != ACTION_FM_RECORD_DBLPRE)
649 rec_lastclick = 0;
650 break;
652 if (current_tick - rec_lastclick > HZ/2)
654 rec_lastclick = current_tick;
655 break;
657 #endif /* FM_RECORD_DBLPRE */
658 #ifndef SIMULATOR
659 if(audio_status() == AUDIO_STATUS_RECORD)
661 rec_command(RECORDING_CMD_START_NEWFILE);
662 update_screen = true;
664 else
666 have_recorded = true;
667 rec_command(RECORDING_CMD_START);
668 update_screen = true;
670 #endif /* SIMULATOR */
671 last_seconds = 0;
672 break;
673 #endif /* #ifdef FM_RECORD */
675 case ACTION_FM_EXIT:
676 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
677 if(audio_status() == AUDIO_STATUS_RECORD)
678 audio_stop();
679 #endif
680 keep_playing = true;
681 done = true;
682 ret_val = GO_TO_ROOT;
683 if(presets_changed)
685 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
687 if(filepreset[0] == '\0')
688 save_preset_list();
689 else
690 radio_save_presets();
694 /* Clear the preset list on exit. */
695 clear_preset_list();
697 break;
699 case ACTION_STD_PREV:
700 case ACTION_STD_NEXT:
701 next_station(button == ACTION_STD_PREV ? -1 : 1);
702 end_search();
703 update_screen = true;
704 talk = true;
705 break;
707 case ACTION_STD_PREVREPEAT:
708 case ACTION_STD_NEXTREPEAT:
710 int dir = search_dir;
711 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
712 if (radio_mode != RADIO_SCAN_MODE)
714 next_preset(search_dir);
715 end_search();
716 update_screen = true;
717 talk = true;
719 else if (dir == 0)
721 /* Starting auto scan */
722 tuner_set(RADIO_MUTE, 1);
723 update_screen = true;
725 break;
728 case ACTION_SETTINGS_INC:
729 case ACTION_SETTINGS_INCREPEAT:
730 global_settings.volume++;
731 setvol();
732 update_screen = true;
733 break;
735 case ACTION_SETTINGS_DEC:
736 case ACTION_SETTINGS_DECREPEAT:
737 global_settings.volume--;
738 setvol();
739 update_screen = true;
740 break;
742 case ACTION_FM_PLAY:
743 if (radio_status == FMRADIO_PLAYING)
744 radio_pause();
745 else
746 radio_start();
748 update_screen = true;
749 talk = false;
750 talk_shutup();
751 break;
753 case ACTION_FM_MENU:
754 viewportmanager_set_statusbar(oldbars);
755 radio_menu();
756 curr_preset = find_preset(curr_freq);
757 viewportmanager_set_statusbar(fmbars);
758 FOR_NB_SCREENS(i)
760 screens[i].set_viewport(&vp[i]);
761 screens[i].clear_viewport();
762 screens[i].update_viewport();
763 screens[i].set_viewport(NULL);
765 #ifdef HAVE_BUTTONBAR
766 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
767 str(LANG_PRESET),
768 str(LANG_FM_BUTTONBAR_RECORD));
769 #endif
770 update_screen = true;
771 break;
773 #ifdef FM_PRESET
774 case ACTION_FM_PRESET:
775 if(num_presets < 1)
777 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
778 update_screen = true;
779 FOR_NB_SCREENS(i)
781 screens[i].set_viewport(&vp[i]);
782 screens[i].clear_viewport();
783 screens[i].update_viewport();
784 screens[i].set_viewport(NULL);
787 break;
789 viewportmanager_set_statusbar(oldbars);
790 handle_radio_presets();
791 viewportmanager_set_statusbar(fmbars);
792 FOR_NB_SCREENS(i)
794 screens[i].set_viewport(&vp[i]);
795 screens[i].stop_scroll();
796 screens[i].clear_viewport();
797 screens[i].update_viewport();
798 screens[i].set_viewport(NULL);
800 #ifdef HAVE_BUTTONBAR
801 gui_buttonbar_set(&buttonbar,
802 str(LANG_BUTTONBAR_MENU),
803 str(LANG_PRESET),
804 str(LANG_FM_BUTTONBAR_RECORD));
805 #endif
806 update_screen = true;
807 break;
808 #endif /* FM_PRESET */
810 #ifdef FM_FREEZE
811 case ACTION_FM_FREEZE:
812 if(!screen_freeze)
814 splash(HZ, str(LANG_FM_FREEZE));
815 screen_freeze = true;
817 else
819 update_screen = true;
820 screen_freeze = false;
822 break;
823 #endif /* FM_FREEZE */
825 case SYS_USB_CONNECTED:
826 #if CONFIG_CODEC != SWCODEC
827 /* Only accept USB connection when not recording */
828 if(audio_status() != AUDIO_STATUS_RECORD)
829 #endif
831 default_event_handler(SYS_USB_CONNECTED);
832 screen_freeze = true; /* Cosmetic: makes sure the
833 radio screen doesn't redraw */
834 done = true;
836 break;
838 #ifdef FM_MODE
839 case ACTION_FM_MODE:
840 if(radio_mode == RADIO_SCAN_MODE)
842 /* Force scan mode if there are no presets. */
843 if(num_presets > 0)
844 radio_mode = RADIO_PRESET_MODE;
846 else
847 radio_mode = RADIO_SCAN_MODE;
848 update_screen = true;
849 cond_talk_ids_fq(radio_mode ?
850 LANG_PRESET : LANG_RADIO_SCAN_MODE);
851 talk = true;
852 break;
853 #endif /* FM_MODE */
855 #ifdef FM_NEXT_PRESET
856 case ACTION_FM_NEXT_PRESET:
857 next_preset(1);
858 end_search();
859 update_screen = true;
860 talk = true;
861 break;
862 #endif
864 #ifdef FM_PREV_PRESET
865 case ACTION_FM_PREV_PRESET:
866 next_preset(-1);
867 end_search();
868 update_screen = true;
869 talk = true;
870 break;
871 #endif
873 default:
874 default_event_handler(button);
875 break;
876 } /*switch(button)*/
878 #ifdef FM_RECORD_DBLPRE
879 if (button != ACTION_NONE)
880 lastbutton = button;
881 #endif
883 #if CONFIG_CODEC != SWCODEC
884 peak_meter_peek();
885 #endif
887 if(!screen_freeze)
889 /* Only display the peak meter when not recording */
890 #if CONFIG_CODEC != SWCODEC
891 if(!audio_status())
893 FOR_NB_SCREENS(i)
895 screens[i].set_viewport(&vp[i]);
896 peak_meter_screen(&screens[i],0,
897 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
898 fh);
899 screens[i].update_rect(0,
900 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
901 screens[i].getwidth(), fh);
902 screens[i].set_viewport(NULL);
906 if(TIME_AFTER(current_tick, timeout))
908 timeout = current_tick + HZ;
909 #else /* SWCODEC */
911 #endif /* CONFIG_CODEC == SWCODEC */
913 /* keep "mono" from always being displayed when paused */
914 if (radio_status != FMRADIO_PAUSED)
916 stereo = tuner_get(RADIO_STEREO) &&
917 !global_settings.fm_force_mono;
919 if(stereo != last_stereo)
921 update_screen = true;
922 last_stereo = stereo;
927 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
928 seconds = audio_recorded_time() / HZ;
929 if (update_screen || seconds > last_seconds)
931 last_seconds = seconds;
932 #else
933 if (update_screen)
935 #endif
936 int freq;
938 FOR_NB_SCREENS(i)
940 screens[i].set_viewport(&vp[i]);
943 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
944 curr_preset + 1, presets[curr_preset].name);
946 FOR_NB_SCREENS(i)
947 screens[i].puts_scroll(0, top_of_screen, buf);
949 freq = curr_freq / 10000;
950 snprintf(buf, 128, str(LANG_FM_STATION),
951 freq / 100, freq % 100);
952 FOR_NB_SCREENS(i)
953 screens[i].puts_scroll(0, top_of_screen + 1, buf);
955 snprintf(buf, 128, "%s", stereo?str(LANG_CHANNEL_STEREO):
956 str(LANG_CHANNEL_MONO));
957 FOR_NB_SCREENS(i)
958 screens[i].puts_scroll(0, top_of_screen + 2, buf);
960 snprintf(buf, 128, "%s %s", str(LANG_MODE),
961 radio_mode ? str(LANG_PRESET) :
962 str(LANG_RADIO_SCAN_MODE));
963 FOR_NB_SCREENS(i)
964 screens[i].puts_scroll(0, top_of_screen + 3, buf);
966 #if CONFIG_CODEC != SWCODEC
967 if(audio_status() == AUDIO_STATUS_RECORD)
969 hours = seconds / 3600;
970 minutes = (seconds - (hours * 3600)) / 60;
971 snprintf(buf, 32, "%s %02d:%02d:%02d",
972 str(LANG_RECORDING_TIME),
973 hours, minutes, seconds%60);
974 FOR_NB_SCREENS(i)
975 screens[i].puts_scroll(0, top_of_screen + 4, buf);
977 else
979 if(rec_options.rec_prerecord_time)
981 snprintf(buf, 32, "%s %02d",
982 str(LANG_RECORD_PRERECORD), seconds%60);
983 FOR_NB_SCREENS(i)
984 screens[i].puts_scroll(0, top_of_screen + 4, buf);
987 #endif /* CONFIG_CODEC != SWCODEC */
989 FOR_NB_SCREENS(i)
991 screens[i].update_viewport();
992 screens[i].set_viewport(NULL);
995 #ifdef HAVE_BUTTONBAR
996 gui_buttonbar_draw(&buttonbar);
997 #endif
1001 update_screen = false;
1003 if (global_settings.talk_file && talk
1004 && radio_status == FMRADIO_PAUSED)
1006 talk = false;
1007 bool enqueue = false;
1008 if (radio_mode == RADIO_SCAN_MODE)
1010 talk_freq(curr_freq, enqueue);
1011 enqueue = true;
1013 if (curr_preset >= 0)
1014 talk_preset(curr_preset, radio_mode == RADIO_PRESET_MODE,
1015 enqueue);
1018 #if CONFIG_CODEC != SWCODEC
1019 if(audio_status() & AUDIO_STATUS_ERROR)
1021 done = true;
1023 #endif
1025 #ifndef HAVE_NOISY_IDLE_MODE
1026 if (TIME_AFTER(current_tick, button_timeout))
1028 cpu_idle_mode(true);
1030 #endif
1031 } /*while(!done)*/
1033 #ifndef SIMULATOR
1034 #if CONFIG_CODEC != SWCODEC
1035 if(audio_status() & AUDIO_STATUS_ERROR)
1037 splash(0, str(LANG_DISK_FULL));
1038 FOR_NB_SCREENS(i)
1040 screens[i].set_viewport(&vp[i]);
1041 screens[i].update_viewport();
1042 screens[i].set_viewport(NULL);
1044 audio_error_clear();
1046 while(1)
1048 button = get_action(CONTEXT_FM, TIMEOUT_BLOCK);
1049 if(button == ACTION_FM_STOP)
1050 break;
1054 audio_init_playback();
1055 #endif /* CONFIG_CODEC != SWCODEC */
1057 sound_settings_apply();
1058 #endif /* SIMULATOR */
1060 if(keep_playing)
1062 /* Catch FMRADIO_PLAYING status for the sim. */
1063 #ifndef SIMULATOR
1064 #if CONFIG_CODEC != SWCODEC
1065 /* Enable the Left and right A/D Converter */
1066 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
1067 sound_default(SOUND_RIGHT_GAIN),
1068 AUDIO_GAIN_LINEIN);
1069 mas_codec_writereg(6, 0x4000);
1070 #endif
1071 end_search();
1072 #endif /* SIMULATOR */
1074 else
1076 #if CONFIG_CODEC == SWCODEC
1077 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1078 #else
1079 radio_stop();
1080 #endif
1083 #ifndef HAVE_NOISY_IDLE_MODE
1084 cpu_idle_mode(false);
1085 #endif
1087 viewportmanager_set_statusbar(oldbars);
1088 in_screen = false;
1089 #if CONFIG_CODEC != SWCODEC
1090 return have_recorded;
1091 #else
1092 return false;
1093 #endif
1094 } /* radio_screen */
1096 static void radio_save_presets(void)
1098 int fd;
1099 int i;
1101 fd = creat(filepreset);
1102 if(fd >= 0)
1104 for(i = 0;i < num_presets;i++)
1106 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
1108 close(fd);
1110 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1111 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1112 presets_changed = false;
1114 else
1116 splash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1120 void radio_load_presets(char *filename)
1122 int fd;
1123 int rc;
1124 char buf[128];
1125 char *freq;
1126 char *name;
1127 bool done = false;
1128 int f;
1130 memset(presets, 0, sizeof(presets));
1131 num_presets = 0;
1133 /* No Preset in configuration. */
1134 if(filename[0] == '\0')
1136 filepreset[0] = '\0';
1137 return;
1139 /* Temporary preset, loaded until player shuts down. */
1140 else if(filename[0] == '/')
1141 strncpy(filepreset, filename, sizeof(filepreset));
1142 /* Preset from default directory. */
1143 else
1144 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1145 FMPRESET_PATH, filename);
1147 fd = open_utf8(filepreset, O_RDONLY);
1148 if(fd >= 0)
1150 while(!done && num_presets < MAX_PRESETS)
1152 rc = read_line(fd, buf, 128);
1153 if(rc > 0)
1155 if(settings_parseline(buf, &freq, &name))
1157 f = atoi(freq);
1158 if(f) /* For backwards compatibility */
1160 struct fmstation * const fms = &presets[num_presets];
1161 fms->frequency = f;
1162 strncpy(fms->name, name, MAX_FMPRESET_LEN);
1163 fms->name[MAX_FMPRESET_LEN] = '\0';
1164 num_presets++;
1168 else
1169 done = true;
1171 close(fd);
1173 else /* invalid file name? */
1174 filepreset[0] = '\0';
1176 presets_loaded = num_presets > 0;
1177 presets_changed = false;
1181 static int radio_add_preset(void)
1183 char buf[MAX_FMPRESET_LEN + 1];
1185 if(num_presets < MAX_PRESETS)
1187 buf[0] = '\0';
1189 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1191 struct fmstation * const fms = &presets[num_presets];
1192 strcpy(fms->name, buf);
1193 fms->frequency = curr_freq;
1194 num_presets++;
1195 presets_changed = true;
1196 presets_loaded = num_presets > 0;
1197 return true;
1200 else
1202 splash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1204 return false;
1207 /* needed to know which preset we are edit/delete-ing */
1208 static int selected_preset = -1;
1209 static int radio_edit_preset(void)
1211 char buf[MAX_FMPRESET_LEN + 1];
1213 if (num_presets > 0)
1215 struct fmstation * const fms = &presets[selected_preset];
1217 strcpy(buf, fms->name);
1219 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1221 strcpy(fms->name, buf);
1222 presets_changed = true;
1226 return 1;
1229 static int radio_delete_preset(void)
1231 if (num_presets > 0)
1233 struct fmstation * const fms = &presets[selected_preset];
1235 if (selected_preset >= --num_presets)
1236 selected_preset = num_presets - 1;
1238 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1239 (uintptr_t)fms);
1241 if (curr_preset >= num_presets)
1242 --curr_preset;
1245 /* Don't ask to save when all presets are deleted. */
1246 presets_changed = num_presets > 0;
1248 if (!presets_changed)
1250 /* The preset list will be cleared, switch to Scan Mode. */
1251 radio_mode = RADIO_SCAN_MODE;
1252 curr_preset = -1;
1253 presets_loaded = false;
1256 return 1;
1259 static int load_preset_list(void)
1261 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1264 static int save_preset_list(void)
1266 if(num_presets > 0)
1268 bool bad_file_name = true;
1270 if(!dir_exists(FMPRESET_PATH)) /* Check if there is preset folder */
1271 mkdir(FMPRESET_PATH);
1273 create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
1274 ".fmr", 2 IF_CNFN_NUM_(, NULL));
1276 while(bad_file_name)
1278 if(!kbd_input(filepreset, sizeof(filepreset)))
1280 /* check the name: max MAX_FILENAME (20) chars */
1281 char* p2;
1282 char* p1;
1283 int len;
1284 p1 = strrchr(filepreset, '/');
1285 p2 = p1;
1286 while((p1) && (*p2) && (*p2 != '.'))
1287 p2++;
1288 len = (int)(p2-p1) - 1;
1289 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1291 /* no slash, too long or too short */
1292 splash(HZ, ID2P(LANG_INVALID_FILENAME));
1294 else
1296 /* add correct extension (easier to always write)
1297 at this point, p2 points to 0 or the extension dot */
1298 *p2 = '\0';
1299 strcat(filepreset,".fmr");
1300 bad_file_name = false;
1301 radio_save_presets();
1304 else
1306 /* user aborted */
1307 return false;
1311 else
1312 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
1314 return true;
1317 static int clear_preset_list(void)
1319 /* Clear all the preset entries */
1320 memset(presets, 0, sizeof (presets));
1322 num_presets = 0;
1323 presets_loaded = false;
1324 /* The preset list will be cleared switch to Scan Mode. */
1325 radio_mode = RADIO_SCAN_MODE;
1326 curr_preset = -1;
1328 presets_changed = false; /* Don't ask to save when clearing the list. */
1330 return true;
1333 MENUITEM_FUNCTION(radio_edit_preset_item, MENU_FUNC_CHECK_RETVAL,
1334 ID2P(LANG_FM_EDIT_PRESET),
1335 radio_edit_preset, NULL, NULL, Icon_NOICON);
1336 MENUITEM_FUNCTION(radio_delete_preset_item, MENU_FUNC_CHECK_RETVAL,
1337 ID2P(LANG_FM_DELETE_PRESET),
1338 radio_delete_preset, NULL, NULL, Icon_NOICON);
1339 static int radio_preset_callback(int action,
1340 const struct menu_item_ex *this_item)
1342 if (action == ACTION_STD_OK)
1343 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1344 return action;
1345 (void)this_item;
1347 MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_PRESET),
1348 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
1349 &radio_delete_preset_item);
1350 /* present a list of preset stations */
1351 static char * presets_get_name(int selected_item, void *data,
1352 char *buffer, size_t buffer_len)
1354 (void)data;
1355 struct fmstation *p = &presets[selected_item];
1356 if(p->name[0])
1357 return p->name;
1358 int freq = p->frequency / 10000;
1359 int frac = freq % 100;
1360 freq /= 100;
1361 snprintf(buffer, buffer_len,
1362 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1363 return buffer;
1366 static int presets_speak_name(int selected_item, void * data)
1368 (void)data;
1369 talk_preset(selected_item, true, false);
1370 return 0;
1373 static int handle_radio_presets(void)
1375 struct gui_synclist lists;
1376 int result = 0;
1377 int action = ACTION_NONE;
1378 #ifdef HAVE_BUTTONBAR
1379 struct gui_buttonbar buttonbar;
1380 #endif
1382 if(presets_loaded == false)
1383 return result;
1385 #ifdef HAVE_BUTTONBAR
1386 gui_buttonbar_init(&buttonbar);
1387 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
1388 gui_buttonbar_set(&buttonbar, str(LANG_FM_BUTTONBAR_ADD),
1389 str(LANG_FM_BUTTONBAR_EXIT),
1390 str(LANG_FM_BUTTONBAR_ACTION));
1391 gui_buttonbar_draw(&buttonbar);
1392 #endif
1393 gui_synclist_init(&lists, presets_get_name, NULL, false, 1, NULL);
1394 gui_synclist_set_title(&lists, str(LANG_PRESET), NOICON);
1395 gui_synclist_set_icon_callback(&lists, NULL);
1396 if(global_settings.talk_file)
1397 gui_synclist_set_voice_callback(&lists, presets_speak_name);
1398 gui_synclist_set_nb_items(&lists, num_presets);
1399 gui_synclist_select_item(&lists, curr_preset<0 ? 0 : curr_preset);
1400 gui_synclist_speak_item(&lists);
1402 while (result == 0)
1404 gui_synclist_draw(&lists);
1405 list_do_action(CONTEXT_STD, TIMEOUT_BLOCK,
1406 &lists, &action, LIST_WRAP_UNLESS_HELD);
1407 switch (action)
1409 case ACTION_STD_MENU:
1410 if (radio_add_preset())
1412 gui_synclist_set_nb_items(&lists, num_presets);
1413 gui_synclist_select_item(&lists, num_presets - 1);
1415 break;
1416 case ACTION_STD_CANCEL:
1417 result = 1;
1418 break;
1419 case ACTION_STD_OK:
1420 curr_preset = gui_synclist_get_sel_pos(&lists);
1421 curr_freq = presets[curr_preset].frequency;
1422 next_station(0);
1423 remember_frequency();
1424 result = 1;
1425 break;
1426 case ACTION_F3:
1427 case ACTION_STD_CONTEXT:
1428 selected_preset = gui_synclist_get_sel_pos(&lists);
1429 do_menu(&handle_radio_preset_menu, NULL, NULL, false);
1430 gui_synclist_set_nb_items(&lists, num_presets);
1431 gui_synclist_select_item(&lists, selected_preset);
1432 gui_synclist_speak_item(&lists);
1433 break;
1434 default:
1435 if(default_event_handler(action) == SYS_USB_CONNECTED)
1436 result = 2;
1439 return result - 1;
1442 void toggle_mono_mode(bool mono)
1444 tuner_set(RADIO_FORCE_MONO, mono);
1447 void set_radio_region(int region)
1449 #ifdef HAVE_RADIO_REGION
1450 tuner_set(RADIO_REGION, region);
1451 #endif
1452 next_station(0);
1453 remember_frequency();
1454 (void)region;
1457 MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL);
1458 MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL);
1460 #ifndef FM_MODE
1461 static char* get_mode_text(int selected_item, void * data, char *buffer)
1463 (void)selected_item;
1464 (void)data;
1465 snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE),
1466 radio_mode ? str(LANG_PRESET) :
1467 str(LANG_RADIO_SCAN_MODE));
1468 return buffer;
1470 static int toggle_radio_mode(void)
1472 radio_mode = (radio_mode == RADIO_SCAN_MODE) ?
1473 RADIO_PRESET_MODE : RADIO_SCAN_MODE;
1474 return 0;
1476 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0,
1477 toggle_radio_mode, NULL,
1478 get_mode_text, NULL, NULL, NULL, Icon_NOICON);
1479 #endif
1481 static int scan_presets(void *viewports)
1483 bool do_scan = true;
1484 int i;
1485 struct viewport *vp = (struct viewport *)viewports;
1487 FOR_NB_SCREENS(i)
1488 screens[i].set_viewport(vp?&vp[i]:NULL);
1489 if(num_presets > 0) /* Do that to avoid 2 questions. */
1490 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1492 if(do_scan)
1494 const struct fm_region_data * const fmr =
1495 &fm_region_data[global_settings.fm_region];
1497 curr_freq = fmr->freq_min;
1498 num_presets = 0;
1499 memset(presets, 0, sizeof(presets));
1500 tuner_set(RADIO_MUTE, 1);
1502 while(curr_freq <= fmr->freq_max)
1504 int freq, frac;
1505 if(num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1506 break;
1508 freq = curr_freq / 10000;
1509 frac = freq % 100;
1510 freq /= 100;
1512 splashf(0, str(LANG_FM_SCANNING), freq, frac);
1514 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
1516 /* add preset */
1517 presets[num_presets].name[0] = '\0';
1518 presets[num_presets].frequency = curr_freq;
1519 num_presets++;
1522 curr_freq += fmr->freq_step;
1525 if (radio_status == FMRADIO_PLAYING)
1526 tuner_set(RADIO_MUTE, 0);
1528 presets_changed = true;
1530 FOR_NB_SCREENS(i)
1532 screens[i].clear_viewport();
1533 screens[i].update_viewport();
1536 if(num_presets > 0)
1538 curr_freq = presets[0].frequency;
1539 radio_mode = RADIO_PRESET_MODE;
1540 presets_loaded = true;
1541 next_station(0);
1543 else
1545 /* Wrap it to beginning or we'll be past end of band */
1546 presets_loaded = false;
1547 next_station(1);
1550 return true;
1554 #ifdef HAVE_RECORDING
1556 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1557 #define FM_RECORDING_SCREEN
1558 static int fm_recording_screen(void)
1560 bool ret;
1562 /* switch recording source to FMRADIO for the duration */
1563 int rec_source = global_settings.rec_source;
1564 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1566 ret = recording_screen(true);
1568 /* safe to reset as changing sources is prohibited here */
1569 global_settings.rec_source = rec_source;
1571 return ret;
1574 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1576 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1577 #define FM_RECORDING_SETTINGS
1578 static int fm_recording_settings(void)
1580 bool ret = recording_menu(true);
1582 #if CONFIG_CODEC != SWCODEC
1583 if (!ret)
1585 struct audio_recording_options rec_options;
1586 rec_init_recording_options(&rec_options);
1587 rec_options.rec_source = AUDIO_SRC_LINEIN;
1588 rec_set_recording_options(&rec_options);
1590 #endif
1592 return ret;
1595 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1596 #endif /* HAVE_RECORDING */
1598 #ifdef FM_RECORDING_SCREEN
1599 MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING),
1600 fm_recording_screen, NULL, NULL, Icon_Recording);
1601 #endif
1602 #ifdef FM_RECORDING_SETTINGS
1603 MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS),
1604 fm_recording_settings, NULL, NULL, Icon_Recording);
1605 #endif
1606 #ifndef FM_PRESET
1607 MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET),
1608 handle_radio_presets, NULL, NULL, Icon_NOICON);
1609 #endif
1610 #ifndef FM_PRESET_ADD
1611 MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET),
1612 radio_add_preset, NULL, NULL, Icon_NOICON);
1613 #endif
1616 MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD),
1617 load_preset_list, NULL, NULL, Icon_NOICON);
1618 MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE),
1619 save_preset_list, NULL, NULL, Icon_NOICON);
1620 MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR),
1621 clear_preset_list, NULL, NULL, Icon_NOICON);
1622 MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM,
1623 ID2P(LANG_FM_SCAN_PRESETS),
1624 scan_presets, NULL, NULL, Icon_NOICON);
1626 MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1627 Icon_Radio_screen,
1628 #ifndef FM_PRESET
1629 &radio_presets_item,
1630 #endif
1631 #ifndef FM_PRESET_ADD
1632 &radio_addpreset_item,
1633 #endif
1634 &presetload_item, &presetsave_item, &presetclear_item,
1635 &force_mono,
1636 #ifndef FM_MODE
1637 &radio_mode_item,
1638 #endif
1639 &set_region, &sound_settings,
1640 #ifdef FM_RECORDING_SCREEN
1641 &recscreen_item,
1642 #endif
1643 #ifdef FM_RECORDING_SETTINGS
1644 &recsettings_item,
1645 #endif
1646 &scan_presets_item);
1647 /* main menu of the radio screen */
1648 static bool radio_menu(void)
1650 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1651 MENU_ATTACHED_USB;
1654 #endif