new logger source (still a bit buggy, some synchronization issues) - not hooked into main app yet!

git-svn-id: http://svn.3splooges.com/romraider-arch/trunk@170 d2e2e1cd-ba16-0410-be16-b7c4453c7c2d
This commit is contained in:
kascade 2006-07-24 14:00:41 +00:00
parent fca2b4919c
commit 2e83cf3f10
28 changed files with 866 additions and 4 deletions

View File

@ -1,9 +1,6 @@
package enginuity;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.*;
import java.io.File;
import java.io.Serializable;
import java.util.Vector;
@ -40,6 +37,8 @@ public class Settings implements Serializable {
private Color axisColor = new Color(255, 255, 255);
private Color warningColor = new Color(255, 0, 0);
private int tableClickCount = 2; // number of clicks to open table
private String loggerPort = "COM3";
public Settings() {
//center window by default
@ -261,4 +260,12 @@ public class Settings implements Serializable {
public void setWarningColor(Color warningColor) {
this.warningColor = warningColor;
}
public String getLoggerPort() {
return loggerPort;
}
public void setLoggerPort(String loggerPort) {
this.loggerPort = loggerPort;
}
}

View File

@ -0,0 +1,45 @@
package enginuity.logger;
import enginuity.logger.comms.DefaultSerialPortDiscoverer;
import enginuity.logger.comms.SerialPortDiscoverer;
import enginuity.logger.manager.DefaultQueryManager;
import enginuity.logger.manager.QueryManager;
import enginuity.logger.query.DefaultRegisteredQuery;
import enginuity.logger.query.LoggerCallback;
import static enginuity.util.ParamChecker.checkNotNull;
import gnu.io.CommPortIdentifier;
import java.util.ArrayList;
import java.util.List;
public final class DefaultLoggerController implements LoggerController {
private final QueryManager queryManager = new DefaultQueryManager();
public List<String> listSerialPorts() {
SerialPortDiscoverer serialPortDiscoverer = new DefaultSerialPortDiscoverer();
List<CommPortIdentifier> portIdentifiers = serialPortDiscoverer.listPorts();
List<String> portNames = new ArrayList<String>(portIdentifiers.size());
for (CommPortIdentifier portIdentifier : portIdentifiers) {
portNames.add(portIdentifier.getName());
}
return portNames;
}
public void start() {
new Thread(queryManager).start();
}
public void addLogger(String address, LoggerCallback callback) {
checkNotNull(address, callback);
queryManager.addQuery(new DefaultRegisteredQuery(address, callback));
}
public void removeLogger(String address) {
checkNotNull(address, "address");
queryManager.removeQuery(address);
}
public void stop() {
queryManager.stop();
}
}

View File

@ -0,0 +1,19 @@
package enginuity.logger;
import enginuity.logger.query.LoggerCallback;
import java.util.List;
public interface LoggerController {
List<String> listSerialPorts();
void start();
void addLogger(String address, LoggerCallback callback);
void removeLogger(String address);
void stop();
}

View File

@ -0,0 +1,93 @@
package enginuity.logger;
import enginuity.logger.comms.DefaultSerialPortDiscoverer;
import enginuity.logger.comms.DefaultTwoWaySerialComm;
import enginuity.logger.comms.SerialConnection;
import enginuity.logger.comms.SerialPortDiscoverer;
import enginuity.logger.comms.TwoWaySerialComm;
import enginuity.logger.query.DefaultQuery;
import enginuity.logger.query.LoggerCallback;
import gnu.io.CommPortIdentifier;
import static gnu.io.SerialPort.DATABITS_8;
import static gnu.io.SerialPort.PARITY_NONE;
import static gnu.io.SerialPort.STOPBITS_1;
import java.util.List;
public final class TestEcuLogger {
private static final int CONNECT_TIMEOUT = 2000;
private TestEcuLogger() {
}
public static void main(String... args) {
try {
//testTwoWaySerialComm();
testLoggerController();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void testLoggerController() {
LoggerController controller = new DefaultLoggerController();
try {
controller.start();
addLogger(controller, "1");
addLogger(controller, "2");
addLogger(controller, "3");
sleep(1000);
controller.removeLogger("2");
controller.removeLogger("1");
controller.removeLogger("3");
addLogger(controller, "4");
sleep(1000);
} finally {
controller.stop();
}
}
private static void addLogger(LoggerController controller, String address) {
controller.addLogger(address, new LoggerCallback() {
public void callback(byte[] value) {
printResponse(value);
}
});
}
private static void testTwoWaySerialComm() {
SerialPortDiscoverer serialPortDiscoverer = new DefaultSerialPortDiscoverer();
List<CommPortIdentifier> portIdentifiers = serialPortDiscoverer.listPorts();
for (CommPortIdentifier commPortIdentifier : portIdentifiers) {
TwoWaySerialComm twoWaySerialComm = new DefaultTwoWaySerialComm();
try {
SerialConnection serialConnection = twoWaySerialComm.connect(commPortIdentifier.getName(), 10400, DATABITS_8,
STOPBITS_1, PARITY_NONE, CONNECT_TIMEOUT);
executeQuery(serialConnection, "FooBar");
executeQuery(serialConnection, "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789");
executeQuery(serialConnection, "HAZAA!!");
} finally {
twoWaySerialComm.disconnect();
}
}
}
private static void executeQuery(SerialConnection serialConnection, String queryString) {
byte[] response = serialConnection.transmit(new DefaultQuery(queryString.getBytes()));
printResponse(response);
}
private static void printResponse(byte[] value) {
System.out.println("Bytes read: " + String.valueOf(value));
}
private static void sleep(long time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,31 @@
package enginuity.logger.comms;
import enginuity.logger.query.Query;
import enginuity.util.ParamChecker;
public final class DefaultSerialConnection implements SerialConnection {
private SerialWriter serialWriter;
private SerialReader serialReader;
public DefaultSerialConnection(SerialWriter serialWriter, SerialReader serialReader) {
this.serialWriter = serialWriter;
this.serialReader = serialReader;
}
public byte[] transmit(Query query) {
ParamChecker.checkNotNull(query, "query");
return query.execute(serialWriter, serialReader);
}
public void close() {
try {
try {
serialWriter.close();
} finally {
serialReader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,25 @@
package enginuity.logger.comms;
import gnu.io.CommPortIdentifier;
import static gnu.io.CommPortIdentifier.PORT_SERIAL;
import static gnu.io.CommPortIdentifier.getPortIdentifiers;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
public final class DefaultSerialPortDiscoverer implements SerialPortDiscoverer {
@SuppressWarnings({"unchecked"})
public List<CommPortIdentifier> listPorts() {
List<CommPortIdentifier> serialPortIdentifiers = new ArrayList<CommPortIdentifier>();
Enumeration<CommPortIdentifier> portEnum = getPortIdentifiers();
while (portEnum.hasMoreElements()) {
CommPortIdentifier portIdentifier = portEnum.nextElement();
if (portIdentifier.getPortType() == PORT_SERIAL) {
serialPortIdentifiers.add(portIdentifier);
}
}
return serialPortIdentifiers;
}
}

View File

@ -0,0 +1,81 @@
package enginuity.logger.comms;
import enginuity.logger.exception.SerialCommunicationException;
import static enginuity.util.ParamChecker.checkNotNull;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import static gnu.io.SerialPortEvent.DATA_AVAILABLE;
import gnu.io.SerialPortEventListener;
import java.io.IOException;
import java.io.InputStream;
import java.util.TooManyListenersException;
// TODO: Add a read timeout
public final class DefaultSerialReader implements SerialReader, SerialPortEventListener {
private static final int BUFFER_SIZE = 32;
private final SerialPort port;
private boolean stop = false;
private byte[] readBuffer = new byte[0];
public DefaultSerialReader(SerialPort port) {
checkNotNull(port, "port");
this.port = port;
initListener();
}
public void run() {
System.out.println("SerialReader thread started.");
while (!stop) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("SerialReader thread stopped.");
}
public byte[] read() {
// TODO: Probably should return a copy? System.arraycopy()
return readBuffer;
}
public void close() {
stop = true;
}
@SuppressWarnings({"ResultOfMethodCallIgnored"})
public void serialEvent(SerialPortEvent serialPortEvent) {
checkNotNull(serialPortEvent, "serialPortEvent");
if (serialPortEvent.getEventType() == DATA_AVAILABLE) {
readBuffer = new byte[0];
try {
InputStream is = port.getInputStream();
while (is.available() > 0) {
byte[] tmp = new byte[BUFFER_SIZE];
int i = is.read(tmp);
byte[] tmp2 = new byte[readBuffer.length + i];
System.arraycopy(readBuffer, 0, tmp2, 0, readBuffer.length);
System.arraycopy(tmp, 0, tmp2, readBuffer.length, i);
readBuffer = tmp2;
}
System.out.println("Bytes read from port: " + new String(readBuffer));
} catch (IOException e) {
throw new SerialCommunicationException(e);
}
}
}
private void initListener() {
try {
port.addEventListener(this);
} catch (TooManyListenersException e) {
throw new SerialCommunicationException(e);
}
port.notifyOnDataAvailable(true);
}
}

View File

@ -0,0 +1,43 @@
package enginuity.logger.comms;
import enginuity.logger.exception.SerialCommunicationException;
import static enginuity.util.ParamChecker.checkNotNull;
import gnu.io.SerialPort;
import java.io.IOException;
public final class DefaultSerialWriter implements SerialWriter {
private final SerialPort port;
private boolean stop = false;
public DefaultSerialWriter(SerialPort port) {
checkNotNull(port, "port");
this.port = port;
}
public void run() {
System.out.println("SerialWriter thread started.");
while (!stop) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("SerialWriter thread stopped.");
}
public void write(byte[] bytes) {
try {
System.out.println("Writing bytes: " + new String(bytes));
port.getOutputStream().write(bytes);
} catch (IOException e) {
throw new SerialCommunicationException(e);
}
}
public void close() {
stop = true;
}
}

View File

@ -0,0 +1,134 @@
package enginuity.logger.comms;
import enginuity.logger.exception.PortNotFoundException;
import enginuity.logger.exception.SerialCommunicationException;
import enginuity.logger.exception.UnsupportedPortTypeException;
import static enginuity.util.ParamChecker.checkGreaterThanZero;
import static enginuity.util.ParamChecker.checkNotNull;
import gnu.io.CommPortIdentifier;
import static gnu.io.CommPortIdentifier.PORT_SERIAL;
import static gnu.io.CommPortIdentifier.getPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import static gnu.io.SerialPort.FLOWCONTROL_NONE;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public final class DefaultTwoWaySerialComm implements TwoWaySerialComm {
private SerialPort serialPort;
private OutputStream os;
private InputStream is;
private SerialConnection serialConnection;
public SerialConnection connect(String portName, int baudrate, int dataBits, int stopBits, int parity, int connectTimeout) {
checkConnectParams(portName, baudrate, dataBits, stopBits, connectTimeout);
try {
serialPort = resolveSerialPort(portName, connectTimeout);
initSerialPort(serialPort, baudrate, dataBits, stopBits, parity);
resolveIoStreams(serialPort);
serialConnection = doConnect(serialPort);
System.out.println("Connected to " + portName + ".");
return serialConnection;
} catch (Throwable e) {
disconnect();
throw new SerialCommunicationException("Unable to connect to port " + portName + " with following config - [baudrate: "
+ baudrate + "bps, dataBits: " + dataBits + ", stopBits: " + stopBits + ", parity: " + parity + ", connectTimeout: "
+ connectTimeout + "ms]", e);
}
}
public void disconnect() {
if (serialConnection != null) {
serialConnection.close();
}
if (serialPort != null) {
cleanupIoStreams();
serialPort.close();
}
System.out.println("Disconnected.");
}
private void checkConnectParams(String portName, int baudrate, int dataBits, int stopBits, int connectTimeout) {
checkNotNull(portName, "portName");
checkGreaterThanZero(baudrate, "baudrate");
checkGreaterThanZero(dataBits, "dataBits");
checkGreaterThanZero(stopBits, "stopBits");
checkGreaterThanZero(connectTimeout, "connectTimeout");
}
private SerialPort resolveSerialPort(String portName, int connectTimeout) {
CommPortIdentifier portIdentifier = resolvePortIdentifier(portName);
return openPort(portIdentifier, connectTimeout);
}
private void initSerialPort(SerialPort serialPort, int baudrate, int dataBits, int stopBits, int parity) {
try {
serialPort.setSerialPortParams(baudrate, dataBits, stopBits, parity);
serialPort.setFlowControlMode(FLOWCONTROL_NONE);
} catch (UnsupportedCommOperationException e) {
throw new UnsupportedOperationException(e);
}
}
private void resolveIoStreams(SerialPort serialPort) {
try {
os = serialPort.getOutputStream();
is = serialPort.getInputStream();
} catch (IOException e) {
cleanupIoStreams();
throw new SerialCommunicationException(e);
}
}
private void cleanupIoStreams() {
try {
try {
if (os != null) {
os.close();
}
} finally {
if (is != null) {
is.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
private SerialConnection doConnect(SerialPort serialPort) {
SerialReader serialReader = new DefaultSerialReader(serialPort);
SerialWriter serialWriter = new DefaultSerialWriter(serialPort);
(new Thread(serialReader)).start();
(new Thread(serialWriter)).start();
return new DefaultSerialConnection(serialWriter, serialReader);
}
private CommPortIdentifier resolvePortIdentifier(String portName) {
try {
return getPortIdentifier(portName);
} catch (NoSuchPortException e) {
throw new PortNotFoundException(e);
}
}
private void checkIsSerialPort(CommPortIdentifier portIdentifier) {
if (portIdentifier.getPortType() != PORT_SERIAL) {
throw new UnsupportedPortTypeException("Port type " + portIdentifier.getPortType() + " not supported - must be serial.");
}
}
private SerialPort openPort(CommPortIdentifier portIdentifier, int connectTimeout) {
checkIsSerialPort(portIdentifier);
try {
return (SerialPort) portIdentifier.open(this.getClass().getName(), connectTimeout);
} catch (PortInUseException e) {
throw new SerialCommunicationException("Port is currently in use: " + portIdentifier.getName());
}
}
}

View File

@ -0,0 +1,11 @@
package enginuity.logger.comms;
import enginuity.logger.query.Query;
public interface SerialConnection {
byte[] transmit(Query query);
void close();
}

View File

@ -0,0 +1,11 @@
package enginuity.logger.comms;
import gnu.io.CommPortIdentifier;
import java.util.List;
public interface SerialPortDiscoverer {
List<CommPortIdentifier> listPorts();
}

View File

@ -0,0 +1,9 @@
package enginuity.logger.comms;
public interface SerialReader extends Runnable {
byte[] read();
void close();
}

View File

@ -0,0 +1,9 @@
package enginuity.logger.comms;
public interface SerialWriter extends Runnable {
void write(byte[] bytes);
void close();
}

View File

@ -0,0 +1,9 @@
package enginuity.logger.comms;
public interface TwoWaySerialComm {
SerialConnection connect(String portName, int baudrate, int dataBits, int stopBits, int parity, int connectTimeout);
void disconnect();
}

View File

@ -0,0 +1,18 @@
package enginuity.logger.exception;
public final class NotConnectedException extends RuntimeException {
public NotConnectedException() {
}
public NotConnectedException(String string) {
super(string);
}
public NotConnectedException(String string, Throwable throwable) {
super(string, throwable);
}
public NotConnectedException(Throwable throwable) {
super(throwable);
}
}

View File

@ -0,0 +1,19 @@
package enginuity.logger.exception;
public final class PortNotFoundException extends RuntimeException {
public PortNotFoundException() {
}
public PortNotFoundException(String string) {
super(string);
}
public PortNotFoundException(String string, Throwable throwable) {
super(string, throwable);
}
public PortNotFoundException(Throwable throwable) {
super(throwable);
}
}

View File

@ -0,0 +1,20 @@
package enginuity.logger.exception;
public final class SerialCommunicationException extends RuntimeException {
public SerialCommunicationException() {
}
public SerialCommunicationException(String msg) {
super(msg);
}
public SerialCommunicationException(String msg, Throwable cause) {
super(msg, cause);
}
public SerialCommunicationException(Throwable cause) {
super(cause);
}
}

View File

@ -0,0 +1,19 @@
package enginuity.logger.exception;
public final class UnsupportedPortTypeException extends RuntimeException {
public UnsupportedPortTypeException() {
}
public UnsupportedPortTypeException(String string) {
super(string);
}
public UnsupportedPortTypeException(String string, Throwable throwable) {
super(string, throwable);
}
public UnsupportedPortTypeException(Throwable throwable) {
super(throwable);
}
}

View File

@ -0,0 +1,72 @@
package enginuity.logger.manager;
import enginuity.Settings;
import enginuity.logger.query.RegisteredQuery;
import static enginuity.util.ParamChecker.checkNotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public final class DefaultQueryManager implements QueryManager {
private final TransmissionManager txManager = new DefaultTransmissionManager();
private final Map<String, RegisteredQuery> queryMap = Collections.synchronizedMap(new HashMap<String, RegisteredQuery>());
private final List<RegisteredQuery> addList = new ArrayList<RegisteredQuery>();
private final List<String> removeList = new ArrayList<String>();
private boolean stop = false;
public synchronized void addQuery(RegisteredQuery registeredQuery) {
checkNotNull(registeredQuery, "registeredQuery");
System.out.println("Adding address: " + registeredQuery.getAddress());
addList.add(registeredQuery);
}
public synchronized void removeQuery(String address) {
removeList.add(address);
}
public void run() {
try {
// TODO: Pass in actual app settings object!! Move TxMgr construction/initialization out to LoggerController
txManager.start(new Settings());
while (!stop) {
updateQueryList();
for (String address : queryMap.keySet()) {
RegisteredQuery registeredQuery = queryMap.get(address);
byte[] response = txManager.queryAddress(address);
registeredQuery.setResponse(response);
}
}
} finally {
txManager.stop();
}
}
public void stop() {
stop = true;
}
private synchronized void updateQueryList() {
addQueries();
removeQueries();
}
private void addQueries() {
for (RegisteredQuery registeredQuery : addList) {
System.out.println("Adding address: " + registeredQuery.getAddress());
queryMap.put(registeredQuery.getAddress(), registeredQuery);
}
addList.clear();
}
private void removeQueries() {
for (String address : removeList) {
System.out.println("Removing address: " + address);
queryMap.remove(address);
}
removeList.clear();
}
}

View File

@ -0,0 +1,41 @@
package enginuity.logger.manager;
import enginuity.Settings;
import enginuity.logger.comms.DefaultTwoWaySerialComm;
import enginuity.logger.comms.SerialConnection;
import enginuity.logger.comms.TwoWaySerialComm;
import enginuity.logger.exception.NotConnectedException;
import enginuity.logger.query.DefaultQuery;
import static gnu.io.SerialPort.DATABITS_8;
import static gnu.io.SerialPort.PARITY_NONE;
import static gnu.io.SerialPort.STOPBITS_1;
public final class DefaultTransmissionManager implements TransmissionManager {
private static final int BAUDRATE = 10400;
private static final int CONNECT_TIMEOUT = 2000;
private final TwoWaySerialComm twoWaySerialComm = new DefaultTwoWaySerialComm();
private SerialConnection serialConnection = null;
public void start(Settings settings) {
serialConnection = twoWaySerialComm.connect(settings.getLoggerPort(), BAUDRATE, DATABITS_8, STOPBITS_1, PARITY_NONE, CONNECT_TIMEOUT);
}
public byte[] queryAddress(String address) {
if (serialConnection != null) {
byte[] request = buildRequest(address);
return serialConnection.transmit(new DefaultQuery(request));
} else {
throw new NotConnectedException("TransmissionManager must be started before an address is queried!");
}
}
public void stop() {
twoWaySerialComm.disconnect();
}
private byte[] buildRequest(String address) {
// TODO Implement this!! What is the correct message format??
return address.getBytes();
}
}

View File

@ -0,0 +1,13 @@
package enginuity.logger.manager;
import enginuity.logger.query.RegisteredQuery;
public interface QueryManager extends Runnable {
void addQuery(RegisteredQuery registeredQuery);
void removeQuery(String address);
void stop();
}

View File

@ -0,0 +1,13 @@
package enginuity.logger.manager;
import enginuity.Settings;
public interface TransmissionManager {
void start(Settings settings);
byte[] queryAddress(String address);
void stop();
}

View File

@ -0,0 +1,29 @@
package enginuity.logger.query;
import enginuity.logger.comms.SerialReader;
import enginuity.logger.comms.SerialWriter;
import enginuity.logger.exception.SerialCommunicationException;
import static enginuity.util.ParamChecker.checkNotNull;
public final class DefaultQuery implements Query {
private byte[] request;
public DefaultQuery(byte[] request) {
this.request = request;
}
public byte[] execute(SerialWriter writer, SerialReader reader) {
checkNotNull(writer, reader);
writer.write(request);
byte[] response;
while ((response = reader.read()).length == 0) {
try {
Thread.sleep(20);
} catch (InterruptedException e) {
throw new SerialCommunicationException(e);
}
}
return response;
}
}

View File

@ -0,0 +1,22 @@
package enginuity.logger.query;
import enginuity.util.ParamChecker;
public final class DefaultRegisteredQuery implements RegisteredQuery {
private final String address;
private final LoggerCallback callback;
public DefaultRegisteredQuery(String address, LoggerCallback callback) {
ParamChecker.checkNotNull(address, callback);
this.address = address;
this.callback = callback;
}
public String getAddress() {
return address;
}
public void setResponse(byte[] response) {
callback.callback(response);
}
}

View File

@ -0,0 +1,7 @@
package enginuity.logger.query;
public interface LoggerCallback {
void callback(byte[] value);
}

View File

@ -0,0 +1,10 @@
package enginuity.logger.query;
import enginuity.logger.comms.SerialReader;
import enginuity.logger.comms.SerialWriter;
public interface Query {
byte[] execute(SerialWriter writer, SerialReader reader);
}

View File

@ -0,0 +1,9 @@
package enginuity.logger.query;
public interface RegisteredQuery {
String getAddress();
void setResponse(byte[] response);
}

View File

@ -0,0 +1,43 @@
package enginuity.util;
public final class ParamChecker {
private ParamChecker() {
}
public static void checkNotNull(Object param, String paramName) {
if (param == null) {
throw new IllegalArgumentException("Parameter " + paramName + " must not be null");
}
}
public static void checkNotNull(Object... params) {
for (int i = 0; i < params.length; i++) {
checkNotNull(params[i], "arg" + i);
}
}
public static void checkNotNullOrEmpty(String param, String paramName) {
if (param == null || param.length() == 0) {
throw new IllegalArgumentException("Parameter " + paramName + " must not be null or empty");
}
}
public static void checkNotNullOrEmpty(Object[] param, String paramName) {
if (param == null || param.length == 0) {
throw new IllegalArgumentException("Parameter " + paramName + " must not be null or empty");
}
}
public static void checkGreaterThanZero(int param, String paramName) {
if (param <= 0) {
throw new IllegalArgumentException("Parameter " + paramName + " must be > 0");
}
}
public static void checkNotNullOrEmpty(byte[] param, String paramName) {
if (param == null || param.length == 0) {
throw new IllegalArgumentException("Parameter " + paramName + " must not be null or empty");
}
}
}