line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Hardware::iButton::Connection; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
606
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
27
|
|
4
|
1
|
|
|
1
|
|
4
|
no strict "subs"; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
22
|
|
5
|
1
|
|
|
1
|
|
4
|
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
73
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
require Exporter; |
8
|
|
|
|
|
|
|
#require AutoLoader; |
9
|
1
|
|
|
1
|
|
758
|
use IO::File; |
|
1
|
|
|
|
|
9783
|
|
|
1
|
|
|
|
|
117
|
|
10
|
1
|
|
|
1
|
|
835
|
use Time::HiRes qw(usleep); |
|
1
|
|
|
|
|
1736
|
|
|
1
|
|
|
|
|
5
|
|
11
|
|
|
|
|
|
|
#use POSIX qw(tcdrain); # for drain in write() |
12
|
1
|
|
|
1
|
|
742
|
use Hardware::iButton::Device; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
132
|
|
13
|
|
|
|
|
|
|
#use IO::Stty; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
@ISA = qw(Exporter); |
16
|
|
|
|
|
|
|
# Items to export into callers namespace by default. Note: do not export |
17
|
|
|
|
|
|
|
# names by default without a very good reason. Use EXPORT_OK instead. |
18
|
|
|
|
|
|
|
# Do not simply export all your public functions/methods/constants. |
19
|
|
|
|
|
|
|
@EXPORT = qw(); |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
( $VERSION ) = '$Revision: 1.2 $ ' =~ /\$Revision:\s+([^\s]+)/; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
=head1 NAME |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
Hardware::iButton - talk to DalSemi iButtons via a DS2480 serial widget |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
=head1 SYNOPSIS |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
use Hardware::iButton::Connection; |
30
|
|
|
|
|
|
|
$c = new Hardware::iButton::Connection "/dev/ttyS0"; |
31
|
|
|
|
|
|
|
@b = $c->scan(); |
32
|
|
|
|
|
|
|
foreach $b (@b) { |
33
|
|
|
|
|
|
|
print "family: ",$b->family(), "serial number: ", $b->serial(),"\n"; |
34
|
|
|
|
|
|
|
print "id: ",$b->id(),"\n"; # id = family . serial . crc |
35
|
|
|
|
|
|
|
print "reg0: ",$b->readreg(0),"\n"; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
=head1 DESCRIPTION |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
This module talks to iButtons via the "active" serial interface (anything |
41
|
|
|
|
|
|
|
using the DS2480, including the DS1411k and the DS 9097U). It builds up a list |
42
|
|
|
|
|
|
|
of devices available, lets you read and write their registers, etc. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
The connection object is an Hardware::iButton::Connection. The main |
45
|
|
|
|
|
|
|
user-visible purpose of it is to provide a list of Hardware::iButton::Device |
46
|
|
|
|
|
|
|
objects. These can be subclassed once their family codes are known to provide |
47
|
|
|
|
|
|
|
specialized methods unique to the capabilities of that device. Those devices |
48
|
|
|
|
|
|
|
will then be Hardware::iButton::Device::DS1920, etc. |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
iButtons and solder-mount Touch Memory devices are each identified with a |
51
|
|
|
|
|
|
|
unique 64-bit number. This is broken up into 8 bits of a "family code", which |
52
|
|
|
|
|
|
|
specifies the part number (and consequently the capabilities), then 48 bits |
53
|
|
|
|
|
|
|
of device ID (which Dallas insures is globally unique), then 8 bits of CRC. |
54
|
|
|
|
|
|
|
When you pass these IDs to and from this package, use hex strings like |
55
|
|
|
|
|
|
|
"0123456789ab". |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
=head1 AUTHOR |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
Brian Warner, warner@lothar.com |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
=head1 SEE ALSO |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
http://www.ibutton.com, http://sof.mit.edu/ibuttonpunks/ |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=cut |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
# constants listed in the Book of DS19xx iButton Standards |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
# "Network Layer" constants |
70
|
1
|
|
|
1
|
|
6
|
use constant READ_ROM => "\x33"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
91
|
|
71
|
1
|
|
|
1
|
|
5
|
use constant SKIP_ROM => "\xcc"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
72
|
1
|
|
|
1
|
|
4
|
use constant MATCH_ROM => "\x55"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
45
|
|
73
|
1
|
|
|
1
|
|
4
|
use constant SEARCH_ROM => "\xf0"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
40
|
|
74
|
1
|
|
|
1
|
|
5
|
use constant OD_SKIP_ROM => "\x3c"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
42
|
|
75
|
1
|
|
|
1
|
|
5
|
use constant OD_MATCH_ROM => "\x69"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
38
|
|
76
|
|
|
|
|
|
|
# "Transport Layer" constants |
77
|
1
|
|
|
1
|
|
4
|
use constant READ_MEMORY => "\xf0"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
59
|
|
78
|
1
|
|
|
1
|
|
5
|
use constant EXT_READ_MEMORY => "\xa5"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
36
|
|
79
|
1
|
|
|
1
|
|
4
|
use constant READ_SUBKEY => "\x66"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
57
|
|
80
|
1
|
|
|
1
|
|
5
|
use constant WRITE_SCRATCHPAD => "\x0f"; |
|
1
|
|
|
|
|
22
|
|
|
1
|
|
|
|
|
49
|
|
81
|
1
|
|
|
1
|
|
5
|
use constant READ_SCRATCHPAD => "\xaa"; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
54
|
|
82
|
1
|
|
|
1
|
|
4
|
use constant COPY_SCRATCHPAD => "\x55"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
47
|
|
83
|
|
|
|
|
|
|
# etc.. |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# there are constants used by the DS2480 too. |
86
|
1
|
|
|
1
|
|
5
|
use constant SET_DATA_MODE => "\xe1"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
44
|
|
87
|
1
|
|
|
1
|
|
4
|
use constant SET_COMMAND_MODE => "\xe3"; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
55
|
|
88
|
|
|
|
|
|
|
# XXX Not sure if this is the correct method. |
89
|
1
|
|
|
1
|
|
10
|
use constant SET_FINDALARM_MODE => "\xec"; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
40
|
|
90
|
1
|
|
|
1
|
|
5
|
use constant SEARCH_ACCEL_ON => "\xb1"; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
55
|
|
91
|
1
|
|
|
1
|
|
6
|
use constant SEARCH_ACCEL_OFF => "\xa1"; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
51
|
|
92
|
|
|
|
|
|
|
|
93
|
1
|
|
|
1
|
|
5
|
use constant DEBUG => 0; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
2473
|
|
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
$Hardware::iButton::Connection::debug = 0; |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
# devices are in one of three states: active in network layer, deselected, |
98
|
|
|
|
|
|
|
# active in transport layer. In addition some devices can be "overdrive active" |
99
|
|
|
|
|
|
|
# in the transport layer. We call these states "active, deselected, |
100
|
|
|
|
|
|
|
# selected, OD selected". |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
# after a bus reset, all devices are active in the "network layer" and you're |
103
|
|
|
|
|
|
|
# only supposed to do "network layer" commands. |
104
|
|
|
|
|
|
|
# READ_ROM gets everybody's id at once. If the CRC is right then there was |
105
|
|
|
|
|
|
|
# only one device. Everyone is still active |
106
|
|
|
|
|
|
|
# SKIP_ROM selects everyone |
107
|
|
|
|
|
|
|
# MATCH_ROM selects the device with a matching ID, deselects everyone else |
108
|
|
|
|
|
|
|
# SEARCH_ROM will end up selecting one device, deselecting the others |
109
|
|
|
|
|
|
|
# OD_SKIP_ROM makes everyone OD selected |
110
|
|
|
|
|
|
|
# OD_MATCH_ROM will OD select the matching device, deselect everyone else |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# Preloaded methods go here. |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# we need some kind of slow substitute if Time::HiRes is not available |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
#sub usleep { |
117
|
|
|
|
|
|
|
# my($usec) = @_; |
118
|
|
|
|
|
|
|
# sleep(1); |
119
|
|
|
|
|
|
|
#} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head2 new |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
$c = new Hardware::iButton::Connection "/dev/ttyS0"; |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
Creates a new Hardware::iButton::Connection object by opening the given serial |
126
|
|
|
|
|
|
|
port and attempting to communicate with a DS2480 chip. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=cut |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
sub new { |
131
|
0
|
|
|
0
|
1
|
|
my($class, $port) = @_; |
132
|
0
|
|
|
|
|
|
my $self = bless {},$class; |
133
|
0
|
|
|
|
|
|
$self->{'port'} = $port; |
134
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
$self->{'s'} = new IO::File "+<$port"; |
136
|
0
|
0
|
|
|
|
|
return undef unless $self->{'s'}; |
137
|
|
|
|
|
|
|
#print "orig settings: ",IO::Stty::stty($self->{'s'},'-a'),"\n"; |
138
|
|
|
|
|
|
|
#$self->{'s.oldstty'} = IO::Stty::stty($self->{'s'},'-g'); |
139
|
0
|
|
|
|
|
|
$self->{'s.changed'} = 1; |
140
|
0
|
|
|
|
|
|
$self->{'s'}->blocking(0); |
141
|
0
|
|
|
|
|
|
$self->{'s'}->autoflush(1); |
142
|
|
|
|
|
|
|
#IO::Stty::stty($self->{'s'}, qw(9600 raw -echo -echoe -echok)); |
143
|
|
|
|
|
|
|
#print "new settings: ",IO::Stty::stty($self->{'s'},'-a'),"\n"; |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# we should also do the equivalent of a 'stty raw' here |
146
|
|
|
|
|
|
|
# stty 9600 raw -onlcr -iexten -echo -echoe -echok -echoctl -echoke |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# reset |
149
|
0
|
|
|
|
|
|
$self->{'mode'} = SET_COMMAND_MODE; |
150
|
0
|
|
|
|
|
|
$self->write(SET_COMMAND_MODE); |
151
|
0
|
|
|
|
|
|
usleep(50 * 1000); |
152
|
0
|
|
|
|
|
|
$self->write("\xc1"); |
153
|
0
|
|
|
|
|
|
usleep(50 * 1000); |
154
|
0
|
|
|
|
|
|
$self->write("\xf1"); |
155
|
0
|
|
|
|
|
|
usleep(50 * 1000); |
156
|
0
|
|
|
|
|
|
$self->write("\xc1"); |
157
|
0
|
|
|
|
|
|
usleep(50 * 1000); |
158
|
0
|
|
|
|
|
|
$self->write("\xf1"); |
159
|
0
|
|
|
|
|
|
usleep(50 * 1000); |
160
|
0
|
|
|
|
|
|
my $dummy; |
161
|
0
|
|
|
|
|
|
$dummy = $self->read(0); # flush |
162
|
|
|
|
|
|
|
#print "dummy (",length($dummy),"): ",unpack("H*",$dummy),"\n"; |
163
|
|
|
|
|
|
|
|
164
|
0
|
|
|
|
|
|
my $times = 1; |
165
|
0
|
|
|
|
|
|
while ($times) { |
166
|
0
|
|
|
|
|
|
$self->write("\xc1"); |
167
|
0
|
|
|
|
|
|
usleep(50 * 1000); |
168
|
0
|
|
|
|
|
|
$dummy = $self->read(0); |
169
|
0
|
0
|
0
|
|
|
|
last if (length($dummy) == 1 and ((ord($dummy) & 0xdc) == 0xc8)); |
170
|
0
|
|
|
|
|
|
print "reset, but got back (",length($dummy),"): ",unpack("H*",$dummy),"\n"; |
171
|
0
|
|
|
|
|
|
usleep(300 * 1000); $self->read(0); |
|
0
|
|
|
|
|
|
|
172
|
0
|
|
|
|
|
|
$times--; |
173
|
|
|
|
|
|
|
} |
174
|
0
|
0
|
|
|
|
|
if (!$times) { |
175
|
|
|
|
|
|
|
#k die "couldn't reset bus"; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# we just reset.. all buttons are listening, so none is currently selected |
179
|
0
|
|
|
|
|
|
$self->{'selected'} = undef; |
180
|
|
|
|
|
|
|
|
181
|
0
|
|
|
|
|
|
return $self; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
sub resetstty { |
185
|
0
|
|
|
0
|
0
|
|
my($self) = @_; |
186
|
|
|
|
|
|
|
#print "resetstty\n"; |
187
|
|
|
|
|
|
|
#foreach my $key (keys(%$self)) { |
188
|
|
|
|
|
|
|
#print "$key: $self->{$key}\n"; |
189
|
|
|
|
|
|
|
#} |
190
|
0
|
0
|
|
|
|
|
unless ($self->{'s.changed'}) { |
191
|
|
|
|
|
|
|
#print "not restoring\n"; |
192
|
0
|
|
|
|
|
|
return; |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
#print "restoring..\n"; |
195
|
|
|
|
|
|
|
# restore terminal parameters |
196
|
|
|
|
|
|
|
#print "current settings: ",IO::Stty::stty($self->{'s'},'-a'),"\n"; |
197
|
|
|
|
|
|
|
#IO::Stty::stty($self->{'s'},$self->{'s.oldstty'}); |
198
|
0
|
|
|
|
|
|
$self->{'s.changed'} = 0; |
199
|
|
|
|
|
|
|
#print "restored settings: ",IO::Stty::stty($self->{'s'},'-a'),"\n"; |
200
|
|
|
|
|
|
|
} |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub DESTROY { |
203
|
0
|
|
|
0
|
|
|
my($self) = @_; |
204
|
|
|
|
|
|
|
#print "DESTROY $self\n"; |
205
|
0
|
|
|
|
|
|
$self->resetstty(); |
206
|
0
|
|
|
|
|
|
undef $self; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# write string, wait for output to drain, wait a bit more |
210
|
|
|
|
|
|
|
sub write { |
211
|
0
|
|
|
0
|
0
|
|
my($self, $string) = @_; |
212
|
0
|
0
|
|
|
|
|
print "write(",length($string),": ",unpack("H*",$string),")\n" |
213
|
|
|
|
|
|
|
if $Hardware::iButton::Connection::debug; |
214
|
0
|
|
|
|
|
|
$self->{'s'}->syswrite($string, length($string)); |
215
|
|
|
|
|
|
|
# drain |
216
|
|
|
|
|
|
|
#print "fileno: ",$self->{'s'}->fileno(),"\n"; |
217
|
|
|
|
|
|
|
#my $r = tcdrain($self->{'s'}->fileno()); print "tcdrain: $r\n"; |
218
|
0
|
|
|
|
|
|
usleep(1000); |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
# read $bytes. If $timeout seconds goes by without anything read, |
222
|
|
|
|
|
|
|
# return whatever we've got. If $timeout is unspecified, use a system default |
223
|
|
|
|
|
|
|
# of 100ms. If $bytes is 0, just read whatever is available. |
224
|
|
|
|
|
|
|
sub read { |
225
|
0
|
|
|
0
|
0
|
|
my($self, $bytes, $timeout) = @_; |
226
|
0
|
|
|
|
|
|
my($dummy, $input); |
227
|
0
|
0
|
|
|
|
|
if ($bytes) { |
228
|
0
|
|
|
|
|
|
my $start = time; |
229
|
0
|
|
|
|
|
|
while($bytes) { |
230
|
0
|
|
|
|
|
|
my $count = $self->{'s'}->sysread($dummy, $bytes); |
231
|
0
|
0
|
|
|
|
|
unless ($count) { |
232
|
|
|
|
|
|
|
# error. Probably EWOULDBLOCK. |
233
|
0
|
|
|
|
|
|
print "sleep\n" if DEBUG; |
234
|
0
|
|
|
|
|
|
usleep(1000); |
235
|
0
|
0
|
|
|
|
|
if (time - $start > 2) { |
236
|
0
|
|
|
|
|
|
warn("read timed out, got ",length($input), |
237
|
|
|
|
|
|
|
" still want $bytes\n"); |
238
|
0
|
0
|
|
|
|
|
print "read(",length($input),": ",unpack("H*",$input),")\n" |
239
|
|
|
|
|
|
|
if $Hardware::iButton::Connection::debug; |
240
|
0
|
|
|
|
|
|
return $input; |
241
|
|
|
|
|
|
|
} |
242
|
0
|
|
|
|
|
|
next; |
243
|
|
|
|
|
|
|
} |
244
|
0
|
|
|
|
|
|
$input .= $dummy; $bytes -= $count; |
|
0
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
} |
246
|
|
|
|
|
|
|
} else { |
247
|
0
|
|
|
|
|
|
$self->{'s'}->sysread($input, 10000); |
248
|
|
|
|
|
|
|
} |
249
|
0
|
0
|
|
|
|
|
print "read(",length($input),": ",unpack("H*",$input),")\n" |
250
|
|
|
|
|
|
|
if $Hardware::iButton::Connection::debug; |
251
|
0
|
|
|
|
|
|
return $input; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub mode { |
255
|
0
|
|
|
0
|
0
|
|
my($self, $newmode) = @_; |
256
|
0
|
0
|
|
|
|
|
if ($self->{'mode'} ne $newmode) { |
257
|
0
|
|
|
|
|
|
$self->write($newmode); |
258
|
0
|
|
|
|
|
|
$self->{'mode'} = $newmode; |
259
|
|
|
|
|
|
|
} |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
# send a series of bytes to the one-wire bus, as opposed to merely sending a |
263
|
|
|
|
|
|
|
# series of bytes to the DS2480. This deals with making sure we're in the |
264
|
|
|
|
|
|
|
# SET_DATA_MODE and escaping the SET_COMMAND_MODE chars |
265
|
|
|
|
|
|
|
|
266
|
|
|
|
|
|
|
sub send { |
267
|
0
|
|
|
0
|
0
|
|
my($self, $str) = @_; |
268
|
0
|
|
|
|
|
|
$self->mode(SET_DATA_MODE); |
269
|
0
|
|
|
|
|
|
$str =~ s/\xe3/\xe3\xe3/g; # double SET_COMMAND_MODE chars |
270
|
0
|
|
|
|
|
|
$self->write($str); |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
|
273
|
|
|
|
|
|
|
# DESTROY: nothing special to do, the port will be closed for us. Once we |
274
|
|
|
|
|
|
|
# start doing 'stty' stuff, though, we should really return the port to the |
275
|
|
|
|
|
|
|
# way it was before |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head2 reset |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
$status = $c->reset(); |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
resets the One-Wire bus. Returns a status code: |
282
|
|
|
|
|
|
|
0: bus shorted |
283
|
|
|
|
|
|
|
1: presence pulse: at least one device is present on the bus |
284
|
|
|
|
|
|
|
2: alarming presence pulse: at least one device is alarmed |
285
|
|
|
|
|
|
|
3: no presence pulse: there are no devices on the bus |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
=cut |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub reset { |
290
|
0
|
|
|
0
|
1
|
|
my($self) = @_; |
291
|
|
|
|
|
|
|
|
292
|
0
|
|
|
|
|
|
$self->read(0); |
293
|
0
|
|
|
|
|
|
$self->mode(SET_COMMAND_MODE); |
294
|
0
|
|
|
|
|
|
$self->write("\xc1"); |
295
|
0
|
|
|
|
|
|
$self->{'selected'} = undef; |
296
|
0
|
|
|
|
|
|
my $status = $self->read(1); |
297
|
0
|
|
|
|
|
|
$status = ord($status) & 0x03; |
298
|
0
|
|
|
|
|
|
return $status; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=head2 scan |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
@buttons = $c->scan(); |
304
|
|
|
|
|
|
|
@buttons = $c->scan($family_code); |
305
|
|
|
|
|
|
|
$button = $c->scan($family_code, $serial); |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
scans the One-Wire bus with the ROM Search command and builds up a list of all |
308
|
|
|
|
|
|
|
devices present. Hardware::iButton::Device objects are created for each, and |
309
|
|
|
|
|
|
|
an array of these objects is returned. If a family code is given, the search |
310
|
|
|
|
|
|
|
is restricted to devices of that family type. If a serial number is given |
311
|
|
|
|
|
|
|
(which must be a 12 character string), then the bus is searched for that one |
312
|
|
|
|
|
|
|
particular device (family code plus id) and, if present, an object is returned |
313
|
|
|
|
|
|
|
for it. |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
If no buttons match the search criteria (or none are present), an empty list |
316
|
|
|
|
|
|
|
or undef is returned. |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=cut |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
# encode bits into the 16-byte string used to give the Search Accelerator |
321
|
|
|
|
|
|
|
# command a preferred path |
322
|
|
|
|
|
|
|
# $byte[0] = "b3XXb2XXb1XXb0XX", $byte[1] = "b7XXb6XXb5XXb4XX", etc |
323
|
|
|
|
|
|
|
# $byte[0] = $bit[3] << 7 | $bit[2] << 5 | $bit[1] << 3 | $bit[0] << 1 |
324
|
|
|
|
|
|
|
# etc |
325
|
|
|
|
|
|
|
# take an array of 0 or 1 |
326
|
|
|
|
|
|
|
# return a 16 character string ready to be written |
327
|
|
|
|
|
|
|
# the One-Wire protocol uses ROM values that are 64 bits, LSB first, first |
328
|
|
|
|
|
|
|
# the family code, then serial number, then CRC. |
329
|
|
|
|
|
|
|
sub packbits { |
330
|
0
|
|
|
0
|
0
|
|
my($bits) = @_; # [0 .. 63], each either 1 or 0 |
331
|
0
|
|
|
|
|
|
print "packbits(bits=($bits)\n" if DEBUG; |
332
|
0
|
|
|
|
|
|
$bits =~ s/(.)/0 . $1/ge; # insert the "XX"s as zeros |
|
0
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
|
$bits = pack("b128", $bits); |
334
|
0
|
|
|
|
|
|
print " (",length($bits),"):",join(',',unpack("C*",$bits)),"\n" if DEBUG; |
335
|
0
|
|
|
|
|
|
return $bits; |
336
|
|
|
|
|
|
|
} |
337
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
# extract bits returned by the Search Accelerator command |
339
|
|
|
|
|
|
|
# the bits are interleaved "chosen bits" and "discrepancy bits" |
340
|
|
|
|
|
|
|
# first byte is r3d3r2d2r1d1r0d0 |
341
|
|
|
|
|
|
|
# second is r7d7r6d6r5d5r4d4 |
342
|
|
|
|
|
|
|
# we are given a string of 16 chars straight from read() |
343
|
|
|
|
|
|
|
# generate two arrays, $r[0..63] and $d[0..63], each with 0 or 1 |
344
|
|
|
|
|
|
|
# find $firstconflict: the lowest $i>=$bits for which $conflict[$i] == 1, |
345
|
|
|
|
|
|
|
# return $firstconflict, @r |
346
|
|
|
|
|
|
|
sub unpackbits { |
347
|
0
|
|
|
0
|
0
|
|
my($bits, $string) = @_; |
348
|
0
|
|
|
|
|
|
print "unpackbits(bits=$bits,string(",length($string),"):" if DEBUG; |
349
|
0
|
|
|
|
|
|
print join(',',map {sprintf('0x%02x',$_)} unpack("C*",$string)),")\n" |
350
|
|
|
|
|
|
|
if DEBUG; |
351
|
0
|
|
|
|
|
|
my $b1 = unpack("b128", $string); |
352
|
|
|
|
|
|
|
# now extract every other char into a separate array |
353
|
0
|
|
|
|
|
|
my($chosen,$d) = ($b1,$b1); |
354
|
0
|
|
|
|
|
|
$chosen =~ s/.(.)/$1/g; |
355
|
0
|
|
|
|
|
|
$d =~ s/(.)./$1/g; |
356
|
0
|
|
|
|
|
|
print " r: $chosen\n" if DEBUG; print " d: $d\n" if DEBUG; |
|
0
|
|
|
|
|
|
|
357
|
0
|
|
|
|
|
|
my(@conflict) = split(//,$d); |
358
|
|
|
|
|
|
|
# find $firstconflict |
359
|
0
|
|
|
|
|
|
my $firstconflict = -1; |
360
|
0
|
|
|
|
|
|
for(my $i=$bits; $i<64; $i++) { |
361
|
0
|
0
|
|
|
|
|
if ($conflict[$i]) { |
362
|
0
|
|
|
|
|
|
$firstconflict = $i; |
363
|
0
|
|
|
|
|
|
last; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
} |
366
|
0
|
|
|
|
|
|
print " first=$firstconflict, chosen=$chosen\n" if DEBUG; |
367
|
0
|
|
|
|
|
|
return($firstconflict, $chosen); |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# find all IDs that have substr($path, 0, $bits) in them. Recurse. |
371
|
|
|
|
|
|
|
# substr($path, $bits+1) will be all "0"s |
372
|
|
|
|
|
|
|
sub scan1 { |
373
|
0
|
|
|
0
|
0
|
|
my($self, $bits, $path) = @_; |
374
|
0
|
|
|
|
|
|
print "scan1(bits=$bits,path=$path)\n" if DEBUG; |
375
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
#print "str: ",join(' ', map {sprintf('0x%02x', ord($_))} (split(//,$str))),"\n" if DEBUG; |
377
|
0
|
|
|
|
|
|
$self->reset(); # puts us in COMMAND_MODE |
378
|
0
|
|
|
|
|
|
$self->mode(SET_DATA_MODE); |
379
|
0
|
|
|
|
|
|
$self->write(SEARCH_ROM); |
380
|
0
|
|
|
|
|
|
$self->mode(SET_COMMAND_MODE); |
381
|
0
|
|
|
|
|
|
$self->write(SEARCH_ACCEL_ON); |
382
|
0
|
|
|
|
|
|
$self->mode(SET_DATA_MODE); |
383
|
0
|
|
|
|
|
|
$self->write(packbits($path)); |
384
|
0
|
|
|
|
|
|
$self->mode(SET_COMMAND_MODE); |
385
|
0
|
|
|
|
|
|
$self->write(SEARCH_ACCEL_OFF); |
386
|
|
|
|
|
|
|
|
387
|
0
|
|
|
|
|
|
my $in = $self->read(17); |
388
|
|
|
|
|
|
|
# the first byte is the echo of SEARCH_ROM. Then 16 bytes of data. |
389
|
0
|
|
|
|
|
|
print "read ",length($in)," bytes: " if DEBUG; |
390
|
0
|
|
|
|
|
|
print join(',',map{sprintf('0x%02x',$_)} unpack("C*",$in)),"\n" if DEBUG; |
391
|
0
|
|
|
|
|
|
$in = substr($in, 1); |
392
|
0
|
|
|
|
|
|
my($firstconflict, $chosen) = unpackbits($bits, $in); |
393
|
0
|
0
|
|
|
|
|
if ($firstconflict == -1) { |
394
|
|
|
|
|
|
|
# there was no conflict. That means there was only one ID with this |
395
|
|
|
|
|
|
|
# prefix. Return it. |
396
|
0
|
|
|
|
|
|
return ($chosen); |
397
|
|
|
|
|
|
|
} else { |
398
|
|
|
|
|
|
|
# there was a conflict at $firstconflict. Recurse and return the two |
399
|
|
|
|
|
|
|
# possible paths. The Search Accelerator has already given us the |
400
|
|
|
|
|
|
|
# lowest numerical ID with this prefix (since we gave 0's to @path) |
401
|
|
|
|
|
|
|
# but using that data would be too much of a nuisance. |
402
|
0
|
|
|
|
|
|
my($way0,$way1) = ($path,$path); |
403
|
0
|
|
|
|
|
|
substr($way0, $firstconflict, 1) = "0"; |
404
|
0
|
|
|
|
|
|
substr($way1, $firstconflict, 1) = "1"; |
405
|
0
|
|
|
|
|
|
return($self->scan1($firstconflict+1, $way0), |
406
|
|
|
|
|
|
|
$self->scan1($firstconflict+1, $way1)); |
407
|
|
|
|
|
|
|
} |
408
|
|
|
|
|
|
|
} |
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
sub scan { |
411
|
0
|
|
|
0
|
1
|
|
my($self, $family_code, $serial) = @_; |
412
|
0
|
|
|
|
|
|
my(@buttons); |
413
|
|
|
|
|
|
|
my(@ids); |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# scan bus. Each ID is an 8 byte list, starting with the family code, |
416
|
|
|
|
|
|
|
# then 6 ID bytes, then the CRC. The ID bytes are in the same order as |
417
|
|
|
|
|
|
|
# the label engraved on the button, which is backwards of the order |
418
|
|
|
|
|
|
|
# read from the bus. |
419
|
|
|
|
|
|
|
|
420
|
0
|
|
|
|
|
|
my $r = $self->reset(); |
421
|
0
|
0
|
0
|
|
|
|
if ($r == 0 or $r == 3) { |
422
|
|
|
|
|
|
|
# short or nothing present |
423
|
0
|
|
|
|
|
|
return undef; |
424
|
|
|
|
|
|
|
} |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
# use the DS2480's Search Accelerator function |
427
|
0
|
|
|
|
|
|
my(@raw_ids); |
428
|
|
|
|
|
|
|
# the raw_ids used here are 64-char strings: |
429
|
|
|
|
|
|
|
# f0f1f2f3..f7 . s0s1s2s3..s47 . c0c1..c7 |
430
|
|
|
|
|
|
|
# f: family code (lsb first) |
431
|
|
|
|
|
|
|
# s: serial number (lsb first). label is printed msb first. |
432
|
|
|
|
|
|
|
# c: crc (lsb first) |
433
|
|
|
|
|
|
|
|
434
|
0
|
0
|
|
|
|
|
if (!defined($family_code)) { |
435
|
|
|
|
|
|
|
# find everyone |
436
|
0
|
|
|
|
|
|
@raw_ids = $self->scan1(0, "0" x 64); |
437
|
|
|
|
|
|
|
} else { |
438
|
0
|
|
|
|
|
|
my $family_bits; |
439
|
0
|
|
|
|
|
|
$family_bits = unpack("b8", chr(hex($family_code))); |
440
|
0
|
0
|
|
|
|
|
if (defined($serial)) { |
441
|
0
|
|
|
|
|
|
my $device_bits; |
442
|
|
|
|
|
|
|
# find this particular device |
443
|
0
|
0
|
|
|
|
|
die 'scan(): \$serial must have 12 hex chars' |
444
|
|
|
|
|
|
|
unless ($serial =~ /^[0-9a-fA-f]{12}$/); |
445
|
0
|
|
|
|
|
|
$device_bits = reverse(unpack("B48",pack("H12",$serial))); |
446
|
0
|
|
|
|
|
|
@raw_ids = $self->scan1(8+48, $family_bits . $device_bits . "0"x8); |
447
|
0
|
|
|
|
|
|
@raw_ids = grep {/^\Q$family_bits$device_bits\E/} @raw_ids; |
|
0
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
} else { |
449
|
|
|
|
|
|
|
# find everyone with this family code |
450
|
0
|
|
|
|
|
|
@raw_ids = $self->scan1(8, $family_bits . "0" x 56); |
451
|
0
|
|
|
|
|
|
@raw_ids = grep {/^\Q$family_bits\E/} @raw_ids; |
|
0
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
} |
453
|
|
|
|
|
|
|
} |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
|
456
|
0
|
|
|
|
|
|
foreach my $raw_id (@raw_ids) { |
457
|
|
|
|
|
|
|
# $raw_id is a 64 character string of "0" and "1" |
458
|
0
|
|
|
|
|
|
my $button = Hardware::iButton::Device->new($self, $raw_id); |
459
|
|
|
|
|
|
|
#print "id: ",$button->id(),"\n"; |
460
|
0
|
|
|
|
|
|
push(@buttons, $button); |
461
|
|
|
|
|
|
|
} |
462
|
|
|
|
|
|
|
|
463
|
0
|
|
|
|
|
|
$self->reset(); |
464
|
0
|
|
|
|
|
|
return @buttons; |
465
|
|
|
|
|
|
|
} |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=head2 readrom |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
@id = $c->readrom(); # FIXME |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
Run a Read ROM command on the bus, and return the 8 bytes that result as a |
472
|
|
|
|
|
|
|
string of 16 hex chars. This command is only useful if there is exactly 1 |
473
|
|
|
|
|
|
|
device on the bus. This is rarely the case, since most containers of DS2480 |
474
|
|
|
|
|
|
|
chips have solder-mount touch memory devices already on the bus (the 1411k |
475
|
|
|
|
|
|
|
seems to have a DS2401 id-only device on it, and the DS9097U appears to have a |
476
|
|
|
|
|
|
|
DS2502 1k add-only eprom in it). |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
=cut |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
sub readrom { |
481
|
0
|
|
|
0
|
1
|
|
my($self) = @_; |
482
|
|
|
|
|
|
|
|
483
|
0
|
|
|
|
|
|
$self->write("\xc1\xe1\x33\xff\xff\xff\xff\xff\xff\xff\xff\xe3\xc9"); |
484
|
0
|
|
|
|
|
|
my $dummy = $self->read(11); |
485
|
0
|
|
|
|
|
|
my(@bin_id) = map {ord($_)} split(//, $dummy); |
|
0
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
# first byte is the reset result, second is an echo of the 0x33 Read ROM |
487
|
|
|
|
|
|
|
# code. Next 8 are familycode, id[5..0], then crc. Last is reset result. |
488
|
0
|
|
|
|
|
|
my(@id) = @bin_id[2,8,7,6,5,4,3,9]; |
489
|
|
|
|
|
|
|
|
490
|
0
|
|
|
|
|
|
return @id; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
# $c->select($rawid); |
494
|
|
|
|
|
|
|
# activate the button with $rawid, if it isn't already. |
495
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
# todo: keep track of how long it's been since we actually heard from this |
497
|
|
|
|
|
|
|
# device. If it's been more than a couple of seconds, do a Search ROM |
498
|
|
|
|
|
|
|
# ($self->scan($family,$serial)) to make sure it's still there. |
499
|
|
|
|
|
|
|
sub select { |
500
|
0
|
|
|
0
|
0
|
|
my($self, $rawid) = @_; |
501
|
|
|
|
|
|
|
|
502
|
0
|
0
|
0
|
|
|
|
if ($self->{'selected'} and $self->{'selected'} eq $rawid) { |
503
|
|
|
|
|
|
|
# already selected |
504
|
0
|
|
|
|
|
|
return 1; |
505
|
|
|
|
|
|
|
} |
506
|
|
|
|
|
|
|
|
507
|
0
|
|
|
|
|
|
my $r = $self->reset(); |
508
|
0
|
0
|
0
|
|
|
|
if ($r == 0 or $r == 3) { |
509
|
|
|
|
|
|
|
# short or nothing present |
510
|
0
|
|
|
|
|
|
return undef; |
511
|
|
|
|
|
|
|
} |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# send Match ROM command |
514
|
0
|
|
|
|
|
|
my $str = MATCH_ROM . pack("b64",$rawid); |
515
|
0
|
|
|
|
|
|
$self->send($str); |
516
|
0
|
|
|
|
|
|
$self->read(length($str)); # read echos |
517
|
|
|
|
|
|
|
|
518
|
0
|
|
|
|
|
|
$self->{'selected'} = $rawid; |
519
|
|
|
|
|
|
|
# see if anyone is still there?? |
520
|
|
|
|
|
|
|
# nope, no way to tell |
521
|
|
|
|
|
|
|
|
522
|
0
|
|
|
|
|
|
return 1; |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
sub verify { |
526
|
0
|
|
|
0
|
0
|
|
my ($self, $rawid) = @_; |
527
|
0
|
|
|
|
|
|
my $str = MATCH_ROM . "\xFF" x 24 . pack("b64",$rawid); |
528
|
0
|
|
|
|
|
|
$self->send($str); |
529
|
0
|
|
|
|
|
|
my $ret = $self->read(length($str)); # read echos |
530
|
|
|
|
|
|
|
# return (ord(substr($ret, 32, 1)) == 121); |
531
|
0
|
|
|
|
|
|
print STDERR "LEN = " . length($ret) . "\n"; |
532
|
0
|
|
|
|
|
|
print STDERR "RET = '$ret'\n"; |
533
|
0
|
|
|
|
|
|
print STDERR "CHARS = "; |
534
|
0
|
|
|
|
|
|
foreach my $chr (split(//, $ret)) { |
535
|
0
|
|
|
|
|
|
print STDERR ord($chr) . " "; |
536
|
|
|
|
|
|
|
} |
537
|
0
|
|
|
|
|
|
print STDERR "\n"; |
538
|
0
|
|
|
|
|
|
print STDERR "LAST = " . ord(substr($ret, 32, 1)) . "\n"; |
539
|
|
|
|
|
|
|
# 218, 121 |
540
|
0
|
0
|
|
|
|
|
if ($ret eq "") { |
541
|
0
|
|
|
|
|
|
print STDERR "0\n"; |
542
|
0
|
|
|
|
|
|
return 0; |
543
|
|
|
|
|
|
|
} else { |
544
|
0
|
|
|
|
|
|
print STDERR "1\n"; |
545
|
0
|
|
|
|
|
|
return 1; |
546
|
|
|
|
|
|
|
} |
547
|
|
|
|
|
|
|
# print STDERR "'$ret'\n"; |
548
|
|
|
|
|
|
|
} |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
# for (i = 0; i < 192; i += 3) |
551
|
|
|
|
|
|
|
# { |
552
|
|
|
|
|
|
|
# tst = (bitacc(READ_FUNCTION,0,i,&sendpacket[1]) << 1) | |
553
|
|
|
|
|
|
|
# bitacc(READ_FUNCTION,0,(int)(i+1),&sendpacket[1]); |
554
|
|
|
|
|
|
|
# |
555
|
|
|
|
|
|
|
# s = bitacc(READ_FUNCTION,0,cnt++,&SerialNum[portnum][0]); |
556
|
|
|
|
|
|
|
# |
557
|
|
|
|
|
|
|
# if (tst == 0x03) // no device on line |
558
|
|
|
|
|
|
|
# { |
559
|
|
|
|
|
|
|
# goodbits = 0; // number of good bits set to zero |
560
|
|
|
|
|
|
|
# break; // quit |
561
|
|
|
|
|
|
|
# } |
562
|
|
|
|
|
|
|
# |
563
|
|
|
|
|
|
|
# if (((s == 0x01) && (tst == 0x02)) || |
564
|
|
|
|
|
|
|
# ((s == 0x00) && (tst == 0x01)) ) // correct bit |
565
|
|
|
|
|
|
|
# goodbits++; // count as a good bit |
566
|
|
|
|
|
|
|
# } |
567
|
|
|
|
|
|
|
# |
568
|
|
|
|
|
|
|
# // check too see if there were enough good bits to be successful |
569
|
|
|
|
|
|
|
# if (goodbits >= 8) |
570
|
|
|
|
|
|
|
# return TRUE; |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
sub crc { |
574
|
0
|
|
|
0
|
0
|
|
my($crc, @newbytes) = @_; |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
sub addbit { |
577
|
0
|
|
|
0
|
0
|
|
my($crc, $bit) = @_; |
578
|
|
|
|
|
|
|
#printf("addbit($bit): 0x%02x -> ",$crc);; |
579
|
0
|
|
|
|
|
|
my $in = ($crc & 1) ^ $bit; |
580
|
0
|
0
|
|
|
|
|
$crc ^= 0x18 if $in; |
581
|
0
|
|
|
|
|
|
$crc >>= 1; |
582
|
0
|
0
|
|
|
|
|
$crc |= 0x80 if $in; |
583
|
|
|
|
|
|
|
#printf("0x%02x\n",$crc); |
584
|
0
|
|
|
|
|
|
return $crc; |
585
|
|
|
|
|
|
|
} |
586
|
|
|
|
|
|
|
|
587
|
0
|
|
|
|
|
|
foreach my $byte (@newbytes) { |
588
|
0
|
|
|
|
|
|
my $bits = unpack("b8", $byte); |
589
|
0
|
|
|
|
|
|
my(@bits) = split(//,$bits); |
590
|
0
|
|
|
|
|
|
foreach (@bits) { |
591
|
0
|
|
|
|
|
|
$crc = addbit($crc, $_); |
592
|
|
|
|
|
|
|
} |
593
|
|
|
|
|
|
|
} |
594
|
0
|
|
|
|
|
|
return $crc; |
595
|
|
|
|
|
|
|
} |
596
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
# Autoload methods go after =cut, and are processed by the autosplit program. |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
1; |
601
|
|
|
|
|
|
|
__END__ |