Move c/h files implementing/defining standard library stuff into a new libc directory...
[kugel-rb.git] / apps / recorder / radio.c
blob7761f248ca8283f8d86cf11f59fe9c27b00dea25
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 "mas.h"
27 #include "settings.h"
28 #include "button.h"
29 #include "status.h"
30 #include "thread.h"
31 #include "audio.h"
32 #include "mp3_playback.h"
33 #include "ctype.h"
34 #include "file.h"
35 #include "general.h"
36 #include "errno.h"
37 #include "string-extra.h"
38 #include "system.h"
39 #include "radio.h"
40 #include "menu.h"
41 #include "misc.h"
42 #include "keyboard.h"
43 #include "screens.h"
44 #include "peakmeter.h"
45 #include "lang.h"
46 #include "font.h"
47 #include "sound_menu.h"
48 #ifdef HAVE_RECORDING
49 #include "recording.h"
50 #endif
51 #ifdef IPOD_ACCESSORY_PROTOCOL
52 #include "iap.h"
53 #endif
54 #include "talk.h"
55 #include "tuner.h"
56 #include "power.h"
57 #include "sound.h"
58 #include "screen_access.h"
59 #include "splash.h"
60 #include "yesno.h"
61 #include "buttonbar.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"
69 #ifdef HAVE_QUICKSCREEN
70 #include "quickscreen.h"
71 #endif
73 #if CONFIG_TUNER
75 #if CONFIG_KEYPAD == RECORDER_PAD
76 #define FM_RECORD
77 #define FM_PRESET_ADD
78 #define FM_PRESET_ACTION
79 #define FM_PRESET
80 #define FM_MODE
82 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
83 #define FM_PRESET
84 #define FM_MODE
85 #define FM_NEXT_PRESET
86 #define FM_PREV_PRESET
88 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
89 #define FM_PRESET
90 #define FM_MODE
92 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
93 #define FM_PRESET
94 #define FM_MODE
95 /* This should be removeable if the whole tuning thing is sorted out since
96 proper tuning quiets the screen almost entirely in that extreme measures
97 have to be taken to hear any interference. */
98 #define HAVE_NOISY_IDLE_MODE
100 #elif CONFIG_KEYPAD == ONDIO_PAD
101 #define FM_RECORD_DBLPRE
102 #define FM_RECORD
103 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD) \
104 || (CONFIG_KEYPAD == SANSA_FUZE_PAD)
105 #define FM_PRESET
106 #define FM_MODE
108 #elif (CONFIG_KEYPAD == GIGABEAT_S_PAD)
109 #define FM_PRESET
110 #define FM_MODE
112 #elif (CONFIG_KEYPAD == COWON_D2_PAD)
113 #define FM_PRESET
115 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
116 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
117 #define FM_MODE
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);
149 static void radio_off(void);
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_off();
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 static void radio_off(void)
260 tuner_set(RADIO_MUTE, 1);
261 tuner_set(RADIO_SLEEP, 1); /* low power mode, if available */
262 radio_status = FMRADIO_OFF;
263 tuner_power(false); /* status update, power off if avail. */
266 void radio_stop(void)
268 if(radio_status == FMRADIO_OFF)
269 return;
271 radio_off();
272 } /* radio_stop */
274 bool radio_hardware_present(void)
276 return tuner_get(RADIO_PRESENT);
279 /* Keep freq on the grid for the current region */
280 static int snap_freq_to_grid(int freq)
282 const struct fm_region_data * const fmr =
283 &fm_region_data[global_settings.fm_region];
285 /* Range clamp if out of range or just round to nearest */
286 if (freq < fmr->freq_min)
287 freq = fmr->freq_min;
288 else if (freq > fmr->freq_max)
289 freq = fmr->freq_max;
290 else
291 freq = (freq - fmr->freq_min + fmr->freq_step/2) /
292 fmr->freq_step * fmr->freq_step + fmr->freq_min;
294 return freq;
297 /* Find a matching preset to freq */
298 static int find_preset(int freq)
300 int i;
301 if(num_presets < 1)
302 return -1;
303 for(i = 0;i < MAX_PRESETS;i++)
305 if(freq == presets[i].frequency)
306 return i;
309 return -1;
312 /* Return the closest preset encountered in the search direction with
313 wraparound. */
314 static int find_closest_preset(int freq, int direction)
316 int i;
317 int lowpreset = 0;
318 int highpreset = 0;
319 int closest = -1;
321 if (direction == 0) /* direction == 0 isn't really used */
322 return 0;
324 for (i = 0; i < num_presets; i++)
326 int f = presets[i].frequency;
327 if (f == freq)
328 return i; /* Exact match = stop */
330 /* remember the highest and lowest presets for wraparound */
331 if (f < presets[lowpreset].frequency)
332 lowpreset = i;
333 if (f > presets[highpreset].frequency)
334 highpreset = i;
336 /* find the closest preset in the given direction */
337 if (direction > 0 && f > freq)
339 if (closest < 0 || f < presets[closest].frequency)
340 closest = i;
342 else if (direction < 0 && f < freq)
344 if (closest < 0 || f > presets[closest].frequency)
345 closest = i;
349 if (closest < 0)
351 /* no presets in the given direction */
352 /* wrap around depending on direction */
353 if (direction < 0)
354 closest = highpreset;
355 else
356 closest = lowpreset;
359 return closest;
362 static void remember_frequency(void)
364 const struct fm_region_data * const fmr =
365 &fm_region_data[global_settings.fm_region];
366 global_status.last_frequency = (curr_freq - fmr->freq_min)
367 / fmr->freq_step;
368 status_save();
371 static void next_preset(int direction)
373 if (num_presets < 1)
374 return;
376 if (curr_preset == -1)
377 curr_preset = find_closest_preset(curr_freq, direction);
378 else
379 curr_preset = (curr_preset + direction + num_presets) % num_presets;
381 /* Must stay on the current grid for the region */
382 curr_freq = snap_freq_to_grid(presets[curr_preset].frequency);
384 tuner_set(RADIO_FREQUENCY, curr_freq);
385 remember_frequency();
388 /* Step to the next or previous frequency */
389 static int step_freq(int freq, int direction)
391 const struct fm_region_data * const fmr =
392 &fm_region_data[global_settings.fm_region];
394 freq += direction*fmr->freq_step;
396 /* Wrap first or snapping to grid will not let us on the band extremes */
397 if (freq > fmr->freq_max)
398 freq = direction > 0 ? fmr->freq_min : fmr->freq_max;
399 else if (freq < fmr->freq_min)
400 freq = direction < 0 ? fmr->freq_max : fmr->freq_min;
401 else
402 freq = snap_freq_to_grid(freq);
404 return freq;
407 /* Step to the next or previous station */
408 static void next_station(int direction)
410 if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
412 next_preset(direction);
413 return;
416 curr_freq = step_freq(curr_freq, direction);
418 if (radio_status == FMRADIO_PLAYING)
419 tuner_set(RADIO_MUTE, 1);
421 tuner_set(RADIO_FREQUENCY, curr_freq);
423 if (radio_status == FMRADIO_PLAYING)
424 tuner_set(RADIO_MUTE, 0);
426 curr_preset = find_preset(curr_freq);
427 remember_frequency();
430 /* Ends an in-progress search */
431 static void end_search(void)
433 if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
434 tuner_set(RADIO_MUTE, 0);
435 search_dir = 0;
438 /* Speak a frequency. */
439 static void talk_freq(int freq, bool enqueue)
441 freq /= 10000;
442 talk_number(freq / 100, enqueue);
443 talk_id(LANG_POINT, true);
444 talk_number(freq % 100 / 10, true);
445 if (freq % 10)
446 talk_number(freq % 10, true);
449 /* Speak a preset by number or by spelling its name, depending on settings. */
450 static void talk_preset(int preset, bool fallback, bool enqueue)
452 if (global_settings.talk_file == 1) /* number */
453 talk_number(preset + 1, enqueue);
454 else
455 { /* spell */
456 if(presets[preset].name[0])
457 talk_spell(presets[preset].name, enqueue);
458 else if(fallback)
459 talk_freq(presets[preset].frequency, enqueue);
463 static void fms_restore(struct viewport vp[NB_SCREENS])
465 struct screen *display;
466 int i;
467 FOR_NB_SCREENS(i)
469 display = &screens[i];
470 display->set_viewport(&vp[i]);
471 display->clear_viewport();
472 display->update_viewport();
476 int radio_screen(void)
478 char buf[MAX_PATH];
479 bool done = false;
480 int ret_val = GO_TO_ROOT;
481 int button;
482 int i;
483 bool stereo = false, last_stereo = false;
484 int fh;
485 int top_of_screen = 0;
486 bool update_screen = true;
487 bool screen_freeze = false;
488 bool keep_playing = false;
489 bool talk = false;
490 #ifdef FM_RECORD_DBLPRE
491 int lastbutton = BUTTON_NONE;
492 unsigned long rec_lastclick = 0;
493 #endif
494 #if CONFIG_CODEC != SWCODEC
495 bool have_recorded = false;
496 int timeout = current_tick + HZ/10;
497 unsigned int seconds = 0;
498 unsigned int last_seconds = 0;
499 int hours, minutes;
500 struct audio_recording_options rec_options;
501 #endif /* CONFIG_CODEC != SWCODEC */
502 #ifndef HAVE_NOISY_IDLE_MODE
503 int button_timeout = current_tick + (2*HZ);
504 #endif
505 struct viewport vp[NB_SCREENS];
506 #ifdef HAVE_BUTTONBAR
507 struct gui_buttonbar buttonbar;
508 gui_buttonbar_init(&buttonbar);
509 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
510 #endif
512 /* change status to "in screen" */
513 in_screen = true;
515 /* always display status bar in radio screen for now */
516 FOR_NB_SCREENS(i)
518 viewport_set_defaults(&vp[i], i);
519 #ifdef HAVE_BUTTONBAR
520 if (global_settings.buttonbar)
521 vp[i].height -= BUTTONBAR_HEIGHT;
522 #endif
524 fms_restore(vp);
526 fh = font_get(FONT_UI)->height;
528 /* Adjust for font size, trying to center the information vertically */
529 if(fh < 10)
530 top_of_screen = 1;
532 if(num_presets <= 0)
534 radio_load_presets(global_settings.fmr_file);
537 if(radio_status == FMRADIO_OFF)
538 audio_stop();
539 #ifndef SIMULATOR
541 #if CONFIG_CODEC != SWCODEC
542 if(rec_create_directory() > 0)
543 have_recorded = true;
545 audio_init_recording(talk_get_bufsize());
547 sound_settings_apply();
548 /* Yes, we use the D/A for monitoring */
549 peak_meter_playback(true);
551 peak_meter_enabled = true;
553 rec_init_recording_options(&rec_options);
554 rec_options.rec_source = AUDIO_SRC_LINEIN;
555 rec_set_recording_options(&rec_options);
557 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
558 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
560 #endif /* CONFIG_CODEC != SWCODEC */
561 #endif /* ndef SIMULATOR */
563 /* turn on radio */
564 #if CONFIG_CODEC == SWCODEC
565 audio_set_input_source(AUDIO_SRC_FMRADIO,
566 (radio_status == FMRADIO_PAUSED) ?
567 SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
568 #else
569 if (radio_status == FMRADIO_OFF)
570 radio_start();
571 #endif
573 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
574 scan_presets(vp);
576 curr_preset = find_preset(curr_freq);
577 if(curr_preset != -1)
578 radio_mode = RADIO_PRESET_MODE;
580 #ifdef HAVE_BUTTONBAR
581 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
582 str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD));
583 #endif
585 #ifndef HAVE_NOISY_IDLE_MODE
586 cpu_idle_mode(true);
587 #endif
589 while(!done)
591 if(search_dir != 0)
593 curr_freq = step_freq(curr_freq, search_dir);
594 update_screen = true;
596 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
598 curr_preset = find_preset(curr_freq);
599 remember_frequency();
600 end_search();
601 talk = true;
603 trigger_cpu_boost();
606 if (!update_screen)
608 cancel_cpu_boost();
611 #if CONFIG_CODEC != SWCODEC
612 /* TODO: Can we timeout at HZ when recording since peaks aren't
613 displayed? This should quiet recordings too. */
614 button = get_action(CONTEXT_FM,
615 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
616 #else
617 button = get_action(CONTEXT_FM,
618 update_screen ? TIMEOUT_NOBLOCK : HZ);
619 #endif
621 #ifndef HAVE_NOISY_IDLE_MODE
622 if (button != ACTION_NONE)
624 cpu_idle_mode(false);
625 button_timeout = current_tick + (2*HZ);
627 #endif
628 switch(button)
630 case ACTION_FM_STOP:
631 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
632 if(audio_status() == AUDIO_STATUS_RECORD)
634 audio_stop();
636 else
637 #endif
639 done = true;
640 if(presets_changed)
642 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
644 if(filepreset[0] == '\0')
645 save_preset_list();
646 else
647 radio_save_presets();
650 /* Clear the preset list on exit. */
651 clear_preset_list();
653 update_screen = true;
654 break;
656 #ifdef FM_RECORD
657 case ACTION_FM_RECORD:
658 #ifdef FM_RECORD_DBLPRE
659 if (lastbutton != ACTION_FM_RECORD_DBLPRE)
661 rec_lastclick = 0;
662 break;
664 if (current_tick - rec_lastclick > HZ/2)
666 rec_lastclick = current_tick;
667 break;
669 #endif /* FM_RECORD_DBLPRE */
670 #ifndef SIMULATOR
671 if(audio_status() == AUDIO_STATUS_RECORD)
673 rec_command(RECORDING_CMD_START_NEWFILE);
674 update_screen = true;
676 else
678 have_recorded = true;
679 rec_command(RECORDING_CMD_START);
680 update_screen = true;
682 #endif /* SIMULATOR */
683 last_seconds = 0;
684 break;
685 #endif /* #ifdef FM_RECORD */
687 case ACTION_FM_EXIT:
688 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
689 if(audio_status() == AUDIO_STATUS_RECORD)
690 audio_stop();
691 #endif
692 keep_playing = true;
693 done = true;
694 ret_val = GO_TO_ROOT;
695 if(presets_changed)
697 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
699 if(filepreset[0] == '\0')
700 save_preset_list();
701 else
702 radio_save_presets();
706 /* Clear the preset list on exit. */
707 clear_preset_list();
709 break;
711 case ACTION_STD_PREV:
712 case ACTION_STD_NEXT:
713 next_station(button == ACTION_STD_PREV ? -1 : 1);
714 end_search();
715 update_screen = true;
716 talk = true;
717 break;
719 case ACTION_STD_PREVREPEAT:
720 case ACTION_STD_NEXTREPEAT:
722 int dir = search_dir;
723 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
724 if (radio_mode != RADIO_SCAN_MODE)
726 next_preset(search_dir);
727 end_search();
728 update_screen = true;
729 talk = true;
731 else if (dir == 0)
733 /* Starting auto scan */
734 tuner_set(RADIO_MUTE, 1);
735 update_screen = true;
737 break;
740 case ACTION_SETTINGS_INC:
741 case ACTION_SETTINGS_INCREPEAT:
742 global_settings.volume++;
743 setvol();
744 update_screen = true;
745 break;
747 case ACTION_SETTINGS_DEC:
748 case ACTION_SETTINGS_DECREPEAT:
749 global_settings.volume--;
750 setvol();
751 update_screen = true;
752 break;
754 case ACTION_FM_PLAY:
755 if (radio_status == FMRADIO_PLAYING)
756 radio_pause();
757 else
758 radio_start();
760 update_screen = true;
761 talk = false;
762 talk_shutup();
763 break;
765 case ACTION_FM_MENU:
766 FOR_NB_SCREENS(i)
768 screens[i].scroll_stop(&vp[i]);
770 radio_menu();
771 curr_preset = find_preset(curr_freq);
772 fms_restore(vp);
773 #ifdef HAVE_BUTTONBAR
774 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
775 str(LANG_PRESET),
776 str(LANG_FM_BUTTONBAR_RECORD));
777 #endif
778 update_screen = true;
779 break;
781 #ifdef FM_PRESET
782 case ACTION_FM_PRESET:
783 if(num_presets < 1)
785 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
786 update_screen = true;
787 fms_restore(vp);
789 break;
791 FOR_NB_SCREENS(i)
792 screens[i].scroll_stop(&vp[i]);
793 handle_radio_presets();
794 fms_restore(vp);
795 #ifdef HAVE_BUTTONBAR
796 gui_buttonbar_set(&buttonbar,
797 str(LANG_BUTTONBAR_MENU),
798 str(LANG_PRESET),
799 str(LANG_FM_BUTTONBAR_RECORD));
800 #endif
801 update_screen = true;
802 break;
803 #endif /* FM_PRESET */
805 #ifdef HAVE_QUICKSCREEN
806 case ACTION_FM_QUICKSCREEN:
808 if (quick_screen_quick(button))
810 done = true;
811 break;
813 fms_restore(vp);
814 update_screen = true;
816 break;
817 #endif
818 #ifdef FM_FREEZE
819 case ACTION_FM_FREEZE:
820 if(!screen_freeze)
822 splash(HZ, str(LANG_FM_FREEZE));
823 screen_freeze = true;
825 else
827 update_screen = true;
828 screen_freeze = false;
830 break;
831 #endif /* FM_FREEZE */
833 case SYS_USB_CONNECTED:
834 #if CONFIG_CODEC != SWCODEC
835 /* Only accept USB connection when not recording */
836 if(audio_status() != AUDIO_STATUS_RECORD)
837 #endif
839 default_event_handler(SYS_USB_CONNECTED);
840 screen_freeze = true; /* Cosmetic: makes sure the
841 radio screen doesn't redraw */
842 done = true;
844 break;
846 #ifdef FM_MODE
847 case ACTION_FM_MODE:
848 if(radio_mode == RADIO_SCAN_MODE)
850 /* Force scan mode if there are no presets. */
851 if(num_presets > 0)
852 radio_mode = RADIO_PRESET_MODE;
854 else
855 radio_mode = RADIO_SCAN_MODE;
856 update_screen = true;
857 cond_talk_ids_fq(radio_mode ?
858 LANG_PRESET : LANG_RADIO_SCAN_MODE);
859 talk = true;
860 break;
861 #endif /* FM_MODE */
863 #ifdef FM_NEXT_PRESET
864 case ACTION_FM_NEXT_PRESET:
865 next_preset(1);
866 end_search();
867 update_screen = true;
868 talk = true;
869 break;
870 #endif
872 #ifdef FM_PREV_PRESET
873 case ACTION_FM_PREV_PRESET:
874 next_preset(-1);
875 end_search();
876 update_screen = true;
877 talk = true;
878 break;
879 #endif
881 default:
882 default_event_handler(button);
883 #ifdef HAVE_RDS_CAP
884 if (tuner_get(RADIO_EVENT))
885 update_screen = true;
886 #endif
887 if (!tuner_get(RADIO_PRESENT))
889 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
890 if(audio_status() == AUDIO_STATUS_RECORD)
891 audio_stop();
892 #endif
893 keep_playing = false;
894 done = true;
895 ret_val = GO_TO_ROOT;
896 if(presets_changed)
898 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
900 if(filepreset[0] == '\0')
901 save_preset_list();
902 else
903 radio_save_presets();
907 /* Clear the preset list on exit. */
908 clear_preset_list();
910 break;
911 } /*switch(button)*/
913 #ifdef FM_RECORD_DBLPRE
914 if (button != ACTION_NONE)
915 lastbutton = button;
916 #endif
918 #if CONFIG_CODEC != SWCODEC
919 peak_meter_peek();
920 #endif
922 if(!screen_freeze)
924 /* Only display the peak meter when not recording */
925 #if CONFIG_CODEC != SWCODEC
926 if(!audio_status())
928 FOR_NB_SCREENS(i)
930 screens[i].set_viewport(&vp[i]);
931 peak_meter_screen(&screens[i],0, fh*(top_of_screen + 4),fh);
932 screens[i].update_rect(0, fh*(top_of_screen + 4),
933 screens[i].getwidth(), fh);
937 if(TIME_AFTER(current_tick, timeout))
939 timeout = current_tick + HZ;
940 #else /* SWCODEC */
942 #endif /* CONFIG_CODEC == SWCODEC */
944 /* keep "mono" from always being displayed when paused */
945 if (radio_status != FMRADIO_PAUSED)
947 stereo = tuner_get(RADIO_STEREO) &&
948 !global_settings.fm_force_mono;
950 if(stereo != last_stereo)
952 update_screen = true;
953 last_stereo = stereo;
958 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
959 seconds = audio_recorded_time() / HZ;
960 if (update_screen || seconds > last_seconds)
962 last_seconds = seconds;
963 #else
964 if (update_screen)
966 #endif
967 int freq;
969 FOR_NB_SCREENS(i)
971 screens[i].set_viewport(&vp[i]);
974 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
975 curr_preset + 1, presets[curr_preset].name);
977 FOR_NB_SCREENS(i)
978 screens[i].puts_scroll(0, top_of_screen, buf);
980 freq = curr_freq / 10000;
981 snprintf(buf, 128, str(LANG_FM_STATION),
982 freq / 100, freq % 100);
983 FOR_NB_SCREENS(i)
984 screens[i].puts_scroll(0, top_of_screen + 1, buf);
986 FOR_NB_SCREENS(i)
987 screens[i].puts_scroll(0, top_of_screen + 2,
988 stereo ? str(LANG_CHANNEL_STEREO) :
989 str(LANG_CHANNEL_MONO));
991 snprintf(buf, 128, "%s %s", str(LANG_MODE),
992 radio_mode ? str(LANG_PRESET) :
993 str(LANG_RADIO_SCAN_MODE));
994 FOR_NB_SCREENS(i)
995 screens[i].puts_scroll(0, top_of_screen + 3, buf);
996 #ifndef SIMULATOR
997 #ifdef HAVE_RDS_CAP
998 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME));
999 FOR_NB_SCREENS(i)
1000 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1002 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_TEXT));
1003 FOR_NB_SCREENS(i)
1004 screens[i].puts_scroll(0, top_of_screen + 5, buf);
1005 #endif
1006 #endif /* SIMULATOR */
1008 #if CONFIG_CODEC != SWCODEC
1009 if(audio_status() == AUDIO_STATUS_RECORD)
1011 hours = seconds / 3600;
1012 minutes = (seconds - (hours * 3600)) / 60;
1013 snprintf(buf, 32, "%s %02d:%02d:%02d",
1014 str(LANG_RECORDING_TIME),
1015 hours, minutes, seconds%60);
1016 FOR_NB_SCREENS(i)
1017 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1019 else
1021 if(rec_options.rec_prerecord_time)
1023 snprintf(buf, 32, "%s %02d",
1024 str(LANG_RECORD_PRERECORD), seconds%60);
1025 FOR_NB_SCREENS(i)
1026 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1029 #endif /* CONFIG_CODEC != SWCODEC */
1031 FOR_NB_SCREENS(i)
1032 screens[i].update_viewport();
1033 #ifdef HAVE_BUTTONBAR
1034 gui_buttonbar_draw(&buttonbar);
1035 #endif
1039 update_screen = false;
1041 if (global_settings.talk_file && talk
1042 && radio_status == FMRADIO_PAUSED)
1044 talk = false;
1045 bool enqueue = false;
1046 if (radio_mode == RADIO_SCAN_MODE)
1048 talk_freq(curr_freq, enqueue);
1049 enqueue = true;
1051 if (curr_preset >= 0)
1052 talk_preset(curr_preset, radio_mode == RADIO_PRESET_MODE,
1053 enqueue);
1056 #if CONFIG_CODEC != SWCODEC
1057 if(audio_status() & AUDIO_STATUS_ERROR)
1059 done = true;
1061 #endif
1063 #ifndef HAVE_NOISY_IDLE_MODE
1064 if (TIME_AFTER(current_tick, button_timeout))
1066 cpu_idle_mode(true);
1068 #endif
1069 } /*while(!done)*/
1071 #ifndef SIMULATOR
1072 #if CONFIG_CODEC != SWCODEC
1073 if(audio_status() & AUDIO_STATUS_ERROR)
1075 splash(0, str(LANG_DISK_FULL));
1076 fms_restore(vp);
1077 audio_error_clear();
1079 while(1)
1081 button = get_action(CONTEXT_FM, TIMEOUT_BLOCK);
1082 if(button == ACTION_FM_STOP)
1083 break;
1087 audio_init_playback();
1088 #endif /* CONFIG_CODEC != SWCODEC */
1090 sound_settings_apply();
1091 #endif /* SIMULATOR */
1093 if(keep_playing)
1095 /* Catch FMRADIO_PLAYING status for the sim. */
1096 #ifndef SIMULATOR
1097 #if CONFIG_CODEC != SWCODEC
1098 /* Enable the Left and right A/D Converter */
1099 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
1100 sound_default(SOUND_RIGHT_GAIN),
1101 AUDIO_GAIN_LINEIN);
1102 mas_codec_writereg(6, 0x4000);
1103 #endif
1104 end_search();
1105 #endif /* SIMULATOR */
1107 else
1109 #if CONFIG_CODEC == SWCODEC
1110 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1111 #else
1112 radio_stop();
1113 #endif
1116 #ifndef HAVE_NOISY_IDLE_MODE
1117 cpu_idle_mode(false);
1118 #endif
1119 FOR_NB_SCREENS(i)
1121 screens[i].scroll_stop(&vp[i]);
1122 screens[i].set_viewport(NULL);
1124 in_screen = false;
1125 #if CONFIG_CODEC != SWCODEC
1126 return have_recorded;
1127 #else
1128 return false;
1129 #endif
1130 } /* radio_screen */
1132 static void radio_save_presets(void)
1134 int fd;
1135 int i;
1137 fd = creat(filepreset, 0666);
1138 if(fd >= 0)
1140 for(i = 0;i < num_presets;i++)
1142 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
1144 close(fd);
1146 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1147 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1148 presets_changed = false;
1150 else
1152 splash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1156 void radio_load_presets(char *filename)
1158 int fd;
1159 int rc;
1160 char buf[128];
1161 char *freq;
1162 char *name;
1163 bool done = false;
1164 int f;
1166 memset(presets, 0, sizeof(presets));
1167 num_presets = 0;
1169 /* No Preset in configuration. */
1170 if(filename[0] == '\0')
1172 filepreset[0] = '\0';
1173 return;
1175 /* Temporary preset, loaded until player shuts down. */
1176 else if(filename[0] == '/')
1177 strlcpy(filepreset, filename, sizeof(filepreset));
1178 /* Preset from default directory. */
1179 else
1180 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1181 FMPRESET_PATH, filename);
1183 fd = open_utf8(filepreset, O_RDONLY);
1184 if(fd >= 0)
1186 while(!done && num_presets < MAX_PRESETS)
1188 rc = read_line(fd, buf, 128);
1189 if(rc > 0)
1191 if(settings_parseline(buf, &freq, &name))
1193 f = atoi(freq);
1194 if(f) /* For backwards compatibility */
1196 struct fmstation * const fms = &presets[num_presets];
1197 fms->frequency = f;
1198 strlcpy(fms->name, name, MAX_FMPRESET_LEN+1);
1199 num_presets++;
1203 else
1204 done = true;
1206 close(fd);
1208 else /* invalid file name? */
1209 filepreset[0] = '\0';
1211 presets_loaded = num_presets > 0;
1212 presets_changed = false;
1216 static int radio_add_preset(void)
1218 char buf[MAX_FMPRESET_LEN + 1];
1220 if(num_presets < MAX_PRESETS)
1222 buf[0] = '\0';
1224 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1226 struct fmstation * const fms = &presets[num_presets];
1227 strcpy(fms->name, buf);
1228 fms->frequency = curr_freq;
1229 num_presets++;
1230 presets_changed = true;
1231 presets_loaded = num_presets > 0;
1232 return true;
1235 else
1237 splash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1239 return false;
1242 /* needed to know which preset we are edit/delete-ing */
1243 static int selected_preset = -1;
1244 static int radio_edit_preset(void)
1246 char buf[MAX_FMPRESET_LEN + 1];
1248 if (num_presets > 0)
1250 struct fmstation * const fms = &presets[selected_preset];
1252 strcpy(buf, fms->name);
1254 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1256 strcpy(fms->name, buf);
1257 presets_changed = true;
1261 return 1;
1264 static int radio_delete_preset(void)
1266 if (num_presets > 0)
1268 struct fmstation * const fms = &presets[selected_preset];
1270 if (selected_preset >= --num_presets)
1271 selected_preset = num_presets - 1;
1273 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1274 (uintptr_t)fms);
1276 if (curr_preset >= num_presets)
1277 --curr_preset;
1280 /* Don't ask to save when all presets are deleted. */
1281 presets_changed = num_presets > 0;
1283 if (!presets_changed)
1285 /* The preset list will be cleared, switch to Scan Mode. */
1286 radio_mode = RADIO_SCAN_MODE;
1287 curr_preset = -1;
1288 presets_loaded = false;
1291 return 1;
1294 static int load_preset_list(void)
1296 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1299 static int save_preset_list(void)
1301 if(num_presets > 0)
1303 bool bad_file_name = true;
1305 if(!dir_exists(FMPRESET_PATH)) /* Check if there is preset folder */
1306 mkdir(FMPRESET_PATH);
1308 create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
1309 ".fmr", 2 IF_CNFN_NUM_(, NULL));
1311 while(bad_file_name)
1313 if(!kbd_input(filepreset, sizeof(filepreset)))
1315 /* check the name: max MAX_FILENAME (20) chars */
1316 char* p2;
1317 char* p1;
1318 int len;
1319 p1 = strrchr(filepreset, '/');
1320 p2 = p1;
1321 while((p1) && (*p2) && (*p2 != '.'))
1322 p2++;
1323 len = (int)(p2-p1) - 1;
1324 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1326 /* no slash, too long or too short */
1327 splash(HZ, ID2P(LANG_INVALID_FILENAME));
1329 else
1331 /* add correct extension (easier to always write)
1332 at this point, p2 points to 0 or the extension dot */
1333 *p2 = '\0';
1334 strcat(filepreset,".fmr");
1335 bad_file_name = false;
1336 radio_save_presets();
1339 else
1341 /* user aborted */
1342 return false;
1346 else
1347 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
1349 return true;
1352 static int clear_preset_list(void)
1354 /* Clear all the preset entries */
1355 memset(presets, 0, sizeof (presets));
1357 num_presets = 0;
1358 presets_loaded = false;
1359 /* The preset list will be cleared switch to Scan Mode. */
1360 radio_mode = RADIO_SCAN_MODE;
1361 curr_preset = -1;
1363 presets_changed = false; /* Don't ask to save when clearing the list. */
1365 return true;
1368 MENUITEM_FUNCTION(radio_edit_preset_item, MENU_FUNC_CHECK_RETVAL,
1369 ID2P(LANG_FM_EDIT_PRESET),
1370 radio_edit_preset, NULL, NULL, Icon_NOICON);
1371 MENUITEM_FUNCTION(radio_delete_preset_item, MENU_FUNC_CHECK_RETVAL,
1372 ID2P(LANG_FM_DELETE_PRESET),
1373 radio_delete_preset, NULL, NULL, Icon_NOICON);
1374 static int radio_preset_callback(int action,
1375 const struct menu_item_ex *this_item)
1377 if (action == ACTION_STD_OK)
1378 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1379 return action;
1380 (void)this_item;
1382 MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_PRESET),
1383 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
1384 &radio_delete_preset_item);
1385 /* present a list of preset stations */
1386 static const char* presets_get_name(int selected_item, void *data,
1387 char *buffer, size_t buffer_len)
1389 (void)data;
1390 struct fmstation *p = &presets[selected_item];
1391 if(p->name[0])
1392 return p->name;
1393 int freq = p->frequency / 10000;
1394 int frac = freq % 100;
1395 freq /= 100;
1396 snprintf(buffer, buffer_len,
1397 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1398 return buffer;
1401 static int presets_speak_name(int selected_item, void * data)
1403 (void)data;
1404 talk_preset(selected_item, true, false);
1405 return 0;
1408 static int handle_radio_presets(void)
1410 struct gui_synclist lists;
1411 int result = 0;
1412 int action = ACTION_NONE;
1413 #ifdef HAVE_BUTTONBAR
1414 struct gui_buttonbar buttonbar;
1415 #endif
1417 if(presets_loaded == false)
1418 return result;
1420 #ifdef HAVE_BUTTONBAR
1421 gui_buttonbar_init(&buttonbar);
1422 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
1423 gui_buttonbar_set(&buttonbar, str(LANG_FM_BUTTONBAR_ADD),
1424 str(LANG_FM_BUTTONBAR_EXIT),
1425 str(LANG_FM_BUTTONBAR_ACTION));
1426 gui_buttonbar_draw(&buttonbar);
1427 #endif
1428 gui_synclist_init(&lists, presets_get_name, NULL, false, 1, NULL);
1429 gui_synclist_set_title(&lists, str(LANG_PRESET), NOICON);
1430 gui_synclist_set_icon_callback(&lists, NULL);
1431 if(global_settings.talk_file)
1432 gui_synclist_set_voice_callback(&lists, presets_speak_name);
1433 gui_synclist_set_nb_items(&lists, num_presets);
1434 gui_synclist_select_item(&lists, curr_preset<0 ? 0 : curr_preset);
1435 gui_synclist_speak_item(&lists);
1437 while (result == 0)
1439 gui_synclist_draw(&lists);
1440 list_do_action(CONTEXT_STD, TIMEOUT_BLOCK,
1441 &lists, &action, LIST_WRAP_UNLESS_HELD);
1442 switch (action)
1444 case ACTION_STD_MENU:
1445 if (radio_add_preset())
1447 gui_synclist_set_nb_items(&lists, num_presets);
1448 gui_synclist_select_item(&lists, num_presets - 1);
1450 break;
1451 case ACTION_STD_CANCEL:
1452 result = 1;
1453 break;
1454 case ACTION_STD_OK:
1455 curr_preset = gui_synclist_get_sel_pos(&lists);
1456 curr_freq = presets[curr_preset].frequency;
1457 next_station(0);
1458 remember_frequency();
1459 result = 1;
1460 break;
1461 case ACTION_F3:
1462 case ACTION_STD_CONTEXT:
1463 selected_preset = gui_synclist_get_sel_pos(&lists);
1464 do_menu(&handle_radio_preset_menu, NULL, NULL, false);
1465 gui_synclist_set_nb_items(&lists, num_presets);
1466 gui_synclist_select_item(&lists, selected_preset);
1467 gui_synclist_speak_item(&lists);
1468 break;
1469 default:
1470 if(default_event_handler(action) == SYS_USB_CONNECTED)
1471 result = 2;
1474 gui_synclist_scroll_stop(&lists);
1475 return result - 1;
1478 void toggle_mono_mode(bool mono)
1480 tuner_set(RADIO_FORCE_MONO, mono);
1483 void set_radio_region(int region)
1485 #ifdef HAVE_RADIO_REGION
1486 tuner_set(RADIO_REGION, region);
1487 #endif
1488 next_station(0);
1489 remember_frequency();
1490 (void)region;
1493 MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL);
1494 MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL);
1496 #ifndef FM_MODE
1497 static char* get_mode_text(int selected_item, void * data, char *buffer)
1499 (void)selected_item;
1500 (void)data;
1501 snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE),
1502 radio_mode ? str(LANG_PRESET) :
1503 str(LANG_RADIO_SCAN_MODE));
1504 return buffer;
1506 static int toggle_radio_mode(void)
1508 radio_mode = (radio_mode == RADIO_SCAN_MODE) ?
1509 RADIO_PRESET_MODE : RADIO_SCAN_MODE;
1510 return 0;
1512 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0,
1513 toggle_radio_mode, NULL,
1514 get_mode_text, NULL, NULL, NULL, Icon_NOICON);
1515 #endif
1517 static int scan_presets(void *viewports)
1519 bool do_scan = true;
1520 int i;
1521 struct viewport *vp = (struct viewport *)viewports;
1523 FOR_NB_SCREENS(i)
1524 screens[i].set_viewport(vp?&vp[i]:NULL);
1525 if(num_presets > 0) /* Do that to avoid 2 questions. */
1526 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1528 if(do_scan)
1530 const struct fm_region_data * const fmr =
1531 &fm_region_data[global_settings.fm_region];
1533 curr_freq = fmr->freq_min;
1534 num_presets = 0;
1535 memset(presets, 0, sizeof(presets));
1537 tuner_set(RADIO_MUTE, 1);
1539 while(curr_freq <= fmr->freq_max)
1541 int freq, frac;
1542 if(num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1543 break;
1545 freq = curr_freq / 10000;
1546 frac = freq % 100;
1547 freq /= 100;
1549 splashf(0, str(LANG_FM_SCANNING), freq, frac);
1551 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
1553 /* add preset */
1554 presets[num_presets].name[0] = '\0';
1555 presets[num_presets].frequency = curr_freq;
1556 num_presets++;
1559 curr_freq += fmr->freq_step;
1562 if (radio_status == FMRADIO_PLAYING)
1563 tuner_set(RADIO_MUTE, 0);
1565 presets_changed = true;
1567 FOR_NB_SCREENS(i)
1569 screens[i].clear_viewport();
1570 screens[i].update_viewport();
1573 if(num_presets > 0)
1575 curr_freq = presets[0].frequency;
1576 radio_mode = RADIO_PRESET_MODE;
1577 presets_loaded = true;
1578 next_station(0);
1580 else
1582 /* Wrap it to beginning or we'll be past end of band */
1583 presets_loaded = false;
1584 next_station(1);
1587 return true;
1591 #ifdef HAVE_RECORDING
1593 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1594 #define FM_RECORDING_SCREEN
1595 static int fm_recording_screen(void)
1597 bool ret;
1599 /* switch recording source to FMRADIO for the duration */
1600 int rec_source = global_settings.rec_source;
1601 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1602 ret = recording_screen(true);
1604 /* safe to reset as changing sources is prohibited here */
1605 global_settings.rec_source = rec_source;
1607 return ret;
1610 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1612 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1613 #define FM_RECORDING_SETTINGS
1614 static int fm_recording_settings(void)
1616 bool ret = recording_menu(true);
1618 #if CONFIG_CODEC != SWCODEC
1619 if (!ret)
1621 struct audio_recording_options rec_options;
1622 rec_init_recording_options(&rec_options);
1623 rec_options.rec_source = AUDIO_SRC_LINEIN;
1624 rec_set_recording_options(&rec_options);
1626 #endif
1628 return ret;
1631 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1632 #endif /* HAVE_RECORDING */
1634 #ifdef FM_RECORDING_SCREEN
1635 MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING),
1636 fm_recording_screen, NULL, NULL, Icon_Recording);
1637 #endif
1638 #ifdef FM_RECORDING_SETTINGS
1639 MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS),
1640 fm_recording_settings, NULL, NULL, Icon_Recording);
1641 #endif
1642 #ifndef FM_PRESET
1643 MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET),
1644 handle_radio_presets, NULL, NULL, Icon_NOICON);
1645 #endif
1646 #ifndef FM_PRESET_ADD
1647 MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET),
1648 radio_add_preset, NULL, NULL, Icon_NOICON);
1649 #endif
1652 MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD),
1653 load_preset_list, NULL, NULL, Icon_NOICON);
1654 MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE),
1655 save_preset_list, NULL, NULL, Icon_NOICON);
1656 MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR),
1657 clear_preset_list, NULL, NULL, Icon_NOICON);
1658 MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM,
1659 ID2P(LANG_FM_SCAN_PRESETS),
1660 scan_presets, NULL, NULL, Icon_NOICON);
1662 MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1663 Icon_Radio_screen,
1664 #ifndef FM_PRESET
1665 &radio_presets_item,
1666 #endif
1667 #ifndef FM_PRESET_ADD
1668 &radio_addpreset_item,
1669 #endif
1670 &presetload_item, &presetsave_item, &presetclear_item,
1671 &force_mono,
1672 #ifndef FM_MODE
1673 &radio_mode_item,
1674 #endif
1675 &set_region, &sound_settings,
1676 #ifdef FM_RECORDING_SCREEN
1677 &recscreen_item,
1678 #endif
1679 #ifdef FM_RECORDING_SETTINGS
1680 &recsettings_item,
1681 #endif
1682 &scan_presets_item);
1683 /* main menu of the radio screen */
1684 static bool radio_menu(void)
1686 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1687 MENU_ATTACHED_USB;
1690 #endif