File Coverage

blib/lib/USB/HID/Report/Field.pm
Criterion Covered Total %
statement 9 98 9.1
branch 0 38 0.0
condition 0 3 0.0
subroutine 3 22 13.6
pod 17 17 100.0
total 29 178 16.2


line stmt bran cond sub pod time code
1             package USB::HID::Report::Field;
2              
3 1     1   7 use strict;
  1         1  
  1         40  
4 1     1   7 use warnings;
  1         2  
  1         31  
5 1     1   6 use feature 'switch';
  1         2  
  1         2405  
6              
7             our $VERSION = '1';
8              
9             =head1 NAME
10              
11             USB::HID::Report::Field - USB HID Report Field
12              
13             =head1 SYNOPSIS
14              
15             An object representation of a USB HID Report Field. L
16             doesn't directly correspond to any particular part of a HID report desriptor. It
17             provides a convenience interface for specifying the properties of a report
18             field that can be translated into the appropriate descriptor items.
19              
20             use USB::HID::Report::Field;
21              
22             my $field = USB::HID::Report::Field->new( 'usage' => 1, ... );
23             $field->set_attribute('variable');
24             ...
25              
26             =head1 DESCRIPTION
27              
28             L is an abstract representation of a field in a USB HID
29             Report. When added to an instance of L it can be used to
30             generate the items in HID Report Descriptor.
31              
32             Several convenience constructors are provided for creating commonly used field
33             types.
34              
35             use USB::HID::Report::Field;
36              
37             # Button 1
38             my $button = USB::HID::Report::Field->button( 'usage' => 1 );
39             # 7 bits of padding
40             my $constant = USB::HID::Report::Field->constant(7);
41              
42              
43             =head1 CONSTRUCTORS
44              
45             Several convenience constructors are provided for creating commonly used field
46             types. Each constructor accepts the same arguments as the default constructor
47             (C). Some constructors also accept a simplified argument set.
48              
49             =over
50              
51             =item $field = USB::HID::Report::Field->new('usage'=>$usage, ...);
52              
53             Constructs and returns a new L object using the passed
54             options. Each option key is the name of an accessor method.
55              
56             =item $button = USB::HID::Report::Field->button();
57              
58             Constructs and returns a L configured as a button.
59             B and B are automatically set and override any
60             corresponding arguments. Specify a B to set the button number.
61              
62             Alternatively, a single scalar can be passed to set the button number:
63              
64             $button = USB::HID::Report::Field->button(3); # Button 3
65              
66             =item $padding = USB::HID::Report::Field->constant($num_bits);
67              
68             Constructs and returns a L configured to be used as
69             constant padding bits in a report. Pass a single integer to set the number of
70             bits. Alternatively, a hash containing a 'bits' key can be used to set the
71             number of bits.
72              
73             =back
74              
75             =cut
76              
77             sub new
78             {
79 0     0 1   my ($this, %options) = @_;
80 0   0       my $class = ref($this) || $this;
81              
82             # Set defaults
83 0           my $self =
84             {
85             'usage' => 0, # Undefined
86             };
87              
88 0           bless $self, $class;
89              
90 0           while( my ($key, $value) = each %options )
91             {
92 0           $self->$key($value);
93             }
94              
95 0           return $self;
96             }
97              
98             sub button
99             {
100             # If a single scalar was passed, assume it's a button number and pass it
101             # as the field's Usage
102 0 0   0 1   push @_, 'usage' => pop(@_) if( 2 == @_ );
103              
104 0           my $s = new(@_);
105              
106 0           $s->logical_range(0,1); # Binary
107 0           $s->page(9); # Buttons
108 0           $s->count(1); # Each button is a single bit
109 0           $s->size(1); # Each button is a single bit
110 0           $s->set_attribute('variable');
111              
112 0           return $s;
113             }
114              
115             # Accepts a single integer that behaves like 'bits'
116             sub constant
117             {
118 0 0   0 1   if( 2 == @_ )
119             {
120 0           new($_[0], 'bits' => $_[1], 'attributes' => ['constant']);
121             }
122             else
123             {
124 0           new(@_, 'attributes' => ['constant']);
125             }
126             }
127              
128             =head1 ARRAYIFICATION
129              
130             =over
131              
132             =item $field->bytes(\%state)
133              
134             Returns an array of bytes containing all of the items for the field. Uses %state
135             to avoid repeating items that have been emitted by previous fields.
136              
137             =back
138              
139             =cut
140              
141             sub _should_emit
142             {
143 0     0     my ($state, $tag, $value) = @_;
144 0 0         if( defined($value) )
145             {
146 0 0         if( exists $state->{$tag} ) { $value != $state->{$tag} }
  0            
147 0           else { 1 }
148             }
149 0           else { 0 }
150             }
151              
152             sub _emit_item
153             {
154 0     0     my ($state, $tag, $value) = @_;
155 0           my $type = USB::HID::Descriptor::Report::item_type($tag);
156 0 0         if( _should_emit($state->{$type}, $tag, $value) )
157             {
158 0           $state->{$type}{$tag} = $value;
159 0           USB::HID::Descriptor::Report::item($tag, $value);
160             }
161 0           else { () }
162             }
163              
164             sub bytes
165             {
166 0     0 1   my ($s, $state) = @_;
167              
168             (
169 0           _emit_item($state, 'logical_minimum', $s->logical_min),
170             _emit_item($state, 'logical_maximum', $s->logical_max),
171             _emit_item($state, 'report_count', $s->count),
172             _emit_item($state, 'report_size', $s->size),
173             _emit_item($state, 'usage', $s->usage),
174             USB::HID::Descriptor::Report::item($state->{'main'}, $s->attributes),
175             )
176             }
177              
178             =head1 MAIN ITEM ATTRIBUTES
179              
180             HID report B
s have a number of attributes that can be set. Anything
181             that isn't explicitly set defaults to 0. These attributes correspond to the
182             names of the bits of the "Main Items" specified on page 28 of the
183             L.
184              
185             The attribute names accepted by C are:
186              
187             constant variable relative wrap nonlinear noprefered null volatile buffered
188             data array absolute nowrap linear preferred nonull nonvolatile bitfield
189              
190             =over
191              
192             =item $field->attributes(...)
193              
194             Set the list of attributes for the field object and replace any existing list.
195             Returns all currently set attributes.
196              
197             =item $field->set_attribute(...)
198              
199             Add the passed attributes to the current list of attributes. Returns all
200             currently set attributes, including the passed arguments.
201              
202             =back
203              
204             =cut
205              
206             # Replace the existing set of attributes with the given list
207             sub attributes
208             {
209 0     0 1   my $s = shift;
210 0 0         if( @_ )
211             {
212 0           $s->{'attributes'} = {};
213 0           $s->set_attribute(@_);
214             }
215 0           keys %{$s->{'attributes'}};
  0            
216             }
217              
218             # Set the given list of attributes. Doesn't clear existing attributes.
219             sub set_attribute
220             {
221 0     0 1   my $s = shift;
222 0           for(@_)
223             {
224             when([qw(constant variable relative wrap nonlinear noprefered null volatile buffered)])
225 0           {
226 0           $s->{'attributes'}{$_} = 1;
227             }
228             when([qw(data array absolute nowrap linear preferred nonull nonvolatile bitfield)])
229 0           {
230 0           delete $s->{'attributes'}{$_};
231             }
232             }
233 0           keys %{$s->{'attributes'}};
  0            
234             }
235              
236             =head1 ATTRIBUTES
237              
238             =over
239              
240             =item $field->bits($num_bits)
241              
242             Sets C to 1 and C to C<$num_bits>. Returns C,
243              
244             =item $field->count()
245              
246             Get/Set the field's B property.
247              
248             =item $field->logical_max()
249              
250             Get/Set the field's maximum logical value.
251              
252             =item $field->logical_min()
253              
254             Get/Set the field's minimum logical value.
255              
256             =item $field->logical_range($min, $max)
257              
258             Get/Set both C and C.
259              
260             =item $field->page($page_number)
261              
262             Get/Set the field's B.
263              
264             =item $field->size()
265              
266             Get/Set the field's B property.
267              
268             =item $field->usage($usage_number)
269              
270             Get/Set the field's B.
271              
272             =item $field->usage_max()
273              
274             Get/Set the upper end of the usage range for field objects that correspond to
275             multiple B
s.
276              
277             =item $field->usage_min()
278              
279             Get/Set the lower end of the usage range for field objects that correspond to
280             mutiple B
s.
281              
282             =item $field->usage_range($min, $max)
283              
284             Get/Set both C and C.
285              
286             =back
287              
288             =cut
289              
290             sub page
291             {
292 0     0 1   my $s = shift;
293 0 0         $s->{'page'} = shift if scalar @_;
294 0           $s->{'page'};
295             }
296              
297             sub usage
298             {
299 0     0 1   my $s = shift;
300 0 0         $s->{'usage'} = int(shift) & 0xFF if scalar @_;
301 0           $s->{'usage'};
302             }
303              
304             sub usage_max
305             {
306 0     0 1   my $s = shift;
307 0 0         $s->{'usage_max'} = shift if scalar @_;
308 0           $s->{'usage_max'};
309             }
310              
311             sub usage_min
312             {
313 0     0 1   my $s = shift;
314 0 0         $s->{'usage_min'} = shift if scalar @_;
315 0           $s->{'usage_min'};
316             }
317              
318             # Pass (min,max)
319             sub usage_range
320             {
321 0     0 1   my $s = shift;
322 0 0         if( 2 == @_ )
323             {
324 0 0         @_[0..1] = @_[1..0] if( $_[1] < $_[0] ); # swap?
325 0           $s->usage_min($_[0]);
326 0           $s->usage_max($_[1]);
327             }
328 0           grep { defined $_; } ($s->usage_min, $s->usage_max);# elide undefs
  0            
329             }
330              
331             sub logical_max
332             {
333 0     0 1   my $s = shift;
334 0 0         $s->{'logical_max'} = shift if scalar @_;
335 0           $s->{'logical_max'};
336             }
337              
338             sub logical_min
339             {
340 0     0 1   my $s = shift;
341 0 0         $s->{'logical_min'} = shift if scalar @_;
342 0           $s->{'logical_min'};
343             }
344              
345             sub logical_range
346             {
347 0     0 1   my $s = shift;
348 0 0         if( 2 == @_ )
349             {
350 0 0         @_[0..1] = @_[1..0] if( $_[1] < $_[0] ); # swap?
351 0           $s->logical_min($_[0]);
352 0           $s->logical_max($_[1]);
353             }
354 0           grep { defined $_; } ($s->logical_min, $s->logical_max); # elide undefs
  0            
355             }
356              
357             sub count
358             {
359 0     0 1   my $s = shift;
360 0 0         $s->{'count'} = shift if scalar @_;
361 0           $s->{'count'};
362             }
363              
364             sub size
365             {
366 0     0 1   my $s = shift;
367 0 0         $s->{'size'} = shift if scalar @_;
368 0           $s->{'size'};
369             }
370              
371             sub bits
372             {
373 0     0 1   my $s = shift;
374 0 0         if( @_ )
375             {
376 0           $s->size(1);
377 0           $s->count(shift);
378             }
379 0           $s->count;
380             }
381              
382             1;
383              
384             =head1 AUTHOR
385              
386             Brandon Fosdick, C<< >>
387              
388             =head1 BUGS
389              
390             Please report any bugs or feature requests to C, or through
391             the web interface at L. I will be notified, and then you'll
392             automatically be notified of progress on your bug as I make changes.
393              
394             =head1 SUPPORT
395              
396             You can find documentation for this module with the perldoc command.
397              
398             perldoc USB::HID::Report::Field
399              
400              
401             You can also look for information at:
402              
403             =over 4
404              
405             =item * RT: CPAN's request tracker (report bugs here)
406              
407             L
408              
409             =item * AnnoCPAN: Annotated CPAN documentation
410              
411             L
412              
413             =item * CPAN Ratings
414              
415             L
416              
417             =item * Search CPAN
418              
419             L
420              
421             =back
422              
423              
424             =head1 ACKNOWLEDGEMENTS
425              
426              
427             =head1 LICENSE AND COPYRIGHT
428              
429             Copyright 2011 Brandon Fosdick.
430              
431             This program is released under the terms of the BSD License.
432              
433             =cut