Have had lots of fun getting reliable serial port under vbox on my laptop using usb serial devices. (linux host, now vbox 2.02, no serial port laptop, XP guest)
Cannot get direct port to work reliable...named pipes appear to work as advertised.
With the use of pluggable serial ports under vbox there are a number of problematic issues!
Issue #1: Vbox enforces named pipe presence at startup, and then if port drops during session it fails to reattempt a connection. Most annoying, especially as usb-serial adaptors are always slightly unreliable.
Seems to me changing default behavior to non-enforced pipe at startup, and reattempting connection on loss of pipe would help immensely.
Issue #2: Using Vbox usb support ,usb-serial adaptors work (just) but are unreliable to downright flaky. (2 out of 3 work and only on some hardware and then mean uptime < 3min. [moxa uport 1150, targus pa088 and pci-express dual port mos7840 based])
socat is a great app, however it does not appear to have an option to keep a port open indefinitely after loss of other end.
After much playing around I managed to get a combination that works in keeping the vbox port up, but allows disconnects on usb side.
Command 1: Prior to vbox startup run
Code: Select all
socat -x -d -d -d unix-listen:/tmp/vbox-com1,reuseaddr,fork pty:/tmp/vmodem0,raw,echo=0,bind=/tmp/vmodem0
Command 2: at any time after usb serial port e.g. /dev/ttyUSB0 becomes available
Code: Select all
socat -x -d -d -d open:/tmp/vmodem0,raw,echo=0,forever /dev/ttyUSB0,nonblock,raw,echo=0
This command will not work unless both ends are present and available.
You can repeat this command after a comm loss even with vbox running. [the Woohoo moment!]
One could possibly write a udev rule to handle this, however you need to check that the /tmp/vmodem0 pts is already available so a script is needed.
Handling two serial adaptors of same type under udev can be hairy here as they often do not carry totally unique serial id for udev to match 100%, so ports may swap.
In this case I have written a startup script that monitors a device and checks for the pts presence and then launches socat. This is hands free in operation although it may take 5s to get an operational port after a plugin of usb-serial adaptor [you can speed poll up in script if you want it faster]
In my startup script (/etc/conf.d/local/start on my gentoo box) I have the following two lines to get it all going.
Code: Select all
socat unix-listen:/tmp/vbox-com1,reuseaddr,fork pty:/tmp vmodem0,raw,echo=0,bind=/tmp/vmodem0 &
/usr/local/bin/vbox_serial.py -D
vbox_serial.py
Code: Select all
#!/usr/bin/python
"""
/* vbox_serial.py (C) 2008 Tarek HEILAND (tarek@illimitable.com)
* Version 0.02
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
Assumes linux host.
This is alpha code - bugs what bugs!
Virtualbox serial handling is a bit problematic for transitory serial connection
since.
a) virtualbox checks and expects serial connection at startup, and fails
if not present
b) only checks once at startup
c) does not try to restore a lost connection eg a named pipe
For those of us who need to laptops to communicate with hardware
such as PLC's etc this is annoying especially as buying laptops
with permanent laptops is getting difficult.
Additionaly OSE version forces one to use linux serial interfaces to talk
through host as usb is not available
In addition use of usb adaptors in non OSE edition is not very reliable.
(tried three different brands/types - all drivers installed ok - but serial comms
was very patchy and lost connection to hardware all the time)
(running on 2.5GHz core duo with 1GB ram allocated to vbox)
This script is part of a double socat solution to workaround these issues.
It monits port and pts for pre-conditions and then launching socat to join the two.
Once running use stty to set serial port parameters to match that of application may be needed.
REQUIRES: recent python
typical run example
vbox_serial.py -t /dev/ttyUSB0 -D -p /tmp/vmodem0
"""
import os, os.path, signal, subprocess, time
from stat import *
from sys import *
from optparse import OptionParser
class c_daemon:
"""Detach a process from the controlling terminal and run it in the
background as a daemon.
"""
def create(self):
try:
pid = os.fork()
except OSError, e:
return((e.errno, e.strerror))
if (pid == 0):
os.setsid()
signal.signal(signal.SIGHUP, signal.SIG_IGN)
try:
pid = os.fork()
except OSError, e:
return((e.errno, e.strerror))
if (pid == 0):
os.chdir("/")
os.umask(0)
else:
os._exit(0)
else:
os._exit(0)
try:
maxfd = os.sysconf("SC_OPEN_MAX")
except (AttributeError, ValueError):
maxfd = 256 # default maximum
for fd in range(0, maxfd):
try:
os.close(fd)
except OSError:
pass
# Redirect the standard file descriptors to /dev/null.
os.open("/dev/null", os.O_RDONLY) # standard input (0)
os.open("/dev/null", os.O_RDWR) # standard output (1)
os.open("/dev/null", os.O_RDWR) # standard error (2)
return(0)
def d(str, cr=1): #verbose debug
global gv
if gv['debug']:
if cr:
s="\n"+time.strftime("%a, %d %b %Y %H:%M:%S: ", time.localtime())+str
else: s=str
stderr.write(s)
def main():
global gv
gv={}
#deal with command line options
parser = OptionParser()
parser.add_option("-D","--daemon",action="store_true",help="Run process as daemon")
parser.add_option("-t", "--tty", action="store", type="string", dest="tty",help="tty name [/dev/ttyUSB0]", default='/dev/ttyUSB0')
parser.add_option("-s", "--secs", action="store", type="float", dest="secs",help="Port Check Interval [2]", default=2.)
parser.add_option("-p", "--pty", action="store", type="string", dest="pipe",help="pipe [/tmp/vmodem0]", default='/tmp/vmodem0')
parser.add_option("-v", "--verbose", action="store_true", help="Be verbose")
(options, args) = parser.parse_args()
gv['debug']=options.verbose
gv['tty']=options.tty
gv['secs']=options.secs
gv['pty']=options.pipe
if options.daemon:
print "Deamonising ....."
C_Daemon=c_daemon()
ret=C_Daemon.create()
daemon()
else:
daemon()
def daemon():
global gv
p=check()
while 1:
#this loop checks alternatly for avail tty's
#this is more for debugging purpose as it does not lock
#onto single tty eg when you pull usb adaptor
passed=0
while not passed==2:
passed=0
if p.avail(gv['tty'] ):
passed+=1
time.sleep(gv['secs'])
if p.avail(gv['pty']):
passed+=1
time.sleep(gv['secs'])
#should now have both tty and pty
#run socat - should block until it dies
p.go(gv['tty'], gv['pty'])
class check():
def avail(self, tty):
d("Testing for %s" %(tty))
if os.path.exists(tty):
mode = os.stat(tty)[ST_MODE]
if S_ISCHR(mode):
d("....Found", cr=0)
return 1
else:
d("........not found", cr=0)
return 0
def go(self, tty, pty):
s="/usr/bin/socat"
s1=" open:%s,raw,echo=0,forever" %(pty)
s2=" %s,nonblock,raw,echo=0,forever"%(tty)
d("launching socat %s <=> %s" %(tty, pty))
d("with %s%s%s"% (s, s1, s2))
subprocess.call( (s,"-x","-d","-d","-d", s1, s2) )
d("socat exit")
main()
print "\n" #cleanup
1) copy code to a file in your fs [/usr/local/bin]
2) ensure first line points to your python exec
3) make file exec eg chmod 755
4) set up vbox with com port with named pipe eg /tmp/vbox-com1
I took home an omron NT20s HMI panel this week that has been a pain to upload code to through direct usb vbox connection (perhaps 1 in 20 attempts worked). With this socat solution this has worked 100% even after repeated attempts, plugins etc etc.
I should also note that stty can be needed to get things working...eg for the panel I needed once after boot only
Code: Select all
stty -F /dev/ttyUSB0 cs8