IoT Development with a Raspberry Pi and Arduino

Eric J. Bruno
March 2016

Although originally created as an affordable learning computer for kids, it’s common to find people working with the Raspberry Pi as an IoT development and even a production device. The Raspbian Linux distribution available for it comes with multiple programming environments already setup, including Python, Java SE, and Scratch (for learning).

Don't let its size fool you, it's a full-fledged computer complete with a desktop UI. To see how small it is, the photo in Figure 1 shows a Pi on a 9.7" iPad.

Figure 1 - The Raspberry Pi Model B next to an iPad for size comparison.

Be sure to check out http://www.raspberrypi.org/about for the full history and inspiring story behind the Pi. It's an entire system on a chip. The Rev 1 Model B comes complete with 512MB of RAM, a ARMv6 CPU capable 700Mhz to 1GHz (via overclocking), two USB ports, an Ethernet port, an HDMI and composite video port, and various I/O ports to serve as a controller for other devices, all for around $25.

Figure 2 - A Rev 1 Model B Raspberry Pi.

For a little more money you can get a Raspberry Pi 2, which is a very capable device with a 900 MHz quad-core ARM Cortex-A7 processor, and a full 1GB RAM. It also includes two extra USB ports, a microSDHC slot, and even more capable video processing. This version can run Raspbian Linux and Windows 10 IoT Core.

Figure 3 - A more capable Raspberry Pi 2.

Kids, hobbyists, teachers, and others interested in making the most of cool and affordable technology have done some interesting things with the Pi. You can run Java on the Pi, and even use it to control an Arduino and other sensors via the serial (USB) port and the GPIO interface. Let's see what it takes to get up and running with your Raspberry Pi, install Java if it’s not already there, or upgrade it. If you already have a Pi working, you can skip to the section titled "Upgrading Your OS Image" below. Don't skip that section, especially if your Pi has 512MB of RAM.

Setting Up Your Pi

After you acquire a Pi—you can get it through multiple online vendors including Amazon —you'll need to purchase an SD card for a Rev 1 Pi (or microSDHC for Rev 2) to serve as local disk. Caution: be careful which SD card you buy. Not only does it need to be one of the known cards that work with the Pi, you want to be sure to get one with enough space to hold the software you need, that it's fast enough so boot up and operation times are acceptable, and that the price is reasonable. Size matters if you want to install other software on it, additional libraries, a Web server or embedded application server, or even a database. You can find a list of acceptable SD cards of all sizes, speeds, and manufacturers here

Next, you'll need to get an OS image and write it to the card. To do this, follow these steps:

  1. First, download the OS. You can download Raspbian "Wheezy" or “Jessie”
  2. here , both of which include Java SE.
  3. Next, "burn" the OS image to the SD card from your host computer, which can be a desktop or laptop running Windows, Linux, or Mac OS X. Instructions are available
  4. here . The RPI-sd card builder for Mac OS X works on a Mac, although the command-line is your best choice (see below).
  5. For Windows, a good choice is the
  6. Win32DiskImager utility .
  7. For Linux, there's ImageWriter or the command-line (see below).

If you run into problems, or you just don't care to spend your time burning OS images, you can purchase SD cards with a Raspberry Pi Linux OS already on it.

Using the Command Line to Install the OS Image

To use the command line, insert the SD card or microSDHC card into your host computer, and determine the device name. For instance, on a Mac, run:

> diskUtil list

On Linux, you can look in the /dev/disk directory, then choose to list the available disk devices by ID with this command:

> ls /dev/disk/by-id

Look through the list of devices and locate the SD card. Once you know its device name (i.e. /dev/disk1) you can write the image to it with the dd command as follows (using sudo if needed):

> sudo dd if=~/2016-02-09-raspbian-jessie.img of=/dev/disk1

By the way, you can reverse the if and of parameters to create an image file from the SD card after, say, you’ve installed all of your software and you want to duplicate the image across multiple Raspberry Pi boards:

> sudo dd if=/dev/disk1 of=~/my-pi-app-install.img

Once your SD card is ready, place the card into the card slot on the back of your Pi and power it up. To do so, plug a micro USB end of a USB cable into the Pi, and the other end into either a powered USB hub, a wall socket adapter (such as ones that most smartphones use), or the USB port of a computer. Whichever power source you choose, make sure there's enough current available to reliably power your Pi, especially if you plan to plug in a keyboard and mouse into the Pi's USB ports.

For our purposes, a keyboard and mouse are not required. You'll simply need to plug your Pi into your network via the Ethernet cable, although USB Wifi adapters are available as well. From there, you’ll be working from the command-line.

Logging in to your Pi

Once your Pi is up and running, and connected to your network, you can login via SSH from your desktop or laptop computer, or even from another Raspberry Pi. I do this sometimes to easily transfer files (via FTP or SCP) from one Pi to another. The default user ID is "pi", and the default password is "raspberry". Note: since most people have the same default login information for their Pi, you should change this password right away if you plan to access your Pi remotely, for security reasons.

You may need to use a port scanning utility to determine the IP address of your Pi. This isn’t an issue on your home network, but on a public network it can be an issue. To avoid this, or if you have any issues connecting to your Pi over the network, you can connect a keyboard and monitor to it and login directly from the console window.

Network Setup:

In some cases, you may need to manually configure networking for your Pi (for instance, to enable Wifi wireless networking). Start by editing the ‘interfaces’ file found in the /etc/network directory:

> vi /etc/network/interfaces

Ensure these lines exist in this file, and add them if they’re not there already:

auto loiface lo inet loopbackiface eth0 inet dhcp

Those entries enable networking over the built-in Ethernet port. To enable Wifi networking with a compatible USB Wifi adapter, add the following:

allow-hotplug wlan0
auto wlan0
iface wlan0 inet dhcp
	wpa-ssid "[ssid]"
	wpa-psk "[password]"

Make sure to replace [ssid] and [password] above with the actual SSID and password for your wireless network. For full instructions on network configuration for Raspberry Pi, go here .

Install or Upgrade Java SE

Running Java on your Pi means that you can tap into all of the available libraries and open-source code, as well as knowledge and talent in the developer community world-wide. To begin, if Java isn’t already installed or you wish to upgrade it, download Java on your host computer and then transfer it to the Pi via FTP or secure copy (scp). Make sure to download Java for Linux ARM 32-bit with hard float support from http://java.oracle.com . Accept the license agreement and be sure to choose the “Linux ARM 32 Hard Float ABI” download.

Next, copy the file over to your Pi. Assuming 192.168.0.10 is the IP address of your Raspberry Pi, you can execute the following command from a Mac or Linux computer in the local directory where the JDK was downloaded:

> scp jdk-8u71-linux-arm32-vfp-hflt.tar pi@192.168.0.10:~/

If you’re using Windows, you can use WinSCP, a visual file transfer utility, or Putty. Be sure to replace the filename above with the actual name of the JDK you downloaded previously. You’ll be prompted for the password for user pi. After you enter it correctly, the file will be copied into the home directory as specified. When the file copy is complete, login to your Pi and simply expand the JDK TAR file with the following command:

> tar xvf jdk-8u71-linux-arm32-vfp-hflt.tar

Again, remember to replace the name of the TAR file above with the actual filename you downloaded. In the end, Java will be installed in a directory such as /home/pi/jdk1.8.0_71, depending on the version you download. You can test that all is well by executing the following:

> /home/pi/jdk1.8.0_71/bin/java -version

The output should resemble the following:

java version "1.8.0_71"
Java(TM) SE Runtime Environment (build 1.8.0_71-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.71-b23, mixed mode)

Oracle Java Embedded Suite

Don't stop with just the JVM. You can install the Oracle Java Embedded Suite (JES), which includes an embedded version of Glassfish, Java DB, the Jersey Web services framework, in addition to Java SE Embedded. So technically you can skip the previous step of installing standalone Java if you download the install JES, available here.

JES includes a scaled back version of the Glassfish Java EE application server, but it does run most Java Servlets unchanged, and with the web services frameworks, it makes for an excellent web server / application interface. For the specifics, read the documentation here.

Other Application Servers

IBM offers the Websphere Liberty Profile download specifically for the Raspberry P. For more information on how to install and use it, along with videos showing it in use, go here .

Installing Java ME Embedded

If you're using the Pi as a platform to develop and test a Java application for a much more constrained device (i.e. small memory or disk footprint), you can install Java ME on your Pi. This includes both the CDC and CLDC (for very small devices), with which you can test your embedded Java application. Specifically, the CLDC-based runtime is targeted for use on highly memory constrained devices (up to 1MB), also known as Oracle Java ME Embedded . The CDC-based runtime is targeted for use on devices with slightly higher memory capacity (up to 10MB), also known as Oracle Java Micro Edition Embedded Client.

You can find versions of Java ME built specifically for the Raspberry Pi here . To see Java ME on the Pi in action, check out this video .

Control an Arduino from Your Pi with Java

You can run Java SE Embedded or Java ME on a Raspberry Pi, but the Arduino is a bit too constrained to run Java directly. However, with the help of serial port communication software, you can communicate with and a control an Arduino from Java running on another computer (such as the Pi). Although the code to do so has been published on the Arduino site, it's still a little tricky. Let’s explore how to make this work from different host operating systems. First, locate and download the RXTX library here: http://rxtx.qbang.org/wiki/index.php/Main_Page

When you unzip the downloaded file, you'll notice directories for various operating systems (OS's). Make note of which you're using as you'll need those specific files.

Next, create a new Java project in the IDE of your choice, and be sure to copy the following RXTX files (from the download in the first step) into the project directory:

Next, modify your project's settings to include RXTXcomm.jar on the class path, and the path to the native library in the command line via the
-Djava.library.path parameter, like this (all on one line):

> java -Djava.library.path=/Users/ericjbruno/ArduinoTest1 -cp ./RXTXcomm.jar:./build/classes arduinotest1.ArduinoTest1

Connecting Via Java

The trickiest part of the code to get working is to findthe correct serial port to connect to the Arduino. This part varies by OS. On the Mac, the serial port should begin with /dev/tty.usbmodemXXXX. On Windows, it's usually "COM3", and on Linux, it will be one of the /dev/tty or /dev/usbdev/ports. In the code, I've included an array of the port Strings (see Listing 1). Just comment out the ones not for your host OS, or better yet, add code to detect your OS at runtime and use the proper String:

private static final String PORT_NAMES[] = { 
    "/dev/tty.usbmodem", // Mac OS X
    "/dev/usbdev", // Linux
    "/dev/tty", // Linux
    "/dev/serial", // Linux
    "COM3", // Windows
};
Listing 1 - Possible port names for the Arduino connection.

When the sample application (available for download here) starts up, it iterates through all of the system ports looking for a match for your OS, and then attempts to connect to it, as shown in Listing 2.

// Enumerate system ports and try connecting to Arduino over each
while (portId == null && portEnum.hasMoreElements()) {
    CommPortIdentifier currPortId = 
        (CommPortIdentifier) portEnum.nextElement();
    for (String portName : PORT_NAMES) {
        if ( currPortId.getName().equals(portName) 
          || currPortId.getName().startsWith(portName)) 
        {
            // Try to connect to the Arduino on this port
            serialPort = (SerialPort)currPortId.open(appName, TIME_OUT);
            portId = currPortId;
            break;
        }
    }
}
Listing 2 - Dynamically discovering the connected Arduino port.

Once a match is found, the code will break out of the for and while loops, and then connect on the appropriate port and configure it as shown in Listing 3.

// set port parameters
serialPort.setSerialPortParams(
                DATA_RATE, // 9600 baud
                SerialPort.DATABITS_8,
                SerialPort.STOPBITS_1,
                SerialPort.PARITY_NONE);
Listing 3 - Configuring the serial port for Arduino communication.

The last step in initialization is to add an event listener (more on this later) to receive events from the Arduino, and tell it to call us back when there's data available (see Listing 4).

// add event listeners
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
Listing 4 - Setting Arduino serial port notification callbacks.

When the code is run on a host system, you should see output similar to the following:

Experimental:  JNI_OnLoad called.
Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
Trying:
   port /dev/tty.Bluetooth-Serial-1
   port /dev/cu.Bluetooth-Serial-1
   port /dev/tty.Bluetooth-Serial-2
   port /dev/cu.Bluetooth-Serial-2
   port /dev/tty.EricsiPhone-WirelessiAP
   port /dev/cu.EricsiPhone-WirelessiAP
   port /dev/tty.Bluetooth-Modem
   port /dev/cu.Bluetooth-Modem
   port /dev/tty.Bluetooth-PDA-Sync
   port /dev/cu.Bluetooth-PDA-Sync
   port /dev/tty.usbmodem1411
Connected on port /dev/tty.usbmodem1411

If the classpath and library path settings are correct, the RXTX library will load and output the version information at the top of the output above. Next, you’ll see the names of the serial ports available on ypur host, and how it finally finds a match and connects to a port (i.e. /dev/tty.usbmodem1411). You've now successfully connected to an Arduino from a Java application. It’s time to do something useful with this connectivity.

The Arduino Sketch

This sample application uses a PowerSwitch Tail which accepts a low voltage input to turn a connected AC device on or off. Simply connect the PowerSwitch Tail to pins 13 and 2 (ground) on the Arduino as shown in Figure 4 below.

Figure 4 - Connecting a PowerSwitch Tail to an Arduino.

All we have to do now is send some data over the serial port to the Arduino to instruct it to turn the PowerSwitch Tail on (along with the AC appliance plugged into it) by setting pin 13 high, and pin 2 low. To turn the appliance off, we just do the opposite. Here's the Arduino sketch to make this happen (once you load this onto your Arduino you're good to go from that point onward):

int led = 13; // LED connected to digital pin 13
int pts = 2;  // Powertail Switch 2 connected to digital pin 2
int recv = 0; // byte received on the serial port

void setup() {
  // initialize onboard LED (led), Powertail (pts) and serial port
  pinMode(led, OUTPUT);
  pinMode(pts, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // if serial port is available, read incoming bytes
  if (Serial.available() > 0) {
    recv = Serial.read();

    // if 'y' (decimal 121) is received, turn LED/Powertail on
    // anything other than 121 is received, turn LED/Powertail off
    if (recv == 121){
      digitalWrite(led, HIGH);
      digitalWrite(pts,LOW);
    } else {
      digitalWrite(led, LOW);
      digitalWrite(pts,HIGH);
    }
    
    // confirm values received in serial monitor window
    Serial.print("--Arduino received: ");
    Serial.println(recv);
  }
}
Listing 5 - The Arduino Sketch to control a PowerSwitch Tail AC device.

As a useful side-effect, turning pin 13 high also turns on an LED on the Arduino, which is helpful when debugging, or if you don't have a PowerSwitch Tail.

To make this all work from Java, simply write the correct data (the character 'y' in this case) to the serial port as the command to turn the LED and connected AC switch on, or any other data (i.e. the character 'n') to turn both off:

String data = "y"; 
output = serialPort.getOutputStream();
output.write( data.getBytes() );

The Arduino sketch also writes back to the host over the serial port to verify that it received a command. The Java code in Listing 6 receives and processes these and other events. This method is part of the RXTX SerialPortEventListener interface, which is provided as a listener in the initialization code:

public synchronized void serialEvent(SerialPortEvent oEvent) {
    try {
        switch (oEvent.getEventType() ) {
            case SerialPortEvent.DATA_AVAILABLE: 
                if ( input == null ) {
                    input = new BufferedReader(
                        new InputStreamReader(
                                serialPort.getInputStream()));
                }
                String inputLine = input.readLine();
                System.out.println(inputLine);
                break;

            default:
                break;
        }
    } 
    catch (Exception e) {
        System.err.println(e.toString());
    }
}
Listing 6 - Listening for and receiving Arduino events from Java.

Finally, to ensure that the serial port and Arduino are left in a state to communicate again, make sure you close the serial port. This removes any file system locks on the host computer, created to ensure only one device at a time communicates with the Arduino:

if ( serialPort != null ) {
    serialPort.removeEventListener();
    serialPort.close();
}

Other Important Steps

On Unix-based systems, the RXTX library places its lock files in the folder /var/lock. If this doesn't exist, communication will not work, although you won't receive any obvious errors as to why. To create this directory if missing, open the terminal application and create the lock directory as the root user or equivalent:

> sudo mkdir /var/lock

Enter your root or administrator password if prompted.

Finally, on Unix-based systems, you may also need to run the Java application with root (or equivalent) access to ensure the lock file can be created in /var/lock. Running the application as a user with the proper privilege or via the sudo command will do the trick.

More On Arduino Event Handling

Recall that after connecting to the Arduino above, an event listener was set in Listing 4. The code passes a reference to a class that implements the gnu.io.SerialPortEventListener interface, which includes just one method, serialEvent(). A SerialPortEvent object is passed as the lone parameter. Implementing this method is straightforward; just check the event type for DATA_AVAILABLE and process the data by reading from the serial port's InputStream as shown here:

// Setup input reader for incoming data from Arduino
input = new BufferedReader(
    new InputStreamReader( serialPort.getInputStream() ));

Temperature Sensor

To make the event processing interesting, the sample uses a temperature sensor such as the one available from ManyLabs . The kit comes with an Arduino shield that allows multiple analog and digital sensors to be connected at the same time. Place the shield on the Arduino, plug the sensor into port S1, and use the sketch in Listing 7 that publishes the sensor readings over the serial port. Let's walk through the code.

	
int tempSensorPin = 0;

void setup() {
	Serial.begin(9600);  //Start the serial connection with the computer
	                     //to view the result open the serial monitor 
}

void loop() {
	//getting the voltage reading from the temperature sensor
	int tempSensorVal = analogRead(tempSensorPin);  

	// Formula for converting voltage to temp in C
	const int B=3975; 
	float Rsensor = (float)(1023-tempSensorVal)*10000/tempSensorVal;
	double TEMP = 1 / (log(Rsensor/10000)/B+1/298.15)-273.15;

	// now convert to Fahrenheit
	float temperatureF = (TEMP * 9.0 / 5.0) + 32.0;
	Serial.print(temperatureF); Serial.println(" degrees F");

	delay(1000); //waiting a second
}
Listing 7 - An Arduino sketch to read a temperature sensor.

The sensor works by generating a voltage reading that varies by temperature. The trick is to take this reading, convert it to a temperature using a formula (it's simpler than it may appear), and then converting to either Celsius or Fahrenheit. To "publish" this as an event over the serial port, simply use Serial.print and/or Serial.println, assuming you've initialized the serial port as shown earlier.

You should be able to verify your temperature reading by using the Arduino Serial Monitor to view the output, which is sent once per second. To process the events in Java, add specific temperature processing and display code to the previous Java example to handle the Arduino events (see Listing 8).

@Override
public void serialEvent(SerialPortEvent spe) {
    try {
        switch (spe.getEventType() ) {
            case SerialPortEvent.DATA_AVAILABLE: 
                String inputLine = input.readLine();
                int end = inputLine.indexOf("degrees");
                if ( end > 0 ) {
                    String temp = inputLine.substring(0, end);
                    tempGauge.setValue(new Double(temp));
                }
                break;

            default:
                break;
        }
    } 
    catch (Exception e) {
        System.err.println(e.toString());
    }
}
Listing 8 - Handle the Arduino Serial events from Java.

This code parses the temperature value from the published String, and sets a GUI temperature gauge (not shown here) value accordingly. As the temperature changes (which you can force by holding or blowing on the temperature sensor), serialEvent will be called, and the gauge will update as a result.

Java Communications without JNI

The use of the RXTX library above requires Java to native system access, with some associated complexities in order to work. For instance, you need all of the right native libraries specific to your OS and version, and you need to set the library path on the Java command line as well as the classpath. There exists a pure Java alternative to RXTX called PureJavaComm by Spare Time Labs as well.

The goal of PureJavaComm is to provide Java-only access to the comms port requiring only the Java Native Access (JNA) library . JNA is an open source project maintained by Tim Wall that allows you to write pure Java code to call into native libraries (i.e. DLLs on Windows). Without JNA, you would have to write potentially complex Java Native Interface (JNI) code or other glue code to make this work. For instance, the code sample in Listing 9—from the JNA Wikipedia page—works as is on Windows, Linux, or OS X, to call the native C runtime printf function.

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
 
/* Simple example of native library declaration and usage. */
public class HelloWorld {
    public interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary) Native.loadLibrary(
            (Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
        void printf(String format, Object... args);
    }
 
    public static void main(String[] args) {
        CLibrary.INSTANCE.printf("Hello, World\n");
        for (int i = 0; i < args.length; i++) {
            CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);
        }
    }
}
Listing 9 - Calling the native C printf function from Java with JNA.

Let’s take a look at how it works, and explore an example using it with an Arduino.

Inside JNA

JNA works similar to Java reflection/introspection, or Microsoft’s Platform Invocation Services , or Microsoft COM’s IDispatch . It implements a single small layer of JNI code that acts as a stub to call into any native library from your Java code. It runs on most platforms that support Java, maps all Java primitive types to native types, handles conversion between Java and C strings, supports unicode, and variable arguments. See the JNA project page for a complete list of features, but this is the bulk of them. C pointers are mapped to Java through the use of arrays, as shown in Listing 10.

// C method
void fill_buffer(int *buf, int len);

// Equivalent JNA mapping
void fill_buffer(int[] buf, int len);
Listing 10 - JNA uses arrays to map C pointers to Java

However, if you want the memory to be accessible beyond the local scope of a function call, you need to use a com.sun.jna.Memory object:

private com.sun.jna.Memory buffer = new com.sun.jna.Memory(1024);

private void doSomethingNative() {
    //...
    fill_buffer(buffer, 1024);
}
Listing 11 - Using com.sun.jna.Memory buffers to transfer data.

Using PureJavaComm for Serial Port Communications

To begin with the PureJavaComm library, download the code from github and open the project in an IDE such as NetBeans or Eclipse. The included Maven build scripts download all the dependencies and then build the project seamlessly, without issue.

You can use the sample application from earlier in this article to test JNA with an Arduino, with only slight modifications (starting with Listing 1). First, instead of RXTX, include only two JAR files:

  1. jna-4.0.0.jar, which is included with PureJavaComm in the lib directory
  2. purejavacomm-0.0.21.jar, the output of the PureJavaComm build, found in the bin directory of the project

The updated Java-to-Arduino code is below. Here’s a quick summary of the changes (marked in the comments as well):

  1. Import the purejavacomms jtermios packages (marked by “IMPORTS” in the comments)
  2. There are slight differences in the COMM port names returned (marked by “PORTS”)
  3. Changes to handle the difference in port names (marked by “CONTAINS”)
  4. Setting flow control parameters (marked by “FLOW-CONTROL”)

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Enumeration;
import purejavacomm.*;       // IMPORTS
import jtermios.Termios.*;

public class ArduinoJavaComms implements SerialPortEventListener {
    SerialPort port = null;

    private String appName = getClass().getName();
    private BufferedReader input = null;
    
    // Port open timeout
    private static final int TIME_OUT = 1000; 

    private static final String PORT_NAMES[] = {  // PORTS
        "tty.usbmodem", // Mac OS X
//        "usbdev", // Linux
//        "tty", // Linux
//        "serial", // Linux
//        "COM3", // Windows
    };
    
    public static void main(String[] args) {
        ArduinoJavaComms lightSensor = new ArduinoJavaComms();
        lightSensor.initialize();
    }

    public void initialize() {
        try {
            CommPortIdentifier portid = null;
            Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();

            while (ported == null && portEnum.hasMoreElements()) {
                portid = (CommPortIdentifier)portEnum.nextElement();
                if ( portid == null ) 
                    continue;
                
                System.out.println("Trying: " + portid.getName());
                for ( String portName: PORT_NAMES ) {
                    if ( portid.getName().equals(portName) 
                      || portid.getName().contains(portName)) {  // CONTAINS
                        port = (SerialPort)portid.open(
                                  "ArduinoJavaComms", TIME_OUT);

                        // FLOW-CONTROL
                        port.setFlowControlMode(
                          SerialPort.FLOWCONTROL_XONXOFF_IN+ 
                          SerialPort.FLOWCONTROL_XONXOFF_OUT); 

                        input = new BufferedReader(
                          new InputStreamReader( port.getInputStream() ));

                        System.out.println( 
                          "Connected on port: " + portid.getName() );

                        port.addEventListener(this);
                        port.notifyOnDataAvailable(true);
                    }
                }
            }

            while ( true ) {
                try { Thread.sleep(100); } catch (Exception ex) { }
            }
        } 
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void serialEvent(SerialPortEvent event) {
        try {
            switch (event.getEventType() ) {
                case SerialPortEvent.DATA_AVAILABLE: 
                    String inputLine = input.readLine();
                    System.out.println(inputLine);
                    break;

                default:
                    break;
            }
        } 
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
Listing 12 - Communicating from Java to an Arduino using JNA.

Running this project requires that you have the two JAR files mentioned above in the classpath, and that’s it. The application should begin receiving events from an Arduino as soon as it runs.

If you're interested in receiving the full set of source code and project files for this article, simply send an email with the article title to eric@programmingwithreason.com