Java tutorial
//@formatter:off /* programm: SubmatixSPXLog purpose: configuration and read logs from SUBMATIX SPX42 divecomputer via Bluethooth Copyright (C) 2012 Dirk Marciniak This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/ */ //@formatter:on package de.dmarcini.submatix.pclogger.comm; import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.sql.SQLException; import java.util.ArrayList; import java.util.regex.Pattern; import org.apache.log4j.Logger; import org.joda.time.DateTime; import de.dmarcini.submatix.pclogger.res.ProjectConst; import de.dmarcini.submatix.pclogger.utils.LogDerbyDatabaseUtil; import de.dmarcini.submatix.pclogger.utils.SPX42Config; import de.dmarcini.submatix.pclogger.utils.SPX42GasList; import de.dmarcini.submatix.pclogger.utils.SpxPcloggerProgramConfig; /** * Klasse zur direkten Kommunikation mit dem BT-Device Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 08.01.2012 */ //@formatter:off public class BTCommunication implements IBTCommunication { @SuppressWarnings("javadoc") public static final int CONFIG_WRITE_KDO_COUNT = 4; @SuppressWarnings("javadoc") public static final int CONFIG_READ_KDO_COUNT = 7; // bersichtlicher machen mit Objekt fr alle static Logger lg = null; private LogDerbyDatabaseUtil dbUtil = null; private volatile boolean isConnected = false; private ActionListener aListener = null; private WriterRunnable writer = null; private ReaderRunnable reader = null; private AliveTask alive = null; private String connectedVirtualDevice = null; private SerialPort serialPort = null; private int writeWatchDog = -1; protected String url; @SuppressWarnings("unused") private static final Pattern fieldPattern0x09 = Pattern.compile(ProjectConst.LOGSELECTOR); private static final Pattern fieldPatternDp = Pattern.compile(":"); //@formatter:on /** * Lokale Klasse, Thread zum Schreiben auf Device Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 11.01.2012 */ //@formatter:off public class WriterRunnable implements Runnable { private OutputStream outStream = null; private boolean running = false; private final ArrayList<String> writeList = new ArrayList<String>(); //@formatter:on /** * Konstruktor des Schreibthreads erstellt: 22.08.2013 * * @param outStr */ public WriterRunnable(OutputStream outStr) { outStream = outStr; } @Override public void run() { // solange was auszugeben ist, mach ich das... lg.debug("start writer thread..."); writeList.clear(); this.running = true; while (this.running == true) { // syncronisiete Methode aufrufen, damit wait und notify machbar sind wtSync(); } lg.debug("stop writer thread..."); isConnected = false; try { outStream.close(); } catch (IOException ex) { } if (aListener != null) { ActionEvent ev = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ev); } } /** * Zeilenweise an SPX schreiben, wenn nix zu tun ist schlafen legen Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 11.01.2012 */ private synchronized void wtSync() { if (writeList.isEmpty() || outStream == null) { // ist die Liste leer, mach nix, einfach relaxen try { Thread.yield(); wait(20); } catch (InterruptedException ex) { } } else { // ich gebe einen Eintrag aus... try { // Watchdog fr Schreiben aktivieren writeWatchDog = ProjectConst.WATCHDOG_FOR_WRITEOPS; // also den String Eintrag in den Outstream... outStream.write((writeList.remove(0)).getBytes()); // kommt das an, den Watchog wieder AUS writeWatchDog = -1; // zwischen den Kommandos etwas warten, der SPX braucht etwas bis er wieder zuhrt... // das gibt dem Swing-Thread etwas Gelegenheit zum Zeichnen oder irgendwas anderem for (int factor = 0; factor < 5; factor++) { Thread.yield(); Thread.sleep(80); } } catch (IndexOutOfBoundsException ex) { isConnected = false; if (aListener != null) { ActionEvent ev = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ev); } running = false; return; } catch (IOException ex) { isConnected = false; if (aListener != null) { ActionEvent ev = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ev); } running = false; return; } catch (InterruptedException ex) { } } } /** * Terminieren lassen geht hier Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 11.01.2012 */ public synchronized void doTeminate() { notifyAll(); this.running = false; try { Thread.sleep(300); outStream.close(); } catch (InterruptedException ex) { lg.error("exception while Thread.sleep (" + ex.getLocalizedMessage() + ")"); } catch (IOException ex) { lg.error("exception while closing outstream (" + ex.getLocalizedMessage() + ")"); } } /** * Schreibe zum SPX Daten Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 11.01.2012 * @param msg */ public synchronized void writeToDevice(String msg) { writeList.add(msg); notifyAll(); } } /** * Lokale Klasse zum lesen vom SPX42 Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 11.01.2012 */ //@formatter:off public class ReaderRunnable implements Runnable { private final byte[] buffer = new byte[1024]; private InputStream inStream = null; private boolean running = false; private volatile boolean isLogentryMode = false; private final StringBuffer mInStrBuffer = new StringBuffer(1024); //@formatter:on /** * Konstruktor des Lesethreads erstellt: 22.08.2013 * * @param inStr */ public ReaderRunnable(InputStream inStr) { inStream = inStr; } @Override public void run() { int bytes = 0; String readMessage = ""; int start, end, lstart, lend; boolean logCmd, normalCmd; // solange was auszugeben ist, mach ich das... lg.debug("start reader thread..."); this.running = true; while (this.running == true) { try { bytes = inStream.read(buffer); if (bytes == -1) { // Verbindung beendet/verloren isConnected = false; lg.error("reader connection lost..."); if (aListener != null) { ActionEvent ev = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ev); } running = false; return; } readMessage = new String(buffer, 0, bytes); } catch (IOException ex) { // IO Fehler isConnected = false; lg.error("reader connection lost (" + ex.getLocalizedMessage() + ")..."); if (aListener != null) { ActionEvent ev = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ev); } running = false; return; } // // was mach ich jetzt mit dem empfangenen Zeuch? // // Puffer auffllen, wenn noch Platz ist if ((mInStrBuffer.capacity() + readMessage.length()) > ProjectConst.MAXINBUFFER) { isConnected = false; lg.error("INPUT BUFFER OVERFLOW!"); if (aListener != null) { ActionEvent ev = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ev); } running = false; return; } mInStrBuffer.append(readMessage); readMessage = mInStrBuffer.toString(); // // die Nachricht abarbeitern, solange komplette MSG da sind // start = mInStrBuffer.indexOf(ProjectConst.STX); end = mInStrBuffer.indexOf(ProjectConst.ETX); if (isLogentryMode) { // Logeintrge werden abgearbeitet lstart = mInStrBuffer.indexOf(ProjectConst.FILLER); lend = mInStrBuffer.indexOf(ProjectConst.FILLER, start + ProjectConst.FILLER.length()); } else { // der "normalmode" lstart = -1; lend = -1; } // solange etwas gefunden wird while (((start > -1) && (end > start)) || ((lstart > -1) && (lend > lstart))) { if ((start > -1) && (end > start)) normalCmd = true; else normalCmd = false; if ((lstart > -1) && (lend > lstart)) logCmd = true; else logCmd = false; // womit anfangen? // sind beide zu finden? if (normalCmd == true && logCmd == true) { // entscheidung, wer zuerst if (start < lstart) { execNormalCmd(start, end, mInStrBuffer); } else { execLogentryCmd(lstart, lend, mInStrBuffer); } } else { // nein, nur ein Typ. Welcher? if (normalCmd == true) { execNormalCmd(start, end, mInStrBuffer); } else if (logCmd == true) { execLogentryCmd(lstart, lend, mInStrBuffer); } } start = mInStrBuffer.indexOf(ProjectConst.STX); end = mInStrBuffer.indexOf(ProjectConst.ETX); if (isLogentryMode) { lstart = mInStrBuffer.indexOf(ProjectConst.FILLER); lend = mInStrBuffer.indexOf(ProjectConst.FILLER, start + ProjectConst.FILLER.length()); } else { lstart = -1; lend = -1; } } } if (inStream != null) { try { inStream.close(); } catch (IOException ex) { } } isConnected = false; lg.debug("stop reader thread..."); } /** * Bearbeite einen Logeintrag Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 11.01.2012 * @param start * @param end * @param mInStrBuffer */ private void execLogentryCmd(int start, int end, StringBuffer mInStrBuffer) { String readMessage; int lstart, lend; lg.debug("execLogentryCmd..."); lstart = mInStrBuffer.indexOf(ProjectConst.STX); lend = mInStrBuffer.indexOf(ProjectConst.ETX); if (lstart > -1 && lend > lstart) { // ups, hier ist ein "normales" Kommando verpackt lg.debug("oops, normalCmd found.... change to execNormalCmd..."); isLogentryMode = false; execNormalCmd(lstart, lend, mInStrBuffer); return; } // muss der anfang weg? if (start > 0) { // das davor kann dann weg... mInStrBuffer = mInStrBuffer.delete(0, start); readMessage = mInStrBuffer.toString(); // Indizies korrigieren end = mInStrBuffer.indexOf(ProjectConst.FILLER, start + ProjectConst.FILLER.length()); start = 0; } // lese das Ding ohne den Schmandzius der Fller readMessage = mInStrBuffer.substring(ProjectConst.FILLER.length(), end); // lsche das schon mal raus... mInStrBuffer = mInStrBuffer.delete(0, end); readMessage = readMessage.replaceAll(ProjectConst.FILLERCHAR, ""); // Sende an aufrufende Activity lg.debug("Logline Recived <" + readMessage.substring(10).replaceAll("\t", " ") + "...>"); if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_LOGENTRY_LINE, readMessage, System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } } /** * Bearbeite eine Meldung vom SPX42 Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 24.12.2011 * @param start * @param end * @param mInStrBuffer */ private void execNormalCmd(int start, int end, StringBuffer mInStrBuffer) { String readMessage; String[] fields; int command; lg.debug("execNormalCmd..."); // muss der anfang weg? if (start > 0) { // das davor kann dann weg... mInStrBuffer = mInStrBuffer.delete(0, start); readMessage = mInStrBuffer.toString(); // Indizies korrigieren end = mInStrBuffer.indexOf(ProjectConst.ETX); start = 0; } // jetz beginnt der String immer bei 0, lese das Ding readMessage = mInStrBuffer.substring(1, end); // lsche das schon mal raus... mInStrBuffer = mInStrBuffer.delete(0, end + 1); lg.debug("normal Message Recived <" + readMessage + ">"); // Trenne die Parameter voneinander, fields[0] ist dann das Kommando fields = fieldPatternDp.split(readMessage); // // // if (0 == readMessage.indexOf(ProjectConst.IS_END_LOGLISTENTRY)) { // Logbucheintrge fertig gelesen if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_DIRENTRY_END, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("Logentry list final recived."); return; } // // // fields[0] = fields[0].replaceFirst("~", ""); try { command = Integer.parseInt(fields[0], 16); } catch (NumberFormatException ex) { lg.error("Convert String to Int (" + ex.getLocalizedMessage() + ")"); return; } // bekomme heraus, welcher Art die ankommende Message ist switch (command) { case ProjectConst.SPX_MANUFACTURERS: // Sende Nachricht Gertename empfangen! if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_MANUFACTURER_READ, new String(fields[1]), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("SPX Devicename recived! <" + fields[1] + ">"); break; case ProjectConst.SPX_ALIVE: // Ackuspannung bertragen if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_SPXALIVE, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("SPX is Alive, Acku value recived."); break; case ProjectConst.SPX_APPLICATION_ID: // Sende Nachricht Firmwareversion empfangen! if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_FWVERSION_READ, new String(fields[1]), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("Application ID (Firmware Version) recived! <" + fields[1] + ">"); break; case ProjectConst.SPX_SERIAL_NUMBER: // Sende Nachricht Seriennummer empfangen! if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_SERIAL_READ, new String(fields[1]), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("Serial Number recived! <" + fields[1] + ">"); break; case ProjectConst.SPX_DATETIME: // Quittung fr Setzen des Datums lg.debug("SPX_DATETIME Acknoweledge recived <" + readMessage + ">"); break; case ProjectConst.SPX_SET_SETUP_DEKO: // Quittung fr Setze DECO lg.debug("Response for set deco <" + readMessage + "> was recived."); // // TODO: readDecoPrefs(); // break; case ProjectConst.SPX_SET_SETUP_SETPOINT: // Quittung fr Setzen der Auto-Setpointeinstelungen lg.debug("SPX_SET_SETUP_SETPOINT Acknoweledge recived <" + readMessage + ">"); break; case ProjectConst.SPX_SET_SETUP_DISPLAYSETTINGS: // Quittung fr Setzen der Displayeinstellungen lg.debug("SET_SETUP_DISPLAYSETTINGS Acknoweledge recived <" + readMessage + ">"); break; case ProjectConst.SPX_SET_SETUP_UNITS: // Quittung fr Setzen der Einheiten lg.debug("SPX_SET_SETUP_UNITS Acknoweledge recived <" + readMessage + ">"); break; case ProjectConst.SPX_SET_SETUP_INDIVIDUAL: // Quittung fr Individualeinstellungen lg.debug("SPX_SET_SETUP_INDIVIDUAL Acknoweledge recived <" + readMessage + ">"); break; case ProjectConst.SPX_GET_SETUP_DEKO: // Kommando DEC liefert zurck: // ~34:LL:HH:D:Y:C // LL=GF-Low, HH=GF-High, // D=Deepstops (0/1) // Y=Dynamische Gradienten (0/1) // C=Last Decostop (0=3 Meter/1=6 Meter) if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_DECO_READ, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("DECO_EINST recived <" + readMessage + ">"); break; case ProjectConst.SPX_GET_SETUP_SETPOINT: // Kommando GET_SETUP_SETPOINT liefert // ~35:A:P // A = Setpoint bei (0,1,2,3) = (0,5,15,20) // P = Partialdruck (0..4) 1.0 .. 1.4 if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_SETPOINT_READ, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("GET_SETUP_SETPOINT recived <" + readMessage + ">"); break; case ProjectConst.SPX_GET_SETUP_DISPLAYSETTINGS: // Kommando GET_SETUP_DISPLAYSETTINGS liefert // ~36:D:A // ALT: D= 0->10&, 1->50%, 2->100% // NEU: 0->20%, 1->40%, 2->60%, 3->80%, 4->100% // A= 0->Landscape 1->180Grad if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_DISPLAY_READ, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("GET_SETUP_DISPLAYSETTINGS recived <" + readMessage + ">"); break; case ProjectConst.SPX_GET_SETUP_UNITS: // Kommando GET_SETUP_UNITS // ~37:UD:UL:UW // UD= Fahrenheit/Celsius => immer 0 in der aktuellen Firmware 2.6.7.7_U // UL= 0=metrisch 1=imperial // UW= 0->Salzwasser 1->Swasser if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_UNITS_READ, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("GET_SETUP_UNITS recived <" + readMessage + ">"); break; case ProjectConst.SPX_GET_SETUP_INDIVIDUAL: // Kommando GET_SETUP_INDIVIDUAL liefert // ~38:SE:PS:SC:SN:LI:?? // SE: Sensors 0->ON 1->OFF // PS: PSCRMODE 0->OFF 1->ON // SC: SensorCount // SN: Sound 0->OFF 1->ON // LI: Loginterval 0->10sec 1->30Sec 2->60 Sec // ??: unbekannter Parameter (Low Setup?) // ab Version 2.7_H_r83 if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_INDIVID_READ, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("GET_SETUP_INDIVIDUAL recived <" + readMessage + ">"); break; case ProjectConst.SPX_GET_SETUP_GASLIST: // Kommando GET_SETUP_GASLIST // ~39:NR:ST:HE:BA:AA:CG // NR: Numer des Gases // ST Stickstoff in Prozent (hex) // HELIUM // Bailout // AA Diluent 1 oder 2 oder keins // CG curent Gas if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_GAS_READ, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("GET_SETUP_GASLIST recived <" + readMessage + ">"); break; case ProjectConst.SPX_SET_SETUP_GASLIST: // Besaetigung fuer Gas setzen bekommen if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_GAS_WRITTEN, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("SET_SETUP_GASLIST recived <" + readMessage + ">"); break; case ProjectConst.SPX_GET_LOG_INDEX: // Ein Logbuch Verzeichniseintrag gefunden if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_DIRENTRY_READ, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("SPX_GET_LOG_INDEX recived!"); break; case ProjectConst.SPX_GET_LOG_NUMBER_SE: if (0 == fields[1].indexOf("1")) { // bertragung Logfile gestartet if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_LOGENTRY_START, new String(fields[2]), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("Logfile transmission started..."); isLogentryMode = true; } else if (0 == fields[1].indexOf("0")) { { // bertragung beendet if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_LOGENTRY_STOP, new String(fields[2]), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("Logfile transmission finished."); isLogentryMode = false; } } break; case ProjectConst.SPX_GET_DEVICE_OFF: // SPX meldet, er geht aus dem Sync-Mode if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_SYCSTAT_OFF, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("SPX42 switch syncmode OFF! Connection will failure!"); break; case ProjectConst.SPX_LICENSE_STATE: // LICENSE_STATE gefunden if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_LICENSE_STATE_READ, new String(readMessage), System.currentTimeMillis() / 100, 0); aListener.actionPerformed(ex); } lg.debug("LICENSE_STATE recived <" + readMessage + ">"); break; default: lg.warn("unknown Messagetype recived <" + readMessage + ">"); } } /** * Terminieren lassen geht hier Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 11.01.2012 */ public synchronized void doTeminate() { this.running = false; // einfach den Stream wegputzen! try { inStream.close(); } catch (IOException ex) { } } } /** * Task soll einfach von Zeit zu Zeit gucken, ob alles noch luft Project: SubmatixBTForPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 06.05.2012 */ private class AliveTask implements Runnable { private boolean running = false; @Override public void run() { this.running = true; int counter = 0; while (this.running) { try { // 1 Sekunden schlafen gehen Thread.sleep(1000); counter++; } catch (InterruptedException ex) { lg.error("Exception while ticker sleeps: <" + ex.getMessage() + ">"); } // aller 90 sekunden if (isConnected && counter > 90) { askForSPXAlive(); counter = 0; } // den Watchdog testen if (isConnected && writeWatchDog > -1) { if (writeWatchDog == 0) { if (aListener != null) { ActionEvent ev = new ActionEvent(this, ProjectConst.MESSAGE_COMMTIMEOUT, "timeout"); aListener.actionPerformed(ev); } } // runterzhlen, bei -1 ist eh schluss writeWatchDog--; } // regelmaessig bescheid geben if (aListener != null && (counter % 10 == 0)) { ActionEvent ev = new ActionEvent(this, ProjectConst.MESSAGE_TICK, "tick"); aListener.actionPerformed(ev); } } } /** * Soll es mglich machen, den Task abzubrechen Project: SubmatixBTForPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 06.05.2012 */ @SuppressWarnings("unused") public synchronized void doTeminate() { this.running = false; } } @SuppressWarnings("unused") private BTCommunication() { }; /** * Konstruktor der Kommunikation Project: SubmatixBTConfigPC Package: de.dmarcini.submatix.pclogger.comm * * @author Dirk Marciniak (dirk_marciniak@arcor.de) Stand: 11.01.2012 * @param dbUtil */ public BTCommunication(final LogDerbyDatabaseUtil dbUtil) { lg = SpxPcloggerProgramConfig.LOGGER; lg.debug("bluethooth communication object create..."); this.dbUtil = dbUtil; // besorg mir die Gertenamen aus der Datenbank if (!this.dbUtil.isOpenDB()) { try { this.dbUtil.createConnection(); } catch (SQLException ex) { lg.error("error while construct bluethooth object: <" + ex.getLocalizedMessage() + ">"); ex.printStackTrace(); } catch (ClassNotFoundException ex) { lg.error("error while construct bluethooth object: <" + ex.getLocalizedMessage() + ">"); ex.printStackTrace(); } } // // jetzt noch Tick starten und dabei ALIVE abfragen... // lg.debug("bluethooth communication object create...start ticker..."); alive = new AliveTask(); Thread al = new Thread(alive); al.setName("bt_alive_task"); al.setPriority(Thread.NORM_PRIORITY - 2); al.start(); lg.debug("bluethooth communication object create...OK"); } @Override public boolean isConnected() { return this.isConnected; } @Override public void addActionListener(ActionListener al) { aListener = al; } @Override public void removeActionListener() { aListener = null; } @Override public void connectVirtDevice(final String devName) { // lg.debug("try to connect virtual device <" + devName + ">..."); this.connectedVirtualDevice = null; this.serialPort = null; isConnected = false; // // Da das lnger dauern kann, wieder einen Thread erffnen, // damit Swing eine Change hat die Grafik zu erneutern // Thread ct = new Thread() { @SuppressWarnings("resource") @Override public void run() { // Port ID holen CommPortIdentifier portIdentifier; CommPort commPort = null; try { portIdentifier = CommPortIdentifier.getPortIdentifier(devName); // versuch den Port zu ffnen, wirft PortInUseException commPort = portIdentifier.open(this.getClass().getName(), 10000); if (commPort instanceof SerialPort) { lg.debug("device <" + devName + "> is serial port..."); serialPort = (SerialPort) commPort; connectedVirtualDevice = "virtual"; // Ist ein virtueller Port, da brauch ioch keine Parameter einstellen.... // serialPort.setSerialPortParams(57600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE); // Eingabe erzeugen InputStream din; din = serialPort.getInputStream(); reader = new ReaderRunnable(din); Thread rt = new Thread(reader); rt.setName("bt_reader_thread"); rt.setPriority(Thread.NORM_PRIORITY - 1); rt.start(); // // Ausgabe erzeugen OutputStream dout = serialPort.getOutputStream(); writer = new WriterRunnable(dout); Thread wt = new Thread(writer); wt.setName("bt_writer_thread"); wt.setPriority(Thread.NORM_PRIORITY - 2); wt.start(); isConnected = true; if (aListener != null) { ActionEvent ex = new ActionEvent(this, ProjectConst.MESSAGE_CONNECTED, null); aListener.actionPerformed(ex); } } else { lg.error("device <" + devName + "> is NOT serial port ABORT!"); if (aListener != null) { ActionEvent ex1 = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ex1); } } } catch (NoSuchPortException ex) { lg.error("device <" + devName + "> is NOT serial port ABORT!"); if (aListener != null) { ActionEvent ex1 = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ex1); } } catch (PortInUseException ex) { lg.error("device <" + devName + "> is in use. ABORT!"); if (aListener != null) { ActionEvent ex1 = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ex1); } } catch (IOException ex) { lg.error("device <" + devName + "> had an Exception : <" + ex.getLocalizedMessage() + ">"); if (aListener != null) { ActionEvent ex1 = new ActionEvent(this, ProjectConst.MESSAGE_DISCONNECTED, null); aListener.actionPerformed(ex1); } } } }; ct.setName("virt_device_connect"); ct.start(); } @Override public void disconnectDevice() { if (writer != null) { writer.doTeminate(); } if (reader != null) { reader.doTeminate(); } try { Thread.sleep(500); } catch (InterruptedException ex) { } writer = null; reader = null; if (this.serialPort != null) { this.serialPort.close(); } this.serialPort = null; this.connectedVirtualDevice = null; } @Override public synchronized void writeToDevice(String msg) { if (isConnected && (writer != null)) { writer.writeToDevice(msg); } } @Override public void writeSPXMsgToDevice(String msg) { if (isConnected && (writer != null)) { writer.writeToDevice(ProjectConst.STX + msg + ProjectConst.ETX); } } @Override public void askForSerialNumber() { this.writeToDevice( String.format("%s~%x%s", ProjectConst.STX, ProjectConst.SPX_SERIAL_NUMBER, ProjectConst.ETX)); } @Override public void askForSPXAlive() { this.writeToDevice(String.format("%s~%x%s", ProjectConst.STX, ProjectConst.SPX_ALIVE, ProjectConst.ETX)); } @Override public void readConfigFromSPX42() { String kdoString; kdoString = String.format("%s~%x~%x~%x~%x~%x~%x~%x%s", ProjectConst.STX, ProjectConst.SPX_GET_SETUP_DEKO, ProjectConst.SPX_GET_SETUP_SETPOINT, ProjectConst.SPX_GET_SETUP_DISPLAYSETTINGS, ProjectConst.SPX_GET_SETUP_UNITS, ProjectConst.SPX_GET_SETUP_INDIVIDUAL, ProjectConst.SPX_LICENSE_STATE, ProjectConst.SPX_ALIVE, ProjectConst.ETX); { lg.debug("readConfigFromSPX()...send <" + kdoString + ">"); } this.writeToDevice(kdoString); } @Override public void askForDeviceName() { this.writeToDevice( String.format("%s~%x%s", ProjectConst.STX, ProjectConst.SPX_MANUFACTURERS, ProjectConst.ETX)); } @Override public void askForFirmwareVersion() { this.writeToDevice( String.format("%s~%x%s", ProjectConst.STX, ProjectConst.SPX_APPLICATION_ID, ProjectConst.ETX)); } @Override public void askForLicenseFromSPX() { this.writeToDevice( String.format("%s~%x%s", ProjectConst.STX, ProjectConst.SPX_LICENSE_STATE, ProjectConst.ETX)); } @Override public String getDeviceInfos() { // Mach aus den HashMaps einen String zum Wiedereinlesen return null; } @Override public void putDeviceInfos(String infos) throws Exception { } @Override public void writeConfigToSPX(final SPX42Config config) { Thread configWriteThread = null; // if (!config.isInitialized()) { lg.error("config was not initialized! CANCEL!"); return; } if (ProjectConst.FIRMWARE_2_6_7_7V.equals(config.getFirmwareVersion()) || config.getFirmwareVersion().startsWith(ProjectConst.FIRMWARE_2_7Vx) || config.getFirmwareVersion().startsWith(ProjectConst.FIRMWARE_2_7Hx)) { // Fhre als eigenen Thread aus, damit die Swing-Oberflche // Gelegenheit bekommt, sich zu zeichnen configWriteThread = new Thread() { ActionEvent ae; @Override public void run() { String command = null; if (!config.isFirmwareSupported()) { lg.error("Firmware not supportet! CANCEL!"); if (aListener != null) { lg.error("SEND MESSAGE!"); ae = new ActionEvent(this, ProjectConst.MESSAGE_FWNOTSUPPORTED, config.getFirmwareVersion()); aListener.actionPerformed(ae); } return; } // // Kommando SPX_SET_SETUP_DEKO // Deco-Einstellungen setzen lg.info("write deco propertys"); if (config.isOldParamSorting()) { // ~29:GH:GL:LS:DY:DS // GH = Gradient HIGH // GL = Gradient LOW // LS = Last Stop 0=>6m 1=>3m // DY = Dynamische gradienten 0->off 1->on // DS = Deepstops 0=> enabled, 1=>disabled command = String.format("~%x:%x:%x:%x:%x:%x", ProjectConst.SPX_SET_SETUP_DEKO, config.getDecoGfHigh(), config.getDecoGfLow(), config.getLastStop(), config.getDynGradientsEnable(), config.getDeepStopEnable()); } else { // Kommando SPX_SET_SETUP_DEKO // ~29:GL:GH:DS:DY:LS // GL=GF-Low, GH=GF-High, // DS=Deepstops (0/1) // DY=Dynamische Gradienten (0/1) // LS=Last Decostop (0=3 Meter/1=6 Meter) command = String.format("~%x:%x:%x:%x:%x:%x", ProjectConst.SPX_SET_SETUP_DEKO, config.getDecoGfLow(), config.getDecoGfHigh(), config.getDeepStopEnable(), config.getDynGradientsEnable(), config.getLastStop()); } lg.debug("Send <" + command + ">"); writeSPXMsgToDevice(command); // gib Bescheid if (aListener != null) { ae = new ActionEvent(this, ProjectConst.MESSAGE_PROCESS_NEXT, null); aListener.actionPerformed(ae); } // // Kommando SPX_SET_SETUP_DISPLAYSETTINGS // ~31:D:A // Alte Settings D= 0->10&, 1->50%, 2->100% // Neuere Settings 0->20%, 1->40%, 2->60%, 3->80%, 4->100% // A= 0->Landscape 1->180Grad // Display setzen lg.info("write display propertys"); command = String.format("~%x:%x:%x", ProjectConst.SPX_SET_SETUP_DISPLAYSETTINGS, config.getDisplayBrightness(), config.getDisplayOrientation()); lg.debug("Send <" + command + ">"); writeSPXMsgToDevice(command); // gib Bescheid if (aListener != null) { ae = new ActionEvent(this, ProjectConst.MESSAGE_PROCESS_NEXT, null); aListener.actionPerformed(ae); } // // Kommando SPX_SET_SETUP_UNITS // ~32:UD:UL:UW // UD= Fahrenheit/Celsius => immer 0 in der aktuellen Firmware 2.6.7.7_U // UL= 0=>metrisch 1=>imperial // UW= 0->Salzwasser 1->Swasser lg.info("write units propertys"); command = String.format("~%x:%x:%x:%x", ProjectConst.SPX_SET_SETUP_UNITS, config.getUnitTemperature(), config.getUnitDepth(), config.getUnitSalnity()); lg.debug("Send <" + command + ">"); writeSPXMsgToDevice(command); // gib Bescheid if (aListener != null) { ae = new ActionEvent(this, ProjectConst.MESSAGE_PROCESS_NEXT, null); aListener.actionPerformed(ae); } lg.info("write setpoint propertys"); if (config.isOldParamSorting()) { // // Kommando SPX_SET_SETUP_SETPOINT // ~30:P:A // P = Partialdruck (0..4) 1.0 .. 1.4 // A = Setpoint bei (0,1,2,3,4) = (0,5,15,20,25) command = String.format("~%x:%x:%x", ProjectConst.SPX_SET_SETUP_SETPOINT, config.getMaxSetpoint(), config.getAutoSetpoint()); } else { // ~30:A:P // A = Setpoint bei (0,1,2,3,4) = (0,5/6,15,20,25) // P = Partialdruck (0..4) 1.0 .. 1.4 command = String.format("~%x:%x:%x", ProjectConst.SPX_SET_SETUP_SETPOINT, config.getAutoSetpoint(), config.getMaxSetpoint()); } lg.debug("Send <" + command + ">"); writeSPXMsgToDevice(command); // gib Bescheid if (aListener != null) { ae = new ActionEvent(this, ProjectConst.MESSAGE_PROCESS_NEXT, null); aListener.actionPerformed(ae); } // if (config.getCustomEnabled() == 1) { // Kommando SPX_SET_SETUP_INDIVIDUAL // ~33:SM:PS:SC:AC:LT:TS // SM = 0-> Sensoren ON, 1-> No Sensor // PS = PSCR Mode 0->off; 1->ON (sollte eigentlich immer off (0 ) sein) // SC = SensorsCount 0->1 Sensor, 1->2 sensoren, 2->3 Sensoren // AC = acoustic 0->off, 1->on // LT = Logbook Timeinterval 0->10s, 1->30s, 2->60s // Ab Version 2.7_H_R_83ce // TS : TempStick == 0 lg.info("write individual propertys"); if (config.hasSixValuesIndividual()) { // Ab Version 2.7_H_r83 command = String.format("~%x:%x:%x:%x:%x:%x:%x", ProjectConst.SPX_SET_SETUP_INDIVIDUAL, config.getSensorsOn(), config.getPscrModeOn(), config.getSensorsCount(), config.getSoundOn(), config.getLogInterval(), config.getTempStickVer()); } else { command = String.format("~%x:%x:%x:%x:%x:%x", ProjectConst.SPX_SET_SETUP_INDIVIDUAL, config.getSensorsOn(), config.getPscrModeOn(), config.getSensorsCount(), config.getSoundOn(), config.getLogInterval()); } lg.debug("Send <" + command + ">"); writeSPXMsgToDevice(command); // gib Bescheid if (aListener != null) { ae = new ActionEvent(this, ProjectConst.MESSAGE_PROCESS_NEXT, null); aListener.actionPerformed(ae); } } // gib Bescheid Vorgang zuende lg.info("write config endet."); if (aListener != null) { ae = new ActionEvent(this, ProjectConst.MESSAGE_PROCESS_END, "config_write"); aListener.actionPerformed(ae); } } }; configWriteThread.setName("write_config_to_spx"); configWriteThread.start(); } else { lg.error("write for this firmware version not confirmed! CANCEL!"); if (aListener != null) { lg.error("SEND MESSAGE!"); ActionEvent ev = new ActionEvent(this, ProjectConst.MESSAGE_FWNOTSUPPORTED, config.getFirmwareVersion()); aListener.actionPerformed(ev); } } } @Override public void readGaslistFromSPX42() { String kdoString; kdoString = String.format("%s~%x%s", ProjectConst.STX, ProjectConst.SPX_GET_SETUP_GASLIST, ProjectConst.ETX); { lg.debug("readGaslistFromSPX42()...send <" + kdoString + ">"); } this.writeToDevice(kdoString); } @Override public void writeGaslistToSPX42(final SPX42GasList gList, final boolean isOldParamSorting) { Thread gasListWriteThread = null; // if (!gList.isInitialized()) { lg.error("config was not initialized! CANCEL!"); return; } // Schreibe fr die leicht Fehlerhafte Version // Fhre als eigenen Thread aus, damit die Swing-Oberflche // Gelegenheit bekommt, sich zu zeichnen gasListWriteThread = new Thread() { ActionEvent ae; @Override public void run() { String command; int gasCount = gList.getGasCount(); int gasNr; int diluent; // // Alle Gase des Computers durchexerzieren // for (gasNr = 0; gasNr < gasCount; gasNr++) { lg.info(String.format("write gas number %d to SPX...", gasNr)); if (isOldParamSorting) { // ############ Alte Parameter Reihenfolge // Kommando SPX_SET_SETUP_GASLIST // ~40:NR:HE:N2:BO:DI:CU // NR -> Gas Nummer // HE -> Heliumanteil // N2 -> Stickstoffanteil // BO -> Bailoutgas? (3?) // DI -> Diluent ( 0, 1 oder 2 ) // CU Current Gas (0 oder 1) if (gList.getDiulent1() == gasNr) { diluent = 1; } else if (gList.getDiluent2() == gasNr) { diluent = 2; } else { diluent = 0; } command = String.format("~%x:%x:%x:%x:%x:%x:%x", ProjectConst.SPX_SET_SETUP_GASLIST, gasNr, gList.getHEFromGas(gasNr), gList.getN2FromGas(gasNr), gList.getBailout(gasNr), diluent, gList.getCurrGas(gasNr)); } else { // ############ NEUE Parameter Reihenfolge // Kommando SPX_SET_SETUP_GASLIST // ~40:NR:N2:HE:BO:DI:CU // NR: Nummer des Gases 0..7 // N2: Sticksoff in % // HE: Heluim in % // BO: Bailout (Werte 0,1 und 3 gefunden, 0 kein BO, 3 BO Wert 1 unbekannt?) // DI: Diluent 1 oder 2 // CU: Current Gas if (gList.getDiulent1() == gasNr) { diluent = 1; } else if (gList.getDiluent2() == gasNr) { diluent = 2; } else { diluent = 0; } command = String.format("~%x:%x:%x:%x:%x:%x:%x", ProjectConst.SPX_SET_SETUP_GASLIST, gasNr, gList.getN2FromGas(gasNr), gList.getHEFromGas(gasNr), gList.getBailout(gasNr), diluent, gList.getCurrGas(gasNr)); } // lg.debug("Send <" + command + ">"); writeSPXMsgToDevice(command); // gib Bescheid if (aListener != null) { ae = new ActionEvent(this, ProjectConst.MESSAGE_PROCESS_NEXT, null); aListener.actionPerformed(ae); } } // gib Bescheid Vorgang zuende lg.info("write gaslist success."); if (aListener != null) { ae = new ActionEvent(this, ProjectConst.MESSAGE_PROCESS_END, null); aListener.actionPerformed(ae); } } }; gasListWriteThread.setName("write_gaslist_to_spx"); gasListWriteThread.start(); } @Override public void readLogDirectoryFromSPX() { String kdoString; kdoString = String.format("%s~%x%s", ProjectConst.STX, ProjectConst.SPX_GET_LOG_INDEX, ProjectConst.ETX); { lg.debug("readLogDirectoryFromSPX()...send <" + kdoString + ">"); } this.writeToDevice(kdoString); } @Override public String getConnectedDevice() { if (isConnected) { // ist es ein virtuelles Gert? if (this.connectedVirtualDevice != null) { // ja, dann guck ich mal weiter return (this.connectedVirtualDevice); } lg.warn("connected Device is again NULL!"); } return null; } @Override public void readLogDetailFromSPX(int logNumber) { if (isConnected) { String kdoString = String.format("%s~%x:%x%s", ProjectConst.STX, ProjectConst.SPX_GET_LOG_NUMBER, logNumber, ProjectConst.ETX); { lg.debug("readLogDetailFromSPX()...send <" + kdoString + ">"); } this.writeToDevice(kdoString); } } @Override public void setNameForVirtualDevice(String serialNumber) { this.connectedVirtualDevice = serialNumber; } @Override public void writeDateTimeToDevice(DateTime dTime) { String kdoString; // if (isConnected) { // // Setze das Zeit und Datum als Kommandostring zusammen // kdoString = String.format("%s~%x:%02x:%02x:%02x:%02x:%02x%s", ProjectConst.STX, ProjectConst.SPX_DATETIME, dTime.getHourOfDay(), dTime.getMinuteOfHour(), dTime.getDayOfMonth(), dTime.getMonthOfYear(), dTime.getYearOfCentury(), ProjectConst.ETX); { lg.debug("writeDateTimeToDevice()...send <" + kdoString + "> (DATETIME)"); } this.writeToDevice(kdoString); } } }