File Coverage

blib/lib/Device/BusPirate/Mode.pm
Criterion Covered Total %
statement 80 87 91.9
branch 11 16 68.7
condition 4 7 57.1
subroutine 15 16 93.7
pod 7 7 100.0
total 117 133 87.9


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             # (C) Paul Evans, 2014-2021 -- leonerd@leonerd.org.uk
5              
6 8     8   98 use v5.26;
  8         32  
7 8     8   40 use warnings;
  8         15  
  8         514  
8 8     8   49 use Object::Pad 0.800;
  8         56  
  8         354  
9              
10             package Device::BusPirate::Mode 0.25;
11             class Device::BusPirate::Mode;
12              
13 8     8   3453 use Carp;
  8         16  
  8         749  
14              
15 8     8   43 use Future::AsyncAwait;
  8         14  
  8         114  
16              
17 8   50 8   744 use constant PIRATE_DEBUG => $ENV{PIRATE_DEBUG} // 0;
  8         15  
  8         866  
18              
19             use constant {
20 8         12047 CONF_CS => 0x01,
21             CONF_AUX => 0x02,
22             CONF_PULLUP => 0x04,
23             CONF_POWER => 0x08,
24 8     8   45 };
  8         12  
25              
26             =head1 NAME
27              
28             C - base class for C modes
29              
30             =head1 DESCRIPTION
31              
32             The following methods are implemented by all the various mode subclasses.
33              
34             =cut
35              
36 170     170 1 588 field $_pirate :reader :param;
  170         1227  
37              
38             field $_cs = 0;
39             field $_power = 0;
40             field $_pullup = 0;
41             field $_aux = 0;
42              
43             =head1 METHODS
44              
45             The following methods documented with C expressions L instances.
46              
47             =cut
48              
49             =head2 pirate
50              
51             $pirate = $mode->pirate;
52              
53             Returns the underlying L instance.
54              
55             =cut
56              
57             # generated accessor
58              
59 5     5   14 async method _start_mode_and_await ( $send, $await )
  5         61  
  5         15  
  5         13  
  5         62  
60 5         10 {
61 5         36 my $pirate = $self->pirate;
62              
63 5         26 $pirate->write( $send );
64 5         74 my $buf = await $pirate->read( length $await, "start mode" );
65              
66 5 50       5178 return $buf if $buf eq $await;
67 0         0 die "Expected '$await' response but got '$buf'";
68             }
69              
70             =head2 power
71              
72             await $mode->power( $power );
73              
74             Enable or disable the C 5V and 3.3V power outputs.
75              
76             =cut
77              
78 2     2 1 1165 method power ( $on )
  2         12  
  2         5  
  2         5  
79             {
80 2         6 $_power = !!$on;
81 2         12 $self->_update_peripherals;
82             }
83              
84             =head2 pullup
85              
86             await $mode->pullup( $pullup );
87              
88             Enable or disable the IO pin pullup resistors from C. These are connected
89             to the C, C, C and C pins.
90              
91             =cut
92              
93 6     6 1 290 method pullup ( $on )
  6         54  
  6         16  
  6         11  
94             {
95 6         17 $_pullup = !!$on;
96 6         33 $self->_update_peripherals;
97             }
98              
99             =head2 aux
100              
101             await $mode->aux( $aux );
102              
103             Set the C output pin level.
104              
105             =cut
106              
107 2     2 1 3332 method aux ( $on )
  2         13  
  2         5  
  2         5  
108             {
109 2         7 $_aux = !!$on;
110 2         19 $self->_update_peripherals;
111             }
112              
113             =head2 cs
114              
115             await $mode->cs( $cs );
116              
117             Set the C output pin level.
118              
119             =cut
120              
121             # For SPI subclass
122             method _set_cs { $_cs = shift }
123              
124 0     0 1 0 method cs ( $on )
  0         0  
  0         0  
  0         0  
125             {
126 0         0 $_cs = !!$on;
127 0         0 $self->_update_peripherals;
128             }
129              
130             method _update_peripherals
131             {
132             $self->pirate->write_expect_ack( chr( 0x40 |
133             ( $_power ? CONF_POWER : 0 ) |
134             ( $_pullup ? CONF_PULLUP : 0 ) |
135             ( $_aux ? CONF_AUX : 0 ) |
136             ( $_cs ? CONF_CS : 0 ) ), "_update_peripherals" );
137             }
138              
139             =head2 set_pwm
140              
141             await $mode->set_pwm( freq => $freq, duty => $duty );
142              
143             Sets the PWM generator to the given frequency and duty cycle, as a percentage.
144             If unspecified, duty cycle will be 50%. Set frequency to 0 to disable.
145              
146             =cut
147              
148             use constant {
149 8         8761 PRESCALE_1 => 0,
150             PRESCALE_8 => 1,
151             PRESCALE_64 => 2,
152             PRESCALE_256 => 3,
153 8     8   63 };
  8         13  
154              
155 5     5 1 618 method set_pwm ( %args )
  5         15  
  5         11  
  5         4  
156             {
157 5 50       20 $self->MODE eq "BB" or
158             croak "Cannot ->set_pwm except in BB mode";
159              
160 5   33     13 my $freq = $args{freq} // croak "Require freq";
161 5   100     17 my $duty = $args{duty} // 50;
162              
163 5 100       10 if( $freq == 0 ) {
164 1         2 print STDERR "PIRATE BB CLEAR-PWM\n" if PIRATE_DEBUG;
165 1         3 return $self->pirate->write_expect_ack( "\x13", "clear PWM" );
166             }
167              
168             # in fCPU counts at 16MHz
169 4         6 my $period = 16E6 / $freq;
170              
171 4         5 my $prescale = PRESCALE_1;
172 4 100       11 $prescale = PRESCALE_8, $period /= 8 if $period >= 2**16;
173 4 100       7 $prescale = PRESCALE_64, $period /= 8 if $period >= 2**16;
174 4 50       7 $prescale = PRESCALE_256, $period /= 4 if $period >= 2**16;
175 4 50       6 croak "PWM frequency too low" if $period >= 2**16;
176              
177 4         9 $duty = $period * $duty / 100;
178              
179 4         4 print STDERR "PIRATE BB SET-PWM\n" if PIRATE_DEBUG;
180 4         6 $self->pirate->write_expect_ack(
181             pack( "C C S> S>", 0x12, $prescale, $duty, $period ), "set PWM"
182             );
183             }
184              
185             =head2 read_adc_voltage
186              
187             $voltage = await $mode->read_adc_voltage;
188              
189             Reads the voltage on the ADC pin and returns it as a numerical value in volts.
190              
191             =cut
192              
193 1     1 1 357 async method read_adc_voltage ()
  1         3  
  1         2  
194 1         2 {
195 1 50       7 $self->MODE eq "BB" or
196             croak "Cannot ->read_adc except in BB mode";
197              
198 1         4 await $self->pirate->write( "\x14" );
199 1         19 my $buf = await $self->pirate->read( 2 );
200              
201 1         146 return unpack( "S>", $buf ) * 6.6 / 1024;
202             }
203              
204             =head1 AUTHOR
205              
206             Paul Evans
207              
208             =cut
209              
210             0x55AA;