[cooja/serialsocket] SerialSocketServer: Fixed and improved server
implementation. Added visual feedback for new user interface.
This commit is contained in:
parent
585db7df96
commit
a18a7fa717
|
@ -44,9 +44,13 @@ import java.io.IOException;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.text.NumberFormat;
|
import java.text.NumberFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
|
@ -85,12 +89,18 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
|
|
||||||
private final static int STATUSBAR_WIDTH = 350;
|
private final static int STATUSBAR_WIDTH = 350;
|
||||||
|
|
||||||
|
private static final Color COLOR_NEUTRAL = Color.DARK_GRAY;
|
||||||
|
private static final Color COLOR_POSITIVE = new Color(0, 161, 83);
|
||||||
|
private static final Color COLOR_NEGATIVE = Color.RED;
|
||||||
|
|
||||||
private final int SERVER_DEFAULT_PORT;
|
private final int SERVER_DEFAULT_PORT;
|
||||||
|
|
||||||
private final SerialPort serialPort;
|
private final SerialPort serialPort;
|
||||||
private Observer serialDataObserver;
|
private Observer serialDataObserver;
|
||||||
|
|
||||||
private JLabel socketStatusLabel, socketToMoteLabel, moteToSocketLabel;
|
private JLabel socketToMoteLabel;
|
||||||
|
private JLabel moteToSocketLabel;
|
||||||
|
private JLabel socketStatusLabel;
|
||||||
private JButton serverStartButton;
|
private JButton serverStartButton;
|
||||||
|
|
||||||
private int inBytes = 0, outBytes = 0;
|
private int inBytes = 0, outBytes = 0;
|
||||||
|
@ -205,7 +215,12 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
// XXX
|
try {
|
||||||
|
serverPortField.commitEdit();
|
||||||
|
} catch (ParseException ex) {
|
||||||
|
java.util.logging.Logger.getLogger(SerialSocketClient.class.getName()).log(Level.SEVERE, null, ex);
|
||||||
|
}
|
||||||
|
startServer(((Long) serverPortField.getValue()).intValue());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -218,59 +233,188 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
throw new RuntimeException("No mote serial port");
|
throw new RuntimeException("No mote serial port");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (Cooja.isVisualized()) {
|
||||||
logger.info("Listening on port: " + SERVER_DEFAULT_PORT);
|
// gui updates for server status updates
|
||||||
if (Cooja.isVisualized()) {
|
addServerListener(new ServerListener() {
|
||||||
socketStatusLabel.setText("Listening on port: " + SERVER_DEFAULT_PORT);
|
|
||||||
}
|
|
||||||
server = new ServerSocket(SERVER_DEFAULT_PORT);
|
|
||||||
new Thread() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
while (server != null) {
|
|
||||||
try {
|
|
||||||
clientSocket = server.accept();
|
|
||||||
in = new DataInputStream(clientSocket.getInputStream());
|
|
||||||
out = new DataOutputStream(clientSocket.getOutputStream());
|
|
||||||
out.flush();
|
|
||||||
|
|
||||||
startSocketReadThread(in);
|
@Override
|
||||||
if (Cooja.isVisualized()) {
|
public void onServerStarted(final int port) {
|
||||||
socketStatusLabel.setText("Client connected: " + clientSocket.getInetAddress());
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
socketStatusLabel.setForeground(COLOR_NEUTRAL);
|
||||||
|
socketStatusLabel.setText("Listening on port " + String.valueOf(port));
|
||||||
|
serverStartButton.setEnabled(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClientConnected(final Socket client) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
socketStatusLabel.setForeground(COLOR_POSITIVE);
|
||||||
|
socketStatusLabel.setText(String.format("Client " + client.getInetAddress() + " connected."));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClientDisconnected(final Socket client) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
socketStatusLabel.setForeground(COLOR_NEUTRAL);
|
||||||
|
socketStatusLabel.setText("Listening on port " + String.valueOf(server.getLocalPort()));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServerStopped() {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
serverStartButton.setEnabled(true);
|
||||||
|
socketStatusLabel.setForeground(COLOR_NEUTRAL);
|
||||||
|
socketStatusLabel.setText("Idle");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServerError(final String msg) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
socketStatusLabel.setForeground(COLOR_NEGATIVE);
|
||||||
|
socketStatusLabel.setText(msg);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<ServerListener> listeners = new LinkedList<>();
|
||||||
|
|
||||||
|
public interface ServerListener {
|
||||||
|
void onServerStarted(int port);
|
||||||
|
void onClientConnected(Socket client);
|
||||||
|
void onClientDisconnected(Socket client);
|
||||||
|
void onServerStopped();
|
||||||
|
void onServerError(String msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addServerListener(ServerListener listener) {
|
||||||
|
listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyServerStarted(int port) {
|
||||||
|
for (ServerListener listener : listeners) {
|
||||||
|
listener.onServerStarted(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyClientConnected(Socket client) {
|
||||||
|
for (ServerListener listener : listeners) {
|
||||||
|
listener.onClientConnected(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyClientDisconnected(Socket client) {
|
||||||
|
for (ServerListener listener : listeners) {
|
||||||
|
listener.onClientDisconnected(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyServerStopped() {
|
||||||
|
for (ServerListener listener : listeners) {
|
||||||
|
listener.onServerStopped();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void notifyServerError(String msg) {
|
||||||
|
for (ServerListener listener : listeners) {
|
||||||
|
listener.onServerError(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start server ..
|
||||||
|
* @param port
|
||||||
|
*/
|
||||||
|
public void startServer(int port) {
|
||||||
|
try {
|
||||||
|
server = new ServerSocket(port);
|
||||||
|
logger.info("Listening on port: " + port);
|
||||||
|
notifyServerStarted(port);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error(ex.getMessage());
|
||||||
|
notifyServerError(ex.getMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
new Thread() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (!server.isClosed()) {
|
||||||
|
try {
|
||||||
|
// wait for next client
|
||||||
|
clientSocket = server.accept();
|
||||||
|
in = new DataInputStream(clientSocket.getInputStream());
|
||||||
|
out = new DataOutputStream(clientSocket.getOutputStream());
|
||||||
|
out.flush();
|
||||||
|
startSocketReadThread(in);
|
||||||
|
|
||||||
|
/* Observe serial port for outgoing data */
|
||||||
|
serialPort.addSerialDataObserver(serialDataObserver = new Observer() {
|
||||||
|
@Override
|
||||||
|
public void update(Observable obs, Object obj) {
|
||||||
|
try {
|
||||||
|
if (out == null) {
|
||||||
|
/*logger.debug("out is null");*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.write(serialPort.getLastSerialData());
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
outBytes++;
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error(ex);
|
||||||
|
cleanupClient();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
});
|
||||||
logger.fatal("Listening thread shut down: " + e.getMessage());
|
|
||||||
server = null;
|
inBytes = outBytes = 0;
|
||||||
cleanupClient();
|
|
||||||
break;
|
logger.info("Client connected: " + clientSocket.getInetAddress());
|
||||||
|
notifyClientConnected(clientSocket);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.fatal("Listening thread shut down: " + e.getMessage());
|
||||||
|
try {
|
||||||
|
server.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.error(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.start();
|
cleanupClient();
|
||||||
} catch (Exception e) {
|
notifyServerStopped();
|
||||||
throw (RuntimeException) new RuntimeException(
|
|
||||||
"Connection error: " + e.getMessage()).initCause(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Observe serial port for outgoing data */
|
|
||||||
serialPort.addSerialDataObserver(serialDataObserver = new Observer() {
|
|
||||||
@Override
|
|
||||||
public void update(Observable obs, Object obj) {
|
|
||||||
try {
|
|
||||||
if (out == null) {
|
|
||||||
/*logger.debug("out is null");*/
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
out.write(serialPort.getLastSerialData());
|
|
||||||
out.flush();
|
|
||||||
|
|
||||||
outBytes++;
|
|
||||||
} catch (IOException e) {
|
|
||||||
cleanupClient();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
}.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startSocketReadThread(final DataInputStream in) {
|
private void startSocketReadThread(final DataInputStream in) {
|
||||||
|
@ -281,25 +425,21 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
int numRead = 0;
|
int numRead = 0;
|
||||||
byte[] data = new byte[1024];
|
byte[] data = new byte[1024];
|
||||||
logger.info("Forwarder: socket -> serial port");
|
logger.info("Forwarder: socket -> serial port");
|
||||||
while (true) {
|
while (numRead >= 0) {
|
||||||
numRead = -1;
|
for (int i = 0; i < numRead; i++) {
|
||||||
|
serialPort.writeByte(data[i]);
|
||||||
|
}
|
||||||
|
inBytes += numRead;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
numRead = in.read(data);
|
numRead = in.read(data);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
numRead = -1;
|
numRead = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (numRead >= 0) {
|
|
||||||
for (int i=0; i < numRead; i++) {
|
|
||||||
serialPort.writeByte(data[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
inBytes += numRead;
|
|
||||||
} else {
|
|
||||||
cleanupClient();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
logger.info("End of Stream");
|
||||||
|
cleanupClient();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
incomingDataThread.start();
|
incomingDataThread.start();
|
||||||
|
@ -322,6 +462,7 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
clientSocket = null;
|
clientSocket = null;
|
||||||
}
|
}
|
||||||
} catch (IOException e1) {
|
} catch (IOException e1) {
|
||||||
|
logger.error(e1.getMessage());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (in != null) {
|
if (in != null) {
|
||||||
|
@ -329,6 +470,7 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
in = null;
|
in = null;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (out != null) {
|
if (out != null) {
|
||||||
|
@ -336,16 +478,11 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
out = null;
|
out = null;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
logger.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
serialPort.deleteSerialDataObserver(serialDataObserver);
|
||||||
|
|
||||||
if (Cooja.isVisualized()) {
|
notifyClientDisconnected(null);
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
socketStatusLabel.setText("Listening on port: " + SERVER_DEFAULT_PORT);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean closed = false;
|
private boolean closed = false;
|
||||||
|
@ -353,7 +490,6 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
public void closePlugin() {
|
public void closePlugin() {
|
||||||
closed = true;
|
closed = true;
|
||||||
cleanupClient();
|
cleanupClient();
|
||||||
serialPort.deleteSerialDataObserver(serialDataObserver);
|
|
||||||
try {
|
try {
|
||||||
server.close();
|
server.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
Loading…
Reference in a new issue