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"
50 static volatile int iap_pollspeed
= 0;
51 static volatile bool iap_remotetick
= true;
52 static bool iap_setupflag
= false, iap_updateflag
= false;
53 static int iap_changedctr
= 0;
55 static unsigned long iap_remotebtn
= 0;
56 static int iap_repeatbtn
= 0;
57 static bool iap_btnrepeat
= false, iap_btnshuffle
= false;
59 static unsigned char serbuf
[RX_BUFLEN
];
61 static unsigned char response
[TX_BUFLEN
];
63 static char cur_dbrecord
[5] = {0};
65 /* states of the iap de-framing state machine */
67 ST_SYNC
, /* wait for 0xFF sync byte */
68 ST_SOF
, /* wait for 0x55 start-of-frame byte */
69 ST_LEN
, /* receive length byte (small packet) */
70 ST_LENH
, /* receive length high byte (large packet) */
71 ST_LENL
, /* receive length low byte (large packet) */
72 ST_DATA
, /* receive data */
73 ST_CHECK
/* verify checksum */
76 static struct state_t
{
77 enum fsm_state state
; /* current fsm state */
78 unsigned int len
; /* payload data length */
79 unsigned char *payload
; /* payload data pointer */
80 unsigned int check
; /* running checksum over [len,payload,check] */
81 unsigned int count
; /* playload bytes counter */
86 static void put_u32(unsigned char *buf
, uint32_t data
)
88 buf
[0] = (data
>> 24) & 0xFF;
89 buf
[1] = (data
>> 16) & 0xFF;
90 buf
[2] = (data
>> 8) & 0xFF;
91 buf
[3] = (data
>> 0) & 0xFF;
94 static uint32_t get_u32(const unsigned char *buf
)
96 return (buf
[0] << 24) | (buf
[1] << 16) | (buf
[2] << 8) | buf
[3];
99 static void iap_task(void)
101 static int count
= 0;
103 count
+= iap_pollspeed
;
104 if (count
< (500/10)) return;
106 /* exec every 500ms if pollspeed == 1 */
108 queue_post(&button_queue
, SYS_IAP_PERIODIC
, 0);
111 /* called by playback when the next track starts */
112 static void iap_track_changed(void *ignored
)
118 void iap_setup(int ratenum
)
120 iap_bitrate_set(ratenum
);
122 iap_remotetick
= true;
123 iap_updateflag
= false;
125 iap_setupflag
= true;
126 iap_remotebtn
= BUTTON_NONE
;
127 tick_add_task(iap_task
);
128 add_event(PLAYBACK_EVENT_TRACK_CHANGE
, false, iap_track_changed
);
131 void iap_bitrate_set(int ratenum
)
139 serial_bitrate(9600);
142 serial_bitrate(19200);
145 serial_bitrate(38400);
148 serial_bitrate(57600);
159 parameters (0-n bytes)
160 checksum (length+mode+parameters+checksum == 0)
163 void iap_send_pkt(const unsigned char * data
, int len
)
165 int i
, chksum
, responselen
;
167 if(len
> TX_BUFLEN
-4) len
= TX_BUFLEN
-4;
168 responselen
= len
+ 4;
173 chksum
= response
[2] = len
;
174 for(i
= 0; i
< len
; i
++)
177 response
[i
+3] = data
[i
];
180 response
[i
+3] = 0x100 - (chksum
& 0xFF);
182 for(i
= 0; i
< responselen
; i
++)
185 tx_writec(response
[i
]);
189 bool iap_getc(unsigned char x
)
191 struct state_t
*s
= &frame_state
;
193 /* run state machine to detect and extract a valid frame */
202 /* received a valid sync/SOF pair */
230 if ((s
->len
== 0) || (s
->len
> RX_BUFLEN
)) {
240 s
->payload
[s
->count
++] = x
;
241 if (s
->count
== s
->len
) {
247 if ((s
->check
& 0xFF) == 0) {
248 /* done, received a valid frame */
249 queue_post(&button_queue
, SYS_IAP_HANDLEPKT
, 0);
254 panicf("Unhandled iap state %d", (int) s
->state
);
258 /* return true while still hunting for the sync and start-of-frame byte */
259 return (s
->state
== ST_SYNC
) || (s
->state
== ST_SOF
);
262 void iap_periodic(void)
264 if(!iap_setupflag
) return;
265 if(!iap_pollspeed
) return;
267 /* PlayStatusChangeNotification */
268 unsigned char data
[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00};
269 unsigned long time_elapsed
= audio_current_track()->elapsed
;
271 time_elapsed
+= wps_get_ff_rewind_count();
273 data
[3] = 0x04; /* playing */
275 /* If info has changed, don't flag it right away */
276 if(iap_changedctr
&& iap_changedctr
++ >= iap_pollspeed
* 2)
278 /* track info has changed */
280 data
[3] = 0x01; /* 0x02 has same effect? */
281 iap_updateflag
= true;
284 put_u32(&data
[4], time_elapsed
);
285 iap_send_pkt(data
, sizeof(data
));
288 static void iap_set_remote_volume(void)
290 unsigned char data
[] = {0x03, 0x0D, 0x04, 0x00, 0x00};
291 data
[4] = (char)((global_settings
.volume
+58) * 4);
292 iap_send_pkt(data
, sizeof(data
));
295 static void cmd_ok_mode0(unsigned char cmd
)
297 unsigned char data
[] = {0x00, 0x02, 0x00, 0x00};
298 data
[3] = cmd
; /* respond with cmd */
299 iap_send_pkt(data
, sizeof(data
));
302 static void iap_handlepkt_mode0(unsigned int len
, const unsigned char *buf
)
304 (void)len
; /* len currently unused */
306 unsigned int cmd
= buf
[1];
311 /* FM transmitter sends this: */
312 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
316 /* RF Transmitter: Begin transmission */
317 unsigned char data
[] = {0x05, 0x02};
318 iap_send_pkt(data
, sizeof(data
));
320 /* FM remote sends this: */
321 /* FF 55 03 00 01 02 FA (1st thing sent) */
322 else if (buf
[2] == 0x02)
324 /* useful only for apple firmware */
329 /* EnterRemoteUIMode, FM transmitter sends FF 55 02 00 05 F9 */
332 /* ACK Pending (3000 ms) */
333 unsigned char data
[] = {0x00, 0x02, 0x06,
334 0x05, 0x00, 0x00, 0x0B, 0xB8};
335 iap_send_pkt(data
, sizeof(data
));
340 /* ExitRemoteUIMode */
348 /* RequestiPodSoftwareVersion, Ipod FM remote sends FF 55 02 00 09 F5 */
351 /* ReturniPodSoftwareVersion, ipod5G firmware version */
352 unsigned char data
[] = {0x00, 0x0A, 0x01, 0x02, 0x01};
353 iap_send_pkt(data
, sizeof(data
));
357 /* RequestiPodModelNum */
360 /* ipod is supposed to work only with 5G and nano 2G */
361 /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34,
362 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */
363 /* ReturniPodModelNum */
364 unsigned char data
[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
365 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
366 iap_send_pkt(data
, sizeof(data
));
370 /* RequestLingoProtocolVersion */
373 /* ReturnLingoProtocolVersion */
374 unsigned char data
[] = {0x00, 0x10, 0x00, 0x01, 0x05};
376 iap_send_pkt(data
, sizeof(data
));
380 /* IdentifyDeviceLingoes */
385 uint32_t lingoes
= get_u32(&buf
[2]);
388 /* FM transmitter sends this: */
389 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
391 /* GetAccessoryInfo */
392 unsigned char data2
[] = {0x00, 0x27, 0x00};
393 iap_send_pkt(data2
, sizeof(data2
));
394 /* RF Transmitter: Begin transmission */
395 unsigned char data3
[] = {0x05, 0x02};
396 iap_send_pkt(data3
, sizeof(data3
));
400 /* ipod fm remote sends this: */
401 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
402 if (lingoes
& (1 << 7)) /* bit 7 = RF tuner lingo */
404 /* GetDevAuthenticationInfo */
405 unsigned char data4
[] = {0x00, 0x14};
406 iap_send_pkt(data4
, sizeof(data4
));
411 /* RetDevAuthenticationInfo */
414 /* AckDevAuthenticationInfo */
415 unsigned char data0
[] = {0x00, 0x16, 0x00};
416 iap_send_pkt(data0
, sizeof(data0
));
417 /* GetAccessoryInfo */
418 unsigned char data1
[] = {0x00, 0x27, 0x00};
419 iap_send_pkt(data1
, sizeof(data1
));
420 /* AckDevAuthenticationStatus, mandatory to enable some hardware */
421 unsigned char data2
[] = {0x00, 0x19, 0x00};
422 iap_send_pkt(data2
, sizeof(data2
));
423 if (radio_present
== 1)
426 unsigned char data3
[] = {0x07, 0x01};
427 iap_send_pkt(data3
, sizeof(data3
));
429 iap_set_remote_volume();
433 /* RetDevAuthenticationSignature */
436 /* Isn't used since we don't send the 0x00 0x17 command */
443 /* RetIpodOptions (ipod video send this) */
444 unsigned char data
[] = {0x00, 0x25, 0x00, 0x00, 0x00,
445 0x00, 0x00, 0x00, 0x00, 0x01};
446 iap_send_pkt(data
, sizeof(data
));
450 /* default response is with cmd ok packet */
459 static void iap_handlepkt_mode2(unsigned int len
, const unsigned char *buf
)
461 if(buf
[1] != 0) return;
462 iap_remotebtn
= BUTTON_NONE
;
463 iap_remotetick
= false;
465 if(len
>= 3 && buf
[2] != 0)
468 iap_remotebtn
|= BUTTON_RC_PLAY
;
470 iap_remotebtn
|= BUTTON_RC_VOL_UP
;
472 iap_remotebtn
|= BUTTON_RC_VOL_DOWN
;
474 iap_remotebtn
|= BUTTON_RC_RIGHT
;
476 iap_remotebtn
|= BUTTON_RC_LEFT
;
478 else if(len
>= 4 && buf
[3] != 0)
480 if(buf
[3] & 1) /* play */
482 if (audio_status() != AUDIO_STATUS_PLAY
)
484 iap_remotebtn
|= BUTTON_RC_PLAY
;
486 iap_remotetick
= false;
490 if(buf
[3] & 2) /* pause */
492 if (audio_status() == AUDIO_STATUS_PLAY
)
494 iap_remotebtn
|= BUTTON_RC_PLAY
;
496 iap_remotetick
= false;
500 if((buf
[3] & 128) && !iap_btnshuffle
) /* shuffle */
502 iap_btnshuffle
= true;
503 if(!global_settings
.playlist_shuffle
)
505 global_settings
.playlist_shuffle
= 1;
507 if (audio_status() & AUDIO_STATUS_PLAY
)
508 playlist_randomise(NULL
, current_tick
, true);
510 else if(global_settings
.playlist_shuffle
)
512 global_settings
.playlist_shuffle
= 0;
514 if (audio_status() & AUDIO_STATUS_PLAY
)
515 playlist_sort(NULL
, true);
519 iap_btnshuffle
= false;
521 else if(len
>= 5 && buf
[4] != 0)
523 if((buf
[4] & 1) && !iap_btnrepeat
) /* repeat */
525 int oldmode
= global_settings
.repeat_mode
;
526 iap_btnrepeat
= true;
528 if (oldmode
== REPEAT_ONE
)
529 global_settings
.repeat_mode
= REPEAT_OFF
;
530 else if (oldmode
== REPEAT_ALL
)
531 global_settings
.repeat_mode
= REPEAT_ONE
;
532 else if (oldmode
== REPEAT_OFF
)
533 global_settings
.repeat_mode
= REPEAT_ALL
;
536 if (audio_status() & AUDIO_STATUS_PLAY
)
537 audio_flush_and_reload_tracks();
540 iap_btnrepeat
= false;
542 if(buf
[4] & 16) /* ffwd */
544 iap_remotebtn
|= BUTTON_RC_RIGHT
;
546 if(buf
[4] & 32) /* frwd */
548 iap_remotebtn
|= BUTTON_RC_LEFT
;
553 static void iap_handlepkt_mode3(unsigned int len
, const unsigned char *buf
)
555 (void)len
; /* len currently unused */
557 unsigned int cmd
= buf
[1];
560 /* GetCurrentEQProfileIndex */
563 /* RetCurrentEQProfileIndex */
564 unsigned char data
[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
565 iap_send_pkt(data
, sizeof(data
));
569 /* SetRemoteEventNotification */
573 unsigned char data
[] = {0x03, 0x00, 0x00, 0x08};
574 iap_send_pkt(data
, sizeof(data
));
578 /* GetiPodStateInfo */
581 /* request ipod volume */
584 iap_set_remote_volume();
589 /* SetiPodStateInfo */
593 global_settings
.volume
= (-58)+((int)buf
[4]+1)/4;
594 sound_set_volume(global_settings
.volume
); /* indent BUG? */
600 static void cmd_ok_mode4(unsigned int cmd
)
602 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
603 data
[4] = (cmd
>> 8) & 0xFF;
604 data
[5] = (cmd
>> 0) & 0xFF;
605 iap_send_pkt(data
, sizeof(data
));
608 static void get_playlist_name(unsigned char *dest
,
609 unsigned long item_offset
,
612 if (item_offset
== 0) return;
614 struct dirent
* playlist_file
= NULL
;
616 dp
= opendir(global_settings
.playlist_catalog_dir
);
619 unsigned long nbr
= 0;
620 while ((nbr
< item_offset
) && ((playlist_file
= readdir(dp
)) != NULL
))
622 /*Increment only if there is a playlist extension*/
623 if ((extension
=strrchr(playlist_file
->d_name
, '.')) != NULL
){
624 if ((strcmp(extension
, ".m3u") == 0 ||
625 strcmp(extension
, ".m3u8") == 0))
629 if (playlist_file
!= NULL
) {
630 strlcpy(dest
, playlist_file
->d_name
, max_length
);
635 static void iap_handlepkt_mode4(unsigned int len
, const unsigned char *buf
)
637 (void)len
; /* len currently unused */
639 unsigned int cmd
= (buf
[1] << 8) | buf
[2];
642 /* GetAudioBookSpeed */
645 /* ReturnAudioBookSpeed */
646 unsigned char data
[] = {0x04, 0x00, 0x0A, 0x00};
647 data
[3] = iap_updateflag
? 0 : 1;
648 iap_send_pkt(data
, sizeof(data
));
652 /* SetAudioBookSpeed */
655 iap_updateflag
= buf
[3] ? 0 : 1;
656 /* respond with cmd ok packet */
661 /* RequestProtocolVersion */
664 /* ReturnProtocolVersion */
665 unsigned char data
[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
666 iap_send_pkt(data
, sizeof(data
));
673 memcpy(cur_dbrecord
, buf
+ 3, 5);
678 /* GetNumberCategorizedDBRecords */
681 /* ReturnNumberCategorizedDBRecords */
682 unsigned char data
[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
683 unsigned long num
= 0;
686 unsigned long nbr_total_playlists
= 0;
687 struct dirent
* playlist_file
= NULL
;
690 switch(buf
[3]) /* type number */
692 case 0x01: /* total number of playlists */
693 dp
= opendir(global_settings
.playlist_catalog_dir
);
694 while ((playlist_file
= readdir(dp
)) != NULL
)
696 /*Increment only if there is a playlist extension*/
697 if ((extension
=strrchr(playlist_file
->d_name
, '.'))
699 if ((strcmp(extension
, ".m3u") == 0 ||
700 strcmp(extension
, ".m3u8") == 0))
701 nbr_total_playlists
++;
705 /*Add 1 for the main playlist*/
706 num
= nbr_total_playlists
+ 1;
708 case 0x05: /* total number of songs */
712 put_u32(&data
[3], num
);
713 iap_send_pkt(data
, sizeof(data
));
717 /* RetrieveCategorizedDatabaseRecords */
720 /* ReturnCategorizedDatabaseRecord */
721 unsigned char data
[7 + MAX_PATH
] =
722 {0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00,
723 'R', 'O', 'C', 'K', 'B', 'O', 'X', '\0'};
725 unsigned long item_offset
= get_u32(&buf
[4]);
727 get_playlist_name(data
+ 7, item_offset
, MAX_PATH
);
728 /*Remove file extension*/
730 dot
= (strrchr(data
+7, '.'));
733 iap_send_pkt(data
, 7 + strlen(data
+7) + 1);
740 /* ReturnPlayStatus */
741 unsigned char data
[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
743 struct mp3entry
*id3
= audio_current_track();
744 unsigned long time_total
= id3
->length
;
745 unsigned long time_elapsed
= id3
->elapsed
;
746 int status
= audio_status();
747 put_u32(&data
[3], time_total
);
748 put_u32(&data
[7], time_elapsed
);
749 if (status
== AUDIO_STATUS_PLAY
)
750 data
[11] = 0x01; /* play */
751 else if (status
& AUDIO_STATUS_PAUSE
)
752 data
[11] = 0x02; /* pause */
753 iap_send_pkt(data
, sizeof(data
));
757 /* GetCurrentPlayingTrackIndex */
760 /* ReturnCurrentPlayingTrackIndex */
761 unsigned char data
[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
762 long playlist_pos
= playlist_next(0);
763 playlist_pos
-= playlist_get_first_index(NULL
);
765 playlist_pos
+= playlist_amount();
766 put_u32(&data
[3], playlist_pos
);
767 iap_send_pkt(data
, sizeof(data
));
771 /* GetIndexedPlayingTrackTitle */
773 /* GetIndexedPlayingTrackArtistName */
775 /* GetIndexedPlayingTrackAlbumName */
778 unsigned char data
[70] = {0x04, 0x00, 0xFF};
782 long tracknum
= get_u32(&buf
[3]);
785 memcpy(&id3
, audio_current_track(), sizeof(id3
));
786 tracknum
+= playlist_get_first_index(NULL
);
787 if(tracknum
>= playlist_amount())
788 tracknum
-= playlist_amount();
790 /* If the tracknumber is not the current one,
791 read id3 from disk */
792 if(playlist_next(0) != tracknum
)
794 struct playlist_track_info info
;
795 playlist_get_track_info(NULL
, tracknum
, &info
);
796 fd
= open(info
.filename
, O_RDONLY
);
797 memset(&id3
, 0, sizeof(struct mp3entry
));
798 get_metadata(&id3
, fd
, info
.filename
);
802 /* Return the requested track data */
806 len
= strlcpy((char *)&data
[3], id3
.title
, 64);
807 iap_send_pkt(data
, 4+len
);
810 len
= strlcpy((char *)&data
[3], id3
.artist
, 64);
811 iap_send_pkt(data
, 4+len
);
814 len
= strlcpy((char *)&data
[3], id3
.album
, 64);
815 iap_send_pkt(data
, 4+len
);
821 /* SetPlayStatusChangeNotification */
824 iap_pollspeed
= buf
[3] ? 1 : 0;
825 /* respond with cmd ok packet */
830 /* PlayCurrentSelection */
833 switch (cur_dbrecord
[0])
837 unsigned long item_offset
= get_u32(&cur_dbrecord
[1]);
839 unsigned char selected_playlist
840 [sizeof(global_settings
.playlist_catalog_dir
)
844 strcpy(selected_playlist
,
845 global_settings
.playlist_catalog_dir
);
846 int len
= strlen(selected_playlist
);
847 selected_playlist
[len
] = '/';
848 get_playlist_name (selected_playlist
+ len
+ 1,
851 ft_play_playlist(selected_playlist
,
852 global_settings
.playlist_catalog_dir
,
853 strrchr(selected_playlist
, '/') + 1);
866 case 0x01: /* play/pause */
867 iap_remotebtn
= BUTTON_RC_PLAY
;
869 iap_remotetick
= false;
872 case 0x02: /* stop */
873 iap_remotebtn
= BUTTON_RC_PLAY
|BUTTON_REPEAT
;
875 iap_remotetick
= false;
878 case 0x03: /* skip++ */
879 iap_remotebtn
= BUTTON_RC_RIGHT
;
881 iap_remotetick
= false;
883 case 0x04: /* skip-- */
884 iap_remotebtn
= BUTTON_RC_LEFT
;
886 iap_remotetick
= false;
888 case 0x05: /* ffwd */
889 iap_remotebtn
= BUTTON_RC_RIGHT
;
890 iap_remotetick
= false;
891 if(iap_pollspeed
) iap_pollspeed
= 5;
893 case 0x06: /* frwd */
894 iap_remotebtn
= BUTTON_RC_LEFT
;
895 iap_remotetick
= false;
896 if(iap_pollspeed
) iap_pollspeed
= 5;
898 case 0x07: /* end ffwd/frwd */
899 iap_remotebtn
= BUTTON_NONE
;
900 iap_remotetick
= false;
901 if(iap_pollspeed
) iap_pollspeed
= 1;
904 /* respond with cmd ok packet */
913 unsigned char data
[] = {0x04, 0x00, 0x2D, 0x00};
914 data
[3] = global_settings
.playlist_shuffle
? 1 : 0;
915 iap_send_pkt(data
, sizeof(data
));
922 if(buf
[3] && !global_settings
.playlist_shuffle
)
924 global_settings
.playlist_shuffle
= 1;
926 if (audio_status() & AUDIO_STATUS_PLAY
)
927 playlist_randomise(NULL
, current_tick
, true);
929 else if(!buf
[3] && global_settings
.playlist_shuffle
)
931 global_settings
.playlist_shuffle
= 0;
933 if (audio_status() & AUDIO_STATUS_PLAY
)
934 playlist_sort(NULL
, true);
937 /* respond with cmd ok packet */
946 unsigned char data
[] = {0x04, 0x00, 0x30, 0x00};
947 if(global_settings
.repeat_mode
== REPEAT_OFF
)
949 else if(global_settings
.repeat_mode
== REPEAT_ONE
)
953 iap_send_pkt(data
, sizeof(data
));
960 int oldmode
= global_settings
.repeat_mode
;
962 global_settings
.repeat_mode
= REPEAT_OFF
;
963 else if (buf
[3] == 1)
964 global_settings
.repeat_mode
= REPEAT_ONE
;
965 else if (buf
[3] == 2)
966 global_settings
.repeat_mode
= REPEAT_ALL
;
968 if (oldmode
!= global_settings
.repeat_mode
)
971 if (audio_status() & AUDIO_STATUS_PLAY
)
972 audio_flush_and_reload_tracks();
975 /* respond with cmd ok packet */
980 /* GetMonoDisplayImageLimits */
983 /* ReturnMonoDisplayImageLimits */
984 unsigned char data
[] = {0x04, 0x00, 0x34,
985 LCD_WIDTH
>> 8, LCD_WIDTH
& 0xff,
986 LCD_HEIGHT
>> 8, LCD_HEIGHT
& 0xff,
988 iap_send_pkt(data
, sizeof(data
));
992 /* GetNumPlayingTracks */
995 /* ReturnNumPlayingTracks */
996 unsigned char data
[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
997 unsigned long playlist_amt
= playlist_amount();
998 put_u32(&data
[3], playlist_amt
);
999 iap_send_pkt(data
, sizeof(data
));
1003 /* SetCurrentPlayingTrack */
1006 int paused
= (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE
));
1007 long tracknum
= get_u32(&buf
[3]);
1010 audio_skip(tracknum
- playlist_next(0));
1014 /* respond with cmd ok packet */
1021 /* default response is with cmd ok packet */
1028 static void iap_handlepkt_mode7(unsigned int len
, const unsigned char *buf
)
1030 unsigned int cmd
= buf
[1];
1038 /* GetAccessoryInfo */
1039 unsigned char data
[] = {0x00, 0x27, 0x00};
1040 iap_send_pkt(data
, sizeof(data
));
1050 rmt_tuner_freq(len
, buf
);
1054 /* RdsReadyNotify, RDS station name 0x21 1E 00 + ASCII text*/
1057 rmt_tuner_rds_data(len
, buf
);
1063 void iap_handlepkt(void)
1065 struct state_t
*s
= &frame_state
;
1067 if(!iap_setupflag
) return;
1069 /* if we are waiting for a remote button to go out,
1070 delay the handling of the new packet */
1073 queue_post(&button_queue
, SYS_IAP_HANDLEPKT
, 0);
1077 /* handle command by mode */
1078 unsigned char mode
= s
->payload
[0];
1080 case 0: iap_handlepkt_mode0(s
->len
, s
->payload
); break;
1081 case 2: iap_handlepkt_mode2(s
->len
, s
->payload
); break;
1082 case 3: iap_handlepkt_mode3(s
->len
, s
->payload
); break;
1083 case 4: iap_handlepkt_mode4(s
->len
, s
->payload
); break;
1084 case 7: iap_handlepkt_mode7(s
->len
, s
->payload
); break;
1088 int remote_control_rx(void)
1090 int btn
= iap_remotebtn
;
1096 iap_remotebtn
= BUTTON_NONE
;
1097 iap_remotetick
= true;
1101 iap_remotetick
= true;
1106 const unsigned char *iap_get_serbuf(void)