Commit patch in FS#7967 by Vuong Minh Hiep (with some small changes to variable names...
[kugel-rb.git] / apps / iap.c
blob51f5e5900b495bef5e5cfd75bda08e903df0c07c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: iap.c 17400 2008-05-07 14:30:29Z xxxxxx $
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 "gwps.h"
41 #include "action.h"
43 #define RX_BUFLEN 260
44 #define TX_BUFLEN 128
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 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 void iap_setup(int ratenum)
75 iap_bitrate_set(ratenum);
76 iap_pollspeed = 0;
77 iap_remotetick = true;
78 iap_updateflag = false;
79 iap_changedctr = 0;
80 iap_setupflag = true;
81 iap_remotebtn = BUTTON_NONE;
82 tick_add_task(iap_task);
83 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed);
86 void iap_bitrate_set(int ratenum)
88 switch(ratenum)
90 case 0:
91 serial_bitrate(0);
92 break;
93 case 1:
94 serial_bitrate(9600);
95 break;
96 case 2:
97 serial_bitrate(19200);
98 break;
99 case 3:
100 serial_bitrate(38400);
101 break;
102 case 4:
103 serial_bitrate(57600);
104 break;
108 /* Message format:
109 0xff
110 0x55
111 length
112 mode
113 command (2 bytes)
114 parameters (0-n bytes)
115 checksum (length+mode+parameters+checksum == 0)
118 static void iap_send_pkt(const unsigned char * data, int len)
120 int i, chksum;
122 if(len > TX_BUFLEN-4) len = TX_BUFLEN-4;
123 responselen = len + 4;
125 response[0] = 0xFF;
126 response[1] = 0x55;
128 chksum = response[2] = len;
129 for(i = 0; i < len; i ++)
131 chksum += data[i];
132 response[i+3] = data[i];
135 response[i+3] = 0x100 - (chksum & 0xFF);
137 for(i = 0; i < responselen; i ++)
139 while (!tx_rdy()) ;
140 tx_writec(response[i]);
144 int iap_getc(unsigned char x)
146 static unsigned char last_x = 0;
147 static bool newpkt = true;
148 static unsigned char chksum = 0;
150 /* Restart if the sync word is seen */
151 if(x == 0x55 && last_x == 0xff/* && newpkt*/)
153 serbuf[0] = 0;
154 serbuf_i = 0;
155 chksum = 0;
156 newpkt = false;
158 else
160 if(serbuf_i >= RX_BUFLEN)
161 serbuf_i = 0;
163 serbuf[serbuf_i++] = x;
164 chksum += x;
166 last_x = x;
168 /* Broadcast to queue if we have a complete message */
169 if(serbuf_i && (serbuf_i == serbuf[0]+2))
171 serbuf_i = 0;
172 newpkt = true;
173 if(chksum == 0)
174 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
176 return newpkt;
179 /* called by playback when the next track starts */
180 void iap_track_changed(void *ignored)
182 (void)ignored;
183 iap_changedctr = 1;
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_state.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 void iap_handlepkt(void)
217 if(!iap_setupflag) return;
218 if(serbuf[0] == 0) return;
220 /* if we are waiting for a remote button to go out,
221 delay the handling of the new packet */
222 if(!iap_remotetick)
224 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
225 return;
228 /* Handle Mode 0 */
229 if (serbuf[1] == 0x00)
231 switch (serbuf[2])
233 /* get model info */
234 case 0x0D:
236 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
237 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
238 iap_send_pkt(data, sizeof(data));
239 break;
241 /* No idea ??? */
242 case 0x0F:
244 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
245 iap_send_pkt(data, sizeof(data));
246 break;
248 /* FM transmitter sends this: FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
249 case 0x01:
251 if(serbuf[3] == 0x05)
253 sleep(HZ/3);
254 unsigned char data[] = {0x05, 0x02};
255 iap_send_pkt(data, sizeof(data));
257 break;
259 /* FM transmitter sends this: FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (???)*/
260 case 0x13:
262 unsigned char data[] = {0x00, 0x02, 0x00, 0x13};
263 iap_send_pkt(data, sizeof(data));
264 unsigned char data2[] = {0x00, 0x27, 0x00};
265 iap_send_pkt(data2, sizeof(data2));
266 unsigned char data3[] = {0x05, 0x02};
267 iap_send_pkt(data3, sizeof(data3));
268 break;
270 /* FM transmitter sends this: FF 55 02 00 05 F9 (mode switch: AiR mode) */
271 case 0x05:
273 unsigned char data[] = {0x00, 0x02, 0x06, 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28};
274 iap_send_pkt(data, sizeof(data));
275 unsigned char data2[] = {0x00, 0x02, 0x00, 0x05};
276 iap_send_pkt(data2, sizeof(data2));
277 break;
279 /* default response is with cmd ok packet */
280 default:
282 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
283 data[3] = serbuf[2]; //respond with cmd
284 iap_send_pkt(data, sizeof(data));
285 break;
289 /* Handle Mode 2 */
290 else if (serbuf[1] == 0x02)
292 if(serbuf[2] != 0) return;
293 iap_remotebtn = BUTTON_NONE;
294 iap_remotetick = false;
296 if(serbuf[0] >= 3 && serbuf[3] != 0)
298 if(serbuf[3] & 1)
299 iap_remotebtn |= BUTTON_RC_PLAY;
300 if(serbuf[3] & 2)
301 iap_remotebtn |= BUTTON_RC_VOL_UP;
302 if(serbuf[3] & 4)
303 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
304 if(serbuf[3] & 8)
305 iap_remotebtn |= BUTTON_RC_RIGHT;
306 if(serbuf[3] & 16)
307 iap_remotebtn |= BUTTON_RC_LEFT;
309 else if(serbuf[0] >= 4 && serbuf[4] != 0)
311 if(serbuf[4] & 1) /* play */
313 if (audio_status() != AUDIO_STATUS_PLAY)
315 iap_remotebtn |= BUTTON_RC_PLAY;
316 iap_repeatbtn = 2;
317 iap_remotetick = false;
318 iap_changedctr = 1;
321 if(serbuf[4] & 2) /* pause */
323 if (audio_status() == AUDIO_STATUS_PLAY)
325 iap_remotebtn |= BUTTON_RC_PLAY;
326 iap_repeatbtn = 2;
327 iap_remotetick = false;
328 iap_changedctr = 1;
331 if((serbuf[4] & 128) && !iap_btnshuffle) /* shuffle */
333 iap_btnshuffle = true;
334 if(!global_settings.playlist_shuffle)
336 global_settings.playlist_shuffle = 1;
337 settings_save();
338 settings_apply(false);
339 if (audio_status() & AUDIO_STATUS_PLAY)
340 playlist_randomise(NULL, current_tick, true);
342 else if(global_settings.playlist_shuffle)
344 global_settings.playlist_shuffle = 0;
345 settings_save();
346 settings_apply(false);
347 if (audio_status() & AUDIO_STATUS_PLAY)
348 playlist_sort(NULL, true);
351 else
352 iap_btnshuffle = false;
354 else if(serbuf[0] >= 5 && serbuf[5] != 0)
356 if((serbuf[5] & 1) && !iap_btnrepeat) /* repeat */
358 int oldmode = global_settings.repeat_mode;
359 iap_btnrepeat = true;
361 if (oldmode == REPEAT_ONE)
362 global_settings.repeat_mode = REPEAT_OFF;
363 else if (oldmode == REPEAT_ALL)
364 global_settings.repeat_mode = REPEAT_ONE;
365 else if (oldmode == REPEAT_OFF)
366 global_settings.repeat_mode = REPEAT_ALL;
368 settings_save();
369 settings_apply(false);
370 if (audio_status() & AUDIO_STATUS_PLAY)
371 audio_flush_and_reload_tracks();
373 else
374 iap_btnrepeat = false;
376 if(serbuf[5] & 16) /* ffwd */
378 iap_remotebtn |= BUTTON_RC_RIGHT;
380 if(serbuf[5] & 32) /* frwd */
382 iap_remotebtn |= BUTTON_RC_LEFT;
386 /* Handle Mode 3 */
387 else if (serbuf[1] == 0x03)
389 switch(serbuf[2])
391 /* some kind of status packet? */
392 case 0x01:
394 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
395 iap_send_pkt(data, sizeof(data));
396 break;
400 /* Handle Mode 4 */
401 else if (serbuf[1] == 0x04)
403 switch (((unsigned long)serbuf[2] << 8) | serbuf[3])
405 /* Get data updated??? flag */
406 case 0x0009:
408 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
409 data[3] = iap_updateflag ? 0 : 1;
410 iap_send_pkt(data, sizeof(data));
411 break;
413 /* Set data updated??? flag */
414 case 0x000B:
416 iap_updateflag = serbuf[4] ? 0 : 1;
417 /* respond with cmd ok packet */
418 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x0B};
419 iap_send_pkt(data, sizeof(data));
420 break;
422 /* Get iPod size? */
423 case 0x0012:
425 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
426 iap_send_pkt(data, sizeof(data));
427 break;
429 /* Get count of given types */
430 case 0x0018:
432 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
433 unsigned long num = 0;
434 switch(serbuf[4]) /* type number */
436 case 0x01: /* total number of playlists */
437 num = 1;
438 break;
439 case 0x05: /* total number of songs */
440 num = 1;
442 data[3] = num >> 24;
443 data[4] = num >> 16;
444 data[5] = num >> 8;
445 data[6] = num;
446 iap_send_pkt(data, sizeof(data));
447 break;
449 /* Get time and status */
450 case 0x001C:
452 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
453 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
454 struct mp3entry *id3 = audio_current_track();
455 unsigned long time_total = id3->length;
456 unsigned long time_elapsed = id3->elapsed;
457 int status = audio_status();
458 data[3] = time_total >> 24;
459 data[4] = time_total >> 16;
460 data[5] = time_total >> 8;
461 data[6] = time_total;
462 data[7] = time_elapsed >> 24;
463 data[8] = time_elapsed >> 16;
464 data[9] = time_elapsed >> 8;
465 data[10] = time_elapsed;
466 if (status == AUDIO_STATUS_PLAY)
467 data[11] = 0x01; /* play */
468 else if (status & AUDIO_STATUS_PAUSE)
469 data[11] = 0x02; /* pause */
470 iap_send_pkt(data, sizeof(data));
471 break;
473 /* Get current pos in playlist */
474 case 0x001E:
476 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
477 long playlist_pos = playlist_next(0);
478 playlist_pos -= playlist_get_first_index(NULL);
479 if(playlist_pos < 0)
480 playlist_pos += playlist_amount();
481 data[3] = playlist_pos >> 24;
482 data[4] = playlist_pos >> 16;
483 data[5] = playlist_pos >> 8;
484 data[6] = playlist_pos;
485 iap_send_pkt(data, sizeof(data));
486 break;
488 /* Get title of a song number */
489 case 0x0020:
490 /* Get artist of a song number */
491 case 0x0022:
492 /* Get album of a song number */
493 case 0x0024:
495 unsigned char data[70] = {0x04, 0x00, 0xFF};
496 struct mp3entry id3;
497 int fd;
498 long tracknum = (signed long)serbuf[4] << 24 |
499 (signed long)serbuf[5] << 16 |
500 (signed long)serbuf[6] << 8 | serbuf[7];
501 data[2] = serbuf[3] + 1;
502 memcpy(&id3, audio_current_track(), sizeof(id3));
503 tracknum += playlist_get_first_index(NULL);
504 if(tracknum >= playlist_amount())
505 tracknum -= playlist_amount();
507 /* If the tracknumber is not the current one,
508 read id3 from disk */
509 if(playlist_next(0) != tracknum)
511 struct playlist_track_info info;
512 playlist_get_track_info(NULL, tracknum, &info);
513 fd = open(info.filename, O_RDONLY);
514 memset(&id3, 0, sizeof(struct mp3entry));
515 get_metadata(&id3, fd, info.filename);
516 close(fd);
519 /* Return the requested track data */
520 switch(serbuf[3])
522 case 0x20:
523 strncpy((char *)&data[3], id3.title, 64);
524 iap_send_pkt(data, 4+strlen(id3.title));
525 break;
526 case 0x22:
527 strncpy((char *)&data[3], id3.artist, 64);
528 iap_send_pkt(data, 4+strlen(id3.artist));
529 break;
530 case 0x24:
531 strncpy((char *)&data[3], id3.album, 64);
532 iap_send_pkt(data, 4+strlen(id3.album));
533 break;
535 break;
537 /* Set polling mode */
538 case 0x0026:
540 iap_pollspeed = serbuf[4] ? 1 : 0;
541 /*responsed with cmd ok packet */
542 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x26};
543 iap_send_pkt(data, sizeof(data));
544 break;
546 /* AiR playback control */
547 case 0x0029:
549 /* respond with cmd ok packet */
550 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
551 iap_send_pkt(data, sizeof(data));
552 switch(serbuf[4])
554 case 0x01: /* play/pause */
555 iap_remotebtn = BUTTON_RC_PLAY;
556 iap_repeatbtn = 2;
557 iap_remotetick = false;
558 iap_changedctr = 1;
559 break;
560 case 0x02: /* stop */
561 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
562 iap_repeatbtn = 2;
563 iap_remotetick = false;
564 iap_changedctr = 1;
565 break;
566 case 0x03: /* skip++ */
567 iap_remotebtn = BUTTON_RC_RIGHT;
568 iap_repeatbtn = 2;
569 iap_remotetick = false;
570 break;
571 case 0x04: /* skip-- */
572 iap_remotebtn = BUTTON_RC_LEFT;
573 iap_repeatbtn = 2;
574 iap_remotetick = false;
575 break;
576 case 0x05: /* ffwd */
577 iap_remotebtn = BUTTON_RC_RIGHT;
578 iap_remotetick = false;
579 if(iap_pollspeed) iap_pollspeed = 5;
580 break;
581 case 0x06: /* frwd */
582 iap_remotebtn = BUTTON_RC_LEFT;
583 iap_remotetick = false;
584 if(iap_pollspeed) iap_pollspeed = 5;
585 break;
586 case 0x07: /* end ffwd/frwd */
587 iap_remotebtn = BUTTON_NONE;
588 iap_remotetick = false;
589 if(iap_pollspeed) iap_pollspeed = 1;
590 break;
592 break;
594 /* Get shuffle mode */
595 case 0x002C:
597 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
598 data[3] = global_settings.playlist_shuffle ? 1 : 0;
599 iap_send_pkt(data, sizeof(data));
600 break;
602 /* Set shuffle mode */
603 case 0x002E:
605 if(serbuf[4] && !global_settings.playlist_shuffle)
607 global_settings.playlist_shuffle = 1;
608 settings_save();
609 settings_apply(false);
610 if (audio_status() & AUDIO_STATUS_PLAY)
611 playlist_randomise(NULL, current_tick, true);
613 else if(!serbuf[4] && global_settings.playlist_shuffle)
615 global_settings.playlist_shuffle = 0;
616 settings_save();
617 settings_apply(false);
618 if (audio_status() & AUDIO_STATUS_PLAY)
619 playlist_sort(NULL, true);
623 /* respond with cmd ok packet */
624 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x2E};
625 iap_send_pkt(data, sizeof(data));
626 break;
628 /* Get repeat mode */
629 case 0x002F:
631 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
632 if(global_settings.repeat_mode == REPEAT_OFF)
633 data[3] = 0;
634 else if(global_settings.repeat_mode == REPEAT_ONE)
635 data[3] = 1;
636 else
637 data[3] = 2;
638 iap_send_pkt(data, sizeof(data));
639 break;
641 /* Set repeat mode */
642 case 0x0031:
644 int oldmode = global_settings.repeat_mode;
645 if (serbuf[4] == 0)
646 global_settings.repeat_mode = REPEAT_OFF;
647 else if (serbuf[4] == 1)
648 global_settings.repeat_mode = REPEAT_ONE;
649 else if (serbuf[4] == 2)
650 global_settings.repeat_mode = REPEAT_ALL;
652 if (oldmode != global_settings.repeat_mode)
654 settings_save();
655 settings_apply(false);
656 if (audio_status() & AUDIO_STATUS_PLAY)
657 audio_flush_and_reload_tracks();
660 /* respond with cmd ok packet */
661 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x31};
662 iap_send_pkt(data, sizeof(data));
663 break;
665 /* Get Max Screen Size for Picture Upload??? */
666 case 0x0033:
668 unsigned char data[] = {0x04, 0x00, 0x34, 0x01, 0x36, 0x00, 0xA8, 0x01};
669 iap_send_pkt(data, sizeof(data));
670 break;
672 /* Get number songs in current playlist */
673 case 0x0035:
675 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
676 unsigned long playlist_amt = playlist_amount();
677 data[3] = playlist_amt >> 24;
678 data[4] = playlist_amt >> 16;
679 data[5] = playlist_amt >> 8;
680 data[6] = playlist_amt;
681 iap_send_pkt(data, sizeof(data));
682 break;
684 /* Jump to track number in current playlist */
685 case 0x0037:
687 long tracknum = (signed long)serbuf[4] << 24 |
688 (signed long)serbuf[5] << 16 |
689 (signed long)serbuf[6] << 8 | serbuf[7];
690 if (!wps_state.paused)
691 audio_pause();
692 audio_skip(tracknum - playlist_next(0));
693 if (!wps_state.paused)
694 audio_resume();
696 /* respond with cmd ok packet */
697 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
698 data[4] = serbuf[2];
699 data[5] = serbuf[3];
700 iap_send_pkt(data, sizeof(data));
701 break;
703 default:
705 /* default response is with cmd ok packet */
706 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
707 data[4] = serbuf[2];
708 data[5] = serbuf[3];
709 iap_send_pkt(data, sizeof(data));
710 break;
714 serbuf[0] = 0;
717 int remote_control_rx(void)
719 int btn = iap_remotebtn;
720 if(iap_repeatbtn)
722 iap_repeatbtn--;
723 if(!iap_repeatbtn)
725 iap_remotebtn = BUTTON_NONE;
726 iap_remotetick = true;
729 else
730 iap_remotetick = true;
732 return btn;