/[RFID]/3m-810.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /3m-810.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 29 by dpavlin, Mon Apr 6 13:10:40 2009 UTC revision 56 by dpavlin, Fri Jun 26 11:46:45 2009 UTC
# Line 8  use Data::Dump qw/dump/; Line 8  use Data::Dump qw/dump/;
8  use Carp qw/confess/;  use Carp qw/confess/;
9  use Getopt::Long;  use Getopt::Long;
10  use File::Slurp;  use File::Slurp;
11    use JSON;
12    
13  use IO::Socket::INET;  use IO::Socket::INET;
14    
15  my $meteor_server = '192.168.1.13:4671';  my $debug = 0;
16    
17    my $tags_data;
18    my $tags_security;
19    my $visible_tags;
20    
21    my $meteor_server; # = '192.168.1.13:4671';
22  my $meteor_fh;  my $meteor_fh;
23    
24  sub meteor {  sub meteor {
# Line 19  sub meteor { Line 26  sub meteor {
26          push @a, scalar localtime() if $a[0] =~ m{^info};          push @a, scalar localtime() if $a[0] =~ m{^info};
27    
28          if ( ! defined $meteor_fh ) {          if ( ! defined $meteor_fh ) {
29                  warn "# open connection to $meteor_server";                  if ( $meteor_fh =
30                  $meteor_fh = IO::Socket::INET->new(                                  IO::Socket::INET->new(
31                                  PeerAddr => $meteor_server,                                          PeerAddr => $meteor_server,
32                                  Timeout => 1,                                          Timeout => 1,
33                  ) || warn "can't connect to meteor $meteor_server: $!"; # FIXME warn => die for production                                  )
34                  $meteor_fh = 0; # don't try again                  ) {
35                            warn "# meteor connected to $meteor_server";
36                    } else {
37                            warn "can't connect to meteor $meteor_server: $!";
38                            $meteor_fh = 0;
39                    }
40          }          }
41    
42          warn ">> meteor ",dump( @a );          if ( $meteor_fh ) {
43          print $meteor_fh "ADDMESSAGE test ",join('|',@a),"\n" if $meteor_fh;                  warn ">> meteor ",dump( @a );
44                    print $meteor_fh "ADDMESSAGE test ",join('|',@a),"\n"
45            }
46  }  }
47    
48  my $debug = 0;  my $listen_port = 9000;                  # pick something not in use
49    sub http_server {
50    
51            my $server = IO::Socket::INET->new(
52                    Proto     => 'tcp',
53                    LocalPort => $listen_port,
54                    Listen    => SOMAXCONN,
55                    Reuse     => 1
56            );
57                                                                      
58            die "can't setup server" unless $server;
59    
60            print "Server $0 accepting clients at http://localhost:$listen_port/\n";
61    
62            sub static {
63                    my ($client,$path) = @_;
64    
65                    $path = "www/$path";
66                    $path .= 'rfid.html' if $path =~ m{/$};
67    
68                    return unless -e $path;
69    
70                    my $type = 'text/plain';
71                    $type = 'text/html' if $path =~ m{\.htm};
72                    $type = 'application/javascript' if $path =~ m{\.js};
73    
74                    print $client "HTTP/1.0 200 OK\r\nContent-Type: $type\r\n\r\n";
75                    open(my $html, $path);
76                    while(<$html>) {
77                            print $client $_;
78                    }
79                    close($html);
80    
81                    return $path;
82            }
83    
84            while (my $client = $server->accept()) {
85                    $client->autoflush(1);
86                    my $request = <$client>;
87    
88                    warn "WEB << $request\n" if $debug;
89    
90                    if ($request =~ m{^GET (/.*) HTTP/1.[01]}) {
91                            my $method = $1;
92                            my $param;
93                            if ( $method =~ s{\?(.+)}{} ) {
94                                    foreach my $p ( split(/[&;]/, $1) ) {
95                                            my ($n,$v) = split(/=/, $p, 2);
96                                            $param->{$n} = $v;
97                                    }
98                                    warn "WEB << param: ",dump( $param ) if $debug;
99                            }
100                            if ( my $path = static( $client,$1 ) ) {
101                                    warn "WEB >> $path" if $debug;
102                            } elsif ( $method =~ m{/scan} ) {
103                                    my $tags = scan_for_tags();
104                                    my $json = { time => time() };
105                                    map {
106                                            my $d = decode_tag($_);
107                                            $d->{sid} = $_;
108                                            $d->{security} = $tags_security->{$_};
109                                            push @{ $json->{tags} },  $d;
110                                    } keys %$tags;
111                                    print $client "HTTP/1.0 200 OK\r\nContent-Type: application/x-javascript\r\n\r\n",
112                                            $param->{callback}, "(", to_json($json), ")\r\n";
113                            } else {
114                                    print $client "HTTP/1.0 404 Unkown method\r\n";
115                            }
116                    } else {
117                            print $client "HTTP/1.0 500 No method\r\n";
118                    }
119                    close $client;
120            }
121    
122            die "server died";
123    }
124    
125    
126    my $last_message = {};
127    sub _message {
128            my $type = shift @_;
129            my $text = join(' ',@_);
130            my $last = $last_message->{$type};
131            if ( $text ne $last ) {
132                    warn $type eq 'diag' ? '# ' : '', $text, "\n";
133                    $last_message->{$type} = $text;
134            }
135    }
136    
137    sub _log { _message('log',@_) };
138    sub diag { _message('diag',@_) };
139    
140  my $device    = "/dev/ttyUSB0";  my $device    = "/dev/ttyUSB0";
141  my $baudrate  = "19200";  my $baudrate  = "19200";
# Line 41  my $stopbits  = "1"; Line 145  my $stopbits  = "1";
145  my $handshake = "none";  my $handshake = "none";
146    
147  my $program_path = './program/';  my $program_path = './program/';
148    my $secure_path = './secure/';
149    
150    # http server
151    my $http_server = 1;
152    
153    # 3M defaults: 8,4
154    my $max_rfid_block = 16;
155    my $read_blocks = 8;
156    
157  my $response = {  my $response = {
158          'd500090400110a0500027250'                              => 'version?',          'd500090400110a0500027250'                              => 'version?',
# Line 63  GetOptions( Line 175  GetOptions(
175          'stopbits=i'  => \$stopbits,          'stopbits=i'  => \$stopbits,
176          'handshake=s' => \$handshake,          'handshake=s' => \$handshake,
177          'meteor=s'    => \$meteor_server,          'meteor=s'    => \$meteor_server,
178            'http-server!' => \$http_server,
179  ) or die $!;  ) or die $!;
180    
181  my $verbose = $debug > 0 ? $debug-- : 0;  my $verbose = $debug > 0 ? $debug-- : 0;
# Line 98  it under the same terms ans Perl itself. Line 211  it under the same terms ans Perl itself.
211    
212  =cut  =cut
213    
214  my $tags_data;  my $item_type = {
215  my $visible_tags;          1 => 'Book',
216            6 => 'CD/CD ROM',
217            2 => 'Magazine',
218            13 => 'Book with Audio Tape',
219            9 => 'Book with CD/CD ROM',
220            0 => 'Other',
221    
222            5 => 'Video',
223            4 => 'Audio Tape',
224            3 => 'Bound Journal',
225            8 => 'Book with Diskette',
226            7 => 'Diskette',
227    };
228    
229    warn "## known item type: ",dump( $item_type ) if $debug;
230    
231  my $port=new Device::SerialPort($device) || die "can't open serial port $device: $!\n";  my $port=new Device::SerialPort($device) || die "can't open serial port $device: $!\n";
232  warn "using $device $handshake $baudrate $databits $parity $stopbits" if $debug;  warn "using $device $handshake $baudrate $databits $parity $stopbits" if $debug;
# Line 109  $databits=$port->databits($databits); Line 236  $databits=$port->databits($databits);
236  $parity=$port->parity($parity);  $parity=$port->parity($parity);
237  $stopbits=$port->stopbits($stopbits);  $stopbits=$port->stopbits($stopbits);
238    
239  print "## using $device $baudrate $databits $parity $stopbits debug: $debug verbose: $verbose\n";  warn "## using $device $baudrate $databits $parity $stopbits debug: $debug verbose: $verbose\n";
240    
241  # Just in case: reset our timing and buffers  # Just in case: reset our timing and buffers
242  $port->lookclear();  $port->lookclear();
# Line 132  cmd( 'D5 00  05   04 00 11 Line 259  cmd( 'D5 00  05   04 00 11
259  cmd( 'D6 00  0C   13  04  01 00  02 00  03 00  04 00   AAF2','FIXME: stats?',  cmd( 'D6 00  0C   13  04  01 00  02 00  03 00  04 00   AAF2','FIXME: stats?',
260       'D6 00  0C   13  00  02 01 01 03 02 02 03  00     E778', sub { assert() }  );       'D6 00  0C   13  00  02 01 01 03 02 02 03  00     E778', sub { assert() }  );
261    
262  # start scanning for tags  sub scan_for_tags {
263    
264  cmd( 'D6 00  05   FE     00  05         FA40', "scan for tags, retry $_",          my @tags;
          'D6 00  0F   FE  00 00  05 ', sub { # 01 E00401003123AA26  941A         # seen, serial length: 8  
                 my $rest = shift || die "no rest?";  
                 my $nr = ord( substr( $rest, 0, 1 ) );  
   
                 if ( ! $nr ) {  
                         print "no tags in range\n";  
                         update_visible_tags();  
                         meteor( 'info-none-in-range' );  
                         $tags_data = {};  
                 } else {  
265    
266                          my $tags = substr( $rest, 1 );          cmd( 'D6 00  05   FE     00  05         FA40', "scan for tags",
267                     'D6 00  0F   FE  00 00  05 ', sub { # 01 E00401003123AA26  941A         # seen, serial length: 8
268                            my $rest = shift || die "no rest?";
269                            my $nr = ord( substr( $rest, 0, 1 ) );
270    
271                            if ( ! $nr ) {
272                                    _log "no tags in range\n";
273                                    update_visible_tags();
274                                    meteor( 'info-none-in-range' );
275                                    $tags_data = {};
276                            } else {
277    
278                          my $tl = length( $tags );                                  my $tags = substr( $rest, 1 );
279                          die "wrong length $tl for $nr tags: ",dump( $tags ) if $tl =! $nr * 8;                                  my $tl = length( $tags );
280                                    die "wrong length $tl for $nr tags: ",dump( $tags ) if $tl =! $nr * 8;
281    
282                          my @tags;                                  push @tags, uc(unpack('H16', substr($tags, $_ * 8, 8))) foreach ( 0 .. $nr - 1 );
283                          push @tags, uc(unpack('H16', substr($tags, $_ * 8, 8))) foreach ( 0 .. $nr - 1 );                                  warn "## tags ",as_hex($tags), " [$tl] = ",dump( $tags ) if $debug;
284                          warn "## tags ",as_hex($tags), " [$tl] = ",dump( $tags ) if $debug;                                  _log "$nr tags in range: ", join(',', @tags ) , "\n";
                         print "$nr tags in range: ", join(',', @tags ) , "\n";  
285    
286                          meteor( 'info-in-range', join(' ',@tags));                                  meteor( 'info-in-range', join(' ',@tags));
287    
288                          update_visible_tags( @tags );                                  update_visible_tags( @tags );
289                            }
290                  }                  }
291          }          );
292  ) while(1);  
293  #) foreach ( 1 .. 100 );          diag "tags: ",dump( @tags );
294            return $tags_data;
295    
296    }
297    
298    # start scanning for tags
299    
300    if ( $http_server ) {
301            http_server;
302    } else {
303            scan_for_tags while 1;
304    }
305    
306    die "over and out";
307    
308  sub update_visible_tags {  sub update_visible_tags {
309          my @tags = @_;          my @tags = @_;
# Line 173  sub update_visible_tags { Line 312  sub update_visible_tags {
312          $visible_tags = {};          $visible_tags = {};
313    
314          foreach my $tag ( @tags ) {          foreach my $tag ( @tags ) {
315                    $visible_tags->{$tag}++;
316                  if ( ! defined $last_visible_tags->{$tag} ) {                  if ( ! defined $last_visible_tags->{$tag} ) {
317                          if ( defined $tags_data->{$tag} ) {                          if ( defined $tags_data->{$tag} ) {
318  #                               meteor( 'in-range', $tag );  #                               meteor( 'in-range', $tag );
# Line 180  sub update_visible_tags { Line 320  sub update_visible_tags {
320                                  meteor( 'read', $tag );                                  meteor( 'read', $tag );
321                                  read_tag( $tag );                                  read_tag( $tag );
322                          }                          }
                         $visible_tags->{$tag}++;  
323                  } else {                  } else {
324                          warn "## using cached data for $tag" if $debug;                          warn "## using cached data for $tag" if $debug;
325                  }                  }
# Line 190  sub update_visible_tags { Line 329  sub update_visible_tags {
329                                  meteor( 'write', $tag );                                  meteor( 'write', $tag );
330                                  write_tag( $tag );                                  write_tag( $tag );
331                  }                  }
332                    if ( -e "$secure_path/$tag" ) {
333                                    meteor( 'secure', $tag );
334                                    secure_tag( $tag );
335                    }
336          }          }
337    
338          foreach my $tag ( keys %$last_visible_tags ) {          foreach my $tag ( keys %$last_visible_tags ) {
# Line 206  my $tag_data_block; Line 349  my $tag_data_block;
349  sub read_tag_data {  sub read_tag_data {
350          my ($start_block,$rest) = @_;          my ($start_block,$rest) = @_;
351          die "no rest?" unless $rest;          die "no rest?" unless $rest;
352    
353            my $last_block = 0;
354    
355          warn "## DATA [$start_block] ", dump( $rest ) if $debug;          warn "## DATA [$start_block] ", dump( $rest ) if $debug;
356          my $tag = uc(unpack('H16',substr( $rest, 0, 8 )));          my $tag = uc(unpack('H16',substr( $rest, 0, 8 )));
357          my $blocks = ord(substr($rest,8,1));          my $blocks = ord(substr($rest,8,1));
# Line 215  sub read_tag_data { Line 361  sub read_tag_data {
361                  warn "## block ",as_hex( $block ) if $debug;                  warn "## block ",as_hex( $block ) if $debug;
362                  my $ord   = unpack('v',substr( $block, 0, 2 ));                  my $ord   = unpack('v',substr( $block, 0, 2 ));
363                  my $expected_ord = $nr + $start_block;                  my $expected_ord = $nr + $start_block;
364                  die "got block $ord, expected block $expected_ord from ",dump( $block ) if $ord != $expected_ord;                  warn "got block $ord, expected block $expected_ord from ",dump( $block ) if $ord != $expected_ord;
365                  my $data  = substr( $block, 2 );                  my $data  = substr( $block, 2 );
366                  die "data payload should be 4 bytes" if length($data) != 4;                  die "data payload should be 4 bytes" if length($data) != 4;
367                  warn sprintf "## tag %9s %02d %s |%-4s|\n", $tag, $ord, as_hex( $data ), $data;                  warn sprintf "## tag %9s %02d: %s |%-4s|\n", $tag, $ord, as_hex( $data ), $data;
368                  $tag_data_block->{$tag}->[ $ord ] = $data;                  $tag_data_block->{$tag}->[ $ord ] = $data;
369                    $last_block = $ord;
370          }          }
371          $tags_data->{ $tag } = join('', @{ $tag_data_block->{$tag} });          $tags_data->{ $tag } = join('', @{ $tag_data_block->{$tag} });
372          print "DATA $tag ",dump( $tags_data ), "\n";  
373            my $item_type_nr = ord(substr( $tags_data->{$tag}, 3, 1 ));
374            print "DATA $tag ",dump( $tags_data ), " item type: ", ( $item_type->{ $item_type_nr } || "UNKWOWN '$item_type_nr'" ), "\n";
375    
376            return $last_block + 1;
377    }
378    
379    sub decode_tag {
380            my $tag = shift;
381    
382            my $data = $tags_data->{$tag} || die "no data for $tag";
383    
384            my ( $u1, $set_item, $u2, $type, $content, $br_lib, $custom ) = unpack('C4Z16Nl>',$data);
385            my $hash = {
386                    u1 => $u1,
387                    u2 => $u2,
388                    set => ( $set_item & 0xf0 ) >> 4,
389                    total => ( $set_item & 0x0f ),
390    
391                    type => $type,
392                    content => $content,
393    
394                    branch => $br_lib >> 20,
395                    library => $br_lib & 0x000fffff,
396    
397                    custom => $custom,
398            };
399    
400            return $hash;
401  }  }
402    
403  sub read_tag {  sub read_tag {
# Line 232  sub read_tag { Line 407  sub read_tag {
407    
408          print "read_tag $tag\n";          print "read_tag $tag\n";
409    
410          cmd(          my $start_block = 0;
411                  "D6 00  0D  02      $tag   00   03     1CC4", "read $tag offset: 0 blocks: 3",  
412                  "D6 00  0F  FE  00 00  05 01   $tag    941A", sub {          while ( $start_block < $max_rfid_block ) {
413                          print "FIXME: tag $tag ready?\n";  
414                  },                  cmd(
415                  "D6 00  1F  02 00", sub { # $tag  03   00 00   04 11 00 01   01 00   31 32 33 34   02 00   35 36 37 38    531F\n";                           sprintf( "D6 00  0D  02      $tag   %02x   %02x     ffff", $start_block, $read_blocks ),
416                          read_tag_data( 0, @_ );                                  "read $tag offset: $start_block blocks: $read_blocks",
417                  },                          "D6 00  1F  02 00", sub { # $tag  03   00 00   04 11 00 01   01 00   31 32 33 34   02 00   35 36 37 38    531F\n";
418          );                                  $start_block = read_tag_data( $start_block, @_ );
419                                    warn "# read tag upto $start_block\n";
420                            },
421                            "D6 00  0F  FE  00 00  05 01   $tag    941A", sub {
422                                    print "FIXME: tag $tag ready? (expected block read instead)\n";
423                            },
424                    );
425    
426            }
427    
428            my $security;
429    
430          cmd(          cmd(
431                  "D6 00  0D  02      $tag   03   04     3970", "read $tag offset: 3 blocks: 4",                  "D6 00 0B 0A $tag 1234", "check security $tag",
432                  "D6 00  25  02 00", sub { # $tag   04                         03 00   30 30 00 00   04 00   00 00 00 00                    "D6 00 0D 0A 00", sub {
433                          read_tag_data( 3, @_ );                          my $rest = shift;
434                            my $from_tag;
435                            ( $from_tag, $security ) = ( substr($rest,0,8), substr($rest,8,1) );
436                            die "security from other tag: ",as_hex( $from_tag ) if $from_tag ne str2bytes( $tag );
437                            $security = as_hex( $security );
438                            $tags_security->{$tag} = $security;
439                            warn "# SECURITY $tag = $security\n";
440                  }                  }
441          );          );
442    
443            print "TAG $tag ", dump(decode_tag( $tag ));
444  }  }
445    
446  sub write_tag {  sub write_tag {
# Line 257  sub write_tag { Line 449  sub write_tag {
449          my $path = "$program_path/$tag";          my $path = "$program_path/$tag";
450    
451          my $data = read_file( $path );          my $data = read_file( $path );
452            my $hex_data;
453    
454            if ( $data =~ s{^hex\s+}{} ) {
455                    $hex_data = $data;
456                    $hex_data =~ s{\s+}{}g;
457            } else {
458    
459                    $data .= "\0" x ( 4 - ( length($data) % 4 ) );
460    
461          print "write_tag $tag = $data\n";                  my $max_len = $max_rfid_block * 4;
462    
463                    if ( length($data) > $max_len ) {
464                            $data = substr($data,0,$max_len);
465                            warn "strip content to $max_len bytes\n";
466                    }
467    
468                    $hex_data = unpack('H*', $data);
469            }
470    
471            my $len = length($hex_data) / 2;
472            # pad to block size
473            $hex_data .= '00' x ( 4 - $len % 4 );
474            my $blocks = sprintf('%02x', length($hex_data) / 4);
475    
476            print "write_tag $tag = ",dump( $data ), " [$len/$blocks] == $hex_data\n";
477    
478          cmd(          cmd(
479                  "D6 00  26  04  $tag  00 06 00  04 11 00 01  61 61 61 61  62 62 62 62  63 63 63 63  64 64 64 64  00 00 00 00  FD3B", "write $tag",                  "d6 00  ff  04  $tag  00 $blocks 00  $hex_data  ffff", "write $tag",
480                  "D6 00  0D  04 00  $tag  06  AFB1", sub { assert() },                  "d6 00  0d  04 00  $tag  $blocks  afb1", sub { assert() },
481          ) foreach ( 1 .. 3 ); # XXX 3M software does this three times!          ); # foreach ( 1 .. 3 ); # XXX 3m software does this three times!
482    
483          my $to = $path;          my $to = $path;
484          $to .= '.' . time();          $to .= '.' . time();
# Line 271  sub write_tag { Line 486  sub write_tag {
486          rename $path, $to;          rename $path, $to;
487          print ">> $to\n";          print ">> $to\n";
488    
489            delete $tags_data->{$tag};      # force re-read of tag
490    }
491    
492    sub secure_tag {
493            my ($tag) = @_;
494    
495            my $path = "$secure_path/$tag";
496            my $data = substr(read_file( $path ),0,2);
497    
498            cmd(
499                    "d6 00  0c  09  $tag $data 1234", "secure $tag -> $data",
500                    "d6 00  0c  09 00  $tag  1234", sub { assert() },
501            );
502    
503            my $to = $path;
504            $to .= '.' . time();
505    
506            rename $path, $to;
507            print ">> $to\n";
508  }  }
509    
510  exit;  exit;
# Line 305  sub writechunk Line 539  sub writechunk
539  {  {
540          my $str=shift;          my $str=shift;
541          my $count = $port->write($str);          my $count = $port->write($str);
542            my $len = length($str);
543            die "wrong write length $count != $len in ",as_hex( $str ) if $count != $len;
544          print "#> ", as_hex( $str ), "\t[$count]\n" if $debug;          print "#> ", as_hex( $str ), "\t[$count]\n" if $debug;
545  }  }
546    
# Line 371  sub crcccitt { Line 607  sub crcccitt {
607  sub checksum {  sub checksum {
608          my ( $bytes, $checksum ) = @_;          my ( $bytes, $checksum ) = @_;
609    
         my $xor = crcccitt( substr($bytes,1) ); # skip D6  
         warn "## checksum ",dump( $bytes, $xor, $checksum ) if $debug;  
   
610          my $len = ord(substr($bytes,2,1));          my $len = ord(substr($bytes,2,1));
611          my $len_real = length($bytes) - 1;          my $len_real = length($bytes) - 1;
612    
613          if ( $len_real != $len ) {          if ( $len_real != $len ) {
614                  print "length wrong: $len_real != $len\n";                  print "length wrong: $len_real != $len\n";
615                  $bytes = substr($bytes,0,2) . chr($len_real) . substr($bytes,4);                  $bytes = substr($bytes,0,2) . chr($len_real) . substr($bytes,3);
616          }          }
617    
618            my $xor = crcccitt( substr($bytes,1) ); # skip D6
619            warn "## checksum ",dump( $bytes, $xor, $checksum ) if $debug;
620    
621          if ( defined $checksum && $xor ne $checksum ) {          if ( defined $checksum && $xor ne $checksum ) {
622                  print "checksum doesn't match: ", as_hex($xor), " != ", as_hex($checksum), " data: ", as_hex($bytes), "\n";                  print "checksum doesn't match: ", as_hex($xor), " != ", as_hex($checksum), " data: ", as_hex($bytes), "\n";
623                  return $bytes . $xor;                  return $bytes . $xor;
# Line 392  sub checksum { Line 628  sub checksum {
628  our $dispatch;  our $dispatch;
629    
630  sub readchunk {  sub readchunk {
631          sleep 1;        # FIXME remove  #       sleep 1;        # FIXME remove
632    
633          # read header of packet          # read header of packet
634          my $header = read_bytes( 2, 'header' );          my $header = read_bytes( 2, 'header' );
# Line 421  sub readchunk { Line 657  sub readchunk {
657          warn "?? payload dispatch to ",dump( $payload, $dispatch, $to ) if $debug;          warn "?? payload dispatch to ",dump( $payload, $dispatch, $to ) if $debug;
658    
659          if ( defined $to ) {          if ( defined $to ) {
660                  my $rest = substr( $payload, length($to) );                  my $rest = substr( $payload, length($to) ) if length($to) < length($payload);
661                  warn "## DISPATCH payload to with rest", dump( $payload, $to, $rest ) if $debug;                  warn "## DISPATCH payload to with rest", dump( $payload, $to, $rest ) if $debug;
662                  $dispatch->{ $to }->( $rest );                  $dispatch->{ $to }->( $rest );
663          } else {          } else {
664                  print "NO DISPATCH for ",dump( $full ),"\n";                  print "NO DISPATCH for ",as_hex( $full ),"\n";
665          }          }
666    
667          return $data;          return $data;

Legend:
Removed from v.29  
changed lines
  Added in v.56

  ViewVC Help
Powered by ViewVC 1.1.26