Fix FS#11152 in a cleaner way. At least on the sim, the state remained in FMRADIO_PLA...
[kugel-rb.git] / apps / recorder / radio.c
blob0523f1ecac9433878c85d71157adca1393d2d5db
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);
150 static void radio_off(void);
152 /* Function to manipulate all yesno dialogues.
153 This function needs the output text as an argument. */
154 static bool yesno_pop(const char* text)
156 int i;
157 const char *lines[]={text};
158 const struct text_message message={lines, 1};
159 bool ret = (gui_syncyesno_run(&message,NULL,NULL)== YESNO_YES);
160 FOR_NB_SCREENS(i)
161 screens[i].clear_viewport();
162 return ret;
165 void radio_init(void)
167 tuner_init();
168 radio_off();
171 int get_radio_status(void)
173 return radio_status;
176 bool in_radio_screen(void)
178 return in_screen;
181 /* TODO: Move some more of the control functionality to firmware
182 and clean up the mess */
184 /* secret flag for starting paused - prevents unmute */
185 #define FMRADIO_START_PAUSED 0x8000
186 void radio_start(void)
188 const struct fm_region_data *fmr;
189 bool start_paused;
191 if(radio_status == FMRADIO_PLAYING)
192 return;
194 fmr = &fm_region_data[global_settings.fm_region];
196 start_paused = radio_status & FMRADIO_START_PAUSED;
197 /* clear flag before any yielding */
198 radio_status &= ~FMRADIO_START_PAUSED;
200 if(radio_status == FMRADIO_OFF)
201 tuner_power(true);
203 curr_freq = global_status.last_frequency * fmr->freq_step + fmr->freq_min;
205 tuner_set(RADIO_SLEEP, 0); /* wake up the tuner */
207 if(radio_status == FMRADIO_OFF)
209 #ifdef HAVE_RADIO_REGION
210 tuner_set(RADIO_REGION, global_settings.fm_region);
211 #endif
212 tuner_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
215 tuner_set(RADIO_FREQUENCY, curr_freq);
217 #ifdef HAVE_RADIO_MUTE_TIMEOUT
219 unsigned long mute_timeout = current_tick + HZ;
220 if (radio_status != FMRADIO_OFF)
222 /* paused */
223 mute_timeout += HZ;
226 while(!tuner_get(RADIO_STEREO) && !tuner_get(RADIO_TUNED))
228 if(TIME_AFTER(current_tick, mute_timeout))
229 break;
230 yield();
233 #endif
235 /* keep radio from sounding initially */
236 if(!start_paused)
237 tuner_set(RADIO_MUTE, 0);
239 radio_status = FMRADIO_PLAYING;
240 } /* radio_start */
242 void radio_pause(void)
244 if(radio_status == FMRADIO_PAUSED)
245 return;
247 if(radio_status == FMRADIO_OFF)
249 radio_status |= FMRADIO_START_PAUSED;
250 radio_start();
253 tuner_set(RADIO_MUTE, 1);
254 tuner_set(RADIO_SLEEP, 1);
256 radio_status = FMRADIO_PAUSED;
257 } /* radio_pause */
259 static void radio_off(void)
261 tuner_set(RADIO_MUTE, 1);
262 tuner_set(RADIO_SLEEP, 1); /* low power mode, if available */
263 radio_status = FMRADIO_OFF;
264 tuner_power(false); /* status update, power off if avail. */
267 void radio_stop(void)
269 if(radio_status == FMRADIO_OFF)
270 return;
272 radio_off();
273 } /* radio_stop */
275 bool radio_hardware_present(void)
277 return tuner_get(RADIO_PRESENT);
280 /* Keep freq on the grid for the current region */
281 static int snap_freq_to_grid(int freq)
283 const struct fm_region_data * const fmr =
284 &fm_region_data[global_settings.fm_region];
286 /* Range clamp if out of range or just round to nearest */
287 if (freq < fmr->freq_min)
288 freq = fmr->freq_min;
289 else if (freq > fmr->freq_max)
290 freq = fmr->freq_max;
291 else
292 freq = (freq - fmr->freq_min + fmr->freq_step/2) /
293 fmr->freq_step * fmr->freq_step + fmr->freq_min;
295 return freq;
298 /* Find a matching preset to freq */
299 static int find_preset(int freq)
301 int i;
302 if(num_presets < 1)
303 return -1;
304 for(i = 0;i < MAX_PRESETS;i++)
306 if(freq == presets[i].frequency)
307 return i;
310 return -1;
313 /* Return the closest preset encountered in the search direction with
314 wraparound. */
315 static int find_closest_preset(int freq, int direction)
317 int i;
318 int lowpreset = 0;
319 int highpreset = 0;
320 int closest = -1;
322 if (direction == 0) /* direction == 0 isn't really used */
323 return 0;
325 for (i = 0; i < num_presets; i++)
327 int f = presets[i].frequency;
328 if (f == freq)
329 return i; /* Exact match = stop */
331 /* remember the highest and lowest presets for wraparound */
332 if (f < presets[lowpreset].frequency)
333 lowpreset = i;
334 if (f > presets[highpreset].frequency)
335 highpreset = i;
337 /* find the closest preset in the given direction */
338 if (direction > 0 && f > freq)
340 if (closest < 0 || f < presets[closest].frequency)
341 closest = i;
343 else if (direction < 0 && f < freq)
345 if (closest < 0 || f > presets[closest].frequency)
346 closest = i;
350 if (closest < 0)
352 /* no presets in the given direction */
353 /* wrap around depending on direction */
354 if (direction < 0)
355 closest = highpreset;
356 else
357 closest = lowpreset;
360 return closest;
363 static void remember_frequency(void)
365 const struct fm_region_data * const fmr =
366 &fm_region_data[global_settings.fm_region];
367 global_status.last_frequency = (curr_freq - fmr->freq_min)
368 / fmr->freq_step;
369 status_save();
372 static void next_preset(int direction)
374 if (num_presets < 1)
375 return;
377 if (curr_preset == -1)
378 curr_preset = find_closest_preset(curr_freq, direction);
379 else
380 curr_preset = (curr_preset + direction + num_presets) % num_presets;
382 /* Must stay on the current grid for the region */
383 curr_freq = snap_freq_to_grid(presets[curr_preset].frequency);
385 tuner_set(RADIO_FREQUENCY, curr_freq);
386 remember_frequency();
389 /* Step to the next or previous frequency */
390 static int step_freq(int freq, int direction)
392 const struct fm_region_data * const fmr =
393 &fm_region_data[global_settings.fm_region];
395 freq += direction*fmr->freq_step;
397 /* Wrap first or snapping to grid will not let us on the band extremes */
398 if (freq > fmr->freq_max)
399 freq = direction > 0 ? fmr->freq_min : fmr->freq_max;
400 else if (freq < fmr->freq_min)
401 freq = direction < 0 ? fmr->freq_max : fmr->freq_min;
402 else
403 freq = snap_freq_to_grid(freq);
405 return freq;
408 /* Step to the next or previous station */
409 static void next_station(int direction)
411 if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
413 next_preset(direction);
414 return;
417 curr_freq = step_freq(curr_freq, direction);
419 if (radio_status == FMRADIO_PLAYING)
420 tuner_set(RADIO_MUTE, 1);
422 tuner_set(RADIO_FREQUENCY, curr_freq);
424 if (radio_status == FMRADIO_PLAYING)
425 tuner_set(RADIO_MUTE, 0);
427 curr_preset = find_preset(curr_freq);
428 remember_frequency();
431 /* Ends an in-progress search */
432 static void end_search(void)
434 if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
435 tuner_set(RADIO_MUTE, 0);
436 search_dir = 0;
439 /* Speak a frequency. */
440 static void talk_freq(int freq, bool enqueue)
442 freq /= 10000;
443 talk_number(freq / 100, enqueue);
444 talk_id(LANG_POINT, true);
445 talk_number(freq % 100 / 10, true);
446 if (freq % 10)
447 talk_number(freq % 10, true);
450 /* Speak a preset by number or by spelling its name, depending on settings. */
451 static void talk_preset(int preset, bool fallback, bool enqueue)
453 if (global_settings.talk_file == 1) /* number */
454 talk_number(preset + 1, enqueue);
455 else
456 { /* spell */
457 if(presets[preset].name[0])
458 talk_spell(presets[preset].name, enqueue);
459 else if(fallback)
460 talk_freq(presets[preset].frequency, enqueue);
464 static void fms_restore(struct viewport vp[NB_SCREENS])
466 struct screen *display;
467 int i;
468 FOR_NB_SCREENS(i)
470 display = &screens[i];
471 display->set_viewport(&vp[i]);
472 display->clear_viewport();
473 display->update_viewport();
477 int radio_screen(void)
479 char buf[MAX_PATH];
480 bool done = false;
481 int ret_val = GO_TO_ROOT;
482 int button;
483 int i;
484 bool stereo = false, last_stereo = false;
485 int fh;
486 int top_of_screen = 0;
487 bool update_screen = true;
488 bool screen_freeze = false;
489 bool keep_playing = false;
490 bool talk = false;
491 #ifdef FM_RECORD_DBLPRE
492 int lastbutton = BUTTON_NONE;
493 unsigned long rec_lastclick = 0;
494 #endif
495 #if CONFIG_CODEC != SWCODEC
496 bool have_recorded = false;
497 int timeout = current_tick + HZ/10;
498 unsigned int seconds = 0;
499 unsigned int last_seconds = 0;
500 int hours, minutes;
501 struct audio_recording_options rec_options;
502 #endif /* CONFIG_CODEC != SWCODEC */
503 #ifndef HAVE_NOISY_IDLE_MODE
504 int button_timeout = current_tick + (2*HZ);
505 #endif
506 struct viewport vp[NB_SCREENS];
507 #ifdef HAVE_BUTTONBAR
508 struct gui_buttonbar buttonbar;
509 gui_buttonbar_init(&buttonbar);
510 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
511 #endif
513 /* change status to "in screen" */
514 in_screen = true;
516 /* always display status bar in radio screen for now */
517 FOR_NB_SCREENS(i)
519 viewport_set_defaults(&vp[i], i);
520 #ifdef HAVE_BUTTONBAR
521 if (global_settings.buttonbar)
522 vp[i].height -= BUTTONBAR_HEIGHT;
523 #endif
525 fms_restore(vp);
527 fh = font_get(FONT_UI)->height;
529 /* Adjust for font size, trying to center the information vertically */
530 if(fh < 10)
531 top_of_screen = 1;
533 if(num_presets <= 0)
535 radio_load_presets(global_settings.fmr_file);
538 if(radio_status == FMRADIO_OFF)
539 audio_stop();
540 #ifndef SIMULATOR
542 #if CONFIG_CODEC != SWCODEC
543 if(rec_create_directory() > 0)
544 have_recorded = true;
546 audio_init_recording(talk_get_bufsize());
548 sound_settings_apply();
549 /* Yes, we use the D/A for monitoring */
550 peak_meter_playback(true);
552 peak_meter_enabled = true;
554 rec_init_recording_options(&rec_options);
555 rec_options.rec_source = AUDIO_SRC_LINEIN;
556 rec_set_recording_options(&rec_options);
558 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
559 sound_default(SOUND_RIGHT_GAIN), AUDIO_GAIN_LINEIN);
561 #endif /* CONFIG_CODEC != SWCODEC */
562 #endif /* ndef SIMULATOR */
564 /* turn on radio */
565 #if CONFIG_CODEC == SWCODEC
566 audio_set_input_source(AUDIO_SRC_FMRADIO,
567 (radio_status == FMRADIO_PAUSED) ?
568 SRCF_FMRADIO_PAUSED : SRCF_FMRADIO_PLAYING);
569 #else
570 if (radio_status == FMRADIO_OFF)
571 radio_start();
572 #endif
574 if(num_presets < 1 && yesno_pop(ID2P(LANG_FM_FIRST_AUTOSCAN)))
575 scan_presets(vp);
577 curr_preset = find_preset(curr_freq);
578 if(curr_preset != -1)
579 radio_mode = RADIO_PRESET_MODE;
581 #ifdef HAVE_BUTTONBAR
582 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
583 str(LANG_PRESET), str(LANG_FM_BUTTONBAR_RECORD));
584 #endif
586 #ifndef HAVE_NOISY_IDLE_MODE
587 cpu_idle_mode(true);
588 #endif
590 while(!done)
592 if(search_dir != 0)
594 curr_freq = step_freq(curr_freq, search_dir);
595 update_screen = true;
597 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
599 curr_preset = find_preset(curr_freq);
600 remember_frequency();
601 end_search();
602 talk = true;
604 trigger_cpu_boost();
607 if (!update_screen)
609 cancel_cpu_boost();
612 #if CONFIG_CODEC != SWCODEC
613 /* TODO: Can we timeout at HZ when recording since peaks aren't
614 displayed? This should quiet recordings too. */
615 button = get_action(CONTEXT_FM,
616 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
617 #else
618 button = get_action(CONTEXT_FM,
619 update_screen ? TIMEOUT_NOBLOCK : HZ);
620 #endif
622 #ifndef HAVE_NOISY_IDLE_MODE
623 if (button != ACTION_NONE)
625 cpu_idle_mode(false);
626 button_timeout = current_tick + (2*HZ);
628 #endif
629 switch(button)
631 case ACTION_FM_STOP:
632 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
633 if(audio_status() == AUDIO_STATUS_RECORD)
635 audio_stop();
637 else
638 #endif
640 done = true;
641 if(presets_changed)
643 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
645 if(filepreset[0] == '\0')
646 save_preset_list();
647 else
648 radio_save_presets();
651 /* Clear the preset list on exit. */
652 clear_preset_list();
654 update_screen = true;
655 break;
657 #ifdef FM_RECORD
658 case ACTION_FM_RECORD:
659 #ifdef FM_RECORD_DBLPRE
660 if (lastbutton != ACTION_FM_RECORD_DBLPRE)
662 rec_lastclick = 0;
663 break;
665 if (current_tick - rec_lastclick > HZ/2)
667 rec_lastclick = current_tick;
668 break;
670 #endif /* FM_RECORD_DBLPRE */
671 #ifndef SIMULATOR
672 if(audio_status() == AUDIO_STATUS_RECORD)
674 rec_command(RECORDING_CMD_START_NEWFILE);
675 update_screen = true;
677 else
679 have_recorded = true;
680 rec_command(RECORDING_CMD_START);
681 update_screen = true;
683 #endif /* SIMULATOR */
684 last_seconds = 0;
685 break;
686 #endif /* #ifdef FM_RECORD */
688 case ACTION_FM_EXIT:
689 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
690 if(audio_status() == AUDIO_STATUS_RECORD)
691 audio_stop();
692 #endif
693 keep_playing = true;
694 done = true;
695 ret_val = GO_TO_ROOT;
696 if(presets_changed)
698 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
700 if(filepreset[0] == '\0')
701 save_preset_list();
702 else
703 radio_save_presets();
707 /* Clear the preset list on exit. */
708 clear_preset_list();
710 break;
712 case ACTION_STD_PREV:
713 case ACTION_STD_NEXT:
714 next_station(button == ACTION_STD_PREV ? -1 : 1);
715 end_search();
716 update_screen = true;
717 talk = true;
718 break;
720 case ACTION_STD_PREVREPEAT:
721 case ACTION_STD_NEXTREPEAT:
723 int dir = search_dir;
724 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
725 if (radio_mode != RADIO_SCAN_MODE)
727 next_preset(search_dir);
728 end_search();
729 update_screen = true;
730 talk = true;
732 else if (dir == 0)
734 /* Starting auto scan */
735 tuner_set(RADIO_MUTE, 1);
736 update_screen = true;
738 break;
741 case ACTION_SETTINGS_INC:
742 case ACTION_SETTINGS_INCREPEAT:
743 global_settings.volume++;
744 setvol();
745 update_screen = true;
746 break;
748 case ACTION_SETTINGS_DEC:
749 case ACTION_SETTINGS_DECREPEAT:
750 global_settings.volume--;
751 setvol();
752 update_screen = true;
753 break;
755 case ACTION_FM_PLAY:
756 if (radio_status == FMRADIO_PLAYING)
757 radio_pause();
758 else
759 radio_start();
761 update_screen = true;
762 talk = false;
763 talk_shutup();
764 break;
766 case ACTION_FM_MENU:
767 FOR_NB_SCREENS(i)
769 screens[i].scroll_stop(&vp[i]);
771 radio_menu();
772 curr_preset = find_preset(curr_freq);
773 fms_restore(vp);
774 #ifdef HAVE_BUTTONBAR
775 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
776 str(LANG_PRESET),
777 str(LANG_FM_BUTTONBAR_RECORD));
778 #endif
779 update_screen = true;
780 break;
782 #ifdef FM_PRESET
783 case ACTION_FM_PRESET:
784 if(num_presets < 1)
786 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
787 update_screen = true;
788 fms_restore(vp);
790 break;
792 FOR_NB_SCREENS(i)
793 screens[i].scroll_stop(&vp[i]);
794 handle_radio_presets();
795 fms_restore(vp);
796 #ifdef HAVE_BUTTONBAR
797 gui_buttonbar_set(&buttonbar,
798 str(LANG_BUTTONBAR_MENU),
799 str(LANG_PRESET),
800 str(LANG_FM_BUTTONBAR_RECORD));
801 #endif
802 update_screen = true;
803 break;
804 #endif /* FM_PRESET */
806 #ifdef HAVE_QUICKSCREEN
807 case ACTION_FM_QUICKSCREEN:
809 if (quick_screen_quick(button))
811 done = true;
812 break;
814 fms_restore(vp);
815 update_screen = true;
817 break;
818 #endif
819 #ifdef FM_FREEZE
820 case ACTION_FM_FREEZE:
821 if(!screen_freeze)
823 splash(HZ, str(LANG_FM_FREEZE));
824 screen_freeze = true;
826 else
828 update_screen = true;
829 screen_freeze = false;
831 break;
832 #endif /* FM_FREEZE */
834 case SYS_USB_CONNECTED:
835 #if CONFIG_CODEC != SWCODEC
836 /* Only accept USB connection when not recording */
837 if(audio_status() != AUDIO_STATUS_RECORD)
838 #endif
840 default_event_handler(SYS_USB_CONNECTED);
841 screen_freeze = true; /* Cosmetic: makes sure the
842 radio screen doesn't redraw */
843 done = true;
845 break;
847 #ifdef FM_MODE
848 case ACTION_FM_MODE:
849 if(radio_mode == RADIO_SCAN_MODE)
851 /* Force scan mode if there are no presets. */
852 if(num_presets > 0)
853 radio_mode = RADIO_PRESET_MODE;
855 else
856 radio_mode = RADIO_SCAN_MODE;
857 update_screen = true;
858 cond_talk_ids_fq(radio_mode ?
859 LANG_PRESET : LANG_RADIO_SCAN_MODE);
860 talk = true;
861 break;
862 #endif /* FM_MODE */
864 #ifdef FM_NEXT_PRESET
865 case ACTION_FM_NEXT_PRESET:
866 next_preset(1);
867 end_search();
868 update_screen = true;
869 talk = true;
870 break;
871 #endif
873 #ifdef FM_PREV_PRESET
874 case ACTION_FM_PREV_PRESET:
875 next_preset(-1);
876 end_search();
877 update_screen = true;
878 talk = true;
879 break;
880 #endif
882 default:
883 default_event_handler(button);
884 #ifdef HAVE_RDS_CAP
885 if (tuner_get(RADIO_EVENT))
886 update_screen = true;
887 #endif
888 if (!tuner_get(RADIO_PRESENT))
890 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
891 if(audio_status() == AUDIO_STATUS_RECORD)
892 audio_stop();
893 #endif
894 keep_playing = false;
895 done = true;
896 ret_val = GO_TO_ROOT;
897 if(presets_changed)
899 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
901 if(filepreset[0] == '\0')
902 save_preset_list();
903 else
904 radio_save_presets();
908 /* Clear the preset list on exit. */
909 clear_preset_list();
911 break;
912 } /*switch(button)*/
914 #ifdef FM_RECORD_DBLPRE
915 if (button != ACTION_NONE)
916 lastbutton = button;
917 #endif
919 #if CONFIG_CODEC != SWCODEC
920 peak_meter_peek();
921 #endif
923 if(!screen_freeze)
925 /* Only display the peak meter when not recording */
926 #if CONFIG_CODEC != SWCODEC
927 if(!audio_status())
929 FOR_NB_SCREENS(i)
931 screens[i].set_viewport(&vp[i]);
932 peak_meter_screen(&screens[i],0, fh*(top_of_screen + 4),fh);
933 screens[i].update_rect(0, fh*(top_of_screen + 4),
934 screens[i].getwidth(), fh);
938 if(TIME_AFTER(current_tick, timeout))
940 timeout = current_tick + HZ;
941 #else /* SWCODEC */
943 #endif /* CONFIG_CODEC == SWCODEC */
945 /* keep "mono" from always being displayed when paused */
946 if (radio_status != FMRADIO_PAUSED)
948 stereo = tuner_get(RADIO_STEREO) &&
949 !global_settings.fm_force_mono;
951 if(stereo != last_stereo)
953 update_screen = true;
954 last_stereo = stereo;
959 #if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
960 seconds = audio_recorded_time() / HZ;
961 if (update_screen || seconds > last_seconds)
963 last_seconds = seconds;
964 #else
965 if (update_screen)
967 #endif
968 int freq;
970 FOR_NB_SCREENS(i)
972 screens[i].set_viewport(&vp[i]);
975 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
976 curr_preset + 1, presets[curr_preset].name);
978 FOR_NB_SCREENS(i)
979 screens[i].puts_scroll(0, top_of_screen, buf);
981 freq = curr_freq / 10000;
982 snprintf(buf, 128, str(LANG_FM_STATION),
983 freq / 100, freq % 100);
984 FOR_NB_SCREENS(i)
985 screens[i].puts_scroll(0, top_of_screen + 1, buf);
987 FOR_NB_SCREENS(i)
988 screens[i].puts_scroll(0, top_of_screen + 2,
989 stereo ? str(LANG_CHANNEL_STEREO) :
990 str(LANG_CHANNEL_MONO));
992 snprintf(buf, 128, "%s %s", str(LANG_MODE),
993 radio_mode ? str(LANG_PRESET) :
994 str(LANG_RADIO_SCAN_MODE));
995 FOR_NB_SCREENS(i)
996 screens[i].puts_scroll(0, top_of_screen + 3, buf);
997 #ifndef SIMULATOR
998 #ifdef HAVE_RDS_CAP
999 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME));
1000 FOR_NB_SCREENS(i)
1001 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1003 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_TEXT));
1004 FOR_NB_SCREENS(i)
1005 screens[i].puts_scroll(0, top_of_screen + 5, buf);
1006 #endif
1007 #endif /* SIMULATOR */
1009 #if CONFIG_CODEC != SWCODEC
1010 if(audio_status() == AUDIO_STATUS_RECORD)
1012 hours = seconds / 3600;
1013 minutes = (seconds - (hours * 3600)) / 60;
1014 snprintf(buf, 32, "%s %02d:%02d:%02d",
1015 str(LANG_RECORDING_TIME),
1016 hours, minutes, seconds%60);
1017 FOR_NB_SCREENS(i)
1018 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1020 else
1022 if(rec_options.rec_prerecord_time)
1024 snprintf(buf, 32, "%s %02d",
1025 str(LANG_RECORD_PRERECORD), seconds%60);
1026 FOR_NB_SCREENS(i)
1027 screens[i].puts_scroll(0, top_of_screen + 4, buf);
1030 #endif /* CONFIG_CODEC != SWCODEC */
1032 FOR_NB_SCREENS(i)
1033 screens[i].update_viewport();
1034 #ifdef HAVE_BUTTONBAR
1035 gui_buttonbar_draw(&buttonbar);
1036 #endif
1040 update_screen = false;
1042 if (global_settings.talk_file && talk
1043 && radio_status == FMRADIO_PAUSED)
1045 talk = false;
1046 bool enqueue = false;
1047 if (radio_mode == RADIO_SCAN_MODE)
1049 talk_freq(curr_freq, enqueue);
1050 enqueue = true;
1052 if (curr_preset >= 0)
1053 talk_preset(curr_preset, radio_mode == RADIO_PRESET_MODE,
1054 enqueue);
1057 #if CONFIG_CODEC != SWCODEC
1058 if(audio_status() & AUDIO_STATUS_ERROR)
1060 done = true;
1062 #endif
1064 #ifndef HAVE_NOISY_IDLE_MODE
1065 if (TIME_AFTER(current_tick, button_timeout))
1067 cpu_idle_mode(true);
1069 #endif
1070 } /*while(!done)*/
1072 #ifndef SIMULATOR
1073 #if CONFIG_CODEC != SWCODEC
1074 if(audio_status() & AUDIO_STATUS_ERROR)
1076 splash(0, str(LANG_DISK_FULL));
1077 fms_restore(vp);
1078 audio_error_clear();
1080 while(1)
1082 button = get_action(CONTEXT_FM, TIMEOUT_BLOCK);
1083 if(button == ACTION_FM_STOP)
1084 break;
1088 audio_init_playback();
1089 #endif /* CONFIG_CODEC != SWCODEC */
1091 sound_settings_apply();
1092 #endif /* SIMULATOR */
1094 if(keep_playing)
1096 /* Catch FMRADIO_PLAYING status for the sim. */
1097 #ifndef SIMULATOR
1098 #if CONFIG_CODEC != SWCODEC
1099 /* Enable the Left and right A/D Converter */
1100 audio_set_recording_gain(sound_default(SOUND_LEFT_GAIN),
1101 sound_default(SOUND_RIGHT_GAIN),
1102 AUDIO_GAIN_LINEIN);
1103 mas_codec_writereg(6, 0x4000);
1104 #endif
1105 end_search();
1106 #endif /* SIMULATOR */
1108 else
1110 #if CONFIG_CODEC == SWCODEC
1111 audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
1112 #else
1113 radio_stop();
1114 #endif
1117 #ifndef HAVE_NOISY_IDLE_MODE
1118 cpu_idle_mode(false);
1119 #endif
1120 FOR_NB_SCREENS(i)
1122 screens[i].scroll_stop(&vp[i]);
1123 screens[i].set_viewport(NULL);
1125 in_screen = false;
1126 #if CONFIG_CODEC != SWCODEC
1127 return have_recorded;
1128 #else
1129 return false;
1130 #endif
1131 } /* radio_screen */
1133 static void radio_save_presets(void)
1135 int fd;
1136 int i;
1138 fd = creat(filepreset);
1139 if(fd >= 0)
1141 for(i = 0;i < num_presets;i++)
1143 fdprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
1145 close(fd);
1147 if(!strncasecmp(FMPRESET_PATH, filepreset, strlen(FMPRESET_PATH)))
1148 set_file(filepreset, global_settings.fmr_file, MAX_FILENAME);
1149 presets_changed = false;
1151 else
1153 splash(HZ, ID2P(LANG_FM_PRESET_SAVE_FAILED));
1157 void radio_load_presets(char *filename)
1159 int fd;
1160 int rc;
1161 char buf[128];
1162 char *freq;
1163 char *name;
1164 bool done = false;
1165 int f;
1167 memset(presets, 0, sizeof(presets));
1168 num_presets = 0;
1170 /* No Preset in configuration. */
1171 if(filename[0] == '\0')
1173 filepreset[0] = '\0';
1174 return;
1176 /* Temporary preset, loaded until player shuts down. */
1177 else if(filename[0] == '/')
1178 strlcpy(filepreset, filename, sizeof(filepreset));
1179 /* Preset from default directory. */
1180 else
1181 snprintf(filepreset, sizeof(filepreset), "%s/%s.fmr",
1182 FMPRESET_PATH, filename);
1184 fd = open_utf8(filepreset, O_RDONLY);
1185 if(fd >= 0)
1187 while(!done && num_presets < MAX_PRESETS)
1189 rc = read_line(fd, buf, 128);
1190 if(rc > 0)
1192 if(settings_parseline(buf, &freq, &name))
1194 f = atoi(freq);
1195 if(f) /* For backwards compatibility */
1197 struct fmstation * const fms = &presets[num_presets];
1198 fms->frequency = f;
1199 strlcpy(fms->name, name, MAX_FMPRESET_LEN+1);
1200 num_presets++;
1204 else
1205 done = true;
1207 close(fd);
1209 else /* invalid file name? */
1210 filepreset[0] = '\0';
1212 presets_loaded = num_presets > 0;
1213 presets_changed = false;
1217 static int radio_add_preset(void)
1219 char buf[MAX_FMPRESET_LEN + 1];
1221 if(num_presets < MAX_PRESETS)
1223 buf[0] = '\0';
1225 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1227 struct fmstation * const fms = &presets[num_presets];
1228 strcpy(fms->name, buf);
1229 fms->frequency = curr_freq;
1230 num_presets++;
1231 presets_changed = true;
1232 presets_loaded = num_presets > 0;
1233 return true;
1236 else
1238 splash(HZ, ID2P(LANG_FM_NO_FREE_PRESETS));
1240 return false;
1243 /* needed to know which preset we are edit/delete-ing */
1244 static int selected_preset = -1;
1245 static int radio_edit_preset(void)
1247 char buf[MAX_FMPRESET_LEN + 1];
1249 if (num_presets > 0)
1251 struct fmstation * const fms = &presets[selected_preset];
1253 strcpy(buf, fms->name);
1255 if (!kbd_input(buf, MAX_FMPRESET_LEN + 1))
1257 strcpy(fms->name, buf);
1258 presets_changed = true;
1262 return 1;
1265 static int radio_delete_preset(void)
1267 if (num_presets > 0)
1269 struct fmstation * const fms = &presets[selected_preset];
1271 if (selected_preset >= --num_presets)
1272 selected_preset = num_presets - 1;
1274 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1275 (uintptr_t)fms);
1277 if (curr_preset >= num_presets)
1278 --curr_preset;
1281 /* Don't ask to save when all presets are deleted. */
1282 presets_changed = num_presets > 0;
1284 if (!presets_changed)
1286 /* The preset list will be cleared, switch to Scan Mode. */
1287 radio_mode = RADIO_SCAN_MODE;
1288 curr_preset = -1;
1289 presets_loaded = false;
1292 return 1;
1295 static int load_preset_list(void)
1297 return !rockbox_browse(FMPRESET_PATH, SHOW_FMR);
1300 static int save_preset_list(void)
1302 if(num_presets > 0)
1304 bool bad_file_name = true;
1306 if(!dir_exists(FMPRESET_PATH)) /* Check if there is preset folder */
1307 mkdir(FMPRESET_PATH);
1309 create_numbered_filename(filepreset, FMPRESET_PATH, "preset",
1310 ".fmr", 2 IF_CNFN_NUM_(, NULL));
1312 while(bad_file_name)
1314 if(!kbd_input(filepreset, sizeof(filepreset)))
1316 /* check the name: max MAX_FILENAME (20) chars */
1317 char* p2;
1318 char* p1;
1319 int len;
1320 p1 = strrchr(filepreset, '/');
1321 p2 = p1;
1322 while((p1) && (*p2) && (*p2 != '.'))
1323 p2++;
1324 len = (int)(p2-p1) - 1;
1325 if((!p1) || (len > MAX_FILENAME) || (len == 0))
1327 /* no slash, too long or too short */
1328 splash(HZ, ID2P(LANG_INVALID_FILENAME));
1330 else
1332 /* add correct extension (easier to always write)
1333 at this point, p2 points to 0 or the extension dot */
1334 *p2 = '\0';
1335 strcat(filepreset,".fmr");
1336 bad_file_name = false;
1337 radio_save_presets();
1340 else
1342 /* user aborted */
1343 return false;
1347 else
1348 splash(HZ, ID2P(LANG_FM_NO_PRESETS));
1350 return true;
1353 static int clear_preset_list(void)
1355 /* Clear all the preset entries */
1356 memset(presets, 0, sizeof (presets));
1358 num_presets = 0;
1359 presets_loaded = false;
1360 /* The preset list will be cleared switch to Scan Mode. */
1361 radio_mode = RADIO_SCAN_MODE;
1362 curr_preset = -1;
1364 presets_changed = false; /* Don't ask to save when clearing the list. */
1366 return true;
1369 MENUITEM_FUNCTION(radio_edit_preset_item, MENU_FUNC_CHECK_RETVAL,
1370 ID2P(LANG_FM_EDIT_PRESET),
1371 radio_edit_preset, NULL, NULL, Icon_NOICON);
1372 MENUITEM_FUNCTION(radio_delete_preset_item, MENU_FUNC_CHECK_RETVAL,
1373 ID2P(LANG_FM_DELETE_PRESET),
1374 radio_delete_preset, NULL, NULL, Icon_NOICON);
1375 static int radio_preset_callback(int action,
1376 const struct menu_item_ex *this_item)
1378 if (action == ACTION_STD_OK)
1379 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1380 return action;
1381 (void)this_item;
1383 MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_PRESET),
1384 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
1385 &radio_delete_preset_item);
1386 /* present a list of preset stations */
1387 static const char* presets_get_name(int selected_item, void *data,
1388 char *buffer, size_t buffer_len)
1390 (void)data;
1391 struct fmstation *p = &presets[selected_item];
1392 if(p->name[0])
1393 return p->name;
1394 int freq = p->frequency / 10000;
1395 int frac = freq % 100;
1396 freq /= 100;
1397 snprintf(buffer, buffer_len,
1398 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1399 return buffer;
1402 static int presets_speak_name(int selected_item, void * data)
1404 (void)data;
1405 talk_preset(selected_item, true, false);
1406 return 0;
1409 static int handle_radio_presets(void)
1411 struct gui_synclist lists;
1412 int result = 0;
1413 int action = ACTION_NONE;
1414 #ifdef HAVE_BUTTONBAR
1415 struct gui_buttonbar buttonbar;
1416 #endif
1418 if(presets_loaded == false)
1419 return result;
1421 #ifdef HAVE_BUTTONBAR
1422 gui_buttonbar_init(&buttonbar);
1423 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
1424 gui_buttonbar_set(&buttonbar, str(LANG_FM_BUTTONBAR_ADD),
1425 str(LANG_FM_BUTTONBAR_EXIT),
1426 str(LANG_FM_BUTTONBAR_ACTION));
1427 gui_buttonbar_draw(&buttonbar);
1428 #endif
1429 gui_synclist_init(&lists, presets_get_name, NULL, false, 1, NULL);
1430 gui_synclist_set_title(&lists, str(LANG_PRESET), NOICON);
1431 gui_synclist_set_icon_callback(&lists, NULL);
1432 if(global_settings.talk_file)
1433 gui_synclist_set_voice_callback(&lists, presets_speak_name);
1434 gui_synclist_set_nb_items(&lists, num_presets);
1435 gui_synclist_select_item(&lists, curr_preset<0 ? 0 : curr_preset);
1436 gui_synclist_speak_item(&lists);
1438 while (result == 0)
1440 gui_synclist_draw(&lists);
1441 list_do_action(CONTEXT_STD, TIMEOUT_BLOCK,
1442 &lists, &action, LIST_WRAP_UNLESS_HELD);
1443 switch (action)
1445 case ACTION_STD_MENU:
1446 if (radio_add_preset())
1448 gui_synclist_set_nb_items(&lists, num_presets);
1449 gui_synclist_select_item(&lists, num_presets - 1);
1451 break;
1452 case ACTION_STD_CANCEL:
1453 result = 1;
1454 break;
1455 case ACTION_STD_OK:
1456 curr_preset = gui_synclist_get_sel_pos(&lists);
1457 curr_freq = presets[curr_preset].frequency;
1458 next_station(0);
1459 remember_frequency();
1460 result = 1;
1461 break;
1462 case ACTION_F3:
1463 case ACTION_STD_CONTEXT:
1464 selected_preset = gui_synclist_get_sel_pos(&lists);
1465 do_menu(&handle_radio_preset_menu, NULL, NULL, false);
1466 gui_synclist_set_nb_items(&lists, num_presets);
1467 gui_synclist_select_item(&lists, selected_preset);
1468 gui_synclist_speak_item(&lists);
1469 break;
1470 default:
1471 if(default_event_handler(action) == SYS_USB_CONNECTED)
1472 result = 2;
1475 gui_synclist_scroll_stop(&lists);
1476 return result - 1;
1479 void toggle_mono_mode(bool mono)
1481 tuner_set(RADIO_FORCE_MONO, mono);
1484 void set_radio_region(int region)
1486 #ifdef HAVE_RADIO_REGION
1487 tuner_set(RADIO_REGION, region);
1488 #endif
1489 next_station(0);
1490 remember_frequency();
1491 (void)region;
1494 MENUITEM_SETTING(set_region, &global_settings.fm_region, NULL);
1495 MENUITEM_SETTING(force_mono, &global_settings.fm_force_mono, NULL);
1497 #ifndef FM_MODE
1498 static char* get_mode_text(int selected_item, void * data, char *buffer)
1500 (void)selected_item;
1501 (void)data;
1502 snprintf(buffer, MAX_PATH, "%s %s", str(LANG_MODE),
1503 radio_mode ? str(LANG_PRESET) :
1504 str(LANG_RADIO_SCAN_MODE));
1505 return buffer;
1507 static int toggle_radio_mode(void)
1509 radio_mode = (radio_mode == RADIO_SCAN_MODE) ?
1510 RADIO_PRESET_MODE : RADIO_SCAN_MODE;
1511 return 0;
1513 MENUITEM_FUNCTION_DYNTEXT(radio_mode_item, 0,
1514 toggle_radio_mode, NULL,
1515 get_mode_text, NULL, NULL, NULL, Icon_NOICON);
1516 #endif
1518 static int scan_presets(void *viewports)
1520 bool do_scan = true;
1521 int i;
1522 struct viewport *vp = (struct viewport *)viewports;
1524 FOR_NB_SCREENS(i)
1525 screens[i].set_viewport(vp?&vp[i]:NULL);
1526 if(num_presets > 0) /* Do that to avoid 2 questions. */
1527 do_scan = yesno_pop(ID2P(LANG_FM_CLEAR_PRESETS));
1529 if(do_scan)
1531 const struct fm_region_data * const fmr =
1532 &fm_region_data[global_settings.fm_region];
1534 curr_freq = fmr->freq_min;
1535 num_presets = 0;
1536 memset(presets, 0, sizeof(presets));
1538 tuner_set(RADIO_MUTE, 1);
1540 while(curr_freq <= fmr->freq_max)
1542 int freq, frac;
1543 if(num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1544 break;
1546 freq = curr_freq / 10000;
1547 frac = freq % 100;
1548 freq /= 100;
1550 splashf(0, str(LANG_FM_SCANNING), freq, frac);
1552 if(tuner_set(RADIO_SCAN_FREQUENCY, curr_freq))
1554 /* add preset */
1555 presets[num_presets].name[0] = '\0';
1556 presets[num_presets].frequency = curr_freq;
1557 num_presets++;
1560 curr_freq += fmr->freq_step;
1563 if (radio_status == FMRADIO_PLAYING)
1564 tuner_set(RADIO_MUTE, 0);
1566 presets_changed = true;
1568 FOR_NB_SCREENS(i)
1570 screens[i].clear_viewport();
1571 screens[i].update_viewport();
1574 if(num_presets > 0)
1576 curr_freq = presets[0].frequency;
1577 radio_mode = RADIO_PRESET_MODE;
1578 presets_loaded = true;
1579 next_station(0);
1581 else
1583 /* Wrap it to beginning or we'll be past end of band */
1584 presets_loaded = false;
1585 next_station(1);
1588 return true;
1592 #ifdef HAVE_RECORDING
1594 #if defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC
1595 #define FM_RECORDING_SCREEN
1596 static int fm_recording_screen(void)
1598 bool ret;
1600 /* switch recording source to FMRADIO for the duration */
1601 int rec_source = global_settings.rec_source;
1602 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1603 ret = recording_screen(true);
1605 /* safe to reset as changing sources is prohibited here */
1606 global_settings.rec_source = rec_source;
1608 return ret;
1611 #endif /* defined(HAVE_FMRADIO_REC) && CONFIG_CODEC == SWCODEC */
1613 #if defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC
1614 #define FM_RECORDING_SETTINGS
1615 static int fm_recording_settings(void)
1617 bool ret = recording_menu(true);
1619 #if CONFIG_CODEC != SWCODEC
1620 if (!ret)
1622 struct audio_recording_options rec_options;
1623 rec_init_recording_options(&rec_options);
1624 rec_options.rec_source = AUDIO_SRC_LINEIN;
1625 rec_set_recording_options(&rec_options);
1627 #endif
1629 return ret;
1632 #endif /* defined(HAVE_FMRADIO_REC) || CONFIG_CODEC != SWCODEC */
1633 #endif /* HAVE_RECORDING */
1635 #ifdef FM_RECORDING_SCREEN
1636 MENUITEM_FUNCTION(recscreen_item, 0, ID2P(LANG_RECORDING),
1637 fm_recording_screen, NULL, NULL, Icon_Recording);
1638 #endif
1639 #ifdef FM_RECORDING_SETTINGS
1640 MENUITEM_FUNCTION(recsettings_item, 0, ID2P(LANG_RECORDING_SETTINGS),
1641 fm_recording_settings, NULL, NULL, Icon_Recording);
1642 #endif
1643 #ifndef FM_PRESET
1644 MENUITEM_FUNCTION(radio_presets_item, 0, ID2P(LANG_PRESET),
1645 handle_radio_presets, NULL, NULL, Icon_NOICON);
1646 #endif
1647 #ifndef FM_PRESET_ADD
1648 MENUITEM_FUNCTION(radio_addpreset_item, 0, ID2P(LANG_FM_ADD_PRESET),
1649 radio_add_preset, NULL, NULL, Icon_NOICON);
1650 #endif
1653 MENUITEM_FUNCTION(presetload_item, 0, ID2P(LANG_FM_PRESET_LOAD),
1654 load_preset_list, NULL, NULL, Icon_NOICON);
1655 MENUITEM_FUNCTION(presetsave_item, 0, ID2P(LANG_FM_PRESET_SAVE),
1656 save_preset_list, NULL, NULL, Icon_NOICON);
1657 MENUITEM_FUNCTION(presetclear_item, 0, ID2P(LANG_FM_PRESET_CLEAR),
1658 clear_preset_list, NULL, NULL, Icon_NOICON);
1659 MENUITEM_FUNCTION(scan_presets_item, MENU_FUNC_USEPARAM,
1660 ID2P(LANG_FM_SCAN_PRESETS),
1661 scan_presets, NULL, NULL, Icon_NOICON);
1663 MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1664 Icon_Radio_screen,
1665 #ifndef FM_PRESET
1666 &radio_presets_item,
1667 #endif
1668 #ifndef FM_PRESET_ADD
1669 &radio_addpreset_item,
1670 #endif
1671 &presetload_item, &presetsave_item, &presetclear_item,
1672 &force_mono,
1673 #ifndef FM_MODE
1674 &radio_mode_item,
1675 #endif
1676 &set_region, &sound_settings,
1677 #ifdef FM_RECORDING_SCREEN
1678 &recscreen_item,
1679 #endif
1680 #ifdef FM_RECORDING_SETTINGS
1681 &recsettings_item,
1682 #endif
1683 &scan_presets_item);
1684 /* main menu of the radio screen */
1685 static bool radio_menu(void)
1687 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1688 MENU_ATTACHED_USB;
1691 #endif