Remove unneeded function call (radio_load_presets does clear the memory)
[kugel-rb/myfork.git] / apps / recorder / radio.c
blobc802e760d87ebcc62d697ade43b24c857b85b36b
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 "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
112 #elif (CONFIG_KEYPAD == COWOND2_PAD)
113 #define FM_MENU
114 #define FM_PRESET
115 #define FM_STOP
116 #define FM_MODE
117 #define FM_EXIT
118 #define FM_PLAY
119 #endif
121 #define RADIO_SCAN_MODE 0
122 #define RADIO_PRESET_MODE 1
124 static int curr_preset = -1;
125 static int curr_freq; /* current frequency in Hz */
126 static int radio_mode = RADIO_SCAN_MODE;
127 static int search_dir = 0;
129 static int radio_status = FMRADIO_OFF;
130 static bool in_screen = false;
132 #define MAX_PRESETS 64
133 static bool presets_loaded = false, presets_changed = false;
134 static struct fmstation presets[MAX_PRESETS];
136 static char filepreset[MAX_PATH]; /* preset filename variable */
138 static int num_presets = 0; /* The number of presets in the preset list */
140 static void radio_save_presets(void);
141 static int handle_radio_presets(void);
142 static bool radio_menu(void);
143 static int radio_add_preset(void);
144 static int save_preset_list(void);
145 static int load_preset_list(void);
146 static int clear_preset_list(void);
148 static int scan_presets(void *viewports);
150 /* Function to manipulate all yesno dialogues.
151 This function needs the output text as an argument. */
152 static bool yesno_pop(const char* text)
154 int i;
155 const char *lines[]={text};
156 const struct text_message message={lines, 1};
157 bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES);
158 FOR_NB_SCREENS(i)
159 screens[i].clear_viewport();
160 return ret;
163 void radio_init(void)
165 tuner_init();
166 radio_stop();
169 int get_radio_status(void)
171 return radio_status;
174 bool in_radio_screen(void)
176 return in_screen;
179 /* TODO: Move some more of the control functionality to firmware
180 and clean up the mess */
182 /* secret flag for starting paused - prevents unmute */
183 #define FMRADIO_START_PAUSED 0x8000
184 void radio_start(void)
186 const struct fm_region_data *fmr;
187 bool start_paused;
189 if(radio_status == FMRADIO_PLAYING)
190 return;
192 fmr = &fm_region_data[global_settings.fm_region];
194 start_paused = radio_status & FMRADIO_START_PAUSED;
195 /* clear flag before any yielding */
196 radio_status &= ~FMRADIO_START_PAUSED;
198 if(radio_status == FMRADIO_OFF)
199 tuner_power(true);
201 curr_freq = global_status.last_frequency * fmr->freq_step + fmr->freq_min;
203 tuner_set(RADIO_SLEEP, 0); /* wake up the tuner */
205 if(radio_status == FMRADIO_OFF)
207 #ifdef HAVE_RADIO_REGION
208 tuner_set(RADIO_REGION, global_settings.fm_region);
209 #endif
210 tuner_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
213 tuner_set(RADIO_FREQUENCY, curr_freq);
215 #ifdef HAVE_RADIO_MUTE_TIMEOUT
217 unsigned long mute_timeout = current_tick + HZ;
218 if (radio_status != FMRADIO_OFF)
220 /* paused */
221 mute_timeout += HZ;
224 while(!tuner_get(RADIO_STEREO) && !tuner_get(RADIO_TUNED))
226 if(TIME_AFTER(current_tick, mute_timeout))
227 break;
228 yield();
231 #endif
233 /* keep radio from sounding initially */
234 if(!start_paused)
235 tuner_set(RADIO_MUTE, 0);
237 radio_status = FMRADIO_PLAYING;
238 } /* radio_start */
240 void radio_pause(void)
242 if(radio_status == FMRADIO_PAUSED)
243 return;
245 if(radio_status == FMRADIO_OFF)
247 radio_status |= FMRADIO_START_PAUSED;
248 radio_start();
251 tuner_set(RADIO_MUTE, 1);
252 tuner_set(RADIO_SLEEP, 1);
254 radio_status = FMRADIO_PAUSED;
255 } /* radio_pause */
257 void radio_stop(void)
259 if(radio_status == FMRADIO_OFF)
260 return;
262 tuner_set(RADIO_MUTE, 1);
263 tuner_set(RADIO_SLEEP, 1); /* low power mode, if available */
264 radio_status = FMRADIO_OFF;
265 tuner_power(false); /* status update, power off if avail. */
266 } /* radio_stop */
268 bool radio_hardware_present(void)
270 return tuner_get(RADIO_PRESENT);
273 /* Keep freq on the grid for the current region */
274 static int snap_freq_to_grid(int freq)
276 const struct fm_region_data * const fmr =
277 &fm_region_data[global_settings.fm_region];
279 /* Range clamp if out of range or just round to nearest */
280 if (freq < fmr->freq_min)
281 freq = fmr->freq_min;
282 else if (freq > fmr->freq_max)
283 freq = fmr->freq_max;
284 else
285 freq = (freq - fmr->freq_min + fmr->freq_step/2) /
286 fmr->freq_step * fmr->freq_step + fmr->freq_min;
288 return freq;
291 /* Find a matching preset to freq */
292 static int find_preset(int freq)
294 int i;
295 if(num_presets < 1)
296 return -1;
297 for(i = 0;i < MAX_PRESETS;i++)
299 if(freq == presets[i].frequency)
300 return i;
303 return -1;
306 /* Return the closest preset encountered in the search direction with
307 wraparound. */
308 static int find_closest_preset(int freq, int direction)
310 int i;
311 int lowpreset = 0;
312 int highpreset = 0;
313 int closest = -1;
315 if (direction == 0) /* direction == 0 isn't really used */
316 return 0;
318 for (i = 0; i < num_presets; i++)
320 int f = presets[i].frequency;
321 if (f == freq)
322 return i; /* Exact match = stop */
324 /* remember the highest and lowest presets for wraparound */
325 if (f < presets[lowpreset].frequency)
326 lowpreset = i;
327 if (f > presets[highpreset].frequency)
328 highpreset = i;
330 /* find the closest preset in the given direction */
331 if (direction > 0 && f > freq)
333 if (closest < 0 || f < presets[closest].frequency)
334 closest = i;
336 else if (direction < 0 && f < freq)
338 if (closest < 0 || f > presets[closest].frequency)
339 closest = i;
343 if (closest < 0)
345 /* no presets in the given direction */
346 /* wrap around depending on direction */
347 if (direction < 0)
348 closest = highpreset;
349 else
350 closest = lowpreset;
353 return closest;
356 static void remember_frequency(void)
358 const struct fm_region_data * const fmr =
359 &fm_region_data[global_settings.fm_region];
360 global_status.last_frequency = (curr_freq - fmr->freq_min)
361 / fmr->freq_step;
362 status_save();
365 static void next_preset(int direction)
367 if (num_presets < 1)
368 return;
370 if (curr_preset == -1)
371 curr_preset = find_closest_preset(curr_freq, direction);
372 else
373 curr_preset = (curr_preset + direction + num_presets) % num_presets;
375 /* Must stay on the current grid for the region */
376 curr_freq = snap_freq_to_grid(presets[curr_preset].frequency);
378 tuner_set(RADIO_FREQUENCY, curr_freq);
379 remember_frequency();
382 /* Step to the next or previous frequency */
383 static int step_freq(int freq, int direction)
385 const struct fm_region_data * const fmr =
386 &fm_region_data[global_settings.fm_region];
388 freq += direction*fmr->freq_step;
390 /* Wrap first or snapping to grid will not let us on the band extremes */
391 if (freq > fmr->freq_max)
392 freq = direction > 0 ? fmr->freq_min : fmr->freq_max;
393 else if (freq < fmr->freq_min)
394 freq = direction < 0 ? fmr->freq_max : fmr->freq_min;
395 else
396 freq = snap_freq_to_grid(freq);
398 return freq;
401 /* Step to the next or previous station */
402 static void next_station(int direction)
404 if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
406 next_preset(direction);
407 return;
410 curr_freq = step_freq(curr_freq, direction);
412 if (radio_status == FMRADIO_PLAYING)
413 tuner_set(RADIO_MUTE, 1);
415 tuner_set(RADIO_FREQUENCY, curr_freq);
417 if (radio_status == FMRADIO_PLAYING)
418 tuner_set(RADIO_MUTE, 0);
420 curr_preset = find_preset(curr_freq);
421 remember_frequency();
424 /* Ends an in-progress search */
425 static void end_search(void)
427 if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
428 tuner_set(RADIO_MUTE, 0);
429 search_dir = 0;
432 /* Speak a frequency. */
433 static void talk_freq(int freq, bool enqueue)
435 freq /= 10000;
436 talk_number(freq / 100, enqueue);
437 talk_id(LANG_POINT, true);
438 talk_number(freq % 100 / 10, true);
439 if (freq % 10)
440 talk_number(freq % 10, true);
443 /* Speak a preset by number or by spelling its name, depending on settings. */
444 static void talk_preset(int preset, bool fallback, bool enqueue)
446 if (global_settings.talk_file == 1) /* number */
447 talk_number(preset + 1, enqueue);
448 else
449 { /* spell */
450 if(presets[preset].name[0])
451 talk_spell(presets[preset].name, enqueue);
452 else if(fallback)
453 talk_freq(presets[preset].frequency, enqueue);
457 int radio_screen(void)
459 char buf[MAX_PATH];
460 bool done = false;
461 int ret_val = GO_TO_ROOT;
462 int button;
463 int i;
464 bool stereo = false, last_stereo = false;
465 int fh;
466 int top_of_screen = 0;
467 bool update_screen = true;
468 bool screen_freeze = false;
469 bool keep_playing = false;
470 bool talk = false;
471 #ifdef FM_RECORD_DBLPRE
472 int lastbutton = BUTTON_NONE;
473 unsigned long rec_lastclick = 0;
474 #endif
475 #if CONFIG_CODEC != SWCODEC
476 bool have_recorded = false;
477 int timeout = current_tick + HZ/10;
478 unsigned int seconds = 0;
479 unsigned int last_seconds = 0;
480 int hours, minutes;
481 struct audio_recording_options rec_options;
482 #endif /* CONFIG_CODEC != SWCODEC */
483 #ifndef HAVE_NOISY_IDLE_MODE
484 int button_timeout = current_tick + (2*HZ);
485 #endif
486 struct viewport vp[NB_SCREENS];
487 int oldbars = 0, fmbars = VP_SB_ALLSCREENS;
488 #ifdef HAVE_BUTTONBAR
489 struct gui_buttonbar buttonbar;
490 gui_buttonbar_init(&buttonbar);
491 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
492 #endif
494 /* change status to "in screen" */
495 in_screen = true;
497 /* always display status bar in radio screen for now */
498 FOR_NB_SCREENS(i)
499 fmbars |= VP_SB_IGNORE_SETTING(i);
500 oldbars = viewportmanager_set_statusbar(fmbars);
501 FOR_NB_SCREENS(i)
503 viewport_set_defaults(&vp[i], i);
504 #ifdef HAVE_BUTTONBAR
505 if (global_settings.buttonbar)
506 vp[i].height -= BUTTONBAR_HEIGHT;
507 #endif
508 screens[i].set_viewport(&vp[i]);
509 screens[i].stop_scroll();
510 screens[i].clear_viewport();
511 screens[i].update_viewport();
514 fh = font_get(FONT_UI)->height;
516 /* Adjust for font size, trying to center the information vertically */
517 if(fh < 10)
518 top_of_screen = 1;
520 if(num_presets <= 0)
522 radio_load_presets(global_settings.fmr_file);
525 if(radio_status == FMRADIO_OFF)
526 audio_stop();
527 #ifndef SIMULATOR
529 #if CONFIG_CODEC != SWCODEC
530 if(rec_create_directory() > 0)
531 have_recorded = true;
533 audio_init_recording(talk_get_bufsize());
535 sound_settings_apply();
536 /* Yes, we use the D/A for monitoring */
537 peak_meter_playback(true);
539 peak_meter_enabled = true;
541 rec_init_recording_options(&rec_options);
542 rec_options.rec_source = AUDIO_SRC_LINEIN;
543 rec_set_recording_options(&rec_options);
545 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
546 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
548 #endif /* CONFIG_CODEC != SWCODEC */
549 #endif /* ndef SIMULATOR */
551 /* turn on radio */
552 #if CONFIG_CODEC == SWCODEC
553 audio_set_input_source(AUDIO_SRC_FMRADIO,
554 (radio_status == FMRADIO_PAUSED) ?
555 SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
556 #else
557 if (radio_status == FMRADIO_OFF)
558 radio_start();
559 #endif
561 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
562 scan_presets(vp);
564 curr_preset = find_preset(curr_freq);
565 if(curr_preset != -1)
566 radio_mode = RADIO_PRESET_MODE;
568 #ifdef HAVE_BUTTONBAR
569 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
570 str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD));
571 #endif
573 #ifndef HAVE_NOISY_IDLE_MODE
574 cpu_idle_mode(true);
575 #endif
577 while(!done)
579 if(search_dir != 0)
581 curr_freq = step_freq(curr_freq, search_dir);
582 update_screen = true;
584 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
586 curr_preset = find_preset(curr_freq);
587 remember_frequency();
588 end_search();
589 talk = true;
592 trigger_cpu_boost();
595 if (!update_screen)
597 cancel_cpu_boost();
600 #if CONFIG_CODEC != SWCODEC
601 /* TODO: Can we timeout at HZ when recording since peaks aren't
602 displayed? This should quiet recordings too. */
603 button = get_action(CONTEXT_FM,
604 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
605 #else
606 button = get_action(CONTEXT_FM,
607 update_screen ? TIMEOUT_NOBLOCK : HZ);
608 #endif
610 #ifndef HAVE_NOISY_IDLE_MODE
611 if (button != ACTION_NONE)
613 cpu_idle_mode(false);
614 button_timeout = current_tick + (2*HZ);
616 #endif
617 switch(button)
619 case ACTION_FM_STOP:
620 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
621 if(audio_status() == AUDIO_STATUS_RECORD)
623 audio_stop();
625 else
626 #endif
628 done = true;
629 if(presets_changed)
631 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
633 if(filepreset[0] == '\0')
634 save_preset_list();
635 else
636 radio_save_presets();
639 /* Clear the preset list on exit. */
640 clear_preset_list();
642 update_screen = true;
643 break;
645 #ifdef FM_RECORD
646 case ACTION_FM_RECORD:
647 #ifdef FM_RECORD_DBLPRE
648 if (lastbutton != ACTION_FM_RECORD_DBLPRE)
650 rec_lastclick = 0;
651 break;
653 if (current_tick - rec_lastclick > HZ/2)
655 rec_lastclick = current_tick;
656 break;
658 #endif /* FM_RECORD_DBLPRE */
659 #ifndef SIMULATOR
660 if(audio_status() == AUDIO_STATUS_RECORD)
662 rec_command(RECORDING_CMD_START_NEWFILE);
663 update_screen = true;
665 else
667 have_recorded = true;
668 rec_command(RECORDING_CMD_START);
669 update_screen = true;
671 #endif /* SIMULATOR */
672 last_seconds = 0;
673 break;
674 #endif /* #ifdef FM_RECORD */
676 case ACTION_FM_EXIT:
677 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
678 if(audio_status() == AUDIO_STATUS_RECORD)
679 audio_stop();
680 #endif
681 keep_playing = true;
682 done = true;
683 ret_val = GO_TO_ROOT;
684 if(presets_changed)
686 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
688 if(filepreset[0] == '\0')
689 save_preset_list();
690 else
691 radio_save_presets();
695 /* Clear the preset list on exit. */
696 clear_preset_list();
698 break;
700 case ACTION_STD_PREV:
701 case ACTION_STD_NEXT:
702 next_station(button == ACTION_STD_PREV ? -1 : 1);
703 end_search();
704 update_screen = true;
705 talk = true;
706 break;
708 case ACTION_STD_PREVREPEAT:
709 case ACTION_STD_NEXTREPEAT:
711 int dir = search_dir;
712 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
713 if (radio_mode != RADIO_SCAN_MODE)
715 next_preset(search_dir);
716 end_search();
717 update_screen = true;
718 talk = true;
720 else if (dir == 0)
722 /* Starting auto scan */
723 tuner_set(RADIO_MUTE, 1);
724 update_screen = true;
726 break;
729 case ACTION_SETTINGS_INC:
730 case ACTION_SETTINGS_INCREPEAT:
731 global_settings.volume++;
732 setvol();
733 update_screen = true;
734 break;
736 case ACTION_SETTINGS_DEC:
737 case ACTION_SETTINGS_DECREPEAT:
738 global_settings.volume--;
739 setvol();
740 update_screen = true;
741 break;
743 case ACTION_FM_PLAY:
744 if (radio_status == FMRADIO_PLAYING)
745 radio_pause();
746 else
747 radio_start();
749 update_screen = true;
750 talk = false;
751 talk_shutup();
752 break;
754 case ACTION_FM_MENU:
755 viewportmanager_set_statusbar(oldbars);
756 radio_menu();
757 curr_preset = find_preset(curr_freq);
758 viewportmanager_set_statusbar(fmbars);
759 FOR_NB_SCREENS(i)
761 screens[i].set_viewport(&vp[i]);
762 screens[i].clear_viewport();
763 screens[i].update_viewport();
764 screens[i].set_viewport(NULL);
766 #ifdef HAVE_BUTTONBAR
767 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
768 str(LANG_PRESET),
769 str(LANG_FM_BUTTONBAR_RECORD));
770 #endif
771 update_screen = true;
772 break;
774 #ifdef FM_PRESET
775 case ACTION_FM_PRESET:
776 if(num_presets < 1)
778 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
779 update_screen = true;
780 FOR_NB_SCREENS(i)
782 screens[i].set_viewport(&vp[i]);
783 screens[i].clear_viewport();
784 screens[i].update_viewport();
785 screens[i].set_viewport(NULL);
788 break;
790 viewportmanager_set_statusbar(oldbars);
791 handle_radio_presets();
792 viewportmanager_set_statusbar(fmbars);
793 FOR_NB_SCREENS(i)
795 screens[i].set_viewport(&vp[i]);
796 screens[i].stop_scroll();
797 screens[i].clear_viewport();
798 screens[i].update_viewport();
799 screens[i].set_viewport(NULL);
801 #ifdef HAVE_BUTTONBAR
802 gui_buttonbar_set(&buttonbar,
803 str(LANG_BUTTONBAR_MENU),
804 str(LANG_PRESET),
805 str(LANG_FM_BUTTONBAR_RECORD));
806 #endif
807 update_screen = true;
808 break;
809 #endif /* FM_PRESET */
811 #ifdef FM_FREEZE
812 case ACTION_FM_FREEZE:
813 if(!screen_freeze)
815 splash(HZ, str(LANG_FM_FREEZE));
816 screen_freeze = true;
818 else
820 update_screen = true;
821 screen_freeze = false;
823 break;
824 #endif /* FM_FREEZE */
826 case SYS_USB_CONNECTED:
827 #if CONFIG_CODEC != SWCODEC
828 /* Only accept USB connection when not recording */
829 if(audio_status() != AUDIO_STATUS_RECORD)
830 #endif
832 default_event_handler(SYS_USB_CONNECTED);
833 screen_freeze = true; /* Cosmetic: makes sure the
834 radio screen doesn't redraw */
835 done = true;
837 break;
839 #ifdef FM_MODE
840 case ACTION_FM_MODE:
841 if(radio_mode == RADIO_SCAN_MODE)
843 /* Force scan mode if there are no presets. */
844 if(num_presets > 0)
845 radio_mode = RADIO_PRESET_MODE;
847 else
848 radio_mode = RADIO_SCAN_MODE;
849 update_screen = true;
850 cond_talk_ids_fq(radio_mode ?
851 LANG_PRESET : LANG_RADIO_SCAN_MODE);
852 talk = true;
853 break;
854 #endif /* FM_MODE */
856 #ifdef FM_NEXT_PRESET
857 case ACTION_FM_NEXT_PRESET:
858 next_preset(1);
859 end_search();
860 update_screen = true;
861 talk = true;
862 break;
863 #endif
865 #ifdef FM_PREV_PRESET
866 case ACTION_FM_PREV_PRESET:
867 next_preset(-1);
868 end_search();
869 update_screen = true;
870 talk = true;
871 break;
872 #endif
874 default:
875 default_event_handler(button);
876 break;
877 } /*switch(button)*/
879 #ifdef FM_RECORD_DBLPRE
880 if (button != ACTION_NONE)
881 lastbutton = button;
882 #endif
884 #if CONFIG_CODEC != SWCODEC
885 peak_meter_peek();
886 #endif
888 if(!screen_freeze)
890 /* Only display the peak meter when not recording */
891 #if CONFIG_CODEC != SWCODEC
892 if(!audio_status())
894 FOR_NB_SCREENS(i)
896 screens[i].set_viewport(&vp[i]);
897 peak_meter_screen(&screens[i],0,
898 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
899 fh);
900 screens[i].update_rect(0,
901 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
902 screens[i].getwidth(), fh);
903 screens[i].set_viewport(NULL);
907 if(TIME_AFTER(current_tick, timeout))
909 timeout = current_tick + HZ;
910 #else /* SWCODEC */
912 #endif /* CONFIG_CODEC == SWCODEC */
914 /* keep "mono" from always being displayed when paused */
915 if (radio_status != FMRADIO_PAUSED)
917 stereo = tuner_get(RADIO_STEREO) &&
918 !global_settings.fm_force_mono;
920 if(stereo != last_stereo)
922 update_screen = true;
923 last_stereo = stereo;
928 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
929 seconds = audio_recorded_time() / HZ;
930 if (update_screen || seconds > last_seconds)
932 last_seconds = seconds;
933 #else
934 if (update_screen)
936 #endif
937 int freq;
939 FOR_NB_SCREENS(i)
941 screens[i].set_viewport(&vp[i]);
944 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
945 curr_preset + 1, presets[curr_preset].name);
947 FOR_NB_SCREENS(i)
948 screens[i].puts_scroll(0, top_of_screen, buf);
950 freq = curr_freq / 10000;
951 snprintf(buf, 128, str(LANG_FM_STATION),
952 freq / 100, freq % 100);
953 FOR_NB_SCREENS(i)
954 screens[i].puts_scroll(0, top_of_screen + 1, buf);
956 snprintf(buf, 128, "%s", stereo?str(LANG_CHANNEL_STEREO):
957 str(LANG_CHANNEL_MONO));
958 FOR_NB_SCREENS(i)
959 screens[i].puts_scroll(0, top_of_screen + 2, buf);
961 snprintf(buf, 128, "%s %s", str(LANG_MODE),
962 radio_mode ? str(LANG_PRESET) :
963 str(LANG_RADIO_SCAN_MODE));
964 FOR_NB_SCREENS(i)
965 screens[i].puts_scroll(0, top_of_screen + 3, buf);
967 #if CONFIG_CODEC != SWCODEC
968 if(audio_status() == AUDIO_STATUS_RECORD)
970 hours = seconds / 3600;
971 minutes = (seconds - (hours * 3600)) / 60;
972 snprintf(buf, 32, "%s %02d:%02d:%02d",
973 str(LANG_RECORDING_TIME),
974 hours, minutes, seconds%60);
975 FOR_NB_SCREENS(i)
976 screens[i].puts_scroll(0, top_of_screen + 4, buf);
978 else
980 if(rec_options.rec_prerecord_time)
982 snprintf(buf, 32, "%s %02d",
983 str(LANG_RECORD_PRERECORD), seconds%60);
984 FOR_NB_SCREENS(i)
985 screens[i].puts_scroll(0, top_of_screen + 4, buf);
988 #endif /* CONFIG_CODEC != SWCODEC */
990 FOR_NB_SCREENS(i)
992 screens[i].update_viewport();
993 screens[i].set_viewport(NULL);
996 #ifdef HAVE_BUTTONBAR
997 gui_buttonbar_draw(&buttonbar);
998 #endif
1002 update_screen = false;
1004 if (global_settings.talk_file && talk
1005 && radio_status == FMRADIO_PAUSED)
1007 talk = false;
1008 bool enqueue = false;
1009 if (radio_mode == RADIO_SCAN_MODE)
1011 talk_freq(curr_freq, enqueue);
1012 enqueue = true;
1014 if (curr_preset >= 0)
1015 talk_preset(curr_preset, radio_mode == RADIO_PRESET_MODE,
1016 enqueue);
1019 #if CONFIG_CODEC != SWCODEC
1020 if(audio_status() & AUDIO_STATUS_ERROR)
1022 done = true;
1024 #endif
1026 #ifndef HAVE_NOISY_IDLE_MODE
1027 if (TIME_AFTER(current_tick, button_timeout))
1029 cpu_idle_mode(true);
1031 #endif
1032 } /*while(!done)*/
1034 #ifndef SIMULATOR
1035 #if CONFIG_CODEC != SWCODEC
1036 if(audio_status() & AUDIO_STATUS_ERROR)
1038 splash(0, str(LANG_DISK_FULL));
1039 FOR_NB_SCREENS(i)
1041 screens[i].set_viewport(&vp[i]);
1042 screens[i].update_viewport();
1043 screens[i].set_viewport(NULL);
1045 audio_error_clear();
1047 while(1)
1049 button = get_action(CONTEXT_FM, TIMEOUT_BLOCK);
1050 if(button == ACTION_FM_STOP)
1051 break;
1055 audio_init_playback();
1056 #endif /* CONFIG_CODEC != SWCODEC */
1058 sound_settings_apply();
1059 #endif /* SIMULATOR */
1061 if(keep_playing)
1063 /* Catch FMRADIO_PLAYING status for the sim. */
1064 #ifndef SIMULATOR
1065 #if CONFIG_CODEC != SWCODEC
1066 /* Enable the Left and right A/D Converter */
1067 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
1068 sound_default(SOUND_RIGHT_GAIN),
1069 AUDIO_GAIN_LINEIN);
1070 mas_codec_writereg(6, 0x4000);
1071 #endif
1072 end_search();
1073 #endif /* SIMULATOR */
1075 else
1077 #if CONFIG_CODEC == SWCODEC
1078 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1079 #else
1080 radio_stop();
1081 #endif
1084 #ifndef HAVE_NOISY_IDLE_MODE
1085 cpu_idle_mode(false);
1086 #endif
1088 viewportmanager_set_statusbar(oldbars);
1089 in_screen = false;
1090 #if CONFIG_CODEC != SWCODEC
1091 return have_recorded;
1092 #else
1093 return false;
1094 #endif
1095 } /* radio_screen */
1097 static void radio_save_presets(void)
1099 int fd;
1100 int i;
1102 fd = creat(filepreset);
1103 if(fd >= 0)
1105 for(i = 0;i < num_presets;i++)
1107 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
1109 close(fd);
1111 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1112 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1113 presets_changed = false;
1115 else
1117 splash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1121 void radio_load_presets(char *filename)
1123 int fd;
1124 int rc;
1125 char buf[128];
1126 char *freq;
1127 char *name;
1128 bool done = false;
1129 int f;
1131 memset(presets, 0, sizeof(presets));
1132 num_presets = 0;
1134 /* No Preset in configuration. */
1135 if(filename[0] == '\0')
1137 filepreset[0] = '\0';
1138 return;
1140 /* Temporary preset, loaded until player shuts down. */
1141 else if(filename[0] == '/')
1142 strncpy(filepreset, filename, sizeof(filepreset));
1143 /* Preset from default directory. */
1144 else
1145 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1146 FMPRESET_PATH, filename);
1148 fd = open_utf8(filepreset, O_RDONLY);
1149 if(fd >= 0)
1151 while(!done && num_presets < MAX_PRESETS)
1153 rc = read_line(fd, buf, 128);
1154 if(rc > 0)
1156 if(settings_parseline(buf, &freq, &name))
1158 f = atoi(freq);
1159 if(f) /* For backwards compatibility */
1161 struct fmstation * const fms = &presets[num_presets];
1162 fms->frequency = f;
1163 strncpy(fms->name, name, MAX_FMPRESET_LEN);
1164 fms->name[MAX_FMPRESET_LEN] = '\0';
1165 num_presets++;
1169 else
1170 done = true;
1172 close(fd);
1174 else /* invalid file name? */
1175 filepreset[0] = '\0';
1177 presets_loaded = num_presets > 0;
1178 presets_changed = false;
1182 static int radio_add_preset(void)
1184 char buf[MAX_FMPRESET_LEN + 1];
1186 if(num_presets < MAX_PRESETS)
1188 buf[0] = '\0';
1190 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1192 struct fmstation * const fms = &presets[num_presets];
1193 strcpy(fms->name, buf);
1194 fms->frequency = curr_freq;
1195 num_presets++;
1196 presets_changed = true;
1197 presets_loaded = num_presets > 0;
1198 return true;
1201 else
1203 splash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1205 return false;
1208 /* needed to know which preset we are edit/delete-ing */
1209 static int selected_preset = -1;
1210 static int radio_edit_preset(void)
1212 char buf[MAX_FMPRESET_LEN + 1];
1214 if (num_presets > 0)
1216 struct fmstation * const fms = &presets[selected_preset];
1218 strcpy(buf, fms->name);
1220 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1222 strcpy(fms->name, buf);
1223 presets_changed = true;
1227 return 1;
1230 static int radio_delete_preset(void)
1232 if (num_presets > 0)
1234 struct fmstation * const fms = &presets[selected_preset];
1236 if (selected_preset >= --num_presets)
1237 selected_preset = num_presets - 1;
1239 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1240 (uintptr_t)fms);
1242 if (curr_preset >= num_presets)
1243 --curr_preset;
1246 /* Don't ask to save when all presets are deleted. */
1247 presets_changed = num_presets > 0;
1249 if (!presets_changed)
1251 /* The preset list will be cleared, switch to Scan Mode. */
1252 radio_mode = RADIO_SCAN_MODE;
1253 curr_preset = -1;
1254 presets_loaded = false;
1257 return 1;
1260 static int load_preset_list(void)
1262 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1265 static int save_preset_list(void)
1267 if(num_presets > 0)
1269 bool bad_file_name = true;
1271 if(!dir_exists(FMPRESET_PATH)) /* Check if there is preset folder */
1272 mkdir(FMPRESET_PATH);
1274 create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
1275 ".fmr", 2 IF_CNFN_NUM_(, NULL));
1277 while(bad_file_name)
1279 if(!kbd_input(filepreset, sizeof(filepreset)))
1281 /* check the name: max MAX_FILENAME (20) chars */
1282 char* p2;
1283 char* p1;
1284 int len;
1285 p1 = strrchr(filepreset, '/');
1286 p2 = p1;
1287 while((p1) && (*p2) && (*p2 != '.'))
1288 p2++;
1289 len = (int)(p2-p1) - 1;
1290 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1292 /* no slash, too long or too short */
1293 splash(HZ, ID2P(LANG_INVALID_FILENAME));
1295 else
1297 /* add correct extension (easier to always write)
1298 at this point, p2 points to 0 or the extension dot */
1299 *p2 = '\0';
1300 strcat(filepreset,".fmr");
1301 bad_file_name = false;
1302 radio_save_presets();
1305 else
1307 /* user aborted */
1308 return false;
1312 else
1313 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
1315 return true;
1318 static int clear_preset_list(void)
1320 /* Clear all the preset entries */
1321 memset(presets, 0, sizeof (presets));
1323 num_presets = 0;
1324 presets_loaded = false;
1325 /* The preset list will be cleared switch to Scan Mode. */
1326 radio_mode = RADIO_SCAN_MODE;
1327 curr_preset = -1;
1329 presets_changed = false; /* Don't ask to save when clearing the list. */
1331 return true;
1334 MENUITEM_FUNCTION(radio_edit_preset_item, MENU_FUNC_CHECK_RETVAL,
1335 ID2P(LANG_FM_EDIT_PRESET),
1336 radio_edit_preset, NULL, NULL, Icon_NOICON);
1337 MENUITEM_FUNCTION(radio_delete_preset_item, MENU_FUNC_CHECK_RETVAL,
1338 ID2P(LANG_FM_DELETE_PRESET),
1339 radio_delete_preset, NULL, NULL, Icon_NOICON);
1340 static int radio_preset_callback(int action,
1341 const struct menu_item_ex *this_item)
1343 if (action == ACTION_STD_OK)
1344 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1345 return action;
1346 (void)this_item;
1348 MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_PRESET),
1349 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
1350 &radio_delete_preset_item);
1351 /* present a list of preset stations */
1352 static char * presets_get_name(int selected_item, void *data,
1353 char *buffer, size_t buffer_len)
1355 (void)data;
1356 struct fmstation *p = &presets[selected_item];
1357 if(p->name[0])
1358 return p->name;
1359 int freq = p->frequency / 10000;
1360 int frac = freq % 100;
1361 freq /= 100;
1362 snprintf(buffer, buffer_len,
1363 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1364 return buffer;
1367 static int presets_speak_name(int selected_item, void * data)
1369 (void)data;
1370 talk_preset(selected_item, true, false);
1371 return 0;
1374 static int handle_radio_presets(void)
1376 struct gui_synclist lists;
1377 int result = 0;
1378 int action = ACTION_NONE;
1379 #ifdef HAVE_BUTTONBAR
1380 struct gui_buttonbar buttonbar;
1381 #endif
1383 if(presets_loaded == false)
1384 return result;
1386 #ifdef HAVE_BUTTONBAR
1387 gui_buttonbar_init(&buttonbar);
1388 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
1389 gui_buttonbar_set(&buttonbar, str(LANG_FM_BUTTONBAR_ADD),
1390 str(LANG_FM_BUTTONBAR_EXIT),
1391 str(LANG_FM_BUTTONBAR_ACTION));
1392 gui_buttonbar_draw(&buttonbar);
1393 #endif
1394 gui_synclist_init(&lists, presets_get_name, NULL, false, 1, NULL);
1395 gui_synclist_set_title(&lists, str(LANG_PRESET), NOICON);
1396 gui_synclist_set_icon_callback(&lists, NULL);
1397 if(global_settings.talk_file)
1398 gui_synclist_set_voice_callback(&lists, presets_speak_name);
1399 gui_synclist_set_nb_items(&lists, num_presets);
1400 gui_synclist_select_item(&lists, curr_preset<0 ? 0 : curr_preset);
1401 gui_synclist_speak_item(&lists);
1403 while (result == 0)
1405 gui_synclist_draw(&lists);
1406 list_do_action(CONTEXT_STD, TIMEOUT_BLOCK,
1407 &lists, &action, LIST_WRAP_UNLESS_HELD);
1408 switch (action)
1410 case ACTION_STD_MENU:
1411 if (radio_add_preset())
1413 gui_synclist_set_nb_items(&lists, num_presets);
1414 gui_synclist_select_item(&lists, num_presets - 1);
1416 break;
1417 case ACTION_STD_CANCEL:
1418 result = 1;
1419 break;
1420 case ACTION_STD_OK:
1421 curr_preset = gui_synclist_get_sel_pos(&lists);
1422 curr_freq = presets[curr_preset].frequency;
1423 next_station(0);
1424 remember_frequency();
1425 result = 1;
1426 break;
1427 case ACTION_F3:
1428 case ACTION_STD_CONTEXT:
1429 selected_preset = gui_synclist_get_sel_pos(&lists);
1430 do_menu(&handle_radio_preset_menu, NULL, NULL, false);
1431 gui_synclist_set_nb_items(&lists, num_presets);
1432 gui_synclist_select_item(&lists, selected_preset);
1433 gui_synclist_speak_item(&lists);
1434 break;
1435 default:
1436 if(default_event_handler(action) == SYS_USB_CONNECTED)
1437 result = 2;
1440 return result - 1;
1443 void toggle_mono_mode(bool mono)
1445 tuner_set(RADIO_FORCE_MONO, mono);
1448 void set_radio_region(int region)
1450 #ifdef HAVE_RADIO_REGION
1451 tuner_set(RADIO_REGION, region);
1452 #endif
1453 next_station(0);
1454 remember_frequency();
1455 (void)region;
1458 MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL);
1459 MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL);
1461 #ifndef FM_MODE
1462 static char* get_mode_text(int selected_item, void * data, char *buffer)
1464 (void)selected_item;
1465 (void)data;
1466 snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE),
1467 radio_mode ? str(LANG_PRESET) :
1468 str(LANG_RADIO_SCAN_MODE));
1469 return buffer;
1471 static int toggle_radio_mode(void)
1473 radio_mode = (radio_mode == RADIO_SCAN_MODE) ?
1474 RADIO_PRESET_MODE : RADIO_SCAN_MODE;
1475 return 0;
1477 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0,
1478 toggle_radio_mode, NULL,
1479 get_mode_text, NULL, NULL, NULL, Icon_NOICON);
1480 #endif
1482 static int scan_presets(void *viewports)
1484 bool do_scan = true;
1485 int i;
1486 struct viewport *vp = (struct viewport *)viewports;
1488 FOR_NB_SCREENS(i)
1489 screens[i].set_viewport(vp?&vp[i]:NULL);
1490 if(num_presets > 0) /* Do that to avoid 2 questions. */
1491 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1493 if(do_scan)
1495 const struct fm_region_data * const fmr =
1496 &fm_region_data[global_settings.fm_region];
1498 curr_freq = fmr->freq_min;
1499 num_presets = 0;
1500 memset(presets, 0, sizeof(presets));
1501 tuner_set(RADIO_MUTE, 1);
1503 while(curr_freq <= fmr->freq_max)
1505 int freq, frac;
1506 if(num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1507 break;
1509 freq = curr_freq / 10000;
1510 frac = freq % 100;
1511 freq /= 100;
1513 splashf(0, str(LANG_FM_SCANNING), freq, frac);
1515 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
1517 /* add preset */
1518 presets[num_presets].name[0] = '\0';
1519 presets[num_presets].frequency = curr_freq;
1520 num_presets++;
1523 curr_freq += fmr->freq_step;
1526 if (radio_status == FMRADIO_PLAYING)
1527 tuner_set(RADIO_MUTE, 0);
1529 presets_changed = true;
1531 FOR_NB_SCREENS(i)
1533 screens[i].clear_viewport();
1534 screens[i].update_viewport();
1537 if(num_presets > 0)
1539 curr_freq = presets[0].frequency;
1540 radio_mode = RADIO_PRESET_MODE;
1541 presets_loaded = true;
1542 next_station(0);
1544 else
1546 /* Wrap it to beginning or we'll be past end of band */
1547 presets_loaded = false;
1548 next_station(1);
1551 return true;
1555 #ifdef HAVE_RECORDING
1557 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1558 #define FM_RECORDING_SCREEN
1559 static int fm_recording_screen(void)
1561 bool ret;
1563 /* switch recording source to FMRADIO for the duration */
1564 int rec_source = global_settings.rec_source;
1565 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1567 ret = recording_screen(true);
1569 /* safe to reset as changing sources is prohibited here */
1570 global_settings.rec_source = rec_source;
1572 return ret;
1575 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1577 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1578 #define FM_RECORDING_SETTINGS
1579 static int fm_recording_settings(void)
1581 bool ret = recording_menu(true);
1583 #if CONFIG_CODEC != SWCODEC
1584 if (!ret)
1586 struct audio_recording_options rec_options;
1587 rec_init_recording_options(&rec_options);
1588 rec_options.rec_source = AUDIO_SRC_LINEIN;
1589 rec_set_recording_options(&rec_options);
1591 #endif
1593 return ret;
1596 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1597 #endif /* HAVE_RECORDING */
1599 #ifdef FM_RECORDING_SCREEN
1600 MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING),
1601 fm_recording_screen, NULL, NULL, Icon_Recording);
1602 #endif
1603 #ifdef FM_RECORDING_SETTINGS
1604 MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS),
1605 fm_recording_settings, NULL, NULL, Icon_Recording);
1606 #endif
1607 #ifndef FM_PRESET
1608 MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET),
1609 handle_radio_presets, NULL, NULL, Icon_NOICON);
1610 #endif
1611 #ifndef FM_PRESET_ADD
1612 MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET),
1613 radio_add_preset, NULL, NULL, Icon_NOICON);
1614 #endif
1617 MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD),
1618 load_preset_list, NULL, NULL, Icon_NOICON);
1619 MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE),
1620 save_preset_list, NULL, NULL, Icon_NOICON);
1621 MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR),
1622 clear_preset_list, NULL, NULL, Icon_NOICON);
1623 MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM,
1624 ID2P(LANG_FM_SCAN_PRESETS),
1625 scan_presets, NULL, NULL, Icon_NOICON);
1627 MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1628 Icon_Radio_screen,
1629 #ifndef FM_PRESET
1630 &radio_presets_item,
1631 #endif
1632 #ifndef FM_PRESET_ADD
1633 &radio_addpreset_item,
1634 #endif
1635 &presetload_item, &presetsave_item, &presetclear_item,
1636 &force_mono,
1637 #ifndef FM_MODE
1638 &radio_mode_item,
1639 #endif
1640 &set_region, &sound_settings,
1641 #ifdef FM_RECORDING_SCREEN
1642 &recscreen_item,
1643 #endif
1644 #ifdef FM_RECORDING_SETTINGS
1645 &recsettings_item,
1646 #endif
1647 &scan_presets_item);
1648 /* main menu of the radio screen */
1649 static bool radio_menu(void)
1651 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1652 MENU_ATTACHED_USB;
1655 #endif