summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Gautier <creposucre@rockbox.org>2009-12-01 17:54:40 +0000
committerLaurent Gautier <creposucre@rockbox.org>2009-12-01 17:54:40 +0000
commit0260852771aef7a6e9045684f0c3d0d7e01909f7 (patch)
tree6fa4b42230d1289857f84405defad94cc2de86b8
parent63d79148fd07aebd2b425c0414b7b9622b312399 (diff)
downloadrockbox-0260852771aef7a6e9045684f0c3d0d7e01909f7.tar.gz
rockbox-0260852771aef7a6e9045684f0c3d0d7e01909f7.zip
Add support for the ipod FM remote to the 4G, Color, 5G, nano 1G with RDS
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23805 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/iap.c208
-rw-r--r--apps/keymaps/keymap-ipod.c52
-rw-r--r--apps/recorder/radio.c63
-rw-r--r--docs/COMMITTERS1
-rw-r--r--firmware/SOURCES5
-rw-r--r--firmware/drivers/tuner/ipod_remote_tuner.c444
-rw-r--r--firmware/export/config-ipod4g.h6
-rw-r--r--firmware/export/config-ipodcolor.h6
-rw-r--r--firmware/export/config-ipodnano.h6
-rw-r--r--firmware/export/config-ipodvideo.h6
-rw-r--r--firmware/export/config.h1
-rw-r--r--firmware/export/iap.h5
-rw-r--r--firmware/export/ipod_remote_tuner.h75
-rw-r--r--firmware/export/tuner.h21
-rw-r--r--firmware/target/arm/audio-pp.c7
-rw-r--r--firmware/tuner.c19
16 files changed, 876 insertions, 49 deletions
diff --git a/apps/iap.c b/apps/iap.c
index 29cee22ab5..741ff9fb0c 100644
--- a/apps/iap.c
+++ b/apps/iap.c
@@ -37,11 +37,12 @@
37#include "settings.h" 37#include "settings.h"
38#include "metadata.h" 38#include "metadata.h"
39#include "wps.h" 39#include "wps.h"
40 40#include "sound.h"
41#include "action.h" 41#include "action.h"
42#include "powermgmt.h"
42 43
43#define RX_BUFLEN 260 44#include "tuner.h"
44#define TX_BUFLEN 128 45#include "ipod_remote_tuner.h"
45 46
46static volatile int iap_pollspeed = 0; 47static volatile int iap_pollspeed = 0;
47static volatile bool iap_remotetick = true; 48static volatile bool iap_remotetick = true;
@@ -115,7 +116,7 @@ void iap_bitrate_set(int ratenum)
115 checksum (length+mode+parameters+checksum == 0) 116 checksum (length+mode+parameters+checksum == 0)
116*/ 117*/
117 118
118static void iap_send_pkt(const unsigned char * data, int len) 119void iap_send_pkt(const unsigned char * data, int len)
119{ 120{
120 int i, chksum; 121 int i, chksum;
121 122
@@ -192,15 +193,15 @@ void iap_periodic(void)
192 unsigned long time_elapsed = audio_current_track()->elapsed; 193 unsigned long time_elapsed = audio_current_track()->elapsed;
193 194
194 time_elapsed += wps_get_ff_rewind_count(); 195 time_elapsed += wps_get_ff_rewind_count();
195 196
196 data[3] = 0x04; // playing 197 data[3] = 0x04; /* playing */
197 198
198 /* If info has changed, don't flag it right away */ 199 /* If info has changed, don't flag it right away */
199 if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2) 200 if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2)
200 { 201 {
201 /* track info has changed */ 202 /* track info has changed */
202 iap_changedctr = 0; 203 iap_changedctr = 0;
203 data[3] = 0x01; // 0x02 has same effect? 204 data[3] = 0x01; /* 0x02 has same effect? */
204 iap_updateflag = true; 205 iap_updateflag = true;
205 } 206 }
206 207
@@ -211,12 +212,19 @@ void iap_periodic(void)
211 iap_send_pkt(data, sizeof(data)); 212 iap_send_pkt(data, sizeof(data));
212} 213}
213 214
215void iap_set_remote_volume(void)
216{
217 unsigned char data[] = {0x03, 0x0D, 0x04, 0x00, 0x00};
218 data[4] = (char)((global_settings.volume+58) * 4);
219 iap_send_pkt(data, sizeof(data));
220}
221
214void iap_handlepkt(void) 222void iap_handlepkt(void)
215{ 223{
216 224
217 if(!iap_setupflag) return; 225 if(!iap_setupflag) return;
218 if(serbuf[0] == 0) return; 226 if(serbuf[0] == 0) return;
219 227
220 /* if we are waiting for a remote button to go out, 228 /* if we are waiting for a remote button to go out,
221 delay the handling of the new packet */ 229 delay the handling of the new packet */
222 if(!iap_remotetick) 230 if(!iap_remotetick)
@@ -224,63 +232,140 @@ void iap_handlepkt(void)
224 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0); 232 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
225 return; 233 return;
226 } 234 }
227 235
228 /* Handle Mode 0 */ 236 /* Handle Mode 0 */
229 if (serbuf[1] == 0x00) 237 if (serbuf[1] == 0x00)
230 { 238 {
231 switch (serbuf[2]) 239 switch (serbuf[2])
232 { 240 {
233 /* get model info */ 241 case 0x24:
234 case 0x0D:
235 { 242 {
236 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10, 243 /* ipod video send this */
237 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00}; 244 unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00,0x01};
238 iap_send_pkt(data, sizeof(data)); 246 iap_send_pkt(data, sizeof(data));
239 break; 247 break;
240 } 248 }
241 /* No idea ??? */ 249
242 case 0x0F: 250 case 0x18:
243 { 251 {
244 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05}; 252 /* ciphered authentication command */
245 iap_send_pkt(data, sizeof(data)); 253 /* Isn't used since we don't send the 0x00 0x17 command */
246 break; 254 break;
247 } 255 }
248 /* FM transmitter sends this: FF 55 06 00 01 05 00 02 01 F1 (mode switch) */ 256
249 case 0x01: 257 case 0x15:
250 { 258 {
251 if(serbuf[3] == 0x05) 259 unsigned char data0[] = {0x00, 0x16, 0x00};
260 iap_send_pkt(data0, sizeof(data0));
261 unsigned char data1[] = {0x00, 0x27, 0x00};
262 iap_send_pkt(data1, sizeof(data1));
263 /* authentication ack, mandatory to enable some hardware */
264 unsigned char data2[] = {0x00, 0x19, 0x00};
265 iap_send_pkt(data2, sizeof(data2));
266 if (radio_present == 1)
252 { 267 {
253 sleep(HZ/3); 268 /* get tuner capacities */
254 unsigned char data[] = {0x05, 0x02}; 269 unsigned char data3[] = {0x07, 0x01};
255 iap_send_pkt(data, sizeof(data)); 270 iap_send_pkt(data3, sizeof(data3));
256 } 271 }
272 iap_set_remote_volume();
257 break; 273 break;
258 } 274 }
259 /* FM transmitter sends this: FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (???)*/ 275
260 case 0x13: 276 case 0x13:
261 { 277 {
262 unsigned char data[] = {0x00, 0x02, 0x00, 0x13}; 278 unsigned char data[] = {0x00, 0x02, 0x00, 0x13};
263 iap_send_pkt(data, sizeof(data)); 279 iap_send_pkt(data, sizeof(data));
264 unsigned char data2[] = {0x00, 0x27, 0x00}; 280
265 iap_send_pkt(data2, sizeof(data2)); 281 if (serbuf[6] == 0x35)
266 unsigned char data3[] = {0x05, 0x02}; 282 /* FM transmitter sends this: */
267 iap_send_pkt(data3, sizeof(data3)); 283 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
284 {
285 unsigned char data2[] = {0x00, 0x27, 0x00};
286 iap_send_pkt(data2, sizeof(data2));
287 unsigned char data3[] = {0x05, 0x02};
288 iap_send_pkt(data3, sizeof(data3));
289 }
290
291 else
292 {
293 /* ipod fm remote sends this: */
294 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
295 if (serbuf[6] |= 0x80)
296 radio_present = 1;
297 unsigned char data4[] = {0x00, 0x14};
298 iap_send_pkt(data4, sizeof(data4));
299 }
268 break; 300 break;
269 } 301 }
270 /* FM transmitter sends this: FF 55 02 00 05 F9 (mode switch: AiR mode) */ 302
303 /* Init */
304 case 0x0F:
305 {
306 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
307 data[2] = serbuf[3];
308 iap_send_pkt(data, sizeof(data));
309 break;
310 }
311
312 /* get model info */
313 case 0x0D:
314 {
315 /* ipod is supposed to work only with 5G and nano 2G */
316 /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34,
317 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */
318 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
319 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
320 iap_send_pkt(data, sizeof(data));
321 break;
322 }
323
324 /* Ipod FM remote sends this: FF 55 02 00 09 F5 */
325 case 0x09:
326 {
327 /* ipod5G firmware version */
328 unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01 };
329 iap_send_pkt(data, sizeof(data));
330 break;
331 }
332
333 /* FM transmitter sends this: */
334 /* FF 55 02 00 05 F9 (mode switch: AiR mode) */
271 case 0x05: 335 case 0x05:
272 { 336 {
273 unsigned char data[] = {0x00, 0x02, 0x06, 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28}; 337 unsigned char data[] = {0x00, 0x02, 0x06,
338 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28};
274 iap_send_pkt(data, sizeof(data)); 339 iap_send_pkt(data, sizeof(data));
275 unsigned char data2[] = {0x00, 0x02, 0x00, 0x05}; 340 unsigned char data2[] = {0x00, 0x02, 0x00, 0x05};
276 iap_send_pkt(data2, sizeof(data2)); 341 iap_send_pkt(data2, sizeof(data2));
277 break; 342 break;
278 } 343 }
344
345 case 0x01:
346 {
347 /* FM transmitter sends this: */
348 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
349 if(serbuf[3] == 0x05)
350 {
351 sleep(HZ/3);
352 unsigned char data[] = {0x05, 0x02};
353 iap_send_pkt(data, sizeof(data));
354 }
355 /* FM remote sends this: */
356 /* FF 55 03 00 01 02 FA (1st thing sent) */
357 else if(serbuf[3] == 0x02)
358 {
359 /* useful only for apple firmware */
360 }
361 break;
362 }
363
279 /* default response is with cmd ok packet */ 364 /* default response is with cmd ok packet */
280 default: 365 default:
281 { 366 {
282 unsigned char data[] = {0x00, 0x02, 0x00, 0x00}; 367 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
283 data[3] = serbuf[2]; //respond with cmd 368 data[3] = serbuf[2]; /* respond with cmd */
284 iap_send_pkt(data, sizeof(data)); 369 iap_send_pkt(data, sizeof(data));
285 break; 370 break;
286 } 371 }
@@ -395,6 +480,30 @@ void iap_handlepkt(void)
395 iap_send_pkt(data, sizeof(data)); 480 iap_send_pkt(data, sizeof(data));
396 break; 481 break;
397 } 482 }
483
484 case 0x08:
485 {
486 /* ACK */
487 unsigned char data[] = {0x03, 0x00, 0x00, 0x08};
488 iap_send_pkt(data, sizeof(data));
489 break;
490 }
491
492 case 0x0C:
493 {
494 /* request ipod volume */
495 if (serbuf[3] == 0x04)
496 {
497 iap_set_remote_volume();
498 }
499 break;
500 }
501 /* get volume from accessory */
502 case 0x0E:
503 if (serbuf[3] == 0x04)
504 global_settings.volume = (-58)+((int)serbuf[5]+1)/4;
505 sound_set_volume(global_settings.volume);
506 break;
398 } 507 }
399 } 508 }
400 /* Handle Mode 4 */ 509 /* Handle Mode 4 */
@@ -712,6 +821,37 @@ void iap_handlepkt(void)
712 } 821 }
713 } 822 }
714 } 823 }
824 /* Handle Mode 7 */
825 else if (serbuf[1] == 0x07)
826 {
827 switch(serbuf[2])
828 {
829 /* tuner capabilities */
830 case 0x02:
831 {
832 /* do nothing */
833
834 unsigned char data[] = {0x00, 0x27, 0x00};
835 iap_send_pkt(data, sizeof(data));
836 break;
837 }
838 /* actual tuner frequency */
839 case 0x0A:
840 /* fall through */
841 /* tuner frequency from scan */
842 case 0x13:
843 {
844 rmt_tuner_freq();
845 break;
846 }
847 /* RDS station name 0x21 1E 00 + ASCII text*/
848 case 0x21:
849 {
850 rmt_tuner_rds_data();
851 break;
852 }
853 }
854 }
715 serbuf[0] = 0; 855 serbuf[0] = 0;
716} 856}
717 857
diff --git a/apps/keymaps/keymap-ipod.c b/apps/keymaps/keymap-ipod.c
index 1a8f7a25ff..9b3323bb82 100644
--- a/apps/keymaps/keymap-ipod.c
+++ b/apps/keymaps/keymap-ipod.c
@@ -193,6 +193,26 @@ const struct button_mapping button_context_recscreen[] = {
193}; /* button_context_recscreen */ 193}; /* button_context_recscreen */
194#endif 194#endif
195 195
196/** FM Radio Screen **/
197 #if CONFIG_TUNER
198 static const struct button_mapping button_context_radio[] = {
199 { ACTION_FM_MENU, BUTTON_SELECT | BUTTON_REPEAT, BUTTON_NONE },
200 { ACTION_FM_STOP, BUTTON_PLAY | BUTTON_REPEAT, BUTTON_PLAY },
201 { ACTION_FM_MODE, BUTTON_SELECT, BUTTON_NONE },
202 { ACTION_FM_EXIT, BUTTON_MENU | BUTTON_REL, BUTTON_NONE },
203 { ACTION_FM_PLAY, BUTTON_PLAY | BUTTON_REL, BUTTON_PLAY },
204 { ACTION_SETTINGS_INC, BUTTON_SCROLL_FWD, BUTTON_NONE },
205 { ACTION_SETTINGS_INCREPEAT,BUTTON_SCROLL_FWD|BUTTON_REPEAT, BUTTON_NONE },
206 { ACTION_SETTINGS_DEC, BUTTON_SCROLL_BACK, BUTTON_NONE },
207 { ACTION_SETTINGS_DECREPEAT,BUTTON_SCROLL_BACK|BUTTON_REPEAT,BUTTON_NONE },
208 { ACTION_STD_NEXT, BUTTON_RIGHT, BUTTON_NONE },
209 { ACTION_STD_NEXTREPEAT, BUTTON_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
210 { ACTION_STD_PREV, BUTTON_LEFT, BUTTON_NONE },
211 { ACTION_STD_PREVREPEAT, BUTTON_LEFT|BUTTON_REPEAT, BUTTON_NONE },
212 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_SETTINGS)
213 }; /* button_context_radio */
214 #endif
215
196#ifdef USB_ENABLE_HID 216#ifdef USB_ENABLE_HID
197static const struct button_mapping button_context_usb_hid[] = { 217static const struct button_mapping button_context_usb_hid[] = {
198 { ACTION_USB_HID_MODE_SWITCH_NEXT, BUTTON_SELECT|BUTTON_RIGHT|BUTTON_REL, BUTTON_SELECT|BUTTON_RIGHT }, 218 { ACTION_USB_HID_MODE_SWITCH_NEXT, BUTTON_SELECT|BUTTON_RIGHT|BUTTON_REL, BUTTON_SELECT|BUTTON_RIGHT },
@@ -311,6 +331,26 @@ static const struct button_mapping remote_button_context_wps[] = {
311 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD) 331 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
312}; /* remote_button_context_wps */ 332}; /* remote_button_context_wps */
313 333
334static const struct button_mapping remote_button_context_tree[] = {
335 { ACTION_TREE_WPS, BUTTON_RC_PLAY|BUTTON_REL, BUTTON_RC_PLAY },
336 { ACTION_TREE_STOP, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_RC_PLAY },
337
338 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
339}; /* remote_button_context_tree */
340
341#if CONFIG_TUNER
342 static const struct button_mapping remote_button_context_radio[] = {
343 { ACTION_FM_STOP, BUTTON_RC_PLAY | BUTTON_REPEAT, BUTTON_NONE },
344 { ACTION_FM_PLAY, BUTTON_RC_PLAY | BUTTON_REL, BUTTON_RC_PLAY },
345 { ACTION_STD_NEXT, BUTTON_RC_RIGHT|BUTTON_REL, BUTTON_RC_RIGHT },
346 { ACTION_STD_NEXTREPEAT, BUTTON_RC_RIGHT|BUTTON_REPEAT, BUTTON_NONE },
347 { ACTION_STD_PREV, BUTTON_RC_LEFT|BUTTON_REL, BUTTON_RC_LEFT },
348 { ACTION_STD_PREVREPEAT, BUTTON_RC_LEFT|BUTTON_REPEAT, BUTTON_NONE },
349
350 LAST_ITEM_IN_LIST
351 }; /* remote_button_context_radio */
352#endif
353
314static const struct button_mapping* get_context_mapping_remote( int context ) 354static const struct button_mapping* get_context_mapping_remote( int context )
315{ 355{
316 context ^= CONTEXT_REMOTE; 356 context ^= CONTEXT_REMOTE;
@@ -319,6 +359,14 @@ static const struct button_mapping* get_context_mapping_remote( int context )
319 { 359 {
320 case CONTEXT_WPS: 360 case CONTEXT_WPS:
321 return remote_button_context_wps; 361 return remote_button_context_wps;
362 case CONTEXT_TREE:
363 case CONTEXT_CUSTOM|CONTEXT_TREE:
364 return remote_button_context_tree;
365
366#ifdef CONFIG_TUNER
367 case CONTEXT_FM:
368 return remote_button_context_radio;
369#endif
322 default: 370 default:
323 return remote_button_context_standard; 371 return remote_button_context_standard;
324 } 372 }
@@ -371,6 +419,10 @@ const struct button_mapping* get_context_mapping(int context)
371 case CONTEXT_RECSCREEN: 419 case CONTEXT_RECSCREEN:
372 return button_context_recscreen; 420 return button_context_recscreen;
373#endif 421#endif
422#if CONFIG_TUNER
423 case CONTEXT_FM:
424 return button_context_radio;
425#endif
374#ifdef USB_ENABLE_HID 426#ifdef USB_ENABLE_HID
375 case CONTEXT_USB_HID: 427 case CONTEXT_USB_HID:
376 return button_context_usb_hid; 428 return button_context_usb_hid;
diff --git a/apps/recorder/radio.c b/apps/recorder/radio.c
index b70c682922..87614aec15 100644
--- a/apps/recorder/radio.c
+++ b/apps/recorder/radio.c
@@ -49,6 +49,9 @@
49#ifdef HAVE_RECORDING 49#ifdef HAVE_RECORDING
50#include "recording.h" 50#include "recording.h"
51#endif 51#endif
52#ifdef IPOD_ACCESSORY_PROTOCOL
53#include "iap.h"
54#endif
52#include "talk.h" 55#include "talk.h"
53#include "tuner.h" 56#include "tuner.h"
54#include "power.h" 57#include "power.h"
@@ -114,6 +117,15 @@
114#define FM_MODE 117#define FM_MODE
115#define FM_EXIT 118#define FM_EXIT
116#define FM_PLAY 119#define FM_PLAY
120
121#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
122 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
123#define FM_MENU
124#define FM_STOP
125#define FM_EXIT
126#define FM_PLAY
127#define FM_MODE
128
117#endif 129#endif
118 130
119#define RADIO_SCAN_MODE 0 131#define RADIO_SCAN_MODE 0
@@ -586,7 +598,6 @@ int radio_screen(void)
586 end_search(); 598 end_search();
587 talk = true; 599 talk = true;
588 } 600 }
589
590 trigger_cpu_boost(); 601 trigger_cpu_boost();
591 } 602 }
592 603
@@ -873,6 +884,33 @@ int radio_screen(void)
873 884
874 default: 885 default:
875 default_event_handler(button); 886 default_event_handler(button);
887#ifdef HAVE_RDS_CAP
888 if (tuner_get(RADIO_EVENT))
889 update_screen = true;
890#endif
891 if (!tuner_get(RADIO_PRESENT))
892 {
893#if CONFIG_CODEC != SWCODEC && !defined(SIMULATOR)
894 if(audio_status() == AUDIO_STATUS_RECORD)
895 audio_stop();
896#endif
897 keep_playing = false;
898 done = true;
899 ret_val = GO_TO_ROOT;
900 if(presets_changed)
901 {
902 if(yesno_pop(ID2P(LANG_FM_SAVE_CHANGES)))
903 {
904 if(filepreset[0] == '\0')
905 save_preset_list();
906 else
907 radio_save_presets();
908 }
909 }
910
911 /* Clear the preset list on exit. */
912 clear_preset_list();
913 }
876 break; 914 break;
877 } /*switch(button)*/ 915 } /*switch(button)*/
878 916
@@ -895,11 +933,11 @@ int radio_screen(void)
895 { 933 {
896 screens[i].set_viewport(&vp[i]); 934 screens[i].set_viewport(&vp[i]);
897 peak_meter_screen(&screens[i],0, 935 peak_meter_screen(&screens[i],0,
898 STATUSBAR_HEIGHT + fh*(top_of_screen + 4), 936 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
899 fh); 937 fh);
900 screens[i].update_rect(0, 938 screens[i].update_rect(0,
901 STATUSBAR_HEIGHT + fh*(top_of_screen + 4), 939 STATUSBAR_HEIGHT + fh*(top_of_screen + 4),
902 screens[i].getwidth(), fh); 940 screens[i].getwidth(), fh);
903 screens[i].set_viewport(NULL); 941 screens[i].set_viewport(NULL);
904 } 942 }
905 } 943 }
@@ -963,7 +1001,18 @@ int radio_screen(void)
963 str(LANG_RADIO_SCAN_MODE)); 1001 str(LANG_RADIO_SCAN_MODE));
964 FOR_NB_SCREENS(i) 1002 FOR_NB_SCREENS(i)
965 screens[i].puts_scroll(0, top_of_screen + 3, buf); 1003 screens[i].puts_scroll(0, top_of_screen + 3, buf);
1004#ifndef SIMULATOR
1005#ifdef HAVE_RDS_CAP
1006 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_NAME));
1007 FOR_NB_SCREENS(i)
1008 screens[i].puts_scroll(0, top_of_screen + 4, buf);
966 1009
1010 snprintf(buf, 128, "%s",tuner_get_rds_info(RADIO_RDS_TEXT));
1011 FOR_NB_SCREENS(i)
1012 screens[i].puts_scroll(0, top_of_screen + 5, buf);
1013#endif
1014#endif /* SIMULATOR */
1015
967#if CONFIG_CODEC != SWCODEC 1016#if CONFIG_CODEC != SWCODEC
968 if(audio_status() == AUDIO_STATUS_RECORD) 1017 if(audio_status() == AUDIO_STATUS_RECORD)
969 { 1018 {
@@ -1498,6 +1547,7 @@ static int scan_presets(void *viewports)
1498 curr_freq = fmr->freq_min; 1547 curr_freq = fmr->freq_min;
1499 num_presets = 0; 1548 num_presets = 0;
1500 memset(presets, 0, sizeof(presets)); 1549 memset(presets, 0, sizeof(presets));
1550
1501 tuner_set(RADIO_MUTE, 1); 1551 tuner_set(RADIO_MUTE, 1);
1502 1552
1503 while(curr_freq <= fmr->freq_max) 1553 while(curr_freq <= fmr->freq_max)
@@ -1563,7 +1613,6 @@ static int fm_recording_screen(void)
1563 /* switch recording source to FMRADIO for the duration */ 1613 /* switch recording source to FMRADIO for the duration */
1564 int rec_source = global_settings.rec_source; 1614 int rec_source = global_settings.rec_source;
1565 global_settings.rec_source = AUDIO_SRC_FMRADIO; 1615 global_settings.rec_source = AUDIO_SRC_FMRADIO;
1566
1567 ret = recording_screen(true); 1616 ret = recording_screen(true);
1568 1617
1569 /* safe to reset as changing sources is prohibited here */ 1618 /* safe to reset as changing sources is prohibited here */
@@ -1649,7 +1698,7 @@ MAKE_MENU(radio_settings_menu, ID2P(LANG_FM_MENU), NULL,
1649static bool radio_menu(void) 1698static bool radio_menu(void)
1650{ 1699{
1651 return do_menu(&radio_settings_menu, NULL, NULL, false) == 1700 return do_menu(&radio_settings_menu, NULL, NULL, false) ==
1652 MENU_ATTACHED_USB; 1701 MENU_ATTACHED_USB;
1653} 1702}
1654 1703
1655#endif 1704#endif
diff --git a/docs/COMMITTERS b/docs/COMMITTERS
index 0b107e1c0a..705891a543 100644
--- a/docs/COMMITTERS
+++ b/docs/COMMITTERS
@@ -61,6 +61,7 @@ kjer Kjell Ericson
61kkurbjun Karl Kurbjun 61kkurbjun Karl Kurbjun
62kugel Thomas Martitz 62kugel Thomas Martitz
63lamed Shachar Liberman 63lamed Shachar Liberman
64laurent Gautier
64learman Magnus Holmgren 65learman Magnus Holmgren
65len0x Anton Oleynikov 66len0x Anton Oleynikov
66lenzone10 Alessio Lenzi 67lenzone10 Alessio Lenzi
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 061c6323c8..1a078ada29 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -201,6 +201,7 @@ drivers/rtc/rtc_d2.c
201#endif /* (CONFIG_RTC == RTC_) */ 201#endif /* (CONFIG_RTC == RTC_) */
202#endif /* SIMULATOR */ 202#endif /* SIMULATOR */
203 203
204#ifndef BOOTLOADER
204/* Tuner */ 205/* Tuner */
205#if CONFIG_TUNER 206#if CONFIG_TUNER
206tuner.c 207tuner.c
@@ -221,8 +222,12 @@ drivers/tuner/tea5767.c
221#if (CONFIG_TUNER & SI4700) 222#if (CONFIG_TUNER & SI4700)
222drivers/tuner/si4700.c 223drivers/tuner/si4700.c
223#endif /* (CONFIG_TUNER & SI4700) */ 224#endif /* (CONFIG_TUNER & SI4700) */
225#if (CONFIG_TUNER & IPOD_REMOTE_TUNER)
226drivers/tuner/ipod_remote_tuner.c
227#endif /* (CONFIG_TUNER & IPOD_REMOTE_TUNER) */
224#endif /*SIMULATOR */ 228#endif /*SIMULATOR */
225#endif /* CONFIG_TUNER */ 229#endif /* CONFIG_TUNER */
230#endif /* BOOTLOADER */
226 231
227/* Sound */ 232/* Sound */
228#if CONFIG_CODEC != SWCODEC 233#if CONFIG_CODEC != SWCODEC
diff --git a/firmware/drivers/tuner/ipod_remote_tuner.c b/firmware/drivers/tuner/ipod_remote_tuner.c
new file mode 100644
index 0000000000..07a5eeb9a6
--- /dev/null
+++ b/firmware/drivers/tuner/ipod_remote_tuner.c
@@ -0,0 +1,444 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 * tuner for the ipod fm remote and other ipod remote tuners
10 *
11 * Copyright (C) 2009 Laurent Gautier
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include "config.h"
23#include <stdio.h>
24#include <stdbool.h>
25#include <string.h>
26#include <stdlib.h>
27#include "kernel.h"
28#include "iap.h"
29#include "tuner.h" /* tuner abstraction interface */
30#include "adc.h"
31#include "settings.h"
32
33static bool powered = false;
34
35static unsigned char tuner_param = 0x00, old_tuner_param = 0xFF;
36/* temp var for tests to avoid looping execution in submenus settings*/
37int mono_mode = -1, old_region = -1;
38
39int radio_present = 0;
40int tuner_frequency = 0;
41int tuner_signal_power = 0;
42int radio_tuned = 0;
43int rds_event = 0;
44
45char rds_radioname[9];
46char rds_radioinfo[70]; /* do we need more? */
47
48union FRQ {
49 unsigned long int frequency_radio;
50 char data_frequency[4];
51}Frequency;
52
53void rmt_tuner_freq(void)
54{
55 char tempdata[4];
56 tempdata[0] = serbuf[6];
57 tempdata[1] = serbuf[5];
58 tempdata[2] = serbuf[4];
59 tempdata[3] = serbuf[3];
60
61 memcpy(Frequency.data_frequency,tempdata,4);
62 tuner_frequency = (Frequency.frequency_radio*1000);
63 radio_tuned = 1;
64 rmt_tuner_signal_power(serbuf[7]);
65}
66
67void rmt_tuner_set_freq(int curr_freq)
68{
69 if (curr_freq != tuner_frequency)
70 {
71 radio_tuned = 0;
72 tuner_signal_power = 0;
73 /* clear rds name and info */
74 memset(rds_radioname,' ',sizeof(rds_radioname));
75 memset(rds_radioinfo,' ',sizeof(rds_radioinfo));
76 /* ex: 00 01 63 14 = 90.9MHz */
77 unsigned char data[] = {0x07, 0x0B, 0x00, 0x01, 0x63, 0x14};
78
79 if (curr_freq != 0)
80 {
81 curr_freq = curr_freq / 1000;
82 char tempdata[4];
83
84 Frequency.frequency_radio = curr_freq;
85 tempdata[0] = Frequency.data_frequency[3];
86 tempdata[1] = Frequency.data_frequency[2];
87 tempdata[2] = Frequency.data_frequency[1];
88 tempdata[3] = Frequency.data_frequency[0];
89
90 memcpy(data+2,tempdata,4);
91 iap_send_pkt(data, sizeof(data));
92 }
93 }
94}
95
96void rmt_tuner_signal_power(unsigned char value)
97{
98 tuner_signal_power = (int)(value);
99}
100
101void rmt_tuner_sleep(int state)
102{
103 if (state == 0)
104 {
105 /* tuner HW on */
106 unsigned char data[] = {0x07, 0x05, 0x01};
107 iap_send_pkt(data, sizeof(data));
108 /* boost gain */
109 unsigned char data1[] = {0x07, 0x24, 0x06 };
110 iap_send_pkt(data1, sizeof(data1));
111 /* set volume */
112 unsigned char data2[] = {0x03, 0x09, 0x04, 0x00, 0x77 };
113 iap_send_pkt(data2, sizeof(data2));
114 /* set rds on */
115 unsigned char data3[] = {0x07, 0x20, 0x40, 0x00, 0x00, 0x10 };
116 iap_send_pkt(data3, sizeof(data3));
117 }
118 else
119 {
120 /* unbooste gain */
121 unsigned char data[] = {0x07, 0x24, 0x00};
122 iap_send_pkt(data, sizeof(data));
123 /* set rds off */
124 unsigned char data1[] = {0x07, 0x20, 0x00, 0x00, 0x00, 0x00 };
125 iap_send_pkt(data1, sizeof(data1));
126 /* stop tuner HW */
127 unsigned char data2[] = {0x07, 0x05, 0x00};
128 iap_send_pkt(data2, sizeof(data2));
129 }
130}
131
132void rmt_tuner_scan(int param)
133{
134 unsigned char data[] = {0x07, 0x11, 0x08}; /* RSSI level */
135 unsigned char updown = 0x00;
136 radio_tuned = 0;
137 iap_send_pkt(data, sizeof(data));
138
139 if (param == 1)
140 {
141 updown = 0x07; /* scan up */
142 }
143 else if (param == -1)
144 {
145 updown = 0x08; /* scan down */
146 }
147 else if (param == 10)
148 {
149 updown = 0x01; /* scan up starting from beginning of the band */
150 }
151 unsigned char data1[] = {0x07, 0x12, updown};
152 iap_send_pkt(data1, sizeof(data1));
153}
154
155void rmt_tuner_mute(int value)
156{
157 /* mute flag off (play) */
158 unsigned char data[] = {0x03, 0x09, 0x03, 0x01};
159 if (value)
160 {
161 /* mute flag on (pause) */
162 data[3] = 0x02;
163 }
164 iap_send_pkt(data, sizeof(data));
165}
166
167void rmt_tuner_region(int region)
168{
169 if (region != old_region)
170 {
171 unsigned char data[] = {0x07, 0x08, 0x00};
172 if (region == 2)
173 {
174 data[2] = 0x02; /* japan band */
175 }
176 else
177 {
178 data[2] = 0x01; /* us eur band */
179 }
180 iap_send_pkt(data, sizeof(data));
181 sleep(HZ/100);
182 old_region = region;
183 }
184}
185
186/* set stereo/mono, deemphasis, delta freq... */
187void rmt_tuner_set_param(unsigned char tuner_param)
188{
189 if(tuner_param != old_tuner_param)
190 {
191 unsigned char data[] = {0x07, 0x0E, 0x00};
192
193 data[2] = tuner_param;
194 iap_send_pkt(data, sizeof(data));
195 old_tuner_param = tuner_param;
196 }
197}
198
199void set_deltafreq(int delta)
200{
201 tuner_param &= 0xFC;
202 switch (delta)
203 {
204 case 1:
205 {
206 /* 100KHz */
207 tuner_param |= 0x01;
208 break;
209 }
210 case 2:
211 {
212 /* 50KHz */
213 tuner_param |= 0x02;
214 break;
215 }
216
217 default:
218 {
219 /* 200KHz */
220 tuner_param |= 0x00;
221 break;
222 }
223 }
224}
225
226void set_deemphasis(int deemphasis)
227{
228 tuner_param &= 0xBF;
229 switch (deemphasis)
230 {
231 case 1:
232 {
233 tuner_param |= 0x40;
234 break;
235 }
236 default:
237 {
238 tuner_param |= 0x00;
239 break;
240 }
241 }
242}
243
244void set_mono(int value)
245{
246 tuner_param &= 0xEF;
247
248 if (value != mono_mode)
249 {
250 tuner_param |= 0x10;
251 rmt_tuner_set_param(tuner_param);
252 sleep(HZ/100);
253 mono_mode = value;
254 }
255}
256
257bool reply_timeout(void)
258{
259 int timeout = 0;
260
261 sleep(HZ/50);
262 do
263 {
264 iap_handlepkt();
265 sleep(HZ/50);
266 timeout++;
267 }
268 while((ipod_rmt_tuner_get(RADIO_TUNED) == 0) && (timeout < TIMEOUT_VALUE));
269
270 if (timeout >= TIMEOUT_VALUE)
271 return true;
272 else return false;
273}
274
275void rmt_tuner_rds_data(void)
276{
277 if (serbuf[3] == 0x1E)
278 {
279 strlcpy(rds_radioname,serbuf+5,8);
280 }
281 else if(serbuf[3] == 0x04)
282 {
283 strlcpy(rds_radioinfo,serbuf+5,(serbuf[0]-4));
284 }
285 rds_event = 1;
286}
287
288/* tuner abstraction layer: set something to the tuner */
289int ipod_rmt_tuner_set(int setting, int value)
290{
291 switch(setting)
292 {
293 case RADIO_SLEEP:
294 {
295 rmt_tuner_sleep(value);
296 sleep(HZ/2);
297 break;
298 }
299
300 case RADIO_FREQUENCY:
301 {
302 rmt_tuner_set_freq(value);
303 if (reply_timeout() == true)
304 return 0;
305 break;
306 }
307
308 case RADIO_SCAN_FREQUENCY:
309 {
310 const struct fm_region_data * const fmr =
311 &fm_region_data[global_settings.fm_region];
312
313 /* case: scan for presets, back to beginning of the band */
314 if ((radio_tuned == 1) && (value == fmr->freq_min))
315 {
316 tuner_set(RADIO_FREQUENCY,value);
317 }
318
319 /* scan through frequencies */
320 if (radio_tuned == 1)
321 {
322 /* scan down */
323 if(value < tuner_frequency)
324 rmt_tuner_scan(-1);
325 /* scan up */
326 else
327 rmt_tuner_scan(1);
328
329 if (reply_timeout() == true)
330 return 0;
331 radio_tuned = 0;
332 }
333
334 if (tuner_frequency == value)
335 {
336 radio_tuned = 1;
337 return 1;
338 }
339 else
340 {
341 radio_tuned = 0;
342 return 0;
343 }
344 }
345
346 case RADIO_MUTE:
347 {
348 /* mute flag sent to accessory */
349 /* rmt_tuner_mute(value); */
350 break;
351 }
352
353 case RADIO_REGION:
354 {
355 const struct rmt_tuner_region_data *rd =
356 &rmt_tuner_region_data[value];
357
358 rmt_tuner_region(rd->band);
359 set_deltafreq(rd->spacing);
360 set_deemphasis(rd->deemphasis);
361 rmt_tuner_set_param(tuner_param);
362 break;
363 }
364
365 case RADIO_FORCE_MONO:
366 {
367 set_mono(value);
368 break;
369 }
370
371 default:
372 return -1;
373 }
374 return 1;
375}
376
377/* tuner abstraction layer: read something from the tuner */
378int ipod_rmt_tuner_get(int setting)
379{
380 int val = -1; /* default for unsupported query */
381
382 switch(setting)
383 {
384 case RADIO_PRESENT:
385 val = radio_present;
386 if (val)
387 {
388 /* if accessory disconnected */
389 if(adc_read(ADC_ACCESSORY) >= 10)
390 {
391 radio_present = 0;
392 val = 0;
393 }
394 }
395 break;
396
397 /* radio tuned: yes no */
398 case RADIO_TUNED:
399 val = 0;
400 if (radio_tuned == 1)
401 val = 1;
402 break;
403
404 /* radio is always stereo */
405 /* we can't know when it's in mono mode, depending of signal quality */
406 /* except if it is forced in mono mode */
407 case RADIO_STEREO:
408 val = true;
409 break;
410
411 case RADIO_EVENT:
412 if (rds_event)
413 {
414 val = 1;
415 rds_event = 0;
416 }
417 break;
418 }
419 return val;
420}
421
422char* ipod_get_rds_info(int setting)
423{
424 char *text = NULL;
425
426 switch(setting)
427 {
428 case RADIO_RDS_NAME:
429 text = rds_radioname;
430 break;
431
432 case RADIO_RDS_TEXT:
433 text = rds_radioinfo;
434 break;
435 }
436 return text;
437}
438
439bool tuner_power(bool status)
440{
441 bool oldstatus = powered;
442 powered = status;
443 return oldstatus;
444}
diff --git a/firmware/export/config-ipod4g.h b/firmware/export/config-ipod4g.h
index c00a6788c6..e6bdc35bd8 100644
--- a/firmware/export/config-ipod4g.h
+++ b/firmware/export/config-ipod4g.h
@@ -18,7 +18,7 @@
18 18
19/* Define bitmask of input sources - recordable bitmask can be defined 19/* Define bitmask of input sources - recordable bitmask can be defined
20 explicitly if different */ 20 explicitly if different */
21#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN) 21#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN | SRC_CAP_FMRADIO)
22 22
23/* define the bitmask of hardware sample rates */ 23/* define the bitmask of hardware sample rates */
24#define HW_SAMPR_CAPS (SAMPR_CAP_44) 24#define HW_SAMPR_CAPS (SAMPR_CAP_44)
@@ -144,6 +144,10 @@
144#define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ 144#define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
145#endif 145#endif
146 146
147/* Define Apple remote tuner */
148#define CONFIG_TUNER IPOD_REMOTE_TUNER
149#define HAVE_RDS_CAP
150
147/* Define this if you have a PortalPlayer PP5020 */ 151/* Define this if you have a PortalPlayer PP5020 */
148#define CONFIG_CPU PP5020 152#define CONFIG_CPU PP5020
149 153
diff --git a/firmware/export/config-ipodcolor.h b/firmware/export/config-ipodcolor.h
index 751522d47b..0f1de4fdba 100644
--- a/firmware/export/config-ipodcolor.h
+++ b/firmware/export/config-ipodcolor.h
@@ -18,7 +18,7 @@
18 18
19/* Define bitmask of input sources - recordable bitmask can be defined 19/* Define bitmask of input sources - recordable bitmask can be defined
20 explicitly if different */ 20 explicitly if different */
21#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN) 21#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN | SRC_CAP_FMRADIO)
22 22
23/* define the bitmask of hardware sample rates */ 23/* define the bitmask of hardware sample rates */
24#define HW_SAMPR_CAPS (SAMPR_CAP_44) 24#define HW_SAMPR_CAPS (SAMPR_CAP_44)
@@ -121,6 +121,10 @@
121/* define this if the unit can be powered or charged via USB */ 121/* define this if the unit can be powered or charged via USB */
122#define HAVE_USB_POWER 122#define HAVE_USB_POWER
123 123
124/* Define Apple remote tuner */
125#define CONFIG_TUNER IPOD_REMOTE_TUNER
126#define HAVE_RDS_CAP
127
124/* Define this if you have a PortalPlayer PP5020 */ 128/* Define this if you have a PortalPlayer PP5020 */
125#define CONFIG_CPU PP5020 129#define CONFIG_CPU PP5020
126 130
diff --git a/firmware/export/config-ipodnano.h b/firmware/export/config-ipodnano.h
index 68ed152cda..e1ec1afa86 100644
--- a/firmware/export/config-ipodnano.h
+++ b/firmware/export/config-ipodnano.h
@@ -18,7 +18,7 @@
18 18
19/* Define bitmask of input sources - recordable bitmask can be defined 19/* Define bitmask of input sources - recordable bitmask can be defined
20 explicitly if different */ 20 explicitly if different */
21#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN) 21#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN | SRC_CAP_FMRADIO)
22 22
23/* define the bitmask of hardware sample rates */ 23/* define the bitmask of hardware sample rates */
24#define HW_SAMPR_CAPS (SAMPR_CAP_44) 24#define HW_SAMPR_CAPS (SAMPR_CAP_44)
@@ -134,6 +134,10 @@
134#define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ 134#define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
135#endif 135#endif
136 136
137/* Define Apple remote tuner */
138#define CONFIG_TUNER IPOD_REMOTE_TUNER
139#define HAVE_RDS_CAP
140
137/* Define this if you have a PortalPlayer PP5022 */ 141/* Define this if you have a PortalPlayer PP5022 */
138#define CONFIG_CPU PP5022 142#define CONFIG_CPU PP5022
139 143
diff --git a/firmware/export/config-ipodvideo.h b/firmware/export/config-ipodvideo.h
index f00de9cbfd..59ac6466e5 100644
--- a/firmware/export/config-ipodvideo.h
+++ b/firmware/export/config-ipodvideo.h
@@ -18,7 +18,7 @@
18 18
19/* Define bitmask of input sources - recordable bitmask can be defined 19/* Define bitmask of input sources - recordable bitmask can be defined
20 explicitly if different */ 20 explicitly if different */
21#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN) 21#define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_LINEIN | SRC_CAP_FMRADIO)
22 22
23/* define the bitmask of hardware sample rates */ 23/* define the bitmask of hardware sample rates */
24#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ 24#define HW_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
@@ -155,6 +155,10 @@
155#define CURRENT_RECORD 35 /* FIXME: this needs adjusting */ 155#define CURRENT_RECORD 35 /* FIXME: this needs adjusting */
156#endif 156#endif
157 157
158/* Define Apple remote tuner */
159#define CONFIG_TUNER IPOD_REMOTE_TUNER
160#define HAVE_RDS_CAP
161
158/* Define this if you have a PortalPlayer PP5022 */ 162/* Define this if you have a PortalPlayer PP5022 */
159#define CONFIG_CPU PP5022 163#define CONFIG_CPU PP5022
160 164
diff --git a/firmware/export/config.h b/firmware/export/config.h
index 9c7beca2bd..088cab7212 100644
--- a/firmware/export/config.h
+++ b/firmware/export/config.h
@@ -40,6 +40,7 @@
40#define SI4700 0x08 /* Silicon Labs */ 40#define SI4700 0x08 /* Silicon Labs */
41#define TEA5760 0x10 /* Philips */ 41#define TEA5760 0x10 /* Philips */
42#define LV240000 0x20 /* Sanyo */ 42#define LV240000 0x20 /* Sanyo */
43#define IPOD_REMOTE_TUNER 0x40 /* Apple */
43 44
44/* CONFIG_CODEC */ 45/* CONFIG_CODEC */
45#define MAS3587F 3587 46#define MAS3587F 3587
diff --git a/firmware/export/iap.h b/firmware/export/iap.h
index e945d0c979..d00e5f398a 100644
--- a/firmware/export/iap.h
+++ b/firmware/export/iap.h
@@ -20,6 +20,9 @@
20#ifndef __IAP_H__ 20#ifndef __IAP_H__
21#define __IAP_H__ 21#define __IAP_H__
22 22
23#define RX_BUFLEN 260
24#define TX_BUFLEN 128
25
23extern int iap_getc(unsigned char x); 26extern int iap_getc(unsigned char x);
24extern void iap_write_pkt(unsigned char data, int len); 27extern void iap_write_pkt(unsigned char data, int len);
25extern void iap_setup(int ratenum); 28extern void iap_setup(int ratenum);
@@ -27,5 +30,7 @@ extern void iap_bitrate_set(int ratenum);
27extern void iap_periodic(void); 30extern void iap_periodic(void);
28extern void iap_handlepkt(void); 31extern void iap_handlepkt(void);
29extern void iap_track_changed(void *ignored); 32extern void iap_track_changed(void *ignored);
33extern void iap_send_pkt(const unsigned char * data, int len);
34extern unsigned char serbuf[RX_BUFLEN];
30 35
31#endif 36#endif
diff --git a/firmware/export/ipod_remote_tuner.h b/firmware/export/ipod_remote_tuner.h
new file mode 100644
index 0000000000..28fcfe1e93
--- /dev/null
+++ b/firmware/export/ipod_remote_tuner.h
@@ -0,0 +1,75 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: ipod_remote_tuner.h
9 * Tuner header for the ipod remote tuner and others remote tuners
10 *
11 * Copyright (C) 2009 Laurent Gautier
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22
23#ifndef _IPOD_REMOTE_TUNER_H_
24#define _IPOD_REMOTE_TUNER_H_
25
26#define HAVE_RADIO_REGION
27#define TIMEOUT_VALUE 20
28
29extern int radio_present;
30extern int tuner_frequency;
31extern int tuner_signal_power;
32extern int radio_tuned;
33
34/* update tuner state: plugged or unplugged when in radio mode */
35extern void rmt_tuner_region(int region);
36extern void rmt_tuner_set_freq(int curr_freq);
37extern void rmt_tuner_freq(void);
38extern void rmt_tuner_scan(int direction);
39
40/* tuner mode state: ON or OFF */
41extern void rmt_tuner_sleep(int state);
42
43/* parameters are stereo/mono, deemphasis, delta freq... */
44extern void rmt_tuner_set_param(unsigned char tuner_param);
45
46extern void rmt_tuner_mute(int value);
47extern void rmt_tuner_signal_power(unsigned char value);
48
49extern void rmt_tuner_rds_data(void);
50
51struct rmt_tuner_region_data
52{
53 /* 0: 50us, 1: 75us */
54 unsigned char deemphasis;
55 /* 0: europe, 1: japan (BL in TEA spec)*/
56 unsigned char band;
57 /* 0: us/australia (200kHz), 1: europe/japan (100kHz), 2: (50kHz) */
58 unsigned char spacing;
59} __attribute__((packed));
60
61extern const struct rmt_tuner_region_data
62 rmt_tuner_region_data[TUNER_NUM_REGIONS];
63
64int ipod_rmt_tuner_set(int setting, int value);
65int ipod_rmt_tuner_get(int setting);
66char* ipod_get_rds_info(int setting);
67
68
69#ifndef CONFIG_TUNER_MULTI
70#define tuner_set ipod_rmt_tuner_set
71#define tuner_get ipod_rmt_tuner_get
72#define tuner_get_rds_info ipod_get_rds_info
73#endif
74
75#endif /* _IPOD_REMOTE_TUNER_H_ */
diff --git a/firmware/export/tuner.h b/firmware/export/tuner.h
index b27e660667..63392160e5 100644
--- a/firmware/export/tuner.h
+++ b/firmware/export/tuner.h
@@ -33,7 +33,7 @@ enum
33 RADIO_MUTE, 33 RADIO_MUTE,
34 RADIO_FORCE_MONO, 34 RADIO_FORCE_MONO,
35 RADIO_SCAN_FREQUENCY, 35 RADIO_SCAN_FREQUENCY,
36 36
37 /* Put new general-purpose settings above this line */ 37 /* Put new general-purpose settings above this line */
38 __RADIO_SET_STANDARD_LAST 38 __RADIO_SET_STANDARD_LAST
39}; 39};
@@ -44,11 +44,25 @@ enum
44 RADIO_PRESENT = 0, 44 RADIO_PRESENT = 0,
45 RADIO_TUNED, 45 RADIO_TUNED,
46 RADIO_STEREO, 46 RADIO_STEREO,
47 /* RADIO_EVENT is an event that requests a screen update */
48 RADIO_EVENT,
47 49
48 /* Put new general-purpose readback values above this line */ 50 /* Put new general-purpose readback values above this line */
49 __RADIO_GET_STANDARD_LAST 51 __RADIO_GET_STANDARD_LAST
50}; 52};
51 53
54#ifdef HAVE_RDS_CAP
55/** Readback from the tuner RDS layer **/
56enum
57{
58 RADIO_RDS_NAME,
59 RADIO_RDS_TEXT,
60
61 /* Put new general-purpose readback values above this line */
62 __RADIO_GET_RDS_INFO_STANDARD_LAST
63};
64#endif
65
52/** Tuner regions **/ 66/** Tuner regions **/
53 67
54/* Basic region information */ 68/* Basic region information */
@@ -114,6 +128,11 @@ extern int (*tuner_get)(int setting);
114#include "si4700.h" 128#include "si4700.h"
115#endif 129#endif
116 130
131/* Apple remote tuner */
132#if (CONFIG_TUNER & IPOD_REMOTE_TUNER)
133#include "ipod_remote_tuner.h"
134#endif
135
117#endif /* SIMULATOR */ 136#endif /* SIMULATOR */
118 137
119/* Additional messages that get enumerated after tuner driver headers */ 138/* Additional messages that get enumerated after tuner driver headers */
diff --git a/firmware/target/arm/audio-pp.c b/firmware/target/arm/audio-pp.c
index 1a4952fcc3..8f22bab765 100644
--- a/firmware/target/arm/audio-pp.c
+++ b/firmware/target/arm/audio-pp.c
@@ -104,11 +104,17 @@ void audio_input_mux(int source, unsigned flags)
104 if (!recording) 104 if (!recording)
105 audiohw_set_recvol(0x17, 0x17, AUDIO_GAIN_LINEIN); 105 audiohw_set_recvol(0x17, 0x17, AUDIO_GAIN_LINEIN);
106#endif 106#endif
107
107 if (source == last_source && recording == last_recording) 108 if (source == last_source && recording == last_recording)
108 break; 109 break;
109 110
110 last_recording = recording; 111 last_recording = recording;
111 112
113#if defined(IPOD_REMOTE_TUNER)
114 /* Ipod FM tuner is in the remote connected to line-in */
115 audiohw_enable_recording(false); /* source line */
116 audiohw_set_monitor(true); /* enable bypass mode */
117#else
112 if (recording) 118 if (recording)
113 { 119 {
114 audiohw_set_monitor(false); /* disable bypass mode */ 120 audiohw_set_monitor(false); /* disable bypass mode */
@@ -119,6 +125,7 @@ void audio_input_mux(int source, unsigned flags)
119 audiohw_disable_recording(); 125 audiohw_disable_recording();
120 audiohw_set_monitor(true); /* enable bypass mode */ 126 audiohw_set_monitor(true); /* enable bypass mode */
121 } 127 }
128#endif
122 break; 129 break;
123#endif 130#endif
124 } /* end switch */ 131 } /* end switch */
diff --git a/firmware/tuner.c b/firmware/tuner.c
index 5fd7fa1f38..cca5cf2491 100644
--- a/firmware/tuner.c
+++ b/firmware/tuner.c
@@ -89,17 +89,31 @@ const struct si4700_region_data si4700_region_data[TUNER_NUM_REGIONS] =
89}; 89};
90#endif /* (CONFIG_TUNER & SI4700) */ 90#endif /* (CONFIG_TUNER & SI4700) */
91 91
92#if (CONFIG_TUNER & IPOD_REMOTE_TUNER)
93const struct rmt_tuner_region_data
94 rmt_tuner_region_data[TUNER_NUM_REGIONS] =
95{
96 [REGION_EUROPE] = { 1, 0, 1 }, /* 50uS, US/Europe band, 100kHz spacing */
97 [REGION_US_CANADA] = { 0, 0, 0 }, /* 75uS, US/Europe band, 200kHz spacing */
98 [REGION_JAPAN] = { 1, 2, 1 }, /* 50uS, Japanese band, 100kHz spacing */
99 [REGION_KOREA] = { 1, 0, 0 }, /* 50uS, US/Europe band, 200kHz spacing */
100 [REGION_ITALY] = { 1, 0, 2 }, /* 50uS, US/Europe band, 50kHz spacing */
101 [REGION_OTHER] = { 1, 0, 2 }, /* 50uS, US/Europe band, 50kHz spacing */
102};
103#endif /* (CONFIG_TUNER & IPOD_REMOTE_TUNER) */
104
92#ifdef CONFIG_TUNER_MULTI 105#ifdef CONFIG_TUNER_MULTI
93int (*tuner_set)(int setting, int value); 106int (*tuner_set)(int setting, int value);
94int (*tuner_get)(int setting); 107int (*tuner_get)(int setting);
95#define TUNER_TYPE_CASE(type, set, get, ...) \ 108
109#define TUNER_TYPE_CASE(type, set, get, ...) \
96 case type: \ 110 case type: \
97 tuner_set = set; \ 111 tuner_set = set; \
98 tuner_get = get; \ 112 tuner_get = get; \
99 __VA_ARGS__; \ 113 __VA_ARGS__; \
100 break; 114 break;
101#else 115#else
102#define TUNER_TYPE_CASE(type, set, get, ...) \ 116#define TUNER_TYPE_CASE(type, set, get, ...) \
103 __VA_ARGS__; 117 __VA_ARGS__;
104#endif /* CONFIG_TUNER_MULTI */ 118#endif /* CONFIG_TUNER_MULTI */
105 119
@@ -139,5 +153,4 @@ void tuner_init(void)
139 #endif 153 #endif
140 } 154 }
141} 155}
142
143#endif /* SIMULATOR */ 156#endif /* SIMULATOR */