File Coverage

blib/lib/Device/Hypnocube/Serial.pm
Criterion Covered Total %
statement 27 128 21.0
branch 4 60 6.6
condition 0 22 0.0
subroutine 10 19 52.6
pod 9 9 100.0
total 50 238 21.0


line stmt bran cond sub pod time code
1             # ABSTRACT: Talk to a hypnocube over a serial link
2              
3              
4             package Device::Hypnocube::Serial ;
5             $Device::Hypnocube::Serial::VERSION = '1.9';
6 1     1   32 use 5.010 ;
  1         4  
  1         48  
7 1     1   6 use strict ;
  1         4  
  1         32  
8 1     1   5 use warnings ;
  1         2  
  1         37  
9              
10 1     1   6 use vars qw( $OS_win $has_serialport $stty_path) ;
  1         1  
  1         73  
11              
12 1     1   22 use constant DEFAULT_BAUD => 38400 ;
  1         2  
  1         59  
13 1     1   6 use constant DEFAULT_TIMEOUT => 10 ;
  1         2  
  1         168  
14              
15             # -----------------------------------------------------------------------------
16              
17              
18             BEGIN {
19              
20             #Taken from SerialPort/eg/any_os.plx
21              
22             #We try to use Device::SerialPort or
23             #Win32::SerialPort, if it's not windows
24             #and there's no Device::SerialPort installed,
25             #then we just use the FileHandle module that
26             #comes with perl
27              
28 1 50   1   5 $OS_win = ( $^O eq "MSWin32" ) ? 1 : 0 ;
29              
30 1 50   1   76 if ($OS_win) {
  1 50   1   549  
  0 50   1   0  
  0 0       0  
  1         968  
  1         9169  
  1         8  
  1         2689  
  1         10788  
  1         5  
31 0         0 eval "use Win32::SerialPort" ;
32 0 0       0 die "Must have Win32::SerialPort correctly installed: $@\n" if ($@) ;
33 0         0 $has_serialport++ ;
34             }
35             elsif ( eval q{ use Device::SerialPort; 1 } ) {
36 0         0 $has_serialport++ ;
37             }
38             elsif ( eval q{ use POSIX qw(:termios_h); use FileHandle; 1} ) {
39             # NOP
40             }
41             elsif ( -x "/bin/stty" ) {
42 0         0 $stty_path = "/bin/stty" ;
43             }
44             else {
45 0         0 die
46             "Missing either POSIX, FileHandle, Device::SerialPort or /bin/stty" ;
47             }
48             } # End BEGIN
49              
50              
51             # -----------------------------------------------------------------------------
52              
53              
54             sub new {
55 0     0 1   my $class = shift;
56 0           my $param = shift ;
57              
58 0   0       my $port = $param->{serial} ||
59             ($^O eq 'MSWin32'
60             ? 'COM1'
61             : ($^O =~ /^(?:(?:free|net|open)bsd|bsd(?:os|i))$/
62             ? (-e '/dev/cuad0'
63             ? '/dev/cuad0' # FreeBSD 6.x and later
64             : '/dev/cuaa0'
65             )
66             : '/dev/ttyS1'
67             )
68             );
69              
70 0   0       my $self = bless {
71             'port' => $port
72             , 'baud' => DEFAULT_BAUD
73             , 'timeout' => $param->{timeout} || DEFAULT_TIMEOUT
74             , 'verbose' => $param->{verbose}
75             } ;
76 0           bless $self, $class;
77              
78 0 0         $self->connect unless $param->{do_not_init};
79              
80 0           return $self;
81             }
82              
83             # -----------------------------------------------------------------------------
84              
85              
86             sub connect {
87 0     0 1   my $self = shift ;
88 0 0         return $self->serial if $self->serial ;
89              
90 0 0 0       if ( $OS_win || $has_serialport ) {
    0          
91 0           $self->{serial} = $self->serialport_connect ;
92             }
93             elsif ( defined $stty_path ) {
94 0           $self->{serial} = $self->stty_connect ;
95             }
96             else {
97 0           $self->{serial} = $self->unix_connect ;
98             }
99              
100 0 0         print "Using $$self{serialtype}\n" if $self->verbose ;
101             }
102              
103             # -----------------------------------------------------------------------------
104              
105              
106             sub serialport_connect {
107 0     0 1   my $self = shift ;
108 0   0       my $PortObj = (
109             $OS_win
110             ? ( new Win32::SerialPort( $self->{port} ) )
111             : ( new Device::SerialPort( $self->{port} ) )
112             ) || die "Can't open $$self{port}: $!\n" ;
113              
114 0           $PortObj->baudrate( $self->{baud} ) ;
115 0           $PortObj->parity("none") ;
116 0           $PortObj->databits(8) ;
117 0           $PortObj->stopbits(1) ;
118 0 0         $PortObj->read_interval(5) if $OS_win ;
119 0           $PortObj->write_settings ;
120 0           $self->{serialtype} = 'SerialPort' ;
121 0           $PortObj ;
122             }
123              
124             # -----------------------------------------------------------------------------
125              
126              
127             sub unix_connect {
128              
129             #This was adapted from a script on connecting to a sony DSS, credits to its author (lost his email)
130 0     0 1   my $self = shift ;
131 0           my $port = $self->{port} ;
132 0           my $baud = $self->{baud} ;
133 0           my ( $termios, $cflag, $lflag, $iflag, $oflag, $voice ) ;
134              
135 0   0       my $serial = new FileHandle("+>$port") || die "Could not open $port: $!\n" ;
136              
137 0           $termios = POSIX::Termios->new() ;
138 0 0         $termios->getattr( $serial->fileno() ) || die "getattr: $!\n" ;
139 0           $cflag = 0 | CS8() | CREAD() | CLOCAL() ;
140 0           $lflag = 0 ;
141 0           $iflag = 0 | IGNBRK() | IGNPAR() ;
142 0           $oflag = 0 ;
143              
144 0           $termios->setcflag($cflag) ;
145 0           $termios->setlflag($lflag) ;
146 0           $termios->setiflag($iflag) ;
147 0           $termios->setoflag($oflag) ;
148 0 0         $termios->setattr( $serial->fileno(), TCSANOW() ) || die "setattr: $!\n" ;
149 0           eval qq[
150             \$termios->setospeed(POSIX::B$baud) || die "setospeed: \$!\n";
151             \$termios->setispeed(POSIX::B$baud) || die "setispeed: \$!\n";
152             ] ;
153              
154 0 0         die $@ if $@ ;
155              
156 0 0         $termios->setattr( $serial->fileno(), TCSANOW() ) || die "setattr: $!\n" ;
157              
158 0 0         $termios->getattr( $serial->fileno() ) || die "getattr: $!\n" ;
159 0           for ( 0 .. NCCS() ) {
160 0 0         if ( $_ == NCCS() ) {
161 0           last ;
162             }
163 0 0 0       if ( $_ == VSTART() || $_ == VSTOP() ) {
164 0           next ;
165             }
166 0           $termios->setcc( $_, 0 ) ;
167             }
168 0 0         $termios->setattr( $serial->fileno(), TCSANOW() ) || die "setattr: $!\n" ;
169              
170 0           $self->{serialtype} = 'FileHandle' ;
171 0           $serial ;
172             }
173              
174             # -----------------------------------------------------------------------------
175              
176              
177             sub stty_connect {
178 0     0 1   my $self = shift ;
179 0           my $port = $self->{port} ;
180 0           my $baud = $self->{baud} ;
181 0           my ( $termios, $cflag, $lflag, $iflag, $oflag, $voice ) ;
182              
183 0 0         if ( $^O eq 'freebsd' ) {
184 0           my $cc =
185             join( " ",
186 0           map { "$_ undef" }
187             qw(eof eol eol2 erase erase2 werase kill quit susp dsusp lnext reprint status)
188             ) ;
189 0           system(
190             "$stty_path <$port cs8 cread clocal ignbrk ignpar ospeed $baud ispeed $baud $cc"
191             ) ;
192 0 0         warn "$stty_path failed" if $? ;
193 0           system("$stty_path <$port -e") ;
194             }
195             else { # linux
196 0           my $cc =
197             join( " ",
198 0           map { "$_ undef" }
199             qw(eof eol eol2 erase werase kill intr quit susp start stop lnext rprnt flush)
200             ) ;
201 0           system(
202             "$stty_path <$port cs8 clocal -hupcl ignbrk ignpar ispeed $baud ospeed $baud $cc"
203             ) ;
204 0 0         die "$stty_path failed" if $? ;
205 0           system("$stty_path <$port -a") ;
206             }
207              
208 0 0         open( FH, "+>$port" ) or die "Could not open $port: $!\n" ;
209 0           $self->{serialtype} = 'FileHandle' ;
210 0           \*FH ;
211             }
212              
213             # -----------------------------------------------------------------------------
214              
215              
216             sub read {
217              
218             #$self->_read(length)
219             #reads packets from whatever you're listening from.
220             #length defaults to 1
221              
222 0     0 1   my ( $self, $len ) = @_ ;
223 0   0       $len ||= 1 ;
224              
225 0 0         $self->serial or die "Read from an uninitialized handle" ;
226              
227             # show we are using it
228 0           $self->{activity} = 1 ;
229              
230 0           my $buf ;
231              
232 0 0         if ( $self->{serialtype} eq 'FileHandle' ) {
233 0           sysread( $self->serial, $buf, $len ) ;
234             }
235             else {
236 0           ( undef, $buf ) = $self->serial->read($len) ;
237             }
238              
239 0           $self->{activity} = 0 ;
240              
241 0           return $buf ;
242             }
243              
244             # -----------------------------------------------------------------------------
245              
246              
247             sub write {
248              
249             #$self->_write(buffer,length)
250             #syswrite wrapper for the serial device
251             #length defaults to buffer length
252              
253 0     0 1   my ( $self, $buf, $len, $offset ) = @_ ;
254 0 0         $self->connect() or die "Write to an uninitialized handle" ;
255              
256             # show we are using it
257 0           $self->{activity} = 1 ;
258              
259 0   0       $len ||= length($buf) ;
260              
261 0 0         $self->serial or die "Write to an uninitialized handle" ;
262              
263 0 0         if ( $self->{serialtype} eq 'FileHandle' ) {
264 0   0       syswrite( $self->serial, $buf, $len, $offset || 0 ) ;
265             }
266             else {
267 0           my $out_len = $self->serial->write($buf) ;
268 0 0         warn "Write incomplete ($len != $out_len)\n" if ( $len != $out_len ) ;
269             }
270 0           $self->{activity} = 0 ;
271             }
272              
273             # -----------------------------------------------------------------------------
274              
275              
276 0     0 1   sub serial { shift->{serial} }
277              
278             # -----------------------------------------------------------------------------
279              
280              
281 0     0 1   sub verbose { shift->{verbose} }
282              
283             # -----------------------------------------------------------------------------
284              
285             1 ;
286              
287             __END__