Introduction: Intel Edison Arduino Serial to Host Process Serial Communication

The Intel Edison Arduino breakout is a linux based mini computer that can be programmed using the Arduino IDE and Framework. It can also be programmed as any other Linux system in C/C++, Python, node.js, and many other languages.

The way its Arduino programming works, the IDE compiles a native Linux binary and uploads and executes it on the Edison. For serial, there a 3 serial objects available as a follows:

Serial: Maps to /dev/ttyGS0 on linux, which connects to the J16 USB port on the Arduino breakout.  This port is what's used in the Arduino IDE Serial Monitor.
Serial1: Maps to /dev/ttyMFD1 on Linux, which is a hardware UART that connects to pins 0,1 on the Arduino pinout. 
Serial2: Maps to /dev/ttyMFD2 on Linux, which is a hardware UART that connects to the J3 USB port on the Arduino Breakout.  This port is used as a console terminal, and if used by a sketch the console terminal will be disconnected.

Because the Arduino sketch runs as a native Linux program is not possible for another program on linux to use any of these ports when the sketch is using them, so you cannot "talk" between a host process and a sketch using one of the 3 Serial objects. However, there is a TTYUARTClass that can be used to make a Serial-like object in Arduino from any serial-like linux file. We're going to use a common Linux utility called socat to create some serial-like files that a Sketch and a host process can connect to. We're going to use Node.js, but the same process should work in any language.

Step 1: Install Socat

Prerequisite: You'll need have your Edison setup with an active internet connection and either SSH or the serial console working.

Unfortunately Intel Yocto Linux does not come with socat and i was not able to find a Yocto repository for it, so we'll build it from source.

Use SSH or the serial console and login as root. Then download the socat source code, extract the tarball (the tar.gz file), and compile the program. The following serial of commands will do this.

wget http://www.dest-unreach.org/socat/download/socat-2.0.0-b8.tar.gz
tar xvf socat-2.0.0-b8.tar.gz
cd socat-2.0.0-b8
./configure
make
make install

"./configure / make / make install" is the defacto "install from source" set of commands. Unless a program has specific install instructions these 3 commands will usually do the trick.

Step 2: Setup Serial Devices

Since devices and files in Linux are presented as files this lets us create files that are backed by software that acts like a hardware device, and that's what socat lets us do. We'll be making 2 files and backing them with socat so that they behave like 2 ends of a serial cable.

socat has many many options and is a fairly powerful little utility. we're going to create some raw PTY, or pseudoterminal, devices. Pseudoterminal is an old Unix concept that was originally meant for serial connected user terminals, Serial devices are often implemented as a PTY device and Linux is no exception. Additionally, we want to run the socat process in the background using "&" so we'll run it with the "nohup" command. Without nohup the process may end when the console connection is terminated.

nohup socat pty,link=$HOME/tty0,raw,echo=0 pty,link=$HOME/tty1,raw,echo=0 &

By default socat will generate some /dev/pts/ files for you, so we're using the link option to have to make a symlink for us. $HOME is a shell variable that gets replaced with user's home folder, and on the edison as root this will be /home/root. Our files will be /home/root/tty0 and /home/root/tty1. One of these is master and one is slave. It doesn't matter which you use for arduino and which for Node, we're going to use 0 for Arduino Just Because.

To test we'll use the shell command echo to send an "A" into one file and use the cat command to read the other to see the result.

echo "A" > tty0 && cat tty1

the > redirects the output of a command to a file or stream device(serial is kind of stream), and the && is a command separator, it means "wait for the first command to complete with success then run the 2nd command". If the first command gives an error, the 2nd command will not run. cat allows printing the contents of a file or stream to the console. Since pty devices are streams we have to CTRL-C to interrupt the cat process and return to the prompt.

If everything is working you should see an A output. you can use the "ps" command to see that the socat process is running, and you can use the kill command to stop it if you need to change any settings.

Step 3: Arduino: Connect a Serial Object to the Tty

In the Arduino IDE the Edison board comes with libraries RingBuffer and TTYUARTClass that can be used to create a Serial-like object attached to any PTY on the host. We'll use these to connect to the tty0 file we just created using socat.

RingBuffer rx_buffer_S1; 
TTYUARTClass mySerial(&rx_buffer_S1, 3, false);
mySerial.init_tty("/home/root/tty0");

You can view the full sketch on gist.

Make sure the socat process is still running from the previous step and upload the sketch to your Edison. If the socat process is not running your sketch will most likely crash. This could be prevented by adding some C++ file commands to make sure the tty file exists before trying to initialize it.

Step 4: Arduino Sketch Universal

We can take this a step further and make our test sketch work on any Arduino connected via USB. To do that we can use a board constant __ARDUINO_X86__ to know when we're compiling for an Intel-based board and use preprocessor directive conditionals #if, #elif, and #endif

#if defined(__ARDUINO_X86__)
RingBuffer rx_buffer_S1;
TTYUARTClass mySerial(&rx_buffer_S1, 3, false);
#elif
#define mySerial Serial
#endif

The #elif redefines mySerial as Serial so that on a normal Arduino board the Serial object will be used when referencing mySerial.

The you can view the full sketch on gist.

Step 5: Serial Server

For our "server' we'll use a Node.js script using the node serialport module. Edison's Yocto Linux comes with node installed, so our first step is to make a folder for our project.

mkdir serial_test
cd serial_test

And instal the serialport module into our project

npm install serialport

Now we can make our server script. We'll start with a very basic script based on the examples on the serialport page. Since the Arduino sketch uses tty0 we'll need to use its paired port tty1 in this script. You can find the script attached or on gist. Save as serial_test.js in the project folder.

Finally, run it using the node command:

# node serial_test.js

You should see something like:

open
err undefined
data received: A
data received: A
data received: A
sending B
data received: A!
data received: A
data received: A
sending A
data received: A$
data received: A
data received: A

To stop the script press CTRL+c.

Step 6: Next Steps

This should give you a basic way to make your existing arduino sketches and linux scripts work together on the Edison and still work on RaspberryPi and PCs too. The next steps would be to make the socat process start on bootup, possibly even being launched from inside the Arduino sketch, or via your linux scripts.