File Coverage

blib/lib/Device/BusPirate/Mode/UART.pm
Criterion Covered Total %
statement 65 71 91.5
branch 11 16 68.7
condition 10 25 40.0
subroutine 12 15 80.0
pod 6 7 85.7
total 104 134 77.6


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 7     7   14710 use v5.14;
  7         27  
7 7     7   44 use Object::Pad 0.45;
  7         84  
  7         36  
8              
9             package Device::BusPirate::Mode::UART 0.23;
10             class Device::BusPirate::Mode::UART isa Device::BusPirate::Mode;
11              
12 7     7   1838 use Carp;
  7         14  
  7         414  
13              
14 7     7   44 use Future::AsyncAwait;
  7         15  
  7         37  
15 7     7   417 use List::Util 1.33 qw( any );
  7         203  
  7         993  
16              
17 7     7   55 use constant MODE => "UART";
  7         13  
  7         641  
18              
19 7   50 7   50 use constant PIRATE_DEBUG => $ENV{PIRATE_DEBUG} // 0;
  7         27  
  7         10881  
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 0     0 1 0 has $_open_drain :mutator;
  0         0  
52 0     0 1 0 has $_bits :mutator;
  0         0  
53 1     1 1 3 has $_parity :mutator;
  1         5  
54 0     0 1 0 has $_stop :mutator;
  0         0  
55             has $_baud;
56             has $_version;
57              
58             async method start
59 1         3 {
60             # Bus Pirate defaults
61 1         3 $_open_drain = 1;
62 1         3 $_bits = 8;
63 1         2 $_parity = "n";
64 1         2 $_stop = 1; # 1 stop bit, not 2
65              
66 1         2 $_baud = 0;
67              
68 1         8 await $self->_start_mode_and_await( "\x03", "ART" );
69 1         71 ( $_version ) = await $self->pirate->read( 1, "UART start" );
70              
71 1         589 print STDERR "PIRATE UART STARTED\n" if PIRATE_DEBUG;
72 1         5 return $self;
73 1     1 0 3 }
74              
75             =head2 configure
76              
77             $uart->configure( %args )->get
78              
79             Change configuration options. The following options exist:
80              
81             =over 4
82              
83             =item open_drain
84              
85             If enabled (default), a "high" output pin will be set as an input; i.e. hi-Z.
86             When disabled, a "high" output pin will be driven by 3.3V. A "low" output will
87             be driven to GND in either case.
88              
89             =item bits
90              
91             Number of data bits of transfer. Must be either 8 or 9.
92              
93             =item parity
94              
95             A single character string indicating whether to send a parity bit of
96             even ("E") or odd ("O"), or not ("N").
97              
98             =item stop
99              
100             An integer giving the number of bit-times for stop, either 1 or 2.
101              
102             =item baud
103              
104             An integer giving the baud rate. Must be one of the values:
105              
106             300 1200 2400 4800 9600 19200 31250 38400 57600 115200
107              
108             The default speed is 300.
109              
110             =back
111              
112             =cut
113              
114             my %DATACONF = (
115             '8N' => 0,
116             '8E' => 1,
117             '8O' => 2,
118             '9N' => 3,
119             );
120              
121             my %BAUDS = (
122             300 => 0,
123             1200 => 1,
124             2400 => 2,
125             4800 => 3,
126             9600 => 4,
127             19200 => 5,
128             31250 => 6,
129             38400 => 7,
130             57600 => 8,
131             115200 => 10, # sic - there is no rate 9
132             );
133              
134 2         6 method configure ( %args )
  2         5  
  2         4  
135 2     2 1 1452 {
136 2         5 my @f;
137              
138 2 100 33 7   15 if( any { defined $args{$_} and $args{$_}//0 ne $self->$_ } qw( open_drain bits parity stop ) ) {
  7 100       24  
139 1   33     8 my $bits = $args{bits} // $_bits;
140 1   33     4 my $parity = $args{parity} // $_parity;
141 1   33     8 my $stop = $args{stop} // $_stop;
142              
143 1 50       7 defined( my $dataconf = $DATACONF{$bits . uc $parity} ) or
144             croak "Unrecognised bitsize/parity $bits$parity";
145 1 50 33     4 $stop == 1 or $stop == 2 or
146             croak "Unrecognised stop length $stop";
147              
148 1   50     13 defined $args{$_} and $self->$_ = $args{$_}//0 for qw( open_drain bits parity stop );
      66        
149              
150 1 50       6 push @f, $self->pirate->write_expect_ack(
    50          
151             chr( 0x80 |
152             ( $_open_drain ? 0 : 0x10 ) | # sense is reversed
153             ( $dataconf << 2 ) |
154             ( $stop == 2 ? 0x02 : 0 ) |
155             0 ), "UART configure" );
156             }
157              
158 2 100       321 if( defined $args{baud} ) {{
159 1         2 my $baud = $BAUDS{$args{baud}} //
160 1   33     5 croak "Unrecognised baud '$args{baud}'";
161              
162 1 50       3 last if $baud == $_baud;
163              
164 1         2 $_baud = $baud;
165 1         5 push @f, $self->pirate->write_expect_ack(
166             chr( 0x60 | $_baud ), "UART set baud" );
167             }}
168              
169 2         312 return Future->needs_all( @f );
170             }
171              
172             =head2 write
173              
174             $uart->write( $bytes )->get
175              
176             Sends the given bytes over the TX wire.
177              
178             =cut
179              
180 1         2 async method write ( $bytes )
  1         3  
  1         2  
181 1         5 {
182 1         2 printf STDERR "PIRATE UART WRITE %v02X\n", $bytes if PIRATE_DEBUG;
183              
184             # "Bulk Transfer" command can only send up to 16 bytes at once.
185              
186 1         8 my @chunks = $bytes =~ m/(.{1,16})/gs;
187              
188 1         4 foreach my $bytes ( @chunks ) {
189 1         3 my $len_1 = length( $bytes ) - 1;
190              
191 1         5 await $self->pirate->write_expect_acked_data(
192             chr( 0x10 | $len_1 ) . $bytes, length $bytes, "UART bulk write"
193             );
194             }
195              
196 1         73 return;
197 1     1 1 427 }
198              
199             =head1 AUTHOR
200              
201             Paul Evans
202              
203             =cut
204              
205             0x55AA;