java-org.hwo/src/org/hwo/io/NewSerialPort/NewSerialPort.java

470 lines
11 KiB
Java

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<NewSerialPortListener> serialPortListeners;
public NewSerialPort(String portName) {
this.nsp = nsp_alloc();
serialPortListeners = new LinkedList<NewSerialPortListener>();
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<String> tokens = new LinkedList<String>();
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<String> portNames = new ArrayList<String>();
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<String> portNames = new ArrayList<String>();
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<String> portNames = new ArrayList<String>();
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]);
}
}