File Coverage

blib/lib/Device/BusPirate/Mode/UART.pm
Criterion Covered Total %
statement 62 62 100.0
branch 11 16 68.7
condition 10 25 40.0
subroutine 12 12 100.0
pod 2 3 66.6
total 97 118 82.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, 2020-2021 -- leonerd@leonerd.org.uk
5              
6             package Device::BusPirate::Mode::UART 0.22;
7              
8 7     7   15983 use v5.14;
  7         29  
9 7     7   41 use warnings;
  7         20  
  7         289  
10 7     7   41 use base qw( Device::BusPirate::Mode );
  7         16  
  7         906  
11              
12 7     7   49 use Carp;
  7         15  
  7         435  
13              
14 7     7   42 use Future::AsyncAwait;
  7         18  
  7         51  
15 7     7   470 use List::Util 1.33 qw( any );
  7         132  
  7         880  
16              
17 7     7   54 use constant MODE => "UART";
  7         15  
  7         629  
18              
19 7   50 7   49 use constant PIRATE_DEBUG => $ENV{PIRATE_DEBUG} // 0;
  7         25  
  7         6865  
20              
21             =head1 NAME
22              
23             C - use C in UART mode
24              
25             =head1 SYNOPSIS
26              
27             use Device::BusPirate;
28              
29             my $pirate = Device::BusPirate->new;
30             my $uart = $pirate->enter_mode( "UART" )->get;
31              
32             $uart->configure( baud => 19200 )->get;
33              
34             $uart->write( "Hello, world!" )->get;
35              
36             =head1 DESCRIPTION
37              
38             This object is returned by a L instance when switching it
39             into C mode. It provides methods to configure the hardware and to
40             transmit bytes.
41              
42             =cut
43              
44             =head1 METHODS
45              
46             The following methods documented with a trailing call to C<< ->get >> return
47             L instances.
48              
49             =cut
50              
51             async sub start
52 1     1 0 2 {
53 1         2 my $self = shift;
54              
55             # Bus Pirate defaults
56 1         2 $self->{open_drain} = 1;
57 1         3 $self->{bits} = 8;
58 1         3 $self->{parity} = "n";
59 1         3 $self->{stop} = 1; # 1 stop bit, not 2
60              
61 1         2 $self->{baud} = 0;
62              
63 1         6 await $self->_start_mode_and_await( "\x03", "ART" );
64 1         70 ( $self->{version} ) = await $self->pirate->read( 1, "UART start" );
65              
66 1         630 print STDERR "PIRATE UART STARTED\n" if PIRATE_DEBUG;
67 1         4 return $self;
68             }
69              
70             =head2 configure
71              
72             $uart->configure( %args )->get
73              
74             Change configuration options. The following options exist:
75              
76             =over 4
77              
78             =item open_drain
79              
80             If enabled (default), a "high" output pin will be set as an input; i.e. hi-Z.
81             When disabled, a "high" output pin will be driven by 3.3V. A "low" output will
82             be driven to GND in either case.
83              
84             =item bits
85              
86             Number of data bits of transfer. Must be either 8 or 9.
87              
88             =item parity
89              
90             A single character string indicating whether to send a parity bit of
91             even ("E") or odd ("O"), or not ("N").
92              
93             =item stop
94              
95             An integer giving the number of bit-times for stop, either 1 or 2.
96              
97             =item baud
98              
99             An integer giving the baud rate. Must be one of the values:
100              
101             300 1200 2400 4800 9600 19200 31250 38400 57600 115200
102              
103             The default speed is 300.
104              
105             =back
106              
107             =cut
108              
109             my %DATACONF = (
110             '8N' => 0,
111             '8E' => 1,
112             '8O' => 2,
113             '9N' => 3,
114             );
115              
116             my %BAUDS = (
117             300 => 0,
118             1200 => 1,
119             2400 => 2,
120             4800 => 3,
121             9600 => 4,
122             19200 => 5,
123             31250 => 6,
124             38400 => 7,
125             57600 => 8,
126             115200 => 10, # sic - there is no rate 9
127             );
128              
129             sub configure
130             {
131 2     2 1 1351 my $self = shift;
132 2         7 my %args = @_;
133              
134 2         5 my @f;
135              
136 2 100 33 7   14 if( any { defined $args{$_} and $args{$_}//0 ne $self->{$_} } qw( open_drain bits parity stop ) ) {
  7 100       23  
137 1   33     6 my $bits = $args{bits} // $self->{bits};
138 1   33     7 my $parity = $args{parity} // $self->{parity};
139 1   33     8 my $stop = $args{stop} // $self->{stop};
140              
141 1 50       6 defined( my $dataconf = $DATACONF{$bits . uc $parity} ) or
142             croak "Unrecognised bitsize/parity $bits$parity";
143 1 50 33     5 $stop == 1 or $stop == 2 or
144             croak "Unrecognised stop length $stop";
145              
146 1   50     10 defined $args{$_} and $self->{$_} = $args{$_}//0 for qw( open_drain bits parity stop );
      66        
147              
148             push @f, $self->pirate->write_expect_ack(
149             chr( 0x80 |
150 1 50       23 ( $self->{open_drain} ? 0 : 0x10 ) | # sense is reversed
    50          
151             ( $dataconf << 2 ) |
152             ( $stop == 2 ? 0x02 : 0 ) |
153             0 ), "UART configure" );
154             }
155              
156 2 100       317 if( defined $args{baud} ) {{
157 1         3 my $baud = $BAUDS{$args{baud}} //
158 1   33     5 croak "Unrecognised baud '$args{baud}'";
159              
160 1 50       4 last if $baud == $self->{baud};
161              
162 1         2 $self->{baud} = $baud;
163             push @f, $self->pirate->write_expect_ack(
164 1         5 chr( 0x60 | $self->{baud} ), "UART set baud" );
165             }}
166              
167 2         296 return Future->needs_all( @f );
168             }
169              
170             =head2 write
171              
172             $uart->write( $bytes )->get
173              
174             Sends the given bytes over the TX wire.
175              
176             =cut
177              
178             async sub write
179 1     1 1 465 {
180 1         3 my $self = shift;
181 1         3 my ( $bytes ) = @_;
182              
183 1         2 printf STDERR "PIRATE UART WRITE %v02X\n", $bytes if PIRATE_DEBUG;
184              
185             # "Bulk Transfer" command can only send up to 16 bytes at once.
186              
187 1         7 my @chunks = $bytes =~ m/(.{1,16})/gs;
188              
189 1         3 foreach my $bytes ( @chunks ) {
190 1         4 my $len_1 = length( $bytes ) - 1;
191              
192 1         4 await $self->pirate->write_expect_acked_data(
193             chr( 0x10 | $len_1 ) . $bytes, length $bytes, "UART bulk write"
194             );
195             }
196              
197 1         75 return;
198             }
199              
200             =head1 AUTHOR
201              
202             Paul Evans
203              
204             =cut
205              
206             0x55AA;