package org.hwo.io.NewSerialPort; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import org.hwo.StringHelper; import org.hwo.io.NativeSerialPort; import org.hwo.io.SerialPortExeption; import org.hwo.io.SerialPortWINDOWS; import org.hwo.platform.Platform; import org.hwo.platform.natives.NativeLoader; import static org.hwo.logging.Logging.*; import static org.hwo.logging.LogLevel.*; public class NewSerialPort { public static long nsp_RET_OK = 0; // Kein Fehler public static long nsp_RET_NOTFOUND = -1; // Port konnte nicht geöffnet werden public static long nsp_RET_PARAM = -2; // Parameter ungültig public static long nsp_RET_SHORTREAD = -3; public static long nsp_RET_TIMEOUT = -4; public static long nsp_RET_NOTOPEN = -5; public static long nsp_RET_OTHER = -99; // Unbekannter Fehler public static long EAGAIN; String portName; int baudRate; int databits; boolean stopbit2; HandShake handShake; Parity parity; int timeout; long nsp; boolean wasOpened; boolean autoOpen; private NewSerialPortInputStream inputStream; private NewSerialPortOutputStream outputStream; private List serialPortListeners; public NewSerialPort(String portName) { this.nsp = nsp_alloc(); serialPortListeners = new LinkedList(); setPortName(portName); setBaudRate(9600); setDatabits(8); setStopBit2(false); setHandShake(HandShake.NONE); setParity(Parity.NONE); setTimeOut(0); this.inputStream = new NewSerialPortInputStream(); this.outputStream = new NewSerialPortOutputStream(); } @Override protected void finalize() throws Throwable { nsp_free(this.nsp); super.finalize(); } public void addNewSerialPortListener(NewSerialPortListener listener){ serialPortListeners.add(listener); } public void removeNewSerialPortListener(NewSerialPortListener listener){ serialPortListeners.remove(listener); } private void fireConnectionStateChanged(){ for (NewSerialPortListener l: serialPortListeners) l.connectionStateChanged(this, isOpen()); } public NewSerialPortInputStream getInputStream() { return inputStream; } public NewSerialPortOutputStream getOutputStream() { return outputStream; } public boolean isAutoOpen(){ return autoOpen; } public void setAutoOpen(boolean autoOpen){ this.autoOpen = autoOpen; } public String getPortName() { return portName; } public void setPortName(String portName) { this.portName = portName; nsp_set_portname(nsp, portName); } public int getBaudRate() { return baudRate; } public void setBaudRate(int baudRate) { this.baudRate = baudRate; nsp_setup_baudrate(nsp, baudRate); } public void setBaudRate(BaudRate baudRate) { setBaudRate(baudRate.getValue()); } public BaudRate getBaudRate2(){ return BaudRate.fromInt(this.baudRate); } public int getDatabits() { return databits; } public void setDatabits(int databits) { this.databits = databits; nsp_setup_bits(nsp, databits, this.stopbit2 ? 2 : 1); } public HandShake getHandShake() { return handShake; } public void setHandShake(HandShake handShake) { this.handShake = handShake; nsp_setup_handshake(nsp, handShake.getValue()); } public Parity getParity() { return parity; } public void setParity(Parity parity) { this.parity = parity; nsp_setup_parity(nsp, parity.getValue()); } public boolean getStopBit2(){ return this.stopbit2; } public void setStopBit2(boolean sb2){ this.stopbit2 = sb2; nsp_setup_bits(nsp, databits, this.stopbit2 ? 2 : 1); } public int getTimeOut(){ return this.timeout; } public void setTimeOut(int timeout){ this.timeout = timeout; log(DEBUG,"NSP: setTimeOut( %d )",timeout); nsp_setup_timeout(nsp, timeout); } public boolean open(){ if (wasOpened) return false; int r = nsp_open(nsp); wasOpened = (r == 0); System.err.println(String.format("nsp_open(): %d",r)); if (wasOpened) fireConnectionStateChanged(); return wasOpened; } public void close(){ if (wasOpened){ nsp_close(nsp); wasOpened = false; fireConnectionStateChanged(); } } public boolean isOpen(){ return wasOpened; } /* * getSettings(...) * * Erstelle eine Text-Repräsentation der aktuellen Port Einstellungen * */ public String getSettings(boolean includePortName){ List tokens = new LinkedList(); if (includePortName){ tokens.add(String.format("PN=%s",this.portName)); } tokens.add(String.format("B=%d",this.baudRate)); tokens.add(String.format("P=%s",this.parity.getLetter())); tokens.add(String.format("H=%s", this.handShake.getLetter())); tokens.add(String.format("SB=%d", (this.stopbit2) ? 2 : 1 )); return StringHelper.join(tokens, ";"); } public boolean parseSettings(String settings){ String[] tokens = settings.split(";"); for (String token: tokens){ String[] st = token.split("=", 2); if (st.length == 2){ if (st[0].equals("PN")){ this.setPortName(st[1]); } if (st[0].equals("B")){ this.setBaudRate(Integer.parseInt(st[1])); } if (st[0].equals("P")){ this.setParity( Parity.fromLetter(st[1])); } if (st[0].equals("H")){ this.setHandShake( HandShake.fromLetter(st[1])); } if (st[0].equals("SB")){ this.setStopBit2( st[1].equals("2")); } } } return true; } private static native synchronized long nsp_alloc(); private static native synchronized int nsp_free(long msp); private static native synchronized int nsp_set_portname(long nsp,String portName); private static native synchronized int nsp_setup_baudrate(long nsp,int baudRate); private static native synchronized int nsp_setup_bits(long nsp,int dataBits,int stopBits); private static native synchronized int nsp_setup_parity(long nsp,int parity); private static native synchronized int nsp_setup_handshake(long nsp,int handshake); private static native synchronized int nsp_setup_timeout(long nsp,int timeout); private static native int nsp_open(long nsp); private static native int nsp_close(long nsp); private static native int nsp_read(long nsp); private static native int nsp_write(long nsp,int ch); private static native int nsp_read_bytes(long nsp,byte[] bytes,int offset,int len); private static native int nsp_write_bytes(long nsp,byte[] bytes,int offset,int len); private static native int nsp_EAGAIN(); static { NativeLoader.loadLibrary("nsp"); EAGAIN = nsp_EAGAIN(); } public class NewSerialPortInputStream extends InputStream { @Override public int read() throws IOException { if (autoOpen && !isOpen()) open(); log(DEBUGDETAIL,"NSP::read()"); int ch = nsp_read(nsp); if (ch < 0){ if (ch == nsp_RET_TIMEOUT) return -1; if (ch == nsp_RET_NOTOPEN){ NewSerialPort.this.close(); return -1; } if (ch == nsp_RET_OTHER){ NewSerialPort.this.close(); NewSerialPort.this.open(); } throw new IOException(String.format("nsp_read()=%d", ch)); }; return ch; } @Override public int read(byte[] b, int off, int len) throws IOException { //log(DEBUGDETAIL,"NSP::read()"); int nRead = nsp_read_bytes(nsp, b, off, len); if (nRead < 0){ if (nRead == EAGAIN){ // -EAGAIN (timeout, keine zeichen verfügbar) return 0; }; throw new IOException(String.format("nsp_read_bytes() returned %d", nRead)); } return nRead; } @Override public int read(byte[] b) throws IOException { int nRead = nsp_read_bytes(nsp, b, 0, b.length); if (nRead < 0){ throw new IOException(String.format("nsp_read_bytes() returned %d", nRead)); } return nRead; } } public class NewSerialPortOutputStream extends OutputStream { @Override public void write(int arg0) throws IOException{ int r; boolean retry = true; if (autoOpen && !isOpen()) open(); if (!isOpen()) throw new IOException("Port not opened"); while (true){ r = nsp_write(nsp, arg0); if (r == -11){ // -EAGAIN try { Thread.sleep(5); } catch (InterruptedException e){ log(e); } } else if (r<0){ if (r == nsp_RET_NOTOPEN) NewSerialPort.this.close(); if (r == nsp_RET_OTHER){ NewSerialPort.this.close(); NewSerialPort.this.open(); } throw new IOException(String.format("nsp_write()=%d", r)); } else { break; } } } @Override public void write(byte[] b, int off, int len) throws IOException { int nWritten = 0; log(DEBUGDETAIL,"NSP::write(...)"); for (int redo=0; redo < 5 ; redo++){ nWritten = nsp_write_bytes(nsp, b, off, len); if (nWritten == EAGAIN){ try { log(DEBUGDETAIL,"SL-TX-EAGAIN... [%d]",redo); Thread.sleep(5); } catch (Exception e){ } } else if (nWritten != len){ throw new IOException(String.format("nsp_write_bytes() returned %d", nWritten)); } else { break; } } if (nWritten != len){ throw new IOException(String.format("nsp_write_bytes() returned %d after retry", nWritten)); } } @Override public void write(byte[] b) throws IOException { write(b, 0, b.length); } } static public String[] getPortNames(){ switch (Platform.getOperatingSystem()){ case LINUX: return getPortNamesLIN(); case WINDOWS: return getPortNamesWIN(); case OSX: return getPortNamesOSX(); default: return new String[0]; } } static public String[] getPortNamesWIN() { ArrayList portNames = new ArrayList(); NewSerialPort sp = new NewSerialPort(""); for (int i = 1; i < 32; i++) { sp.setPortName(String.format("COM%d",i)); if (sp.open()) { portNames.add(String.format("COM%d",i)); sp.close(); } } return portNames.toArray(new String[0]); } static public String[] getPortNamesLIN() { ArrayList portNames = new ArrayList(); File devDir = new File("/dev"); File[] list = devDir.listFiles(new FilenameFilter() { @Override public boolean accept(File arg0, String arg1) { if (arg1.startsWith("ttyS") || arg1.startsWith("ttyACM")) return true; return false; } }); for (File file:list) portNames.add("/dev/" + file.getName()); return portNames.toArray(new String[0]); } static public String[] getPortNamesOSX() { ArrayList portNames = new ArrayList(); File devDir = new File("/dev"); File[] list = devDir.listFiles(new FilenameFilter() { @Override public boolean accept(File arg0, String arg1) { if (arg1.startsWith("tty.") || arg1.startsWith("ttyS")) return true; return false; } }); for (File file:list) portNames.add("/dev/" + file.getName()); return portNames.toArray(new String[0]); } }