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);
41 sub usec_from_to ($$) {
42 my ($from,$to) = @_; # uses $from->{S}, $from->{U}, $to->{S}, $to->{U}
44 $s= $to->{S} - $from->{S};
45 $u= $to->{U} - $from->{U};
46 die "interval $s.$u secs too big" if $s < -100 or $s > 100;
47 return $s * 1000000 + $u;
50 #---------- bit stream (packet) decoder ----------
52 our ($idle_counter, $bitnum, @bytes);
54 sub reset_packet_decoder () {
58 sub packet_decoder_error ($) {
59 printf "EP (%s)\n", $_[0];
60 reset_packet_decoder();
65 if (defined $idle_counter) {
68 printf "I%-4d\n", $idle_counter;
71 if ($idle_counter < 10) {
72 packet_decoder_error("I only $idle_counter");
83 foreach $byte (@bytes) {
84 $checksum ^= hex $byte;
87 $checksum= sprintf '%02x', $checksum;
88 packet_decoder_error("csum err $checksum in @bytes");
96 print "F @bytes...\n";
100 $b= hex $bytes[$#bytes];
101 $b |= ($bit << $bitnum);
102 $bytes[$#bytes]= sprintf "%02x", $b;
103 print "B @bytes($bitnum)\n";
107 #---------- interval -> bit decoder ----------
110 # @valuefor[0] = value for first half of a bit
111 # @valuefor[1] = value for second half of a bit
112 # undef: not seen yet
115 # undef: not in a bit
119 our ($bit_phase_determined);
121 sub interval_mapchar ($$@) {
122 # compares $len with values in @l in turn, selecting
123 # first char from $chars if it is less than $l[0],
124 # otherwise 2nd char from $chars if it is less than $l[1],
125 # etc.; $chars should be one char longer than @l is long.
126 my ($len, $chars, @l) = @_;
127 while (@l && $len >= $l[0]) {
131 return substr($chars,0,1);
134 sub reset_bit_decoder () {
135 printf "-- restarting bit decoder --\n";
138 $bit_phase_determined= 0;
139 reset_packet_decoder();
142 sub found_interval ($$$) {
143 my ($value, $minlen, $maxlen) = @_;
144 die "$value $minlen $maxlen" if $minlen > $maxlen;
146 printf "%6.2f .. %6.2f %s ", $minlen, $maxlen, $value;
148 my ($class, $fudge_class);
149 my (@nomlens,$min_char,$max_char,$nomlens_chars);
150 my ($bit_half, $bit_value);
152 # $minlen and $maxlen are actually differences of rounded values;
153 # so there's an extra 1 us of slop in each of them (from 2x 0.5us
154 # rounding error). Ie, real value satisfies
155 # $minlen - 1 < $real_value < $maxlen + 1
159 @nomlens= qw(90 95 10000 12000);
160 } elsif ($maxlen < 80) {
162 @nomlens= qw(52 55 61 64);
165 @nomlens= qw(52 55 61 64);
167 $nomlens_chars= '<-=+>';
168 $min_char= interval_mapchar($minlen-0.9, $nomlens_chars, @nomlens);
169 $max_char= interval_mapchar($maxlen+0.9, $nomlens_chars, @nomlens);
172 $class, $min_char, $max_char);
174 if (defined $in_bit and (($class eq 'U') xor ($in_bit eq 'U'))) {
175 $fudge_class= $class.$in_bit;
176 $fudge_class =~ s/U//;
177 $class= $in_bit= $fudge_class;
178 printf("%s ",$fudge_class);
183 if (defined $in_bit and $in_bit ne $class) {
184 if ($bit_phase_determined) {
185 printf("E (exp'd %s)\n", $in_bit);
191 $bit_phase_determined= 1;
193 $bit_half= !!defined $in_bit;
194 if (!exists $valuefor[$bit_half]) {
195 $valuefor[$bit_half]= $value;
197 if ($valuefor[$bit_half] ne $value) {
198 printf("E (%s, exp'd %s)\n", $bit_half ? '2nd' : '1st',
199 $valuefor[$bit_half]);
208 reset_packet_decoder();
211 $bit_value= !!($class eq 'S');
212 printf " %d ", $bit_value;
213 found_bit($bit_value);
220 #---------- interval scanner ----------
222 our ($begintmin,$begintmax);
223 our ($lastt,$lastvalue);
225 sub found_datapoint ($$) {
227 # called when we find that $value was measured at $t
229 if ($value > -0.01 && $value < 0.01) {
230 return; # treat as zero, ignore
233 if (defined $lastt && $value * $lastvalue < 0) {
234 if (defined $begintmin) {
235 printf "@%10.2f ", $t;
236 found_interval($value < 0 ? 'H' : 'L',
237 $lastt-$begintmax, $t-$begintmin);
246 #---------- datapoint reader ----------
248 our $filter= NmraAssist::HighPassFilter->new();
256 m/^\s*([-.0-9e]+)\s+([-.0-9e]+)\s*$/ or die "$_ ?";
257 my ($t, $value) = ($1,$2);
258 $value= $filter->transform($t, $value);
260 found_datapoint($t, $value);
262 die $! if STDIN->error;
266 exec './display-nmra-decoded <t.nmra.dat - 2>&1 |less';
268 } elsif (@ARGV==1 and $ARGV[0] eq '-') {
274 die $! if STDOUT->error;