1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
32 #include "appevents.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 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)
65 count
+= iap_pollspeed
;
66 if (count
< (500/10)) return;
68 /* exec every 500ms if pollspeed == 1 */
70 queue_post(&button_queue
, SYS_IAP_PERIODIC
, 0);
73 void iap_setup(int ratenum
)
75 iap_bitrate_set(ratenum
);
77 iap_remotetick
= true;
78 iap_updateflag
= false;
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
)
97 serial_bitrate(19200);
100 serial_bitrate(38400);
103 serial_bitrate(57600);
114 parameters (0-n bytes)
115 checksum (length+mode+parameters+checksum == 0)
118 static void iap_send_pkt(const unsigned char * data
, int len
)
122 if(len
> TX_BUFLEN
-4) len
= TX_BUFLEN
-4;
123 responselen
= len
+ 4;
128 chksum
= response
[2] = len
;
129 for(i
= 0; i
< len
; i
++)
132 response
[i
+3] = data
[i
];
135 response
[i
+3] = 0x100 - (chksum
& 0xFF);
137 for(i
= 0; i
< responselen
; i
++)
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*/)
160 if(serbuf_i
>= RX_BUFLEN
)
163 serbuf
[serbuf_i
++] = x
;
168 /* Broadcast to queue if we have a complete message */
169 if(serbuf_i
&& (serbuf_i
== serbuf
[0]+2))
174 queue_post(&button_queue
, SYS_IAP_HANDLEPKT
, 0);
179 /* called by playback when the next track starts */
180 void iap_track_changed(void *ignored
)
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 */
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 */
224 queue_post(&button_queue
, SYS_IAP_HANDLEPKT
, 0);
229 if (serbuf
[1] == 0x00)
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
));
244 unsigned char data
[] = {0x00, 0x10, 0x00, 0x01, 0x05};
245 iap_send_pkt(data
, sizeof(data
));
248 /* FM transmitter sends this: FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
251 if(serbuf
[3] == 0x05)
254 unsigned char data
[] = {0x05, 0x02};
255 iap_send_pkt(data
, sizeof(data
));
259 /* FM transmitter sends this: FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (???)*/
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
));
270 /* FM transmitter sends this: FF 55 02 00 05 F9 (mode switch: AiR mode) */
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
));
279 /* default response is with cmd ok packet */
282 unsigned char data
[] = {0x00, 0x02, 0x00, 0x00};
283 data
[3] = serbuf
[2]; //respond with cmd
284 iap_send_pkt(data
, sizeof(data
));
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)
299 iap_remotebtn
|= BUTTON_RC_PLAY
;
301 iap_remotebtn
|= BUTTON_RC_VOL_UP
;
303 iap_remotebtn
|= BUTTON_RC_VOL_DOWN
;
305 iap_remotebtn
|= BUTTON_RC_RIGHT
;
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
;
317 iap_remotetick
= false;
321 if(serbuf
[4] & 2) /* pause */
323 if (audio_status() == AUDIO_STATUS_PLAY
)
325 iap_remotebtn
|= BUTTON_RC_PLAY
;
327 iap_remotetick
= false;
331 if((serbuf
[4] & 128) && !iap_btnshuffle
) /* shuffle */
333 iap_btnshuffle
= true;
334 if(!global_settings
.playlist_shuffle
)
336 global_settings
.playlist_shuffle
= 1;
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;
346 settings_apply(false);
347 if (audio_status() & AUDIO_STATUS_PLAY
)
348 playlist_sort(NULL
, true);
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
;
369 settings_apply(false);
370 if (audio_status() & AUDIO_STATUS_PLAY
)
371 audio_flush_and_reload_tracks();
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
;
387 else if (serbuf
[1] == 0x03)
391 /* some kind of status packet? */
394 unsigned char data
[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
395 iap_send_pkt(data
, sizeof(data
));
401 else if (serbuf
[1] == 0x04)
403 switch (((unsigned long)serbuf
[2] << 8) | serbuf
[3])
405 /* Get data updated??? flag */
408 unsigned char data
[] = {0x04, 0x00, 0x0A, 0x00};
409 data
[3] = iap_updateflag
? 0 : 1;
410 iap_send_pkt(data
, sizeof(data
));
413 /* Set data updated??? flag */
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
));
425 unsigned char data
[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
426 iap_send_pkt(data
, sizeof(data
));
429 /* Get count of given types */
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 */
439 case 0x05: /* total number of songs */
446 iap_send_pkt(data
, sizeof(data
));
449 /* Get time and status */
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
));
473 /* Get current pos in playlist */
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
);
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
));
488 /* Get title of a song number */
490 /* Get artist of a song number */
492 /* Get album of a song number */
495 unsigned char data
[70] = {0x04, 0x00, 0xFF};
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
);
519 /* Return the requested track data */
523 strncpy((char *)&data
[3], id3
.title
, 64);
524 iap_send_pkt(data
, 4+strlen(id3
.title
));
527 strncpy((char *)&data
[3], id3
.artist
, 64);
528 iap_send_pkt(data
, 4+strlen(id3
.artist
));
531 strncpy((char *)&data
[3], id3
.album
, 64);
532 iap_send_pkt(data
, 4+strlen(id3
.album
));
537 /* Set polling mode */
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
));
546 /* AiR playback control */
549 /* respond with cmd ok packet */
550 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
551 iap_send_pkt(data
, sizeof(data
));
554 case 0x01: /* play/pause */
555 iap_remotebtn
= BUTTON_RC_PLAY
;
557 iap_remotetick
= false;
560 case 0x02: /* stop */
561 iap_remotebtn
= BUTTON_RC_PLAY
|BUTTON_REPEAT
;
563 iap_remotetick
= false;
566 case 0x03: /* skip++ */
567 iap_remotebtn
= BUTTON_RC_RIGHT
;
569 iap_remotetick
= false;
571 case 0x04: /* skip-- */
572 iap_remotebtn
= BUTTON_RC_LEFT
;
574 iap_remotetick
= false;
576 case 0x05: /* ffwd */
577 iap_remotebtn
= BUTTON_RC_RIGHT
;
578 iap_remotetick
= false;
579 if(iap_pollspeed
) iap_pollspeed
= 5;
581 case 0x06: /* frwd */
582 iap_remotebtn
= BUTTON_RC_LEFT
;
583 iap_remotetick
= false;
584 if(iap_pollspeed
) iap_pollspeed
= 5;
586 case 0x07: /* end ffwd/frwd */
587 iap_remotebtn
= BUTTON_NONE
;
588 iap_remotetick
= false;
589 if(iap_pollspeed
) iap_pollspeed
= 1;
594 /* Get shuffle mode */
597 unsigned char data
[] = {0x04, 0x00, 0x2D, 0x00};
598 data
[3] = global_settings
.playlist_shuffle
? 1 : 0;
599 iap_send_pkt(data
, sizeof(data
));
602 /* Set shuffle mode */
605 if(serbuf
[4] && !global_settings
.playlist_shuffle
)
607 global_settings
.playlist_shuffle
= 1;
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;
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
));
628 /* Get repeat mode */
631 unsigned char data
[] = {0x04, 0x00, 0x30, 0x00};
632 if(global_settings
.repeat_mode
== REPEAT_OFF
)
634 else if(global_settings
.repeat_mode
== REPEAT_ONE
)
638 iap_send_pkt(data
, sizeof(data
));
641 /* Set repeat mode */
644 int oldmode
= global_settings
.repeat_mode
;
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
)
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
));
665 /* Get Max Screen Size for Picture Upload??? */
668 unsigned char data
[] = {0x04, 0x00, 0x34, 0x01, 0x36, 0x00, 0xA8, 0x01};
669 iap_send_pkt(data
, sizeof(data
));
672 /* Get number songs in current playlist */
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
));
684 /* Jump to track number in current playlist */
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
)
692 audio_skip(tracknum
- playlist_next(0));
693 if (!wps_state
.paused
)
696 /* respond with cmd ok packet */
697 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
700 iap_send_pkt(data
, sizeof(data
));
705 /* default response is with cmd ok packet */
706 unsigned char data
[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
709 iap_send_pkt(data
, sizeof(data
));
717 int remote_control_rx(void)
719 int btn
= iap_remotebtn
;
725 iap_remotebtn
= BUTTON_NONE
;
726 iap_remotetick
= true;
730 iap_remotetick
= true;