woops... fix the header and bump the plugin API
[kugel-rb.git] / apps / recorder / radio.c
blobd01d24ccf2f5ced8e1654dcf27c875df0fd31638
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 statusbar = global_settings.statusbar;
463 bool talk = false;
464 #ifdef FM_RECORD_DBLPRE
465 int lastbutton = BUTTON_NONE;
466 unsigned long rec_lastclick = 0;
467 #endif
468 #if CONFIG_CODEC != SWCODEC
469 bool have_recorded = false;
470 int timeout = current_tick + HZ/10;
471 unsigned int seconds = 0;
472 unsigned int last_seconds = 0;
473 int hours, minutes;
474 struct audio_recording_options rec_options;
475 #endif /* CONFIG_CODEC != SWCODEC */
476 #ifndef HAVE_NOISY_IDLE_MODE
477 int button_timeout = current_tick + (2*HZ);
478 #endif
479 struct viewport vp[NB_SCREENS];
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 global_status.statusbar_forced = statusbar?0:1;
491 global_settings.statusbar = true;
492 FOR_NB_SCREENS(i)
494 viewport_set_defaults(&vp[i], i);
495 #ifdef HAVE_BUTTONBAR
496 if (global_settings.buttonbar)
497 vp[i].height -= BUTTONBAR_HEIGHT;
498 #endif
499 screens[i].set_viewport(&vp[i]);
500 screens[i].stop_scroll();
501 screens[i].clear_viewport();
502 screens[i].update_viewport();
505 fh = font_get(FONT_UI)->height;
507 /* Adjust for font size, trying to center the information vertically */
508 if(fh < 10)
509 top_of_screen = 1;
511 if(num_presets <= 0)
513 memset(presets, 0, sizeof(presets));
514 radio_load_presets(global_settings.fmr_file);
517 if(radio_status == FMRADIO_OFF)
518 audio_stop();
519 #ifndef SIMULATOR
521 #if CONFIG_CODEC != SWCODEC
522 if(rec_create_directory() > 0)
523 have_recorded = true;
525 audio_init_recording(talk_get_bufsize());
527 sound_settings_apply();
528 /* Yes, we use the D/A for monitoring */
529 peak_meter_playback(true);
531 peak_meter_enabled = true;
533 rec_init_recording_options(&rec_options);
534 rec_options.rec_source = AUDIO_SRC_LINEIN;
535 rec_set_recording_options(&rec_options);
537 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
538 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
540 #endif /* CONFIG_CODEC != SWCODEC */
541 #endif /* ndef SIMULATOR */
543 /* turn on radio */
544 #if CONFIG_CODEC == SWCODEC
545 audio_set_input_source(AUDIO_SRC_FMRADIO,
546 (radio_status == FMRADIO_PAUSED) ?
547 SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
548 #else
549 if (radio_status == FMRADIO_OFF)
550 radio_start();
551 #endif
553 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
554 scan_presets(vp);
556 curr_preset = find_preset(curr_freq);
557 if(curr_preset != -1)
558 radio_mode = RADIO_PRESET_MODE;
560 #ifdef HAVE_BUTTONBAR
561 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
562 str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD));
563 #endif
565 #ifndef HAVE_NOISY_IDLE_MODE
566 cpu_idle_mode(true);
567 #endif
569 while(!done)
571 if(search_dir != 0)
573 curr_freq = step_freq(curr_freq, search_dir);
574 update_screen = true;
576 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
578 curr_preset = find_preset(curr_freq);
579 remember_frequency();
580 end_search();
581 talk = true;
584 trigger_cpu_boost();
587 if (!update_screen)
589 cancel_cpu_boost();
592 #if CONFIG_CODEC != SWCODEC
593 /* TODO: Can we timeout at HZ when recording since peaks aren't
594 displayed? This should quiet recordings too. */
595 button = get_action(CONTEXT_FM,
596 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
597 #else
598 button = get_action(CONTEXT_FM,
599 update_screen ? TIMEOUT_NOBLOCK : HZ);
600 #endif
602 #ifndef HAVE_NOISY_IDLE_MODE
603 if (button != ACTION_NONE)
605 cpu_idle_mode(false);
606 button_timeout = current_tick + (2*HZ);
608 #endif
609 switch(button)
611 case ACTION_FM_STOP:
612 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
613 if(audio_status() == AUDIO_STATUS_RECORD)
615 audio_stop();
617 else
618 #endif
620 done = true;
621 if(presets_changed)
623 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
625 if(filepreset[0] == '\0')
626 save_preset_list();
627 else
628 radio_save_presets();
631 /* Clear the preset list on exit. */
632 clear_preset_list();
634 update_screen = true;
635 break;
637 #ifdef FM_RECORD
638 case ACTION_FM_RECORD:
639 #ifdef FM_RECORD_DBLPRE
640 if (lastbutton != ACTION_FM_RECORD_DBLPRE)
642 rec_lastclick = 0;
643 break;
645 if (current_tick - rec_lastclick > HZ/2)
647 rec_lastclick = current_tick;
648 break;
650 #endif /* FM_RECORD_DBLPRE */
651 #ifndef SIMULATOR
652 if(audio_status() == AUDIO_STATUS_RECORD)
654 rec_command(RECORDING_CMD_START_NEWFILE);
655 update_screen = true;
657 else
659 have_recorded = true;
660 rec_command(RECORDING_CMD_START);
661 update_screen = true;
663 #endif /* SIMULATOR */
664 last_seconds = 0;
665 break;
666 #endif /* #ifdef FM_RECORD */
668 case ACTION_FM_EXIT:
669 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
670 if(audio_status() == AUDIO_STATUS_RECORD)
671 audio_stop();
672 #endif
673 keep_playing = true;
674 done = true;
675 ret_val = GO_TO_ROOT;
676 if(presets_changed)
678 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
680 if(filepreset[0] == '\0')
681 save_preset_list();
682 else
683 radio_save_presets();
687 /* Clear the preset list on exit. */
688 clear_preset_list();
690 break;
692 case ACTION_STD_PREV:
693 case ACTION_STD_NEXT:
694 next_station(button == ACTION_STD_PREV ? -1 : 1);
695 end_search();
696 update_screen = true;
697 talk = true;
698 break;
700 case ACTION_STD_PREVREPEAT:
701 case ACTION_STD_NEXTREPEAT:
703 int dir = search_dir;
704 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
705 if (radio_mode != RADIO_SCAN_MODE)
707 next_preset(search_dir);
708 end_search();
709 update_screen = true;
710 talk = true;
712 else if (dir == 0)
714 /* Starting auto scan */
715 tuner_set(RADIO_MUTE, 1);
716 update_screen = true;
718 break;
721 case ACTION_SETTINGS_INC:
722 case ACTION_SETTINGS_INCREPEAT:
723 global_settings.volume++;
724 setvol();
725 update_screen = true;
726 break;
728 case ACTION_SETTINGS_DEC:
729 case ACTION_SETTINGS_DECREPEAT:
730 global_settings.volume--;
731 setvol();
732 update_screen = true;
733 break;
735 case ACTION_FM_PLAY:
736 if (radio_status == FMRADIO_PLAYING)
737 radio_pause();
738 else
739 radio_start();
741 update_screen = true;
742 talk = false;
743 talk_shutup();
744 break;
746 case ACTION_FM_MENU:
747 radio_menu();
748 curr_preset = find_preset(curr_freq);
749 FOR_NB_SCREENS(i)
751 screens[i].set_viewport(&vp[i]);
752 screens[i].clear_viewport();
753 screens[i].update_viewport();
754 screens[i].set_viewport(NULL);
756 #ifdef HAVE_BUTTONBAR
757 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
758 str(LANG_PRESET),
759 str(LANG_FM_BUTTONBAR_RECORD));
760 #endif
761 update_screen = true;
762 break;
764 #ifdef FM_PRESET
765 case ACTION_FM_PRESET:
766 if(num_presets < 1)
768 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
769 update_screen = true;
770 FOR_NB_SCREENS(i)
772 screens[i].set_viewport(&vp[i]);
773 screens[i].clear_viewport();
774 screens[i].update_viewport();
775 screens[i].set_viewport(NULL);
778 break;
780 handle_radio_presets();
781 FOR_NB_SCREENS(i)
783 screens[i].set_viewport(&vp[i]);
784 screens[i].stop_scroll();
785 screens[i].clear_viewport();
786 screens[i].update_viewport();
787 screens[i].set_viewport(NULL);
789 #ifdef HAVE_BUTTONBAR
790 gui_buttonbar_set(&buttonbar,
791 str(LANG_BUTTONBAR_MENU),
792 str(LANG_PRESET),
793 str(LANG_FM_BUTTONBAR_RECORD));
794 #endif
795 update_screen = true;
796 break;
797 #endif /* FM_PRESET */
799 #ifdef FM_FREEZE
800 case ACTION_FM_FREEZE:
801 if(!screen_freeze)
803 splash(HZ, str(LANG_FM_FREEZE));
804 screen_freeze = true;
806 else
808 update_screen = true;
809 screen_freeze = false;
811 break;
812 #endif /* FM_FREEZE */
814 case SYS_USB_CONNECTED:
815 #if CONFIG_CODEC != SWCODEC
816 /* Only accept USB connection when not recording */
817 if(audio_status() != AUDIO_STATUS_RECORD)
818 #endif
820 default_event_handler(SYS_USB_CONNECTED);
821 screen_freeze = true; /* Cosmetic: makes sure the
822 radio screen doesn't redraw */
823 done = true;
825 break;
827 #ifdef FM_MODE
828 case ACTION_FM_MODE:
829 if(radio_mode == RADIO_SCAN_MODE)
831 /* Force scan mode if there are no presets. */
832 if(num_presets > 0)
833 radio_mode = RADIO_PRESET_MODE;
835 else
836 radio_mode = RADIO_SCAN_MODE;
837 update_screen = true;
838 cond_talk_ids_fq(radio_mode ?
839 LANG_PRESET : LANG_RADIO_SCAN_MODE);
840 talk = true;
841 break;
842 #endif /* FM_MODE */
844 #ifdef FM_NEXT_PRESET
845 case ACTION_FM_NEXT_PRESET:
846 next_preset(1);
847 end_search();
848 update_screen = true;
849 talk = true;
850 break;
851 #endif
853 #ifdef FM_PREV_PRESET
854 case ACTION_FM_PREV_PRESET:
855 next_preset(-1);
856 end_search();
857 update_screen = true;
858 talk = true;
859 break;
860 #endif
862 default:
863 default_event_handler(button);
864 break;
865 } /*switch(button)*/
867 #ifdef FM_RECORD_DBLPRE
868 if (button != ACTION_NONE)
869 lastbutton = button;
870 #endif
872 #if CONFIG_CODEC != SWCODEC
873 peak_meter_peek();
874 #endif
876 if(!screen_freeze)
878 /* Only display the peak meter when not recording */
879 #if CONFIG_CODEC != SWCODEC
880 if(!audio_status())
882 FOR_NB_SCREENS(i)
884 screens[i].set_viewport(&vp[i]);
885 peak_meter_screen(&screens[i],0,
886 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
887 fh);
888 screens[i].update_rect(0,
889 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
890 screens[i].getwidth(), fh);
891 screens[i].set_viewport(NULL);
895 if(TIME_AFTER(current_tick, timeout))
897 timeout = current_tick + HZ;
898 #else /* SWCODEC */
900 #endif /* CONFIG_CODEC == SWCODEC */
902 /* keep "mono" from always being displayed when paused */
903 if (radio_status != FMRADIO_PAUSED)
905 stereo = tuner_get(RADIO_STEREO) &&
906 !global_settings.fm_force_mono;
908 if(stereo != last_stereo)
910 update_screen = true;
911 last_stereo = stereo;
916 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
917 seconds = audio_recorded_time() / HZ;
918 if (update_screen || seconds > last_seconds)
920 last_seconds = seconds;
921 #else
922 if (update_screen)
924 #endif
925 int freq;
927 FOR_NB_SCREENS(i)
929 screens[i].set_viewport(&vp[i]);
932 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
933 curr_preset + 1, presets[curr_preset].name);
935 FOR_NB_SCREENS(i)
936 screens[i].puts_scroll(0, top_of_screen, buf);
938 freq = curr_freq / 10000;
939 snprintf(buf, 128, str(LANG_FM_STATION),
940 freq / 100, freq % 100);
941 FOR_NB_SCREENS(i)
942 screens[i].puts_scroll(0, top_of_screen + 1, buf);
944 snprintf(buf, 128, "%s", stereo?str(LANG_CHANNEL_STEREO):
945 str(LANG_CHANNEL_MONO));
946 FOR_NB_SCREENS(i)
947 screens[i].puts_scroll(0, top_of_screen + 2, buf);
949 snprintf(buf, 128, "%s %s", str(LANG_MODE),
950 radio_mode ? str(LANG_PRESET) :
951 str(LANG_RADIO_SCAN_MODE));
952 FOR_NB_SCREENS(i)
953 screens[i].puts_scroll(0, top_of_screen + 3, buf);
955 #if CONFIG_CODEC != SWCODEC
956 if(audio_status() == AUDIO_STATUS_RECORD)
958 hours = seconds / 3600;
959 minutes = (seconds - (hours * 3600)) / 60;
960 snprintf(buf, 32, "%s %02d:%02d:%02d",
961 str(LANG_RECORDING_TIME),
962 hours, minutes, seconds%60);
963 FOR_NB_SCREENS(i)
964 screens[i].puts_scroll(0, top_of_screen + 4, buf);
966 else
968 if(rec_options.rec_prerecord_time)
970 snprintf(buf, 32, "%s %02d",
971 str(LANG_RECORD_PRERECORD), seconds%60);
972 FOR_NB_SCREENS(i)
973 screens[i].puts_scroll(0, top_of_screen + 4, buf);
976 #endif /* CONFIG_CODEC != SWCODEC */
978 FOR_NB_SCREENS(i)
980 screens[i].update_viewport();
981 screens[i].set_viewport(NULL);
984 #ifdef HAVE_BUTTONBAR
985 gui_buttonbar_draw(&buttonbar);
986 #endif
990 update_screen = false;
992 if (global_settings.talk_file && talk
993 && radio_status == FMRADIO_PAUSED)
995 talk = false;
996 bool enqueue = false;
997 if (radio_mode == RADIO_SCAN_MODE)
999 talk_freq(curr_freq, enqueue);
1000 enqueue = true;
1002 if (curr_preset >= 0)
1003 talk_preset(curr_preset, radio_mode == RADIO_PRESET_MODE,
1004 enqueue);
1007 #if CONFIG_CODEC != SWCODEC
1008 if(audio_status() & AUDIO_STATUS_ERROR)
1010 done = true;
1012 #endif
1014 #ifndef HAVE_NOISY_IDLE_MODE
1015 if (TIME_AFTER(current_tick, button_timeout))
1017 cpu_idle_mode(true);
1019 #endif
1020 } /*while(!done)*/
1022 #ifndef SIMULATOR
1023 #if CONFIG_CODEC != SWCODEC
1024 if(audio_status() & AUDIO_STATUS_ERROR)
1026 splash(0, str(LANG_DISK_FULL));
1027 FOR_NB_SCREENS(i)
1029 screens[i].set_viewport(&vp[i]);
1030 screens[i].update_viewport();
1031 screens[i].set_viewport(NULL);
1033 audio_error_clear();
1035 while(1)
1037 button = get_action(CONTEXT_FM, TIMEOUT_BLOCK);
1038 if(button == ACTION_FM_STOP)
1039 break;
1043 audio_init_playback();
1044 #endif /* CONFIG_CODEC != SWCODEC */
1046 sound_settings_apply();
1047 #endif /* SIMULATOR */
1049 if(keep_playing)
1051 /* Catch FMRADIO_PLAYING status for the sim. */
1052 #ifndef SIMULATOR
1053 #if CONFIG_CODEC != SWCODEC
1054 /* Enable the Left and right A/D Converter */
1055 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
1056 sound_default(SOUND_RIGHT_GAIN),
1057 AUDIO_GAIN_LINEIN);
1058 mas_codec_writereg(6, 0x4000);
1059 #endif
1060 end_search();
1061 #endif /* SIMULATOR */
1063 else
1065 #if CONFIG_CODEC == SWCODEC
1066 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1067 #else
1068 radio_stop();
1069 #endif
1072 #ifndef HAVE_NOISY_IDLE_MODE
1073 cpu_idle_mode(false);
1074 #endif
1076 /* restore status bar settings */
1077 global_settings.statusbar = statusbar;
1078 global_status.statusbar_forced = 0;
1079 in_screen = false;
1080 #if CONFIG_CODEC != SWCODEC
1081 return have_recorded;
1082 #else
1083 return false;
1084 #endif
1085 } /* radio_screen */
1087 static void radio_save_presets(void)
1089 int fd;
1090 int i;
1092 fd = creat(filepreset);
1093 if(fd >= 0)
1095 for(i = 0;i < num_presets;i++)
1097 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
1099 close(fd);
1101 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1102 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1103 presets_changed = false;
1105 else
1107 splash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1111 void radio_load_presets(char *filename)
1113 int fd;
1114 int rc;
1115 char buf[128];
1116 char *freq;
1117 char *name;
1118 bool done = false;
1119 int f;
1121 memset(presets, 0, sizeof(presets));
1122 num_presets = 0;
1124 /* No Preset in configuration. */
1125 if(filename[0] == '\0')
1127 filepreset[0] = '\0';
1128 return;
1130 /* Temporary preset, loaded until player shuts down. */
1131 else if(filename[0] == '/')
1132 strncpy(filepreset, filename, sizeof(filepreset));
1133 /* Preset from default directory. */
1134 else
1135 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1136 FMPRESET_PATH, filename);
1138 fd = open_utf8(filepreset, O_RDONLY);
1139 if(fd >= 0)
1141 while(!done && num_presets < MAX_PRESETS)
1143 rc = read_line(fd, buf, 128);
1144 if(rc > 0)
1146 if(settings_parseline(buf, &freq, &name))
1148 f = atoi(freq);
1149 if(f) /* For backwards compatibility */
1151 struct fmstation * const fms = &presets[num_presets];
1152 fms->frequency = f;
1153 strncpy(fms->name, name, MAX_FMPRESET_LEN);
1154 fms->name[MAX_FMPRESET_LEN] = '\0';
1155 num_presets++;
1159 else
1160 done = true;
1162 close(fd);
1164 else /* invalid file name? */
1165 filepreset[0] = '\0';
1167 presets_loaded = num_presets > 0;
1168 presets_changed = false;
1172 static int radio_add_preset(void)
1174 char buf[MAX_FMPRESET_LEN + 1];
1176 if(num_presets < MAX_PRESETS)
1178 buf[0] = '\0';
1180 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1182 struct fmstation * const fms = &presets[num_presets];
1183 strcpy(fms->name, buf);
1184 fms->frequency = curr_freq;
1185 num_presets++;
1186 presets_changed = true;
1187 presets_loaded = num_presets > 0;
1188 return true;
1191 else
1193 splash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1195 return false;
1198 /* needed to know which preset we are edit/delete-ing */
1199 static int selected_preset = -1;
1200 static int radio_edit_preset(void)
1202 char buf[MAX_FMPRESET_LEN + 1];
1204 if (num_presets > 0)
1206 struct fmstation * const fms = &presets[selected_preset];
1208 strcpy(buf, fms->name);
1210 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1212 strcpy(fms->name, buf);
1213 presets_changed = true;
1217 return 1;
1220 static int radio_delete_preset(void)
1222 if (num_presets > 0)
1224 struct fmstation * const fms = &presets[selected_preset];
1226 if (selected_preset >= --num_presets)
1227 selected_preset = num_presets - 1;
1229 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1230 (uintptr_t)fms);
1232 if (curr_preset >= num_presets)
1233 --curr_preset;
1236 /* Don't ask to save when all presets are deleted. */
1237 presets_changed = num_presets > 0;
1239 if (!presets_changed)
1241 /* The preset list will be cleared, switch to Scan Mode. */
1242 radio_mode = RADIO_SCAN_MODE;
1243 curr_preset = -1;
1244 presets_loaded = false;
1247 return 1;
1250 static int load_preset_list(void)
1252 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1255 static int save_preset_list(void)
1257 if(num_presets > 0)
1259 bool bad_file_name = true;
1261 if(!dir_exists(FMPRESET_PATH)) /* Check if there is preset folder */
1262 mkdir(FMPRESET_PATH);
1264 create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
1265 ".fmr", 2 IF_CNFN_NUM_(, NULL));
1267 while(bad_file_name)
1269 if(!kbd_input(filepreset, sizeof(filepreset)))
1271 /* check the name: max MAX_FILENAME (20) chars */
1272 char* p2;
1273 char* p1;
1274 int len;
1275 p1 = strrchr(filepreset, '/');
1276 p2 = p1;
1277 while((p1) && (*p2) && (*p2 != '.'))
1278 p2++;
1279 len = (int)(p2-p1) - 1;
1280 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1282 /* no slash, too long or too short */
1283 splash(HZ, ID2P(LANG_INVALID_FILENAME));
1285 else
1287 /* add correct extension (easier to always write)
1288 at this point, p2 points to 0 or the extension dot */
1289 *p2 = '\0';
1290 strcat(filepreset,".fmr");
1291 bad_file_name = false;
1292 radio_save_presets();
1295 else
1297 /* user aborted */
1298 return false;
1302 else
1303 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
1305 return true;
1308 static int clear_preset_list(void)
1310 /* Clear all the preset entries */
1311 memset(presets, 0, sizeof (presets));
1313 num_presets = 0;
1314 presets_loaded = false;
1315 /* The preset list will be cleared switch to Scan Mode. */
1316 radio_mode = RADIO_SCAN_MODE;
1317 curr_preset = -1;
1319 presets_changed = false; /* Don't ask to save when clearing the list. */
1321 return true;
1324 MENUITEM_FUNCTION(radio_edit_preset_item, MENU_FUNC_CHECK_RETVAL,
1325 ID2P(LANG_FM_EDIT_PRESET),
1326 radio_edit_preset, NULL, NULL, Icon_NOICON);
1327 MENUITEM_FUNCTION(radio_delete_preset_item, MENU_FUNC_CHECK_RETVAL,
1328 ID2P(LANG_FM_DELETE_PRESET),
1329 radio_delete_preset, NULL, NULL, Icon_NOICON);
1330 static int radio_preset_callback(int action,
1331 const struct menu_item_ex *this_item)
1333 if (action == ACTION_STD_OK)
1334 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1335 return action;
1336 (void)this_item;
1338 MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_PRESET),
1339 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
1340 &radio_delete_preset_item);
1341 /* present a list of preset stations */
1342 static char * presets_get_name(int selected_item, void *data,
1343 char *buffer, size_t buffer_len)
1345 (void)data;
1346 struct fmstation *p = &presets[selected_item];
1347 if(p->name[0])
1348 return p->name;
1349 int freq = p->frequency / 10000;
1350 int frac = freq % 100;
1351 freq /= 100;
1352 snprintf(buffer, buffer_len,
1353 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1354 return buffer;
1357 static int presets_speak_name(int selected_item, void * data)
1359 (void)data;
1360 talk_preset(selected_item, true, false);
1361 return 0;
1364 static int handle_radio_presets(void)
1366 struct gui_synclist lists;
1367 int result = 0;
1368 int action = ACTION_NONE;
1369 #ifdef HAVE_BUTTONBAR
1370 struct gui_buttonbar buttonbar;
1371 #endif
1373 if(presets_loaded == false)
1374 return result;
1376 #ifdef HAVE_BUTTONBAR
1377 gui_buttonbar_init(&buttonbar);
1378 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
1379 gui_buttonbar_set(&buttonbar, str(LANG_FM_BUTTONBAR_ADD),
1380 str(LANG_FM_BUTTONBAR_EXIT),
1381 str(LANG_FM_BUTTONBAR_ACTION));
1382 gui_buttonbar_draw(&buttonbar);
1383 #endif
1384 gui_synclist_init(&lists, presets_get_name, NULL, false, 1, NULL);
1385 gui_synclist_set_title(&lists, str(LANG_PRESET), NOICON);
1386 gui_synclist_set_icon_callback(&lists, NULL);
1387 if(global_settings.talk_file)
1388 gui_synclist_set_voice_callback(&lists, presets_speak_name);
1389 gui_synclist_set_nb_items(&lists, num_presets);
1390 gui_synclist_select_item(&lists, curr_preset<0 ? 0 : curr_preset);
1391 gui_synclist_speak_item(&lists);
1393 while (result == 0)
1395 gui_synclist_draw(&lists);
1396 list_do_action(CONTEXT_STD, TIMEOUT_BLOCK,
1397 &lists, &action, LIST_WRAP_UNLESS_HELD);
1398 switch (action)
1400 case ACTION_STD_MENU:
1401 if (radio_add_preset())
1403 gui_synclist_set_nb_items(&lists, num_presets);
1404 gui_synclist_select_item(&lists, num_presets - 1);
1406 break;
1407 case ACTION_STD_CANCEL:
1408 result = 1;
1409 break;
1410 case ACTION_STD_OK:
1411 curr_preset = gui_synclist_get_sel_pos(&lists);
1412 curr_freq = presets[curr_preset].frequency;
1413 next_station(0);
1414 remember_frequency();
1415 result = 1;
1416 break;
1417 case ACTION_F3:
1418 case ACTION_STD_CONTEXT:
1419 selected_preset = gui_synclist_get_sel_pos(&lists);
1420 do_menu(&handle_radio_preset_menu, NULL, NULL, false);
1421 gui_synclist_set_nb_items(&lists, num_presets);
1422 gui_synclist_select_item(&lists, selected_preset);
1423 gui_synclist_speak_item(&lists);
1424 break;
1425 default:
1426 if(default_event_handler(action) == SYS_USB_CONNECTED)
1427 result = 2;
1430 return result - 1;
1433 void toggle_mono_mode(bool mono)
1435 tuner_set(RADIO_FORCE_MONO, mono);
1438 void set_radio_region(int region)
1440 #ifdef HAVE_RADIO_REGION
1441 tuner_set(RADIO_REGION, region);
1442 #endif
1443 next_station(0);
1444 remember_frequency();
1445 (void)region;
1448 MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL);
1449 MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL);
1451 #ifndef FM_MODE
1452 static char* get_mode_text(int selected_item, void * data, char *buffer)
1454 (void)selected_item;
1455 (void)data;
1456 snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE),
1457 radio_mode ? str(LANG_PRESET) :
1458 str(LANG_RADIO_SCAN_MODE));
1459 return buffer;
1461 static int toggle_radio_mode(void)
1463 radio_mode = (radio_mode == RADIO_SCAN_MODE) ?
1464 RADIO_PRESET_MODE : RADIO_SCAN_MODE;
1465 return 0;
1467 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0,
1468 toggle_radio_mode, NULL,
1469 get_mode_text, NULL, NULL, NULL, Icon_NOICON);
1470 #endif
1472 static int scan_presets(void *viewports)
1474 bool do_scan = true;
1475 int i;
1476 struct viewport *vp = (struct viewport *)viewports;
1478 FOR_NB_SCREENS(i)
1479 screens[i].set_viewport(vp?&vp[i]:NULL);
1480 if(num_presets > 0) /* Do that to avoid 2 questions. */
1481 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1483 if(do_scan)
1485 const struct fm_region_data * const fmr =
1486 &fm_region_data[global_settings.fm_region];
1488 curr_freq = fmr->freq_min;
1489 num_presets = 0;
1490 memset(presets, 0, sizeof(presets));
1491 tuner_set(RADIO_MUTE, 1);
1493 while(curr_freq <= fmr->freq_max)
1495 int freq, frac;
1496 if(num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1497 break;
1499 freq = curr_freq / 10000;
1500 frac = freq % 100;
1501 freq /= 100;
1503 splashf(0, str(LANG_FM_SCANNING), freq, frac);
1505 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
1507 /* add preset */
1508 presets[num_presets].name[0] = '\0';
1509 presets[num_presets].frequency = curr_freq;
1510 num_presets++;
1513 curr_freq += fmr->freq_step;
1516 if (radio_status == FMRADIO_PLAYING)
1517 tuner_set(RADIO_MUTE, 0);
1519 presets_changed = true;
1521 FOR_NB_SCREENS(i)
1523 screens[i].clear_viewport();
1524 screens[i].update_viewport();
1527 if(num_presets > 0)
1529 curr_freq = presets[0].frequency;
1530 radio_mode = RADIO_PRESET_MODE;
1531 presets_loaded = true;
1532 next_station(0);
1534 else
1536 /* Wrap it to beginning or we'll be past end of band */
1537 presets_loaded = false;
1538 next_station(1);
1541 return true;
1545 #ifdef HAVE_RECORDING
1547 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1548 #define FM_RECORDING_SCREEN
1549 static int fm_recording_screen(void)
1551 bool ret;
1553 /* switch recording source to FMRADIO for the duration */
1554 int rec_source = global_settings.rec_source;
1555 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1557 ret = recording_screen(true);
1559 /* safe to reset as changing sources is prohibited here */
1560 global_settings.rec_source = rec_source;
1562 return ret;
1565 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1567 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1568 #define FM_RECORDING_SETTINGS
1569 static int fm_recording_settings(void)
1571 bool ret = recording_menu(true);
1573 #if CONFIG_CODEC != SWCODEC
1574 if (!ret)
1576 struct audio_recording_options rec_options;
1577 rec_init_recording_options(&rec_options);
1578 rec_options.rec_source = AUDIO_SRC_LINEIN;
1579 rec_set_recording_options(&rec_options);
1581 #endif
1583 return ret;
1586 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1587 #endif /* HAVE_RECORDING */
1589 #ifdef FM_RECORDING_SCREEN
1590 MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING),
1591 fm_recording_screen, NULL, NULL, Icon_Recording);
1592 #endif
1593 #ifdef FM_RECORDING_SETTINGS
1594 MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS),
1595 fm_recording_settings, NULL, NULL, Icon_Recording);
1596 #endif
1597 #ifndef FM_PRESET
1598 MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET),
1599 handle_radio_presets, NULL, NULL, Icon_NOICON);
1600 #endif
1601 #ifndef FM_PRESET_ADD
1602 MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET),
1603 radio_add_preset, NULL, NULL, Icon_NOICON);
1604 #endif
1607 MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD),
1608 load_preset_list, NULL, NULL, Icon_NOICON);
1609 MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE),
1610 save_preset_list, NULL, NULL, Icon_NOICON);
1611 MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR),
1612 clear_preset_list, NULL, NULL, Icon_NOICON);
1613 MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM,
1614 ID2P(LANG_FM_SCAN_PRESETS),
1615 scan_presets, NULL, NULL, Icon_NOICON);
1617 MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1618 Icon_Radio_screen,
1619 #ifndef FM_PRESET
1620 &radio_presets_item,
1621 #endif
1622 #ifndef FM_PRESET_ADD
1623 &radio_addpreset_item,
1624 #endif
1625 &presetload_item, &presetsave_item, &presetclear_item,
1626 &force_mono,
1627 #ifndef FM_MODE
1628 &radio_mode_item,
1629 #endif
1630 &set_region, &sound_settings,
1631 #ifdef FM_RECORDING_SCREEN
1632 &recscreen_item,
1633 #endif
1634 #ifdef FM_RECORDING_SETTINGS
1635 &recsettings_item,
1636 #endif
1637 &scan_presets_item);
1638 /* main menu of the radio screen */
1639 static bool radio_menu(void)
1641 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1642 MENU_ATTACHED_USB;
1645 #endif