iap: pass length and data pointer to iap_handlepkt functions, this prepares for iap...
[kugel-rb.git] / apps / iap.c
blobeaee21bc8964705e9c1839094d7e9b4cab69e3a9
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <string.h>
24 #include "iap.h"
25 #include "button.h"
26 #include "config.h"
27 #include "cpu.h"
28 #include "system.h"
29 #include "kernel.h"
30 #include "serial.h"
31 #include "appevents.h"
33 #include "playlist.h"
34 #include "playback.h"
35 #include "audio.h"
36 #include "settings.h"
37 #include "metadata.h"
38 #include "wps.h"
39 #include "sound.h"
40 #include "action.h"
41 #include "powermgmt.h"
43 #include "tuner.h"
44 #include "ipod_remote_tuner.h"
46 #include "filetree.h"
47 #include "dir.h"
49 static volatile int iap_pollspeed = 0;
50 static volatile bool iap_remotetick = true;
51 static bool iap_setupflag = false, iap_updateflag = false;
52 static int iap_changedctr = 0;
54 static unsigned long iap_remotebtn = 0;
55 static int iap_repeatbtn = 0;
56 static bool iap_btnrepeat = false, iap_btnshuffle = false;
58 static unsigned char serbuf[RX_BUFLEN];
59 static int serbuf_i = 0;
61 static unsigned char response[TX_BUFLEN];
62 static int responselen;
64 static char cur_dbrecord[5] = {0};
66 static void put_u32(unsigned char *buf, uint32_t data)
68 buf[0] = (data >> 24) & 0xFF;
69 buf[1] = (data >> 16) & 0xFF;
70 buf[2] = (data >> 8) & 0xFF;
71 buf[3] = (data >> 0) & 0xFF;
74 static uint32_t get_u32(const unsigned char *buf)
76 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
79 static void iap_task(void)
81 static int count = 0;
83 count += iap_pollspeed;
84 if (count < (500/10)) return;
86 /* exec every 500ms if pollspeed == 1 */
87 count = 0;
88 queue_post(&button_queue, SYS_IAP_PERIODIC, 0);
91 /* called by playback when the next track starts */
92 static void iap_track_changed(void *ignored)
94 (void)ignored;
95 iap_changedctr = 1;
98 void iap_setup(int ratenum)
100 iap_bitrate_set(ratenum);
101 iap_pollspeed = 0;
102 iap_remotetick = true;
103 iap_updateflag = false;
104 iap_changedctr = 0;
105 iap_setupflag = true;
106 iap_remotebtn = BUTTON_NONE;
107 tick_add_task(iap_task);
108 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed);
111 void iap_bitrate_set(int ratenum)
113 switch(ratenum)
115 case 0:
116 serial_bitrate(0);
117 break;
118 case 1:
119 serial_bitrate(9600);
120 break;
121 case 2:
122 serial_bitrate(19200);
123 break;
124 case 3:
125 serial_bitrate(38400);
126 break;
127 case 4:
128 serial_bitrate(57600);
129 break;
133 /* Message format:
134 0xff
135 0x55
136 length
137 mode
138 command (2 bytes)
139 parameters (0-n bytes)
140 checksum (length+mode+parameters+checksum == 0)
143 void iap_send_pkt(const unsigned char * data, int len)
145 int i, chksum;
147 if(len > TX_BUFLEN-4) len = TX_BUFLEN-4;
148 responselen = len + 4;
150 response[0] = 0xFF;
151 response[1] = 0x55;
153 chksum = response[2] = len;
154 for(i = 0; i < len; i ++)
156 chksum += data[i];
157 response[i+3] = data[i];
160 response[i+3] = 0x100 - (chksum & 0xFF);
162 for(i = 0; i < responselen; i ++)
164 while (!tx_rdy()) ;
165 tx_writec(response[i]);
169 bool iap_getc(unsigned char x)
171 static unsigned char last_x = 0;
172 static bool newpkt = true;
173 static unsigned char chksum = 0;
175 /* Restart if the sync word is seen */
176 if(x == 0x55 && last_x == 0xff/* && newpkt*/)
178 serbuf[0] = 0;
179 serbuf_i = 0;
180 chksum = 0;
181 newpkt = false;
183 else
185 if(serbuf_i >= RX_BUFLEN)
186 serbuf_i = 0;
188 serbuf[serbuf_i++] = x;
189 chksum += x;
191 last_x = x;
193 /* Broadcast to queue if we have a complete message */
194 if(serbuf_i && (serbuf_i == serbuf[0]+2))
196 serbuf_i = 0;
197 newpkt = true;
198 if(chksum == 0)
199 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
201 return newpkt;
204 void iap_periodic(void)
206 if(!iap_setupflag) return;
207 if(!iap_pollspeed) return;
209 /* PlayStatusChangeNotification */
210 unsigned char data[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00};
211 unsigned long time_elapsed = audio_current_track()->elapsed;
213 time_elapsed += wps_get_ff_rewind_count();
215 data[3] = 0x04; /* playing */
217 /* If info has changed, don't flag it right away */
218 if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2)
220 /* track info has changed */
221 iap_changedctr = 0;
222 data[3] = 0x01; /* 0x02 has same effect? */
223 iap_updateflag = true;
226 put_u32(&data[4], time_elapsed);
227 iap_send_pkt(data, sizeof(data));
230 static void iap_set_remote_volume(void)
232 unsigned char data[] = {0x03, 0x0D, 0x04, 0x00, 0x00};
233 data[4] = (char)((global_settings.volume+58) * 4);
234 iap_send_pkt(data, sizeof(data));
237 static void cmd_ok_mode0(unsigned char cmd)
239 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
240 data[3] = cmd; /* respond with cmd */
241 iap_send_pkt(data, sizeof(data));
244 static void iap_handlepkt_mode0(unsigned int len, const unsigned char *buf)
246 (void)len; /* len currently unused */
248 unsigned int cmd = buf[1];
249 switch (cmd) {
250 /* Identify */
251 case 0x01:
253 /* FM transmitter sends this: */
254 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
255 if(buf[2] == 0x05)
257 sleep(HZ/3);
258 /* RF Transmitter: Begin transmission */
259 unsigned char data[] = {0x05, 0x02};
260 iap_send_pkt(data, sizeof(data));
262 /* FM remote sends this: */
263 /* FF 55 03 00 01 02 FA (1st thing sent) */
264 else if (buf[2] == 0x02)
266 /* useful only for apple firmware */
268 break;
271 /* EnterRemoteUIMode, FM transmitter sends FF 55 02 00 05 F9 */
272 case 0x05:
274 /* ACK Pending (3000 ms) */
275 unsigned char data[] = {0x00, 0x02, 0x06,
276 0x05, 0x00, 0x00, 0x0B, 0xB8};
277 iap_send_pkt(data, sizeof(data));
278 cmd_ok_mode0(cmd);
279 break;
282 /* ExitRemoteUIMode */
283 case 0x06:
285 audio_stop();
286 cmd_ok_mode0(cmd);
287 break;
290 /* RequestiPodSoftwareVersion, Ipod FM remote sends FF 55 02 00 09 F5 */
291 case 0x09:
293 /* ReturniPodSoftwareVersion, ipod5G firmware version */
294 unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01};
295 iap_send_pkt(data, sizeof(data));
296 break;
299 /* RequestiPodModelNum */
300 case 0x0D:
302 /* ipod is supposed to work only with 5G and nano 2G */
303 /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34,
304 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */
305 /* ReturniPodModelNum */
306 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
307 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
308 iap_send_pkt(data, sizeof(data));
309 break;
312 /* RequestLingoProtocolVersion */
313 case 0x0F:
315 /* ReturnLingoProtocolVersion */
316 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
317 data[2] = buf[2];
318 iap_send_pkt(data, sizeof(data));
319 break;
322 /* IdentifyDeviceLingoes */
323 case 0x13:
325 cmd_ok_mode0(cmd);
327 uint32_t lingoes = get_u32(&buf[2]);
329 if (lingoes == 0x35)
330 /* FM transmitter sends this: */
331 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
333 /* GetAccessoryInfo */
334 unsigned char data2[] = {0x00, 0x27, 0x00};
335 iap_send_pkt(data2, sizeof(data2));
336 /* RF Transmitter: Begin transmission */
337 unsigned char data3[] = {0x05, 0x02};
338 iap_send_pkt(data3, sizeof(data3));
340 else
342 /* ipod fm remote sends this: */
343 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
344 if (lingoes & (1 << 7)) /* bit 7 = RF tuner lingo */
345 radio_present = 1;
346 /* GetDevAuthenticationInfo */
347 unsigned char data4[] = {0x00, 0x14};
348 iap_send_pkt(data4, sizeof(data4));
350 break;
353 /* RetDevAuthenticationInfo */
354 case 0x15:
356 /* AckDevAuthenticationInfo */
357 unsigned char data0[] = {0x00, 0x16, 0x00};
358 iap_send_pkt(data0, sizeof(data0));
359 /* GetAccessoryInfo */
360 unsigned char data1[] = {0x00, 0x27, 0x00};
361 iap_send_pkt(data1, sizeof(data1));
362 /* AckDevAuthenticationStatus, mandatory to enable some hardware */
363 unsigned char data2[] = {0x00, 0x19, 0x00};
364 iap_send_pkt(data2, sizeof(data2));
365 if (radio_present == 1)
367 /* GetTunerCaps */
368 unsigned char data3[] = {0x07, 0x01};
369 iap_send_pkt(data3, sizeof(data3));
371 iap_set_remote_volume();
372 break;
375 /* RetDevAuthenticationSignature */
376 case 0x18:
378 /* Isn't used since we don't send the 0x00 0x17 command */
379 break;
382 /* GetIpodOptions */
383 case 0x24:
385 /* RetIpodOptions (ipod video send this) */
386 unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00,
387 0x00, 0x00, 0x00, 0x00, 0x01};
388 iap_send_pkt(data, sizeof(data));
389 break;
392 /* default response is with cmd ok packet */
393 default:
395 cmd_ok_mode0(cmd);
396 break;
401 static void iap_handlepkt_mode2(unsigned int len, const unsigned char *buf)
403 if(buf[1] != 0) return;
404 iap_remotebtn = BUTTON_NONE;
405 iap_remotetick = false;
407 if(len >= 3 && buf[2] != 0)
409 if(buf[2] & 1)
410 iap_remotebtn |= BUTTON_RC_PLAY;
411 if(buf[2] & 2)
412 iap_remotebtn |= BUTTON_RC_VOL_UP;
413 if(buf[2] & 4)
414 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
415 if(buf[2] & 8)
416 iap_remotebtn |= BUTTON_RC_RIGHT;
417 if(buf[2] & 16)
418 iap_remotebtn |= BUTTON_RC_LEFT;
420 else if(len >= 4 && buf[3] != 0)
422 if(buf[3] & 1) /* play */
424 if (audio_status() != AUDIO_STATUS_PLAY)
426 iap_remotebtn |= BUTTON_RC_PLAY;
427 iap_repeatbtn = 2;
428 iap_remotetick = false;
429 iap_changedctr = 1;
432 if(buf[3] & 2) /* pause */
434 if (audio_status() == AUDIO_STATUS_PLAY)
436 iap_remotebtn |= BUTTON_RC_PLAY;
437 iap_repeatbtn = 2;
438 iap_remotetick = false;
439 iap_changedctr = 1;
442 if((buf[3] & 128) && !iap_btnshuffle) /* shuffle */
444 iap_btnshuffle = true;
445 if(!global_settings.playlist_shuffle)
447 global_settings.playlist_shuffle = 1;
448 settings_save();
449 if (audio_status() & AUDIO_STATUS_PLAY)
450 playlist_randomise(NULL, current_tick, true);
452 else if(global_settings.playlist_shuffle)
454 global_settings.playlist_shuffle = 0;
455 settings_save();
456 if (audio_status() & AUDIO_STATUS_PLAY)
457 playlist_sort(NULL, true);
460 else
461 iap_btnshuffle = false;
463 else if(len >= 5 && buf[4] != 0)
465 if((buf[4] & 1) && !iap_btnrepeat) /* repeat */
467 int oldmode = global_settings.repeat_mode;
468 iap_btnrepeat = true;
470 if (oldmode == REPEAT_ONE)
471 global_settings.repeat_mode = REPEAT_OFF;
472 else if (oldmode == REPEAT_ALL)
473 global_settings.repeat_mode = REPEAT_ONE;
474 else if (oldmode == REPEAT_OFF)
475 global_settings.repeat_mode = REPEAT_ALL;
477 settings_save();
478 if (audio_status() & AUDIO_STATUS_PLAY)
479 audio_flush_and_reload_tracks();
481 else
482 iap_btnrepeat = false;
484 if(buf[4] & 16) /* ffwd */
486 iap_remotebtn |= BUTTON_RC_RIGHT;
488 if(buf[4] & 32) /* frwd */
490 iap_remotebtn |= BUTTON_RC_LEFT;
495 static void iap_handlepkt_mode3(unsigned int len, const unsigned char *buf)
497 (void)len; /* len currently unused */
499 unsigned int cmd = buf[1];
500 switch (cmd)
502 /* GetCurrentEQProfileIndex */
503 case 0x01:
505 /* RetCurrentEQProfileIndex */
506 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
507 iap_send_pkt(data, sizeof(data));
508 break;
511 /* SetRemoteEventNotification */
512 case 0x08:
514 /* ACK */
515 unsigned char data[] = {0x03, 0x00, 0x00, 0x08};
516 iap_send_pkt(data, sizeof(data));
517 break;
520 /* GetiPodStateInfo */
521 case 0x0C:
523 /* request ipod volume */
524 if (buf[2] == 0x04)
526 iap_set_remote_volume();
528 break;
531 /* SetiPodStateInfo */
532 case 0x0E:
534 if (buf[2] == 0x04)
535 global_settings.volume = (-58)+((int)buf[4]+1)/4;
536 sound_set_volume(global_settings.volume); /* indent BUG? */
537 break;
542 static void cmd_ok_mode4(unsigned int cmd)
544 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
545 data[4] = (cmd >> 8) & 0xFF;
546 data[5] = (cmd >> 0) & 0xFF;
547 iap_send_pkt(data, sizeof(data));
550 static void get_playlist_name(unsigned char *dest,
551 unsigned long item_offset,
552 size_t max_length)
554 if (item_offset == 0) return;
555 DIR* dp;
556 struct dirent* playlist_file = NULL;
558 dp = opendir(global_settings.playlist_catalog_dir);
560 char *extension;
561 unsigned long nbr = 0;
562 while ((nbr < item_offset) && ((playlist_file = readdir(dp)) != NULL))
564 /*Increment only if there is a playlist extension*/
565 if ((extension=strrchr(playlist_file->d_name, '.')) != NULL){
566 if ((strcmp(extension, ".m3u") == 0 ||
567 strcmp(extension, ".m3u8") == 0))
568 nbr++;
571 if (playlist_file != NULL) {
572 strlcpy(dest, playlist_file->d_name, max_length);
574 closedir(dp);
577 static void iap_handlepkt_mode4(unsigned int len, const unsigned char *buf)
579 (void)len; /* len currently unused */
581 unsigned int cmd = (buf[1] << 8) | buf[2];
582 switch (cmd)
584 /* GetAudioBookSpeed */
585 case 0x0009:
587 /* ReturnAudioBookSpeed */
588 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
589 data[3] = iap_updateflag ? 0 : 1;
590 iap_send_pkt(data, sizeof(data));
591 break;
594 /* SetAudioBookSpeed */
595 case 0x000B:
597 iap_updateflag = buf[3] ? 0 : 1;
598 /* respond with cmd ok packet */
599 cmd_ok_mode4(cmd);
600 break;
603 /* RequestProtocolVersion */
604 case 0x0012:
606 /* ReturnProtocolVersion */
607 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
608 iap_send_pkt(data, sizeof(data));
609 break;
612 /* SelectDBRecord */
613 case 0x0017:
615 memcpy(cur_dbrecord, buf + 3, 5);
616 cmd_ok_mode4(cmd);
617 break;
620 /* GetNumberCategorizedDBRecords */
621 case 0x0018:
623 /* ReturnNumberCategorizedDBRecords */
624 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
625 unsigned long num = 0;
627 DIR* dp;
628 unsigned long nbr_total_playlists = 0;
629 struct dirent* playlist_file = NULL;
630 char *extension;
632 switch(buf[3]) /* type number */
634 case 0x01: /* total number of playlists */
635 dp = opendir(global_settings.playlist_catalog_dir);
636 while ((playlist_file = readdir(dp)) != NULL)
638 /*Increment only if there is a playlist extension*/
639 if ((extension=strrchr(playlist_file->d_name, '.'))
640 != NULL) {
641 if ((strcmp(extension, ".m3u") == 0 ||
642 strcmp(extension, ".m3u8") == 0))
643 nbr_total_playlists++;
646 closedir(dp);
647 /*Add 1 for the main playlist*/
648 num = nbr_total_playlists + 1;
649 break;
650 case 0x05: /* total number of songs */
651 num = 1;
652 break;
654 put_u32(&data[3], num);
655 iap_send_pkt(data, sizeof(data));
656 break;
659 /* RetrieveCategorizedDatabaseRecords */
660 case 0x001A:
662 /* ReturnCategorizedDatabaseRecord */
663 unsigned char data[7 + MAX_PATH] =
664 {0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00,
665 'R', 'O', 'C', 'K', 'B', 'O', 'X', '\0'};
667 unsigned long item_offset = get_u32(&buf[4]);
669 get_playlist_name(data + 7, item_offset, MAX_PATH);
670 /*Remove file extension*/
671 char *dot=NULL;
672 dot = (strrchr(data+7, '.'));
673 if (dot != NULL)
674 *dot = '\0';
675 iap_send_pkt(data, 7 + strlen(data+7) + 1);
676 break;
679 /* GetPlayStatus */
680 case 0x001C:
682 /* ReturnPlayStatus */
683 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
684 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
685 struct mp3entry *id3 = audio_current_track();
686 unsigned long time_total = id3->length;
687 unsigned long time_elapsed = id3->elapsed;
688 int status = audio_status();
689 put_u32(&data[3], time_total);
690 put_u32(&data[7], time_elapsed);
691 if (status == AUDIO_STATUS_PLAY)
692 data[11] = 0x01; /* play */
693 else if (status & AUDIO_STATUS_PAUSE)
694 data[11] = 0x02; /* pause */
695 iap_send_pkt(data, sizeof(data));
696 break;
699 /* GetCurrentPlayingTrackIndex */
700 case 0x001E:
702 /* ReturnCurrentPlayingTrackIndex */
703 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
704 long playlist_pos = playlist_next(0);
705 playlist_pos -= playlist_get_first_index(NULL);
706 if(playlist_pos < 0)
707 playlist_pos += playlist_amount();
708 put_u32(&data[3], playlist_pos);
709 iap_send_pkt(data, sizeof(data));
710 break;
713 /* GetIndexedPlayingTrackTitle */
714 case 0x0020:
715 /* GetIndexedPlayingTrackArtistName */
716 case 0x0022:
717 /* GetIndexedPlayingTrackAlbumName */
718 case 0x0024:
720 unsigned char data[70] = {0x04, 0x00, 0xFF};
721 struct mp3entry id3;
722 int fd;
723 size_t len;
724 long tracknum = get_u32(&buf[3]);
726 data[2] = cmd + 1;
727 memcpy(&id3, audio_current_track(), sizeof(id3));
728 tracknum += playlist_get_first_index(NULL);
729 if(tracknum >= playlist_amount())
730 tracknum -= playlist_amount();
732 /* If the tracknumber is not the current one,
733 read id3 from disk */
734 if(playlist_next(0) != tracknum)
736 struct playlist_track_info info;
737 playlist_get_track_info(NULL, tracknum, &info);
738 fd = open(info.filename, O_RDONLY);
739 memset(&id3, 0, sizeof(struct mp3entry));
740 get_metadata(&id3, fd, info.filename);
741 close(fd);
744 /* Return the requested track data */
745 switch(cmd)
747 case 0x20:
748 len = strlcpy((char *)&data[3], id3.title, 64);
749 iap_send_pkt(data, 4+len);
750 break;
751 case 0x22:
752 len = strlcpy((char *)&data[3], id3.artist, 64);
753 iap_send_pkt(data, 4+len);
754 break;
755 case 0x24:
756 len = strlcpy((char *)&data[3], id3.album, 64);
757 iap_send_pkt(data, 4+len);
758 break;
760 break;
763 /* SetPlayStatusChangeNotification */
764 case 0x0026:
766 iap_pollspeed = buf[3] ? 1 : 0;
767 /* respond with cmd ok packet */
768 cmd_ok_mode4(cmd);
769 break;
772 /* PlayCurrentSelection */
773 case 0x0028:
775 switch (cur_dbrecord[0])
777 case 0x01:
778 {/*Playlist*/
779 unsigned long item_offset = get_u32(&cur_dbrecord[1]);
781 unsigned char selected_playlist
782 [sizeof(global_settings.playlist_catalog_dir)
784 + MAX_PATH] = {0};
786 strcpy(selected_playlist,
787 global_settings.playlist_catalog_dir);
788 int len = strlen(selected_playlist);
789 selected_playlist[len] = '/';
790 get_playlist_name (selected_playlist + len + 1,
791 item_offset,
792 MAX_PATH);
793 ft_play_playlist(selected_playlist,
794 global_settings.playlist_catalog_dir,
795 strrchr(selected_playlist, '/') + 1);
796 break;
799 cmd_ok_mode4(cmd);
800 break;
803 /* PlayControl */
804 case 0x0029:
806 switch(buf[3])
808 case 0x01: /* play/pause */
809 iap_remotebtn = BUTTON_RC_PLAY;
810 iap_repeatbtn = 2;
811 iap_remotetick = false;
812 iap_changedctr = 1;
813 break;
814 case 0x02: /* stop */
815 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
816 iap_repeatbtn = 2;
817 iap_remotetick = false;
818 iap_changedctr = 1;
819 break;
820 case 0x03: /* skip++ */
821 iap_remotebtn = BUTTON_RC_RIGHT;
822 iap_repeatbtn = 2;
823 iap_remotetick = false;
824 break;
825 case 0x04: /* skip-- */
826 iap_remotebtn = BUTTON_RC_LEFT;
827 iap_repeatbtn = 2;
828 iap_remotetick = false;
829 break;
830 case 0x05: /* ffwd */
831 iap_remotebtn = BUTTON_RC_RIGHT;
832 iap_remotetick = false;
833 if(iap_pollspeed) iap_pollspeed = 5;
834 break;
835 case 0x06: /* frwd */
836 iap_remotebtn = BUTTON_RC_LEFT;
837 iap_remotetick = false;
838 if(iap_pollspeed) iap_pollspeed = 5;
839 break;
840 case 0x07: /* end ffwd/frwd */
841 iap_remotebtn = BUTTON_NONE;
842 iap_remotetick = false;
843 if(iap_pollspeed) iap_pollspeed = 1;
844 break;
846 /* respond with cmd ok packet */
847 cmd_ok_mode4(cmd);
848 break;
851 /* GetShuffle */
852 case 0x002C:
854 /* ReturnShuffle */
855 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
856 data[3] = global_settings.playlist_shuffle ? 1 : 0;
857 iap_send_pkt(data, sizeof(data));
858 break;
861 /* SetShuffle */
862 case 0x002E:
864 if(buf[3] && !global_settings.playlist_shuffle)
866 global_settings.playlist_shuffle = 1;
867 settings_save();
868 if (audio_status() & AUDIO_STATUS_PLAY)
869 playlist_randomise(NULL, current_tick, true);
871 else if(!buf[3] && global_settings.playlist_shuffle)
873 global_settings.playlist_shuffle = 0;
874 settings_save();
875 if (audio_status() & AUDIO_STATUS_PLAY)
876 playlist_sort(NULL, true);
879 /* respond with cmd ok packet */
880 cmd_ok_mode4(cmd);
881 break;
884 /* GetRepeat */
885 case 0x002F:
887 /* ReturnRepeat */
888 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
889 if(global_settings.repeat_mode == REPEAT_OFF)
890 data[3] = 0;
891 else if(global_settings.repeat_mode == REPEAT_ONE)
892 data[3] = 1;
893 else
894 data[3] = 2;
895 iap_send_pkt(data, sizeof(data));
896 break;
899 /* SetRepeat */
900 case 0x0031:
902 int oldmode = global_settings.repeat_mode;
903 if (buf[3] == 0)
904 global_settings.repeat_mode = REPEAT_OFF;
905 else if (buf[3] == 1)
906 global_settings.repeat_mode = REPEAT_ONE;
907 else if (buf[3] == 2)
908 global_settings.repeat_mode = REPEAT_ALL;
910 if (oldmode != global_settings.repeat_mode)
912 settings_save();
913 if (audio_status() & AUDIO_STATUS_PLAY)
914 audio_flush_and_reload_tracks();
917 /* respond with cmd ok packet */
918 cmd_ok_mode4(cmd);
919 break;
922 /* GetMonoDisplayImageLimits */
923 case 0x0033:
925 /* ReturnMonoDisplayImageLimits */
926 unsigned char data[] = {0x04, 0x00, 0x34,
927 LCD_WIDTH >> 8, LCD_WIDTH & 0xff,
928 LCD_HEIGHT >> 8, LCD_HEIGHT & 0xff,
929 0x01};
930 iap_send_pkt(data, sizeof(data));
931 break;
934 /* GetNumPlayingTracks */
935 case 0x0035:
937 /* ReturnNumPlayingTracks */
938 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
939 unsigned long playlist_amt = playlist_amount();
940 put_u32(&data[3], playlist_amt);
941 iap_send_pkt(data, sizeof(data));
942 break;
945 /* SetCurrentPlayingTrack */
946 case 0x0037:
948 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
949 long tracknum = get_u32(&buf[3]);
951 audio_pause();
952 audio_skip(tracknum - playlist_next(0));
953 if (!paused)
954 audio_resume();
956 /* respond with cmd ok packet */
957 cmd_ok_mode4(cmd);
958 break;
961 default:
963 /* default response is with cmd ok packet */
964 cmd_ok_mode4(cmd);
965 break;
970 static void iap_handlepkt_mode7(unsigned int len, const unsigned char *buf)
972 unsigned int cmd = buf[1];
973 switch (cmd)
975 /* RetTunerCaps */
976 case 0x02:
978 /* do nothing */
980 /* GetAccessoryInfo */
981 unsigned char data[] = {0x00, 0x27, 0x00};
982 iap_send_pkt(data, sizeof(data));
983 break;
986 /* RetTunerFreq */
987 case 0x0A:
988 /* fall through */
989 /* TunerSeekDone */
990 case 0x13:
992 rmt_tuner_freq(len, buf);
993 break;
996 /* RdsReadyNotify, RDS station name 0x21 1E 00 + ASCII text*/
997 case 0x21:
999 rmt_tuner_rds_data(len, buf);
1000 break;
1005 void iap_handlepkt(void)
1007 if(!iap_setupflag) return;
1008 if(serbuf[0] == 0) return;
1010 /* if we are waiting for a remote button to go out,
1011 delay the handling of the new packet */
1012 if(!iap_remotetick)
1014 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
1015 return;
1018 /* get length and payload from serbuf */
1019 unsigned int len = serbuf[0];
1020 unsigned char *payload = &serbuf[1];
1022 unsigned char mode = payload[0];
1023 switch (mode) {
1024 case 0: iap_handlepkt_mode0(len, payload); break;
1025 case 2: iap_handlepkt_mode2(len, payload); break;
1026 case 3: iap_handlepkt_mode3(len, payload); break;
1027 case 4: iap_handlepkt_mode4(len, payload); break;
1028 case 7: iap_handlepkt_mode7(len, payload); break;
1031 serbuf[0] = 0;
1034 int remote_control_rx(void)
1036 int btn = iap_remotebtn;
1037 if(iap_repeatbtn)
1039 iap_repeatbtn--;
1040 if(!iap_repeatbtn)
1042 iap_remotebtn = BUTTON_NONE;
1043 iap_remotetick = true;
1046 else
1047 iap_remotetick = true;
1049 return btn;
1052 const unsigned char *iap_get_serbuf(void)
1054 return serbuf;