/[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

Annotation of /3m-810.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 39 - (hide annotations)
Mon Jun 1 21:07:11 2009 UTC (14 years, 10 months ago) by dpavlin
File MIME type: text/plain
File size: 15484 byte(s)
fix few warnings

1 dpavlin 1 #!/usr/bin/perl
2    
3     use Device::SerialPort qw (:STAT);
4     use strict;
5     use warnings;
6    
7     use Data::Dump qw/dump/;
8 dpavlin 2 use Carp qw/confess/;
9 dpavlin 19 use Getopt::Long;
10 dpavlin 29 use File::Slurp;
11 dpavlin 1
12 dpavlin 23 use IO::Socket::INET;
13    
14 dpavlin 25 my $meteor_server = '192.168.1.13:4671';
15 dpavlin 26 my $meteor_fh;
16 dpavlin 23
17     sub meteor {
18 dpavlin 25 my @a = @_;
19     push @a, scalar localtime() if $a[0] =~ m{^info};
20    
21 dpavlin 26 if ( ! defined $meteor_fh ) {
22 dpavlin 35 if ( $meteor_fh =
23     IO::Socket::INET->new(
24     PeerAddr => $meteor_server,
25     Timeout => 1,
26     )
27     ) {
28     warn "# meteor connected to $meteor_server";
29     } else {
30     warn "can't connect to meteor $meteor_server: $!";
31     $meteor_fh = 0;
32     }
33 dpavlin 26 }
34    
35 dpavlin 35 if ( $meteor_fh ) {
36     warn ">> meteor ",dump( @a );
37     print $meteor_fh "ADDMESSAGE test ",join('|',@a),"\n"
38     }
39 dpavlin 23 }
40    
41 dpavlin 4 my $debug = 0;
42    
43 dpavlin 19 my $device = "/dev/ttyUSB0";
44     my $baudrate = "19200";
45     my $databits = "8";
46     my $parity = "none";
47     my $stopbits = "1";
48     my $handshake = "none";
49    
50 dpavlin 29 my $program_path = './program/';
51 dpavlin 34 my $secure_path = './secure/';
52 dpavlin 29
53 dpavlin 1 my $response = {
54     'd500090400110a0500027250' => 'version?',
55     'd60007fe00000500c97b' => 'no tag in range',
56    
57     'd6000ffe00000501e00401003123aa26941a' => 'tag #1',
58     'd6000ffe00000501e0040100017c0c388e2b' => 'rfid card',
59     'd6000ffe00000501e00401003123aa2875d4' => 'tag red-stripe',
60    
61     'd60017fe00000502e00401003123aa26e0040100017c0c38cadb' => 'tag #1 + card',
62     'd60017fe00000502e00401003123aa26e00401003123aa283124' => 'tag #1 + tag red-stripe',
63     };
64    
65 dpavlin 19 GetOptions(
66 dpavlin 22 'd|debug+' => \$debug,
67 dpavlin 19 'device=s' => \$device,
68     'baudrate=i' => \$baudrate,
69     'databits=i' => \$databits,
70     'parity=s' => \$parity,
71     'stopbits=i' => \$stopbits,
72     'handshake=s' => \$handshake,
73 dpavlin 26 'meteor=s' => \$meteor_server,
74 dpavlin 19 ) or die $!;
75    
76 dpavlin 22 my $verbose = $debug > 0 ? $debug-- : 0;
77    
78 dpavlin 1 =head1 NAME
79    
80     3m-810 - support for 3M 810 RFID reader
81    
82     =head1 SYNOPSIS
83    
84 dpavlin 19 3m-810.pl --device /dev/ttyUSB0
85 dpavlin 1
86     =head1 DESCRIPTION
87    
88     Communicate with 3M 810 RFID reader and document it's protocol
89    
90     =head1 SEE ALSO
91    
92     L<Device::SerialPort(3)>
93    
94     L<perl(1)>
95    
96 dpavlin 15 L<http://stackoverflow.com/questions/149617/how-could-i-guess-a-checksum-algorithm>
97    
98 dpavlin 1 =head1 AUTHOR
99    
100     Dobrica Pavlinusic <dpavlin@rot13.org> L<http://www.rot13.org/~dpavlin/>
101    
102     =head1 COPYRIGHT AND LICENSE
103    
104     This program is free software; you may redistribute it and/or modify
105     it under the same terms ans Perl itself.
106    
107     =cut
108    
109 dpavlin 23 my $tags_data;
110     my $visible_tags;
111    
112 dpavlin 31 my $item_type = {
113     1 => 'Book',
114     6 => 'CD/CD ROM',
115     2 => 'Magazine',
116     13 => 'Book with Audio Tape',
117     9 => 'Book with CD/CD ROM',
118     0 => 'Other',
119    
120     5 => 'Video',
121     4 => 'Audio Tape',
122     3 => 'Bound Journal',
123     8 => 'Book with Diskette',
124     7 => 'Diskette',
125     };
126    
127     warn "## known item type: ",dump( $item_type ) if $debug;
128    
129 dpavlin 19 my $port=new Device::SerialPort($device) || die "can't open serial port $device: $!\n";
130     warn "using $device $handshake $baudrate $databits $parity $stopbits" if $debug;
131 dpavlin 1 $handshake=$port->handshake($handshake);
132     $baudrate=$port->baudrate($baudrate);
133     $databits=$port->databits($databits);
134     $parity=$port->parity($parity);
135     $stopbits=$port->stopbits($stopbits);
136    
137 dpavlin 22 print "## using $device $baudrate $databits $parity $stopbits debug: $debug verbose: $verbose\n";
138 dpavlin 1
139     # Just in case: reset our timing and buffers
140     $port->lookclear();
141     $port->read_const_time(100);
142     $port->read_char_time(5);
143    
144     # Turn on parity checking:
145     #$port->stty_inpck(1);
146     #$port->stty_istrip(1);
147    
148 dpavlin 4 # initial hand-shake with device
149    
150 dpavlin 20 cmd( 'D5 00 05 04 00 11 8C66', 'hw version',
151     'D5 00 09 04 00 11 0A 05 00 02 7250', sub {
152 dpavlin 23 my $hw_ver = join('.', unpack('CCCC', skip_assert(3) ));
153     print "hardware version $hw_ver\n";
154 dpavlin 25 meteor( 'info', "Found reader hardware $hw_ver" );
155 dpavlin 2 });
156 dpavlin 1
157 dpavlin 20 cmd( 'D6 00 0C 13 04 01 00 02 00 03 00 04 00 AAF2','FIXME: stats?',
158     'D6 00 0C 13 00 02 01 01 03 02 02 03 00 E778', sub { assert() } );
159 dpavlin 1
160 dpavlin 4 # start scanning for tags
161 dpavlin 1
162 dpavlin 20 cmd( 'D6 00 05 FE 00 05 FA40', "scan for tags, retry $_",
163     'D6 00 0F FE 00 00 05 ', sub { # 01 E00401003123AA26 941A # seen, serial length: 8
164     my $rest = shift || die "no rest?";
165     my $nr = ord( substr( $rest, 0, 1 ) );
166    
167     if ( ! $nr ) {
168     print "no tags in range\n";
169 dpavlin 22 update_visible_tags();
170 dpavlin 25 meteor( 'info-none-in-range' );
171 dpavlin 24 $tags_data = {};
172 dpavlin 20 } else {
173    
174 dpavlin 5 my $tags = substr( $rest, 1 );
175 dpavlin 1
176 dpavlin 5 my $tl = length( $tags );
177     die "wrong length $tl for $nr tags: ",dump( $tags ) if $tl =! $nr * 8;
178    
179     my @tags;
180 dpavlin 16 push @tags, uc(unpack('H16', substr($tags, $_ * 8, 8))) foreach ( 0 .. $nr - 1 );
181 dpavlin 8 warn "## tags ",as_hex($tags), " [$tl] = ",dump( $tags ) if $debug;
182 dpavlin 22 print "$nr tags in range: ", join(',', @tags ) , "\n";
183 dpavlin 16
184 dpavlin 25 meteor( 'info-in-range', join(' ',@tags));
185    
186 dpavlin 22 update_visible_tags( @tags );
187 dpavlin 5 }
188 dpavlin 20 }
189 dpavlin 24 ) while(1);
190     #) foreach ( 1 .. 100 );
191 dpavlin 5
192 dpavlin 22
193    
194     sub update_visible_tags {
195     my @tags = @_;
196    
197     my $last_visible_tags = $visible_tags;
198     $visible_tags = {};
199    
200     foreach my $tag ( @tags ) {
201     if ( ! defined $last_visible_tags->{$tag} ) {
202 dpavlin 25 if ( defined $tags_data->{$tag} ) {
203     # meteor( 'in-range', $tag );
204     } else {
205     meteor( 'read', $tag );
206     read_tag( $tag );
207     }
208 dpavlin 22 $visible_tags->{$tag}++;
209     } else {
210     warn "## using cached data for $tag" if $debug;
211     }
212     delete $last_visible_tags->{$tag}; # leave just missing tags
213 dpavlin 29
214     if ( -e "$program_path/$tag" ) {
215     meteor( 'write', $tag );
216     write_tag( $tag );
217     }
218 dpavlin 34 if ( -e "$secure_path/$tag" ) {
219     meteor( 'secure', $tag );
220     secure_tag( $tag );
221     }
222 dpavlin 22 }
223    
224     foreach my $tag ( keys %$last_visible_tags ) {
225 dpavlin 23 my $data = delete $tags_data->{$tag};
226     print "removed tag $tag with data ",dump( $data ),"\n";
227 dpavlin 25 meteor( 'removed', $tag );
228 dpavlin 22 }
229    
230     warn "## update_visible_tags(",dump( @tags ),") = ",dump( $visible_tags )," removed: ",dump( $last_visible_tags ), " data: ",dump( $tags_data ) if $debug;
231     }
232    
233 dpavlin 28 my $tag_data_block;
234 dpavlin 22
235 dpavlin 28 sub read_tag_data {
236     my ($start_block,$rest) = @_;
237     die "no rest?" unless $rest;
238     warn "## DATA [$start_block] ", dump( $rest ) if $debug;
239     my $tag = uc(unpack('H16',substr( $rest, 0, 8 )));
240     my $blocks = ord(substr($rest,8,1));
241     $rest = substr($rest,9); # leave just data blocks
242     foreach my $nr ( 0 .. $blocks - 1 ) {
243     my $block = substr( $rest, $nr * 6, 6 );
244     warn "## block ",as_hex( $block ) if $debug;
245     my $ord = unpack('v',substr( $block, 0, 2 ));
246     my $expected_ord = $nr + $start_block;
247     die "got block $ord, expected block $expected_ord from ",dump( $block ) if $ord != $expected_ord;
248     my $data = substr( $block, 2 );
249     die "data payload should be 4 bytes" if length($data) != 4;
250     warn sprintf "## tag %9s %02d %s |%-4s|\n", $tag, $ord, as_hex( $data ), $data;
251     $tag_data_block->{$tag}->[ $ord ] = $data;
252     }
253     $tags_data->{ $tag } = join('', @{ $tag_data_block->{$tag} });
254 dpavlin 31
255     my $item_type_nr = ord(substr( $tags_data->{$tag}, 3, 1 ));
256     print "DATA $tag ",dump( $tags_data ), " item type: ", ( $item_type->{ $item_type_nr } || "UNKWOWN '$item_type_nr' in " . dump( $item_type ) ), "\n";
257 dpavlin 28 }
258    
259 dpavlin 16 sub read_tag {
260     my ( $tag ) = @_;
261 dpavlin 1
262 dpavlin 22 confess "no tag?" unless $tag;
263    
264 dpavlin 16 print "read_tag $tag\n";
265 dpavlin 1
266 dpavlin 20 cmd(
267 dpavlin 28 "D6 00 0D 02 $tag 00 03 1CC4", "read $tag offset: 0 blocks: 3",
268 dpavlin 20 "D6 00 0F FE 00 00 05 01 $tag 941A", sub {
269     print "FIXME: tag $tag ready?\n";
270     },
271     "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";
272 dpavlin 28 read_tag_data( 0, @_ );
273     },
274     );
275    
276     cmd(
277     "D6 00 0D 02 $tag 03 04 3970", "read $tag offset: 3 blocks: 4",
278     "D6 00 25 02 00", sub { # $tag 04 03 00 30 30 00 00 04 00 00 00 00 00
279     read_tag_data( 3, @_ );
280 dpavlin 20 }
281     );
282 dpavlin 1
283 dpavlin 33 my $security;
284    
285     cmd(
286     "D6 00 0B 0A $tag 1234", "check security $tag",
287     "D6 00 0D 0A 00", sub {
288     my $rest = shift;
289     my $from_tag;
290     ( $from_tag, $security ) = ( substr($rest,0,8), substr($rest,8,1) );
291     die "security from other tag: ",as_hex( $from_tag ) if $from_tag ne str2bytes( $tag );
292     $security = as_hex( $security );
293     warn "# SECURITY $tag = $security\n";
294     }
295     );
296    
297 dpavlin 32 my $data = $tags_data->{$tag} || die "no data for $tag";
298     my ( $u1, $set_item, $u2, $type, $content, $br_lib, $custom ) = unpack('C4Z16Nl>',$data);
299     my $set = ( $set_item & 0xf0 ) >> 4;
300     my $total = ( $set_item & 0x0f );
301     my $branch = $br_lib >> 20;
302     my $library = $br_lib & 0x000fffff;
303 dpavlin 37 print "TAG $tag [$u1] set: $set/$total [$u2] type: $type '$content' library: $library branch: $branch custom: $custom security: $security\n";
304 dpavlin 32
305 dpavlin 16 }
306    
307 dpavlin 29 sub write_tag {
308     my ($tag) = @_;
309    
310     my $path = "$program_path/$tag";
311    
312     my $data = read_file( $path );
313 dpavlin 38 my $hex_data;
314 dpavlin 29
315 dpavlin 38 if ( $data =~ s{^hex\s+}{} ) {
316     $hex_data = $data;
317     $hex_data =~ s{\s+}{}g;
318     } else {
319 dpavlin 29
320 dpavlin 38 # pad to block size
321     $data .= "\0" x ( 4 - ( length($data) % 4 ) );
322 dpavlin 30
323 dpavlin 38 my $max_len = 7 * 4;
324 dpavlin 30
325 dpavlin 38 if ( length($data) > $max_len ) {
326     $data = substr($data,0,$max_len);
327     warn "strip content to $max_len bytes\n";
328     }
329    
330     $hex_data = unpack('H*', $data);
331     }
332    
333     my $len = length($hex_data) / 2;
334     my $blocks = sprintf('%02x', $len / 4);
335    
336     print "write_tag $tag = ",dump( $data ), " [$len/$blocks] == $hex_data\n";
337    
338 dpavlin 29 cmd(
339 dpavlin 38 "d6 00 ff 04 $tag 00 $blocks 00 $hex_data ffff", "write $tag",
340     "d6 00 0d 04 00 $tag $blocks afb1", sub { assert() },
341 dpavlin 34 ) foreach ( 1 .. 3 ); # xxx 3m software does this three times!
342 dpavlin 29
343     my $to = $path;
344     $to .= '.' . time();
345    
346     rename $path, $to;
347     print ">> $to\n";
348    
349 dpavlin 30 delete $tags_data->{$tag}; # force re-read of tag
350 dpavlin 29 }
351    
352 dpavlin 34 sub secure_tag {
353     my ($tag) = @_;
354    
355     my $path = "$secure_path/$tag";
356     my $data = substr(read_file( $path ),0,2);
357    
358     cmd(
359     "d6 00 0c 09 $tag $data 1234", "secure $tag -> $data",
360     "d6 00 0c 09 00 $tag 1234", sub { assert() },
361     );
362    
363     my $to = $path;
364     $to .= '.' . time();
365    
366     rename $path, $to;
367     print ">> $to\n";
368     }
369    
370 dpavlin 19 exit;
371    
372 dpavlin 1 for ( 1 .. 3 ) {
373    
374     # ++-->type 00-0a
375     # D6 00 2A 04 E00401003123AA26 00 07 00 04 11 00 01 31 31 31 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1C D4
376     # D6 00 2A 04 E0 04 01 00 31 23 AA 26 00 07 00 04 11 00 06 32 32 32 32 32 32 32 32 32 32 32 00 00 00 00 00 00 00 00 00 00 00 00 00 32B7
377     # D6 00 2A 04 E0 04 01 00 31 23 AA 26 00 07 00 04 11 00 02 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33 00 00 00 00 00 00 00 00 42 1F
378    
379     cmd(' D6 00 2A 04 E00401003123AA26 00 07 00 04 11 00 01 30 30 30 30 30 30 30 30 30 30 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8843', "write offset 0, block: 7 -- 0000000000 $_" );
380     warn "D6 00 0D 04 00 E00401003123AA26 07 CFF1 -- ack 7 block?\n";
381    
382     }
383     warn " D6 00 0F FE 00 00 05 01 E00401003123AA26 941A\n";
384    
385     cmd( 'D6 00 05 FE 00 05 FA 40', "port-write scan $_" ) foreach ( 1 .. 2 );
386    
387     cmd('D6 00 0C 09 E00401003123AA26 D7 3AF0', 'checkin?',
388     'D6 00 0C 09 00 E00401003123AA26 6A44 -- no?' );
389     cmd('D6 00 0C 09 E00401003123AA26 DA EB5D', 'checkout?',
390     'D6 00 0C 09 00 E00401003123AA26 6A44 -- no?' );
391    
392     cmd('D6 00 26 04 E00401003123AA26 00 06 00 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 A98B', 'blank offset: 0 blocks: 6',
393     'D6 00 0D 04 00 E00401003123AA26 06 DFD0 -- ack 6 blocks' ) foreach ( 1 .. 3 );
394    
395     undef $port;
396     print "Port closed\n";
397    
398     sub writechunk
399     {
400     my $str=shift;
401     my $count = $port->write($str);
402 dpavlin 38 my $len = length($str);
403     die "wrong write length $count != $len in ",as_hex( $str ) if $count != $len;
404 dpavlin 19 print "#> ", as_hex( $str ), "\t[$count]\n" if $debug;
405 dpavlin 1 }
406    
407     sub as_hex {
408     my @out;
409     foreach my $str ( @_ ) {
410     my $hex = unpack( 'H*', $str );
411 dpavlin 2 $hex =~ s/(..)/$1 /g if length( $str ) > 2;
412 dpavlin 8 $hex =~ s/\s+$//;
413 dpavlin 1 push @out, $hex;
414     }
415 dpavlin 8 return join(' | ', @out);
416 dpavlin 1 }
417    
418     sub read_bytes {
419     my ( $len, $desc ) = @_;
420     my $data = '';
421     while ( length( $data ) < $len ) {
422     my ( $c, $b ) = $port->read(1);
423 dpavlin 28 die "no bytes on port: $!" unless defined $b;
424 dpavlin 1 #warn "## got $c bytes: ", as_hex($b), "\n";
425     $data .= $b;
426     }
427     $desc ||= '?';
428 dpavlin 4 warn "#< ", as_hex($data), "\t$desc\n" if $debug;
429 dpavlin 1 return $data;
430     }
431    
432 dpavlin 5 our $assert;
433 dpavlin 2
434 dpavlin 5 # my $rest = skip_assert( 3 );
435     sub skip_assert {
436     assert( 0, shift );
437     }
438    
439 dpavlin 2 sub assert {
440     my ( $from, $to ) = @_;
441    
442 dpavlin 39 return unless $assert->{expect};
443    
444 dpavlin 5 $from ||= 0;
445 dpavlin 4 $to = length( $assert->{expect} ) if ! defined $to;
446    
447 dpavlin 2 my $p = substr( $assert->{payload}, $from, $to );
448     my $e = substr( $assert->{expect}, $from, $to );
449 dpavlin 3 warn "EXPECTED ",as_hex($e), " GOT ", as_hex($p), " [$from-$to] in ",dump( $assert ), "\n" if $e ne $p;
450 dpavlin 5
451     # return the rest
452     return substr( $assert->{payload}, $to );
453 dpavlin 2 }
454    
455 dpavlin 15 use Digest::CRC;
456    
457     sub crcccitt {
458     my $bytes = shift;
459     my $crc = Digest::CRC->new(
460     # midified CCITT to xor with 0xffff instead of 0x0000
461     width => 16, init => 0xffff, xorout => 0xffff, refout => 0, poly => 0x1021, refin => 0,
462     ) or die $!;
463     $crc->add( $bytes );
464     pack('n', $crc->digest);
465     }
466    
467 dpavlin 8 # my $checksum = checksum( $bytes );
468     # my $checksum = checksum( $bytes, $original_checksum );
469     sub checksum {
470     my ( $bytes, $checksum ) = @_;
471    
472 dpavlin 16 my $len = ord(substr($bytes,2,1));
473 dpavlin 17 my $len_real = length($bytes) - 1;
474 dpavlin 16
475 dpavlin 17 if ( $len_real != $len ) {
476     print "length wrong: $len_real != $len\n";
477 dpavlin 38 $bytes = substr($bytes,0,2) . chr($len_real) . substr($bytes,3);
478 dpavlin 17 }
479    
480 dpavlin 38 my $xor = crcccitt( substr($bytes,1) ); # skip D6
481     warn "## checksum ",dump( $bytes, $xor, $checksum ) if $debug;
482    
483 dpavlin 8 if ( defined $checksum && $xor ne $checksum ) {
484 dpavlin 10 print "checksum doesn't match: ", as_hex($xor), " != ", as_hex($checksum), " data: ", as_hex($bytes), "\n";
485 dpavlin 16 return $bytes . $xor;
486 dpavlin 8 }
487 dpavlin 16 return $bytes . $checksum;
488 dpavlin 8 }
489    
490 dpavlin 20 our $dispatch;
491    
492 dpavlin 1 sub readchunk {
493 dpavlin 2 sleep 1; # FIXME remove
494    
495 dpavlin 1 # read header of packet
496     my $header = read_bytes( 2, 'header' );
497 dpavlin 2 my $length = read_bytes( 1, 'length' );
498     my $len = ord($length);
499 dpavlin 1 my $data = read_bytes( $len, 'data' );
500    
501 dpavlin 2 my $payload = substr( $data, 0, -2 );
502     my $payload_len = length($data);
503     warn "## payload too short $payload_len != $len\n" if $payload_len != $len;
504 dpavlin 8
505 dpavlin 2 my $checksum = substr( $data, -2, 2 );
506 dpavlin 20 checksum( $header . $length . $payload , $checksum );
507 dpavlin 1
508 dpavlin 22 print "<< ",as_hex( $header ), " [$len] ", as_hex( $payload ), " | sum: ",as_hex($checksum),"\n" if $verbose;
509 dpavlin 2
510     $assert->{len} = $len;
511     $assert->{payload} = $payload;
512    
513 dpavlin 20 my $full = $header . $length . $data; # full
514     # find longest match for incomming data
515     my ($to) = grep {
516     my $match = substr($payload,0,length($_));
517     m/^\Q$match\E/
518     } sort { length($a) <=> length($b) } keys %$dispatch;
519     warn "?? payload dispatch to ",dump( $payload, $dispatch, $to ) if $debug;
520 dpavlin 2
521 dpavlin 39 if ( defined $to && $payload ) {
522 dpavlin 20 my $rest = substr( $payload, length($to) );
523     warn "## DISPATCH payload to with rest", dump( $payload, $to, $rest ) if $debug;
524     $dispatch->{ $to }->( $rest );
525     } else {
526     print "NO DISPATCH for ",dump( $full ),"\n";
527     }
528    
529 dpavlin 2 return $data;
530 dpavlin 1 }
531    
532 dpavlin 2 sub str2bytes {
533     my $str = shift || confess "no str?";
534 dpavlin 5 my $b = $str;
535 dpavlin 17 $b =~ s/\s+//g;
536     $b =~ s/(..)/\\x$1/g;
537     $b = "\"$b\"";
538 dpavlin 5 my $bytes = eval $b;
539 dpavlin 2 die $@ if $@;
540 dpavlin 5 warn "## str2bytes( $str ) => $b => ",as_hex($bytes) if $debug;
541 dpavlin 2 return $bytes;
542     }
543    
544     sub cmd {
545 dpavlin 20 my $cmd = shift || confess "no cmd?";
546     my $cmd_desc = shift || confess "no description?";
547     my @expect = @_;
548    
549 dpavlin 2 my $bytes = str2bytes( $cmd );
550    
551 dpavlin 16 # fix checksum if needed
552     $bytes = checksum( substr( $bytes, 0, -2 ), substr( $bytes, -2, 2 ) );
553    
554 dpavlin 22 warn ">> ", as_hex( $bytes ), "\t## $cmd_desc\n" if $verbose;
555 dpavlin 2 $assert->{send} = $cmd;
556     writechunk( $bytes );
557    
558 dpavlin 20 while ( @expect ) {
559     my $pattern = str2bytes( shift @expect ) || confess "no pattern?";
560     my $coderef = shift @expect || confess "no coderef?";
561     confess "not coderef" unless ref $coderef eq 'CODE';
562    
563     next if defined $dispatch->{ $pattern };
564    
565     $dispatch->{ substr($pattern,3) } = $coderef;
566     warn "++ dispatch ", as_hex($pattern) ,dump( $dispatch ) if $debug;
567 dpavlin 2 }
568 dpavlin 20
569     readchunk;
570 dpavlin 2 }
571    

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26