/[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 4 - (hide annotations)
Sun Sep 28 15:59:38 2008 UTC (15 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 7338 byte(s)
nit-picking
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 1
10 dpavlin 4 my $debug = 0;
11    
12 dpavlin 1 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 dpavlin 4 # 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 dpavlin 2 my ( $len, $payload, $checksum ) = @_;
85     assert( 0, 3 );
86     print "hardware version ", join('.', unpack('CCCC', substr($payload,3,4))), "\n";
87     });
88 dpavlin 1
89 dpavlin 4 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 dpavlin 1
92 dpavlin 4 # start scanning for tags
93 dpavlin 1
94 dpavlin 4 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 dpavlin 1 # 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 dpavlin 2 $hex =~ s/(..)/$1 /g if length( $str ) > 2;
149 dpavlin 1 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 dpavlin 4 warn "#< ", as_hex($data), "\t$desc\n" if $debug;
164 dpavlin 1 return $data;
165     }
166    
167 dpavlin 2 my $assert;
168    
169     sub assert {
170     my ( $from, $to ) = @_;
171    
172 dpavlin 4 $to = length( $assert->{expect} ) if ! defined $to;
173    
174 dpavlin 2 my $p = substr( $assert->{payload}, $from, $to );
175     my $e = substr( $assert->{expect}, $from, $to );
176 dpavlin 3 warn "EXPECTED ",as_hex($e), " GOT ", as_hex($p), " [$from-$to] in ",dump( $assert ), "\n" if $e ne $p;
177 dpavlin 2 }
178    
179 dpavlin 1 sub readchunk {
180 dpavlin 2 my ( $parser ) = @_;
181 dpavlin 1
182 dpavlin 2 sleep 1; # FIXME remove
183    
184 dpavlin 1 # read header of packet
185     my $header = read_bytes( 2, 'header' );
186 dpavlin 2 my $length = read_bytes( 1, 'length' );
187     my $len = ord($length);
188 dpavlin 1 my $data = read_bytes( $len, 'data' );
189 dpavlin 2 my ( $cmd ) = unpack('C', $data );
190 dpavlin 1
191 dpavlin 2 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 dpavlin 1
197 dpavlin 2 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 dpavlin 1 }
207    
208 dpavlin 2 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