File Coverage

blib/lib/USB/Descriptor/Configuration.pm
Criterion Covered Total %
statement 15 96 15.6
branch 0 42 0.0
condition 0 15 0.0
subroutine 5 17 29.4
pod 10 10 100.0
total 30 180 16.6


line stmt bran cond sub pod time code
1             package USB::Descriptor::Configuration;
2              
3 1     1   6 use strict;
  1         2  
  1         36  
4 1     1   6 use warnings;
  1         2  
  1         25  
5 1     1   658 use USB::Descriptor::Interface;
  1         3  
  1         60  
6              
7             our $VERSION = '2'; # Bump this when the interface changes
8              
9 1     1   8 use overload '@{}' => \&bytes;
  1         3  
  1         7  
10              
11 1         1201 use constant fields => qw(
12             bLength bDescriptorType wTotalLength bNumInterfaces bConfigurationValue
13             iConfiguration bmAttributes bMaxPower
14 1     1   70 );
  1         3  
15              
16             =head1 NAME
17              
18             USB::Descriptor::Configuration - USB Interface Descriptor
19              
20             =head1 SYNOPSIS
21              
22             An object representation of a USB configuration descriptor.
23              
24             use USB::Descriptor::Configuration;
25              
26             my $configuration = USB::Descriptor::Configuration->new( description => 'My First Configuration' );
27             $configuration->max_current(100); # Max current in mA
28             $configuration->self_powered(1); # Self-powered device
29             $configuration->interfaces( [ USB::Descriptor::Interface->new() ] );
30             ...
31              
32             =head1 DESCRIPTION
33              
34             L represents a USB configuration descriptor.
35             When added to the descriptor tree of a L object it can
36             be used to generate the data structures needed to compile the firmware for a USB
37             device.
38              
39             =head1 CONSTRUCTOR
40              
41             =over
42              
43             =item $configuration = USB::Descriptor::Configuration->new(description=>$description, ...);
44              
45             Constructs and returns a new L object using the
46             passed options. Each option key is the name of an accessor method.
47              
48             =back
49              
50             =cut
51              
52             sub new
53             {
54 0     0 1   my ($this, %options) = @_;
55 0   0       my $class = ref($this) || $this;
56 0           my $self =
57             {
58             'attributes' => 0x80, # Bit 7 is reserved and set
59             'max_current' => 0,
60             'value' => 0,
61             };
62 0           bless $self, $class;
63              
64 0           while( my ($key, $value) = each %options )
65             {
66 0           $self->$key($value);
67             }
68              
69 0           return $self;
70             }
71              
72             =head1 Arrayification
73              
74             =over
75              
76             =item $configuration->bytes (or @{$configuration} )
77              
78             Returns an array of bytes containing all of the fields in the configuration
79             descriptor fields as well as all of the child interface descriptors.
80              
81             =back
82              
83             =cut
84              
85             sub bytes
86             {
87 0     0 1   my $s = shift;
88              
89 0           my @bytes;
90              
91 0           push @bytes, 9; # Configuration descriptors are 9 bytes long
92 0           push @bytes, 0x02; # bDescriptorType
93 0           push @bytes, 0; # Placeholder for wTotalLength low
94 0           push @bytes, 0; # Placeholder for wTotalLength high
95              
96 0 0         my $numInterfaces = $s->{'interfaces'} ? @{$s->{'interfaces'}} : 0;
  0            
97 0           push @bytes, $numInterfaces; # bNumInterfaces
98              
99 0           push @bytes, $s->value; # bConfigurationValue
100              
101 0 0         my $stringIndex = defined($s->_parent) ? $s->_parent->_index_for_string($s->description) : 0;
102 0           push @bytes, $stringIndex; # iConfiguration
103 0           push @bytes, $s->attributes; # bmAttributes
104 0           push @bytes, int($s->max_current/2) & 0xFF; # bMaxPower
105              
106 0 0         warn "Configuration descriptor length is wrong" unless $bytes[0] == scalar @bytes;
107              
108             # Append the interface descriptors
109 0           my $i = 0;
110 0           for( @{$s->{'interfaces'}} )
  0            
111             {
112             # Set the interface number if it hasn't already been set
113 0 0         $_->number($i++) if $_->number <= $i; # Use <= to force update of $i
114              
115             # Update $i if the interface already has a higher number
116 0 0         $i = $_->number if $_->number > $i;
117              
118 0           push @bytes, @{$_->bytes};
  0            
119             }
120              
121             # Update wTotalLength
122 0           my $wTotalLength = scalar @bytes;
123 0           $bytes[2] = $wTotalLength & 0xFF; # wTotalLength low
124 0           $bytes[3] = ($wTotalLength >> 8) & 0xFF; # wTotalLength high
125              
126 0           return \@bytes;
127             }
128              
129             =head1 ATTRIBUTES
130              
131             =over
132              
133             =item $interface->attributes
134              
135             Direct access to the bmAttributes value. Don't use this unless you know what
136             you're doing.
137              
138             =item $interface->description
139              
140             Get/Set the configuration's description string. A string descriptor index
141             (iConfiguration) will be automatically assigned when arrayified by
142             L.
143              
144             =item $interface->interface
145              
146             A convenience method that wraps a single hash reference in an array and passes
147             it to C.
148              
149             =item $interface->interfaces
150              
151             Get/Set the array of L objects. All of the
152             interfaces in the passed array will be arrayified when the configuration object
153             is arrayified by L.
154              
155             =item $interface->max_current
156              
157             Get/Set the configuration's max current draw in milliamps (bMaxPower). Defaults
158             to 0.
159              
160             =item $interface->remote_wakeup
161              
162             Get/Set the configuration's remote wakeup attribute (bmAttributes).
163              
164             =item $interface->self_powered
165              
166             Get/Set the configuration's self-powered attribute (bmAttributes).
167              
168             =item $interface->value
169              
170             Get/Set the configuration's configuration value (bConfigurationValue).
171              
172             If no value is specified, and the configuration has been added to a
173             L, a value will be automatically assigned by
174             L<< USB::Descriptor::Device->bytes() >>.
175              
176             =back
177              
178             =cut
179              
180             sub attributes
181             {
182 0     0 1   my $s = shift;
183 0 0         $s->{'attributes'} = int(shift) & 0xFF if scalar @_;
184 0           $s->{'attributes'};
185             }
186              
187             sub description
188             {
189 0     0 1   my $s = shift;
190 0 0         $s->{'description'} = shift if scalar @_;
191 0           $s->{'description'};
192             }
193              
194             sub interface
195             {
196 0     0 1   my $s = shift;
197 0 0 0       $s->interfaces([$_[0]]) if( scalar(@_) and (ref($_[0]) eq 'HASH') );
198 0           $s->{'interfaces'}[0];
199             }
200              
201             sub interfaces
202             {
203 0     0 1   my $s = shift;
204 0 0         if( scalar @_ )
205             {
206 0 0         if( ref($_[0]) eq 'ARRAY' )
    0          
207             {
208             # Convert hash reference arguments into Interface objects
209             my @interfaces = map
210             {
211 0 0         if( ref($_) eq 'HASH' ) # Hash reference?
  0 0          
212             {
213 0           USB::Descriptor::Interface->new(%{$_});
  0            
214             }
215             elsif( ref($_) ) # Reference to something else?
216             {
217 0           $_; # Use it
218             }
219 0           } @{$_[0]};
220 0           $s->{'interfaces'} = \@interfaces;
221              
222             # Reparent the new interface descriptors
223 0           $_->_parent($s) for @{$s->{'interfaces'}};
  0            
224             }
225             elsif( ref($_[0]) eq 'HASH' )
226             {
227             # If a hash reference was passed, let interface() handle it
228 0           $s->interface($_[0]);
229             }
230             }
231 0           $s->{'interfaces'};
232             }
233              
234             sub max_current
235             {
236 0     0 1   my $s = shift;
237 0 0         $s->{'max_current'} = int(shift) & 0xFF if scalar @_;
238 0           $s->{'max_current'};
239             }
240              
241             sub remote_wakeup
242             {
243 0     0 1   my $s = shift;
244 0 0         if( scalar @_ )
245             {
246 0 0         if( $_[0] )
247             {
248 0           $s->{'attributes'} |= 0x20;
249             }
250             else
251             {
252 0           $s->{'attributes'} &= ~0x20;
253             }
254              
255             }
256 0           $s->{'attributes'} & 0x20;
257             }
258              
259             sub self_powered
260             {
261 0     0 1   my $s = shift;
262 0 0         if( scalar @_ )
263             {
264 0 0         if( $_[0] )
265             {
266 0           $s->{'attributes'} |= 0x40;
267             }
268             else
269             {
270 0           $s->{'attributes'} &= ~0x40;
271             }
272              
273             }
274 0           $s->{'attributes'} & 0x40;
275             }
276              
277             sub value
278             {
279 0     0 1   my $s = shift;
280 0 0         $s->{'value'} = int(shift) & 0xFF if scalar @_;
281 0           $s->{'value'};
282             }
283              
284             # --- String Descriptor support ---
285              
286             # Called by children during arrayification
287             sub _index_for_string
288             {
289 0     0     my ($s, $string) = @_;
290 0 0 0       if( defined($string) and length($string) and defined($s->_parent) )
      0        
291             {
292 0           return $s->_parent->_index_for_string($string);
293             }
294 0           return 0;
295             }
296              
297             # Get/Set the object parent
298             sub _parent
299             {
300 0     0     my $s = shift;
301 0 0 0       $s->{'parent'} = shift if scalar(@_) && $_[0]->can('_index_for_string');
302 0           $s->{'parent'};
303             }
304              
305             1;
306              
307             =head1 AUTHOR
308              
309             Brandon Fosdick, C<< >>
310              
311              
312             =head1 BUGS
313              
314             Please report any bugs or feature requests to C, or through
315             the web interface at L. I will be notified, and then you'll
316             automatically be notified of progress on your bug as I make changes.
317              
318              
319             =head1 SUPPORT
320              
321             You can find documentation for this module with the perldoc command.
322              
323             perldoc USB::Descriptor::Configuration
324              
325              
326             You can also look for information at:
327              
328             =over 4
329              
330             =item * RT: CPAN's request tracker (report bugs here)
331              
332             L
333              
334             =item * AnnoCPAN: Annotated CPAN documentation
335              
336             L
337              
338             =item * CPAN Ratings
339              
340             L
341              
342             =item * Search CPAN
343              
344             L
345              
346             =back
347              
348              
349             =head1 ACKNOWLEDGEMENTS
350              
351              
352             =head1 LICENSE AND COPYRIGHT
353              
354             Copyright 2011 Brandon Fosdick.
355              
356             This program is released under the terms of the BSD License.
357              
358             =cut