some minor changes to checkwps, shouldn't change anything
[kugel-rb.git] / apps / iap.c
blob741ff9fb0c75e93946141ebb36c97969c8fa6328
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 <memory.h>
23 #include <string.h>
25 #include "iap.h"
26 #include "button.h"
27 #include "config.h"
28 #include "cpu.h"
29 #include "system.h"
30 #include "kernel.h"
31 #include "serial.h"
32 #include "appevents.h"
34 #include "playlist.h"
35 #include "playback.h"
36 #include "audio.h"
37 #include "settings.h"
38 #include "metadata.h"
39 #include "wps.h"
40 #include "sound.h"
41 #include "action.h"
42 #include "powermgmt.h"
44 #include "tuner.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)
64 static int count = 0;
66 count += iap_pollspeed;
67 if (count < (500/10)) return;
69 /* exec every 500ms if pollspeed == 1 */
70 count = 0;
71 queue_post(&button_queue, SYS_IAP_PERIODIC, 0);
74 void iap_setup(int ratenum)
76 iap_bitrate_set(ratenum);
77 iap_pollspeed = 0;
78 iap_remotetick = true;
79 iap_updateflag = false;
80 iap_changedctr = 0;
81 iap_setupflag = true;
82 iap_remotebtn = BUTTON_NONE;
83 tick_add_task(iap_task);
84 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed);
87 void iap_bitrate_set(int ratenum)
89 switch(ratenum)
91 case 0:
92 serial_bitrate(0);
93 break;
94 case 1:
95 serial_bitrate(9600);
96 break;
97 case 2:
98 serial_bitrate(19200);
99 break;
100 case 3:
101 serial_bitrate(38400);
102 break;
103 case 4:
104 serial_bitrate(57600);
105 break;
109 /* Message format:
110 0xff
111 0x55
112 length
113 mode
114 command (2 bytes)
115 parameters (0-n bytes)
116 checksum (length+mode+parameters+checksum == 0)
119 void iap_send_pkt(const unsigned char * data, int len)
121 int i, chksum;
123 if(len > TX_BUFLEN-4) len = TX_BUFLEN-4;
124 responselen = len + 4;
126 response[0] = 0xFF;
127 response[1] = 0x55;
129 chksum = response[2] = len;
130 for(i = 0; i < len; i ++)
132 chksum += data[i];
133 response[i+3] = data[i];
136 response[i+3] = 0x100 - (chksum & 0xFF);
138 for(i = 0; i < responselen; i ++)
140 while (!tx_rdy()) ;
141 tx_writec(response[i]);
145 int iap_getc(unsigned char x)
147 static unsigned char last_x = 0;
148 static bool newpkt = true;
149 static unsigned char chksum = 0;
151 /* Restart if the sync word is seen */
152 if(x == 0x55 && last_x == 0xff/* && newpkt*/)
154 serbuf[0] = 0;
155 serbuf_i = 0;
156 chksum = 0;
157 newpkt = false;
159 else
161 if(serbuf_i >= RX_BUFLEN)
162 serbuf_i = 0;
164 serbuf[serbuf_i++] = x;
165 chksum += x;
167 last_x = x;
169 /* Broadcast to queue if we have a complete message */
170 if(serbuf_i && (serbuf_i == serbuf[0]+2))
172 serbuf_i = 0;
173 newpkt = true;
174 if(chksum == 0)
175 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
177 return newpkt;
180 /* called by playback when the next track starts */
181 void iap_track_changed(void *ignored)
183 (void)ignored;
184 iap_changedctr = 1;
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 */
203 iap_changedctr = 0;
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 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 */
230 if(!iap_remotetick)
232 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
233 return;
236 /* Handle Mode 0 */
237 if (serbuf[1] == 0x00)
239 switch (serbuf[2])
241 case 0x24:
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));
247 break;
250 case 0x18:
252 /* ciphered authentication command */
253 /* Isn't used since we don't send the 0x00 0x17 command */
254 break;
257 case 0x15:
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();
273 break;
276 case 0x13:
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));
291 else
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)
296 radio_present = 1;
297 unsigned char data4[] = {0x00, 0x14};
298 iap_send_pkt(data4, sizeof(data4));
300 break;
303 /* Init */
304 case 0x0F:
306 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
307 data[2] = serbuf[3];
308 iap_send_pkt(data, sizeof(data));
309 break;
312 /* get model info */
313 case 0x0D:
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));
321 break;
324 /* Ipod FM remote sends this: FF 55 02 00 09 F5 */
325 case 0x09:
327 /* ipod5G firmware version */
328 unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01 };
329 iap_send_pkt(data, sizeof(data));
330 break;
333 /* FM transmitter sends this: */
334 /* FF 55 02 00 05 F9 (mode switch: AiR mode) */
335 case 0x05:
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));
342 break;
345 case 0x01:
347 /* FM transmitter sends this: */
348 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
349 if(serbuf[3] == 0x05)
351 sleep(HZ/3);
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 */
361 break;
364 /* default response is with cmd ok packet */
365 default:
367 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
368 data[3] = serbuf[2]; /* respond with cmd */
369 iap_send_pkt(data, sizeof(data));
370 break;
374 /* Handle Mode 2 */
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)
383 if(serbuf[3] & 1)
384 iap_remotebtn |= BUTTON_RC_PLAY;
385 if(serbuf[3] & 2)
386 iap_remotebtn |= BUTTON_RC_VOL_UP;
387 if(serbuf[3] & 4)
388 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
389 if(serbuf[3] & 8)
390 iap_remotebtn |= BUTTON_RC_RIGHT;
391 if(serbuf[3] & 16)
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;
401 iap_repeatbtn = 2;
402 iap_remotetick = false;
403 iap_changedctr = 1;
406 if(serbuf[4] & 2) /* pause */
408 if (audio_status() == AUDIO_STATUS_PLAY)
410 iap_remotebtn |= BUTTON_RC_PLAY;
411 iap_repeatbtn = 2;
412 iap_remotetick = false;
413 iap_changedctr = 1;
416 if((serbuf[4] & 128) && !iap_btnshuffle) /* shuffle */
418 iap_btnshuffle = true;
419 if(!global_settings.playlist_shuffle)
421 global_settings.playlist_shuffle = 1;
422 settings_save();
423 settings_apply(false);
424 if (audio_status() & AUDIO_STATUS_PLAY)
425 playlist_randomise(NULL, current_tick, true);
427 else if(global_settings.playlist_shuffle)
429 global_settings.playlist_shuffle = 0;
430 settings_save();
431 settings_apply(false);
432 if (audio_status() & AUDIO_STATUS_PLAY)
433 playlist_sort(NULL, true);
436 else
437 iap_btnshuffle = false;
439 else if(serbuf[0] >= 5 && serbuf[5] != 0)
441 if((serbuf[5] & 1) && !iap_btnrepeat) /* repeat */
443 int oldmode = global_settings.repeat_mode;
444 iap_btnrepeat = true;
446 if (oldmode == REPEAT_ONE)
447 global_settings.repeat_mode = REPEAT_OFF;
448 else if (oldmode == REPEAT_ALL)
449 global_settings.repeat_mode = REPEAT_ONE;
450 else if (oldmode == REPEAT_OFF)
451 global_settings.repeat_mode = REPEAT_ALL;
453 settings_save();
454 settings_apply(false);
455 if (audio_status() & AUDIO_STATUS_PLAY)
456 audio_flush_and_reload_tracks();
458 else
459 iap_btnrepeat = false;
461 if(serbuf[5] & 16) /* ffwd */
463 iap_remotebtn |= BUTTON_RC_RIGHT;
465 if(serbuf[5] & 32) /* frwd */
467 iap_remotebtn |= BUTTON_RC_LEFT;
471 /* Handle Mode 3 */
472 else if (serbuf[1] == 0x03)
474 switch(serbuf[2])
476 /* some kind of status packet? */
477 case 0x01:
479 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
480 iap_send_pkt(data, sizeof(data));
481 break;
484 case 0x08:
486 /* ACK */
487 unsigned char data[] = {0x03, 0x00, 0x00, 0x08};
488 iap_send_pkt(data, sizeof(data));
489 break;
492 case 0x0C:
494 /* request ipod volume */
495 if (serbuf[3] == 0x04)
497 iap_set_remote_volume();
499 break;
501 /* get volume from accessory */
502 case 0x0E:
503 if (serbuf[3] == 0x04)
504 global_settings.volume = (-58)+((int)serbuf[5]+1)/4;
505 sound_set_volume(global_settings.volume);
506 break;
509 /* Handle Mode 4 */
510 else if (serbuf[1] == 0x04)
512 switch (((unsigned long)serbuf[2] << 8) | serbuf[3])
514 /* Get data updated??? flag */
515 case 0x0009:
517 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
518 data[3] = iap_updateflag ? 0 : 1;
519 iap_send_pkt(data, sizeof(data));
520 break;
522 /* Set data updated??? flag */
523 case 0x000B:
525 iap_updateflag = serbuf[4] ? 0 : 1;
526 /* respond with cmd ok packet */
527 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x0B};
528 iap_send_pkt(data, sizeof(data));
529 break;
531 /* Get iPod size? */
532 case 0x0012:
534 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
535 iap_send_pkt(data, sizeof(data));
536 break;
538 /* Get count of given types */
539 case 0x0018:
541 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
542 unsigned long num = 0;
543 switch(serbuf[4]) /* type number */
545 case 0x01: /* total number of playlists */
546 num = 1;
547 break;
548 case 0x05: /* total number of songs */
549 num = 1;
551 data[3] = num >> 24;
552 data[4] = num >> 16;
553 data[5] = num >> 8;
554 data[6] = num;
555 iap_send_pkt(data, sizeof(data));
556 break;
558 /* Get time and status */
559 case 0x001C:
561 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
562 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
563 struct mp3entry *id3 = audio_current_track();
564 unsigned long time_total = id3->length;
565 unsigned long time_elapsed = id3->elapsed;
566 int status = audio_status();
567 data[3] = time_total >> 24;
568 data[4] = time_total >> 16;
569 data[5] = time_total >> 8;
570 data[6] = time_total;
571 data[7] = time_elapsed >> 24;
572 data[8] = time_elapsed >> 16;
573 data[9] = time_elapsed >> 8;
574 data[10] = time_elapsed;
575 if (status == AUDIO_STATUS_PLAY)
576 data[11] = 0x01; /* play */
577 else if (status & AUDIO_STATUS_PAUSE)
578 data[11] = 0x02; /* pause */
579 iap_send_pkt(data, sizeof(data));
580 break;
582 /* Get current pos in playlist */
583 case 0x001E:
585 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
586 long playlist_pos = playlist_next(0);
587 playlist_pos -= playlist_get_first_index(NULL);
588 if(playlist_pos < 0)
589 playlist_pos += playlist_amount();
590 data[3] = playlist_pos >> 24;
591 data[4] = playlist_pos >> 16;
592 data[5] = playlist_pos >> 8;
593 data[6] = playlist_pos;
594 iap_send_pkt(data, sizeof(data));
595 break;
597 /* Get title of a song number */
598 case 0x0020:
599 /* Get artist of a song number */
600 case 0x0022:
601 /* Get album of a song number */
602 case 0x0024:
604 unsigned char data[70] = {0x04, 0x00, 0xFF};
605 struct mp3entry id3;
606 int fd;
607 size_t len;
608 long tracknum = (signed long)serbuf[4] << 24 |
609 (signed long)serbuf[5] << 16 |
610 (signed long)serbuf[6] << 8 | serbuf[7];
611 data[2] = serbuf[3] + 1;
612 memcpy(&id3, audio_current_track(), sizeof(id3));
613 tracknum += playlist_get_first_index(NULL);
614 if(tracknum >= playlist_amount())
615 tracknum -= playlist_amount();
617 /* If the tracknumber is not the current one,
618 read id3 from disk */
619 if(playlist_next(0) != tracknum)
621 struct playlist_track_info info;
622 playlist_get_track_info(NULL, tracknum, &info);
623 fd = open(info.filename, O_RDONLY);
624 memset(&id3, 0, sizeof(struct mp3entry));
625 get_metadata(&id3, fd, info.filename);
626 close(fd);
629 /* Return the requested track data */
630 switch(serbuf[3])
632 case 0x20:
633 len = strlcpy((char *)&data[3], id3.title, 64);
634 iap_send_pkt(data, 4+len);
635 break;
636 case 0x22:
637 len = strlcpy((char *)&data[3], id3.artist, 64);
638 iap_send_pkt(data, 4+len);
639 break;
640 case 0x24:
641 len = strlcpy((char *)&data[3], id3.album, 64);
642 iap_send_pkt(data, 4+len);
643 break;
645 break;
647 /* Set polling mode */
648 case 0x0026:
650 iap_pollspeed = serbuf[4] ? 1 : 0;
651 /*responsed with cmd ok packet */
652 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x26};
653 iap_send_pkt(data, sizeof(data));
654 break;
656 /* AiR playback control */
657 case 0x0029:
659 /* respond with cmd ok packet */
660 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
661 iap_send_pkt(data, sizeof(data));
662 switch(serbuf[4])
664 case 0x01: /* play/pause */
665 iap_remotebtn = BUTTON_RC_PLAY;
666 iap_repeatbtn = 2;
667 iap_remotetick = false;
668 iap_changedctr = 1;
669 break;
670 case 0x02: /* stop */
671 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
672 iap_repeatbtn = 2;
673 iap_remotetick = false;
674 iap_changedctr = 1;
675 break;
676 case 0x03: /* skip++ */
677 iap_remotebtn = BUTTON_RC_RIGHT;
678 iap_repeatbtn = 2;
679 iap_remotetick = false;
680 break;
681 case 0x04: /* skip-- */
682 iap_remotebtn = BUTTON_RC_LEFT;
683 iap_repeatbtn = 2;
684 iap_remotetick = false;
685 break;
686 case 0x05: /* ffwd */
687 iap_remotebtn = BUTTON_RC_RIGHT;
688 iap_remotetick = false;
689 if(iap_pollspeed) iap_pollspeed = 5;
690 break;
691 case 0x06: /* frwd */
692 iap_remotebtn = BUTTON_RC_LEFT;
693 iap_remotetick = false;
694 if(iap_pollspeed) iap_pollspeed = 5;
695 break;
696 case 0x07: /* end ffwd/frwd */
697 iap_remotebtn = BUTTON_NONE;
698 iap_remotetick = false;
699 if(iap_pollspeed) iap_pollspeed = 1;
700 break;
702 break;
704 /* Get shuffle mode */
705 case 0x002C:
707 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
708 data[3] = global_settings.playlist_shuffle ? 1 : 0;
709 iap_send_pkt(data, sizeof(data));
710 break;
712 /* Set shuffle mode */
713 case 0x002E:
715 if(serbuf[4] && !global_settings.playlist_shuffle)
717 global_settings.playlist_shuffle = 1;
718 settings_save();
719 settings_apply(false);
720 if (audio_status() & AUDIO_STATUS_PLAY)
721 playlist_randomise(NULL, current_tick, true);
723 else if(!serbuf[4] && global_settings.playlist_shuffle)
725 global_settings.playlist_shuffle = 0;
726 settings_save();
727 settings_apply(false);
728 if (audio_status() & AUDIO_STATUS_PLAY)
729 playlist_sort(NULL, true);
733 /* respond with cmd ok packet */
734 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x2E};
735 iap_send_pkt(data, sizeof(data));
736 break;
738 /* Get repeat mode */
739 case 0x002F:
741 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
742 if(global_settings.repeat_mode == REPEAT_OFF)
743 data[3] = 0;
744 else if(global_settings.repeat_mode == REPEAT_ONE)
745 data[3] = 1;
746 else
747 data[3] = 2;
748 iap_send_pkt(data, sizeof(data));
749 break;
751 /* Set repeat mode */
752 case 0x0031:
754 int oldmode = global_settings.repeat_mode;
755 if (serbuf[4] == 0)
756 global_settings.repeat_mode = REPEAT_OFF;
757 else if (serbuf[4] == 1)
758 global_settings.repeat_mode = REPEAT_ONE;
759 else if (serbuf[4] == 2)
760 global_settings.repeat_mode = REPEAT_ALL;
762 if (oldmode != global_settings.repeat_mode)
764 settings_save();
765 settings_apply(false);
766 if (audio_status() & AUDIO_STATUS_PLAY)
767 audio_flush_and_reload_tracks();
770 /* respond with cmd ok packet */
771 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x31};
772 iap_send_pkt(data, sizeof(data));
773 break;
775 /* Get Max Screen Size for Picture Upload??? */
776 case 0x0033:
778 unsigned char data[] = {0x04, 0x00, 0x34, 0x01, 0x36, 0x00, 0xA8, 0x01};
779 iap_send_pkt(data, sizeof(data));
780 break;
782 /* Get number songs in current playlist */
783 case 0x0035:
785 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
786 unsigned long playlist_amt = playlist_amount();
787 data[3] = playlist_amt >> 24;
788 data[4] = playlist_amt >> 16;
789 data[5] = playlist_amt >> 8;
790 data[6] = playlist_amt;
791 iap_send_pkt(data, sizeof(data));
792 break;
794 /* Jump to track number in current playlist */
795 case 0x0037:
797 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
798 long tracknum = (signed long)serbuf[4] << 24 |
799 (signed long)serbuf[5] << 16 |
800 (signed long)serbuf[6] << 8 | serbuf[7];
801 audio_pause();
802 audio_skip(tracknum - playlist_next(0));
803 if (!paused)
804 audio_resume();
806 /* respond with cmd ok packet */
807 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
808 data[4] = serbuf[2];
809 data[5] = serbuf[3];
810 iap_send_pkt(data, sizeof(data));
811 break;
813 default:
815 /* default response is with cmd ok packet */
816 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
817 data[4] = serbuf[2];
818 data[5] = serbuf[3];
819 iap_send_pkt(data, sizeof(data));
820 break;
824 /* Handle Mode 7 */
825 else if (serbuf[1] == 0x07)
827 switch(serbuf[2])
829 /* tuner capabilities */
830 case 0x02:
832 /* do nothing */
834 unsigned char data[] = {0x00, 0x27, 0x00};
835 iap_send_pkt(data, sizeof(data));
836 break;
838 /* actual tuner frequency */
839 case 0x0A:
840 /* fall through */
841 /* tuner frequency from scan */
842 case 0x13:
844 rmt_tuner_freq();
845 break;
847 /* RDS station name 0x21 1E 00 + ASCII text*/
848 case 0x21:
850 rmt_tuner_rds_data();
851 break;
855 serbuf[0] = 0;
858 int remote_control_rx(void)
860 int btn = iap_remotebtn;
861 if(iap_repeatbtn)
863 iap_repeatbtn--;
864 if(!iap_repeatbtn)
866 iap_remotebtn = BUTTON_NONE;
867 iap_remotetick = true;
870 else
871 iap_remotetick = true;
873 return btn;