summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorRalf Ertzinger <rockbox@camperquake.de>2013-06-22 10:08:23 +0100
committerFrank Gevaerts <frank@gevaerts.be>2013-11-10 18:41:24 +0100
commitb170c73f922e3457b923b4e7fcbec794a8885c77 (patch)
tree89fbdbd8c25af5101a29a1ede3b896332a4e205c /apps
parent500b137308a6ee5c2aba873734a8956d70472f56 (diff)
downloadrockbox-b170c73f922e3457b923b4e7fcbec794a8885c77.tar.gz
rockbox-b170c73f922e3457b923b4e7fcbec794a8885c77.zip
Updated IAP commands.
Originally written and uploaded by Lalufu (Ralf Ertzinger) in Feb 2012. They have been condensed into a single patch and some further additions by Andy Potter. Currently includes Authentication V2 support from iPod to Accessory, RF/BlueTooth transmitter support, selecting a playlist and selecting a track from the current playlist. Does not support uploading Album Art or podcasts. Has been tested on the following iPods, 4th Gen Grayscale, 4th Gen Color/Photo, Mini 2nd Gen, Nano 1st Gen and Video 5.5Gen. Change-Id: Ie8fc098361844132f0228ecbe3c48da948726f5e Co-Authored by: Andy Potter <liveboxandy@gmail.com> Reviewed-on: http://gerrit.rockbox.org/533 Reviewed-by: Frank Gevaerts <frank@gevaerts.be>
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES6
-rw-r--r--apps/iap.c1110
-rw-r--r--apps/iap/iap-core.c1392
-rw-r--r--apps/iap/iap-core.h250
-rw-r--r--apps/iap/iap-lingo.h23
-rw-r--r--apps/iap/iap-lingo0.c1035
-rw-r--r--apps/iap/iap-lingo2.c278
-rw-r--r--apps/iap/iap-lingo3.c1508
-rw-r--r--apps/iap/iap-lingo4.c3153
-rw-r--r--apps/misc.c8
10 files changed, 7644 insertions, 1119 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index 8fa1a7ed40..3968666d98 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -62,7 +62,11 @@ tagtree.c
62filetree.c 62filetree.c
63scrobbler.c 63scrobbler.c
64#ifdef IPOD_ACCESSORY_PROTOCOL 64#ifdef IPOD_ACCESSORY_PROTOCOL
65iap.c 65iap/iap-core.c
66iap/iap-lingo0.c
67iap/iap-lingo2.c
68iap/iap-lingo3.c
69iap/iap-lingo4.c
66#endif 70#endif
67 71
68screen_access.c 72screen_access.c
diff --git a/apps/iap.c b/apps/iap.c
deleted file mode 100644
index 6fe0a03281..0000000000
--- a/apps/iap.c
+++ /dev/null
@@ -1,1110 +0,0 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdio.h>
20#include <stdlib.h>
21#include <stdarg.h>
22#include <string.h>
23
24#include "panic.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"
33
34#include "playlist.h"
35#include "playback.h"
36#include "audio.h"
37#include "settings.h"
38#include "metadata.h"
39#include "wps.h"
40#include "sound.h"
41#include "action.h"
42#include "powermgmt.h"
43
44#include "tuner.h"
45#include "ipod_remote_tuner.h"
46
47#include "filetree.h"
48#include "dir.h"
49
50static volatile int iap_pollspeed = 0;
51static volatile bool iap_remotetick = true;
52static bool iap_setupflag = false, iap_updateflag = false;
53static int iap_changedctr = 0;
54
55static unsigned long iap_remotebtn = 0;
56static int iap_repeatbtn = 0;
57static bool iap_btnrepeat = false, iap_btnshuffle = false;
58
59static unsigned char serbuf[RX_BUFLEN];
60
61static unsigned char response[TX_BUFLEN];
62
63static char cur_dbrecord[5] = {0};
64
65/* states of the iap de-framing state machine */
66enum fsm_state {
67 ST_SYNC, /* wait for 0xFF sync byte */
68 ST_SOF, /* wait for 0x55 start-of-frame byte */
69 ST_LEN, /* receive length byte (small packet) */
70 ST_LENH, /* receive length high byte (large packet) */
71 ST_LENL, /* receive length low byte (large packet) */
72 ST_DATA, /* receive data */
73 ST_CHECK /* verify checksum */
74};
75
76static struct state_t {
77 enum fsm_state state; /* current fsm state */
78 unsigned int len; /* payload data length */
79 unsigned char *payload; /* payload data pointer */
80 unsigned int check; /* running checksum over [len,payload,check] */
81 unsigned int count; /* playload bytes counter */
82} frame_state = {
83 .state = ST_SYNC
84};
85
86static void put_u32(unsigned char *buf, uint32_t data)
87{
88 buf[0] = (data >> 24) & 0xFF;
89 buf[1] = (data >> 16) & 0xFF;
90 buf[2] = (data >> 8) & 0xFF;
91 buf[3] = (data >> 0) & 0xFF;
92}
93
94static uint32_t get_u32(const unsigned char *buf)
95{
96 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
97}
98
99static void iap_task(void)
100{
101 static int count = 0;
102
103 count += iap_pollspeed;
104 if (count < (500/10)) return;
105
106 /* exec every 500ms if pollspeed == 1 */
107 count = 0;
108 queue_post(&button_queue, SYS_IAP_PERIODIC, 0);
109}
110
111/* called by playback when the next track starts */
112static void iap_track_changed(void *ignored)
113{
114 (void)ignored;
115 iap_changedctr = 1;
116}
117
118void iap_setup(int ratenum)
119{
120 iap_bitrate_set(ratenum);
121 iap_pollspeed = 0;
122 iap_remotetick = true;
123 iap_updateflag = false;
124 iap_changedctr = 0;
125 iap_setupflag = true;
126 iap_remotebtn = BUTTON_NONE;
127 tick_add_task(iap_task);
128 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed);
129}
130
131void iap_bitrate_set(int ratenum)
132{
133 switch(ratenum)
134 {
135 case 0:
136 serial_bitrate(0);
137 break;
138 case 1:
139 serial_bitrate(9600);
140 break;
141 case 2:
142 serial_bitrate(19200);
143 break;
144 case 3:
145 serial_bitrate(38400);
146 break;
147 case 4:
148 serial_bitrate(57600);
149 break;
150 }
151}
152
153/* Message format:
154 0xff
155 0x55
156 length
157 mode
158 command (2 bytes)
159 parameters (0-n bytes)
160 checksum (length+mode+parameters+checksum == 0)
161*/
162
163void iap_send_pkt(const unsigned char * data, int len)
164{
165 int i, chksum, responselen;
166
167 if(len > TX_BUFLEN-4) len = TX_BUFLEN-4;
168 responselen = len + 4;
169
170 response[0] = 0xFF;
171 response[1] = 0x55;
172
173 chksum = response[2] = len;
174 for(i = 0; i < len; i ++)
175 {
176 chksum += data[i];
177 response[i+3] = data[i];
178 }
179
180 response[i+3] = 0x100 - (chksum & 0xFF);
181
182 for(i = 0; i < responselen; i ++)
183 {
184 while (!tx_rdy()) ;
185 tx_writec(response[i]);
186 }
187}
188
189bool iap_getc(unsigned char x)
190{
191 struct state_t *s = &frame_state;
192
193 /* run state machine to detect and extract a valid frame */
194 switch (s->state) {
195 case ST_SYNC:
196 if (x == 0xFF) {
197 s->state = ST_SOF;
198 }
199 break;
200 case ST_SOF:
201 if (x == 0x55) {
202 /* received a valid sync/SOF pair */
203 s->state = ST_LEN;
204 } else {
205 s->state = ST_SYNC;
206 return iap_getc(x);
207 }
208 break;
209 case ST_LEN:
210 s->check = x;
211 s->count = 0;
212 s->payload = serbuf;
213 if (x == 0) {
214 /* large packet */
215 s->state = ST_LENH;
216 } else {
217 /* small packet */
218 s->len = x;
219 s->state = ST_DATA;
220 }
221 break;
222 case ST_LENH:
223 s->check += x;
224 s->len = x << 8;
225 s->state = ST_LENL;
226 break;
227 case ST_LENL:
228 s->check += x;
229 s->len += x;
230 if ((s->len == 0) || (s->len > RX_BUFLEN)) {
231 /* invalid length */
232 s->state = ST_SYNC;
233 return iap_getc(x);
234 } else {
235 s->state = ST_DATA;
236 }
237 break;
238 case ST_DATA:
239 s->check += x;
240 s->payload[s->count++] = x;
241 if (s->count == s->len) {
242 s->state = ST_CHECK;
243 }
244 break;
245 case ST_CHECK:
246 s->check += x;
247 if ((s->check & 0xFF) == 0) {
248 /* done, received a valid frame */
249 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
250 }
251 s->state = ST_SYNC;
252 break;
253 default:
254 panicf("Unhandled iap state %d", (int) s->state);
255 break;
256 }
257
258 /* return true while still hunting for the sync and start-of-frame byte */
259 return (s->state == ST_SYNC) || (s->state == ST_SOF);
260}
261
262void iap_periodic(void)
263{
264 if(!iap_setupflag) return;
265 if(!iap_pollspeed) return;
266
267 /* PlayStatusChangeNotification */
268 unsigned char data[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00};
269 unsigned long time_elapsed = audio_current_track()->elapsed;
270
271 time_elapsed += wps_get_ff_rewind_count();
272
273 data[3] = 0x04; /* playing */
274
275 /* If info has changed, don't flag it right away */
276 if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2)
277 {
278 /* track info has changed */
279 iap_changedctr = 0;
280 data[3] = 0x01; /* 0x02 has same effect? */
281 iap_updateflag = true;
282 }
283
284 put_u32(&data[4], time_elapsed);
285 iap_send_pkt(data, sizeof(data));
286}
287
288static void iap_set_remote_volume(void)
289{
290 unsigned char data[] = {0x03, 0x0D, 0x04, 0x00, 0x00};
291 data[4] = (char)((global_settings.volume+58) * 4);
292 iap_send_pkt(data, sizeof(data));
293}
294
295static void cmd_ok_mode0(unsigned char cmd)
296{
297 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
298 data[3] = cmd; /* respond with cmd */
299 iap_send_pkt(data, sizeof(data));
300}
301
302static void iap_handlepkt_mode0(unsigned int len, const unsigned char *buf)
303{
304 (void)len; /* len currently unused */
305
306 unsigned int cmd = buf[1];
307 switch (cmd) {
308 /* Identify */
309 case 0x01:
310 {
311 /* FM transmitter sends this: */
312 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
313 if(buf[2] == 0x05)
314 {
315 sleep(HZ/3);
316 /* RF Transmitter: Begin transmission */
317 unsigned char data[] = {0x05, 0x02};
318 iap_send_pkt(data, sizeof(data));
319 }
320 /* FM remote sends this: */
321 /* FF 55 03 00 01 02 FA (1st thing sent) */
322 else if (buf[2] == 0x02)
323 {
324 /* useful only for apple firmware */
325 }
326 break;
327 }
328
329 /* EnterRemoteUIMode, FM transmitter sends FF 55 02 00 05 F9 */
330 case 0x05:
331 {
332 /* ACK Pending (3000 ms) */
333 unsigned char data[] = {0x00, 0x02, 0x06,
334 0x05, 0x00, 0x00, 0x0B, 0xB8};
335 iap_send_pkt(data, sizeof(data));
336 cmd_ok_mode0(cmd);
337 break;
338 }
339
340 /* ExitRemoteUIMode */
341 case 0x06:
342 {
343 audio_stop();
344 cmd_ok_mode0(cmd);
345 break;
346 }
347
348 /* RequestiPodSoftwareVersion, Ipod FM remote sends FF 55 02 00 09 F5 */
349 case 0x09:
350 {
351 /* ReturniPodSoftwareVersion, ipod5G firmware version */
352 unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01};
353 iap_send_pkt(data, sizeof(data));
354 break;
355 }
356
357 /* RequestiPodModelNum */
358 case 0x0D:
359 {
360 /* ipod is supposed to work only with 5G and nano 2G */
361 /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34,
362 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */
363 /* ReturniPodModelNum */
364 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
365 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
366 iap_send_pkt(data, sizeof(data));
367 break;
368 }
369
370 /* RequestLingoProtocolVersion */
371 case 0x0F:
372 {
373 /* ReturnLingoProtocolVersion */
374 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
375 data[2] = buf[2];
376 iap_send_pkt(data, sizeof(data));
377 break;
378 }
379
380 /* IdentifyDeviceLingoes */
381 case 0x13:
382 {
383 cmd_ok_mode0(cmd);
384
385 uint32_t lingoes = get_u32(&buf[2]);
386
387 if (lingoes == 0x35)
388 /* FM transmitter sends this: */
389 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
390 {
391 /* GetAccessoryInfo */
392 unsigned char data2[] = {0x00, 0x27, 0x00};
393 iap_send_pkt(data2, sizeof(data2));
394 /* RF Transmitter: Begin transmission */
395 unsigned char data3[] = {0x05, 0x02};
396 iap_send_pkt(data3, sizeof(data3));
397 }
398 else
399 {
400 /* ipod fm remote sends this: */
401 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
402 if (lingoes & (1 << 7)) /* bit 7 = RF tuner lingo */
403 radio_present = 1;
404 /* GetDevAuthenticationInfo */
405 unsigned char data4[] = {0x00, 0x14};
406 iap_send_pkt(data4, sizeof(data4));
407 }
408 break;
409 }
410
411 /* RetDevAuthenticationInfo */
412 case 0x15:
413 {
414 /* AckDevAuthenticationInfo */
415 unsigned char data0[] = {0x00, 0x16, 0x00};
416 iap_send_pkt(data0, sizeof(data0));
417 /* GetAccessoryInfo */
418 unsigned char data1[] = {0x00, 0x27, 0x00};
419 iap_send_pkt(data1, sizeof(data1));
420 /* AckDevAuthenticationStatus, mandatory to enable some hardware */
421 unsigned char data2[] = {0x00, 0x19, 0x00};
422 iap_send_pkt(data2, sizeof(data2));
423 if (radio_present == 1)
424 {
425 /* GetTunerCaps */
426 unsigned char data3[] = {0x07, 0x01};
427 iap_send_pkt(data3, sizeof(data3));
428 }
429 iap_set_remote_volume();
430 break;
431 }
432
433 /* RetDevAuthenticationSignature */
434 case 0x18:
435 {
436 /* Isn't used since we don't send the 0x00 0x17 command */
437 break;
438 }
439
440 /* GetIpodOptions */
441 case 0x24:
442 {
443 /* RetIpodOptions (ipod video send this) */
444 unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00,
445 0x00, 0x00, 0x00, 0x00, 0x01};
446 iap_send_pkt(data, sizeof(data));
447 break;
448 }
449
450 /* default response is with cmd ok packet */
451 default:
452 {
453 cmd_ok_mode0(cmd);
454 break;
455 }
456 }
457}
458
459static void iap_handlepkt_mode2(unsigned int len, const unsigned char *buf)
460{
461 if(buf[1] != 0) return;
462 iap_remotebtn = BUTTON_NONE;
463 iap_remotetick = false;
464
465 if(len >= 3 && buf[2] != 0)
466 {
467 if(buf[2] & 1)
468 iap_remotebtn |= BUTTON_RC_PLAY;
469 if(buf[2] & 2)
470 iap_remotebtn |= BUTTON_RC_VOL_UP;
471 if(buf[2] & 4)
472 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
473 if(buf[2] & 8)
474 iap_remotebtn |= BUTTON_RC_RIGHT;
475 if(buf[2] & 16)
476 iap_remotebtn |= BUTTON_RC_LEFT;
477 }
478 else if(len >= 4 && buf[3] != 0)
479 {
480 if(buf[3] & 1) /* play */
481 {
482 if (audio_status() != AUDIO_STATUS_PLAY)
483 {
484 iap_remotebtn |= BUTTON_RC_PLAY;
485 iap_repeatbtn = 2;
486 iap_remotetick = false;
487 iap_changedctr = 1;
488 }
489 }
490 if(buf[3] & 2) /* pause */
491 {
492 if (audio_status() == AUDIO_STATUS_PLAY)
493 {
494 iap_remotebtn |= BUTTON_RC_PLAY;
495 iap_repeatbtn = 2;
496 iap_remotetick = false;
497 iap_changedctr = 1;
498 }
499 }
500 if((buf[3] & 128) && !iap_btnshuffle) /* shuffle */
501 {
502 iap_btnshuffle = true;
503 if(!global_settings.playlist_shuffle)
504 {
505 global_settings.playlist_shuffle = 1;
506 settings_save();
507 if (audio_status() & AUDIO_STATUS_PLAY)
508 playlist_randomise(NULL, current_tick, true);
509 }
510 else if(global_settings.playlist_shuffle)
511 {
512 global_settings.playlist_shuffle = 0;
513 settings_save();
514 if (audio_status() & AUDIO_STATUS_PLAY)
515 playlist_sort(NULL, true);
516 }
517 }
518 else
519 iap_btnshuffle = false;
520 }
521 else if(len >= 5 && buf[4] != 0)
522 {
523 if((buf[4] & 1) && !iap_btnrepeat) /* repeat */
524 {
525 int oldmode = global_settings.repeat_mode;
526 iap_btnrepeat = true;
527
528 if (oldmode == REPEAT_ONE)
529 global_settings.repeat_mode = REPEAT_OFF;
530 else if (oldmode == REPEAT_ALL)
531 global_settings.repeat_mode = REPEAT_ONE;
532 else if (oldmode == REPEAT_OFF)
533 global_settings.repeat_mode = REPEAT_ALL;
534
535 settings_save();
536 if (audio_status() & AUDIO_STATUS_PLAY)
537 audio_flush_and_reload_tracks();
538 }
539 else
540 iap_btnrepeat = false;
541
542 if(buf[4] & 16) /* ffwd */
543 {
544 iap_remotebtn |= BUTTON_RC_RIGHT;
545 }
546 if(buf[4] & 32) /* frwd */
547 {
548 iap_remotebtn |= BUTTON_RC_LEFT;
549 }
550 }
551}
552
553static void iap_handlepkt_mode3(unsigned int len, const unsigned char *buf)
554{
555 (void)len; /* len currently unused */
556
557 unsigned int cmd = buf[1];
558 switch (cmd)
559 {
560 /* GetCurrentEQProfileIndex */
561 case 0x01:
562 {
563 /* RetCurrentEQProfileIndex */
564 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
565 iap_send_pkt(data, sizeof(data));
566 break;
567 }
568
569 /* SetRemoteEventNotification */
570 case 0x08:
571 {
572 /* ACK */
573 unsigned char data[] = {0x03, 0x00, 0x00, 0x08};
574 iap_send_pkt(data, sizeof(data));
575 break;
576 }
577
578 /* GetiPodStateInfo */
579 case 0x0C:
580 {
581 /* request ipod volume */
582 if (buf[2] == 0x04)
583 {
584 iap_set_remote_volume();
585 }
586 break;
587 }
588
589 /* SetiPodStateInfo */
590 case 0x0E:
591 {
592 if (buf[2] == 0x04)
593 global_settings.volume = (-58)+((int)buf[4]+1)/4;
594 sound_set_volume(global_settings.volume); /* indent BUG? */
595 break;
596 }
597 }
598}
599
600static void cmd_ok_mode4(unsigned int cmd)
601{
602 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
603 data[4] = (cmd >> 8) & 0xFF;
604 data[5] = (cmd >> 0) & 0xFF;
605 iap_send_pkt(data, sizeof(data));
606}
607
608static void get_playlist_name(unsigned char *dest,
609 unsigned long item_offset,
610 size_t max_length)
611{
612 if (item_offset == 0) return;
613 DIR* dp;
614 struct dirent* playlist_file = NULL;
615
616 dp = opendir(global_settings.playlist_catalog_dir);
617
618 char *extension;
619 unsigned long nbr = 0;
620 while ((nbr < item_offset) && ((playlist_file = readdir(dp)) != NULL))
621 {
622 /*Increment only if there is a playlist extension*/
623 if ((extension=strrchr(playlist_file->d_name, '.')) != NULL){
624 if ((strcmp(extension, ".m3u") == 0 ||
625 strcmp(extension, ".m3u8") == 0))
626 nbr++;
627 }
628 }
629 if (playlist_file != NULL) {
630 strlcpy(dest, playlist_file->d_name, max_length);
631 }
632 closedir(dp);
633}
634
635static void iap_handlepkt_mode4(unsigned int len, const unsigned char *buf)
636{
637 (void)len; /* len currently unused */
638
639 unsigned int cmd = (buf[1] << 8) | buf[2];
640 switch (cmd)
641 {
642 /* GetAudioBookSpeed */
643 case 0x0009:
644 {
645 /* ReturnAudioBookSpeed */
646 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
647 data[3] = iap_updateflag ? 0 : 1;
648 iap_send_pkt(data, sizeof(data));
649 break;
650 }
651
652 /* SetAudioBookSpeed */
653 case 0x000B:
654 {
655 iap_updateflag = buf[3] ? 0 : 1;
656 /* respond with cmd ok packet */
657 cmd_ok_mode4(cmd);
658 break;
659 }
660
661 /* RequestProtocolVersion */
662 case 0x0012:
663 {
664 /* ReturnProtocolVersion */
665 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
666 iap_send_pkt(data, sizeof(data));
667 break;
668 }
669
670 /* SelectDBRecord */
671 case 0x0017:
672 {
673 memcpy(cur_dbrecord, buf + 3, 5);
674 cmd_ok_mode4(cmd);
675 break;
676 }
677
678 /* GetNumberCategorizedDBRecords */
679 case 0x0018:
680 {
681 /* ReturnNumberCategorizedDBRecords */
682 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
683 unsigned long num = 0;
684
685 DIR* dp;
686 unsigned long nbr_total_playlists = 0;
687 struct dirent* playlist_file = NULL;
688 char *extension;
689
690 switch(buf[3]) /* type number */
691 {
692 case 0x01: /* total number of playlists */
693 dp = opendir(global_settings.playlist_catalog_dir);
694 while ((playlist_file = readdir(dp)) != NULL)
695 {
696 /*Increment only if there is a playlist extension*/
697 if ((extension=strrchr(playlist_file->d_name, '.'))
698 != NULL) {
699 if ((strcmp(extension, ".m3u") == 0 ||
700 strcmp(extension, ".m3u8") == 0))
701 nbr_total_playlists++;
702 }
703 }
704 closedir(dp);
705 /*Add 1 for the main playlist*/
706 num = nbr_total_playlists + 1;
707 break;
708 case 0x05: /* total number of songs */
709 num = 1;
710 break;
711 }
712 put_u32(&data[3], num);
713 iap_send_pkt(data, sizeof(data));
714 break;
715 }
716
717 /* RetrieveCategorizedDatabaseRecords */
718 case 0x001A:
719 {
720 /* ReturnCategorizedDatabaseRecord */
721 unsigned char data[7 + MAX_PATH] =
722 {0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00,
723 'R', 'O', 'C', 'K', 'B', 'O', 'X', '\0'};
724
725 unsigned long item_offset = get_u32(&buf[4]);
726
727 get_playlist_name(data + 7, item_offset, MAX_PATH);
728 /*Remove file extension*/
729 char *dot=NULL;
730 dot = (strrchr(data+7, '.'));
731 if (dot != NULL)
732 *dot = '\0';
733 iap_send_pkt(data, 7 + strlen(data+7) + 1);
734 break;
735 }
736
737 /* GetPlayStatus */
738 case 0x001C:
739 {
740 /* ReturnPlayStatus */
741 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
742 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
743 struct mp3entry *id3 = audio_current_track();
744 unsigned long time_total = id3->length;
745 unsigned long time_elapsed = id3->elapsed;
746 int status = audio_status();
747 put_u32(&data[3], time_total);
748 put_u32(&data[7], time_elapsed);
749 if (status == AUDIO_STATUS_PLAY)
750 data[11] = 0x01; /* play */
751 else if (status & AUDIO_STATUS_PAUSE)
752 data[11] = 0x02; /* pause */
753 iap_send_pkt(data, sizeof(data));
754 break;
755 }
756
757 /* GetCurrentPlayingTrackIndex */
758 case 0x001E:
759 {
760 /* ReturnCurrentPlayingTrackIndex */
761 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
762 long playlist_pos = playlist_next(0);
763 playlist_pos -= playlist_get_first_index(NULL);
764 if(playlist_pos < 0)
765 playlist_pos += playlist_amount();
766 put_u32(&data[3], playlist_pos);
767 iap_send_pkt(data, sizeof(data));
768 break;
769 }
770
771 /* GetIndexedPlayingTrackTitle */
772 case 0x0020:
773 /* GetIndexedPlayingTrackArtistName */
774 case 0x0022:
775 /* GetIndexedPlayingTrackAlbumName */
776 case 0x0024:
777 {
778 unsigned char data[70] = {0x04, 0x00, 0xFF};
779 struct mp3entry id3;
780 int fd;
781 size_t len;
782 long tracknum = get_u32(&buf[3]);
783
784 data[2] = cmd + 1;
785 memcpy(&id3, audio_current_track(), sizeof(id3));
786 tracknum += playlist_get_first_index(NULL);
787 if(tracknum >= playlist_amount())
788 tracknum -= playlist_amount();
789
790 /* If the tracknumber is not the current one,
791 read id3 from disk */
792 if(playlist_next(0) != tracknum)
793 {
794 struct playlist_track_info info;
795 playlist_get_track_info(NULL, tracknum, &info);
796 fd = open(info.filename, O_RDONLY);
797 memset(&id3, 0, sizeof(struct mp3entry));
798 get_metadata(&id3, fd, info.filename);
799 close(fd);
800 }
801
802 /* Return the requested track data */
803 switch(cmd)
804 {
805 case 0x20:
806 len = strlcpy((char *)&data[3], id3.title, 64);
807 iap_send_pkt(data, 4+len);
808 break;
809 case 0x22:
810 len = strlcpy((char *)&data[3], id3.artist, 64);
811 iap_send_pkt(data, 4+len);
812 break;
813 case 0x24:
814 len = strlcpy((char *)&data[3], id3.album, 64);
815 iap_send_pkt(data, 4+len);
816 break;
817 }
818 break;
819 }
820
821 /* SetPlayStatusChangeNotification */
822 case 0x0026:
823 {
824 iap_pollspeed = buf[3] ? 1 : 0;
825 /* respond with cmd ok packet */
826 cmd_ok_mode4(cmd);
827 break;
828 }
829
830 /* PlayCurrentSelection */
831 case 0x0028:
832 {
833 switch (cur_dbrecord[0])
834 {
835 case 0x01:
836 {/*Playlist*/
837 unsigned long item_offset = get_u32(&cur_dbrecord[1]);
838
839 unsigned char selected_playlist
840 [sizeof(global_settings.playlist_catalog_dir)
841 + 1
842 + MAX_PATH] = {0};
843
844 strcpy(selected_playlist,
845 global_settings.playlist_catalog_dir);
846 int len = strlen(selected_playlist);
847 selected_playlist[len] = '/';
848 get_playlist_name (selected_playlist + len + 1,
849 item_offset,
850 MAX_PATH);
851 ft_play_playlist(selected_playlist,
852 global_settings.playlist_catalog_dir,
853 strrchr(selected_playlist, '/') + 1);
854 break;
855 }
856 }
857 cmd_ok_mode4(cmd);
858 break;
859 }
860
861 /* PlayControl */
862 case 0x0029:
863 {
864 switch(buf[3])
865 {
866 case 0x01: /* play/pause */
867 iap_remotebtn = BUTTON_RC_PLAY;
868 iap_repeatbtn = 2;
869 iap_remotetick = false;
870 iap_changedctr = 1;
871 break;
872 case 0x02: /* stop */
873 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
874 iap_repeatbtn = 2;
875 iap_remotetick = false;
876 iap_changedctr = 1;
877 break;
878 case 0x03: /* skip++ */
879 iap_remotebtn = BUTTON_RC_RIGHT;
880 iap_repeatbtn = 2;
881 iap_remotetick = false;
882 break;
883 case 0x04: /* skip-- */
884 iap_remotebtn = BUTTON_RC_LEFT;
885 iap_repeatbtn = 2;
886 iap_remotetick = false;
887 break;
888 case 0x05: /* ffwd */
889 iap_remotebtn = BUTTON_RC_RIGHT;
890 iap_remotetick = false;
891 if(iap_pollspeed) iap_pollspeed = 5;
892 break;
893 case 0x06: /* frwd */
894 iap_remotebtn = BUTTON_RC_LEFT;
895 iap_remotetick = false;
896 if(iap_pollspeed) iap_pollspeed = 5;
897 break;
898 case 0x07: /* end ffwd/frwd */
899 iap_remotebtn = BUTTON_NONE;
900 iap_remotetick = false;
901 if(iap_pollspeed) iap_pollspeed = 1;
902 break;
903 }
904 /* respond with cmd ok packet */
905 cmd_ok_mode4(cmd);
906 break;
907 }
908
909 /* GetShuffle */
910 case 0x002C:
911 {
912 /* ReturnShuffle */
913 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
914 data[3] = global_settings.playlist_shuffle ? 1 : 0;
915 iap_send_pkt(data, sizeof(data));
916 break;
917 }
918
919 /* SetShuffle */
920 case 0x002E:
921 {
922 if(buf[3] && !global_settings.playlist_shuffle)
923 {
924 global_settings.playlist_shuffle = 1;
925 settings_save();
926 if (audio_status() & AUDIO_STATUS_PLAY)
927 playlist_randomise(NULL, current_tick, true);
928 }
929 else if(!buf[3] && global_settings.playlist_shuffle)
930 {
931 global_settings.playlist_shuffle = 0;
932 settings_save();
933 if (audio_status() & AUDIO_STATUS_PLAY)
934 playlist_sort(NULL, true);
935 }
936
937 /* respond with cmd ok packet */
938 cmd_ok_mode4(cmd);
939 break;
940 }
941
942 /* GetRepeat */
943 case 0x002F:
944 {
945 /* ReturnRepeat */
946 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
947 if(global_settings.repeat_mode == REPEAT_OFF)
948 data[3] = 0;
949 else if(global_settings.repeat_mode == REPEAT_ONE)
950 data[3] = 1;
951 else
952 data[3] = 2;
953 iap_send_pkt(data, sizeof(data));
954 break;
955 }
956
957 /* SetRepeat */
958 case 0x0031:
959 {
960 int oldmode = global_settings.repeat_mode;
961 if (buf[3] == 0)
962 global_settings.repeat_mode = REPEAT_OFF;
963 else if (buf[3] == 1)
964 global_settings.repeat_mode = REPEAT_ONE;
965 else if (buf[3] == 2)
966 global_settings.repeat_mode = REPEAT_ALL;
967
968 if (oldmode != global_settings.repeat_mode)
969 {
970 settings_save();
971 if (audio_status() & AUDIO_STATUS_PLAY)
972 audio_flush_and_reload_tracks();
973 }
974
975 /* respond with cmd ok packet */
976 cmd_ok_mode4(cmd);
977 break;
978 }
979
980 /* GetMonoDisplayImageLimits */
981 case 0x0033:
982 {
983 /* ReturnMonoDisplayImageLimits */
984 unsigned char data[] = {0x04, 0x00, 0x34,
985 LCD_WIDTH >> 8, LCD_WIDTH & 0xff,
986 LCD_HEIGHT >> 8, LCD_HEIGHT & 0xff,
987 0x01};
988 iap_send_pkt(data, sizeof(data));
989 break;
990 }
991
992 /* GetNumPlayingTracks */
993 case 0x0035:
994 {
995 /* ReturnNumPlayingTracks */
996 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
997 unsigned long playlist_amt = playlist_amount();
998 put_u32(&data[3], playlist_amt);
999 iap_send_pkt(data, sizeof(data));
1000 break;
1001 }
1002
1003 /* SetCurrentPlayingTrack */
1004 case 0x0037:
1005 {
1006 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
1007 long tracknum = get_u32(&buf[3]);
1008
1009 audio_pause();
1010 audio_skip(tracknum - playlist_next(0));
1011 if (!paused)
1012 audio_resume();
1013
1014 /* respond with cmd ok packet */
1015 cmd_ok_mode4(cmd);
1016 break;
1017 }
1018
1019 default:
1020 {
1021 /* default response is with cmd ok packet */
1022 cmd_ok_mode4(cmd);
1023 break;
1024 }
1025 }
1026}
1027
1028static void iap_handlepkt_mode7(unsigned int len, const unsigned char *buf)
1029{
1030 unsigned int cmd = buf[1];
1031 switch (cmd)
1032 {
1033 /* RetTunerCaps */
1034 case 0x02:
1035 {
1036 /* do nothing */
1037
1038 /* GetAccessoryInfo */
1039 unsigned char data[] = {0x00, 0x27, 0x00};
1040 iap_send_pkt(data, sizeof(data));
1041 break;
1042 }
1043
1044 /* RetTunerFreq */
1045 case 0x0A:
1046 /* fall through */
1047 /* TunerSeekDone */
1048 case 0x13:
1049 {
1050 rmt_tuner_freq(len, buf);
1051 break;
1052 }
1053
1054 /* RdsReadyNotify, RDS station name 0x21 1E 00 + ASCII text*/
1055 case 0x21:
1056 {
1057 rmt_tuner_rds_data(len, buf);
1058 break;
1059 }
1060 }
1061}
1062
1063void iap_handlepkt(void)
1064{
1065 struct state_t *s = &frame_state;
1066
1067 if(!iap_setupflag) return;
1068
1069 /* if we are waiting for a remote button to go out,
1070 delay the handling of the new packet */
1071 if(!iap_remotetick)
1072 {
1073 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
1074 return;
1075 }
1076
1077 /* handle command by mode */
1078 unsigned char mode = s->payload[0];
1079 switch (mode) {
1080 case 0: iap_handlepkt_mode0(s->len, s->payload); break;
1081 case 2: iap_handlepkt_mode2(s->len, s->payload); break;
1082 case 3: iap_handlepkt_mode3(s->len, s->payload); break;
1083 case 4: iap_handlepkt_mode4(s->len, s->payload); break;
1084 case 7: iap_handlepkt_mode7(s->len, s->payload); break;
1085 }
1086}
1087
1088int remote_control_rx(void)
1089{
1090 int btn = iap_remotebtn;
1091 if(iap_repeatbtn)
1092 {
1093 iap_repeatbtn--;
1094 if(!iap_repeatbtn)
1095 {
1096 iap_remotebtn = BUTTON_NONE;
1097 iap_remotetick = true;
1098 }
1099 }
1100 else
1101 iap_remotetick = true;
1102
1103 return btn;
1104}
1105
1106const unsigned char *iap_get_serbuf(void)
1107{
1108 return serbuf;
1109}
1110
diff --git a/apps/iap/iap-core.c b/apps/iap/iap-core.c
new file mode 100644
index 0000000000..ddcb22853a
--- /dev/null
+++ b/apps/iap/iap-core.c
@@ -0,0 +1,1392 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdio.h>
20#include <stdlib.h>
21#include <stdarg.h>
22#include <string.h>
23
24#include "panic.h"
25#include "iap-core.h"
26#include "iap-lingo.h"
27#include "button.h"
28#include "config.h"
29#include "cpu.h"
30#include "system.h"
31#include "kernel.h"
32#include "thread.h"
33#include "serial.h"
34#include "appevents.h"
35#include "core_alloc.h"
36
37#include "playlist.h"
38#include "playback.h"
39#include "audio.h"
40#include "settings.h"
41#include "metadata.h"
42#include "sound.h"
43#include "action.h"
44#include "powermgmt.h"
45
46#include "tuner.h"
47#include "ipod_remote_tuner.h"
48
49
50/* MS_TO_TICKS converts a milisecond time period into the
51 * corresponding amount of ticks. If the time period cannot
52 * be accurately measured in ticks it will round up.
53 */
54#if (HZ>1000)
55#error "HZ is >1000, please fix MS_TO_TICKS"
56#endif
57#define MS_PER_HZ (1000/HZ)
58#define MS_TO_TICKS(x) (((x)+MS_PER_HZ-1)/MS_PER_HZ)
59/* IAP specifies a timeout of 25ms for traffic from a device to the iPod.
60 * Depending on HZ this cannot be accurately measured. Find out the next
61 * best thing.
62 */
63#define IAP_PKT_TIMEOUT (MS_TO_TICKS(25))
64
65/* Events in the iap_queue */
66#define IAP_EV_TICK (1) /* The regular task timeout */
67#define IAP_EV_MSG_RCVD (2) /* A complete message has been received from the device */
68#define IAP_EV_MALLOC (3) /* Allocate memory for the RX/TX buffers */
69
70static bool iap_started = false;
71static bool iap_setupflag = false, iap_running = false;
72/* This is set to true if a SYS_POWEROFF message is received,
73 * signalling impending power off
74 */
75static bool iap_shutdown = false;
76static struct timeout iap_task_tmo;
77
78unsigned long iap_remotebtn = 0;
79/* Used to make sure a button press is delivered to the processing
80 * backend. While this is !0, no new incoming messasges are processed.
81 * Counted down by remote_control_rx()
82 */
83int iap_repeatbtn = 0;
84/* Used to time out button down events in case we miss the button up event
85 * from the device somehow.
86 * If a device sends a button down event it's required to repeat that event
87 * every 30 to 100ms as long as the button is pressed, and send an explicit
88 * button up event if the button is released.
89 * In case the button up event is lost any down events will time out after
90 * ~200ms.
91 * iap_periodic() will count down this variable and reset all buttons if
92 * it reaches 0
93 */
94unsigned int iap_timeoutbtn = 0;
95bool iap_btnrepeat = false, iap_btnshuffle = false;
96
97static long thread_stack[(DEFAULT_STACK_SIZE*6)/sizeof(long)];
98static struct event_queue iap_queue;
99
100/* These are pointer used to manage a dynamically allocated buffer which
101 * will hold both the RX and TX side of things.
102 *
103 * iap_buffer_handle is the handle returned from core_alloc()
104 * iap_buffers points to the start of the complete buffer
105 *
106 * The buffer is partitioned as follows:
107 * - TX_BUFLEN+6 bytes for the TX buffer
108 * The 6 extra bytes are for the sync byte, the SOP byte, the length indicators
109 * (3 bytes) and the checksum byte.
110 * iap_txstart points to the beginning of the TX buffer
111 * iap_txpayload points to the beginning of the payload portion of the TX buffer
112 * iap_txnext points to the position where the next byte will be placed
113 *
114 * - RX_BUFLEN+2 bytes for the RX buffer
115 * The RX buffer can hold multiple packets at once, up to it's
116 * maximum capacity. Every packet consists of a two byte length
117 * indicator followed by the actual payload. The length indicator
118 * is two bytes for every length, even for packets with a length <256
119 * bytes.
120 *
121 * Once a packet has been processed from the RX buffer the rest
122 * of the buffer (and the pointers below) are shifted to the front
123 * so that the next packet again starts at the beginning of the
124 * buffer. This happens with interrupts disabled, to prevent
125 * writing into the buffer during the move.
126 *
127 * iap_rxstart points to the beginning of the RX buffer
128 * iap_rxpayload starts to the beginning of the currently recieved
129 * packet
130 * iap_rxnext points to the position where the next incoming byte
131 * will be placed
132 * iap_rxlen is not a pointer, but an indicator of the free
133 * space left in the RX buffer.
134 *
135 * The RX buffer is placed behind the TX buffer so that an eventual TX
136 * buffer overflow has some place to spill into where it will not cause
137 * immediate damage. See the comments for IAP_TX_* and iap_send_tx()
138 */
139#define IAP_MALLOC_SIZE (TX_BUFLEN+6+RX_BUFLEN+2)
140#ifdef IAP_MALLOC_DYNAMIC
141static int iap_buffer_handle;
142#endif
143static unsigned char* iap_buffers;
144static unsigned char* iap_rxstart;
145static unsigned char* iap_rxpayload;
146static unsigned char* iap_rxnext;
147static uint32_t iap_rxlen;
148static unsigned char* iap_txstart;
149unsigned char* iap_txpayload;
150unsigned char* iap_txnext;
151
152/* The versions of the various Lingoes we support. A major version
153 * of 0 means unsupported
154 */
155unsigned char lingo_versions[32][2] = {
156 {1, 9}, /* General lingo, 0x00 */
157 {0, 0}, /* Microphone lingo, 0x01, unsupported */
158 {1, 2}, /* Simple remote lingo, 0x02 */
159 {1, 5}, /* Display remote lingo, 0x03 */
160 {1, 12}, /* Extended Interface lingo, 0x04 */
161 {1, 1}, /* RF/BT Transmitter lingo, 0x05 */
162 {} /* All others are unsupported */
163};
164
165/* states of the iap de-framing state machine */
166enum fsm_state {
167 ST_SYNC, /* wait for 0xFF sync byte */
168 ST_SOF, /* wait for 0x55 start-of-frame byte */
169 ST_LEN, /* receive length byte (small packet) */
170 ST_LENH, /* receive length high byte (large packet) */
171 ST_LENL, /* receive length low byte (large packet) */
172 ST_DATA, /* receive data */
173 ST_CHECK /* verify checksum */
174};
175
176static struct state_t {
177 enum fsm_state state; /* current fsm state */
178 unsigned int len; /* payload data length */
179 unsigned int check; /* running checksum over [len,payload,check] */
180 unsigned int count; /* playload bytes counter */
181} frame_state = {
182 .state = ST_SYNC
183};
184
185enum interface_state interface_state = IST_STANDARD;
186
187struct device_t device;
188
189#ifdef IAP_MALLOC_DYNAMIC
190static int iap_move_callback(int handle, void* current, void* new);
191
192static struct buflib_callbacks iap_buflib_callbacks = {
193 iap_move_callback,
194 NULL
195};
196#endif
197
198static void iap_malloc(void);
199
200void put_u16(unsigned char *buf, const uint16_t data)
201{
202 buf[0] = (data >> 8) & 0xFF;
203 buf[1] = (data >> 0) & 0xFF;
204}
205
206void put_u32(unsigned char *buf, const uint32_t data)
207{
208 buf[0] = (data >> 24) & 0xFF;
209 buf[1] = (data >> 16) & 0xFF;
210 buf[2] = (data >> 8) & 0xFF;
211 buf[3] = (data >> 0) & 0xFF;
212}
213
214uint32_t get_u32(const unsigned char *buf)
215{
216 return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
217}
218
219uint16_t get_u16(const unsigned char *buf)
220{
221 return (buf[0] << 8) | buf[1];
222}
223
224#if defined(LOGF_ENABLE) && defined(ROCKBOX_HAS_LOGF)
225/* Convert a buffer into a printable string, perl style
226 * buf contains the data to be converted, len is the length
227 * of the buffer.
228 *
229 * This will convert at most 1024 bytes from buf
230 */
231static char* hexstring(const unsigned char *buf, unsigned int len) {
232 static char hexbuf[4097];
233 unsigned int l;
234 const unsigned char* p;
235 unsigned char* out;
236 unsigned char h[] = {'0', '1', '2', '3', '4', '5', '6', '7',
237 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
238
239 if (len > 1024) {
240 l = 1024;
241 } else {
242 l = len;
243 }
244 p = buf;
245 out = hexbuf;
246 do {
247 *out++ = h[(*p)>>4];
248 *out++ = h[*p & 0x0F];
249 } while(--l && p++);
250
251 *out = 0x00;
252
253 return hexbuf;
254}
255#endif
256
257
258void iap_tx_strlcpy(const unsigned char *str)
259{
260 ptrdiff_t txfree;
261 int r;
262
263 txfree = TX_BUFLEN - (iap_txnext - iap_txstart);
264 r = strlcpy(iap_txnext, str, txfree);
265
266 if (r < txfree)
267 {
268 /* No truncation occured
269 * Account for the terminating \0
270 */
271 iap_txnext += (r+1);
272 } else {
273 /* Truncation occured, the TX buffer is now full. */
274 iap_txnext = iap_txstart + TX_BUFLEN;
275 }
276}
277
278void iap_reset_auth(struct auth_t* auth)
279{
280 auth->state = AUST_NONE;
281 auth->max_section = 0;
282 auth->next_section = 0;
283}
284
285void iap_reset_device(struct device_t* device)
286{
287 iap_reset_auth(&(device->auth));
288 device->lingoes = 0;
289 device->notifications = 0;
290 device->changed_notifications = 0;
291 device->do_notify = false;
292 device->do_power_notify = false;
293 device->accinfo = ACCST_NONE;
294 device->capabilities = 0;
295 device->capabilities_queried = 0;
296}
297
298static int iap_task(struct timeout *tmo)
299{
300 (void) tmo;
301
302 queue_post(&iap_queue, IAP_EV_TICK, 0);
303 return MS_TO_TICKS(100);
304}
305
306/* This thread is waiting for events posted to iap_queue and calls
307 * the appropriate subroutines in response
308 */
309static void iap_thread(void)
310{
311 struct queue_event ev;
312 while(1) {
313 queue_wait(&iap_queue, &ev);
314 switch (ev.id)
315 {
316 /* Handle the regular 100ms tick used for driving the
317 * authentication state machine and notifications
318 */
319 case IAP_EV_TICK:
320 {
321 iap_periodic();
322 break;
323 }
324
325 /* Handle a newly received message from the device */
326 case IAP_EV_MSG_RCVD:
327 {
328 iap_handlepkt();
329 break;
330 }
331
332 /* Handle memory allocation. This is used only once, during
333 * startup
334 */
335 case IAP_EV_MALLOC:
336 {
337 iap_malloc();
338 break;
339 }
340
341 /* Handle poweroff message */
342 case SYS_POWEROFF:
343 {
344 iap_shutdown = true;
345 break;
346 }
347 }
348 }
349}
350
351/* called by playback when the next track starts */
352static void iap_track_changed(void *ignored)
353{
354 (void)ignored;
355 if ((interface_state == IST_EXTENDED) && device.do_notify) {
356 long playlist_pos = playlist_next(0);
357 playlist_pos -= playlist_get_first_index(NULL);
358 if(playlist_pos < 0)
359 playlist_pos += playlist_amount();
360
361 IAP_TX_INIT4(0x04, 0x0027);
362 IAP_TX_PUT(0x01);
363 IAP_TX_PUT_U32(playlist_pos);
364
365 iap_send_tx();
366 return;
367 }
368}
369
370/* Do general setup of the needed infrastructure.
371 *
372 * Please note that a lot of additional work is done by iap_start()
373 */
374void iap_setup(const int ratenum)
375{
376 iap_bitrate_set(ratenum);
377 iap_remotebtn = BUTTON_NONE;
378 iap_setupflag = true;
379 iap_started = false;
380 iap_running = false;
381}
382
383/* Actually bring up the message queue, message handler thread and
384 * notification timer
385 *
386 * NOTE: This is running in interrupt context
387 */
388static void iap_start(void)
389{
390 unsigned int tid;
391
392 if (iap_started)
393 return;
394
395 iap_reset_device(&device);
396 queue_init(&iap_queue, true);
397 tid = create_thread(iap_thread, thread_stack, sizeof(thread_stack),
398 0, "iap"
399 IF_PRIO(, PRIORITY_SYSTEM)
400 IF_COP(, CPU));
401 if (!tid)
402 panicf("Could not create iap thread");
403 timeout_register(&iap_task_tmo, iap_task, MS_TO_TICKS(100), (intptr_t)NULL);
404 add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, iap_track_changed);
405
406 /* Since we cannot allocate memory while in interrupt context
407 * post a message to our own queue to get that done
408 */
409 queue_post(&iap_queue, IAP_EV_MALLOC, 0);
410 iap_started = true;
411}
412
413static void iap_malloc(void)
414{
415#ifndef IAP_MALLOC_DYNAMIC
416 static unsigned char serbuf[IAP_MALLOC_SIZE];
417#endif
418
419 if (iap_running)
420 return;
421
422#ifdef IAP_MALLOC_DYNAMIC
423 iap_buffer_handle = core_alloc_ex("iap", IAP_MALLOC_SIZE, &iap_buflib_callbacks);
424 if (iap_buffer_handle < 0)
425 panicf("Could not allocate buffer memory");
426 iap_buffers = core_get_data(iap_buffer_handle);
427#else
428 iap_buffers = serbuf;
429#endif
430 iap_txstart = iap_buffers;
431 iap_txpayload = iap_txstart+5;
432 iap_txnext = iap_txpayload;
433 iap_rxstart = iap_buffers+(TX_BUFLEN+6);
434 iap_rxpayload = iap_rxstart;
435 iap_rxnext = iap_rxpayload;
436 iap_rxlen = RX_BUFLEN+2;
437 iap_running = true;
438}
439
440void iap_bitrate_set(const int ratenum)
441{
442 switch(ratenum)
443 {
444 case 0:
445 serial_bitrate(0);
446 break;
447 case 1:
448 serial_bitrate(9600);
449 break;
450 case 2:
451 serial_bitrate(19200);
452 break;
453 case 3:
454 serial_bitrate(38400);
455 break;
456 case 4:
457 serial_bitrate(57600);
458 break;
459 }
460}
461
462/* Message format:
463 0xff
464 0x55
465 length
466 mode
467 command (2 bytes)
468 parameters (0-n bytes)
469 checksum (length+mode+parameters+checksum == 0)
470*/
471
472/* Send the current content of the TX buffer.
473 * This will check for TX buffer overflow and panic, but it might
474 * be too late by then (although one would have to overflow the complete
475 * RX buffer as well)
476 */
477void iap_send_tx(void)
478{
479 int i, chksum;
480 ptrdiff_t txlen;
481 unsigned char* txstart;
482
483 txlen = iap_txnext - iap_txpayload;
484
485 if (txlen <= 0)
486 return;
487
488 if (txlen > TX_BUFLEN)
489 panicf("IAP: TX buffer overflow");
490
491 if (txlen < 256)
492 {
493 /* Short packet */
494 txstart = iap_txstart+2;
495 *(txstart+2) = txlen;
496 chksum = txlen;
497 } else {
498 /* Long packet */
499 txstart = iap_txstart;
500 *(txstart+2) = 0x00;
501 *(txstart+3) = (txlen >> 8) & 0xFF;
502 *(txstart+4) = (txlen) & 0xFF;
503 chksum = *(txstart+3) + *(txstart+4);
504 }
505 *(txstart) = 0xFF;
506 *(txstart+1) = 0x55;
507
508 for (i=0; i<txlen; i++)
509 {
510 chksum += iap_txpayload[i];
511 }
512 *(iap_txnext) = 0x100 - (chksum & 0xFF);
513
514#ifdef LOGF_ENABLE
515 logf("T: %s", hexstring(txstart+3, (iap_txnext - txstart)-3));
516#endif
517 for (i=0; i <= (iap_txnext - txstart); i++)
518 {
519 while(!tx_rdy()) ;
520 tx_writec(txstart[i]);
521 }
522}
523
524/* This is just a compatibility wrapper around the new TX buffer
525 * infrastructure
526 */
527void iap_send_pkt(const unsigned char * data, const int len)
528{
529 if (!iap_running)
530 return;
531
532 iap_txnext = iap_txpayload;
533 IAP_TX_PUT_DATA(data, len);
534 iap_send_tx();
535}
536
537bool iap_getc(const unsigned char x)
538{
539 struct state_t *s = &frame_state;
540 static long pkt_timeout;
541
542 if (!iap_setupflag)
543 return false;
544
545 /* Check the time since the last packet arrived. */
546 if ((s->state != ST_SYNC) && TIME_AFTER(current_tick, pkt_timeout)) {
547 /* Packet timeouts only make sense while not waiting for the
548 * sync byte */
549 s->state = ST_SYNC;
550 return iap_getc(x);
551 }
552
553
554 /* run state machine to detect and extract a valid frame */
555 switch (s->state) {
556 case ST_SYNC:
557 if (x == 0xFF) {
558 /* The IAP infrastructure is started by the first received sync
559 * byte. It takes a while to spin up, so do not advance the state
560 * machine until it has started.
561 */
562 if (!iap_running)
563 {
564 iap_start();
565 break;
566 }
567 iap_rxnext = iap_rxpayload;
568 s->state = ST_SOF;
569 }
570 break;
571 case ST_SOF:
572 if (x == 0x55) {
573 /* received a valid sync/SOF pair */
574 s->state = ST_LEN;
575 } else {
576 s->state = ST_SYNC;
577 return iap_getc(x);
578 }
579 break;
580 case ST_LEN:
581 s->check = x;
582 s->count = 0;
583 if (x == 0) {
584 /* large packet */
585 s->state = ST_LENH;
586 } else {
587 /* small packet */
588 if (x > (iap_rxlen-2))
589 {
590 /* Packet too long for buffer */
591 s->state = ST_SYNC;
592 break;
593 }
594 s->len = x;
595 s->state = ST_DATA;
596 put_u16(iap_rxnext, s->len);
597 iap_rxnext += 2;
598 }
599 break;
600 case ST_LENH:
601 s->check += x;
602 s->len = x << 8;
603 s->state = ST_LENL;
604 break;
605 case ST_LENL:
606 s->check += x;
607 s->len += x;
608 if ((s->len == 0) || (s->len > (iap_rxlen-2))) {
609 /* invalid length */
610 s->state = ST_SYNC;
611 break;
612 } else {
613 s->state = ST_DATA;
614 put_u16(iap_rxnext, s->len);
615 iap_rxnext += 2;
616 }
617 break;
618 case ST_DATA:
619 s->check += x;
620 *(iap_rxnext++) = x;
621 s->count += 1;
622 if (s->count == s->len) {
623 s->state = ST_CHECK;
624 }
625 break;
626 case ST_CHECK:
627 s->check += x;
628 if ((s->check & 0xFF) == 0) {
629 /* done, received a valid frame */
630 iap_rxpayload = iap_rxnext;
631 queue_post(&iap_queue, IAP_EV_MSG_RCVD, 0);
632 } else {
633 /* Invalid frame */
634 }
635 s->state = ST_SYNC;
636 break;
637 default:
638#ifdef LOGF_ENABLE
639 logf("Unhandled iap state %d", (int) s->state);
640#else
641 panicf("Unhandled iap state %d", (int) s->state);
642#endif
643 break;
644 }
645
646 pkt_timeout = current_tick + IAP_PKT_TIMEOUT;
647
648 /* return true while still hunting for the sync and start-of-frame byte */
649 return (s->state == ST_SYNC) || (s->state == ST_SOF);
650}
651
652void iap_get_trackinfo(const unsigned int track, struct mp3entry* id3)
653{
654 int tracknum;
655 int fd;
656 struct playlist_track_info info;
657
658 tracknum = track;
659
660 tracknum += playlist_get_first_index(NULL);
661 if(tracknum >= playlist_amount())
662 tracknum -= playlist_amount();
663
664 /* If the tracknumber is not the current one,
665 read id3 from disk */
666 if(playlist_next(0) != tracknum)
667 {
668 playlist_get_track_info(NULL, tracknum, &info);
669 fd = open(info.filename, O_RDONLY);
670 memset(id3, 0, sizeof(*id3));
671 get_metadata(id3, fd, info.filename);
672 close(fd);
673 } else {
674 memcpy(id3, audio_current_track(), sizeof(*id3));
675 }
676}
677
678uint32_t iap_get_trackpos(void)
679{
680 struct mp3entry *id3 = audio_current_track();
681
682 return id3->elapsed;
683}
684
685uint32_t iap_get_trackindex(void)
686{
687 struct playlist_info* playlist = playlist_get_current();
688
689 return (playlist->index - playlist->first_index);
690}
691
692void iap_periodic(void)
693{
694 static int count;
695
696 if(!iap_setupflag) return;
697
698 /* Handle pending authentication tasks */
699 switch (device.auth.state)
700 {
701 case AUST_INIT:
702 {
703 /* Send out GetDevAuthenticationInfo */
704 IAP_TX_INIT(0x00, 0x14);
705
706 iap_send_tx();
707 device.auth.state = AUST_CERTREQ;
708 break;
709 }
710
711 case AUST_CERTDONE:
712 {
713 /* Send out GetDevAuthenticationSignature, with
714 * 20 bytes of challenge and a retry counter of 1.
715 * Since we do not really care about the content of the
716 * challenge we just use the first 20 bytes of whatever
717 * is in the RX buffer right now.
718 */
719 IAP_TX_INIT(0x00, 0x17);
720 IAP_TX_PUT_DATA(iap_rxstart, 20);
721 IAP_TX_PUT(0x01);
722
723 iap_send_tx();
724 device.auth.state = AUST_CHASENT;
725 break;
726 }
727
728 default:
729 {
730 break;
731 }
732 }
733
734 /* Time out button down events */
735 if (iap_timeoutbtn)
736 iap_timeoutbtn -= 1;
737
738 if (!iap_timeoutbtn)
739 {
740 iap_remotebtn = BUTTON_NONE;
741 iap_repeatbtn = 0;
742 iap_btnshuffle = false;
743 iap_btnrepeat = false;
744 }
745
746 /* Handle power down messages. */
747 if (iap_shutdown && device.do_power_notify)
748 {
749 /* NotifyiPodStateChange */
750 IAP_TX_INIT(0x00, 0x23);
751 IAP_TX_PUT(0x01);
752
753 iap_send_tx();
754
755 /* No further actions, we're going down */
756 iap_reset_device(&device);
757 return;
758 }
759
760 /* Handle GetAccessoryInfo messages */
761 if (device.accinfo == ACCST_INIT)
762 {
763 /* GetAccessoryInfo */
764 IAP_TX_INIT(0x00, 0x27);
765 IAP_TX_PUT(0x00);
766
767 iap_send_tx();
768 device.accinfo = ACCST_SENT;
769 }
770
771 /* Do not send requests for device information while
772 * an authentication is still running, this seems to
773 * confuse some devices
774 */
775 if (!DEVICE_AUTH_RUNNING && (device.accinfo == ACCST_DATA))
776 {
777 int first_set;
778
779 /* Find the first bit set in the capabilities field,
780 * ignoring those we already asked for
781 */
782 first_set = find_first_set_bit(device.capabilities & (~device.capabilities_queried));
783
784 if (first_set != 32)
785 {
786 /* Add bit to queried cababilities */
787 device.capabilities_queried |= BIT_N(first_set);
788
789 switch (first_set)
790 {
791 /* Name */
792 case 0x01:
793 /* Firmware version */
794 case 0x04:
795 /* Hardware version */
796 case 0x05:
797 /* Manufacturer */
798 case 0x06:
799 /* Model number */
800 case 0x07:
801 /* Serial number */
802 case 0x08:
803 /* Maximum payload size */
804 case 0x09:
805 {
806 IAP_TX_INIT(0x00, 0x27);
807 IAP_TX_PUT(first_set);
808
809 iap_send_tx();
810 break;
811 }
812
813 /* Minimum supported iPod firmware version */
814 case 0x02:
815 {
816 IAP_TX_INIT(0x00, 0x27);
817 IAP_TX_PUT(2);
818 IAP_TX_PUT_U32(IAP_IPOD_MODEL);
819 IAP_TX_PUT(IAP_IPOD_FIRMWARE_MAJOR);
820 IAP_TX_PUT(IAP_IPOD_FIRMWARE_MINOR);
821 IAP_TX_PUT(IAP_IPOD_FIRMWARE_REV);
822
823 iap_send_tx();
824 break;
825 }
826
827 /* Minimum supported lingo version. Queries Lingo 0 */
828 case 0x03:
829 {
830 IAP_TX_INIT(0x00, 0x27);
831 IAP_TX_PUT(3);
832 IAP_TX_PUT(0);
833
834 iap_send_tx();
835 break;
836 }
837 }
838
839 device.accinfo = ACCST_SENT;
840 }
841 }
842
843 if (!device.do_notify) return;
844 if (device.notifications == 0) return;
845
846 /* Volume change notifications are sent every 100ms */
847 if (device.notifications & (BIT_N(4) | BIT_N(16))) {
848 /* Currently we do not track volume changes, so this is
849 * never sent.
850 *
851 * TODO: Fix volume tracking
852 */
853 }
854
855 /* All other events are sent every 500ms */
856 count += 1;
857 if (count < 5) return;
858
859 count = 0;
860
861 /* RemoteEventNotification */
862
863 /* Mode 04 PlayStatusChangeNotification */
864 /* Are we in Extended Mode */
865 if (interface_state == IST_EXTENDED) {
866 /* Return Track Position */
867 struct mp3entry *id3 = audio_current_track();
868 unsigned long time_elapsed = id3->elapsed;
869 IAP_TX_INIT4(0x04, 0x0027);
870 IAP_TX_PUT(0x04);
871 IAP_TX_PUT_U32(time_elapsed);
872
873 iap_send_tx();
874 }
875
876 /* Track position (ms) or Track position (s) */
877 if (device.notifications & (BIT_N(0) | BIT_N(15)))
878 {
879 uint32_t t;
880 uint16_t ts;
881 bool changed;
882
883 t = iap_get_trackpos();
884 ts = (t / 1000) & 0xFFFF;
885
886 if ((device.notifications & BIT_N(0)) && (device.trackpos_ms != t))
887 {
888 IAP_TX_INIT(0x03, 0x09);
889 IAP_TX_PUT(0x00);
890 IAP_TX_PUT_U32(t);
891 device.changed_notifications |= BIT_N(0);
892 changed = true;
893
894 iap_send_tx();
895 }
896
897 if ((device.notifications & BIT_N(15)) && (device.trackpos_s != ts)) {
898 IAP_TX_INIT(0x03, 0x09);
899 IAP_TX_PUT(0x0F);
900 IAP_TX_PUT_U16(ts);
901 device.changed_notifications |= BIT_N(15);
902 changed = true;
903
904 iap_send_tx();
905 }
906
907 if (changed)
908 {
909 device.trackpos_ms = t;
910 device.trackpos_s = ts;
911 }
912 }
913
914 /* Track index */
915 if (device.notifications & BIT_N(1))
916 {
917 uint32_t index;
918
919 index = iap_get_trackindex();
920
921 if (device.track_index != index) {
922 IAP_TX_INIT(0x03, 0x09);
923 IAP_TX_PUT(0x01);
924 IAP_TX_PUT_U32(index);
925 device.changed_notifications |= BIT_N(1);
926
927 iap_send_tx();
928
929 device.track_index = index;
930 }
931 }
932
933 /* Chapter index */
934 if (device.notifications & BIT_N(2))
935 {
936 uint32_t index;
937
938 index = iap_get_trackindex();
939
940 if (device.track_index != index)
941 {
942 IAP_TX_INIT(0x03, 0x09);
943 IAP_TX_PUT(0x02);
944 IAP_TX_PUT_U32(index);
945 IAP_TX_PUT_U16(0);
946 IAP_TX_PUT_U16(0xFFFF);
947 device.changed_notifications |= BIT_N(2);
948
949 iap_send_tx();
950
951 device.track_index = index;
952 }
953 }
954
955 /* Play status */
956 if (device.notifications & BIT_N(3))
957 {
958 unsigned char play_status;
959
960 play_status = audio_status();
961
962 if (device.play_status != play_status)
963 {
964 IAP_TX_INIT(0x03, 0x09);
965 IAP_TX_PUT(0x03);
966 if (play_status & AUDIO_STATUS_PLAY) {
967 /* Playing or paused */
968 if (play_status & AUDIO_STATUS_PAUSE) {
969 /* Paused */
970 IAP_TX_PUT(0x02);
971 } else {
972 /* Playing */
973 IAP_TX_PUT(0x01);
974 }
975 } else {
976 IAP_TX_PUT(0x00);
977 }
978 device.changed_notifications |= BIT_N(3);
979
980 iap_send_tx();
981
982 device.play_status = play_status;
983 }
984 }
985
986 /* Power/Battery */
987 if (device.notifications & BIT_N(5))
988 {
989 unsigned char power_state;
990 unsigned char battery_l;
991
992 power_state = charger_input_state;
993 battery_l = battery_level();
994
995 if ((device.power_state != power_state) || (device.battery_level != battery_l))
996 {
997 IAP_TX_INIT(0x03, 0x09);
998 IAP_TX_PUT(0x05);
999
1000 iap_fill_power_state();
1001 device.changed_notifications |= BIT_N(5);
1002
1003 iap_send_tx();
1004
1005 device.power_state = power_state;
1006 device.battery_level = battery_l;
1007 }
1008 }
1009
1010 /* Equalizer state
1011 * This is not handled yet.
1012 *
1013 * TODO: Fix equalizer handling
1014 */
1015
1016 /* Shuffle */
1017 if (device.notifications & BIT_N(7))
1018 {
1019 unsigned char shuffle;
1020
1021 shuffle = global_settings.playlist_shuffle;
1022
1023 if (device.shuffle != shuffle)
1024 {
1025 IAP_TX_INIT(0x03, 0x09);
1026 IAP_TX_PUT(0x07);
1027 IAP_TX_PUT(shuffle?0x01:0x00);
1028 device.changed_notifications |= BIT_N(7);
1029
1030 iap_send_tx();
1031
1032 device.shuffle = shuffle;
1033 }
1034 }
1035
1036 /* Repeat */
1037 if (device.notifications & BIT_N(8))
1038 {
1039 unsigned char repeat;
1040
1041 repeat = global_settings.repeat_mode;
1042
1043 if (device.repeat != repeat)
1044 {
1045 IAP_TX_INIT(0x03, 0x09);
1046 IAP_TX_PUT(0x08);
1047 switch (repeat)
1048 {
1049 case REPEAT_OFF:
1050 {
1051 IAP_TX_PUT(0x00);
1052 break;
1053 }
1054
1055 case REPEAT_ONE:
1056 {
1057 IAP_TX_PUT(0x01);
1058 break;
1059 }
1060
1061 case REPEAT_ALL:
1062 {
1063 IAP_TX_PUT(0x02);
1064 break;
1065 }
1066 }
1067 device.changed_notifications |= BIT_N(8);
1068
1069 iap_send_tx();
1070
1071 device.repeat = repeat;
1072 }
1073 }
1074
1075 /* Date/Time */
1076 if (device.notifications & BIT_N(9))
1077 {
1078 struct tm* tm;
1079
1080 tm = get_time();
1081
1082 if (memcmp(tm, &(device.datetime), sizeof(struct tm)))
1083 {
1084 IAP_TX_INIT(0x03, 0x09);
1085 IAP_TX_PUT(0x09);
1086 IAP_TX_PUT_U16(tm->tm_year);
1087
1088 /* Month */
1089 IAP_TX_PUT(tm->tm_mon+1);
1090
1091 /* Day */
1092 IAP_TX_PUT(tm->tm_mday);
1093
1094 /* Hour */
1095 IAP_TX_PUT(tm->tm_hour);
1096
1097 /* Minute */
1098 IAP_TX_PUT(tm->tm_min);
1099
1100 device.changed_notifications |= BIT_N(9);
1101
1102 iap_send_tx();
1103
1104 memcpy(&(device.datetime), tm, sizeof(struct tm));
1105 }
1106 }
1107
1108 /* Alarm
1109 * This is not supported yet.
1110 *
1111 * TODO: Fix alarm handling
1112 */
1113
1114 /* Backlight
1115 * This is not supported yet.
1116 *
1117 * TODO: Fix backlight handling
1118 */
1119
1120 /* Hold switch */
1121 if (device.notifications & BIT_N(0x0C))
1122 {
1123 unsigned char hold;
1124
1125 hold = button_hold();
1126 if (device.hold != hold) {
1127 IAP_TX_INIT(0x03, 0x09);
1128 IAP_TX_PUT(0x0C);
1129 IAP_TX_PUT(hold?0x01:0x00);
1130
1131 device.changed_notifications |= BIT_N(0x0C);
1132
1133 iap_send_tx();
1134
1135 device.hold = hold;
1136 }
1137 }
1138
1139 /* Sound check
1140 * This is not supported yet.
1141 *
1142 * TODO: Fix sound check handling
1143 */
1144
1145 /* Audiobook check
1146 * This is not supported yet.
1147 *
1148 * TODO: Fix audiobook handling
1149 */
1150}
1151
1152/* Change the current interface state.
1153 * On a change from IST_EXTENDED to IST_STANDARD, or from IST_STANDARD
1154 * to IST_EXTENDED, pause playback, if playing
1155 */
1156void iap_interface_state_change(const enum interface_state new)
1157{
1158 if (((interface_state == IST_EXTENDED) && (new == IST_STANDARD)) ||
1159 ((interface_state == IST_STANDARD) && (new == IST_EXTENDED))) {
1160 if (audio_status() == AUDIO_STATUS_PLAY)
1161 {
1162 REMOTE_BUTTON(BUTTON_RC_PLAY);
1163 }
1164 }
1165
1166 interface_state = new;
1167}
1168
1169static void iap_handlepkt_mode5(const unsigned int len, const unsigned char *buf)
1170{
1171 (void) len;
1172 unsigned int cmd = buf[1];
1173 switch (cmd)
1174 {
1175 /* Sent from iPod Begin Transmission */
1176 case 0x02:
1177 {
1178 /* RF Transmitter: Begin High Power transmission */
1179 unsigned char data0[] = {0x05, 0x02};
1180 iap_send_pkt(data0, sizeof(data0));
1181 break;
1182 }
1183
1184 /* Sent from iPod End High Power Transmission */
1185 case 0x03:
1186 {
1187 /* RF Transmitter: End High Power transmission */
1188 unsigned char data1[] = {0x05, 0x03};
1189 iap_send_pkt(data1, sizeof(data1));
1190 break;
1191 }
1192 /* Return Version Number ?*/
1193 case 0x04:
1194 {
1195 /* do nothing */
1196 break;
1197 }
1198 }
1199}
1200
1201#if 0
1202static void iap_handlepkt_mode7(const unsigned int len, const unsigned char *buf)
1203{
1204 unsigned int cmd = buf[1];
1205 switch (cmd)
1206 {
1207 /* RetTunerCaps */
1208 case 0x02:
1209 {
1210 /* do nothing */
1211
1212 /* GetAccessoryInfo */
1213 unsigned char data[] = {0x00, 0x27, 0x00};
1214 iap_send_pkt(data, sizeof(data));
1215 break;
1216 }
1217
1218 /* RetTunerFreq */
1219 case 0x0A:
1220 /* fall through */
1221 /* TunerSeekDone */
1222 case 0x13:
1223 {
1224 rmt_tuner_freq(len, buf);
1225 break;
1226 }
1227
1228 /* RdsReadyNotify, RDS station name 0x21 1E 00 + ASCII text*/
1229 case 0x21:
1230 {
1231 rmt_tuner_rds_data(len, buf);
1232 break;
1233 }
1234 }
1235}
1236#endif
1237
1238void iap_handlepkt(void)
1239{
1240 int level;
1241 int length;
1242
1243 if(!iap_setupflag) return;
1244
1245 /* if we are waiting for a remote button to go out,
1246 delay the handling of the new packet */
1247 if(iap_repeatbtn)
1248 {
1249 queue_post(&iap_queue, IAP_EV_MSG_RCVD, 0);
1250 sleep(1);
1251 return;
1252 }
1253
1254 /* handle command by mode */
1255 length = get_u16(iap_rxstart);
1256#ifdef LOGF_ENABLE
1257 logf("R: %s", hexstring(iap_rxstart+2, (length)));
1258#endif
1259
1260 unsigned char mode = *(iap_rxstart+2);
1261 switch (mode) {
1262 case 0: iap_handlepkt_mode0(length, iap_rxstart+2); break;
1263 case 2: iap_handlepkt_mode2(length, iap_rxstart+2); break;
1264 case 3: iap_handlepkt_mode3(length, iap_rxstart+2); break;
1265 case 4: iap_handlepkt_mode4(length, iap_rxstart+2); break;
1266 case 5: iap_handlepkt_mode5(length, iap_rxstart+2); break;
1267 /* case 7: iap_handlepkt_mode7(length, iap_rxstart+2); break; */
1268 }
1269
1270 /* Remove the handled packet from the RX buffer
1271 * This needs to be done with interrupts disabled, to make
1272 * sure the buffer and the pointers into it are handled
1273 * cleanly
1274 */
1275 level = disable_irq_save();
1276 memmove(iap_rxstart, iap_rxstart+(length+2), (RX_BUFLEN+2)-(length+2));
1277 iap_rxnext -= (length+2);
1278 iap_rxpayload -= (length+2);
1279 iap_rxlen += (length+2);
1280 restore_irq(level);
1281
1282 /* poke the poweroff timer */
1283 reset_poweroff_timer();
1284}
1285
1286int remote_control_rx(void)
1287{
1288 int btn = iap_remotebtn;
1289 if(iap_repeatbtn)
1290 iap_repeatbtn--;
1291
1292 return btn;
1293}
1294
1295const unsigned char *iap_get_serbuf(void)
1296{
1297 return iap_rxstart;
1298}
1299
1300#ifdef IAP_MALLOC_DYNAMIC
1301static int iap_move_callback(int handle, void* current, void* new)
1302{
1303 (void) handle;
1304 (void) current;
1305
1306 iap_txstart = new;
1307 iap_txpayload = iap_txstart+5;
1308 iap_txnext = iap_txpayload;
1309 iap_rxstart = iap_buffers+(TX_BUFLEN+6);
1310
1311 return BUFLIB_CB_OK;
1312}
1313#endif
1314
1315/* Change the shuffle state */
1316void iap_shuffle_state(const bool state)
1317{
1318 /* Set shuffle to enabled */
1319 if(state && !global_settings.playlist_shuffle)
1320 {
1321 global_settings.playlist_shuffle = 1;
1322 settings_save();
1323 if (audio_status() & AUDIO_STATUS_PLAY)
1324 playlist_randomise(NULL, current_tick, true);
1325 }
1326 /* Set shuffle to disabled */
1327 else if(!state && global_settings.playlist_shuffle)
1328 {
1329 global_settings.playlist_shuffle = 0;
1330 settings_save();
1331 if (audio_status() & AUDIO_STATUS_PLAY)
1332 playlist_sort(NULL, true);
1333 }
1334}
1335
1336/* Change the repeat state */
1337void iap_repeat_state(const unsigned char state)
1338{
1339 if (state != global_settings.repeat_mode)
1340 {
1341 global_settings.repeat_mode = state;
1342 settings_save();
1343 if (audio_status() & AUDIO_STATUS_PLAY)
1344 audio_flush_and_reload_tracks();
1345 }
1346}
1347
1348void iap_repeat_next(void)
1349{
1350 switch (global_settings.repeat_mode)
1351 {
1352 case REPEAT_OFF:
1353 {
1354 iap_repeat_state(REPEAT_ALL);
1355 break;
1356 }
1357 case REPEAT_ALL:
1358 {
1359 iap_repeat_state(REPEAT_ONE);
1360 break;
1361 }
1362 case REPEAT_ONE:
1363 {
1364 iap_repeat_state(REPEAT_OFF);
1365 break;
1366 }
1367 }
1368}
1369
1370/* This function puts the current power/battery state
1371 * into the TX buffer. The buffer is assumed to be initialized
1372 */
1373void iap_fill_power_state(void)
1374{
1375 unsigned char power_state;
1376 unsigned char battery_l;
1377
1378 power_state = charger_input_state;
1379 battery_l = battery_level();
1380
1381 if (power_state == NO_CHARGER) {
1382 if (battery_l < 30) {
1383 IAP_TX_PUT(0x00);
1384 } else {
1385 IAP_TX_PUT(0x01);
1386 }
1387 IAP_TX_PUT((char)((battery_l * 255)/100));
1388 } else {
1389 IAP_TX_PUT(0x04);
1390 IAP_TX_PUT(0x00);
1391 }
1392}
diff --git a/apps/iap/iap-core.h b/apps/iap/iap-core.h
new file mode 100644
index 0000000000..d06e3c300c
--- /dev/null
+++ b/apps/iap/iap-core.h
@@ -0,0 +1,250 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#ifndef _IAP_CORE_H
20#define _IAP_CORE_H
21
22#include <stdint.h>
23#include <string.h>
24#include "timefuncs.h"
25#include "metadata.h"
26#include "playlist.h"
27#include "iap.h"
28
29#define LOGF_ENABLE
30/* #undef LOGF_ENABLE */
31#ifdef LOGF_ENABLE
32 #include "logf.h"
33#endif
34
35/* The Model ID of the iPod we emulate. Currently a 160GB classic */
36#define IAP_IPOD_MODEL (0x00130200U)
37
38/* The firmware version we emulate. Currently 2.0.3 */
39#define IAP_IPOD_FIRMWARE_MAJOR (2)
40#define IAP_IPOD_FIRMWARE_MINOR (0)
41#define IAP_IPOD_FIRMWARE_REV (3)
42
43/* Status code for IAP ack messages */
44#define IAP_ACK_OK (0x00) /* Success */
45#define IAP_ACK_UNKNOWN_DB (0x01) /* Unknown Database Category */
46#define IAP_ACK_CMD_FAILED (0x02) /* Command failed */
47#define IAP_ACK_NO_RESOURCE (0x03) /* Out of resources */
48#define IAP_ACK_BAD_PARAM (0x04) /* Bad parameter */
49#define IAP_ACK_UNKNOWN_ID (0x05) /* Unknown ID */
50#define IAP_ACK_PENDING (0x06) /* Command pending */
51#define IAP_ACK_NO_AUTHEN (0x07) /* Not authenticated */
52#define IAP_ACK_BAD_AUTHEN (0x08) /* Bad authentication version */
53/* 0x09 reserved */
54#define IAP_ACK_CERT_INVAL (0x0A) /* Certificate invalid */
55#define IAP_ACK_CERT_PERM (0x0B) /* Certificate permissions invalid */
56/* 0x0C-0x10 reserved */
57#define IAP_ACK_RES_INVAL (0x11) /* Invalid accessory resistor value */
58
59/* Add a button to the remote button bitfield. Also set iap_repeatbtn=1
60 * to ensure a button press is at least delivered once.
61 */
62#define REMOTE_BUTTON(x) do { \
63 iap_remotebtn |= (x); \
64 iap_timeoutbtn = 3; \
65 iap_repeatbtn = 2; \
66 } while(0)
67
68/* States of the extended command support */
69enum interface_state {
70 IST_STANDARD, /* General state, support lingo 0x00 commands */
71 IST_EXTENDED, /* Extended Interface lingo (0x04) negotiated */
72};
73
74/* States of the authentication state machine */
75enum authen_state {
76 AUST_NONE, /* Initial state, no message sent */
77 AUST_INIT, /* Remote side has requested authentication */
78 AUST_CERTREQ, /* Remote certificate requested */
79 AUST_CERTBEG, /* Certificate is being received */
80 AUST_CERTDONE, /* Certificate received */
81 AUST_CHASENT, /* Challenge sent */
82 AUST_CHADONE, /* Challenge response received */
83 AUST_AUTH, /* Authentication complete */
84};
85
86/* State of authentication */
87struct auth_t {
88 enum authen_state state; /* Current state of authentication */
89 unsigned char max_section; /* The maximum number of certificate sections */
90 unsigned char next_section; /* The next expected section number */
91};
92
93/* State of GetAccessoryInfo */
94enum accinfo_state {
95 ACCST_NONE, /* Initial state, no message sent */
96 ACCST_INIT, /* Send out initial GetAccessoryInfo */
97 ACCST_SENT, /* Wait for initial RetAccessoryInfo */
98 ACCST_DATA, /* Query device information, according to capabilities */
99};
100
101/* A struct describing an attached device and it's current
102 * state
103 */
104struct device_t {
105 struct auth_t auth; /* Authentication state */
106 enum accinfo_state accinfo; /* Accessory information state */
107 uint32_t lingoes; /* Negotiated lingoes */
108 uint32_t notifications; /* Requested notifications. These are just the
109 * notifications explicitly requested by the
110 * device
111 */
112 uint32_t changed_notifications; /* Tracks notifications that changed since the last
113 * call to SetRemoteEventNotification or GetRemoteEventStatus
114 */
115 bool do_notify; /* Notifications enabled */
116 bool do_power_notify; /* Whether to send power change notifications.
117 * These are sent automatically to all devices
118 * that used IdentifyDeviceLingoes to identify
119 * themselves, independent of other notifications
120 */
121
122 uint32_t trackpos_ms; /* These fields are to save the current state */
123 uint32_t track_index; /* of various fields so we can send a notification */
124 uint32_t chapter_index; /* if they change */
125 unsigned char play_status;
126 bool mute;
127 unsigned char volume;
128 unsigned char power_state;
129 unsigned char battery_level;
130 uint32_t equalizer_index;
131 unsigned char shuffle;
132 unsigned char repeat;
133 struct tm datetime;
134 unsigned char alarm_state;
135 unsigned char alarm_hour;
136 unsigned char alarm_minute;
137 unsigned char backlight;
138 bool hold;
139 unsigned char soundcheck;
140 unsigned char audiobook;
141 uint16_t trackpos_s;
142 uint32_t capabilities; /* Capabilities of the device, as returned by type 0
143 * of GetAccessoryInfo
144 */
145 uint32_t capabilities_queried; /* Capabilities already queried */
146};
147
148extern struct device_t device;
149#define DEVICE_AUTHENTICATED (device.auth.state == AUST_AUTH)
150#define DEVICE_AUTH_RUNNING ((device.auth.state != AUST_NONE) && (device.auth.state != AUST_AUTH))
151#define DEVICE_LINGO_SUPPORTED(x) (device.lingoes & BIT_N((x)&0x1f))
152
153extern unsigned long iap_remotebtn;
154extern unsigned int iap_timeoutbtn;
155extern int iap_repeatbtn;
156
157extern unsigned char* iap_txpayload;
158extern unsigned char* iap_txnext;
159
160/* These are a number of helper macros to manage the dynamic TX buffer content
161 * These macros DO NOT CHECK for buffer overflow. iap_send_tx() will, but
162 * it might be too late at that point. See the current size of TX_BUFLEN
163 */
164
165/* Initialize the TX buffer with a lingo and command ID. This will reset the
166 * data pointer, effectively invalidating unsent information in the TX buffer.
167 * There are two versions of this, one for 1 byte command IDs (all Lingoes except
168 * 0x04) and one for two byte command IDs (Lingo 0x04)
169 */
170#define IAP_TX_INIT(lingo, command) do { \
171 iap_txnext = iap_txpayload; \
172 IAP_TX_PUT((lingo)); \
173 IAP_TX_PUT((command)); \
174 } while (0)
175
176#define IAP_TX_INIT4(lingo, command) do { \
177 iap_txnext = iap_txpayload; \
178 IAP_TX_PUT((lingo)); \
179 IAP_TX_PUT_U16((command)); \
180 } while (0)
181
182/* Put an unsigned char into the TX buffer */
183#define IAP_TX_PUT(data) *(iap_txnext++) = (data)
184
185/* Put a 16bit unsigned quantity into the TX buffer */
186#define IAP_TX_PUT_U16(data) do { \
187 put_u16(iap_txnext, (data)); \
188 iap_txnext += 2; \
189 } while (0)
190
191/* Put a 32bit unsigned quantity into the TX buffer */
192#define IAP_TX_PUT_U32(data) do { \
193 put_u32(iap_txnext, (data)); \
194 iap_txnext += 4; \
195 } while (0)
196
197/* Put an arbitrary amount of data (identified by a char pointer and
198 * a length) into the TX buffer
199 */
200#define IAP_TX_PUT_DATA(data, len) do { \
201 memcpy(iap_txnext, (unsigned char *)(data), (len)); \
202 iap_txnext += (len); \
203 } while(0)
204
205/* Put a NULL terminated string into the TX buffer, including the
206 * NULL byte
207 */
208#define IAP_TX_PUT_STRING(str) IAP_TX_PUT_DATA((str), strlen((str))+1)
209
210/* Put a NULL terminated string into the TX buffer, taking care not to
211 * overflow the buffer. If the string does not fit into the TX buffer
212 * it will be truncated, but always NULL terminated.
213 *
214 * This function is expensive compared to the other IAP_TX_PUT_*
215 * functions
216 */
217#define IAP_TX_PUT_STRLCPY(str) iap_tx_strlcpy(str)
218
219extern unsigned char lingo_versions[32][2];
220#define LINGO_SUPPORTED(x) (LINGO_MAJOR((x)&0x1f) > 0)
221#define LINGO_MAJOR(x) (lingo_versions[(x)&0x1f][0])
222#define LINGO_MINOR(x) (lingo_versions[(x)&0x1f][1])
223
224void put_u16(unsigned char *buf, const uint16_t data);
225void put_u32(unsigned char *buf, const uint32_t data);
226uint32_t get_u32(const unsigned char *buf);
227uint16_t get_u16(const unsigned char *buf);
228void iap_tx_strlcpy(const unsigned char *str);
229
230void iap_reset_auth(struct auth_t* auth);
231void iap_reset_device(struct device_t* device);
232
233void iap_shuffle_state(bool state);
234void iap_repeat_state(unsigned char state);
235void iap_repeat_next(void);
236void iap_fill_power_state(void);
237
238void iap_send_tx(void);
239
240extern enum interface_state interface_state;
241void iap_interface_state_change(const enum interface_state new);
242
243extern bool iap_btnrepeat;
244extern bool iap_btnshuffle;
245
246uint32_t iap_get_trackpos(void);
247uint32_t iap_get_trackindex(void);
248void iap_get_trackinfo(const unsigned int track, struct mp3entry* id3);
249
250#endif
diff --git a/apps/iap/iap-lingo.h b/apps/iap/iap-lingo.h
new file mode 100644
index 0000000000..0c0a9e633d
--- /dev/null
+++ b/apps/iap/iap-lingo.h
@@ -0,0 +1,23 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf);
21void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf);
22void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf);
23void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf);
diff --git a/apps/iap/iap-lingo0.c b/apps/iap/iap-lingo0.c
new file mode 100644
index 0000000000..9e0355cb3f
--- /dev/null
+++ b/apps/iap/iap-lingo0.c
@@ -0,0 +1,1035 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include "iap-core.h"
21#include "iap-lingo.h"
22#include "kernel.h"
23#include "system.h"
24
25/*
26 * This macro is meant to be used inside an IAP mode message handler.
27 * It is passed the expected minimum length of the message buffer.
28 * If the buffer does not have the required lenght an ACK
29 * packet with a Bad Parameter error is generated.
30 */
31#define CHECKLEN(x) do { \
32 if (len < (x)) { \
33 cmd_ack(cmd, IAP_ACK_BAD_PARAM); \
34 return; \
35 }} while(0)
36
37/* Check for authenticated state, and return an ACK Not
38 * Authenticated on failure.
39 */
40#define CHECKAUTH do { \
41 if (!DEVICE_AUTHENTICATED) { \
42 cmd_ack(cmd, IAP_ACK_NO_AUTHEN); \
43 return; \
44 }} while(0)
45
46static void cmd_ack(const unsigned char cmd, const unsigned char status)
47{
48 IAP_TX_INIT(0x00, 0x02);
49 IAP_TX_PUT(status);
50 IAP_TX_PUT(cmd);
51 iap_send_tx();
52}
53
54#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK)
55
56static void cmd_pending(const unsigned char cmd, const uint32_t msdelay)
57{
58 IAP_TX_INIT(0x00, 0x02);
59 IAP_TX_PUT(0x06);
60 IAP_TX_PUT(cmd);
61 IAP_TX_PUT_U32(msdelay);
62 iap_send_tx();
63}
64
65void iap_handlepkt_mode0(const unsigned int len, const unsigned char *buf)
66{
67 unsigned int cmd = buf[1];
68
69 /* We expect at least two bytes in the buffer, one for the
70 * lingo, one for the command
71 */
72 CHECKLEN(2);
73
74 switch (cmd) {
75 /* RequestIdentify (0x00)
76 *
77 * Sent from the iPod to the device
78 */
79
80 /* Identify (0x01)
81 * This command is deprecated.
82 *
83 * It is used by a device to inform the iPod of the devices
84 * presence and of the lingo the device supports.
85 *
86 * Also, it is used to negotiate power for RF transmitters
87 *
88 * Packet format (offset in buf[]: Description)
89 * 0x00: Lingo ID: General Lingo, always 0x00
90 * 0x01: Command, always 0x01
91 * 0x02: Lingo supported by the device
92 *
93 * Some RF transmitters use an extended version of this
94 * command:
95 *
96 * 0x00: Lingo ID: General Lingo, always 0x00
97 * 0x01: Command, always 0x01
98 * 0x02: Lingo supported by the device, always 0x05 (RF Transmitter)
99 * 0x03: Reserved, always 0x00
100 * 0x04: Number of valid bits in the following fields
101 * 0x05-N: Datafields holding the number of bits specified in 0x04
102 *
103 * Returns: (none)
104 *
105 * TODO:
106 * BeginHighPower/EndHighPower should be send in the periodic handler,
107 * depending on the current play status
108 */
109 case 0x01:
110 {
111 unsigned char lingo = buf[2];
112
113 /* This is sufficient even for Lingo 0x05, as we are
114 * not actually reading from the extended bits for now
115 */
116 CHECKLEN(3);
117
118 /* Issuing this command exits any extended interface states
119 * and resets authentication
120 */
121 iap_interface_state_change(IST_STANDARD);
122 iap_reset_device(&device);
123
124 switch (lingo) {
125 case 0x04:
126 {
127 /* A single lingo device negotiating the
128 * extended interface lingo. This causes an interface
129 * state change.
130 */
131 iap_interface_state_change(IST_EXTENDED);
132 break;
133 }
134
135 case 0x05:
136 {
137 /* FM transmitter sends this: */
138 /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
139 sleep(HZ/3);
140 /* RF Transmitter: Begin transmission */
141 IAP_TX_INIT(0x05, 0x02);
142
143 iap_send_tx();
144 break;
145 }
146 }
147
148 if (lingo < 32) {
149 /* All devices that Identify get access to Lingoes 0x00 and 0x02 */
150 device.lingoes = BIT_N(0x00) | BIT_N(0x02);
151
152 device.lingoes |= BIT_N(lingo);
153
154 /* Devices that Identify with Lingo 0x04 also gain access
155 * to Lingo 0x03
156 */
157 if (lingo == 0x04)
158 device.lingoes |= BIT_N(0x03);
159 } else {
160 device.lingoes = 0;
161 }
162 break;
163 }
164
165 /* ACK (0x02)
166 *
167 * Sent from the iPod to the device
168 */
169
170 /* RequestRemoteUIMode (0x03)
171 *
172 * Request the current Extended Interface Mode state
173 * This command may be used only if the accessory requests Lingo 0x04
174 * during its identification process.
175 *
176 * Packet format (offset in buf[]: Description)
177 * 0x00: Lingo ID: General Lingo, always 0x00
178 * 0x01: Command, always 0x03
179 *
180 * Returns on success:
181 * ReturnRemoteUIMode
182 *
183 * Packet format (offset in data[]: Description)
184 * 0x00: Lingo ID: General Lingo, always 0x00
185 * 0x01: Command, always 0x04
186 * 0x02: Current Extended Interface Mode (zero: false, non-zero: true)
187 *
188 * Returns on failure:
189 * IAP_ACK_BAD_PARAM
190 */
191 case 0x03:
192 {
193 if (!DEVICE_LINGO_SUPPORTED(0x04)) {
194 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
195 break;
196 }
197
198 IAP_TX_INIT(0x00, 0x04);
199 if (interface_state == IST_EXTENDED)
200 IAP_TX_PUT(0x01);
201 else
202 IAP_TX_PUT(0x00);
203
204 iap_send_tx();
205 break;
206 }
207
208 /* ReturnRemoteUIMode (0x04)
209 *
210 * Sent from the iPod to the device
211 */
212
213 /* EnterRemoteUIMode (0x05)
214 *
215 * Request Extended Interface Mode
216 * This command may be used only if the accessory requests Lingo 0x04
217 * during its identification process.
218 *
219 * Packet format (offset in buf[]: Description)
220 * 0x00: Lingo ID: General Lingo, always 0x00
221 * 0x01: Command, always 0x05
222 *
223 * Returns on success:
224 * IAP_ACK_PENDING
225 * IAP_ACK_OK
226 *
227 * Returns on failure:
228 * IAP_ACK_BAD_PARAM
229 */
230 case 0x05:
231 {
232 if (!DEVICE_LINGO_SUPPORTED(0x04)) {
233 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
234 break;
235 }
236
237 cmd_pending(cmd, 1000);
238 iap_interface_state_change(IST_EXTENDED);
239 cmd_ok(cmd);
240 break;
241 }
242
243 /* ExitRemoteUIMode (0x06)
244 *
245 * Leave Extended Interface Mode
246 * This command may be used only if the accessory requests Lingo 0x04
247 * during its identification process.
248 *
249 * Packet format (offset in buf[]: Description)
250 * 0x00: Lingo ID: General Lingo, always 0x00
251 * 0x01: Command, always 0x06
252 *
253 * Returns on success:
254 * IAP_ACK_PENDING
255 * IAP_ACK_OK
256 *
257 * Returns on failure:
258 * IAP_ACK_BAD_PARAM
259 */
260 case 0x06:
261 {
262 if (!DEVICE_LINGO_SUPPORTED(0x04)) {
263 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
264 break;
265 }
266
267 cmd_pending(cmd, 1000);
268 iap_interface_state_change(IST_STANDARD);
269 cmd_ok(cmd);
270 break;
271 }
272
273 /* RequestiPodName (0x07)
274 *
275 * Retrieves the name of the iPod
276 *
277 * Packet format (offset in buf[]: Description)
278 * 0x00: Lingo ID: General Lingo, always 0x00
279 * 0x01: Command, always 0x07
280 *
281 * Returns:
282 * ReturniPodName
283 *
284 * Packet format (offset in data[]: Description)
285 * 0x00: Lingo ID: General Lingo, always 0x00
286 * 0x01: Command, always 0x08
287 * 0x02-0xNN: iPod name as NULL-terminated UTF8 string
288 */
289 case 0x07:
290 {
291 IAP_TX_INIT(0x00, 0x08);
292 IAP_TX_PUT_STRING("ROCKBOX");
293
294 iap_send_tx();
295 break;
296 }
297
298 /* ReturniPodName (0x08)
299 *
300 * Sent from the iPod to the device
301 */
302
303 /* RequestiPodSoftwareVersion (0x09)
304 *
305 * Returns the major, minor and revision numbers of the iPod
306 * software version. This not any Lingo protocol version.
307 *
308 * Packet format (offset in buf[]: Description)
309 * 0x00: Lingo ID: General Lingo, always 0x00
310 * 0x01: Command, always 0x09
311 *
312 * Returns:
313 * ReturniPodSoftwareVersion
314 *
315 * Packet format (offset in data[]: Description)
316 * 0x00: Lingo ID: General Lingo, always 0x00
317 * 0x01: Command, always 0x0A
318 * 0x02: iPod major software version
319 * 0x03: iPod minor software version
320 * 0x04: iPod revision software version
321 */
322 case 0x09:
323 {
324 IAP_TX_INIT(0x00, 0x0A);
325 IAP_TX_PUT(IAP_IPOD_FIRMWARE_MAJOR);
326 IAP_TX_PUT(IAP_IPOD_FIRMWARE_MINOR);
327 IAP_TX_PUT(IAP_IPOD_FIRMWARE_REV);
328
329 iap_send_tx();
330 break;
331 }
332
333 /* ReturniPodSoftwareVersion (0x0A)
334 *
335 * Sent from the iPod to the device
336 */
337
338 /* RequestiPodSerialNum (0x0B)
339 *
340 * Returns the iPod serial number
341 *
342 * Packet format (offset in buf[]: Description)
343 * 0x00: Lingo ID: General Lingo, always 0x00
344 * 0x01: Command, always 0x0B
345 *
346 * Returns:
347 * ReturniPodSerialNumber
348 *
349 * Packet format (offset in data[]: Description)
350 * 0x00: Lingo ID: General Lingo, always 0x00
351 * 0x01: Command, always 0x0C
352 * 0x02-0xNN: Serial number as NULL-terminated UTF8 string
353 */
354 case 0x0B:
355 {
356 IAP_TX_INIT(0x00, 0x0C);
357 IAP_TX_PUT_STRING("0123456789");
358
359 iap_send_tx();
360 break;
361 }
362
363 /* ReturniPodSerialNum (0x0C)
364 *
365 * Sent from the iPod to the device
366 */
367
368 /* RequestiPodModelNum (0x0D)
369 *
370 * Returns the model number as a 32bit unsigned integer and
371 * as a string.
372 *
373 * Packet format (offset in buf[]: Description)
374 * 0x00: Lingo ID: General Lingo, always 0x00
375 * 0x01: Command, always 0x0D
376 *
377 * Returns:
378 * ReturniPodModelNum
379 *
380 * Packet format (offset in data[]: Description)
381 * 0x00: Lingo ID: General Lingo, always 0x00
382 * 0x01: Command, always 0x0E
383 * 0x02-0x05: Model number as 32bit integer
384 * 0x06-0xNN: Model number as NULL-terminated UTF8 string
385 */
386 case 0x0D:
387 {
388 IAP_TX_INIT(0x00, 0x0E);
389 IAP_TX_PUT_U32(IAP_IPOD_MODEL);
390 IAP_TX_PUT_STRING("ROCKBOX");
391
392 iap_send_tx();
393 break;
394 }
395
396 /* ReturniPodSerialNum (0x0E)
397 *
398 * Sent from the iPod to the device
399 */
400
401 /* RequestLingoProtocolVersion (0x0F)
402 *
403 * Packet format (offset in buf[]: Description)
404 * 0x00: Lingo ID: General Lingo, always 0x00
405 * 0x01: Command, always 0x0F
406 * 0x02: Lingo for which to request version information
407 *
408 * Returns on success:
409 * ReturnLingoProtocolVersion
410 *
411 * Packet format (offset in data[]: Description)
412 * 0x00: Lingo ID: General Lingo, always 0x00
413 * 0x01: Command, always 0x10
414 * 0x02: Lingo for which version information is returned
415 * 0x03: Major protocol version for the given lingo
416 * 0x04: Minor protocol version for the given lingo
417 *
418 * Returns on failure:
419 * IAP_ACK_BAD_PARAM
420 */
421 case 0x0F:
422 {
423 unsigned char lingo = buf[2];
424
425 CHECKLEN(3);
426
427 /* Supported lingos and versions are read from the lingo_versions
428 * array
429 */
430 if (LINGO_SUPPORTED(lingo)) {
431 IAP_TX_INIT(0x00, 0x10);
432 IAP_TX_PUT(lingo);
433 IAP_TX_PUT(LINGO_MAJOR(lingo));
434 IAP_TX_PUT(LINGO_MINOR(lingo));
435
436 iap_send_tx();
437 } else {
438 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
439 }
440 break;
441 }
442
443 /* ReturnLingoProtocolVersion (0x10)
444 *
445 * Sent from the iPod to the device
446 */
447
448 /* IdentifyDeviceLingoes (0x13);
449 *
450 * Used by a device to inform the iPod of the devices
451 * presence and of the lingoes the device supports.
452 *
453 * Packet format (offset in buf[]: Description)
454 * 0x00: Lingo ID: General Lingo, always 0x00
455 * 0x01: Command, always 0x13
456 * 0x02-0x05: Device lingoes spoken
457 * 0x06-0x09: Device options
458 * 0x0A-0x0D: Device ID. Only important for authentication
459 *
460 * Returns on success:
461 * IAP_ACK_OK
462 *
463 * Returns on failure:
464 * IAP_ACK_CMD_FAILED
465 */
466 case 0x13:
467 {
468 uint32_t lingoes = get_u32(&buf[2]);
469 uint32_t options = get_u32(&buf[6]);
470 uint32_t deviceid = get_u32(&buf[0x0A]);
471 bool seen_unsupported = false;
472 unsigned char i;
473
474 CHECKLEN(14);
475
476 /* Issuing this command exits any extended interface states */
477 iap_interface_state_change(IST_STANDARD);
478
479 /* Loop through the lingoes advertised by the device.
480 * If it tries to use a lingo we do not support, return
481 * a Command Failed ACK.
482 */
483 for(i=0; i<32; i++) {
484 if (lingoes & BIT_N(i)) {
485 /* Bit set by device */
486 if (!LINGO_SUPPORTED(i)) {
487 seen_unsupported = true;
488 }
489 }
490 }
491
492 /* Bit 0 _must_ be set by the device */
493 if (!(lingoes & 1)) {
494 seen_unsupported = true;
495 }
496
497 /* Specifying a deviceid without requesting authentication is
498 * an error
499 */
500 if (deviceid && !(options & 0x03))
501 seen_unsupported = true;
502
503 /* Specifying authentication without a deviceid is an error */
504 if (!deviceid && (options & 0x03))
505 seen_unsupported = true;
506
507 device.lingoes = 0;
508 if (seen_unsupported) {
509 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
510 break;
511 }
512 iap_reset_device(&device);
513 device.lingoes = lingoes;
514
515 /* Devices using IdentifyDeviceLingoes get power off notifications */
516 device.do_power_notify = true;
517
518 /* If a new authentication is requested, start the auth
519 * process.
520 * The periodic handler will take care of sending out the
521 * GetDevAuthenticationInfo packet
522 *
523 * If no authentication is requested, schedule the start of
524 * GetAccessoryInfo
525 */
526 if (deviceid && (options & 0x03) && !DEVICE_AUTH_RUNNING) {
527 device.auth.state = AUST_INIT;
528 } else {
529 device.accinfo = ACCST_INIT;
530 }
531
532 cmd_ok(cmd);
533
534 /* Bit 5: RF Transmitter lingo */
535 if (lingoes & (1 << 5))
536 {
537 /* FM transmitter sends this: */
538 /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/
539
540 /* GetAccessoryInfo */
541 unsigned char data2[] = {0x00, 0x27, 0x00};
542 iap_send_pkt(data2, sizeof(data2));
543 /* RF Transmitter: Begin transmission */
544 unsigned char data3[] = {0x05, 0x02};
545 iap_send_pkt(data3, sizeof(data3));
546 }
547
548
549#if 0
550 /* Bit 7: RF Tuner lingo */
551 if (lingoes & (1 << 7))
552 {
553 /* ipod fm remote sends this: */
554 /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */
555 radio_present = 1;
556 /* GetDevAuthenticationInfo */
557 unsigned char data4[] = {0x00, 0x14};
558 iap_send_pkt(data4, sizeof(data4));
559 }
560#endif
561 break;
562 }
563
564 /* GetDevAuthenticationInfo (0x14)
565 *
566 * Sent from the iPod to the device
567 */
568
569 /* RetDevAuthenticationInfo (0x15)
570 *
571 * Send certificate information from the device to the iPod.
572 * The certificate may come in multiple parts and has
573 * to be reassembled.
574 *
575 * Packet format (offset in buf[]: Description)
576 * 0x00: Lingo ID: General Lingo, always 0x00
577 * 0x01: Command, always 0x15
578 * 0x02: Authentication major version
579 * 0x03: Authentication minor version
580 * 0x04: Certificate current section index
581 * 0x05: Certificate maximum section index
582 * 0x06-0xNN: Certificate data
583 *
584 * Returns on success:
585 * IAP_ACK_OK for intermediate sections
586 * AckDevAuthenticationInfo for the last section
587 *
588 * Returns on failure:
589 * IAP_ACK_BAD_PARAMETER
590 * AckDevAuthenticationInfo for version mismatches
591 *
592 */
593 case 0x15:
594 {
595 /* There are two formats of this packet. One with only
596 * the version information bytes (for Auth version 1.0)
597 * and the long form shown above
598 */
599 CHECKLEN(4);
600
601 if (!DEVICE_AUTH_RUNNING) {
602 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
603 break;
604 }
605
606 /* We only support version 2.0 */
607 if ((buf[2] != 2) || (buf[3] != 0)) {
608 /* Version mismatches are signalled by AckDevAuthenticationInfo
609 * with the status set to Authentication Information unsupported
610 */
611 iap_reset_auth(&(device.auth));
612
613 IAP_TX_INIT(0x00, 0x16);
614 IAP_TX_PUT(0x08);
615
616 iap_send_tx();
617 break;
618 }
619
620 /* There must be at least one byte of certificate data
621 * in the packet
622 */
623 CHECKLEN(7);
624
625 switch (device.auth.state)
626 {
627 /* This is the first packet. Note the maximum section number
628 * so we can check it later.
629 */
630 case AUST_CERTREQ:
631 {
632 device.auth.max_section = buf[5];
633 device.auth.state = AUST_CERTBEG;
634
635 /* Intentional fall-through */
636 }
637 /* All following packets */
638 case AUST_CERTBEG:
639 {
640 /* Check if this is the expected section */
641 if (buf[4] != device.auth.next_section) {
642 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
643 break;
644 }
645
646 /* Is this the last section? */
647 if (device.auth.next_section == device.auth.max_section) {
648 /* If we could really do authentication we'd have to
649 * check the certificate here. Since we can't, just acknowledge
650 * the packet with an "everything OK" AckDevAuthenticationInfo
651 *
652 * Also, start GetAccessoryInfo process
653 */
654 IAP_TX_INIT(0x00, 0x16);
655 IAP_TX_PUT(0x00);
656
657 iap_send_tx();
658 device.auth.state = AUST_CERTDONE;
659 device.accinfo = ACCST_INIT;
660 } else {
661 device.auth.next_section++;
662 cmd_ok(cmd);
663 }
664 break;
665 }
666
667 default:
668 {
669 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
670 break;
671 }
672 }
673
674 break;
675 }
676
677 /* AckDevAuthenticationInfo (0x16)
678 *
679 * Sent from the iPod to the device
680 */
681
682 /* GetDevAuthenticationSignature (0x17)
683 *
684 * Sent from the iPod to the device
685 */
686
687 /* RetDevAuthenticationSignature (0x18)
688 *
689 * Return a calculated signature based on the device certificate
690 * and the challenge sent with GetDevAuthenticationSignature
691 *
692 * Packet format (offset in buf[]: Description)
693 * 0x00: Lingo ID: General Lingo, always 0x00
694 * 0x01: Command, always 0x17
695 * 0x02-0xNN: Certificate data
696 *
697 * Returns on success:
698 * AckDevAuthenticationStatus
699 *
700 * Packet format (offset in data[]: Description)
701 * 0x00: Lingo ID: General Lingo, always 0x00
702 * 0x01: Command, always 0x19
703 * 0x02: Status (0x00: OK)
704 *
705 * Returns on failure:
706 * IAP_ACK_BAD_PARAM
707 *
708 * TODO:
709 * There is a timeout of 75 seconds between GetDevAuthenticationSignature
710 * and RetDevAuthenticationSignature for Auth 2.0. This is currently not
711 * checked.
712 */
713 case 0x18:
714 {
715 if (device.auth.state != AUST_CHASENT) {
716 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
717 break;
718 }
719
720 /* Here we could check the signature. Since we can't, just
721 * acknowledge and go to authenticated status
722 */
723 IAP_TX_INIT(0x00, 0x19);
724 IAP_TX_PUT(0x00);
725
726 iap_send_tx();
727 device.auth.state = AUST_AUTH;
728 break;
729 }
730
731 /* AckDevAuthenticationStatus (0x19)
732 *
733 * Sent from the iPod to the device
734 */
735
736 /* GetiPodAuthenticationInfo (0x1A)
737 *
738 * Obtain authentication information from the iPod.
739 * This cannot be implemented without posessing an Apple signed
740 * certificate and the corresponding private key.
741 *
742 * Packet format (offset in buf[]: Description)
743 * 0x00: Lingo ID: General Lingo, always 0x00
744 * 0x01: Command, always 0x1A
745 *
746 * This command requires authentication
747 *
748 * Returns:
749 * IAP_ACK_CMD_FAILED
750 */
751 case 0x1A:
752 {
753 CHECKAUTH;
754
755 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
756 break;
757 }
758
759 /* RetiPodAuthenticationInfo (0x1B)
760 *
761 * Sent from the iPod to the device
762 */
763
764 /* AckiPodAuthenticationInfo (0x1C)
765 *
766 * Confirm authentication information from the iPod.
767 * This cannot be implemented without posessing an Apple signed
768 * certificate and the corresponding private key.
769 *
770 * Packet format (offset in buf[]: Description)
771 * 0x00: Lingo ID: General Lingo, always 0x00
772 * 0x01: Command, always 0x1C
773 * 0x02: Authentication state (0x00: OK)
774 *
775 * This command requires authentication
776 *
777 * Returns: (none)
778 */
779 case 0x1C:
780 {
781 CHECKAUTH;
782
783 break;
784 }
785
786 /* GetiPodAuthenticationSignature (0x1D)
787 *
788 * Send challenge information to the iPod.
789 * This cannot be implemented without posessing an Apple signed
790 * certificate and the corresponding private key.
791 *
792 * Packet format (offset in buf[]: Description)
793 * 0x00: Lingo ID: General Lingo, always 0x00
794 * 0x01: Command, always 0x1D
795 * 0x02-0x15: Challenge
796 *
797 * This command requires authentication
798 *
799 * Returns:
800 * IAP_ACK_CMD_FAILED
801 */
802 case 0x1D:
803 {
804 CHECKAUTH;
805
806 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
807 break;
808 }
809
810 /* RetiPodAuthenticationSignature (0x1E)
811 *
812 * Sent from the iPod to the device
813 */
814
815 /* AckiPodAuthenticationStatus (0x1F)
816 *
817 * Confirm chellenge information from the iPod.
818 * This cannot be implemented without posessing an Apple signed
819 * certificate and the corresponding private key.
820 *
821 * Packet format (offset in buf[]: Description)
822 * 0x00: Lingo ID: General Lingo, always 0x00
823 * 0x01: Command, always 0x1C
824 * 0x02: Challenge state (0x00: OK)
825 *
826 * This command requires authentication
827 *
828 * Returns: (none)
829 */
830 case 0x1F:
831 {
832 CHECKAUTH;
833
834 break;
835 }
836
837 /* NotifyiPodStateChange (0x23)
838 *
839 * Sent from the iPod to the device
840 */
841
842 /* GetIpodOptions (0x24)
843 *
844 * Request supported features of the iPod
845 *
846 * Packet format (offset in buf[]: Description)
847 * 0x00: Lingo ID: General Lingo, always 0x00
848 * 0x01: Command, always 0x24
849 *
850 * Retuns:
851 * RetiPodOptions
852 *
853 * Packet format (offset in data[]: Description)
854 * 0x00: Lingo ID: General Lingo, always 0x00
855 * 0x01: Command, always 0x25
856 * 0x02-0x09: Options as a bitfield
857 */
858 case 0x24:
859 {
860 /* There are only two features that can be communicated via this
861 * function, video support and the ability to control line-out usage.
862 * Rockbox supports neither
863 */
864 IAP_TX_INIT(0x00, 0x25);
865 IAP_TX_PUT_U32(0x00);
866 IAP_TX_PUT_U32(0x00);
867
868 iap_send_tx();
869 break;
870 }
871
872 /* RetiPodOptions (0x25)
873 *
874 * Sent from the iPod to the device
875 */
876
877 /* GetAccessoryInfo (0x27)
878 *
879 * Sent from the iPod to the device
880 */
881
882 /* RetAccessoryInfo (0x28)
883 *
884 * Send information about the device
885 *
886 * Packet format (offset in buf[]: Description)
887 * 0x00: Lingo ID: General Lingo, always 0x00
888 * 0x01: Command, always 0x28
889 * 0x02: Accessory info type
890 * 0x03-0xNN: Accessory information (depends on 0x02)
891 *
892 * Returns: (none)
893 *
894 * TODO: Actually do something with the information received here.
895 * Some devices actually expect us to request the data they
896 * offer, so completely ignoring this does not work, either.
897 */
898 case 0x28:
899 {
900 CHECKLEN(3);
901
902 switch (buf[0x02])
903 {
904 /* Info capabilities */
905 case 0x00:
906 {
907 CHECKLEN(7);
908
909 device.capabilities = get_u32(&buf[0x03]);
910 /* Type 0x00 was already queried, that's where this information comes from */
911 device.capabilities_queried = 0x01;
912 device.capabilities &= ~0x01;
913 break;
914 }
915
916 /* For now, ignore all other information */
917 default:
918 {
919 break;
920 }
921 }
922
923 /* If there are any unqueried capabilities left, do so */
924 if (device.capabilities)
925 device.accinfo = ACCST_DATA;
926
927 break;
928 }
929
930 /* GetiPodPreferences (0x29)
931 *
932 * Retrieve information about the current state of the
933 * iPod.
934 *
935 * Packet format (offset in buf[]: Description)
936 * 0x00: Lingo ID: General Lingo, always 0x00
937 * 0x01: Command, always 0x29
938 * 0x02: Information class requested
939 *
940 * This command requires authentication
941 *
942 * Returns on success:
943 * RetiPodPreferences
944 *
945 * Packet format (offset in data[]: Description)
946 * 0x00: Lingo ID: General Lingo, always 0x00
947 * 0x01: Command, always 0x2A
948 * 0x02: Information class provided
949 * 0x03: Information
950 *
951 * Returns on failure:
952 * IAP_ACK_BAD_PARAM
953 */
954 case 0x29:
955 {
956 CHECKLEN(3);
957 CHECKAUTH;
958
959 IAP_TX_INIT(0x00, 0x2A);
960 /* The only information really supported is 0x03, Line-out usage.
961 * All others are video related
962 */
963 if (buf[2] == 0x03) {
964 IAP_TX_PUT(0x03);
965 IAP_TX_PUT(0x01); /* Line-out enabled */
966
967 iap_send_tx();
968 } else {
969 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
970 }
971
972 break;
973 }
974
975 /* RetiPodPreference (0x2A)
976 *
977 * Sent from the iPod to the device
978 */
979
980 /* SetiPodPreferences (0x2B)
981 *
982 * Set preferences on the iPod
983 *
984 * Packet format (offset in buf[]: Description)
985 * 0x00: Lingo ID: General Lingo, always 0x00
986 * 0x01: Command, always 0x29
987 * 0x02: Prefecence class requested
988 * 0x03: Preference setting
989 * 0x04: Restore on exit
990 *
991 * This command requires authentication
992 *
993 * Returns on success:
994 * IAP_ACK_OK
995 *
996 * Returns on failure:
997 * IAP_ACK_BAD_PARAM
998 * IAP_ACK_CMD_FAILED
999 */
1000 case 0x2B:
1001 {
1002 CHECKLEN(5);
1003 CHECKAUTH;
1004
1005 /* The only information really supported is 0x03, Line-out usage.
1006 * All others are video related
1007 */
1008 if (buf[2] == 0x03) {
1009 /* If line-out disabled is requested, reply with IAP_ACK_CMD_FAILED,
1010 * otherwise with IAP_ACK_CMD_OK
1011 */
1012 if (buf[3] == 0x00) {
1013 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
1014 } else {
1015 cmd_ok(cmd);
1016 }
1017 } else {
1018 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1019 }
1020
1021 break;
1022 }
1023
1024 /* The default response is IAP_ACK_BAD_PARAM */
1025 default:
1026 {
1027#ifdef LOGF_ENABLE
1028 logf("iap: Unsupported Mode00 Command");
1029#else
1030 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1031#endif
1032 break;
1033 }
1034 }
1035}
diff --git a/apps/iap/iap-lingo2.c b/apps/iap/iap-lingo2.c
new file mode 100644
index 0000000000..4fbf730192
--- /dev/null
+++ b/apps/iap/iap-lingo2.c
@@ -0,0 +1,278 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20/* Lingo 0x02, Simple Remote Lingo
21 *
22 * TODO:
23 * - Fix cmd 0x00 handling, there has to be a more elegant way of doing
24 * this
25 */
26
27#include "iap-core.h"
28#include "iap-lingo.h"
29#include "system.h"
30#include "button.h"
31#include "audio.h"
32#include "settings.h"
33
34/*
35 * This macro is meant to be used inside an IAP mode message handler.
36 * It is passed the expected minimum length of the message buffer.
37 * If the buffer does not have the required lenght an ACK
38 * packet with a Bad Parameter error is generated.
39 */
40#define CHECKLEN(x) do { \
41 if (len < (x)) { \
42 cmd_ack(cmd, IAP_ACK_BAD_PARAM); \
43 return; \
44 }} while(0)
45
46static void cmd_ack(const unsigned char cmd, const unsigned char status)
47{
48 IAP_TX_INIT(0x02, 0x01);
49 IAP_TX_PUT(status);
50 IAP_TX_PUT(cmd);
51
52 iap_send_tx();
53}
54
55#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK)
56
57void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
58{
59 unsigned int cmd = buf[1];
60
61 /* We expect at least three bytes in the buffer, one for the
62 * lingo, one for the command, and one for the first button
63 * state bits.
64 */
65 CHECKLEN(3);
66
67 /* Lingo 0x02 must have been negotiated */
68 if (!DEVICE_LINGO_SUPPORTED(0x02)) {
69 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
70 return;
71 }
72
73 switch (cmd)
74 {
75 /* ContextButtonStatus (0x00)
76 *
77 * Transmit button events from the device to the iPod
78 *
79 * Packet format (offset in buf[]: Description)
80 * 0x00: Lingo ID: Simple Remote Lingo, always 0x02
81 * 0x01: Command, always 0x00
82 * 0x02: Button states 0:7
83 * 0x03: Button states 8:15 (optional)
84 * 0x04: Button states 16:23 (optional)
85 * 0x05: Button states 24:31 (optional)
86 *
87 * Returns: (none)
88 */
89 case 0x00:
90 {
91 iap_remotebtn = BUTTON_NONE;
92 iap_timeoutbtn = 0;
93
94 if(buf[2] != 0)
95 {
96 if(buf[2] & 1)
97 REMOTE_BUTTON(BUTTON_RC_PLAY);
98 if(buf[2] & 2)
99 REMOTE_BUTTON(BUTTON_RC_VOL_UP);
100 if(buf[2] & 4)
101 REMOTE_BUTTON(BUTTON_RC_VOL_DOWN);
102 if(buf[2] & 8)
103 REMOTE_BUTTON(BUTTON_RC_RIGHT);
104 if(buf[2] & 16)
105 REMOTE_BUTTON(BUTTON_RC_LEFT);
106 }
107 else if(len >= 4 && buf[3] != 0)
108 {
109 if(buf[3] & 1) /* play */
110 {
111 if (audio_status() != AUDIO_STATUS_PLAY)
112 REMOTE_BUTTON(BUTTON_RC_PLAY);
113 }
114 if(buf[3] & 2) /* pause */
115 {
116 if (audio_status() == AUDIO_STATUS_PLAY)
117 REMOTE_BUTTON(BUTTON_RC_PLAY);
118 }
119 if(buf[3] & 128) /* Shuffle */
120 {
121 if (!iap_btnshuffle)
122 {
123 iap_shuffle_state(!global_settings.playlist_shuffle);
124 iap_btnshuffle = true;
125 }
126 }
127 }
128 else if(len >= 5 && buf[4] != 0)
129 {
130 if(buf[4] & 1) /* repeat */
131 {
132 if (!iap_btnrepeat)
133 {
134 iap_repeat_next();
135 iap_btnrepeat = true;
136 }
137 }
138
139 /* Power off
140 * Not quite sure how to react to this, but stopping playback
141 * is a good start.
142 */
143 if (buf[4] & 0x04)
144 {
145 if (audio_status() == AUDIO_STATUS_PLAY)
146 REMOTE_BUTTON(BUTTON_RC_PLAY);
147 }
148
149 if(buf[4] & 16) /* ffwd */
150 REMOTE_BUTTON(BUTTON_RC_RIGHT);
151 if(buf[4] & 32) /* frwd */
152 REMOTE_BUTTON(BUTTON_RC_LEFT);
153 }
154
155 break;
156 }
157 /* ACK (0x01)
158 *
159 * Sent from the iPod to the device
160 */
161
162 /* ImageButtonStatus (0x02)
163 *
164 * Transmit image button events from the device to the iPod
165 *
166 * Packet format (offset in buf[]: Description)
167 * 0x00: Lingo ID: Simple Remote Lingo, always 0x02
168 * 0x01: Command, always 0x02
169 * 0x02: Button states 0:7
170 * 0x03: Button states 8:15 (optional)
171 * 0x04: Button states 16:23 (optional)
172 * 0x05: Button states 24:31 (optional)
173 *
174 * This command requires authentication
175 *
176 * Returns on success:
177 * IAP_ACK_OK
178 *
179 * Returns on failure:
180 * IAP_ACK_*
181 */
182 case 0x02:
183 {
184 if (!DEVICE_AUTHENTICATED) {
185 cmd_ack(cmd, IAP_ACK_NO_AUTHEN);
186 break;
187 }
188
189 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
190 break;
191 }
192
193 /* VideoButtonStatus (0x03)
194 *
195 * Transmit video button events from the device to the iPod
196 *
197 * Packet format (offset in buf[]: Description)
198 * 0x00: Lingo ID: Simple Remote Lingo, always 0x02
199 * 0x01: Command, always 0x03
200 * 0x02: Button states 0:7
201 * 0x03: Button states 8:15 (optional)
202 * 0x04: Button states 16:23 (optional)
203 * 0x05: Button states 24:31 (optional)
204 *
205 * This command requires authentication
206 *
207 * Returns on success:
208 * IAP_ACK_OK
209 *
210 * Returns on failure:
211 * IAP_ACK_*
212 */
213 case 0x03:
214 {
215 if (!DEVICE_AUTHENTICATED) {
216 cmd_ack(cmd, IAP_ACK_NO_AUTHEN);
217 break;
218 }
219
220 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
221 break;
222 }
223
224 /* AudioButtonStatus (0x04)
225 *
226 * Transmit audio button events from the device to the iPod
227 *
228 * Packet format (offset in buf[]: Description)
229 * 0x00: Lingo ID: Simple Remote Lingo, always 0x02
230 * 0x01: Command, always 0x04
231 * 0x02: Button states 0:7
232 * 0x03: Button states 8:15 (optional)
233 * 0x04: Button states 16:23 (optional)
234 * 0x05: Button states 24:31 (optional)
235 *
236 * This command requires authentication
237 *
238 * Returns on success:
239 * IAP_ACK_OK
240 *
241 * Returns on failure:
242 * IAP_ACK_*
243 */
244 case 0x04:
245 {
246 unsigned char repeatbuf[6];
247
248 if (!DEVICE_AUTHENTICATED) {
249 cmd_ack(cmd, IAP_ACK_NO_AUTHEN);
250 break;
251 }
252
253 /* This is basically the same command as ContextButtonStatus (0x00),
254 * with the difference that it requires authentication and that
255 * it returns an ACK packet to the device.
256 * So just route it through the handler again, with 0x00 as the
257 * command
258 */
259 memcpy(repeatbuf, buf, 6);
260 repeatbuf[1] = 0x00;
261 iap_handlepkt_mode2((len<6)?len:6, repeatbuf);
262
263 cmd_ok(cmd);
264 break;
265 }
266
267 /* The default response is IAP_ACK_BAD_PARAM */
268 default:
269 {
270#ifdef LOGF_ENABLE
271 logf("iap: Unsupported Mode02 Command");
272#else
273 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
274#endif
275 break;
276 }
277 }
278}
diff --git a/apps/iap/iap-lingo3.c b/apps/iap/iap-lingo3.c
new file mode 100644
index 0000000000..0ed3df118e
--- /dev/null
+++ b/apps/iap/iap-lingo3.c
@@ -0,0 +1,1508 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20/* Lingo 0x03: Display Remote Lingo
21 *
22 * A bit of a hodgepogde of odds and ends.
23 *
24 * Used to control the equalizer in version 1.00 of the Lingo, but later
25 * grew functions to control album art transfer and check the player
26 * status.
27 *
28 * TODO:
29 * - Actually support multiple equalizer profiles, currently only the
30 * profile 0 (equalizer disabled) is supported
31 */
32
33#include "iap-core.h"
34#include "iap-lingo.h"
35#include "system.h"
36#include "audio.h"
37#include "powermgmt.h"
38#include "settings.h"
39#include "metadata.h"
40#include "playback.h"
41
42/*
43 * This macro is meant to be used inside an IAP mode message handler.
44 * It is passed the expected minimum length of the message buffer.
45 * If the buffer does not have the required lenght an ACK
46 * packet with a Bad Parameter error is generated.
47 */
48#define CHECKLEN(x) do { \
49 if (len < (x)) { \
50 cmd_ack(cmd, IAP_ACK_BAD_PARAM); \
51 return; \
52 }} while(0)
53
54/* Check for authenticated state, and return an ACK Not
55 * Authenticated on failure.
56 */
57#define CHECKAUTH do { \
58 if (!DEVICE_AUTHENTICATED) { \
59 cmd_ack(cmd, IAP_ACK_NO_AUTHEN); \
60 return; \
61 }} while(0)
62
63static void cmd_ack(const unsigned char cmd, const unsigned char status)
64{
65 IAP_TX_INIT(0x03, 0x00);
66 IAP_TX_PUT(status);
67 IAP_TX_PUT(cmd);
68
69 iap_send_tx();
70}
71
72#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK)
73
74void iap_handlepkt_mode3(const unsigned int len, const unsigned char *buf)
75{
76 unsigned int cmd = buf[1];
77
78 /* We expect at least two bytes in the buffer, one for the
79 * state bits.
80 */
81 CHECKLEN(2);
82
83 /* Lingo 0x03 must have been negotiated */
84 if (!DEVICE_LINGO_SUPPORTED(0x03)) {
85 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
86 return;
87 }
88
89 switch (cmd)
90 {
91 /* ACK (0x00)
92 *
93 * Sent from the iPod to the device
94 */
95
96 /* GetCurrentEQProfileIndex (0x01)
97 *
98 * Return the index of the current equalizer profile.
99 *
100 * Packet format (offset in buf[]: Description)
101 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
102 * 0x01: Command, always 0x01
103 *
104 * Returns:
105 * RetCurrentEQProfileIndex
106 *
107 * Packet format (offset in data[]: Description)
108 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
109 * 0x01: Command, always 0x02
110 * 0x02-0x05: Index as an unsigned 32bit integer
111 */
112 case 0x01:
113 {
114 IAP_TX_INIT(0x03, 0x02);
115 IAP_TX_PUT_U32(0x00);
116
117 iap_send_tx();
118 break;
119 }
120
121 /* RetCurrentEQProfileIndex (0x02)
122 *
123 * Sent from the iPod to the device
124 */
125
126 /* SetCurrentEQProfileIndex (0x03)
127 *
128 * Set the active equalizer profile
129 *
130 * Packet format (offset in buf[]: Description)
131 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
132 * 0x01: Command, always 0x03
133 * 0x02-0x05: Profile index to activate
134 * 0x06: Whether to restore the previous profile on detach
135 *
136 * Returns on success:
137 * IAP_ACK_OK
138 *
139 * Returns on failure:
140 * IAP_ACK_CMD_FAILED
141 *
142 * TODO: Figure out return code for invalid index
143 */
144 case 0x03:
145 {
146 uint32_t index;
147
148 CHECKLEN(7);
149
150 index = get_u32(&buf[2]);
151
152 if (index > 0) {
153 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
154 break;
155 }
156
157 /* Currently, we just ignore the command and acknowledge it */
158 cmd_ok(cmd);
159 break;
160 }
161
162 /* GetNumEQProfiles (0x04)
163 *
164 * Get the number of available equalizer profiles
165 *
166 * Packet format (offset in buf[]: Description)
167 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
168 * 0x01: Command, always 0x04
169 *
170 * Returns:
171 * RetNumEQProfiles
172 *
173 * Packet format (offset in data[]: Description)
174 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
175 * 0x01: Command, always 0x05
176 * 0x02-0x05: Number as an unsigned 32bit integer
177 */
178 case 0x04:
179 {
180 IAP_TX_INIT(0x03, 0x05);
181 /* Return one profile (0, the disabled profile) */
182 IAP_TX_PUT_U32(0x01);
183
184 iap_send_tx();
185 break;
186 }
187
188 /* RetNumEQProfiles (0x05)
189 *
190 * Sent from the iPod to the device
191 */
192
193 /* GetIndexedEQProfileName (0x06)
194 *
195 * Return the name of the indexed equalizer profile
196 *
197 * Packet format (offset in buf[]: Description)
198 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
199 * 0x01: Command, always 0x06
200 * 0x02-0x05: Profile index to get the name of
201 *
202 * Returns on success:
203 * RetIndexedEQProfileName
204 *
205 * Packet format (offset in data[]: Description)
206 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
207 * 0x01: Command, always 0x06
208 * 0x02-0xNN: Name as an UTF-8 null terminated string
209 *
210 * Returns on failure:
211 * IAP_ACK_BAD_PARAM
212 *
213 * TODO: Figure out return code for out of range index
214 */
215 case 0x06:
216 {
217 uint32_t index;
218
219 CHECKLEN(6);
220
221 index = get_u32(&buf[2]);
222
223 if (index > 0) {
224 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
225 break;
226 }
227 IAP_TX_INIT(0x03, 0x07);
228 IAP_TX_PUT_STRING("Default");
229
230 iap_send_tx();
231 break;
232 }
233
234 /* RetIndexedQUProfileName (0x07)
235 *
236 * Sent from the iPod to the device
237 */
238
239 /* SetRemoteEventNotification (0x08)
240 *
241 * Set events the device would like to be notified about
242 *
243 * Packet format (offset in buf[]: Description)
244 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
245 * 0x01: Command, always 0x08
246 * 0x02-0x05: Event bitmask
247 *
248 * Returns:
249 * IAP_ACK_OK
250 */
251 case 0x08:
252 {
253 struct tm* tm;
254
255 CHECKLEN(6);
256 CHECKAUTH;
257
258 /* Save the current state of the various attributes we track */
259 device.trackpos_ms = iap_get_trackpos();
260 device.track_index = iap_get_trackindex();
261 device.chapter_index = 0;
262 device.play_status = audio_status();
263 /* TODO: Fix this */
264 device.mute = false;
265 device.volume = 0x80;
266 device.power_state = charger_input_state;
267 device.battery_level = battery_level();
268 /* TODO: Fix this */
269 device.equalizer_index = 0;
270 device.shuffle = global_settings.playlist_shuffle;
271 device.repeat = global_settings.repeat_mode;
272 tm = get_time();
273 memcpy(&(device.datetime), tm, sizeof(struct tm));
274 device.alarm_state = 0;
275 device.alarm_hour = 0;
276 device.alarm_minute = 0;
277 /* TODO: Fix this */
278 device.backlight = 0;
279 device.hold = button_hold();
280 device.soundcheck = 0;
281 device.audiobook = 0;
282 device.trackpos_s = (device.trackpos_ms/1000) & 0xFFFF;
283
284 /* Get the notification bits */
285 device.do_notify = false;
286 device.changed_notifications = 0;
287 device.notifications = get_u32(&buf[0x02]);
288 if (device.notifications)
289 device.do_notify = true;
290
291 cmd_ok(cmd);
292 break;
293 }
294
295 /* RemoteEventNotification (0x09)
296 *
297 * Sent from the iPod to the device
298 */
299
300 /* GetRemoteEventStatus (0x0A)
301 *
302 * Request the events changed since the last call to GetREmoteEventStatus
303 * or SetRemoteEventNotification
304 *
305 * Packet format (offset in buf[]: Description)
306 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
307 * 0x01: Command, always 0x0A
308 *
309 * This command requires authentication
310 *
311 * Returns:
312 * RetRemoteEventNotification
313 *
314 * Packet format (offset in data[]: Description)
315 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
316 * 0x01: Command, always 0x0B
317 * 0x02-0x05: Event status bits
318 */
319 case 0x0A:
320 {
321 CHECKAUTH;
322 IAP_TX_INIT(0x03, 0x0B);
323 IAP_TX_PUT_U32(device.changed_notifications);
324
325 iap_send_tx();
326
327 device.changed_notifications = 0;
328 break;
329 }
330
331 /* RetRemoteEventStatus (0x0B)
332 *
333 * Sent from the iPod to the device
334 */
335
336 /* GetiPodStateInfo (0x0C)
337 *
338 * Request state information from the iPod
339 *
340 * Packet format (offset in buf[]: Description)
341 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
342 * 0x01: Command, always 0x0C
343 * 0x02: Type information
344 *
345 * This command requires authentication
346 *
347 * Returns:
348 * RetiPodStateInfo
349 *
350 * Packet format (offset in data[]: Description)
351 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
352 * 0x01: Command, always 0x0D
353 * 0x02: Type information
354 * 0x03-0xNN: State information
355 */
356 case 0x0C:
357 {
358 struct mp3entry* id3;
359 struct playlist_info* playlist;
360 int play_status;
361 struct tm* tm;
362
363 CHECKLEN(3);
364 CHECKAUTH;
365
366 IAP_TX_INIT(0x03, 0x0D);
367 IAP_TX_PUT(buf[0x02]);
368
369 switch (buf[0x02])
370 {
371 /* 0x00: Track position
372 * Data length: 4
373 */
374 case 0x00:
375 {
376 id3 = audio_current_track();
377 IAP_TX_PUT_U32(id3->elapsed);
378
379 iap_send_tx();
380 break;
381 }
382
383 /* 0x01: Track index
384 * Data length: 4
385 */
386 case 0x01:
387 {
388 playlist = playlist_get_current();
389 IAP_TX_PUT_U32(playlist->index - playlist->first_index);
390
391 iap_send_tx();
392 break;
393 }
394
395 /* 0x02: Chapter information
396 * Data length: 8
397 */
398 case 0x02:
399 {
400 playlist = playlist_get_current();
401 IAP_TX_PUT_U32(playlist->index - playlist->first_index);
402 /* Indicate that track does not have chapters */
403 IAP_TX_PUT_U16(0x0000);
404 IAP_TX_PUT_U16(0xFFFF);
405
406 iap_send_tx();
407 break;
408 }
409
410 /* 0x03: Play status
411 * Data length: 1
412 */
413 case 0x03:
414 {
415 /* TODO: Handle FF/REW
416 */
417 play_status = audio_status();
418 if (play_status & AUDIO_STATUS_PLAY) {
419 if (play_status & AUDIO_STATUS_PAUSE) {
420 IAP_TX_PUT(0x02);
421 } else {
422 IAP_TX_PUT(0x01);
423 }
424 } else {
425 IAP_TX_PUT(0x00);
426 }
427
428 iap_send_tx();
429 break;
430 }
431
432 /* 0x04: Mute/UI/Volume
433 * Data length: 2
434 */
435 case 0x04:
436 {
437 /* Figuring out what the current volume is
438 * seems to be tricky.
439 * TODO: Fix.
440 */
441
442 /* Mute status */
443 IAP_TX_PUT(0x00);
444 /* Volume */
445 IAP_TX_PUT(0x80);
446
447 iap_send_tx();
448 break;
449 }
450
451 /* 0x05: Power/Battery
452 * Data length: 2
453 */
454 case 0x05:
455 {
456 iap_fill_power_state();
457
458 iap_send_tx();
459 break;
460 }
461
462 /* 0x06: Equalizer state
463 * Data length: 4
464 */
465 case 0x06:
466 {
467 /* Currently only one equalizer setting supported, 0 */
468 IAP_TX_PUT_U32(0x00);
469
470 iap_send_tx();
471 break;
472 }
473
474 /* 0x07: Shuffle
475 * Data length: 1
476 */
477 case 0x07:
478 {
479 IAP_TX_PUT(global_settings.playlist_shuffle?0x01:0x00);
480
481 iap_send_tx();
482 break;
483 }
484
485 /* 0x08: Repeat
486 * Data length: 1
487 */
488 case 0x08:
489 {
490 switch (global_settings.repeat_mode)
491 {
492 case REPEAT_OFF:
493 {
494 IAP_TX_PUT(0x00);
495 break;
496 }
497
498 case REPEAT_ONE:
499 {
500 IAP_TX_PUT(0x01);
501 break;
502 }
503
504 case REPEAT_ALL:
505 {
506 IAP_TX_PUT(0x02);
507 break;
508 }
509 }
510
511 iap_send_tx();
512 break;
513 }
514
515 /* 0x09: Data/Time
516 * Data length: 6
517 */
518 case 0x09:
519 {
520 tm = get_time();
521
522 /* Year */
523 IAP_TX_PUT_U16(tm->tm_year);
524
525 /* Month */
526 IAP_TX_PUT(tm->tm_mon+1);
527
528 /* Day */
529 IAP_TX_PUT(tm->tm_mday);
530
531 /* Hour */
532 IAP_TX_PUT(tm->tm_hour);
533
534 /* Minute */
535 IAP_TX_PUT(tm->tm_min);
536
537 iap_send_tx();
538 break;
539 }
540
541 /* 0x0A: Alarm
542 * Data length: 3
543 */
544 case 0x0A:
545 {
546 /* Alarm not supported, always off */
547 IAP_TX_PUT(0x00);
548 IAP_TX_PUT(0x00);
549 IAP_TX_PUT(0x00);
550
551 iap_send_tx();
552 break;
553 }
554
555 /* 0x0B: Backlight
556 * Data length: 1
557 */
558 case 0x0B:
559 {
560 /* TOOD: Find out how to do this */
561 IAP_TX_PUT(0x00);
562
563 iap_send_tx();
564 break;
565 }
566
567 /* 0x0C: Hold switch
568 * Data length: 1
569 */
570 case 0x0C:
571 {
572 IAP_TX_PUT(button_hold()?0x01:0x00);
573
574 iap_send_tx();
575 break;
576 }
577
578 /* 0x0D: Sound check
579 * Data length: 1
580 */
581 case 0x0D:
582 {
583 /* TODO: Find out what the hell this is. Default to off */
584 IAP_TX_PUT(0x00);
585
586 iap_send_tx();
587 break;
588 }
589
590 /* 0x0E: Audiobook
591 * Data length: 1
592 */
593 case 0x0E:
594 {
595 /* Default to normal */
596 IAP_TX_PUT(0x00);
597
598 iap_send_tx();
599 break;
600 }
601
602 /* 0x0F: Track position in seconds
603 * Data length: 2
604 */
605 case 0x0F:
606 {
607 unsigned int pos;
608
609 id3 = audio_current_track();
610 pos = id3->elapsed/1000;
611
612 IAP_TX_PUT_U16(pos);
613
614 iap_send_tx();
615 break;
616 }
617
618 /* 0x10: Mute/UI/Absolute volume
619 * Data length: 3
620 */
621 case 0x10:
622 {
623 /* TODO: See volume above */
624 IAP_TX_PUT(0x00);
625 IAP_TX_PUT(0x80);
626 IAP_TX_PUT(0x80);
627
628 iap_send_tx();
629 break;
630 }
631
632 default:
633 {
634 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
635 break;
636 }
637 }
638 break;
639 }
640
641 /* RetiPodStateInfo (0x0D)
642 *
643 * Sent from the iPod to the device
644 */
645
646 /* SetiPodStateInfo (0x0E)
647 *
648 * Set status information to new values
649 *
650 * Packet format (offset in buf[]: Description)
651 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
652 * 0x01: Command, always 0x0E
653 * 0x02: Type of information to change
654 * 0x03-0xNN: New information
655 *
656 * This command requires authentication
657 *
658 * Returns on success:
659 * IAP_ACK_OK
660 *
661 * Returns on failure:
662 * IAP_ACK_CMD_FAILED
663 * IAP_ACK_BAD_PARAM
664 */
665 case 0x0E:
666 {
667 CHECKLEN(3);
668 CHECKAUTH;
669 switch (buf[0x02])
670 {
671 /* Track position (ms)
672 * Data length: 4
673 */
674 case 0x00:
675 {
676 uint32_t pos;
677
678 CHECKLEN(7);
679 pos = get_u32(&buf[0x03]);
680 audio_ff_rewind(pos);
681
682 cmd_ok(cmd);
683 break;
684 }
685
686 /* Track index
687 * Data length: 4
688 */
689 case 0x01:
690 {
691 uint32_t index;
692
693 CHECKLEN(7);
694 index = get_u32(&buf[0x03]);
695 audio_skip(index-iap_get_trackindex());
696
697 cmd_ok(cmd);
698 break;
699 }
700
701 /* Chapter index
702 * Data length: 2
703 */
704 case 0x02:
705 {
706 /* This is not supported */
707 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
708 break;
709 }
710
711 /* Play status
712 * Data length: 1
713 */
714 case 0x03:
715 {
716 CHECKLEN(4);
717 switch(buf[0x03])
718 {
719 case 0x00:
720 {
721 audio_stop();
722 cmd_ok(cmd);
723 break;
724 }
725
726 case 0x01:
727 {
728 audio_resume();
729 cmd_ok(cmd);
730 break;
731 }
732
733 case 0x02:
734 {
735 audio_pause();
736 cmd_ok(cmd);
737 break;
738 }
739
740 default:
741 {
742 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
743 break;
744 }
745 }
746 break;
747 }
748
749 /* Volume/Mute
750 * Data length: 2
751 * TODO: Fix this
752 */
753 case 0x04:
754 {
755 CHECKLEN(5);
756 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
757 break;
758 }
759
760 /* Equalizer
761 * Data length: 5
762 */
763 case 0x06:
764 {
765 uint32_t index;
766
767 CHECKLEN(8);
768 index = get_u32(&buf[0x03]);
769 if (index == 0) {
770 cmd_ok(cmd);
771 } else {
772 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
773 }
774 break;
775 }
776
777 /* Shuffle
778 * Data length: 2
779 */
780 case 0x07:
781 {
782 CHECKLEN(5);
783
784 switch(buf[0x03])
785 {
786 case 0x00:
787 {
788 iap_shuffle_state(false);
789 cmd_ok(cmd);
790 break;
791 }
792 case 0x01:
793 case 0x02:
794 {
795 iap_shuffle_state(true);
796 cmd_ok(cmd);
797 break;
798 }
799
800 default:
801 {
802 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
803 break;
804 }
805 }
806 break;
807 }
808
809 /* Repeat
810 * Data length: 2
811 */
812 case 0x08:
813 {
814 CHECKLEN(5);
815
816 switch(buf[0x03])
817 {
818 case 0x00:
819 {
820 iap_repeat_state(REPEAT_OFF);
821 cmd_ok(cmd);
822 break;
823 }
824 case 0x01:
825 {
826 iap_repeat_state(REPEAT_ONE);
827 cmd_ok(cmd);
828 break;
829 }
830 case 0x02:
831 {
832 iap_repeat_state(REPEAT_ALL);
833 cmd_ok(cmd);
834 break;
835 }
836 default:
837 {
838 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
839 break;
840 }
841 }
842 break;
843 }
844
845 /* Date/Time
846 * Data length: 6
847 */
848 case 0x09:
849 {
850 CHECKLEN(9);
851
852 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
853 break;
854 }
855
856 /* Alarm
857 * Data length: 4
858 */
859 case 0x0A:
860 {
861 CHECKLEN(7);
862
863 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
864 break;
865 }
866
867 /* Backlight
868 * Data length: 2
869 */
870 case 0x0B:
871 {
872 CHECKLEN(5);
873
874 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
875 break;
876 }
877
878 /* Sound check
879 * Data length: 2
880 */
881 case 0x0D:
882 {
883 CHECKLEN(5);
884
885 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
886 break;
887 }
888
889 /* Audio book speed
890 * Data length: 1
891 */
892 case 0x0E:
893 {
894 CHECKLEN(4);
895
896 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
897 break;
898 }
899
900 /* Track position (s)
901 * Data length: 2
902 */
903 case 0x0F:
904 {
905 uint16_t pos;
906
907 CHECKLEN(5);
908 pos = get_u16(&buf[0x03]);
909 audio_ff_rewind(1000L * pos);
910
911 cmd_ok(cmd);
912 break;
913 }
914
915 /* Volume/Mute/Absolute
916 * Data length: 4
917 * TODO: Fix this
918 */
919 case 0x10:
920 {
921 CHECKLEN(7);
922 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
923 break;
924 }
925
926 default:
927 {
928 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
929 break;
930 }
931 }
932
933 break;
934 }
935
936 /* GetPlayStatus (0x0F)
937 *
938 * Request the current play status information
939 *
940 * Packet format (offset in buf[]: Description)
941 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
942 * 0x01: Command, always 0x0F
943 *
944 * This command requires authentication
945 *
946 * Returns:
947 * RetPlayStatus
948 *
949 * Packet format (offset in data[]: Description)
950 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
951 * 0x01: Command, always 0x10
952 * 0x02: Play state
953 * 0x03-0x06: Current track index
954 * 0x07-0x0A: Current track length (ms)
955 * 0x0B-0x0E: Current track position (ms)
956 */
957 case 0x0F:
958 {
959 int play_status;
960 struct mp3entry* id3;
961 struct playlist_info* playlist;
962
963 CHECKAUTH;
964
965 IAP_TX_INIT(0x03, 0x10);
966
967 play_status = audio_status();
968
969 if (play_status & AUDIO_STATUS_PLAY) {
970 /* Playing or paused */
971 if (play_status & AUDIO_STATUS_PAUSE) {
972 /* Paused */
973 IAP_TX_PUT(0x02);
974 } else {
975 /* Playing */
976 IAP_TX_PUT(0x01);
977 }
978 playlist = playlist_get_current();
979 IAP_TX_PUT_U32(playlist->index - playlist->first_index);
980 id3 = audio_current_track();
981 IAP_TX_PUT_U32(id3->length);
982 IAP_TX_PUT_U32(id3->elapsed);
983 } else {
984 /* Stopped, all values are 0x00 */
985 IAP_TX_PUT(0x00);
986 IAP_TX_PUT_U32(0x00);
987 IAP_TX_PUT_U32(0x00);
988 IAP_TX_PUT_U32(0x00);
989 }
990
991 iap_send_tx();
992 break;
993 }
994
995 /* RetPlayStatus (0x10)
996 *
997 * Sent from the iPod to the device
998 */
999
1000 /* SetCurrentPlayingTrack (0x11)
1001 *
1002 * Set the current playing track
1003 *
1004 * Packet format (offset in buf[]: Description)
1005 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1006 * 0x01: Command, always 0x11
1007 * 0x02-0x05: Index of track to play
1008 *
1009 * This command requires authentication
1010 *
1011 * Returns on success:
1012 * IAP_ACK_OK
1013 *
1014 * Returns on failure:
1015 * IAP_ACK_BAD_PARAM
1016 */
1017 case 0x11:
1018 {
1019 uint32_t index;
1020 uint32_t trackcount;
1021
1022 CHECKAUTH;
1023 CHECKLEN(6);
1024
1025 index = get_u32(&buf[0x02]);
1026 trackcount = playlist_amount();
1027
1028 if (index >= trackcount)
1029 {
1030 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1031 break;
1032 }
1033 audio_skip(index-iap_get_trackindex());
1034 cmd_ok(cmd);
1035
1036 break;
1037 }
1038
1039 /* GetIndexedPlayingTrackInfo (0x12)
1040 *
1041 * Request information about a given track
1042 *
1043 * Packet format (offset in buf[]: Description)
1044 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1045 * 0x01: Command, always 0x12
1046 * 0x02: Type of information to retrieve
1047 * 0x03-0x06: Track index
1048 * 0x07-0x08: Chapter index
1049 *
1050 * This command requires authentication.
1051 *
1052 * Returns:
1053 * RetIndexedPlayingTrackInfo
1054 *
1055 * Packet format (offset in data[]: Description)
1056 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1057 * 0x01: Command, always 0x13
1058 * 0x02: Type of information returned
1059 * 0x03-0xNN: Information
1060 */
1061 case 0x12:
1062 {
1063 /* NOTE:
1064 *
1065 * Retrieving the track information from a track which is not
1066 * the currently playing track can take a seriously long time,
1067 * in the order of several seconds.
1068 *
1069 * This most certainly violates the IAP spec, but there's no way
1070 * around this for now.
1071 */
1072 uint32_t track_index;
1073 struct playlist_track_info track;
1074 struct mp3entry id3;
1075
1076 CHECKLEN(0x09);
1077 CHECKAUTH;
1078
1079 track_index = get_u32(&buf[0x03]);
1080 if (-1 == playlist_get_track_info(NULL, track_index, &track)) {
1081 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1082 break;
1083 }
1084
1085 IAP_TX_INIT(0x03, 0x13);
1086 IAP_TX_PUT(buf[2]);
1087 switch (buf[2])
1088 {
1089 /* 0x00: Track caps/info
1090 * Information length: 10 bytes
1091 */
1092 case 0x00:
1093 {
1094 iap_get_trackinfo(track_index, &id3);
1095 /* Track capabilities. None of these are supported, yet */
1096 IAP_TX_PUT_U32(0x00);
1097
1098 /* Track length in ms */
1099 IAP_TX_PUT_U32(id3.length);
1100
1101 /* Chapter count, stays at 0 */
1102 IAP_TX_PUT_U16(0x00);
1103
1104 iap_send_tx();
1105 break;
1106 }
1107
1108 /* 0x01: Chapter time/name
1109 * Information length: 4+variable
1110 */
1111 case 0x01:
1112 {
1113 /* Chapter length, set at 0 (no chapters) */
1114 IAP_TX_PUT_U32(0x00);
1115
1116 /* Chapter name, empty */
1117 IAP_TX_PUT_STRING("");
1118
1119 iap_send_tx();
1120 break;
1121 }
1122
1123 /* 0x02, Artist name
1124 * Information length: variable
1125 */
1126 case 0x02:
1127 {
1128 /* Artist name */
1129 iap_get_trackinfo(track_index, &id3);
1130 IAP_TX_PUT_STRLCPY(id3.artist);
1131
1132 iap_send_tx();
1133 break;
1134 }
1135
1136 /* 0x03, Album name
1137 * Information length: variable
1138 */
1139 case 0x03:
1140 {
1141 /* Album name */
1142 iap_get_trackinfo(track_index, &id3);
1143 IAP_TX_PUT_STRLCPY(id3.album);
1144
1145 iap_send_tx();
1146 break;
1147 }
1148
1149 /* 0x04, Genre name
1150 * Information length: variable
1151 */
1152 case 0x04:
1153 {
1154 /* Genre name */
1155 iap_get_trackinfo(track_index, &id3);
1156 IAP_TX_PUT_STRLCPY(id3.genre_string);
1157
1158 iap_send_tx();
1159 break;
1160 }
1161
1162 /* 0x05, Track title
1163 * Information length: variable
1164 */
1165 case 0x05:
1166 {
1167 /* Track title */
1168 iap_get_trackinfo(track_index, &id3);
1169 IAP_TX_PUT_STRLCPY(id3.title);
1170
1171 iap_send_tx();
1172 break;
1173 }
1174
1175 /* 0x06, Composer name
1176 * Information length: variable
1177 */
1178 case 0x06:
1179 {
1180 /* Track Composer */
1181 iap_get_trackinfo(track_index, &id3);
1182 IAP_TX_PUT_STRLCPY(id3.composer);
1183
1184 iap_send_tx();
1185 break;
1186 }
1187
1188 /* 0x07, Lyrics
1189 * Information length: variable
1190 */
1191 case 0x07:
1192 {
1193 /* Packet information bits. All 0 (single packet) */
1194 IAP_TX_PUT(0x00);
1195
1196 /* Packet index */
1197 IAP_TX_PUT_U16(0x00);
1198
1199 /* Lyrics */
1200 IAP_TX_PUT_STRING("");
1201
1202 iap_send_tx();
1203 break;
1204 }
1205
1206 /* 0x08, Artwork count
1207 * Information length: variable
1208 */
1209 case 0x08:
1210 {
1211 /* No artwork, return packet containing just the type byte */
1212 iap_send_tx();
1213 break;
1214 }
1215
1216 default:
1217 {
1218 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1219 break;
1220 }
1221 }
1222
1223 break;
1224 }
1225
1226 /* RetIndexedPlayingTrackInfo (0x13)
1227 *
1228 * Sent from the iPod to the device
1229 */
1230
1231 /* GetNumPlayingTracks (0x14)
1232 *
1233 * Request the number of tracks in the current playlist
1234 *
1235 * Packet format (offset in buf[]: Description)
1236 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1237 * 0x01: Command, always 0x14
1238 *
1239 * This command requires authentication.
1240 *
1241 * Returns:
1242 * RetNumPlayingTracks
1243 *
1244 * Packet format (offset in data[]: Description)
1245 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1246 * 0x01: Command, always 0x15
1247 * 0x02-0xNN: Number of tracks
1248 */
1249 case 0x14:
1250 {
1251 CHECKAUTH;
1252
1253 IAP_TX_INIT(0x03, 0x15);
1254 IAP_TX_PUT_U32(playlist_amount());
1255
1256 iap_send_tx();
1257 }
1258
1259 /* RetNumPlayingTracks (0x15)
1260 *
1261 * Sent from the iPod to the device
1262 */
1263
1264 /* GetArtworkFormats (0x16)
1265 *
1266 * Request a list of supported artwork formats
1267 *
1268 * Packet format (offset in buf[]: Description)
1269 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1270 * 0x01: Command, always 0x16
1271 *
1272 * This command requires authentication.
1273 *
1274 * Returns:
1275 * RetArtworkFormats
1276 *
1277 * Packet format (offset in data[]: Description)
1278 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1279 * 0x01: Command, always 0x17
1280 * 0x02-0xNN: list of 7 byte format descriptors
1281 */
1282 case 0x16:
1283 {
1284 CHECKAUTH;
1285
1286 /* We return the empty list, meaning no artwork
1287 * TODO: Fix to return actual artwork formats
1288 */
1289 IAP_TX_INIT(0x03, 0x17);
1290
1291 iap_send_tx();
1292 break;
1293 }
1294
1295 /* RetArtworkFormats (0x17)
1296 *
1297 * Sent from the iPod to the device
1298 */
1299
1300 /* GetTrackArtworkData (0x18)
1301 *
1302 * Request artwork for the given track
1303 *
1304 * Packet format (offset in buf[]: Description)
1305 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1306 * 0x01: Command, always 0x18
1307 * 0x02-0x05: Track index
1308 * 0x06-0x07: Format ID
1309 * 0x08-0x0B: Track offset in ms
1310 *
1311 * This command requires authentication.
1312 *
1313 * Returns:
1314 * RetTrackArtworkData
1315 *
1316 * Packet format (offset in data[]: Description)
1317 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1318 * 0x01: Command, always 0x19
1319 * 0x02-0x03: Descriptor index
1320 * 0x04: Pixel format code
1321 * 0x05-0x06: Image width in pixels
1322 * 0x07-0x08: Image height in pixels
1323 * 0x09-0x0A: Inset rectangle, top left x
1324 * 0x0B-0x0C: Inset rectangle, top left y
1325 * 0x0D-0x0E: Inset rectangle, bottom right x
1326 * 0x0F-0x10: Inset rectangle, bottom right y
1327 * 0x11-0x14: Row size in bytes
1328 * 0x15-0xNN: Image data
1329 *
1330 * If the image data does not fit in a single packet, subsequent
1331 * packets omit bytes 0x04-0x14.
1332 */
1333 case 0x18:
1334 {
1335 CHECKAUTH;
1336 CHECKLEN(0x0C);
1337
1338 /* No artwork support currently */
1339 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1340 break;
1341 }
1342
1343 /* RetTrackArtworkFormat (0x19)
1344 *
1345 * Sent from the iPod to the device
1346 */
1347
1348 /* GetPowerBatteryState (0x1A)
1349 *
1350 * Request the current power state
1351 *
1352 * Packet format (offset in buf[]: Description)
1353 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1354 * 0x01: Command, always 0x1A
1355 *
1356 * This command requires authentication.
1357 *
1358 * Returns:
1359 * RetPowerBatteryState
1360 *
1361 * Packet format (offset in data[]: Description)
1362 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1363 * 0x01: Command, always 0x1B
1364 * 0x02: Power state
1365 * 0x03: Battery state
1366 */
1367 case 0x1A:
1368 {
1369 IAP_TX_INIT(0x03, 0x1B);
1370
1371 iap_fill_power_state();
1372 iap_send_tx();
1373 break;
1374 }
1375
1376 /* RetPowerBatteryState (0x1B)
1377 *
1378 * Sent from the iPod to the device
1379 */
1380
1381 /* GetSoundCheckState (0x1C)
1382 *
1383 * Request the current sound check state
1384 *
1385 * Packet format (offset in buf[]: Description)
1386 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1387 * 0x01: Command, always 0x1C
1388 *
1389 * This command requires authentication.
1390 *
1391 * Returns:
1392 * RetSoundCheckState
1393 *
1394 * Packet format (offset in data[]: Description)
1395 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1396 * 0x01: Command, always 0x1D
1397 * 0x02: Sound check state
1398 */
1399 case 0x1C:
1400 {
1401 CHECKAUTH;
1402
1403 IAP_TX_INIT(0x03, 0x1D);
1404 IAP_TX_PUT(0x00); /* Always off */
1405
1406 iap_send_tx();
1407 break;
1408 }
1409
1410 /* RetSoundCheckState (0x1D)
1411 *
1412 * Sent from the iPod to the device
1413 */
1414
1415 /* SetSoundCheckState (0x1E)
1416 *
1417 * Set the sound check state
1418 *
1419 * Packet format (offset in buf[]: Description)
1420 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1421 * 0x01: Command, always 0x1E
1422 * 0x02: Sound check state
1423 * 0x03: Restore on exit
1424 *
1425 * This command requires authentication.
1426 *
1427 * Returns on success
1428 * IAP_ACK_OK
1429 *
1430 * Returns on failure
1431 * IAP_ACK_CMD_FAILED
1432 */
1433 case 0x1E:
1434 {
1435 CHECKAUTH;
1436 CHECKLEN(4);
1437
1438 /* Sound check is not supported right now
1439 * TODO: Fix
1440 */
1441
1442 cmd_ack(cmd, IAP_ACK_CMD_FAILED);
1443 break;
1444 }
1445
1446 /* GetTrackArtworkTimes (0x1F)
1447 *
1448 * Request a list of timestamps at which artwork exists in a track
1449 *
1450 * Packet format (offset in buf[]: Description)
1451 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1452 * 0x01: Command, always 0x1F
1453 * 0x02-0x05: Track index
1454 * 0x06-0x07: Format ID
1455 * 0x08-0x09: Artwork Index
1456 * 0x0A-0x0B: Artwork count
1457 *
1458 * This command requires authentication.
1459 *
1460 * Returns:
1461 * RetTrackArtworkTimes
1462 *
1463 * Packet format (offset in data[]: Description)
1464 * 0x00: Lingo ID: Display Remote Lingo, always 0x03
1465 * 0x01: Command, always 0x20
1466 * 0x02-0x05: Offset in ms
1467 *
1468 * Bytes 0x02-0x05 can be repeated multiple times
1469 */
1470 case 0x1F:
1471 {
1472 uint32_t index;
1473 uint32_t trackcount;
1474
1475 CHECKAUTH;
1476 CHECKLEN(0x0C);
1477
1478 /* Artwork is currently unsuported, just check for a valid
1479 * track index
1480 */
1481 index = get_u32(&buf[0x02]);
1482 trackcount = playlist_amount();
1483
1484 if (index >= trackcount)
1485 {
1486 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1487 break;
1488 }
1489
1490 /* Send an empty list */
1491 IAP_TX_INIT(0x03, 0x20);
1492
1493 iap_send_tx();
1494 break;
1495 }
1496
1497 /* The default response is IAP_ACK_BAD_PARAM */
1498 default:
1499 {
1500#ifdef LOGF_ENABLE
1501 logf("iap: Unsupported Mode03 Command");
1502#else
1503 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1504#endif
1505 break;
1506 }
1507 }
1508}
diff --git a/apps/iap/iap-lingo4.c b/apps/iap/iap-lingo4.c
new file mode 100644
index 0000000000..fa0196645b
--- /dev/null
+++ b/apps/iap/iap-lingo4.c
@@ -0,0 +1,3153 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Alan Korr & Nick Robinson
11 *
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.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ******************************************************************************/
19
20#include "iap-core.h"
21#include "iap-lingo.h"
22#include "dir.h"
23#include "settings.h"
24#include "filetree.h"
25#include "wps.h"
26#include "playback.h"
27
28/*
29 * This macro is meant to be used inside an IAP mode message handler.
30 * It is passed the expected minimum length of the message buffer.
31 * If the buffer does not have the required lenght an ACK
32 * packet with a Bad Parameter error is generated.
33 */
34#define CHECKLEN(x) do { \
35 if (len < (x)) { \
36 cmd_ack(cmd, IAP_ACK_BAD_PARAM); \
37 return; \
38 }} while(0)
39
40/* Check for authenticated state, and return an ACK Not
41 * Authenticated on failure.
42 */
43#define CHECKAUTH do { \
44 if (!DEVICE_AUTHENTICATED) { \
45 cmd_ack(cmd, IAP_ACK_NO_AUTHEN); \
46 return; \
47 }} while(0)
48
49/* Used to remember the last Type and Record requested */
50static char cur_dbrecord[5] = {0};
51
52/* Used to remember the total number of filtered database records */
53static unsigned long dbrecordcount = 0;
54
55/* Used to remember the LAST playlist selected */
56static unsigned long last_selected_playlist = 0;
57
58static void cmd_ack(const unsigned int cmd, const unsigned char status)
59{
60 IAP_TX_INIT4(0x04, 0x0001);
61 IAP_TX_PUT(status);
62 IAP_TX_PUT_U16(cmd);
63 iap_send_tx();
64}
65
66#define cmd_ok(cmd) cmd_ack((cmd), IAP_ACK_OK)
67
68static void get_playlist_name(unsigned char *dest,
69 unsigned long item_offset,
70 size_t max_length)
71{
72 if (item_offset == 0) return;
73 DIR* dp;
74 struct dirent* playlist_file = NULL;
75
76 dp = opendir(global_settings.playlist_catalog_dir);
77
78 char *extension;
79 unsigned long nbr = 0;
80 while ((nbr < item_offset) && ((playlist_file = readdir(dp)) != NULL))
81 {
82 /*Increment only if there is a playlist extension*/
83 if ((extension=strrchr(playlist_file->d_name, '.')) != NULL){
84 if ((strcmp(extension, ".m3u") == 0 ||
85 strcmp(extension, ".m3u8") == 0))
86 nbr++;
87 }
88 }
89 if (playlist_file != NULL) {
90 strlcpy(dest, playlist_file->d_name, max_length);
91 }
92 closedir(dp);
93}
94
95static void seek_to_playlist(unsigned long index)
96{
97 unsigned char selected_playlist
98 [sizeof(global_settings.playlist_catalog_dir)
99 + 1
100 + MAX_PATH] = {0};
101
102 strcpy(selected_playlist,
103 global_settings.playlist_catalog_dir);
104 int len = strlen(selected_playlist);
105 selected_playlist[len] = '/';
106 get_playlist_name (selected_playlist + len + 1,
107 index,
108 MAX_PATH);
109 ft_play_playlist(selected_playlist,
110 global_settings.playlist_catalog_dir,
111 strrchr(selected_playlist, '/') + 1);
112
113}
114
115static unsigned long nbr_total_playlists(void)
116{
117 DIR* dp;
118 unsigned long nbr_total_playlists = 0;
119 struct dirent* playlist_file = NULL;
120 char *extension;
121 dp = opendir(global_settings.playlist_catalog_dir);
122 while ((playlist_file = readdir(dp)) != NULL)
123 {
124 /*Increment only if there is a playlist extension*/
125 if ((extension=strrchr(playlist_file->d_name, '.')) != NULL)
126 {
127 if ((strcmp(extension, ".m3u") == 0 ||
128 strcmp(extension, ".m3u8") == 0))
129 {
130 nbr_total_playlists++;
131 }
132 }
133 }
134 closedir(dp);
135 return nbr_total_playlists;
136}
137
138void iap_handlepkt_mode4(const unsigned int len, const unsigned char *buf)
139{
140 unsigned int cmd = (buf[1] << 8) | buf[2];
141 /* Lingo 0x04 commands are at least 3 bytes in length */
142 CHECKLEN(3);
143
144 /* Lingo 0x04 must have been negotiated */
145 if (!DEVICE_LINGO_SUPPORTED(0x04)) {
146#ifdef LOGF_ENABLE
147 logf("iap: Mode04 Not Negotiated");
148#endif
149 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
150 return;
151 }
152
153 /* All these commands require extended interface mode */
154 if (interface_state != IST_EXTENDED) {
155#ifdef LOGF_ENABLE
156 logf("iap: Not in Mode04 Extended Mode");
157#endif
158 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
159 return;
160 }
161 switch (cmd)
162 {
163 case 0x0001: /* CmdAck. See above cmd_ack() */
164 /*
165 * The following is the description for the Apple Firmware
166 * The iPod sends this telegram to acknowledge the receipt of a
167 * command and return the command status. The command ID field
168 * indicates the device command for which the response is being
169 * sent. The command status indicates the results of the command
170 * (success or failure).
171 *
172 * Byte Value Meaning
173 * 0 0xFF Sync byte (required only for UART serial)
174 * 1 0x55 Start of telegram
175 * 2 0x06 Telegram payload length
176 * 3 0x04 Lingo ID: Extended Interface lingo
177 * 4 0x00 Command ID (bits 15:8)
178 * 5 0x01 Command ID (bits 7:0)
179 * 6 0xNN Command result status. Possible values are:
180 *  0x00 = Success (OK)
181 * 0x01 = ERROR: Unknown database category
182 *  0x02 = ERROR: Command failed
183 * 0x03 = ERROR: Out of resources
184 * 0x04 = ERROR: Bad parameter
185 * 0x05 = ERROR: Unknown ID
186 * 0x06 = Reserved
187 * 0x07 = Accessory not authenticated
188 *  0x08 - 0xFF = Reserved
189 * 7 0xNN The ID of the command being acknowledged (bits 15:8).
190 * 8 0xNN The ID of the command being acknowledged (bits 7:0).
191 * 9 0xNN Telegram payload checksum byte
192 */
193 {
194 /* We should NEVER receive this command so ERROR if we do */
195 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
196 break;
197 }
198 case 0x0002: /* GetCurrentPlayingTrackChapterInfo */
199 /* The following is the description for the Apple Firmware
200 * Requests the chapter information of the currently playing track.
201 * In response, the iPod sends a
202 * Command 0x0003: ReturnCurrentPlayingTrackChapterInfo
203 * telegram to the device.
204 * Note: The returned track index is valid only when there is a
205 * currently playing or paused track.
206 *
207 * Byte Value Meaning
208 * 0 0xFF Sync byte (required only for UART serial)
209 * 1 0x55 Start of telegram
210 * 2 0x03 Telegram payload length
211 * 3 0x04 Lingo ID: Extended Interface lingo
212 * 4 0x00 Command ID (bits 15:8)
213 * 5 0x02 Command ID (bits 7:0)
214 * 6 0xF7 Telegram payload checksum byte
215 *
216 * We Return that the track does not have chapter information by
217 * returning chapter index -1 (0xFFFFFFFF) and chapter count 0
218 * (0x00000000)
219 */
220 {
221 unsigned char data[] = {0x04, 0x00, 0x03,
222 0xFF, 0xFF, 0xFF, 0xFF,
223 0x00, 0x00, 0x00, 0x00};
224 iap_send_pkt(data, sizeof(data));
225 break;
226 }
227 case 0x0003: /* ReturnCurrentPlayingTrackChapterInfo. See Above */
228 /* The following is the description for the Apple Firmware
229 *
230 * Returns the chapter information of the currently playing track.
231 * The iPod sends this telegramin response to the
232 * Command 0x0002: GetCurrentPlayingTrackChapterInfo
233 * telegram from the device. The track chapter information includes
234 * the currently playingtrack's chapter index,as well as the
235 * total number of chapters in the track. The track chapter and the
236 * total number of chapters are 32-bit signed integers. The chapter
237 * index of the firstchapter is always 0x00000000. If the track does
238 * not have chapter information, a chapter index of -1(0xFFFFFFFF)
239 * and a chapter count of 0 (0x00000000) are returned.
240 *
241 * Byte Value Meaning
242 * 0 0xFF Sync byte (required only for UART serial)
243 * 1 0x55 Start of telegram
244 * 2 0x0B Telegram payload length
245 * 3 0x04 Lingo ID: Extended Interface lingo
246 * 4 0x00 Command ID (bits 15:8)
247 * 5 0x03 Command ID (bits 7:0)
248 * 6 0xNN Current chapter index (bits 31:24)
249 * 7 0xNN Current chapter index (bits 23:16)
250 * 8 0xNN Current chapter index (bits 15:8)
251 * 9 0xNN Current chapter index (bits 7:0)
252 * 10 0xNN Chapter count (bits 31:24)
253 * 11 0xNN Chapter count (bits 23:16)
254 * 12 0xNN Chapter count (bits 15:8)
255 * 13 0xNN Chapter count (bits 7:0)
256 * 14 0xNN Telegram payload checksum byte
257 */
258 {
259 /* We should NEVER receive this command so ERROR if we do */
260 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
261 break;
262 }
263 case 0x0004: /* SetCurrentPlayingTrackChapter */
264 /* The following is the description for the Apple Firmware
265 *
266 * Sets the currently playing track chapter.You can send the Command
267 * 0x0002: GetCurrentPlayingTrackChapterInfo telegram to get the
268 * chapter count and the index of the currently playing chapter in
269 * the current track. In response to the command
270 * SetCurrentPlayingTrackChapter, the iPod sends an ACK telegram
271 * with the command status.
272 *
273 * Note: This command should be used only when the iPod is in a
274 * playing or paused state. The command fails if the iPod is stopped
275 * or if the track does not contain chapter information.
276 *
277 * Byte Value Meaning
278 * 0 0xFF Sync byte (required only for UART serial)
279 * 1 0x55 Start of telegram
280 * 2 0x07 Telegram payload length
281 * 3 0x04 Lingo ID: Extended Interface lingo
282 * 4 0x00 Command ID (bits 15:8)
283 * 5 0x04 Command ID (bits 7:0)
284 * 6 0xNN Chapter index (bits 31:24)
285 * 7 0xNN Chapter index (bits 23:16)
286 * 8 0xNN Chapter index (bits 15:8)
287 * 9 0xNN Chapter index (bits 7:0)
288 * 10 0xNN Telegram payload checksum byte
289 *
290 * We don't do anything with this as we don't support chapters,
291 * so just return BAD_PARAM
292 */
293 {
294 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
295 break;
296 }
297 case 0x0005: /* GetCurrentPlayingTrackChapterPlayStatus */
298 /* The following is the description for the Apple Firmware
299 *
300 * Requests the chapter playtime status of the currently playing
301 * track. The status includes the chapter length and the time
302 * elapsed within that chapter. In response to a valid telegram, the
303 * iPod sends a Command 0x0006:
304 * ReturnCurrentPlayingTrackChapterPlayStatus telegram to the
305 * device.
306 *
307 * Note: If the telegram length or chapter index is invalid for
308 * instance, if the track does not contain chapter information the
309 * iPod responds with an ACK telegram including the specific error
310 * status.
311 *
312 * Byte Value Meaning
313 * 0 0xFF Sync byte (required only for UART serial)
314 * 1 0x55 Start of telegram
315 * 2 0x07 Telegram payload length
316 * 3 0x04 Lingo ID: Extended Interface lingo
317 * 4 0x00 Command ID (bits 15:8)
318 * 5 0x05 Command ID (bits 7:0)
319 * 6 0xNN Currently playingchapter index (bits31:24)
320 * 7 0xNN Currently playingchapter index (bits23:16)
321 * 8 0xNN Currently playing chapter index (bits 15:8)
322 * 9 0xNN Currently playing chapter index (bits 7:0)
323 * 10 0xNN Telegram payload checksum byte
324 *
325 * The returned data includes 4 bytes for Chapter Length followed
326 * by 4 bytes of elapsed time If there is no currently playing
327 * chapter, length and elapsed are 0
328 * We don't do anything with this as we don't support chapters,
329 * so just return BAD_PARAM
330 */
331 {
332 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
333 break;
334 }
335 case 0x0006: /* ReturnCurrentPlayingTrackChapterPlayStatus. See Above */
336 /* The following is the description for the Apple Firmware
337 *
338 * Returns the play status of the currently playing track chapter.
339 * The iPod sends this telegram in response to the Command 0x0005:
340 * GetCurrentPlayingTrackChapterPlayStatus telegram from the device.
341 * The returned information includes the chapter length and elapsed
342 * time, in milliseconds. If there is no currently playing chapter,
343 * the chapter length and elapsed time are zero.
344 *
345 * Byte Value Meaning
346 * 0 0xFF Sync byte (required only for UART serial)
347 * 1 0x55 Start of telegram
348 * 2 0x0B Telegram payload length
349 * 3 0x04 Lingo ID: Extended Interface lingo
350 * 4 0x00 Command ID (bits 15:8)
351 * 5 0x06 Command ID (bits 7:0)
352 * 6 0xNN Chapter length in milliseconds (bits 31:24)
353 * 7 0xNN Chapter length in milliseconds (bits 23:16)
354 * 8 0xNN Chapter length in milliseconds (bits 15:8)
355 * 9 0xNN Chapter length in milliseconds (bits 7:0)
356 * 10 0xNN Elapsed time in chapter, in milliseconds (bits 31:24)
357 * 11 0xNN Elapsed time in chapter, in milliseconds (bits 23:16)
358 * 12 0xNN Elapsed time in chapter, in milliseconds (bits 15:8)
359 * 13 0xNN Elapsed time in chapter, in milliseconds (bits 7:0)
360 * 14 0xNN Telegram payload checksum byte
361 */
362 {
363 /* We should NEVER receive this command so ERROR if we do */
364 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
365 break;
366 }
367 case 0x0007: /* GetCurrentPlayingTrackChapterName */
368 /* The following is the description for the Apple Firmware
369 *
370 * Requests a chapter name in the currently playing track. In
371 * response to a valid telegram, the iPod sends a Command 0x0008:
372 * ReturnCurrentPlayingTrackChapterName telegram to the device.
373 *
374 * Note: If the received telegram length or track index is invalid
375 * for instance, if the track does not have chapter information or
376 * is not a part of the Audiobook category, the iPod responds with
377 * an ACK telegram including the specific error status.
378 *
379 * Byte Value Meaning
380 * 0 0xFF Sync byte (required only for UART serial)
381 * 1 0x55 Start of telegram
382 * 2 0x07 Telegram payload length
383 * 3 0x04 Lingo ID: Extended Interface lingo
384 * 4 0x00 Command ID (bits 15:8)
385 * 5 0x07 Command ID (bits 7:0)
386 * 6 0xNN Chapter index (bits 31:24)
387 * 7 0xNN Chapter index (bits 23:16)
388 * 8 0xNN Chapter index (bits 15:8)
389 * 9 0xNN Chapter index (bits 7:0)
390 * 10 0xNN Telegram payload checksum byte
391 *
392 * We don't do anything with this as we don't support chapters,
393 * so just return BAD_PARAM
394 */
395 {
396 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
397 break;
398 }
399 case 0x0008: /* ReturnCurrentPlayingTrackChapterName. See Above */
400 /* The following is the description for the Apple Firmware
401 *
402 * Returns a chapter name in the currently playing track. The iPod
403 * sends this telegram in response to a valid Command 0x0007:
404 * GetCurrentPlayingTrackChapterName telegram from the
405 * device. The chapter name is encoded as a null-terminated UTF-8
406 * character array.
407 *
408 * Note: The chapter name string is not limited to 252 characters;
409 * it may be sent in small or large telegram format depending on
410 * the string length. The small telegram format is shown.
411 *
412 * Byte Value Meaning
413 * 0 0xFF Sync byte (required only for UART serial)
414 * 1 0x55 Start of telegram
415 * 2 0xNN Telegram payload length
416 * 3 0x04 Lingo ID: Extended Interface lingo
417 * 4 0x00 Command ID (bits 15:8)
418 * 5 0x08 Command ID (bits 7:0)
419 * 6-N 0xNN Chapter name as UTF-8 character array
420 *(last byte) 0xNN Telegram payload checksum byte
421 *
422 */
423 {
424 /* We should NEVER receive this command so ERROR if we do */
425 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
426 break;
427 }
428 case 0x0009: /* GetAudioBookSpeed */
429 /* The following is the description for the Apple Firmware
430 *
431 * Requests the current iPod audiobook speed state. The iPod
432 * responds with the “Command 0x000A: ReturnAudiobookSpeed”
433 * telegram indicating the current audiobook speed.
434 *
435 * Byte Value Meaning
436 * 0 0xFF Sync byte (required only for UART serial)
437 * 1 0x55 Start of telegram
438 * 2 0x03 Telegram payload length
439 * 3 0x04 Lingo ID: Extended Interface lingo
440 * 4 0x00 Command ID (bits 15:8)
441 * 5 0x09 Command ID (bits 7:0)
442 * 6 0xF0 Telegram payload checksum byte
443 *
444 * ReturnAudioBookSpeed
445 * 0x00 = Normal, 0xFF = Slow, 0x01 = Fast
446 * We always respond with Normal speed
447 */
448 {
449 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
450 iap_send_pkt(data, sizeof(data));
451 break;
452 }
453 case 0x000A: /* ReturnAudioBookSpeed. See Above */
454 /* The following is the description for the Apple Firmware
455 *
456 * Returns the current audiobook speed setting. The iPod sends
457 * this telegram in response to the Command 0x0009:
458 * GetAudiobookSpeed command from the device.
459 *
460 * Byte Value Meaning
461 * 0 0xFF Sync byte (required only for UART serial)
462 * 1 0x55 Start of telegram
463 * 2 0x04 Telegram payload length
464 * 3 0x04 Lingo ID: Extended Interface lingo
465 * 4 0x00 Command ID (bits 15:8)
466 * 5 0x0A Command ID (bits 7:0)
467 * 6 0xNN Audiobook speed status code.
468 * 0xFF Slow (-1)
469 * 0x00 Normal
470 * 0x01 Fast (+1)
471 * 7 0xNN Telegram payload checksum byte
472 *
473 */
474 {
475 /* We should NEVER receive this command so ERROR if we do */
476 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
477 break;
478 }
479 case 0x000B: /* SetAudioBookSpeed */
480 /* The following is the description for the Apple Firmware
481 * Sets the speed of audiobook playback. The iPod audiobook speed
482 * states are listed above. This telegram has two modes: one to
483 * set the speed of the currently playing audiobook and a second
484 * to set the audiobook speed for all audiobooks. Byte number 7
485 * is an optional byte; devices should not send this byte if they
486 * want to set the speed only of the currently playing audiobook.
487 * If devices want to set the global audiobook speed setting then
488 * they must use byte number 7. This is the Restore on Exit byte;
489 * a nonzero value restores the original audiobook speed setting
490 * when the accessory is detached. If this byte is zero, the
491 * audiobook speed setting set by the accessory is saved and
492 * persists after the accessory is detached from the iPod. See below
493 * for the telegram format used when including the Restore on Exit
494 * byte.
495 * In response to this command, the iPod sends an ACK telegram with
496 * the command status.
497 *
498 * Note: Accessory developers are encouraged to always use the
499 * Restore on Exit byte with a nonzero value, to restore any of the
500 * user's iPod settings that were modified by the accessory.
501 *
502 * Byte Value Meaning (Cuurent audiobook only
503 * 0 0xFF Sync byte (required only for UART serial)
504 * 1 0x55 Start of telegram
505 * 2 0x04 Telegram payload length
506 * 3 0x04 Lingo ID: Extended Interface lingo
507 * 4 0x00 Command ID (bits 15:8)
508 * 5 0x0B Command ID (bits 7:0)
509 * 6 0xNN New audiobook speed code.
510 * 7 0xNN Telegram payload checksum byte
511 *
512 *
513 * SetAudiobookSpeed telegram to set the global audiobook speed
514 * Byte Value Meaning
515 * 0 0xFF Sync byte (required only for UART serial)
516 * 1 0x55 Start of telegram
517 * 2 0x05 Telegram payload length
518 * 3 0x04 Lingo ID: Extended Interface lingo
519 * 4 0x00 Command ID (bits 15:8)
520 * 5 0x0B Command ID (bits 7:0)
521 * 6 0xNN Global audiobook speed code.
522 * 7 0xNN Restore on Exit byte.
523 * If 1, the original setting is restored on detach;
524 * if 0, the newsetting persists after accessory detach.
525 * 8 0xNN Telegram payload checksum byte
526 *
527 *
528 * We don't do anything with this as we don't support chapters,
529 * so just return BAD_PARAM
530 */
531 {
532 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
533 break;
534 }
535 case 0x000C: /* GetIndexedPlayingTrackInfo */
536 /* The following is the description for the Apple Firmware
537 *
538 * Gets track information for the track at the specified index.
539 * The track info type field specifies the type of information to be
540 * returned, such as song lyrics, podcast name, episode date, and
541 * episode description. In response, the iPod sends the Command
542 * 0x000D: ReturnIndexedPlayingTrackInfo command with the requested
543 * track information. If the information type is invalid or does not
544 * apply to the selected track, the iPod returns an ACK with an
545 * error status.
546 *
547 * Byte Value Meaning
548 * 0 0xFF Sync byte (required only for UART serial)
549 * 1 0x55 Start of telegram
550 * 2 0x0A Telegram payload length
551 * 3 0x04 Lingo ID: Extended Interface lingo
552 * 4 0x00 Command ID (bits 15:8)
553 * 5 0x0C Command ID (bits 7:0)
554 * 6 0xNN Track info type. See Below
555 * 7 0xNN Track index (bits 31:24)
556 * 8 0xNN Track index (bits 23:16)
557 * 9 0xNN Track index (bits 15:8)
558 * 10 0xNN Track index (bits 7:0)
559 * 11 0xNN Chapter index (bits 15:8)
560 * 12 0xNN Chapter index (bits 7:0)
561 * (last byte)0xNN Telegram payload checksum byte
562 *
563 * Track Info Types: Return Data
564 * 0x00 Track Capabilities. 10byte data
565 * 0x01 Podcast Name UTF-8 String
566 * 0x02 Track Release Date 7Byte Data All 0 if invalid
567 * 0x03 Track Description UTF-8 String
568 * 0x04 Track Song Lyrics UTF-8 String
569 * 0x05 Track Genre UTF-8 String
570 * 0x06 Track Composer UTF-8 String
571 * 0x07 Track Artwork Count 2byte formatID and 2byte count of images
572 * 0x08-0xff Reserved
573 *
574 * Track capabilities
575 * 0x00-0x03
576 * Bit0 is Audiobook
577 * Bit1 has chapters
578 * Bit2 has album art
579 * Bit3 has lyrics
580 * Bit4 is podcast episode
581 * Bit5 has Release Date
582 * Bit6 has Decription
583 * Bit7 Contains Video
584 * Bit8 Play as Video
585 * Bit9+ Reserved
586 * 0x04-0x07 Total Track Length in ms
587 * 0x08-0x09 Chapter Count
588 *
589 * Track Release Date Encoding
590 * 0x00 Seconds 0-59
591 * 0x01 Minutes 0-59
592 * 0x02 Hours 0-23
593 * 0x03 Day Of Month 1-31
594 * 0x04 Month 1-12
595 * 0x05 Year Bits 15:8 2006 = 2006AD
596 * 0x06 Year Bits 7:0
597 * 0x07 Weekday 0-6 where 0=Sunday 6=Saturday
598 *
599 *
600 */
601 {
602 if (len < (10))
603 {
604 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
605 break;
606 }
607 struct mp3entry *id3 = audio_current_track();
608
609 switch(buf[3])
610 {
611 case 0x01: /* Podcast Not Supported */
612 case 0x04: /* Lyrics Not Supported */
613 case 0x03: /* Description */
614 case 0x05: /* Genre */
615 case 0x06: /* Composer */
616 {
617 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
618 break;
619 }
620 default:
621 {
622 IAP_TX_INIT4(0x04, 0x000D);
623 IAP_TX_PUT(buf[3]);
624 switch(buf[3])
625 {
626 case 0x00:
627 {
628 /* Track Capabilities 10Bytes Data */
629 IAP_TX_PUT_U32(0); /* Track Capabilities. */
630 /* Currently None Supported*/
631 IAP_TX_PUT_U32(id3->length); /* Track Length */
632 IAP_TX_PUT_U16(0x00); /* Chapter Count */
633 break;
634 }
635 case 0x02:
636 {
637 /* Track Release Date 7 Bytes Data
638 * Currently only returns a fixed value,
639 * Sunday 1st Feb 2011 3Hr 4Min 5Secs
640 */
641 IAP_TX_PUT(5); /* Seconds 0-59 */
642 IAP_TX_PUT(4); /* Minutes 0-59 */
643 IAP_TX_PUT(3); /* Hours 0-23 */
644 IAP_TX_PUT(1); /* Day Of Month 1-31 */
645 IAP_TX_PUT(2); /* Month 1-12 */
646 IAP_TX_PUT_U16(2011); /* Year */
647 IAP_TX_PUT(0); /* Day 0=Sunday */
648 break;
649 }
650 case 0x07:
651 {
652 /* Track Artwork Count */
653 /* Currently not supported */
654 IAP_TX_PUT_U16(0x00); /* Format ID */
655 IAP_TX_PUT_U16(0x00); /* Image Count */
656 break;
657 }
658 }
659 iap_send_tx();
660 break;
661 }
662 }
663 break;
664 }
665 case 0x000D: /* ReturnIndexedPlayingTrackInfo. See Above */
666 /* The following is the description for the Apple Firmware
667 *
668 * Returns the requested track information type and data. The iPod
669 * sends this command in response to the Command 0x000C:
670 * GetIndexedPlayingTrackInfo command.
671 * Data returned as strings are encoded as null-terminated UTF-8
672 * character arrays.
673 * If the track information string does not exist, a null UTF-8
674 * string is returned. If the track has no release date, then the
675 * returned release date has all bytes zeros. Track song lyrics and
676 * the track description are sent in a large or small telegram
677 * format with an incrementing packet index field, spanning
678 * multiple packets if needed.
679 *
680 * Below is the packet format for the
681 * ReturnIndexedPlayingTrackInfo telegram sent in response to a
682 * request for information types 0x00 to 0x02.
683 *
684 * Byte Value Meaning
685 * 0 0xFF Sync byte
686 * 1 0x55 Start of telegram
687 * 2 0xNN Telegram payload length
688 * 3 0x04 Lingo ID: Extended Interface lingo
689 * 4 0x00 Command ID (bits 15:8)
690 * 5 0x0D Command ID (bits 7:0)
691 * 6 0xNN Track info type. See
692 * 7-N 0xNN Track information. The data format is specific
693 * to the track info type.
694 * NN 0xNN Telegram payload checksum byte
695 *
696 * Below is the large packet format for the
697 * ReturnIndexedPlayingTrackInfo telegram sent in response to a
698 * request for information types 0x03 to 0x04. The small telegram
699 * format is not shown.
700 *
701 * Byte Value Meaning
702 * 0 0xFF Sync byte
703 * 1 0x55 Start of telegram
704 * 2 0x00 Telegram payload marker (large format)
705 * 3 0xNN Large telegram payload length (bits 15:8)
706 * 4 0xNN Large telegram payload length (bits 7:0)
707 * 5 0x04 Lingo ID (Extended Interface lingo)
708 * 6 0x00 Command ID (bits 15:8)
709 * 7 0x0D Command ID (bits 7:0)
710 * 8 0xNN Track info type.
711 * 9 0xNN Packet information bits. If set,
712 * these bits have the following meanings:
713 * Bit 0: Indicates that there are multiple packets.
714 * Bit 1: This is the last packet. Applicable only if
715 * bit 0 is set.
716 * Bit 31:2 Reserved
717 * 10 0xNN Packet Index (bits 15:8)
718 * 11 0xNN Packet Index (bits 7:0)
719 * 12-N 0xNN Track information as a UTF-8 string.
720 * NN 0xNN Telegram payload checksum byte
721 *
722 * Track info types and return data
723 * Info Type Code Data Format
724 * 0x00 Track Capabilities and Information 10-byte data.
725 * 0x01 PodcastName UTF-8 string
726 * 0x02 Track Release Date 7-byte data.
727 * 0x03 Track Description UTF-8 string
728 * 0x04 Track Song Lyrics UTF-8 string
729 * 0x05 TrackGenre UTF-8 string
730 * 0x06 Track Composer UTF-8 string
731 * 0x07 Track Artwork Count Artwork count data. The
732 * artwork count is a sequence of 4-byte records; each record
733 * consists of a 2-byte format ID value followed by a 2-byte
734 * count of images in that format for this track. For more
735 * information about formatID and chapter index values, see
736 * commands 0x000E-0x0011 and 0x002A-0x002B.
737 * 0x08-0xFF Reserved
738 *
739 * Track Capabilities and Information encoding
740 * Byte Code
741 * 0x00-0x03 Track Capability bits. If set, these bits have the
742 * following meanings:
743 * Bit 0: Track is audiobook
744 * Bit 1: Track has chapters
745 * Bit 2: Track has album artwork
746 * Bit 3: Track has song lyrics
747 * Bit 4: Track is a podcast episode
748 * Bit 5: Track has release date
749 * Bit 6: Track has description
750 * Bit 7: Track contains video (a video podcast, music
751 * video, movie, or TV show)
752 * Bit 8: Track is currently queued to play as a video
753 * Bit 31:9: Reserved
754 * 0x04 Total track length, in milliseconds (bits 31:24)
755 * 0x05 Total track length, in milliseconds (bits 23:16)
756 * 0x06 Total track length, in milliseconds (bits 15:8)
757 * 0x07 Total track length, in milliseconds (bits 7:0)
758 * 0x08 Chapter count (bits 15:8)
759 * 0x09 Chapter count (bits 7:0)
760 *
761 * Track Release Date encoding
762 * Byte Code
763 * 0x00 Seconds (0-59)
764 * 0x01 Minutes (0-59)
765 * 0x02 Hours (0-23)
766 * 0x03 Day of themonth(1-31)
767 * 0x04 Month (1-12)
768 * 0x05 Year (bits 15:8). For example, 2006 signifies the year 2006
769 * 0x06 Year (bits 7:0)
770 * 0x07 Weekday (0-6, where 0 = Sunday and 6 = Saturday)
771 *
772 */
773 {
774 /* We should NEVER receive this command so ERROR if we do */
775 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
776 break;
777 }
778 case 0x000E: /* GetArtworkFormats */
779 /* The following is the description for the Apple Firmware
780 *
781 * The device sends this command to obtain the list of supported
782 * artwork formats on the iPod. No parameters are sent.
783 *
784 * Byte Value Comment
785 * 0 0xFF Sync byte (required only for UART serial)
786 * 1 0x55 Start of telegram
787 * 2 0x03 Length of packet
788 * 3 0x04 Lingo ID: Extended Interface lingo
789 * 4 0x00 Command ID (bits 15:8)
790 * 5 0x0E Command ID (bits 7:0)
791 * 6 0xEB Checksum/
792 *
793 * Returned Artwork Formats are a 7byte record.
794 * formatID:2
795 * pixelFormat:1
796 * width:2
797 * height:2
798 */
799 {
800 unsigned char data[] = {0x04, 0x00, 0x0F,
801 0x04, 0x04, /* FormatID */
802 0x02, /* PixelFormat*/
803 0x00, 0x64, /* 100 pixels */
804 0x00, 0x64, /* 100 pixels */
805 0x04, 0x05, /* FormatID */
806 0x02, /* PixelFormat*/
807 0x00, 0xC8, /* 200 pixels */
808 0x00, 0xC8 /* 200 pixels */
809 };
810 iap_send_pkt(data, sizeof(data));
811 break;
812 }
813 case 0x000F: /* RetArtworkFormats. See Above */
814 /* The following is the description for the Apple Firmware
815 *
816 * The iPod sends this command to the device, giving it the list
817 * of supported artwork formats. Each format is described in a
818 * 7-byte record (formatID:2, pixelFormat:1, width:2, height:2).
819 * The formatID is used when sending GetTrackArtworkTimes.
820 * The device may return zero records.
821 *
822 * Byte Value Comment
823 * 0 0xFF Sync byte (required only for UART serial)
824 * 1 0x55 Start of telegram
825 * 2 0xNN Length of packet
826 * 3 0x04 Lingo ID: Extended Interface lingo
827 * 4 0x00 Command ID (bits 15:8)
828 * 5 0x0F Command ID (bits 7:0)
829 * NN 0xNN formatID (15:8) iPod-assigned value for this format
830 * NN 0xNN formatID (7:0)
831 * NN 0xNN pixelFormat. Same as from SetDisplayImage
832 * NN 0xNN imageWidth(15:8).Number of pixels widefor eachimage.
833 * NN 0xNN imageWidth (7:0)
834 * NN 0xNN imageHeight (15:8). Number of pixels high for each
835 * NN 0xNN imageHeight (7:0). image
836 * Previous 7 bytes may be repeated NN times
837 * NN 0xNN Checksum
838 *
839 */
840 {
841 /* We should NEVER receive this command so ERROR if we do */
842 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
843 break;
844 }
845 case 0x0010: /* GetTrackArtworkData */
846 /* The following is the description for the Apple Firmware
847 * The device sends this command to the iPod to request data for a
848 * given trackIndex, formatID, and artworkIndex. The time offset
849 * from track start is the value returned by GetTrackArtworkTimes
850 *
851 * Byte Value Comment
852 * 0 0xFF Sync byte (required only for UART serial)
853 * 1 0x55 Start of telegram
854 * 2 0x0D Length of packet
855 * 3 0x04 Lingo ID: Extended Interface lingo
856 * 4 0x00 Command ID (bits 15:8)
857 * 5 0x10 Command ID (bits 7:0)
858 * 6 0xNN trackIndex (31:24).
859 * 7 0xNN trackIndex(23:16)
860 * 8 0xNN trackIndex (15:8)
861 * 9 0xNN trackIndex (7:0)
862 * 10 0xNN formatID (15:8)
863 * 11 0xNN formatID (7:0)
864 * 12 0xNN time offset from track start, in ms (31:24)
865 * 13 0xNN time offset from track start, in ms (23:16)
866 * 14 0xNN time offset from track start, in ms (15:8)
867 * 15 0xNN time offset from track start, in ms (7:0)
868 * 16 0xNN Checksum
869 *
870 * Returned data is
871 * DescriptorTelegramIndex: 2
872 * pixelformatcode: 1
873 * ImageWidthPixels: 2
874 * ImageHeightPixels: 2
875 * InsetRectangleTopLeftX: 2
876 * InsetRectangleTopLeftY: 2
877 * InsetRectangleBotRightX: 2
878 * InsetRectangleBotRightY: 2
879 * RowSizeInBytes: 4
880 * ImagePixelData:VariableLength
881 * Subsequent packets omit bytes 8 - 24
882 */
883 {
884 unsigned char data[] = {0x04, 0x00, 0x11,
885 0x00, 0x00, /* DescriptorIndex */
886 0x00, /* PixelFormat */
887 0x00, 0x00, /* ImageWidthPixels*/
888 0x00, 0x00, /* ImageHeightPixels*/
889 0x00, 0x00, /* InsetRectangleTopLeftX*/
890 0x00, 0x00, /* InsetRectangleTopLeftY*/
891 0x00, 0x00, /* InsetRectangleBotRightX*/
892 0x00, 0x00, /* InsetRectangleBotRoghtY*/
893 0x00, 0x00, 0x00, 0x00,/* RowSize*/
894 0x00 /* ImagePixelData Var Length*/
895 };
896 iap_send_pkt(data, sizeof(data));
897 break;
898 }
899 case 0x0011: /* RetTrackArtworkData. See Abobe */
900 /* The following is the description for the Apple Firmware
901 *
902 * The iPod sends the requested artwork to the accessory. Multiple
903 * RetTrackArtworkData commands may be necessary to transfer all
904 * the data because it will be too much to fit into a single packet.
905 * This command uses nearly the same format as the SetDisplayImage
906 * command (command 0x0032). The only difference is the addition
907 * of 2 coordinates; they define an inset rectangle that describes
908 * any padding that may have been added to the image. The
909 * coordinates consist of two x,y pairs. Each x or y value is 2
910 * bytes, so the total size of the coordinate set is 8 bytes.
911 *
912 * Byte Value Comment
913 * 0 0xFF Sync byte (required only for UART serial)
914 * 1 0x55 Start of telegram
915 * 2 0xNN Length of packet
916 * 3 0x04 Lingo ID: Extended Interface lingo
917 * 4 0x00 Command ID (bits 15:8)
918 * 5 0x11 Command ID (bits 7:0)
919 * 6 0x00 Descriptor telegram index (15:8).
920 * These fields uniquely identify each packet in the
921 * RetTrackArtworkData transaction. The first telegram
922 * is the descriptor telegram, which always starts with
923 * an index of 0x0000.
924 * 7 0x00 Descriptor telegram index (7:0)
925 * 8 0xNN Display pixel format code.
926 * 9 0xNN Imagewidth in pixels (15:8)
927 * 10 0xNN Image width in pixels (7:0)
928 * 11 0xNN Image height in pixels (15:8)
929 * 12 0xNN Image height in pixels (7:0)
930 * 13 0xNN Inset rectangle, top-left point, x value (15:8)
931 * 14 0xNN Inset rectangle, top-left point, x value (7:0)
932 * 15 0xNN Inset rectangle, top-left point, y value (15:8)
933 * 16 0xNN Inset rectangle, top-left point, y value (7:0)
934 * 17 0xNN Inset rectangle,bottom-rightpoint,xvalue(15:8)
935 * 18 0xNN Inset rectangle,bottom-rightpoint, x value(7:0)
936 * 19 0xNN Inset rectangle,bottom-rightpoint,y value(15:8)
937 * 20 0xNN Inset rectangle, bottom-right point, y value(7:0)
938 * 21 0xNN Rowsize in bytes (31:24)
939 * 22 0xNN Rowsize in bytes (23:16)
940 * 23 0xNN Row size in bytes (15:8)
941 * 24 0xNN Row size in bytes (7:0)
942 * 25-NN 0xNN Image pixel data (variable length)
943 * NN 0xNN Checksum
944 *
945 * In subsequent packets in the sequence, bytes 8 through 24 are
946 * omitted.
947 */
948 {
949 /* We should NEVER receive this command so ERROR if we do */
950 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
951 break;
952 }
953 case 0x0012: /* RequestProtocolVersion */
954 /* The following is the description for the Apple Firmware
955 *
956 * This command is deprecated.
957 *
958 * Requests the version of the running protocol from the iPod.
959 * The iPod responds with a Command 0x0013:ReturnProtocolVersion
960 * command.
961 *
962 * Note: This command requests the Extended Interface protocol
963 * version, not the iPod software version.
964 *
965 * Byte Value Meaning
966 * 0 0xFF Sync byte (required only for UART serial)
967 * 1 0x55 Start of telegram
968 * 2 0x03 Telegram payload length
969 * 3 0x04 Lingo ID: Extended Interface lingo
970 * 4 0x00 Command ID (bits 15:8)
971 * 5 0x12 Command ID (bits 7:0)
972 * 6 0xE7 Telegram payload checksum byte
973 *
974 */
975 {
976 IAP_TX_INIT4(0x04, 0x0013);
977 IAP_TX_PUT(LINGO_MAJOR(0x04));
978 IAP_TX_PUT(LINGO_MINOR(0x04));
979 iap_send_tx();
980 break;
981 }
982 case 0x0013: /* ReturnProtocolVersion. See Above */
983 /* The following is the description for the Apple Firmware
984 * This command is deprecated.
985 * Sent from the iPod to the device
986 * Returns the iPod Extended Interface protocol version number.
987 * The iPod sends this command in response to the Command 0x0012:
988 * RequestProtocolVersion command from the device. The major
989 * version number specifies the protocol version digits to the left
990 * of the decimal point; the minor version number specifies the
991 * digits to the right of the decimal point. For example, a major
992 * version number of 0x01 and a minor version number of 0x08
993 * represents an Extended Interface protocol version of 1.08. This
994 * protocol information is also available through the General lingo
995 * (lingo 0x00) command RequestLingoProtocolVersion when passing
996 * lingo 0x04 as the lingo parameter.
997 *
998 * Note: This command returns the Extended Interface protocol
999 * version, not the iPod software version.
1000 *
1001 * Byte Value Meaning
1002 * 0 0xFF Sync byte (required only for UART serial)
1003 * 1 0x55 Start of telegram
1004 * 2 0x05 Telegram payload length
1005 * 3 0x04 Lingo ID: Extended Interface lingo
1006 * 4 0x00 Command ID (bits 15:8)
1007 * 5 0x13 Command ID (bits 7:0)
1008 * 6 0xNN Protocol major version number
1009 * 7 0xNN Protocol minor version number
1010 * 8 0xNN Telegram payload checksum byte
1011 *
1012 */
1013 {
1014 /* We should NEVER receive this command so ERROR if we do */
1015 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1016 break;
1017 }
1018 case 0x0014: /* RequestiPodName */
1019 /* The following is the description for the Apple Firmware
1020 * This command is deprecated.
1021 * Retrieves the name of the iPod
1022 *
1023 * Returns the name of the user's iPod or 'iPod' if the iPod name
1024 * is undefined. This allows the iPod name to be shown in the
1025 * human-machineinterface(HMI) of the interfacingbody. The iPod
1026 * responds with the Command 0x0015: ReturniPodName command
1027 * containing the iPod name text string.
1028 *
1029 * Byte Value Meaning
1030 * 0 0xFF Sync byte (required only for UART serial)
1031 * 1 0x55 Start of telegram
1032 * 2 0x03 Telegram payload length
1033 * 3 0x04 Lingo ID: Extended Interface lingo
1034 * 4 0x00 Command ID (bits 15:8)
1035 * 5 0x14 Command ID (bits 7:0)
1036 * 6 0xE5 Telegram payload checksum byte
1037 *
1038 * We return ROCKBOX, should this be definable?
1039 * Should it be Volume Name?
1040 */
1041 {
1042 IAP_TX_INIT4(0x04, 0x0015);
1043 IAP_TX_PUT_STRING("ROCKBOX");
1044 iap_send_tx();
1045 break;
1046 }
1047 case 0x0015: /* ReturniPodName. See Above */
1048 /* The following is the description for the Apple Firmware
1049 * This command is deprecated.
1050 * Sent from the iPod to the device
1051 *
1052 * The iPod sends this command in response to the Command 0x0014:
1053 * RequestiPodName telegram from the device. The iPod name is
1054 * encoded as a null-terminated UTF-8 character array. The iPod
1055 * name string is not limited to 252 characters; it may be sent
1056 * in small or large telegram format. The small telegram format
1057 * is shown.
1058 *
1059 * Note: Starting with version 1.07 of the Extended Interface lingo,
1060 * the ReturniPodName command on Windows-formatted iPods returns the
1061 * iTunes name of the iPod instead of the Windows volume name.
1062 *
1063 * Byte Value Meaning
1064 * 0 0xFF Sync byte (required only for UART serial)
1065 * 1 0x55 Start of telegram
1066 * 2 0xNN Telegram payload length
1067 * 3 0x04 Lingo ID: Extended Interface lingo
1068 * 4 0x00 Command ID (bits 15:8)
1069 * 5 0x15 Command ID (bits 7:0)
1070 * 6-N 0xNN iPod name as UTF-8 character array
1071 * NN 0xNN Telegram payload checksum byte
1072 *
1073 */
1074 {
1075 /* We should NEVER receive this command so ERROR if we do */
1076 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1077 break;
1078 }
1079 case 0x0016: /* ResetDBSelection */
1080 /* The following is the description for the Apple Firmware
1081 *
1082 * Resets the current database selection to an empty state and
1083 * invalidates the category entry count that is, sets the count
1084 * to 0, for all categories except the playlist category. This is
1085 * analogous to pressing the Menu button repeatedly to get to the
1086 * topmost iPod HMI menu. Any previously selected database items
1087 * are deselected. The command has no effect on the playback engine
1088 * In response, the iPod sends an ACK telegram with the command
1089 * status. Once the accessory has reset the database selection,
1090 * it must initialize the category count before it can select
1091 * database records. Please refer to Command 0x0018:
1092 * GetNumberCategorizedDBRecords and Command 0x0017:
1093 * SelectDBRecord for details.
1094 *
1095 * Note: Starting with protocol version 1.07, the ResetDBSelection
1096 * command clears the sort order.
1097 *
1098 * Byte Value Meaning
1099 * 0 0xFF Sync byte (required only for UART serial)
1100 * 1 0x55 Start of telegram
1101 * 2 0x03 Telegram payload length
1102 * 3 0x04 Lingo ID: Extended Interface lingo
1103 * 4 0x00 Command ID (bits 15:8)
1104 * 5 0x16 Command ID (bits 7:0)
1105 * 6 0xE3 Telegram payload checksum byte
1106 *
1107 *
1108 * Reset the DB Record Type
1109 * Hierarchy is as follows
1110 * All = 0
1111 * Playlist = 1
1112 * Artist = 2
1113 * Album = 3
1114 * Genre = 4
1115 * Tracks = 5
1116 * Composers = 6
1117 * Audiobooks = 7
1118 * Podcasts = 8
1119 *
1120 */
1121 {
1122 cur_dbrecord[0] = 0;
1123 put_u32(&cur_dbrecord[1],0);
1124 /* respond with cmd ok packet */
1125 cmd_ok(cmd);
1126 break;
1127 }
1128 case 0x0017: /* SelectDBRecord */
1129 /* The following is the description for the Apple Firmware
1130 * Selects one or more records in the Database Engine, based on a
1131 * category relative index. For example, selecting category two
1132 * (artist) and record index one results in a list of selected
1133 * tracks (or database records) from the second artist in the
1134 * artist list.
1135 * Selections are additive and limited by the category hierarchy;
1136 * Subsequent selections are made based on the subset of records
1137 * resulting from the previous selections and not from the entire
1138 * database.
1139 * Note that the selection of a single record automatically passes
1140 * it to the Playback Engine and starts its playback. Record indices
1141 * consist of a 32-bit signed integer. To select database records
1142 * with a specific sort order, use
1143 * Command 0x0038: SelectSortDBRecord
1144 * SelectDBRecord should be called only once a category count has
1145 * been initialized through a call to Command 0x0018:
1146 * GetNumberCategorizedDBRecords. Without a valid category count,
1147 * the SelectDBRecord call cannot select a database record and will
1148 * fail with a command failed ACK. Accessories that make use of
1149 * Command 0x0016: ResetDBSelection must always initialize the
1150 * category count before selecting a new database record using
1151 * SelectDBRecord.
1152 * Accessories should pay close attention to the ACK returned by the
1153 * SelectDBRecord command. Ignoring errors may cause unexpected
1154 * behavior.
1155 * To undo a database selection, send the SelectDBRecord telegram
1156 * with the current category selected in theDatabase Engine and a
1157 * record index of -1 (0xFFFFFFFF). This has the same effect as
1158 * pressing the iPod Menu button once and moves the database
1159 * selection up to the next highest menu level. For example, if a
1160 * device selected artist number three and then album number one,
1161 * it could use the SelectDBRecord(Album, -1) telegram to return
1162 * to the database selection of artist number three. If multiple
1163 * database selections have been made, devices can use any of the
1164 * previously used categories to return to the next highest database
1165 * selection. If the category used in one of these SelectDBRecord
1166 * telegrams has not been used in a previous database selection
1167 * then the command is treated as a no-op.
1168 * Sending a SelectDBRecord telegram with the Track category and a
1169 * record index of -1 is invalid, because the previous database
1170 * selection made with the Track category and a valid index passes
1171 * the database selection to the Playback Engine.
1172 * Sending a SelectDBRecord(Track, -1) telegram returns a parameter
1173 * error. The iPod also returns a bad parameter error ACK when
1174 * devices send the SelectDBRecord telegram with an invalid category
1175 * type, or with the Track category and an index greater than the
1176 * total number of tracks available on the iPod.
1177 *
1178 * Note: Selecting a podcast always selects from the main podcast
1179 * library regardless of the current category context of the iPod.
1180 *
1181 * To immediately go to the topmost iPod menu level and reset all
1182 * database selections, send the ResetDBSelection telegram to the
1183 * iPod.
1184 *
1185 * Byte Value Meaning
1186 * 0 0xFF Sync byte (required only for UART serial)
1187 * 1 0x55 Start of telegram
1188 * 2 0x08 Telegram payload length
1189 * 3 0x04 Lingo ID: Extended Interface lingo
1190 * 4 0x00 Command ID (bits 15:8)
1191 * 5 0x17 Command ID (bits 7:0)
1192 * 6 0xNN Database category type. See
1193 * 7 0xNN Database record index (bits 31:24)
1194 * 8 0xNN Database record index (bits 23:16)
1195 * 9 0xNN Database record index (bits 15:8)
1196 * 10 0xNN Database record index (bits 7:0)
1197 * 11 0xNN Telegram payload checksum byte
1198 *
1199 * The valid database categories are listed below
1200 *
1201 * Category Code Protocol version
1202 * Reserved 0x00 N/A
1203 * Playlist 0x01 1.00
1204 * Artist 0x02 1.00
1205 * Album 0x03 1.00
1206 * Genre 0x04 1.00
1207 * Track 0x05 1.00
1208 * Composer 0x06 1.00
1209 * Audiobook0x07 1.06
1210 * Podcast 0x08 1.08
1211 * Reserved 0x09+ N/A
1212 *
1213 * cur_dbrecord[0] is the record type
1214 * cur_dbrecord[1-4] is the u32 of the record number requested
1215 * which might be a playlist or a track number depending on
1216 * the value of cur_dbrecord[0]
1217 */
1218 {
1219 memcpy(cur_dbrecord, buf + 3, 5);
1220
1221 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
1222 uint32_t index;
1223 uint32_t trackcount;
1224 index = get_u32(&cur_dbrecord[1]);
1225 trackcount = playlist_amount();
1226 if ((cur_dbrecord[0] == 5) && (index > trackcount))
1227 {
1228 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1229 break;
1230 }
1231 if ((cur_dbrecord[0] == 1) && (index > (nbr_total_playlists() + 1)))
1232 {
1233 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1234 break;
1235 }
1236 audio_pause();
1237 switch (cur_dbrecord[0])
1238 {
1239 case 0x01: /* Playlist*/
1240 {
1241 if (index != 0x00) /* 0x00 is the On-The-Go Playlist and
1242 we do nothing with it */
1243 {
1244 last_selected_playlist = index;
1245 audio_skip(-iap_get_trackindex());
1246 seek_to_playlist(last_selected_playlist);
1247 }
1248 break;
1249 }
1250 case 0x02: /* Artist */
1251 case 0x03: /* Album */
1252 case 0x04: /* Genre */
1253 case 0x05: /* Track */
1254 case 0x06: /* Composer */
1255 {
1256 audio_skip(index - playlist_next(0));
1257 break;
1258 }
1259 default:
1260 {
1261 /* We don't do anything with the other selections.
1262 * YET.
1263 */
1264 break;
1265 }
1266 }
1267 if (!paused)
1268 audio_resume();
1269 /* respond with cmd ok packet */
1270 cmd_ok(cmd);
1271 break;
1272 }
1273 case 0x0018: /* GetNumberCategorizedDBRecords */
1274 /* The following is the description for the Apple Firmware
1275 *
1276 * Retrieves the number of records in a particular database
1277 * category.
1278 * For example, a device can get the number of artists or albums
1279 * present in the database. The category types are described above.
1280 * The iPod responds with a Command 0x0019:
1281 * ReturnNumberCategorizedDBRecords telegram indicating the number
1282 * of records present for this category.
1283 * GetNumberCategorizedDBRecords must be called to initialize the
1284 * category count before selecting a database record using Command
1285 * 0x0017: SelectDBRecord or Command 0x0038: SelectSortDBRecord
1286 * commands. A category’s record count can change based on the prior
1287 * categories selected and the database hierarchy. The accessory
1288 * is expected to call GetNumberCategorizedDBRecords in order to
1289 * get the valid range of category entries before selecting a
1290 * record in that category.
1291 *
1292 * Note: The record count returned by this command depends on the
1293 * database state before this command is sent. If the database has
1294 * been reset using Command 0x0016: ResetDBSelection this command
1295 * returns the total number of records for a given category.
1296 * However, if this command is sent after one or more categories
1297 * are selected, the record count is the subset of records that are
1298 * members of all the categories selected prior to this command.
1299 *
1300 * Byte Value Meaning
1301 * 0 0xFF Sync byte (required only for UART serial)
1302 * 1 0x55 Start of telegram
1303 * 2 0x04 Telegram payload length
1304 * 3 0x04 Lingo ID: Extended Interface lingo
1305 * 4 0x00 Command ID (bits 15:8)
1306 * 5 0x18 Command ID (bits 7:0)
1307 * 6 0xNN Database category type. See above
1308 * 7 0xNN Telegram payload checksum byte
1309 *
1310 * This is the actual number of available records for that category
1311 * some head units (Alpine CDE-103BT) use this command before
1312 * requesting records and then hang if not enough records are
1313 * returned.
1314 */
1315 {
1316 unsigned char data[] = {0x04, 0x00, 0x19,
1317 0x00, 0x00, 0x00, 0x00};
1318 switch(buf[3]) /* type number */
1319 {
1320 case 0x01: /* total number of playlists */
1321 dbrecordcount = nbr_total_playlists() + 1;
1322 break;
1323 case 0x05: /* total number of Tracks */
1324 case 0x02: /* total number of Artists */
1325 case 0x03: /* total number of Albums */
1326 /* We don't sort on the above but some Head Units
1327 * require at least one to exist so we just return
1328 * the number of tracks in the playlist. */
1329 dbrecordcount = playlist_amount();
1330 break;
1331 case 0x04: /* total number of Genres */
1332 case 0x06: /* total number of Composers */
1333 case 0x07: /* total number of AudioBooks */
1334 case 0x08: /* total number of Podcasts */
1335 /* We don't support the above so just return that
1336 there are none available. */
1337 dbrecordcount = 0;
1338 break;
1339 }
1340 put_u32(&data[3], dbrecordcount);
1341 iap_send_pkt(data, sizeof(data));
1342 break;
1343 }
1344 case 0x0019: /* ReturnNumberCategorizedDBRecords. See Above */
1345 /* The following is the description for the Apple Firmware
1346 *
1347 * Returns the number of database records matching the specified
1348 * database category. The iPod sends this telegram in response to
1349 * the Command 0x0018: GetNumberCategorizedDBRecords telegram from
1350 * the device. Individual records can then be extracted by sending
1351 * Command 0x001A: RetrieveCategorizedDatabaseRecords to the iPod.
1352 * If no matching database records are found, a record count of
1353 * zero is returned. Category types are described above.
1354 * After selecting the podcast category, the number of artist,
1355 * album, composer, genre, and audiobook records is always zero.
1356 *
1357 * Byte Value Meaning
1358 * 0 0xFF Sync byte (required only for UART serial)
1359 * 1 0x55 Start of telegram
1360 * 2 0x07 Telegram payload length
1361 * 3 0x04 Lingo ID: Extended Interface lingo
1362 * 4 0x00 Command ID (bits 15:8)
1363 * 5 0x19 Command ID (bits 7:0)
1364 * 6 0xNN Database record count (bits 31:24)
1365 * 7 0xNN Database record count (bits 23:16)
1366 * 8 0xNN Database record count (bits 15:8)
1367 * 9 0xNN Database record count (bits 7:0)
1368 * 10 0xNN Telegram payload checksum byte
1369 *
1370 */
1371 {
1372 /* We should NEVER receive this command so ERROR if we do */
1373 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1374 break;
1375 }
1376 case 0x001A: /* RetrieveCategorizedDatabaseRecords */
1377 /* The following is the description for the Apple Firmware
1378 *
1379 * Retrieves one or more database records from the iPod,
1380 * typically based on the results from the Command 0x0018:
1381 * GetNumberCategorizedDBRecords query. The database
1382 * category types are described above. This telegram
1383 * specifies the starting record index and the number of
1384 * records to retrieve (the record count). This allows a device
1385 * to retrieve an individual record or the entire set of records
1386 * for a category. The record start index and record count consist
1387 * of 32-bit signed integers. To retrieve all records from a given
1388 * starting record index, set the record count to -1 (0xFFFFFFFF).
1389 * The iPod responds to this telegram with a separate Command
1390 * 0x001B: ReturnCategorizedDatabaseRecord telegram FOR EACH record
1391 * matching the specified criteria (category and record index
1392 * range).
1393 *
1394 * Byte Value Meaning
1395 * 0 0xFF Sync byte (required only for UART serial)
1396 * 1 0x55 Start of telegram
1397 * 2 0x0C Telegram payload length
1398 * 3 0x04 Lingo ID: Extended Interface lingo
1399 * 4 0x00 Command ID (bits 15:8)
1400 * 5 0x1A Command ID (bits 7:0)
1401 * 6 0xNN Database category type. See above
1402 * 7 0xNN Database record start index (bits 31:24)
1403 * 8 0xNN Database record start index (bits 23:16)
1404 * 9 0xNN Database record start index (bits 15:8)
1405 * 10 0xNN Database record start index (bits 7:0)
1406 * 11 0xNN Database record read count (bits 31:24)
1407 * 12 0xNN Database record read count (bits 23:16)
1408 * 13 0xNN Database record read count (bits 15:8)
1409 * 14 0xNN Database record read count (bits 7:0)
1410 * 15 0xNN Telegram payload checksum byte
1411
1412 * The returned data
1413 * contains information for a single database record. The iPod sends
1414 * one or more of these telegrams in response to the Command 0x001A:
1415 * RetrieveCategorizedDatabaseRecords telegram from the device. The
1416 * category record index is included to allow the device to
1417 * determine which record has been sent. The record data is sent as
1418 * a null-terminated UTF-8 encoded data array.
1419 */
1420 {
1421 unsigned char data[7 + MAX_PATH] =
1422 {0x04, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x00,
1423 'O','n','-','T','h','e','-','G','o','\0'};
1424 struct playlist_track_info track;
1425 struct mp3entry id3;
1426
1427 unsigned long start_index = get_u32(&buf[4]);
1428 unsigned long read_count = get_u32(&buf[8]);
1429 unsigned long counter = 0;
1430 unsigned int number_of_playlists = nbr_total_playlists();
1431 uint32_t trackcount;
1432 trackcount = playlist_amount();
1433 size_t len;
1434
1435 if ((buf[3] == 0x05) && ((start_index + read_count ) > trackcount))
1436 {
1437 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1438 break;
1439 }
1440 if ((buf[3] == 0x01) && ((start_index + read_count) > (number_of_playlists + 1)))
1441 {
1442 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1443 break;
1444 }
1445 for (counter=0;counter<read_count;counter++)
1446 {
1447 switch(buf[3]) /* type number */
1448 {
1449 case 0x01: /* Playlists */
1450 get_playlist_name(data +7,start_index+counter, MAX_PATH);
1451 /*Remove file extension*/
1452 char *dot=NULL;
1453 dot = (strrchr(data+7, '.'));
1454 if (dot != NULL)
1455 *dot = '\0';
1456 break;
1457 case 0x05: /* Tracks */
1458 case 0x02: /* Artists */
1459 case 0x03: /* Albums */
1460 case 0x04: /* Genre */
1461 case 0x06: /* Composer */
1462 playlist_get_track_info(NULL, start_index + counter,
1463 &track);
1464 iap_get_trackinfo(start_index + counter, &id3);
1465 switch(buf[3])
1466 {
1467 case 0x05:
1468 len = strlcpy((char *)&data[7], id3.title,64);
1469 break;
1470 case 0x02:
1471 len = strlcpy((char *)&data[7], id3.artist,64);
1472 break;
1473 case 0x03:
1474 len = strlcpy((char *)&data[7], id3.album,64);
1475 break;
1476 case 0x04:
1477 case 0x06:
1478 len = strlcpy((char *)&data[7], "Not Supported",14);
1479 break;
1480 }
1481 break;
1482 }
1483 put_u32(&data[3], start_index+counter);
1484 iap_send_pkt(data, 7 + strlen(data+7) + 1);
1485 yield();
1486 }
1487 break;
1488 }
1489 case 0x001B: /* ReturnCategorizedDatabaseRecord. See Above */
1490 /* The following is the description for the Apple Firmware
1491 *
1492 * Contains information for a single database record. The iPod sends
1493 * ONE OR MORE of these telegrams in response to the Command 0x001A:
1494 * RetrieveCategorizedDatabaseRecords telegram from the device. The
1495 * category record index is included to allow the device to
1496 * determine which record has been sent. The record data is sent
1497 * as a null-terminated UTF-8 encoded data array.
1498 *
1499 * Note: The database record string is not limited to 252 characters
1500 * it may be sent in small or large telegram format, depending on
1501 * the record size. The small telegram format is shown.
1502 *
1503 * Byte Value Meaning
1504 * 0 0xFF Sync byte (required only for UART serial)
1505 * 1 0x55 Start of telegram
1506 * 2 0xNN Telegram payload length
1507 * 3 0x04 Lingo ID: Extended Interface lingo
1508 * 4 0x00 Command ID (bits 15:8)
1509 * 5 0x1B Command ID (bits 7:0)
1510 * 6 0xNN Database record category index (bits 31:24)
1511 * 7 0xNN Database record category index (bits 23:16)
1512 * 8 0xNN Database record category index (bits 15:8)
1513 * 9 0xNN Database record category index (bits 7:0)
1514 * 10-N 0xNN Database record as a UTF-8 character array.
1515 * NN 0xNN Telegram payload checksum byte
1516 *
1517 */
1518 {
1519 /* We should NEVER receive this command so ERROR if we do */
1520 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1521 break;
1522 }
1523 case 0x001C: /* GetPlayStatus */
1524 /* The following is the description for the Apple Firmware
1525 *
1526 * Requests the current iPod playback status, allowing the
1527 * device to display feedback to the user. In response, the
1528 * iPod sends a Command 0x001D: ReturnPlayStatus telegram
1529 * with the current playback status.
1530 *
1531 * Byte Value Meaning
1532 * 0 0xFF Sync byte (required only for UART serial)
1533 * 1 0x55 Start of telegram
1534 * 2 0x03 Telegram payload length
1535 * 3 0x04 Lingo ID: Extended Interface lingo
1536 * 4 0x00 Command ID (bits 15:8)
1537 * 5 0x1C Command ID (bits 7:0)
1538 * 6 0xDD Telegram payload checksum byte
1539 *
1540 */
1541 {
1542 unsigned char data[] = {0x04, 0x00, 0x1D,
1543 0x00, 0x00, 0x00, 0x00,
1544 0x00, 0x00, 0x00, 0x00,
1545 0x00};
1546 struct mp3entry *id3 = audio_current_track();
1547 unsigned long time_total = id3->length;
1548 unsigned long time_elapsed = id3->elapsed;
1549 int status = audio_status();
1550 put_u32(&data[3], time_total);
1551 put_u32(&data[7], time_elapsed);
1552 if (status == AUDIO_STATUS_PLAY)
1553 data[11] = 0x01; /* play */
1554 else if (status & AUDIO_STATUS_PAUSE)
1555 data[11] = 0x02; /* pause */
1556 iap_send_pkt(data, sizeof(data));
1557 break;
1558 }
1559 case 0x001D: /* ReturnPlayStatus. See Above */
1560 /* The following is the description for the Apple Firmware
1561 *
1562 * Returns the current iPod playback status. The iPod sends this
1563 * telegram in response to the Command 0x001C: GetPlayStatus
1564 * telegram from the device. The information returned includes the
1565 * current track length, track position, and player state.
1566 *
1567 * Note: The track length and track position fields are valid only
1568 * if the player state is Playing or Paused. For other player
1569 * states, these fields should be ignored.
1570 *
1571 * Byte Value Meaning
1572 * 0 0xFF Sync byte (required only for UART serial)
1573 * 1 0x55 Start of telegram
1574 * 2 0x0C Telegram payload length
1575 * 3 0x04 Lingo ID: Extended Interface lingo
1576 * 4 0x00 Command ID (bits 15:8)
1577 * 5 0x1D Command ID (bits 7:0)
1578 * 6 0xNN Track length in milliseconds (bits 31:24)
1579 * 7 0xNN Track length in milliseconds (bits 23:16)
1580 * 8 0xNN Track length in milliseconds (bits 15:8)
1581 * 9 0xNN Track length in milliseconds (bits 7:0)
1582 * 10 0xNN Track position in milliseconds (bits 31:24)
1583 * 11 0xNN Track position in milliseconds (bits 23:16)
1584 * 12 0xNN Track position in milliseconds (bits 15:8)
1585 * 13 0xNN Track position in milliseconds (bits 7:0)
1586 * 14 0xNN Player state. Possible values are:
1587 * 0x00 = Stopped
1588 * 0x01 = Playing
1589 * 0x02 = Paused
1590 * 0x03 - 0xFE = Reserved
1591 * 0xFF = Error
1592 * 15 0xNN Telegram payload checksum byte
1593 *
1594 */
1595 {
1596 /* We should NEVER receive this command so ERROR if we do */
1597 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1598 break;
1599 }
1600 case 0x001E: /* GetCurrentPlayingTrackIndex */
1601 /* The following is the description for the Apple Firmware
1602 *
1603 * Requests the playback engine index of the currently playing
1604 * track. In response, the iPod sends a Command 0x001F:
1605 * ReturnCurrentPlayingTrackIndex telegram to the device.
1606 *
1607 * Note: The track index returned is valid only if there is
1608 * currently a track playing or paused.
1609 *
1610 * Byte Value Meaning
1611 * 0 0xFF Sync byte (required only for UART serial)
1612 * 1 0x55 Start of telegram
1613 * 2 0x03 Telegram payload length
1614 * 3 0x04 Lingo ID: Extended Interface lingo
1615 * 4 0x00 Command ID (bits 15:8)
1616 * 5 0x1E Command ID (bits 7:0)
1617 * 6 0xDB Telegram payload checksum byte
1618 *
1619 */
1620 {
1621 unsigned char data[] = {0x04, 0x00, 0x1F,
1622 0xFF, 0xFF, 0xFF, 0xFF};
1623 long playlist_pos = playlist_next(0);
1624 int status = audio_status();
1625 playlist_pos -= playlist_get_first_index(NULL);
1626 if(playlist_pos < 0)
1627 playlist_pos += playlist_amount();
1628 if ((status == AUDIO_STATUS_PLAY) || (status & AUDIO_STATUS_PAUSE))
1629 put_u32(&data[3], playlist_pos);
1630 iap_send_pkt(data, sizeof(data));
1631 break;
1632 }
1633 case 0x001F: /* ReturnCurrentPlayingTrackIndex. See Above */
1634 /* The following is the description for the Apple Firmware
1635 *
1636 * Returns the playback engine index of the current playing track in
1637 * response to the Command 0x001E: GetCurrentPlayingTrackIndex
1638 * telegram from the device. The track index is a 32-bit signed
1639 * integer.
1640 * If there is no track currently playing or paused, an index of -1
1641 * (0xFFFFFFFF) is returned.
1642 *
1643 * Byte Value Meaning
1644 * 0 0xFF Sync byte (required only for UART serial)
1645 * 1 0x55 Start of telegram
1646 * 2 0x07 Telegram payload length
1647 * 3 0x04 Lingo ID: Extended Interface lingo
1648 * 4 0x00 Command ID (bits 15:8)
1649 * 5 0x1F Command ID (bits 7:0)
1650 * 6 0xNN Playback track index (bits 31:24)
1651 * 7 0xNN Playback track index (bits 23:16)
1652 * 8 0xNN Playback track index (bits 15:8)
1653 * 9 0xNN Playback track index (bits 7:0)
1654 * 10 0xNN Telegram payload checksum byte
1655 *
1656 */
1657 {
1658 /* We should NEVER receive this command so ERROR if we do */
1659 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1660 break;
1661 }
1662 case 0x0020: /* GetIndexedPlayingTrackTitle. See 0x0024 below */
1663 /* The following is the description for the Apple Firmware
1664 *
1665 * Requests the title name of the indexed playing track from the
1666 * iPod. In response to a valid telegram, the iPod sends a
1667 * Command 0x0021: ReturnIndexedPlayingTrackTitle telegram to the
1668 * device.
1669 *
1670 * Note: If the telegram length or playing track index is invalid,
1671 * the iPod responds with an ACK telegram including the specific
1672 * error status.
1673 *
1674 * Byte Value Meaning
1675 * 0 0xFF Sync byte (required only for UART serial)
1676 * 1 0x55 Start of telegram
1677 * 2 0x07 Telegram payload length
1678 * 3 0x04 Lingo ID: Extended Interface lingo
1679 * 4 0x00 Command ID (bits 15:8)
1680 * 5 0x20 Command ID (bits 7:0)
1681 * 6 0xNN Playback track index (bits 31:24)
1682 * 7 0xNN Playback track index (bits 23:16)
1683 * 8 0xNN Playback track index (bits 15:8)
1684 * 9 0xNN Playback track index (bits 7:0)
1685 * 10 0xNN Telegram payload checksum byte
1686 *
1687 */
1688 case 0x0021: /* ReturnIndexedPlayingTrackTitle. See 0x0024 Below */
1689 /* The following is the description for the Apple Firmware
1690 *
1691 * Returns the title of the indexed playing track in response to
1692 * a valid Command 0x0020 GetIndexedPlayingTrackTitle telegram from
1693 * the device. The track title is encoded as a null-terminated UTF-8
1694 * character array.
1695 *
1696 * Note: The track title string is not limited to 252 characters;
1697 * it may be sent in small or large telegram format, depending on
1698 * the string length. The small telegram format is shown.
1699 *
1700 * Byte Value Meaning
1701 * 0 0xFF Sync byte (required only for UART serial)
1702 * 1 0x55 Start of telegram
1703 * 2 0xNN Telegram payload length
1704 * 3 0x04 Lingo ID: Extended Interface lingo
1705 * 4 0x00 Command ID (bits 15:8)
1706 * 5 0x21 Command ID (bits 7:0)
1707 * 6-N 0xNN Track title as a UTF-8 character array
1708 * NN 0xNN Telegram payload checksum byte
1709 *
1710 */
1711 case 0x0022: /* GetIndexedPlayingTrackArtistName. See 0x0024 Below */
1712 /* The following is the description for the Apple Firmware
1713 *
1714 * Requests the name of the artist of the indexed playing track
1715 * In response to a valid telegram, the iPod sends a
1716 * Command 0x0023: ReturnIndexedPlayingTrackArtistName telegram to
1717 * the device.
1718 *
1719 * Note: If the telegram length or playing track index is invalid,
1720 * the iPod responds with an ACK telegram including the specific
1721 * error status.
1722 *
1723 * Byte Value Meaning
1724 * 0 0xFF Sync byte (required only for UART serial)
1725 * 1 0x55 Start of telegram
1726 * 2 0x07 Telegram payload length
1727 * 3 0x04 Lingo ID: Extended Interface lingo
1728 * 4 0x00 Command ID (bits 15:8)
1729 * 5 0x22 Command ID (bits 7:0)
1730 * 6 0xNN Playback track index (bits 31:24)
1731 * 7 0xNN Playback track index (bits 23:16)
1732 * 8 0xNN Playback track index (bits 15:8)
1733 * 9 0xNN Playback track index (bits 7:0)
1734 * 10 0xNN Telegram payload checksum byte
1735 *
1736 */
1737 case 0x0023: /* ReturnIndexedPlayingTrackArtistName. See 0x0024 Below */
1738 /* The following is the description for the Apple Firmware
1739 *
1740 * Returns the artist name of the indexed playing track in response
1741 * to a valid Command 0x0022 GetIndexedPlayingTrackArtistName
1742 * telegram from the device. The track artist name is encoded as a
1743 * null-terminated UTF-8 character array.
1744 *
1745 * Note: The artist name string is not limited to 252 characters;
1746 * it may be sent in small or large telegram format, depending on
1747 * the string length. The small telegram format is shown.
1748 *
1749 * Byte Value Meaning
1750 * 0 0xFF Sync byte (required only for UART serial)
1751 * 1 0x55 Start of telegram
1752 * 2 0xNN Telegram payload length
1753 * 3 0x04 Lingo ID: Extended Interface lingo
1754 * 4 0x00 Command ID (bits 15:8)
1755 * 5 0x23 Command ID (bits 7:0)
1756 * 6-N 0xNN Track Artist as a UTF-8 character array
1757 * NN 0xNN Telegram payload checksum byte
1758 *
1759 */
1760 case 0x0024: /* GetIndexedPlayingTrackAlbumName AND
1761 * GetIndexedPlayingTrackTitle AND
1762 * AND GetIndexedPlayingTrackArtistName. */
1763 /* The following is the description for the Apple Firmware
1764 *
1765 * Requests the album name of the indexed playing track
1766 * In response to a valid telegram, the iPod sends a
1767 * Command 0x0025: ReturnIndexedPlayingTrackAlbumName telegram to
1768 * the device.
1769 *
1770 * Note: If the telegram length or playing track index is invalid,
1771 * the iPod responds with an ACK telegram including the specific
1772 * error status.
1773 *
1774 * Byte Value Meaning
1775 * 0 0xFF Sync byte (required only for UART serial)
1776 * 1 0x55 Start of telegram
1777 * 2 0x07 Telegram payload length
1778 * 3 0x04 Lingo ID: Extended Interface lingo
1779 * 4 0x00 Command ID (bits 15:8)
1780 * 5 0x24 Command ID (bits 7:0)
1781 * 6 0xNN Playback track index (bits 31:24)
1782 * 7 0xNN Playback track index (bits 23:16)
1783 * 8 0xNN Playback track index (bits 15:8)
1784 * 9 0xNN Playback track index (bits 7:0)
1785 * 10 0xNN Telegram payload checksum byte
1786 *
1787 */
1788 {
1789 unsigned char data[70] = {0x04, 0x00, 0xFF};
1790 struct mp3entry id3;
1791 int fd;
1792 size_t len;
1793 long tracknum = get_u32(&buf[3]);
1794
1795 data[2] = cmd + 1;
1796 memcpy(&id3, audio_current_track(), sizeof(id3));
1797 tracknum += playlist_get_first_index(NULL);
1798 if(tracknum >= playlist_amount())
1799 tracknum -= playlist_amount();
1800 /* If the tracknumber is not the current one,
1801 read id3 from disk */
1802 if(playlist_next(0) != tracknum)
1803 {
1804 struct playlist_track_info info;
1805 playlist_get_track_info(NULL, tracknum, &info);
1806 fd = open(info.filename, O_RDONLY);
1807 memset(&id3, 0, sizeof(struct mp3entry));
1808 get_metadata(&id3, fd, info.filename);
1809 close(fd);
1810 }
1811 /* Return the requested track data */
1812 switch(cmd)
1813 {
1814 case 0x20:
1815 len = strlcpy((char *)&data[3], id3.title, 64);
1816 iap_send_pkt(data, 4+len);
1817 break;
1818 case 0x22:
1819 len = strlcpy((char *)&data[3], id3.artist, 64);
1820 iap_send_pkt(data, 4+len);
1821 break;
1822 case 0x24:
1823 len = strlcpy((char *)&data[3], id3.album, 64);
1824 iap_send_pkt(data, 4+len);
1825 break;
1826 }
1827 break;
1828 }
1829 case 0x0025: /* ReturnIndexedPlayingTrackAlbumName. See 0x0024 Above */
1830 /* The following is the description for the Apple Firmware
1831 *
1832 * Returns the album name of the indexed playing track in response
1833 * to a valid Command 0x0024 GetIndexedPlayingTrackAlbumName
1834 * telegram from the device. The track artist name is encoded as a
1835 * null-terminated UTF-8 character array.
1836 *
1837 * Note: The album name string is not limited to 252 characters;
1838 * it may be sent in small or large telegram format, depending on
1839 * the string length. The small telegram format is shown.
1840 *
1841 * Byte Value Meaning
1842 * 0 0xFF Sync byte (required only for UART serial)
1843 * 1 0x55 Start of telegram
1844 * 2 0xNN Telegram payload length
1845 * 3 0x04 Lingo ID: Extended Interface lingo
1846 * 4 0x00 Command ID (bits 15:8)
1847 * 5 0x25 Command ID (bits 7:0)
1848 * 6-N 0xNN Track Album as a UTF-8 character array
1849 * NN 0xNN Telegram payload checksum byte
1850 *
1851 */
1852 {
1853 /* We should NEVER receive this command so ERROR if we do */
1854 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
1855 break;
1856 }
1857 case 0x0026: /* SetPlayStatusChangeNotification */
1858 /* The following is the description for the Apple Firmware
1859 * Sets the state of play status change notifications from the iPod
1860 * to the device. Notification of play status changes can be
1861 * globally enabled or disabled. If notifications are enabled, the
1862 * iPod sends a Command 0x0027: PlayStatusChangeNotification
1863 * telegram to the device each time the play status changes, until
1864 * the device sends this telegram again with the disable
1865 * notification option. In response, the iPod sends an ACK telegram
1866 * indicating the status of the SetPlayStatusChangeNotification
1867 * command.
1868 *
1869 * Byte Value Meaning
1870 * 0 0xFF Sync byte (required only for UART serial)
1871 * 1 0x55 Start of telegram
1872 * 2 0x04 Telegram payload length
1873 * 3 0x04 Lingo ID: Extended Interface lingo
1874 * 4 0x00 Command ID (bits 15:8)
1875 * 5 0x26 Command ID (bits 7:0)
1876 * 6 0xNN The state of play status change notifications.
1877 * Possible values are:
1878 * 0x00 = Disable all change notification
1879 * 0x01 = Enable all change notification
1880 * 0x02 - 0xFF = Reserved
1881 * 7 0xNN Telegram payload checksum byte
1882 */
1883 {
1884 device.do_notify = buf[3] ? true : false;
1885 /* respond with cmd ok packet */
1886 cmd_ok(cmd);
1887 break;
1888 }
1889 case 0x0027: /* PlayStatusChangeNotification */
1890 /* This response is handled by iap_track_changed() and iap_periodic()
1891 * within iap-core.c
1892 * The following is the description for the Apple Firmware
1893 *
1894 * The iPod sends this telegram to the device when the iPod play status
1895 * changes, if the device has previously enabled notifications using
1896 * Command 0x0026: SetPlayStatusChangeNotification . This telegram
1897 * contains details about the new play status. Notification telegrams
1898 * for changes in track position occur approximately every 500
1899 * milliseconds while the iPod is playing. Notification telegrams are
1900 * sent from the iPod until the device sends the
1901 * SetPlayStatusChangeNotification telegram with the option to disable
1902 * all notifications.
1903 * Some notifications include additional data about the new play status.
1904 *
1905 * PlayStatusChangeNotification telegram: notifications 0x00, 0x02, 0x03
1906 * Byte Value Meaning
1907 * 0 0xFF Sync byte (required only for UART serial)
1908 * 1 0x55 Start of telegram
1909 * 2 0x04 Telegram payload length
1910 * 3 0x04 Lingo ID: Extended Interface lingo
1911 * 4 0x00 Command ID (bits 15:8)
1912 * 5 0x27 Command ID (bits 7:0)
1913 * 6 0xNN New play status. See Below.
1914 * 7 0xNN Telegram payload checksum byte
1915 *
1916 * Play Status Change Code Extended Status Data (if
1917 * any)
1918 * Playback stopped 0x00 None
1919 * Playback track changed 0x01 New track record index
1920 * (32 bits)
1921 * Playback forward seek stop 0x02 None
1922 * Playback backward seek stop 0x03 None
1923 * Playback track position 0x04 New track position in
1924 * milliseconds (32 bits)
1925 * Playback chapter changed 0x05 New chapter index (32
1926 * bits)
1927 * Reserved 0x06 - 0xFF N/A
1928 *
1929 * Playback track changed (code 0x01)
1930 * Byte Value Meaning
1931 * 0 0xFF Sync byte (required only for UART serial)
1932 * 1 0x55 Start of telegram
1933 * 2 0x08 Telegram payload length
1934 * 3 0x04 Lingo ID: Extended Interface lingo
1935 * 4 0x00 Command ID (bits 15:8)
1936 * 5 0x27 Command ID (bits 7:0)
1937 * 6 0x01 New status: Playback track changed
1938 * 7 0xNN New playback track index (bits 31:24)
1939 * 8 0xNN New playback track index (bits 23:16)
1940 * 9 0xNN New playback track index (bits 15:8)
1941 * 10 0xNN New playback track index (bits 7:0)
1942 * 11 0xNN Telegram payload checksum byte
1943 *
1944 * Playback track position changed (code 0x04)
1945 * Byte Value Meaning
1946 * 0 0xFF Sync byte (required only for UART serial)
1947 * 1 0x55 Start of telegram
1948 * 2 0x08 Telegram payload length
1949 * 3 0x04 Lingo ID: Extended Interface lingo
1950 * 4 0x00 Command ID (bits 15:8)
1951 * 5 0x27 Command ID (bits 7:0)
1952 * 6 0x04 New status: Playback track position changed
1953 * 7 0xNN New track position in milliseconds (bits 31:24)
1954 * 8 0xNN New track position in milliseconds (bits 23:16)
1955 * 9 0xNN New track position in milliseconds (bits 15:8)
1956 * 10 0xNN New track position in milliseconds (bits 7:0)
1957 * 11 0xNN Telegram payload checksum byte
1958 *
1959 * Playback chapter changed (code 0x05)
1960 * Byte Value Meaning
1961 * 0 0xFF Sync byte (required only for UART serial)
1962 * 1 0x55 Start of telegram
1963 * 2 0x08 Telegram payload length
1964 * 3 0x04 Lingo ID: Extended Interface lingo
1965 * 4 0x00 Command ID (bits 15:8)
1966 * 5 0x27 Command ID (bits 7:0)
1967 * 6 0x05 New status: Playback chapter changed
1968 * 7 0xNN New track chapter index (bits 31:24)
1969 * 8 0xNN New track chapter index (bits 23:16)
1970 * 9 0xNN New track chapter index (bits 15:8)
1971 * 10 0xNN New track chapter index (bits 7:0)
1972 * 11 0xNN Telegram payload checksum byte
1973 *
1974 */
1975 case 0x0028: /* PlayCurrentSelection */
1976 /* The following is the description for the Apple Firmware
1977 *
1978 * Requests playback of the currently selected track or list of
1979 * tracks. The currently selected tracks are placed in the Now
1980 * Playing playlist, where they are optionally shuffled (if the
1981 * shuffle feature is enabled). Finally, the specified track record
1982 * index is passed to the player to play. Note that if the track
1983 * index is -1(0xFFFFFFFF), the first track after the shuffle is
1984 * complete is played first. If a track index of n is sent, the nth
1985 * track of the selected tracks is played first, regardless of
1986 * where it is located in the Now Playing playlist after the shuffle
1987 * is performed (assuming that shuffle is on). In response, the iPod
1988 * sends an ACK telegram indicating the status of the command.
1989 *
1990 * Byte Value Meaning
1991 * 0 0xFF Sync byte (required only for UART serial)
1992 * 1 0x55 Start of telegram
1993 * 2 0x07 Telegram payload length
1994 * 3 0x04 Lingo ID: Extended Interface lingo
1995 * 4 0x00 Command ID (bits 15:8)
1996 * 5 0x28 Command ID (bits 7:0)
1997 * 6 0xNN Selection track record index (bits 31:24)
1998 * 7 0xNN Selection track record index (bits 23:16)
1999 * 8 0xNN Selection track record index (bits 15:8)
2000 * 9 0xNN Selection track record index (bits 7:0)
2001 * 10 0xNN Telegram payload checksum byte
2002 *
2003 */
2004 {
2005 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
2006 uint32_t index;
2007 uint32_t trackcount;
2008 index = get_u32(&buf[3]);
2009 trackcount = playlist_amount();
2010 if (index >= trackcount)
2011 {
2012 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
2013 break;
2014 }
2015 audio_pause();
2016 if(global_settings.playlist_shuffle)
2017 {
2018 playlist_randomise(NULL, current_tick, true);
2019 }
2020 else
2021 {
2022 playlist_sort(NULL, true);
2023 }
2024 audio_skip(index - playlist_next(0));
2025 if (!paused)
2026 audio_resume();
2027 /* respond with cmd ok packet */
2028 cmd_ok(cmd);
2029 break;
2030 }
2031 case 0x0029: /* PlayControl */
2032 {
2033 /* The following is the description for the Apple Firmware
2034 *
2035 * Sets the new play state of the iPod. The play control command
2036 * codes are shown below. In response, the iPod sends an ACK
2037 * telegram indicating the status of the command.
2038 *
2039 * Note: If a remote device requests the Next or Previous Chapter
2040 * for a track that does not contain chapters, the iPod returns a
2041 * command failed ACK.
2042 *
2043 * Byte Value Meaning
2044 * 0 0xFF Sync byte (required only for UART serial)
2045 * 1 0x55 Start of telegram
2046 * 2 0x04 Telegram payload length
2047 * 3 0x04 Lingo ID: Extended Interface lingo
2048 * 4 0x00 Command ID (bits 15:8)
2049 * 5 0x29 Command ID (bits 7:0)
2050 * 6 0xNN Play control command code.
2051 * 7 0xNN Telegram payload checksum byte
2052 *
2053 * Play Control Command Code Protocol version
2054 * Reserved 0x00 N/A
2055 * Toggle Play/Pause 0x01 1.00
2056 * Stop 0x02 1.00
2057 * Next Track 0x03 1.00
2058 * Previous Track 0x04 1.00
2059 * StartFF 0x05 1.00
2060 * StartRew 0x06 1.00
2061 * EndFFRew 0x07 1.00
2062 * NextChapter 0x08 1.06
2063 * Previous Chapter 0x09 1.06
2064 * Reserved 0x0A - 0xFF
2065 *
2066 */
2067 switch(buf[3])
2068 {
2069 case 0x01: /* play/pause */
2070 iap_remotebtn = BUTTON_RC_PLAY;
2071 iap_repeatbtn = 2;
2072 break;
2073 case 0x02: /* stop */
2074 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
2075 iap_repeatbtn = 2;
2076 break;
2077 case 0x03: /* skip++ */
2078 iap_remotebtn = BUTTON_RC_RIGHT;
2079 iap_repeatbtn = 2;
2080 break;
2081 case 0x04: /* skip-- */
2082 iap_remotebtn = BUTTON_RC_LEFT;
2083 iap_repeatbtn = 2;
2084 break;
2085 case 0x05: /* ffwd */
2086 iap_remotebtn = BUTTON_RC_RIGHT;
2087 break;
2088 case 0x06: /* frwd */
2089 iap_remotebtn = BUTTON_RC_LEFT;
2090 break;
2091 case 0x07: /* end ffwd/frwd */
2092 iap_remotebtn = BUTTON_NONE;
2093 break;
2094 }
2095 /* respond with cmd ok packet */
2096 cmd_ok(cmd);
2097 break;
2098 }
2099 case 0x002A: /* GetTrackArtworkTimes */
2100 /* The following is the description for the Apple Firmware
2101 *
2102 * The device sends this command to the iPod to request the list of
2103 * artwork time locations for a track. A 4-byte track Index
2104 * specifies which track from the Playback Engine is to be selected.
2105 * A 2-byte formatID indicates which type of artwork is desired.
2106 * The 2-byte artworkIndex specifies at which index to begin
2107 * searching for artwork. A value of 0 indicates that the iPod
2108 * should start with the first available artwork.
2109 * The 2-byte artworkCount specifies the maximum number of times
2110 * (artwork locations) to be returned. A value of -1 (0xFFFF)
2111 * indicates that there is no preferred limit. Note that podcasts
2112 * may have a large number of associated images.
2113 *
2114 * Byte Value Comment
2115 * 0 0xFF Sync byte (required only for UART serial)
2116 * 1 0x55 Start of telegram
2117 * 2 0x0D Length of packet
2118 * 3 0x04 Lingo ID: Extended Interface lingo
2119 * 4 0x00 Command ID (bits 15:8)
2120 * 5 0x2A Command ID (bits 7:0)
2121 * 6 0xNN trackIndex(31:24)
2122 * 7 0xNN trackIndex(23:16)
2123 * 8 0xNN trackIndex (15:8)
2124 * 9 0xNN trackIndex (7:0)
2125 * 10 0xNN formatID (15:8)
2126 * 11 0xNN formatID (7:0)
2127 * 12 0xNN artworkIndex (15:8)
2128 * 13 0xNN artworkIndex (7:0)
2129 * 14 0xNN artworkCount (15:8)
2130 * 15 0xNN artworkCount (7:0)
2131 * 16 0xNN Checksum
2132 *
2133 */
2134 {
2135 unsigned char data[] = {0x04, 0x00, 0x2B,
2136 0x00, 0x00, 0x00, 0x00};
2137 iap_send_pkt(data, sizeof(data));
2138 break;
2139 }
2140 case 0x002B: /* ReturnTrackArtworkTimes. See Above */
2141 /* The following is the description for the Apple Firmware
2142 *
2143 * The iPod sends this command to the device to return the list of
2144 * artwork times for a given track. The iPod returns zero or more
2145 * 4-byte times, one for each piece of artwork associated with the
2146 * track and format specified by GetTrackArtworkTimes.
2147 * The number of records returned will be no greater than the number
2148 * specified in the GetTrackArtworkTimes command. It may however, be
2149 * less than requested. This can happen if there are fewer pieces of
2150 * artwork available than were requested, or if the iPod is unable
2151 * to place the full number in a single packet. Check the number of
2152 * records returned against the results of
2153 * RetIndexedPlayingTrackInfo with infoType 7 to ensure that all
2154 * artwork has been received.
2155 *
2156 * Byte Value Comment
2157 * 0 0xFF Sync byte (required only for UART serial)
2158 * 1 0x55 Start of telegram
2159 * 2 0xNN Length of packet
2160 * 3 0x04 Lingo ID: Extended Interface lingo
2161 * 4 0x00 Command ID (bits 15:8)
2162 * 5 0x2B Command ID (bits 7:0)
2163 * 6 0xNN time offset from track start in ms (31:24)
2164 * 7 0xNN time offset from track start in ms (23:16)
2165 * 8 0xNN time offset from track start in ms (15:8)
2166 * 9 0xNN time offset from track start in ms (7:0)
2167 * Preceding 4 bytes may be repeated NN times
2168 * NN 0xNN Checksum
2169 *
2170 */
2171 {
2172 /* We should NEVER receive this command so ERROR if we do */
2173 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
2174 break;
2175 }
2176 case 0x002C: /* GetShuffle */
2177 {
2178 /* The following is the description for the Apple Firmware
2179 *
2180 * Requests the current state of the iPod shuffle setting. The iPod
2181 * responds with the Command0x002D: ReturnShuffle telegram.
2182 *
2183 * Byte Value Meaning
2184 * 0 0xFF Sync byte (required only for UART serial)
2185 * 1 0x55 Start of telegram
2186 * 2 0x03 Telegram payload length
2187 * 3 0x04 Lingo ID: Extended Interface lingo
2188 * 4 0x00 Command ID (bits 15:8)
2189 * 5 0x2C Command ID (bits 7:0)
2190 * 6 0xCD Telegram payload checksum byte
2191 *
2192 */
2193 unsigned char data[] = {0x04, 0x00, 0x2D,
2194 0x00};
2195 data[3] = global_settings.playlist_shuffle ? 1 : 0;
2196 iap_send_pkt(data, sizeof(data));
2197 break;
2198 }
2199 case 0x002D: /* ReturnShuffle. See Above */
2200 /* The following is the description for the Apple Firmware
2201 *
2202 * Returns the current state of the shuffle setting. The iPod sends
2203 * this telegram in response to the Command 0x002C: GetShuffle
2204 * telegram from the device.
2205 *
2206 * Byte Value Meaning
2207 * 0 0xFF Sync byte (required only for UART serial)
2208 * 1 0x55 Start of telegram
2209 * 2 0x04 Telegram payload length
2210 * 3 0x04 Lingo ID: Extended Interface lingo
2211 * 4 0x00 Command ID (bits 15:8)
2212 * 5 0x2D Command ID (bits 7:0)
2213 * 6 0xNN Shuffle mode. See Below.
2214 * 7 0xNN Telegram payload checksum byte
2215 *
2216 * Possible values of the shufflemode.
2217 * Value Meaning
2218 * 0x00 Shuffle off
2219 * 0x01 Shuffle tracks
2220 * 0x02 Shuffle albums
2221 * 0x03 – 0xFF Reserved
2222 *
2223 */
2224 {
2225 /* We should NEVER receive this command so ERROR if we do */
2226 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
2227 break;
2228 }
2229 case 0x002E: /* SetShuffle */
2230 {
2231 /* The following is the description for the Apple Firmware
2232 *
2233 * Sets the iPod shuffle mode. The iPod shuffle modes are listed
2234 * below. In response, the iPod sends an ACK telegram with the
2235 * command status.
2236 * This telegram has an optional byte, byte 0x07, called the
2237 * RestoreonExit byte. This byte can be used to restore the
2238 * original shuffle setting in use when the accessory was attached
2239 * to the iPod. A non zero value restores the original shuffle
2240 * setting of the iPod when the accessory is detached. If this byte
2241 * is zero, the shuffle setting set by the accessory overwrites the
2242 * original setting and persists after the accessory is detached
2243 * from the iPod.
2244 * Accessory engineers should note that the shuffle mode affects
2245 * items only in the playback engine. The shuffle setting does not
2246 * affect the order of tracks in the database engine, so calling
2247 * Command 0x001A: RetrieveCategorizedDatabaseRecords on a database
2248 * selection with the shuffle mode set returns a list of unshuffled
2249 * tracks. To get the shuffled playlist, an accessory must query the
2250 * playback engine by calling Command 0x0020
2251 * GetIndexedPlayingTrackTitle.
2252 * Shuffling tracks does not affect the track index, just the track
2253 * at that index. If an unshuffled track at playback index 1 is
2254 * shuffled, a new track is placed into index 1. The playback
2255 * indexes themselves are not shuffled.
2256 * When shuffle mode is enabled, tracks that are marked 'skip when
2257 * shuffling' are filtered from the database selection. This affects
2258 * all audiobooks and all tracks that the user has marked in iTunes.
2259 * It also affects all podcasts unless their default 'skip when
2260 * shuffling' markings have been deliberately removed. To apply the
2261 * filter to the playback engine, the accessory should send
2262 * Command 0x0017: SelectDBRecord or
2263 * Command 0x0028: PlayCurrentSelection after enabling shuffle mode.
2264 *
2265 * Note: Accessory developers are encouraged to always use the
2266 * Restore on Exit byte with a nonzero value to restore any settings
2267 * modified by the accessory upon detach.
2268 *
2269 * SetShuffle telegram with Restore on Exit byte
2270 * Byte Value Meaning
2271 * 0 0xFF Sync byte (required only for UART serial)
2272 * 1 0x55 Start of telegram
2273 * 2 0x05 Telegram payload length
2274 * 3 0x04 Lingo ID: Extended Interface lingo
2275 * 4 0x00 Command ID (bits 15:8)
2276 * 5 0x2E Command ID (bits 7:0)
2277 * 6 0xNN New shuffle mode. See above .
2278 * 7 0xNN Restore on Exit byte. If 1, the orig setting is
2279 * restored on detach; if 0, the newsetting persists
2280 * after accessory detach.
2281 * 8 0xNN Telegram payload checksum byte
2282 *
2283 * SetShuffle setting persistent after the accessory detach.
2284 * Byte Value Meaning
2285 * 0 0xFF Sync byte (required only for UART serial)
2286 * 1 0x55 Start of telegram
2287 * 2 0x04 Telegram payload length
2288 * 3 0x04 Lingo ID: Extended Interface lingo
2289 * 4 0x00 Command ID (bits 15:8)
2290 * 5 0x2E Command ID (bits 7:0)
2291 * 6 0xNN New shuffle mode. See above.
2292 * 7 0xNN Telegram payload checksum byte
2293 *
2294 */
2295 if(buf[3] && !global_settings.playlist_shuffle)
2296 {
2297 global_settings.playlist_shuffle = 1;
2298 settings_save();
2299 if (audio_status() & AUDIO_STATUS_PLAY)
2300 playlist_randomise(NULL, current_tick, true);
2301 }
2302 else if(!buf[3] && global_settings.playlist_shuffle)
2303 {
2304 global_settings.playlist_shuffle = 0;
2305 settings_save();
2306 if (audio_status() & AUDIO_STATUS_PLAY)
2307 playlist_sort(NULL, true);
2308 }
2309
2310 /* respond with cmd ok packet */
2311 cmd_ok(cmd);
2312 break;
2313 }
2314 case 0x002F: /* GetRepeat */
2315 {
2316 /* The following is the description for the Apple Firmware
2317 *
2318 * Requests the track repeat state of the iPod. In response, the
2319 * iPod sends a Command 0x0030: ReturnRepeat telegram
2320 * to the device.
2321 *
2322 * Byte Value Meaning
2323 * 0 0xFF Sync byte (required only for UART serial)
2324 * 1 0x55 Start of telegram
2325 * 2 0x03 Telegram payload length
2326 * 3 0x04 Lingo ID: Extended Interface lingo
2327 * 4 0x00 Command ID (bits 15:8)
2328 * 5 0x2F Command ID (bits 7:0)
2329 * 6 0xCA Telegram payload checksum byte
2330 *
2331 */
2332 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
2333 if(global_settings.repeat_mode == REPEAT_OFF)
2334 data[3] = 0;
2335 else if(global_settings.repeat_mode == REPEAT_ONE)
2336 data[3] = 1;
2337 else
2338 data[3] = 2;
2339 iap_send_pkt(data, sizeof(data));
2340 break;
2341 }
2342 case 0x0030: /* ReturnRepeat. See Above */
2343 /* The following is the description for the Apple Firmware
2344 *
2345 * Returns the current iPod track repeat state to the device.
2346 * The iPod sends this telegram in response to the Command
2347 * 0x002F:GetRepeat command.
2348 *
2349 * Byte Value Meaning
2350 * 0 0xFF Sync byte (required only for UART serial)
2351 * 1 0x55 Start of telegram
2352 * 2 0x04 Telegram payload length
2353 * 3 0x04 Lingo ID: Extended Interface lingo
2354 * 4 0x00 Command ID (bits 15:8)
2355 * 5 0x30 Command ID (bits 7:0)
2356 * 6 0xNN Repeat state. See Below.
2357 * 7 0xNN Telegram payload checksum byte
2358 *
2359 * Repeat state values
2360 * Value Meaning
2361 * 0x00 Repeat off
2362 * 0x01 Repeat one track
2363 * 0x02 Repeat all tracks
2364 * 0x03 - 0xFF Reserved
2365 *
2366 */
2367 {
2368 /* We should NEVER receive this command so ERROR if we do */
2369 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
2370 break;
2371 }
2372 case 0x0031: /* SetRepeat */
2373 {
2374 /* The following is the description for the Apple Firmware
2375 *
2376 * Sets the repeat state of the iPod. The iPod track repeat modes
2377 * are listed above. In response, the iPod sends an ACK telegram
2378 * with the command status.
2379 *
2380 * This telegram has an optional byte, byte 0x07, called the
2381 * RestoreonExitbyte. This byte can be used to restore the original
2382 * repeat setting in use when the accessory was attached to the
2383 * iPod. A nonzero value restores the original repeat setting of
2384 * the iPod when the accessory is detached. If this byte is zero,
2385 * the repeat setting set by the accessory overwrites the original
2386 * setting and persists after the accessory is detached from the
2387 * iPod.
2388 *
2389 * Note: Accessory developers are encouraged to always use the
2390 * Restore on Exit byte with a nonzero value to restore any
2391 * settings modified by the accessory upon detach.
2392 *
2393 * SetRepeat telegram with Restore on Exit byte
2394 * Byte Value Meaning
2395 * 0 0xFF Sync byte (required only for UART serial)
2396 * 1 0x55 Start of telegram
2397 * 2 0x05 Telegram payload length
2398 * 3 0x04 Lingo ID: Extended Interface lingo
2399 * 4 0x00 Command ID (bits 15:8)
2400 * 5 0x31 Command ID (bits 7:0)
2401 * 6 0xNN New repeat state. See above.
2402 * 7 0xNN Restore on Exit byte. If 1, the original setting is
2403 * restored on detach; if 0, the newsetting persists
2404 * after accessory detach.
2405 * 8 0xNN Telegram payload checksum byte
2406 *
2407 * SetRepeat setting persistent after the accessory detach.
2408 * Byte Value Meaning
2409 * 0 0xFF Sync byte (required only for UART serial)
2410 * 1 0x55 Start of telegram
2411 * 2 0x04 Telegram payload length
2412 * 3 0x04 Lingo ID: Extended Interface lingo
2413 * 4 0x00 Command ID (bits 15:8)
2414 * 5 0x31 Command ID (bits 7:0)
2415 * 6 0xNN New repeat state. See above.
2416 * 7 0xNN Telegram payload checksum byte
2417 *
2418 */
2419 int oldmode = global_settings.repeat_mode;
2420 if (buf[3] == 0)
2421 global_settings.repeat_mode = REPEAT_OFF;
2422 else if (buf[3] == 1)
2423 global_settings.repeat_mode = REPEAT_ONE;
2424 else if (buf[3] == 2)
2425 global_settings.repeat_mode = REPEAT_ALL;
2426
2427 if (oldmode != global_settings.repeat_mode)
2428 {
2429 settings_save();
2430 if (audio_status() & AUDIO_STATUS_PLAY)
2431 audio_flush_and_reload_tracks();
2432 }
2433 /* respond with cmd ok packet */
2434 cmd_ok(cmd);
2435 break;
2436 }
2437 case 0x0032: /* SetDisplayImage */
2438 {
2439 /* The following is the description for the Apple Firmware
2440 * This sets a bitmap image
2441 * that is displayed on the iPod display when connected to the
2442 * device. It replaces the default checkmark bitmap image that is
2443 * displayed when iPod is connected to an external device
2444 *
2445 * Sets a bitmap image that is shown on the iPod display when it is
2446 * connected to the device. The intent is to allow third party
2447 * branding when the iPod is communicating with an external device.
2448 * An image downloaded using this mechanism replaces the default
2449 * checkmark bitmap image that is displayed when iPod is connected
2450 * to an external device. The new bitmap is retained in RAM for as
2451 * long as the iPod remains powered. After a system reset or deep
2452 * sleep state, the new bitmap is lost and the checkmark image
2453 * restored as the default when the iPod next enters Extended
2454 * Interface mode after power-up.
2455 * Before setting a monochrome display image, the device can send
2456 * the Command 0x0033: GetMonoDisplayImageLimits telegram to obtain
2457 * the current iPod display width, height and pixel format.The
2458 * monochrome display information returned in the Command 0x0034:
2459 * ReturnMonoDisplayImageLimits telegram can be useful to the
2460 * device in deciding which type of display image format is suitable
2461 * for downloading to the iPod.
2462 * On iPods withcolor displays, devices can send the Command 0x0039:
2463 * GetColorDisplayImageLimits telegram to obtain the iPod color
2464 * display width,height,and pixel formats. The color display
2465 * information is returned in the Command 0x003A:
2466 * ReturnColorDisplayImageLimits” telegram.
2467 * To set a display image, the device must successfully send
2468 * SetDisplayImage descriptor and data telegrams to the iPod. The
2469 * SetDisplayImage descriptor telegram (telegram index 0x0000) must
2470 * be sent first, as it gives the iPod a description of the image
2471 * to be downloaded. This telegram is shown in below. The image
2472 * descriptor telegram includes image pixel format, image width and
2473 * height, and display row size (stride) in bytes. Optionally, the
2474 * descriptor telegram may also contain the beginning data of the
2475 * display image, as long as it remains within the maximum length
2476 * limits of the telegram.
2477 * Following the descriptor telegram, the SetDisplayImage data
2478 * telegrams (telegram index 0x0001 - 0xNNNN) should be sent using
2479 * sequential telegram indices until the entire image has been sent
2480 * to the iPod.
2481 *
2482 * Note: The SetDisplayImage telegram payload length is limited to
2483 * 500 bytes. This telegram length limit and the size and format of
2484 * the display image generally determine the minimum number of
2485 * telegrams that are required to set a display image.
2486 *
2487 * Note: Starting with the second generation iPod nano with version
2488 * 1.1.2 firmware, the use of the SetDisplayImage command is
2489 * limited to once every 15 seconds over USB transport. The iPod
2490 * classic and iPod 3G nano apply this restriction to both USB and
2491 * UART transports. Calls made to SetDisplayImage more frequently
2492 * than every 15 seconds will return a successful ACK command, but
2493 * the bitmap will not be displayed on the iPod’s screen. Hence use
2494 * of the SetDisplayImage command should be limited to drawing one
2495 * bitmap image per accessory connect. The iPod touch will accept
2496 * the SetDisplayImage command but will not draw it on the iPod’s
2497 * screen.
2498 *
2499 * Below shows the format of a descriptor telegram. This example
2500 * assumes the display image descriptor data exceeds the small
2501 * telegram payload capacity; a large telegram format is shown.
2502 *
2503 * SetDisplayImage descriptor telegram (telegram index = 0x0000)
2504 * Byte Value Meaning
2505 * 0 0xFF Sync byte (required only for UART serial)
2506 * 1 0x55 Start of telegram
2507 * 2 0x00 Telegram payload marker (large format)
2508 * 3 0xNN Large telegram payload length (bits 15:8)
2509 * 4 0xNN Large telegram payload length (bits 7:0)
2510 * 5 0x04 Lingo ID: Extended Interface lingo
2511 * 6 0x00 Command ID (bits 15:8)
2512 * 7 0x32 Command ID (bits 7:0)
2513 * 8 0x00 Descriptor telegram index (bits 15:8). These fields
2514 * uniquely identify each packet in the SetDisplayImage
2515 * transaction. The first telegram is the Descriptor
2516 * telegram and always starts with an index of 0x0000.
2517 * 9 0x00 Descriptor telegram index (bits 7:0)
2518 * 10 0xNN Display pixel format code. See Below.
2519 * 11 0xNN Imagewidth in pixels (bits 15:8). The number of
2520 * pixels, from left to right, per row.
2521 * 12 0xNN Image width in pixels (bits 7:0)
2522 * 13 0xNN Image height in pixels (bits 15:8). The number of
2523 * rows, from top to bottom, in the image.
2524 * 14 0xNN Image height in pixels (bits 7:0)
2525 * 15 0xNN Row size (stride) in bytes (bits 31:24). The number of
2526 * bytes representing one row of pixels. Each row is
2527 * zero-padded to end on a 32-bit boundary. The
2528 * cumulative size, in bytes, of the image data,
2529 * transferred across all telegrams in this transaction
2530 * is effectively (Row Size * Image Height).
2531 * 16 0xNN Row size (stride) in bytes (bits 23:16)
2532 * 17 0xNN Row size (stride) in bytes (bits 15:8)
2533 * 18 0xNN Row size (stride) in bytes (bits 7:0)
2534 * 19–N 0xNN Display image pixel data
2535 * NN 0xNN Telegram payload checksum byte
2536 *
2537 * SetDisplayImage data telegram (telegram index = 0x0001 - 0xNNNN)
2538 * Byte Value Meaning
2539 * 0 0xFF Sync byte (required only for UART serial)
2540 * 1 0x55 Start of telegram
2541 * 2 0x00 Telegram payload marker (large format)
2542 * 3 0xNN Large telegram payload length (bits 15:8)
2543 * 4 0xNN Large telegram payload length (bits 7:0)
2544 * 5 0x04 Lingo ID: Extended Interface lingo
2545 * 6 0x00 Command ID (bits 15:8)
2546 * 7 0x32 Command ID (bits 7:0)
2547 * 8 0xNN Descriptor telegram index (bits 15:8). These fields
2548 * uniquely identify each packet in the SetDisplayImage
2549 * transaction. The first telegram is the descriptor
2550 * telegram, shown in Table 6-68 (page 97). The
2551 * remaining n-1 telegrams are simply data telegrams,
2552 * where n is determined by the size of the image.
2553 * 9 0xNN Descriptor telegram index (bits 7:0)
2554 * 10–N 0xNN Display image pixel data
2555 * NN 0xNN Telegram payload checksum byte
2556 *
2557 * Note: A known issue causes SetDisplayImage data telegram
2558 * lengths less than 11 bytes to return a bad parameter error (0x04)
2559 * ACK on 3G iPods.
2560 *
2561 * The iPod display is oriented as a rectangular grid of pixels. In
2562 * the horizontal direction (x-coordinate), the pixel columns are
2563 * numbered, left to right, from 0 to Cmax. In the vertical
2564 * direction (y-coordinate), the pixel rows are numbered, top to
2565 * bottom, from 0 to Rmax. Therefore, an (x,y) coordinate of (0,0)
2566 * represents the upper-leftmost pixel on the display and
2567 * (Cmax,Rmax) represents the lower-rightmost pixel on the display.
2568 * A portion of the iPod display pixel layout is shown below, where
2569 * x is the column number, y is the row number, and (Cmax,Rmax)
2570 * represents the maximum row and column numbers.
2571 *
2572 * Pixel layout
2573 * x
2574 * y 0,0 1,0 2,0 3,0 4,0 5,0 6,0 7,0 - Cmax,0
2575 * 0,1 1,1 2,1 3,1 4,1 5,1 6,1 7,1 - Cmax,1
2576 * 0,2 1,2 2,2 3,2 4,2 5,2 6,2 7,2 - Cmax,2
2577 * 0,3 1,3 2,3 3,3 4,3 5,3 6,3 7,3 - Cmax,3
2578 * 0,4 1,4 2,4 3,4 4,4 5,4 6,4 7,4 - Cmax,4
2579 * 0,5 1,5 2,5 3,5 4,5 5,5 6,5 7,5 - Cmax,5
2580 * 0,6 1,6 2,6 3,6 4,6 5,6 6,6 7,6 - Cmax,6
2581 * 0,7 1,7 2,7 3,7 4,7 5,7 6,7 7,7 - Cmax,7
2582 * " " " " " " " " " "
2583 * 0, 1, 2, 3, 4, 5, 6, 7, - Cmax,
2584 * RmaxRmaxRmaxRmaxRmaxRmaxRmaxRmax Rmax
2585 *
2586 * Display pixel format codes
2587 * Display pixel format Code Protocol version
2588 * Reserved 0x00 N/A
2589 * Monochrome, 2 bits per pixel 0x01 1.01
2590 * RGB 565 color, little-endian, 16 bpp 0x02 1.09
2591 * RGB 565 color, big-endian, 16 bpp 0x03 1.09
2592 * Reserved 0x04-0xFF N/A
2593 *
2594 * iPods with color screens support all three image formats. All
2595 * other iPods support only display pixel format 0x01 (monochrome,
2596 * 2 bpp).
2597 *
2598 * Display Pixel Format 0x01
2599 * Display pixel format 0x01 (monochrome, 2 bits per pixel) is the
2600 * pixel format supported by all iPods. Each pixel consists of 2
2601 * bits that control the pixel intensity. The pixel intensities and
2602 * associated binary codes are listed below.
2603 *
2604 * 2 bpp monochrome pixel intensities
2605 * Pixel Intensity Binary Code
2606 * Pixel off (not visible) 00b
2607 * Pixel on 25% (light grey) 01b
2608 * Pixel on 50% (dark grey) 10b
2609 * Pixel on 100% (black) 11b
2610 *
2611 * Each byte of image data contains four packed pixels. The pixel
2612 * ordering within bytes and the byte ordering within 32 bits is
2613 * shown below.
2614 *
2615 * Image Data Byte 0x0000
2616 * Pixel0 Pixel1 Pixel2 Pixel3
2617 * 7 6 5 4 3 2 1 0
2618 *
2619 * Image Data Byte 0x0001
2620 * Pixel4 Pixel5 Pixel6 Pixel7
2621 * 7 6 5 4 3 2 1 0
2622 *
2623 * Image Data Byte 0x0002
2624 * Pixel8 Pixel9 Pixel10 Pixel11
2625 * 7 6 5 4 3 2 1 0
2626 *
2627 * Image Data Byte 0x0003
2628 * Pixel12 Pixel13 Pixel14 Pixel15
2629 * 7 6 5 4 3 2 1 0
2630 *
2631 * Image Data Byte 0xNNNN
2632 * PixelN PixelN+1 PixelN+2 PixelN+3
2633 * 7 6 5 4 3 2 1 0
2634 *
2635 * Display Pixel Formats 0x02 and 0x03
2636 * Display pixel format 0x02 (RGB 565, little-endian) and display
2637 * pixel format 0x03 (RGB 565, big-endian) are available for use
2638 * in all iPods with color screens. Each pixel consists of 16 bits
2639 * that control the pixel intensity for the colors red, green, and
2640 * blue.
2641 * It takes two bytes to represent a single pixel. Red is
2642 * represented by 5 bits, green is represented by 6 bits, and blue
2643 * by the final 5 bits. A 32-bit sequence represents 2 pixels. The
2644 * pixel ordering within bytes and the byte ordering within 32 bits
2645 * for display format 0x02 (RGB 565, little-endian) is shown below.
2646 *
2647 * Image Data Byte 0x0000
2648 * Pixel 0, lower 3 bits of green Pixel 0, all 5 bits of blue
2649 * 7 6 5 4 3 2 1 0
2650 * Image Data Byte 0x0001
2651 * Pixel 0, all 5 bits of red Pixel 0,upper 3 bits of green
2652 * 7 6 5 4 3 2 1 0
2653 *
2654 * Image Data Byte 0x0002
2655 * Pixel 1, lower 3 bits of green Pixel 1, all 5 bits of blue
2656 * 7 6 5 4 3 2 1 0
2657 *
2658 * Image Data Byte 0x0003
2659 * Pixel 1, all 5 bits of red Pixel 1, upper 3 bits of green
2660 * 7 6 5 4 3 2 1 0
2661 *
2662 * The format for display pixel format 0x03 (RGB 565, big-endian, 16
2663 * bpp) is almost identical, with the exception that bytes 0 and 1
2664 * are swapped and bytes 2 and 3 are swapped.
2665 *
2666 */
2667 cmd_ok(cmd);
2668 break;
2669 }
2670 case 0x0033: /* GetMonoDisplayImageLimits */
2671
2672 {
2673 /* The following is the description for the Apple Firmware
2674 *
2675 * Requests the limiting characteristics of the monochrome image
2676 * that can be sent to the iPod for display while it is connected
2677 * to the device. It can be used to determine the display pixel
2678 * format and maximum width and height of a monochrome image to be
2679 * set using the Command 0x0032: SetDisplayImage telegram. In
2680 * response, the iPod sends a Command 0x0034:
2681 * ReturnMonoDisplayImageLimits telegram to the device with the
2682 * requested display information. The GetMonoDisplayImageLimits
2683 * command is supported by iPods with either monochrome or color
2684 * displays. To obtain color display image limits, use Command
2685 * 0x0039: GetColorDisplayImageLimits.
2686 *
2687 * Byte Value Meaning
2688 * 0 0xFF Sync byte (required only for UART serial)
2689 * 1 0x55 Start of telegram
2690 * 2 0x03 Telegram payload length
2691 * 3 0x04 Lingo ID: Extended Interface lingo
2692 * 4 0x00 Command ID (bits 15:8)
2693 * 5 0x33 Command ID (bits 7:0)
2694 * 6 0xC6 Telegram payload checksum byte
2695 *
2696 */
2697 unsigned char data[] = {0x04, 0x00, 0x34,
2698 LCD_WIDTH >> 8, LCD_WIDTH & 0xff,
2699 LCD_HEIGHT >> 8, LCD_HEIGHT & 0xff,
2700 0x01};
2701 iap_send_pkt(data, sizeof(data));
2702 break;
2703 }
2704 case 0x0034: /* ReturnMonoDisplayImageLimits. See Above*/
2705 /* The following is the description for the Apple Firmware
2706 *
2707 * Returns the limiting characteristics of the monochrome image that
2708 * can be sent to the iPod for display while it is connected to the
2709 * device. The iPod sends this telegram in response to the Command
2710 * 0x0033: GetMonoDisplayImageLimits telegram. Monochrome display
2711 * characteristics include maximum image width and height and the
2712 * display pixel format.
2713 *
2714 * Byte Value Meaning
2715 * 0 0xFF Sync byte (required only for UART serial)
2716 * 1 0x55 Start of telegram
2717 * 2 0xNN Telegram payload length
2718 * 3 0x04 Lingo ID: Extended Interface lingo
2719 * 4 0x00 Command ID (bits 15:8)
2720 * 5 0x34 Command ID (bits 7:0)
2721 * 6 0xNN Maximum image width in pixels (bits 15:8)
2722 * 7 0xNN Maximum image width in pixels (bits 7:0)
2723 * 8 0xNN Maximum image height in pixels (bits 15:8)
2724 * 9 0xNN Maximumimage height in pixels (bits 7:0)
2725 * 10 0xNN Display pixel format (see Table 6-70 (page 99)).
2726 * 11 0xNN Telegram payload checksum byte
2727 *
2728 */
2729 {
2730 /* We should NEVER receive this command so ERROR if we do */
2731 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
2732 break;
2733 }
2734 case 0x0035: /* GetNumPlayingTracks */
2735 {
2736 /* The following is the description for the Apple Firmware
2737 *
2738 * Requests the number of tracks in the list of tracks queued to
2739 * play on the iPod. In response, the iPod sends a Command 0x0036:
2740 * ReturnNumPlayingTracks telegram with the count of tracks queued
2741 * to play.
2742 *
2743 * Byte Value Meaning
2744 * 0 0xFF Sync byte (required only for UART serial)
2745 * 1 0x55 Start of telegram
2746 * 2 0x03 Telegram payload length
2747 * 3 0x04 Lingo ID: Extended Interface lingo
2748 * 4 0x00 Command ID (bits 15:8)
2749 * 5 0x35 Command ID (bits 7:0)
2750 * 6 0xC4 Telegram payload checksum byte
2751 *
2752 */
2753 unsigned char data[] = {0x04, 0x00, 0x36,
2754 0x00, 0x00, 0x00, 0x00};
2755 unsigned long playlist_amt = playlist_amount();
2756 put_u32(&data[3], playlist_amt);
2757 iap_send_pkt(data, sizeof(data));
2758 break;
2759 }
2760 case 0x0036: /* ReturnNumPlayingTracks. See Above */
2761 /* The following is the description for the Apple Firmware
2762 *
2763 * Returns the number of tracks in the actual list of tracks queued
2764 * to play, including the currently playing track (if any). The
2765 * iPod sends this telegram in response to the Command 0x0035:
2766 * GetNumPlayingTracks telegram.
2767 *
2768 * Byte Value Meaning
2769 * 0 0xFF Sync byte (required only for UART serial)
2770 * 1 0x55 Start of telegram
2771 * 2 0x07 Telegram payload length
2772 * 3 0x04 Lingo ID: Extended Interface lingo
2773 * 4 0x00 Command ID (bits 15:8)
2774 * 5 0x36 Command ID (bits 7:0)
2775 * 6 0xNN Number of tracks playing(bits 31:24)
2776 * 7 0xNN Number of tracks playing(bits 23:16)
2777 * 8 0xNN Number of tracks playing (bits 15:8)
2778 * 9 0xNN Number of tracks playing (bits 7:0)
2779 * 10 0xNN Telegram payload checksum byte
2780 *
2781 */
2782 {
2783 /* We should NEVER receive this command so ERROR if we do */
2784 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
2785 break;
2786 }
2787 case 0x0037: /* SetCurrentPlayingTrack */
2788 /* The following is the description for the Apple Firmware
2789 *
2790 * Sets the index of the track to play in the Now Playing playlist
2791 * on the iPod. The index that is specified here is obtained by
2792 * sending the Command 0x0035: GetNumPlayingTracks and Command
2793 * 0x001E: GetCurrentPlayingTrackIndex telegrams to obtain the
2794 * number of playing tracks and the current playing track index,
2795 * respectively. In response, the iPod sends an ACK telegram
2796 * indicating the status of the command.
2797 *
2798 * Note: The behavior of this command has changed. Before the
2799 * 2G nano, if this command was sent with the current playing track
2800 * index the iPod would pause playback momentarily and then resume.
2801 * Starting with the 2G nano, the iPod restarts playback of the
2802 * current track from the beginning. Older iPods will not be
2803 * updated to the new behavior.
2804 *
2805 * Note: This command is usable only when the iPod is in a playing
2806 * or paused state. If the iPod is stopped, this command fails.
2807 *
2808 * Byte Value Meaning
2809 * 0 0xFF Sync byte (required only for UART serial)
2810 * 1 0x55 Start of telegram
2811 * 2 0x07 Telegram payload length
2812 * 3 0x04 Lingo ID: Extended Interface lingo
2813 * 4 0x00 Command ID (bits 15:8)
2814 * 5 0x37 Command ID (bits 7:0)
2815 * 6 0xNN New current playing track index (bits 31:24)
2816 * 7 0xNN New current playing track index (bits 23:16)
2817 * 8 0xNN New current playing track index (bits 15:8)
2818 * 9 0xNN New current playing track index (bits 7:0)
2819 * 10 0xNN Telegram payload checksum byte
2820 *
2821 */
2822 {
2823 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
2824 long tracknum = get_u32(&buf[3]);
2825
2826 audio_pause();
2827 audio_skip(tracknum - playlist_next(0));
2828 if (!paused)
2829 audio_resume();
2830
2831 /* respond with cmd ok packet */
2832 cmd_ok(cmd);
2833 break;
2834 }
2835 case 0x0038: /* SelectSortDBRecord */
2836 /* The following is the description for the Apple Firmware
2837 *
2838 * Selects one or more records in the iPod database, based on a
2839 * category-relative index. For example, selecting category 2
2840 * (Artist), record index 1, and sort order 3 (Album) results in a
2841 * list of selected tracks (records) from the second artist in the
2842 * artist list, sorted by album name. Selections are additive and
2843 * limited by the category hierarchy. Subsequent selections are
2844 * made based on the subset of records resulting from previous
2845 * selections and not from the entire database. The database
2846 * category types are shown above. The sort order options and codes
2847 * are shown below.
2848 *
2849 * SelectSortDBRecord telegram
2850 * Byte Value Meaning
2851 * 0 0xFF Sync byte (required only for UART serial)
2852 * 1 0x55 Start of telegram
2853 * 2 0x09 Telegram payload length
2854 * 3 0x04 Lingo ID: Extended Interface lingo
2855 * 4 0x00 Command ID (bits 15:8)
2856 * 5 0x38 Command ID (bits 7:0)
2857 * 6 0xNN Database category type.
2858 * 7 0xNN Category record index (bits 31:24)
2859 * 8 0xNN Category record index (bits 23:16)
2860 * 9 0xNN Category record index (bits 15:8)
2861 * 10 0xNN Category record index (bits 7:0)
2862 * 11 0xNN Database sort type.
2863 * 12 0xNN Telegram payload checksum byte
2864 *
2865 * Database sort order options
2866 * Sort Order Code Protocol version
2867 * Sort by genre 0x00 1.00
2868 * Sort by artist 0x01 1.00
2869 * Sort by composer 0x02 1.00
2870 * Sort by album 0x03 1.00
2871 * Sort by name 0x04 1.00
2872 * Sort by playlist 0x05 1.00
2873 * Sort by release date 0x06 1.08
2874 * Reserved 0x07 - 0xFE N/A
2875 * Use default sort type 0xFF 1.00
2876 *
2877 * The default order of song and audiobook tracks on the iPod is
2878 * alphabetical by artist, then alphabetical by that artist's
2879 * albums, then ordered according to the order of the tracks on the
2880 * album.
2881 * For podcasts, the default order of episode tracks is reverse
2882 * chronological. That is, the newest ones are first,then
2883 * alphabetical by podcast name.
2884 * The SelectSortDBRecord command can be used to sort all the song
2885 * and audiobook tracks on the iPod alphabetically as follows:
2886 * 1. Command 0x0016: ResetDBSelection
2887 * 2. Command 0x0018: GetNumberCategorizedDBRecords for the Playlist
2888 * category.
2889 * 3. SelectSortDBRecord based on the Playlist category, using a
2890 * record index of 0 to select the All Tracks
2891 * playlist and the sort by name (0x04) sort
2892 * order.
2893 * 4. GetNumberCategorizedDBRecords for the Track category.
2894 * 5. Command 0x001A :RetrieveCategorizedDatabaseRecords based on
2895 * the Track category, using a start index of 0
2896 * and an end index of the number of records
2897 * returned by the call to
2898 * GetNumberCategorizedDBRecords in step 4.
2899 *
2900 * The sort order of artist names ignores certain articles such
2901 * that the artist “The Doors” is sorted under the letter ‘D’ and
2902 * not ‘T’; this matches the behavior of iTunes. The sort order is
2903 * different depending on the language setting used in the iPod.
2904 * The list of ignored articles may change in the future without
2905 * notice.
2906 * The SelectDBRecord command may also be used to select a database
2907 * record with the default sort order.
2908 *
2909 * Note: The sort order field is ignored for the Audiobook category.
2910 * Audiobooks are automatically sorted by track title. The sort
2911 * order for podcast tracks defaults to release date, with the
2912 * newest track coming first.
2913 *
2914 * Selects one or more records in the iPod database, based on a
2915 * category-relative index. This appears to be hardcoded hierarchy
2916 * decided by Apple that the external devices follow.
2917 * This is as follows for all except podcasts,
2918 *
2919 * All (highest level),
2920 * Playlist,
2921 * Genre or Media Kind,
2922 * Artist or Composer,
2923 * Album,
2924 * Track or Audiobook (lowest)
2925 *
2926 * for Podcasts, the order is
2927 *
2928 * All (highest),
2929 * Podcast,
2930 * Episode
2931 * Track (lowest)
2932 *
2933 * Categories are
2934 *
2935 * 0x00 Reserved
2936 * 0x01 Playlist
2937 * 0x02 Artist
2938 * 0x03 Album
2939 * 0x04 Genre
2940 * 0x05 Track
2941 * 0x06 Composer
2942 * 0x07 Audiobook
2943 * 0x08 Podcast
2944 * 0x09 - 0xff Reserved
2945 *
2946 * Sort Order optiona and codes are
2947 *
2948 * 0x00 Sort by Genre
2949 * 0x01 Sort by Artist
2950 * 0x02 Sort by Composer
2951 * 0x03 Sort by Album
2952 * 0x04 Sort by Name (Song Title)
2953 * 0x05 Sort by Playlist
2954 * 0x06 Sort by Release Date
2955 * 0x07 - 0xfe Reserved
2956 * 0xff Use default Sort Type
2957 *
2958 * Packet format (offset in data[]: Description)
2959 * 0x00: Lingo ID: Extended Interface Protocol Lingo, always 0x04
2960 * 0x01-0x02: Command, always 0x0038
2961 * 0x03: Database Category Type
2962 * 0x04-0x07: Category Record Index
2963 * 0x08 Database Sort Type
2964 *
2965 * On Rockbox, if the recordtype is playlist, we load the selected
2966 * playlist and start playing from the first track.
2967 * If the recordtype is track, we play that track from the current
2968 * playlist.
2969 * On anything else we just play the current track from the current
2970 * playlist.
2971 * cur_dbrecord[0] is the recordtype
2972 * cur_dbrecord[1-4] is the u32 of the record number requested
2973 * which might be a playlist or a track number depending on
2974 * the value of cur_dbrecord[0]
2975 */
2976 {
2977 memcpy(cur_dbrecord, buf + 3, 5);
2978
2979 int paused = (is_wps_fading() || (audio_status() & AUDIO_STATUS_PAUSE));
2980 unsigned int number_of_playlists = nbr_total_playlists();
2981 uint32_t index;
2982 uint32_t trackcount;
2983 index = get_u32(&cur_dbrecord[1]);
2984 trackcount = playlist_amount();
2985 if ((cur_dbrecord[0] == 0x05) && (index > trackcount))
2986 {
2987 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
2988 break;
2989 }
2990 if ((cur_dbrecord[0] == 0x01) && (index > (number_of_playlists + 1)))
2991 {
2992 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
2993 break;
2994 }
2995 switch (cur_dbrecord[0])
2996 {
2997 case 0x01: /* Playlist*/
2998 {
2999 if (index != 0x00) /* 0x00 is the On-The-Go Playlist and
3000 we do nothing with it */
3001 {
3002 audio_pause();
3003 audio_skip(-iap_get_trackindex());
3004 playlist_sort(NULL, true);
3005 last_selected_playlist = index;
3006 seek_to_playlist(last_selected_playlist);
3007 }
3008 break;
3009 }
3010 case 0x02: /* Artist Do Nothing */
3011 case 0x03: /* Album Do Nothing */
3012 case 0x04: /* Genre Do Nothing */
3013 case 0x06: /* Composer Do Nothing */
3014 break;
3015 case 0x05: /* Track*/
3016 {
3017 audio_pause();
3018 audio_skip(-iap_get_trackindex());
3019 playlist_sort(NULL, true);
3020 audio_skip(index - playlist_next(0));
3021 break;
3022 }
3023 }
3024 if (!paused)
3025 audio_resume();
3026 /* respond with cmd ok packet */
3027 cmd_ok(cmd);
3028 break;
3029 }
3030 case 0x0039: /* GetColorDisplayImageLimits */
3031 /* The following is the description for the Apple Firmware
3032 *
3033 * Requests the limiting characteristics of the color image that
3034 * can be sent to the iPod for display while it is connected to
3035 * the device. It can be used to determine the display pixel format
3036 * and maximum width and height of a color image to be set using
3037 * the Command 0x0032: SetDisplayImage telegram. In response, the
3038 * iPod sends a Command 0x003A: ReturnColorDisplayImageLimits
3039 * telegram to the device with the requested display information.
3040 * This command is supported only by iPods with color displays.
3041 *
3042 * Byte Value Meaning
3043 * 0 0xFF Sync byte (required only for UART serial)
3044 * 1 0x55 Start of telegram
3045 * 2 0x03 Telegram payload length
3046 * 3 0x04 Lingo ID: Extended Interface lingo
3047 * 4 0x00 Command ID (bits 15:8)
3048 * 5 0x39 Command ID (bits 7:0)
3049 * 6 0xC0 Telegram payload checksum byte
3050 *
3051 */
3052 {
3053 /* Set the same as the ReturnMonoDisplayImageLimits */
3054 unsigned char data[] = {0x04, 0x00, 0x3A,
3055 LCD_WIDTH >> 8, LCD_WIDTH & 0xff,
3056 LCD_HEIGHT >> 8, LCD_HEIGHT & 0xff,
3057 0x01};
3058 iap_send_pkt(data, sizeof(data));
3059 break;
3060 }
3061 case 0x003A: /* ReturnColorDisplayImageLimits See Above */
3062 /* The following is the description for the Apple Firmware
3063 *
3064 * Returns the limiting characteristics of the color image that can
3065 * be sent to the iPod for display while it is connected to the
3066 * device. The iPod sends this telegram in response to the Command
3067 * 0x0039: GetColorDisplayImageLimits telegram. Display
3068 * characteristics include maximum image width and height and the
3069 * display pixel format.
3070 *
3071 * Note: If the iPod supports multiple display image formats, a five
3072 * byte block of additional image width, height, and pixel format
3073 * information is appended to the payload for each supported display
3074 * format. The list of supported color display image formats
3075 * returned by the iPod may change in future software versions.
3076 * Devices must be able to parse a variable length list of supported
3077 * color display formats to search for compatible formats.
3078 *
3079 * Byte Value Meaning
3080 * 0 0xFF Sync byte (required only for UART serial)
3081 * 1 0x55 Start of telegram
3082 * 2 0xNN Telegram payload length
3083 * 3 0x04 Lingo ID: Extended Interface lingo
3084 * 4 0x00 Command ID (bits 15:8)
3085 * 5 0x3A Command ID (bits 7:0)
3086 * 6 0xNN Maximum image width in pixels (bits 15:8)
3087 * 7 0xNN Maximum image width in pixels (bits 7:0)
3088 * 8 0xNN Maximum image height in pixels (bits 15:8)
3089 * 9 0xNN Maximum image height in pixels (bits 7:0)
3090 * 10 0xNN Display pixel format (see Table 6-70 (page 99)).
3091 * 11-N 0xNN Optional display image width, height, and pixel format
3092 * for the second to nth supported display formats,
3093 * if present.
3094 * NN 0xNN Telegram payload checksum byte
3095 *
3096 */
3097 {
3098 /* We should NEVER receive this command so ERROR if we do */
3099 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
3100 break;
3101 }
3102 case 0x003B: /* ResetDBSelectionHierarchy */
3103 {
3104 /* The following is the description for the Apple Firmware
3105 *
3106 * This command carries a single byte in its payload (byte 6). A
3107 * hierarchy selection value of 0x01 means that the accessory wants
3108 * to navigate the music hierarchy; a hierarchy selection value of
3109 * 0x02 means that the accessory wants to navigate the video
3110 * hierarchy.
3111 *
3112 * Byte Value Meaning
3113 * 0 0xFF Sync byte (required only for UART serial)
3114 * 1 0x55 Start of telegram
3115 * 2 0x04 Telegram payload length
3116 * 3 0x04 Lingo ID: Extended Interface lingo
3117 * 4 0x00 Command ID (bits 15:8)
3118 * 5 0x3B Command ID (bits 7:0)
3119 * 6 0x01 or 0x02 Hierarchy selection
3120 * 7 0xNN Telegram payload checksum byte
3121 *
3122 * Note: The iPod will return an error if a device attempts to
3123 * enable an unsupported hierarchy, such as a video hierarchy on an
3124 * iPod model that does not support video.
3125 */
3126 dbrecordcount = 0;
3127 cur_dbrecord[0] = 0;
3128 put_u32(&cur_dbrecord[1],0);
3129 switch (buf[3])
3130 {
3131 case 0x01: /* Music */
3132 {
3133 cmd_ok(cmd);
3134 break;
3135 }
3136 default: /* Anything else */
3137 {
3138 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
3139 break;
3140 }
3141 }
3142 }
3143 default:
3144 {
3145#ifdef LOGF_ENABLE
3146 logf("iap: Unsupported Mode04 Command");
3147#endif
3148 /* The default response is IAP_ACK_BAD_PARAM */
3149 cmd_ack(cmd, IAP_ACK_BAD_PARAM);
3150 break;
3151 }
3152 }
3153}
diff --git a/apps/misc.c b/apps/misc.c
index 8dff227bc1..e746c432e6 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -607,14 +607,6 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
607 unplug_change(false); 607 unplug_change(false);
608 return SYS_PHONE_UNPLUGGED; 608 return SYS_PHONE_UNPLUGGED;
609#endif 609#endif
610#ifdef IPOD_ACCESSORY_PROTOCOL
611 case SYS_IAP_PERIODIC:
612 iap_periodic();
613 return SYS_IAP_PERIODIC;
614 case SYS_IAP_HANDLEPKT:
615 iap_handlepkt();
616 return SYS_IAP_HANDLEPKT;
617#endif
618#if CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO) 610#if CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO)
619 /* stop playback if we receive a call */ 611 /* stop playback if we receive a call */
620 case SYS_CALL_INCOMING: 612 case SYS_CALL_INCOMING: