File Coverage

blib/lib/Device/BusPirate.pm
Criterion Covered Total %
statement 108 114 94.7
branch 7 10 70.0
condition 6 9 66.6
subroutine 23 25 92.0
pod 5 9 55.5
total 149 167 89.2


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