Monday, May 14, 2012

GSM modem communication using Java on Linux operating system


Introduction


In my current company we had set of SMS services which are built in Java and were strictly dependent on Windows 32-bit platform because of library which we used to interact with GSM modem. In this example win32com.dll library is used which doesn't have corresponding replacement on Linux systems. In our company we got requirement to move to Linux operating systems and because of that we had to migrate that service to Ubuntu. We decided to implement that using RXTX library which have implementations for Linux and Windows. Our main problem was lack of documentation for this library and because of this I decided to write this post. 




Installing RXTX on Linux Ubuntu


First of all it is necessary to install system libraries for interaction with GSM modem using serial communication port. First time I installed library manually and my JVM crashed with following error:

# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f44f9a065da, pid=8875, tid=139934227818240
#
# JRE version: 7.0_147-b147# Java VM: OpenJDK 64-Bit Server VM (21.0-b17 mixed mode linux-amd64 compressed oops)
# Derivative: IcedTea7 2.0
# Distribution: Ubuntu 11.10, package 7~b147-2.0-0ubuntu0.11.10.1
# Problematic frame:
# C  [librxtxSerial.so+0x75da]  Java_gnu_io_RXTXPort_nativeDrain+0xea
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again#
# An error report file with more information is saved as:
# /home/radek/NetBeansProjects/sms/hs_err_pid8875.log#
# If you would like to submit a bug report, please include# instructions on how to reproduce the bug and visit:
#   https://bugs.launchpad.net/ubuntu/+source/openjdk-7/
#
Java Result: 134



I figure out that I didn't installed proper versions for my architecture. After uninstallation I installed library using aptitude software:



sudo apt-get install librxtx-java



This will search Ubuntu repositories for proper version of library for your architecture which is really cool and easy thing to do. 


After this you are ready to write Java code for communication with GSM modem. 


Java code for interaction with GSM modem


Full runnable code for interaction with GSM modem is bellow. There are comments in code which describes classes and methods.


package ba.mike.sms;
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
 * Class for two way interaction with GSM modem
 * 
 * @author dino
 */
public class GSMModemCommunication {
    public GSMModemCommunication() {
        super();
    }

    /**
     * open connection to serial port
     * 
     * @param portName
     *            - name of serial port (example COM1 on windows $ /dev/ttyUSB1
     *            on linux)
     * 
     * @throws Exception
     */
    void connect(String portName) throws Exception {
        CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
        if (portIdentifier.isCurrentlyOwned()) {
            System.out.println("Error: Port is currently in use");
        } else {
            CommPort commPort = portIdentifier.open(this.getClass().getName(), 2000);

            if (commPort instanceof SerialPort) {
                SerialPort serialPort = (SerialPort) commPort;
                serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

                InputStream in = serialPort.getInputStream();
                OutputStream out = serialPort.getOutputStream();

                (new Thread(new SerialWriter(out))).start();

                serialPort.addEventListener(new SerialReader(in));
                serialPort.notifyOnDataAvailable(true);

            } else {
                System.out.println("Error: Only serial ports are handled by this example.");
            }
        }
    }

    /**
     * Handles the input coming from the serial port. A new line character is
     * treated as the end of a block in this example.
     */
    public static class SerialReader implements SerialPortEventListener {
        private InputStream in;
        private byte[] buffer = new byte[1024];

        public SerialReader(InputStream in) {
            this.in = in;
        }

        public void serialEvent(SerialPortEvent arg0) {
            int data;

            try {
                int len = 0;
                while ((data = in.read()) > -1) {
                    if (data == '\n') {
                        break;
                    }
                    buffer[len++] = (byte) data;
                }
                System.out.print(new String(buffer, 0, len));
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }

    }

    /**
     * Listens to console input and send commands to serial port
     * 
     * @author dino
     * 
     */
    public static class SerialWriter implements Runnable {
        OutputStream out;

        public SerialWriter(OutputStream out) {
            this.out = out;
        }

        public void run() {
            try {
                int c = 0;
                while ((c = System.in.read()) > -1) {
                    this.out.write(c);
                }
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }

    public static void main(String[] args) {
        try {
            (new GSMModemCommunication()).connect("/dev/ttyUSB1");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

How to communicate with GSM modem ?


After establishing connection it is possible to send commands to GSM modem. Each modem uses AT commands as language of interaction and full list of commands could be found on this link