Update Esperanto and add Slovak languages:
[kugel-rb.git] / apps / recorder / radio.c
blobd072cf6cde56d36d6d0b0f34394e3f4d52a9af84
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"
71 #if CONFIG_TUNER
73 #if CONFIG_KEYPAD == RECORDER_PAD
74 #define FM_RECORD
75 #define FM_PRESET_ADD
76 #define FM_PRESET_ACTION
77 #define FM_PRESET
78 #define FM_MODE
80 #elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD)
81 #define FM_PRESET
82 #define FM_MODE
83 #define FM_NEXT_PRESET
84 #define FM_PREV_PRESET
86 #elif CONFIG_KEYPAD == IRIVER_H10_PAD
87 #define FM_PRESET
88 #define FM_MODE
90 #elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
91 #define FM_PRESET
92 #define FM_MODE
93 /* This should be removeable if the whole tuning thing is sorted out since
94 proper tuning quiets the screen almost entirely in that extreme measures
95 have to be taken to hear any interference. */
96 #define HAVE_NOISY_IDLE_MODE
98 #elif CONFIG_KEYPAD == ONDIO_PAD
99 #define FM_RECORD_DBLPRE
100 #define FM_RECORD
101 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || (CONFIG_KEYPAD == SANSA_C200_PAD)
102 #define FM_MENU
103 #define FM_PRESET
104 #define FM_STOP
105 #define FM_MODE
106 #define FM_EXIT
107 #define FM_PLAY
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_MENU
115 #define FM_PRESET
116 #define FM_STOP
117 #define FM_MODE
118 #define FM_EXIT
119 #define FM_PLAY
121 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
122 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
123 #define FM_MENU
124 #define FM_STOP
125 #define FM_EXIT
126 #define FM_PLAY
127 #define FM_MODE
129 #endif
131 #define RADIO_SCAN_MODE 0
132 #define RADIO_PRESET_MODE 1
134 static int curr_preset = -1;
135 static int curr_freq; /* current frequency in Hz */
136 static int radio_mode = RADIO_SCAN_MODE;
137 static int search_dir = 0;
139 static int radio_status = FMRADIO_OFF;
140 static bool in_screen = false;
142 #define MAX_PRESETS 64
143 static bool presets_loaded = false, presets_changed = false;
144 static struct fmstation presets[MAX_PRESETS];
146 static char filepreset[MAX_PATH]; /* preset filename variable */
148 static int num_presets = 0; /* The number of presets in the preset list */
150 static void radio_save_presets(void);
151 static int handle_radio_presets(void);
152 static bool radio_menu(void);
153 static int radio_add_preset(void);
154 static int save_preset_list(void);
155 static int load_preset_list(void);
156 static int clear_preset_list(void);
158 static int scan_presets(void *viewports);
160 /* Function to manipulate all yesno dialogues.
161 This function needs the output text as an argument. */
162 static bool yesno_pop(const char* text)
164 int i;
165 const char *lines[]={text};
166 const struct text_message message={lines, 1};
167 bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES);
168 FOR_NB_SCREENS(i)
169 screens[i].clear_viewport();
170 return ret;
173 void radio_init(void)
175 tuner_init();
176 radio_stop();
179 int get_radio_status(void)
181 return radio_status;
184 bool in_radio_screen(void)
186 return in_screen;
189 /* TODO: Move some more of the control functionality to firmware
190 and clean up the mess */
192 /* secret flag for starting paused - prevents unmute */
193 #define FMRADIO_START_PAUSED 0x8000
194 void radio_start(void)
196 const struct fm_region_data *fmr;
197 bool start_paused;
199 if(radio_status == FMRADIO_PLAYING)
200 return;
202 fmr = &fm_region_data[global_settings.fm_region];
204 start_paused = radio_status & FMRADIO_START_PAUSED;
205 /* clear flag before any yielding */
206 radio_status &= ~FMRADIO_START_PAUSED;
208 if(radio_status == FMRADIO_OFF)
209 tuner_power(true);
211 curr_freq = global_status.last_frequency * fmr->freq_step + fmr->freq_min;
213 tuner_set(RADIO_SLEEP, 0); /* wake up the tuner */
215 if(radio_status == FMRADIO_OFF)
217 #ifdef HAVE_RADIO_REGION
218 tuner_set(RADIO_REGION, global_settings.fm_region);
219 #endif
220 tuner_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
223 tuner_set(RADIO_FREQUENCY, curr_freq);
225 #ifdef HAVE_RADIO_MUTE_TIMEOUT
227 unsigned long mute_timeout = current_tick + HZ;
228 if (radio_status != FMRADIO_OFF)
230 /* paused */
231 mute_timeout += HZ;
234 while(!tuner_get(RADIO_STEREO) && !tuner_get(RADIO_TUNED))
236 if(TIME_AFTER(current_tick, mute_timeout))
237 break;
238 yield();
241 #endif
243 /* keep radio from sounding initially */
244 if(!start_paused)
245 tuner_set(RADIO_MUTE, 0);
247 radio_status = FMRADIO_PLAYING;
248 } /* radio_start */
250 void radio_pause(void)
252 if(radio_status == FMRADIO_PAUSED)
253 return;
255 if(radio_status == FMRADIO_OFF)
257 radio_status |= FMRADIO_START_PAUSED;
258 radio_start();
261 tuner_set(RADIO_MUTE, 1);
262 tuner_set(RADIO_SLEEP, 1);
264 radio_status = FMRADIO_PAUSED;
265 } /* radio_pause */
267 void radio_stop(void)
269 if(radio_status == FMRADIO_OFF)
270 return;
272 tuner_set(RADIO_MUTE, 1);
273 tuner_set(RADIO_SLEEP, 1); /* low power mode, if available */
274 radio_status = FMRADIO_OFF;
275 tuner_power(false); /* status update, power off if avail. */
276 } /* radio_stop */
278 bool radio_hardware_present(void)
280 return tuner_get(RADIO_PRESENT);
283 /* Keep freq on the grid for the current region */
284 static int snap_freq_to_grid(int freq)
286 const struct fm_region_data * const fmr =
287 &fm_region_data[global_settings.fm_region];
289 /* Range clamp if out of range or just round to nearest */
290 if (freq < fmr->freq_min)
291 freq = fmr->freq_min;
292 else if (freq > fmr->freq_max)
293 freq = fmr->freq_max;
294 else
295 freq = (freq - fmr->freq_min + fmr->freq_step/2) /
296 fmr->freq_step * fmr->freq_step + fmr->freq_min;
298 return freq;
301 /* Find a matching preset to freq */
302 static int find_preset(int freq)
304 int i;
305 if(num_presets < 1)
306 return -1;
307 for(i = 0;i < MAX_PRESETS;i++)
309 if(freq == presets[i].frequency)
310 return i;
313 return -1;
316 /* Return the closest preset encountered in the search direction with
317 wraparound. */
318 static int find_closest_preset(int freq, int direction)
320 int i;
321 int lowpreset = 0;
322 int highpreset = 0;
323 int closest = -1;
325 if (direction == 0) /* direction == 0 isn't really used */
326 return 0;
328 for (i = 0; i < num_presets; i++)
330 int f = presets[i].frequency;
331 if (f == freq)
332 return i; /* Exact match = stop */
334 /* remember the highest and lowest presets for wraparound */
335 if (f < presets[lowpreset].frequency)
336 lowpreset = i;
337 if (f > presets[highpreset].frequency)
338 highpreset = i;
340 /* find the closest preset in the given direction */
341 if (direction > 0 && f > freq)
343 if (closest < 0 || f < presets[closest].frequency)
344 closest = i;
346 else if (direction < 0 && f < freq)
348 if (closest < 0 || f > presets[closest].frequency)
349 closest = i;
353 if (closest < 0)
355 /* no presets in the given direction */
356 /* wrap around depending on direction */
357 if (direction < 0)
358 closest = highpreset;
359 else
360 closest = lowpreset;
363 return closest;
366 static void remember_frequency(void)
368 const struct fm_region_data * const fmr =
369 &fm_region_data[global_settings.fm_region];
370 global_status.last_frequency = (curr_freq - fmr->freq_min)
371 / fmr->freq_step;
372 status_save();
375 static void next_preset(int direction)
377 if (num_presets < 1)
378 return;
380 if (curr_preset == -1)
381 curr_preset = find_closest_preset(curr_freq, direction);
382 else
383 curr_preset = (curr_preset + direction + num_presets) % num_presets;
385 /* Must stay on the current grid for the region */
386 curr_freq = snap_freq_to_grid(presets[curr_preset].frequency);
388 tuner_set(RADIO_FREQUENCY, curr_freq);
389 remember_frequency();
392 /* Step to the next or previous frequency */
393 static int step_freq(int freq, int direction)
395 const struct fm_region_data * const fmr =
396 &fm_region_data[global_settings.fm_region];
398 freq += direction*fmr->freq_step;
400 /* Wrap first or snapping to grid will not let us on the band extremes */
401 if (freq > fmr->freq_max)
402 freq = direction > 0 ? fmr->freq_min : fmr->freq_max;
403 else if (freq < fmr->freq_min)
404 freq = direction < 0 ? fmr->freq_max : fmr->freq_min;
405 else
406 freq = snap_freq_to_grid(freq);
408 return freq;
411 /* Step to the next or previous station */
412 static void next_station(int direction)
414 if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
416 next_preset(direction);
417 return;
420 curr_freq = step_freq(curr_freq, direction);
422 if (radio_status == FMRADIO_PLAYING)
423 tuner_set(RADIO_MUTE, 1);
425 tuner_set(RADIO_FREQUENCY, curr_freq);
427 if (radio_status == FMRADIO_PLAYING)
428 tuner_set(RADIO_MUTE, 0);
430 curr_preset = find_preset(curr_freq);
431 remember_frequency();
434 /* Ends an in-progress search */
435 static void end_search(void)
437 if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
438 tuner_set(RADIO_MUTE, 0);
439 search_dir = 0;
442 /* Speak a frequency. */
443 static void talk_freq(int freq, bool enqueue)
445 freq /= 10000;
446 talk_number(freq / 100, enqueue);
447 talk_id(LANG_POINT, true);
448 talk_number(freq % 100 / 10, true);
449 if (freq % 10)
450 talk_number(freq % 10, true);
453 /* Speak a preset by number or by spelling its name, depending on settings. */
454 static void talk_preset(int preset, bool fallback, bool enqueue)
456 if (global_settings.talk_file == 1) /* number */
457 talk_number(preset + 1, enqueue);
458 else
459 { /* spell */
460 if(presets[preset].name[0])
461 talk_spell(presets[preset].name, enqueue);
462 else if(fallback)
463 talk_freq(presets[preset].frequency, enqueue);
467 int radio_screen(void)
469 char buf[MAX_PATH];
470 bool done = false;
471 int ret_val = GO_TO_ROOT;
472 int button;
473 int i;
474 bool stereo = false, last_stereo = false;
475 int fh;
476 int top_of_screen = 0;
477 bool update_screen = true;
478 bool screen_freeze = false;
479 bool keep_playing = false;
480 bool talk = false;
481 #ifdef FM_RECORD_DBLPRE
482 int lastbutton = BUTTON_NONE;
483 unsigned long rec_lastclick = 0;
484 #endif
485 #if CONFIG_CODEC != SWCODEC
486 bool have_recorded = false;
487 int timeout = current_tick + HZ/10;
488 unsigned int seconds = 0;
489 unsigned int last_seconds = 0;
490 int hours, minutes;
491 struct audio_recording_options rec_options;
492 #endif /* CONFIG_CODEC != SWCODEC */
493 #ifndef HAVE_NOISY_IDLE_MODE
494 int button_timeout = current_tick + (2*HZ);
495 #endif
496 struct viewport vp[NB_SCREENS];
497 #ifdef HAVE_BUTTONBAR
498 struct gui_buttonbar buttonbar;
499 gui_buttonbar_init(&buttonbar);
500 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
501 #endif
503 /* change status to "in screen" */
504 in_screen = true;
506 /* always display status bar in radio screen for now */
507 FOR_NB_SCREENS(i)
509 viewport_set_defaults(&vp[i], i);
510 #ifdef HAVE_BUTTONBAR
511 if (global_settings.buttonbar)
512 vp[i].height -= BUTTONBAR_HEIGHT;
513 #endif
514 screens[i].set_viewport(&vp[i]);
515 screens[i].stop_scroll();
516 screens[i].clear_viewport();
517 screens[i].update_viewport();
520 fh = font_get(FONT_UI)->height;
522 /* Adjust for font size, trying to center the information vertically */
523 if(fh < 10)
524 top_of_screen = 1;
526 if(num_presets <= 0)
528 radio_load_presets(global_settings.fmr_file);
531 if(radio_status == FMRADIO_OFF)
532 audio_stop();
533 #ifndef SIMULATOR
535 #if CONFIG_CODEC != SWCODEC
536 if(rec_create_directory() > 0)
537 have_recorded = true;
539 audio_init_recording(talk_get_bufsize());
541 sound_settings_apply();
542 /* Yes, we use the D/A for monitoring */
543 peak_meter_playback(true);
545 peak_meter_enabled = true;
547 rec_init_recording_options(&rec_options);
548 rec_options.rec_source = AUDIO_SRC_LINEIN;
549 rec_set_recording_options(&rec_options);
551 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
552 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
554 #endif /* CONFIG_CODEC != SWCODEC */
555 #endif /* ndef SIMULATOR */
557 /* turn on radio */
558 #if CONFIG_CODEC == SWCODEC
559 audio_set_input_source(AUDIO_SRC_FMRADIO,
560 (radio_status == FMRADIO_PAUSED) ?
561 SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
562 #else
563 if (radio_status == FMRADIO_OFF)
564 radio_start();
565 #endif
567 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
568 scan_presets(vp);
570 curr_preset = find_preset(curr_freq);
571 if(curr_preset != -1)
572 radio_mode = RADIO_PRESET_MODE;
574 #ifdef HAVE_BUTTONBAR
575 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
576 str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD));
577 #endif
579 #ifndef HAVE_NOISY_IDLE_MODE
580 cpu_idle_mode(true);
581 #endif
583 while(!done)
585 if(search_dir != 0)
587 curr_freq = step_freq(curr_freq, search_dir);
588 update_screen = true;
590 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
592 curr_preset = find_preset(curr_freq);
593 remember_frequency();
594 end_search();
595 talk = true;
597 trigger_cpu_boost();
600 if (!update_screen)
602 cancel_cpu_boost();
605 #if CONFIG_CODEC != SWCODEC
606 /* TODO: Can we timeout at HZ when recording since peaks aren't
607 displayed? This should quiet recordings too. */
608 button = get_action(CONTEXT_FM,
609 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
610 #else
611 button = get_action(CONTEXT_FM,
612 update_screen ? TIMEOUT_NOBLOCK : HZ);
613 #endif
615 #ifndef HAVE_NOISY_IDLE_MODE
616 if (button != ACTION_NONE)
618 cpu_idle_mode(false);
619 button_timeout = current_tick + (2*HZ);
621 #endif
622 switch(button)
624 case ACTION_FM_STOP:
625 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
626 if(audio_status() == AUDIO_STATUS_RECORD)
628 audio_stop();
630 else
631 #endif
633 done = true;
634 if(presets_changed)
636 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
638 if(filepreset[0] == '\0')
639 save_preset_list();
640 else
641 radio_save_presets();
644 /* Clear the preset list on exit. */
645 clear_preset_list();
647 update_screen = true;
648 break;
650 #ifdef FM_RECORD
651 case ACTION_FM_RECORD:
652 #ifdef FM_RECORD_DBLPRE
653 if (lastbutton != ACTION_FM_RECORD_DBLPRE)
655 rec_lastclick = 0;
656 break;
658 if (current_tick - rec_lastclick > HZ/2)
660 rec_lastclick = current_tick;
661 break;
663 #endif /* FM_RECORD_DBLPRE */
664 #ifndef SIMULATOR
665 if(audio_status() == AUDIO_STATUS_RECORD)
667 rec_command(RECORDING_CMD_START_NEWFILE);
668 update_screen = true;
670 else
672 have_recorded = true;
673 rec_command(RECORDING_CMD_START);
674 update_screen = true;
676 #endif /* SIMULATOR */
677 last_seconds = 0;
678 break;
679 #endif /* #ifdef FM_RECORD */
681 case ACTION_FM_EXIT:
682 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
683 if(audio_status() == AUDIO_STATUS_RECORD)
684 audio_stop();
685 #endif
686 keep_playing = true;
687 done = true;
688 ret_val = GO_TO_ROOT;
689 if(presets_changed)
691 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
693 if(filepreset[0] == '\0')
694 save_preset_list();
695 else
696 radio_save_presets();
700 /* Clear the preset list on exit. */
701 clear_preset_list();
703 break;
705 case ACTION_STD_PREV:
706 case ACTION_STD_NEXT:
707 next_station(button == ACTION_STD_PREV ? -1 : 1);
708 end_search();
709 update_screen = true;
710 talk = true;
711 break;
713 case ACTION_STD_PREVREPEAT:
714 case ACTION_STD_NEXTREPEAT:
716 int dir = search_dir;
717 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
718 if (radio_mode != RADIO_SCAN_MODE)
720 next_preset(search_dir);
721 end_search();
722 update_screen = true;
723 talk = true;
725 else if (dir == 0)
727 /* Starting auto scan */
728 tuner_set(RADIO_MUTE, 1);
729 update_screen = true;
731 break;
734 case ACTION_SETTINGS_INC:
735 case ACTION_SETTINGS_INCREPEAT:
736 global_settings.volume++;
737 setvol();
738 update_screen = true;
739 break;
741 case ACTION_SETTINGS_DEC:
742 case ACTION_SETTINGS_DECREPEAT:
743 global_settings.volume--;
744 setvol();
745 update_screen = true;
746 break;
748 case ACTION_FM_PLAY:
749 if (radio_status == FMRADIO_PLAYING)
750 radio_pause();
751 else
752 radio_start();
754 update_screen = true;
755 talk = false;
756 talk_shutup();
757 break;
759 case ACTION_FM_MENU:
760 FOR_NB_SCREENS(i)
762 screens[i].scroll_stop(&vp[i]);
764 radio_menu();
765 curr_preset = find_preset(curr_freq);
766 FOR_NB_SCREENS(i)
768 screens[i].set_viewport(&vp[i]);
769 screens[i].clear_viewport();
770 screens[i].update_viewport();
771 screens[i].set_viewport(NULL);
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 FOR_NB_SCREENS(i)
789 screens[i].set_viewport(&vp[i]);
790 screens[i].clear_viewport();
791 screens[i].update_viewport();
792 screens[i].set_viewport(NULL);
795 break;
797 handle_radio_presets();
798 FOR_NB_SCREENS(i)
800 screens[i].set_viewport(&vp[i]);
801 screens[i].stop_scroll();
802 screens[i].clear_viewport();
803 screens[i].update_viewport();
804 screens[i].set_viewport(NULL);
806 #ifdef HAVE_BUTTONBAR
807 gui_buttonbar_set(&buttonbar,
808 str(LANG_BUTTONBAR_MENU),
809 str(LANG_PRESET),
810 str(LANG_FM_BUTTONBAR_RECORD));
811 #endif
812 update_screen = true;
813 break;
814 #endif /* FM_PRESET */
816 #ifdef FM_FREEZE
817 case ACTION_FM_FREEZE:
818 if(!screen_freeze)
820 splash(HZ, str(LANG_FM_FREEZE));
821 screen_freeze = true;
823 else
825 update_screen = true;
826 screen_freeze = false;
828 break;
829 #endif /* FM_FREEZE */
831 case SYS_USB_CONNECTED:
832 #if CONFIG_CODEC != SWCODEC
833 /* Only accept USB connection when not recording */
834 if(audio_status() != AUDIO_STATUS_RECORD)
835 #endif
837 default_event_handler(SYS_USB_CONNECTED);
838 screen_freeze = true; /* Cosmetic: makes sure the
839 radio screen doesn't redraw */
840 done = true;
842 break;
844 #ifdef FM_MODE
845 case ACTION_FM_MODE:
846 if(radio_mode == RADIO_SCAN_MODE)
848 /* Force scan mode if there are no presets. */
849 if(num_presets > 0)
850 radio_mode = RADIO_PRESET_MODE;
852 else
853 radio_mode = RADIO_SCAN_MODE;
854 update_screen = true;
855 cond_talk_ids_fq(radio_mode ?
856 LANG_PRESET : LANG_RADIO_SCAN_MODE);
857 talk = true;
858 break;
859 #endif /* FM_MODE */
861 #ifdef FM_NEXT_PRESET
862 case ACTION_FM_NEXT_PRESET:
863 next_preset(1);
864 end_search();
865 update_screen = true;
866 talk = true;
867 break;
868 #endif
870 #ifdef FM_PREV_PRESET
871 case ACTION_FM_PREV_PRESET:
872 next_preset(-1);
873 end_search();
874 update_screen = true;
875 talk = true;
876 break;
877 #endif
879 default:
880 default_event_handler(button);
881 #ifdef HAVE_RDS_CAP
882 if (tuner_get(RADIO_EVENT))
883 update_screen = true;
884 #endif
885 if (!tuner_get(RADIO_PRESENT))
887 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
888 if(audio_status() == AUDIO_STATUS_RECORD)
889 audio_stop();
890 #endif
891 keep_playing = false;
892 done = true;
893 ret_val = GO_TO_ROOT;
894 if(presets_changed)
896 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
898 if(filepreset[0] == '\0')
899 save_preset_list();
900 else
901 radio_save_presets();
905 /* Clear the preset list on exit. */
906 clear_preset_list();
908 break;
909 } /*switch(button)*/
911 #ifdef FM_RECORD_DBLPRE
912 if (button != ACTION_NONE)
913 lastbutton = button;
914 #endif
916 #if CONFIG_CODEC != SWCODEC
917 peak_meter_peek();
918 #endif
920 if(!screen_freeze)
922 /* Only display the peak meter when not recording */
923 #if CONFIG_CODEC != SWCODEC
924 if(!audio_status())
926 FOR_NB_SCREENS(i)
928 screens[i].set_viewport(&vp[i]);
929 peak_meter_screen(&screens[i],0, fh*(top_of_screen + 4),fh);
930 screens[i].update_rect(0, fh*(top_of_screen + 4),
931 screens[i].getwidth(), fh);
932 screens[i].set_viewport(NULL);
936 if(TIME_AFTER(current_tick, timeout))
938 timeout = current_tick + HZ;
939 #else /* SWCODEC */
941 #endif /* CONFIG_CODEC == SWCODEC */
943 /* keep "mono" from always being displayed when paused */
944 if (radio_status != FMRADIO_PAUSED)
946 stereo = tuner_get(RADIO_STEREO) &&
947 !global_settings.fm_force_mono;
949 if(stereo != last_stereo)
951 update_screen = true;
952 last_stereo = stereo;
957 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
958 seconds = audio_recorded_time() / HZ;
959 if (update_screen || seconds > last_seconds)
961 last_seconds = seconds;
962 #else
963 if (update_screen)
965 #endif
966 int freq;
968 FOR_NB_SCREENS(i)
970 screens[i].set_viewport(&vp[i]);
973 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
974 curr_preset + 1, presets[curr_preset].name);
976 FOR_NB_SCREENS(i)
977 screens[i].puts_scroll(0, top_of_screen, buf);
979 freq = curr_freq / 10000;
980 snprintf(buf, 128, str(LANG_FM_STATION),
981 freq / 100, freq % 100);
982 FOR_NB_SCREENS(i)
983 screens[i].puts_scroll(0, top_of_screen + 1, buf);
985 FOR_NB_SCREENS(i)
986 screens[i].puts_scroll(0, top_of_screen + 2,
987 stereo ? str(LANG_CHANNEL_STEREO) :
988 str(LANG_CHANNEL_MONO));
990 snprintf(buf, 128, "%s %s", str(LANG_MODE),
991 radio_mode ? str(LANG_PRESET) :
992 str(LANG_RADIO_SCAN_MODE));
993 FOR_NB_SCREENS(i)
994 screens[i].puts_scroll(0, top_of_screen + 3, buf);
995 #ifndef SIMULATOR
996 #ifdef HAVE_RDS_CAP
997 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME));
998 FOR_NB_SCREENS(i)
999 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1001 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_TEXT));
1002 FOR_NB_SCREENS(i)
1003 screens[i].puts_scroll(0, top_of_screen + 5, buf);
1004 #endif
1005 #endif /* SIMULATOR */
1007 #if CONFIG_CODEC != SWCODEC
1008 if(audio_status() == AUDIO_STATUS_RECORD)
1010 hours = seconds / 3600;
1011 minutes = (seconds - (hours * 3600)) / 60;
1012 snprintf(buf, 32, "%s %02d:%02d:%02d",
1013 str(LANG_RECORDING_TIME),
1014 hours, minutes, seconds%60);
1015 FOR_NB_SCREENS(i)
1016 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1018 else
1020 if(rec_options.rec_prerecord_time)
1022 snprintf(buf, 32, "%s %02d",
1023 str(LANG_RECORD_PRERECORD), seconds%60);
1024 FOR_NB_SCREENS(i)
1025 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1028 #endif /* CONFIG_CODEC != SWCODEC */
1030 FOR_NB_SCREENS(i)
1032 screens[i].update_viewport();
1033 screens[i].set_viewport(NULL);
1036 #ifdef HAVE_BUTTONBAR
1037 gui_buttonbar_draw(&buttonbar);
1038 #endif
1042 update_screen = false;
1044 if (global_settings.talk_file && talk
1045 && radio_status == FMRADIO_PAUSED)
1047 talk = false;
1048 bool enqueue = false;
1049 if (radio_mode == RADIO_SCAN_MODE)
1051 talk_freq(curr_freq, enqueue);
1052 enqueue = true;
1054 if (curr_preset >= 0)
1055 talk_preset(curr_preset, radio_mode == RADIO_PRESET_MODE,
1056 enqueue);
1059 #if CONFIG_CODEC != SWCODEC
1060 if(audio_status() & AUDIO_STATUS_ERROR)
1062 done = true;
1064 #endif
1066 #ifndef HAVE_NOISY_IDLE_MODE
1067 if (TIME_AFTER(current_tick, button_timeout))
1069 cpu_idle_mode(true);
1071 #endif
1072 } /*while(!done)*/
1074 #ifndef SIMULATOR
1075 #if CONFIG_CODEC != SWCODEC
1076 if(audio_status() & AUDIO_STATUS_ERROR)
1078 splash(0, str(LANG_DISK_FULL));
1079 FOR_NB_SCREENS(i)
1081 screens[i].set_viewport(&vp[i]);
1082 screens[i].update_viewport();
1083 screens[i].set_viewport(NULL);
1085 audio_error_clear();
1087 while(1)
1089 button = get_action(CONTEXT_FM, TIMEOUT_BLOCK);
1090 if(button == ACTION_FM_STOP)
1091 break;
1095 audio_init_playback();
1096 #endif /* CONFIG_CODEC != SWCODEC */
1098 sound_settings_apply();
1099 #endif /* SIMULATOR */
1101 if(keep_playing)
1103 /* Catch FMRADIO_PLAYING status for the sim. */
1104 #ifndef SIMULATOR
1105 #if CONFIG_CODEC != SWCODEC
1106 /* Enable the Left and right A/D Converter */
1107 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
1108 sound_default(SOUND_RIGHT_GAIN),
1109 AUDIO_GAIN_LINEIN);
1110 mas_codec_writereg(6, 0x4000);
1111 #endif
1112 end_search();
1113 #endif /* SIMULATOR */
1115 else
1117 #if CONFIG_CODEC == SWCODEC
1118 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1119 #else
1120 radio_stop();
1121 #endif
1124 #ifndef HAVE_NOISY_IDLE_MODE
1125 cpu_idle_mode(false);
1126 #endif
1127 FOR_NB_SCREENS(i)
1129 screens[i].scroll_stop(&vp[i]);
1131 in_screen = false;
1132 #if CONFIG_CODEC != SWCODEC
1133 return have_recorded;
1134 #else
1135 return false;
1136 #endif
1137 } /* radio_screen */
1139 static void radio_save_presets(void)
1141 int fd;
1142 int i;
1144 fd = creat(filepreset);
1145 if(fd >= 0)
1147 for(i = 0;i < num_presets;i++)
1149 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
1151 close(fd);
1153 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1154 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1155 presets_changed = false;
1157 else
1159 splash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1163 void radio_load_presets(char *filename)
1165 int fd;
1166 int rc;
1167 char buf[128];
1168 char *freq;
1169 char *name;
1170 bool done = false;
1171 int f;
1173 memset(presets, 0, sizeof(presets));
1174 num_presets = 0;
1176 /* No Preset in configuration. */
1177 if(filename[0] == '\0')
1179 filepreset[0] = '\0';
1180 return;
1182 /* Temporary preset, loaded until player shuts down. */
1183 else if(filename[0] == '/')
1184 strlcpy(filepreset, filename, sizeof(filepreset));
1185 /* Preset from default directory. */
1186 else
1187 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1188 FMPRESET_PATH, filename);
1190 fd = open_utf8(filepreset, O_RDONLY);
1191 if(fd >= 0)
1193 while(!done && num_presets < MAX_PRESETS)
1195 rc = read_line(fd, buf, 128);
1196 if(rc > 0)
1198 if(settings_parseline(buf, &freq, &name))
1200 f = atoi(freq);
1201 if(f) /* For backwards compatibility */
1203 struct fmstation * const fms = &presets[num_presets];
1204 fms->frequency = f;
1205 strlcpy(fms->name, name, MAX_FMPRESET_LEN+1);
1206 num_presets++;
1210 else
1211 done = true;
1213 close(fd);
1215 else /* invalid file name? */
1216 filepreset[0] = '\0';
1218 presets_loaded = num_presets > 0;
1219 presets_changed = false;
1223 static int radio_add_preset(void)
1225 char buf[MAX_FMPRESET_LEN + 1];
1227 if(num_presets < MAX_PRESETS)
1229 buf[0] = '\0';
1231 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1233 struct fmstation * const fms = &presets[num_presets];
1234 strcpy(fms->name, buf);
1235 fms->frequency = curr_freq;
1236 num_presets++;
1237 presets_changed = true;
1238 presets_loaded = num_presets > 0;
1239 return true;
1242 else
1244 splash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1246 return false;
1249 /* needed to know which preset we are edit/delete-ing */
1250 static int selected_preset = -1;
1251 static int radio_edit_preset(void)
1253 char buf[MAX_FMPRESET_LEN + 1];
1255 if (num_presets > 0)
1257 struct fmstation * const fms = &presets[selected_preset];
1259 strcpy(buf, fms->name);
1261 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1263 strcpy(fms->name, buf);
1264 presets_changed = true;
1268 return 1;
1271 static int radio_delete_preset(void)
1273 if (num_presets > 0)
1275 struct fmstation * const fms = &presets[selected_preset];
1277 if (selected_preset >= --num_presets)
1278 selected_preset = num_presets - 1;
1280 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1281 (uintptr_t)fms);
1283 if (curr_preset >= num_presets)
1284 --curr_preset;
1287 /* Don't ask to save when all presets are deleted. */
1288 presets_changed = num_presets > 0;
1290 if (!presets_changed)
1292 /* The preset list will be cleared, switch to Scan Mode. */
1293 radio_mode = RADIO_SCAN_MODE;
1294 curr_preset = -1;
1295 presets_loaded = false;
1298 return 1;
1301 static int load_preset_list(void)
1303 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1306 static int save_preset_list(void)
1308 if(num_presets > 0)
1310 bool bad_file_name = true;
1312 if(!dir_exists(FMPRESET_PATH)) /* Check if there is preset folder */
1313 mkdir(FMPRESET_PATH);
1315 create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
1316 ".fmr", 2 IF_CNFN_NUM_(, NULL));
1318 while(bad_file_name)
1320 if(!kbd_input(filepreset, sizeof(filepreset)))
1322 /* check the name: max MAX_FILENAME (20) chars */
1323 char* p2;
1324 char* p1;
1325 int len;
1326 p1 = strrchr(filepreset, '/');
1327 p2 = p1;
1328 while((p1) && (*p2) && (*p2 != '.'))
1329 p2++;
1330 len = (int)(p2-p1) - 1;
1331 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1333 /* no slash, too long or too short */
1334 splash(HZ, ID2P(LANG_INVALID_FILENAME));
1336 else
1338 /* add correct extension (easier to always write)
1339 at this point, p2 points to 0 or the extension dot */
1340 *p2 = '\0';
1341 strcat(filepreset,".fmr");
1342 bad_file_name = false;
1343 radio_save_presets();
1346 else
1348 /* user aborted */
1349 return false;
1353 else
1354 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
1356 return true;
1359 static int clear_preset_list(void)
1361 /* Clear all the preset entries */
1362 memset(presets, 0, sizeof (presets));
1364 num_presets = 0;
1365 presets_loaded = false;
1366 /* The preset list will be cleared switch to Scan Mode. */
1367 radio_mode = RADIO_SCAN_MODE;
1368 curr_preset = -1;
1370 presets_changed = false; /* Don't ask to save when clearing the list. */
1372 return true;
1375 MENUITEM_FUNCTION(radio_edit_preset_item, MENU_FUNC_CHECK_RETVAL,
1376 ID2P(LANG_FM_EDIT_PRESET),
1377 radio_edit_preset, NULL, NULL, Icon_NOICON);
1378 MENUITEM_FUNCTION(radio_delete_preset_item, MENU_FUNC_CHECK_RETVAL,
1379 ID2P(LANG_FM_DELETE_PRESET),
1380 radio_delete_preset, NULL, NULL, Icon_NOICON);
1381 static int radio_preset_callback(int action,
1382 const struct menu_item_ex *this_item)
1384 if (action == ACTION_STD_OK)
1385 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1386 return action;
1387 (void)this_item;
1389 MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_PRESET),
1390 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
1391 &radio_delete_preset_item);
1392 /* present a list of preset stations */
1393 static const char* presets_get_name(int selected_item, void *data,
1394 char *buffer, size_t buffer_len)
1396 (void)data;
1397 struct fmstation *p = &presets[selected_item];
1398 if(p->name[0])
1399 return p->name;
1400 int freq = p->frequency / 10000;
1401 int frac = freq % 100;
1402 freq /= 100;
1403 snprintf(buffer, buffer_len,
1404 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1405 return buffer;
1408 static int presets_speak_name(int selected_item, void * data)
1410 (void)data;
1411 talk_preset(selected_item, true, false);
1412 return 0;
1415 static int handle_radio_presets(void)
1417 struct gui_synclist lists;
1418 int result = 0;
1419 int action = ACTION_NONE;
1420 #ifdef HAVE_BUTTONBAR
1421 struct gui_buttonbar buttonbar;
1422 #endif
1424 if(presets_loaded == false)
1425 return result;
1427 #ifdef HAVE_BUTTONBAR
1428 gui_buttonbar_init(&buttonbar);
1429 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
1430 gui_buttonbar_set(&buttonbar, str(LANG_FM_BUTTONBAR_ADD),
1431 str(LANG_FM_BUTTONBAR_EXIT),
1432 str(LANG_FM_BUTTONBAR_ACTION));
1433 gui_buttonbar_draw(&buttonbar);
1434 #endif
1435 gui_synclist_init(&lists, presets_get_name, NULL, false, 1, NULL);
1436 gui_synclist_set_title(&lists, str(LANG_PRESET), NOICON);
1437 gui_synclist_set_icon_callback(&lists, NULL);
1438 if(global_settings.talk_file)
1439 gui_synclist_set_voice_callback(&lists, presets_speak_name);
1440 gui_synclist_set_nb_items(&lists, num_presets);
1441 gui_synclist_select_item(&lists, curr_preset<0 ? 0 : curr_preset);
1442 gui_synclist_speak_item(&lists);
1444 while (result == 0)
1446 gui_synclist_draw(&lists);
1447 list_do_action(CONTEXT_STD, TIMEOUT_BLOCK,
1448 &lists, &action, LIST_WRAP_UNLESS_HELD);
1449 switch (action)
1451 case ACTION_STD_MENU:
1452 if (radio_add_preset())
1454 gui_synclist_set_nb_items(&lists, num_presets);
1455 gui_synclist_select_item(&lists, num_presets - 1);
1457 break;
1458 case ACTION_STD_CANCEL:
1459 result = 1;
1460 break;
1461 case ACTION_STD_OK:
1462 curr_preset = gui_synclist_get_sel_pos(&lists);
1463 curr_freq = presets[curr_preset].frequency;
1464 next_station(0);
1465 remember_frequency();
1466 result = 1;
1467 break;
1468 case ACTION_F3:
1469 case ACTION_STD_CONTEXT:
1470 selected_preset = gui_synclist_get_sel_pos(&lists);
1471 do_menu(&handle_radio_preset_menu, NULL, NULL, false);
1472 gui_synclist_set_nb_items(&lists, num_presets);
1473 gui_synclist_select_item(&lists, selected_preset);
1474 gui_synclist_speak_item(&lists);
1475 break;
1476 default:
1477 if(default_event_handler(action) == SYS_USB_CONNECTED)
1478 result = 2;
1481 return result - 1;
1484 void toggle_mono_mode(bool mono)
1486 tuner_set(RADIO_FORCE_MONO, mono);
1489 void set_radio_region(int region)
1491 #ifdef HAVE_RADIO_REGION
1492 tuner_set(RADIO_REGION, region);
1493 #endif
1494 next_station(0);
1495 remember_frequency();
1496 (void)region;
1499 MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL);
1500 MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL);
1502 #ifndef FM_MODE
1503 static char* get_mode_text(int selected_item, void * data, char *buffer)
1505 (void)selected_item;
1506 (void)data;
1507 snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE),
1508 radio_mode ? str(LANG_PRESET) :
1509 str(LANG_RADIO_SCAN_MODE));
1510 return buffer;
1512 static int toggle_radio_mode(void)
1514 radio_mode = (radio_mode == RADIO_SCAN_MODE) ?
1515 RADIO_PRESET_MODE : RADIO_SCAN_MODE;
1516 return 0;
1518 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0,
1519 toggle_radio_mode, NULL,
1520 get_mode_text, NULL, NULL, NULL, Icon_NOICON);
1521 #endif
1523 static int scan_presets(void *viewports)
1525 bool do_scan = true;
1526 int i;
1527 struct viewport *vp = (struct viewport *)viewports;
1529 FOR_NB_SCREENS(i)
1530 screens[i].set_viewport(vp?&vp[i]:NULL);
1531 if(num_presets > 0) /* Do that to avoid 2 questions. */
1532 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1534 if(do_scan)
1536 const struct fm_region_data * const fmr =
1537 &fm_region_data[global_settings.fm_region];
1539 curr_freq = fmr->freq_min;
1540 num_presets = 0;
1541 memset(presets, 0, sizeof(presets));
1543 tuner_set(RADIO_MUTE, 1);
1545 while(curr_freq <= fmr->freq_max)
1547 int freq, frac;
1548 if(num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1549 break;
1551 freq = curr_freq / 10000;
1552 frac = freq % 100;
1553 freq /= 100;
1555 splashf(0, str(LANG_FM_SCANNING), freq, frac);
1557 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
1559 /* add preset */
1560 presets[num_presets].name[0] = '\0';
1561 presets[num_presets].frequency = curr_freq;
1562 num_presets++;
1565 curr_freq += fmr->freq_step;
1568 if (radio_status == FMRADIO_PLAYING)
1569 tuner_set(RADIO_MUTE, 0);
1571 presets_changed = true;
1573 FOR_NB_SCREENS(i)
1575 screens[i].clear_viewport();
1576 screens[i].update_viewport();
1579 if(num_presets > 0)
1581 curr_freq = presets[0].frequency;
1582 radio_mode = RADIO_PRESET_MODE;
1583 presets_loaded = true;
1584 next_station(0);
1586 else
1588 /* Wrap it to beginning or we'll be past end of band */
1589 presets_loaded = false;
1590 next_station(1);
1593 return true;
1597 #ifdef HAVE_RECORDING
1599 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1600 #define FM_RECORDING_SCREEN
1601 static int fm_recording_screen(void)
1603 bool ret;
1605 /* switch recording source to FMRADIO for the duration */
1606 int rec_source = global_settings.rec_source;
1607 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1608 ret = recording_screen(true);
1610 /* safe to reset as changing sources is prohibited here */
1611 global_settings.rec_source = rec_source;
1613 return ret;
1616 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1618 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1619 #define FM_RECORDING_SETTINGS
1620 static int fm_recording_settings(void)
1622 bool ret = recording_menu(true);
1624 #if CONFIG_CODEC != SWCODEC
1625 if (!ret)
1627 struct audio_recording_options rec_options;
1628 rec_init_recording_options(&rec_options);
1629 rec_options.rec_source = AUDIO_SRC_LINEIN;
1630 rec_set_recording_options(&rec_options);
1632 #endif
1634 return ret;
1637 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1638 #endif /* HAVE_RECORDING */
1640 #ifdef FM_RECORDING_SCREEN
1641 MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING),
1642 fm_recording_screen, NULL, NULL, Icon_Recording);
1643 #endif
1644 #ifdef FM_RECORDING_SETTINGS
1645 MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS),
1646 fm_recording_settings, NULL, NULL, Icon_Recording);
1647 #endif
1648 #ifndef FM_PRESET
1649 MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET),
1650 handle_radio_presets, NULL, NULL, Icon_NOICON);
1651 #endif
1652 #ifndef FM_PRESET_ADD
1653 MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET),
1654 radio_add_preset, NULL, NULL, Icon_NOICON);
1655 #endif
1658 MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD),
1659 load_preset_list, NULL, NULL, Icon_NOICON);
1660 MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE),
1661 save_preset_list, NULL, NULL, Icon_NOICON);
1662 MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR),
1663 clear_preset_list, NULL, NULL, Icon_NOICON);
1664 MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM,
1665 ID2P(LANG_FM_SCAN_PRESETS),
1666 scan_presets, NULL, NULL, Icon_NOICON);
1668 MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1669 Icon_Radio_screen,
1670 #ifndef FM_PRESET
1671 &radio_presets_item,
1672 #endif
1673 #ifndef FM_PRESET_ADD
1674 &radio_addpreset_item,
1675 #endif
1676 &presetload_item, &presetsave_item, &presetclear_item,
1677 &force_mono,
1678 #ifndef FM_MODE
1679 &radio_mode_item,
1680 #endif
1681 &set_region, &sound_settings,
1682 #ifdef FM_RECORDING_SCREEN
1683 &recscreen_item,
1684 #endif
1685 #ifdef FM_RECORDING_SETTINGS
1686 &recsettings_item,
1687 #endif
1688 &scan_presets_item);
1689 /* main menu of the radio screen */
1690 static bool radio_menu(void)
1692 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1693 MENU_ATTACHED_USB;
1696 #endif