/[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 4 - (show annotations)
Sun Sep 28 15:59:38 2008 UTC (15 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 7338 byte(s)
nit-picking
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 my ( $len, $payload, $checksum ) = @_;
85 assert( 0, 3 );
86 print "hardware version ", join('.', unpack('CCCC', substr($payload,3,4))), "\n";
87 });
88
89 cmd( 'D6 00 0C 13 04 01 00 02 00 03 00 04 00 AAF2','stats?',
90 'D6 00 0C 13 00 02 01 01 03 02 02 03 00 E778','FIXME: unimplemented', sub { assert( 0 ) } );
91
92 # start scanning for tags
93
94 cmd( 'D6 00 05 FE 00 05 FA40', "XXX scan $_",
95 'D6 00 07 FE 00 00 05 00 C97B', 'no tag' ) foreach ( 1 .. 10 );
96 # D6 00 0F FE 00 00 05 01 E00401003123AA26 941A # seen
97
98 cmd( 'D6 00 0D 02 E00401003123AA26 00 03 1CC4', 'read offset: 0 blocks: 3' );
99
100 # 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
101 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";
102
103 cmd( 'D6 00 0D 02 E00401003123AA26 03 04 3970', 'read offset: 3 blocks: 4' );
104
105 # D6 00 25 02 00 E00401003123AA26 04 03 00 30 30 00 00 04 00 00 00 00 00
106 # 05 00 00 00 00 00 06 00 00 00 00 00 B9BA
107 warn "D6 00 25 02 00 E00401003123AA26 04 03 00 39 30 31 32 04 00 33 34 35 36
108 05 00 00 00 00 00 06 00 00 00 00 00 524B\n";
109 warn "D6 00 0F FE 00 00 05 01 E00401003123AA26 941A ##### ready?\n";
110
111 for ( 1 .. 3 ) {
112
113 # ++-->type 00-0a
114 # 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
115 # 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
116 # 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
117
118 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 $_" );
119 warn "D6 00 0D 04 00 E00401003123AA26 07 CFF1 -- ack 7 block?\n";
120
121 }
122 warn " D6 00 0F FE 00 00 05 01 E00401003123AA26 941A\n";
123
124 cmd( 'D6 00 05 FE 00 05 FA 40', "port-write scan $_" ) foreach ( 1 .. 2 );
125
126 cmd('D6 00 0C 09 E00401003123AA26 D7 3AF0', 'checkin?',
127 'D6 00 0C 09 00 E00401003123AA26 6A44 -- no?' );
128 cmd('D6 00 0C 09 E00401003123AA26 DA EB5D', 'checkout?',
129 'D6 00 0C 09 00 E00401003123AA26 6A44 -- no?' );
130
131 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',
132 'D6 00 0D 04 00 E00401003123AA26 06 DFD0 -- ack 6 blocks' ) foreach ( 1 .. 3 );
133
134 undef $port;
135 print "Port closed\n";
136
137 sub writechunk
138 {
139 my $str=shift;
140 my $count = $port->write($str);
141 print ">> ", as_hex( $str ), "\t[$count]\n";
142 }
143
144 sub as_hex {
145 my @out;
146 foreach my $str ( @_ ) {
147 my $hex = unpack( 'H*', $str );
148 $hex =~ s/(..)/$1 /g if length( $str ) > 2;
149 push @out, $hex;
150 }
151 return join(' ', @out);
152 }
153
154 sub read_bytes {
155 my ( $len, $desc ) = @_;
156 my $data = '';
157 while ( length( $data ) < $len ) {
158 my ( $c, $b ) = $port->read(1);
159 #warn "## got $c bytes: ", as_hex($b), "\n";
160 $data .= $b;
161 }
162 $desc ||= '?';
163 warn "#< ", as_hex($data), "\t$desc\n" if $debug;
164 return $data;
165 }
166
167 my $assert;
168
169 sub assert {
170 my ( $from, $to ) = @_;
171
172 $to = length( $assert->{expect} ) if ! defined $to;
173
174 my $p = substr( $assert->{payload}, $from, $to );
175 my $e = substr( $assert->{expect}, $from, $to );
176 warn "EXPECTED ",as_hex($e), " GOT ", as_hex($p), " [$from-$to] in ",dump( $assert ), "\n" if $e ne $p;
177 }
178
179 sub readchunk {
180 my ( $parser ) = @_;
181
182 sleep 1; # FIXME remove
183
184 # read header of packet
185 my $header = read_bytes( 2, 'header' );
186 my $length = read_bytes( 1, 'length' );
187 my $len = ord($length);
188 my $data = read_bytes( $len, 'data' );
189 my ( $cmd ) = unpack('C', $data );
190
191 my $payload = substr( $data, 0, -2 );
192 my $payload_len = length($data);
193 warn "## payload too short $payload_len != $len\n" if $payload_len != $len;
194 my $checksum = substr( $data, -2, 2 );
195 # FIXME check checksum
196
197 print "<< ",as_hex( $header ), " [$len] ", as_hex( $payload ), "checksum: ", as_hex( $checksum ),"\n";
198
199 $assert->{len} = $len;
200 $assert->{payload} = $payload;
201 $assert->{checksum} = $checksum;
202
203 $parser->( $len, $payload, $checksum ) if $parser && ref($parser) eq 'CODE';
204
205 return $data;
206 }
207
208 sub str2bytes {
209 my $str = shift || confess "no str?";
210 $str =~ s/\s+(\S\S)(\S\S)+\s*/ $1 $2/; # fix checksum
211 $str =~ s/\s+/\\x/g;
212 $str = '"\x' . $str . '"';
213 my $bytes = eval $str;
214 die $@ if $@;
215 return $bytes;
216 }
217
218 sub cmd {
219 my ( $cmd, $cmd_desc, $expect, $expect_desc, $coderef ) = @_;
220 my $bytes = str2bytes( $cmd );
221
222 warn ">> ", as_hex( $bytes ), "\t## $cmd_desc\n";
223 $assert->{send} = $cmd;
224 writechunk( $bytes );
225
226 if ( $expect ) {
227 warn "?? $expect", $expect_desc ? "\t## $expect_desc" : '', "\n";
228 $assert->{expect} = substr(str2bytes($expect), 3, -2); # just expected payload
229 readchunk( $coderef );
230 }
231 }
232

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26