summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/lang/english.lang36
-rw-r--r--apps/recorder/radio.c390
2 files changed, 281 insertions, 145 deletions
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index 20195cfbd4..2944e562a8 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -2721,3 +2721,39 @@ desc: browser sorting setting
2721eng: "by type" 2721eng: "by type"
2722voice: "by type" 2722voice: "by type"
2723new: 2723new:
2724
2725id: LANG_FM_EDIT_PRESET
2726desc: in radio screen
2727eng: "Edit preset"
2728voice: "Edit preset"
2729new:
2730
2731id: LANG_FM_MONO_MODE
2732desc: in radio screen
2733eng: "Force mono"
2734voice: "Force mono"
2735new:
2736
2737id: LANG_FM_BUTTONBAR_EXIT
2738desc: in radio screen
2739eng: "Exit"
2740voice: "Exit"
2741new:
2742
2743id: LANG_FM_BUTTONBAR_EDIT
2744desc: in radio screen
2745eng: "Edit"
2746voice: "Edit"
2747new:
2748
2749id: LANG_FM_BUTTONBAR_ADD
2750desc: in radio screen
2751eng: "Add"
2752voice: "Add"
2753new:
2754
2755id: LANG_FM_BUTTONBAR_ACTION
2756desc: in radio screen
2757eng: "Action"
2758voice: "Action"
2759new:
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index f75387739a..d4dc8a93aa 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -55,6 +55,18 @@
55#define PLL_FREQ_STEP 10000 55#define PLL_FREQ_STEP 10000
56#define FREQ_STEP 100000 56#define FREQ_STEP 100000
57 57
58#define RADIO_FREQUENCY 0
59#define RADIO_MUTE 1
60#define RADIO_IF_MEASUREMENT 2
61#define RADIO_SENSITIVITY 3
62#define RADIO_FORCE_MONO 4
63
64#define DEFAULT_IN1 0x100003 /* Mute */
65#define DEFAULT_IN2 0x140884 /* 5kHz, 7.2MHz crystal */
66
67static int fm_in1 = DEFAULT_IN1;
68static int fm_in2 = DEFAULT_IN2;
69
58static int curr_preset = -1; 70static int curr_preset = -1;
59static int curr_freq = 99400000; 71static int curr_freq = 99400000;
60static int pll_cnt; 72static int pll_cnt;
@@ -67,15 +79,59 @@ static char default_filename[] = "/.rockbox/fm-presets-default.fmr";
67 79
68int debug_fm_detection; 80int debug_fm_detection;
69 81
82static int preset_menu; /* The menu index of the preset list */
83static struct menu_item preset_menu_items[MAX_PRESETS];
84static int num_presets; /* The number of presets in the preset list */
85
70void radio_load_presets(void); 86void radio_load_presets(void);
71bool radio_preset_select(void); 87bool handle_radio_presets(void);
72bool radio_menu(void); 88bool radio_menu(void);
73 89
74void radio_stop(void) 90void radio_set(int setting, int value)
75{ 91{
76 /* Mute the FM radio */ 92 switch(setting)
77 fmradio_set(1, 0x100003); 93 {
94 case RADIO_FREQUENCY:
95 /* We add the standard Intermediate Frequency 10.7MHz
96 ** before calculating the divisor
97 ** The reference frequency is set to 50kHz, and the VCO
98 ** output is prescaled by 2.
99 */
100
101 pll_cnt = (value + 10700000) / (PLL_FREQ_STEP/2) / 2;
102
103 /* 0x100000 == FM mode
104 ** 0x000002 == Microprocessor controlled Mute
105 */
106 fm_in1 = (fm_in1 & 0xfff00007) | (pll_cnt << 3);
107 fmradio_set(1, fm_in1);
108 break;
109
110 case RADIO_MUTE:
111 fm_in1 = (fm_in1 & 0xfffffffe) | (value?1:0);
112 fmradio_set(1, fm_in1);
113 break;
114
115 case RADIO_IF_MEASUREMENT:
116 fm_in1 = (fm_in1 & 0xfffffffb) | (value?4:0);
117 fmradio_set(1, fm_in1);
118 break;
119
120 case RADIO_SENSITIVITY:
121 fm_in2 = (fm_in2 & 0xffff9fff) | ((value & 3) << 13);
122 fmradio_set(2, fm_in2);
123 break;
124
125 case RADIO_FORCE_MONO:
126 fm_in2 = (fm_in2 & 0xfffffffb) | (value?0:4);
127 fmradio_set(2, fm_in2);
128 break;
129 }
130}
78 131
132void radio_stop(void)
133{
134 radio_set(RADIO_MUTE, 1);
79} 135}
80 136
81bool radio_hardware_present(void) 137bool radio_hardware_present(void)
@@ -91,22 +147,6 @@ bool radio_hardware_present(void)
91 return false; 147 return false;
92} 148}
93 149
94void radio_set_frequency(int freq)
95{
96 /* We add the standard Intermediate Frequency 10.7MHz before calculating
97 ** the divisor
98 ** The reference frequency is set to 50kHz, and the VCO output is prescaled
99 ** by 2.
100 */
101
102 pll_cnt = (freq + 10700000) / (PLL_FREQ_STEP/2) / 2;
103
104 /* 0x100000 == FM mode
105 ** 0x000002 == Microprocessor controlled Mute
106 */
107 fmradio_set(1, 0x100002 | pll_cnt << 3);
108}
109
110static int find_preset(int freq) 150static int find_preset(int freq)
111{ 151{
112 int i; 152 int i;
@@ -192,8 +232,15 @@ bool radio_screen(void)
192 mpeg_sound_default(SOUND_RIGHT_GAIN), false); 232 mpeg_sound_default(SOUND_RIGHT_GAIN), false);
193#endif 233#endif
194 234
195 fmradio_set(2, 0x140884); /* 5kHz, 7.2MHz crystal */ 235 fmradio_set(1, DEFAULT_IN1);
196 radio_set_frequency(curr_freq); 236 fmradio_set(2, DEFAULT_IN2);
237
238 radio_set(RADIO_FREQUENCY, curr_freq);
239 radio_set(RADIO_IF_MEASUREMENT, 0);
240 radio_set(RADIO_SENSITIVITY, 0);
241 radio_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
242 radio_set(RADIO_MUTE, 0);
243
197 curr_preset = find_preset(curr_freq); 244 curr_preset = find_preset(curr_freq);
198 245
199 buttonbar_set(str(LANG_BUTTONBAR_MENU), str(LANG_FM_BUTTONBAR_PRESETS), 246 buttonbar_set(str(LANG_BUTTONBAR_MENU), str(LANG_FM_BUTTONBAR_PRESETS),
@@ -210,11 +257,11 @@ bool radio_screen(void)
210 curr_freq = MIN_FREQ; 257 curr_freq = MIN_FREQ;
211 258
212 /* Tune in and delay */ 259 /* Tune in and delay */
213 radio_set_frequency(curr_freq); 260 radio_set(RADIO_FREQUENCY, curr_freq);
214 sleep(1); 261 sleep(1);
215 262
216 /* Start IF measurement */ 263 /* Start IF measurement */
217 fmradio_set(1, 0x100006 | pll_cnt << 3); 264 radio_set(RADIO_IF_MEASUREMENT, 1);
218 sleep(1); 265 sleep(1);
219 266
220 /* Now check how close to the IF frequency we are */ 267 /* Now check how close to the IF frequency we are */
@@ -280,7 +327,7 @@ bool radio_screen(void)
280 if(curr_freq < MIN_FREQ) 327 if(curr_freq < MIN_FREQ)
281 curr_freq = MIN_FREQ; 328 curr_freq = MIN_FREQ;
282 329
283 radio_set_frequency(curr_freq); 330 radio_set(RADIO_FREQUENCY, curr_freq);
284 curr_preset = find_preset(curr_freq); 331 curr_preset = find_preset(curr_freq);
285 search_dir = 0; 332 search_dir = 0;
286 update_screen = true; 333 update_screen = true;
@@ -291,7 +338,7 @@ bool radio_screen(void)
291 if(curr_freq > MAX_FREQ) 338 if(curr_freq > MAX_FREQ)
292 curr_freq = MAX_FREQ; 339 curr_freq = MAX_FREQ;
293 340
294 radio_set_frequency(curr_freq); 341 radio_set(RADIO_FREQUENCY, curr_freq);
295 curr_preset = find_preset(curr_freq); 342 curr_preset = find_preset(curr_freq);
296 search_dir = 0; 343 search_dir = 0;
297 update_screen = true; 344 update_screen = true;
@@ -337,7 +384,7 @@ bool radio_screen(void)
337 break; 384 break;
338 385
339 case BUTTON_F2: 386 case BUTTON_F2:
340 radio_preset_select(); 387 handle_radio_presets();
341 curr_preset = find_preset(curr_freq); 388 curr_preset = find_preset(curr_freq);
342 lcd_clear_display(); 389 lcd_clear_display();
343 lcd_setmargins(0, 8); 390 lcd_setmargins(0, 8);
@@ -393,7 +440,8 @@ bool radio_screen(void)
393 timeout = current_tick + HZ; 440 timeout = current_tick + HZ;
394 441
395 val = fmradio_read(3); 442 val = fmradio_read(3);
396 stereo = (val & 0x100000)?true:false; 443 stereo = ((val & 0x100000)?true:false) &
444 !global_settings.fm_force_mono;
397 if(stereo != last_stereo_status) 445 if(stereo != last_stereo_status)
398 { 446 {
399 update_screen = true; 447 update_screen = true;
@@ -441,9 +489,12 @@ bool radio_screen(void)
441 } 489 }
442 else 490 else
443 { 491 {
444 snprintf(buf, 32, "%s %02d", 492 if(global_settings.rec_prerecord_time)
445 str(LANG_RECORD_PRERECORD), seconds%60); 493 {
446 lcd_puts(0, top_of_screen + 3, buf); 494 snprintf(buf, 32, "%s %02d",
495 str(LANG_RECORD_PRERECORD), seconds%60);
496 lcd_puts(0, top_of_screen + 3, buf);
497 }
447 } 498 }
448 499
449 /* Only force the redraw if update_screen is true */ 500 /* Only force the redraw if update_screen is true */
@@ -503,29 +554,6 @@ bool radio_screen(void)
503 return have_recorded; 554 return have_recorded;
504} 555}
505 556
506static bool parseline(char* line, char** freq, char** name)
507{
508 char* ptr;
509
510 while ( isspace(*line) )
511 line++;
512
513 if ( *line == '#' )
514 return false;
515
516 ptr = strchr(line, ':');
517 if ( !ptr )
518 return false;
519
520 *freq = line;
521 *ptr = 0;
522 ptr++;
523 while (isspace(*ptr))
524 ptr++;
525 *name = ptr;
526 return true;
527}
528
529void radio_save_presets(void) 557void radio_save_presets(void)
530{ 558{
531 int fd; 559 int fd;
@@ -534,7 +562,7 @@ void radio_save_presets(void)
534 fd = creat(default_filename, O_WRONLY); 562 fd = creat(default_filename, O_WRONLY);
535 if(fd >= 0) 563 if(fd >= 0)
536 { 564 {
537 for(i = 0;i < MAX_PRESETS;i++) 565 for(i = 0;i < num_presets;i++)
538 { 566 {
539 fprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name); 567 fprintf(fd, "%d:%s\n", presets[i].frequency, presets[i].name);
540 } 568 }
@@ -555,10 +583,12 @@ void radio_load_presets(void)
555 char *name; 583 char *name;
556 bool done = false; 584 bool done = false;
557 int i; 585 int i;
586 int f;
558 587
559 if(!presets_loaded) 588 if(!presets_loaded)
560 { 589 {
561 memset(presets, 0, sizeof(presets)); 590 memset(presets, 0, sizeof(presets));
591 num_presets = 0;
562 592
563 fd = open(default_filename, O_RDONLY); 593 fd = open(default_filename, O_RDONLY);
564 if(fd >= 0) 594 if(fd >= 0)
@@ -569,12 +599,16 @@ void radio_load_presets(void)
569 rc = read_line(fd, buf, 128); 599 rc = read_line(fd, buf, 128);
570 if(rc > 0) 600 if(rc > 0)
571 { 601 {
572 if(parseline(buf, &freq, &name)) 602 if(settings_parseline(buf, &freq, &name))
573 { 603 {
574 presets[i].frequency = atoi(freq); 604 f = atoi(freq);
575 strncpy(presets[i].name, name, 27); 605 if(f) /* For backwards compatibility */
576 presets[i].name[27] = 0; 606 {
577 i++; 607 presets[num_presets].frequency = f;
608 strncpy(presets[num_presets].name, name, 27);
609 presets[num_presets].name[27] = 0;
610 num_presets++;
611 }
578 } 612 }
579 } 613 }
580 else 614 else
@@ -586,71 +620,35 @@ void radio_load_presets(void)
586 presets_loaded = true; 620 presets_loaded = true;
587} 621}
588 622
589bool radio_preset_select(void) 623static void rebuild_preset_menu(void)
590{ 624{
591 struct menu_item menu[MAX_PRESETS];
592 int m, result;
593 int i; 625 int i;
594 bool reload_dir = false; 626 for(i = 0;i < num_presets;i++)
595 int num_presets;
596
597 if(presets_loaded)
598 { 627 {
599 num_presets = 0; 628 preset_menu_items[i].desc = presets[i].name;
600 629 preset_menu_items[i].voice_id = -1;
601 for(i = 0;i < MAX_PRESETS;i++)
602 {
603 if(presets[i].frequency)
604 {
605 menu[num_presets].desc = presets[i].name;
606 menu[num_presets].voice_id = -1;
607 /* We use the function pointer entry for the preset
608 entry index */
609 menu[num_presets++].function = (void *)i;
610 }
611 }
612
613 if(num_presets)
614 {
615 /* DIY menu handling, since we want to exit after selection */
616 m = menu_init( menu, num_presets, NULL, NULL, NULL, NULL );
617 result = menu_show(m);
618 menu_exit(m);
619 if (result == MENU_SELECTED_EXIT)
620 return false;
621 else if (result == MENU_ATTACHED_USB)
622 reload_dir = true;
623
624 if (result >= 0)
625 {
626 i = (int)menu[result].function;
627 curr_freq = presets[i].frequency;
628 radio_set_frequency(curr_freq);
629 }
630 }
631 else
632 {
633 splash(HZ*2, true, str(LANG_FM_NO_PRESETS));
634 }
635 } 630 }
636
637 return reload_dir;
638} 631}
639 632
640static bool radio_add_preset(void) 633static bool radio_add_preset(void)
641{ 634{
642 char buf[27]; 635 char buf[27];
643 int i = find_preset(0);
644 636
645 if(i >= 0) 637 if(num_presets < MAX_PRESETS)
646 { 638 {
647 memset(buf, 0, 27); 639 memset(buf, 0, 27);
648 640
649 if (!kbd_input(buf, 27)) 641 if (!kbd_input(buf, 27))
650 { 642 {
651 buf[27] = 0; 643 buf[27] = 0;
652 strcpy(presets[i].name, buf); 644 strcpy(presets[num_presets].name, buf);
653 presets[i].frequency = curr_freq; 645 presets[num_presets].frequency = curr_freq;
646 menu_insert(preset_menu, -1,
647 presets[num_presets].name, 0, 0);
648 /* We must still rebuild the menu table, since the
649 item name pointers must be updated */
650 rebuild_preset_menu();
651 num_presets++;
654 radio_save_presets(); 652 radio_save_presets();
655 } 653 }
656 } 654 }
@@ -661,47 +659,129 @@ static bool radio_add_preset(void)
661 return true; 659 return true;
662} 660}
663 661
662static int handle_radio_presets_menu_cb(int key, int m)
663{
664 (void)m;
665 switch(key)
666 {
667 case BUTTON_F3:
668 key = BUTTON_LEFT; /* Fake an exit */
669 break;
670 }
671 return key;
672}
673
674static bool radio_edit_preset(void)
675{
676 int pos = menu_cursor(preset_menu);
677 char buf[27];
678
679 strncpy(buf, menu_description(preset_menu, pos), 27);
680
681 if (!kbd_input(buf, 27))
682 {
683 buf[27] = 0;
684 strcpy(presets[pos].name, buf);
685 radio_save_presets();
686 }
687 return true;
688}
689
664bool radio_delete_preset(void) 690bool radio_delete_preset(void)
665{ 691{
666 struct menu_item menu[MAX_PRESETS]; 692 int pos = menu_cursor(preset_menu);
667 int m, result; 693 int i;
694
695 for(i = pos;i < num_presets;i++)
696 presets[i] = presets[i+1];
697 num_presets--;
698
699 menu_delete(preset_menu, pos);
700 /* We must still rebuild the menu table, since the
701 item name pointers must be updated */
702 rebuild_preset_menu();
703 radio_save_presets();
704
705 return true; /* Make the menu return immediately */
706}
707
708bool handle_radio_presets_menu(void)
709{
710 struct menu_item preset_menu_items[] = {
711 { STR(LANG_FM_EDIT_PRESET), radio_edit_preset },
712 { STR(LANG_FM_DELETE_PRESET), radio_delete_preset },
713 };
714 int m;
715
716 m = menu_init( preset_menu_items,
717 sizeof preset_menu_items / sizeof(struct menu_item),
718 handle_radio_presets_menu_cb,
719 NULL, NULL, str(LANG_FM_BUTTONBAR_EXIT));
720 menu_run(m);
721 menu_exit(m);
722 return false;
723}
724
725int handle_radio_presets_cb(int key, int m)
726{
727 bool ret;
728
729 switch(key)
730 {
731 case BUTTON_F1:
732 radio_add_preset();
733 menu_draw(m);
734 key = BUTTON_NONE;
735 break;
736
737 case BUTTON_F2:
738 menu_draw(m);
739 key = BUTTON_LEFT; /* Fake an exit */
740 break;
741
742 case BUTTON_F3:
743 ret = handle_radio_presets_menu();
744 menu_draw(m);
745 if(ret)
746 key = MENU_ATTACHED_USB;
747 else
748 key = BUTTON_NONE;
749 break;
750 }
751 return key;
752}
753
754bool handle_radio_presets(void)
755{
756 int result;
668 int i; 757 int i;
669 bool reload_dir = false; 758 bool reload_dir = false;
670 int num_presets;
671 759
672 if(presets_loaded) 760 if(presets_loaded)
673 { 761 {
674 num_presets = 0; 762 rebuild_preset_menu();
675 763
676 for(i = 0;i < MAX_PRESETS;i++)
677 {
678 if(presets[i].frequency)
679 {
680 menu[num_presets].desc = presets[i].name;
681 menu[num_presets].voice_id = -1;
682 /* We use the function pointer entry for the preset
683 entry index */
684 menu[num_presets++].function = (void *)i;
685 }
686 }
687
688 /* DIY menu handling, since we want to exit after selection */ 764 /* DIY menu handling, since we want to exit after selection */
689 m = menu_init( menu, num_presets, NULL, NULL, NULL, NULL ); 765 preset_menu = menu_init( preset_menu_items, num_presets,
690 result = menu_show(m); 766 handle_radio_presets_cb,
691 menu_exit(m); 767 str(LANG_FM_BUTTONBAR_ADD),
768 str(LANG_FM_BUTTONBAR_EXIT),
769 str(LANG_FM_BUTTONBAR_ACTION));
770 result = menu_show(preset_menu);
771 menu_exit(preset_menu);
692 if (result == MENU_SELECTED_EXIT) 772 if (result == MENU_SELECTED_EXIT)
693 return false; 773 return false;
694 else if (result == MENU_ATTACHED_USB) 774 else if (result == MENU_ATTACHED_USB)
695 reload_dir = true; 775 reload_dir = true;
696 776
697 if (result >= 0) 777 if (result >= 0) /* A preset was selected */
698 { 778 {
699 i = (int)menu[result].function; 779 i = menu_cursor(preset_menu);
700 presets[i].frequency = 0; 780 curr_freq = presets[i].frequency;
701 radio_save_presets(); 781 radio_set(RADIO_FREQUENCY, curr_freq);
702 } 782 }
703 } 783 }
704 784
705 return reload_dir; 785 return reload_dir;
706} 786}
707 787
@@ -726,22 +806,42 @@ static bool fm_recording_settings(void)
726 return ret; 806 return ret;
727} 807}
728#endif 808#endif
809
810char monomode_menu_string[32];
811
812static void create_monomode_menu(void)
813{
814 snprintf(monomode_menu_string, 32, "%s: %s", str(LANG_FM_MONO_MODE),
815 global_settings.fm_force_mono?
816 str(LANG_SET_BOOL_YES):str(LANG_SET_BOOL_NO));
817}
818
819static bool toggle_mono_mode(void)
820{
821 global_settings.fm_force_mono = !global_settings.fm_force_mono;
822 radio_set(RADIO_FORCE_MONO, global_settings.fm_force_mono);
823 settings_save();
824 create_monomode_menu();
825 return false;
826}
827
729bool radio_menu(void) 828bool radio_menu(void)
730{ 829{
731 struct menu_item radio_menu_items[] = { 830 struct menu_item items[3];
732 { STR(LANG_FM_SAVE_PRESET), radio_add_preset },
733 { STR(LANG_FM_DELETE_PRESET), radio_delete_preset },
734 { STR(LANG_SOUND_SETTINGS), sound_menu },
735#ifndef SIMULATOR
736 { STR(LANG_RECORDING_SETTINGS), fm_recording_settings }
737#endif
738 };
739 int m; 831 int m;
740 bool result; 832 bool result;
741 833
742 m = menu_init( radio_menu_items, 834 m = menu_init(items, 0, NULL, NULL, NULL, NULL);
743 sizeof radio_menu_items / sizeof(struct menu_item), NULL, 835
744 NULL, NULL, NULL); 836 create_monomode_menu();
837 menu_insert(m, -1, monomode_menu_string, LANG_FM_MONO_MODE,
838 toggle_mono_mode);
839 menu_insert(m, -1, STR(LANG_SOUND_SETTINGS), sound_menu);
840
841#ifndef SIMULATOR
842 menu_insert(m, -1, STR(LANG_RECORDING_SETTINGS), fm_recording_settings);
843#endif
844
745 result = menu_run(m); 845 result = menu_run(m);
746 menu_exit(m); 846 menu_exit(m);
747 return result; 847 return result;