File Coverage

blib/lib/Device/BusPirate/Mode/UART.pm
Criterion Covered Total %
statement 67 73 91.7
branch 11 16 68.7
condition 10 25 40.0
subroutine 13 16 81.2
pod 6 7 85.7
total 107 137 78.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, 2020-2024 -- leonerd@leonerd.org.uk
5              
6 8     8   19340 use v5.26;
  8         38  
7 8     8   50 use warnings;
  8         17  
  8         575  
8 8     8   49 use Object::Pad 0.800;
  8         68  
  8         399  
9              
10             package Device::BusPirate::Mode::UART 0.25;
11             class Device::BusPirate::Mode::UART :isa(Device::BusPirate::Mode);
12              
13 8     8   3860 use Carp;
  8         16  
  8         653  
14              
15 8     8   50 use Future::AsyncAwait;
  8         16  
  8         62  
16 8     8   565 use List::Util 1.33 qw( any );
  8         148  
  8         778  
17              
18 8     8   53 use constant MODE => "UART";
  8         17  
  8         756  
19              
20 8   50 8   47 use constant PIRATE_DEBUG => $ENV{PIRATE_DEBUG} // 0;
  8         16  
  8         18831  
21              
22             =head1 NAME
23              
24             C - use C in UART mode
25              
26             =head1 SYNOPSIS
27              
28             use Device::BusPirate;
29              
30             my $pirate = Device::BusPirate->new;
31             my $uart = $pirate->enter_mode( "UART" )->get;
32              
33             $uart->configure( baud => 19200 )->get;
34              
35             $uart->write( "Hello, world!" )->get;
36              
37             =head1 DESCRIPTION
38              
39             This object is returned by a L instance when switching it
40             into C mode. It provides methods to configure the hardware and to
41             transmit bytes.
42              
43             =cut
44              
45             =head1 METHODS
46              
47             The following methods documented with C expressions L instances.
48              
49             =cut
50              
51 0     0 1 0 field $_open_drain :mutator;
  0         0  
52 0     0 1 0 field $_bits :mutator;
  0         0  
53 1     1 1 3 field $_parity :mutator;
  1         4  
54 0     0 1 0 field $_stop :mutator;
  0         0  
55             field $_baud;
56             field $_version;
57              
58             async method start
59 1     1 0 2 {
60             # Bus Pirate defaults
61 1         2 $_open_drain = 1;
62 1         2 $_bits = 8;
63 1         1 $_parity = "n";
64 1         2 $_stop = 1; # 1 stop bit, not 2
65              
66 1         1 $_baud = 0;
67              
68 1         9 await $self->_start_mode_and_await( "\x03", "ART" );
69 1         49 ( $_version ) = await $self->pirate->read( 1, "UART start" );
70              
71 1         533 print STDERR "PIRATE UART STARTED\n" if PIRATE_DEBUG;
72 1         4 return $self;
73             }
74              
75             =head2 configure
76              
77             await $uart->configure( %args );
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     2 1 2857 method configure ( %args )
  2         9  
  2         5  
  2         4  
135             {
136 2         3 my @f;
137              
138 2 100 33 7   14 if( any { defined $args{$_} and $args{$_}//0 ne $self->$_ } qw( open_drain bits parity stop ) ) {
  7 100       27  
139 1   33     5 my $bits = $args{bits} // $_bits;
140 1   33     3 my $parity = $args{parity} // $_parity;
141 1   33     4 my $stop = $args{stop} // $_stop;
142              
143 1 50       5 defined( my $dataconf = $DATACONF{$bits . uc $parity} ) or
144             croak "Unrecognised bitsize/parity $bits$parity";
145 1 50 33     6 $stop == 1 or $stop == 2 or
146             croak "Unrecognised stop length $stop";
147              
148 1   50     10 defined $args{$_} and $self->$_ = $args{$_}//0 for qw( open_drain bits parity stop );
      66        
149              
150 1 50       4 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       293 if( defined $args{baud} ) {{
159 1         3 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         323 return Future->needs_all( @f );
170             }
171              
172             =head2 write
173              
174             await $uart->write( $bytes );
175              
176             Sends the given bytes over the TX wire.
177              
178             =cut
179              
180 1     1 1 684 async method write ( $bytes )
  1         3  
  1         2  
  1         1  
181 1         2 {
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         6 my @chunks = $bytes =~ m/(.{1,16})/gs;
187              
188 1         2 foreach my $bytes ( @chunks ) {
189 1         2 my $len_1 = length( $bytes ) - 1;
190              
191 1         4 await $self->pirate->write_expect_acked_data(
192             chr( 0x10 | $len_1 ) . $bytes, length $bytes, "UART bulk write"
193             );
194             }
195              
196 1         51 return;
197             }
198              
199             =head1 AUTHOR
200              
201             Paul Evans
202              
203             =cut
204              
205             0x55AA;