1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2003 Linus Nielsen Feltzing
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
32 #include "mp3_playback.h"
44 #include "peakmeter.h"
47 #include "sound_menu.h"
48 #include "recording.h"
53 #define MAX_FREQ (108000000)
54 #define MIN_FREQ (87500000)
55 #define PLL_FREQ_STEP 10000
56 #define FREQ_STEP 100000
58 static int curr_preset
= -1;
59 static int curr_freq
= 99400000;
62 #define MAX_PRESETS 32
63 static bool presets_loaded
= false;
64 static struct fmstation presets
[MAX_PRESETS
];
66 static char default_filename
[] = "/.rockbox/fm-presets-default.fmr";
68 int debug_fm_detection
;
70 void radio_load_presets(void);
71 bool radio_preset_select(void);
72 bool radio_menu(void);
76 /* Mute the FM radio */
77 fmradio_set(1, 0x100003);
81 bool radio_hardware_present(void)
85 fmradio_set(2, 0x140885); /* 5kHz, 7.2MHz crystal, test mode 1 */
86 val
= fmradio_read(0);
87 debug_fm_detection
= val
;
94 void radio_set_frequency(int freq
)
96 /* We add the standard Intermediate Frequency 10.7MHz before calculating
98 ** The reference frequency is set to 50kHz, and the VCO output is prescaled
102 pll_cnt
= (freq
+ 10700000) / (PLL_FREQ_STEP
/2) / 2;
104 /* 0x100000 == FM mode
105 ** 0x000002 == Microprocessor controlled Mute
107 fmradio_set(1, 0x100002 | pll_cnt
<< 3);
110 static int find_preset(int freq
)
113 for(i
= 0;i
< MAX_PRESETS
;i
++)
115 if(freq
== presets
[i
].frequency
)
122 bool radio_screen(void)
133 int last_stereo_status
= false;
134 int top_of_screen
= 0;
135 bool update_screen
= true;
136 int timeout
= current_tick
+ HZ
/10;
137 bool screen_freeze
= false;
138 bool have_recorded
= false;
139 unsigned int seconds
;
140 unsigned int last_seconds
= 0;
142 bool keep_playing
= false;
145 lcd_setmargins(0, 8);
147 fmradio_set_status(FMRADIO_PLAYING
);
150 lcd_getstringsize("M", &fw
, &fh
);
152 /* Adjust for font size, trying to center the information vertically */
156 radio_load_presets();
160 mpeg_init_recording();
162 mpeg_sound_channel_config(global_settings
.channel_config
);
163 mpeg_sound_set(SOUND_BASS
, global_settings
.bass
);
164 mpeg_sound_set(SOUND_TREBLE
, global_settings
.treble
);
165 mpeg_sound_set(SOUND_BALANCE
, global_settings
.balance
);
166 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
167 mpeg_sound_set(SOUND_LOUDNESS
, global_settings
.loudness
);
168 mpeg_sound_set(SOUND_SUPERBASS
, global_settings
.bass_boost
);
169 mpeg_sound_set(SOUND_AVC
, global_settings
.avc
);
171 status_set_playmode(STATUS_STOP
);
173 /* Yes, we use the D/A for monitoring */
174 peak_meter_playback(true);
176 peak_meter_enabled
= true;
178 if (global_settings
.rec_prerecord_time
)
179 talk_buffer_steal(); /* will use the mp3 buffer */
181 mpeg_set_recording_options(global_settings
.rec_frequency
,
182 global_settings
.rec_quality
,
184 global_settings
.rec_channels
,
185 global_settings
.rec_editable
,
186 global_settings
.rec_prerecord_time
);
189 mpeg_set_recording_gain(mpeg_sound_default(SOUND_LEFT_GAIN
),
190 mpeg_sound_default(SOUND_RIGHT_GAIN
), false);
192 fmradio_set(2, 0x140884); /* 5kHz, 7.2MHz crystal */
193 radio_set_frequency(curr_freq
);
194 curr_preset
= find_preset(curr_freq
);
196 buttonbar_set(str(LANG_BUTTONBAR_MENU
), str(LANG_FM_BUTTONBAR_PRESETS
),
197 str(LANG_FM_BUTTONBAR_RECORD
));
203 curr_freq
+= search_dir
* FREQ_STEP
;
204 if(curr_freq
< MIN_FREQ
)
205 curr_freq
= MAX_FREQ
;
206 if(curr_freq
> MAX_FREQ
)
207 curr_freq
= MIN_FREQ
;
209 /* Tune in and delay */
210 radio_set_frequency(curr_freq
);
213 /* Start IF measurement */
214 fmradio_set(1, 0x100006 | pll_cnt
<< 3);
217 /* Now check how close to the IF frequency we are */
218 val
= fmradio_read(3);
219 i_freq
= (val
& 0x7ffff) / 80;
221 /* Stop searching if the IF frequency is close to 10.7MHz */
222 if(i_freq
> 1065 && i_freq
< 1075)
225 curr_preset
= find_preset(curr_freq
);
228 update_screen
= true;
232 button
= button_get(false);
234 button
= button_get_w_tmo(HZ
/ peak_meter_fps
);
238 if(mpeg_status() == MPEG_STATUS_RECORD
)
241 status_set_playmode(STATUS_STOP
);
248 update_screen
= true;
252 if(mpeg_status() == MPEG_STATUS_RECORD
)
254 mpeg_new_file(rec_create_filename(buf
));
255 update_screen
= true;
259 have_recorded
= true;
260 talk_buffer_steal(); /* we use the mp3 buffer */
261 mpeg_record(rec_create_filename(buf
));
262 status_set_playmode(STATUS_RECORD
);
263 update_screen
= true;
268 case BUTTON_ON
| BUTTON_REL
:
274 curr_freq
-= FREQ_STEP
;
275 if(curr_freq
< MIN_FREQ
)
276 curr_freq
= MIN_FREQ
;
278 radio_set_frequency(curr_freq
);
279 curr_preset
= find_preset(curr_freq
);
281 update_screen
= true;
285 curr_freq
+= FREQ_STEP
;
286 if(curr_freq
> MAX_FREQ
)
287 curr_freq
= MAX_FREQ
;
289 radio_set_frequency(curr_freq
);
290 curr_preset
= find_preset(curr_freq
);
292 update_screen
= true;
295 case BUTTON_LEFT
| BUTTON_REPEAT
:
299 case BUTTON_RIGHT
| BUTTON_REPEAT
:
304 case BUTTON_UP
| BUTTON_REPEAT
:
305 global_settings
.volume
++;
306 if(global_settings
.volume
> mpeg_sound_max(SOUND_VOLUME
))
307 global_settings
.volume
= mpeg_sound_max(SOUND_VOLUME
);
308 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
309 update_screen
= true;
314 case BUTTON_DOWN
| BUTTON_REPEAT
:
315 global_settings
.volume
--;
316 if(global_settings
.volume
< mpeg_sound_min(SOUND_VOLUME
))
317 global_settings
.volume
= mpeg_sound_min(SOUND_VOLUME
);
318 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
319 update_screen
= true;
325 curr_preset
= find_preset(curr_freq
);
327 lcd_setmargins(0, 8);
328 buttonbar_set(str(LANG_BUTTONBAR_MENU
),
329 str(LANG_FM_BUTTONBAR_PRESETS
),
330 str(LANG_FM_BUTTONBAR_RECORD
));
331 update_screen
= true;
335 radio_preset_select();
336 curr_preset
= find_preset(curr_freq
);
338 lcd_setmargins(0, 8);
339 buttonbar_set(str(LANG_BUTTONBAR_MENU
),
340 str(LANG_FM_BUTTONBAR_PRESETS
),
341 str(LANG_FM_BUTTONBAR_RECORD
));
342 update_screen
= true;
348 splash(0, true, "Screen frozen");
350 screen_freeze
= true;
354 update_screen
= true;
355 screen_freeze
= false;
359 case SYS_USB_CONNECTED
:
360 /* Only accept USB connection when not recording */
361 if(mpeg_status() != MPEG_STATUS_RECORD
)
364 fmradio_set_status(0);
365 screen_freeze
= true; /* Cosmetic: makes sure the
366 radio screen doesn't redraw */
376 lcd_setmargins(0, 8);
378 /* Only display the peak meter when not recording */
381 lcd_clearrect(0, 8 + fh
*(top_of_screen
+ 3), LCD_WIDTH
, fh
);
382 peak_meter_draw(0, 8 + fh
*(top_of_screen
+ 3), LCD_WIDTH
, fh
);
383 lcd_update_rect(0, 8 + fh
*(top_of_screen
+ 3), LCD_WIDTH
, fh
);
386 if(TIME_AFTER(current_tick
, timeout
))
388 timeout
= current_tick
+ HZ
;
390 val
= fmradio_read(3);
391 stereo
= (val
& 0x100000)?true:false;
392 if(stereo
!= last_stereo_status
)
394 update_screen
= true;
395 last_stereo_status
= stereo
;
399 seconds
= mpeg_recorded_time() / HZ
;
401 if(update_screen
|| seconds
> last_seconds
)
403 last_seconds
= seconds
;
405 lcd_setfont(FONT_UI
);
409 lcd_puts_scroll(0, top_of_screen
,
410 presets
[curr_preset
].name
);
414 lcd_clearrect(0, 8 + top_of_screen
*fh
, LCD_WIDTH
, fh
);
417 freq
= curr_freq
/ 100000;
418 snprintf(buf
, 128, str(LANG_FM_STATION
), freq
/ 10, freq
% 10);
419 lcd_puts(0, top_of_screen
+ 1, buf
);
422 stereo
?str(LANG_CHANNEL_STEREO
):
423 str(LANG_CHANNEL_MONO
));
424 lcd_puts(0, top_of_screen
+ 2, buf
);
426 if(mpeg_status() == MPEG_STATUS_RECORD
)
428 hours
= seconds
/ 3600;
429 minutes
= (seconds
- (hours
* 3600)) / 60;
430 snprintf(buf
, 32, "%s %02d:%02d:%02d",
431 str(LANG_RECORDING_TIME
),
432 hours
, minutes
, seconds
%60);
433 lcd_puts(0, top_of_screen
+ 3, buf
);
437 snprintf(buf
, 32, "%s %02d",
438 str(LANG_RECORD_PRERECORD
), seconds
%60);
439 lcd_puts(0, top_of_screen
+ 3, buf
);
442 /* Only force the redraw if update_screen is true */
443 status_draw(update_screen
);
449 update_screen
= false;
453 if(mpeg_status() & MPEG_STATUS_ERROR
)
460 if(mpeg_status() & MPEG_STATUS_ERROR
)
462 status_set_playmode(STATUS_STOP
);
463 splash(0, true, str(LANG_DISK_FULL
));
470 button
= button_get(true);
471 if(button
== (BUTTON_OFF
| BUTTON_REL
))
476 mpeg_init_playback();
478 mpeg_sound_channel_config(global_settings
.channel_config
);
479 mpeg_sound_set(SOUND_BASS
, global_settings
.bass
);
480 mpeg_sound_set(SOUND_TREBLE
, global_settings
.treble
);
481 mpeg_sound_set(SOUND_BALANCE
, global_settings
.balance
);
482 mpeg_sound_set(SOUND_VOLUME
, global_settings
.volume
);
483 mpeg_sound_set(SOUND_LOUDNESS
, global_settings
.loudness
);
484 mpeg_sound_set(SOUND_SUPERBASS
, global_settings
.bass_boost
);
485 mpeg_sound_set(SOUND_AVC
, global_settings
.avc
);
487 fmradio_set_status(0);
491 /* Enable the Left and right A/D Converter */
492 mpeg_set_recording_gain(mpeg_sound_default(SOUND_LEFT_GAIN
),
493 mpeg_sound_default(SOUND_RIGHT_GAIN
), false);
494 mas_codec_writereg(6, 0x4000);
496 return have_recorded
;
499 static bool parseline(char* line
, char** freq
, char** name
)
503 while ( isspace(*line
) )
509 ptr
= strchr(line
, ':');
516 while (isspace(*ptr
))
522 void radio_save_presets(void)
527 fd
= creat(default_filename
, O_WRONLY
);
530 for(i
= 0;i
< MAX_PRESETS
;i
++)
532 fprintf(fd
, "%d:%s\n", presets
[i
].frequency
, presets
[i
].name
);
538 splash(HZ
*2, true, str(LANG_FM_PRESET_SAVE_FAILED
));
542 void radio_load_presets(void)
554 memset(presets
, 0, sizeof(presets
));
556 fd
= open(default_filename
, O_RDONLY
);
560 while(!done
&& i
< MAX_PRESETS
)
562 rc
= read_line(fd
, buf
, 128);
565 if(parseline(buf
, &freq
, &name
))
567 presets
[i
].frequency
= atoi(freq
);
568 strncpy(presets
[i
].name
, name
, 27);
569 presets
[i
].name
[27] = 0;
579 presets_loaded
= true;
582 bool radio_preset_select(void)
584 struct menu_item menu
[MAX_PRESETS
];
587 bool reload_dir
= false;
594 for(i
= 0;i
< MAX_PRESETS
;i
++)
596 if(presets
[i
].frequency
)
598 menu
[num_presets
].desc
= presets
[i
].name
;
599 menu
[num_presets
].voice_id
= -1;
600 /* We use the function pointer entry for the preset
602 menu
[num_presets
++].function
= (void *)i
;
608 /* DIY menu handling, since we want to exit after selection */
609 m
= menu_init( menu
, num_presets
, NULL
, NULL
, NULL
, NULL
);
610 result
= menu_show(m
);
612 if (result
== MENU_SELECTED_EXIT
)
614 else if (result
== MENU_ATTACHED_USB
)
619 i
= (int)menu
[result
].function
;
620 curr_freq
= presets
[i
].frequency
;
621 radio_set_frequency(curr_freq
);
626 splash(HZ
*2, true, str(LANG_FM_NO_PRESETS
));
633 static bool radio_add_preset(void)
636 int i
= find_preset(0);
642 if (!kbd_input(buf
, 27))
645 strcpy(presets
[i
].name
, buf
);
646 presets
[i
].frequency
= curr_freq
;
647 radio_save_presets();
652 splash(HZ
*2, true, str(LANG_FM_NO_FREE_PRESETS
));
657 bool radio_delete_preset(void)
659 struct menu_item menu
[MAX_PRESETS
];
662 bool reload_dir
= false;
669 for(i
= 0;i
< MAX_PRESETS
;i
++)
671 if(presets
[i
].frequency
)
673 menu
[num_presets
].desc
= presets
[i
].name
;
674 menu
[num_presets
].voice_id
= -1;
675 /* We use the function pointer entry for the preset
677 menu
[num_presets
++].function
= (void *)i
;
681 /* DIY menu handling, since we want to exit after selection */
682 m
= menu_init( menu
, num_presets
, NULL
, NULL
, NULL
, NULL
);
683 result
= menu_show(m
);
685 if (result
== MENU_SELECTED_EXIT
)
687 else if (result
== MENU_ATTACHED_USB
)
692 i
= (int)menu
[result
].function
;
693 presets
[i
].frequency
= 0;
694 radio_save_presets();
701 static bool fm_recording_settings(void)
705 ret
= recording_menu(true);
708 if (global_settings
.rec_prerecord_time
)
709 talk_buffer_steal(); /* will use the mp3 buffer */
711 mpeg_set_recording_options(global_settings
.rec_frequency
,
712 global_settings
.rec_quality
,
714 global_settings
.rec_channels
,
715 global_settings
.rec_editable
,
716 global_settings
.rec_prerecord_time
);
721 bool radio_menu(void)
723 struct menu_item radio_menu_items
[] = {
724 { STR(LANG_FM_SAVE_PRESET
), radio_add_preset
},
725 { STR(LANG_FM_DELETE_PRESET
), radio_delete_preset
},
726 { STR(LANG_SOUND_SETTINGS
), sound_menu
},
727 { STR(LANG_RECORDING_SETTINGS
), fm_recording_settings
}
732 m
= menu_init( radio_menu_items
,
733 sizeof radio_menu_items
/ sizeof(struct menu_item
), NULL
,
735 result
= menu_run(m
);