From a2ee6a66814191c851efb043802740b4d8d1ab0e Mon Sep 17 00:00:00 2001 From: Michael Sevakis Date: Fri, 16 Mar 2007 14:40:40 +0000 Subject: FM Radio mishmash: Make a quieter screen for the SWCODEC targets esp. for the benefit of x5; I wasn't sure if it was good to alter timeouts for HW codec. Simplify things and prepare for eventual scanning and tuning changes (which should help quiet x5 down even more). Make things behave themselves better in general. Enable SWCODEC FM Recording menu and screen for sim as a bonus. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12804 a1c6a512-1295-4272-9138-f99709370657 --- apps/debug_menu.c | 28 +- apps/recorder/radio.c | 637 ++++++++++++++++++++++--------------------- apps/recorder/radio.h | 10 +- firmware/export/tuner.h | 59 +++- firmware/tuner_philips.c | 23 +- firmware/tuner_samsung.c | 19 +- uisimulator/common/fmradio.c | 10 +- 7 files changed, 449 insertions(+), 337 deletions(-) diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 996f13d55c..71094c0dd9 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c @@ -2074,7 +2074,6 @@ static bool dbg_fm_radio(void) while(1) { int row = 0; - unsigned long regs; lcd_clear_display(); fm_detected = radio_hardware_present(); @@ -2083,16 +2082,31 @@ static bool dbg_fm_radio(void) lcd_puts(0, row++, buf); #if (CONFIG_TUNER & S1A0903X01) - regs = samsung_get(RADIO_ALL); - snprintf(buf, sizeof buf, "Samsung regs: %08lx", regs); + snprintf(buf, sizeof buf, "Samsung regs: %08X", + samsung_get(RADIO_ALL)); lcd_puts(0, row++, buf); #endif #if (CONFIG_TUNER & TEA5767) - regs = philips_get(RADIO_ALL); - snprintf(buf, sizeof buf, "Philips regs: %08lx", regs); - lcd_puts(0, row++, buf); + { + struct philips_dbg_info info; + philips_dbg_info(&info); + + snprintf(buf, sizeof buf, "Philips regs:"); + lcd_puts(0, row++, buf); + + snprintf(buf, sizeof buf, " Read: %02X %02X %02X %02X %02X", + (unsigned)info.read_regs[0], (unsigned)info.read_regs[1], + (unsigned)info.read_regs[2], (unsigned)info.read_regs[3], + (unsigned)info.read_regs[4]); + lcd_puts(0, row++, buf); + + snprintf(buf, sizeof buf, " Write: %02X %02X %02X %02X %02X", + (unsigned)info.write_regs[0], (unsigned)info.write_regs[1], + (unsigned)info.write_regs[2], (unsigned)info.write_regs[3], + (unsigned)info.write_regs[4]); + lcd_puts(0, row++, buf); + } #endif - lcd_update(); if (action_userabort(HZ)) diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c index 7258840dbf..8b79f2c9e7 100644 --- a/apps/recorder/radio.c +++ b/apps/recorder/radio.c @@ -20,12 +20,13 @@ #include "config.h" #include #include +#include #include "sprintf.h" #include "mas.h" #include "settings.h" #include "button.h" #include "status.h" -#include "kernel.h" +#include "thread.h" #include "mpeg.h" #include "audio.h" #include "mp3_playback.h" @@ -47,7 +48,6 @@ #include "recording.h" #include "talk.h" #include "tuner.h" -#include "hwcompat.h" #include "power.h" #include "sound.h" #include "screen_access.h" @@ -82,6 +82,10 @@ #elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) #define FM_PRESET #define FM_MODE +/* This should be removeable if the whole tuning thing is sorted out since + proper tuning quiets the screen almost entirely in that extreme measures + have to be taken to hear any interference. */ +#define HAVE_NOISY_IDLE_MODE #elif CONFIG_KEYPAD == ONDIO_PAD #define FM_RECORD_DBLPRE @@ -91,26 +95,12 @@ #define RADIO_SCAN_MODE 0 #define RADIO_PRESET_MODE 1 -#if (CONFIG_TUNER & TEA5767) -#define DEEMPH_50 0, -#define DEEMPH_75 1, -#define BAND_LIM_EU 0 -#define BAND_LIM_JP 1 -#else -#define DEEMPH_50 -#define DEEMPH_75 -#define BAND_LIM_EU -#define BAND_LIM_JP -#endif -static struct fm_region_setting fm_region[] = { - /* Europe */ - { 87500000, 108000000, 50000, DEEMPH_50 BAND_LIM_EU }, - /* US / Canada */ - { 87900000, 107900000, 200000, DEEMPH_75 BAND_LIM_EU }, - /* Japan */ - { 76000000, 90000000, 100000, DEEMPH_50 BAND_LIM_JP }, - /* Korea */ - { 87500000, 108000000, 100000, DEEMPH_50 BAND_LIM_EU }, +static const struct fm_region_setting fm_region[] = { + /* Note: Desriptive strings are just for display atm and are not compiled. */ + FM_REGION_ENTRY("Europe", 87500000, 108000000, 50000, 0, 0), + FM_REGION_ENTRY("US/Canada", 87900000, 107900000, 200000, 1, 0), + FM_REGION_ENTRY("Japan", 76000000, 90000000, 100000, 0, 1), + FM_REGION_ENTRY("Korea", 87500000, 108000000, 100000, 0, 0), }; static int curr_preset = -1; @@ -138,22 +128,6 @@ static int clear_preset_list(void); static int scan_presets(void); -#ifdef SIMULATOR -void radio_set(int setting, int value); -int radio_get(int setting); -#else -#if CONFIG_TUNER == S1A0903X01 /* FM recorder */ -#define radio_set samsung_set -#define radio_get samsung_get -#elif CONFIG_TUNER == TEA5767 /* iriver, iaudio */ -#define radio_set philips_set -#define radio_get philips_get -#elif CONFIG_TUNER == (S1A0903X01 | TEA5767) /* OndioFM */ -static void (*radio_set)(int setting, int value); -static int (*radio_get)(int setting); -#endif -#endif - /* Function to manipulate all yesno dialogues. This function needs the output text as an argument. */ static bool yesno_pop(char* text) @@ -169,25 +143,10 @@ static bool yesno_pop(char* text) void radio_init(void) { -#ifndef SIMULATOR -#if CONFIG_TUNER == (S1A0903X01 | TEA5767) - if (read_hw_mask() & TUNER_MODEL) - { - radio_set = philips_set; - radio_get = philips_get; - } - else - { - radio_set = samsung_set; - radio_get = samsung_get; - } -#endif -#endif + tuner_init(); radio_stop(); } -/* For powermgmt.c to check status for shutdown since it can't access - the global_status structure directly. */ int get_radio_status(void) { return radio_status; @@ -202,12 +161,15 @@ bool in_radio_screen(void) #define FMRADIO_START_PAUSED 0x8000 void radio_start(void) { + const struct fm_region_setting *fmr; bool start_paused; int mute_timeout; if(radio_status == FMRADIO_PLAYING) return; + fmr = &fm_region[global_settings.fm_region]; + start_paused = radio_status & FMRADIO_START_PAUSED; /* clear flag before any yielding */ radio_status &= ~FMRADIO_START_PAUSED; @@ -216,21 +178,21 @@ void radio_start(void) radio_power(true); curr_freq = global_status.last_frequency - * fm_region[global_settings.fm_region].freq_step - + fm_region[global_settings.fm_region].freq_min; + * fmr->freq_step + fmr->freq_min; radio_set(RADIO_SLEEP, 0); /* wake up the tuner */ radio_set(RADIO_FREQUENCY, curr_freq); if(radio_status == FMRADIO_OFF) { +#if (CONFIG_TUNER & S1A0903X01) radio_set(RADIO_IF_MEASUREMENT, 0); radio_set(RADIO_SENSITIVITY, 0); +#endif radio_set(RADIO_FORCE_MONO, global_settings.fm_force_mono); #if (CONFIG_TUNER & TEA5767) - radio_set(RADIO_SET_DEEMPHASIS, - fm_region[global_settings.fm_region].deemphasis); - radio_set(RADIO_SET_BAND, fm_region[global_settings.fm_region].band); + radio_set(RADIO_SET_DEEMPHASIS, fmr->deemphasis); + radio_set(RADIO_SET_BAND, fmr->band); #endif mute_timeout = current_tick + 1*HZ; } @@ -295,6 +257,25 @@ bool radio_hardware_present(void) #endif } +/* Keep freq on the grid for the current region */ +static int snap_freq_to_grid(int freq) +{ + const struct fm_region_setting * const fmr = + &fm_region[global_settings.fm_region]; + + /* Range clamp if out of range or just round to nearest */ + if (freq < fmr->freq_min) + freq = fmr->freq_min; + else if (freq > fmr->freq_max) + freq = fmr->freq_max; + else + freq = (freq - fmr->freq_min + fmr->freq_step/2) / + fmr->freq_step * fmr->freq_step + fmr->freq_min; + + return freq; +} + +/* Find a matching preset to freq */ static int find_preset(int freq) { int i; @@ -309,35 +290,43 @@ static int find_preset(int freq) return -1; } -static int find_closest_preset(int freq) +/* Return the first preset encountered in the search direction with + wraparound. */ +static int find_closest_preset(int freq, int direction) { - int i; - int diff; - int min_diff = fm_region[global_settings.fm_region].freq_min; - int preset = -1; + int i; - for(i = 0;i < MAX_PRESETS;i++) + if (direction == 0) /* direction == 0 isn't really used */ + return 0; + + for (i = 0; i < MAX_PRESETS; i++) { - diff = freq - presets[i].frequency; - if(diff==0) - return i; - if(diff < 0) - diff = -diff; - if(diff < min_diff) - { - preset = i; - min_diff = diff; - } + int preset_frequency = presets[i].frequency; + + if (preset_frequency == freq) + return i; /* Exact match = stop */ + /* Stop when the preset frequency exeeds freq so that we can + pick the correct one based on direction */ + if (preset_frequency > freq) + break; } - return preset; + /* wrap around depending on direction */ + if (i == 0 || i >= num_presets - 1) + i = direction < 0 ? num_presets - 1 : 0; + else if (direction < 0) + i--; /* use previous */ + + return i; } static void remember_frequency(void) { - global_status.last_frequency = (curr_freq - - fm_region[global_settings.fm_region].freq_min) - / fm_region[global_settings.fm_region].freq_step; + const struct fm_region_setting * const fmr = + &fm_region[global_settings.fm_region]; + + global_status.last_frequency = (curr_freq - fmr->freq_min) + / fmr->freq_step; status_save(); } @@ -346,60 +335,104 @@ static void next_preset(int direction) if (num_presets < 1) return; - if(curr_preset == -1) - curr_preset = find_closest_preset(curr_freq); - - if(direction > 0) - if(curr_preset == num_presets - 1) - curr_preset = 0; - else - curr_preset++; + if (curr_preset == -1) + curr_preset = find_closest_preset(curr_freq, direction); else - if(curr_preset == 0) - curr_preset = num_presets - 1; - else - curr_preset--; - - curr_freq = presets[curr_preset].frequency; + curr_preset = (curr_preset + direction + num_presets) % num_presets; + + /* Must stay on the current grid for the region */ + curr_freq = snap_freq_to_grid(presets[curr_preset].frequency); + radio_set(RADIO_FREQUENCY, curr_freq); remember_frequency(); } +/* Step to the next or previous frequency */ +static int step_freq(int freq, int direction) +{ + const struct fm_region_setting * const fmr = + &fm_region[global_settings.fm_region]; + + freq += direction*fmr->freq_step; + + /* Wrap first or snapping to grid will not let us on the band extremes */ + if (freq > fmr->freq_max) + freq = direction > 0 ? fmr->freq_min : fmr->freq_max; + else if (freq < fmr->freq_min) + freq = direction < 0 ? fmr->freq_max : fmr->freq_min; + else + freq = snap_freq_to_grid(freq); + + return freq; +} + +/* Step to the next or previous station */ +static void next_station(int direction) +{ + if (direction != 0 && radio_mode != RADIO_SCAN_MODE) + { + next_preset(direction); + return; + } + + curr_freq = step_freq(curr_freq, direction); + + if (radio_status == FMRADIO_PLAYING) + radio_set(RADIO_MUTE, 1); + + radio_set(RADIO_FREQUENCY, curr_freq); + + if (radio_status == FMRADIO_PLAYING) + radio_set(RADIO_MUTE, 0); + + curr_preset = find_preset(curr_freq); + remember_frequency(); +} int radio_screen(void) { char buf[MAX_PATH]; bool done = false; - int button, lastbutton = BUTTON_NONE; int ret_val = GO_TO_ROOT; -#ifdef FM_RECORD_DBLPRE - unsigned long rec_lastclick = 0; -#endif - int freq, i; - bool tuned; - bool stereo = false; + int button; + int i; int search_dir = 0; + bool stereo = false, last_stereo = false; int fh; - bool last_stereo_status = false; int top_of_screen = 0; bool update_screen = true; - int timeout = current_tick + HZ/10; bool screen_freeze = false; + bool keep_playing = false; + bool statusbar = global_settings.statusbar; +#ifdef FM_RECORD_DBLPRE + int lastbutton = BUTTON_NONE; + unsigned long rec_lastclick = 0; +#endif +#if CONFIG_CODEC != SWCODEC bool have_recorded = false; + int timeout = current_tick + HZ/10; unsigned int seconds = 0; unsigned int last_seconds = 0; -#if CONFIG_CODEC != SWCODEC int hours, minutes; struct audio_recording_options rec_options; -#endif - bool keep_playing = false; - bool statusbar = global_settings.statusbar; +#endif /* CONFIG_CODEC != SWCODEC */ +#ifndef HAVE_NOISY_IDLE_MODE int button_timeout = current_tick + (2*HZ); +#endif #ifdef HAS_BUTTONBAR struct gui_buttonbar buttonbar; gui_buttonbar_init(&buttonbar); gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) ); #endif + + /* Ends an in-progress search - needs access to search_dir */ + void end_search(void) + { + if (search_dir != 0 && radio_status == FMRADIO_PLAYING) + radio_set(RADIO_MUTE, 0); + search_dir = 0; + } + /* change status to "in screen" */ in_screen = true; @@ -419,7 +452,7 @@ int radio_screen(void) if(fh < 10) top_of_screen = 1; - if(!num_presets) + if(num_presets <= 0) { memset(presets, 0, sizeof(presets)); radio_load_presets(global_settings.fmr_file); @@ -461,8 +494,7 @@ int radio_screen(void) radio_start(); #endif - /* I hate this thing with vehement passion (jhMikeS): */ - if(num_presets == 0 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN))) + if(num_presets < 1 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN))) scan_presets(); curr_preset = find_preset(curr_freq); @@ -474,50 +506,44 @@ int radio_screen(void) str(LANG_FM_BUTTONBAR_PRESETS), str(LANG_FM_BUTTONBAR_RECORD)); #endif +#ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(true); - +#endif + while(!done) { - if(search_dir) + if(search_dir != 0) { - curr_freq += search_dir - * fm_region[global_settings.fm_region].freq_step; - if(curr_freq < fm_region[global_settings.fm_region].freq_min) - curr_freq = fm_region[global_settings.fm_region].freq_max; - if(curr_freq > fm_region[global_settings.fm_region].freq_max) - curr_freq = fm_region[global_settings.fm_region].freq_min; - - /* Tune in and delay */ - radio_set(RADIO_FREQUENCY, curr_freq); - sleep(1); - - /* Start IF measurement */ - radio_set(RADIO_IF_MEASUREMENT, 1); - sleep(1); - - /* Now check how close to the IF frequency we are */ - tuned = radio_get(RADIO_TUNED); + curr_freq = step_freq(curr_freq, search_dir); + update_screen = true; - /* Stop searching if the tuning is close */ - if(tuned) + if(radio_set(RADIO_SCAN_FREQUENCY, curr_freq)) { - search_dir = 0; curr_preset = find_preset(curr_freq); remember_frequency(); + end_search(); } - - update_screen = true; + + trigger_cpu_boost(); } - if(search_dir) - button = button_get(false); - else - button = get_action(CONTEXT_FM, HZ / PEAK_METER_FPS); +#if CONFIG_CODEC != SWCODEC + /* TODO: Can we timeout at HZ when recording since peaks aren't + displayed? This should quiet recordings too. */ + button = get_action(CONTEXT_FM, + update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS); +#else + button = get_action(CONTEXT_FM, + update_screen ? TIMEOUT_NOBLOCK : HZ); +#endif + +#ifndef HAVE_NOISY_IDLE_MODE if (button != ACTION_NONE) { cpu_idle_mode(false); button_timeout = current_tick + (2*HZ); } +#endif switch(button) { case ACTION_FM_STOP: @@ -559,7 +585,7 @@ int radio_screen(void) rec_lastclick = current_tick; break; } -#endif +#endif /* FM_RECORD_DBLPRE */ #ifndef SIMULATOR if(audio_status() == AUDIO_STATUS_RECORD) { @@ -572,7 +598,7 @@ int radio_screen(void) rec_record(); update_screen = true; } -#endif +#endif /* SIMULATOR */ last_seconds = 0; break; #endif /* #ifdef FM_RECORD */ @@ -602,63 +628,31 @@ int radio_screen(void) break; case ACTION_STD_PREV: - if(radio_mode == RADIO_SCAN_MODE) - { - curr_freq - -= fm_region[global_settings.fm_region].freq_step; - if(curr_freq < fm_region[global_settings.fm_region].freq_min) - curr_freq - = fm_region[global_settings.fm_region].freq_max; - radio_set(RADIO_FREQUENCY, curr_freq); - curr_preset = find_preset(curr_freq); - remember_frequency(); - } - else - next_preset(-1); - search_dir = 0; - update_screen = true; - break; - case ACTION_STD_NEXT: - if(radio_mode == RADIO_SCAN_MODE) - { - curr_freq - += fm_region[global_settings.fm_region].freq_step; - if(curr_freq > fm_region[global_settings.fm_region].freq_max) - curr_freq - = fm_region[global_settings.fm_region].freq_min; - radio_set(RADIO_FREQUENCY, curr_freq); - curr_preset = find_preset(curr_freq); - remember_frequency(); - } - else - next_preset(1); - search_dir = 0; + next_station(button == ACTION_STD_PREV ? -1 : 1); + end_search(); update_screen = true; break; case ACTION_STD_PREVREPEAT: - if(radio_mode == RADIO_SCAN_MODE) - search_dir = -1; - else + case ACTION_STD_NEXTREPEAT: + { + int dir = search_dir; + search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1; + if (radio_mode != RADIO_SCAN_MODE) { - next_preset(-1); + next_preset(search_dir); + end_search(); update_screen = true; } - - break; - - case ACTION_STD_NEXTREPEAT: - if(radio_mode == RADIO_SCAN_MODE) - search_dir = 1; - else + else if (dir == 0) { - next_preset(1); + /* Starting auto scan */ + radio_set(RADIO_MUTE, 1); update_screen = true; } - break; - + } case ACTION_SETTINGS_INC: case ACTION_SETTINGS_INCREPEAT: @@ -693,8 +687,9 @@ int radio_screen(void) radio_menu(); curr_preset = find_preset(curr_freq); FOR_NB_SCREENS(i){ - gui_textarea_clear(&screens[i]); - screen_set_xmargin(&screens[i],0); + struct screen *sc = &screens[i]; + gui_textarea_clear(sc); + screen_set_xmargin(sc, 0); } #ifdef HAS_BUTTONBAR gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU), @@ -712,9 +707,10 @@ int radio_screen(void) update_screen = true; FOR_NB_SCREENS(i) { - gui_textarea_clear(&screens[i]); - screen_set_xmargin(&screens[i],0); - gui_textarea_update(&screens[i]); + struct screen *sc = &screens[i]; + gui_textarea_clear(sc); + screen_set_xmargin(sc, 0); + gui_textarea_update(sc); } break; @@ -722,9 +718,10 @@ int radio_screen(void) handle_radio_presets(); FOR_NB_SCREENS(i) { - gui_textarea_clear(&screens[i]); - screen_set_xmargin(&screens[i],0); - gui_textarea_update(&screens[i]); + struct screen *sc = &screens[i]; + gui_textarea_clear(sc); + screen_set_xmargin(sc, 0); + gui_textarea_update(sc); } #ifdef HAS_BUTTONBAR gui_buttonbar_set(&buttonbar, @@ -734,7 +731,7 @@ int radio_screen(void) #endif update_screen = true; break; -#endif +#endif /* FM_PRESET */ #ifdef FM_FREEZE case ACTION_FM_FREEZE: @@ -749,10 +746,13 @@ int radio_screen(void) screen_freeze = false; } break; -#endif +#endif /* FM_FREEZE */ + case SYS_USB_CONNECTED: +#if CONFIG_CODEC != SWCODEC /* Only accept USB connection when not recording */ if(audio_status() != AUDIO_STATUS_RECORD) +#endif { default_event_handler(SYS_USB_CONNECTED); screen_freeze = true; /* Cosmetic: makes sure the @@ -773,18 +773,20 @@ int radio_screen(void) radio_mode = RADIO_SCAN_MODE; update_screen = true; break; -#endif +#endif /* FM_MODE */ + #ifdef FM_NEXT_PRESET case ACTION_FM_NEXT_PRESET: next_preset(1); - search_dir = 0; + end_search(); update_screen = true; break; #endif + #ifdef FM_PREV_PRESET case ACTION_FM_PREV_PRESET: next_preset(-1); - search_dir = 0; + end_search(); update_screen = true; break; #endif @@ -794,8 +796,10 @@ int radio_screen(void) break; } /*switch(button)*/ +#ifdef FM_RECORD_DBLPRE if (button != ACTION_NONE) lastbutton = button; +#endif #if CONFIG_CODEC != SWCODEC peak_meter_peek(); @@ -804,10 +808,9 @@ int radio_screen(void) if(!screen_freeze) { /* Only display the peak meter when not recording */ +#if CONFIG_CODEC != SWCODEC if(!audio_status()) { - -#if CONFIG_CODEC != SWCODEC FOR_NB_SCREENS(i) { peak_meter_screen(&screens[i],0, @@ -815,44 +818,46 @@ int radio_screen(void) screens[i].update_rect(0, STATUSBAR_HEIGHT + fh*(top_of_screen + 4), screens[i].width, fh); } -#endif - } if(TIME_AFTER(current_tick, timeout)) { timeout = current_tick + HZ; +#else /* SWCODEC */ + { +#endif /* CONFIG_CODEC == SWCODEC */ /* keep "mono" from always being displayed when paused */ if (radio_status != FMRADIO_PAUSED) { stereo = radio_get(RADIO_STEREO) && !global_settings.fm_force_mono; - if(stereo != last_stereo_status) + + if(stereo != last_stereo) { update_screen = true; - last_stereo_status = stereo; + last_stereo = stereo; } } } - -#ifndef SIMULATOR -#if CONFIG_CODEC != SWCODEC + +#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR) seconds = audio_recorded_time() / HZ; -#endif -#endif - if(update_screen || seconds > last_seconds) + if (update_screen || seconds > last_seconds) { last_seconds = seconds; +#else + if (update_screen) + { +#endif + int freq; FOR_NB_SCREENS(i) screens[i].setfont(FONT_UI); - if (curr_preset >= 0 ) - snprintf(buf, 128, "%d. %s",curr_preset + 1, - presets[curr_preset].name); - else - snprintf(buf, 128, " "); + snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ", + curr_preset + 1, presets[curr_preset].name); + FOR_NB_SCREENS(i) screens[i].puts_scroll(0, top_of_screen, buf); @@ -871,6 +876,7 @@ int radio_screen(void) str(LANG_RADIO_SCAN_MODE)); FOR_NB_SCREENS(i) screens[i].puts_scroll(0, top_of_screen + 3, buf); + #if CONFIG_CODEC != SWCODEC if(audio_status() == AUDIO_STATUS_RECORD) { @@ -892,7 +898,7 @@ int radio_screen(void) screens[i].puts_scroll(0, top_of_screen + 4, buf); } } -#endif +#endif /* CONFIG_CODEC != SWCODEC */ #ifdef HAS_BUTTONBAR gui_buttonbar_draw(&buttonbar); @@ -902,21 +908,27 @@ int radio_screen(void) } /* Only force the redraw if update_screen is true */ gui_syncstatusbar_draw(&statusbars,true); - - update_screen = false; } + update_screen = false; + +#if CONFIG_CODEC != SWCODEC if(audio_status() & AUDIO_STATUS_ERROR) { done = true; } +#endif + +#ifndef HAVE_NOISY_IDLE_MODE if (TIME_AFTER(current_tick, button_timeout)) { cpu_idle_mode(true); } +#endif } /*while(!done)*/ #ifndef SIMULATOR +#if CONFIG_CODEC != SWCODEC if(audio_status() & AUDIO_STATUS_ERROR) { gui_syncsplash(0, true, str(LANG_DISK_FULL)); @@ -933,16 +945,15 @@ int radio_screen(void) } } -#if CONFIG_CODEC != SWCODEC audio_init_playback(); -#endif +#endif /* CONFIG_CODEC != SWCODEC */ sound_settings_apply(); #endif /* SIMULATOR */ if(keep_playing) { -/* Catch FMRADIO_PLAYING status for the sim. */ +/* Catch FMRADIO_PLAYING status for the sim. */ #ifndef SIMULATOR #if CONFIG_CODEC != SWCODEC /* Enable the Left and right A/D Converter */ @@ -951,7 +962,8 @@ int radio_screen(void) AUDIO_GAIN_LINEIN); mas_codec_writereg(6, 0x4000); #endif -#endif + end_search(); +#endif /* SIMULATOR */ } else { @@ -961,15 +973,20 @@ int radio_screen(void) radio_stop(); #endif } - + +#ifndef HAVE_NOISY_IDLE_MODE cpu_idle_mode(false); +#endif /* restore status bar settings */ global_settings.statusbar = statusbar; in_screen = false; - +#if CONFIG_CODEC != SWCODEC return have_recorded; +#else + return false; +#endif } /* radio_screen */ static void radio_save_presets(void) @@ -1006,7 +1023,6 @@ void radio_load_presets(char *filename) bool done = false; int f; - memset(presets, 0, sizeof(presets)); num_presets = 0; @@ -1037,9 +1053,10 @@ void radio_load_presets(char *filename) f = atoi(freq); if(f) /* For backwards compatibility */ { - presets[num_presets].frequency = f; - strncpy(presets[num_presets].name, name, MAX_FMPRESET_LEN); - presets[num_presets].name[MAX_FMPRESET_LEN] = 0; + struct fmstation * const fms = &presets[num_presets]; + fms->frequency = f; + strncpy(fms->name, name, MAX_FMPRESET_LEN); + fms->name[MAX_FMPRESET_LEN] = '\0'; num_presets++; } } @@ -1051,12 +1068,8 @@ void radio_load_presets(char *filename) } else /* invalid file name? */ filepreset[0] = '\0'; - - if(num_presets > 0) - presets_loaded = true; - else - presets_loaded = false; - + + presets_loaded = num_presets > 0; presets_changed = false; } @@ -1071,13 +1084,13 @@ static int radio_add_preset(void) if (!kbd_input(buf, MAX_FMPRESET_LEN)) { - buf[MAX_FMPRESET_LEN] = 0; - strcpy(presets[num_presets].name, buf); - presets[num_presets].frequency = curr_freq; + struct fmstation * const fms = &presets[num_presets]; + buf[MAX_FMPRESET_LEN] = '\0'; + strcpy(fms->name, buf); + fms->frequency = curr_freq; num_presets++; presets_changed = true; - if(num_presets > 0) - presets_loaded = true; + presets_loaded = num_presets > 0; } } else @@ -1088,43 +1101,53 @@ static int radio_add_preset(void) } /* needed to know which preset we are edit/delete-ing */ -static int selected_preset = 0; +static int selected_preset = -1; static int radio_edit_preset(void) { char buf[MAX_FMPRESET_LEN]; - strncpy(buf, presets[selected_preset].name, MAX_FMPRESET_LEN); - - if (!kbd_input(buf, MAX_FMPRESET_LEN)) + if (num_presets > 0) { - buf[MAX_FMPRESET_LEN] = 0; - strcpy(presets[selected_preset].name, buf); - presets_changed = true; + struct fmstation * const fms = &presets[selected_preset]; + + strncpy(buf, fms->name, MAX_FMPRESET_LEN); + + if (!kbd_input(buf, MAX_FMPRESET_LEN)) + { + buf[MAX_FMPRESET_LEN] = '\0'; + strcpy(fms->name, buf); + presets_changed = true; + } } + return true; } static int radio_delete_preset(void) { - int pos = selected_preset; - int i; + if (num_presets > 0) + { + struct fmstation * const fms = &presets[selected_preset]; + + if (selected_preset >= --num_presets) + selected_preset = num_presets - 1; - for(i = pos;i < num_presets;i++) - presets[i] = presets[i+1]; - num_presets--; + memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) - + (uintptr_t)fms); + + } /* Don't ask to save when all presets are deleted. */ - if(num_presets > 0) - presets_changed = true; - else + presets_changed = num_presets > 0; + + if (!presets_changed) { - presets_changed = false; /* The preset list will be cleared, switch to Scan Mode. */ radio_mode = RADIO_SCAN_MODE; presets_loaded = false; } - return true; /* Make the menu return immediately */ + return true; } static int load_preset_list(void) @@ -1134,7 +1157,7 @@ static int load_preset_list(void) static int save_preset_list(void) { - if(num_presets != 0) + if(num_presets > 0) { bool bad_file_name = true; @@ -1187,13 +1210,8 @@ static int save_preset_list(void) static int clear_preset_list(void) { - int i; - /* Clear all the preset entries */ - for(i = 0;i <= num_presets;i++){ - presets[i].name[0] = '\0'; - presets[i].frequency = 0; - } + memset(presets, 0, sizeof (presets)); num_presets = 0; presets_loaded = false; @@ -1211,10 +1229,10 @@ MENUITEM_FUNCTION(radio_delete_preset_item, ID2P(LANG_FM_DELETE_PRESET), radio_delete_preset, NULL, Icon_NOICON); int radio_preset_callback(int action, const struct menu_item_ex *this_item) { - (void)this_item; if (action == ACTION_STD_OK) - return ACTION_EXIT_AFTER_THIS_MENUITEM; + action = ACTION_EXIT_AFTER_THIS_MENUITEM; return action; + (void)this_item; } MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_FM_BUTTONBAR_PRESETS), radio_preset_callback, Icon_NOICON, &radio_edit_preset_item, @@ -1272,7 +1290,7 @@ static int handle_radio_presets(void) case ACTION_STD_OK: curr_preset = gui_synclist_get_sel_pos(&lists); curr_freq = presets[curr_preset].frequency; - radio_set(RADIO_FREQUENCY, curr_freq); + next_station(0); remember_frequency(); result = 1; break; @@ -1302,15 +1320,7 @@ void set_radio_region(int region) fm_region[region].deemphasis); radio_set(RADIO_SET_BAND, fm_region[region].band); #endif - /* make sure the current frequency is in the region range */ - curr_freq -= (curr_freq - fm_region[region].freq_min) - % fm_region[region].freq_step; - if(curr_freq < fm_region[region].freq_min) - curr_freq = fm_region[region].freq_min; - if(curr_freq > fm_region[region].freq_max) - curr_freq = fm_region[region].freq_max; - radio_set(RADIO_FREQUENCY, curr_freq); - + next_station(0); remember_frequency(); } @@ -1340,52 +1350,52 @@ MENUITEM_FUNCTION_WPARAM_DYNTEXT(radio_mode_item, toggle_radio_mode, NULL, NULL, static int scan_presets(void) { - bool tuned = false, do_scan = true; - char buf[MAX_FMPRESET_LEN]; - int freq, i; + bool do_scan = true; if(num_presets > 0) /* Do that to avoid 2 questions. */ do_scan = yesno_pop(str(LANG_FM_CLEAR_PRESETS)); if(do_scan) { - curr_freq = fm_region[global_settings.fm_region].freq_min; + const struct fm_region_setting * const fmr = + &fm_region[global_settings.fm_region]; + char buf[MAX_FMPRESET_LEN]; + int i; + + curr_freq = fmr->freq_min; num_presets = 0; memset(presets, 0, sizeof(presets)); - while(curr_freq <= fm_region[global_settings.fm_region].freq_max) + radio_set(RADIO_MUTE, 1); + + while(curr_freq <= fmr->freq_max) { + int freq, frac; if (num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK)) break; freq = curr_freq / 10000; - snprintf(buf, MAX_FMPRESET_LEN, str(LANG_FM_SCANNING), - freq/100, freq % 100); + frac = freq % 100; + freq /= 100; + + snprintf(buf, MAX_FMPRESET_LEN, str(LANG_FM_SCANNING), freq, frac); gui_syncsplash(0, true, buf); - /* Tune in and delay */ - radio_set(RADIO_FREQUENCY, curr_freq); - sleep(1); - - /* Start IF measurement */ - radio_set(RADIO_IF_MEASUREMENT, 1); - sleep(1); - - /* Now check how close to the IF frequency we are */ - tuned = radio_get(RADIO_TUNED); - - /* add preset */ - if(tuned){ - snprintf(buf, MAX_FMPRESET_LEN, - str(LANG_FM_DEFAULT_PRESET_NAME),freq/100, freq % 100); - strcpy(presets[num_presets].name,buf); - presets[num_presets].frequency = curr_freq; - num_presets++; + if(radio_set(RADIO_SCAN_FREQUENCY, curr_freq)) + { + /* add preset */ + snprintf(buf, MAX_FMPRESET_LEN, + str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac); + strcpy(presets[num_presets].name,buf); + presets[num_presets].frequency = curr_freq; + num_presets++; } - curr_freq += fm_region[global_settings.fm_region].freq_step; - + curr_freq += fmr->freq_step; } + if (radio_status == FMRADIO_PLAYING) + radio_set(RADIO_MUTE, 0); + presets_changed = true; FOR_NB_SCREENS(i) @@ -1395,22 +1405,24 @@ static int scan_presets(void) gui_textarea_update(&screens[i]); } - if(num_presets > 0 ) + if(num_presets > 0) { curr_freq = presets[0].frequency; - radio_set(RADIO_FREQUENCY, curr_freq); - remember_frequency(); radio_mode = RADIO_PRESET_MODE; presets_loaded = true; + next_station(0); } else + { + /* Wrap it to beginning or we'll be past end of band */ presets_loaded = false; + next_station(1); + } } return true; } -#ifndef SIMULATOR #ifdef HAVE_RECORDING #if defined(HAVE_FMRADIO_IN) && CONFIG_CODEC == SWCODEC @@ -1433,8 +1445,6 @@ static int fm_recording_screen(void) return ret; } -MENUITEM_FUNCTION(recscreen_item, ID2P(LANG_RECORDING_MENU), - fm_recording_screen, NULL, Icon_NOICON); #endif /* defined(HAVE_FMRADIO_IN) && CONFIG_CODEC == SWCODEC */ #if defined(HAVE_FMRADIO_IN) || CONFIG_CODEC != SWCODEC @@ -1442,6 +1452,7 @@ MENUITEM_FUNCTION(recscreen_item, ID2P(LANG_RECORDING_MENU), static int fm_recording_settings(void) { bool ret = recording_menu(true); + #if CONFIG_CODEC != SWCODEC if (!ret) { @@ -1454,11 +1465,17 @@ static int fm_recording_settings(void) return ret; } -MENUITEM_FUNCTION(recsettings_item, ID2P(LANG_RECORDING_SETTINGS), - fm_recording_settings, NULL, Icon_NOICON); #endif /* defined(HAVE_FMRADIO_IN) || CONFIG_CODEC != SWCODEC */ #endif /* HAVE_RECORDING */ -#endif /* SIMULATOR */ + +#ifdef FM_RECORDING_SCREEN +MENUITEM_FUNCTION(recscreen_item, ID2P(LANG_RECORDING_MENU), + fm_recording_screen, NULL, Icon_NOICON); +#endif +#ifdef FM_RECORDING_SETTINGS +MENUITEM_FUNCTION(recsettings_item, ID2P(LANG_RECORDING_SETTINGS), + fm_recording_settings, NULL, Icon_NOICON); +#endif #ifndef FM_PRESET MENUITEM_FUNCTION(radio_presets_item, ID2P(LANG_FM_BUTTONBAR_PRESETS), handle_radio_presets, NULL, Icon_NOICON); diff --git a/apps/recorder/radio.h b/apps/recorder/radio.h index add3989061..f04c14d6d3 100644 --- a/apps/recorder/radio.h +++ b/apps/recorder/radio.h @@ -50,8 +50,14 @@ struct fm_region_setting int freq_max; int freq_step; #if (CONFIG_TUNER & TEA5767) - int deemphasis; /* 0: 50us, 1: 75us */ - int band; /* 0: europe, 1: japan (BL in TEA spec)*/ + char deemphasis; /* 0: 50us, 1: 75us */ + char band; /* 0: europe, 1: japan (BL in TEA spec)*/ + /* Note: "region" parameter is just for display atm and is not compiled. */ + #define FM_REGION_ENTRY(region, fmin, fmax, fstep, deemph, band) \ + { fmin, fmax, fstep, deemph, band } +#else + #define FM_REGION_ENTRY(region, fmin, fmax, fstep, deemph, band) \ + { fmin, fmax, fstep } #endif }; diff --git a/firmware/export/tuner.h b/firmware/export/tuner.h index 0a13613711..590e61dedb 100644 --- a/firmware/export/tuner.h +++ b/firmware/export/tuner.h @@ -20,34 +20,81 @@ #ifndef __TUNER_SAMSUNG_H__ #define __TUNER_SAMSUNG_H__ +#include "hwcompat.h" + /* settings to the tuner layer */ +#define RADIO_ALL -1 /* debug */ #define RADIO_SLEEP 0 #define RADIO_FREQUENCY 1 #define RADIO_MUTE 2 #define RADIO_IF_MEASUREMENT 3 #define RADIO_SENSITIVITY 4 #define RADIO_FORCE_MONO 5 +#define RADIO_SCAN_FREQUENCY 6 #if (CONFIG_TUNER & TEA5767) -#define RADIO_SET_DEEMPHASIS 6 -#define RADIO_SET_BAND 7 +#define RADIO_SET_DEEMPHASIS 7 +#define RADIO_SET_BAND 8 #endif /* readback from the tuner layer */ #define RADIO_PRESENT 0 #define RADIO_TUNED 1 #define RADIO_STEREO 2 -#define RADIO_ALL 3 /* debug */ #if CONFIG_TUNER +#ifdef SIMULATOR +int radio_set(int setting, int value); +int radio_get(int setting); +#else +#if CONFIG_TUNER == S1A0903X01 /* FM recorder */ +#define radio_set samsung_set +#define radio_get samsung_get +#elif CONFIG_TUNER == TEA5767 /* iRiver, iAudio */ +#define radio_set philips_set +#define radio_get philips_get +#elif CONFIG_TUNER == (S1A0903X01 | TEA5767) /* OndioFM */ +#define radio_set _radio_set +#define radio_get _radio_get +int (*_radio_set)(int setting, int value); +int (*_radio_get)(int setting); +#endif +#endif + #if (CONFIG_TUNER & S1A0903X01) -void samsung_set(int setting, int value); +int samsung_set(int setting, int value); int samsung_get(int setting); -#endif +#endif /* CONFIG_TUNER & S1A0903X01 */ #if (CONFIG_TUNER & TEA5767) -void philips_set(int setting, int value); +struct philips_dbg_info +{ + unsigned char read_regs[5]; + unsigned char write_regs[5]; +}; +int philips_set(int setting, int value); int philips_get(int setting); +void philips_dbg_info(struct philips_dbg_info *info); +#endif /* CONFIG_TUNER & TEA5767 */ + +/* Just inline here since only radio screen needs this atm and + there's no tuner.c. */ +static inline void tuner_init(void) +{ +#ifndef SIMULATOR +#if CONFIG_TUNER == (S1A0903X01 | TEA5767) + if (read_hw_mask() & TUNER_MODEL) + { + _radio_set = philips_set; + _radio_get = philips_get; + } + else + { + _radio_set = samsung_set; + _radio_get = samsung_get; + } +#endif #endif +} #endif /* #if CONFIG_TUNER */ diff --git a/firmware/tuner_philips.c b/firmware/tuner_philips.c index 0a6f5c4c7f..8520fdbae9 100644 --- a/firmware/tuner_philips.c +++ b/firmware/tuner_philips.c @@ -29,7 +29,7 @@ static unsigned char write_bytes[5] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; /* tuner abstraction layer: set something to the tuner */ -void philips_set(int setting, int value) +int philips_set(int setting, int value) { switch(setting) { @@ -60,6 +60,11 @@ void philips_set(int setting, int value) } break; + case RADIO_SCAN_FREQUENCY: + philips_set(RADIO_FREQUENCY, value); + sleep(HZ/30); + return philips_get(RADIO_TUNED); + case RADIO_MUTE: write_bytes[0] = (write_bytes[0] & 0x7F) | (value ? 0x80 : 0); break; @@ -75,9 +80,10 @@ void philips_set(int setting, int value) case RADIO_SET_BAND: write_bytes[3] = (write_bytes[3] & ~(1<<5)) | (value ? (1<<5) : 0); default: - return; + return -1; } fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); + return 1; } /* tuner abstraction layer: read something from the tuner */ @@ -106,13 +112,12 @@ int philips_get(int setting) case RADIO_STEREO: val = read_bytes[2] >> 7; break; - - case RADIO_ALL: /* debug query */ - val = read_bytes[0] << 24 - | read_bytes[1] << 16 - | read_bytes[2] << 8 - | read_bytes[3]; - break; } return val; } + +void philips_dbg_info(struct philips_dbg_info *info) +{ + fmradio_i2c_read(I2C_ADR, info->read_regs, 5); + memcpy(info->write_regs, write_bytes, 5); +} diff --git a/firmware/tuner_samsung.c b/firmware/tuner_samsung.c index b0887d0d7a..82934d7160 100644 --- a/firmware/tuner_samsung.c +++ b/firmware/tuner_samsung.c @@ -21,6 +21,7 @@ #include #include #include "config.h" +#include "kernel.h" #include "tuner.h" /* tuner abstraction interface */ #include "fmradio.h" /* physical interface driver */ #include "mpeg.h" @@ -34,8 +35,10 @@ static int fm_in1; static int fm_in2; /* tuner abstraction layer: set something to the tuner */ -void samsung_set(int setting, int value) +int samsung_set(int setting, int value) { + int val = 1; + switch(setting) { case RADIO_SLEEP: @@ -90,6 +93,16 @@ void samsung_set(int setting, int value) break; } + case RADIO_SCAN_FREQUENCY: + /* Tune in and delay */ + samsung_set(RADIO_FREQUENCY, value); + sleep(1); + /* Start IF measurement */ + samsung_set(RADIO_IF_MEASUREMENT, 1); + sleep(1); + val = samsung_get(RADIO_TUNED); + break; + case RADIO_MUTE: fm_in1 = (fm_in1 & 0xfffffffe) | (value?1:0); fmradio_set(1, fm_in1); @@ -109,7 +122,11 @@ void samsung_set(int setting, int value) fm_in2 = (fm_in2 & 0xfffffffb) | (value?0:4); fmradio_set(2, fm_in2); break; + default: + val = -1; } + + return val; } /* tuner abstraction layer: read something from the tuner */ diff --git a/uisimulator/common/fmradio.c b/uisimulator/common/fmradio.c index ea6d6f6aa5..d7acaa513b 100644 --- a/uisimulator/common/fmradio.c +++ b/uisimulator/common/fmradio.c @@ -26,7 +26,7 @@ static int frequency = 0; static bool mono = false; -void radio_set(int setting, int value) +int radio_set(int setting, int value) { switch(setting) { @@ -37,6 +37,10 @@ void radio_set(int setting, int value) frequency = value; break; + case RADIO_SCAN_FREQUENCY: + frequency = value; + break; + case RADIO_MUTE: break; @@ -45,8 +49,10 @@ void radio_set(int setting, int value) break; default: - return; + return -1; } + + return 1; } int radio_get(int setting) -- cgit v1.2.3