-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathraw4t_gp2_to_human.pl
executable file
·630 lines (550 loc) · 27.1 KB
/
raw4t_gp2_to_human.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
#!/usr/bin/perl -w
# by Matija Nalis <[email protected]> GPLv3+, started 2014-06-24
# extended by Hrvoje Cavrak <[email protected]> 2014/07
# parse decapsulated GSD4t .gp2 container format data and interprets it for human use
#
# Usage: ./strace_to_gp2.pl data/strace4/strace.log.3491 | ./enc4t_gp2_to_raw4t_gp2.pl | ./raw4t_gp2_to_human.pl
#
use strict;
use autodie;
use feature "switch";
use feature "say";
use Tie::IxHash; # needed to preserve order of 'keys %array'
use Readonly;
my $DEBUG = 3;
$| = 1;
# format is like:
# 00/00/0006 16:21:36.400 (0) E1 0A 2D 03 12 40 08 34 05 00 0E 1E 60 01 81 C7 00 00 20 F8 # seq1=0070 seq2=0007 len=0014
# E1 0A -- lead-in (although there seems to be others, like E1 09, 84, 8E etc... find them out later)
# 2D -- command/MID ("ACQ:")
# 03 -- subommand/SID ("New")
# 12 -- lenght of packet (ignoring E1 0A lead-in)
# 40....F8 -- rest of payload
# #comments
my $packet; # whole packet
my @data=(); # split packet
my $CMD; # command/MID equivalent
my $SUB; # subcommand/SID equivalent
my $expected_len; # expected total length of packet
# returns n-byte value
sub get_byte($) {
my ($count) = @_;
my $ret = '';
print " reading $count byte-value: 0x" if $DEBUG > 6;
while ($count--) {
my $h = shift @data;
if (!defined $h) { die "not enough data in packet, at least " . ($count+1) . " missing -- read so far: $ret. Full packet data: $packet" }
$ret .= $h;
}
say "$ret" if $DEBUG > 6;
return $ret;
}
# converts binary string to decimal number
sub bin2dec($) {
my ($bin) = @_;
return oct('0b' . $bin); # funny function name, yeah. See perldoc -f oct
}
# returns variable-length variable
sub get_var() {
my $size = get_byte(1);
print " possible variable-length variable follows: 0x$size" if $DEBUG > 7;
return get_byte(1) if ($size eq '20');
return get_byte(2) if ($size eq '40');
return get_byte(3) if ($size eq '60');
return get_byte(4) if ($size eq '80');
die "unknown length variable of 0x$size -- $_" if ($size eq 'A0') or ($size eq 'C0') or ($size eq 'E0') ; # FIXME - maybe those are special too, maybe not. die for now so we can check...
return $size; # if no special prefix for size, then it is our one-byte value!
}
# like hex(), but autodetect signed values
sub signhex($) {
my ($h) = @_;
my $ret = hex($h);
$ret = unpack('l', pack('L', $ret)) if $h =~ /^FFFF....$/; # FIXME: support any 32-bit? other sizes too?
return $ret;
}
# returns floating point number from packet (encoded as 4-byte)
sub get_float() {
sub float($) { # returns floating point representation
my ($h) = @_;
return sprintf("%.2f", unpack "f*", pack "N*", unpack "V*", pack "H*", $h); # convert (assumed) 4 hex bytes in IEEE-754 floating point. beware of the endian issues!
}
return float get_byte(4);
}
# returns double-precision floating point number from packet (encoded as 8-byte)
sub get_double() {
sub double($) { # returns double precision floating point representation
my ($h) = @_;
my @h2 = reverse map "$_", $h =~ /(..)/g;
return sprintf("%.9f", unpack "d*", pack "H*", join('',@h2)); # convert (assumed) 8 hex bytes in IEEE-754 double precision floating point. beware of the endian issues!
}
return double get_byte(8);
}
# given format string, returns debug text describing packet.
# uses sprintf(3)-alike templates:
# %u is variable length unsigned decimal
# %d is variable length signed decimal
# %x is variable length unsigned hexadecimal
# %f is 4-byte float
# %g is 8-byte double
# %c is 1-byte char
# %s is variable length (AND 0-terminated) array of chars (C string prefixed with length)
# %X (special) is 1-byte hex value
# %B (special) is 1-byte binary value
# %0 (special) - read 1-byte value and discard it, not printing anything
sub parsed_raw($) {
# FIXME - maybe we should just use sprintf() instead trying to reinvent it badly?
sub parse_one($) { # fetches from packet and parses one format variable
my ($format) = @_;
say " parse_one: %$format" if $DEBUG > 9;
given ($format) {
when ('u') { return hex get_var() }
when ('d') { return signhex get_var() }
when ('x') { return get_var() }
when ('f') { return get_float() }
when ('g') { return get_double() }
when ('c') { return chr hex get_var() }
when ('s') {
my $size = hex get_byte(1);
my $r='';
while (my $c=hex get_byte(1)) {
$r .= chr $c;
$size--;
};
if ($size != 0) { die "$size bytes remains in %s of '$r'" }
return $r;
}
when ('X') { return get_byte(1) }
when ('B') { return sprintf ("%08b", hex get_byte(1)) }
when ('0') { get_byte(1); return '' }
default { die "parse_one: unknown format char %$format" }
}
}
my ($str) = @_;
$str =~ s/%(.)/parse_one($1)/ge;
if ($str =~ /%/) { die "unknown format parametar in $str" }
return $str;
}
sub parsed($) {
my ($str) = @_;
return "parsed 0x$CMD$SUB: " . parsed_raw($str);
}
# parse unknown number of subpackets
sub parse_subpackets ($$) {
my ($cmd_sub, $len_sub) = @_;
my $str = '';
while (@data) {
my $sCMD = get_byte(1);
my $sSUB = get_byte(1);
my $sLEN = get_byte(1);
if ("$sCMD$sSUB" ne $cmd_sub) { die "don't understand 0x$CMD$SUB subpacket 0x$sCMD$sSUB($sLEN) -- should be 0x$cmd_sub($len_sub)" }
# elsif ($sLEN != $len_sub) { say "# wrong length of 0x$CMD$SUB subpacket 0x$sCMD$sSUB: $sLEN should be $len_sub" }
my $sDATA = get_byte ($sLEN-3); # sCMD+sSUB+sLEN have already been read
foreach my $d (map "$_", $sDATA =~ /(..)/g) {
$str .= hex($d) . "-";
}
chop $str; $str .= ' ';
$expected_len += $sLEN;
}
chop $str;
return $str;
}
# 50BPS data, parsing one subframe
sub parse_50bps_subframe() {
our $b30_dword = '';
our $old_D29 = '0'; # needed for (32,26) Hamming Code parity calculation
our $old_D30 = '0'; # needed for (32,26) Hamming Code parity calculation
our $word_count = 1; # number of 30-bit words which have already been read
our $inverted_preamble = 0; # if preamble is inverted, need to invert all bits in subframe!
our $parity_failed = 0; # set if parity has failed -- we should discard whole subframe as any data in it is unreliable
sub get_30bits() { # returns 30 bits dword
die "data remaining in b30=$b30_dword, and should be empty!" if length($b30_dword) != 0;
$b30_dword = substr (sprintf ("%032b", hex get_byte(4)),2);
if ($word_count == 1) { # we are reading TLM word
#say "\tword_count=1, reading TLM = " . substr($b30_dword, 0, 8);
if (substr($b30_dword, 0, 8) eq '10001011') { # normal TLM preamble, do nothing
$inverted_preamble = 0;
} elsif (substr($b30_dword, 0, 8) eq '01110100') { # inverted TLM preamble, we'll need to invert all words
$inverted_preamble = 1;
say "\t(inverted preamble 01110100 found; we'll invert all words in this subframe)"
}
}
if ($inverted_preamble) {
#say "\tinverting word $word_count. before = $b30_dword";
$b30_dword =~ tr/01/10/;
#say "\tinverting word $word_count. after = $b30_dword";
}
$word_count++;
}
sub next_x_bits($) { # returns next x bits from 30-bit dword $b30_dword (and truncate it)
my ($num_bits) = @_;
return substr ($b30_dword, 0, $num_bits, '');
}
sub parse_30bit { # parse all bitfields from 30bit word and verify parity
sub eor { # exclusive or / XOR (which works on array of characters)
my $x = (shift)+0; # we convert character "0"/"1" to actual number, so we can XOR it
while (@_) { my $y = (shift)+0; $x = $x^$y; }
return "$x";
}
sub calc_parity($) { # calculates parity information of this word. See IS-GPS-200F.pdf "20.3.5.2 User Parity Algorithm."
my ($data) = @_;
my @D = ('_', split (//, $data)); # D1..D30 == bits as transmited by SV
my @d = ('_'); # d1..d24 == source data bits. We use '_' as index 0, so we can use GPS notation (first bit = #1, not #0)
# say "input D[]=" . join('.', @D);
for my $i (1..24) { $d[$i] = eor($D[$i], $old_D30) };
# say "source d[]=" . join('.', @d);
$D[25] = eor ($old_D29, $d[1], $d[2], $d[3], $d[5], $d[6], $d[10], $d[11], $d[12], $d[13], $d[14], $d[17], $d[18], $d[20], $d[23] );
$D[26] = eor ($old_D30, $d[2], $d[3], $d[4], $d[6], $d[7], $d[11], $d[12], $d[13], $d[14], $d[15], $d[18], $d[19], $d[21], $d[24] );
$D[27] = eor ($old_D29, $d[1], $d[3], $d[4], $d[5], $d[7], $d[8], $d[12], $d[13], $d[14], $d[15], $d[16], $d[19], $d[20], $d[22] );
$D[28] = eor ($old_D30, $d[2], $d[4], $d[5], $d[6], $d[8], $d[9], $d[13], $d[14], $d[15], $d[16], $d[17], $d[20], $d[21], $d[23] );
$D[29] = eor ($old_D30, $d[1], $d[3], $d[5], $d[6], $d[7], $d[9], $d[10], $d[14], $d[15], $d[16], $d[17], $d[18], $d[21], $d[22], $d[24] );
$D[30] = eor ($old_D29, $d[3], $d[5], $d[6], $d[8], $d[9], $d[10], $d[11], $d[13], $d[15], $d[19], $d[22], $d[23], $d[24] );
# say "output D[]=" . join('.', @D);
$old_D29 = $D[29]; $old_D30 = $D[30];
return "$D[25]$D[26]$D[27]$D[28]$D[29]$D[30]"; # return just parity bits (D25..D30)
}
my @ret = ();
my $count = 6;
while (my $bits = shift) {
push @ret, next_x_bits($bits);
$count += $bits;
}
my $verify_parity = next_x_bits(6);
die "did not parse all 30 bits: $count" if $count != 30;
my $calc_parity = calc_parity(join('',@ret) . $verify_parity);
if ($calc_parity eq $verify_parity) {
# say "\t (parity is valid $verify_parity)";
} else {
$parity_failed = 1;
say "\t (parity check HAS FAILED - $calc_parity should be $verify_parity !)";
}
return @ret;
}
sub parse_subframe_data_words_3_10 { # parse rest of subframe (words 3-10) given hash subframe bit definition
my $format_ref = shift;
my $subframe_data = '';
my %ret = (); tie %ret, 'Tie::IxHash';
my $count = 0;
for (3..10) { get_30bits; $subframe_data .= (parse_30bit(30-6))[0] } # DWORD 3-10 : fetch all data (minus parity)
# say "subframe_data = $subframe_data";
foreach my $key (keys %$format_ref) {
my $bits_needed = $$format_ref{$key};
$count += $bits_needed;
#say "format{$key} = $bits_needed (total bits used $count / 192)"; # 192 content bits = (30-6 parity bits) * (10-2 [TLM,HOW] words)
$ret{$key} = bin2dec(substr($subframe_data, $count-$bits_needed, $bits_needed)); # fetch required number of bits and truncate $subframe_data
#say "\tvalue=$ret{$key}";
}
if ($count != 192) { die "invalid number of data bits used $count != 192" }
if ($parity_failed) {
say parsed_raw "\t parity has failed, aborting data parsing.";
return;
}
print "\tSUBFRAME PARSED: ";
foreach my $key (keys %ret) {
next if $key =~ /DELME/; # skip uninteresting keys
print "$key=$ret{$key} ";
}
say '.';
}
# every subframe starts with TLM (telemetry word)
get_30bits;
say "\tTLM=$b30_dword";
my ($TLM_preamble, $TLM_message, $TLM_integrity, $TLM_reserver) = parse_30bit (8,14,1,1);
say "\t preamble=$TLM_preamble extra_integrity=$TLM_integrity";
if ($TLM_preamble ne '10001011') {
say parsed_raw "\t INVALID TLM PREAMBLE (Should be 10001011), aborting subframe processing. Remaining 50Bps raw 30-bit words are: " . "\n\t %X %X %X %X"x9;
return;
}
if ($parity_failed) {
say parsed_raw "\t TLM parity failed, aborting subframe processing. Remaining 50Bps raw 30-bit words are: " . "\n\t %X %X %X %X"x9;
return;
}
# every subframe continues with HOW (handover word)
get_30bits;
say "\tHOW=$b30_dword";
my ($TOW_trunc, $HOW_alert, $HOW_antispoof, $HOW_subframe_ID, $HOW_parityfix) = parse_30bit (17,1,1,3,2);
$TOW_trunc = bin2dec($TOW_trunc); $HOW_subframe_ID=bin2dec($HOW_subframe_ID); # convert to decimal instead of binary
say "\t TOW=$TOW_trunc alert=$HOW_alert antispoof=$HOW_antispoof subframe_ID=$HOW_subframe_ID";
if ($parity_failed) {
say parsed_raw "\t HOW parity failed, aborting subframe processing. Remaining 50Bps raw 30-bit words are: " . "\n\t %X %X %X %X"x8;
return;
}
# FIMXE we should parse depending on subpage only if TLM/HOW passed sanity/parity checks...
given ($HOW_subframe_ID) {
when (1) { # subframe 1 (health and time)
my Readonly %subframe_format;
tie %subframe_format, 'Tie::IxHash', (
WN => 10,
CA_or_P_L2 => 2,
URA_idx => 4,
SV_health => 6,
IODC_MSB => 2,
L2_P => 1,
reserved1_DELME => 23,
reserved2_DELME => 24,
reserved3_DELME => 24,
reserved4_DELME => 16,
Tgd => 8,
IODC_LSB => 8,
t_oc => 16,
a_f2 => 8,
a_f1 => 16,
a_f0 => 22,
parity_fix_DELME => 2
);
parse_subframe_data_words_3_10 (\%subframe_format);
}
when (2) { # subframe 2 (Ephemeris data)
my Readonly %subframe_format;
tie %subframe_format, 'Tie::IxHash', (
IODE => 8,
Crs => 16,
delta_n => 16,
M0 => 8+24,
Cuc => 16,
e => 8+24,
Cus => 16,
sqrt_A => 8+24,
toe => 16,
fit_interval => 1,
AODO => 5,
parity_fix_DELME => 2
);
parse_subframe_data_words_3_10 (\%subframe_format);
}
when (3) { # subframe 3 (Ephemeris data)
my Readonly %subframe_format;
tie %subframe_format, 'Tie::IxHash', (
Cic => 16,
OMEGA0 => 8+24,
Cis => 16,
i0 => 8+24,
Crc => 16,
omega => 8+24,
OMEGA_DOT => 24,
IODE => 8,
IDOT => 14,
parity_fix_DELME => 2
);
parse_subframe_data_words_3_10 (\%subframe_format);
}
default { # FIXME - all other subframes not parsed yet.
# verify parity on rest of words
for my $dword (3..10) {
print "\tDWORD $dword (FIXME unparsed yet) = ";
get_30bits;
my ($dword_data) = parse_30bit(24);
say "\t $dword_data";
}
}
}
# FIXME get remaining stuff
#say parsed_raw "\t50Bps raw 10 30-bit (expanded to 32-bit - FIXME just remaining 8 out of 10) words: " . "\n\t %B %B %B %B"x8;
}
######### MAIN ##########
while (<>) {
next if /^\s*$/; # skip empty lines
next if /^\s*#/; # skip comment lines
if (m{^(\d{2}/\d{2}/\d{4}) (\d{2}:\d{2}:\d{2})(\.\d{3}) \(0\) ([A-F0-9 ]*)\h*(\h+.*?)?$}) {
print "raw: $_" if $DEBUG > 8;
my $date = $1; my $time = $2; my $msec=$3;
$packet = $4;
my $comments = $5;
@data = split ' ', $packet;
if (!@data) {
say "$time$msec empty packet $comments" if $DEBUG > 2;
next;
}
my $LEAD_IN = get_byte(2);
if ($LEAD_IN eq 'E10A' or $LEAD_IN eq 'E109' ) {
$CMD = get_byte(1);
$SUB = get_byte(1);
$expected_len = hex get_byte(1);
my $rest = join '', @data;
my $real_len = 3+ scalar @data; # "expected_len" includes CMD, SUB and expected_len
say " $time $LEAD_IN $CMD $SUB ($expected_len) $rest" if $DEBUG > 3;
print "$time$msec ";
given ("$CMD$SUB") {
when ('1420') {
print parsed "%u ChdevsA: ";
say parse_subpackets('1422', 5);
}
when ('1421') {
print parsed "%u ChdevsB: ";
say parse_subpackets('1422', 5);
}
when ('1423') {
print parsed "%u SSPa:%u: ";
say parse_subpackets('1425', 6);
}
when ('1A00') {
say parsed "%u SSS: Start. %x sssMode%u preposMode %u";
}
when ('1E04') {
say parsed "%u SSS: Commanded l:%u h:%u new:%x";
}
when ('1E0B') {
say parsed "%u ATX: Insample ADC select: %u";
}
when ('1E0D') {
say parsed "%u ATX: Insample mode switch: Mode:%u Ins:%u status=0x%x";
}
when ('1E0F') {
say parsed "%u ATX: Insample Switch Request: Evt:0x%x oldIns:%u newIns:%u";
}
when ('1F00') {
say parsed "%u ATX Init: Seq:%u Mode:%u Ev:0x%x SVList:0x%x 0x%x SVs:%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u";
}
when ('1F01') {
say parsed "%u ATX PP: Seq:%u Mode:%u Ev:0x%x A:%u SVList:0x%x 0x%x SVs:%u %u %u %u %u %u %u %u %u %u %u %u %u %u %u";
}
when ('2208') {
say parsed "%u ACQ: New%u type%u sv%u ch %u D:%u C:%d cno%u t %u ms %u bn %u";
}
when ('2D03') {
say parsed "%u ACQ: New%u type%u sv%u ch%u D:%u C:%d %u %u";
}
when ('2D0B') {
# FIXME is "%x" before "ms:" ok? one byte, but we should get '0000'... huh
say parsed "%u ACQ: %c%u sv%u ch%u CN0:%u D:%u %u C:%f %f Th:%u %u Pk:%u %u %u %x ms:%u vo:%u bs:%u %u %u %u";
}
when ('3D04') {
say parsed "AGC: noise %u %u freq %u gain %u";
}
when ('4E0B') {
say parsed "%u TRACK: StartTrack sv%u ch%u cno%u sync%u val%u frq%u -- FIXME rest: %X %X %X %X %X %X";
}
when ('5400') {
say parsed "%u BEP:SetTime(RTC) YY T:%g %u %u A:%u AC:%f Adj:%g dCB:%f";
}
when ('5413') {
say parsed "CM:RtcGetPrecise: rtcCal:%g rtcDft:%g rtcTT:%g Dt:%g rtcCnt:%u rtcAcq:%u tUnc:%g towCal:%g tow:%g cd:%u";
}
when ('5426') {
say parsed "%u CM:RtcEdgeAlign T:%u dRate:%u count:%u %u Acq:%u Wclk:%u dRtc:%g prevAcq:%u bepDrift:%g rtcDrift:%g";
}
when ('5493') {
say parsed "%u CM:XO:Upd:tVal:%u wn:%u freq:%u freqEst:%u uTNEst:%u uMN:%u uMF:%u uTN:%u uTF:%u uAN:%u uAF:%u uN:%u uF:%u";
}
when ('5494') {
say parsed "%u CM:XO:LastCal:%u freq:%u freqUnc:%u rD:%g rT:%g tr:%u uG:%u fHC:%u mD:%u";
}
when ('5495') {
say parsed "%u CM:XoRampRateCheck:%u reset:%u rr:%u dTemp:%u dt:%u t:%u to:%u";
}
when ('69AB') {
say parsed "%u ATX: Meas Send:%u %u %u %u %u %u %u %u";
}
#### FIXME: E109 uses much of the same infrastucture as E10A, so we keep it here, and hope for no same CMD/SUB pairs :) ####
when ('5800') {
if ($LEAD_IN ne 'E109') { die "0x$CMD$SUB should only be in E109, not $LEAD_IN" }
say parsed "(guess) SiRF GPS SW Version: %s";
}
when ('5802') {
if ($LEAD_IN ne 'E109') { die "0x$CMD$SUB should only be in E109, not $LEAD_IN" }
say parsed "(guess) Compiler: %s";
}
when ('5803') {
if ($LEAD_IN ne 'E109') { die "0x$CMD$SUB should only be in E109, not $LEAD_IN" }
say parsed "(guess) ASIC %s 0x%x";
}
when ('5805') {
if ($LEAD_IN ne 'E109') { die "0x$CMD$SUB should only be in E109, not $LEAD_IN" }
say parsed "(guess) Config: RefClk: %u Hz ClkOffset: %u Hz Unc: %u ppb Lna: %s Baud: %u Backup LDO: %s";
}
when ('5804') {
if ($LEAD_IN ne 'E109') { die "0x$CMD$SUB should only be in E109, not $LEAD_IN" }
say parsed "CPU Speed: %s Cache: %s";
}
when ('5E09') {
if ($LEAD_IN ne 'E109') { die "0x$CMD$SUB should only be in E109, not $LEAD_IN" }
say parsed "%s";
}
when ('5700') {
if ($LEAD_IN ne 'E109') { die "0x$CMD$SUB should only be in E109, not $LEAD_IN" }
say parsed "%s";
}
#### FIXME: end E109 command block ####
default {
say "skip lead-in 0x$LEAD_IN unknown CMD 0x$CMD SUB 0x$SUB $rest (FIXME)" if $DEBUG > 0;
#next; # FIXME DELME
my $count=0;
while (@data) {
if ($data[0] =~ /^[ACE]0/) { # this would die on get_var(). so assume float (athough it might be double, too)
my $unk_float = get_float();
say " unknown var$count (guess float?) = $unk_float";
} else { # guess normal byte
my $unknown = get_var();
my $unk_dec = hex($unknown);
say " unknown var$count = 0x$unknown ($unk_dec)";
}
$count++;
}
# die "FIXME this cmdcode" if "$CMD$SUB" eq '1F01';
# die "FIXME please parse and add this command code $CMD $SUB";
next;
}
}
# if we parsed packet correctly, there should be NO data remaining...
if (@data) {
die "finished decoding packet, but data still remains: @data";
}
if ($real_len != $expected_len) {
die "FATAL: invalid length - found $real_len, expected $expected_len: $_";
}
} elsif ($LEAD_IN =~ /^81..$/) {
say "$time$msec unknown empty-load LEAD-IN of 0x$LEAD_IN";
if (@data) { die "finished decoding packet, but data still remains: @data" }
} elsif ($LEAD_IN =~ /^82..$/) {
say "$time$msec LEAD-IN of 0x82 is part of SiRFbinary MID 64 (0x40) - Nav Library, SID 1 GPS Data (FIXME - more parsing if we need it)";
} elsif ($LEAD_IN =~ /^84..$/) {
say "$time$msec LEAD-IN of $LEAD_IN might be part of SiRFbinary MID 64 (0x40), SID 2 - Navigation Library (NL) Auxiliary Measurement Data GPS Data (FIXME - more parsing of unknown values)";
my $rest = join '', @data;
say " $time $LEAD_IN ($expected_len) $rest" if $DEBUG > 3;
say "\t" . parsed_raw 'unknown %X, maybe_counter %X%X%X%X';
say "\t" . parsed_raw 'unknown header stuff: ' . '%X ' x 43;
my $num_sv = hex get_byte(1);
say "\t" . parsed_raw "number of entries $num_sv (zero %X)";
while ($num_sv--) {
say parsed_raw " SVID: %X (unk: %X%X%X) timeTag:%X%X%X%X codePhase: %X%X%X%X carrierPhase: %X%X%X%X carrierFreq: %X%X%X%X carrierAccel: %X%X millisec: %X%X bit#%X%X%X%X";
say parsed_raw " codeCorrections: %X%X%X%X smoothCode: %X%X%X%X zeroes (%X%X%X%X) codeOffset: %X%X%X%X pseudorangeNoise: %X%X deltaRangeQuality: %X%X phaselockQuality: %X%X";
say parsed_raw " (unk: %X%X%X%X%X%X%X%X%X) -- list of 10 somethings: " . "(%X%X) " x 10;
say parsed_raw " sumI: %X%X sumQ: %X%X SVbit#%X%X%X%X MpathLosDetVal: %X%X MpathOnlyDetVal: %X%X (unk: %X%X%X)";
}
# if we parsed packet correctly, there should be NO data remaining...
if (@data) {
die "finished decoding packet, but data still remains: @data";
}
} elsif ($LEAD_IN =~ /^85..$/) {
say "$time$msec LEAD-IN of 0x$LEAD_IN is (sometimes multiple) part of SiRFbinary MID 8 (0x08) - 50 BPS data subframe, FIXME extract leap-second from this";
say " (debug) all MID8 data: @data";
# FIXME http://www.navipedia.net/index.php/GPS_Navigation_Message
# and http://en.wikipedia.org/wiki/GPS_signals#Navigation_message
# L1 C/A -- The current “legacy” Navigation Message (NAV) is modulated on both carriers at 50 bps. The whole message contains 25 pages (or ’frames’) of 30 seconds each, forming the master frame that takes 12,5 minutes to be transmitted. Every frame is subdivided into 5 sub-frames of 6 seconds each; in turn, every sub-frame consists of 10 words, with 30 bits per word (see figure 3). Every sub-frame always starts with the telemetry word (TLM), which is necessary for synchronism. Next, the transference word (HOW) appears. This word provides time information (seconds of the GPS week), allowing the receiver to acquire the week-long P(Y)-code segment.
# and most of all GPS-Subframe-Decode.git and gps_compendiumgps-x-02007.pdf
#
# 25 pages (in 12.5 minutes). Each page consists of 5 subframes. Each subframe 10 dwords (of 30 bits each).
#
my $num_sub = hex get_byte(1);
say " " . parsed_raw "number of 50Bps sub-frames: $num_sub";
while ($num_sub--) {
say " " . parsed_raw "from SVID %X (unk %X%X%X%X%X%X%X)";
parse_50bps_subframe();
}
# if we parsed packet correctly, there should be NO data remaining...
if (@data) {
die "finished decoding packet, but data still remains: @data";
}
} elsif ($LEAD_IN =~ /^8E01$/) {
say "$time$msec LEAD-IN of 0x$LEAD_IN MAYBE related to SiRFbinary MID 92 (0x5C) - CW Controller Output, SID 1? (logically, but no data match found)";
} elsif ($LEAD_IN =~ /^8E02$/) {
say "$time$msec LEAD-IN of 0x$LEAD_IN equivalent to SiRFbinary MID 92 (0x5C) - CW Controller Output, SID 2! (not interesting?)";
} elsif ($LEAD_IN =~ /^8F0[12]$/) {
say "$time$msec LEAD-IN of 0x$LEAD_IN equivalent to SiRFbinary MID 93 (0x5D) - TCXO Output! (not interesting?)";
} else {
print "$time$msec currently unsupported LEAD-IN $LEAD_IN: $_";
next;
}
} else {
die "FATAL: unknown format for line: $_";
}
}