File Coverage

blib/lib/Device/BusPirate.pm
Criterion Covered Total %
statement 89 102 87.2
branch 7 12 58.3
condition 7 16 43.7
subroutine 24 26 92.3
pod 6 10 60.0
total 133 166 80.1


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             package Device::BusPirate 0.21;
7              
8 7     7   450185 use v5.14;
  7         78  
9 7     7   38 use warnings;
  7         13  
  7         214  
10              
11 7     7   37 use Carp;
  7         14  
  7         455  
12              
13 7     7   43 use Fcntl qw( O_NOCTTY O_NDELAY );
  7         23  
  7         358  
14 7     7   3987 use Future::AsyncAwait;
  7         114370  
  7         36  
15 7     7   3631 use Future::Mutex;
  7         3726  
  7         240  
16 7     7   3653 use Future::IO 0.04; # ->syswrite_exactly
  7         52519  
  7         297  
17 7     7   4049 use IO::Termios 0.07; # cfmakeraw
  7         195225  
  7         43  
18 7     7   361 use Time::HiRes qw( time );
  7         17  
  7         55  
19              
20             use Module::Pluggable
21 7         78 search_path => "Device::BusPirate::Mode",
22             except => qr/^Device::BusPirate::Mode::_/,
23             require => 1,
24 7     7   4818 sub_name => "modes";
  7         82293  
25             my %MODEMAP = map { $_->MODE => $_ } __PACKAGE__->modes;
26              
27 7   50 7   945 use constant BUS_PIRATE => $ENV{BUS_PIRATE} || "/dev/ttyUSB0";
  7         14  
  7         561  
28 7   50 7   45 use constant PIRATE_DEBUG => $ENV{PIRATE_DEBUG} // 0;
  7         13  
  7         9670  
29              
30             =head1 NAME
31              
32             C - interact with a F device
33              
34             =head1 DESCRIPTION
35              
36             This module allows a program to interact with a F hardware
37             electronics debugging device, attached over a USB-emulated serial port. In the
38             following description, the reader is assumed to be generally aware of the
39             device and its capabilities. For more information about the F see:
40              
41             =over 2
42              
43             L
44              
45             =back
46              
47             This module and its various component modules are based on L, allowing
48             either synchronous or asynchronous communication with the attached hardware
49             device.
50              
51             To use it synchronously, call the C method of any returned C
52             instances to obtain the eventual result:
53              
54             my $spi = $pirate->enter_mode( "SPI" )->get;
55              
56             $spi->power( 1 )->get;
57             my $input = $spi->writeread_cs( $output )->get;
58              
59             A truely-asynchronous program would use the futures more conventionally,
60             perhaps by using C<< ->then >> chaining:
61              
62             my $input = $pirate->enter_mode( "SPI" )
63             ->then( sub {
64             my ( $spi ) = @_;
65              
66             $spi->power( 1 )->then( sub {
67             $spi->writeread_cs( $output );
68             });
69             });
70              
71             This module uses L for its underlying IO operations, so using it
72             in a program would require the event system to integrate with C
73             appropriately.
74              
75             =cut
76              
77             =head1 CONSTRUCTOR
78              
79             =cut
80              
81             =head2 new
82              
83             $pirate = Device::BusPirate->new( %args )
84              
85             Returns a new C instance to communicate with the given
86             device. Takes the following named arguments:
87              
88             =over 4
89              
90             =item serial => STRING
91              
92             Path to the serial port device node the Bus Pirate is attached to. If not
93             supplied, the C environment variable is used; falling back on a
94             default of F.
95              
96             =item baud => INT
97              
98             Serial baud rate to communicate at. Normally it should not be necessary to
99             change this from its default of C<115200>.
100              
101             =back
102              
103             =cut
104              
105             sub new
106             {
107 6     6 1 528 my $class = shift;
108 6         28 my %args = @_;
109              
110             # undocumented 'fh 'argument for unit testing
111 6   33     44 my $fh = $args{fh} // do {
112 0   0     0 my $serial = $args{serial} || BUS_PIRATE;
113 0   0     0 my $baud = $args{baud} || 115200;
114              
115 0 0       0 my $fh = IO::Termios->open( $serial, "$baud,8,n,1", O_NOCTTY|O_NDELAY )
116             or croak "Cannot open serial port $serial - $!";
117              
118 0         0 for( $fh->getattr ) {
119 0         0 $_->cfmakeraw();
120 0         0 $_->setflag_clocal( 1 );
121              
122 0         0 $fh->setattr( $_ );
123             }
124              
125 0         0 $fh->blocking( 0 );
126              
127 0         0 $fh;
128             };
129              
130 6         33 return bless {
131             fh => $fh,
132             }, $class;
133             }
134              
135             =head1 METHODS
136              
137             The following methods documented with a trailing call to C<< ->get >> return
138             L instances.
139              
140             =cut
141              
142             # For Modes
143             sub write
144             {
145 112     112 0 1285 my $self = shift;
146 112         205 my ( $buf ) = @_;
147              
148 112         157 printf STDERR "PIRATE >> %v02x\n", $buf if PIRATE_DEBUG > 1;
149              
150 112         389 my $f = Future::IO->syswrite_exactly( $self->{fh}, $buf );
151              
152 112 50       4519 return $f if wantarray;
153 112     112   509 $f->on_ready( sub { undef $f } );
  112         2176  
154             }
155              
156             async sub write_expect_ack
157 58     58 0 108 {
158 58         84 my $self = shift;
159 58         128 my ( $out, $name, $timeout ) = @_;
160              
161 58         143 await $self->write_expect_acked_data( $out, 0, $name, $timeout );
162 58         4151 return;
163             }
164              
165             async sub write_expect_acked_data
166 78     78 0 117 {
167 78         117 my $self = shift;
168 78         171 my ( $out, $readlen, $name, $timeout ) = @_;
169              
170 78         206 $self->write( $out );
171 78         495 my $buf = await $self->read( 1 + $readlen, $name, $timeout );
172              
173 78 50       50999 substr( $buf, 0, 1, "" ) eq "\x01" or
174             die "Expected ACK response to $name";
175              
176 78         334 return $buf;
177             }
178              
179             # For Modes
180             sub read
181             {
182 115     115 0 1417 my $self = shift;
183 115         248 my ( $n, $name, $timeout ) = @_;
184              
185 115 100       250 return Future->done( "" ) unless $n;
186              
187 114         171 my $buf = "";
188 114         346 my $f = Future::IO->sysread_exactly( $self->{fh}, $n );
189              
190             $f->on_done( sub {
191 0     0   0 printf STDERR "PIRATE << %v02x\n", $_[0];
192 114         7352 }) if Device::BusPirate::PIRATE_DEBUG > 1;
193              
194 114 100       301 return $f unless defined $name;
195              
196 105   100     464 return Future->wait_any(
197             $f,
198             $self->sleep( $timeout // 2 )->then_fail( "Timeout waiting for $name" ),
199             );
200             }
201              
202             =head2 sleep
203              
204             $pirate->sleep( $timeout )->get
205              
206             Returns a C that will become ready after the given timeout (in
207             seconds), unless it is cancelled first.
208              
209             =cut
210              
211             sub sleep
212             {
213 110     110 1 183 my $self = shift;
214 110         199 my ( $timeout ) = @_;
215              
216 110         329 return Future::IO->sleep( $timeout );
217             }
218              
219             =head2 enter_mutex
220              
221             @result = $pirate->enter_mutex( $code )->get
222              
223             Acts as a mutex lock, to ensure only one block of code runs at once. Calls to
224             C will be queued up; each C<$code> block will only be invoked
225             once the C returned from the previous has completed.
226              
227             Mode implementations should use this method to guard complete wire-level
228             transactions, ensuring that multiple concurrent ones will not collide with
229             each other.
230              
231             =cut
232              
233             sub enter_mutex
234             {
235 9     9 1 20 my $self = shift;
236 9         17 my ( $code ) = @_;
237              
238 9   66     60 ( $self->{mutex} //= Future::Mutex->new )->enter( $code );
239             }
240              
241             =head2 enter_mode
242              
243             $mode = $pirate->enter_mode( $modename )->get
244              
245             Switches the attached device into the given mode, and returns an object to
246             represent that hardware mode to interact with. This will be an instance of a
247             class depending on the given mode name.
248              
249             =over 4
250              
251             =item C
252              
253             The bit-banging mode. Returns an instance of L.
254              
255             =item C
256              
257             The I2C mode. Returns an instance of L.
258              
259             =item C
260              
261             The SPI mode. Returns an instance of L.
262              
263             =item C
264              
265             The UART mode. Returns an instance of L.
266              
267             =back
268              
269             Once a mode object has been created, most of the interaction with the device
270             would be done using that mode object, as it will have methods relating to the
271             specifics of that hardware mode. See the classes listed above for more
272             information.
273              
274             =cut
275              
276             async sub enter_mode
277 5     5 1 103 {
278 5         13 my $self = shift;
279 5         14 my ( $modename ) = @_;
280              
281 5 50       27 my $modeclass = $MODEMAP{$modename} or
282             croak "Unrecognised mode '$modename'";
283              
284 5         19 await $self->start;
285              
286 5         1491 $self->{mode} = $modeclass->new( $self );
287 5         37 await $self->{mode}->start;
288             }
289              
290             =head2 start
291              
292             $pirate->start->get
293              
294             Starts binary IO mode on the F device, enabling the module to
295             actually communicate with it. Normally it is not necessary to call this method
296             explicitly as it will be done by the setup code of the mode object.
297              
298             =cut
299              
300             sub start
301             {
302 5     5 1 11 my $self = shift;
303              
304             Future->wait_any(
305 5     5   11 (async sub {
306 5         22 my $buf = await $self->read( 5, "start", 2.5 );
307 5         3864 ( $self->{version} ) = $buf =~ m/^BBIO(\d)/;
308 5         31 return $self->{version};
309             })->(),
310 5     5   1774 (async sub {
311 5         26 foreach my $i ( 1 .. 20 ) {
312 5         23 $self->write( "\0" );
313 5         55 await $self->sleep( 0.05 );
314             }
315 0           die "Timed out waiting for device to enter bitbang mode";
316 5         32 })->(),
317             );
318             }
319              
320             =head2 stop
321              
322             $pirate->stop
323              
324             Stops binary IO mode on the F device and returns it to user
325             terminal mode. It may be polite to perform this at the end of a program to
326             return it to a mode that a user can interact with normally on a terminal.
327              
328             =cut
329              
330             sub stop
331             {
332 0     0 1   my $self = shift;
333              
334 0           $self->write( "\0\x0f" );
335             }
336              
337             =head1 TODO
338              
339             =over 4
340              
341             =item *
342              
343             More modes - 1-wire, raw-wire
344              
345             =item *
346              
347             AUX frequency measurement and ADC support.
348              
349             =back
350              
351             =head1 AUTHOR
352              
353             Paul Evans
354              
355             =cut
356              
357             0x55AA;