Negli articoli precedenti abbiamo analizzato alcune delle tematiche più importanti relative agli short message, ora in quest‘ultimo articolo analizzeremo alcuni aspetti fondamentali per scrivere un piccolo programma Java che consenta di comunicare con un modem GSM e che potrà essere ampliato e sviluppato fino a consentire l‘invio e la ricezione di messaggi.
Aspetti generali
Una volta compresi gli aspetti generali relativi alla messaggistica via SMS, in questo articolo verranno analizzati i passi necessari per scrivere un piccolo programma Java che consenta di comunicare con un modem GSM e di inviare e ricevere messaggi. Il programma sfrutta le JavaComm in quanto è necessario stabilire la comunicazione con il modem tramite una porta COM. Per prima cosa è necessario, quindi, installare le librerie JavaComm.
Installazione libreria
Il primo passo è quello di scaricare dal sito www.javasoft.com la libreria Java per la comunicazione con la porta COM. Esistono diverse implementazioni, ciascuna utilizzabile per un particolare sistema operativo; è necessario, quindi, scaricare quella compatibile con quello da voi utilizzato.
Le prove fatte in questo articolo si riferiscono al sistema operativo Windows XP.
Una volta fatto il download, è necessario installare la libreria. L‘installazione avviene in maniera manuale ed è necessario copiare alcuni file in opportune cartelle. E‘ importante individuare, nel caso in cui siano installate diverse versioni di Java, la java_home in modo che le librerie vengano caricate correttamente.
Insieme al pacchetto scaricato esistono alcuni programmi di test che consentono di verificare se l‘installazione è stata fatta correttamente. La procedura di installazione è piuttosto semplice e molto ben spiegata nel tutorial allegato alla libreria.
Il diagramma delle classi
Una volta installata la libreria JavaComm passiamo ad analizzare le classi necessarie per realizzare il semplice driver che consente di comunicare con il modem GSM. Qui di seguito è riportato il diagramma delle classi che illustra le relazioni esistenti fra le singole classi che compongono il driver.
Figura 1 – Diagramma delle classi
Il cuore del sistema è rappresentato dalla classe ModemConnection che si occupa di gestire i dettagli della comunicazione con il modem, tale classe implementa un‘interfaccia chiamata IModemConnection.
La classe ModemConnectionFactory ha il compito di creare una istanza valida di una classe che gestisce la comunicazione con il modem e che implementa l‘interfaccia IModemConnection.
Nel caso in esame abbiamo una sola implementazione dell‘interfaccia IModemConnection ma in casi più complessi potrebbe essere necessario avere a disposizione diverse implementazioni.
Le altre classi hanno un ruolo marginale nel driver e quindi non verranno analizzate nel resto di questo articolo.
La classe ModemConnection
Questa classe come detto è il cuore dell‘intero sistema e si occupa di gestire la comunicazione con la porta COM. La classe implementa tre metodi che derivano dalla interfaccia IModemConnection:
- public void configure(ConfigInfo config): Questo metodo serve per passare a tale classe i dettagli della connessione. La classe ConfigInfo ingloba tutti i parametri relativi alla configurazione della porta ed il nome della porta stessa. Questa classe può essere estesa in modo da contenere altri parametri di configurazione che potrebbe risultare utili.
- public void connect(): Questo metodo effettua la connessione vera e propria utilizzando i parametri ricevuti nella fase di configurazione
- public void sendCommand(String cmd): Questo metodo è utilizzato per inviare un comando al modem, vedremo più avanti come utilizzarlo.
Concentriamo ora la nostra attenzione sul metodo connect() che, come detto, consente di effettuare la connessione con la porta COM.
Riportiamo qui di seguito alcune linee di codice che rivestono una particolare importanza per comprendere come si deve agire per comunicare con la porta COM:
comId = CommPortIdentifier.getPortIdentifier(config.getPort());
if (comId.getPortType()
!= CommPortIdentifier.PORT_SERIAL){
// do something
}
Nella prima linea di codice si identifica la porta su cui connettersi in base alla configurazione ricevuta, successivamente si verifica che la porta sia una porta seriale, se così non fosse viene lanciata una eccezione (// do something) del tipo ModemConnectionException.
Successivamente, si ottengono l‘InputStream e l‘OutputStream tramite i quali è possibile leggere e scrivere.
serialPort = (SerialPort)comId.open(getClass().toString(), 60);
is = serialPort.getInputStream();
os = serialPort.getOutputStream();
A questo punto si configura la porta (è ovviamente possibile cambiare i parametri di configurazione in funzione delle caratteristiche della porta COM utilizzata):
serialPort.setSerialPortParams(config.getBitRate(),SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
Si attiva la notifica quando sono disponibili dati da leggere:
serialPort.notifyOnDataAvailable(true);
ed infine si dichiara che la classe ModemConnection è il listener per gli eventi della connessione.
serialPort.addEventListener(this);
È evidente che molti di questi metodi utilizzati lanciano delle eccezione che verranno catturate e trasformate in ModemConnectionException in modo da isolare il client che utilizza il driver da tali eccezioni e dai dettagli dell‘implementazione.
Ricezione degli eventi della porta COM
La porta COM invia degli eventi che è necessario gestire per il corretto funzionamento del driver. Nel paragrafo precedente abbiamo detto che tramite:
serialPort.addEventListener(this);
abbiamo dichiarato che la classe ModemConnection è il listener per tali eventi. Affinchè tutto funzioni correttamente è necessario che tale classe implementi l‘interfaccia SerialPortEventListener e che quindi implementi il metodo:
public void serialEvent(SerialPortEvent serialPortEvent)
In questo metodo dovranno essere gestiti tutti gli eventi che la porta può inviarci ed in particolare l‘evento che ci informa che sono disponibili dati da leggere.
Tramite
if (serialPortEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE)
controlliamo che l‘evento sia quello che stiamo aspettando. In caso positivo allora iniziamo a leggere dalla porta fino a quando il carattere letto ha un valore decimale pari a 13 (il ritorno a capo).
Qui di seguito sono riportate alcune linee di codice che si occupano proprio di leggere i dati dalla seriale:
while( (count = is.read(b)) > 0) {
bais = new ByteArrayInputStream(b, 0, count);
while (bais.available() > 0) {
char c = (char) bais.read();
if (c == 13) {
buffer.append(c);
String line = buffer.toString().trim();
if(!line.equals("")) {
Utils.log("Line ["+line+"]");
// Notificare l‘evento
}
buffer.setLength(0);
}
else
buffer.append(c);
}
}
Con queste semplici righe non facciamo altro che leggere i dati. In questo caso una volta raggiunto il ‘ritorno a capo‘ stampiamo a video la riga letta.
Si potrebbe fare molto di più come per esempio notificare l‘evento al client ,che dovrebbe implementare un‘opportuna interfaccia per ricevere gli eventi che noi intendiamo notificare; in questo modo riusciamo ad informare il client quando arriva per esempio un nuovo SMS.
Il Client
L‘applicazione client per prima cosa crea una istanza della classe ConfigInfo contenente tutti i parametri di configurazione:
ConfigInfo config = new ConfigInfo();
config.setPort("COM15");
config.setBitRate(9600);
Successivamente:
IModemConnection connection = ModemConnectionFactory.getInstance().getConnection();
connection.configure(config);
connection.connect();
connection.sendCommand("AT");
connection.sendCommand("AT+CSQ");
connection.sendCommand("AT+CMGL");
Tramite questa sequenza di linee di codice il client per prima cosa ottiene una istanza valida della classe che gestisce la connessione verso il modem e successivamente configura i parametri di connessione. A questo punto, una volta configurata la connessione, il client inizia ad inviare i comandi al modem. Nella sequenza sopra riportata il client ottiene la lista dei messaggi presenti nella SIM. Ampliando e modificando alcune parti sopra riportate si può semplicemente inviare un SMS ad un altro numero telefonico, utilizzando i comandi illustrati nell‘articolo precedente.
Conclusioni
In questo articolo abbiamo analizzato le linee guida per scrivere un piccolo programma Java che comunichi con la porta COM. È evidente che quanto sopra riportato è un prototipo che dovrà essere ampliato e sviluppato affinchà© risulti effettivamente utile.
In particolare un aspetto importante è stato tralasciato: la codifica e decodifica dei messaggi. Applicando le regole descritte nell‘articolo precedente è possibile codificare e decodificare qualsiasi tipo di messaggio. A tale proposito nell‘articolo JavaComm e GSM del numero 66 di Mokabyte si possono trovare alcuni spunti interessanti per quanto riguarda alcune linee guida per la codifica e decodifica dei messaggi.
Riferimenti
[1] JavaComm e GSM – Mokabyte nð 66
[2] www.javasoft.com