// 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 javax.comm.*; //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); // } 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 { }