3 # Feed this the output from readlots
5 # Note that the interval length determination is known to be slightly
6 # buggy at least under certain adverse conditions.
9 # ,value during interval
10 # / ,classification chars
11 # @<1105296455.621813 55..59 5e S-= 1 I112
12 # ^interval ends just before \ decoded bit' `interpretation
13 # `computed min and maxlength
14 # Classification chars
17 # U interval might have been short or long but we don't know
18 # (interval is short iff actual length < 80)
19 # followed by two chars which classify the measurement error etc.
20 # first the min length is classified
21 # < too short for NMRA decoder spec for interval (as classified)
22 # - decoder must decode but power station may not produce, too short
24 # + decoder must decode but power station may not produce, too long
25 # > too long for NMRA decoder spec for interval (as classified)
26 # then the max length, just the same way.
29 # Innn idle/preamble bit, number nnn
30 # F <bytes>... framing bit indicates more data
31 # <bytes> is those already received
32 # B <bytes>(<bitno>) data bit no <bitno>
33 # <bytes> includes byte under construction
34 # P <bytes> packet end bit of good packet, <bytes> includes csum
35 # EP (<error msg>) framing/decoding error
37 use strict qw(vars refs);
40 sub usec_from_to ($$) {
41 my ($from,$to) = @_; # uses $from->{S}, $from->{U}, $to->{S}, $to->{U}
43 $s= $to->{S} - $from->{S};
44 $u= $to->{U} - $from->{U};
45 die "interval $s.$u secs too big" if $s < -100 or $s > 100;
46 return $s * 1000000 + $u;
49 #---------- bit stream (packet) decoder ----------
51 our ($idle_counter, $bitnum, @bytes);
53 sub reset_packet_decoder () {
57 sub packet_decoder_error ($) {
58 printf "EP (%s)\n", $_[0];
59 reset_packet_decoder();
64 if (defined $idle_counter) {
67 printf "I%-4d\n", $idle_counter;
70 if ($idle_counter < 10) {
71 packet_decoder_error("I only $idle_counter");
82 foreach $byte (@bytes) {
83 $checksum ^= hex $byte;
86 $checksum= sprintf '%02x', $checksum;
87 packet_decoder_error("csum err $checksum in @bytes");
95 print "F @bytes...\n";
99 $b= hex $bytes[$#bytes];
100 $b |= ($bit << $bitnum);
101 $bytes[$#bytes]= sprintf "%02x", $b;
102 print "B @bytes($bitnum)\n";
106 #---------- interval -> bit decoder ----------
109 # @valuefor[0] = value for first half of a bit
110 # @valuefor[1] = value for second half of a bit
111 # undef: not seen yet
114 # undef: not in a bit
118 our ($bit_phase_determined);
120 sub interval_mapchar ($$@) {
121 # compares $len with values in @l in turn, selecting
122 # first char from $chars if it is less than $l[0],
123 # otherwise 2nd char from $chars if it is less than $l[1],
124 # etc.; $chars should be one char longer than @l is long.
125 my ($len, $chars, @l) = @_;
126 while (@l && $len >= $l[0]) {
130 return substr($chars,0,1);
133 sub reset_bit_decoder () {
134 printf "-- restarting bit decoder --\n";
137 $bit_phase_determined= 0;
138 reset_packet_decoder();
141 sub found_interval ($$$) {
142 my ($value, $minlen, $maxlen) = @_;
143 die "$value $minlen $maxlen" if $minlen > $maxlen;
145 printf "%6.2f .. %6.2f %s ", $minlen, $maxlen, $value;
147 my ($class, $fudge_class);
148 my (@nomlens,$min_char,$max_char,$nomlens_chars);
149 my ($bit_half, $bit_value);
151 # $minlen and $maxlen are actually differences of rounded values;
152 # so there's an extra 1 us of slop in each of them (from 2x 0.5us
153 # rounding error). Ie, real value satisfies
154 # $minlen - 1 < $real_value < $maxlen + 1
158 @nomlens= qw(90 95 10000 12000);
159 } elsif ($maxlen < 80) {
161 @nomlens= qw(52 55 61 64);
164 @nomlens= qw(52 55 61 64);
166 $nomlens_chars= '<-=+>';
167 $min_char= interval_mapchar($minlen-0.9, $nomlens_chars, @nomlens);
168 $max_char= interval_mapchar($maxlen+0.9, $nomlens_chars, @nomlens);
171 $class, $min_char, $max_char);
173 if (defined $in_bit and (($class eq 'U') xor ($in_bit eq 'U'))) {
174 $fudge_class= $class.$in_bit;
175 $fudge_class =~ s/U//;
176 $class= $in_bit= $fudge_class;
177 printf("%s ",$fudge_class);
182 if (defined $in_bit and $in_bit ne $class) {
183 if ($bit_phase_determined) {
184 printf("E (exp'd %s)\n", $in_bit);
190 $bit_phase_determined= 1;
192 $bit_half= !!defined $in_bit;
193 if (!exists $valuefor[$bit_half]) {
194 $valuefor[$bit_half]= $value;
196 if ($valuefor[$bit_half] ne $value) {
197 printf("E (%s, exp'd %s)\n", $bit_half ? '2nd' : '1st',
198 $valuefor[$bit_half]);
207 reset_packet_decoder();
210 $bit_value= !!($class eq 'S');
211 printf " %d ", $bit_value;
212 found_bit($bit_value);
219 #---------- interval scanner ----------
221 our ($begintmin,$begintmax);
222 our ($lastt,$lastvalue);
224 sub found_datapoint ($$) {
226 # called when we find that $value was measured at $t
228 if ($value > -0.01 && $value < 0.01) {
229 return; # treat as zero, ignore
232 if (defined $lastt && $value * $lastvalue < 0) {
233 if (defined $begintmin) {
234 printf "@%10.2f ", $t;
235 found_interval($value < 0 ? 'H' : 'L',
236 $lastt-$begintmax, $t-$begintmin);
245 #---------- datapoint reader ----------
253 m/^\s*([-.0-9e]+)\s+([-.0-9e]+)\s*$/ or die "$_ ?";
254 found_datapoint($1 * 1e6, $2);
256 die $! if STDIN->error;
260 exec './display-nmra-decoded <t.nmra.dat - 2>&1 |less';
262 } elsif (@ARGV==1 and $ARGV[0] eq '-') {
268 die $! if STDOUT->error;