Submit FS#12081. Check validity of channel configuration, comment unneeded code that...
[kugel-rb.git] / apps / iap.c
blob2941326ad0583e21bbeae2a456be71f17850e3fa
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 /* PlayStatusChangeNotification */
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 static 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 static void cmd_ok_mode0(unsigned char cmd)
224 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
225 data[3] = cmd; /* respond with cmd */
226 iap_send_pkt(data, sizeof(data));
229 static void iap_handlepkt_mode0(void)
231 unsigned int cmd = serbuf[2];
232 switch (cmd) {
233 /* Identify */
234 case 0x01:
236 /* FM transmitter sends this: */
237 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
238 if(serbuf[3] == 0x05)
240 sleep(HZ/3);
241 /* RF Transmitter: Begin transmission */
242 unsigned char data[] = {0x05, 0x02};
243 iap_send_pkt(data, sizeof(data));
245 /* FM remote sends this: */
246 /* FF 55 03 00 01 02 FA (1st thing sent) */
247 else if(serbuf[3] == 0x02)
249 /* useful only for apple firmware */
251 break;
254 /* EnterRemoteUIMode, FM transmitter sends FF 55 02 00 05 F9 */
255 case 0x05:
257 /* ACK Pending (3000 ms) */
258 unsigned char data[] = {0x00, 0x02, 0x06,
259 0x05, 0x00, 0x00, 0x0B, 0xB8};
260 iap_send_pkt(data, sizeof(data));
261 cmd_ok_mode0(cmd);
262 break;
265 /* ExitRemoteUIMode */
266 case 0x06:
268 audio_stop();
269 cmd_ok_mode0(cmd);
270 break;
273 /* RequestiPodSoftwareVersion, Ipod FM remote sends FF 55 02 00 09 F5 */
274 case 0x09:
276 /* ReturniPodSoftwareVersion, ipod5G firmware version */
277 unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01};
278 iap_send_pkt(data, sizeof(data));
279 break;
282 /* RequestiPodModelNum */
283 case 0x0D:
285 /* ipod is supposed to work only with 5G and nano 2G */
286 /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34,
287 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */
288 /* ReturniPodModelNum */
289 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
290 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
291 iap_send_pkt(data, sizeof(data));
292 break;
295 /* RequestLingoProtocolVersion */
296 case 0x0F:
298 /* ReturnLingoProtocolVersion */
299 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
300 data[2] = serbuf[3];
301 iap_send_pkt(data, sizeof(data));
302 break;
305 /* IdentifyDeviceLingoes */
306 case 0x13:
308 cmd_ok_mode0(cmd);
310 if (serbuf[6] == 0x35)
311 /* FM transmitter sends this: */
312 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
314 /* GetAccessoryInfo */
315 unsigned char data2[] = {0x00, 0x27, 0x00};
316 iap_send_pkt(data2, sizeof(data2));
317 /* RF Transmitter: Begin transmission */
318 unsigned char data3[] = {0x05, 0x02};
319 iap_send_pkt(data3, sizeof(data3));
322 else
324 /* ipod fm remote sends this: */
325 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
326 if (serbuf[6] |= 0x80)
327 radio_present = 1;
328 /* GetDevAuthenticationInfo */
329 unsigned char data4[] = {0x00, 0x14};
330 iap_send_pkt(data4, sizeof(data4));
332 break;
335 /* RetDevAuthenticationInfo */
336 case 0x15:
338 /* AckDevAuthenticationInfo */
339 unsigned char data0[] = {0x00, 0x16, 0x00};
340 iap_send_pkt(data0, sizeof(data0));
341 /* GetAccessoryInfo */
342 unsigned char data1[] = {0x00, 0x27, 0x00};
343 iap_send_pkt(data1, sizeof(data1));
344 /* AckDevAuthenticationStatus, mandatory to enable some hardware */
345 unsigned char data2[] = {0x00, 0x19, 0x00};
346 iap_send_pkt(data2, sizeof(data2));
347 if (radio_present == 1)
349 /* GetTunerCaps */
350 unsigned char data3[] = {0x07, 0x01};
351 iap_send_pkt(data3, sizeof(data3));
353 iap_set_remote_volume();
354 break;
357 /* RetDevAuthenticationSignature */
358 case 0x18:
360 /* Isn't used since we don't send the 0x00 0x17 command */
361 break;
364 /* GetIpodOptions */
365 case 0x24:
367 /* RetIpodOptions (ipod video send this) */
368 unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00,
369 0x00, 0x00, 0x00, 0x00, 0x01};
370 iap_send_pkt(data, sizeof(data));
371 break;
374 /* default response is with cmd ok packet */
375 default:
377 cmd_ok_mode0(cmd);
378 break;
383 static void iap_handlepkt_mode2(void)
385 if(serbuf[2] != 0) return;
386 iap_remotebtn = BUTTON_NONE;
387 iap_remotetick = false;
389 if(serbuf[0] >= 3 && serbuf[3] != 0)
391 if(serbuf[3] & 1)
392 iap_remotebtn |= BUTTON_RC_PLAY;
393 if(serbuf[3] & 2)
394 iap_remotebtn |= BUTTON_RC_VOL_UP;
395 if(serbuf[3] & 4)
396 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
397 if(serbuf[3] & 8)
398 iap_remotebtn |= BUTTON_RC_RIGHT;
399 if(serbuf[3] & 16)
400 iap_remotebtn |= BUTTON_RC_LEFT;
402 else if(serbuf[0] >= 4 && serbuf[4] != 0)
404 if(serbuf[4] & 1) /* play */
406 if (audio_status() != AUDIO_STATUS_PLAY)
408 iap_remotebtn |= BUTTON_RC_PLAY;
409 iap_repeatbtn = 2;
410 iap_remotetick = false;
411 iap_changedctr = 1;
414 if(serbuf[4] & 2) /* pause */
416 if (audio_status() == AUDIO_STATUS_PLAY)
418 iap_remotebtn |= BUTTON_RC_PLAY;
419 iap_repeatbtn = 2;
420 iap_remotetick = false;
421 iap_changedctr = 1;
424 if((serbuf[4] & 128) && !iap_btnshuffle) /* shuffle */
426 iap_btnshuffle = true;
427 if(!global_settings.playlist_shuffle)
429 global_settings.playlist_shuffle = 1;
430 settings_save();
431 if (audio_status() & AUDIO_STATUS_PLAY)
432 playlist_randomise(NULL, current_tick, true);
434 else if(global_settings.playlist_shuffle)
436 global_settings.playlist_shuffle = 0;
437 settings_save();
438 if (audio_status() & AUDIO_STATUS_PLAY)
439 playlist_sort(NULL, true);
442 else
443 iap_btnshuffle = false;
445 else if(serbuf[0] >= 5 && serbuf[5] != 0)
447 if((serbuf[5] & 1) && !iap_btnrepeat) /* repeat */
449 int oldmode = global_settings.repeat_mode;
450 iap_btnrepeat = true;
452 if (oldmode == REPEAT_ONE)
453 global_settings.repeat_mode = REPEAT_OFF;
454 else if (oldmode == REPEAT_ALL)
455 global_settings.repeat_mode = REPEAT_ONE;
456 else if (oldmode == REPEAT_OFF)
457 global_settings.repeat_mode = REPEAT_ALL;
459 settings_save();
460 if (audio_status() & AUDIO_STATUS_PLAY)
461 audio_flush_and_reload_tracks();
463 else
464 iap_btnrepeat = false;
466 if(serbuf[5] & 16) /* ffwd */
468 iap_remotebtn |= BUTTON_RC_RIGHT;
470 if(serbuf[5] & 32) /* frwd */
472 iap_remotebtn |= BUTTON_RC_LEFT;
477 static void iap_handlepkt_mode3(void)
479 unsigned int cmd = serbuf[2];
480 switch (cmd)
482 /* GetCurrentEQProfileIndex */
483 case 0x01:
485 /* RetCurrentEQProfileIndex */
486 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
487 iap_send_pkt(data, sizeof(data));
488 break;
491 /* SetRemoteEventNotification */
492 case 0x08:
494 /* ACK */
495 unsigned char data[] = {0x03, 0x00, 0x00, 0x08};
496 iap_send_pkt(data, sizeof(data));
497 break;
500 /* GetiPodStateInfo */
501 case 0x0C:
503 /* request ipod volume */
504 if (serbuf[3] == 0x04)
506 iap_set_remote_volume();
508 break;
511 /* SetiPodStateInfo */
512 case 0x0E:
514 if (serbuf[3] == 0x04)
515 global_settings.volume = (-58)+((int)serbuf[5]+1)/4;
516 sound_set_volume(global_settings.volume); /* indent BUG? */
517 break;
522 static void cmd_ok_mode4(unsigned int cmd)
524 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
525 data[4] = (cmd >> 8) & 0xFF;
526 data[5] = (cmd >> 0) & 0xFF;
527 iap_send_pkt(data, sizeof(data));
530 static void iap_handlepkt_mode4(void)
532 unsigned int cmd = (serbuf[2] << 8) | serbuf[3];
533 switch (cmd)
535 /* GetAudioBookSpeed */
536 case 0x0009:
538 /* ReturnAudioBookSpeed */
539 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
540 data[3] = iap_updateflag ? 0 : 1;
541 iap_send_pkt(data, sizeof(data));
542 break;
545 /* SetAudioBookSpeed */
546 case 0x000B:
548 iap_updateflag = serbuf[4] ? 0 : 1;
549 /* respond with cmd ok packet */
550 cmd_ok_mode4(cmd);
551 break;
554 /* RequestProtocolVersion */
555 case 0x0012:
557 /* ReturnProtocolVersion */
558 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
559 iap_send_pkt(data, sizeof(data));
560 break;
563 /* GetNumberCategorizedDBRecords */
564 case 0x0018:
566 /* ReturnNumberCategorizedDBRecords */
567 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
568 unsigned long num = 0;
569 switch(serbuf[4]) /* type number */
571 case 0x01: /* total number of playlists */
572 num = 1;
573 break;
574 case 0x05: /* total number of songs */
575 num = 1;
577 data[3] = num >> 24;
578 data[4] = num >> 16;
579 data[5] = num >> 8;
580 data[6] = num;
581 iap_send_pkt(data, sizeof(data));
582 break;
585 /* GetPlayStatus */
586 case 0x001C:
588 /* ReturnPlayStatus */
589 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
590 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
591 struct mp3entry *id3 = audio_current_track();
592 unsigned long time_total = id3->length;
593 unsigned long time_elapsed = id3->elapsed;
594 int status = audio_status();
595 data[3] = time_total >> 24;
596 data[4] = time_total >> 16;
597 data[5] = time_total >> 8;
598 data[6] = time_total;
599 data[7] = time_elapsed >> 24;
600 data[8] = time_elapsed >> 16;
601 data[9] = time_elapsed >> 8;
602 data[10] = time_elapsed;
603 if (status == AUDIO_STATUS_PLAY)
604 data[11] = 0x01; /* play */
605 else if (status & AUDIO_STATUS_PAUSE)
606 data[11] = 0x02; /* pause */
607 iap_send_pkt(data, sizeof(data));
608 break;
611 /* GetCurrentPlayingTrackIndex */
612 case 0x001E:
614 /* ReturnCurrentPlayingTrackIndex */
615 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
616 long playlist_pos = playlist_next(0);
617 playlist_pos -= playlist_get_first_index(NULL);
618 if(playlist_pos < 0)
619 playlist_pos += playlist_amount();
620 data[3] = playlist_pos >> 24;
621 data[4] = playlist_pos >> 16;
622 data[5] = playlist_pos >> 8;
623 data[6] = playlist_pos;
624 iap_send_pkt(data, sizeof(data));
625 break;
628 /* GetIndexedPlayingTrackTitle */
629 case 0x0020:
630 /* GetIndexedPlayingTrackArtistName */
631 case 0x0022:
632 /* GetIndexedPlayingTrackAlbumName */
633 case 0x0024:
635 unsigned char data[70] = {0x04, 0x00, 0xFF};
636 struct mp3entry id3;
637 int fd;
638 size_t len;
639 long tracknum = (signed long)serbuf[4] << 24 |
640 (signed long)serbuf[5] << 16 |
641 (signed long)serbuf[6] << 8 | serbuf[7];
642 data[2] = cmd + 1;
643 memcpy(&id3, audio_current_track(), sizeof(id3));
644 tracknum += playlist_get_first_index(NULL);
645 if(tracknum >= playlist_amount())
646 tracknum -= playlist_amount();
648 /* If the tracknumber is not the current one,
649 read id3 from disk */
650 if(playlist_next(0) != tracknum)
652 struct playlist_track_info info;
653 playlist_get_track_info(NULL, tracknum, &info);
654 fd = open(info.filename, O_RDONLY);
655 memset(&id3, 0, sizeof(struct mp3entry));
656 get_metadata(&id3, fd, info.filename);
657 close(fd);
660 /* Return the requested track data */
661 switch(cmd)
663 case 0x20:
664 len = strlcpy((char *)&data[3], id3.title, 64);
665 iap_send_pkt(data, 4+len);
666 break;
667 case 0x22:
668 len = strlcpy((char *)&data[3], id3.artist, 64);
669 iap_send_pkt(data, 4+len);
670 break;
671 case 0x24:
672 len = strlcpy((char *)&data[3], id3.album, 64);
673 iap_send_pkt(data, 4+len);
674 break;
676 break;
679 /* SetPlayStatusChangeNotification */
680 case 0x0026:
682 iap_pollspeed = serbuf[4] ? 1 : 0;
683 /* respond with cmd ok packet */
684 cmd_ok_mode4(cmd);
685 break;
688 /* PlayControl */
689 case 0x0029:
691 switch(serbuf[4])
693 case 0x01: /* play/pause */
694 iap_remotebtn = BUTTON_RC_PLAY;
695 iap_repeatbtn = 2;
696 iap_remotetick = false;
697 iap_changedctr = 1;
698 break;
699 case 0x02: /* stop */
700 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
701 iap_repeatbtn = 2;
702 iap_remotetick = false;
703 iap_changedctr = 1;
704 break;
705 case 0x03: /* skip++ */
706 iap_remotebtn = BUTTON_RC_RIGHT;
707 iap_repeatbtn = 2;
708 iap_remotetick = false;
709 break;
710 case 0x04: /* skip-- */
711 iap_remotebtn = BUTTON_RC_LEFT;
712 iap_repeatbtn = 2;
713 iap_remotetick = false;
714 break;
715 case 0x05: /* ffwd */
716 iap_remotebtn = BUTTON_RC_RIGHT;
717 iap_remotetick = false;
718 if(iap_pollspeed) iap_pollspeed = 5;
719 break;
720 case 0x06: /* frwd */
721 iap_remotebtn = BUTTON_RC_LEFT;
722 iap_remotetick = false;
723 if(iap_pollspeed) iap_pollspeed = 5;
724 break;
725 case 0x07: /* end ffwd/frwd */
726 iap_remotebtn = BUTTON_NONE;
727 iap_remotetick = false;
728 if(iap_pollspeed) iap_pollspeed = 1;
729 break;
731 /* respond with cmd ok packet */
732 cmd_ok_mode4(cmd);
733 break;
736 /* GetShuffle */
737 case 0x002C:
739 /* ReturnShuffle */
740 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
741 data[3] = global_settings.playlist_shuffle ? 1 : 0;
742 iap_send_pkt(data, sizeof(data));
743 break;
746 /* SetShuffle */
747 case 0x002E:
749 if(serbuf[4] && !global_settings.playlist_shuffle)
751 global_settings.playlist_shuffle = 1;
752 settings_save();
753 if (audio_status() & AUDIO_STATUS_PLAY)
754 playlist_randomise(NULL, current_tick, true);
756 else if(!serbuf[4] && global_settings.playlist_shuffle)
758 global_settings.playlist_shuffle = 0;
759 settings_save();
760 if (audio_status() & AUDIO_STATUS_PLAY)
761 playlist_sort(NULL, true);
764 /* respond with cmd ok packet */
765 cmd_ok_mode4(cmd);
766 break;
769 /* GetRepeat */
770 case 0x002F:
772 /* ReturnRepeat */
773 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
774 if(global_settings.repeat_mode == REPEAT_OFF)
775 data[3] = 0;
776 else if(global_settings.repeat_mode == REPEAT_ONE)
777 data[3] = 1;
778 else
779 data[3] = 2;
780 iap_send_pkt(data, sizeof(data));
781 break;
784 /* SetRepeat */
785 case 0x0031:
787 int oldmode = global_settings.repeat_mode;
788 if (serbuf[4] == 0)
789 global_settings.repeat_mode = REPEAT_OFF;
790 else if (serbuf[4] == 1)
791 global_settings.repeat_mode = REPEAT_ONE;
792 else if (serbuf[4] == 2)
793 global_settings.repeat_mode = REPEAT_ALL;
795 if (oldmode != global_settings.repeat_mode)
797 settings_save();
798 if (audio_status() & AUDIO_STATUS_PLAY)
799 audio_flush_and_reload_tracks();
802 /* respond with cmd ok packet */
803 cmd_ok_mode4(cmd);
804 break;
807 /* GetMonoDisplayImageLimits */
808 case 0x0033:
810 /* ReturnMonoDisplayImageLimits */
811 unsigned char data[] = {0x04, 0x00, 0x34,
812 LCD_WIDTH >> 8, LCD_WIDTH & 0xff,
813 LCD_HEIGHT >> 8, LCD_HEIGHT & 0xff,
814 0x01};
815 iap_send_pkt(data, sizeof(data));
816 break;
819 /* GetNumPlayingTracks */
820 case 0x0035:
822 /* ReturnNumPlayingTracks */
823 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
824 unsigned long playlist_amt = playlist_amount();
825 data[3] = playlist_amt >> 24;
826 data[4] = playlist_amt >> 16;
827 data[5] = playlist_amt >> 8;
828 data[6] = playlist_amt;
829 iap_send_pkt(data, sizeof(data));
830 break;
833 /* SetCurrentPlayingTrack */
834 case 0x0037:
836 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
837 long tracknum = (signed long)serbuf[4] << 24 |
838 (signed long)serbuf[5] << 16 |
839 (signed long)serbuf[6] << 8 | serbuf[7];
840 audio_pause();
841 audio_skip(tracknum - playlist_next(0));
842 if (!paused)
843 audio_resume();
845 /* respond with cmd ok packet */
846 cmd_ok_mode4(cmd);
847 break;
850 default:
852 /* default response is with cmd ok packet */
853 cmd_ok_mode4(cmd);
854 break;
859 static void iap_handlepkt_mode7(void)
861 unsigned int cmd = serbuf[2];
862 switch (cmd)
864 /* RetTunerCaps */
865 case 0x02:
867 /* do nothing */
869 /* GetAccessoryInfo */
870 unsigned char data[] = {0x00, 0x27, 0x00};
871 iap_send_pkt(data, sizeof(data));
872 break;
875 /* RetTunerFreq */
876 case 0x0A:
877 /* fall through */
878 /* TunerSeekDone */
879 case 0x13:
881 rmt_tuner_freq(serbuf);
882 break;
885 /* RdsReadyNotify, RDS station name 0x21 1E 00 + ASCII text*/
886 case 0x21:
888 rmt_tuner_rds_data(serbuf);
889 break;
894 void iap_handlepkt(void)
897 if(!iap_setupflag) return;
898 if(serbuf[0] == 0) return;
900 /* if we are waiting for a remote button to go out,
901 delay the handling of the new packet */
902 if(!iap_remotetick)
904 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
905 return;
908 unsigned char mode = serbuf[1];
909 switch (mode) {
910 case 0: iap_handlepkt_mode0(); break;
911 case 2: iap_handlepkt_mode2(); break;
912 case 3: iap_handlepkt_mode3(); break;
913 case 4: iap_handlepkt_mode4(); break;
914 case 7: iap_handlepkt_mode7(); break;
917 serbuf[0] = 0;
920 int remote_control_rx(void)
922 int btn = iap_remotebtn;
923 if(iap_repeatbtn)
925 iap_repeatbtn--;
926 if(!iap_repeatbtn)
928 iap_remotebtn = BUTTON_NONE;
929 iap_remotetick = true;
932 else
933 iap_remotetick = true;
935 return btn;
938 const unsigned char *iap_get_serbuf(void)
940 return serbuf;