iap: introduce functions (put_u32 and get_u32) to convert a uint32_t to a byte array...
[kugel-rb.git] / apps / iap.c
blob4d8a34fa571c0b02c5ef6c495d2a2a949c97d9fa
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(void)
246 unsigned int cmd = serbuf[2];
247 switch (cmd) {
248 /* Identify */
249 case 0x01:
251 /* FM transmitter sends this: */
252 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
253 if(serbuf[3] == 0x05)
255 sleep(HZ/3);
256 /* RF Transmitter: Begin transmission */
257 unsigned char data[] = {0x05, 0x02};
258 iap_send_pkt(data, sizeof(data));
260 /* FM remote sends this: */
261 /* FF 55 03 00 01 02 FA (1st thing sent) */
262 else if(serbuf[3] == 0x02)
264 /* useful only for apple firmware */
266 break;
269 /* EnterRemoteUIMode, FM transmitter sends FF 55 02 00 05 F9 */
270 case 0x05:
272 /* ACK Pending (3000 ms) */
273 unsigned char data[] = {0x00, 0x02, 0x06,
274 0x05, 0x00, 0x00, 0x0B, 0xB8};
275 iap_send_pkt(data, sizeof(data));
276 cmd_ok_mode0(cmd);
277 break;
280 /* ExitRemoteUIMode */
281 case 0x06:
283 audio_stop();
284 cmd_ok_mode0(cmd);
285 break;
288 /* RequestiPodSoftwareVersion, Ipod FM remote sends FF 55 02 00 09 F5 */
289 case 0x09:
291 /* ReturniPodSoftwareVersion, ipod5G firmware version */
292 unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01};
293 iap_send_pkt(data, sizeof(data));
294 break;
297 /* RequestiPodModelNum */
298 case 0x0D:
300 /* ipod is supposed to work only with 5G and nano 2G */
301 /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34,
302 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */
303 /* ReturniPodModelNum */
304 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
305 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
306 iap_send_pkt(data, sizeof(data));
307 break;
310 /* RequestLingoProtocolVersion */
311 case 0x0F:
313 /* ReturnLingoProtocolVersion */
314 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
315 data[2] = serbuf[3];
316 iap_send_pkt(data, sizeof(data));
317 break;
320 /* IdentifyDeviceLingoes */
321 case 0x13:
323 cmd_ok_mode0(cmd);
325 uint32_t lingoes = get_u32(&serbuf[3]);
327 if (lingoes == 0x35)
328 /* FM transmitter sends this: */
329 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
331 /* GetAccessoryInfo */
332 unsigned char data2[] = {0x00, 0x27, 0x00};
333 iap_send_pkt(data2, sizeof(data2));
334 /* RF Transmitter: Begin transmission */
335 unsigned char data3[] = {0x05, 0x02};
336 iap_send_pkt(data3, sizeof(data3));
338 else
340 /* ipod fm remote sends this: */
341 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
342 if (lingoes & (1 << 7)) /* bit 7 = RF tuner lingo */
343 radio_present = 1;
344 /* GetDevAuthenticationInfo */
345 unsigned char data4[] = {0x00, 0x14};
346 iap_send_pkt(data4, sizeof(data4));
348 break;
351 /* RetDevAuthenticationInfo */
352 case 0x15:
354 /* AckDevAuthenticationInfo */
355 unsigned char data0[] = {0x00, 0x16, 0x00};
356 iap_send_pkt(data0, sizeof(data0));
357 /* GetAccessoryInfo */
358 unsigned char data1[] = {0x00, 0x27, 0x00};
359 iap_send_pkt(data1, sizeof(data1));
360 /* AckDevAuthenticationStatus, mandatory to enable some hardware */
361 unsigned char data2[] = {0x00, 0x19, 0x00};
362 iap_send_pkt(data2, sizeof(data2));
363 if (radio_present == 1)
365 /* GetTunerCaps */
366 unsigned char data3[] = {0x07, 0x01};
367 iap_send_pkt(data3, sizeof(data3));
369 iap_set_remote_volume();
370 break;
373 /* RetDevAuthenticationSignature */
374 case 0x18:
376 /* Isn't used since we don't send the 0x00 0x17 command */
377 break;
380 /* GetIpodOptions */
381 case 0x24:
383 /* RetIpodOptions (ipod video send this) */
384 unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00,
385 0x00, 0x00, 0x00, 0x00, 0x01};
386 iap_send_pkt(data, sizeof(data));
387 break;
390 /* default response is with cmd ok packet */
391 default:
393 cmd_ok_mode0(cmd);
394 break;
399 static void iap_handlepkt_mode2(void)
401 if(serbuf[2] != 0) return;
402 iap_remotebtn = BUTTON_NONE;
403 iap_remotetick = false;
405 if(serbuf[0] >= 3 && serbuf[3] != 0)
407 if(serbuf[3] & 1)
408 iap_remotebtn |= BUTTON_RC_PLAY;
409 if(serbuf[3] & 2)
410 iap_remotebtn |= BUTTON_RC_VOL_UP;
411 if(serbuf[3] & 4)
412 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
413 if(serbuf[3] & 8)
414 iap_remotebtn |= BUTTON_RC_RIGHT;
415 if(serbuf[3] & 16)
416 iap_remotebtn |= BUTTON_RC_LEFT;
418 else if(serbuf[0] >= 4 && serbuf[4] != 0)
420 if(serbuf[4] & 1) /* play */
422 if (audio_status() != AUDIO_STATUS_PLAY)
424 iap_remotebtn |= BUTTON_RC_PLAY;
425 iap_repeatbtn = 2;
426 iap_remotetick = false;
427 iap_changedctr = 1;
430 if(serbuf[4] & 2) /* pause */
432 if (audio_status() == AUDIO_STATUS_PLAY)
434 iap_remotebtn |= BUTTON_RC_PLAY;
435 iap_repeatbtn = 2;
436 iap_remotetick = false;
437 iap_changedctr = 1;
440 if((serbuf[4] & 128) && !iap_btnshuffle) /* shuffle */
442 iap_btnshuffle = true;
443 if(!global_settings.playlist_shuffle)
445 global_settings.playlist_shuffle = 1;
446 settings_save();
447 if (audio_status() & AUDIO_STATUS_PLAY)
448 playlist_randomise(NULL, current_tick, true);
450 else if(global_settings.playlist_shuffle)
452 global_settings.playlist_shuffle = 0;
453 settings_save();
454 if (audio_status() & AUDIO_STATUS_PLAY)
455 playlist_sort(NULL, true);
458 else
459 iap_btnshuffle = false;
461 else if(serbuf[0] >= 5 && serbuf[5] != 0)
463 if((serbuf[5] & 1) && !iap_btnrepeat) /* repeat */
465 int oldmode = global_settings.repeat_mode;
466 iap_btnrepeat = true;
468 if (oldmode == REPEAT_ONE)
469 global_settings.repeat_mode = REPEAT_OFF;
470 else if (oldmode == REPEAT_ALL)
471 global_settings.repeat_mode = REPEAT_ONE;
472 else if (oldmode == REPEAT_OFF)
473 global_settings.repeat_mode = REPEAT_ALL;
475 settings_save();
476 if (audio_status() & AUDIO_STATUS_PLAY)
477 audio_flush_and_reload_tracks();
479 else
480 iap_btnrepeat = false;
482 if(serbuf[5] & 16) /* ffwd */
484 iap_remotebtn |= BUTTON_RC_RIGHT;
486 if(serbuf[5] & 32) /* frwd */
488 iap_remotebtn |= BUTTON_RC_LEFT;
493 static void iap_handlepkt_mode3(void)
495 unsigned int cmd = serbuf[2];
496 switch (cmd)
498 /* GetCurrentEQProfileIndex */
499 case 0x01:
501 /* RetCurrentEQProfileIndex */
502 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
503 iap_send_pkt(data, sizeof(data));
504 break;
507 /* SetRemoteEventNotification */
508 case 0x08:
510 /* ACK */
511 unsigned char data[] = {0x03, 0x00, 0x00, 0x08};
512 iap_send_pkt(data, sizeof(data));
513 break;
516 /* GetiPodStateInfo */
517 case 0x0C:
519 /* request ipod volume */
520 if (serbuf[3] == 0x04)
522 iap_set_remote_volume();
524 break;
527 /* SetiPodStateInfo */
528 case 0x0E:
530 if (serbuf[3] == 0x04)
531 global_settings.volume = (-58)+((int)serbuf[5]+1)/4;
532 sound_set_volume(global_settings.volume); /* indent BUG? */
533 break;
538 static void cmd_ok_mode4(unsigned int cmd)
540 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
541 data[4] = (cmd >> 8) & 0xFF;
542 data[5] = (cmd >> 0) & 0xFF;
543 iap_send_pkt(data, sizeof(data));
546 static void get_playlist_name(unsigned char *dest,
547 unsigned long item_offset,
548 size_t max_length)
550 if (item_offset == 0) return;
551 DIR* dp;
552 struct dirent* playlist_file = NULL;
554 dp = opendir(global_settings.playlist_catalog_dir);
556 char *extension;
557 unsigned long nbr = 0;
558 while ((nbr < item_offset) && ((playlist_file = readdir(dp)) != NULL))
560 /*Increment only if there is a playlist extension*/
561 if ((extension=strrchr(playlist_file->d_name, '.')) != NULL){
562 if ((strcmp(extension, ".m3u") == 0 ||
563 strcmp(extension, ".m3u8") == 0))
564 nbr++;
567 if (playlist_file != NULL) {
568 strlcpy(dest, playlist_file->d_name, max_length);
570 closedir(dp);
573 static void iap_handlepkt_mode4(void)
575 unsigned int cmd = (serbuf[2] << 8) | serbuf[3];
576 switch (cmd)
578 /* GetAudioBookSpeed */
579 case 0x0009:
581 /* ReturnAudioBookSpeed */
582 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
583 data[3] = iap_updateflag ? 0 : 1;
584 iap_send_pkt(data, sizeof(data));
585 break;
588 /* SetAudioBookSpeed */
589 case 0x000B:
591 iap_updateflag = serbuf[4] ? 0 : 1;
592 /* respond with cmd ok packet */
593 cmd_ok_mode4(cmd);
594 break;
597 /* RequestProtocolVersion */
598 case 0x0012:
600 /* ReturnProtocolVersion */
601 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
602 iap_send_pkt(data, sizeof(data));
603 break;
606 /* SelectDBRecord */
607 case 0x0017:
609 memcpy(cur_dbrecord, serbuf + 4, 5);
610 cmd_ok_mode4(cmd);
611 break;
614 /* GetNumberCategorizedDBRecords */
615 case 0x0018:
617 /* ReturnNumberCategorizedDBRecords */
618 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
619 unsigned long num = 0;
621 DIR* dp;
622 unsigned long nbr_total_playlists = 0;
623 struct dirent* playlist_file = NULL;
624 char *extension;
626 switch(serbuf[4]) /* type number */
628 case 0x01: /* total number of playlists */
629 dp = opendir(global_settings.playlist_catalog_dir);
630 while ((playlist_file = readdir(dp)) != NULL)
632 /*Increment only if there is a playlist extension*/
633 if ((extension=strrchr(playlist_file->d_name, '.'))
634 != NULL) {
635 if ((strcmp(extension, ".m3u") == 0 ||
636 strcmp(extension, ".m3u8") == 0))
637 nbr_total_playlists++;
640 closedir(dp);
641 /*Add 1 for the main playlist*/
642 num = nbr_total_playlists + 1;
643 break;
644 case 0x05: /* total number of songs */
645 num = 1;
646 break;
648 put_u32(&data[3], num);
649 iap_send_pkt(data, sizeof(data));
650 break;
653 /* RetrieveCategorizedDatabaseRecords */
654 case 0x001A:
656 /* ReturnCategorizedDatabaseRecord */
657 unsigned char data[7 + MAX_PATH] =
658 {0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00,
659 'R', 'O', 'C', 'K', 'B', 'O', 'X', '\0'};
661 unsigned long item_offset = get_u32(&serbuf[5]);
663 get_playlist_name(data + 7, item_offset, MAX_PATH);
664 /*Remove file extension*/
665 char *dot=NULL;
666 dot = (strrchr(data+7, '.'));
667 if (dot != NULL)
668 *dot = '\0';
669 iap_send_pkt(data, 7 + strlen(data+7) + 1);
670 break;
673 /* GetPlayStatus */
674 case 0x001C:
676 /* ReturnPlayStatus */
677 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
678 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
679 struct mp3entry *id3 = audio_current_track();
680 unsigned long time_total = id3->length;
681 unsigned long time_elapsed = id3->elapsed;
682 int status = audio_status();
683 put_u32(&data[3], time_total);
684 put_u32(&data[7], time_elapsed);
685 if (status == AUDIO_STATUS_PLAY)
686 data[11] = 0x01; /* play */
687 else if (status & AUDIO_STATUS_PAUSE)
688 data[11] = 0x02; /* pause */
689 iap_send_pkt(data, sizeof(data));
690 break;
693 /* GetCurrentPlayingTrackIndex */
694 case 0x001E:
696 /* ReturnCurrentPlayingTrackIndex */
697 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
698 long playlist_pos = playlist_next(0);
699 playlist_pos -= playlist_get_first_index(NULL);
700 if(playlist_pos < 0)
701 playlist_pos += playlist_amount();
702 put_u32(&data[3], playlist_pos);
703 iap_send_pkt(data, sizeof(data));
704 break;
707 /* GetIndexedPlayingTrackTitle */
708 case 0x0020:
709 /* GetIndexedPlayingTrackArtistName */
710 case 0x0022:
711 /* GetIndexedPlayingTrackAlbumName */
712 case 0x0024:
714 unsigned char data[70] = {0x04, 0x00, 0xFF};
715 struct mp3entry id3;
716 int fd;
717 size_t len;
718 long tracknum = get_u32(&serbuf[4]);
720 data[2] = cmd + 1;
721 memcpy(&id3, audio_current_track(), sizeof(id3));
722 tracknum += playlist_get_first_index(NULL);
723 if(tracknum >= playlist_amount())
724 tracknum -= playlist_amount();
726 /* If the tracknumber is not the current one,
727 read id3 from disk */
728 if(playlist_next(0) != tracknum)
730 struct playlist_track_info info;
731 playlist_get_track_info(NULL, tracknum, &info);
732 fd = open(info.filename, O_RDONLY);
733 memset(&id3, 0, sizeof(struct mp3entry));
734 get_metadata(&id3, fd, info.filename);
735 close(fd);
738 /* Return the requested track data */
739 switch(cmd)
741 case 0x20:
742 len = strlcpy((char *)&data[3], id3.title, 64);
743 iap_send_pkt(data, 4+len);
744 break;
745 case 0x22:
746 len = strlcpy((char *)&data[3], id3.artist, 64);
747 iap_send_pkt(data, 4+len);
748 break;
749 case 0x24:
750 len = strlcpy((char *)&data[3], id3.album, 64);
751 iap_send_pkt(data, 4+len);
752 break;
754 break;
757 /* SetPlayStatusChangeNotification */
758 case 0x0026:
760 iap_pollspeed = serbuf[4] ? 1 : 0;
761 /* respond with cmd ok packet */
762 cmd_ok_mode4(cmd);
763 break;
766 /* PlayCurrentSelection */
767 case 0x0028:
769 switch (cur_dbrecord[0])
771 case 0x01:
772 {/*Playlist*/
773 unsigned long item_offset = get_u32(&cur_dbrecord[1]);
775 unsigned char selected_playlist
776 [sizeof(global_settings.playlist_catalog_dir)
778 + MAX_PATH] = {0};
780 strcpy(selected_playlist,
781 global_settings.playlist_catalog_dir);
782 int len = strlen(selected_playlist);
783 selected_playlist[len] = '/';
784 get_playlist_name (selected_playlist + len + 1,
785 item_offset,
786 MAX_PATH);
787 ft_play_playlist(selected_playlist,
788 global_settings.playlist_catalog_dir,
789 strrchr(selected_playlist, '/') + 1);
790 break;
793 cmd_ok_mode4(cmd);
794 break;
797 /* PlayControl */
798 case 0x0029:
800 switch(serbuf[4])
802 case 0x01: /* play/pause */
803 iap_remotebtn = BUTTON_RC_PLAY;
804 iap_repeatbtn = 2;
805 iap_remotetick = false;
806 iap_changedctr = 1;
807 break;
808 case 0x02: /* stop */
809 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
810 iap_repeatbtn = 2;
811 iap_remotetick = false;
812 iap_changedctr = 1;
813 break;
814 case 0x03: /* skip++ */
815 iap_remotebtn = BUTTON_RC_RIGHT;
816 iap_repeatbtn = 2;
817 iap_remotetick = false;
818 break;
819 case 0x04: /* skip-- */
820 iap_remotebtn = BUTTON_RC_LEFT;
821 iap_repeatbtn = 2;
822 iap_remotetick = false;
823 break;
824 case 0x05: /* ffwd */
825 iap_remotebtn = BUTTON_RC_RIGHT;
826 iap_remotetick = false;
827 if(iap_pollspeed) iap_pollspeed = 5;
828 break;
829 case 0x06: /* frwd */
830 iap_remotebtn = BUTTON_RC_LEFT;
831 iap_remotetick = false;
832 if(iap_pollspeed) iap_pollspeed = 5;
833 break;
834 case 0x07: /* end ffwd/frwd */
835 iap_remotebtn = BUTTON_NONE;
836 iap_remotetick = false;
837 if(iap_pollspeed) iap_pollspeed = 1;
838 break;
840 /* respond with cmd ok packet */
841 cmd_ok_mode4(cmd);
842 break;
845 /* GetShuffle */
846 case 0x002C:
848 /* ReturnShuffle */
849 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
850 data[3] = global_settings.playlist_shuffle ? 1 : 0;
851 iap_send_pkt(data, sizeof(data));
852 break;
855 /* SetShuffle */
856 case 0x002E:
858 if(serbuf[4] && !global_settings.playlist_shuffle)
860 global_settings.playlist_shuffle = 1;
861 settings_save();
862 if (audio_status() & AUDIO_STATUS_PLAY)
863 playlist_randomise(NULL, current_tick, true);
865 else if(!serbuf[4] && global_settings.playlist_shuffle)
867 global_settings.playlist_shuffle = 0;
868 settings_save();
869 if (audio_status() & AUDIO_STATUS_PLAY)
870 playlist_sort(NULL, true);
873 /* respond with cmd ok packet */
874 cmd_ok_mode4(cmd);
875 break;
878 /* GetRepeat */
879 case 0x002F:
881 /* ReturnRepeat */
882 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
883 if(global_settings.repeat_mode == REPEAT_OFF)
884 data[3] = 0;
885 else if(global_settings.repeat_mode == REPEAT_ONE)
886 data[3] = 1;
887 else
888 data[3] = 2;
889 iap_send_pkt(data, sizeof(data));
890 break;
893 /* SetRepeat */
894 case 0x0031:
896 int oldmode = global_settings.repeat_mode;
897 if (serbuf[4] == 0)
898 global_settings.repeat_mode = REPEAT_OFF;
899 else if (serbuf[4] == 1)
900 global_settings.repeat_mode = REPEAT_ONE;
901 else if (serbuf[4] == 2)
902 global_settings.repeat_mode = REPEAT_ALL;
904 if (oldmode != global_settings.repeat_mode)
906 settings_save();
907 if (audio_status() & AUDIO_STATUS_PLAY)
908 audio_flush_and_reload_tracks();
911 /* respond with cmd ok packet */
912 cmd_ok_mode4(cmd);
913 break;
916 /* GetMonoDisplayImageLimits */
917 case 0x0033:
919 /* ReturnMonoDisplayImageLimits */
920 unsigned char data[] = {0x04, 0x00, 0x34,
921 LCD_WIDTH >> 8, LCD_WIDTH & 0xff,
922 LCD_HEIGHT >> 8, LCD_HEIGHT & 0xff,
923 0x01};
924 iap_send_pkt(data, sizeof(data));
925 break;
928 /* GetNumPlayingTracks */
929 case 0x0035:
931 /* ReturnNumPlayingTracks */
932 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
933 unsigned long playlist_amt = playlist_amount();
934 put_u32(&data[3], playlist_amt);
935 iap_send_pkt(data, sizeof(data));
936 break;
939 /* SetCurrentPlayingTrack */
940 case 0x0037:
942 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
943 long tracknum = get_u32(&serbuf[4]);
945 audio_pause();
946 audio_skip(tracknum - playlist_next(0));
947 if (!paused)
948 audio_resume();
950 /* respond with cmd ok packet */
951 cmd_ok_mode4(cmd);
952 break;
955 default:
957 /* default response is with cmd ok packet */
958 cmd_ok_mode4(cmd);
959 break;
964 static void iap_handlepkt_mode7(void)
966 unsigned int cmd = serbuf[2];
967 switch (cmd)
969 /* RetTunerCaps */
970 case 0x02:
972 /* do nothing */
974 /* GetAccessoryInfo */
975 unsigned char data[] = {0x00, 0x27, 0x00};
976 iap_send_pkt(data, sizeof(data));
977 break;
980 /* RetTunerFreq */
981 case 0x0A:
982 /* fall through */
983 /* TunerSeekDone */
984 case 0x13:
986 rmt_tuner_freq(serbuf);
987 break;
990 /* RdsReadyNotify, RDS station name 0x21 1E 00 + ASCII text*/
991 case 0x21:
993 rmt_tuner_rds_data(serbuf);
994 break;
999 void iap_handlepkt(void)
1002 if(!iap_setupflag) return;
1003 if(serbuf[0] == 0) return;
1005 /* if we are waiting for a remote button to go out,
1006 delay the handling of the new packet */
1007 if(!iap_remotetick)
1009 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
1010 return;
1013 unsigned char mode = serbuf[1];
1014 switch (mode) {
1015 case 0: iap_handlepkt_mode0(); break;
1016 case 2: iap_handlepkt_mode2(); break;
1017 case 3: iap_handlepkt_mode3(); break;
1018 case 4: iap_handlepkt_mode4(); break;
1019 case 7: iap_handlepkt_mode7(); break;
1022 serbuf[0] = 0;
1025 int remote_control_rx(void)
1027 int btn = iap_remotebtn;
1028 if(iap_repeatbtn)
1030 iap_repeatbtn--;
1031 if(!iap_repeatbtn)
1033 iap_remotebtn = BUTTON_NONE;
1034 iap_remotetick = true;
1037 else
1038 iap_remotetick = true;
1040 return btn;
1043 const unsigned char *iap_get_serbuf(void)
1045 return serbuf;