File Coverage

blib/lib/Device/USB/PCSensor/HidTEMPer/Device.pm
Criterion Covered Total %
statement 16 85 18.8
branch 1 38 2.6
condition 2 3 66.6
subroutine 5 13 38.4
pod 5 5 100.0
total 29 144 20.1


line stmt bran cond sub pod time code
1             package Device::USB::PCSensor::HidTEMPer::Device;
2              
3 1     1   16014 use strict;
  1         2  
  1         32  
4 1     1   5 use warnings;
  1         2  
  1         27  
5 1     1   5 use Carp;
  1         4  
  1         103  
6              
7             =head1
8              
9             Device::USB::PCSensor::HidTEMPer::Device - Generic device class
10              
11             =head1 VERSION
12              
13             Version 0.02
14              
15             =cut
16              
17             our $VERSION = 0.02;
18              
19             =head1 SYNOPSIS
20              
21             None
22              
23             =head1 DESCRIPTION
24              
25             This module contains a generic class that all HidTEMPer devices should
26             inherit from, thereby keeping the implemented methods consistent and making it
27             possible to use the same code to contact every supported device.
28              
29             =head2 CONSTANTS
30              
31             =over 3
32              
33             =item * CONNECTION_TIMEOUT
34              
35             USB communication timeout, specified in milliseconds.
36              
37             =back
38             =cut
39              
40 1     1   5 use constant CONNECTION_TIMEOUT => 60;
  1         1  
  1         829  
41              
42             =head2 METHODS
43              
44             =over 3
45              
46             =item * new( $usb_device )
47              
48             Creates a new generic Device object.
49              
50             =cut
51              
52             sub new
53             {
54 0     0 1 0 my $class = shift;
55 0         0 my ( $usb ) = @_; # Device::USB::Device interface that should be used
56            
57             # Make sure that this is always a reference to the device.
58 0 0       0 $usb = ref $usb
59             ? $usb
60             : \$usb;
61            
62 0         0 my $self = {
63             device => $usb,
64             };
65            
66             # Possible sensors
67 0         0 $self->{sensor} = {
68             internal => undef,
69             external => undef,
70             };
71            
72             # If the two interfaces are currently in use, detach them and thereby
73             # make them available for use.
74 0 0       0 $usb->detach_kernel_driver_np(0) if $usb->get_driver_np(0);
75 0 0       0 $usb->detach_kernel_driver_np(1) if $usb->get_driver_np(1);
76            
77             # Opens the device for use by this object.
78 0 0       0 croak 'Error opening device' unless $usb->open();
79            
80             # It is only needed to set the configuration used under a Windows system.
81 0 0       0 $usb->set_configuration(1) if $^O eq 'MSWin32';
82            
83             # Claim the two interfaces for use by this object.
84 0 0       0 croak 'Could not claim interface' if $usb->claim_interface(0);
85 0 0       0 croak 'Could not claim interface' if $usb->claim_interface(1);
86            
87 0         0 bless $self, $class;
88 0         0 return $self;
89             }
90              
91             sub DESTROY
92             {
93 0     0   0 my $self = shift;
94              
95             # Delete sensors
96 0         0 delete $self->{sensor}->{internal};
97 0         0 delete $self->{sensor}->{external};
98              
99             # Release the interfaces back to the operating system.
100 0         0 $self->{device}->release_interface(0);
101 0         0 $self->{device}->release_interface(1);
102              
103 0         0 delete $self->{device};
104            
105 0         0 return undef;
106             }
107              
108             =item * identifier()
109              
110             This method is used to acquire the numerical value representing the device
111             type identifier.
112              
113             =cut
114              
115             sub identifier
116             {
117 0     0 1 0 my $self = shift;
118            
119             # Command 0x52 will return the following 8 byte result, repeated 4 times.
120             # Position 0: unknown
121             # Position 1: Device ID
122             # Position 2: Calibration value one for the internal sensor
123             # Position 3: Calibration value two for the internal sensor
124             # Position 4: Calibration value one for the external sensor
125             # Position 5: Calibration value two for the external sensor
126             # Position 6: unknown
127             # Position 7: unknown
128            
129 0         0 my ( undef, $identifier ) = $self->_read( 0x52 );
130 0         0 return $identifier;
131             }
132              
133             # _read( @command_bytes )
134              
135             # Used to read information from the device.
136              
137             # Input parameter
138             # @command_bytes = Array of 8 bit hex values, maximum of 32 bytes,
139             # representing the commands that will be executed by the device.
140              
141             # Output parameter
142             # An array of 8 bit hex values or a text string using chars
143             # (from 0x00 to 0xFF) to represent the hex values. Returns undef on error.
144              
145             sub _read
146             {
147 0     0   0 my $self = shift;
148 0         0 my ( @bytes ) = @_;
149 0         0 my ( $data, $checksum ) = ( 0, 0 );
150            
151 0         0 $checksum += $self->_command(32, 0xA, 0xB, 0xC, 0xD, 0x0, 0x0, 0x2 );
152 0         0 $checksum += $self->_command(32, @bytes );
153 0         0 $checksum += $self->_command(32, 0x0 );
154 0         0 $checksum += $self->_command(32, 0x0 );
155 0         0 $checksum += $self->_command(32, 0x0 );
156 0         0 $checksum += $self->_command(32, 0x0 );
157 0         0 $checksum += $self->_command(32, 0x0 );
158 0         0 $checksum += $self->_command(32, 0x0 );
159 0         0 $checksum += $self->_command(32, 0x0 );
160 0         0 $checksum += $self->_command(32, 0xA, 0xB, 0xC, 0xD, 0x0, 0x0, 0x1 );
161            
162             # On error a wrong amount of bytes is returened.
163 0 0       0 carp 'The device returned to few bytes' if $checksum < 320;
164 0 0       0 carp 'The device returned to many bytes' if $checksum > 320;
165 0 0       0 return undef if $checksum != 320;
166            
167             # Send a message to the device, capturing the output into into $data
168 0         0 $checksum = $self->{device}->control_msg(
169             0xA1, # Request type
170             0x1, # Request
171             0x300, # Value
172             0x1, # Index
173             $data, # Bytes to be transfeered
174             32, # Number of bytes to be transferred, more than 32 eq seg fault
175             CONNECTION_TIMEOUT # Timeout
176             );
177            
178             # Ensure that 32 bytes are read from the device.
179 0 0       0 carp 'Error reading information from device' if $checksum != 32;
180            
181 0 0       0 return wantarray ? unpack "C*", $data : $data;
182             }
183              
184             # _command( $total_byte_size, @data )
185              
186             # This method is used to send a command to the device, only used for commands
187             # where the output is not needed to be captured.
188              
189             # Input parameters
190             # $total_byte_size = The total size that should be sent. Zero padding will be
191             # added at the end to achieve specified length.
192              
193             # @data = An array of 8bit hex values representing the data that
194             # should be sent.
195              
196             # Output parameter
197             # Returns the number of bytes that where sent to the device if successful
198             # execution. This is the same amout of bytes that where specified as input.
199             # Returns undef on error.
200              
201             sub _command
202             {
203 0     0   0 my $self = shift;
204 0         0 my ( $size, @bytes ) = @_;
205              
206             # Convert to char and add zero padding at the end
207 0         0 my $data = join '', map{ chr $_ } @bytes;
  0         0  
208 0         0 $data .= join '', map{ chr $_ } ( (0)x( $size - $#bytes ) );
  0         0  
209              
210             # Send the message to the device
211 0         0 my $return = $self->{device}->control_msg(
212             0x21, # Request type
213             0x9, # Request
214             0x200, # Value
215             0x1, # Index
216             $data, # Bytes to be transferred
217             $size, # Number of bytes to be transferred
218             CONNECTION_TIMEOUT # Timeout
219             );
220            
221             # If the device returns correct amount of bytes return count, all OK.
222 0 0       0 return $return if $return == $size;
223            
224 0 0       0 carp 'The device return less bytes than anticipated' if $return < $size;
225 0 0       0 carp 'The device returned more bytes than anticipated' if $return > $size;
226 0         0 return undef;
227             }
228              
229             # _write( @bytes )
230              
231             # This method is used to write information back to the device. Be carefull
232             # when using this, since any wrong information sent may destroy the device.
233              
234             # Input parameter
235             # @bytes = The bytes that should be written to the device, a maximum of
236             # 32 bytes.
237              
238             # Output parameter
239             # Returns the number of bytes that where sent to the device if successful
240             # execution. This should be 288 if everything is successful.
241              
242             sub _write
243             {
244 2     2   772 my $self = shift;
245 2         3 my ( @bytes ) = @_;
246 2         5 my ( $data, $checksum ) = ( 0, 0 );
247              
248             # Filter out possible actions
249 2 50 66     17 return undef if $bytes[0] > 0x68 || $bytes[0] < 0x61;
250              
251 0           $checksum += $self->_command(32, 0xA, 0xB, 0xC, 0xD, 0x0, 0x0, 0x2 );
252 0           $checksum += $self->_command(32, @bytes );
253 0           $checksum += $self->_command(32, 0x0 );
254 0           $checksum += $self->_command(32, 0x0 );
255 0           $checksum += $self->_command(32, 0x0 );
256 0           $checksum += $self->_command(32, 0x0 );
257 0           $checksum += $self->_command(32, 0x0 );
258 0           $checksum += $self->_command(32, 0x0 );
259 0           $checksum += $self->_command(32, 0x0 );
260              
261             # On error a wrong amount of bytes is returened.
262 0 0         carp 'The device returned to few bytes' if $checksum < 288;
263 0 0         carp 'The device returned to many bytes' if $checksum > 288;
264 0 0         return undef if $checksum != 288;
265              
266 0           return $checksum;
267             }
268              
269             =item * internal()
270              
271             Returns the corresponding Sensor object representing the internal sensor
272             connected to the device. If the device does not have an internal sensor undef
273             is returned.
274              
275             =cut
276              
277             sub internal
278             {
279 0     0 1   return $_[0]->{sensor}->{internal};
280             }
281              
282             =item * external()
283              
284             Returns the corresponding Sensor object representing the external sensor
285             connected to the device. If the device does not have an external sensor undef
286             is returned.
287              
288             =cut
289              
290             sub external
291             {
292 0     0 1   return $_[0]->{sensor}->{external};
293             }
294              
295             =item * init()
296              
297             Empty method that should be implemented in order to be able to initialize
298             a object instance.
299              
300             =cut
301              
302             sub init
303             {
304 0     0 1   return undef;
305             }
306              
307             =back
308              
309             =head1 DEPENDENCIES
310              
311             This module internally includes and takes use of the following packages:
312              
313             use Carp;
314             use Device::USB;
315             use Device::USB::Device;
316              
317             This module uses the strict and warning pragmas.
318              
319             =head1 BUGS
320              
321             Please report any bugs or missing features using the CPAN RT tool.
322              
323             =head1 FOR MORE INFORMATION
324              
325             None
326              
327             =head1 AUTHOR
328              
329             Magnus Sulland < msulland@cpan.org >
330              
331             =head1 ACKNOWLEDGEMENTS
332              
333             None
334              
335             =head1 COPYRIGHT & LICENSE
336              
337             Copyright (c) 2010-2011 Magnus Sulland
338              
339             This program is free software; you can redistribute it and/or modify it
340             under the same terms as Perl itself.
341              
342             =cut
343              
344             1;