This report has been modified on September 10, 2007 in order to reflect recent changes in supported phones and required third-party software. Sun have decided to no longer support JavaComm 2.0 and the Microsoft Windows platform. See further details in the Serial Communication in Java section.
This report has been modified on November 30, 2005 in order to reflect recent changes in the SMS library code. In order to use all the features mentioned here, you need to have the latest version of the JavaLib-file, which can be downloaded in the download section.
Since the introduction of the GSM networks in 1992, SMS has been a service with an increasing interest. SMS is actually not designed for the success it is having today. The marketing guys within the standardization group could not see any use of a service, requiring that the user should press the same key several times to write a character. The only reason for SMS became part of the standard, was the techical guys wanting it for service messages and testing.
Today, SMS is an extensively used service and almost everyone is able to use it. This has lead to an increasing number of applications using SMS as the interface to the user. This project contains an SMS framework, written in Java. The framework is designed for robustness in order to serve as a gateway between users with their mobile phone, and the application. The implemented application is an SMS-to-OSC gateway, sending all incomming SMS' to an OSC capable host. OSC is expained in greater detail in section OSC.
Throughout the rest of this paper, we first describe what SMS is from a technical point of view. Next we discuss some aspects of serial communication in general and in Java. Then we go into the details of the SMS framework and how it can be used in an application. We then present OSC and the Java implementation of OSC. Finally we present the SMS2OSC application.
It is assumed that the reader is familiar with general Java programming.
Short Message System (SMS) is a part of the Global System for Mobile Communications (GSM) specification. GSM is initially specified by European Telecommunications Standards Institute (ETSI - http://www.etsi.org). The current specification is controlled by 3rd Generation Partnership Project (3GPP - http://www.3gpp.org), from where the specification can be downloaded. Note, it is huge!
In the first phase of the GSM networks, SMS reception was mandatory for a mobile phone (called Mobile Station (MS) in the specification), but sending SMS was an optional feature. From phase 2 of the GSM networks (1997), sending SMS became mandatory. The current networks are all phase 2 or later.
SMS is a no-guaranties service. The operator of the GSM network does
not give any guaranties for delivery of SMSs. Because of this, SMS is a
costless service for the operator, as messages can be sent during idle
periods of the network.
An SMS is just a single datapacket or Protocol Data Unit
(PDU) in the network, but PDUs cannot be sent without a connection. In
order to send an MS originated SMS, the MS creates a
connection to the Base Transceiver Station (BTS),
sends the PDU containing the SMS, and finally closes the
connection. Because an SMS is limited to one single PDU, it can
only contain 160 characters. Modern MSs are able to send longer SMSs,
called Extended Message System (EMS), which just are several
ordinary SMSs displayed as one on the MS.
In order to use SMS in a computer application, an interface between the computer and the GSM network is needed. This interface is typically an MS connected to a serial port on the computer. In this project the serial connection to an MS is the interface.
In Java, serial communication is specified in the package
javax.comm, which is a part of the extended
specification (the javax). Because it is part of the
extended specification, it it not part of the reference Java implementation
from Sun (http://java.sun.com). Sun
has only implemented javax.comm for Microsoft Windows and
Sun's Solaris/SPARC platform (see
http://java.sun.com/products/javacomm/).
Implementations for other platforms exist, e.g. the RxTx project (http://www.rxtx.org), which provides
the javax.comm package for Linux, MacOS X, etc.
Update: Sun has released a new version 3 of the JavaComm API. This version is not tested with the framework presented here. Furthermore, Sun has no longer support for the Microsoft Windows platform and the JavaComm API is no longer available for download for Microsoft Windows in version 2. I have version 2 for Windows and it can be downloaded in the download section.
When an application is communicating through a serial interface, it
can basicly do this in two ways: It can poll the serial port for data
(synchronously), and it can receive data events (something like
interrupts) when data is received (asynchronously). The
javax.comm allows you to do both. Synchronous
communication is done by using the read methods on the
InputStream of the serial port. If there is no data, the method will
wait (block) until data is available or a timeout occurs. The timeout value
can be set by the
SerialPort.enableReceiveTimeout(int). Asynchronously
communication is done by implementing the
SerialPortEventListener interface. This requires
implementation of the method serialEvent(SerialPortEvent
event). It is possible to specify which kind of serial events
the application wants, by using the
SerialPort.notifyOn*() methods.
When using serial ports in Java, it is very important to close the port when the class has finish using it. If the port is not closed correctly, no other application will be able to use it. In an environment where the Java Virtual Machine (JVM) is running for a long time, e.g. in an application server, forgetting to close the serial port might result in the need for a restart of the JVM (and thereby the application server) in order to release the serial port.
Installing the Sun javax.comm on Microsoft Windows has a
minor detail not described in the documentation. The file
javax.comm.properties has to be in the folder
[JavaSDK]\jre\lib - it is not enough to put it in
[JavaSDK]\lib. If your JavaSDK is in
C:\j2sdk1.4.1_01, then you have to put the
javax.comm.properties in
C:\j2sdk1.4.1_01\jre\lib.
I have included a small test application for the SMS framework, which tests the serial communication. Please note that the test requires the SMS framework - it is not just a serial test. The source can be downloaded here: TestComm.java
import dk.daimi.jones.services.sms.*;
import dk.daimi.jones.impl.sms.*;
public class Basic {
public static void main(String[] args) {
dk.daimi.jones.debug.Debugger.getDebugger().enableDebug();
SMS sms = new SMSImpl();
System.out.println("Testing SMS service...");
if (((SMSImpl)sms).open("COM1", "")) {
System.out.println("SMS service test was succesful!");
} else {
System.out.println("SMS service test FAILED!");
}
((SMSImpl)sms).close();
}
}
In this section, we describe the SMS framework in a top-down manner, i.e. we start the presentation of the framework from the application using it, then we present the SMS Interface and its implementation, and finally we present the lowest layer - the modified jSMSEngine.
Writing an application using the SMS framework is really simple. The following code shows a basic application using the SMS framework, though only initializing the framework and not doing anything interesting. The source can be downloaded here: Basic.java
import dk.daimi.jones.services.sms.*;
import dk.daimi.jones.impl.sms.*;
public class Basic {
public static void main(String[] args) {
SMS sms = new SMSImpl();
System.out.print("Starting SMS service... ");
if (((SMSImpl)sms).open("COM1", "")) {
System.out.println("Done!");
} else {
System.out.println("Failed!");
}
((SMSImpl)sms).close();
}
}
The next example of an application is retrieving information about the attached MS. The information is the manufacturer, the model, and the IMEI number, which is a unique serial number for the MS. The IMEI number is used for tracking stolen MSs. The source can be downloaded here: ShowProperties.java
import dk.daimi.jones.services.sms.*;
import dk.daimi.jones.impl.sms.*;
public class ShowProperties {
public static void main(String[] args) {
SMS sms = new SMSImpl();
System.out.print("Starting SMS service... ");
if (((SMSImpl)sms).open("COM1", "")) {
System.out.println("Done!");
System.out.println("SMS Device info:");
System.out.println("----------------");
System.out.println("Manufacturer: " + sms.getManufacturer());
System.out.println("Model.......: " + sms.getModel());
System.out.println("IMEI........: " + sms.getIMEI());
} else {
System.out.println("Failed!");
}
((SMSImpl)sms).close();
}
}
The last example given here, shows how to send an SMS. The applications sends the SMS to the (probably) fictive phone number +45 12 34 56 78. It is important to add the country code to the phone number, i.e. +45 for Denmark. The source can be downloaded here: SendSMS.java
import dk.daimi.jones.services.sms.*;
import dk.daimi.jones.impl.sms.*;
public class SendSMS {
public static void main(String[] args) {
SMS sms = new SMSImpl();
System.out.print("Starting SMS service... ");
if (((SMSImpl)sms).open("COM1", "")) {
System.out.println("Done!");
try {
sms.send(new SMSMessage("+4512345678", "Hello Phone!"));
} catch (SMSException e) {
System.out.println("Failed to send SMS");
}
} else {
System.out.println("Failed!");
}
((SMSImpl)sms).close();
}
}
It should by now be clear, that writing an application with SMS capabilities is quite simple, when using the SMS framework. In the next section we take a closer look at the SMS interface and its implementation.
The previously shown applications uses the SMS interface. We have made a general interface for specifying the minimum requirements for a simple SMS framework. The SMS interface is shown here:
public interface SMS {
public abstract void send(SMSMessage smsmessage)
throws SMSException;
public abstract void addNMIListener(NMIListener nmilistener);
public abstract void removeNMIListener(NMIListener nmilistener);
public abstract String getManufacturer();
public abstract String getModel();
public abstract String getIMEI();
}
The SMS interface does not specify anything about the communication with the MS, e.g. which serial port the MS is attached to. The implementation of the interface specifies this. The reason for this separation is, that one might want a completely different backend for an USB connected MS, where the name of the serial port is irrelevant. One would then have to write another implementation of the SMS interface, alowing the user to specify an USB port in stead of a serial port.
Most of the SMS interface is pretty self explaing, except for the
NMIListener stuff. When the SMS framework receives an
SMS, it notifies all registred NMIListeners with the received SMS. If
an application wants to receive incomming SMSs, it must register an
implementation of the NMIListener interface with
the framework. This registration is done by calling the
addNMIListener method. The following code gives an
example on using NMIListeners, and it can be downloadet here:
ReceiveSMS.java
import dk.daimi.jones.services.sms.*;
import dk.daimi.jones.impl.sms.*;
public class ReceiveSMS {
public static void main(String[] args) {
// Anonousmus class for implementing the NMIListener interface
NMIListener myNMIListener = new NMIListener() {
public void messageReceived(SMSMessage smsMessage) {
System.out.println("Received SMS from '" + smsMessage.getAddress() + "'");
System.out.println("Text: '" + smsMessage.getData() + "'");
}
};
SMS sms = new SMSImpl();
System.out.print("Starting SMS service... ");
if (((SMSImpl)sms).open("COM1", "")) {
System.out.println("Done!");
// Register reception of incomming messages with the framework
sms.addNMIListener(myNMIListener);
// Keep the application running so we can see the result
try {
while (true) {
Thread.sleep(100);
}
} catch( Exception e ) {}
} else {
System.out.println("Failed!");
}
((SMSImpl)sms).close();
}
}
The name 'NMI' is short for 'New Message Indication' and comes from the command being sent to the MS, telling it to notify the computer when messages arrive. This is described in the section New Message Indication.
SMSImpl
All the applications previously shown, cast the variable
sms to the class SMSImpl, when they open or
close the framework. The SMSImpl is the implementation of
the SMS interface, designed for using the modified jSMSEngine
(described in section
The modified jSMSEngine Package)
as backend for communication with the
MS. The SMSImpl class has the previously seen
open and close methods and of couse all
methods from the SMS interface as it is implementing this
interface. The open method takes two parameters:
port and pin. Port is the name
of the serial port to which the MS is attached. Pin is
the Pin code for the SIM card in the MS. The pin code is needed, if
the MS has been detached from the GSM network, i.e. if it has been
powered off. If the MS is a normal mobile phone, this parameter will be
given to the phone by the user, when it is powered on. If the MS is
some stationary GSM equipment, there might not be any keyboard on the
MS, so the pin has to be given through the application.
The SMSImpl is also responsible for logging SMS activity
on the console. When a class register itself as an NMIListener, a
[+] followed by the registred class is written to the
console. When a class is removed as an NMIListener, a [-]
followed by the removed class is written. Incoming messages are written
as [<] followed by phone number and text. Outgoing messages are written
with a [>] in the beginning of the line. If an error occurs, the line
starts with [E].
Besides being a wrapper for the backend jSMSEngine, the SMSImpl is
also responsible for controlling concurrent access to the MS. If
several threads are trying to send SMSs at the same time, it
would crash the framework. By controlling the access to the
send method with semaphores, the framework is threadsafe
and thereby scaleable for environment where several services are using
SMS as their communication medium.
Below the nice SMS interface and the implementation of it, is the real SMS kernel. This is based on the jSMSEngine (http://www.jsmsengine.org). It is however a modified version of the jSMSEngine. In this section we describe our modifications of the jSMSEngine, but we do not describe the jSMSEngine in total - for this we refer to the documentation for jSMSEngine.
Low level SMS communications involves quite complicated code. Most MSs exspect that the application creates a ready to send PDU containing the SMS. Creating a PDU is a lot of bitnibling and though hard to code and not very interesting. This part of the jSMSEngine is left as the author wrote it. Our modifications are on the low level serial communication layer.
As mentioned in the section Serial Communication in Java, serial communication can be synchronous or asynchronous. The same is the case for notifying a computer when an SMS is received. An MS is able to notify the computer in three ways: No notification, address in MSs memory where the message is stored, or dump the received message directly on the serial port. The original jSMSEngine used the first approach. This worked fine on one MS (Nokia 30), but not on other MSs (Sony Ericsson). Sony Ericsson phones do not allow an application to read messages from its memory. In order to use such phones (I have one myself), the last approach was necessary.
Allowing the MS to send data on the serial port whenever a message arrives, gives rise to some problems. If a command has been sent from the computer to the MS and the computer waits for an answer, an incoming SMS might be interleaved with the answer. To avoid this problem, we rewrote the serial communication module to handle incoming messages so they are not interleaved with answers given to commands.
In order to get the MS to dump incoming messages on the serial
interface, a 'New Message Indication' command (AT+CNMI)
has to be sent to the MS. The parameters for this command varies from
vendor to vendor. On a Nokia 30 MS, the full command is
AT+CNMI=1,2,0,0,0 but on a Sony Ericsson MS the command
is AT+CNMI=3,3,0,0,0. The two very different parameters,
makes the MSs behave in the required way. Because different vendors
accept so different parameters, we wrote code for querying the MS for
its NMI capabilities and from that information setting the parameters
correct to get the MS to dump messages immediatly.
The last modification to the jSMSEngine was to limit its external functionality. It has an XML based phonebook, which requires access to writing files to the disc. This is not always allowed and it gave rise to more problems than it helped. This part has been removed.
In order to troubleshout the communication with the MS, I have made a debugging feature available. This feature is used in the TestComm.java test application. All you have to do to get the debugging information from the framework, it to add the following line of code to your application before you start using the framework:
dk.daimi.jones.debug.Debugger.getDebugger().enableDebug();
You can also use the debugging functionality in you own code. In stead
of using System.out.println(...) when you want to display
debugging information, you can use my Debugger-class. The interface is
displayed here (details are available in the
Debugger.java
file):
public final class Debugger {
/* Returns (singleton) Debugger for this process. */
public static Debugger getDebugger();
public void enableDebug();
public void disableDebug();
public void debug(String s);
}
The following code illustrates how to use the debugging functionality:
ímport dk.daimi.jones.debug;
...
Debugger myDebug = dk.daimi.jones.debug.Debugger.getDebugger();
...
myDebug.debug("Debugging text is only visible if debugging is enabled");
Open Sound Control (OSC - http://cnmat.cnmat.berkeley.edu/OSC/ is a relatively new protocol exspected to replace the elderly Musical Instrument Digital Interface (MIDI) standard. OSC is based on UDP packets being sent between Internet attached devices. An UDP packet can contain up to 64 KB in theory, but should not exceed 8 KB i praxis. The idea of using UDP for sending information between musical instruments in this way is fine - it allows instruments to communicate over the Internet. On the other hand might it be a problem, because UDP packets might get lost in transit. There are no upper bound for the time taken to transmit an UDP packet, which might be a problem if the protocol is going to be used to synchronize instruments.
The OSC protocol exits in two versions: With basic type tags and with aditional type tags. Type tags are symbols representing the type of some data i the packet. The problem is, that with basic type tags, the symbol 's' means a string but with additional type tags, 'S' is a string and 's' means a symbol. This is a very bad design giving rise to a lot of problems, when finding out what data is included in the packet.
We have used a half-written library called Java OSC (http://www.mat.ucsb.edu/%7Ec.ramakr/illposed/javaosc.html). This labrary allows us to send OSC messages, but not to receive. The library is actually not a library, but an application, so we have 'converted' it to a library.
The final application is based on the previously described components: The SMS framework and the Java OSC library. When combining the two by making an NMIListener that sends an OSC message to a specified host, containing the received SMS, we have an SMS-to-OSC application. It is really that easy!
The SMS2OSC NMIListener is shown below, and it can be downloade here: SMS2osc.java
import dk.daimi.jones.services.sms.*;
import com.illposed.osc.*;
import java.net.*;
public class SMS2osc implements NMIListener {
private static OscPort oscPort = null;
private static String oscMessageText = "/sms";
public SMS2osc(String portName, int portNumber) {
try {
System.out.print("Setting OSC port to " + portName + ":" + portNumber + "... ");
oscPort = new OscPort(InetAddress.getByName(portName), portNumber);
System.out.println("Done!");
} catch (Exception e) {
System.out.println("Failed!");
oscPort = null;
}
}
public void messageReceived(SMSMessage smsMessage) {
String from = smsMessage.getAddress();
String message = smsMessage.getData();
if (oscPort != null) {
Object[] oscArgs = {from, message};
OscSuperColliderMessage msg = new OscSuperColliderMessage(oscMessageText, oscArgs);
try {
oscPort.send(msg);
} catch (Exception e) {
System.out.println("Could not send OSC message:\n" + e.getMessage());
e.printStackTrace();
}
}
}
}
The main application for running the SMS-to-OSC service is shown below, and the source can be downloaded here: SMSServer.java
import dk.daimi.jones.services.sms.*;
import dk.daimi.jones.impl.sms.*;
public class SMSServer {
private static SMS sms;
public static SMS getSMS() {
return sms;
}
public SMSServer () throws Exception {
System.out.print("Creating SMS service... ");
sms = new SMSImpl();
if (sms == null) {
System.out.println("Failed!");
throw new Exception("Failed to create SMS service!");
} else {
System.out.println("Done!");
}
System.out.print("Starting SMS service... ");
if (((SMSImpl)sms).open("COM1", "")) {
System.out.println("Done!");
} else {
System.out.println("Failed!");
throw new Exception("Failed to start SMS service!");
}
}
public static void main(String args[]) {
String portName = "";
int portNumber = 0;
if (args.length >= 2) {
portName = args[0];
portNumber = Integer.parseInt(args[1]);
} else {
System.out.println("Usage: SMSServer ");
System.exit(1);
}
try {
new SMSServer();
} catch( Exception e ) {
System.exit(2);
}
SMS2osc sms2osc = new SMS2osc(portName, portNumber);
SMSServer.getSMS().addNMIListener(sms2osc);
try {
while (true) {
Thread.sleep(100);
}
} catch( Exception e ) {
e.printStackTrace();
}
}
}
The SMS framework has been tested with to following MSs:
Throughout this paper we refer to external documents. In this section we give some additional references.
Communication with an MS through a serial interface is done by the Extended AT Command Set. This is documented in the GSM specification, but the different vendors have their own interpretation. The following are downloaded for your convenience:
The source code for the entire project can be downloaded here: