Rework of libfaad in several areas. Allow removal of malloc with a new define FAAD_ST...
[kugel-rb.git] / apps / iap.c
blobecf70b2e6979241ddb35ac3b7b3ab23f3a8fefb1
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 static volatile int iap_pollspeed = 0;
47 static volatile bool iap_remotetick = true;
48 static bool iap_setupflag = false, iap_updateflag = false;
49 static int iap_changedctr = 0;
51 static unsigned long iap_remotebtn = 0;
52 static int iap_repeatbtn = 0;
53 static bool iap_btnrepeat = false, iap_btnshuffle = false;
55 static unsigned char serbuf[RX_BUFLEN];
56 static int serbuf_i = 0;
58 static unsigned char response[TX_BUFLEN];
59 static int responselen;
61 static void iap_task(void)
63 static int count = 0;
65 count += iap_pollspeed;
66 if (count < (500/10)) return;
68 /* exec every 500ms if pollspeed == 1 */
69 count = 0;
70 queue_post(&button_queue, SYS_IAP_PERIODIC, 0);
73 /* called by playback when the next track starts */
74 static void iap_track_changed(void *ignored)
76 (void)ignored;
77 iap_changedctr = 1;
80 void iap_setup(int ratenum)
82 iap_bitrate_set(ratenum);
83 iap_pollspeed = 0;
84 iap_remotetick = true;
85 iap_updateflag = false;
86 iap_changedctr = 0;
87 iap_setupflag = true;
88 iap_remotebtn = BUTTON_NONE;
89 tick_add_task(iap_task);
90 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed);
93 void iap_bitrate_set(int ratenum)
95 switch(ratenum)
97 case 0:
98 serial_bitrate(0);
99 break;
100 case 1:
101 serial_bitrate(9600);
102 break;
103 case 2:
104 serial_bitrate(19200);
105 break;
106 case 3:
107 serial_bitrate(38400);
108 break;
109 case 4:
110 serial_bitrate(57600);
111 break;
115 /* Message format:
116 0xff
117 0x55
118 length
119 mode
120 command (2 bytes)
121 parameters (0-n bytes)
122 checksum (length+mode+parameters+checksum == 0)
125 void iap_send_pkt(const unsigned char * data, int len)
127 int i, chksum;
129 if(len > TX_BUFLEN-4) len = TX_BUFLEN-4;
130 responselen = len + 4;
132 response[0] = 0xFF;
133 response[1] = 0x55;
135 chksum = response[2] = len;
136 for(i = 0; i < len; i ++)
138 chksum += data[i];
139 response[i+3] = data[i];
142 response[i+3] = 0x100 - (chksum & 0xFF);
144 for(i = 0; i < responselen; i ++)
146 while (!tx_rdy()) ;
147 tx_writec(response[i]);
151 bool iap_getc(unsigned char x)
153 static unsigned char last_x = 0;
154 static bool newpkt = true;
155 static unsigned char chksum = 0;
157 /* Restart if the sync word is seen */
158 if(x == 0x55 && last_x == 0xff/* && newpkt*/)
160 serbuf[0] = 0;
161 serbuf_i = 0;
162 chksum = 0;
163 newpkt = false;
165 else
167 if(serbuf_i >= RX_BUFLEN)
168 serbuf_i = 0;
170 serbuf[serbuf_i++] = x;
171 chksum += x;
173 last_x = x;
175 /* Broadcast to queue if we have a complete message */
176 if(serbuf_i && (serbuf_i == serbuf[0]+2))
178 serbuf_i = 0;
179 newpkt = true;
180 if(chksum == 0)
181 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
183 return newpkt;
186 void iap_periodic(void)
188 if(!iap_setupflag) return;
189 if(!iap_pollspeed) return;
191 unsigned char data[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00};
192 unsigned long time_elapsed = audio_current_track()->elapsed;
194 time_elapsed += wps_get_ff_rewind_count();
196 data[3] = 0x04; /* playing */
198 /* If info has changed, don't flag it right away */
199 if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2)
201 /* track info has changed */
202 iap_changedctr = 0;
203 data[3] = 0x01; /* 0x02 has same effect? */
204 iap_updateflag = true;
207 data[4] = time_elapsed >> 24;
208 data[5] = time_elapsed >> 16;
209 data[6] = time_elapsed >> 8;
210 data[7] = time_elapsed;
211 iap_send_pkt(data, sizeof(data));
214 static void iap_set_remote_volume(void)
216 unsigned char data[] = {0x03, 0x0D, 0x04, 0x00, 0x00};
217 data[4] = (char)((global_settings.volume+58) * 4);
218 iap_send_pkt(data, sizeof(data));
221 static void cmd_ok_mode0(unsigned char cmd)
223 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
224 data[3] = cmd; /* respond with cmd */
225 iap_send_pkt(data, sizeof(data));
228 static void iap_handlepkt_mode0(void)
230 unsigned int cmd = serbuf[2];
231 switch (cmd) {
232 /* Identify */
233 case 0x01:
235 /* FM transmitter sends this: */
236 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
237 if(serbuf[3] == 0x05)
239 sleep(HZ/3);
240 /* RF Transmitter: Begin transmission */
241 unsigned char data[] = {0x05, 0x02};
242 iap_send_pkt(data, sizeof(data));
244 /* FM remote sends this: */
245 /* FF 55 03 00 01 02 FA (1st thing sent) */
246 else if(serbuf[3] == 0x02)
248 /* useful only for apple firmware */
250 break;
253 /* EnterRemoteUIMode, FM transmitter sends FF 55 02 00 05 F9 */
254 case 0x05:
256 /* ACK Pending (3000 ms) */
257 unsigned char data[] = {0x00, 0x02, 0x06,
258 0x05, 0x00, 0x00, 0x0B, 0xB8};
259 iap_send_pkt(data, sizeof(data));
260 cmd_ok_mode0(cmd);
261 break;
264 /* RequestiPodSoftwareVersion, Ipod FM remote sends FF 55 02 00 09 F5 */
265 case 0x09:
267 /* ReturniPodSoftwareVersion, ipod5G firmware version */
268 unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01};
269 iap_send_pkt(data, sizeof(data));
270 break;
273 /* RequestiPodModelNum */
274 case 0x0D:
276 /* ipod is supposed to work only with 5G and nano 2G */
277 /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34,
278 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */
279 /* ReturniPodModelNum */
280 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
281 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
282 iap_send_pkt(data, sizeof(data));
283 break;
286 /* RequestLingoProtocolVersion */
287 case 0x0F:
289 /* ReturnLingoProtocolVersion */
290 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
291 data[2] = serbuf[3];
292 iap_send_pkt(data, sizeof(data));
293 break;
296 /* IdentifyDeviceLingoes */
297 case 0x13:
299 cmd_ok_mode0(cmd);
301 if (serbuf[6] == 0x35)
302 /* FM transmitter sends this: */
303 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
305 /* GetAccessoryInfo */
306 unsigned char data2[] = {0x00, 0x27, 0x00};
307 iap_send_pkt(data2, sizeof(data2));
308 /* RF Transmitter: Begin transmission */
309 unsigned char data3[] = {0x05, 0x02};
310 iap_send_pkt(data3, sizeof(data3));
313 else
315 /* ipod fm remote sends this: */
316 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
317 if (serbuf[6] |= 0x80)
318 radio_present = 1;
319 /* GetDevAuthenticationInfo */
320 unsigned char data4[] = {0x00, 0x14};
321 iap_send_pkt(data4, sizeof(data4));
323 break;
326 /* RetDevAuthenticationInfo */
327 case 0x15:
329 /* AckDevAuthenticationInfo */
330 unsigned char data0[] = {0x00, 0x16, 0x00};
331 iap_send_pkt(data0, sizeof(data0));
332 /* GetAccessoryInfo */
333 unsigned char data1[] = {0x00, 0x27, 0x00};
334 iap_send_pkt(data1, sizeof(data1));
335 /* AckDevAuthenticationStatus, mandatory to enable some hardware */
336 unsigned char data2[] = {0x00, 0x19, 0x00};
337 iap_send_pkt(data2, sizeof(data2));
338 if (radio_present == 1)
340 /* GetTunerCaps */
341 unsigned char data3[] = {0x07, 0x01};
342 iap_send_pkt(data3, sizeof(data3));
344 iap_set_remote_volume();
345 break;
348 /* RetDevAuthenticationSignature */
349 case 0x18:
351 /* Isn't used since we don't send the 0x00 0x17 command */
352 break;
355 /* GetIpodOptions */
356 case 0x24:
358 /* RetIpodOptions (ipod video send this) */
359 unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00,
360 0x00, 0x00, 0x00, 0x00, 0x01};
361 iap_send_pkt(data, sizeof(data));
362 break;
365 /* default response is with cmd ok packet */
366 default:
368 cmd_ok_mode0(cmd);
369 break;
374 static void iap_handlepkt_mode2(void)
376 if(serbuf[2] != 0) return;
377 iap_remotebtn = BUTTON_NONE;
378 iap_remotetick = false;
380 if(serbuf[0] >= 3 && serbuf[3] != 0)
382 if(serbuf[3] & 1)
383 iap_remotebtn |= BUTTON_RC_PLAY;
384 if(serbuf[3] & 2)
385 iap_remotebtn |= BUTTON_RC_VOL_UP;
386 if(serbuf[3] & 4)
387 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
388 if(serbuf[3] & 8)
389 iap_remotebtn |= BUTTON_RC_RIGHT;
390 if(serbuf[3] & 16)
391 iap_remotebtn |= BUTTON_RC_LEFT;
393 else if(serbuf[0] >= 4 && serbuf[4] != 0)
395 if(serbuf[4] & 1) /* play */
397 if (audio_status() != AUDIO_STATUS_PLAY)
399 iap_remotebtn |= BUTTON_RC_PLAY;
400 iap_repeatbtn = 2;
401 iap_remotetick = false;
402 iap_changedctr = 1;
405 if(serbuf[4] & 2) /* pause */
407 if (audio_status() == AUDIO_STATUS_PLAY)
409 iap_remotebtn |= BUTTON_RC_PLAY;
410 iap_repeatbtn = 2;
411 iap_remotetick = false;
412 iap_changedctr = 1;
415 if((serbuf[4] & 128) && !iap_btnshuffle) /* shuffle */
417 iap_btnshuffle = true;
418 if(!global_settings.playlist_shuffle)
420 global_settings.playlist_shuffle = 1;
421 settings_save();
422 if (audio_status() & AUDIO_STATUS_PLAY)
423 playlist_randomise(NULL, current_tick, true);
425 else if(global_settings.playlist_shuffle)
427 global_settings.playlist_shuffle = 0;
428 settings_save();
429 if (audio_status() & AUDIO_STATUS_PLAY)
430 playlist_sort(NULL, true);
433 else
434 iap_btnshuffle = false;
436 else if(serbuf[0] >= 5 && serbuf[5] != 0)
438 if((serbuf[5] & 1) && !iap_btnrepeat) /* repeat */
440 int oldmode = global_settings.repeat_mode;
441 iap_btnrepeat = true;
443 if (oldmode == REPEAT_ONE)
444 global_settings.repeat_mode = REPEAT_OFF;
445 else if (oldmode == REPEAT_ALL)
446 global_settings.repeat_mode = REPEAT_ONE;
447 else if (oldmode == REPEAT_OFF)
448 global_settings.repeat_mode = REPEAT_ALL;
450 settings_save();
451 if (audio_status() & AUDIO_STATUS_PLAY)
452 audio_flush_and_reload_tracks();
454 else
455 iap_btnrepeat = false;
457 if(serbuf[5] & 16) /* ffwd */
459 iap_remotebtn |= BUTTON_RC_RIGHT;
461 if(serbuf[5] & 32) /* frwd */
463 iap_remotebtn |= BUTTON_RC_LEFT;
468 static void iap_handlepkt_mode3(void)
470 unsigned int cmd = serbuf[2];
471 switch (cmd)
473 /* some kind of status packet? */
474 case 0x01:
476 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
477 iap_send_pkt(data, sizeof(data));
478 break;
481 case 0x08:
483 /* ACK */
484 unsigned char data[] = {0x03, 0x00, 0x00, 0x08};
485 iap_send_pkt(data, sizeof(data));
486 break;
489 case 0x0C:
491 /* request ipod volume */
492 if (serbuf[3] == 0x04)
494 iap_set_remote_volume();
496 break;
498 /* get volume from accessory */
499 case 0x0E:
501 if (serbuf[3] == 0x04)
502 global_settings.volume = (-58)+((int)serbuf[5]+1)/4;
503 sound_set_volume(global_settings.volume); /* indent BUG? */
504 break;
509 static void cmd_ok_mode4(unsigned int cmd)
511 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
512 data[4] = (cmd >> 8) & 0xFF;
513 data[5] = (cmd >> 0) & 0xFF;
514 iap_send_pkt(data, sizeof(data));
517 static void iap_handlepkt_mode4(void)
519 unsigned int cmd = (serbuf[2] << 8) | serbuf[3];
520 switch (cmd)
522 /* Get data updated??? flag */
523 case 0x0009:
525 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
526 data[3] = iap_updateflag ? 0 : 1;
527 iap_send_pkt(data, sizeof(data));
528 break;
530 /* Set data updated??? flag */
531 case 0x000B:
533 iap_updateflag = serbuf[4] ? 0 : 1;
534 /* respond with cmd ok packet */
535 cmd_ok_mode4(cmd);
536 break;
538 /* Get iPod size? */
539 case 0x0012:
541 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
542 iap_send_pkt(data, sizeof(data));
543 break;
545 /* Get count of given types */
546 case 0x0018:
548 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
549 unsigned long num = 0;
550 switch(serbuf[4]) /* type number */
552 case 0x01: /* total number of playlists */
553 num = 1;
554 break;
555 case 0x05: /* total number of songs */
556 num = 1;
558 data[3] = num >> 24;
559 data[4] = num >> 16;
560 data[5] = num >> 8;
561 data[6] = num;
562 iap_send_pkt(data, sizeof(data));
563 break;
565 /* Get time and status */
566 case 0x001C:
568 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
569 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
570 struct mp3entry *id3 = audio_current_track();
571 unsigned long time_total = id3->length;
572 unsigned long time_elapsed = id3->elapsed;
573 int status = audio_status();
574 data[3] = time_total >> 24;
575 data[4] = time_total >> 16;
576 data[5] = time_total >> 8;
577 data[6] = time_total;
578 data[7] = time_elapsed >> 24;
579 data[8] = time_elapsed >> 16;
580 data[9] = time_elapsed >> 8;
581 data[10] = time_elapsed;
582 if (status == AUDIO_STATUS_PLAY)
583 data[11] = 0x01; /* play */
584 else if (status & AUDIO_STATUS_PAUSE)
585 data[11] = 0x02; /* pause */
586 iap_send_pkt(data, sizeof(data));
587 break;
589 /* Get current pos in playlist */
590 case 0x001E:
592 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
593 long playlist_pos = playlist_next(0);
594 playlist_pos -= playlist_get_first_index(NULL);
595 if(playlist_pos < 0)
596 playlist_pos += playlist_amount();
597 data[3] = playlist_pos >> 24;
598 data[4] = playlist_pos >> 16;
599 data[5] = playlist_pos >> 8;
600 data[6] = playlist_pos;
601 iap_send_pkt(data, sizeof(data));
602 break;
604 /* Get title of a song number */
605 case 0x0020:
606 /* Get artist of a song number */
607 case 0x0022:
608 /* Get album of a song number */
609 case 0x0024:
611 unsigned char data[70] = {0x04, 0x00, 0xFF};
612 struct mp3entry id3;
613 int fd;
614 size_t len;
615 long tracknum = (signed long)serbuf[4] << 24 |
616 (signed long)serbuf[5] << 16 |
617 (signed long)serbuf[6] << 8 | serbuf[7];
618 data[2] = serbuf[3] + 1;
619 memcpy(&id3, audio_current_track(), sizeof(id3));
620 tracknum += playlist_get_first_index(NULL);
621 if(tracknum >= playlist_amount())
622 tracknum -= playlist_amount();
624 /* If the tracknumber is not the current one,
625 read id3 from disk */
626 if(playlist_next(0) != tracknum)
628 struct playlist_track_info info;
629 playlist_get_track_info(NULL, tracknum, &info);
630 fd = open(info.filename, O_RDONLY);
631 memset(&id3, 0, sizeof(struct mp3entry));
632 get_metadata(&id3, fd, info.filename);
633 close(fd);
636 /* Return the requested track data */
637 switch(serbuf[3])
639 case 0x20:
640 len = strlcpy((char *)&data[3], id3.title, 64);
641 iap_send_pkt(data, 4+len);
642 break;
643 case 0x22:
644 len = strlcpy((char *)&data[3], id3.artist, 64);
645 iap_send_pkt(data, 4+len);
646 break;
647 case 0x24:
648 len = strlcpy((char *)&data[3], id3.album, 64);
649 iap_send_pkt(data, 4+len);
650 break;
652 break;
654 /* Set polling mode */
655 case 0x0026:
657 iap_pollspeed = serbuf[4] ? 1 : 0;
658 /*respond with cmd ok packet */
659 cmd_ok_mode4(cmd);
660 break;
662 /* AiR playback control */
663 case 0x0029:
665 /* respond with cmd ok packet */
666 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
667 iap_send_pkt(data, sizeof(data));
668 switch(serbuf[4])
670 case 0x01: /* play/pause */
671 iap_remotebtn = BUTTON_RC_PLAY;
672 iap_repeatbtn = 2;
673 iap_remotetick = false;
674 iap_changedctr = 1;
675 break;
676 case 0x02: /* stop */
677 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
678 iap_repeatbtn = 2;
679 iap_remotetick = false;
680 iap_changedctr = 1;
681 break;
682 case 0x03: /* skip++ */
683 iap_remotebtn = BUTTON_RC_RIGHT;
684 iap_repeatbtn = 2;
685 iap_remotetick = false;
686 break;
687 case 0x04: /* skip-- */
688 iap_remotebtn = BUTTON_RC_LEFT;
689 iap_repeatbtn = 2;
690 iap_remotetick = false;
691 break;
692 case 0x05: /* ffwd */
693 iap_remotebtn = BUTTON_RC_RIGHT;
694 iap_remotetick = false;
695 if(iap_pollspeed) iap_pollspeed = 5;
696 break;
697 case 0x06: /* frwd */
698 iap_remotebtn = BUTTON_RC_LEFT;
699 iap_remotetick = false;
700 if(iap_pollspeed) iap_pollspeed = 5;
701 break;
702 case 0x07: /* end ffwd/frwd */
703 iap_remotebtn = BUTTON_NONE;
704 iap_remotetick = false;
705 if(iap_pollspeed) iap_pollspeed = 1;
706 break;
708 break;
710 /* Get shuffle mode */
711 case 0x002C:
713 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
714 data[3] = global_settings.playlist_shuffle ? 1 : 0;
715 iap_send_pkt(data, sizeof(data));
716 break;
718 /* Set shuffle mode */
719 case 0x002E:
721 if(serbuf[4] && !global_settings.playlist_shuffle)
723 global_settings.playlist_shuffle = 1;
724 settings_save();
725 if (audio_status() & AUDIO_STATUS_PLAY)
726 playlist_randomise(NULL, current_tick, true);
728 else if(!serbuf[4] && global_settings.playlist_shuffle)
730 global_settings.playlist_shuffle = 0;
731 settings_save();
732 if (audio_status() & AUDIO_STATUS_PLAY)
733 playlist_sort(NULL, true);
737 /* respond with cmd ok packet */
738 cmd_ok_mode4(cmd);
739 break;
741 /* Get repeat mode */
742 case 0x002F:
744 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
745 if(global_settings.repeat_mode == REPEAT_OFF)
746 data[3] = 0;
747 else if(global_settings.repeat_mode == REPEAT_ONE)
748 data[3] = 1;
749 else
750 data[3] = 2;
751 iap_send_pkt(data, sizeof(data));
752 break;
754 /* Set repeat mode */
755 case 0x0031:
757 int oldmode = global_settings.repeat_mode;
758 if (serbuf[4] == 0)
759 global_settings.repeat_mode = REPEAT_OFF;
760 else if (serbuf[4] == 1)
761 global_settings.repeat_mode = REPEAT_ONE;
762 else if (serbuf[4] == 2)
763 global_settings.repeat_mode = REPEAT_ALL;
765 if (oldmode != global_settings.repeat_mode)
767 settings_save();
768 if (audio_status() & AUDIO_STATUS_PLAY)
769 audio_flush_and_reload_tracks();
772 /* respond with cmd ok packet */
773 cmd_ok_mode4(cmd);
774 break;
776 /* Get Screen Size */
777 case 0x0033:
779 unsigned char data[] = {0x04, 0x00, 0x34,
780 LCD_WIDTH >> 8, LCD_WIDTH & 0xff,
781 LCD_HEIGHT >> 8, LCD_HEIGHT & 0xff,
782 0x01};
783 iap_send_pkt(data, sizeof(data));
784 break;
786 /* Get number songs in current playlist */
787 case 0x0035:
789 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
790 unsigned long playlist_amt = playlist_amount();
791 data[3] = playlist_amt >> 24;
792 data[4] = playlist_amt >> 16;
793 data[5] = playlist_amt >> 8;
794 data[6] = playlist_amt;
795 iap_send_pkt(data, sizeof(data));
796 break;
798 /* Jump to track number in current playlist */
799 case 0x0037:
801 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
802 long tracknum = (signed long)serbuf[4] << 24 |
803 (signed long)serbuf[5] << 16 |
804 (signed long)serbuf[6] << 8 | serbuf[7];
805 audio_pause();
806 audio_skip(tracknum - playlist_next(0));
807 if (!paused)
808 audio_resume();
810 /* respond with cmd ok packet */
811 cmd_ok_mode4(cmd);
812 break;
814 default:
816 /* default response is with cmd ok packet */
817 cmd_ok_mode4(cmd);
818 break;
823 static void iap_handlepkt_mode7(void)
825 unsigned int cmd = serbuf[2];
826 switch (cmd)
828 /* tuner capabilities */
829 case 0x02:
831 /* do nothing */
833 unsigned char data[] = {0x00, 0x27, 0x00};
834 iap_send_pkt(data, sizeof(data));
835 break;
837 /* actual tuner frequency */
838 case 0x0A:
839 /* fall through */
840 /* tuner frequency from scan */
841 case 0x13:
843 rmt_tuner_freq(serbuf);
844 break;
846 /* RDS station name 0x21 1E 00 + ASCII text*/
847 case 0x21:
849 rmt_tuner_rds_data(serbuf);
850 break;
855 void iap_handlepkt(void)
858 if(!iap_setupflag) return;
859 if(serbuf[0] == 0) return;
861 /* if we are waiting for a remote button to go out,
862 delay the handling of the new packet */
863 if(!iap_remotetick)
865 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
866 return;
869 unsigned char mode = serbuf[1];
870 switch (mode) {
871 case 0: iap_handlepkt_mode0(); break;
872 case 2: iap_handlepkt_mode2(); break;
873 case 3: iap_handlepkt_mode3(); break;
874 case 4: iap_handlepkt_mode4(); break;
875 case 7: iap_handlepkt_mode7(); break;
878 serbuf[0] = 0;
881 int remote_control_rx(void)
883 int btn = iap_remotebtn;
884 if(iap_repeatbtn)
886 iap_repeatbtn--;
887 if(!iap_repeatbtn)
889 iap_remotebtn = BUTTON_NONE;
890 iap_remotetick = true;
893 else
894 iap_remotetick = true;
896 return btn;
899 const unsigned char *iap_get_serbuf(void)
901 return serbuf;