diff options
author | Ralf Ertzinger <rockbox@camperquake.de> | 2013-06-22 10:08:23 +0100 |
---|---|---|
committer | Frank Gevaerts <frank@gevaerts.be> | 2013-11-10 18:41:24 +0100 |
commit | b170c73f922e3457b923b4e7fcbec794a8885c77 (patch) | |
tree | 89fbdbd8c25af5101a29a1ede3b896332a4e205c /tools/iap/iap-verbose.pl | |
parent | 500b137308a6ee5c2aba873734a8956d70472f56 (diff) | |
download | rockbox-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 'tools/iap/iap-verbose.pl')
-rw-r--r-- | tools/iap/iap-verbose.pl | 1856 |
1 files changed, 1856 insertions, 0 deletions
diff --git a/tools/iap/iap-verbose.pl b/tools/iap/iap-verbose.pl new file mode 100644 index 0000000000..ed25de7548 --- /dev/null +++ b/tools/iap/iap-verbose.pl | |||
@@ -0,0 +1,1856 @@ | |||
1 | #!/usr/bin/perl -w | ||
2 | |||
3 | package iap::decode; | ||
4 | |||
5 | use Device::iPod; | ||
6 | use Data::Dumper; | ||
7 | use strict; | ||
8 | |||
9 | sub new { | ||
10 | my $class = shift; | ||
11 | my $self = {-state => {}}; | ||
12 | |||
13 | return bless($self, $class); | ||
14 | } | ||
15 | |||
16 | sub display { | ||
17 | my $self = shift; | ||
18 | my $lingo = shift; | ||
19 | my $command = shift; | ||
20 | my $data = shift; | ||
21 | my $name; | ||
22 | my $handler; | ||
23 | my $r; | ||
24 | |||
25 | |||
26 | $name = sprintf("_h_%02x_%04x", $lingo, $command); | ||
27 | $handler = $self->can($name); | ||
28 | if ($handler) { | ||
29 | unless(exists($self->{-state}->{$name})) { | ||
30 | $self->{-state}->{$name} = {}; | ||
31 | } | ||
32 | $r = $handler->($self, $data, $self->{-state}->{$name}); | ||
33 | } else { | ||
34 | $r = $self->generic($lingo, $command, $data); | ||
35 | } | ||
36 | |||
37 | printf("\n"); | ||
38 | return $r; | ||
39 | } | ||
40 | |||
41 | sub generic { | ||
42 | my $self = shift; | ||
43 | my $lingo = shift; | ||
44 | my $command = shift; | ||
45 | my $data = shift; | ||
46 | |||
47 | printf("Unknown command\n"); | ||
48 | printf(" Lingo: 0x%02x\n", $lingo); | ||
49 | printf(" Command 0x%04x\n", $command); | ||
50 | printf(" Data: %s\n", Device::iPod->_hexstring($data)); | ||
51 | |||
52 | exit(1); | ||
53 | |||
54 | return 1; | ||
55 | } | ||
56 | |||
57 | sub _h_00_0001 { | ||
58 | my $self = shift; | ||
59 | my $data = shift; | ||
60 | my $state = shift; | ||
61 | my $lingo = shift; | ||
62 | |||
63 | $lingo = unpack("C", $data); | ||
64 | |||
65 | printf("Identify (0x00, 0x01) D->I\n"); | ||
66 | printf(" Lingo: 0x%02x\n", $lingo); | ||
67 | |||
68 | return 1; | ||
69 | } | ||
70 | |||
71 | sub _h_00_0002 { | ||
72 | my $self = shift; | ||
73 | my $data = shift; | ||
74 | my $state = shift; | ||
75 | my $res; | ||
76 | my $cmd; | ||
77 | my $delay; | ||
78 | |||
79 | ($res, $cmd, $delay) = unpack("CCN", $data); | ||
80 | |||
81 | printf("ACK (0x00, 0x02) I->D\n"); | ||
82 | printf(" Acknowledged command: 0x%02x\n", $cmd); | ||
83 | printf(" Status: %s (%d)\n", | ||
84 | ("Success", | ||
85 | "ERROR: Unknown Database Category", | ||
86 | "ERROR: Command Failed", | ||
87 | "ERROR: Out Of Resource", | ||
88 | "ERROR: Bad Parameter", | ||
89 | "ERROR: Unknown ID", | ||
90 | "Command Pending", | ||
91 | "ERROR: Not Authenticated", | ||
92 | "ERROR: Bad Authentication Version", | ||
93 | "ERROR: Accessory Power Mode Request Failed", | ||
94 | "ERROR: Certificate Invalid", | ||
95 | "ERROR: Certificate permissions invalid", | ||
96 | "ERROR: File is in use", | ||
97 | "ERROR: Invalid file handle", | ||
98 | "ERROR: Directory not empty", | ||
99 | "ERROR: Operation timed out", | ||
100 | "ERROR: Command unavailable in this iPod mode", | ||
101 | "ERROR: Invalid accessory resistor ID", | ||
102 | "Reserved", | ||
103 | "Reserved", | ||
104 | "Reserved", | ||
105 | "ERROR: Maximum number of accessory connections already reached")[$res], $res); | ||
106 | if ($res == 6) { | ||
107 | $delay = unpack("xxN", $data); | ||
108 | printf(" Delay: %d ms\n", $delay); | ||
109 | } | ||
110 | |||
111 | return 1; | ||
112 | } | ||
113 | |||
114 | sub _h_00_0005 { | ||
115 | my $self = shift; | ||
116 | my $data = shift; | ||
117 | my $state = shift; | ||
118 | |||
119 | printf("EnterRemoteUIMode (0x00, 0x05) D->I\n"); | ||
120 | |||
121 | return 1; | ||
122 | } | ||
123 | |||
124 | sub _h_00_000d { | ||
125 | my $self = shift; | ||
126 | my $data = shift; | ||
127 | my $state = shift; | ||
128 | |||
129 | printf("RequestiPodModelNum (0x00, 0x0D) D->I\n"); | ||
130 | |||
131 | return 1; | ||
132 | } | ||
133 | |||
134 | sub _h_00_000e { | ||
135 | my $self = shift; | ||
136 | my $data = shift; | ||
137 | my $state = shift; | ||
138 | my ($modelnum, $name); | ||
139 | |||
140 | ($modelnum, $name) = unpack("NZ*", $data); | ||
141 | |||
142 | printf("ReturniPodModelNum (0x00, 0x0E) I->D\n"); | ||
143 | printf(" Model number: %08x\n", $modelnum); | ||
144 | printf(" Model name: %s\n", $name); | ||
145 | |||
146 | return 1; | ||
147 | } | ||
148 | |||
149 | sub _h_00_000f { | ||
150 | my $self = shift; | ||
151 | my $data = shift; | ||
152 | my $state = shift; | ||
153 | my $lingo; | ||
154 | |||
155 | $lingo = unpack("C", $data); | ||
156 | |||
157 | printf("RequestLingoProtocolVersion (0x00, 0x0F) D->I\n"); | ||
158 | printf(" Lingo: 0x%02x\n", $lingo); | ||
159 | |||
160 | return 1; | ||
161 | } | ||
162 | |||
163 | sub _h_00_0010 { | ||
164 | my $self = shift; | ||
165 | my $data = shift; | ||
166 | my $state = shift; | ||
167 | my ($lingo, $maj, $min); | ||
168 | |||
169 | ($lingo, $maj, $min) = unpack("CCC", $data); | ||
170 | |||
171 | printf("ReturnLingoProtocolVersion (0x00, 0x10) I->D\n"); | ||
172 | printf(" Lingo: 0x%02x\n", $lingo); | ||
173 | printf(" Version: %d.%02d\n", $maj, $min); | ||
174 | |||
175 | return 1; | ||
176 | } | ||
177 | |||
178 | |||
179 | sub _h_00_0013 { | ||
180 | my $self = shift; | ||
181 | my $data = shift; | ||
182 | my $state = shift; | ||
183 | my @lingolist; | ||
184 | my ($lingoes, $options, $devid); | ||
185 | |||
186 | ($lingoes, $options, $devid) = unpack("N3", $data); | ||
187 | |||
188 | foreach (0..31) { | ||
189 | push(@lingolist, $_) if ($lingoes & (1 << $_)); | ||
190 | } | ||
191 | |||
192 | printf("IdentifyDeviceLingoes (0x00, 0x13) D->I\n"); | ||
193 | printf(" Supported lingoes: %s\n", join(", ", @lingolist)); | ||
194 | printf(" Options:\n"); | ||
195 | printf(" Authentication: %s\n", ("None", "Defer (1.0)", "Immediate (2.0)", "Reserved")[$options & 0x03]); | ||
196 | printf(" Power: %s\n", ("Low", "Intermittent high", "Reserved", "Constant high")[($options & 0x0C) >> 2]); | ||
197 | printf(" Device ID: 0x%08x\n", $devid); | ||
198 | |||
199 | delete($self->{-state}->{'_h_00_0015'}); | ||
200 | |||
201 | return 1; | ||
202 | } | ||
203 | |||
204 | sub _h_00_0014 { | ||
205 | my $self = shift; | ||
206 | my $data = shift; | ||
207 | my $state = shift; | ||
208 | |||
209 | printf("GetDevAuthenticationInfo (0x00, 0x14) I->D\n"); | ||
210 | |||
211 | return 1; | ||
212 | } | ||
213 | |||
214 | sub _h_00_0015 { | ||
215 | my $self = shift; | ||
216 | my $data = shift; | ||
217 | my $state = shift; | ||
218 | my ($amaj, $amin, $curidx, $maxidx, $certdata); | ||
219 | |||
220 | $state->{-curidx} = -1 unless(exists($state->{-curidx})); | ||
221 | $state->{-maxidx} = -1 unless(exists($state->{-maxidx})); | ||
222 | $state->{-cert} = '' unless(exists($state->{-cert})); | ||
223 | |||
224 | ($amaj, $amin, $curidx, $maxidx, $certdata) = unpack("CCCCa*", $data); | ||
225 | |||
226 | printf("RetDevAuthenticationInfo (0x00, 0x15) D->I\n"); | ||
227 | printf(" Authentication version: %d.%d\n", $amaj, $amin); | ||
228 | printf(" Segment: %d of %d\n", $curidx, $maxidx); | ||
229 | |||
230 | if ($curidx-1 != $state->{-curidx}) { | ||
231 | printf(" WARNING! Out of order segment\n"); | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | if (($maxidx != $state->{-maxidx}) && ($state->{-maxidx} != -1)) { | ||
236 | printf(" WARNING! maxidx changed midstream\n"); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | if ($curidx > $maxidx) { | ||
241 | printf(" WARNING! Too many segments\n"); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | $state->{-curidx} = $curidx; | ||
246 | $state->{-maxidx} = $maxidx; | ||
247 | $state->{-cert} .= $certdata; | ||
248 | |||
249 | if ($curidx == $maxidx) { | ||
250 | printf(" Certificate: %s\n", Device::iPod->_hexstring($state->{-cert})); | ||
251 | } | ||
252 | |||
253 | return 1; | ||
254 | } | ||
255 | |||
256 | sub _h_00_0016 { | ||
257 | my $self = shift; | ||
258 | my $data = shift; | ||
259 | my $state = shift; | ||
260 | my $res; | ||
261 | |||
262 | $res = unpack("C", $data); | ||
263 | |||
264 | printf("AckDevAuthenticationInfo (0x00, 0x16) I->D\n"); | ||
265 | printf(" Result: "); | ||
266 | if ($res == 0x00) { | ||
267 | printf("Authentication information supported\n"); | ||
268 | } elsif ($res == 0x08) { | ||
269 | printf("Authentication information unpported\n"); | ||
270 | } elsif ($res == 0x0A) { | ||
271 | printf("Certificate invalid\n"); | ||
272 | } elsif ($res == 0x0B) { | ||
273 | printf("Certificate permissions are invalid\n"); | ||
274 | } else { | ||
275 | printf("Unknown result 0x%02x\n", $res); | ||
276 | } | ||
277 | |||
278 | return 1; | ||
279 | } | ||
280 | |||
281 | sub _h_00_0017 { | ||
282 | my $self = shift; | ||
283 | my $data = shift; | ||
284 | my $state = shift; | ||
285 | my ($challenge, $retry); | ||
286 | |||
287 | printf("GetDevAuthenticationSignature (0x00, 0x17) I->D\n"); | ||
288 | |||
289 | if (length($data) == 17) { | ||
290 | ($challenge, $retry) = unpack("a16C", $data); | ||
291 | } elsif (length($data) == 21) { | ||
292 | ($challenge, $retry) = unpack("a20C", $data); | ||
293 | } else { | ||
294 | printf(" WARNING! Unsupported data length: %d\n", length($data)); | ||
295 | return 0; | ||
296 | } | ||
297 | |||
298 | printf(" Challenge: %s (%d bytes)\n", Device::iPod->_hexstring($challenge), length($challenge)); | ||
299 | printf(" Retry counter: %d\n", $retry); | ||
300 | |||
301 | return 1; | ||
302 | } | ||
303 | |||
304 | sub _h_00_0018 { | ||
305 | my $self = shift; | ||
306 | my $data = shift; | ||
307 | my $state = shift; | ||
308 | my $reply; | ||
309 | |||
310 | printf("RetDevAuthenticationSignature (0x00, 0x18) D->I\n"); | ||
311 | printf(" Data: %s\n", Device::iPod->_hexstring($data)); | ||
312 | |||
313 | return 1; | ||
314 | } | ||
315 | |||
316 | sub _h_00_0019 { | ||
317 | my $self = shift; | ||
318 | my $data = shift; | ||
319 | my $state = shift; | ||
320 | my $res; | ||
321 | |||
322 | $res = unpack("C", $data); | ||
323 | |||
324 | printf("AckiPodAuthenticationInfo (0x00, 0x19) I->D\n"); | ||
325 | printf(" Status: %s (%d)\n", ( | ||
326 | "OK")[$res], $res); | ||
327 | |||
328 | return 1; | ||
329 | } | ||
330 | |||
331 | sub _h_00_0024 { | ||
332 | my $self = shift; | ||
333 | my $data = shift; | ||
334 | my $state = shift; | ||
335 | |||
336 | printf("GetiPodOptions (0x00, 0x24) D->I\n"); | ||
337 | |||
338 | return 1; | ||
339 | } | ||
340 | |||
341 | sub _h_00_0025 { | ||
342 | my $self = shift; | ||
343 | my $data = shift; | ||
344 | my $state = shift; | ||
345 | my ($ophi, $oplo); | ||
346 | |||
347 | ($ophi, $oplo) = unpack("NN", $data); | ||
348 | |||
349 | printf("RetiPodOptions (0x00, 0x25) I->D\n"); | ||
350 | printf(" Options:\n"); | ||
351 | printf(" iPod supports SetiPodPreferences\n") if ($oplo & 0x02); | ||
352 | printf(" iPod supports video\n") if ($oplo & 0x01); | ||
353 | |||
354 | return 1; | ||
355 | } | ||
356 | |||
357 | |||
358 | sub _h_00_0027 { | ||
359 | my $self = shift; | ||
360 | my $data = shift; | ||
361 | my $state = shift; | ||
362 | my $acctype; | ||
363 | my $accparam; | ||
364 | |||
365 | $acctype = unpack("C", $data); | ||
366 | |||
367 | printf("GetAccessoryInfo (0x00, 0x27) I->D\n"); | ||
368 | printf(" Accessory Info Type: %s (%d)\n", ( | ||
369 | "Info capabilities", | ||
370 | "Name", | ||
371 | "Minimum supported iPod firmware version", | ||
372 | "Minimum supported lingo version", | ||
373 | "Firmware version", | ||
374 | "Hardware version", | ||
375 | "Manufacturer", | ||
376 | "Model Number", | ||
377 | "Serial Number", | ||
378 | "Maximum payload size")[$acctype], $acctype); | ||
379 | if ($acctype == 0x02) { | ||
380 | my ($modelid, $maj, $min, $rev); | ||
381 | |||
382 | ($modelid, $maj, $min, $rev) = unpack("xNCCC", $data); | ||
383 | printf(" Model ID: 0x%04x\n", $modelid); | ||
384 | printf(" iPod Firmware: %d.%d.%d\n", $maj, $min, $rev); | ||
385 | } elsif ($acctype == 0x03) { | ||
386 | my $lingo; | ||
387 | |||
388 | $lingo = unpack("xC", $data); | ||
389 | printf(" Lingo: 0x%02x\n", $lingo); | ||
390 | } | ||
391 | |||
392 | return 1; | ||
393 | } | ||
394 | |||
395 | sub _h_00_0028 { | ||
396 | my $self = shift; | ||
397 | my $data = shift; | ||
398 | my $state = shift; | ||
399 | my $acctype; | ||
400 | my $accparam; | ||
401 | |||
402 | $acctype = unpack("C", $data); | ||
403 | |||
404 | printf("RetAccessoryInfo (0x00, 0x28) D->I\n"); | ||
405 | printf(" Accessory Info Type: %s (%d)\n", ( | ||
406 | "Info capabilities", | ||
407 | "Name", | ||
408 | "Minimum supported iPod firmware version", | ||
409 | "Minimum supported lingo version", | ||
410 | "Firmware version", | ||
411 | "Hardware version", | ||
412 | "Manufacturer", | ||
413 | "Model Number", | ||
414 | "Serial Number", | ||
415 | "Maximum payload size")[$acctype], $acctype); | ||
416 | |||
417 | if ($acctype == 0x00) { | ||
418 | $accparam = unpack("xN", $data); | ||
419 | printf(" Accessory Info capabilities\n") if ($accparam & 0x01); | ||
420 | printf(" Accessory name\n") if ($accparam & 0x02); | ||
421 | printf(" Accessory minimum supported iPod firmware\n") if ($accparam & 0x04); | ||
422 | printf(" Accessory minimum supported lingo version\n") if ($accparam & 0x08); | ||
423 | printf(" Accessory firmware version\n") if ($accparam & 0x10); | ||
424 | printf(" Accessory hardware version\n") if ($accparam & 0x20); | ||
425 | printf(" Accessory manufacturer\n") if ($accparam & 0x40); | ||
426 | printf(" Accessory model number\n") if ($accparam & 0x80); | ||
427 | printf(" Accessory serial number\n") if ($accparam & 0x100); | ||
428 | printf(" Accessory incoming max packet size\n") if ($accparam & 0x200); | ||
429 | } | ||
430 | |||
431 | if ($acctype ~~ [0x01, 0x06, 0x07, 0x08]) { | ||
432 | $accparam = unpack("xZ*", $data); | ||
433 | printf(" Data: %s\n", $accparam); | ||
434 | } | ||
435 | |||
436 | if ($acctype == 0x02) { | ||
437 | $accparam = [ unpack("xNCCC", $data) ]; | ||
438 | printf(" Model ID: %08x\n", $accparam->[0]); | ||
439 | printf(" Firmware version: %d.%02d.%02d\n", $accparam->[1], $accparam->[2], $accparam->[3]); | ||
440 | } | ||
441 | |||
442 | if ($acctype == 0x03) { | ||
443 | $accparam = [ unpack("xCCC", $data) ]; | ||
444 | printf(" Lingo: %02x\n", $accparam->[0]); | ||
445 | printf(" Version: %d.%02d\n", $accparam->[1], $accparam->[2]); | ||
446 | } | ||
447 | |||
448 | if ($acctype ~~ [0x04, 0x05]) { | ||
449 | $accparam = [ unpack("xCCC", $data) ]; | ||
450 | printf(" Version: %d.%02d.%02d\n", @{$accparam}); | ||
451 | } | ||
452 | |||
453 | return 1; | ||
454 | } | ||
455 | |||
456 | sub _h_00_0029 { | ||
457 | my $self = shift; | ||
458 | my $data = shift; | ||
459 | my $state = shift; | ||
460 | my $class; | ||
461 | |||
462 | $class = unpack("C", $data); | ||
463 | |||
464 | printf("GetiPodPreferences (0x00, 0x29) D->I\n"); | ||
465 | printf(" Class: %s (%d)\n", ( | ||
466 | "Video out setting", | ||
467 | "Screen configuration", | ||
468 | "Video signal format", | ||
469 | "Line Out usage", | ||
470 | "(Reserved)", | ||
471 | "(Reserved)", | ||
472 | "(Reserved)", | ||
473 | "(Reserved)", | ||
474 | "Video out connection", | ||
475 | "Closed captioning", | ||
476 | "Video aspect ratio", | ||
477 | "(Reserved)", | ||
478 | "Subtitles", | ||
479 | "Video alternate audio channel")[$class], $class); | ||
480 | |||
481 | return 1; | ||
482 | } | ||
483 | |||
484 | sub _h_00_002b { | ||
485 | my $self = shift; | ||
486 | my $data = shift; | ||
487 | my $state = shift; | ||
488 | my ($class, $setting); | ||
489 | |||
490 | ($class, $setting) = unpack("CC", $data); | ||
491 | |||
492 | printf("SetiPodPreferences (0x00, 0x2B) D->I\n"); | ||
493 | printf(" Class: %s (%d)\n", ( | ||
494 | "Video out setting", | ||
495 | "Screen configuration", | ||
496 | "Video signal format", | ||
497 | "Line out usage", | ||
498 | "Reserved", | ||
499 | "Reserved", | ||
500 | "Reserved", | ||
501 | "Reserved", | ||
502 | "Video-out connection", | ||
503 | "Closed captioning", | ||
504 | "Video monitor aspect ratio", | ||
505 | "Reserved", | ||
506 | "Subtitles", | ||
507 | "Video alternate audio channel")[$class], $class); | ||
508 | printf(" Setting: %s (%d)\n", ( | ||
509 | ["Off", | ||
510 | "On", | ||
511 | "Ask user"], | ||
512 | ["Fill screen", | ||
513 | "Fit to screen edge"], | ||
514 | ["NTSC", | ||
515 | "PAL"], | ||
516 | ["Not used", | ||
517 | "Used"], | ||
518 | [], | ||
519 | [], | ||
520 | [], | ||
521 | [], | ||
522 | ["None", | ||
523 | "Composite", | ||
524 | "S-video", | ||
525 | "Component"], | ||
526 | ["Off", | ||
527 | "On"], | ||
528 | ["4:3", | ||
529 | "16:9"], | ||
530 | [], | ||
531 | ["Off", | ||
532 | "On"], | ||
533 | ["Off", | ||
534 | "On"])[$class][$setting], $setting); | ||
535 | |||
536 | return 1; | ||
537 | } | ||
538 | |||
539 | sub _h_00_0038 { | ||
540 | my $self = shift; | ||
541 | my $data = shift; | ||
542 | my $state = shift; | ||
543 | my $transid; | ||
544 | |||
545 | $transid = unpack("n", $data); | ||
546 | |||
547 | printf("StartIDPS (0x00, 0x38) D->I\n"); | ||
548 | printf(" TransID: %d\n", $transid); | ||
549 | |||
550 | return 1; | ||
551 | } | ||
552 | |||
553 | sub _h_00_003b { | ||
554 | my $self = shift; | ||
555 | my $data = shift; | ||
556 | my $state = shift; | ||
557 | my ($transid, $status); | ||
558 | |||
559 | ($transid, $status) = unpack("nC", $data); | ||
560 | |||
561 | printf("EndIDPS (0x00, 0x3B) D->I\n"); | ||
562 | printf(" TransID: %d\n", $transid); | ||
563 | printf(" Action: %s (%d)\n", ( | ||
564 | "Finished", | ||
565 | "Reset")[$status], $status); | ||
566 | |||
567 | return 1; | ||
568 | } | ||
569 | |||
570 | sub _h_00_004b { | ||
571 | my $self = shift; | ||
572 | my $data = shift; | ||
573 | my $state = shift; | ||
574 | my $lingo; | ||
575 | |||
576 | $lingo = unpack("C", $data); | ||
577 | |||
578 | printf("GetiPodOptionsForLingo (0x00, 0x4B) D->I\n"); | ||
579 | printf(" Lingo: 0x%02x\n", $lingo); | ||
580 | |||
581 | return 1; | ||
582 | } | ||
583 | |||
584 | sub _h_02_0000 { | ||
585 | my $self = shift; | ||
586 | my $data = shift; | ||
587 | my $state = shift; | ||
588 | my @keys; | ||
589 | |||
590 | @keys = unpack("CCCC", $data); | ||
591 | |||
592 | printf("ContextButtonStatus (0x02, 0x00) D->I\n"); | ||
593 | printf(" Buttons:\n"); | ||
594 | printf(" Play/Pause\n") if ($keys[0] & 0x01); | ||
595 | printf(" Volume Up\n") if ($keys[0] & 0x02); | ||
596 | printf(" Volume Down\n") if ($keys[0] & 0x04); | ||
597 | printf(" Next Track\n") if ($keys[0] & 0x08); | ||
598 | printf(" Previous Track\n") if ($keys[0] & 0x10); | ||
599 | printf(" Next Album\n") if ($keys[0] & 0x20); | ||
600 | printf(" Previous Album\n") if ($keys[0] & 0x40); | ||
601 | printf(" Stop\n") if ($keys[0] & 0x80); | ||
602 | |||
603 | if (exists($keys[1])) { | ||
604 | printf(" Play/Resume\n") if ($keys[1] & 0x01); | ||
605 | printf(" Pause\n") if ($keys[1] & 0x02); | ||
606 | printf(" Mute toggle\n") if ($keys[1] & 0x04); | ||
607 | printf(" Next Chapter\n") if ($keys[1] & 0x08); | ||
608 | printf(" Previous Chapter\n") if ($keys[1] & 0x10); | ||
609 | printf(" Next Playlist\n") if ($keys[1] & 0x20); | ||
610 | printf(" Previous Playlist\n") if ($keys[1] & 0x40); | ||
611 | printf(" Shuffle Setting Advance\n") if ($keys[1] & 0x80); | ||
612 | } | ||
613 | |||
614 | if (exists($keys[2])) { | ||
615 | printf(" Repeat Setting Advance\n") if ($keys[2] & 0x01); | ||
616 | printf(" Power On\n") if ($keys[2] & 0x02); | ||
617 | printf(" Power Off\n") if ($keys[2] & 0x04); | ||
618 | printf(" Backlight for 30 seconds\n") if ($keys[2] & 0x08); | ||
619 | printf(" Begin FF\n") if ($keys[2] & 0x10); | ||
620 | printf(" Begin REW\n") if ($keys[2] & 0x20); | ||
621 | printf(" Menu\n") if ($keys[2] & 0x40); | ||
622 | printf(" Select\n") if ($keys[2] & 0x80); | ||
623 | } | ||
624 | |||
625 | if (exists($keys[3])) { | ||
626 | printf(" Up Arrow\n") if ($keys[3] & 0x01); | ||
627 | printf(" Down Arrow\n") if ($keys[3] & 0x02); | ||
628 | printf(" Backlight off\n") if ($keys[3] & 0x04); | ||
629 | } | ||
630 | |||
631 | return 1; | ||
632 | } | ||
633 | |||
634 | sub _h_02_0001 { | ||
635 | my $self = shift; | ||
636 | my $data = shift; | ||
637 | my $state = shift; | ||
638 | my $res; | ||
639 | my $cmd; | ||
640 | |||
641 | ($res, $cmd) = unpack("CC", $data); | ||
642 | |||
643 | printf("ACK (0x02, 0x01) I->D\n"); | ||
644 | printf(" Acknowledged command: 0x%02x\n", $cmd); | ||
645 | printf(" Status: %s (%d)\n", | ||
646 | ("Success", | ||
647 | "ERROR: Unknown Database Category", | ||
648 | "ERROR: Command Failed", | ||
649 | "ERROR: Out Of Resource", | ||
650 | "ERROR: Bad Parameter", | ||
651 | "ERROR: Unknown ID", | ||
652 | "Command Pending", | ||
653 | "ERROR: Not Authenticated", | ||
654 | "ERROR: Bad Authentication Version", | ||
655 | "ERROR: Accessory Power Mode Request Failed", | ||
656 | "ERROR: Certificate Invalid", | ||
657 | "ERROR: Certificate permissions invalid", | ||
658 | "ERROR: File is in use", | ||
659 | "ERROR: Invalid file handle", | ||
660 | "ERROR: Directory not empty", | ||
661 | "ERROR: Operation timed out", | ||
662 | "ERROR: Command unavailable in this iPod mode", | ||
663 | "ERROR: Invalid accessory resistor ID", | ||
664 | "Reserved", | ||
665 | "Reserved", | ||
666 | "Reserved", | ||
667 | "ERROR: Maximum number of accessory connections already reached")[$res], $res); | ||
668 | |||
669 | return 1; | ||
670 | } | ||
671 | |||
672 | sub _h_03_0000 { | ||
673 | my $self = shift; | ||
674 | my $data = shift; | ||
675 | my $state = shift; | ||
676 | my $res; | ||
677 | my $cmd; | ||
678 | |||
679 | ($res, $cmd) = unpack("CC", $data); | ||
680 | |||
681 | printf("ACK (0x03, 0x00) I->D\n"); | ||
682 | printf(" Acknowledged command: 0x%02x\n", $cmd); | ||
683 | printf(" Status: %s (%d)\n", | ||
684 | ("Success", | ||
685 | "ERROR: Unknown Database Category", | ||
686 | "ERROR: Command Failed", | ||
687 | "ERROR: Out Of Resource", | ||
688 | "ERROR: Bad Parameter", | ||
689 | "ERROR: Unknown ID", | ||
690 | "Command Pending", | ||
691 | "ERROR: Not Authenticated", | ||
692 | "ERROR: Bad Authentication Version", | ||
693 | "ERROR: Accessory Power Mode Request Failed", | ||
694 | "ERROR: Certificate Invalid", | ||
695 | "ERROR: Certificate permissions invalid", | ||
696 | "ERROR: File is in use", | ||
697 | "ERROR: Invalid file handle", | ||
698 | "ERROR: Directory not empty", | ||
699 | "ERROR: Operation timed out", | ||
700 | "ERROR: Command unavailable in this iPod mode", | ||
701 | "ERROR: Invalid accessory resistor ID", | ||
702 | "Reserved", | ||
703 | "Reserved", | ||
704 | "Reserved", | ||
705 | "ERROR: Maximum number of accessory connections already reached")[$res], $res); | ||
706 | |||
707 | return 1; | ||
708 | } | ||
709 | |||
710 | sub _h_03_0008 { | ||
711 | my $self = shift; | ||
712 | my $data = shift; | ||
713 | my $state = shift; | ||
714 | my $events;; | ||
715 | |||
716 | $events = unpack("N", $data); | ||
717 | |||
718 | printf("SetRemoteEventsNotification (0x03, 0x08) D->I\n"); | ||
719 | printf(" Events:\n"); | ||
720 | printf(" Track position in ms\n") if ($events & 0x00000001); | ||
721 | printf(" Track playback index\n") if ($events & 0x00000002); | ||
722 | printf(" Chapter index\n") if ($events & 0x00000004); | ||
723 | printf(" Play status\n") if ($events & 0x00000008); | ||
724 | printf(" Mute/UI volume\n") if ($events & 0x00000010); | ||
725 | printf(" Power/Battery\n") if ($events & 0x00000020); | ||
726 | printf(" Equalizer setting\n") if ($events & 0x00000040); | ||
727 | printf(" Shuffle setting\n") if ($events & 0x00000080); | ||
728 | printf(" Repeat setting\n") if ($events & 0x00000100); | ||
729 | printf(" Date and time setting\n") if ($events & 0x00000200); | ||
730 | printf(" Alarm setting\n") if ($events & 0x00000400); | ||
731 | printf(" Backlight state\n") if ($events & 0x00000800); | ||
732 | printf(" Hold switch state\n") if ($events & 0x00001000); | ||
733 | printf(" Sound check state\n") if ($events & 0x00002000); | ||
734 | printf(" Audiobook speed\n") if ($events & 0x00004000); | ||
735 | printf(" Track position in s\n") if ($events & 0x00008000); | ||
736 | printf(" Mute/UI/Absolute volume\n") if ($events & 0x00010000); | ||
737 | |||
738 | return 1; | ||
739 | } | ||
740 | |||
741 | sub _h_03_0009 { | ||
742 | my $self = shift; | ||
743 | my $data = shift; | ||
744 | my $state = shift; | ||
745 | my $event; | ||
746 | my $eventdata; | ||
747 | |||
748 | $event = unpack("C", $data); | ||
749 | |||
750 | printf("RemoteEventNotification (0x03, 0x09) I->D\n"); | ||
751 | printf(" Event: %s (%d)\n", ( | ||
752 | "Track position in ms", | ||
753 | "Track playback index", | ||
754 | "Chapter index", | ||
755 | "Play status", | ||
756 | "Mute/UI volume", | ||
757 | "Power/Battery", | ||
758 | "Equalizer setting", | ||
759 | "Shuffle setting", | ||
760 | "Repeat setting", | ||
761 | "Date and time setting", | ||
762 | "Alarm setting", | ||
763 | "Backlight state", | ||
764 | "Hold switch state", | ||
765 | "Sound check state", | ||
766 | "Audiobook speed", | ||
767 | "Track position in s", | ||
768 | "Mute/UI/Absolute volume")[$event], $event); | ||
769 | |||
770 | if ($event == 0x00) { | ||
771 | $eventdata = unpack("xN", $data); | ||
772 | printf(" Position: %d ms\n", $eventdata); | ||
773 | } elsif ($event == 0x01) { | ||
774 | $eventdata = unpack("xN", $data); | ||
775 | printf(" Track: %d\n", $eventdata); | ||
776 | } elsif ($event == 0x02) { | ||
777 | $eventdata = [ unpack("xNnn", $data) ]; | ||
778 | printf(" Track: %d\n", $eventdata->[0]); | ||
779 | printf(" Chapter count: %d\n", $eventdata->[1]); | ||
780 | printf(" Chapter index: %d\n", $eventdata->[2]); | ||
781 | } elsif ($event == 0x03) { | ||
782 | $eventdata = unpack("xC", $data); | ||
783 | printf(" Status: %s (%d)\n", ( | ||
784 | "Stopped", | ||
785 | "Playing", | ||
786 | "Paused", | ||
787 | "FF", | ||
788 | "REW", | ||
789 | "End FF/REW")[$eventdata], $eventdata); | ||
790 | } elsif ($event == 0x04) { | ||
791 | $eventdata = [ unpack("xCC") ]; | ||
792 | printf(" Mute: %s\n", $eventdata->[0]?"Off":"On"); | ||
793 | printf(" Volume: %d\n", $eventdata->[1]); | ||
794 | } elsif ($event == 0x0F) { | ||
795 | $eventdata = unpack("xn", $data); | ||
796 | printf(" Position: %d s\n", $eventdata); | ||
797 | } | ||
798 | |||
799 | return 1; | ||
800 | } | ||
801 | |||
802 | sub _h_03_000c { | ||
803 | my $self = shift; | ||
804 | my $data = shift; | ||
805 | my $state = shift; | ||
806 | my $info; | ||
807 | |||
808 | $info = unpack("C", $data); | ||
809 | |||
810 | printf("GetiPodStateInfo (0x03, 0x0C) D->I\n"); | ||
811 | printf(" Info to get: %s (%d)\n", ( | ||
812 | "Track time in ms", | ||
813 | "Track playback index", | ||
814 | "Chapter information", | ||
815 | "Play status", | ||
816 | "Mute and volume information", | ||
817 | "Power and battery status", | ||
818 | "Equalizer setting", | ||
819 | "Shuffle setting", | ||
820 | "Repeat setting", | ||
821 | "Date and time", | ||
822 | "Alarm state and time", | ||
823 | "Backlight state", | ||
824 | "Hold switch state", | ||
825 | "Audiobook speed", | ||
826 | "Track time in seconds", | ||
827 | "Mute/UI/Absolute volume")[$info], $info); | ||
828 | |||
829 | return 1; | ||
830 | } | ||
831 | |||
832 | sub _h_03_000d { | ||
833 | my $self = shift; | ||
834 | my $data = shift; | ||
835 | my $state = shift; | ||
836 | my $type; | ||
837 | my $info; | ||
838 | |||
839 | $type = unpack("C", $data); | ||
840 | |||
841 | printf("RetiPodStateInfo (0x03, 0x0E) D->I\n"); | ||
842 | |||
843 | if ($type == 0x00) { | ||
844 | $info = unpack("xN", $data); | ||
845 | printf(" Type: Track position\n"); | ||
846 | printf(" Position: %d ms\n", $info); | ||
847 | } elsif ($type == 0x01) { | ||
848 | $info = unpack("xN", $data); | ||
849 | printf(" Type: Track index\n"); | ||
850 | printf(" Index: %d\n", $info); | ||
851 | } elsif ($type == 0x02) { | ||
852 | $info = [ unpack("xNnn", $data) ]; | ||
853 | printf(" Type: Chapter Information\n"); | ||
854 | printf(" Playing Track: %d\n", $info->[0]); | ||
855 | printf(" Chapter count: %d\n", $info->[1]); | ||
856 | printf(" Chapter index: %d\n", $info->[2]); | ||
857 | } elsif ($type == 0x03) { | ||
858 | $info = unpack("xC", $data); | ||
859 | printf(" Type: Play status\n"); | ||
860 | printf(" Status: %s (%d)\n", ( | ||
861 | "Stopped", | ||
862 | "Playing", | ||
863 | "Paused", | ||
864 | "FF", | ||
865 | "REW", | ||
866 | "End FF/REW")[$info], $info); | ||
867 | } elsif ($type == 0x04) { | ||
868 | $info = [unpack("xCC", $data)]; | ||
869 | printf(" Type: Mute/Volume\n"); | ||
870 | printf(" Mute State: %s\n", $info->[0]?"On":"Off"); | ||
871 | printf(" Volume level: %d\n", $info->[1]); | ||
872 | } elsif ($type == 0x05) { | ||
873 | $info = [unpack("xCC", $data)]; | ||
874 | printf(" Type: Battery Information\n"); | ||
875 | printf(" Power state: %s (%d)\n", ( | ||
876 | "Internal, low power (<30%)", | ||
877 | "Internal", | ||
878 | "External battery pack, no charging", | ||
879 | "External power, no charging", | ||
880 | "External power, charging", | ||
881 | "External power, charged")[$info->[0]], $info->[0]); | ||
882 | printf(" Battery level: %d%%\n", $info->[1]*100/255); | ||
883 | } elsif ($type == 0x06) { | ||
884 | $info = [unpack("xN", $data)]; | ||
885 | printf(" Type: Equalizer\n"); | ||
886 | printf(" Index: %d\n", $info->[0]); | ||
887 | } elsif ($type == 0x07) { | ||
888 | $info = [unpack("xC", $data)]; | ||
889 | printf(" Type: Shuffle\n"); | ||
890 | printf(" Shuffle State: %s\n", $info->[0]?"On":"Off"); | ||
891 | } elsif ($type == 0x08) { | ||
892 | $info = [unpack("xC", $data)]; | ||
893 | printf(" Type: Repeat\n"); | ||
894 | printf(" Repeat State: %s\n", $info->[0]?"On":"Off"); | ||
895 | } elsif ($type == 0x09) { | ||
896 | $info = [unpack("xnCCCC", $data)]; | ||
897 | printf(" Type: Date\n"); | ||
898 | printf(" Date: %02d.%02d.%04d %02d:%02d\n", $info->[2], $info->[1], $info->[0], $info->[3], $info->[4]); | ||
899 | } elsif ($type == 0x0A) { | ||
900 | $info = [unpack("xCCC", $data)]; | ||
901 | printf(" Type: Alarm\n"); | ||
902 | printf(" Alarm State: %s\n", $info->[0]?"On":"Off"); | ||
903 | printf(" Time: %02d:%02d\n", $info->[1], $info->[2]); | ||
904 | } elsif ($type == 0x0B) { | ||
905 | $info = [unpack("xC", $data)]; | ||
906 | printf(" Type: Backlight\n"); | ||
907 | printf(" Backlight State: %s\n", $info->[0]?"On":"Off"); | ||
908 | } elsif ($type == 0x0C) { | ||
909 | $info = [unpack("xC", $data)]; | ||
910 | printf(" Type: Hold switch\n"); | ||
911 | printf(" Switch State: %s\n", $info->[0]?"On":"Off"); | ||
912 | } elsif ($type == 0x0D) { | ||
913 | $info = [unpack("xC", $data)]; | ||
914 | printf(" Type: Sound check\n"); | ||
915 | printf(" Sound check: %s\n", $info->[0]?"On":"Off"); | ||
916 | } elsif ($type == 0x0E) { | ||
917 | $info = [unpack("xC", $data)]; | ||
918 | printf(" Type: Audiobook speed\n"); | ||
919 | printf(" Speed: %s\n", $info->[0]==0x00?"Normal":$info->[0]==0x01?"Faster":$info->[0]==0xFF?"Slower":"Reserved"); | ||
920 | } elsif ($type == 0x0F) { | ||
921 | $info = unpack("xN", $data); | ||
922 | printf(" Type: Track position\n"); | ||
923 | printf(" Position: %d s\n", $info); | ||
924 | } elsif ($type == 0x10) { | ||
925 | $info = [unpack("xCCC", $data)]; | ||
926 | printf(" Type: Mute/UI/Absolute volume\n"); | ||
927 | printf(" Mute State: %s\n", $info->[0]?"On":"Off"); | ||
928 | printf(" UI Volume level: %d\n", $info->[1]); | ||
929 | printf(" Absolute Volume: %d\n", $info->[2]); | ||
930 | } else { | ||
931 | printf(" Reserved\n"); | ||
932 | } | ||
933 | |||
934 | return 1; | ||
935 | } | ||
936 | |||
937 | |||
938 | sub _h_03_000e { | ||
939 | my $self = shift; | ||
940 | my $data = shift; | ||
941 | my $state = shift; | ||
942 | my $type; | ||
943 | my $info; | ||
944 | |||
945 | $type = unpack("C", $data); | ||
946 | |||
947 | printf("SetiPodStateInfo (0x03, 0x0E) D->I\n"); | ||
948 | |||
949 | if ($type == 0x00) { | ||
950 | $info = unpack("xN", $data); | ||
951 | printf(" Type: Track position\n"); | ||
952 | printf(" Position: %d ms\n", $info); | ||
953 | } elsif ($type == 0x01) { | ||
954 | $info = unpack("xN", $data); | ||
955 | printf(" Type: Track index\n"); | ||
956 | printf(" Index: %d\n", $info); | ||
957 | } elsif ($type == 0x02) { | ||
958 | $info = unpack("xn", $data); | ||
959 | printf(" Type: Chapter index\n"); | ||
960 | printf(" Index: %d\n", $info); | ||
961 | } elsif ($type == 0x03) { | ||
962 | $info = unpack("xC", $data); | ||
963 | printf(" Type: Play status\n"); | ||
964 | printf(" Status: %s (%d)\n", ( | ||
965 | "Stopped", | ||
966 | "Playing", | ||
967 | "Paused", | ||
968 | "FF", | ||
969 | "REW", | ||
970 | "End FF/REW")[$info], $info); | ||
971 | } elsif ($type == 0x04) { | ||
972 | $info = [unpack("xCCC", $data)]; | ||
973 | printf(" Type: Mute/Volume\n"); | ||
974 | printf(" Mute State: %s\n", $info->[0]?"On":"Off"); | ||
975 | printf(" Volume level: %d\n", $info->[1]); | ||
976 | printf(" Restore on exit: %s\n", $info->[2]?"Yes":"No"); | ||
977 | } elsif ($type == 0x06) { | ||
978 | $info = [unpack("xNC", $data)]; | ||
979 | printf(" Type: Equalizer\n"); | ||
980 | printf(" Index: %d\n", $info->[0]); | ||
981 | printf(" Restore on exit: %s\n", $info->[1]?"Yes":"No"); | ||
982 | } elsif ($type == 0x07) { | ||
983 | $info = [unpack("xCC", $data)]; | ||
984 | printf(" Type: Shuffle\n"); | ||
985 | printf(" Shuffle State: %s\n", $info->[0]?"On":"Off"); | ||
986 | printf(" Restore on exit: %s\n", $info->[1]?"Yes":"No"); | ||
987 | } elsif ($type == 0x08) { | ||
988 | $info = [unpack("xCC", $data)]; | ||
989 | printf(" Type: Repeat\n"); | ||
990 | printf(" Repeat State: %s\n", $info->[0]?"On":"Off"); | ||
991 | printf(" Restore on exit: %s\n", $info->[1]?"Yes":"No"); | ||
992 | } elsif ($type == 0x09) { | ||
993 | $info = [unpack("xnCCCC", $data)]; | ||
994 | printf(" Type: Date\n"); | ||
995 | printf(" Date: %02d.%02d.%04d %02d:%02d\n", $info->[2], $info->[1], $info->[0], $info->[3], $info->[4]); | ||
996 | } elsif ($type == 0x0A) { | ||
997 | $info = [unpack("xCCCC", $data)]; | ||
998 | printf(" Type: Alarm\n"); | ||
999 | printf(" Alarm State: %s\n", $info->[0]?"On":"Off"); | ||
1000 | printf(" Time: %02d:%02d\n", $info->[1], $info->[2]); | ||
1001 | printf(" Restore on exit: %s\n", $info->[3]?"Yes":"No"); | ||
1002 | } elsif ($type == 0x0B) { | ||
1003 | $info = [unpack("xCC", $data)]; | ||
1004 | printf(" Type: Backlight\n"); | ||
1005 | printf(" Backlight State: %s\n", $info->[0]?"On":"Off"); | ||
1006 | printf(" Restore on exit: %s\n", $info->[1]?"Yes":"No"); | ||
1007 | } elsif ($type == 0x0D) { | ||
1008 | $info = [unpack("xCC", $data)]; | ||
1009 | printf(" Type: Sound check\n"); | ||
1010 | printf(" Sound check: %s\n", $info->[0]?"On":"Off"); | ||
1011 | printf(" Restore on exit: %s\n", $info->[1]?"Yes":"No"); | ||
1012 | } elsif ($type == 0x0E) { | ||
1013 | $info = [unpack("xCC", $data)]; | ||
1014 | printf(" Type: Audiobook speed\n"); | ||
1015 | printf(" Speed: %s\n", $info->[0]==0x00?"Normal":$info->[0]==0x01?"Faster":$info->[0]==0xFF?"Slower":"Reserved"); | ||
1016 | printf(" Restore on exit: %s\n", $info->[1]?"Yes":"No"); | ||
1017 | } elsif ($type == 0x0F) { | ||
1018 | $info = unpack("xN", $data); | ||
1019 | printf(" Type: Track position\n"); | ||
1020 | printf(" Position: %d s\n", $info); | ||
1021 | } elsif ($type == 0x10) { | ||
1022 | $info = [unpack("xCCCC", $data)]; | ||
1023 | printf(" Type: Mute/UI/Absolute volume\n"); | ||
1024 | printf(" Mute State: %s\n", $info->[0]?"On":"Off"); | ||
1025 | printf(" UI Volume level: %d\n", $info->[1]); | ||
1026 | printf(" Absolute Volume: %d\n", $info->[2]); | ||
1027 | printf(" Restore on exit: %s\n", $info->[3]?"Yes":"No"); | ||
1028 | } else { | ||
1029 | printf(" Reserved\n"); | ||
1030 | } | ||
1031 | |||
1032 | return 1; | ||
1033 | } | ||
1034 | |||
1035 | sub _h_03_000f { | ||
1036 | my $self = shift; | ||
1037 | my $data = shift; | ||
1038 | my $state = shift; | ||
1039 | |||
1040 | print("GetPlayStatus (0x03, 0x0F) D->I\n"); | ||
1041 | |||
1042 | return 1; | ||
1043 | } | ||
1044 | |||
1045 | sub _h_03_0010 { | ||
1046 | my $self = shift; | ||
1047 | my $data = shift; | ||
1048 | my $state = shift; | ||
1049 | my ($status, $idx, $len, $pos); | ||
1050 | |||
1051 | ($status, $idx, $len, $pos) = unpack("CNNN", $data); | ||
1052 | |||
1053 | printf("RetPlayStatus (0x03, 0x10) I->D\n"); | ||
1054 | printf(" Status: %s (%d)\n", ( | ||
1055 | "Stopped", | ||
1056 | "Playing", | ||
1057 | "Paused")[$status], $status); | ||
1058 | if ($status != 0x00) { | ||
1059 | printf(" Track index: %d\n", $idx); | ||
1060 | printf(" Track length: %d\n", $len); | ||
1061 | printf(" Track position: %d\n", $pos); | ||
1062 | } | ||
1063 | |||
1064 | return 1; | ||
1065 | } | ||
1066 | |||
1067 | sub _h_03_0012 { | ||
1068 | my $self = shift; | ||
1069 | my $data = shift; | ||
1070 | my $state = shift; | ||
1071 | my ($info, $tidx, $cidx); | ||
1072 | |||
1073 | ($info, $tidx, $cidx) = unpack("CNn", $data); | ||
1074 | |||
1075 | printf("GetIndexedPlayingTrackInfo (0x03, 0x12) D->I\n"); | ||
1076 | printf(" Requested info: %s (%d)\n", ( | ||
1077 | "Track caps/info", | ||
1078 | "Chapter time/name", | ||
1079 | "Artist name", | ||
1080 | "Album name", | ||
1081 | "Genre name", | ||
1082 | "Track title", | ||
1083 | "Composer name", | ||
1084 | "Lyrics", | ||
1085 | "Artwork count")[$info], $info); | ||
1086 | printf(" Track index: %d\n", $tidx); | ||
1087 | printf(" Chapter index: %d\n", $cidx); | ||
1088 | |||
1089 | return 1; | ||
1090 | } | ||
1091 | |||
1092 | sub _h_03_0013 { | ||
1093 | my $self = shift; | ||
1094 | my $data = shift; | ||
1095 | my $state = shift; | ||
1096 | my $info; | ||
1097 | |||
1098 | $info = unpack("C", $data); | ||
1099 | printf("RetIndexedPlayingTrackInfo (0x03, 0x13) I->D\n"); | ||
1100 | printf(" Returned info: %s (%d)\n", ( | ||
1101 | "Track caps/info", | ||
1102 | "Chapter time/name", | ||
1103 | "Artist name", | ||
1104 | "Album name", | ||
1105 | "Genre name", | ||
1106 | "Track title", | ||
1107 | "Composer name", | ||
1108 | "Lyrics", | ||
1109 | "Artwork count")[$info], $info); | ||
1110 | if ($info == 0x00) { | ||
1111 | my ($caps, $len, $chap) = unpack("xNNn", $data); | ||
1112 | printf(" Track is audiobook\n") if ($caps & 0x01); | ||
1113 | printf(" Track has chapters\n") if ($caps & 0x02); | ||
1114 | printf(" Track has artwork\n") if ($caps & 0x04); | ||
1115 | printf(" Track contains video\n") if ($caps & 0x80); | ||
1116 | printf(" Track queued as video\n") if ($caps & 0x100); | ||
1117 | |||
1118 | printf(" Track length: %d ms\n", $len); | ||
1119 | printf(" Track chapters: %d\n", $chap); | ||
1120 | } elsif ($info == 0x01) { | ||
1121 | my ($len, $name) = unpack("xNZ*"); | ||
1122 | printf(" Chapter time: %d ms\n", $len); | ||
1123 | printf(" Chapter name: %s\n", $name); | ||
1124 | } elsif ($info >= 0x02 && $info <= 0x06) { | ||
1125 | my $name = unpack("xZ*", $data); | ||
1126 | printf(" Name/Title: %s\n", $name) | ||
1127 | } elsif ($info == 0x07) { | ||
1128 | my ($info, $index, $data) = unpack("xCnZ*"); | ||
1129 | printf(" Part of multiple packets\n") if ($info & 0x01); | ||
1130 | printf(" Is last packet\n") if ($info & 0x02); | ||
1131 | printf(" Packet index: %d\n", $index); | ||
1132 | printf(" Data: %s\n", $data); | ||
1133 | } elsif ($info == 0x08) { | ||
1134 | |||
1135 | } | ||
1136 | |||
1137 | return 1; | ||
1138 | } | ||
1139 | |||
1140 | sub _h_04_0001 { | ||
1141 | my $self = shift; | ||
1142 | my $data = shift; | ||
1143 | my $state = shift; | ||
1144 | my $res; | ||
1145 | my $cmd; | ||
1146 | |||
1147 | ($res, $cmd) = unpack("Cn", $data); | ||
1148 | |||
1149 | printf("ACK (0x04, 0x0001) I->D\n"); | ||
1150 | printf(" Acknowledged command: 0x%02x\n", $cmd); | ||
1151 | printf(" Status: %s (%d)\n", | ||
1152 | ("Success", | ||
1153 | "ERROR: Unknown Database Category", | ||
1154 | "ERROR: Command Failed", | ||
1155 | "ERROR: Out Of Resource", | ||
1156 | "ERROR: Bad Parameter", | ||
1157 | "ERROR: Unknown ID", | ||
1158 | "Reserved", | ||
1159 | "ERROR: Not Authenticated")[$res], $res); | ||
1160 | |||
1161 | return 1; | ||
1162 | } | ||
1163 | |||
1164 | sub _h_04_000c { | ||
1165 | my $self = shift; | ||
1166 | my $data = shift; | ||
1167 | my $state = shift; | ||
1168 | my ($info, $track, $chapter); | ||
1169 | |||
1170 | ($info, $track, $chapter) = unpack("CNn", $data); | ||
1171 | |||
1172 | printf("GetIndexedPlayingTrackInfo (0x04, 0x000C) D->I\n"); | ||
1173 | printf(" Track: %d\n", $track); | ||
1174 | printf(" Chapter: %d\n", $chapter); | ||
1175 | printf(" Info requested: %s (%d)\n", ( | ||
1176 | "Capabilities and information", | ||
1177 | "Podcast name", | ||
1178 | "Track release date", | ||
1179 | "Track description", | ||
1180 | "Track song lyrics", | ||
1181 | "Track genre", | ||
1182 | "Track Composer", | ||
1183 | "Tracn Artwork count")[$info], $info); | ||
1184 | |||
1185 | return 1; | ||
1186 | } | ||
1187 | |||
1188 | sub _h_04_000d { | ||
1189 | my $self = shift; | ||
1190 | my $data = shift; | ||
1191 | my $state = shift; | ||
1192 | my $info; | ||
1193 | |||
1194 | $info = unpack("C", $data); | ||
1195 | |||
1196 | printf("ReturnIndexedPlayingTrackInfo (0x04, 0x000D) I->D\n"); | ||
1197 | if ($info == 0x00) { | ||
1198 | my ($capability, $length, $chapter); | ||
1199 | |||
1200 | ($capability, $length, $chapter) = unpack("xNNn", $data); | ||
1201 | printf(" Capabilities:\n"); | ||
1202 | printf(" Is audiobook\n") if ($capability & 0x00000001); | ||
1203 | printf(" Has chapters\n") if ($capability & 0x00000002); | ||
1204 | printf(" Has album artwork\n") if ($capability & 0x00000004); | ||
1205 | printf(" Has song lyrics\n") if ($capability & 0x00000008); | ||
1206 | printf(" Is a podcast episode\n") if ($capability & 0x00000010); | ||
1207 | printf(" Has release date\n") if ($capability & 0x00000020); | ||
1208 | printf(" Has description\n") if ($capability & 0x00000040); | ||
1209 | printf(" Contains video\n") if ($capability & 0x00000080); | ||
1210 | printf(" Queued to play as video\n") if ($capability & 0x00000100); | ||
1211 | |||
1212 | printf(" Length: %d ms\n", $length); | ||
1213 | printf(" Chapters: %d\n", $chapter); | ||
1214 | } else { | ||
1215 | printf(" WARNING: Unknown info\n"); | ||
1216 | return 1; | ||
1217 | } | ||
1218 | |||
1219 | return 1; | ||
1220 | } | ||
1221 | |||
1222 | sub _h_04_0012 { | ||
1223 | my $self = shift; | ||
1224 | my $data = shift; | ||
1225 | my $state = shift; | ||
1226 | |||
1227 | printf("RequestProtocolVersion (0x04, 0x0012) D->I\n"); | ||
1228 | |||
1229 | return 1; | ||
1230 | } | ||
1231 | |||
1232 | sub _h_04_0013 { | ||
1233 | my $self = shift; | ||
1234 | my $data = shift; | ||
1235 | my $state = shift; | ||
1236 | my ($maj, $min); | ||
1237 | |||
1238 | ($maj, $min) = unpack("CC", $data); | ||
1239 | |||
1240 | printf("ReturnProtocolVersion (0x04, 0x0013) I->D\n"); | ||
1241 | printf(" Lingo 0x04 version: %d.%02d\n", $maj, $min); | ||
1242 | |||
1243 | return 1; | ||
1244 | } | ||
1245 | |||
1246 | sub _h_04_0016 { | ||
1247 | my $self = shift; | ||
1248 | my $data = shift; | ||
1249 | my $state = shift; | ||
1250 | |||
1251 | printf("ResetDBSelection (0x04, 0x0016) D->I\n"); | ||
1252 | |||
1253 | return 1; | ||
1254 | } | ||
1255 | |||
1256 | sub _h_04_0018 { | ||
1257 | my $self = shift; | ||
1258 | my $data = shift; | ||
1259 | my $state = shift; | ||
1260 | my $category; | ||
1261 | |||
1262 | $category = unpack("C", $data); | ||
1263 | |||
1264 | printf("GetNumberCategorizedDBRecords (0x04, 0x0018) D->I\n"); | ||
1265 | printf(" Category: %s (%d)\n", ( | ||
1266 | "Reserved", | ||
1267 | "Playlist", | ||
1268 | "Artist", | ||
1269 | "Album", | ||
1270 | "Genre", | ||
1271 | "Track", | ||
1272 | "Composer", | ||
1273 | "Audiobook", | ||
1274 | "Podcast", | ||
1275 | "Nested Playlist")[$category], $category); | ||
1276 | |||
1277 | return 1; | ||
1278 | } | ||
1279 | |||
1280 | sub _h_04_0019 { | ||
1281 | my $self = shift; | ||
1282 | my $data = shift; | ||
1283 | my $state = shift; | ||
1284 | my $count; | ||
1285 | |||
1286 | $count = unpack("N", $data); | ||
1287 | |||
1288 | printf("ReturnNumberCategorizedDBRecords (0x04, 0x0019) I->D\n"); | ||
1289 | printf(" Count: %d\n", $count); | ||
1290 | |||
1291 | return 1; | ||
1292 | } | ||
1293 | |||
1294 | sub _h_04_001c { | ||
1295 | my $self = shift; | ||
1296 | my $data = shift; | ||
1297 | my $state = shift; | ||
1298 | |||
1299 | printf("GetPlayStatus (0x04, 0x001C) D->I\n"); | ||
1300 | |||
1301 | return 1; | ||
1302 | } | ||
1303 | |||
1304 | sub _h_04_001d { | ||
1305 | my $self = shift; | ||
1306 | my $data = shift; | ||
1307 | my $state = shift; | ||
1308 | my ($len, $pos, $s); | ||
1309 | |||
1310 | ($len, $pos, $s) = unpack("NNC", $data); | ||
1311 | |||
1312 | printf("ReturnPlayStatus (0x04, 0x001D) I->D\n"); | ||
1313 | printf(" Song length: %d ms\n", $len); | ||
1314 | printf(" Song position: %d ms\n", $pos); | ||
1315 | printf(" Player state: "); | ||
1316 | if ($s == 0x00) { | ||
1317 | printf("Stopped\n"); | ||
1318 | } elsif ($s == 0x01) { | ||
1319 | printf("Playing\n"); | ||
1320 | } elsif ($s == 0x02) { | ||
1321 | printf("Paused\n"); | ||
1322 | } elsif ($s == 0xFF) { | ||
1323 | printf("Error\n"); | ||
1324 | } else { | ||
1325 | printf("Reserved\n"); | ||
1326 | } | ||
1327 | |||
1328 | return 1; | ||
1329 | } | ||
1330 | |||
1331 | sub _h_04_001e { | ||
1332 | my $self = shift; | ||
1333 | my $data = shift; | ||
1334 | my $state = shift; | ||
1335 | |||
1336 | printf("GetCurrentPlayingTrackIndex (0x04, 0x001E) D->I\n"); | ||
1337 | |||
1338 | return 1; | ||
1339 | } | ||
1340 | |||
1341 | sub _h_04_001f { | ||
1342 | my $self = shift; | ||
1343 | my $data = shift; | ||
1344 | my $state = shift; | ||
1345 | my $num; | ||
1346 | |||
1347 | $num = unpack("N", $data); | ||
1348 | |||
1349 | printf("ReturnCurrentPlayingTrackIndex (0x04, 0x001F) I->D\n"); | ||
1350 | printf(" Index: %d\n", $num); | ||
1351 | |||
1352 | return 1; | ||
1353 | } | ||
1354 | |||
1355 | sub _h_04_0020 { | ||
1356 | my $self = shift; | ||
1357 | my $data = shift; | ||
1358 | my $state = shift; | ||
1359 | my $track; | ||
1360 | |||
1361 | $track = unpack("N", $data); | ||
1362 | |||
1363 | printf("GetIndexedPlayingTrackTitle (0x04, 0x0020) D->I\n"); | ||
1364 | printf(" Track: %d\n", $track); | ||
1365 | |||
1366 | return 1; | ||
1367 | } | ||
1368 | |||
1369 | sub _h_04_0021 { | ||
1370 | my $self = shift; | ||
1371 | my $data = shift; | ||
1372 | my $state = shift; | ||
1373 | my $title; | ||
1374 | |||
1375 | $title = unpack("Z*", $data); | ||
1376 | |||
1377 | printf("ReturnIndexedPlayingTrackTitle (0x04, 0x0021) I->D\n"); | ||
1378 | printf(" Title: %s\n", $title); | ||
1379 | |||
1380 | return 1; | ||
1381 | } | ||
1382 | |||
1383 | sub _h_04_0022 { | ||
1384 | my $self = shift; | ||
1385 | my $data = shift; | ||
1386 | my $state = shift; | ||
1387 | my $track; | ||
1388 | |||
1389 | $track = unpack("N", $data); | ||
1390 | |||
1391 | printf("GetIndexedPlayingTrackArtistName (0x04, 0x0022) D->I\n"); | ||
1392 | printf(" Track: %d\n", $track); | ||
1393 | |||
1394 | return 1; | ||
1395 | } | ||
1396 | |||
1397 | sub _h_04_0023 { | ||
1398 | my $self = shift; | ||
1399 | my $data = shift; | ||
1400 | my $state = shift; | ||
1401 | my $artist; | ||
1402 | |||
1403 | $artist = unpack("Z*", $data); | ||
1404 | |||
1405 | printf("ReturnIndexedPlayingTrackArtistName (0x04, 0x0023) I->D\n"); | ||
1406 | printf(" Artist: %s\n", $artist); | ||
1407 | |||
1408 | return 1; | ||
1409 | } | ||
1410 | |||
1411 | sub _h_04_0024 { | ||
1412 | my $self = shift; | ||
1413 | my $data = shift; | ||
1414 | my $state = shift; | ||
1415 | my $track; | ||
1416 | |||
1417 | $track = unpack("N", $data); | ||
1418 | |||
1419 | printf("GetIndexedPlayingTrackAlbumName (0x04, 0x0024) D->I\n"); | ||
1420 | printf(" Track: %d\n", $track); | ||
1421 | |||
1422 | return 1; | ||
1423 | } | ||
1424 | |||
1425 | sub _h_04_0025 { | ||
1426 | my $self = shift; | ||
1427 | my $data = shift; | ||
1428 | my $state = shift; | ||
1429 | my $title; | ||
1430 | |||
1431 | $title = unpack("Z*", $data); | ||
1432 | |||
1433 | printf("ReturnIndexedPlayingTrackAlbumName (0x04, 0x0025) I->D\n"); | ||
1434 | printf(" Album: %s\n", $title); | ||
1435 | |||
1436 | return 1; | ||
1437 | } | ||
1438 | |||
1439 | sub _h_04_0026 { | ||
1440 | my $self = shift; | ||
1441 | my $data = shift; | ||
1442 | my $state = shift; | ||
1443 | my $notification; | ||
1444 | |||
1445 | if (length($data) == 1) { | ||
1446 | $notification = unpack("C", $data); | ||
1447 | } elsif (length($data) == 4) { | ||
1448 | $notification = unpack("N", $data); | ||
1449 | } | ||
1450 | |||
1451 | printf("SetPlayStatusChangeNotification (0x04, 0x0026) D->I\n"); | ||
1452 | |||
1453 | if (length($data) == 1) { | ||
1454 | printf(" Events for: %s (%d)\n", ( | ||
1455 | "Disable all", | ||
1456 | "Basic play state, track index, track time position, FFW/REW seek stop, and chapter index changes")[$notification], $notification); | ||
1457 | } elsif (length($data) == 4) { | ||
1458 | printf(" Events for:\n"); | ||
1459 | printf(" Basic play state changes\n") if ($notification & 0x00000001); | ||
1460 | printf(" Extended play state changes\n") if ($notification & 0x00000002); | ||
1461 | printf(" Track index\n") if ($notification & 0x00000004); | ||
1462 | printf(" Track time offset (ms)\n") if ($notification & 0x00000008); | ||
1463 | printf(" Track time offset (s)\n") if ($notification & 0x00000010); | ||
1464 | printf(" Chapter index\n") if ($notification & 0x00000020); | ||
1465 | printf(" Chapter time offset (ms)\n") if ($notification & 0x00000040); | ||
1466 | printf(" Chapter time offset (s)\n") if ($notification & 0x00000080); | ||
1467 | printf(" Track unique identifier\n") if ($notification & 0x00000100); | ||
1468 | printf(" Track media tyoe\n") if ($notification & 0x00000200); | ||
1469 | printf(" Track lyrics\n") if ($notification & 0x00000400); | ||
1470 | } else { | ||
1471 | printf(" WARNING: Unknown length for state\n"); | ||
1472 | return 0; | ||
1473 | } | ||
1474 | |||
1475 | return 1; | ||
1476 | } | ||
1477 | |||
1478 | sub _h_04_0027 { | ||
1479 | my $self = shift; | ||
1480 | my $data = shift; | ||
1481 | my $state = shift; | ||
1482 | my $info; | ||
1483 | |||
1484 | $info = unpack("C", $data); | ||
1485 | |||
1486 | printf("PlayStatusChangeNotification (0x04, 0x0029) I->D\n"); | ||
1487 | printf(" Status:\n"); | ||
1488 | if ($info == 0x00) { | ||
1489 | printf(" Playback stopped\n"); | ||
1490 | } elsif ($info == 0x01) { | ||
1491 | my $index = unpack("xN", $data); | ||
1492 | |||
1493 | printf(" Track index: %d\n", $index); | ||
1494 | } elsif ($info == 0x02) { | ||
1495 | printf(" Playback FF seek stop\n"); | ||
1496 | } elsif ($info == 0x03) { | ||
1497 | printf(" Playback REW seek stop\n"); | ||
1498 | } elsif ($info == 0x04) { | ||
1499 | my $offset = unpack("xN", $data); | ||
1500 | |||
1501 | printf(" Track time offset: %d ms\n", $offset); | ||
1502 | } elsif ($info == 0x05) { | ||
1503 | my $index = unpack("xN", $data); | ||
1504 | |||
1505 | printf(" Chapter index: %d\n", $index); | ||
1506 | } elsif ($info == 0x06) { | ||
1507 | my $status = unpack("xC", $data); | ||
1508 | |||
1509 | printf(" Playback status extended: %s (%d)\n", ( | ||
1510 | "Reserved", | ||
1511 | "Reserved", | ||
1512 | "Stopped", | ||
1513 | "Reserved", | ||
1514 | "Reserved", | ||
1515 | "FF seek started", | ||
1516 | "REW seek started", | ||
1517 | "FF/REW seek stopped", | ||
1518 | "Reserved", | ||
1519 | "Reserved", | ||
1520 | "Playing", | ||
1521 | "Paused")[$status], $status); | ||
1522 | } elsif ($info == 0x07) { | ||
1523 | my $offset = unpack("xN", $data); | ||
1524 | |||
1525 | printf(" Track time offset: %d s\n", $offset); | ||
1526 | } elsif ($info == 0x08) { | ||
1527 | my $offset = unpack("xN", $data); | ||
1528 | |||
1529 | printf(" Chapter time offset %d ms\n", $offset); | ||
1530 | } elsif ($info == 0x09) { | ||
1531 | my $offset = unpack("xN", $data); | ||
1532 | |||
1533 | printf(" Chapter time offset %d s\n", $offset); | ||
1534 | } elsif ($info == 0x0A) { | ||
1535 | my ($uidhi, $uidlo) = unpack("xNN", $data); | ||
1536 | |||
1537 | printf(" Track UID: %08x%08x\n", $uidhi, $uidlo); | ||
1538 | } elsif ($info == 0x0B) { | ||
1539 | my $mode = unpack("xC", $data); | ||
1540 | |||
1541 | printf(" Track mode: %s (%d)\n", ( | ||
1542 | "Audio track", | ||
1543 | "Video track")[$mode], $mode); | ||
1544 | } elsif ($info == 0x0C) { | ||
1545 | printf(" Track lyrics ready\n"); | ||
1546 | } else { | ||
1547 | printf(" Reserved\n"); | ||
1548 | } | ||
1549 | |||
1550 | return 1; | ||
1551 | } | ||
1552 | |||
1553 | sub _h_04_0029 { | ||
1554 | my $self = shift; | ||
1555 | my $data = shift; | ||
1556 | my $state = shift; | ||
1557 | my $control; | ||
1558 | |||
1559 | $control = unpack("C", $data); | ||
1560 | |||
1561 | printf("PlayControl (0x04, 0x0029) D->I\n"); | ||
1562 | printf(" Command: %s (%d)\n", ( | ||
1563 | "Reserved", | ||
1564 | "Toggle Play/Pause", | ||
1565 | "Stop", | ||
1566 | "Next track", | ||
1567 | "Previous track", | ||
1568 | "Start FF", | ||
1569 | "Start Rev", | ||
1570 | "Stop FF/Rev", | ||
1571 | "Next", | ||
1572 | "Previous", | ||
1573 | "Play", | ||
1574 | "Pause", | ||
1575 | "Next chapter", | ||
1576 | "Previous chapter")[$control], $control); | ||
1577 | |||
1578 | return 1; | ||
1579 | } | ||
1580 | |||
1581 | sub _h_04_002c { | ||
1582 | my $self = shift; | ||
1583 | my $data = shift; | ||
1584 | my $state = shift; | ||
1585 | |||
1586 | printf("GetShuffle (0x04, 0x002C) D->I\n"); | ||
1587 | |||
1588 | return 1; | ||
1589 | } | ||
1590 | |||
1591 | sub _h_04_002d { | ||
1592 | my $self = shift; | ||
1593 | my $data = shift; | ||
1594 | my $state = shift; | ||
1595 | my $mode; | ||
1596 | |||
1597 | $mode = unpack("C", $data); | ||
1598 | |||
1599 | printf("ReturnShuffle (0x04, 0x002D) I->D\n"); | ||
1600 | printf(" Mode: %s (%d)\n", ( | ||
1601 | "Off", | ||
1602 | "Tracks", | ||
1603 | "Albums")[$mode], $mode); | ||
1604 | |||
1605 | return 1; | ||
1606 | } | ||
1607 | |||
1608 | sub _h_04_002f { | ||
1609 | my $self = shift; | ||
1610 | my $data = shift; | ||
1611 | my $state = shift; | ||
1612 | |||
1613 | printf("GetRepeat (0x04, 0x002F) D->I\n"); | ||
1614 | |||
1615 | return 1; | ||
1616 | } | ||
1617 | |||
1618 | sub _h_04_0030 { | ||
1619 | my $self = shift; | ||
1620 | my $data = shift; | ||
1621 | my $state = shift; | ||
1622 | my $mode; | ||
1623 | |||
1624 | $mode = unpack("C", $data); | ||
1625 | |||
1626 | printf("ReturnRepeat (0x04, 0x0030) I->D\n"); | ||
1627 | printf(" Mode: %s (%d)\n", ( | ||
1628 | "Off", | ||
1629 | "One Track", | ||
1630 | "All Tracks")[$mode], $mode); | ||
1631 | |||
1632 | return 1; | ||
1633 | } | ||
1634 | |||
1635 | sub _h_04_0032 { | ||
1636 | my $self = shift; | ||
1637 | my $data = shift; | ||
1638 | my $state = shift; | ||
1639 | my ($index, $format, $width, $height, $stride, $imagedata); | ||
1640 | |||
1641 | $state->{-index} = -1 unless(exists($state->{-index})); | ||
1642 | $state->{-image} = '' unless(exists($state->{-image})); | ||
1643 | |||
1644 | ($index, $format, $width, $height, $stride, $imagedata) = unpack("nCnnNa*", $data); | ||
1645 | |||
1646 | printf("SetDisplayImage (0x04, 0x0032) D->I\n"); | ||
1647 | if ($index == 0) { | ||
1648 | printf(" Width: %d\n", $width); | ||
1649 | printf(" Height: %d\n", $height); | ||
1650 | printf(" Stride: %d\n", $stride); | ||
1651 | printf(" Format: %s (%d)\n", ( | ||
1652 | "Reserved", | ||
1653 | "Monochrome, 2 bps", | ||
1654 | "RGB 565, little endian", | ||
1655 | "RGB 565, big endian")[$format], $format); | ||
1656 | |||
1657 | $state->{-imagelength} = $height * $stride; | ||
1658 | } else { | ||
1659 | ($index, $imagedata) = unpack("na*", $data); | ||
1660 | } | ||
1661 | |||
1662 | if ($index-1 != $state->{-index}) { | ||
1663 | printf(" WARNING! Out of order segment\n"); | ||
1664 | return 0; | ||
1665 | } | ||
1666 | |||
1667 | $state->{-index} = $index; | ||
1668 | $state->{-image} .= $imagedata; | ||
1669 | |||
1670 | if (length($state->{-image}) >= $state->{-imagelength}) { | ||
1671 | printf(" Image data: %s\n", Device::iPod->_hexstring($state->{-image})); | ||
1672 | } | ||
1673 | |||
1674 | return 1; | ||
1675 | } | ||
1676 | |||
1677 | sub _h_04_0033 { | ||
1678 | my $self = shift; | ||
1679 | my $data = shift; | ||
1680 | my $state = shift; | ||
1681 | |||
1682 | printf("GetMonoDisplayImageLimits (0x04, 0x0033) D->I\n"); | ||
1683 | |||
1684 | return 1; | ||
1685 | } | ||
1686 | |||
1687 | sub _h_04_0034 { | ||
1688 | my $self = shift; | ||
1689 | my $data = shift; | ||
1690 | my $state = shift; | ||
1691 | my ($width, $height, $format); | ||
1692 | |||
1693 | ($width, $height, $format) = unpack("nnC", $data); | ||
1694 | |||
1695 | printf("ReturnMonoDisplayImageLimits (0x04, 0x0034) I->D\n"); | ||
1696 | printf(" Width: %d\n", $width); | ||
1697 | printf(" Height: %d\n", $height); | ||
1698 | printf(" Format: %s (%d)\n", ( | ||
1699 | "Reserved", | ||
1700 | "Monochrome, 2 bps", | ||
1701 | "RGB 565, little endian", | ||
1702 | "RGB 565, big endian")[$format], $format); | ||
1703 | |||
1704 | return 1; | ||
1705 | } | ||
1706 | |||
1707 | sub _h_04_0035 { | ||
1708 | my $self = shift; | ||
1709 | my $data = shift; | ||
1710 | my $state = shift; | ||
1711 | |||
1712 | printf("GetNumPlayingTracks (0x04, 0x0035) D->I\n"); | ||
1713 | |||
1714 | return 1; | ||
1715 | } | ||
1716 | |||
1717 | sub _h_04_0036 { | ||
1718 | my $self = shift; | ||
1719 | my $data = shift; | ||
1720 | my $state = shift; | ||
1721 | my $num; | ||
1722 | |||
1723 | $num = unpack("N", $data); | ||
1724 | |||
1725 | printf("ReturnNumPlayingTracks (0x04, 0x0036) I->D\n"); | ||
1726 | printf(" Number: %d\n", $num); | ||
1727 | |||
1728 | return 1; | ||
1729 | } | ||
1730 | |||
1731 | sub _h_04_0037 { | ||
1732 | my $self = shift; | ||
1733 | my $data = shift; | ||
1734 | my $state = shift; | ||
1735 | my $num; | ||
1736 | |||
1737 | $num = unpack("N", $data); | ||
1738 | |||
1739 | printf("SetCurrentPlayingTrack (0x04, 0x0037) D->I\n"); | ||
1740 | printf(" Track: %d\n", $num); | ||
1741 | |||
1742 | return 1; | ||
1743 | } | ||
1744 | |||
1745 | sub _h_07_0005 { | ||
1746 | my $self = shift; | ||
1747 | my $data = shift; | ||
1748 | my $state = shift; | ||
1749 | my $control; | ||
1750 | |||
1751 | $control = unpack("C", $data); | ||
1752 | |||
1753 | printf("SetTunerCtrl (0x07, 0x05) I->D\n"); | ||
1754 | printf(" Options:\n"); | ||
1755 | printf(" Power %s\n", ($control & 0x01)?"on":"off"); | ||
1756 | printf(" Status change notifications %s\n", ($control & 0x02)?"on":"off"); | ||
1757 | printf(" Raw mode %s\n", ($control & 0x04)?"on":"off"); | ||
1758 | } | ||
1759 | |||
1760 | sub _h_07_0020 { | ||
1761 | my $self = shift; | ||
1762 | my $data = shift; | ||
1763 | my $state = shift; | ||
1764 | my $options; | ||
1765 | |||
1766 | $options = unpack("N", $data); | ||
1767 | |||
1768 | printf("SetRDSNotifyMask (0x07, 0x20) I->D\n"); | ||
1769 | printf(" Options:\n"); | ||
1770 | printf(" Radiotext\n") if ($options & 0x00000010); | ||
1771 | printf(" Program Service Name\n") if ($options & 0x40000000); | ||
1772 | printf(" Reserved\n") if ($options & 0xBFFFFFEF); | ||
1773 | |||
1774 | return 1; | ||
1775 | } | ||
1776 | |||
1777 | sub _h_07_0024 { | ||
1778 | my $self = shift; | ||
1779 | my $data = shift; | ||
1780 | my $state = shift; | ||
1781 | |||
1782 | printf("Reserved command (0x07, 0x24) I->D\n"); | ||
1783 | |||
1784 | return 1; | ||
1785 | } | ||
1786 | |||
1787 | |||
1788 | package main; | ||
1789 | |||
1790 | use Device::iPod; | ||
1791 | use Getopt::Long; | ||
1792 | use strict; | ||
1793 | |||
1794 | my $decoder; | ||
1795 | my $device; | ||
1796 | my $unpacker; | ||
1797 | my $line; | ||
1798 | |||
1799 | sub unpack_hexstring { | ||
1800 | my $line = shift; | ||
1801 | my $m; | ||
1802 | my @m; | ||
1803 | |||
1804 | $line =~ s/(..)/chr(hex($1))/ge; | ||
1805 | $device->{-inbuf} = $line; | ||
1806 | |||
1807 | $m = $device->_message(); | ||
1808 | next unless defined($m); | ||
1809 | @m = $device->_unframe_cmd($m); | ||
1810 | unless(@m) { | ||
1811 | printf("Line %d: Error decoding frame: %s\n", $., $device->error()); | ||
1812 | return (); | ||
1813 | } | ||
1814 | |||
1815 | return @m; | ||
1816 | } | ||
1817 | |||
1818 | sub unpack_iaplog { | ||
1819 | my $line = shift; | ||
1820 | my @m; | ||
1821 | |||
1822 | unless ($line =~ /^(?:\[\d+\] )?[RT]::? /) { | ||
1823 | printf("Skipped: %s\n", $line); | ||
1824 | return (); | ||
1825 | } | ||
1826 | |||
1827 | $line =~ s/^(?:\[\d+\] )?[RT]::? //; | ||
1828 | $line =~ s/\\x(..)/chr(hex($1))/ge; | ||
1829 | $line =~ s/\\\\/\\/g; | ||
1830 | |||
1831 | @m = unpack("CCa*", $line); | ||
1832 | if ($m[0] == 0x04) { | ||
1833 | @m = unpack("Cna*", $line); | ||
1834 | } | ||
1835 | |||
1836 | return @m; | ||
1837 | } | ||
1838 | |||
1839 | |||
1840 | $decoder = iap::decode->new(); | ||
1841 | $device = Device::iPod->new(); | ||
1842 | $unpacker = \&unpack_iaplog; | ||
1843 | |||
1844 | GetOptions("hexstring" => sub {$unpacker = \&unpack_hexstring}); | ||
1845 | |||
1846 | while ($line = <>) { | ||
1847 | my @m; | ||
1848 | |||
1849 | chomp($line); | ||
1850 | |||
1851 | @m = $unpacker->($line); | ||
1852 | next unless (@m); | ||
1853 | |||
1854 | printf("Line %d: ", $.); | ||
1855 | $decoder->display(@m); | ||
1856 | } | ||