File Coverage

blib/lib/Device/Chip/Adapter/UART.pm
Criterion Covered Total %
statement 24 75 32.0
branch 0 10 0.0
condition 0 9 0.0
subroutine 8 22 36.3
pod 10 13 76.9
total 42 129 32.5


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, 2018-2020 -- leonerd@leonerd.org.uk
5              
6             package Device::Chip::Adapter::UART;
7              
8 1     1   826 use strict;
  1         2  
  1         35  
9 1     1   5 use warnings;
  1         2  
  1         28  
10 1     1   5 use base qw( Device::Chip::Adapter );
  1         2  
  1         641  
11              
12             our $VERSION = '0.02';
13              
14 1     1   20068 use Carp;
  1         3  
  1         53  
15              
16 1     1   7 use Future;
  1         2  
  1         17  
17 1     1   547 use Future::Buffer;
  1         1210  
  1         37  
18 1     1   479 use Future::IO 0.04; # ->syswrite_exactly
  1         3153  
  1         42  
19 1     1   550 use IO::Termios;
  1         27959  
  1         8  
20              
21             =head1 NAME
22              
23             C - a C implementation for
24             serial devices
25              
26             =head1 DESCRIPTION
27              
28             This class implements the L interface around a regular
29             serial port, such as a USB UART adapter, allowing an instance of a
30             L driver to communicate with actual chip hardware using this
31             adapter.
32              
33             This adapter provides both the C and C protocols. The C
34             protocol wraps the modem control and handshaking lines. The C protocol
35             adds access to the transmit and receive lines by adding the L and
36             L methods.
37              
38             =cut
39              
40             =head1 CONSTRUCTOR
41              
42             =cut
43              
44             =head2 new
45              
46             $adapter = Device::Chip::Adapter::UART->new( %args )
47              
48             Returns a new instance of a C.
49              
50             Takes the following named arguments:
51              
52             =over 4
53              
54             =item dev => STRING
55              
56             Path to the device node representing the UART; usually something like
57             F or F.
58              
59             =back
60              
61             =cut
62              
63             sub new
64             {
65 0     0 1   my $class = shift;
66 0           my %args = @_;
67              
68 0 0         my $termios = IO::Termios->open( $args{dev} ) or
69             die "Cannot open $args{dev} - $!";
70              
71 0           $termios->blocking( 0 );
72              
73 0           for( $termios->getattr ) {
74 0           $_->cfmakeraw;
75 0           $_->setflag_clocal( 1 );
76              
77 0           $termios->setattr( $_ );
78             }
79              
80 0           return bless {
81             termios => $termios,
82              
83             # protocol defaults
84             bits => 8,
85             parity => "n",
86             stop => 1,
87             }, $class;
88             }
89              
90             sub new_from_description
91             {
92 0     0 1   my $class = shift;
93 0           my %args = @_;
94 0           return $class->new( map { $_ => $args{$_} } qw( dev ) );
  0            
95             }
96              
97             =head1 PROTOCOLS
98              
99             The following C protocol types are supported
100              
101             =over 2
102              
103             =item *
104              
105             GPIO
106              
107             =back
108              
109             =cut
110              
111 0     0 0   sub make_protocol_GPIO { return Future->done( $_[0] ) }
112 0     0 0   sub make_protocol_UART { return Future->done( $_[0] ) }
113              
114             # Protocol implementation
115              
116             my %GPIOS_READ = (
117             DSR => 1,
118             CTS => 1,
119             CD => 1,
120             RI => 1,
121             );
122              
123             sub configure
124             {
125 0     0 1   my $self = shift;
126 0           my %args = @_;
127              
128             exists $args{$_} and $self->{$_} = delete $args{$_}
129 0   0       for qw( baudrate bits parity stop );
130              
131 0 0         keys %args and
132             croak "Unrecognised configure options: " . join( ", ", keys %args );
133              
134             $self->{termios}->set_mode( join ",",
135 0           @{$self}{qw( baudrate bits parity stop )}
  0            
136             );
137              
138 0           return Future->done;
139             }
140              
141             sub list_gpios
142             {
143 0     0 1   return qw( DTR DSR RTS CTS CD RI );
144             }
145              
146             sub meta_gpios
147             {
148             return map {
149 0 0   0 1   $GPIOS_READ{$_} ?
  0            
150             Device::Chip::Adapter::GPIODefinition( $_, "r", 1 ) :
151             Device::Chip::Adapter::GPIODefinition( $_, "w", 1 );
152             } shift->list_gpios;
153             }
154              
155             sub read_gpios
156             {
157 0     0 1   my $self = shift;
158 0           my ( $gpios ) = @_;
159              
160 0           my $values = $self->{termios}->get_modem();
161              
162 0           my %ret;
163              
164 0           foreach my $gpio ( @$gpios ) {
165 0 0         $ret{$gpio} = $values->{lc $gpio} if $GPIOS_READ{$gpio};
166             }
167              
168 0           return Future->done( \%ret );
169             }
170              
171             sub write_gpios
172             {
173 0     0 1   my $self = shift;
174 0           my ( $gpios ) = @_;
175              
176 0           my %set;
177             defined $gpios->{$_} and $set{lc $_} = $gpios->{$_}
178 0   0       for qw( DTR RTS );
179              
180 0 0         if( %set ) {
181 0           $self->{termios}->set_modem( \%set );
182             }
183              
184 0           return Future->done;
185             }
186              
187             sub tris_gpios
188             {
189             # ignore
190 0     0 1   Future->done;
191             }
192              
193             sub write
194             {
195 0     0 1   my $self = shift;
196 0           my ( $bytes ) = @_;
197              
198 0           return Future::IO->syswrite_exactly( $self->{termios}, $bytes );
199             }
200              
201             sub readbuffer
202             {
203 0     0 0   my $self = shift;
204 0   0       return $self->{readbuf} //= do {
205 0           my $fh = $self->{termios};
206              
207             Future::Buffer->new(
208 0     0     fill => sub { Future::IO->sysread( $fh, 256 ) },
209 0           );
210             };
211             }
212              
213             sub read
214             {
215 0     0 1   my $self = shift;
216 0           my ( $len ) = @_;
217              
218             # This is a 'read_exactly'
219 0           return $self->readbuffer->read_exactly( $len );
220             }
221              
222             =head1 AUTHOR
223              
224             Paul Evans
225              
226             =cut
227              
228             0x55AA;