1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
32 #include "appevents.h"
42 #include "powermgmt.h"
45 #include "ipod_remote_tuner.h"
47 static volatile int iap_pollspeed
= 0;
48 static volatile bool iap_remotetick
= true;
49 static bool iap_setupflag
= false, iap_updateflag
= false;
50 static int iap_changedctr
= 0;
52 static unsigned long iap_remotebtn
= 0;
53 static int iap_repeatbtn
= 0;
54 static bool iap_btnrepeat
= false, iap_btnshuffle
= false;
56 unsigned char serbuf
[RX_BUFLEN
];
57 static int serbuf_i
= 0;
59 static unsigned char response
[TX_BUFLEN
];
60 static int responselen
;
62 static void iap_task(void)
66 count
+= iap_pollspeed
;
67 if (count
< (500/10)) return;
69 /* exec every 500ms if pollspeed == 1 */
71 queue_post(&button_queue
, SYS_IAP_PERIODIC
, 0);
74 /* called by playback when the next track starts */
75 static void iap_track_changed(void *ignored
)
81 void iap_setup(int ratenum
)
83 iap_bitrate_set(ratenum
);
85 iap_remotetick
= true;
86 iap_updateflag
= false;
89 iap_remotebtn
= BUTTON_NONE
;
90 tick_add_task(iap_task
);
91 add_event(PLAYBACK_EVENT_TRACK_CHANGE
, false, iap_track_changed
);
94 void iap_bitrate_set(int ratenum
)
102 serial_bitrate(9600);
105 serial_bitrate(19200);
108 serial_bitrate(38400);
111 serial_bitrate(57600);
122 parameters (0-n bytes)
123 checksum (length+mode+parameters+checksum == 0)
126 void iap_send_pkt(const unsigned char * data
, int len
)
130 if(len
> TX_BUFLEN
-4) len
= TX_BUFLEN
-4;
131 responselen
= len
+ 4;
136 chksum
= response
[2] = len
;
137 for(i
= 0; i
< len
; i
++)
140 response
[i
+3] = data
[i
];
143 response
[i
+3] = 0x100 - (chksum
& 0xFF);
145 for(i
= 0; i
< responselen
; i
++)
148 tx_writec(response
[i
]);
152 int iap_getc(unsigned char x
)
154 static unsigned char last_x
= 0;
155 static bool newpkt
= true;
156 static unsigned char chksum
= 0;
158 /* Restart if the sync word is seen */
159 if(x
== 0x55 && last_x
== 0xff/* && newpkt*/)
168 if(serbuf_i
>= RX_BUFLEN
)
171 serbuf
[serbuf_i
++] = x
;
176 /* Broadcast to queue if we have a complete message */
177 if(serbuf_i
&& (serbuf_i
== serbuf
[0]+2))
182 queue_post(&button_queue
, SYS_IAP_HANDLEPKT
, 0);
187 void iap_periodic(void)
189 if(!iap_setupflag
) return;
190 if(!iap_pollspeed
) return;
192 unsigned char data
[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00};
193 unsigned long time_elapsed
= audio_current_track()->elapsed
;
195 time_elapsed
+= wps_get_ff_rewind_count();
197 data
[3] = 0x04; /* playing */
199 /* If info has changed, don't flag it right away */
200 if(iap_changedctr
&& iap_changedctr
++ >= iap_pollspeed
* 2)
202 /* track info has changed */
204 data
[3] = 0x01; /* 0x02 has same effect? */
205 iap_updateflag
= true;
208 data
[4] = time_elapsed
>> 24;
209 data
[5] = time_elapsed
>> 16;
210 data
[6] = time_elapsed
>> 8;
211 data
[7] = time_elapsed
;
212 iap_send_pkt(data
, sizeof(data
));
215 static void iap_set_remote_volume(void)
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
));
222 void iap_handlepkt(void)
225 if(!iap_setupflag
) return;
226 if(serbuf
[0] == 0) return;
228 /* if we are waiting for a remote button to go out,
229 delay the handling of the new packet */
232 queue_post(&button_queue
, SYS_IAP_HANDLEPKT
, 0);
237 if (serbuf
[1] == 0x00)
243 /* ipod video send this */
244 unsigned char data
[] = {0x00, 0x25, 0x00, 0x00, 0x00,
245 0x00, 0x00, 0x00, 0x00,0x01};
246 iap_send_pkt(data
, sizeof(data
));
252 /* ciphered authentication command */
253 /* Isn't used since we don't send the 0x00 0x17 command */
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)
268 /* get tuner capacities */
269 unsigned char data3
[] = {0x07, 0x01};
270 iap_send_pkt(data3
, sizeof(data3
));
272 iap_set_remote_volume();
278 unsigned char data
[] = {0x00, 0x02, 0x00, 0x13};
279 iap_send_pkt(data
, sizeof(data
));
281 if (serbuf
[6] == 0x35)
282 /* FM transmitter sends this: */
283 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
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
));
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)
297 unsigned char data4
[] = {0x00, 0x14};
298 iap_send_pkt(data4
, sizeof(data4
));
306 unsigned char data
[] = {0x00, 0x10, 0x00, 0x01, 0x05};
308 iap_send_pkt(data
, sizeof(data
));
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
));
324 /* Ipod FM remote sends this: FF 55 02 00 09 F5 */
327 /* ipod5G firmware version */
328 unsigned char data
[] = {0x00, 0x0A, 0x01, 0x02, 0x01 };
329 iap_send_pkt(data
, sizeof(data
));
333 /* FM transmitter sends this: */
334 /* FF 55 02 00 05 F9 (mode switch: AiR mode) */
337 unsigned char data
[] = {0x00, 0x02, 0x06,
338 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28};
339 iap_send_pkt(data
, sizeof(data
));
340 unsigned char data2
[] = {0x00, 0x02, 0x00, 0x05};
341 iap_send_pkt(data2
, sizeof(data2
));
347 /* FM transmitter sends this: */
348 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
349 if(serbuf
[3] == 0x05)
352 unsigned char data
[] = {0x05, 0x02};
353 iap_send_pkt(data
, sizeof(data
));
355 /* FM remote sends this: */
356 /* FF 55 03 00 01 02 FA (1st thing sent) */
357 else if(serbuf
[3] == 0x02)
359 /* useful only for apple firmware */
364 /* default response is with cmd ok packet */
367 unsigned char data
[] = {0x00, 0x02, 0x00, 0x00};
368 data
[3] = serbuf
[2]; /* respond with cmd */
369 iap_send_pkt(data
, sizeof(data
));
375 else if (serbuf
[1] == 0x02)
377 if(serbuf
[2] != 0) return;
378 iap_remotebtn
= BUTTON_NONE
;
379 iap_remotetick
= false;
381 if(serbuf
[0] >= 3 && serbuf
[3] != 0)
384 iap_remotebtn
|= BUTTON_RC_PLAY
;
386 iap_remotebtn
|= BUTTON_RC_VOL_UP
;
388 iap_remotebtn
|= BUTTON_RC_VOL_DOWN
;
390 iap_remotebtn
|= BUTTON_RC_RIGHT
;
392 iap_remotebtn
|= BUTTON_RC_LEFT
;
394 else if(serbuf
[0] >= 4 && serbuf
[4] != 0)
396 if(serbuf
[4] & 1) /* play */
398 if (audio_status() != AUDIO_STATUS_PLAY
)
400 iap_remotebtn
|= BUTTON_RC_PLAY
;
402 iap_remotetick
= false;
406 if(serbuf
[4] & 2) /* pause */
408 if (audio_status() == AUDIO_STATUS_PLAY
)
410 iap_remotebtn
|= BUTTON_RC_PLAY
;
412 iap_remotetick
= false;
416 if((serbuf
[4] & 128) && !iap_btnshuffle
) /* shuffle */
418 iap_btnshuffle
= true;
419 if(!global_settings
.playlist_shuffle
)
421 global_settings
.playlist_shuffle
= 1;
423 if (audio_status() & AUDIO_STATUS_PLAY
)
424 playlist_randomise(NULL
, current_tick
, true);
426 else if(global_settings
.playlist_shuffle
)
428 global_settings
.playlist_shuffle
= 0;
430 if (audio_status() & AUDIO_STATUS_PLAY
)
431 playlist_sort(NULL
, true);
435 iap_btnshuffle
= false;
437 else if(serbuf
[0] >= 5 && serbuf
[5] != 0)
439 if((serbuf
[5] & 1) && !iap_btnrepeat
) /* repeat */
441 int oldmode
= global_settings
.repeat_mode
;
442 iap_btnrepeat
= true;
444 if (oldmode
== REPEAT_ONE
)
445 global_settings
.repeat_mode
= REPEAT_OFF
;
446 else if (oldmode
== REPEAT_ALL
)
447 global_settings
.repeat_mode
= REPEAT_ONE
;
448 else if (oldmode
== REPEAT_OFF
)
449 global_settings
.repeat_mode
= REPEAT_ALL
;
452 if (audio_status() & AUDIO_STATUS_PLAY
)
453 audio_flush_and_reload_tracks();
456 iap_btnrepeat
= false;
458 if(serbuf
[5] & 16) /* ffwd */
460 iap_remotebtn
|= BUTTON_RC_RIGHT
;
462 if(serbuf
[5] & 32) /* frwd */
464 iap_remotebtn
|= BUTTON_RC_LEFT
;
469 else if (serbuf
[1] == 0x03)
473 /* some kind of status packet? */
476 unsigned char data
[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
477 iap_send_pkt(data
, sizeof(data
));
484 unsigned char data
[] = {0x03, 0x00, 0x00, 0x08};
485 iap_send_pkt(data
, sizeof(data
));
491 /* request ipod volume */
492 if (serbuf
[3] == 0x04)
494 iap_set_remote_volume();
498 /* get volume from accessory */
500 if (serbuf
[3] == 0x04)
501 global_settings
.volume
= (-58)+((int)serbuf
[5]+1)/4;
502 sound_set_volume(global_settings
.volume
);
507 else if (serbuf
[1] == 0x04)
509 switch (((unsigned long)serbuf
[2] << 8) | serbuf
[3])
511 /* Get data updated??? flag */
514 unsigned char data
[] = {0x04, 0x00, 0x0A, 0x00};
515 data
[3] = iap_updateflag
? 0 : 1;
516 iap_send_pkt(data
, sizeof(data
));
519 /* Set data updated??? flag */
522 iap_updateflag
= serbuf
[4] ? 0 : 1;
523 /* respond with cmd ok packet */
524 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x0B};
525 iap_send_pkt(data
, sizeof(data
));
531 unsigned char data
[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
532 iap_send_pkt(data
, sizeof(data
));
535 /* Get count of given types */
538 unsigned char data
[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
539 unsigned long num
= 0;
540 switch(serbuf
[4]) /* type number */
542 case 0x01: /* total number of playlists */
545 case 0x05: /* total number of songs */
552 iap_send_pkt(data
, sizeof(data
));
555 /* Get time and status */
558 unsigned char data
[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
559 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
560 struct mp3entry
*id3
= audio_current_track();
561 unsigned long time_total
= id3
->length
;
562 unsigned long time_elapsed
= id3
->elapsed
;
563 int status
= audio_status();
564 data
[3] = time_total
>> 24;
565 data
[4] = time_total
>> 16;
566 data
[5] = time_total
>> 8;
567 data
[6] = time_total
;
568 data
[7] = time_elapsed
>> 24;
569 data
[8] = time_elapsed
>> 16;
570 data
[9] = time_elapsed
>> 8;
571 data
[10] = time_elapsed
;
572 if (status
== AUDIO_STATUS_PLAY
)
573 data
[11] = 0x01; /* play */
574 else if (status
& AUDIO_STATUS_PAUSE
)
575 data
[11] = 0x02; /* pause */
576 iap_send_pkt(data
, sizeof(data
));
579 /* Get current pos in playlist */
582 unsigned char data
[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
583 long playlist_pos
= playlist_next(0);
584 playlist_pos
-= playlist_get_first_index(NULL
);
586 playlist_pos
+= playlist_amount();
587 data
[3] = playlist_pos
>> 24;
588 data
[4] = playlist_pos
>> 16;
589 data
[5] = playlist_pos
>> 8;
590 data
[6] = playlist_pos
;
591 iap_send_pkt(data
, sizeof(data
));
594 /* Get title of a song number */
596 /* Get artist of a song number */
598 /* Get album of a song number */
601 unsigned char data
[70] = {0x04, 0x00, 0xFF};
605 long tracknum
= (signed long)serbuf
[4] << 24 |
606 (signed long)serbuf
[5] << 16 |
607 (signed long)serbuf
[6] << 8 | serbuf
[7];
608 data
[2] = serbuf
[3] + 1;
609 memcpy(&id3
, audio_current_track(), sizeof(id3
));
610 tracknum
+= playlist_get_first_index(NULL
);
611 if(tracknum
>= playlist_amount())
612 tracknum
-= playlist_amount();
614 /* If the tracknumber is not the current one,
615 read id3 from disk */
616 if(playlist_next(0) != tracknum
)
618 struct playlist_track_info info
;
619 playlist_get_track_info(NULL
, tracknum
, &info
);
620 fd
= open(info
.filename
, O_RDONLY
);
621 memset(&id3
, 0, sizeof(struct mp3entry
));
622 get_metadata(&id3
, fd
, info
.filename
);
626 /* Return the requested track data */
630 len
= strlcpy((char *)&data
[3], id3
.title
, 64);
631 iap_send_pkt(data
, 4+len
);
634 len
= strlcpy((char *)&data
[3], id3
.artist
, 64);
635 iap_send_pkt(data
, 4+len
);
638 len
= strlcpy((char *)&data
[3], id3
.album
, 64);
639 iap_send_pkt(data
, 4+len
);
644 /* Set polling mode */
647 iap_pollspeed
= serbuf
[4] ? 1 : 0;
648 /*responsed with cmd ok packet */
649 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x26};
650 iap_send_pkt(data
, sizeof(data
));
653 /* AiR playback control */
656 /* respond with cmd ok packet */
657 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
658 iap_send_pkt(data
, sizeof(data
));
661 case 0x01: /* play/pause */
662 iap_remotebtn
= BUTTON_RC_PLAY
;
664 iap_remotetick
= false;
667 case 0x02: /* stop */
668 iap_remotebtn
= BUTTON_RC_PLAY
|BUTTON_REPEAT
;
670 iap_remotetick
= false;
673 case 0x03: /* skip++ */
674 iap_remotebtn
= BUTTON_RC_RIGHT
;
676 iap_remotetick
= false;
678 case 0x04: /* skip-- */
679 iap_remotebtn
= BUTTON_RC_LEFT
;
681 iap_remotetick
= false;
683 case 0x05: /* ffwd */
684 iap_remotebtn
= BUTTON_RC_RIGHT
;
685 iap_remotetick
= false;
686 if(iap_pollspeed
) iap_pollspeed
= 5;
688 case 0x06: /* frwd */
689 iap_remotebtn
= BUTTON_RC_LEFT
;
690 iap_remotetick
= false;
691 if(iap_pollspeed
) iap_pollspeed
= 5;
693 case 0x07: /* end ffwd/frwd */
694 iap_remotebtn
= BUTTON_NONE
;
695 iap_remotetick
= false;
696 if(iap_pollspeed
) iap_pollspeed
= 1;
701 /* Get shuffle mode */
704 unsigned char data
[] = {0x04, 0x00, 0x2D, 0x00};
705 data
[3] = global_settings
.playlist_shuffle
? 1 : 0;
706 iap_send_pkt(data
, sizeof(data
));
709 /* Set shuffle mode */
712 if(serbuf
[4] && !global_settings
.playlist_shuffle
)
714 global_settings
.playlist_shuffle
= 1;
716 if (audio_status() & AUDIO_STATUS_PLAY
)
717 playlist_randomise(NULL
, current_tick
, true);
719 else if(!serbuf
[4] && global_settings
.playlist_shuffle
)
721 global_settings
.playlist_shuffle
= 0;
723 if (audio_status() & AUDIO_STATUS_PLAY
)
724 playlist_sort(NULL
, true);
728 /* respond with cmd ok packet */
729 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x2E};
730 iap_send_pkt(data
, sizeof(data
));
733 /* Get repeat mode */
736 unsigned char data
[] = {0x04, 0x00, 0x30, 0x00};
737 if(global_settings
.repeat_mode
== REPEAT_OFF
)
739 else if(global_settings
.repeat_mode
== REPEAT_ONE
)
743 iap_send_pkt(data
, sizeof(data
));
746 /* Set repeat mode */
749 int oldmode
= global_settings
.repeat_mode
;
751 global_settings
.repeat_mode
= REPEAT_OFF
;
752 else if (serbuf
[4] == 1)
753 global_settings
.repeat_mode
= REPEAT_ONE
;
754 else if (serbuf
[4] == 2)
755 global_settings
.repeat_mode
= REPEAT_ALL
;
757 if (oldmode
!= global_settings
.repeat_mode
)
760 if (audio_status() & AUDIO_STATUS_PLAY
)
761 audio_flush_and_reload_tracks();
764 /* respond with cmd ok packet */
765 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x31};
766 iap_send_pkt(data
, sizeof(data
));
769 /* Get Screen Size */
772 unsigned char data
[] = {0x04, 0x00, 0x34,
773 LCD_WIDTH
>> 8, LCD_WIDTH
& 0xff,
774 LCD_HEIGHT
>> 8, LCD_HEIGHT
& 0xff,
776 iap_send_pkt(data
, sizeof(data
));
779 /* Get number songs in current playlist */
782 unsigned char data
[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
783 unsigned long playlist_amt
= playlist_amount();
784 data
[3] = playlist_amt
>> 24;
785 data
[4] = playlist_amt
>> 16;
786 data
[5] = playlist_amt
>> 8;
787 data
[6] = playlist_amt
;
788 iap_send_pkt(data
, sizeof(data
));
791 /* Jump to track number in current playlist */
794 int paused
= (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE
));
795 long tracknum
= (signed long)serbuf
[4] << 24 |
796 (signed long)serbuf
[5] << 16 |
797 (signed long)serbuf
[6] << 8 | serbuf
[7];
799 audio_skip(tracknum
- playlist_next(0));
803 /* respond with cmd ok packet */
804 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
807 iap_send_pkt(data
, sizeof(data
));
812 /* default response is with cmd ok packet */
813 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
816 iap_send_pkt(data
, sizeof(data
));
822 else if (serbuf
[1] == 0x07)
826 /* tuner capabilities */
831 unsigned char data
[] = {0x00, 0x27, 0x00};
832 iap_send_pkt(data
, sizeof(data
));
835 /* actual tuner frequency */
838 /* tuner frequency from scan */
844 /* RDS station name 0x21 1E 00 + ASCII text*/
847 rmt_tuner_rds_data();
855 int remote_control_rx(void)
857 int btn
= iap_remotebtn
;
863 iap_remotebtn
= BUTTON_NONE
;
864 iap_remotetick
= true;
868 iap_remotetick
= true;