1 package RFID::Serial::3M810;
3 use base 'RFID::Serial';
6 use Data::Dump qw(dump);
11 sub serial_settings {{
12 device => "/dev/ttyUSB1", # FIXME comment out before shipping
26 my ( $count, $str ) = $port->read(3);
27 my $data = $port->read( ord(substr($str,2,1)) );
28 warn "drain ",as_hex( $str, $data ),"\n";
36 my $crc = Digest::CRC->new(
37 # midified CCITT to xor with 0xffff instead of 0x0000
38 width => 16, init => 0xffff, xorout => 0xffff, refout => 0, poly => 0x1021, refin => 0,
41 pack('n', $crc->digest);
45 Time::HiRes::sleep 0.015;
49 my ( $hex, $description, $coderef ) = @_;
50 my $bytes = hex2bytes($hex);
51 if ( substr($bytes,0,1) !~ /(\xD5|\xD6)/ ) {
52 my $len = pack( 'n', length( $bytes ) + 2 );
53 $bytes = $len . $bytes;
54 my $checksum = checksum($bytes);
55 $bytes = "\xD6" . $bytes . $checksum;
58 warn ">> ", as_hex( $bytes ), "\t\t[$description]\n";
59 $port->write( $bytes );
63 my $r_len = $port->read(3);
67 $r_len = $port->read(3);
70 # FIXME sometimes, reader returns left-over junk
71 if ( ! ord(substr($r_len,0,1)) && 0xD0 ) {
72 warn "INVALID reponse ",as_hex($r_len);
74 while ( $c ne "\xD6" ) {
75 $c = $port->read(1) || return;
76 warn "# c ",as_hex($c);
78 $r_len = $c . $port->read(2);
79 warn "FIXED ",as_hex($r_len);
84 my $len = ord( substr($r_len,2,1) );
85 $data = $port->read( $len );
86 warn "<< ", as_hex($r_len,$data)," $len\n";
88 $coderef->( $data ) if $coderef;
93 my ( $got, $expected ) = @_;
94 $expected = hex2bytes($expected);
96 my $len = length($got);
97 $len = length($expected) if length $expected < $len;
99 confess "got ", as_hex($got), " expected ", as_hex($expected)
100 unless substr($got,0,$len) eq substr($expected,0,$len);
102 return substr($got,$len);
108 'D5 00 05 04 00 11 8C66', 'hw version', sub {
110 my $rest = assert $data => '04 00 11';
111 my $hw_ver = join('.', unpack('CCCC', $rest));
112 warn "# 3M 810 hardware version $hw_ver\n";
116 '13 04 01 00 02 00 03 00 04 00','FIXME: stats? rf-on?', sub { assert(shift,
117 '13 00 02 01 01 03 02 02 03 00'
123 my @tags = inventory;
131 cmd( 'FE 00 05', 'scan for tags', sub {
133 my $rest = assert $data => 'FE 00 00 05';
134 my $nr = ord( substr( $rest, 0, 1 ) );
137 warn "# no tags in range\n";
139 my $tags = substr( $rest, 1 );
140 my $tl = length( $tags );
141 die "wrong length $tl for $nr tags: ",dump( $tags ) if $tl =! $nr * 8;
143 foreach ( 0 .. $nr - 1 ) {
144 push @tags, hex_tag substr($tags, $_ * 8, 8);
150 warn "# tags ",dump @tags;
156 # cards 16, stickers: 8
157 my $max_rfid_block = 8;
161 my ( $data, $hex ) = @_;
162 my $b = hex2bytes $hex;
164 if ( substr($data,0,$l) eq $b ) {
165 warn "_matched $hex [$l] in ",as_hex($data);
166 return substr($data,$l);
171 my $tag = shift || confess "no tag?";
172 $tag = shift if ref($tag);
177 sprintf( "02 $tag %02x %02x", $start, $blocks ) => "read_blocks $tag $start/$blocks", sub {
179 if ( my $rest = _matched $data => '02 00' ) {
181 my $tag = hex_tag substr($rest,0,8);
182 my $blocks = ord(substr($rest,8,1));
183 warn "# response from $tag $blocks blocks ",as_hex substr($rest,9);
184 foreach ( 1 .. $blocks ) {
185 my $pos = ( $_ - 1 ) * 6 + 9;
186 my $nr = unpack('v', substr($rest,$pos,2));
187 my $payload = substr($rest,$pos+2,4);
188 warn "## pos $pos block $nr ",as_hex($payload), $/;
189 $tag_blocks->{$tag}->[$nr] = $payload;
191 } elsif ( my $rest = _matched $data => 'FE 00 00 05 01' ) {
192 warn "FIXME ready? ",as_hex $test;
193 } elsif ( my $rest = _matched $data => '02 06' ) {
194 warn "ERROR ",as_hex($rest);
196 warn "FIXME unsuported ",as_hex($rest);
200 warn "# tag_blocks ",dump($tag_blocks);