Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

Re: Re: Writing a serial-to-Ethernet adapter with Win32::SerialPort

by sgifford (Prior)
on May 14, 2004 at 19:33 UTC ( #353466=note: print w/replies, xml ) Need Help??

in reply to Re: Writing a serial-to-Ethernet adapter with Win32::SerialPort
in thread Writing a serial-to-Ethernet adapter with Win32::SerialPort

Thanks BrowserUK! I followed part of your advice and created a seperate thread to handle the serial IO, but instead of using a Thread::Queue I simply created a socket with socketpair, and used it to communicate back to the main thread. That way I could use IO::Select to handle everything.

Here's the code I ended up with.

#!/usr/bin/perl -w use threads; use threads::shared; use strict; use Socket; use IO::Socket; use IO::Select; use Win32::SerialPort; use Win32API::CommPort; use Getopt::Std; use constant DEFAULT_BAUDRATE => 38400; use constant DATABITS => 8; use constant STOPBITS => 2; use constant PARITY => 'none'; use constant HANDSHAKE => 'none'; use constant BUFSIZE => 64; use constant SOCKET_TIMEOUT => 0.1; use constant SERIAL_TIMEOUT => 0xffffffff; sub usage { die "Usage: $0 -c com-port -p tcp-port [-b baudrate]\n"; } our $debug = $ENV{SERIALSERVER_DEBUG}||0; sub debug($@) { my $msglevel = shift; warn @_ if ($debug >= $msglevel); } our %opt; getopts("c:b:p:",\%opt); $opt{c} and $opt{p} or usage(); # Set up the COM port our $com = Win32::SerialPort->new($opt{c}) or die "Couldn't create COM port: $!\n"; $com->databits(DATABITS); $com->stopbits(STOPBITS); $com->parity(PARITY); $com->handshake(HANDSHAKE); $com->baudrate($opt{b}||DEFAULT_BAUDRATE); $com->write_settings or die "Error writing settings: $!\n"; # Set up the socket our $listen = IO::Socket::INET->new(Listen => 0, ReuseAddr => 1, Proto => 'tcp', LocalPort => $opt{p}) or die "Couldn't create listen socket: $@\n"; our $done = 1; share $done; # Set up the commport thread my($com_read,$com_write); socketpair($com_read,$com_write,AF_UNIX,SOCK_STREAM,PF_UNSPEC) or die "socketpair failed: $!"; my $com_thread = threads->create('monitor_serial',$com,$com_write) or die "Couldn't create monitor_serial thread: $!\n"; # Now start the main loop my $sock; my $select = IO::Select->new($listen,$com_read) or die "Couldn't create select object: $!\n"; while(my @ready = $select->can_read) { foreach my $fh (@ready) { if ($fh eq $listen) { # Blocks waiting for connection my $newsock = $listen->accept or die "Accept error: $!\n"; if ($sock) { debug 1,"Rejected connection from ",$newsock->peerhost," (alre +ady have client)\n"; syswrite($newsock,"Sorry, I already have a client\r\n"); close($newsock); } else { debug 1,"Got new connection from ",$newsock->peerhost,"\n"; $sock=$newsock; $select->add($sock); } } elsif ($sock and ($fh eq $sock)) { # Data from the network my $buf; if (!sysread($sock,$buf,BUFSIZE)) { # Connection closed debug 1,"Connection from ",$sock->peerhost," closed.\n"; $select->remove($sock); close($sock); undef($sock); next; } debug 2,"Got ",length($buf)," bytes from network\n"; com_writebytes($com, 1000, $buf) or die "Couldn't write bytes to com: $!\n"; } elsif ($fh eq $com_read) { # Data from the serial port thread my $buf; sysread($com_read,$buf,BUFSIZE) or die "Read from COM thread failed.\n"; if ($sock and defined($buf) and (length($buf)) > 0) { debug 2,"Got ",length($buf)," bytes from serial port\n"; syswrite($sock,$buf) or die "Couldn't write to socket: $!\n"; } } } } # Loop never exits # Thread to monitor the serial port for activity, and send it back # over a socket. sub monitor_serial { my($com,$sock)=@_; while(1) { my $buf = com_readbytes($com, 60000, 1); if (defined($buf) and (length($buf)) > 0) { my $morebuf = com_readbytes($com,5,256); $buf .= $morebuf if ($morebuf); syswrite($sock,$buf) or die "Couldn't write to socket: $!\n"; } } } # Write bytes to serial port sub com_writebytes { my($com,$timeout,$data)=@_; my $bytesleft = length($data); $com->write_const_time($timeout); my $start = time; while ($bytesleft > 0) { if ( (time - $start) > $timeout) { die "Write timeout.\n"; } my $wb = $com->write($data) or die "Error writing data to COM port: $!\n"; substr($data,0,$wb,""); $bytesleft -= $wb; } 1; } sub com_readbytes { my($com,$timeout,$bytesleft)=@_; $com->read_const_time($timeout); my($rb,$data)=$com->read($bytesleft); $data; }

Replies are listed 'Best First'.
Re: Re: Re: Writing a serial-to-Ethernet adapter with Win32::SerialPort
by BrowserUk (Pope) on May 14, 2004 at 20:13 UTC


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://353466]
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (3)
As of 2018-06-25 05:21 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (126 votes). Check out past polls.