Factor out some drawing code.
[kugel-rb.git] / apps / recorder / radio.c
blob9e891389bdf7701fa974d7c162acdeecc5d4c72a
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 "audio.h"
33 #include "mp3_playback.h"
34 #include "ctype.h"
35 #include "file.h"
36 #include "general.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 #ifdef IPOD_ACCESSORY_PROTOCOL
53 #include "iap.h"
54 #endif
55 #include "talk.h"
56 #include "tuner.h"
57 #include "power.h"
58 #include "sound.h"
59 #include "screen_access.h"
60 #include "splash.h"
61 #include "yesno.h"
62 #include "buttonbar.h"
63 #include "tree.h"
64 #include "dir.h"
65 #include "action.h"
66 #include "list.h"
67 #include "menus/exported_menus.h"
68 #include "root_menu.h"
69 #include "viewport.h"
70 #ifdef HAVE_QUICKSCREEN
71 #include "quickscreen.h"
72 #endif
74 #if CONFIG_TUNER
76 #if CONFIG_KEYPAD == RECORDER_PAD
77 #define FM_RECORD
78 #define FM_PRESET_ADD
79 #define FM_PRESET_ACTION
80 #define FM_PRESET
81 #define FM_MODE
83 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
84 #define FM_PRESET
85 #define FM_MODE
86 #define FM_NEXT_PRESET
87 #define FM_PREV_PRESET
89 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
90 #define FM_PRESET
91 #define FM_MODE
93 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
94 #define FM_PRESET
95 #define FM_MODE
96 /* This should be removeable if the whole tuning thing is sorted out since
97 proper tuning quiets the screen almost entirely in that extreme measures
98 have to be taken to hear any interference. */
99 #define HAVE_NOISY_IDLE_MODE
101 #elif CONFIG_KEYPAD == ONDIO_PAD
102 #define FM_RECORD_DBLPRE
103 #define FM_RECORD
104 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD) \
105 || (CONFIG_KEYPAD == SANSA_FUZE_PAD)
106 #define FM_PRESET
107 #define FM_MODE
109 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
110 #define FM_PRESET
111 #define FM_MODE
113 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
114 #define FM_PRESET
116 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
117 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
118 #define FM_MODE
120 #endif
122 #define RADIO_SCAN_MODE 0
123 #define RADIO_PRESET_MODE 1
125 static int curr_preset = -1;
126 static int curr_freq; /* current frequency in Hz */
127 static int radio_mode = RADIO_SCAN_MODE;
128 static int search_dir = 0;
130 static int radio_status = FMRADIO_OFF;
131 static bool in_screen = false;
133 #define MAX_PRESETS 64
134 static bool presets_loaded = false, presets_changed = false;
135 static struct fmstation presets[MAX_PRESETS];
137 static char filepreset[MAX_PATH]; /* preset filename variable */
139 static int num_presets = 0; /* The number of presets in the preset list */
141 static void radio_save_presets(void);
142 static int handle_radio_presets(void);
143 static bool radio_menu(void);
144 static int radio_add_preset(void);
145 static int save_preset_list(void);
146 static int load_preset_list(void);
147 static int clear_preset_list(void);
149 static int scan_presets(void *viewports);
151 /* Function to manipulate all yesno dialogues.
152 This function needs the output text as an argument. */
153 static bool yesno_pop(const char* text)
155 int i;
156 const char *lines[]={text};
157 const struct text_message message={lines, 1};
158 bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES);
159 FOR_NB_SCREENS(i)
160 screens[i].clear_viewport();
161 return ret;
164 void radio_init(void)
166 tuner_init();
167 radio_stop();
170 int get_radio_status(void)
172 return radio_status;
175 bool in_radio_screen(void)
177 return in_screen;
180 /* TODO: Move some more of the control functionality to firmware
181 and clean up the mess */
183 /* secret flag for starting paused - prevents unmute */
184 #define FMRADIO_START_PAUSED 0x8000
185 void radio_start(void)
187 const struct fm_region_data *fmr;
188 bool start_paused;
190 if(radio_status == FMRADIO_PLAYING)
191 return;
193 fmr = &fm_region_data[global_settings.fm_region];
195 start_paused = radio_status & FMRADIO_START_PAUSED;
196 /* clear flag before any yielding */
197 radio_status &= ~FMRADIO_START_PAUSED;
199 if(radio_status == FMRADIO_OFF)
200 tuner_power(true);
202 curr_freq = global_status.last_frequency * fmr->freq_step + fmr->freq_min;
204 tuner_set(RADIO_SLEEP, 0); /* wake up the tuner */
206 if(radio_status == FMRADIO_OFF)
208 #ifdef HAVE_RADIO_REGION
209 tuner_set(RADIO_REGION, global_settings.fm_region);
210 #endif
211 tuner_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
214 tuner_set(RADIO_FREQUENCY, curr_freq);
216 #ifdef HAVE_RADIO_MUTE_TIMEOUT
218 unsigned long mute_timeout = current_tick + HZ;
219 if (radio_status != FMRADIO_OFF)
221 /* paused */
222 mute_timeout += HZ;
225 while(!tuner_get(RADIO_STEREO) && !tuner_get(RADIO_TUNED))
227 if(TIME_AFTER(current_tick, mute_timeout))
228 break;
229 yield();
232 #endif
234 /* keep radio from sounding initially */
235 if(!start_paused)
236 tuner_set(RADIO_MUTE, 0);
238 radio_status = FMRADIO_PLAYING;
239 } /* radio_start */
241 void radio_pause(void)
243 if(radio_status == FMRADIO_PAUSED)
244 return;
246 if(radio_status == FMRADIO_OFF)
248 radio_status |= FMRADIO_START_PAUSED;
249 radio_start();
252 tuner_set(RADIO_MUTE, 1);
253 tuner_set(RADIO_SLEEP, 1);
255 radio_status = FMRADIO_PAUSED;
256 } /* radio_pause */
258 void radio_stop(void)
260 if(radio_status == FMRADIO_OFF)
261 return;
263 tuner_set(RADIO_MUTE, 1);
264 tuner_set(RADIO_SLEEP, 1); /* low power mode, if available */
265 radio_status = FMRADIO_OFF;
266 tuner_power(false); /* status update, power off if avail. */
267 } /* radio_stop */
269 bool radio_hardware_present(void)
271 return tuner_get(RADIO_PRESENT);
274 /* Keep freq on the grid for the current region */
275 static int snap_freq_to_grid(int freq)
277 const struct fm_region_data * const fmr =
278 &fm_region_data[global_settings.fm_region];
280 /* Range clamp if out of range or just round to nearest */
281 if (freq < fmr->freq_min)
282 freq = fmr->freq_min;
283 else if (freq > fmr->freq_max)
284 freq = fmr->freq_max;
285 else
286 freq = (freq - fmr->freq_min + fmr->freq_step/2) /
287 fmr->freq_step * fmr->freq_step + fmr->freq_min;
289 return freq;
292 /* Find a matching preset to freq */
293 static int find_preset(int freq)
295 int i;
296 if(num_presets < 1)
297 return -1;
298 for(i = 0;i < MAX_PRESETS;i++)
300 if(freq == presets[i].frequency)
301 return i;
304 return -1;
307 /* Return the closest preset encountered in the search direction with
308 wraparound. */
309 static int find_closest_preset(int freq, int direction)
311 int i;
312 int lowpreset = 0;
313 int highpreset = 0;
314 int closest = -1;
316 if (direction == 0) /* direction == 0 isn't really used */
317 return 0;
319 for (i = 0; i < num_presets; i++)
321 int f = presets[i].frequency;
322 if (f == freq)
323 return i; /* Exact match = stop */
325 /* remember the highest and lowest presets for wraparound */
326 if (f < presets[lowpreset].frequency)
327 lowpreset = i;
328 if (f > presets[highpreset].frequency)
329 highpreset = i;
331 /* find the closest preset in the given direction */
332 if (direction > 0 && f > freq)
334 if (closest < 0 || f < presets[closest].frequency)
335 closest = i;
337 else if (direction < 0 && f < freq)
339 if (closest < 0 || f > presets[closest].frequency)
340 closest = i;
344 if (closest < 0)
346 /* no presets in the given direction */
347 /* wrap around depending on direction */
348 if (direction < 0)
349 closest = highpreset;
350 else
351 closest = lowpreset;
354 return closest;
357 static void remember_frequency(void)
359 const struct fm_region_data * const fmr =
360 &fm_region_data[global_settings.fm_region];
361 global_status.last_frequency = (curr_freq - fmr->freq_min)
362 / fmr->freq_step;
363 status_save();
366 static void next_preset(int direction)
368 if (num_presets < 1)
369 return;
371 if (curr_preset == -1)
372 curr_preset = find_closest_preset(curr_freq, direction);
373 else
374 curr_preset = (curr_preset + direction + num_presets) % num_presets;
376 /* Must stay on the current grid for the region */
377 curr_freq = snap_freq_to_grid(presets[curr_preset].frequency);
379 tuner_set(RADIO_FREQUENCY, curr_freq);
380 remember_frequency();
383 /* Step to the next or previous frequency */
384 static int step_freq(int freq, int direction)
386 const struct fm_region_data * const fmr =
387 &fm_region_data[global_settings.fm_region];
389 freq += direction*fmr->freq_step;
391 /* Wrap first or snapping to grid will not let us on the band extremes */
392 if (freq > fmr->freq_max)
393 freq = direction > 0 ? fmr->freq_min : fmr->freq_max;
394 else if (freq < fmr->freq_min)
395 freq = direction < 0 ? fmr->freq_max : fmr->freq_min;
396 else
397 freq = snap_freq_to_grid(freq);
399 return freq;
402 /* Step to the next or previous station */
403 static void next_station(int direction)
405 if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
407 next_preset(direction);
408 return;
411 curr_freq = step_freq(curr_freq, direction);
413 if (radio_status == FMRADIO_PLAYING)
414 tuner_set(RADIO_MUTE, 1);
416 tuner_set(RADIO_FREQUENCY, curr_freq);
418 if (radio_status == FMRADIO_PLAYING)
419 tuner_set(RADIO_MUTE, 0);
421 curr_preset = find_preset(curr_freq);
422 remember_frequency();
425 /* Ends an in-progress search */
426 static void end_search(void)
428 if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
429 tuner_set(RADIO_MUTE, 0);
430 search_dir = 0;
433 /* Speak a frequency. */
434 static void talk_freq(int freq, bool enqueue)
436 freq /= 10000;
437 talk_number(freq / 100, enqueue);
438 talk_id(LANG_POINT, true);
439 talk_number(freq % 100 / 10, true);
440 if (freq % 10)
441 talk_number(freq % 10, true);
444 /* Speak a preset by number or by spelling its name, depending on settings. */
445 static void talk_preset(int preset, bool fallback, bool enqueue)
447 if (global_settings.talk_file == 1) /* number */
448 talk_number(preset + 1, enqueue);
449 else
450 { /* spell */
451 if(presets[preset].name[0])
452 talk_spell(presets[preset].name, enqueue);
453 else if(fallback)
454 talk_freq(presets[preset].frequency, enqueue);
458 static void fms_restore(struct viewport vp[NB_SCREENS])
460 struct screen *display;
461 int i;
462 FOR_NB_SCREENS(i)
464 display = &screens[i];
465 display->set_viewport(&vp[i]);
466 display->clear_viewport();
467 display->update_viewport();
471 int radio_screen(void)
473 char buf[MAX_PATH];
474 bool done = false;
475 int ret_val = GO_TO_ROOT;
476 int button;
477 int i;
478 bool stereo = false, last_stereo = false;
479 int fh;
480 int top_of_screen = 0;
481 bool update_screen = true;
482 bool screen_freeze = false;
483 bool keep_playing = false;
484 bool talk = false;
485 #ifdef FM_RECORD_DBLPRE
486 int lastbutton = BUTTON_NONE;
487 unsigned long rec_lastclick = 0;
488 #endif
489 #if CONFIG_CODEC != SWCODEC
490 bool have_recorded = false;
491 int timeout = current_tick + HZ/10;
492 unsigned int seconds = 0;
493 unsigned int last_seconds = 0;
494 int hours, minutes;
495 struct audio_recording_options rec_options;
496 #endif /* CONFIG_CODEC != SWCODEC */
497 #ifndef HAVE_NOISY_IDLE_MODE
498 int button_timeout = current_tick + (2*HZ);
499 #endif
500 struct viewport vp[NB_SCREENS];
501 #ifdef HAVE_BUTTONBAR
502 struct gui_buttonbar buttonbar;
503 gui_buttonbar_init(&buttonbar);
504 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
505 #endif
507 /* change status to "in screen" */
508 in_screen = true;
510 /* always display status bar in radio screen for now */
511 FOR_NB_SCREENS(i)
513 viewport_set_defaults(&vp[i], i);
514 #ifdef HAVE_BUTTONBAR
515 if (global_settings.buttonbar)
516 vp[i].height -= BUTTONBAR_HEIGHT;
517 #endif
519 fms_restore(vp);
521 fh = font_get(FONT_UI)->height;
523 /* Adjust for font size, trying to center the information vertically */
524 if(fh < 10)
525 top_of_screen = 1;
527 if(num_presets <= 0)
529 radio_load_presets(global_settings.fmr_file);
532 if(radio_status == FMRADIO_OFF)
533 audio_stop();
534 #ifndef SIMULATOR
536 #if CONFIG_CODEC != SWCODEC
537 if(rec_create_directory() > 0)
538 have_recorded = true;
540 audio_init_recording(talk_get_bufsize());
542 sound_settings_apply();
543 /* Yes, we use the D/A for monitoring */
544 peak_meter_playback(true);
546 peak_meter_enabled = true;
548 rec_init_recording_options(&rec_options);
549 rec_options.rec_source = AUDIO_SRC_LINEIN;
550 rec_set_recording_options(&rec_options);
552 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
553 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
555 #endif /* CONFIG_CODEC != SWCODEC */
556 #endif /* ndef SIMULATOR */
558 /* turn on radio */
559 #if CONFIG_CODEC == SWCODEC
560 audio_set_input_source(AUDIO_SRC_FMRADIO,
561 (radio_status == FMRADIO_PAUSED) ?
562 SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
563 #else
564 if (radio_status == FMRADIO_OFF)
565 radio_start();
566 #endif
568 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
569 scan_presets(vp);
571 curr_preset = find_preset(curr_freq);
572 if(curr_preset != -1)
573 radio_mode = RADIO_PRESET_MODE;
575 #ifdef HAVE_BUTTONBAR
576 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
577 str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD));
578 #endif
580 #ifndef HAVE_NOISY_IDLE_MODE
581 cpu_idle_mode(true);
582 #endif
584 while(!done)
586 if(search_dir != 0)
588 curr_freq = step_freq(curr_freq, search_dir);
589 update_screen = true;
591 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
593 curr_preset = find_preset(curr_freq);
594 remember_frequency();
595 end_search();
596 talk = true;
598 trigger_cpu_boost();
601 if (!update_screen)
603 cancel_cpu_boost();
606 #if CONFIG_CODEC != SWCODEC
607 /* TODO: Can we timeout at HZ when recording since peaks aren't
608 displayed? This should quiet recordings too. */
609 button = get_action(CONTEXT_FM,
610 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
611 #else
612 button = get_action(CONTEXT_FM,
613 update_screen ? TIMEOUT_NOBLOCK : HZ);
614 #endif
616 #ifndef HAVE_NOISY_IDLE_MODE
617 if (button != ACTION_NONE)
619 cpu_idle_mode(false);
620 button_timeout = current_tick + (2*HZ);
622 #endif
623 switch(button)
625 case ACTION_FM_STOP:
626 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
627 if(audio_status() == AUDIO_STATUS_RECORD)
629 audio_stop();
631 else
632 #endif
634 done = true;
635 if(presets_changed)
637 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
639 if(filepreset[0] == '\0')
640 save_preset_list();
641 else
642 radio_save_presets();
645 /* Clear the preset list on exit. */
646 clear_preset_list();
648 update_screen = true;
649 break;
651 #ifdef FM_RECORD
652 case ACTION_FM_RECORD:
653 #ifdef FM_RECORD_DBLPRE
654 if (lastbutton != ACTION_FM_RECORD_DBLPRE)
656 rec_lastclick = 0;
657 break;
659 if (current_tick - rec_lastclick > HZ/2)
661 rec_lastclick = current_tick;
662 break;
664 #endif /* FM_RECORD_DBLPRE */
665 #ifndef SIMULATOR
666 if(audio_status() == AUDIO_STATUS_RECORD)
668 rec_command(RECORDING_CMD_START_NEWFILE);
669 update_screen = true;
671 else
673 have_recorded = true;
674 rec_command(RECORDING_CMD_START);
675 update_screen = true;
677 #endif /* SIMULATOR */
678 last_seconds = 0;
679 break;
680 #endif /* #ifdef FM_RECORD */
682 case ACTION_FM_EXIT:
683 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
684 if(audio_status() == AUDIO_STATUS_RECORD)
685 audio_stop();
686 #endif
687 keep_playing = true;
688 done = true;
689 ret_val = GO_TO_ROOT;
690 if(presets_changed)
692 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
694 if(filepreset[0] == '\0')
695 save_preset_list();
696 else
697 radio_save_presets();
701 /* Clear the preset list on exit. */
702 clear_preset_list();
704 break;
706 case ACTION_STD_PREV:
707 case ACTION_STD_NEXT:
708 next_station(button == ACTION_STD_PREV ? -1 : 1);
709 end_search();
710 update_screen = true;
711 talk = true;
712 break;
714 case ACTION_STD_PREVREPEAT:
715 case ACTION_STD_NEXTREPEAT:
717 int dir = search_dir;
718 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
719 if (radio_mode != RADIO_SCAN_MODE)
721 next_preset(search_dir);
722 end_search();
723 update_screen = true;
724 talk = true;
726 else if (dir == 0)
728 /* Starting auto scan */
729 tuner_set(RADIO_MUTE, 1);
730 update_screen = true;
732 break;
735 case ACTION_SETTINGS_INC:
736 case ACTION_SETTINGS_INCREPEAT:
737 global_settings.volume++;
738 setvol();
739 update_screen = true;
740 break;
742 case ACTION_SETTINGS_DEC:
743 case ACTION_SETTINGS_DECREPEAT:
744 global_settings.volume--;
745 setvol();
746 update_screen = true;
747 break;
749 case ACTION_FM_PLAY:
750 if (radio_status == FMRADIO_PLAYING)
751 radio_pause();
752 else
753 radio_start();
755 update_screen = true;
756 talk = false;
757 talk_shutup();
758 break;
760 case ACTION_FM_MENU:
761 FOR_NB_SCREENS(i)
763 screens[i].scroll_stop(&vp[i]);
765 radio_menu();
766 curr_preset = find_preset(curr_freq);
767 fms_restore(vp);
768 #ifdef HAVE_BUTTONBAR
769 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
770 str(LANG_PRESET),
771 str(LANG_FM_BUTTONBAR_RECORD));
772 #endif
773 update_screen = true;
774 break;
776 #ifdef FM_PRESET
777 case ACTION_FM_PRESET:
778 if(num_presets < 1)
780 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
781 update_screen = true;
782 fms_restore(vp);
784 break;
786 FOR_NB_SCREENS(i)
787 screens[i].scroll_stop(&vp[i]);
788 handle_radio_presets();
789 fms_restore(vp);
790 #ifdef HAVE_BUTTONBAR
791 gui_buttonbar_set(&buttonbar,
792 str(LANG_BUTTONBAR_MENU),
793 str(LANG_PRESET),
794 str(LANG_FM_BUTTONBAR_RECORD));
795 #endif
796 update_screen = true;
797 break;
798 #endif /* FM_PRESET */
800 #ifdef HAVE_QUICKSCREEN
801 case ACTION_FM_QUICKSCREEN:
803 if (quick_screen_quick(button))
805 done = true;
806 break;
808 fms_restore(vp);
809 update_screen = true;
811 break;
812 #endif
813 #ifdef FM_FREEZE
814 case ACTION_FM_FREEZE:
815 if(!screen_freeze)
817 splash(HZ, str(LANG_FM_FREEZE));
818 screen_freeze = true;
820 else
822 update_screen = true;
823 screen_freeze = false;
825 break;
826 #endif /* FM_FREEZE */
828 case SYS_USB_CONNECTED:
829 #if CONFIG_CODEC != SWCODEC
830 /* Only accept USB connection when not recording */
831 if(audio_status() != AUDIO_STATUS_RECORD)
832 #endif
834 default_event_handler(SYS_USB_CONNECTED);
835 screen_freeze = true; /* Cosmetic: makes sure the
836 radio screen doesn't redraw */
837 done = true;
839 break;
841 #ifdef FM_MODE
842 case ACTION_FM_MODE:
843 if(radio_mode == RADIO_SCAN_MODE)
845 /* Force scan mode if there are no presets. */
846 if(num_presets > 0)
847 radio_mode = RADIO_PRESET_MODE;
849 else
850 radio_mode = RADIO_SCAN_MODE;
851 update_screen = true;
852 cond_talk_ids_fq(radio_mode ?
853 LANG_PRESET : LANG_RADIO_SCAN_MODE);
854 talk = true;
855 break;
856 #endif /* FM_MODE */
858 #ifdef FM_NEXT_PRESET
859 case ACTION_FM_NEXT_PRESET:
860 next_preset(1);
861 end_search();
862 update_screen = true;
863 talk = true;
864 break;
865 #endif
867 #ifdef FM_PREV_PRESET
868 case ACTION_FM_PREV_PRESET:
869 next_preset(-1);
870 end_search();
871 update_screen = true;
872 talk = true;
873 break;
874 #endif
876 default:
877 default_event_handler(button);
878 #ifdef HAVE_RDS_CAP
879 if (tuner_get(RADIO_EVENT))
880 update_screen = true;
881 #endif
882 if (!tuner_get(RADIO_PRESENT))
884 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
885 if(audio_status() == AUDIO_STATUS_RECORD)
886 audio_stop();
887 #endif
888 keep_playing = false;
889 done = true;
890 ret_val = GO_TO_ROOT;
891 if(presets_changed)
893 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
895 if(filepreset[0] == '\0')
896 save_preset_list();
897 else
898 radio_save_presets();
902 /* Clear the preset list on exit. */
903 clear_preset_list();
905 break;
906 } /*switch(button)*/
908 #ifdef FM_RECORD_DBLPRE
909 if (button != ACTION_NONE)
910 lastbutton = button;
911 #endif
913 #if CONFIG_CODEC != SWCODEC
914 peak_meter_peek();
915 #endif
917 if(!screen_freeze)
919 /* Only display the peak meter when not recording */
920 #if CONFIG_CODEC != SWCODEC
921 if(!audio_status())
923 FOR_NB_SCREENS(i)
925 screens[i].set_viewport(&vp[i]);
926 peak_meter_screen(&screens[i],0, fh*(top_of_screen + 4),fh);
927 screens[i].update_rect(0, fh*(top_of_screen + 4),
928 screens[i].getwidth(), fh);
932 if(TIME_AFTER(current_tick, timeout))
934 timeout = current_tick + HZ;
935 #else /* SWCODEC */
937 #endif /* CONFIG_CODEC == SWCODEC */
939 /* keep "mono" from always being displayed when paused */
940 if (radio_status != FMRADIO_PAUSED)
942 stereo = tuner_get(RADIO_STEREO) &&
943 !global_settings.fm_force_mono;
945 if(stereo != last_stereo)
947 update_screen = true;
948 last_stereo = stereo;
953 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
954 seconds = audio_recorded_time() / HZ;
955 if (update_screen || seconds > last_seconds)
957 last_seconds = seconds;
958 #else
959 if (update_screen)
961 #endif
962 int freq;
964 FOR_NB_SCREENS(i)
966 screens[i].set_viewport(&vp[i]);
969 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
970 curr_preset + 1, presets[curr_preset].name);
972 FOR_NB_SCREENS(i)
973 screens[i].puts_scroll(0, top_of_screen, buf);
975 freq = curr_freq / 10000;
976 snprintf(buf, 128, str(LANG_FM_STATION),
977 freq / 100, freq % 100);
978 FOR_NB_SCREENS(i)
979 screens[i].puts_scroll(0, top_of_screen + 1, buf);
981 FOR_NB_SCREENS(i)
982 screens[i].puts_scroll(0, top_of_screen + 2,
983 stereo ? str(LANG_CHANNEL_STEREO) :
984 str(LANG_CHANNEL_MONO));
986 snprintf(buf, 128, "%s %s", str(LANG_MODE),
987 radio_mode ? str(LANG_PRESET) :
988 str(LANG_RADIO_SCAN_MODE));
989 FOR_NB_SCREENS(i)
990 screens[i].puts_scroll(0, top_of_screen + 3, buf);
991 #ifndef SIMULATOR
992 #ifdef HAVE_RDS_CAP
993 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME));
994 FOR_NB_SCREENS(i)
995 screens[i].puts_scroll(0, top_of_screen + 4, buf);
997 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_TEXT));
998 FOR_NB_SCREENS(i)
999 screens[i].puts_scroll(0, top_of_screen + 5, buf);
1000 #endif
1001 #endif /* SIMULATOR */
1003 #if CONFIG_CODEC != SWCODEC
1004 if(audio_status() == AUDIO_STATUS_RECORD)
1006 hours = seconds / 3600;
1007 minutes = (seconds - (hours * 3600)) / 60;
1008 snprintf(buf, 32, "%s %02d:%02d:%02d",
1009 str(LANG_RECORDING_TIME),
1010 hours, minutes, seconds%60);
1011 FOR_NB_SCREENS(i)
1012 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1014 else
1016 if(rec_options.rec_prerecord_time)
1018 snprintf(buf, 32, "%s %02d",
1019 str(LANG_RECORD_PRERECORD), seconds%60);
1020 FOR_NB_SCREENS(i)
1021 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1024 #endif /* CONFIG_CODEC != SWCODEC */
1026 FOR_NB_SCREENS(i)
1027 screens[i].update_viewport();
1028 #ifdef HAVE_BUTTONBAR
1029 gui_buttonbar_draw(&buttonbar);
1030 #endif
1034 update_screen = false;
1036 if (global_settings.talk_file && talk
1037 && radio_status == FMRADIO_PAUSED)
1039 talk = false;
1040 bool enqueue = false;
1041 if (radio_mode == RADIO_SCAN_MODE)
1043 talk_freq(curr_freq, enqueue);
1044 enqueue = true;
1046 if (curr_preset >= 0)
1047 talk_preset(curr_preset, radio_mode == RADIO_PRESET_MODE,
1048 enqueue);
1051 #if CONFIG_CODEC != SWCODEC
1052 if(audio_status() & AUDIO_STATUS_ERROR)
1054 done = true;
1056 #endif
1058 #ifndef HAVE_NOISY_IDLE_MODE
1059 if (TIME_AFTER(current_tick, button_timeout))
1061 cpu_idle_mode(true);
1063 #endif
1064 } /*while(!done)*/
1066 #ifndef SIMULATOR
1067 #if CONFIG_CODEC != SWCODEC
1068 if(audio_status() & AUDIO_STATUS_ERROR)
1070 splash(0, str(LANG_DISK_FULL));
1071 fms_restore(vp);
1072 audio_error_clear();
1074 while(1)
1076 button = get_action(CONTEXT_FM, TIMEOUT_BLOCK);
1077 if(button == ACTION_FM_STOP)
1078 break;
1082 audio_init_playback();
1083 #endif /* CONFIG_CODEC != SWCODEC */
1085 sound_settings_apply();
1086 #endif /* SIMULATOR */
1088 if(keep_playing)
1090 /* Catch FMRADIO_PLAYING status for the sim. */
1091 #ifndef SIMULATOR
1092 #if CONFIG_CODEC != SWCODEC
1093 /* Enable the Left and right A/D Converter */
1094 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
1095 sound_default(SOUND_RIGHT_GAIN),
1096 AUDIO_GAIN_LINEIN);
1097 mas_codec_writereg(6, 0x4000);
1098 #endif
1099 end_search();
1100 #endif /* SIMULATOR */
1102 else
1104 #if CONFIG_CODEC == SWCODEC
1105 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1106 #else
1107 radio_stop();
1108 #endif
1111 #ifndef HAVE_NOISY_IDLE_MODE
1112 cpu_idle_mode(false);
1113 #endif
1114 FOR_NB_SCREENS(i)
1116 screens[i].scroll_stop(&vp[i]);
1117 screens[i].set_viewport(NULL);
1119 in_screen = false;
1120 #if CONFIG_CODEC != SWCODEC
1121 return have_recorded;
1122 #else
1123 return false;
1124 #endif
1125 } /* radio_screen */
1127 static void radio_save_presets(void)
1129 int fd;
1130 int i;
1132 fd = creat(filepreset);
1133 if(fd >= 0)
1135 for(i = 0;i < num_presets;i++)
1137 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
1139 close(fd);
1141 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1142 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1143 presets_changed = false;
1145 else
1147 splash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1151 void radio_load_presets(char *filename)
1153 int fd;
1154 int rc;
1155 char buf[128];
1156 char *freq;
1157 char *name;
1158 bool done = false;
1159 int f;
1161 memset(presets, 0, sizeof(presets));
1162 num_presets = 0;
1164 /* No Preset in configuration. */
1165 if(filename[0] == '\0')
1167 filepreset[0] = '\0';
1168 return;
1170 /* Temporary preset, loaded until player shuts down. */
1171 else if(filename[0] == '/')
1172 strlcpy(filepreset, filename, sizeof(filepreset));
1173 /* Preset from default directory. */
1174 else
1175 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1176 FMPRESET_PATH, filename);
1178 fd = open_utf8(filepreset, O_RDONLY);
1179 if(fd >= 0)
1181 while(!done && num_presets < MAX_PRESETS)
1183 rc = read_line(fd, buf, 128);
1184 if(rc > 0)
1186 if(settings_parseline(buf, &freq, &name))
1188 f = atoi(freq);
1189 if(f) /* For backwards compatibility */
1191 struct fmstation * const fms = &presets[num_presets];
1192 fms->frequency = f;
1193 strlcpy(fms->name, name, MAX_FMPRESET_LEN+1);
1194 num_presets++;
1198 else
1199 done = true;
1201 close(fd);
1203 else /* invalid file name? */
1204 filepreset[0] = '\0';
1206 presets_loaded = num_presets > 0;
1207 presets_changed = false;
1211 static int radio_add_preset(void)
1213 char buf[MAX_FMPRESET_LEN + 1];
1215 if(num_presets < MAX_PRESETS)
1217 buf[0] = '\0';
1219 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1221 struct fmstation * const fms = &presets[num_presets];
1222 strcpy(fms->name, buf);
1223 fms->frequency = curr_freq;
1224 num_presets++;
1225 presets_changed = true;
1226 presets_loaded = num_presets > 0;
1227 return true;
1230 else
1232 splash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1234 return false;
1237 /* needed to know which preset we are edit/delete-ing */
1238 static int selected_preset = -1;
1239 static int radio_edit_preset(void)
1241 char buf[MAX_FMPRESET_LEN + 1];
1243 if (num_presets > 0)
1245 struct fmstation * const fms = &presets[selected_preset];
1247 strcpy(buf, fms->name);
1249 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1251 strcpy(fms->name, buf);
1252 presets_changed = true;
1256 return 1;
1259 static int radio_delete_preset(void)
1261 if (num_presets > 0)
1263 struct fmstation * const fms = &presets[selected_preset];
1265 if (selected_preset >= --num_presets)
1266 selected_preset = num_presets - 1;
1268 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1269 (uintptr_t)fms);
1271 if (curr_preset >= num_presets)
1272 --curr_preset;
1275 /* Don't ask to save when all presets are deleted. */
1276 presets_changed = num_presets > 0;
1278 if (!presets_changed)
1280 /* The preset list will be cleared, switch to Scan Mode. */
1281 radio_mode = RADIO_SCAN_MODE;
1282 curr_preset = -1;
1283 presets_loaded = false;
1286 return 1;
1289 static int load_preset_list(void)
1291 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1294 static int save_preset_list(void)
1296 if(num_presets > 0)
1298 bool bad_file_name = true;
1300 if(!dir_exists(FMPRESET_PATH)) /* Check if there is preset folder */
1301 mkdir(FMPRESET_PATH);
1303 create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
1304 ".fmr", 2 IF_CNFN_NUM_(, NULL));
1306 while(bad_file_name)
1308 if(!kbd_input(filepreset, sizeof(filepreset)))
1310 /* check the name: max MAX_FILENAME (20) chars */
1311 char* p2;
1312 char* p1;
1313 int len;
1314 p1 = strrchr(filepreset, '/');
1315 p2 = p1;
1316 while((p1) && (*p2) && (*p2 != '.'))
1317 p2++;
1318 len = (int)(p2-p1) - 1;
1319 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1321 /* no slash, too long or too short */
1322 splash(HZ, ID2P(LANG_INVALID_FILENAME));
1324 else
1326 /* add correct extension (easier to always write)
1327 at this point, p2 points to 0 or the extension dot */
1328 *p2 = '\0';
1329 strcat(filepreset,".fmr");
1330 bad_file_name = false;
1331 radio_save_presets();
1334 else
1336 /* user aborted */
1337 return false;
1341 else
1342 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
1344 return true;
1347 static int clear_preset_list(void)
1349 /* Clear all the preset entries */
1350 memset(presets, 0, sizeof (presets));
1352 num_presets = 0;
1353 presets_loaded = false;
1354 /* The preset list will be cleared switch to Scan Mode. */
1355 radio_mode = RADIO_SCAN_MODE;
1356 curr_preset = -1;
1358 presets_changed = false; /* Don't ask to save when clearing the list. */
1360 return true;
1363 MENUITEM_FUNCTION(radio_edit_preset_item, MENU_FUNC_CHECK_RETVAL,
1364 ID2P(LANG_FM_EDIT_PRESET),
1365 radio_edit_preset, NULL, NULL, Icon_NOICON);
1366 MENUITEM_FUNCTION(radio_delete_preset_item, MENU_FUNC_CHECK_RETVAL,
1367 ID2P(LANG_FM_DELETE_PRESET),
1368 radio_delete_preset, NULL, NULL, Icon_NOICON);
1369 static int radio_preset_callback(int action,
1370 const struct menu_item_ex *this_item)
1372 if (action == ACTION_STD_OK)
1373 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1374 return action;
1375 (void)this_item;
1377 MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_PRESET),
1378 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
1379 &radio_delete_preset_item);
1380 /* present a list of preset stations */
1381 static const char* presets_get_name(int selected_item, void *data,
1382 char *buffer, size_t buffer_len)
1384 (void)data;
1385 struct fmstation *p = &presets[selected_item];
1386 if(p->name[0])
1387 return p->name;
1388 int freq = p->frequency / 10000;
1389 int frac = freq % 100;
1390 freq /= 100;
1391 snprintf(buffer, buffer_len,
1392 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1393 return buffer;
1396 static int presets_speak_name(int selected_item, void * data)
1398 (void)data;
1399 talk_preset(selected_item, true, false);
1400 return 0;
1403 static int handle_radio_presets(void)
1405 struct gui_synclist lists;
1406 int result = 0;
1407 int action = ACTION_NONE;
1408 #ifdef HAVE_BUTTONBAR
1409 struct gui_buttonbar buttonbar;
1410 #endif
1412 if(presets_loaded == false)
1413 return result;
1415 #ifdef HAVE_BUTTONBAR
1416 gui_buttonbar_init(&buttonbar);
1417 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
1418 gui_buttonbar_set(&buttonbar, str(LANG_FM_BUTTONBAR_ADD),
1419 str(LANG_FM_BUTTONBAR_EXIT),
1420 str(LANG_FM_BUTTONBAR_ACTION));
1421 gui_buttonbar_draw(&buttonbar);
1422 #endif
1423 gui_synclist_init(&lists, presets_get_name, NULL, false, 1, NULL);
1424 gui_synclist_set_title(&lists, str(LANG_PRESET), NOICON);
1425 gui_synclist_set_icon_callback(&lists, NULL);
1426 if(global_settings.talk_file)
1427 gui_synclist_set_voice_callback(&lists, presets_speak_name);
1428 gui_synclist_set_nb_items(&lists, num_presets);
1429 gui_synclist_select_item(&lists, curr_preset<0 ? 0 : curr_preset);
1430 gui_synclist_speak_item(&lists);
1432 while (result == 0)
1434 gui_synclist_draw(&lists);
1435 list_do_action(CONTEXT_STD, TIMEOUT_BLOCK,
1436 &lists, &action, LIST_WRAP_UNLESS_HELD);
1437 switch (action)
1439 case ACTION_STD_MENU:
1440 if (radio_add_preset())
1442 gui_synclist_set_nb_items(&lists, num_presets);
1443 gui_synclist_select_item(&lists, num_presets - 1);
1445 break;
1446 case ACTION_STD_CANCEL:
1447 result = 1;
1448 break;
1449 case ACTION_STD_OK:
1450 curr_preset = gui_synclist_get_sel_pos(&lists);
1451 curr_freq = presets[curr_preset].frequency;
1452 next_station(0);
1453 remember_frequency();
1454 result = 1;
1455 break;
1456 case ACTION_F3:
1457 case ACTION_STD_CONTEXT:
1458 selected_preset = gui_synclist_get_sel_pos(&lists);
1459 do_menu(&handle_radio_preset_menu, NULL, NULL, false);
1460 gui_synclist_set_nb_items(&lists, num_presets);
1461 gui_synclist_select_item(&lists, selected_preset);
1462 gui_synclist_speak_item(&lists);
1463 break;
1464 default:
1465 if(default_event_handler(action) == SYS_USB_CONNECTED)
1466 result = 2;
1469 gui_synclist_scroll_stop(&lists);
1470 return result - 1;
1473 void toggle_mono_mode(bool mono)
1475 tuner_set(RADIO_FORCE_MONO, mono);
1478 void set_radio_region(int region)
1480 #ifdef HAVE_RADIO_REGION
1481 tuner_set(RADIO_REGION, region);
1482 #endif
1483 next_station(0);
1484 remember_frequency();
1485 (void)region;
1488 MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL);
1489 MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL);
1491 #ifndef FM_MODE
1492 static char* get_mode_text(int selected_item, void * data, char *buffer)
1494 (void)selected_item;
1495 (void)data;
1496 snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE),
1497 radio_mode ? str(LANG_PRESET) :
1498 str(LANG_RADIO_SCAN_MODE));
1499 return buffer;
1501 static int toggle_radio_mode(void)
1503 radio_mode = (radio_mode == RADIO_SCAN_MODE) ?
1504 RADIO_PRESET_MODE : RADIO_SCAN_MODE;
1505 return 0;
1507 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0,
1508 toggle_radio_mode, NULL,
1509 get_mode_text, NULL, NULL, NULL, Icon_NOICON);
1510 #endif
1512 static int scan_presets(void *viewports)
1514 bool do_scan = true;
1515 int i;
1516 struct viewport *vp = (struct viewport *)viewports;
1518 FOR_NB_SCREENS(i)
1519 screens[i].set_viewport(vp?&vp[i]:NULL);
1520 if(num_presets > 0) /* Do that to avoid 2 questions. */
1521 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1523 if(do_scan)
1525 const struct fm_region_data * const fmr =
1526 &fm_region_data[global_settings.fm_region];
1528 curr_freq = fmr->freq_min;
1529 num_presets = 0;
1530 memset(presets, 0, sizeof(presets));
1532 tuner_set(RADIO_MUTE, 1);
1534 while(curr_freq <= fmr->freq_max)
1536 int freq, frac;
1537 if(num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1538 break;
1540 freq = curr_freq / 10000;
1541 frac = freq % 100;
1542 freq /= 100;
1544 splashf(0, str(LANG_FM_SCANNING), freq, frac);
1546 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
1548 /* add preset */
1549 presets[num_presets].name[0] = '\0';
1550 presets[num_presets].frequency = curr_freq;
1551 num_presets++;
1554 curr_freq += fmr->freq_step;
1557 if (radio_status == FMRADIO_PLAYING)
1558 tuner_set(RADIO_MUTE, 0);
1560 presets_changed = true;
1562 FOR_NB_SCREENS(i)
1564 screens[i].clear_viewport();
1565 screens[i].update_viewport();
1568 if(num_presets > 0)
1570 curr_freq = presets[0].frequency;
1571 radio_mode = RADIO_PRESET_MODE;
1572 presets_loaded = true;
1573 next_station(0);
1575 else
1577 /* Wrap it to beginning or we'll be past end of band */
1578 presets_loaded = false;
1579 next_station(1);
1582 return true;
1586 #ifdef HAVE_RECORDING
1588 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1589 #define FM_RECORDING_SCREEN
1590 static int fm_recording_screen(void)
1592 bool ret;
1594 /* switch recording source to FMRADIO for the duration */
1595 int rec_source = global_settings.rec_source;
1596 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1597 ret = recording_screen(true);
1599 /* safe to reset as changing sources is prohibited here */
1600 global_settings.rec_source = rec_source;
1602 return ret;
1605 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1607 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1608 #define FM_RECORDING_SETTINGS
1609 static int fm_recording_settings(void)
1611 bool ret = recording_menu(true);
1613 #if CONFIG_CODEC != SWCODEC
1614 if (!ret)
1616 struct audio_recording_options rec_options;
1617 rec_init_recording_options(&rec_options);
1618 rec_options.rec_source = AUDIO_SRC_LINEIN;
1619 rec_set_recording_options(&rec_options);
1621 #endif
1623 return ret;
1626 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1627 #endif /* HAVE_RECORDING */
1629 #ifdef FM_RECORDING_SCREEN
1630 MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING),
1631 fm_recording_screen, NULL, NULL, Icon_Recording);
1632 #endif
1633 #ifdef FM_RECORDING_SETTINGS
1634 MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS),
1635 fm_recording_settings, NULL, NULL, Icon_Recording);
1636 #endif
1637 #ifndef FM_PRESET
1638 MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET),
1639 handle_radio_presets, NULL, NULL, Icon_NOICON);
1640 #endif
1641 #ifndef FM_PRESET_ADD
1642 MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET),
1643 radio_add_preset, NULL, NULL, Icon_NOICON);
1644 #endif
1647 MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD),
1648 load_preset_list, NULL, NULL, Icon_NOICON);
1649 MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE),
1650 save_preset_list, NULL, NULL, Icon_NOICON);
1651 MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR),
1652 clear_preset_list, NULL, NULL, Icon_NOICON);
1653 MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM,
1654 ID2P(LANG_FM_SCAN_PRESETS),
1655 scan_presets, NULL, NULL, Icon_NOICON);
1657 MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1658 Icon_Radio_screen,
1659 #ifndef FM_PRESET
1660 &radio_presets_item,
1661 #endif
1662 #ifndef FM_PRESET_ADD
1663 &radio_addpreset_item,
1664 #endif
1665 &presetload_item, &presetsave_item, &presetclear_item,
1666 &force_mono,
1667 #ifndef FM_MODE
1668 &radio_mode_item,
1669 #endif
1670 &set_region, &sound_settings,
1671 #ifdef FM_RECORDING_SCREEN
1672 &recscreen_item,
1673 #endif
1674 #ifdef FM_RECORDING_SETTINGS
1675 &recsettings_item,
1676 #endif
1677 &scan_presets_item);
1678 /* main menu of the radio screen */
1679 static bool radio_menu(void)
1681 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1682 MENU_ATTACHED_USB;
1685 #endif