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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26