|
// Generated by P Bennett: Monday, 4 October 1999 at: 05:24:32 pm
|
|
// Com Port Handler.
|
|
// I have released this code as a guide only.
|
|
// It will not run without the supporting classes.
|
|
// It was origanally written to communicate with a development prototype
|
|
// and runs under Slackware Linux Version 4 with Blackdown jdk1.1.7_v3
|
|
// Green Threads and rxtx version 3.4 with Java Comms API V2.0
|
|
// This thread is controlled by a thread that implements a queue
|
|
// and methods for controlling the queue and allocating the resources (modems)
|
|
// The modem used for development was a Siemens M20 Cellular modem.
|
|
// The remote equipment dumped its data upon connection and then hangs up.
|
|
// The protocol has changed somewhat now. (A Subset of HDLC)
|
|
// I have added extra comments for your benefit.
|
|
// It is free to use.
|
|
// Just a quick note. I have no formal training therefor the programming techniques
|
|
// may not be the best ones to use. However the technique I use has been developed
|
|
// through experience and it seems to work for me.
|
|
|
|
import java.util.*;
|
|
import java.io.*;
|
|
import gnu.io.*; //Comms Extensions
|
|
|
|
/** Class To Talk To A GSM Cellular Modem, Dial an SNU and retrieve the data.
|
|
* Uses Java Comm API 2.0
|
|
* @author P Bennett
|
|
* @version 1.0
|
|
* @see SNServerIO
|
|
* @see SNComThread
|
|
*/
|
|
|
|
public class SNComHandler extends java.lang.Thread implements
|
|
SerialPortEventListener {
|
|
|
|
private static SNComThread comThread; // A reference back to the parent.
|
|
private static SNLogger comLog; // Log handler
|
|
private static SNConfig serverConfig; // Server Configuration object
|
|
private String comName = "Nil"; // The com port name to use as in /dev/ttyS0
|
|
private boolean process = false; // Process a request
|
|
private String requestId = "Nil"; // Request ID
|
|
private String num = "Nil"; // The phone number to dial
|
|
private boolean running = true; // Make it go around
|
|
private CommPortIdentifier portId; // Port Identifier
|
|
private SerialPort serialPort = null; // Serial Port object
|
|
private OutputStream outputStream = null; // The streams
|
|
private InputStream inputStream = null;
|
|
private String errMessage = ""; // An error message
|
|
private boolean fatalErr = false; // Big problems call the emergency team :-(
|
|
private boolean waitForInput = true; // Wait for incoming data
|
|
|
|
/** Construct a new SNComHandler Object..
|
|
* For initialising the array of Com Handlers.
|
|
* @see SNComThread
|
|
*/
|
|
public SNComHandler() {
|
|
}
|
|
|
|
/** Construct a new SNComHandler Object.
|
|
* Created with the following parameters.
|
|
* @param cThread The parent thread.
|
|
* @param sLog The Logging object.
|
|
* @param sConfig The server config object.
|
|
* @param cName The Com Port name eg. /dev/ttyS0
|
|
* @see SNLogger
|
|
* @see SNConfig
|
|
*/
|
|
public SNComHandler(SNComThread cThread, SNLogger sLog, SNConfig
|
|
sConfig, String cName) throws NoSuchPortException {
|
|
this.comThread = cThread; // Parent thread
|
|
this.comLog = sLog; // Log object
|
|
this.serverConfig = sConfig; // Config object
|
|
this.comName = cName; // The com port name
|
|
portId =
|
|
(CommPortIdentifier)CommPortIdentifier.getPortIdentifier(this.comName);
|
|
// Set up the ID
|
|
this.comLog.log("Com Handler Initialised For " + comName); // Log start
|
|
}
|
|
|
|
/** Thread run method
|
|
* Call unit num, when requested and
|
|
* pass the recieved data back to
|
|
* the parent thread que.
|
|
*/
|
|
public void run() {
|
|
// comLog.debugInfo("Com Handler Run Method Started For " + comName);
|
|
int resetCount = 0; // Reset attempts
|
|
int resetCount2 = 0; // And again. There must be a better way
|
|
int resetCount3 = 0; // And again. of doing this!!!! They are all the same.
|
|
while (running) { // While we are doin it.
|
|
if (fatalErr) { // Big problems
|
|
comThread.queRequest(requestId, errMessage, "Error"); // Tell the parent
|
|
comLog.log(errMessage + " " + comName + " " + num); // Tell everyone
|
|
num = "Nil"; // Reset some variables
|
|
resetCount = 0; // The error resets process
|
|
resetCount2 = 0; // Round we go again.
|
|
resetCount3 = 0;
|
|
fatalErr = false;
|
|
}
|
|
if (!process) { // Nothing to do
|
|
try {
|
|
Thread.sleep(500); // Have a sleep
|
|
} catch (InterruptedException e) {}
|
|
continue; // Round we go again.
|
|
}
|
|
comLog.debugInfo("**********We Are Processing***********");
|
|
if (num.equals("Nil")) { // Can't dial Nil!
|
|
try { // Just a catch never tested
|
|
Thread.sleep(500); // Have a sleep
|
|
} catch (InterruptedException e) {} // Prolly does not work as intended
|
|
continue; // Round we go again.
|
|
}
|
|
comLog.debugInfo("**********Trying To Open Port***********");
|
|
if (!openPort()) { // Try to open port
|
|
closePort(); // Try to close it then
|
|
try {
|
|
Thread.sleep(500); // Have a sleep
|
|
} catch (InterruptedException e) {}
|
|
resetCount ++; // Up the counter
|
|
//***************** 3 goes in serverconfig ************************8
|
|
if (resetCount > 3) { // Check the counter
|
|
process = false; // We got problems
|
|
errMessage = "Error! Could Not Open Port";
|
|
fatalErr = true; // We got big problems
|
|
}
|
|
continue; // Round we go to sort it out
|
|
}
|
|
comLog.debugInfo("**********Trying To Reset Modem***********");
|
|
if (!reset()) { // We got the port now reset the modem
|
|
try {
|
|
Thread.sleep(500); // Have a sleep
|
|
} catch (InterruptedException e) {}
|
|
resetCount2 ++; // Up the counter
|
|
//***************** 3 goes in serverconfig ************************8
|
|
if (resetCount2 > 3) { // Check the counter
|
|
process = false; // We got problems
|
|
errMessage = "Error! Could Not Reset Modem";
|
|
fatalErr = true; // We got big problems
|
|
}
|
|
continue; // Round we go to sort it out
|
|
}
|
|
comLog.debugInfo("**********Trying To Dial***********");
|
|
if (!dial()) { // The modem reset OK now dial
|
|
comLog.debugInfo("**********" + errMessage + "***********");
|
|
try {
|
|
Thread.sleep(500); // Have a sleep
|
|
} catch (InterruptedException e) {}
|
|
resetCount3 ++; // Up the count
|
|
//***************** 3 goes in serverconfig ************************8
|
|
if (resetCount3 > 2) { // Check the count
|
|
process = false; // We got problems
|
|
errMessage = "Error! Could Not Dial";
|
|
fatalErr = true; // We got big problems
|
|
}
|
|
continue; // Round we go to sort it out
|
|
}
|
|
int numBytes = 0; // Number of bytes read from input
|
|
byte[] readBuffer = new byte[20]; // Tmp Read buffer of 20 bytes
|
|
String sReadBuff = ""; // Read Buffer
|
|
boolean dLoop = true; // Loop
|
|
while (dLoop) { // Wait for incoming data
|
|
try {
|
|
while (inputStream.available() > 0) { // While there is something to read
|
|
numBytes = inputStream.read(readBuffer); // Get the bytes
|
|
String tmpR = new String(readBuffer); // Set up a string
|
|
sReadBuff += tmpR.substring(0, numBytes); // Add to read buffer
|
|
}
|
|
} catch (IOException e) {
|
|
dLoop = false; // Problems
|
|
process = false; // This has never occured
|
|
}
|
|
if (sReadBuff.indexOf("NO CARRIER") != -1) { // Test incoming data
|
|
errMessage = ""; // Unit hangs up once it
|
|
dLoop = false; // dumps its data
|
|
} else if (sReadBuff.indexOf("ERROR") != -1) { // Check for error
|
|
errMessage = "Error! Recieved Data Not Clean " + num + " " + comName;
|
|
dLoop = false;
|
|
} else if (sReadBuff.length() > 5000) { // Check for receive runnaway
|
|
errMessage = "";
|
|
dLoop = false;
|
|
}
|
|
}
|
|
if (errMessage.equals("")) { // No error occured
|
|
comThread.queRequest(requestId, sReadBuff, "Ready"); // Tell the parent the result
|
|
comLog.log("Data Recieved " + " " + requestId + " " + num); // Log it
|
|
System.out.println("*********" + sReadBuff + "*********"); // Raw Debug code
|
|
} else {
|
|
if (!fatalErr) { // Error
|
|
comThread.queRequest(requestId, errMessage, "Error"); // Tell parent
|
|
comLog.log(errMessage + " " + comName + " " + num); // Log
|
|
System.out.println("*********" + errMessage + "*********"); // Raw debug
|
|
}
|
|
}
|
|
closePort(); // Close the port
|
|
resetCount = 0; // Reset the variables ready for next request
|
|
resetCount2 = 0;
|
|
resetCount3 = 0;
|
|
num = "Nil";
|
|
process = false;
|
|
}
|
|
}
|
|
|
|
/** Open Com Port
|
|
* @return true if succesfull
|
|
*/
|
|
private boolean openPort() {
|
|
if (serialPort == null) { // Set up serial port object if need be
|
|
comLog.debugInfo("**********Open Port Routine***********");
|
|
try {
|
|
serialPort = (SerialPort) portId.open("SimpleReadApp", 2000); // Open serial port
|
|
comLog.debugInfo("**********Port Open***********");
|
|
} catch (PortInUseException e) {
|
|
return false; // Hmm its in use
|
|
}
|
|
if (inputStream == null) { // Set up the input stream if need be
|
|
try {
|
|
inputStream = serialPort.getInputStream(); // Get the stream
|
|
} catch (IOException e) {
|
|
return false;
|
|
}
|
|
}
|
|
if (outputStream == null) { // Set up the output stream if need be
|
|
try {
|
|
outputStream = serialPort.getOutputStream(); // Get the stream
|
|
} catch (IOException e) {
|
|
return false;
|
|
}
|
|
}
|
|
try {
|
|
serialPort.addEventListener(this); // Add the event listener
|
|
} catch (TooManyListenersException e) {
|
|
return false;
|
|
}
|
|
serialPort.notifyOnDataAvailable(true); // Set the port to notify on incoming data
|
|
//********* Maybe this goes in serverconfig maybe on a per port basis
|
|
// Set the port parameters
|
|
try {
|
|
serialPort.setSerialPortParams(19200, SerialPort.DATABITS_8,
|
|
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
|
|
} catch (UnsupportedCommOperationException e) {
|
|
return false;
|
|
}
|
|
}
|
|
return true; // Everything went ok
|
|
}
|
|
|
|
/** Close Com Port. */
|
|
|
|
private void closePort() {
|
|
if (serialPort != null) { // Check that the serial port is not null
|
|
serialPort.notifyOnDataAvailable(false); // Close down notification
|
|
serialPort.removeEventListener(); // Remove the event listener
|
|
if (inputStream != null) { // Check for null
|
|
try {
|
|
inputStream.close(); // Close it
|
|
inputStream = null; // Clean up
|
|
}
|
|
catch (IOException e) {}
|
|
}
|
|
if (outputStream != null) { // Check for null
|
|
try {
|
|
outputStream.close(); // Close it
|
|
outputStream = null; // Clean up
|
|
}
|
|
catch (IOException e) {}
|
|
}
|
|
serialPort.close(); // Close the serial port
|
|
serialPort = null; // Clean up
|
|
}
|
|
}
|
|
|
|
/** Reset The Modem
|
|
* @return true if succesfull.
|
|
*/
|
|
private boolean reset() {
|
|
try {
|
|
outputStream.write(new String("atz").getBytes()); // Send the modem atz
|
|
outputStream.write((byte)0x0D); // And the other stuff
|
|
outputStream.write((byte)0x0A); // <CR> <LF>
|
|
} catch (IOException e) {
|
|
return false;
|
|
}
|
|
int waitingCount = 0; // Heres another counter
|
|
waitForInput = true; // We are waiting
|
|
while (waitForInput) { // Yes we are
|
|
try {
|
|
Thread.sleep(100); // We have a little rest
|
|
} catch (InterruptedException e) {}
|
|
waitingCount ++; // We count
|
|
//***************** 20 goes in serverconfig ************************
|
|
if (waitingCount > 20) { // We have counted to much
|
|
return false; // Could not reset
|
|
}
|
|
}
|
|
int numBytes = 0; // Set up number of bytes read
|
|
byte[] readBuffer = new byte[20]; // And a buffer
|
|
String sReadBuff = ""; // And another buffer
|
|
try {
|
|
while (inputStream.available() > 0) {
|
|
numBytes = inputStream.read(readBuffer); // Read from the port
|
|
String tmpR = new String(readBuffer);
|
|
sReadBuff += tmpR.substring(0, numBytes);
|
|
}
|
|
} catch (IOException e) {
|
|
return false;
|
|
}
|
|
//********************Maybe for serverconfig
|
|
if (sReadBuff.indexOf("OK") != -1) { // Test for OK response from modem
|
|
try {
|
|
Thread.sleep(1000); // We have another sleep to allow things
|
|
} catch (InterruptedException e) {} // to settle
|
|
return true;
|
|
}
|
|
return false; // We did not reset OK
|
|
}
|
|
|
|
/** Dial number requested
|
|
* @return true if connected
|
|
*/
|
|
private boolean dial() {
|
|
try {
|
|
comLog.debugInfo("**********" + num + "***********");
|
|
outputStream.write(new String("atd").getBytes()); // Send atd
|
|
outputStream.write(num.getBytes()); // And the number
|
|
outputStream.write((byte)0x0D); // And the other stuff
|
|
outputStream.write((byte)0x0A);
|
|
} catch (IOException e) {
|
|
errMessage = "Error! Could Not Write To Port ";
|
|
comLog.debugInfo("**********Error Writing***********");
|
|
return false; // Bad could not write
|
|
}
|
|
int waitingCount = 0; // We are counting again
|
|
waitForInput = true; // Waiting
|
|
while (waitForInput) {
|
|
try {
|
|
Thread.sleep(100); // Have a sleep
|
|
} catch (InterruptedException e) {}
|
|
waitingCount ++; // Counting
|
|
//**************** For serverconfig ************************
|
|
if (waitingCount > 200) { // Counted to much
|
|
errMessage = "Error! Timed Out Waiting For Response";
|
|
return false; // Timed out
|
|
}
|
|
}
|
|
int numBytes = 0; // Set up for reading
|
|
byte[] readBuffer = new byte[20]; // Youve seen it before
|
|
String sReadBuff = ""; // The comments are getting thinner
|
|
boolean dLoop = true; // No need to repeat
|
|
while (dLoop) {
|
|
try {
|
|
while (inputStream.available() > 0) {
|
|
numBytes = inputStream.read(readBuffer);
|
|
String tmpR = new String(readBuffer);
|
|
sReadBuff += tmpR.substring(0, numBytes); // We read it
|
|
}
|
|
if (sReadBuff.indexOf("NO CARRIER") != -1) { // Out of area
|
|
errMessage = "Error! No Carrier";
|
|
return false;
|
|
} else if (sReadBuff.indexOf("BUSY") != -1) { // Busy
|
|
errMessage = "Error! Busy"; // Who is ringing our units
|
|
return false; // Maybe it is dialing out
|
|
} else if (sReadBuff.indexOf("NO DIAL TONE") != -1) { // Bad no signal
|
|
errMessage = "Error! No Dial Tone"; // Were has the ariel gone
|
|
return false;
|
|
} else if (sReadBuff.indexOf("OK") != -1) { // Hmm voice call no good
|
|
errMessage = "Error! Voice Call";
|
|
return false;
|
|
} else if (sReadBuff.indexOf("CONNECT") != -1) { // Ah this is what we want
|
|
return true; // Return true
|
|
}
|
|
} catch (IOException e) {
|
|
errMessage = "Error! Could Not Read From Com Port";
|
|
return false; // Bad but never happened yet
|
|
}
|
|
}
|
|
errMessage = "Error! Invalid Data " + sReadBuff;
|
|
return false; // Something has gone wrong
|
|
}
|
|
|
|
/** Serial Event Routine
|
|
* Set waitForInput to false when data ready
|
|
*/
|
|
public void serialEvent(SerialPortEvent event) {
|
|
switch(event.getEventType()) {
|
|
case SerialPortEvent.BI:
|
|
case SerialPortEvent.OE:
|
|
case SerialPortEvent.FE:
|
|
case SerialPortEvent.PE:
|
|
case SerialPortEvent.CD:
|
|
case SerialPortEvent.CTS:
|
|
case SerialPortEvent.DSR:
|
|
case SerialPortEvent.RI:
|
|
case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
|
|
break;
|
|
case SerialPortEvent.DATA_AVAILABLE:
|
|
waitForInput = false; // We got incoming
|
|
break; // Thats it for serial events
|
|
}
|
|
}
|
|
|
|
/** Process Request To Call SNU.
|
|
* Request that a call be made and the data
|
|
* returned to the controlling thread.
|
|
* @see SNComThread
|
|
*/
|
|
public void processRequest(String req, String num) {
|
|
requestId = req; // Set ID
|
|
this.num = num; // Set the phone number
|
|
process = true; // Make it go
|
|
}
|
|
|
|
/** Is Processing Call
|
|
* @return true if thread is busy
|
|
* @see SNComThread
|
|
*/
|
|
public boolean isProcessing() {
|
|
return process; // Are you busy
|
|
}
|
|
|
|
/** Is Processing This Q Id.
|
|
* @param qID The ID to test for
|
|
* @return true if the thread is processing qID
|
|
* @see SNComThread
|
|
*/
|
|
public boolean isProcessing(String qID) {
|
|
return requestId.equals(qID); // Are you busy doing this job
|
|
}
|
|
}
|
|
/* the following was added so the code will compile. Its not proper */
|
|
class SNLogger
|
|
{
|
|
public void debugInfo(java.lang.String it)
|
|
{
|
|
}
|
|
public void log(java.lang.String it)
|
|
{
|
|
}
|
|
}
|
|
class SNComThread
|
|
{
|
|
public void queRequest(java.lang.String a, java.lang.String b, java.lang.String c)
|
|
{
|
|
}
|
|
}
|
|
class SNConfig
|
|
{
|
|
}
|