fix yellow
[maemo-rb.git] / apps / iap.c
blobd432a16dc38ec4e2e655618ed90299a38e3b1799
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 void iap_handlepkt(void)
224 if(!iap_setupflag) return;
225 if(serbuf[0] == 0) return;
227 /* if we are waiting for a remote button to go out,
228 delay the handling of the new packet */
229 if(!iap_remotetick)
231 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
232 return;
235 /* Handle Mode 0 */
236 if (serbuf[1] == 0x00)
238 switch (serbuf[2])
240 case 0x24:
242 /* ipod video send this */
243 unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00,
244 0x00, 0x00, 0x00, 0x00,0x01};
245 iap_send_pkt(data, sizeof(data));
246 break;
249 case 0x18:
251 /* ciphered authentication command */
252 /* Isn't used since we don't send the 0x00 0x17 command */
253 break;
256 case 0x15:
258 unsigned char data0[] = {0x00, 0x16, 0x00};
259 iap_send_pkt(data0, sizeof(data0));
260 unsigned char data1[] = {0x00, 0x27, 0x00};
261 iap_send_pkt(data1, sizeof(data1));
262 /* authentication ack, mandatory to enable some hardware */
263 unsigned char data2[] = {0x00, 0x19, 0x00};
264 iap_send_pkt(data2, sizeof(data2));
265 if (radio_present == 1)
267 /* get tuner capacities */
268 unsigned char data3[] = {0x07, 0x01};
269 iap_send_pkt(data3, sizeof(data3));
271 iap_set_remote_volume();
272 break;
275 case 0x13:
277 unsigned char data[] = {0x00, 0x02, 0x00, 0x13};
278 iap_send_pkt(data, sizeof(data));
280 if (serbuf[6] == 0x35)
281 /* FM transmitter sends this: */
282 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
284 unsigned char data2[] = {0x00, 0x27, 0x00};
285 iap_send_pkt(data2, sizeof(data2));
286 unsigned char data3[] = {0x05, 0x02};
287 iap_send_pkt(data3, sizeof(data3));
290 else
292 /* ipod fm remote sends this: */
293 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
294 if (serbuf[6] |= 0x80)
295 radio_present = 1;
296 unsigned char data4[] = {0x00, 0x14};
297 iap_send_pkt(data4, sizeof(data4));
299 break;
302 /* Init */
303 case 0x0F:
305 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
306 data[2] = serbuf[3];
307 iap_send_pkt(data, sizeof(data));
308 break;
311 /* get model info */
312 case 0x0D:
314 /* ipod is supposed to work only with 5G and nano 2G */
315 /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34,
316 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */
317 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
318 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
319 iap_send_pkt(data, sizeof(data));
320 break;
323 /* Ipod FM remote sends this: FF 55 02 00 09 F5 */
324 case 0x09:
326 /* ipod5G firmware version */
327 unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01 };
328 iap_send_pkt(data, sizeof(data));
329 break;
332 /* FM transmitter sends this: */
333 /* FF 55 02 00 05 F9 (mode switch: AiR mode) */
334 case 0x05:
336 unsigned char data[] = {0x00, 0x02, 0x06,
337 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28};
338 iap_send_pkt(data, sizeof(data));
339 unsigned char data2[] = {0x00, 0x02, 0x00, 0x05};
340 iap_send_pkt(data2, sizeof(data2));
341 break;
344 case 0x01:
346 /* FM transmitter sends this: */
347 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
348 if(serbuf[3] == 0x05)
350 sleep(HZ/3);
351 unsigned char data[] = {0x05, 0x02};
352 iap_send_pkt(data, sizeof(data));
354 /* FM remote sends this: */
355 /* FF 55 03 00 01 02 FA (1st thing sent) */
356 else if(serbuf[3] == 0x02)
358 /* useful only for apple firmware */
360 break;
363 /* default response is with cmd ok packet */
364 default:
366 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
367 data[3] = serbuf[2]; /* respond with cmd */
368 iap_send_pkt(data, sizeof(data));
369 break;
373 /* Handle Mode 2 */
374 else if (serbuf[1] == 0x02)
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;
467 /* Handle Mode 3 */
468 else if (serbuf[1] == 0x03)
470 switch(serbuf[2])
472 /* some kind of status packet? */
473 case 0x01:
475 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
476 iap_send_pkt(data, sizeof(data));
477 break;
480 case 0x08:
482 /* ACK */
483 unsigned char data[] = {0x03, 0x00, 0x00, 0x08};
484 iap_send_pkt(data, sizeof(data));
485 break;
488 case 0x0C:
490 /* request ipod volume */
491 if (serbuf[3] == 0x04)
493 iap_set_remote_volume();
495 break;
497 /* get volume from accessory */
498 case 0x0E:
499 if (serbuf[3] == 0x04)
500 global_settings.volume = (-58)+((int)serbuf[5]+1)/4;
501 sound_set_volume(global_settings.volume);
502 break;
505 /* Handle Mode 4 */
506 else if (serbuf[1] == 0x04)
508 switch (((unsigned long)serbuf[2] << 8) | serbuf[3])
510 /* Get data updated??? flag */
511 case 0x0009:
513 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
514 data[3] = iap_updateflag ? 0 : 1;
515 iap_send_pkt(data, sizeof(data));
516 break;
518 /* Set data updated??? flag */
519 case 0x000B:
521 iap_updateflag = serbuf[4] ? 0 : 1;
522 /* respond with cmd ok packet */
523 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x0B};
524 iap_send_pkt(data, sizeof(data));
525 break;
527 /* Get iPod size? */
528 case 0x0012:
530 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
531 iap_send_pkt(data, sizeof(data));
532 break;
534 /* Get count of given types */
535 case 0x0018:
537 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
538 unsigned long num = 0;
539 switch(serbuf[4]) /* type number */
541 case 0x01: /* total number of playlists */
542 num = 1;
543 break;
544 case 0x05: /* total number of songs */
545 num = 1;
547 data[3] = num >> 24;
548 data[4] = num >> 16;
549 data[5] = num >> 8;
550 data[6] = num;
551 iap_send_pkt(data, sizeof(data));
552 break;
554 /* Get time and status */
555 case 0x001C:
557 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
558 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
559 struct mp3entry *id3 = audio_current_track();
560 unsigned long time_total = id3->length;
561 unsigned long time_elapsed = id3->elapsed;
562 int status = audio_status();
563 data[3] = time_total >> 24;
564 data[4] = time_total >> 16;
565 data[5] = time_total >> 8;
566 data[6] = time_total;
567 data[7] = time_elapsed >> 24;
568 data[8] = time_elapsed >> 16;
569 data[9] = time_elapsed >> 8;
570 data[10] = time_elapsed;
571 if (status == AUDIO_STATUS_PLAY)
572 data[11] = 0x01; /* play */
573 else if (status & AUDIO_STATUS_PAUSE)
574 data[11] = 0x02; /* pause */
575 iap_send_pkt(data, sizeof(data));
576 break;
578 /* Get current pos in playlist */
579 case 0x001E:
581 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
582 long playlist_pos = playlist_next(0);
583 playlist_pos -= playlist_get_first_index(NULL);
584 if(playlist_pos < 0)
585 playlist_pos += playlist_amount();
586 data[3] = playlist_pos >> 24;
587 data[4] = playlist_pos >> 16;
588 data[5] = playlist_pos >> 8;
589 data[6] = playlist_pos;
590 iap_send_pkt(data, sizeof(data));
591 break;
593 /* Get title of a song number */
594 case 0x0020:
595 /* Get artist of a song number */
596 case 0x0022:
597 /* Get album of a song number */
598 case 0x0024:
600 unsigned char data[70] = {0x04, 0x00, 0xFF};
601 struct mp3entry id3;
602 int fd;
603 size_t len;
604 long tracknum = (signed long)serbuf[4] << 24 |
605 (signed long)serbuf[5] << 16 |
606 (signed long)serbuf[6] << 8 | serbuf[7];
607 data[2] = serbuf[3] + 1;
608 memcpy(&id3, audio_current_track(), sizeof(id3));
609 tracknum += playlist_get_first_index(NULL);
610 if(tracknum >= playlist_amount())
611 tracknum -= playlist_amount();
613 /* If the tracknumber is not the current one,
614 read id3 from disk */
615 if(playlist_next(0) != tracknum)
617 struct playlist_track_info info;
618 playlist_get_track_info(NULL, tracknum, &info);
619 fd = open(info.filename, O_RDONLY);
620 memset(&id3, 0, sizeof(struct mp3entry));
621 get_metadata(&id3, fd, info.filename);
622 close(fd);
625 /* Return the requested track data */
626 switch(serbuf[3])
628 case 0x20:
629 len = strlcpy((char *)&data[3], id3.title, 64);
630 iap_send_pkt(data, 4+len);
631 break;
632 case 0x22:
633 len = strlcpy((char *)&data[3], id3.artist, 64);
634 iap_send_pkt(data, 4+len);
635 break;
636 case 0x24:
637 len = strlcpy((char *)&data[3], id3.album, 64);
638 iap_send_pkt(data, 4+len);
639 break;
641 break;
643 /* Set polling mode */
644 case 0x0026:
646 iap_pollspeed = serbuf[4] ? 1 : 0;
647 /*responsed with cmd ok packet */
648 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x26};
649 iap_send_pkt(data, sizeof(data));
650 break;
652 /* AiR playback control */
653 case 0x0029:
655 /* respond with cmd ok packet */
656 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
657 iap_send_pkt(data, sizeof(data));
658 switch(serbuf[4])
660 case 0x01: /* play/pause */
661 iap_remotebtn = BUTTON_RC_PLAY;
662 iap_repeatbtn = 2;
663 iap_remotetick = false;
664 iap_changedctr = 1;
665 break;
666 case 0x02: /* stop */
667 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
668 iap_repeatbtn = 2;
669 iap_remotetick = false;
670 iap_changedctr = 1;
671 break;
672 case 0x03: /* skip++ */
673 iap_remotebtn = BUTTON_RC_RIGHT;
674 iap_repeatbtn = 2;
675 iap_remotetick = false;
676 break;
677 case 0x04: /* skip-- */
678 iap_remotebtn = BUTTON_RC_LEFT;
679 iap_repeatbtn = 2;
680 iap_remotetick = false;
681 break;
682 case 0x05: /* ffwd */
683 iap_remotebtn = BUTTON_RC_RIGHT;
684 iap_remotetick = false;
685 if(iap_pollspeed) iap_pollspeed = 5;
686 break;
687 case 0x06: /* frwd */
688 iap_remotebtn = BUTTON_RC_LEFT;
689 iap_remotetick = false;
690 if(iap_pollspeed) iap_pollspeed = 5;
691 break;
692 case 0x07: /* end ffwd/frwd */
693 iap_remotebtn = BUTTON_NONE;
694 iap_remotetick = false;
695 if(iap_pollspeed) iap_pollspeed = 1;
696 break;
698 break;
700 /* Get shuffle mode */
701 case 0x002C:
703 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
704 data[3] = global_settings.playlist_shuffle ? 1 : 0;
705 iap_send_pkt(data, sizeof(data));
706 break;
708 /* Set shuffle mode */
709 case 0x002E:
711 if(serbuf[4] && !global_settings.playlist_shuffle)
713 global_settings.playlist_shuffle = 1;
714 settings_save();
715 if (audio_status() & AUDIO_STATUS_PLAY)
716 playlist_randomise(NULL, current_tick, true);
718 else if(!serbuf[4] && global_settings.playlist_shuffle)
720 global_settings.playlist_shuffle = 0;
721 settings_save();
722 if (audio_status() & AUDIO_STATUS_PLAY)
723 playlist_sort(NULL, true);
727 /* respond with cmd ok packet */
728 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x2E};
729 iap_send_pkt(data, sizeof(data));
730 break;
732 /* Get repeat mode */
733 case 0x002F:
735 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
736 if(global_settings.repeat_mode == REPEAT_OFF)
737 data[3] = 0;
738 else if(global_settings.repeat_mode == REPEAT_ONE)
739 data[3] = 1;
740 else
741 data[3] = 2;
742 iap_send_pkt(data, sizeof(data));
743 break;
745 /* Set repeat mode */
746 case 0x0031:
748 int oldmode = global_settings.repeat_mode;
749 if (serbuf[4] == 0)
750 global_settings.repeat_mode = REPEAT_OFF;
751 else if (serbuf[4] == 1)
752 global_settings.repeat_mode = REPEAT_ONE;
753 else if (serbuf[4] == 2)
754 global_settings.repeat_mode = REPEAT_ALL;
756 if (oldmode != global_settings.repeat_mode)
758 settings_save();
759 if (audio_status() & AUDIO_STATUS_PLAY)
760 audio_flush_and_reload_tracks();
763 /* respond with cmd ok packet */
764 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x31};
765 iap_send_pkt(data, sizeof(data));
766 break;
768 /* Get Screen Size */
769 case 0x0033:
771 unsigned char data[] = {0x04, 0x00, 0x34,
772 LCD_WIDTH >> 8, LCD_WIDTH & 0xff,
773 LCD_HEIGHT >> 8, LCD_HEIGHT & 0xff,
774 0x01};
775 iap_send_pkt(data, sizeof(data));
776 break;
778 /* Get number songs in current playlist */
779 case 0x0035:
781 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
782 unsigned long playlist_amt = playlist_amount();
783 data[3] = playlist_amt >> 24;
784 data[4] = playlist_amt >> 16;
785 data[5] = playlist_amt >> 8;
786 data[6] = playlist_amt;
787 iap_send_pkt(data, sizeof(data));
788 break;
790 /* Jump to track number in current playlist */
791 case 0x0037:
793 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
794 long tracknum = (signed long)serbuf[4] << 24 |
795 (signed long)serbuf[5] << 16 |
796 (signed long)serbuf[6] << 8 | serbuf[7];
797 audio_pause();
798 audio_skip(tracknum - playlist_next(0));
799 if (!paused)
800 audio_resume();
802 /* respond with cmd ok packet */
803 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
804 data[4] = serbuf[2];
805 data[5] = serbuf[3];
806 iap_send_pkt(data, sizeof(data));
807 break;
809 default:
811 /* default response is with cmd ok packet */
812 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
813 data[4] = serbuf[2];
814 data[5] = serbuf[3];
815 iap_send_pkt(data, sizeof(data));
816 break;
820 /* Handle Mode 7 */
821 else if (serbuf[1] == 0x07)
823 switch(serbuf[2])
825 /* tuner capabilities */
826 case 0x02:
828 /* do nothing */
830 unsigned char data[] = {0x00, 0x27, 0x00};
831 iap_send_pkt(data, sizeof(data));
832 break;
834 /* actual tuner frequency */
835 case 0x0A:
836 /* fall through */
837 /* tuner frequency from scan */
838 case 0x13:
840 rmt_tuner_freq(serbuf);
841 break;
843 /* RDS station name 0x21 1E 00 + ASCII text*/
844 case 0x21:
846 rmt_tuner_rds_data(serbuf);
847 break;
851 serbuf[0] = 0;
854 int remote_control_rx(void)
856 int btn = iap_remotebtn;
857 if(iap_repeatbtn)
859 iap_repeatbtn--;
860 if(!iap_repeatbtn)
862 iap_remotebtn = BUTTON_NONE;
863 iap_remotetick = true;
866 else
867 iap_remotetick = true;
869 return btn;
872 const unsigned char *iap_get_serbuf(void)
874 return serbuf;