File Coverage

blib/lib/USB/Descriptor/Interface.pm
Criterion Covered Total %
statement 15 88 17.0
branch 0 38 0.0
condition 0 18 0.0
subroutine 5 18 27.7
pod 11 11 100.0
total 31 173 17.9


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