summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/SOURCES3
-rw-r--r--apps/debug_menu.c8
-rw-r--r--apps/features.txt4
-rw-r--r--apps/iap.c730
-rw-r--r--apps/keymaps/keymap-ipod.c53
-rw-r--r--apps/lang/english.lang111
-rw-r--r--apps/main.c7
-rw-r--r--apps/menus/settings_menu.c6
-rw-r--r--apps/misc.c12
-rw-r--r--apps/playback.c9
-rw-r--r--apps/playback.h2
-rw-r--r--apps/settings.h3
-rw-r--r--apps/settings_list.c9
13 files changed, 955 insertions, 2 deletions
diff --git a/apps/SOURCES b/apps/SOURCES
index c63bcb78e2..bd20136d1e 100644
--- a/apps/SOURCES
+++ b/apps/SOURCES
@@ -52,6 +52,9 @@ tagtree.c
52#endif 52#endif
53filetree.c 53filetree.c
54scrobbler.c 54scrobbler.c
55#ifdef IPOD_ACCESSORY_PROTOCOL
56iap.c
57#endif
55 58
56screen_access.c 59screen_access.c
57#ifdef HAVE_BUTTONBAR 60#ifdef HAVE_BUTTONBAR
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index abb6018a10..f390cced85 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -1195,6 +1195,14 @@ bool dbg_ports(void)
1195 lcd_puts(0, line++, buf); 1195 lcd_puts(0, line++, buf);
1196#endif 1196#endif
1197 1197
1198#if defined(IPOD_ACCESSORY_PROTOCOL)
1199extern unsigned char serbuf[];
1200 snprintf(buf, sizeof(buf), "IAP PACKET: %02x %02x %02x %02x %02x %02x %02x %02x",
1201 serbuf[0], serbuf[1], serbuf[2], serbuf[3], serbuf[4], serbuf[5],
1202 serbuf[6], serbuf[7]);
1203 lcd_puts(0, line++, buf);
1204#endif
1205
1198#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB) 1206#if defined(IRIVER_H10) || defined(IRIVER_H10_5GB)
1199 line++; 1207 line++;
1200 snprintf(buf, sizeof(buf), "BATT: %03x UNK1: %03x", 1208 snprintf(buf, sizeof(buf), "BATT: %03x UNK1: %03x",
diff --git a/apps/features.txt b/apps/features.txt
index 0ddccced3c..4fbf427a23 100644
--- a/apps/features.txt
+++ b/apps/features.txt
@@ -181,3 +181,7 @@ usbstack
181#if defined(HAVE_ACCESSORY_SUPPLY) 181#if defined(HAVE_ACCESSORY_SUPPLY)
182accessory_supply 182accessory_supply
183#endif 183#endif
184
185#if defined(IPOD_ACCESSORY_PROTOCOL)
186serial_port
187#endif
diff --git a/apps/iap.c b/apps/iap.c
new file mode 100644
index 0000000000..a15fd81a90
--- /dev/null
+++ b/apps/iap.c
@@ -0,0 +1,730 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: iap.c 17400 2008-05-07 14:30:29Z xxxxxx $
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 <memory.h>
23#include <string.h>
24
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
33#include "playlist.h"
34#include "playback.h"
35#include "audio.h"
36#include "settings.h"
37#include "metadata.h"
38#include "gwps.h"
39
40#include "button.h"
41#include "action.h"
42
43#define RX_BUFLEN 260
44#define TX_BUFLEN 128
45
46static volatile int iap_pollspeed = 0;
47static volatile bool iap_remotetick = true;
48static bool iap_setupflag = false, iap_updateflag = false;
49static int iap_changedctr = 0;
50
51static unsigned long iap_remotebtn = 0;
52static int iap_repeatbtn = 0;
53static bool iap_btnrepeat = false, iap_btnshuffle = false;
54
55unsigned char serbuf[RX_BUFLEN];
56static int serbuf_i = 0;
57
58static unsigned char response[TX_BUFLEN];
59static int responselen;
60
61static void iap_task(void)
62{
63 static int count = 0;
64
65 count += iap_pollspeed;
66 if (count < (500/10)) return;
67
68 /* exec every 500ms if pollspeed == 1 */
69 count = 0;
70 queue_post(&button_queue, SYS_IAP_PERIODIC, 0);
71}
72
73void iap_setup(int ratenum)
74{
75 iap_bitrate_set(ratenum);
76 iap_pollspeed = 0;
77 iap_remotetick = true;
78 iap_updateflag = false;
79 iap_changedctr = 0;
80 iap_setupflag = true;
81 iap_remotebtn = BUTTON_NONE;
82 tick_add_task(iap_task);
83}
84
85void iap_bitrate_set(int ratenum)
86{
87 switch(ratenum)
88 {
89 case 0:
90 serial_bitrate(0);
91 break;
92 case 1:
93 serial_bitrate(9600);
94 break;
95 case 2:
96 serial_bitrate(19200);
97 break;
98 case 3:
99 serial_bitrate(38400);
100 break;
101 case 4:
102 serial_bitrate(57600);
103 break;
104 }
105}
106
107/* Message format:
108 0xff
109 0x55
110 length
111 mode
112 command (2 bytes)
113 parameters (0-n bytes)
114 checksum (length+mode+parameters+checksum == 0)
115*/
116
117void iap_send_pkt(unsigned char * data, int len)
118{
119 int i, chksum;
120
121 if(len > TX_BUFLEN-4) len = TX_BUFLEN-4;
122 responselen = len + 4;
123
124 response[0] = 0xFF;
125 response[1] = 0x55;
126
127 chksum = response[2] = len;
128 for(i = 0; i < len; i ++)
129 {
130 chksum += data[i];
131 response[i+3] = data[i];
132 }
133
134 response[i+3] = 0x100 - (chksum & 0xFF);
135
136 for(i = 0; i < responselen; i ++)
137 {
138 while (!tx_rdy()) ;
139 tx_writec(response[i]);
140 }
141}
142
143int iap_getc(unsigned char x)
144{
145 static unsigned char last_x = 0;
146 static bool newpkt = true;
147 static unsigned char chksum = 0;
148
149 /* Restart if the sync word is seen */
150 if(x == 0x55 && last_x == 0xff/* && newpkt*/)
151 {
152 serbuf[0] = 0;
153 serbuf_i = 0;
154 chksum = 0;
155 newpkt = false;
156 }
157 else
158 {
159 if(serbuf_i >= RX_BUFLEN)
160 serbuf_i = 0;
161
162 serbuf[serbuf_i++] = x;
163 chksum += x;
164 }
165 last_x = x;
166
167 /* Broadcast to queue if we have a complete message */
168 if(serbuf_i && (serbuf_i == serbuf[0]+2))
169 {
170 serbuf_i = 0;
171 newpkt = true;
172 if(chksum == 0)
173 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
174 }
175 return newpkt;
176}
177
178void iap_track_changed(void)
179{
180 iap_changedctr = 1;
181}
182
183void iap_periodic(void)
184{
185 if(!iap_setupflag) return;
186 if(!iap_pollspeed) return;
187
188 unsigned char data[] = {0x04, 0x00, 0x27, 0x04, 0x00, 0x00, 0x00, 0x00};
189 unsigned long time_elapsed = audio_current_track()->elapsed;
190
191 time_elapsed += wps_state.ff_rewind_count;
192
193 data[3] = 0x04; // playing
194
195 /* If info has changed, don't flag it right away */
196 if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2)
197 {
198 /* track info has changed */
199 iap_changedctr = 0;
200 data[3] = 0x01; // 0x02 has same effect?
201 iap_updateflag = true;
202 }
203
204 data[4] = time_elapsed >> 24;
205 data[5] = time_elapsed >> 16;
206 data[6] = time_elapsed >> 8;
207 data[7] = time_elapsed;
208 iap_send_pkt(data, sizeof(data));
209}
210
211void iap_handlepkt(void)
212{
213
214 if(!iap_setupflag) return;
215 if(serbuf[0] == 0) return;
216
217 /* if we are waiting for a remote button to go out,
218 delay the handling of the new packet */
219 if(!iap_remotetick)
220 {
221 queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0);
222 return;
223 }
224
225 /* Handle Mode 0 */
226 if (serbuf[1] == 0x00)
227 {
228 switch (serbuf[2])
229 {
230 /* get model info */
231 case 0x0D:
232 {
233 unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10,
234 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00};
235 iap_send_pkt(data, sizeof(data));
236 break;
237 }
238 /* No idea ??? */
239 case 0x0F:
240 {
241 unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05};
242 iap_send_pkt(data, sizeof(data));
243 break;
244 }
245 /* FM transmitter sends this: FF 55 06 00 01 05 00 02 01 F1 (mode switch) */
246 case 0x01:
247 {
248 if(serbuf[3] == 0x05)
249 {
250 sleep(HZ/3);
251 unsigned char data[] = {0x05, 0x02};
252 iap_send_pkt(data, sizeof(data));
253 }
254 break;
255 }
256 /* FM transmitter sends this: FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (???)*/
257 case 0x13:
258 {
259 unsigned char data[] = {0x00, 0x02, 0x00, 0x13};
260 iap_send_pkt(data, sizeof(data));
261 unsigned char data2[] = {0x00, 0x27, 0x00};
262 iap_send_pkt(data2, sizeof(data2));
263 unsigned char data3[] = {0x05, 0x02};
264 iap_send_pkt(data3, sizeof(data3));
265 break;
266 }
267 /* FM transmitter sends this: FF 55 02 00 05 F9 (mode switch: AiR mode) */
268 case 0x05:
269 {
270 unsigned char data[] = {0x00, 0x02, 0x06, 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28};
271 iap_send_pkt(data, sizeof(data));
272 unsigned char data2[] = {0x00, 0x02, 0x00, 0x05};
273 iap_send_pkt(data2, sizeof(data2));
274 break;
275 }
276 /* default response is with cmd ok packet */
277 default:
278 {
279 unsigned char data[] = {0x00, 0x02, 0x00, 0x00};
280 data[3] = serbuf[2]; //respond with cmd
281 iap_send_pkt(data, sizeof(data));
282 break;
283 }
284 }
285 }
286 /* Handle Mode 2 */
287 else if (serbuf[1] == 0x02)
288 {
289 if(serbuf[2] != 0) return;
290 iap_remotebtn = BUTTON_NONE;
291 iap_remotetick = false;
292
293 if(serbuf[0] >= 3 && serbuf[3] != 0)
294 {
295 if(serbuf[3] & 1)
296 iap_remotebtn |= BUTTON_RC_PLAY;
297 if(serbuf[3] & 2)
298 iap_remotebtn |= BUTTON_RC_VOL_UP;
299 if(serbuf[3] & 4)
300 iap_remotebtn |= BUTTON_RC_VOL_DOWN;
301 if(serbuf[3] & 8)
302 iap_remotebtn |= BUTTON_RC_RIGHT;
303 if(serbuf[3] & 16)
304 iap_remotebtn |= BUTTON_RC_LEFT;
305 }
306 else if(serbuf[0] >= 4 && serbuf[4] != 0)
307 {
308 if(serbuf[4] & 1) /* play */
309 {
310 if (audio_status() != AUDIO_STATUS_PLAY)
311 {
312 iap_remotebtn |= BUTTON_RC_PLAY;
313 iap_repeatbtn = 2;
314 iap_remotetick = false;
315 iap_changedctr = 1;
316 }
317 }
318 if(serbuf[4] & 2) /* pause */
319 {
320 if (audio_status() == AUDIO_STATUS_PLAY)
321 {
322 iap_remotebtn |= BUTTON_RC_PLAY;
323 iap_repeatbtn = 2;
324 iap_remotetick = false;
325 iap_changedctr = 1;
326 }
327 }
328 if((serbuf[4] & 128) && !iap_btnshuffle) /* shuffle */
329 {
330 iap_btnshuffle = true;
331 if(!global_settings.playlist_shuffle)
332 {
333 global_settings.playlist_shuffle = 1;
334 settings_save();
335 settings_apply(false);
336 if (audio_status() & AUDIO_STATUS_PLAY)
337 playlist_randomise(NULL, current_tick, true);
338 }
339 else if(global_settings.playlist_shuffle)
340 {
341 global_settings.playlist_shuffle = 0;
342 settings_save();
343 settings_apply(false);
344 if (audio_status() & AUDIO_STATUS_PLAY)
345 playlist_sort(NULL, true);
346 }
347 }
348 else
349 iap_btnshuffle = false;
350 }
351 else if(serbuf[0] >= 5 && serbuf[5] != 0)
352 {
353 if((serbuf[5] & 1) && !iap_btnrepeat) /* repeat */
354 {
355 int oldmode = global_settings.repeat_mode;
356 iap_btnrepeat = true;
357
358 if (oldmode == REPEAT_ONE)
359 global_settings.repeat_mode = REPEAT_OFF;
360 else if (oldmode == REPEAT_ALL)
361 global_settings.repeat_mode = REPEAT_ONE;
362 else if (oldmode == REPEAT_OFF)
363 global_settings.repeat_mode = REPEAT_ALL;
364
365 settings_save();
366 settings_apply(false);
367 if (audio_status() & AUDIO_STATUS_PLAY)
368 audio_flush_and_reload_tracks();
369 }
370 else
371 iap_btnrepeat = false;
372
373 if(serbuf[5] & 16) /* ffwd */
374 {
375 iap_remotebtn |= BUTTON_RC_RIGHT;
376 }
377 if(serbuf[5] & 32) /* frwd */
378 {
379 iap_remotebtn |= BUTTON_RC_LEFT;
380 }
381 }
382 }
383 /* Handle Mode 3 */
384 else if (serbuf[1] == 0x03)
385 {
386 switch(serbuf[2])
387 {
388 /* some kind of status packet? */
389 case 0x01:
390 {
391 unsigned char data[] = {0x03, 0x02, 0x00, 0x00, 0x00, 0x00};
392 iap_send_pkt(data, sizeof(data));
393 break;
394 }
395 }
396 }
397 /* Handle Mode 4 */
398 else if (serbuf[1] == 0x04)
399 {
400 switch (((unsigned long)serbuf[2] << 8) | serbuf[3])
401 {
402 /* Get data updated??? flag */
403 case 0x0009:
404 {
405 unsigned char data[] = {0x04, 0x00, 0x0A, 0x00};
406 data[3] = iap_updateflag ? 0 : 1;
407 iap_send_pkt(data, sizeof(data));
408 break;
409 }
410 /* Set data updated??? flag */
411 case 0x000B:
412 {
413 iap_updateflag = serbuf[4] ? 0 : 1;
414 /* respond with cmd ok packet */
415 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x0B};
416 iap_send_pkt(data, sizeof(data));
417 break;
418 }
419 /* Get iPod size? */
420 case 0x0012:
421 {
422 unsigned char data[] = {0x04, 0x00, 0x13, 0x01, 0x0B};
423 iap_send_pkt(data, sizeof(data));
424 break;
425 }
426 /* Get count of given types */
427 case 0x0018:
428 {
429 unsigned char data[] = {0x04, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00};
430 unsigned long num = 0;
431 switch(serbuf[4]) /* type number */
432 {
433 case 0x01: /* total number of playlists */
434 num = 1;
435 break;
436 case 0x05: /* total number of songs */
437 num = 1;
438 }
439 data[3] = num >> 24;
440 data[4] = num >> 16;
441 data[5] = num >> 8;
442 data[6] = num;
443 iap_send_pkt(data, sizeof(data));
444 break;
445 }
446 /* Get time and status */
447 case 0x001C:
448 {
449 unsigned char data[] = {0x04, 0x00, 0x1D, 0x00, 0x00, 0x00,
450 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
451 struct mp3entry *id3 = audio_current_track();
452 unsigned long time_total = id3->length;
453 unsigned long time_elapsed = id3->elapsed;
454 int status = audio_status();
455 data[3] = time_total >> 24;
456 data[4] = time_total >> 16;
457 data[5] = time_total >> 8;
458 data[6] = time_total;
459 data[7] = time_elapsed >> 24;
460 data[8] = time_elapsed >> 16;
461 data[9] = time_elapsed >> 8;
462 data[10] = time_elapsed;
463 if (status == AUDIO_STATUS_PLAY)
464 data[11] = 0x01; /* play */
465 else if (status & AUDIO_STATUS_PAUSE)
466 data[11] = 0x02; /* pause */
467 iap_send_pkt(data, sizeof(data));
468 break;
469 }
470 /* Get current pos in playlist */
471 case 0x001E:
472 {
473 unsigned char data[] = {0x04, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00};
474 long playlist_pos = playlist_next(0);
475 playlist_pos -= playlist_get_first_index(NULL);
476 if(playlist_pos < 0)
477 playlist_pos += playlist_amount();
478 data[3] = playlist_pos >> 24;
479 data[4] = playlist_pos >> 16;
480 data[5] = playlist_pos >> 8;
481 data[6] = playlist_pos;
482 iap_send_pkt(data, sizeof(data));
483 break;
484 }
485 /* Get title of a song number */
486 case 0x0020:
487 /* Get artist of a song number */
488 case 0x0022:
489 /* Get album of a song number */
490 case 0x0024:
491 {
492 unsigned char data[70] = {0x04, 0x00, 0xFF};
493 struct mp3entry id3;
494 int fd;
495 long tracknum = (signed long)serbuf[4] << 24 |
496 (signed long)serbuf[5] << 16 |
497 (signed long)serbuf[6] << 8 | serbuf[7];
498 data[2] = serbuf[3] + 1;
499 memcpy(&id3, audio_current_track(), sizeof(id3));
500 tracknum += playlist_get_first_index(NULL);
501 if(tracknum >= playlist_amount())
502 tracknum -= playlist_amount();
503
504 /* If the tracknumber is not the current one,
505 read id3 from disk */
506 if(playlist_next(0) != tracknum)
507 {
508 struct playlist_track_info info;
509 playlist_get_track_info(NULL, tracknum, &info);
510 fd = open(info.filename, O_RDONLY);
511 memset(&id3, 0, sizeof(struct mp3entry));
512 get_metadata(&id3, fd, info.filename);
513 close(fd);
514 }
515
516 /* Return the requested track data */
517 switch(serbuf[3])
518 {
519 case 0x20:
520 strncpy((char *)&data[3], id3.title, 64);
521 iap_send_pkt(data, 4+strlen(id3.title));
522 break;
523 case 0x22:
524 strncpy((char *)&data[3], id3.artist, 64);
525 iap_send_pkt(data, 4+strlen(id3.artist));
526 break;
527 case 0x24:
528 strncpy((char *)&data[3], id3.album, 64);
529 iap_send_pkt(data, 4+strlen(id3.album));
530 break;
531 }
532 break;
533 }
534 /* Set polling mode */
535 case 0x0026:
536 {
537 iap_pollspeed = serbuf[4] ? 1 : 0;
538 /*responsed with cmd ok packet */
539 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x26};
540 iap_send_pkt(data, sizeof(data));
541 break;
542 }
543 /* AiR playback control */
544 case 0x0029:
545 {
546 /* respond with cmd ok packet */
547 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x29};
548 iap_send_pkt(data, sizeof(data));
549 switch(serbuf[4])
550 {
551 case 0x01: /* play/pause */
552 iap_remotebtn = BUTTON_RC_PLAY;
553 iap_repeatbtn = 2;
554 iap_remotetick = false;
555 iap_changedctr = 1;
556 break;
557 case 0x02: /* stop */
558 iap_remotebtn = BUTTON_RC_PLAY|BUTTON_REPEAT;
559 iap_repeatbtn = 2;
560 iap_remotetick = false;
561 iap_changedctr = 1;
562 break;
563 case 0x03: /* skip++ */
564 iap_remotebtn = BUTTON_RC_RIGHT;
565 iap_repeatbtn = 2;
566 iap_remotetick = false;
567 break;
568 case 0x04: /* skip-- */
569 iap_remotebtn = BUTTON_RC_LEFT;
570 iap_repeatbtn = 2;
571 iap_remotetick = false;
572 break;
573 case 0x05: /* ffwd */
574 iap_remotebtn = BUTTON_RC_RIGHT;
575 iap_remotetick = false;
576 if(iap_pollspeed) iap_pollspeed = 5;
577 break;
578 case 0x06: /* frwd */
579 iap_remotebtn = BUTTON_RC_LEFT;
580 iap_remotetick = false;
581 if(iap_pollspeed) iap_pollspeed = 5;
582 break;
583 case 0x07: /* end ffwd/frwd */
584 iap_remotebtn = BUTTON_NONE;
585 iap_remotetick = false;
586 if(iap_pollspeed) iap_pollspeed = 1;
587 break;
588 }
589 break;
590 }
591 /* Get shuffle mode */
592 case 0x002C:
593 {
594 unsigned char data[] = {0x04, 0x00, 0x2D, 0x00};
595 data[3] = global_settings.playlist_shuffle ? 1 : 0;
596 iap_send_pkt(data, sizeof(data));
597 break;
598 }
599 /* Set shuffle mode */
600 case 0x002E:
601 {
602 if(serbuf[4] && !global_settings.playlist_shuffle)
603 {
604 global_settings.playlist_shuffle = 1;
605 settings_save();
606 settings_apply(false);
607 if (audio_status() & AUDIO_STATUS_PLAY)
608 playlist_randomise(NULL, current_tick, true);
609 }
610 else if(!serbuf[4] && global_settings.playlist_shuffle)
611 {
612 global_settings.playlist_shuffle = 0;
613 settings_save();
614 settings_apply(false);
615 if (audio_status() & AUDIO_STATUS_PLAY)
616 playlist_sort(NULL, true);
617 }
618
619
620 /* respond with cmd ok packet */
621 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x2E};
622 iap_send_pkt(data, sizeof(data));
623 break;
624 }
625 /* Get repeat mode */
626 case 0x002F:
627 {
628 unsigned char data[] = {0x04, 0x00, 0x30, 0x00};
629 if(global_settings.repeat_mode == REPEAT_OFF)
630 data[3] = 0;
631 else if(global_settings.repeat_mode == REPEAT_ONE)
632 data[3] = 1;
633 else
634 data[3] = 2;
635 iap_send_pkt(data, sizeof(data));
636 break;
637 }
638 /* Set repeat mode */
639 case 0x0031:
640 {
641 int oldmode = global_settings.repeat_mode;
642 if (serbuf[4] == 0)
643 global_settings.repeat_mode = REPEAT_OFF;
644 else if (serbuf[4] == 1)
645 global_settings.repeat_mode = REPEAT_ONE;
646 else if (serbuf[4] == 2)
647 global_settings.repeat_mode = REPEAT_ALL;
648
649 if (oldmode != global_settings.repeat_mode)
650 {
651 settings_save();
652 settings_apply(false);
653 if (audio_status() & AUDIO_STATUS_PLAY)
654 audio_flush_and_reload_tracks();
655 }
656
657 /* respond with cmd ok packet */
658 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x31};
659 iap_send_pkt(data, sizeof(data));
660 break;
661 }
662 /* Get Max Screen Size for Picture Upload??? */
663 case 0x0033:
664 {
665 unsigned char data[] = {0x04, 0x00, 0x34, 0x01, 0x36, 0x00, 0xA8, 0x01};
666 iap_send_pkt(data, sizeof(data));
667 break;
668 }
669 /* Get number songs in current playlist */
670 case 0x0035:
671 {
672 unsigned char data[] = {0x04, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00};
673 unsigned long playlist_amt = playlist_amount();
674 data[3] = playlist_amt >> 24;
675 data[4] = playlist_amt >> 16;
676 data[5] = playlist_amt >> 8;
677 data[6] = playlist_amt;
678 iap_send_pkt(data, sizeof(data));
679 break;
680 }
681 /* Jump to track number in current playlist */
682 case 0x0037:
683 {
684 long tracknum = (signed long)serbuf[4] << 24 |
685 (signed long)serbuf[5] << 16 |
686 (signed long)serbuf[6] << 8 | serbuf[7];
687 if (!wps_state.paused)
688 audio_pause();
689 audio_skip(tracknum - playlist_next(0));
690 if (!wps_state.paused)
691 audio_resume();
692
693 /* respond with cmd ok packet */
694 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
695 data[4] = serbuf[2];
696 data[5] = serbuf[3];
697 iap_send_pkt(data, sizeof(data));
698 break;
699 }
700 default:
701 {
702 /* default response is with cmd ok packet */
703 unsigned char data[] = {0x04, 0x00, 0x01, 0x00, 0x00, 0x00};
704 data[4] = serbuf[2];
705 data[5] = serbuf[3];
706 iap_send_pkt(data, sizeof(data));
707 break;
708 }
709 }
710 }
711 serbuf[0] = 0;
712}
713
714int remote_control_rx(void)
715{
716 int btn = iap_remotebtn;
717 if(iap_repeatbtn)
718 {
719 iap_repeatbtn--;
720 if(!iap_repeatbtn)
721 {
722 iap_remotebtn = BUTTON_NONE;
723 iap_remotetick = true;
724 }
725 }
726 else
727 iap_remotetick = true;
728
729 return btn;
730}
diff --git a/apps/keymaps/keymap-ipod.c b/apps/keymaps/keymap-ipod.c
index 5b735eb530..02854524d2 100644
--- a/apps/keymaps/keymap-ipod.c
+++ b/apps/keymaps/keymap-ipod.c
@@ -187,9 +187,62 @@ const struct button_mapping button_context_recscreen[] = {
187}; /* button_context_recscreen */ 187}; /* button_context_recscreen */
188#endif 188#endif
189 189
190#if BUTTON_REMOTE != 0
191/*****************************************************************************
192 * Remote control mappings
193 *****************************************************************************/
194
195static const struct button_mapping remote_button_context_standard[] = {
196 { ACTION_STD_PREV, BUTTON_RC_LEFT, BUTTON_NONE },
197 { ACTION_STD_NEXT, BUTTON_RC_RIGHT, BUTTON_NONE },
198 { ACTION_STD_CANCEL, BUTTON_RC_STOP, BUTTON_NONE },
199 { ACTION_STD_OK, BUTTON_RC_PLAY, BUTTON_NONE },
200
201 LAST_ITEM_IN_LIST
202};
203
204static const struct button_mapping remote_button_context_wps[] = {
205 { ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN, BUTTON_NONE },
206 { ACTION_WPS_VOLDOWN, BUTTON_RC_VOL_DOWN|BUTTON_REPEAT, BUTTON_NONE },
207 { ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP, BUTTON_NONE },
208 { ACTION_WPS_VOLUP, BUTTON_RC_VOL_UP|BUTTON_REPEAT, BUTTON_NONE },
209
210 { ACTION_WPS_PLAY, BUTTON_RC_PLAY|BUTTON_REL, BUTTON_RC_PLAY },
211 { ACTION_WPS_STOP, BUTTON_RC_PLAY|BUTTON_REPEAT, BUTTON_NONE },
212 { ACTION_WPS_SKIPNEXT, BUTTON_RC_RIGHT|BUTTON_REL, BUTTON_RC_RIGHT },
213 { ACTION_WPS_SEEKFWD, BUTTON_RC_RIGHT|BUTTON_REPEAT,BUTTON_NONE },
214 { ACTION_WPS_STOPSEEK, BUTTON_RC_RIGHT|BUTTON_REL, BUTTON_RC_RIGHT|BUTTON_REPEAT },
215 { ACTION_WPS_SKIPPREV, BUTTON_RC_LEFT|BUTTON_REL, BUTTON_RC_LEFT },
216 { ACTION_WPS_SEEKBACK, BUTTON_RC_LEFT|BUTTON_REPEAT, BUTTON_NONE },
217 { ACTION_WPS_STOPSEEK, BUTTON_RC_LEFT|BUTTON_REL, BUTTON_RC_LEFT|BUTTON_REPEAT },
218
219 LAST_ITEM_IN_LIST__NEXTLIST(CONTEXT_STD)
220};
221
222
223static const struct button_mapping* get_context_mapping_remote( int context )
224{
225 context ^= CONTEXT_REMOTE;
226
227 switch (context)
228 {
229 case CONTEXT_WPS:
230 return remote_button_context_wps;
231
232 default:
233 return remote_button_context_standard;
234 }
235}
236#endif /* BUTTON_REMOTE != 0 */
237
190/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */ 238/* get_context_mapping returns a pointer to one of the above defined arrays depending on the context */
191const struct button_mapping* get_context_mapping(int context) 239const struct button_mapping* get_context_mapping(int context)
192{ 240{
241#if BUTTON_REMOTE != 0
242 if (context&CONTEXT_REMOTE)
243 return get_context_mapping_remote(context);
244#endif
245
193 switch (context) 246 switch (context)
194 { 247 {
195 case CONTEXT_STD: 248 case CONTEXT_STD:
diff --git a/apps/lang/english.lang b/apps/lang/english.lang
index f0099e4ec9..f5f9ed3b80 100644
--- a/apps/lang/english.lang
+++ b/apps/lang/english.lang
@@ -11811,6 +11811,110 @@
11811 gigabeatf: "High" 11811 gigabeatf: "High"
11812 </voice> 11812 </voice>
11813</phrase> 11813</phrase>
11814<<<<<<< .mine
11815<phrase>
11816 id: LANG_SERIAL_BITRATE
11817 desc: in system settings menu
11818 user:
11819 <source>
11820 *: none
11821 serial_port: "Serial Bitrate"
11822 </source>
11823 <dest>
11824 *: none
11825 serial_port: "Serial Bitrate"
11826 </dest>
11827 <voice>
11828 *: none
11829 serial_port: "Serial Bitrate"
11830 </voice>
11831</phrase>
11832<phrase>
11833 id: LANG_SERIAL_BITRATE_AUTO
11834 desc: in system settings menu
11835 user:
11836 <source>
11837 *: none
11838 serial_port: "Auto"
11839 </source>
11840 <dest>
11841 *: none
11842 serial_port: "Auto"
11843 </dest>
11844 <voice>
11845 *: none
11846 serial_port: "Automatic"
11847 </voice>
11848</phrase>
11849<phrase>
11850 id: LANG_SERIAL_BITRATE_9600
11851 desc: in system settings menu
11852 user:
11853 <source>
11854 *: none
11855 serial_port: "9600"
11856 </source>
11857 <dest>
11858 *: none
11859 serial_port: "9600"
11860 </dest>
11861 <voice>
11862 *: none
11863 serial_port: "9600"
11864 </voice>
11865</phrase>
11866<phrase>
11867 id: LANG_SERIAL_BITRATE_19200
11868 desc: in system settings menu
11869 user:
11870 <source>
11871 *: none
11872 serial_port: "19200"
11873 </source>
11874 <dest>
11875 *: none
11876 serial_port: "19200"
11877 </dest>
11878 <voice>
11879 *: none
11880 serial_port: "19200"
11881 </voice>
11882</phrase>
11883<phrase>
11884 id: LANG_SERIAL_BITRATE_38400
11885 desc: in system settings menu
11886 user:
11887 <source>
11888 *: none
11889 serial_port: "38400"
11890 </source>
11891 <dest>
11892 *: none
11893 serial_port: "38400"
11894 </dest>
11895 <voice>
11896 *: none
11897 serial_port: "38400"
11898 </voice>
11899</phrase>
11900<phrase>
11901 id: LANG_SERIAL_BITRATE_57600
11902 desc: in system settings menu
11903 user:
11904 <source>
11905 *: none
11906 serial_port: "57600"
11907 </source>
11908 <dest>
11909 *: none
11910 serial_port: "57600"
11911 </dest>
11912 <voice>
11913 *: none
11914 serial_port: "57600"
11915 </voice>
11916</phrase>
11917=======
11814<phrase> 11918<phrase>
11815 id: LANG_VERY_SLOW 11919 id: LANG_VERY_SLOW
11816 desc: in settings_menu 11920 desc: in settings_menu
@@ -11909,6 +12013,9 @@
11909 *: "slash" 12013 *: "slash"
11910 </voice> 12014 </voice>
11911</phrase> 12015</phrase>
12016<<<<<<< .mine
12017>>>>>>> .r18116
12018=======
11912<phrase> 12019<phrase>
11913 id: LANG_GAIN_LEFT 12020 id: LANG_GAIN_LEFT
11914 desc: in the recording screen 12021 desc: in the recording screen
@@ -12110,6 +12217,9 @@
12110 *: "Search Results" 12217 *: "Search Results"
12111 </voice> 12218 </voice>
12112</phrase> 12219</phrase>
12220<<<<<<< .mine
12221>>>>>>> .r18870
12222=======
12113<phrase> 12223<phrase>
12114 id: LANG_QS_ITEMS 12224 id: LANG_QS_ITEMS
12115 desc: DEPRECATED 12225 desc: DEPRECATED
@@ -12243,3 +12353,4 @@
12243 quickscreen: "Set as Bottom Quickscreen Item" 12353 quickscreen: "Set as Bottom Quickscreen Item"
12244 </voice> 12354 </voice>
12245</phrase> 12355</phrase>
12356>>>>>>> .r19041
diff --git a/apps/main.c b/apps/main.c
index 111c5d1e78..45e6c77801 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -73,6 +73,10 @@
73#include "scrobbler.h" 73#include "scrobbler.h"
74#include "icon.h" 74#include "icon.h"
75 75
76#ifdef IPOD_ACCESSORY_PROTOCOL
77#include "iap.h"
78#endif
79
76#if (CONFIG_CODEC == SWCODEC) 80#if (CONFIG_CODEC == SWCODEC)
77#include "playback.h" 81#include "playback.h"
78#endif 82#endif
@@ -583,6 +587,9 @@ static void init(void)
583#if CONFIG_CHARGING 587#if CONFIG_CHARGING
584 car_adapter_mode_init(); 588 car_adapter_mode_init();
585#endif 589#endif
590#ifdef IPOD_ACCESSORY_PROTOCOL
591 iap_setup(global_settings.serial_bitrate);
592#endif
586#ifdef HAVE_ACCESSORY_SUPPLY 593#ifdef HAVE_ACCESSORY_SUPPLY
587 accessory_supply_set(global_settings.accessory_supply); 594 accessory_supply_set(global_settings.accessory_supply);
588#endif 595#endif
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index d05726ea44..b6e5ad4171 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -247,6 +247,9 @@ MENUITEM_SETTING(line_in, &global_settings.line_in, linein_callback);
247#if CONFIG_CHARGING 247#if CONFIG_CHARGING
248MENUITEM_SETTING(car_adapter_mode, &global_settings.car_adapter_mode, NULL); 248MENUITEM_SETTING(car_adapter_mode, &global_settings.car_adapter_mode, NULL);
249#endif 249#endif
250#ifdef IPOD_ACCESSORY_PROTOCOL
251MENUITEM_SETTING(serial_bitrate, &global_settings.serial_bitrate, NULL);
252#endif
250#ifdef HAVE_ACCESSORY_SUPPLY 253#ifdef HAVE_ACCESSORY_SUPPLY
251MENUITEM_SETTING(accessory_supply, &global_settings.accessory_supply, NULL); 254MENUITEM_SETTING(accessory_supply, &global_settings.accessory_supply, NULL);
252#endif 255#endif
@@ -282,6 +285,9 @@ MAKE_MENU(system_menu, ID2P(LANG_SYSTEM),
282#if CONFIG_CHARGING 285#if CONFIG_CHARGING
283 &car_adapter_mode, 286 &car_adapter_mode,
284#endif 287#endif
288#ifdef IPOD_ACCESSORY_PROTOCOL,
289 &serial_bitrate,
290#endif
285#ifdef HAVE_ACCESSORY_SUPPLY 291#ifdef HAVE_ACCESSORY_SUPPLY
286 &accessory_supply, 292 &accessory_supply,
287#endif 293#endif
diff --git a/apps/misc.c b/apps/misc.c
index 11cdee17b9..8b73411549 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -61,6 +61,10 @@
61#include "playlist.h" 61#include "playlist.h"
62#include "yesno.h" 62#include "yesno.h"
63 63
64#ifdef IPOD_ACCESSORY_PROTOCOL
65#include "iap.h"
66#endif
67
64#if (CONFIG_STORAGE & STORAGE_MMC) 68#if (CONFIG_STORAGE & STORAGE_MMC)
65#include "ata_mmc.h" 69#include "ata_mmc.h"
66#endif 70#endif
@@ -959,6 +963,14 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
959 unplug_change(false); 963 unplug_change(false);
960 return SYS_PHONE_UNPLUGGED; 964 return SYS_PHONE_UNPLUGGED;
961#endif 965#endif
966#ifdef IPOD_ACCESSORY_PROTOCOL
967 case SYS_IAP_PERIODIC:
968 iap_periodic();
969 return SYS_IAP_PERIODIC;
970 case SYS_IAP_HANDLEPKT:
971 iap_handlepkt();
972 return SYS_IAP_HANDLEPKT;
973#endif
962 } 974 }
963 return 0; 975 return 0;
964} 976}
diff --git a/apps/playback.c b/apps/playback.c
index d2d9bb6a34..0f76666c1e 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -82,6 +82,10 @@
82#include "pcm_record.h" 82#include "pcm_record.h"
83#endif 83#endif
84 84
85#ifdef IPOD_ACCESSORY_PROTOCOL
86#include "iap.h"
87#endif
88
85#define PLAYBACK_VOICE 89#define PLAYBACK_VOICE
86 90
87/* default point to start buffer refill */ 91/* default point to start buffer refill */
@@ -646,6 +650,9 @@ bool audio_has_changed_track(void)
646{ 650{
647 if (track_changed) 651 if (track_changed)
648 { 652 {
653#ifdef IPOD_ACCESSORY_PROTOCOL
654 iap_track_changed();
655#endif
649 track_changed = false; 656 track_changed = false;
650 return true; 657 return true;
651 } 658 }
@@ -691,7 +698,7 @@ void audio_resume(void)
691 queue_send(&audio_queue, Q_AUDIO_PAUSE, false); 698 queue_send(&audio_queue, Q_AUDIO_PAUSE, false);
692} 699}
693 700
694static void audio_skip(int direction) 701void audio_skip(int direction)
695{ 702{
696 if (playlist_check(ci.new_track + wps_offset + direction)) 703 if (playlist_check(ci.new_track + wps_offset + direction))
697 { 704 {
diff --git a/apps/playback.h b/apps/playback.h
index d9f29cc56a..e65d5da150 100644
--- a/apps/playback.h
+++ b/apps/playback.h
@@ -33,7 +33,7 @@ int audio_track_count(void);
33long audio_filebufused(void); 33long audio_filebufused(void);
34void audio_pre_ff_rewind(void); 34void audio_pre_ff_rewind(void);
35void audio_set_crossfade(int type); 35void audio_set_crossfade(int type);
36 36void audio_skip(int direction);
37void audio_hard_stop(void); /* Stops audio from serving playback */ 37void audio_hard_stop(void); /* Stops audio from serving playback */
38 38
39enum 39enum
diff --git a/apps/settings.h b/apps/settings.h
index b0117874cc..f9b3239e05 100644
--- a/apps/settings.h
+++ b/apps/settings.h
@@ -488,6 +488,9 @@ struct user_settings
488 bool peak_meter_clipcounter; /* clipping count indicator */ 488 bool peak_meter_clipcounter; /* clipping count indicator */
489#endif 489#endif
490 bool car_adapter_mode; /* 0=off 1=on */ 490 bool car_adapter_mode; /* 0=off 1=on */
491#ifdef IPOD_ACCESSORY_PROTOCOL
492 int serial_bitrate; /* 0=auto 1=9600 2=19200 3=38400 4=57600 */
493#endif
491#ifdef HAVE_ACCESSORY_SUPPLY 494#ifdef HAVE_ACCESSORY_SUPPLY
492 bool accessory_supply; /* 0=off 1=on, accessory power supply for iPod */ 495 bool accessory_supply; /* 0=off 1=on, accessory power supply for iPod */
493#endif 496#endif
diff --git a/apps/settings_list.c b/apps/settings_list.c
index 27739b29c9..e3874566ac 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -49,6 +49,9 @@
49#if CONFIG_TUNER 49#if CONFIG_TUNER
50#include "radio.h" 50#include "radio.h"
51#endif 51#endif
52#ifdef IPOD_ACCESSORY_PROTOCOL
53#include "iap.h"
54#endif
52 55
53#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT) 56#define NVRAM(bytes) (bytes<<F_NVRAM_MASK_SHIFT)
54/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h 57/** NOTE: NVRAM_CONFIG_VERSION is in settings_list.h
@@ -595,6 +598,12 @@ const struct settings_list settings[] = {
595 OFFON_SETTING(NVRAM(1), car_adapter_mode, 598 OFFON_SETTING(NVRAM(1), car_adapter_mode,
596 LANG_CAR_ADAPTER_MODE, false, "car adapter mode", NULL), 599 LANG_CAR_ADAPTER_MODE, false, "car adapter mode", NULL),
597#endif 600#endif
601#ifdef IPOD_ACCESSORY_PROTOCOL
602 CHOICE_SETTING(0, serial_bitrate, LANG_SERIAL_BITRATE, 0, "serial bitrate",
603 "auto,9600,19200,38400,57600", iap_bitrate_set, 5, ID2P(LANG_SERIAL_BITRATE_AUTO),
604 ID2P(LANG_SERIAL_BITRATE_9600),ID2P(LANG_SERIAL_BITRATE_19200),
605 ID2P(LANG_SERIAL_BITRATE_38400),ID2P(LANG_SERIAL_BITRATE_57600)),
606#endif
598#ifdef HAVE_ACCESSORY_SUPPLY 607#ifdef HAVE_ACCESSORY_SUPPLY
599 OFFON_SETTING(0, accessory_supply, LANG_ACCESSORY_SUPPLY, 608 OFFON_SETTING(0, accessory_supply, LANG_ACCESSORY_SUPPLY,
600 true, "accessory power supply", accessory_supply_set), 609 true, "accessory power supply", accessory_supply_set),