File Coverage

blib/lib/Device/BusPirate/Mode.pm
Criterion Covered Total %
statement 81 88 92.0
branch 19 24 79.1
condition 4 7 57.1
subroutine 16 17 94.1
pod 7 7 100.0
total 127 143 88.8


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