diff options
author | Laurent Gautier <creposucre@rockbox.org> | 2009-12-01 17:54:40 +0000 |
---|---|---|
committer | Laurent Gautier <creposucre@rockbox.org> | 2009-12-01 17:54:40 +0000 |
commit | 0260852771aef7a6e9045684f0c3d0d7e01909f7 (patch) | |
tree | 6fa4b42230d1289857f84405defad94cc2de86b8 /apps/iap.c | |
parent | 63d79148fd07aebd2b425c0414b7b9622b312399 (diff) | |
download | rockbox-0260852771aef7a6e9045684f0c3d0d7e01909f7.tar.gz rockbox-0260852771aef7a6e9045684f0c3d0d7e01909f7.zip |
Add support for the ipod FM remote to the 4G, Color, 5G, nano 1G with RDS
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23805 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/iap.c')
-rw-r--r-- | apps/iap.c | 208 |
1 files changed, 174 insertions, 34 deletions
diff --git a/apps/iap.c b/apps/iap.c index 29cee22ab5..741ff9fb0c 100644 --- a/apps/iap.c +++ b/apps/iap.c | |||
@@ -37,11 +37,12 @@ | |||
37 | #include "settings.h" | 37 | #include "settings.h" |
38 | #include "metadata.h" | 38 | #include "metadata.h" |
39 | #include "wps.h" | 39 | #include "wps.h" |
40 | 40 | #include "sound.h" | |
41 | #include "action.h" | 41 | #include "action.h" |
42 | #include "powermgmt.h" | ||
42 | 43 | ||
43 | #define RX_BUFLEN 260 | 44 | #include "tuner.h" |
44 | #define TX_BUFLEN 128 | 45 | #include "ipod_remote_tuner.h" |
45 | 46 | ||
46 | static volatile int iap_pollspeed = 0; | 47 | static volatile int iap_pollspeed = 0; |
47 | static volatile bool iap_remotetick = true; | 48 | static volatile bool iap_remotetick = true; |
@@ -115,7 +116,7 @@ void iap_bitrate_set(int ratenum) | |||
115 | checksum (length+mode+parameters+checksum == 0) | 116 | checksum (length+mode+parameters+checksum == 0) |
116 | */ | 117 | */ |
117 | 118 | ||
118 | static void iap_send_pkt(const unsigned char * data, int len) | 119 | void iap_send_pkt(const unsigned char * data, int len) |
119 | { | 120 | { |
120 | int i, chksum; | 121 | int i, chksum; |
121 | 122 | ||
@@ -192,15 +193,15 @@ void iap_periodic(void) | |||
192 | unsigned long time_elapsed = audio_current_track()->elapsed; | 193 | unsigned long time_elapsed = audio_current_track()->elapsed; |
193 | 194 | ||
194 | time_elapsed += wps_get_ff_rewind_count(); | 195 | time_elapsed += wps_get_ff_rewind_count(); |
195 | 196 | ||
196 | data[3] = 0x04; // playing | 197 | data[3] = 0x04; /* playing */ |
197 | 198 | ||
198 | /* If info has changed, don't flag it right away */ | 199 | /* If info has changed, don't flag it right away */ |
199 | if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2) | 200 | if(iap_changedctr && iap_changedctr++ >= iap_pollspeed * 2) |
200 | { | 201 | { |
201 | /* track info has changed */ | 202 | /* track info has changed */ |
202 | iap_changedctr = 0; | 203 | iap_changedctr = 0; |
203 | data[3] = 0x01; // 0x02 has same effect? | 204 | data[3] = 0x01; /* 0x02 has same effect? */ |
204 | iap_updateflag = true; | 205 | iap_updateflag = true; |
205 | } | 206 | } |
206 | 207 | ||
@@ -211,12 +212,19 @@ void iap_periodic(void) | |||
211 | iap_send_pkt(data, sizeof(data)); | 212 | iap_send_pkt(data, sizeof(data)); |
212 | } | 213 | } |
213 | 214 | ||
215 | void iap_set_remote_volume(void) | ||
216 | { | ||
217 | unsigned char data[] = {0x03, 0x0D, 0x04, 0x00, 0x00}; | ||
218 | data[4] = (char)((global_settings.volume+58) * 4); | ||
219 | iap_send_pkt(data, sizeof(data)); | ||
220 | } | ||
221 | |||
214 | void iap_handlepkt(void) | 222 | void iap_handlepkt(void) |
215 | { | 223 | { |
216 | 224 | ||
217 | if(!iap_setupflag) return; | 225 | if(!iap_setupflag) return; |
218 | if(serbuf[0] == 0) return; | 226 | if(serbuf[0] == 0) return; |
219 | 227 | ||
220 | /* if we are waiting for a remote button to go out, | 228 | /* if we are waiting for a remote button to go out, |
221 | delay the handling of the new packet */ | 229 | delay the handling of the new packet */ |
222 | if(!iap_remotetick) | 230 | if(!iap_remotetick) |
@@ -224,63 +232,140 @@ void iap_handlepkt(void) | |||
224 | queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0); | 232 | queue_post(&button_queue, SYS_IAP_HANDLEPKT, 0); |
225 | return; | 233 | return; |
226 | } | 234 | } |
227 | 235 | ||
228 | /* Handle Mode 0 */ | 236 | /* Handle Mode 0 */ |
229 | if (serbuf[1] == 0x00) | 237 | if (serbuf[1] == 0x00) |
230 | { | 238 | { |
231 | switch (serbuf[2]) | 239 | switch (serbuf[2]) |
232 | { | 240 | { |
233 | /* get model info */ | 241 | case 0x24: |
234 | case 0x0D: | ||
235 | { | 242 | { |
236 | unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10, | 243 | /* ipod video send this */ |
237 | 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00}; | 244 | unsigned char data[] = {0x00, 0x25, 0x00, 0x00, 0x00, |
245 | 0x00, 0x00, 0x00, 0x00,0x01}; | ||
238 | iap_send_pkt(data, sizeof(data)); | 246 | iap_send_pkt(data, sizeof(data)); |
239 | break; | 247 | break; |
240 | } | 248 | } |
241 | /* No idea ??? */ | 249 | |
242 | case 0x0F: | 250 | case 0x18: |
243 | { | 251 | { |
244 | unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05}; | 252 | /* ciphered authentication command */ |
245 | iap_send_pkt(data, sizeof(data)); | 253 | /* Isn't used since we don't send the 0x00 0x17 command */ |
246 | break; | 254 | break; |
247 | } | 255 | } |
248 | /* FM transmitter sends this: FF 55 06 00 01 05 00 02 01 F1 (mode switch) */ | 256 | |
249 | case 0x01: | 257 | case 0x15: |
250 | { | 258 | { |
251 | if(serbuf[3] == 0x05) | 259 | unsigned char data0[] = {0x00, 0x16, 0x00}; |
260 | iap_send_pkt(data0, sizeof(data0)); | ||
261 | unsigned char data1[] = {0x00, 0x27, 0x00}; | ||
262 | iap_send_pkt(data1, sizeof(data1)); | ||
263 | /* authentication ack, mandatory to enable some hardware */ | ||
264 | unsigned char data2[] = {0x00, 0x19, 0x00}; | ||
265 | iap_send_pkt(data2, sizeof(data2)); | ||
266 | if (radio_present == 1) | ||
252 | { | 267 | { |
253 | sleep(HZ/3); | 268 | /* get tuner capacities */ |
254 | unsigned char data[] = {0x05, 0x02}; | 269 | unsigned char data3[] = {0x07, 0x01}; |
255 | iap_send_pkt(data, sizeof(data)); | 270 | iap_send_pkt(data3, sizeof(data3)); |
256 | } | 271 | } |
272 | iap_set_remote_volume(); | ||
257 | break; | 273 | break; |
258 | } | 274 | } |
259 | /* FM transmitter sends this: FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (???)*/ | 275 | |
260 | case 0x13: | 276 | case 0x13: |
261 | { | 277 | { |
262 | unsigned char data[] = {0x00, 0x02, 0x00, 0x13}; | 278 | unsigned char data[] = {0x00, 0x02, 0x00, 0x13}; |
263 | iap_send_pkt(data, sizeof(data)); | 279 | iap_send_pkt(data, sizeof(data)); |
264 | unsigned char data2[] = {0x00, 0x27, 0x00}; | 280 | |
265 | iap_send_pkt(data2, sizeof(data2)); | 281 | if (serbuf[6] == 0x35) |
266 | unsigned char data3[] = {0x05, 0x02}; | 282 | /* FM transmitter sends this: */ |
267 | iap_send_pkt(data3, sizeof(data3)); | 283 | /* FF 55 0E 00 13 00 00 00 35 00 00 00 04 00 00 00 00 A6 (??)*/ |
284 | { | ||
285 | unsigned char data2[] = {0x00, 0x27, 0x00}; | ||
286 | iap_send_pkt(data2, sizeof(data2)); | ||
287 | unsigned char data3[] = {0x05, 0x02}; | ||
288 | iap_send_pkt(data3, sizeof(data3)); | ||
289 | } | ||
290 | |||
291 | else | ||
292 | { | ||
293 | /* ipod fm remote sends this: */ | ||
294 | /* FF 55 0E 00 13 00 00 00 8D 00 00 00 0E 00 00 00 03 41 */ | ||
295 | if (serbuf[6] |= 0x80) | ||
296 | radio_present = 1; | ||
297 | unsigned char data4[] = {0x00, 0x14}; | ||
298 | iap_send_pkt(data4, sizeof(data4)); | ||
299 | } | ||
268 | break; | 300 | break; |
269 | } | 301 | } |
270 | /* FM transmitter sends this: FF 55 02 00 05 F9 (mode switch: AiR mode) */ | 302 | |
303 | /* Init */ | ||
304 | case 0x0F: | ||
305 | { | ||
306 | unsigned char data[] = {0x00, 0x10, 0x00, 0x01, 0x05}; | ||
307 | data[2] = serbuf[3]; | ||
308 | iap_send_pkt(data, sizeof(data)); | ||
309 | break; | ||
310 | } | ||
311 | |||
312 | /* get model info */ | ||
313 | case 0x0D: | ||
314 | { | ||
315 | /* ipod is supposed to work only with 5G and nano 2G */ | ||
316 | /*{0x00, 0x0E, 0x00, 0x0B, 0x00, 0x05, 0x50, 0x41, 0x31, 0x34, | ||
317 | 0x37, 0x4C, 0x4C, 0x00}; PA147LL (IPOD 5G 60 GO) */ | ||
318 | unsigned char data[] = {0x00, 0x0E, 0x00, 0x0B, 0x00, 0x10, | ||
319 | 'R', 'O', 'C', 'K', 'B', 'O', 'X', 0x00}; | ||
320 | iap_send_pkt(data, sizeof(data)); | ||
321 | break; | ||
322 | } | ||
323 | |||
324 | /* Ipod FM remote sends this: FF 55 02 00 09 F5 */ | ||
325 | case 0x09: | ||
326 | { | ||
327 | /* ipod5G firmware version */ | ||
328 | unsigned char data[] = {0x00, 0x0A, 0x01, 0x02, 0x01 }; | ||
329 | iap_send_pkt(data, sizeof(data)); | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | /* FM transmitter sends this: */ | ||
334 | /* FF 55 02 00 05 F9 (mode switch: AiR mode) */ | ||
271 | case 0x05: | 335 | case 0x05: |
272 | { | 336 | { |
273 | unsigned char data[] = {0x00, 0x02, 0x06, 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28}; | 337 | unsigned char data[] = {0x00, 0x02, 0x06, |
338 | 0x05, 0x00, 0x00, 0x0B, 0xB8, 0x28}; | ||
274 | iap_send_pkt(data, sizeof(data)); | 339 | iap_send_pkt(data, sizeof(data)); |
275 | unsigned char data2[] = {0x00, 0x02, 0x00, 0x05}; | 340 | unsigned char data2[] = {0x00, 0x02, 0x00, 0x05}; |
276 | iap_send_pkt(data2, sizeof(data2)); | 341 | iap_send_pkt(data2, sizeof(data2)); |
277 | break; | 342 | break; |
278 | } | 343 | } |
344 | |||
345 | case 0x01: | ||
346 | { | ||
347 | /* FM transmitter sends this: */ | ||
348 | /* FF 55 06 00 01 05 00 02 01 F1 (mode switch) */ | ||
349 | if(serbuf[3] == 0x05) | ||
350 | { | ||
351 | sleep(HZ/3); | ||
352 | unsigned char data[] = {0x05, 0x02}; | ||
353 | iap_send_pkt(data, sizeof(data)); | ||
354 | } | ||
355 | /* FM remote sends this: */ | ||
356 | /* FF 55 03 00 01 02 FA (1st thing sent) */ | ||
357 | else if(serbuf[3] == 0x02) | ||
358 | { | ||
359 | /* useful only for apple firmware */ | ||
360 | } | ||
361 | break; | ||
362 | } | ||
363 | |||
279 | /* default response is with cmd ok packet */ | 364 | /* default response is with cmd ok packet */ |
280 | default: | 365 | default: |
281 | { | 366 | { |
282 | unsigned char data[] = {0x00, 0x02, 0x00, 0x00}; | 367 | unsigned char data[] = {0x00, 0x02, 0x00, 0x00}; |
283 | data[3] = serbuf[2]; //respond with cmd | 368 | data[3] = serbuf[2]; /* respond with cmd */ |
284 | iap_send_pkt(data, sizeof(data)); | 369 | iap_send_pkt(data, sizeof(data)); |
285 | break; | 370 | break; |
286 | } | 371 | } |
@@ -395,6 +480,30 @@ void iap_handlepkt(void) | |||
395 | iap_send_pkt(data, sizeof(data)); | 480 | iap_send_pkt(data, sizeof(data)); |
396 | break; | 481 | break; |
397 | } | 482 | } |
483 | |||
484 | case 0x08: | ||
485 | { | ||
486 | /* ACK */ | ||
487 | unsigned char data[] = {0x03, 0x00, 0x00, 0x08}; | ||
488 | iap_send_pkt(data, sizeof(data)); | ||
489 | break; | ||
490 | } | ||
491 | |||
492 | case 0x0C: | ||
493 | { | ||
494 | /* request ipod volume */ | ||
495 | if (serbuf[3] == 0x04) | ||
496 | { | ||
497 | iap_set_remote_volume(); | ||
498 | } | ||
499 | break; | ||
500 | } | ||
501 | /* get volume from accessory */ | ||
502 | case 0x0E: | ||
503 | if (serbuf[3] == 0x04) | ||
504 | global_settings.volume = (-58)+((int)serbuf[5]+1)/4; | ||
505 | sound_set_volume(global_settings.volume); | ||
506 | break; | ||
398 | } | 507 | } |
399 | } | 508 | } |
400 | /* Handle Mode 4 */ | 509 | /* Handle Mode 4 */ |
@@ -712,6 +821,37 @@ void iap_handlepkt(void) | |||
712 | } | 821 | } |
713 | } | 822 | } |
714 | } | 823 | } |
824 | /* Handle Mode 7 */ | ||
825 | else if (serbuf[1] == 0x07) | ||
826 | { | ||
827 | switch(serbuf[2]) | ||
828 | { | ||
829 | /* tuner capabilities */ | ||
830 | case 0x02: | ||
831 | { | ||
832 | /* do nothing */ | ||
833 | |||
834 | unsigned char data[] = {0x00, 0x27, 0x00}; | ||
835 | iap_send_pkt(data, sizeof(data)); | ||
836 | break; | ||
837 | } | ||
838 | /* actual tuner frequency */ | ||
839 | case 0x0A: | ||
840 | /* fall through */ | ||
841 | /* tuner frequency from scan */ | ||
842 | case 0x13: | ||
843 | { | ||
844 | rmt_tuner_freq(); | ||
845 | break; | ||
846 | } | ||
847 | /* RDS station name 0x21 1E 00 + ASCII text*/ | ||
848 | case 0x21: | ||
849 | { | ||
850 | rmt_tuner_rds_data(); | ||
851 | break; | ||
852 | } | ||
853 | } | ||
854 | } | ||
715 | serbuf[0] = 0; | 855 | serbuf[0] = 0; |
716 | } | 856 | } |
717 | 857 | ||