Add myself to the manual credits
[maemo-rb.git] / apps / iap.c
blobdd29563b1e492995af76ef63445a1cd845ef6cda
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"
33 #include "playlist.h"
34 #include "playback.h"
35 #include "audio.h"
36 #include "settings.h"
37 #include "metadata.h"
38 #include "gwps.h"
40 #include "button.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);
85 void iap_bitrate_set(int ratenum)
87 switch(ratenum)
89 case 0:
90 serial_bitrate(0);
91 break;
92 case 1:
93 serial_bitrate(9600);
94 break;
95 case 2:
96 serial_bitrate(19200);
97 break;
98 case 3:
99 serial_bitrate(38400);
100 break;
101 case 4:
102 serial_bitrate(57600);
103 break;
107 /* Message format:
108 0xff
109 0x55
110 length
111 mode
112 command (2 bytes)
113 parameters (0-n bytes)
114 checksum (length+mode+parameters+checksum == 0)
117 static void iap_send_pkt(const unsigned char * data, int len)
119 int i, chksum;
121 if(len > TX_BUFLEN-4) len = TX_BUFLEN-4;
122 responselen = len + 4;
124 response[0] = 0xFF;
125 response[1] = 0x55;
127 chksum = response[2] = len;
128 for(i = 0; i < len; i ++)
130 chksum += data[i];
131 response[i+3] = data[i];
134 response[i+3] = 0x100 - (chksum & 0xFF);
136 for(i = 0; i < responselen; i ++)
138 while (!tx_rdy()) ;
139 tx_writec(response[i]);
143 int iap_getc(unsigned char x)
145 static unsigned char last_x = 0;
146 static bool newpkt = true;
147 static unsigned char chksum = 0;
149 /* Restart if the sync word is seen */
150 if(x == 0x55 && last_x == 0xff/* && newpkt*/)
152 serbuf[0] = 0;
153 serbuf_i = 0;
154 chksum = 0;
155 newpkt = false;
157 else
159 if(serbuf_i >= RX_BUFLEN)
160 serbuf_i = 0;
162 serbuf[serbuf_i++] = x;
163 chksum += x;
165 last_x = x;
167 /* Broadcast to queue if we have a complete message */
168 if(serbuf_i && (serbuf_i == serbuf[0]+2))
170 serbuf_i = 0;
171 newpkt = true;
172 if(chksum == 0)
173 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
175 return newpkt;
178 void iap_track_changed(void)
180 iap_changedctr = 1;
183 void iap_periodic(void)
185 if(!iap_setupflag) return;
186 if(!iap_pollspeed) return;
188 unsigned char data[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00};
189 unsigned long time_elapsed = audio_current_track()->elapsed;
191 time_elapsed += wps_state.ff_rewind_count;
193 data[3] = 0x04; // playing
195 /* If info has changed, don't flag it right away */
196 if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2)
198 /* track info has changed */
199 iap_changedctr = 0;
200 data[3] = 0x01; // 0x02 has same effect?
201 iap_updateflag = true;
204 data[4] = time_elapsed >> 24;
205 data[5] = time_elapsed >> 16;
206 data[6] = time_elapsed >> 8;
207 data[7] = time_elapsed;
208 iap_send_pkt(data, sizeof(data));
211 void iap_handlepkt(void)
214 if(!iap_setupflag) return;
215 if(serbuf[0] == 0) return;
217 /* if we are waiting for a remote button to go out,
218 delay the handling of the new packet */
219 if(!iap_remotetick)
221 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
222 return;
225 /* Handle Mode 0 */
226 if (serbuf[1] == 0x00)
228 switch (serbuf[2])
230 /* get model info */
231 case 0x0D:
233 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
234 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
235 iap_send_pkt(data, sizeof(data));
236 break;
238 /* No idea ??? */
239 case 0x0F:
241 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
242 iap_send_pkt(data, sizeof(data));
243 break;
245 /* FM transmitter sends this: FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
246 case 0x01:
248 if(serbuf[3] == 0x05)
250 sleep(HZ/3);
251 unsigned char data[] = {0x05, 0x02};
252 iap_send_pkt(data, sizeof(data));
254 break;
256 /* FM transmitter sends this: FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (???)*/
257 case 0x13:
259 unsigned char data[] = {0x00, 0x02, 0x00, 0x13};
260 iap_send_pkt(data, sizeof(data));
261 unsigned char data2[] = {0x00, 0x27, 0x00};
262 iap_send_pkt(data2, sizeof(data2));
263 unsigned char data3[] = {0x05, 0x02};
264 iap_send_pkt(data3, sizeof(data3));
265 break;
267 /* FM transmitter sends this: FF 55 02 00 05 F9 (mode switch: AiR mode) */
268 case 0x05:
270 unsigned char data[] = {0x00, 0x02, 0x06, 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28};
271 iap_send_pkt(data, sizeof(data));
272 unsigned char data2[] = {0x00, 0x02, 0x00, 0x05};
273 iap_send_pkt(data2, sizeof(data2));
274 break;
276 /* default response is with cmd ok packet */
277 default:
279 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
280 data[3] = serbuf[2]; //respond with cmd
281 iap_send_pkt(data, sizeof(data));
282 break;
286 /* Handle Mode 2 */
287 else if (serbuf[1] == 0x02)
289 if(serbuf[2] != 0) return;
290 iap_remotebtn = BUTTON_NONE;
291 iap_remotetick = false;
293 if(serbuf[0] >= 3 && serbuf[3] != 0)
295 if(serbuf[3] & 1)
296 iap_remotebtn |= BUTTON_RC_PLAY;
297 if(serbuf[3] & 2)
298 iap_remotebtn |= BUTTON_RC_VOL_UP;
299 if(serbuf[3] & 4)
300 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
301 if(serbuf[3] & 8)
302 iap_remotebtn |= BUTTON_RC_RIGHT;
303 if(serbuf[3] & 16)
304 iap_remotebtn |= BUTTON_RC_LEFT;
306 else if(serbuf[0] >= 4 && serbuf[4] != 0)
308 if(serbuf[4] & 1) /* play */
310 if (audio_status() != AUDIO_STATUS_PLAY)
312 iap_remotebtn |= BUTTON_RC_PLAY;
313 iap_repeatbtn = 2;
314 iap_remotetick = false;
315 iap_changedctr = 1;
318 if(serbuf[4] & 2) /* pause */
320 if (audio_status() == AUDIO_STATUS_PLAY)
322 iap_remotebtn |= BUTTON_RC_PLAY;
323 iap_repeatbtn = 2;
324 iap_remotetick = false;
325 iap_changedctr = 1;
328 if((serbuf[4] & 128) && !iap_btnshuffle) /* shuffle */
330 iap_btnshuffle = true;
331 if(!global_settings.playlist_shuffle)
333 global_settings.playlist_shuffle = 1;
334 settings_save();
335 settings_apply(false);
336 if (audio_status() & AUDIO_STATUS_PLAY)
337 playlist_randomise(NULL, current_tick, true);
339 else if(global_settings.playlist_shuffle)
341 global_settings.playlist_shuffle = 0;
342 settings_save();
343 settings_apply(false);
344 if (audio_status() & AUDIO_STATUS_PLAY)
345 playlist_sort(NULL, true);
348 else
349 iap_btnshuffle = false;
351 else if(serbuf[0] >= 5 && serbuf[5] != 0)
353 if((serbuf[5] & 1) && !iap_btnrepeat) /* repeat */
355 int oldmode = global_settings.repeat_mode;
356 iap_btnrepeat = true;
358 if (oldmode == REPEAT_ONE)
359 global_settings.repeat_mode = REPEAT_OFF;
360 else if (oldmode == REPEAT_ALL)
361 global_settings.repeat_mode = REPEAT_ONE;
362 else if (oldmode == REPEAT_OFF)
363 global_settings.repeat_mode = REPEAT_ALL;
365 settings_save();
366 settings_apply(false);
367 if (audio_status() & AUDIO_STATUS_PLAY)
368 audio_flush_and_reload_tracks();
370 else
371 iap_btnrepeat = false;
373 if(serbuf[5] & 16) /* ffwd */
375 iap_remotebtn |= BUTTON_RC_RIGHT;
377 if(serbuf[5] & 32) /* frwd */
379 iap_remotebtn |= BUTTON_RC_LEFT;
383 /* Handle Mode 3 */
384 else if (serbuf[1] == 0x03)
386 switch(serbuf[2])
388 /* some kind of status packet? */
389 case 0x01:
391 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
392 iap_send_pkt(data, sizeof(data));
393 break;
397 /* Handle Mode 4 */
398 else if (serbuf[1] == 0x04)
400 switch (((unsigned long)serbuf[2] << 8) | serbuf[3])
402 /* Get data updated??? flag */
403 case 0x0009:
405 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
406 data[3] = iap_updateflag ? 0 : 1;
407 iap_send_pkt(data, sizeof(data));
408 break;
410 /* Set data updated??? flag */
411 case 0x000B:
413 iap_updateflag = serbuf[4] ? 0 : 1;
414 /* respond with cmd ok packet */
415 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x0B};
416 iap_send_pkt(data, sizeof(data));
417 break;
419 /* Get iPod size? */
420 case 0x0012:
422 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
423 iap_send_pkt(data, sizeof(data));
424 break;
426 /* Get count of given types */
427 case 0x0018:
429 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
430 unsigned long num = 0;
431 switch(serbuf[4]) /* type number */
433 case 0x01: /* total number of playlists */
434 num = 1;
435 break;
436 case 0x05: /* total number of songs */
437 num = 1;
439 data[3] = num >> 24;
440 data[4] = num >> 16;
441 data[5] = num >> 8;
442 data[6] = num;
443 iap_send_pkt(data, sizeof(data));
444 break;
446 /* Get time and status */
447 case 0x001C:
449 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
451 struct mp3entry *id3 = audio_current_track();
452 unsigned long time_total = id3->length;
453 unsigned long time_elapsed = id3->elapsed;
454 int status = audio_status();
455 data[3] = time_total >> 24;
456 data[4] = time_total >> 16;
457 data[5] = time_total >> 8;
458 data[6] = time_total;
459 data[7] = time_elapsed >> 24;
460 data[8] = time_elapsed >> 16;
461 data[9] = time_elapsed >> 8;
462 data[10] = time_elapsed;
463 if (status == AUDIO_STATUS_PLAY)
464 data[11] = 0x01; /* play */
465 else if (status & AUDIO_STATUS_PAUSE)
466 data[11] = 0x02; /* pause */
467 iap_send_pkt(data, sizeof(data));
468 break;
470 /* Get current pos in playlist */
471 case 0x001E:
473 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
474 long playlist_pos = playlist_next(0);
475 playlist_pos -= playlist_get_first_index(NULL);
476 if(playlist_pos < 0)
477 playlist_pos += playlist_amount();
478 data[3] = playlist_pos >> 24;
479 data[4] = playlist_pos >> 16;
480 data[5] = playlist_pos >> 8;
481 data[6] = playlist_pos;
482 iap_send_pkt(data, sizeof(data));
483 break;
485 /* Get title of a song number */
486 case 0x0020:
487 /* Get artist of a song number */
488 case 0x0022:
489 /* Get album of a song number */
490 case 0x0024:
492 unsigned char data[70] = {0x04, 0x00, 0xFF};
493 struct mp3entry id3;
494 int fd;
495 long tracknum = (signed long)serbuf[4] << 24 |
496 (signed long)serbuf[5] << 16 |
497 (signed long)serbuf[6] << 8 | serbuf[7];
498 data[2] = serbuf[3] + 1;
499 memcpy(&id3, audio_current_track(), sizeof(id3));
500 tracknum += playlist_get_first_index(NULL);
501 if(tracknum >= playlist_amount())
502 tracknum -= playlist_amount();
504 /* If the tracknumber is not the current one,
505 read id3 from disk */
506 if(playlist_next(0) != tracknum)
508 struct playlist_track_info info;
509 playlist_get_track_info(NULL, tracknum, &info);
510 fd = open(info.filename, O_RDONLY);
511 memset(&id3, 0, sizeof(struct mp3entry));
512 get_metadata(&id3, fd, info.filename);
513 close(fd);
516 /* Return the requested track data */
517 switch(serbuf[3])
519 case 0x20:
520 strncpy((char *)&data[3], id3.title, 64);
521 iap_send_pkt(data, 4+strlen(id3.title));
522 break;
523 case 0x22:
524 strncpy((char *)&data[3], id3.artist, 64);
525 iap_send_pkt(data, 4+strlen(id3.artist));
526 break;
527 case 0x24:
528 strncpy((char *)&data[3], id3.album, 64);
529 iap_send_pkt(data, 4+strlen(id3.album));
530 break;
532 break;
534 /* Set polling mode */
535 case 0x0026:
537 iap_pollspeed = serbuf[4] ? 1 : 0;
538 /*responsed with cmd ok packet */
539 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x26};
540 iap_send_pkt(data, sizeof(data));
541 break;
543 /* AiR playback control */
544 case 0x0029:
546 /* respond with cmd ok packet */
547 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
548 iap_send_pkt(data, sizeof(data));
549 switch(serbuf[4])
551 case 0x01: /* play/pause */
552 iap_remotebtn = BUTTON_RC_PLAY;
553 iap_repeatbtn = 2;
554 iap_remotetick = false;
555 iap_changedctr = 1;
556 break;
557 case 0x02: /* stop */
558 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
559 iap_repeatbtn = 2;
560 iap_remotetick = false;
561 iap_changedctr = 1;
562 break;
563 case 0x03: /* skip++ */
564 iap_remotebtn = BUTTON_RC_RIGHT;
565 iap_repeatbtn = 2;
566 iap_remotetick = false;
567 break;
568 case 0x04: /* skip-- */
569 iap_remotebtn = BUTTON_RC_LEFT;
570 iap_repeatbtn = 2;
571 iap_remotetick = false;
572 break;
573 case 0x05: /* ffwd */
574 iap_remotebtn = BUTTON_RC_RIGHT;
575 iap_remotetick = false;
576 if(iap_pollspeed) iap_pollspeed = 5;
577 break;
578 case 0x06: /* frwd */
579 iap_remotebtn = BUTTON_RC_LEFT;
580 iap_remotetick = false;
581 if(iap_pollspeed) iap_pollspeed = 5;
582 break;
583 case 0x07: /* end ffwd/frwd */
584 iap_remotebtn = BUTTON_NONE;
585 iap_remotetick = false;
586 if(iap_pollspeed) iap_pollspeed = 1;
587 break;
589 break;
591 /* Get shuffle mode */
592 case 0x002C:
594 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
595 data[3] = global_settings.playlist_shuffle ? 1 : 0;
596 iap_send_pkt(data, sizeof(data));
597 break;
599 /* Set shuffle mode */
600 case 0x002E:
602 if(serbuf[4] && !global_settings.playlist_shuffle)
604 global_settings.playlist_shuffle = 1;
605 settings_save();
606 settings_apply(false);
607 if (audio_status() & AUDIO_STATUS_PLAY)
608 playlist_randomise(NULL, current_tick, true);
610 else if(!serbuf[4] && global_settings.playlist_shuffle)
612 global_settings.playlist_shuffle = 0;
613 settings_save();
614 settings_apply(false);
615 if (audio_status() & AUDIO_STATUS_PLAY)
616 playlist_sort(NULL, true);
620 /* respond with cmd ok packet */
621 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x2E};
622 iap_send_pkt(data, sizeof(data));
623 break;
625 /* Get repeat mode */
626 case 0x002F:
628 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
629 if(global_settings.repeat_mode == REPEAT_OFF)
630 data[3] = 0;
631 else if(global_settings.repeat_mode == REPEAT_ONE)
632 data[3] = 1;
633 else
634 data[3] = 2;
635 iap_send_pkt(data, sizeof(data));
636 break;
638 /* Set repeat mode */
639 case 0x0031:
641 int oldmode = global_settings.repeat_mode;
642 if (serbuf[4] == 0)
643 global_settings.repeat_mode = REPEAT_OFF;
644 else if (serbuf[4] == 1)
645 global_settings.repeat_mode = REPEAT_ONE;
646 else if (serbuf[4] == 2)
647 global_settings.repeat_mode = REPEAT_ALL;
649 if (oldmode != global_settings.repeat_mode)
651 settings_save();
652 settings_apply(false);
653 if (audio_status() & AUDIO_STATUS_PLAY)
654 audio_flush_and_reload_tracks();
657 /* respond with cmd ok packet */
658 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x31};
659 iap_send_pkt(data, sizeof(data));
660 break;
662 /* Get Max Screen Size for Picture Upload??? */
663 case 0x0033:
665 unsigned char data[] = {0x04, 0x00, 0x34, 0x01, 0x36, 0x00, 0xA8, 0x01};
666 iap_send_pkt(data, sizeof(data));
667 break;
669 /* Get number songs in current playlist */
670 case 0x0035:
672 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
673 unsigned long playlist_amt = playlist_amount();
674 data[3] = playlist_amt >> 24;
675 data[4] = playlist_amt >> 16;
676 data[5] = playlist_amt >> 8;
677 data[6] = playlist_amt;
678 iap_send_pkt(data, sizeof(data));
679 break;
681 /* Jump to track number in current playlist */
682 case 0x0037:
684 long tracknum = (signed long)serbuf[4] << 24 |
685 (signed long)serbuf[5] << 16 |
686 (signed long)serbuf[6] << 8 | serbuf[7];
687 if (!wps_state.paused)
688 audio_pause();
689 audio_skip(tracknum - playlist_next(0));
690 if (!wps_state.paused)
691 audio_resume();
693 /* respond with cmd ok packet */
694 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
695 data[4] = serbuf[2];
696 data[5] = serbuf[3];
697 iap_send_pkt(data, sizeof(data));
698 break;
700 default:
702 /* default response is with cmd ok packet */
703 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
704 data[4] = serbuf[2];
705 data[5] = serbuf[3];
706 iap_send_pkt(data, sizeof(data));
707 break;
711 serbuf[0] = 0;
714 int remote_control_rx(void)
716 int btn = iap_remotebtn;
717 if(iap_repeatbtn)
719 iap_repeatbtn--;
720 if(!iap_repeatbtn)
722 iap_remotebtn = BUTTON_NONE;
723 iap_remotetick = true;
726 else
727 iap_remotetick = true;
729 return btn;