summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2007-03-16 14:40:40 +0000
committerMichael Sevakis <jethead71@rockbox.org>2007-03-16 14:40:40 +0000
commita2ee6a66814191c851efb043802740b4d8d1ab0e (patch)
tree82dc1d505b3606e192241ded2d6626be14c71704
parenta91a35be74774742d8efc766a89ca33fcb880ab1 (diff)
downloadrockbox-a2ee6a66814191c851efb043802740b4d8d1ab0e.tar.gz
rockbox-a2ee6a66814191c851efb043802740b4d8d1ab0e.zip
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
-rw-r--r--apps/debug_menu.c28
-rw-r--r--apps/recorder/radio.c637
-rw-r--r--apps/recorder/radio.h10
-rw-r--r--firmware/export/tuner.h59
-rw-r--r--firmware/tuner_philips.c23
-rw-r--r--firmware/tuner_samsung.c19
-rw-r--r--uisimulator/common/fmradio.c10
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)
2074 while(1) 2074 while(1)
2075 { 2075 {
2076 int row = 0; 2076 int row = 0;
2077 unsigned long regs;
2078 2077
2079 lcd_clear_display(); 2078 lcd_clear_display();
2080 fm_detected = radio_hardware_present(); 2079 fm_detected = radio_hardware_present();
@@ -2083,16 +2082,31 @@ static bool dbg_fm_radio(void)
2083 lcd_puts(0, row++, buf); 2082 lcd_puts(0, row++, buf);
2084 2083
2085#if (CONFIG_TUNER & S1A0903X01) 2084#if (CONFIG_TUNER & S1A0903X01)
2086 regs = samsung_get(RADIO_ALL); 2085 snprintf(buf, sizeof buf, "Samsung regs: %08X",
2087 snprintf(buf, sizeof buf, "Samsung regs: %08lx", regs); 2086 samsung_get(RADIO_ALL));
2088 lcd_puts(0, row++, buf); 2087 lcd_puts(0, row++, buf);
2089#endif 2088#endif
2090#if (CONFIG_TUNER & TEA5767) 2089#if (CONFIG_TUNER & TEA5767)
2091 regs = philips_get(RADIO_ALL); 2090 {
2092 snprintf(buf, sizeof buf, "Philips regs: %08lx", regs); 2091 struct philips_dbg_info info;
2093 lcd_puts(0, row++, buf); 2092 philips_dbg_info(&info);
2093
2094 snprintf(buf, sizeof buf, "Philips regs:");
2095 lcd_puts(0, row++, buf);
2096
2097 snprintf(buf, sizeof buf, " Read: %02X %02X %02X %02X %02X",
2098 (unsigned)info.read_regs[0], (unsigned)info.read_regs[1],
2099 (unsigned)info.read_regs[2], (unsigned)info.read_regs[3],
2100 (unsigned)info.read_regs[4]);
2101 lcd_puts(0, row++, buf);
2102
2103 snprintf(buf, sizeof buf, " Write: %02X %02X %02X %02X %02X",
2104 (unsigned)info.write_regs[0], (unsigned)info.write_regs[1],
2105 (unsigned)info.write_regs[2], (unsigned)info.write_regs[3],
2106 (unsigned)info.write_regs[4]);
2107 lcd_puts(0, row++, buf);
2108 }
2094#endif 2109#endif
2095
2096 lcd_update(); 2110 lcd_update();
2097 2111
2098 if (action_userabort(HZ)) 2112 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 @@
20#include "config.h" 20#include "config.h"
21#include <stdio.h> 21#include <stdio.h>
22#include <stdbool.h> 22#include <stdbool.h>
23#include <stdlib.h>
23#include "sprintf.h" 24#include "sprintf.h"
24#include "mas.h" 25#include "mas.h"
25#include "settings.h" 26#include "settings.h"
26#include "button.h" 27#include "button.h"
27#include "status.h" 28#include "status.h"
28#include "kernel.h" 29#include "thread.h"
29#include "mpeg.h" 30#include "mpeg.h"
30#include "audio.h" 31#include "audio.h"
31#include "mp3_playback.h" 32#include "mp3_playback.h"
@@ -47,7 +48,6 @@
47#include "recording.h" 48#include "recording.h"
48#include "talk.h" 49#include "talk.h"
49#include "tuner.h" 50#include "tuner.h"
50#include "hwcompat.h"
51#include "power.h" 51#include "power.h"
52#include "sound.h" 52#include "sound.h"
53#include "screen_access.h" 53#include "screen_access.h"
@@ -82,6 +82,10 @@
82#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD) 82#elif (CONFIG_KEYPAD == IAUDIO_X5_PAD)
83#define FM_PRESET 83#define FM_PRESET
84#define FM_MODE 84#define FM_MODE
85/* This should be removeable if the whole tuning thing is sorted out since
86 proper tuning quiets the screen almost entirely in that extreme measures
87 have to be taken to hear any interference. */
88#define HAVE_NOISY_IDLE_MODE
85 89
86#elif CONFIG_KEYPAD == ONDIO_PAD 90#elif CONFIG_KEYPAD == ONDIO_PAD
87#define FM_RECORD_DBLPRE 91#define FM_RECORD_DBLPRE
@@ -91,26 +95,12 @@
91#define RADIO_SCAN_MODE 0 95#define RADIO_SCAN_MODE 0
92#define RADIO_PRESET_MODE 1 96#define RADIO_PRESET_MODE 1
93 97
94#if (CONFIG_TUNER & TEA5767) 98static const struct fm_region_setting fm_region[] = {
95#define DEEMPH_50 0, 99 /* Note: Desriptive strings are just for display atm and are not compiled. */
96#define DEEMPH_75 1, 100 FM_REGION_ENTRY("Europe", 87500000, 108000000, 50000, 0, 0),
97#define BAND_LIM_EU 0 101 FM_REGION_ENTRY("US/Canada", 87900000, 107900000, 200000, 1, 0),
98#define BAND_LIM_JP 1 102 FM_REGION_ENTRY("Japan", 76000000, 90000000, 100000, 0, 1),
99#else 103 FM_REGION_ENTRY("Korea", 87500000, 108000000, 100000, 0, 0),
100#define DEEMPH_50
101#define DEEMPH_75
102#define BAND_LIM_EU
103#define BAND_LIM_JP
104#endif
105static struct fm_region_setting fm_region[] = {
106 /* Europe */
107 { 87500000, 108000000, 50000, DEEMPH_50 BAND_LIM_EU },
108 /* US / Canada */
109 { 87900000, 107900000, 200000, DEEMPH_75 BAND_LIM_EU },
110 /* Japan */
111 { 76000000, 90000000, 100000, DEEMPH_50 BAND_LIM_JP },
112 /* Korea */
113 { 87500000, 108000000, 100000, DEEMPH_50 BAND_LIM_EU },
114 }; 104 };
115 105
116static int curr_preset = -1; 106static int curr_preset = -1;
@@ -138,22 +128,6 @@ static int clear_preset_list(void);
138 128
139static int scan_presets(void); 129static int scan_presets(void);
140 130
141#ifdef SIMULATOR
142void radio_set(int setting, int value);
143int radio_get(int setting);
144#else
145#if CONFIG_TUNER == S1A0903X01 /* FM recorder */
146#define radio_set samsung_set
147#define radio_get samsung_get
148#elif CONFIG_TUNER == TEA5767 /* iriver, iaudio */
149#define radio_set philips_set
150#define radio_get philips_get
151#elif CONFIG_TUNER == (S1A0903X01 | TEA5767) /* OndioFM */
152static void (*radio_set)(int setting, int value);
153static int (*radio_get)(int setting);
154#endif
155#endif
156
157/* Function to manipulate all yesno dialogues. 131/* Function to manipulate all yesno dialogues.
158 This function needs the output text as an argument. */ 132 This function needs the output text as an argument. */
159static bool yesno_pop(char* text) 133static bool yesno_pop(char* text)
@@ -169,25 +143,10 @@ static bool yesno_pop(char* text)
169 143
170void radio_init(void) 144void radio_init(void)
171{ 145{
172#ifndef SIMULATOR 146 tuner_init();
173#if CONFIG_TUNER == (S1A0903X01 | TEA5767)
174 if (read_hw_mask() & TUNER_MODEL)
175 {
176 radio_set = philips_set;
177 radio_get = philips_get;
178 }
179 else
180 {
181 radio_set = samsung_set;
182 radio_get = samsung_get;
183 }
184#endif
185#endif
186 radio_stop(); 147 radio_stop();
187} 148}
188 149
189/* For powermgmt.c to check status for shutdown since it can't access
190 the global_status structure directly. */
191int get_radio_status(void) 150int get_radio_status(void)
192{ 151{
193 return radio_status; 152 return radio_status;
@@ -202,12 +161,15 @@ bool in_radio_screen(void)
202#define FMRADIO_START_PAUSED 0x8000 161#define FMRADIO_START_PAUSED 0x8000
203void radio_start(void) 162void radio_start(void)
204{ 163{
164 const struct fm_region_setting *fmr;
205 bool start_paused; 165 bool start_paused;
206 int mute_timeout; 166 int mute_timeout;
207 167
208 if(radio_status == FMRADIO_PLAYING) 168 if(radio_status == FMRADIO_PLAYING)
209 return; 169 return;
210 170
171 fmr = &fm_region[global_settings.fm_region];
172
211 start_paused = radio_status & FMRADIO_START_PAUSED; 173 start_paused = radio_status & FMRADIO_START_PAUSED;
212 /* clear flag before any yielding */ 174 /* clear flag before any yielding */
213 radio_status &= ~FMRADIO_START_PAUSED; 175 radio_status &= ~FMRADIO_START_PAUSED;
@@ -216,21 +178,21 @@ void radio_start(void)
216 radio_power(true); 178 radio_power(true);
217 179
218 curr_freq = global_status.last_frequency 180 curr_freq = global_status.last_frequency
219 * fm_region[global_settings.fm_region].freq_step 181 * fmr->freq_step + fmr->freq_min;
220 + fm_region[global_settings.fm_region].freq_min;
221 182
222 radio_set(RADIO_SLEEP, 0); /* wake up the tuner */ 183 radio_set(RADIO_SLEEP, 0); /* wake up the tuner */
223 radio_set(RADIO_FREQUENCY, curr_freq); 184 radio_set(RADIO_FREQUENCY, curr_freq);
224 185
225 if(radio_status == FMRADIO_OFF) 186 if(radio_status == FMRADIO_OFF)
226 { 187 {
188#if (CONFIG_TUNER & S1A0903X01)
227 radio_set(RADIO_IF_MEASUREMENT, 0); 189 radio_set(RADIO_IF_MEASUREMENT, 0);
228 radio_set(RADIO_SENSITIVITY, 0); 190 radio_set(RADIO_SENSITIVITY, 0);
191#endif
229 radio_set(RADIO_FORCE_MONO, global_settings.fm_force_mono); 192 radio_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
230#if (CONFIG_TUNER & TEA5767) 193#if (CONFIG_TUNER & TEA5767)
231 radio_set(RADIO_SET_DEEMPHASIS, 194 radio_set(RADIO_SET_DEEMPHASIS, fmr->deemphasis);
232 fm_region[global_settings.fm_region].deemphasis); 195 radio_set(RADIO_SET_BAND, fmr->band);
233 radio_set(RADIO_SET_BAND, fm_region[global_settings.fm_region].band);
234#endif 196#endif
235 mute_timeout = current_tick + 1*HZ; 197 mute_timeout = current_tick + 1*HZ;
236 } 198 }
@@ -295,6 +257,25 @@ bool radio_hardware_present(void)
295#endif 257#endif
296} 258}
297 259
260/* Keep freq on the grid for the current region */
261static int snap_freq_to_grid(int freq)
262{
263 const struct fm_region_setting * const fmr =
264 &fm_region[global_settings.fm_region];
265
266 /* Range clamp if out of range or just round to nearest */
267 if (freq < fmr->freq_min)
268 freq = fmr->freq_min;
269 else if (freq > fmr->freq_max)
270 freq = fmr->freq_max;
271 else
272 freq = (freq - fmr->freq_min + fmr->freq_step/2) /
273 fmr->freq_step * fmr->freq_step + fmr->freq_min;
274
275 return freq;
276}
277
278/* Find a matching preset to freq */
298static int find_preset(int freq) 279static int find_preset(int freq)
299{ 280{
300 int i; 281 int i;
@@ -309,35 +290,43 @@ static int find_preset(int freq)
309 return -1; 290 return -1;
310} 291}
311 292
312static int find_closest_preset(int freq) 293/* Return the first preset encountered in the search direction with
294 wraparound. */
295static int find_closest_preset(int freq, int direction)
313{ 296{
314 int i; 297 int i;
315 int diff;
316 int min_diff = fm_region[global_settings.fm_region].freq_min;
317 int preset = -1;
318 298
319 for(i = 0;i < MAX_PRESETS;i++) 299 if (direction == 0) /* direction == 0 isn't really used */
300 return 0;
301
302 for (i = 0; i < MAX_PRESETS; i++)
320 { 303 {
321 diff = freq - presets[i].frequency; 304 int preset_frequency = presets[i].frequency;
322 if(diff==0) 305
323 return i; 306 if (preset_frequency == freq)
324 if(diff < 0) 307 return i; /* Exact match = stop */
325 diff = -diff; 308 /* Stop when the preset frequency exeeds freq so that we can
326 if(diff < min_diff) 309 pick the correct one based on direction */
327 { 310 if (preset_frequency > freq)
328 preset = i; 311 break;
329 min_diff = diff;
330 }
331 } 312 }
332 313
333 return preset; 314 /* wrap around depending on direction */
315 if (i == 0 || i >= num_presets - 1)
316 i = direction < 0 ? num_presets - 1 : 0;
317 else if (direction < 0)
318 i--; /* use previous */
319
320 return i;
334} 321}
335 322
336static void remember_frequency(void) 323static void remember_frequency(void)
337{ 324{
338 global_status.last_frequency = (curr_freq 325 const struct fm_region_setting * const fmr =
339 - fm_region[global_settings.fm_region].freq_min) 326 &fm_region[global_settings.fm_region];
340 / fm_region[global_settings.fm_region].freq_step; 327
328 global_status.last_frequency = (curr_freq - fmr->freq_min)
329 / fmr->freq_step;
341 status_save(); 330 status_save();
342} 331}
343 332
@@ -346,60 +335,104 @@ static void next_preset(int direction)
346 if (num_presets < 1) 335 if (num_presets < 1)
347 return; 336 return;
348 337
349 if(curr_preset == -1) 338 if (curr_preset == -1)
350 curr_preset = find_closest_preset(curr_freq); 339 curr_preset = find_closest_preset(curr_freq, direction);
351
352 if(direction > 0)
353 if(curr_preset == num_presets - 1)
354 curr_preset = 0;
355 else
356 curr_preset++;
357 else 340 else
358 if(curr_preset == 0) 341 curr_preset = (curr_preset + direction + num_presets) % num_presets;
359 curr_preset = num_presets - 1; 342
360 else 343 /* Must stay on the current grid for the region */
361 curr_preset--; 344 curr_freq = snap_freq_to_grid(presets[curr_preset].frequency);
362 345
363 curr_freq = presets[curr_preset].frequency;
364 radio_set(RADIO_FREQUENCY, curr_freq); 346 radio_set(RADIO_FREQUENCY, curr_freq);
365 remember_frequency(); 347 remember_frequency();
366} 348}
367 349
350/* Step to the next or previous frequency */
351static int step_freq(int freq, int direction)
352{
353 const struct fm_region_setting * const fmr =
354 &fm_region[global_settings.fm_region];
355
356 freq += direction*fmr->freq_step;
357
358 /* Wrap first or snapping to grid will not let us on the band extremes */
359 if (freq > fmr->freq_max)
360 freq = direction > 0 ? fmr->freq_min : fmr->freq_max;
361 else if (freq < fmr->freq_min)
362 freq = direction < 0 ? fmr->freq_max : fmr->freq_min;
363 else
364 freq = snap_freq_to_grid(freq);
365
366 return freq;
367}
368
369/* Step to the next or previous station */
370static void next_station(int direction)
371{
372 if (direction != 0 && radio_mode != RADIO_SCAN_MODE)
373 {
374 next_preset(direction);
375 return;
376 }
377
378 curr_freq = step_freq(curr_freq, direction);
379
380 if (radio_status == FMRADIO_PLAYING)
381 radio_set(RADIO_MUTE, 1);
382
383 radio_set(RADIO_FREQUENCY, curr_freq);
384
385 if (radio_status == FMRADIO_PLAYING)
386 radio_set(RADIO_MUTE, 0);
387
388 curr_preset = find_preset(curr_freq);
389 remember_frequency();
390}
368 391
369int radio_screen(void) 392int radio_screen(void)
370{ 393{
371 char buf[MAX_PATH]; 394 char buf[MAX_PATH];
372 bool done = false; 395 bool done = false;
373 int button, lastbutton = BUTTON_NONE;
374 int ret_val = GO_TO_ROOT; 396 int ret_val = GO_TO_ROOT;
375#ifdef FM_RECORD_DBLPRE 397 int button;
376 unsigned long rec_lastclick = 0; 398 int i;
377#endif
378 int freq, i;
379 bool tuned;
380 bool stereo = false;
381 int search_dir = 0; 399 int search_dir = 0;
400 bool stereo = false, last_stereo = false;
382 int fh; 401 int fh;
383 bool last_stereo_status = false;
384 int top_of_screen = 0; 402 int top_of_screen = 0;
385 bool update_screen = true; 403 bool update_screen = true;
386 int timeout = current_tick + HZ/10;
387 bool screen_freeze = false; 404 bool screen_freeze = false;
405 bool keep_playing = false;
406 bool statusbar = global_settings.statusbar;
407#ifdef FM_RECORD_DBLPRE
408 int lastbutton = BUTTON_NONE;
409 unsigned long rec_lastclick = 0;
410#endif
411#if CONFIG_CODEC != SWCODEC
388 bool have_recorded = false; 412 bool have_recorded = false;
413 int timeout = current_tick + HZ/10;
389 unsigned int seconds = 0; 414 unsigned int seconds = 0;
390 unsigned int last_seconds = 0; 415 unsigned int last_seconds = 0;
391#if CONFIG_CODEC != SWCODEC
392 int hours, minutes; 416 int hours, minutes;
393 struct audio_recording_options rec_options; 417 struct audio_recording_options rec_options;
394#endif 418#endif /* CONFIG_CODEC != SWCODEC */
395 bool keep_playing = false; 419#ifndef HAVE_NOISY_IDLE_MODE
396 bool statusbar = global_settings.statusbar;
397 int button_timeout = current_tick + (2*HZ); 420 int button_timeout = current_tick + (2*HZ);
421#endif
398#ifdef HAS_BUTTONBAR 422#ifdef HAS_BUTTONBAR
399 struct gui_buttonbar buttonbar; 423 struct gui_buttonbar buttonbar;
400 gui_buttonbar_init(&buttonbar); 424 gui_buttonbar_init(&buttonbar);
401 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) ); 425 gui_buttonbar_set_display(&buttonbar, &(screens[SCREEN_MAIN]) );
402#endif 426#endif
427
428 /* Ends an in-progress search - needs access to search_dir */
429 void end_search(void)
430 {
431 if (search_dir != 0 && radio_status == FMRADIO_PLAYING)
432 radio_set(RADIO_MUTE, 0);
433 search_dir = 0;
434 }
435
403 /* change status to "in screen" */ 436 /* change status to "in screen" */
404 in_screen = true; 437 in_screen = true;
405 438
@@ -419,7 +452,7 @@ int radio_screen(void)
419 if(fh < 10) 452 if(fh < 10)
420 top_of_screen = 1; 453 top_of_screen = 1;
421 454
422 if(!num_presets) 455 if(num_presets <= 0)
423 { 456 {
424 memset(presets, 0, sizeof(presets)); 457 memset(presets, 0, sizeof(presets));
425 radio_load_presets(global_settings.fmr_file); 458 radio_load_presets(global_settings.fmr_file);
@@ -461,8 +494,7 @@ int radio_screen(void)
461 radio_start(); 494 radio_start();
462#endif 495#endif
463 496
464 /* I hate this thing with vehement passion (jhMikeS): */ 497 if(num_presets < 1 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN)))
465 if(num_presets == 0 && yesno_pop(str(LANG_FM_FIRST_AUTOSCAN)))
466 scan_presets(); 498 scan_presets();
467 499
468 curr_preset = find_preset(curr_freq); 500 curr_preset = find_preset(curr_freq);
@@ -474,50 +506,44 @@ int radio_screen(void)
474 str(LANG_FM_BUTTONBAR_PRESETS), str(LANG_FM_BUTTONBAR_RECORD)); 506 str(LANG_FM_BUTTONBAR_PRESETS), str(LANG_FM_BUTTONBAR_RECORD));
475#endif 507#endif
476 508
509#ifndef HAVE_NOISY_IDLE_MODE
477 cpu_idle_mode(true); 510 cpu_idle_mode(true);
478 511#endif
512
479 while(!done) 513 while(!done)
480 { 514 {
481 if(search_dir) 515 if(search_dir != 0)
482 { 516 {
483 curr_freq += search_dir 517 curr_freq = step_freq(curr_freq, search_dir);
484 * fm_region[global_settings.fm_region].freq_step; 518 update_screen = true;
485 if(curr_freq < fm_region[global_settings.fm_region].freq_min)
486 curr_freq = fm_region[global_settings.fm_region].freq_max;
487 if(curr_freq > fm_region[global_settings.fm_region].freq_max)
488 curr_freq = fm_region[global_settings.fm_region].freq_min;
489
490 /* Tune in and delay */
491 radio_set(RADIO_FREQUENCY, curr_freq);
492 sleep(1);
493
494 /* Start IF measurement */
495 radio_set(RADIO_IF_MEASUREMENT, 1);
496 sleep(1);
497
498 /* Now check how close to the IF frequency we are */
499 tuned = radio_get(RADIO_TUNED);
500 519
501 /* Stop searching if the tuning is close */ 520 if(radio_set(RADIO_SCAN_FREQUENCY, curr_freq))
502 if(tuned)
503 { 521 {
504 search_dir = 0;
505 curr_preset = find_preset(curr_freq); 522 curr_preset = find_preset(curr_freq);
506 remember_frequency(); 523 remember_frequency();
524 end_search();
507 } 525 }
508 526
509 update_screen = true; 527 trigger_cpu_boost();
510 } 528 }
511 529
512 if(search_dir) 530#if CONFIG_CODEC != SWCODEC
513 button = button_get(false); 531 /* TODO: Can we timeout at HZ when recording since peaks aren't
514 else 532 displayed? This should quiet recordings too. */
515 button = get_action(CONTEXT_FM, HZ / PEAK_METER_FPS); 533 button = get_action(CONTEXT_FM,
534 update_screen ? TIMEOUT_NOBLOCK : HZ / PEAK_METER_FPS);
535#else
536 button = get_action(CONTEXT_FM,
537 update_screen ? TIMEOUT_NOBLOCK : HZ);
538#endif
539
540#ifndef HAVE_NOISY_IDLE_MODE
516 if (button != ACTION_NONE) 541 if (button != ACTION_NONE)
517 { 542 {
518 cpu_idle_mode(false); 543 cpu_idle_mode(false);
519 button_timeout = current_tick + (2*HZ); 544 button_timeout = current_tick + (2*HZ);
520 } 545 }
546#endif
521 switch(button) 547 switch(button)
522 { 548 {
523 case ACTION_FM_STOP: 549 case ACTION_FM_STOP:
@@ -559,7 +585,7 @@ int radio_screen(void)
559 rec_lastclick = current_tick; 585 rec_lastclick = current_tick;
560 break; 586 break;
561 } 587 }
562#endif 588#endif /* FM_RECORD_DBLPRE */
563#ifndef SIMULATOR 589#ifndef SIMULATOR
564 if(audio_status() == AUDIO_STATUS_RECORD) 590 if(audio_status() == AUDIO_STATUS_RECORD)
565 { 591 {
@@ -572,7 +598,7 @@ int radio_screen(void)
572 rec_record(); 598 rec_record();
573 update_screen = true; 599 update_screen = true;
574 } 600 }
575#endif 601#endif /* SIMULATOR */
576 last_seconds = 0; 602 last_seconds = 0;
577 break; 603 break;
578#endif /* #ifdef FM_RECORD */ 604#endif /* #ifdef FM_RECORD */
@@ -602,63 +628,31 @@ int radio_screen(void)
602 break; 628 break;
603 629
604 case ACTION_STD_PREV: 630 case ACTION_STD_PREV:
605 if(radio_mode == RADIO_SCAN_MODE)
606 {
607 curr_freq
608 -= fm_region[global_settings.fm_region].freq_step;
609 if(curr_freq < fm_region[global_settings.fm_region].freq_min)
610 curr_freq
611 = fm_region[global_settings.fm_region].freq_max;
612 radio_set(RADIO_FREQUENCY, curr_freq);
613 curr_preset = find_preset(curr_freq);
614 remember_frequency();
615 }
616 else
617 next_preset(-1);
618 search_dir = 0;
619 update_screen = true;
620 break;
621
622 case ACTION_STD_NEXT: 631 case ACTION_STD_NEXT:
623 if(radio_mode == RADIO_SCAN_MODE) 632 next_station(button == ACTION_STD_PREV ? -1 : 1);
624 { 633 end_search();
625 curr_freq
626 += fm_region[global_settings.fm_region].freq_step;
627 if(curr_freq > fm_region[global_settings.fm_region].freq_max)
628 curr_freq
629 = fm_region[global_settings.fm_region].freq_min;
630 radio_set(RADIO_FREQUENCY, curr_freq);
631 curr_preset = find_preset(curr_freq);
632 remember_frequency();
633 }
634 else
635 next_preset(1);
636 search_dir = 0;
637 update_screen = true; 634 update_screen = true;
638 break; 635 break;
639 636
640 case ACTION_STD_PREVREPEAT: 637 case ACTION_STD_PREVREPEAT:
641 if(radio_mode == RADIO_SCAN_MODE) 638 case ACTION_STD_NEXTREPEAT:
642 search_dir = -1; 639 {
643 else 640 int dir = search_dir;
641 search_dir = button == ACTION_STD_PREVREPEAT ? -1 : 1;
642 if (radio_mode != RADIO_SCAN_MODE)
644 { 643 {
645 next_preset(-1); 644 next_preset(search_dir);
645 end_search();
646 update_screen = true; 646 update_screen = true;
647 } 647 }
648 648 else if (dir == 0)
649 break;
650
651 case ACTION_STD_NEXTREPEAT:
652 if(radio_mode == RADIO_SCAN_MODE)
653 search_dir = 1;
654 else
655 { 649 {
656 next_preset(1); 650 /* Starting auto scan */
651 radio_set(RADIO_MUTE, 1);
657 update_screen = true; 652 update_screen = true;
658 } 653 }
659
660 break; 654 break;
661 655 }
662 656
663 case ACTION_SETTINGS_INC: 657 case ACTION_SETTINGS_INC:
664 case ACTION_SETTINGS_INCREPEAT: 658 case ACTION_SETTINGS_INCREPEAT:
@@ -693,8 +687,9 @@ int radio_screen(void)
693 radio_menu(); 687 radio_menu();
694 curr_preset = find_preset(curr_freq); 688 curr_preset = find_preset(curr_freq);
695 FOR_NB_SCREENS(i){ 689 FOR_NB_SCREENS(i){
696 gui_textarea_clear(&screens[i]); 690 struct screen *sc = &screens[i];
697 screen_set_xmargin(&screens[i],0); 691 gui_textarea_clear(sc);
692 screen_set_xmargin(sc, 0);
698 } 693 }
699#ifdef HAS_BUTTONBAR 694#ifdef HAS_BUTTONBAR
700 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU), 695 gui_buttonbar_set(&buttonbar, str(LANG_BUTTONBAR_MENU),
@@ -712,9 +707,10 @@ int radio_screen(void)
712 update_screen = true; 707 update_screen = true;
713 FOR_NB_SCREENS(i) 708 FOR_NB_SCREENS(i)
714 { 709 {
715 gui_textarea_clear(&screens[i]); 710 struct screen *sc = &screens[i];
716 screen_set_xmargin(&screens[i],0); 711 gui_textarea_clear(sc);
717 gui_textarea_update(&screens[i]); 712 screen_set_xmargin(sc, 0);
713 gui_textarea_update(sc);
718 } 714 }
719 715
720 break; 716 break;
@@ -722,9 +718,10 @@ int radio_screen(void)
722 handle_radio_presets(); 718 handle_radio_presets();
723 FOR_NB_SCREENS(i) 719 FOR_NB_SCREENS(i)
724 { 720 {
725 gui_textarea_clear(&screens[i]); 721 struct screen *sc = &screens[i];
726 screen_set_xmargin(&screens[i],0); 722 gui_textarea_clear(sc);
727 gui_textarea_update(&screens[i]); 723 screen_set_xmargin(sc, 0);
724 gui_textarea_update(sc);
728 } 725 }
729#ifdef HAS_BUTTONBAR 726#ifdef HAS_BUTTONBAR
730 gui_buttonbar_set(&buttonbar, 727 gui_buttonbar_set(&buttonbar,
@@ -734,7 +731,7 @@ int radio_screen(void)
734#endif 731#endif
735 update_screen = true; 732 update_screen = true;
736 break; 733 break;
737#endif 734#endif /* FM_PRESET */
738 735
739#ifdef FM_FREEZE 736#ifdef FM_FREEZE
740 case ACTION_FM_FREEZE: 737 case ACTION_FM_FREEZE:
@@ -749,10 +746,13 @@ int radio_screen(void)
749 screen_freeze = false; 746 screen_freeze = false;
750 } 747 }
751 break; 748 break;
752#endif 749#endif /* FM_FREEZE */
750
753 case SYS_USB_CONNECTED: 751 case SYS_USB_CONNECTED:
752#if CONFIG_CODEC != SWCODEC
754 /* Only accept USB connection when not recording */ 753 /* Only accept USB connection when not recording */
755 if(audio_status() != AUDIO_STATUS_RECORD) 754 if(audio_status() != AUDIO_STATUS_RECORD)
755#endif
756 { 756 {
757 default_event_handler(SYS_USB_CONNECTED); 757 default_event_handler(SYS_USB_CONNECTED);
758 screen_freeze = true; /* Cosmetic: makes sure the 758 screen_freeze = true; /* Cosmetic: makes sure the
@@ -773,18 +773,20 @@ int radio_screen(void)
773 radio_mode = RADIO_SCAN_MODE; 773 radio_mode = RADIO_SCAN_MODE;
774 update_screen = true; 774 update_screen = true;
775 break; 775 break;
776#endif 776#endif /* FM_MODE */
777
777#ifdef FM_NEXT_PRESET 778#ifdef FM_NEXT_PRESET
778 case ACTION_FM_NEXT_PRESET: 779 case ACTION_FM_NEXT_PRESET:
779 next_preset(1); 780 next_preset(1);
780 search_dir = 0; 781 end_search();
781 update_screen = true; 782 update_screen = true;
782 break; 783 break;
783#endif 784#endif
785
784#ifdef FM_PREV_PRESET 786#ifdef FM_PREV_PRESET
785 case ACTION_FM_PREV_PRESET: 787 case ACTION_FM_PREV_PRESET:
786 next_preset(-1); 788 next_preset(-1);
787 search_dir = 0; 789 end_search();
788 update_screen = true; 790 update_screen = true;
789 break; 791 break;
790#endif 792#endif
@@ -794,8 +796,10 @@ int radio_screen(void)
794 break; 796 break;
795 } /*switch(button)*/ 797 } /*switch(button)*/
796 798
799#ifdef FM_RECORD_DBLPRE
797 if (button != ACTION_NONE) 800 if (button != ACTION_NONE)
798 lastbutton = button; 801 lastbutton = button;
802#endif
799 803
800#if CONFIG_CODEC != SWCODEC 804#if CONFIG_CODEC != SWCODEC
801 peak_meter_peek(); 805 peak_meter_peek();
@@ -804,10 +808,9 @@ int radio_screen(void)
804 if(!screen_freeze) 808 if(!screen_freeze)
805 { 809 {
806 /* Only display the peak meter when not recording */ 810 /* Only display the peak meter when not recording */
811#if CONFIG_CODEC != SWCODEC
807 if(!audio_status()) 812 if(!audio_status())
808 { 813 {
809
810#if CONFIG_CODEC != SWCODEC
811 FOR_NB_SCREENS(i) 814 FOR_NB_SCREENS(i)
812 { 815 {
813 peak_meter_screen(&screens[i],0, 816 peak_meter_screen(&screens[i],0,
@@ -815,44 +818,46 @@ int radio_screen(void)
815 screens[i].update_rect(0, STATUSBAR_HEIGHT + fh*(top_of_screen + 4), 818 screens[i].update_rect(0, STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
816 screens[i].width, fh); 819 screens[i].width, fh);
817 } 820 }
818#endif
819
820 } 821 }
821 822
822 if(TIME_AFTER(current_tick, timeout)) 823 if(TIME_AFTER(current_tick, timeout))
823 { 824 {
824 timeout = current_tick + HZ; 825 timeout = current_tick + HZ;
826#else /* SWCODEC */
827 {
828#endif /* CONFIG_CODEC == SWCODEC */
825 829
826 /* keep "mono" from always being displayed when paused */ 830 /* keep "mono" from always being displayed when paused */
827 if (radio_status != FMRADIO_PAUSED) 831 if (radio_status != FMRADIO_PAUSED)
828 { 832 {
829 stereo = radio_get(RADIO_STEREO) && 833 stereo = radio_get(RADIO_STEREO) &&
830 !global_settings.fm_force_mono; 834 !global_settings.fm_force_mono;
831 if(stereo != last_stereo_status) 835
836 if(stereo != last_stereo)
832 { 837 {
833 update_screen = true; 838 update_screen = true;
834 last_stereo_status = stereo; 839 last_stereo = stereo;
835 } 840 }
836 } 841 }
837 } 842 }
838 843
839#ifndef SIMULATOR 844#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
840#if CONFIG_CODEC != SWCODEC
841 seconds = audio_recorded_time() / HZ; 845 seconds = audio_recorded_time() / HZ;
842#endif 846 if (update_screen || seconds > last_seconds)
843#endif
844 if(update_screen || seconds > last_seconds)
845 { 847 {
846 last_seconds = seconds; 848 last_seconds = seconds;
849#else
850 if (update_screen)
851 {
852#endif
853 int freq;
847 854
848 FOR_NB_SCREENS(i) 855 FOR_NB_SCREENS(i)
849 screens[i].setfont(FONT_UI); 856 screens[i].setfont(FONT_UI);
850 857
851 if (curr_preset >= 0 ) 858 snprintf(buf, 128, curr_preset >= 0 ? "%d. %s" : " ",
852 snprintf(buf, 128, "%d. %s",curr_preset + 1, 859 curr_preset + 1, presets[curr_preset].name);
853 presets[curr_preset].name); 860
854 else
855 snprintf(buf, 128, " ");
856 FOR_NB_SCREENS(i) 861 FOR_NB_SCREENS(i)
857 screens[i].puts_scroll(0, top_of_screen, buf); 862 screens[i].puts_scroll(0, top_of_screen, buf);
858 863
@@ -871,6 +876,7 @@ int radio_screen(void)
871 str(LANG_RADIO_SCAN_MODE)); 876 str(LANG_RADIO_SCAN_MODE));
872 FOR_NB_SCREENS(i) 877 FOR_NB_SCREENS(i)
873 screens[i].puts_scroll(0, top_of_screen + 3, buf); 878 screens[i].puts_scroll(0, top_of_screen + 3, buf);
879
874#if CONFIG_CODEC != SWCODEC 880#if CONFIG_CODEC != SWCODEC
875 if(audio_status() == AUDIO_STATUS_RECORD) 881 if(audio_status() == AUDIO_STATUS_RECORD)
876 { 882 {
@@ -892,7 +898,7 @@ int radio_screen(void)
892 screens[i].puts_scroll(0, top_of_screen + 4, buf); 898 screens[i].puts_scroll(0, top_of_screen + 4, buf);
893 } 899 }
894 } 900 }
895#endif 901#endif /* CONFIG_CODEC != SWCODEC */
896 902
897#ifdef HAS_BUTTONBAR 903#ifdef HAS_BUTTONBAR
898 gui_buttonbar_draw(&buttonbar); 904 gui_buttonbar_draw(&buttonbar);
@@ -902,21 +908,27 @@ int radio_screen(void)
902 } 908 }
903 /* Only force the redraw if update_screen is true */ 909 /* Only force the redraw if update_screen is true */
904 gui_syncstatusbar_draw(&statusbars,true); 910 gui_syncstatusbar_draw(&statusbars,true);
905
906 update_screen = false;
907 } 911 }
908 912
913 update_screen = false;
914
915#if CONFIG_CODEC != SWCODEC
909 if(audio_status() & AUDIO_STATUS_ERROR) 916 if(audio_status() & AUDIO_STATUS_ERROR)
910 { 917 {
911 done = true; 918 done = true;
912 } 919 }
920#endif
921
922#ifndef HAVE_NOISY_IDLE_MODE
913 if (TIME_AFTER(current_tick, button_timeout)) 923 if (TIME_AFTER(current_tick, button_timeout))
914 { 924 {
915 cpu_idle_mode(true); 925 cpu_idle_mode(true);
916 } 926 }
927#endif
917 } /*while(!done)*/ 928 } /*while(!done)*/
918 929
919#ifndef SIMULATOR 930#ifndef SIMULATOR
931#if CONFIG_CODEC != SWCODEC
920 if(audio_status() & AUDIO_STATUS_ERROR) 932 if(audio_status() & AUDIO_STATUS_ERROR)
921 { 933 {
922 gui_syncsplash(0, true, str(LANG_DISK_FULL)); 934 gui_syncsplash(0, true, str(LANG_DISK_FULL));
@@ -933,16 +945,15 @@ int radio_screen(void)
933 } 945 }
934 } 946 }
935 947
936#if CONFIG_CODEC != SWCODEC
937 audio_init_playback(); 948 audio_init_playback();
938#endif 949#endif /* CONFIG_CODEC != SWCODEC */
939 950
940 sound_settings_apply(); 951 sound_settings_apply();
941#endif /* SIMULATOR */ 952#endif /* SIMULATOR */
942 953
943 if(keep_playing) 954 if(keep_playing)
944 { 955 {
945/* Catch FMRADIO_PLAYING status for the sim. */ 956/* Catch FMRADIO_PLAYING status for the sim. */
946#ifndef SIMULATOR 957#ifndef SIMULATOR
947#if CONFIG_CODEC != SWCODEC 958#if CONFIG_CODEC != SWCODEC
948 /* Enable the Left and right A/D Converter */ 959 /* Enable the Left and right A/D Converter */
@@ -951,7 +962,8 @@ int radio_screen(void)
951 AUDIO_GAIN_LINEIN); 962 AUDIO_GAIN_LINEIN);
952 mas_codec_writereg(6, 0x4000); 963 mas_codec_writereg(6, 0x4000);
953#endif 964#endif
954#endif 965 end_search();
966#endif /* SIMULATOR */
955 } 967 }
956 else 968 else
957 { 969 {
@@ -961,15 +973,20 @@ int radio_screen(void)
961 radio_stop(); 973 radio_stop();
962#endif 974#endif
963 } 975 }
964 976
977#ifndef HAVE_NOISY_IDLE_MODE
965 cpu_idle_mode(false); 978 cpu_idle_mode(false);
979#endif
966 980
967 /* restore status bar settings */ 981 /* restore status bar settings */
968 global_settings.statusbar = statusbar; 982 global_settings.statusbar = statusbar;
969 983
970 in_screen = false; 984 in_screen = false;
971 985#if CONFIG_CODEC != SWCODEC
972 return have_recorded; 986 return have_recorded;
987#else
988 return false;
989#endif
973} /* radio_screen */ 990} /* radio_screen */
974 991
975static void radio_save_presets(void) 992static void radio_save_presets(void)
@@ -1006,7 +1023,6 @@ void radio_load_presets(char *filename)
1006 bool done = false; 1023 bool done = false;
1007 int f; 1024 int f;
1008 1025
1009
1010 memset(presets, 0, sizeof(presets)); 1026 memset(presets, 0, sizeof(presets));
1011 num_presets = 0; 1027 num_presets = 0;
1012 1028
@@ -1037,9 +1053,10 @@ void radio_load_presets(char *filename)
1037 f = atoi(freq); 1053 f = atoi(freq);
1038 if(f) /* For backwards compatibility */ 1054 if(f) /* For backwards compatibility */
1039 { 1055 {
1040 presets[num_presets].frequency = f; 1056 struct fmstation * const fms = &presets[num_presets];
1041 strncpy(presets[num_presets].name, name, MAX_FMPRESET_LEN); 1057 fms->frequency = f;
1042 presets[num_presets].name[MAX_FMPRESET_LEN] = 0; 1058 strncpy(fms->name, name, MAX_FMPRESET_LEN);
1059 fms->name[MAX_FMPRESET_LEN] = '\0';
1043 num_presets++; 1060 num_presets++;
1044 } 1061 }
1045 } 1062 }
@@ -1051,12 +1068,8 @@ void radio_load_presets(char *filename)
1051 } 1068 }
1052 else /* invalid file name? */ 1069 else /* invalid file name? */
1053 filepreset[0] = '\0'; 1070 filepreset[0] = '\0';
1054 1071
1055 if(num_presets > 0) 1072 presets_loaded = num_presets > 0;
1056 presets_loaded = true;
1057 else
1058 presets_loaded = false;
1059
1060 presets_changed = false; 1073 presets_changed = false;
1061} 1074}
1062 1075
@@ -1071,13 +1084,13 @@ static int radio_add_preset(void)
1071 1084
1072 if (!kbd_input(buf, MAX_FMPRESET_LEN)) 1085 if (!kbd_input(buf, MAX_FMPRESET_LEN))
1073 { 1086 {
1074 buf[MAX_FMPRESET_LEN] = 0; 1087 struct fmstation * const fms = &presets[num_presets];
1075 strcpy(presets[num_presets].name, buf); 1088 buf[MAX_FMPRESET_LEN] = '\0';
1076 presets[num_presets].frequency = curr_freq; 1089 strcpy(fms->name, buf);
1090 fms->frequency = curr_freq;
1077 num_presets++; 1091 num_presets++;
1078 presets_changed = true; 1092 presets_changed = true;
1079 if(num_presets > 0) 1093 presets_loaded = num_presets > 0;
1080 presets_loaded = true;
1081 } 1094 }
1082 } 1095 }
1083 else 1096 else
@@ -1088,43 +1101,53 @@ static int radio_add_preset(void)
1088} 1101}
1089 1102
1090/* needed to know which preset we are edit/delete-ing */ 1103/* needed to know which preset we are edit/delete-ing */
1091static int selected_preset = 0; 1104static int selected_preset = -1;
1092static int radio_edit_preset(void) 1105static int radio_edit_preset(void)
1093{ 1106{
1094 char buf[MAX_FMPRESET_LEN]; 1107 char buf[MAX_FMPRESET_LEN];
1095 1108
1096 strncpy(buf, presets[selected_preset].name, MAX_FMPRESET_LEN); 1109 if (num_presets > 0)
1097
1098 if (!kbd_input(buf, MAX_FMPRESET_LEN))
1099 { 1110 {
1100 buf[MAX_FMPRESET_LEN] = 0; 1111 struct fmstation * const fms = &presets[selected_preset];
1101 strcpy(presets[selected_preset].name, buf); 1112
1102 presets_changed = true; 1113 strncpy(buf, fms->name, MAX_FMPRESET_LEN);
1114
1115 if (!kbd_input(buf, MAX_FMPRESET_LEN))
1116 {
1117 buf[MAX_FMPRESET_LEN] = '\0';
1118 strcpy(fms->name, buf);
1119 presets_changed = true;
1120 }
1103 } 1121 }
1122
1104 return true; 1123 return true;
1105} 1124}
1106 1125
1107static int radio_delete_preset(void) 1126static int radio_delete_preset(void)
1108{ 1127{
1109 int pos = selected_preset; 1128 if (num_presets > 0)
1110 int i; 1129 {
1130 struct fmstation * const fms = &presets[selected_preset];
1131
1132 if (selected_preset >= --num_presets)
1133 selected_preset = num_presets - 1;
1111 1134
1112 for(i = pos;i < num_presets;i++) 1135 memmove(fms, fms + 1, (uintptr_t)(fms + num_presets) -
1113 presets[i] = presets[i+1]; 1136 (uintptr_t)fms);
1114 num_presets--; 1137
1138 }
1115 1139
1116 /* Don't ask to save when all presets are deleted. */ 1140 /* Don't ask to save when all presets are deleted. */
1117 if(num_presets > 0) 1141 presets_changed = num_presets > 0;
1118 presets_changed = true; 1142
1119 else 1143 if (!presets_changed)
1120 { 1144 {
1121 presets_changed = false;
1122 /* The preset list will be cleared, switch to Scan Mode. */ 1145 /* The preset list will be cleared, switch to Scan Mode. */
1123 radio_mode = RADIO_SCAN_MODE; 1146 radio_mode = RADIO_SCAN_MODE;
1124 presets_loaded = false; 1147 presets_loaded = false;
1125 } 1148 }
1126 1149
1127 return true; /* Make the menu return immediately */ 1150 return true;
1128} 1151}
1129 1152
1130static int load_preset_list(void) 1153static int load_preset_list(void)
@@ -1134,7 +1157,7 @@ static int load_preset_list(void)
1134 1157
1135static int save_preset_list(void) 1158static int save_preset_list(void)
1136{ 1159{
1137 if(num_presets != 0) 1160 if(num_presets > 0)
1138 { 1161 {
1139 bool bad_file_name = true; 1162 bool bad_file_name = true;
1140 1163
@@ -1187,13 +1210,8 @@ static int save_preset_list(void)
1187 1210
1188static int clear_preset_list(void) 1211static int clear_preset_list(void)
1189{ 1212{
1190 int i;
1191
1192 /* Clear all the preset entries */ 1213 /* Clear all the preset entries */
1193 for(i = 0;i <= num_presets;i++){ 1214 memset(presets, 0, sizeof (presets));
1194 presets[i].name[0] = '\0';
1195 presets[i].frequency = 0;
1196 }
1197 1215
1198 num_presets = 0; 1216 num_presets = 0;
1199 presets_loaded = false; 1217 presets_loaded = false;
@@ -1211,10 +1229,10 @@ MENUITEM_FUNCTION(radio_delete_preset_item, ID2P(LANG_FM_DELETE_PRESET),
1211 radio_delete_preset, NULL, Icon_NOICON); 1229 radio_delete_preset, NULL, Icon_NOICON);
1212int radio_preset_callback(int action, const struct menu_item_ex *this_item) 1230int radio_preset_callback(int action, const struct menu_item_ex *this_item)
1213{ 1231{
1214 (void)this_item;
1215 if (action == ACTION_STD_OK) 1232 if (action == ACTION_STD_OK)
1216 return ACTION_EXIT_AFTER_THIS_MENUITEM; 1233 action = ACTION_EXIT_AFTER_THIS_MENUITEM;
1217 return action; 1234 return action;
1235 (void)this_item;
1218} 1236}
1219MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_FM_BUTTONBAR_PRESETS), 1237MAKE_MENU(handle_radio_preset_menu, ID2P(LANG_FM_BUTTONBAR_PRESETS),
1220 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item, 1238 radio_preset_callback, Icon_NOICON, &radio_edit_preset_item,
@@ -1272,7 +1290,7 @@ static int handle_radio_presets(void)
1272 case ACTION_STD_OK: 1290 case ACTION_STD_OK:
1273 curr_preset = gui_synclist_get_sel_pos(&lists); 1291 curr_preset = gui_synclist_get_sel_pos(&lists);
1274 curr_freq = presets[curr_preset].frequency; 1292 curr_freq = presets[curr_preset].frequency;
1275 radio_set(RADIO_FREQUENCY, curr_freq); 1293 next_station(0);
1276 remember_frequency(); 1294 remember_frequency();
1277 result = 1; 1295 result = 1;
1278 break; 1296 break;
@@ -1302,15 +1320,7 @@ void set_radio_region(int region)
1302 fm_region[region].deemphasis); 1320 fm_region[region].deemphasis);
1303 radio_set(RADIO_SET_BAND, fm_region[region].band); 1321 radio_set(RADIO_SET_BAND, fm_region[region].band);
1304#endif 1322#endif
1305 /* make sure the current frequency is in the region range */ 1323 next_station(0);
1306 curr_freq -= (curr_freq - fm_region[region].freq_min)
1307 % fm_region[region].freq_step;
1308 if(curr_freq < fm_region[region].freq_min)
1309 curr_freq = fm_region[region].freq_min;
1310 if(curr_freq > fm_region[region].freq_max)
1311 curr_freq = fm_region[region].freq_max;
1312 radio_set(RADIO_FREQUENCY, curr_freq);
1313
1314 remember_frequency(); 1324 remember_frequency();
1315} 1325}
1316 1326
@@ -1340,52 +1350,52 @@ MENUITEM_FUNCTION_WPARAM_DYNTEXT(radio_mode_item, toggle_radio_mode, NULL, NULL,
1340 1350
1341static int scan_presets(void) 1351static int scan_presets(void)
1342{ 1352{
1343 bool tuned = false, do_scan = true; 1353 bool do_scan = true;
1344 char buf[MAX_FMPRESET_LEN];
1345 int freq, i;
1346 1354
1347 if(num_presets > 0) /* Do that to avoid 2 questions. */ 1355 if(num_presets > 0) /* Do that to avoid 2 questions. */
1348 do_scan = yesno_pop(str(LANG_FM_CLEAR_PRESETS)); 1356 do_scan = yesno_pop(str(LANG_FM_CLEAR_PRESETS));
1349 1357
1350 if(do_scan) 1358 if(do_scan)
1351 { 1359 {
1352 curr_freq = fm_region[global_settings.fm_region].freq_min; 1360 const struct fm_region_setting * const fmr =
1361 &fm_region[global_settings.fm_region];
1362 char buf[MAX_FMPRESET_LEN];
1363 int i;
1364
1365 curr_freq = fmr->freq_min;
1353 num_presets = 0; 1366 num_presets = 0;
1354 memset(presets, 0, sizeof(presets)); 1367 memset(presets, 0, sizeof(presets));
1355 while(curr_freq <= fm_region[global_settings.fm_region].freq_max) 1368 radio_set(RADIO_MUTE, 1);
1369
1370 while(curr_freq <= fmr->freq_max)
1356 { 1371 {
1372 int freq, frac;
1357 if (num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK)) 1373 if (num_presets >= MAX_PRESETS || action_userabort(TIMEOUT_NOBLOCK))
1358 break; 1374 break;
1359 1375
1360 freq = curr_freq / 10000; 1376 freq = curr_freq / 10000;
1361 snprintf(buf, MAX_FMPRESET_LEN, str(LANG_FM_SCANNING), 1377 frac = freq % 100;
1362 freq/100, freq % 100); 1378 freq /= 100;
1379
1380 snprintf(buf, MAX_FMPRESET_LEN, str(LANG_FM_SCANNING), freq, frac);
1363 gui_syncsplash(0, true, buf); 1381 gui_syncsplash(0, true, buf);
1364 1382
1365 /* Tune in and delay */ 1383 if(radio_set(RADIO_SCAN_FREQUENCY, curr_freq))
1366 radio_set(RADIO_FREQUENCY, curr_freq); 1384 {
1367 sleep(1); 1385 /* add preset */
1368 1386 snprintf(buf, MAX_FMPRESET_LEN,
1369 /* Start IF measurement */ 1387 str(LANG_FM_DEFAULT_PRESET_NAME), freq, frac);
1370 radio_set(RADIO_IF_MEASUREMENT, 1); 1388 strcpy(presets[num_presets].name,buf);
1371 sleep(1); 1389 presets[num_presets].frequency = curr_freq;
1372 1390 num_presets++;
1373 /* Now check how close to the IF frequency we are */
1374 tuned = radio_get(RADIO_TUNED);
1375
1376 /* add preset */
1377 if(tuned){
1378 snprintf(buf, MAX_FMPRESET_LEN,
1379 str(LANG_FM_DEFAULT_PRESET_NAME),freq/100, freq % 100);
1380 strcpy(presets[num_presets].name,buf);
1381 presets[num_presets].frequency = curr_freq;
1382 num_presets++;
1383 } 1391 }
1384 1392
1385 curr_freq += fm_region[global_settings.fm_region].freq_step; 1393 curr_freq += fmr->freq_step;
1386
1387 } 1394 }
1388 1395
1396 if (radio_status == FMRADIO_PLAYING)
1397 radio_set(RADIO_MUTE, 0);
1398
1389 presets_changed = true; 1399 presets_changed = true;
1390 1400
1391 FOR_NB_SCREENS(i) 1401 FOR_NB_SCREENS(i)
@@ -1395,22 +1405,24 @@ static int scan_presets(void)
1395 gui_textarea_update(&screens[i]); 1405 gui_textarea_update(&screens[i]);
1396 } 1406 }
1397 1407
1398 if(num_presets > 0 ) 1408 if(num_presets > 0)
1399 { 1409 {
1400 curr_freq = presets[0].frequency; 1410 curr_freq = presets[0].frequency;
1401 radio_set(RADIO_FREQUENCY, curr_freq);
1402 remember_frequency();
1403 radio_mode = RADIO_PRESET_MODE; 1411 radio_mode = RADIO_PRESET_MODE;
1404 presets_loaded = true; 1412 presets_loaded = true;
1413 next_station(0);
1405 } 1414 }
1406 else 1415 else
1416 {
1417 /* Wrap it to beginning or we'll be past end of band */
1407 presets_loaded = false; 1418 presets_loaded = false;
1419 next_station(1);
1420 }
1408 } 1421 }
1409 return true; 1422 return true;
1410} 1423}
1411 1424
1412 1425
1413#ifndef SIMULATOR
1414#ifdef HAVE_RECORDING 1426#ifdef HAVE_RECORDING
1415 1427
1416#if defined(HAVE_FMRADIO_IN) && CONFIG_CODEC == SWCODEC 1428#if defined(HAVE_FMRADIO_IN) && CONFIG_CODEC == SWCODEC
@@ -1433,8 +1445,6 @@ static int fm_recording_screen(void)
1433 1445
1434 return ret; 1446 return ret;
1435} 1447}
1436MENUITEM_FUNCTION(recscreen_item, ID2P(LANG_RECORDING_MENU),
1437 fm_recording_screen, NULL, Icon_NOICON);
1438#endif /* defined(HAVE_FMRADIO_IN) && CONFIG_CODEC == SWCODEC */ 1448#endif /* defined(HAVE_FMRADIO_IN) && CONFIG_CODEC == SWCODEC */
1439 1449
1440#if defined(HAVE_FMRADIO_IN) || CONFIG_CODEC != SWCODEC 1450#if defined(HAVE_FMRADIO_IN) || CONFIG_CODEC != SWCODEC
@@ -1442,6 +1452,7 @@ MENUITEM_FUNCTION(recscreen_item, ID2P(LANG_RECORDING_MENU),
1442static int fm_recording_settings(void) 1452static int fm_recording_settings(void)
1443{ 1453{
1444 bool ret = recording_menu(true); 1454 bool ret = recording_menu(true);
1455
1445#if CONFIG_CODEC != SWCODEC 1456#if CONFIG_CODEC != SWCODEC
1446 if (!ret) 1457 if (!ret)
1447 { 1458 {
@@ -1454,11 +1465,17 @@ static int fm_recording_settings(void)
1454 1465
1455 return ret; 1466 return ret;
1456} 1467}
1457MENUITEM_FUNCTION(recsettings_item, ID2P(LANG_RECORDING_SETTINGS),
1458 fm_recording_settings, NULL, Icon_NOICON);
1459#endif /* defined(HAVE_FMRADIO_IN) || CONFIG_CODEC != SWCODEC */ 1468#endif /* defined(HAVE_FMRADIO_IN) || CONFIG_CODEC != SWCODEC */
1460#endif /* HAVE_RECORDING */ 1469#endif /* HAVE_RECORDING */
1461#endif /* SIMULATOR */ 1470
1471#ifdef FM_RECORDING_SCREEN
1472MENUITEM_FUNCTION(recscreen_item, ID2P(LANG_RECORDING_MENU),
1473 fm_recording_screen, NULL, Icon_NOICON);
1474#endif
1475#ifdef FM_RECORDING_SETTINGS
1476MENUITEM_FUNCTION(recsettings_item, ID2P(LANG_RECORDING_SETTINGS),
1477 fm_recording_settings, NULL, Icon_NOICON);
1478#endif
1462#ifndef FM_PRESET 1479#ifndef FM_PRESET
1463MENUITEM_FUNCTION(radio_presets_item, ID2P(LANG_FM_BUTTONBAR_PRESETS), 1480MENUITEM_FUNCTION(radio_presets_item, ID2P(LANG_FM_BUTTONBAR_PRESETS),
1464 handle_radio_presets, NULL, Icon_NOICON); 1481 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
50 int freq_max; 50 int freq_max;
51 int freq_step; 51 int freq_step;
52#if (CONFIG_TUNER & TEA5767) 52#if (CONFIG_TUNER & TEA5767)
53 int deemphasis; /* 0: 50us, 1: 75us */ 53 char deemphasis; /* 0: 50us, 1: 75us */
54 int band; /* 0: europe, 1: japan (BL in TEA spec)*/ 54 char band; /* 0: europe, 1: japan (BL in TEA spec)*/
55 /* Note: "region" parameter is just for display atm and is not compiled. */
56 #define FM_REGION_ENTRY(region, fmin, fmax, fstep, deemph, band) \
57 { fmin, fmax, fstep, deemph, band }
58#else
59 #define FM_REGION_ENTRY(region, fmin, fmax, fstep, deemph, band) \
60 { fmin, fmax, fstep }
55#endif 61#endif
56}; 62};
57 63
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 @@
20#ifndef __TUNER_SAMSUNG_H__ 20#ifndef __TUNER_SAMSUNG_H__
21#define __TUNER_SAMSUNG_H__ 21#define __TUNER_SAMSUNG_H__
22 22
23#include "hwcompat.h"
24
23/* settings to the tuner layer */ 25/* settings to the tuner layer */
26#define RADIO_ALL -1 /* debug */
24#define RADIO_SLEEP 0 27#define RADIO_SLEEP 0
25#define RADIO_FREQUENCY 1 28#define RADIO_FREQUENCY 1
26#define RADIO_MUTE 2 29#define RADIO_MUTE 2
27#define RADIO_IF_MEASUREMENT 3 30#define RADIO_IF_MEASUREMENT 3
28#define RADIO_SENSITIVITY 4 31#define RADIO_SENSITIVITY 4
29#define RADIO_FORCE_MONO 5 32#define RADIO_FORCE_MONO 5
33#define RADIO_SCAN_FREQUENCY 6
30#if (CONFIG_TUNER & TEA5767) 34#if (CONFIG_TUNER & TEA5767)
31#define RADIO_SET_DEEMPHASIS 6 35#define RADIO_SET_DEEMPHASIS 7
32#define RADIO_SET_BAND 7 36#define RADIO_SET_BAND 8
33#endif 37#endif
34/* readback from the tuner layer */ 38/* readback from the tuner layer */
35#define RADIO_PRESENT 0 39#define RADIO_PRESENT 0
36#define RADIO_TUNED 1 40#define RADIO_TUNED 1
37#define RADIO_STEREO 2 41#define RADIO_STEREO 2
38#define RADIO_ALL 3 /* debug */
39 42
40#if CONFIG_TUNER 43#if CONFIG_TUNER
41 44
45#ifdef SIMULATOR
46int radio_set(int setting, int value);
47int radio_get(int setting);
48#else
49#if CONFIG_TUNER == S1A0903X01 /* FM recorder */
50#define radio_set samsung_set
51#define radio_get samsung_get
52#elif CONFIG_TUNER == TEA5767 /* iRiver, iAudio */
53#define radio_set philips_set
54#define radio_get philips_get
55#elif CONFIG_TUNER == (S1A0903X01 | TEA5767) /* OndioFM */
56#define radio_set _radio_set
57#define radio_get _radio_get
58int (*_radio_set)(int setting, int value);
59int (*_radio_get)(int setting);
60#endif
61#endif
62
42#if (CONFIG_TUNER & S1A0903X01) 63#if (CONFIG_TUNER & S1A0903X01)
43void samsung_set(int setting, int value); 64int samsung_set(int setting, int value);
44int samsung_get(int setting); 65int samsung_get(int setting);
45#endif 66#endif /* CONFIG_TUNER & S1A0903X01 */
46 67
47#if (CONFIG_TUNER & TEA5767) 68#if (CONFIG_TUNER & TEA5767)
48void philips_set(int setting, int value); 69struct philips_dbg_info
70{
71 unsigned char read_regs[5];
72 unsigned char write_regs[5];
73};
74int philips_set(int setting, int value);
49int philips_get(int setting); 75int philips_get(int setting);
76void philips_dbg_info(struct philips_dbg_info *info);
77#endif /* CONFIG_TUNER & TEA5767 */
78
79/* Just inline here since only radio screen needs this atm and
80 there's no tuner.c. */
81static inline void tuner_init(void)
82{
83#ifndef SIMULATOR
84#if CONFIG_TUNER == (S1A0903X01 | TEA5767)
85 if (read_hw_mask() & TUNER_MODEL)
86 {
87 _radio_set = philips_set;
88 _radio_get = philips_get;
89 }
90 else
91 {
92 _radio_set = samsung_set;
93 _radio_get = samsung_get;
94 }
95#endif
50#endif 96#endif
97}
51 98
52#endif /* #if CONFIG_TUNER */ 99#endif /* #if CONFIG_TUNER */
53 100
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 @@
29static unsigned char write_bytes[5] = { 0x00, 0x00, 0x00, 0x00, 0x00 }; 29static unsigned char write_bytes[5] = { 0x00, 0x00, 0x00, 0x00, 0x00 };
30 30
31/* tuner abstraction layer: set something to the tuner */ 31/* tuner abstraction layer: set something to the tuner */
32void philips_set(int setting, int value) 32int philips_set(int setting, int value)
33{ 33{
34 switch(setting) 34 switch(setting)
35 { 35 {
@@ -60,6 +60,11 @@ void philips_set(int setting, int value)
60 } 60 }
61 break; 61 break;
62 62
63 case RADIO_SCAN_FREQUENCY:
64 philips_set(RADIO_FREQUENCY, value);
65 sleep(HZ/30);
66 return philips_get(RADIO_TUNED);
67
63 case RADIO_MUTE: 68 case RADIO_MUTE:
64 write_bytes[0] = (write_bytes[0] & 0x7F) | (value ? 0x80 : 0); 69 write_bytes[0] = (write_bytes[0] & 0x7F) | (value ? 0x80 : 0);
65 break; 70 break;
@@ -75,9 +80,10 @@ void philips_set(int setting, int value)
75 case RADIO_SET_BAND: 80 case RADIO_SET_BAND:
76 write_bytes[3] = (write_bytes[3] & ~(1<<5)) | (value ? (1<<5) : 0); 81 write_bytes[3] = (write_bytes[3] & ~(1<<5)) | (value ? (1<<5) : 0);
77 default: 82 default:
78 return; 83 return -1;
79 } 84 }
80 fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes)); 85 fmradio_i2c_write(I2C_ADR, write_bytes, sizeof(write_bytes));
86 return 1;
81} 87}
82 88
83/* tuner abstraction layer: read something from the tuner */ 89/* tuner abstraction layer: read something from the tuner */
@@ -106,13 +112,12 @@ int philips_get(int setting)
106 case RADIO_STEREO: 112 case RADIO_STEREO:
107 val = read_bytes[2] >> 7; 113 val = read_bytes[2] >> 7;
108 break; 114 break;
109
110 case RADIO_ALL: /* debug query */
111 val = read_bytes[0] << 24
112 | read_bytes[1] << 16
113 | read_bytes[2] << 8
114 | read_bytes[3];
115 break;
116 } 115 }
117 return val; 116 return val;
118} 117}
118
119void philips_dbg_info(struct philips_dbg_info *info)
120{
121 fmradio_i2c_read(I2C_ADR, info->read_regs, 5);
122 memcpy(info->write_regs, write_bytes, 5);
123}
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 @@
21#include <stdbool.h> 21#include <stdbool.h>
22#include <stdlib.h> 22#include <stdlib.h>
23#include "config.h" 23#include "config.h"
24#include "kernel.h"
24#include "tuner.h" /* tuner abstraction interface */ 25#include "tuner.h" /* tuner abstraction interface */
25#include "fmradio.h" /* physical interface driver */ 26#include "fmradio.h" /* physical interface driver */
26#include "mpeg.h" 27#include "mpeg.h"
@@ -34,8 +35,10 @@ static int fm_in1;
34static int fm_in2; 35static int fm_in2;
35 36
36/* tuner abstraction layer: set something to the tuner */ 37/* tuner abstraction layer: set something to the tuner */
37void samsung_set(int setting, int value) 38int samsung_set(int setting, int value)
38{ 39{
40 int val = 1;
41
39 switch(setting) 42 switch(setting)
40 { 43 {
41 case RADIO_SLEEP: 44 case RADIO_SLEEP:
@@ -90,6 +93,16 @@ void samsung_set(int setting, int value)
90 break; 93 break;
91 } 94 }
92 95
96 case RADIO_SCAN_FREQUENCY:
97 /* Tune in and delay */
98 samsung_set(RADIO_FREQUENCY, value);
99 sleep(1);
100 /* Start IF measurement */
101 samsung_set(RADIO_IF_MEASUREMENT, 1);
102 sleep(1);
103 val = samsung_get(RADIO_TUNED);
104 break;
105
93 case RADIO_MUTE: 106 case RADIO_MUTE:
94 fm_in1 = (fm_in1 & 0xfffffffe) | (value?1:0); 107 fm_in1 = (fm_in1 & 0xfffffffe) | (value?1:0);
95 fmradio_set(1, fm_in1); 108 fmradio_set(1, fm_in1);
@@ -109,7 +122,11 @@ void samsung_set(int setting, int value)
109 fm_in2 = (fm_in2 & 0xfffffffb) | (value?0:4); 122 fm_in2 = (fm_in2 & 0xfffffffb) | (value?0:4);
110 fmradio_set(2, fm_in2); 123 fmradio_set(2, fm_in2);
111 break; 124 break;
125 default:
126 val = -1;
112 } 127 }
128
129 return val;
113} 130}
114 131
115/* tuner abstraction layer: read something from the tuner */ 132/* 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 @@
26static int frequency = 0; 26static int frequency = 0;
27static bool mono = false; 27static bool mono = false;
28 28
29void radio_set(int setting, int value) 29int radio_set(int setting, int value)
30{ 30{
31 switch(setting) 31 switch(setting)
32 { 32 {
@@ -37,6 +37,10 @@ void radio_set(int setting, int value)
37 frequency = value; 37 frequency = value;
38 break; 38 break;
39 39
40 case RADIO_SCAN_FREQUENCY:
41 frequency = value;
42 break;
43
40 case RADIO_MUTE: 44 case RADIO_MUTE:
41 break; 45 break;
42 46
@@ -45,8 +49,10 @@ void radio_set(int setting, int value)
45 break; 49 break;
46 50
47 default: 51 default:
48 return; 52 return -1;
49 } 53 }
54
55 return 1;
50} 56}
51 57
52int radio_get(int setting) 58int radio_get(int setting)