We recently built a small application for a geology contractor who works on active oil rigs and needed a way for his gas detection equipment to communicate with the oil rig network. The communication with the oil rig network needed to happen over a serial port. My laptop doesn't have a serial port, and honestly sometimes I have a hard time remembering what a serial port looks like, yet I needed a way to test the send/receive functionality of my program. After a good bit of Googling I was able to piece together a solution that works pretty well using my OSX computer as a host with a Windows 10 Virtual Machine (VM) guest managed by VirtualBox.

The final application needed to run on a Windows computer and needed to be able to send and receive data to an oil rig computer network using the WITS level 0 protocol and a Serial Port connection. The WITS protocol level 0 is ASCII data, and specifically I needed to adhere to the Pason implementation. More on WITS and Pason here and here.

For development, I chose to use a Windows 10 VM managed by VirtualBox. Thus, I needed a way to send data from the guest as well as receive data on the guest.

Send from guest to host

This was quite straight forward. In VirtualBox->Machine->Settings->Ports page, I chose to enable a port, and chose "Raw File" as the Port Mode. I left the IRQ and I/O Port settings at their default, chose to connect to an existing file, and pointed to a file in my host's /tmp/ directory:

Virtual Box Setup Pane

Then on the host computer, I created that file:

$ touch /tmp/test_C2

The next time I started the VM, I was able to see a port named COM2 enabled in the Windows Device Manager, and to interact with the port from my VB.Net code. On the host computer I was able to see data sent from the guest by reading the file:

# On host
$ tail -f /tmp/test_C2

Receive data from host

This took me a bit of reading to figure out, but ended up being quite easy:

With VirtualBox->Machine->Settings->Ports, set "Port Mode" as "Host Pipe", leave the IRQ and I/O defaults, de-select "connect to existing pipe/socket" and provide an address (on the host):

Virtual Box Setup Pane

Next, on the host, we need an additional piece of software that can emulate a serial port. After some reading I found that the tool socat would do the trick. socat seems to be a super tool that can do about 1000 things more than I need right now. Reading, trial and error led to this:

# On host
$ socat - UNIX-CONNECT:/tmp/vsp_sock1

Which I believe takes the stdin stream (-) and connects it to the the address provided to UNIX-CONNECT as a "unix domain socket". With the above socat command issued on the host, I could see data sent over the guest's serial port streaming to the console on the host. Additionally, typing into the host's console and hitting enter would send a line of text to the guest. On the guest, data sent from the host successfully triggered an event on the .NET serial Port object, allowing me to run a callback and read a line of data. Two way communication!

Next step is to write a script on the host to build and send fake WITS packets so I can working on parsing them in the guest.

From the socat man page:

UNIX-CONNECT:<filename>
      Connects to <filename> assuming it is a UNIX domain socket.   If
      <filename>  does  not  exist, this is an error; if <filename> is
      not a UNIX domain socket, this is an error; if <filename>  is  a
      UNIX  domain  socket,  but  no  process is listening, this is an
      error.
      Option groups: FD,SOCKET,NAMED,RETRY,UNIX
      ) Useful options: bind
      See also: UNIX-LISTEN, UNIX-SENDTO, TCP