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

Contents of /3m-810.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (show annotations)
Sun Sep 28 22:10:55 2008 UTC (15 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 8823 byte(s)
checksum placehodler, and more output tuning
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 use Carp qw/confess/;
9
10 my $debug = 0;
11
12 my $response = {
13 'd500090400110a0500027250' => 'version?',
14 'd60007fe00000500c97b' => 'no tag in range',
15
16 'd6000ffe00000501e00401003123aa26941a' => 'tag #1',
17 'd6000ffe00000501e0040100017c0c388e2b' => 'rfid card',
18 'd6000ffe00000501e00401003123aa2875d4' => 'tag red-stripe',
19
20 'd60017fe00000502e00401003123aa26e0040100017c0c38cadb' => 'tag #1 + card',
21 'd60017fe00000502e00401003123aa26e00401003123aa283124' => 'tag #1 + tag red-stripe',
22 };
23
24 =head1 NAME
25
26 3m-810 - support for 3M 810 RFID reader
27
28 =head1 SYNOPSIS
29
30 3m-810.pl [DEVICE [BAUD [DATA [PARITY [STOP [FLOW]]]]]]
31
32 =head1 DESCRIPTION
33
34 Communicate with 3M 810 RFID reader and document it's protocol
35
36 =head1 SEE ALSO
37
38 L<Device::SerialPort(3)>
39
40 L<perl(1)>
41
42 =head1 AUTHOR
43
44 Dobrica Pavlinusic <dpavlin@rot13.org> L<http://www.rot13.org/~dpavlin/>
45
46 =head1 COPYRIGHT AND LICENSE
47
48 This program is free software; you may redistribute it and/or modify
49 it under the same terms ans Perl itself.
50
51 =cut
52
53 # your serial port.
54 my ($device,$baudrate,$databits,$parity,$stopbits,$handshake)=@ARGV;
55 $device ||= "/dev/ttyUSB0";
56 $baudrate ||= "19200";
57 $databits ||= "8";
58 $parity ||= "none";
59 $stopbits ||= "1";
60 $handshake ||= "none";
61
62 my $port=new Device::SerialPort($device) || die "new($device): $!\n";
63 $handshake=$port->handshake($handshake);
64 $baudrate=$port->baudrate($baudrate);
65 $databits=$port->databits($databits);
66 $parity=$port->parity($parity);
67 $stopbits=$port->stopbits($stopbits);
68
69 print "## using $device $baudrate $databits $parity $stopbits\n";
70
71 # Just in case: reset our timing and buffers
72 $port->lookclear();
73 $port->read_const_time(100);
74 $port->read_char_time(5);
75
76 # Turn on parity checking:
77 #$port->stty_inpck(1);
78 #$port->stty_istrip(1);
79
80 # initial hand-shake with device
81
82 cmd( 'D5 00 05 04 00 11 8C66', 'hw version?',
83 'D5 00 09 04 00 11 0A 05 00 02 7250', 'hw 10.5.0.2', sub {
84 print "hardware version ", join('.', unpack('CCCC', skip_assert(3) )), "\n";
85 });
86
87 cmd( 'D6 00 0C 13 04 01 00 02 00 03 00 04 00 AAF2','stats?',
88 'D6 00 0C 13 00 02 01 01 03 02 02 03 00 E778','FIXME: unimplemented', sub { assert() } );
89
90 # start scanning for tags
91
92 cmd( 'D6 00 05 FE 00 05 FA40', "XXX scan $_",
93 'D6 00 07 FE 00 00 05 00 C97B', 'no tag', sub {
94 dispatch(
95 'D6 00 0F FE 00 00 05 ',# 01 E00401003123AA26 941A # seen, serial length: 8
96 sub {
97 my $rest = shift || die "no rest?";
98 my $nr = ord( substr( $rest, 0, 1 ) );
99 my $tags = substr( $rest, 1 );
100
101 my $tl = length( $tags );
102 die "wrong length $tl for $nr tags: ",dump( $tags ) if $tl =! $nr * 8;
103
104 my @tags;
105 push @tags, substr($tags, $_ * 8, 8) foreach ( 0 .. $nr - 1 );
106 warn "## tags ",as_hex($tags), " [$tl] = ",dump( $tags ) if $debug;
107 print "seen $nr tags: ", join(',', map { unpack('H16', $_) } @tags ) , "\n";
108 }
109 ) }
110
111 ) foreach ( 1 .. 100 );
112
113 cmd( 'D6 00 0D 02 E00401003123AA26 00 03 1CC4', 'read offset: 0 blocks: 3' );
114
115 # D6 00 1F 02 00 E00401003123AA26 03 00 00 04 11 00 01 01 00 30 30 30 30 02 00 30 30 30 30 E5F4
116 warn "D6 00 1F 02 00 E00401003123AA26 03 00 00 04 11 00 01 01 00 31 32 33 34 02 00 35 36 37 38 531F\n";
117
118 cmd( 'D6 00 0D 02 E00401003123AA26 03 04 3970', 'read offset: 3 blocks: 4' );
119
120 # D6 00 25 02 00 E00401003123AA26 04 03 00 30 30 00 00 04 00 00 00 00 00
121 # 05 00 00 00 00 00 06 00 00 00 00 00 B9BA
122 warn "D6 00 25 02 00 E00401003123AA26 04 03 00 39 30 31 32 04 00 33 34 35 36
123 05 00 00 00 00 00 06 00 00 00 00 00 524B\n";
124 warn "D6 00 0F FE 00 00 05 01 E00401003123AA26 941A ##### ready?\n";
125
126 for ( 1 .. 3 ) {
127
128 # ++-->type 00-0a
129 # 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
130 # 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
131 # 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
132
133 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 $_" );
134 warn "D6 00 0D 04 00 E00401003123AA26 07 CFF1 -- ack 7 block?\n";
135
136 }
137 warn " D6 00 0F FE 00 00 05 01 E00401003123AA26 941A\n";
138
139 cmd( 'D6 00 05 FE 00 05 FA 40', "port-write scan $_" ) foreach ( 1 .. 2 );
140
141 cmd('D6 00 0C 09 E00401003123AA26 D7 3AF0', 'checkin?',
142 'D6 00 0C 09 00 E00401003123AA26 6A44 -- no?' );
143 cmd('D6 00 0C 09 E00401003123AA26 DA EB5D', 'checkout?',
144 'D6 00 0C 09 00 E00401003123AA26 6A44 -- no?' );
145
146 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',
147 'D6 00 0D 04 00 E00401003123AA26 06 DFD0 -- ack 6 blocks' ) foreach ( 1 .. 3 );
148
149 undef $port;
150 print "Port closed\n";
151
152 sub writechunk
153 {
154 my $str=shift;
155 my $count = $port->write($str);
156 print "#> ", as_hex( $str ), "\t[$count]\n";
157 }
158
159 sub as_hex {
160 my @out;
161 foreach my $str ( @_ ) {
162 my $hex = unpack( 'H*', $str );
163 $hex =~ s/(..)/$1 /g if length( $str ) > 2;
164 $hex =~ s/\s+$//;
165 push @out, $hex;
166 }
167 return join(' | ', @out);
168 }
169
170 sub read_bytes {
171 my ( $len, $desc ) = @_;
172 my $data = '';
173 while ( length( $data ) < $len ) {
174 my ( $c, $b ) = $port->read(1);
175 #warn "## got $c bytes: ", as_hex($b), "\n";
176 $data .= $b;
177 }
178 $desc ||= '?';
179 warn "#< ", as_hex($data), "\t$desc\n" if $debug;
180 return $data;
181 }
182
183 our $assert;
184
185 # my $rest = skip_assert( 3 );
186 sub skip_assert {
187 assert( 0, shift );
188 }
189
190 sub assert {
191 my ( $from, $to ) = @_;
192
193 $from ||= 0;
194 $to = length( $assert->{expect} ) if ! defined $to;
195
196 my $p = substr( $assert->{payload}, $from, $to );
197 my $e = substr( $assert->{expect}, $from, $to );
198 warn "EXPECTED ",as_hex($e), " GOT ", as_hex($p), " [$from-$to] in ",dump( $assert ), "\n" if $e ne $p;
199
200 # return the rest
201 return substr( $assert->{payload}, $to );
202 }
203
204 our $dispatch;
205 sub dispatch {
206 my ( $pattern, $coderef ) = @_;
207 my $patt = substr( str2bytes($pattern), 3 ); # just payload
208 my $l = length($patt);
209 my $p = substr( $assert->{payload}, 0, $l );
210 warn "## dispatch pattern $pattern [$l] ",dump( $patt, $p ) if $debug;
211
212 if ( $assert->{payload} eq $assert->{expect} ) {
213 warn "## no dispatch, payload expected" if $debug;
214 } elsif ( $p eq $patt ) {
215 # if matched call with rest of payload
216 $coderef->( substr( $assert->{payload}, $l ) );
217 } else {
218 warn "## dispatch ignored" if $debug;
219 }
220 }
221
222 # my $checksum = checksum( $bytes );
223 # my $checksum = checksum( $bytes, $original_checksum );
224 sub checksum {
225 my ( $bytes, $checksum ) = @_;
226 my $xor = 0;
227
228 if ( defined $checksum && $xor ne $checksum ) {
229 printf "checksum doesn't match: %04x != %04x data: %s\n", $xor, $checksum;
230 }
231 }
232
233 sub readchunk {
234 my ( $parser ) = @_;
235
236 sleep 1; # FIXME remove
237
238 # read header of packet
239 my $header = read_bytes( 2, 'header' );
240 my $length = read_bytes( 1, 'length' );
241 my $len = ord($length);
242 my $data = read_bytes( $len, 'data' );
243
244 my $payload = substr( $data, 0, -2 );
245 my $payload_len = length($data);
246 warn "## payload too short $payload_len != $len\n" if $payload_len != $len;
247
248 my $checksum = substr( $data, -2, 2 );
249 checksum( $header . $length . $payload, $checksum );
250
251 print "<< ",as_hex( $header ), " [$len] ", as_hex( $payload ), " | sum: ",as_hex($checksum),"\n";
252
253 $assert->{len} = $len;
254 $assert->{payload} = $payload;
255
256 $parser->( $len, $payload ) if $parser && ref($parser) eq 'CODE';
257
258 return $data;
259 }
260
261 sub str2bytes {
262 my $str = shift || confess "no str?";
263 my $b = $str;
264 $b =~ s/\s+(\S\S)(\S\S)+\s*/ $1 $2/; # fix checksum
265 $b =~ s/\s+$//;
266 $b =~ s/\s+/\\x/g;
267 $b = '"\x' . $b . '"';
268 my $bytes = eval $b;
269 die $@ if $@;
270 warn "## str2bytes( $str ) => $b => ",as_hex($bytes) if $debug;
271 return $bytes;
272 }
273
274 sub cmd {
275 my ( $cmd, $cmd_desc, $expect, $expect_desc, $coderef ) = @_;
276 my $bytes = str2bytes( $cmd );
277
278 warn ">> ", as_hex( $bytes ), "\t## $cmd_desc\n";
279 $assert->{send} = $cmd;
280 writechunk( $bytes );
281
282 if ( $expect ) {
283 warn "?? $expect", $expect_desc ? "\t## $expect_desc" : '', "\n";
284 $assert->{expect} = substr(str2bytes($expect), 3, -2); # just expected payload
285 readchunk( $coderef );
286 }
287 }
288

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26