File Coverage

blib/lib/Device/Chip/TMP102.pm
Criterion Covered Total %
statement 85 85 100.0
branch 13 18 72.2
condition 1 2 50.0
subroutine 24 24 100.0
pod 7 8 87.5
total 130 137 94.8


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4              
5             package Device::Chip::TMP102;
6              
7 4     4   254898 use strict;
  4         20  
  4         117  
8 4     4   25 use warnings;
  4         8  
  4         95  
9 4     4   68 use 5.010;
  4         14  
10 4     4   19 use base qw( Device::Chip::Base::RegisteredI2C );
  4         8  
  4         1942  
11             Device::Chip::Base::RegisteredI2C->VERSION('0.10');
12              
13 4     4   17527 use constant REG_DATA_SIZE => 16;
  4         10  
  4         200  
14              
15 4     4   23 use constant DEBUG => 0;
  4         9  
  4         156  
16              
17 4     4   23 use utf8;
  4         8  
  4         15  
18              
19             our $VERSION = '0.02';
20              
21 4     4   2000 use Data::Bitfield qw( bitfield boolfield enumfield );
  4         6793  
  4         625  
22              
23             =encoding UTF-8
24              
25             =head1 NAME
26              
27             C - chip driver for a F
28              
29             =head1 SYNOPSIS
30              
31             use Device::Chip::TMP102;
32              
33             my $chip = Device::Chip::TMP102->new;
34             $chip->mount( Device::Chip::Adapter::...->new )->get;
35              
36             printf "Temperature is %2.2f C\n", $chip->read_temp->get;
37              
38             =head1 DESCRIPTION
39              
40             This L subclass provides specific communication to a
41             F F attached to a computer via an I²C adapter.
42              
43             Not all of the chip's capabilities are currently accessible through this driver. Extended mode is supported.
44              
45             The reader is presumed to be familiar with the general operation of this chip;
46             the documentation here will not attempt to explain or define chip-specific
47             concepts or features, only the use of this module to access them.
48              
49             =cut
50              
51             =head1 MOUNT PARAMETERS
52              
53             =head2 addr
54              
55             The I²C address of the device. Can be specified in decimal, octal or hex with
56             leading C<0> or C<0x> prefixes.
57              
58             =cut
59              
60             sub I2C_options {
61 3     3 0 3051 my $self = shift;
62 3         9 my %params = @_;
63              
64 3   50     23 my $addr = delete $params{addr} // 0x40;
65 3 50       35 $addr = oct $addr if $addr =~ m/^0/;
66              
67             return (
68 3         22 %params, # this needs to fixed with resolution of 127570
69             addr => $addr,
70             max_bitrate => 400E3,
71             );
72             }
73              
74             =head1 METHODS
75              
76             The following methods documented with a trailing call to C<< ->get >> return
77             L instances.
78              
79             =cut
80              
81             use constant {
82 4         4063 REG_TEMP => 0x00, # R
83             REG_CONFIG => 0x01, # R/W
84             REG_T_LOW => 0x02, # R/W
85             REG_T_HIGH => 0x03, # R/W
86 4     4   33 };
  4         8  
87              
88             bitfield CONFIG =>
89             SD => boolfield(0),
90             TM => boolfield(1),
91             POL => boolfield(2),
92             F => enumfield(3, qw( 1 2 4 6 )),
93             R0 => boolfield(5), # R
94             R1 => boolfield(6), # R
95             OS => boolfield(7),
96             EM => boolfield(12),
97             AL => boolfield(13),
98             CR => enumfield(14, qw( 0.25Hz 1Hz 4Hz 8hz ));
99              
100             =head2 read_config
101              
102             $config = $chip->read_config->get
103              
104             Reads and returns the current chip configuration as a C reference.
105              
106             SD => 0 | 1
107             TM => 0 | 1
108             POL => 0 | 1
109             F => "1" | "2" | "4" | "6"
110             R0 => 0 | 1 (read only)
111             R1 => 0 | 1 (read only)
112             OS => 0 | 1
113             EM => 0 | 1
114             AL => 0 | 1
115             CR => "0.25Hz" | "1Hz" | "4Hz" | "8Hz"
116              
117             =cut
118              
119             sub read_config
120             {
121 3     3 1 421 my $self = shift;
122              
123             $self->cached_read_reg( REG_CONFIG, 1 )->then( sub {
124 3     3   670 my ( $bytes ) = @_;
125 3         27 Future->done( $self->{config} = { unpack_CONFIG( unpack "S<", $bytes ) } );
126 3         37 });
127             }
128              
129             =head2 change_config
130              
131             $chip->change_config( %config )->get
132              
133             Changes the configuration. Any field names not mentioned will be preserved.
134              
135             =cut
136              
137             sub change_config
138             {
139 1     1 1 3604 my $self = shift;
140 1         4 my %changes = @_;
141              
142             ( defined $self->{config} ? Future->done( $self->{config} ) :
143             $self->read_config )->then( sub {
144 1     1   86 my %config = ( %{ $_[0] }, %changes );
  1         9  
145              
146 1         4 undef $self->{config}; # invalidate the cache
147 1         6 $self->write_reg( REG_CONFIG, pack "S<", pack_CONFIG( %config ) );
148 1 50       7 });
149             }
150              
151             =head2 read_temp
152              
153             $temp = $chip->read_temp->get
154              
155             Returns the temperature in degrees Celsius.
156              
157             =cut
158              
159             sub read_temp {
160 14     14 1 36768 my $self = shift;
161              
162             Future->needs_all(
163             $self->read_reg( REG_TEMP, 1 ),
164             ( $self->{config} ? Future->done( $self->{config} ) :
165             $self->read_config ),
166             )->then( sub {
167 14     14   3974 my ( $value, $config ) = @_;
168              
169 14         59 Future->done($self->_bytes_to_temp(unpack "s<", $value));
170 14 50       48 });
171             }
172              
173             =head2 write_temp_low
174              
175             $chip->write_temp_low( $temp )->get
176              
177             Changes the low temperature threshold in degrees Celsius.
178              
179             =cut
180              
181             sub write_temp_low {
182 3     3 1 8293 my ($self, $temp) = @_;
183              
184 3         13 $self->write_reg( REG_T_LOW, pack "s>", $self->_temp_to_bytes($temp) );
185             }
186              
187             =head2 read_temp_low
188              
189             $temp = $chip->read_temp_low->get
190              
191             Returns the low temperature threshold in degrees Celsius.
192              
193             =cut
194              
195             sub read_temp_low {
196 2     2 1 5863 my $self = shift;
197              
198             Future->needs_all(
199             $self->read_reg( REG_T_LOW, 1 ),
200             ( $self->{config} ? Future->done( $self->{config} ) :
201             $self->read_config ),
202             )->then( sub {
203 2     2   565 my ( $value, $config ) = @_;
204              
205 2         11 Future->done($self->_bytes_to_temp(unpack "s<", $value));
206 2 50       9 });
207             }
208              
209             =head2 write_temp_high
210              
211             $chip->write_temp_high( $temp )->get
212              
213             Changes the high temperature threshold in degrees Celsius.
214              
215             =cut
216              
217             sub write_temp_high {
218 2     2 1 5798 my ($self, $temp) = @_;
219              
220 2         9 $self->write_reg( REG_T_HIGH, pack "s>", $self->_temp_to_bytes($temp) );
221             }
222              
223             =head2 read_temp_high
224              
225             $temp = $chip->read_temp_high->get
226              
227             Returns the high temperature threshold in degrees Celsius.
228              
229             =cut
230              
231             sub read_temp_high {
232 2     2 1 5590 my $self = shift;
233              
234             Future->needs_all(
235             $self->read_reg( REG_T_HIGH, 1 ),
236             ( $self->{config} ? Future->done( $self->{config} ) :
237             $self->read_config ),
238             )->then( sub {
239 2     2   574 my ( $value, $config ) = @_;
240              
241 2         11 Future->done($self->_bytes_to_temp(unpack "s<", $value));
242 2 50       10 });
243             }
244              
245             sub _bytes_to_temp {
246 18     18   37 my ($self, $value) = @_;
247              
248 18         31 my $lo = ( $value & 0xff00 );
249 18         30 $lo = $lo >> 8;
250              
251 18         28 my $hi = $value & 0x00ff;
252              
253 18         34 my $hilo = $hi*256+$lo; # data is read little endian so swap bytes
254              
255 18         22 printf( "res < : %04x\n", $value ) if DEBUG;
256 18         26 printf( "hi: %02x\n", $hi ) if DEBUG;
257 18         24 printf( "lo: %02x\n", $lo ) if DEBUG;
258 18         21 printf( "res > : %04x\n", $hilo) if DEBUG;
259              
260 18         27 my $shift = 4;
261 18 100       51 if ($self->{config}{EM}) { $shift = 3 }
  9         14  
262              
263 18         27 my $t = $hilo >> $shift;
264              
265 18 100       47 if (($hi | 0x7F) == 0xFF) { # negative temperature
266 4         10 $t = ~$t +1;
267 4         7 $t &= 0xFFF;
268 4         7 $t *= -1;
269             }
270              
271 18         69 return $t * 0.0625;
272             }
273              
274             sub _temp_to_bytes {
275 5     5   13 my ($self, $temp) = @_;
276              
277 5         11 my $shift = 4;
278 5 100       40 if ($self->{config}{EM}) { $shift = 3 }
  3         9  
279              
280 5         17 my $t = int(abs($temp)/0.0625) << $shift;
281              
282 5 100       15 if ($temp < 0) {
283 1         3 $t = ~$t + 1;
284 1         3 $t &= 0xFFFF;
285             }
286 5         53 return $t
287             }
288              
289             0x55AA;