Added more options to send and receive data (via command, file, standard in)

This commit is contained in:
nifi 2010-10-07 21:13:00 +00:00
parent 20e04b5c23
commit e770e87995
9 changed files with 777 additions and 245 deletions

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: CollectServer.java,v 1.23 2010/10/03 20:19:12 adamdunkels Exp $ * $Id: CollectServer.java,v 1.24 2010/10/07 21:13:00 nifi Exp $
* *
* ----------------------------------------------------------------- * -----------------------------------------------------------------
* *
@ -34,8 +34,8 @@
* *
* Authors : Joakim Eriksson, Niclas Finne * Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008 * Created : 3 jul 2008
* Updated : $Date: 2010/10/03 20:19:12 $ * Updated : $Date: 2010/10/07 21:13:00 $
* $Revision: 1.23 $ * $Revision: 1.24 $
*/ */
package se.sics.contiki.collect; package se.sics.contiki.collect;
@ -93,9 +93,10 @@ import se.sics.contiki.collect.gui.TimeChartPanel;
/** /**
* *
*/ */
public class CollectServer { public class CollectServer implements SerialConnectionListener {
public static final String WINDOW_TITLE = "Sensor Data Collect with Contiki"; public static final String WINDOW_TITLE = "Sensor Data Collect with Contiki";
public static final String STDIN_COMMAND = "<STDIN>";
public static final String CONFIG_FILE = "collect.conf"; public static final String CONFIG_FILE = "collect.conf";
public static final String SENSORDATA_FILE = "sensordata.log"; public static final String SENSORDATA_FILE = "sensordata.log";
@ -116,6 +117,7 @@ public class CollectServer {
private ArrayList<SensorData> sensorDataList = new ArrayList<SensorData>(); private ArrayList<SensorData> sensorDataList = new ArrayList<SensorData>();
private PrintWriter sensorDataOutput; private PrintWriter sensorDataOutput;
private boolean isSensorLogUsed;
private Hashtable<String,Node> nodeTable = new Hashtable<String,Node>(); private Hashtable<String,Node> nodeTable = new Hashtable<String,Node>();
private Node[] nodeCache; private Node[] nodeCache;
@ -136,21 +138,20 @@ public class CollectServer {
private Node[] selectedNodes; private Node[] selectedNodes;
private SerialConnection serialConnection; private SerialConnection serialConnection;
private boolean hasSerialOpened;
private boolean hasSentInit;
private String initScript; private String initScript;
private long nodeTimeDelta; private long nodeTimeDelta;
@SuppressWarnings("serial") @SuppressWarnings("serial")
public CollectServer(String comPort) { public CollectServer() {
loadConfig(config, CONFIG_FILE); loadConfig(config, CONFIG_FILE);
this.configFile = config.getProperty("config.datafile", CONFIG_DATA_FILE); this.configFile = config.getProperty("config.datafile", CONFIG_DATA_FILE);
if (this.configFile != null) { if (this.configFile != null) {
loadConfig(configTable, this.configFile); loadConfig(configTable, this.configFile);
} }
if (comPort == null) {
comPort = configTable.getProperty("collect.serialport");
}
this.initScript = config.getProperty("init.script", INIT_SCRIPT); this.initScript = config.getProperty("init.script", INIT_SCRIPT);
/* Make sure we have nice window decorations */ /* Make sure we have nice window decorations */
@ -631,7 +632,9 @@ public class CollectServer {
item.addActionListener(new ActionListener() { item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
int reply = JOptionPane.showConfirmDialog(window, "Also clear the sensor data log file?"); int reply = isSensorLogUsed
? JOptionPane.showConfirmDialog(window, "Also clear the sensor data log file?")
: JOptionPane.NO_OPTION;
if (reply == JOptionPane.YES_OPTION) { if (reply == JOptionPane.YES_OPTION) {
// Clear data from both memory and sensor log file // Clear data from both memory and sensor log file
clearSensorDataLog(); clearSensorDataLog();
@ -713,96 +716,31 @@ public class CollectServer {
getNode(property, true); getNode(property, true);
} }
} }
initSensorData(); }
void start(SerialConnection connection) {
if (this.serialConnection != null) {
throw new IllegalStateException("already started");
}
this.serialConnection = connection;
if (isSensorLogUsed) {
initSensorData();
}
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
public void run() { public void run() {
window.setVisible(true); window.setVisible(true);
} }
}); });
serialConnection = new SerialConnection() {
private boolean hasOpened;
private boolean hasSentInit;
@Override
protected void serialOpened() {
serialConsole.addSerialData("*** Serial console listening on port: " + getComPort() + " ***");
hasOpened = true;
// Remember the last selected serial port
configTable.put("collect.serialport", getComPort());
setSystemMessage("connected to " + getComPort());
// Send any initial commands
if (!hasSentInit) {
hasSentInit = true;
if (hasInitScript()) {
// Wait a short time before running the init script
sleep(3000);
runInitScript();
}
}
}
@Override
protected void serialClosed() {
String comPort = getComPort();
String prefix;
if (hasOpened) {
serialConsole.addSerialData("*** Serial connection terminated ***");
prefix = "Serial connection terminated.\n";
hasOpened = false;
setSystemMessage("not connected");
} else {
prefix = "Failed to connect to " + getComPort() + '\n';
}
if (!isClosed) {
String options[] = {"Retry", "Search for connected nodes", "Cancel"};
int value = JOptionPane.showOptionDialog(window,
prefix + "Do you want to retry or search for connected nodes?",
"Reconnect to serial port?",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
null, options, options[0]);
if (value == JOptionPane.CLOSED_OPTION || value == 2) {
// exit();
} else {
if (value == 1) {
// Select new serial port
comPort = MoteFinder.selectComPort(window);
if (comPort == null) {
// exit();
}
}
// Try to open com port again
if (comPort != null) {
open(comPort);
}
}
}
}
@Override
protected void serialData(String line) {
parseIncomingLine(System.currentTimeMillis(), line);
}
};
if (comPort != null) {
serialConnection.setComPort(comPort);
}
connectToSerial(); connectToSerial();
} }
protected void connectToSerial() { protected void connectToSerial() {
if (!serialConnection.isOpen()) { if (!serialConnection.isOpen()) {
String comPort = serialConnection.getComPort(); String comPort = serialConnection.getComPort();
if (comPort == null) { if (comPort == null && serialConnection.isMultiplePortsSupported()) {
comPort = MoteFinder.selectComPort(window); comPort = MoteFinder.selectComPort(window);
} }
if (comPort != null) { if (comPort != null || !serialConnection.isMultiplePortsSupported()) {
serialConnection.open(comPort); serialConnection.open(comPort);
} }
} }
@ -893,14 +831,15 @@ public class CollectServer {
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
public void run() { public void run() {
boolean isOpen = serialConnection.isOpen(); boolean isOpen = serialConnection != null && serialConnection.isOpen();
if (message == null) { if (message == null) {
window.setTitle(WINDOW_TITLE); window.setTitle(WINDOW_TITLE);
} else { } else {
window.setTitle(WINDOW_TITLE + " (" + message + ')'); window.setTitle(WINDOW_TITLE + " (" + message + ')');
} }
serialItem.setText(isOpen ? "Disconnect from serial" : "Connect to serial"); serialItem.setText(isOpen ? "Disconnect from serial" : "Connect to serial");
runInitScriptItem.setEnabled(isOpen && hasInitScript()); runInitScriptItem.setEnabled(isOpen
&& serialConnection.isSerialOutputSupported() && hasInitScript());
} }
}); });
@ -1073,7 +1012,7 @@ public class CollectServer {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
public boolean sendToNode(String data) { public boolean sendToNode(String data) {
if (serialConnection != null && serialConnection.isOpen()) { if (serialConnection != null && serialConnection.isOpen() && serialConnection.isSerialOutputSupported()) {
serialConsole.addSerialData("SEND: " + data); serialConsole.addSerialData("SEND: " + data);
serialConnection.writeSerialData(data); serialConnection.writeSerialData(data);
return true; return true;
@ -1148,10 +1087,10 @@ public class CollectServer {
} }
private void initSensorData() { private void initSensorData() {
loadSensorData(SENSORDATA_FILE); loadSensorData(SENSORDATA_FILE, true);
} }
private boolean loadSensorData(String filename) { private boolean loadSensorData(String filename, boolean isStrict) {
File fp = new File(filename); File fp = new File(filename);
if (fp.exists() && fp.canRead()) { if (fp.exists() && fp.canRead()) {
BufferedReader in = null; BufferedReader in = null;
@ -1171,7 +1110,7 @@ public class CollectServer {
sensorDataList.add(data); sensorDataList.add(data);
handleLinks(data); handleLinks(data);
} }
} else { } else if (isStrict) {
// TODO exit here? // TODO exit here?
System.err.println("Failed to parse sensor data from log line " + no + ": " + line); System.err.println("Failed to parse sensor data from log line " + no + ": " + line);
} }
@ -1189,7 +1128,7 @@ public class CollectServer {
private void saveSensorData(SensorData data) { private void saveSensorData(SensorData data) {
PrintWriter output = this.sensorDataOutput; PrintWriter output = this.sensorDataOutput;
if (output == null) { if (output == null && isSensorLogUsed) {
try { try {
output = sensorDataOutput = new PrintWriter(new FileWriter(SENSORDATA_FILE, true)); output = sensorDataOutput = new PrintWriter(new FileWriter(SENSORDATA_FILE, true));
} catch (IOException e) { } catch (IOException e) {
@ -1288,8 +1227,10 @@ public class CollectServer {
int reply = JOptionPane.showConfirmDialog(window, "Found " + motes.length + " connected Sky nodes.\n" int reply = JOptionPane.showConfirmDialog(window, "Found " + motes.length + " connected Sky nodes.\n"
+ "Do you want to upload the firmware " + FIRMWARE_FILE + '?'); + "Do you want to upload the firmware " + FIRMWARE_FILE + '?');
if (reply == JFileChooser.APPROVE_OPTION) { if (reply == JFileChooser.APPROVE_OPTION) {
boolean wasOpen = serialConnection.isOpen(); boolean wasOpen = serialConnection != null && serialConnection.isOpen();
serialConnection.close(); if (serialConnection != null) {
serialConnection.close();
}
if (wasOpen) { if (wasOpen) {
Thread.sleep(1000); Thread.sleep(1000);
} }
@ -1309,20 +1250,177 @@ public class CollectServer {
} }
// -------------------------------------------------------------------
// SerialConnection Listener
// -------------------------------------------------------------------
@Override
public void serialData(SerialConnection connection, String line) {
parseIncomingLine(System.currentTimeMillis(), line);
}
@Override
public void serialOpened(SerialConnection connection) {
String connectionName = connection.getConnectionName();
serialConsole.addSerialData("*** Serial console listening on " + connectionName + " ***");
hasSerialOpened = true;
if (connection.isMultiplePortsSupported()) {
String comPort = connection.getComPort();
// Remember the last selected serial port
configTable.put("collect.serialport", comPort);
}
setSystemMessage("connected to " + connectionName);
if (!connection.isSerialOutputSupported()) {
serialConsole.addSerialData("*** Serial output not supported ***");
} else if (!hasSentInit) {
// Send any initial commands
hasSentInit = true;
if (hasInitScript()) {
// Wait a short time before running the init script
sleep(3000);
runInitScript();
}
}
}
@Override
public void serialClosed(SerialConnection connection) {
String prefix;
if (hasSerialOpened) {
serialConsole.addSerialData("*** Serial connection terminated ***");
prefix = "Serial connection terminated.\n";
hasSerialOpened = false;
setSystemMessage("not connected");
} else {
prefix = "Failed to connect to " + connection.getConnectionName() + '\n';
}
if (!connection.isClosed()) {
if (connection.isMultiplePortsSupported()) {
String options[] = {"Retry", "Search for connected nodes", "Cancel"};
int value = JOptionPane.showOptionDialog(window,
prefix + "Do you want to retry or search for connected nodes?",
"Reconnect to serial port?",
JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE,
null, options, options[0]);
if (value == JOptionPane.CLOSED_OPTION || value == 2) {
// exit();
} else {
String comPort = connection.getComPort();
if (value == 1) {
// Select new serial port
comPort = MoteFinder.selectComPort(window);
if (comPort == null) {
// exit();
}
}
// Try to open com port again
if (comPort != null) {
connection.open(comPort);
}
}
} else {
// JOptionPane.showMessageDialog(window,
// prefix, "Serial Connection Closed", JOptionPane.ERROR_MESSAGE);
}
}
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Main // Main
// ------------------------------------------------------------------- // -------------------------------------------------------------------
public static void main(String[] args) { public static void main(String[] args) {
boolean resetSensorLog = false;
boolean useSensorLog = true;
boolean useSerialOutput = true;
String command = null;
String logFileToLoad = null;
String comPort = null; String comPort = null;
if (args.length > 0) { for(int i = 0, n = args.length; i < n; i++) {
if (args.length > 1 || args[0].startsWith("-h")) { String arg = args[i];
System.err.println("Usage: java CollectServer COMPORT"); if (arg.length() == 2 && arg.charAt(0) == '-') {
System.exit(1); switch (arg.charAt(1)) {
case 'c':
if (i + 1 < n) {
command = args[++i];
} else {
usage(arg);
}
break;
case 'r':
resetSensorLog = true;
break;
case 'n':
useSensorLog = false;
break;
case 'i':
useSerialOutput = false;
break;
case 'f':
command = STDIN_COMMAND;
if (i + 1 < n && !args[i + 1].startsWith("-")) {
logFileToLoad = args[++i];
}
break;
case 'h':
usage(null);
break;
default:
usage(arg);
break;
}
} else if (comPort == null) {
comPort = arg;
} else {
usage(arg);
} }
comPort = args[0];
} }
new CollectServer(comPort);
CollectServer server = new CollectServer();
SerialConnection serialConnection;
if (command == null) {
serialConnection = new SerialDumpConnection(server);
} else if (command == STDIN_COMMAND) {
serialConnection = new StdinConnection(server);
} else {
serialConnection = new CommandConnection(server, command);
}
if (comPort == null) {
comPort = server.getConfig("collect.serialport");
}
if (comPort != null) {
serialConnection.setComPort(comPort);
}
if (!useSerialOutput) {
serialConnection.setSerialOutputSupported(false);
}
server.isSensorLogUsed = useSensorLog;
if (useSensorLog && resetSensorLog) {
server.clearSensorDataLog();
}
if (logFileToLoad != null) {
server.loadSensorData(logFileToLoad, false);
}
server.start(serialConnection);
} }
private static void usage(String arg) {
if (arg != null) {
System.err.println("Unknown argument '" + arg + '\'');
}
System.err.println("Usage: java CollectServer [-n] [-i] [-r] [-f [file]] [-c command] [COMPORT]");
System.err.println(" -n : Do not read or save sensor data log");
System.err.println(" -r : Clear any existing sensor data log at startup");
System.err.println(" -i : Do not allow serial output");
System.err.println(" -f : Read serial data from standard in");
System.err.println(" -c : Use specified command for serial data input/output");
System.err.println(" COMPORT: The serial port to connect to");
System.exit(arg != null ? 1 : 0);
}
} }

View File

@ -0,0 +1,165 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: CommandConnection.java,v 1.1 2010/10/07 21:13:00 nifi Exp $
*
* -----------------------------------------------------------------
*
* CommandConnection
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 5 oct 2010
* Updated : $Date: 2010/10/07 21:13:00 $
* $Revision: 1.1 $
*/
package se.sics.contiki.collect;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
/**
*
*/
public class CommandConnection extends SerialConnection {
protected Process commandProcess;
protected String command;
public CommandConnection(SerialConnectionListener listener) {
super(listener);
}
public CommandConnection(SerialConnectionListener listener, String command) {
super(listener);
this.command = command;
}
@Override
public String getConnectionName() {
return command;
}
public String getCommand() {
return command;
}
public void setCommand(String command) {
this.command = command;
}
@Override
public void open(String comPort) {
close();
this.comPort = comPort == null ? "" : comPort;
String fullCommand = getCommand();
isClosed = false;
try {
String[] cmd = fullCommand.split(" ");
System.err.println("Running '" + fullCommand + '\'');
commandProcess = Runtime.getRuntime().exec(cmd);
final BufferedReader input = new BufferedReader(new InputStreamReader(commandProcess.getInputStream()));
final BufferedReader err = new BufferedReader(new InputStreamReader(commandProcess.getErrorStream()));
setSerialOutput(new PrintWriter(new OutputStreamWriter(commandProcess.getOutputStream())));
/* Start thread listening on standard out */
Thread readInput = new Thread(new Runnable() {
public void run() {
String line;
try {
while ((line = input.readLine()) != null) {
standardData(line);
}
input.close();
System.err.println("SerialConnection command terminated.");
closeConnection();
} catch (IOException e) {
lastError = "Error when reading from SerialConnection command: " + e;
System.err.println(lastError);
if (!isClosed) {
e.printStackTrace();
closeConnection();
}
}
}
}, "read input stream thread");
/* Start thread listening on standard err */
Thread readError = new Thread(new Runnable() {
public void run() {
String line;
try {
while ((line = err.readLine()) != null) {
errorData(line);
}
err.close();
} catch (IOException e) {
if (!isClosed) {
System.err.println("Error when reading from SerialConnection command: " + e);
e.printStackTrace();
}
}
}
}, "read error stream thread");
readInput.start();
readError.start();
} catch (Exception e) {
lastError = "Failed to execute '" + fullCommand + "': " + e;
System.err.println(lastError);
e.printStackTrace();
closeConnection();
}
}
protected void standardData(String line) {
if (!isOpen) {
isOpen = true;
serialOpened();
}
serialData(line);
}
protected void errorData(String line) {
System.err.println("SerialConnection error stream> " + line);
}
@Override
protected void doClose() {
if (commandProcess != null) {
commandProcess.destroy();
commandProcess = null;
}
}
}

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: Node.java,v 1.6 2010/09/30 22:24:45 nifi Exp $ * $Id: Node.java,v 1.7 2010/10/07 21:13:00 nifi Exp $
* *
* ----------------------------------------------------------------- * -----------------------------------------------------------------
* *
@ -34,8 +34,8 @@
* *
* Authors : Joakim Eriksson, Niclas Finne * Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008 * Created : 3 jul 2008
* Updated : $Date: 2010/09/30 22:24:45 $ * Updated : $Date: 2010/10/07 21:13:00 $
* $Revision: 1.6 $ * $Revision: 1.7 $
*/ */
package se.sics.contiki.collect; package se.sics.contiki.collect;
@ -176,8 +176,7 @@ public class Node implements Comparable<Node> {
public boolean addSensorData(SensorData data) { public boolean addSensorData(SensorData data) {
if (sensorDataList.size() > 0) { if (sensorDataList.size() > 0) {
SensorData last = sensorDataList.get(sensorDataList.size() - 1); SensorData last = sensorDataList.get(sensorDataList.size() - 1);
// TODO should check seqno! if (data.getNodeTime() < last.getNodeTime()) {
if (data.getNodeTime() <= last.getNodeTime()) {
// Sensor data already added // Sensor data already added
System.out.println("SensorData: ignoring (time " + (data.getNodeTime() - last.getNodeTime()) System.out.println("SensorData: ignoring (time " + (data.getNodeTime() - last.getNodeTime())
+ "msec): " + data); + "msec): " + data);

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: SerialConnection.java,v 1.3 2008/09/03 13:35:21 nifi Exp $ * $Id: SerialConnection.java,v 1.4 2010/10/07 21:13:00 nifi Exp $
* *
* ----------------------------------------------------------------- * -----------------------------------------------------------------
* *
@ -34,15 +34,11 @@
* *
* Authors : Joakim Eriksson, Niclas Finne * Authors : Joakim Eriksson, Niclas Finne
* Created : 5 jul 2008 * Created : 5 jul 2008
* Updated : $Date: 2008/09/03 13:35:21 $ * Updated : $Date: 2010/10/07 21:13:00 $
* $Revision: 1.3 $ * $Revision: 1.4 $
*/ */
package se.sics.contiki.collect; package se.sics.contiki.collect;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter; import java.io.PrintWriter;
/** /**
@ -50,20 +46,43 @@ import java.io.PrintWriter;
*/ */
public abstract class SerialConnection { public abstract class SerialConnection {
public static final String SERIALDUMP_WINDOWS = "./tools/serialdump-windows.exe"; protected final SerialConnectionListener listener;
public static final String SERIALDUMP_LINUX = "./tools/serialdump-linux";
private String comPort; protected boolean isSerialOutputSupported = true;
private Process serialDumpProcess;
private PrintWriter serialOutput; protected String comPort;
protected boolean isOpen; protected boolean isOpen;
protected boolean isClosed = true; protected boolean isClosed = true;
protected String lastError; protected String lastError;
protected PrintWriter serialOutput;
protected SerialConnection(SerialConnectionListener listener) {
this.listener = listener;
}
public boolean isMultiplePortsSupported() {
return false;
}
public void setSerialOutputSupported(boolean isSerialOutputSupported) {
this.isSerialOutputSupported = isSerialOutputSupported;
}
public boolean isSerialOutputSupported() {
return isSerialOutputSupported;
}
public boolean isOpen() { public boolean isOpen() {
return isOpen; return isOpen;
} }
public boolean isClosed() {
return isClosed;
}
public abstract String getConnectionName();
public String getComPort() { public String getComPort() {
return comPort; return comPort;
} }
@ -76,91 +95,12 @@ public abstract class SerialConnection {
return lastError; return lastError;
} }
public void open(String comPort) { protected PrintWriter getSerialOutput() {
if (comPort == null) { return serialOutput;
throw new IllegalStateException("no com port");
}
close();
this.comPort = comPort;
/* Connect to COM using external serialdump application */
String osName = System.getProperty("os.name").toLowerCase();
String fullCommand;
if (osName.startsWith("win")) {
fullCommand = SERIALDUMP_WINDOWS + " " + "-b115200" + " " + getMappedComPortForWindows(comPort);
} else {
fullCommand = SERIALDUMP_LINUX + " " + "-b115200" + " " + comPort;
}
isClosed = false;
try {
String[] cmd = fullCommand.split(" ");
serialDumpProcess = Runtime.getRuntime().exec(cmd);
final BufferedReader input = new BufferedReader(new InputStreamReader(serialDumpProcess.getInputStream()));
final BufferedReader err = new BufferedReader(new InputStreamReader(serialDumpProcess.getErrorStream()));
serialOutput = new PrintWriter(new OutputStreamWriter(serialDumpProcess.getOutputStream()));
/* Start thread listening on stdout */
Thread readInput = new Thread(new Runnable() {
public void run() {
String line;
try {
while ((line = input.readLine()) != null) {
serialData(line);
}
input.close();
System.out.println("Serialdump process terminated.");
closeConnection();
} catch (IOException e) {
lastError = "Error when reading from serialdump process: " + e;
System.err.println(lastError);
if (!isClosed) {
e.printStackTrace();
closeConnection();
}
}
}
}, "read input stream thread");
/* Start thread listening on stderr */
Thread readError = new Thread(new Runnable() {
public void run() {
String line;
try {
while ((line = err.readLine()) != null) {
if (!isOpen && line.startsWith("connecting") && line.endsWith("[OK]")) {
isOpen = true;
serialOpened();
} else {
System.err.println("Serialdump error stream> " + line);
}
}
err.close();
} catch (IOException e) {
if (!isClosed) {
System.err.println("Error when reading from serialdump process: " + e);
e.printStackTrace();
}
}
}
}, "read error stream thread");
readInput.start();
readError.start();
} catch (Exception e) {
lastError = "Failed to execute '" + fullCommand + "': " + e;
System.err.println(lastError);
e.printStackTrace();
closeConnection();
}
} }
private String getMappedComPortForWindows(String comPort) { protected void setSerialOutput(PrintWriter serialOutput) {
if (comPort.startsWith("COM")) { this.serialOutput = serialOutput;
comPort = "/dev/com" + comPort.substring(3);
}
return comPort;
} }
public void writeSerialData(String data) { public void writeSerialData(String data) {
@ -171,29 +111,36 @@ public abstract class SerialConnection {
} }
} }
public void close() { public abstract void open(String comPort);
public final void close() {
isClosed = true; isClosed = true;
lastError = null; lastError = null;
closeConnection(); closeConnection();
} }
protected void closeConnection() { protected final void closeConnection() {
isOpen = false; isOpen = false;
if (serialOutput != null) { if (serialOutput != null) {
serialOutput.close(); serialOutput.close();
serialOutput = null; serialOutput = null;
} }
if (serialDumpProcess != null) { doClose();
serialDumpProcess.destroy();
serialDumpProcess = null;
}
serialClosed(); serialClosed();
} }
protected abstract void serialData(String line); protected abstract void doClose();
protected abstract void serialOpened(); protected final void serialData(String line) {
listener.serialData(this, line);
}
protected abstract void serialClosed(); protected final void serialOpened() {
listener.serialOpened(this);
}
protected final void serialClosed() {
listener.serialClosed(this);
}
} }

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: SerialConnectionListener.java,v 1.1 2010/10/07 21:13:00 nifi Exp $
*
* -----------------------------------------------------------------
*
* SerialConnectionListener
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 5 oct 2010
* Updated : $Date: 2010/10/07 21:13:00 $
* $Revision: 1.1 $
*/
package se.sics.contiki.collect;
public interface SerialConnectionListener {
public void serialData(SerialConnection connection, String line);
public void serialOpened(SerialConnection connection);
public void serialClosed(SerialConnection connection);
}

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: SerialDumpConnection.java,v 1.1 2010/10/07 21:13:00 nifi Exp $
*
* -----------------------------------------------------------------
*
* SerialDumpConnection
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 5 oct 2010
* Updated : $Date: 2010/10/07 21:13:00 $
* $Revision: 1.1 $
*/
package se.sics.contiki.collect;
/**
*
*/
public class SerialDumpConnection extends CommandConnection {
public static final String SERIALDUMP_WINDOWS = "./tools/serialdump-windows.exe";
public static final String SERIALDUMP_LINUX = "./tools/serialdump-linux";
public SerialDumpConnection(SerialConnectionListener listener) {
super(listener);
}
@Override
public boolean isMultiplePortsSupported() {
return true;
}
@Override
public String getConnectionName() {
return comPort;
}
@Override
public void open(String comPort) {
if (comPort == null) {
throw new IllegalStateException("no com port");
}
/* Connect to COM using external serialdump application */
String osName = System.getProperty("os.name").toLowerCase();
String fullCommand;
if (osName.startsWith("win")) {
fullCommand = SERIALDUMP_WINDOWS + " " + "-b115200" + " " + getMappedComPortForWindows(comPort);
} else {
fullCommand = SERIALDUMP_LINUX + " " + "-b115200" + " " + comPort;
}
setCommand(fullCommand);
super.open(comPort);
}
@Override
protected void standardData(String line) {
serialData(line);
}
@Override
protected void errorData(String line) {
if (!isOpen && line.startsWith("connecting") && line.endsWith("[OK]")) {
isOpen = true;
serialOpened();
} else {
super.errorData(line);
}
}
private String getMappedComPortForWindows(String comPort) {
if (comPort.startsWith("COM")) {
comPort = "/dev/com" + comPort.substring(3);
}
return comPort;
}
}

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the Institute nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: StdinConnection.java,v 1.1 2010/10/07 21:13:00 nifi Exp $
*
* -----------------------------------------------------------------
*
* StdinConnection
*
* Authors : Niclas Finne
* Created : 5 oct 2010
* Updated : $Date: 2010/10/07 21:13:00 $
* $Revision: 1.1 $
*/
package se.sics.contiki.collect;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
/**
*
*/
public class StdinConnection extends SerialConnection {
private PrintWriter stdout;
public StdinConnection(SerialConnectionListener listener) {
super(listener);
// Redirect standard out as standard err to use standard out for serial output
stdout = new PrintWriter(new OutputStreamWriter(System.out));
System.setOut(System.err);
}
@Override
public String getConnectionName() {
return "<stdin>";
}
@Override
public void open(String comPort) {
close();
this.comPort = comPort == null ? "" : comPort;
isClosed = false;
try {
final BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
setSerialOutput(stdout);
/* Start thread listening on standard in */
Thread readInput = new Thread(new Runnable() {
public void run() {
String line;
try {
while ((line = input.readLine()) != null) {
serialData(line);
// Do not send data too fast
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
input.close();
System.out.println("SerialConnection stdin terminated.");
closeConnection();
} catch (IOException e) {
lastError = "Error when reading from SerialConnection stdin: " + e;
System.err.println(lastError);
if (!isClosed) {
e.printStackTrace();
closeConnection();
}
}
}
}, "read input stream thread");
isOpen = true;
serialOpened();
readInput.start();
} catch (Exception e) {
lastError = "Failed to open stdin for reading: " + e;
System.err.println(lastError);
e.printStackTrace();
closeConnection();
}
}
@Override
protected void doClose() {
}
}

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: NodeControl.java,v 1.3 2010/10/03 20:19:37 adamdunkels Exp $ * $Id: NodeControl.java,v 1.4 2010/10/07 21:13:00 nifi Exp $
* *
* ----------------------------------------------------------------- * -----------------------------------------------------------------
* *
@ -34,14 +34,15 @@
* *
* Authors : Niclas Finne * Authors : Niclas Finne
* Created : 27 sep 2010 * Created : 27 sep 2010
* Updated : $Date: 2010/10/03 20:19:37 $ * Updated : $Date: 2010/10/07 21:13:00 $
* $Revision: 1.3 $ * $Revision: 1.4 $
*/ */
package se.sics.contiki.collect.gui; package se.sics.contiki.collect.gui;
import java.awt.BorderLayout; import java.awt.BorderLayout;
import java.awt.Color; import java.awt.Color;
import java.awt.Component; import java.awt.Component;
import java.awt.Cursor;
import java.awt.GridBagConstraints; import java.awt.GridBagConstraints;
import java.awt.GridBagLayout; import java.awt.GridBagLayout;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
@ -63,6 +64,8 @@ import se.sics.contiki.collect.Visualizer;
*/ */
public class NodeControl implements Visualizer { public class NodeControl implements Visualizer {
private final static String SET_TIME_COMMAND = "time %TIME% | null";
private final CollectServer server; private final CollectServer server;
private final String category; private final String category;
private final JPanel panel; private final JPanel panel;
@ -79,15 +82,11 @@ public class NodeControl implements Visualizer {
final JFormattedTextField rexmitsField = new JFormattedTextField(new Integer(15)); final JFormattedTextField rexmitsField = new JFormattedTextField(new Integer(15));
statusLabel = new JLabel("", JLabel.CENTER); statusLabel = new JLabel("", JLabel.CENTER);
statusLabel.setOpaque(true); statusLabel.setOpaque(true);
statusLabel.setBackground(Color.white);
statusLabel.setBorder(LineBorder.createBlackLineBorder());
statusLabel.setVisible(false);
JButton stopButton = new JButton("Send stop to nodes"); JButton stopButton = createCommandButton("Send stop to nodes", "netcmd killall");
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sendCommand("netcmd killall");
}
});
JButton sendButton = new JButton("Send command to nodes"); JButton sendButton = new JButton("Send command to nodes");
sendButton.addActionListener(new ActionListener() { sendButton.addActionListener(new ActionListener() {
@ -104,6 +103,10 @@ public class NodeControl implements Visualizer {
}); });
JButton collectButton = createCommandButton("Start Collect",
"mac 0", SET_TIME_COMMAND, "collect | timestamp | blink | binprint &");
JButton stopCollectButton = createCommandButton("Stop Collect", "~K", "killall");
JPanel controlPanel = new JPanel(new GridBagLayout()); JPanel controlPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints(); GridBagConstraints c = new GridBagConstraints();
@ -144,35 +147,76 @@ public class NodeControl implements Visualizer {
controlPanel.add(new JLabel("(0 = report forever)"), c); controlPanel.add(new JLabel("(0 = report forever)"), c);
c.gridy++; c.gridy++;
c.gridx = 1; c.gridwidth = 3;
c.weightx = 0; c.weightx = 0;
c.fill = GridBagConstraints.NONE; c.fill = GridBagConstraints.NONE;
c.insets.bottom = 50; c.insets.bottom = 20;
controlPanel.add(sendButton, c); JPanel p = new JPanel();
p.add(sendButton);
p.add(stopButton);
controlPanel.add(p, c);
c.gridx = 0;
c.gridy++; c.gridy++;
c.gridwidth = 3; c.insets.bottom = 3;
c.ipadx = c.ipady = 6; controlPanel.add(new JLabel("Base Station Control", JLabel.CENTER), c);
controlPanel.add(statusLabel, c);
c.gridy++;
c.insets.bottom = 20;
p = new JPanel();
p.add(collectButton);
p.add(stopCollectButton);
controlPanel.add(p, c);
panel.add(controlPanel, BorderLayout.NORTH); panel.add(controlPanel, BorderLayout.NORTH);
panel.add(statusLabel, BorderLayout.SOUTH);
controlPanel = new JPanel();
controlPanel.add(stopButton);
panel.add(controlPanel, BorderLayout.SOUTH);
} }
protected void sendCommand(String command) { private JButton createCommandButton(String name, final String... command) {
statusLabel.setBackground(Color.white); JButton button = new JButton(name);
statusLabel.setBorder(LineBorder.createBlackLineBorder()); button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
// TODO Should use separate thread to send commands
panel.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
for(int i = 0, n = command.length; i < n; i++) {
if (i > 0) {
try {
// Do not send multiple commands too fast
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
}
String cmd = command[i];
if (cmd == SET_TIME_COMMAND) {
cmd = "time " + (System.currentTimeMillis() / 1000) + " | null";
}
if (!sendCommand(cmd)) {
break;
}
}
} finally {
panel.setCursor(Cursor.getDefaultCursor());
}
}
});
return button;
}
protected boolean sendCommand(String command) {
if (server.sendToNode(command)) { if (server.sendToNode(command)) {
statusLabel.setForeground(Color.black); setStatus("Sent command '" + command + "'", false);
statusLabel.setText("Sent command '" + command + "'"); return true;
} else {
statusLabel.setForeground(Color.red);
statusLabel.setText("Failed to send command. No serial connection.");
} }
setStatus("Failed to send command. No serial connection.", true);
return false;
}
private void setStatus(String text, boolean isWarning) {
statusLabel.setForeground(isWarning ? Color.red : Color.black);
statusLabel.setText(text);
statusLabel.setVisible(true);
} }
public String getCategory() { public String getCategory() {

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $Id: SerialConsole.java,v 1.2 2010/09/15 16:15:10 nifi Exp $ * $Id: SerialConsole.java,v 1.3 2010/10/07 21:13:00 nifi Exp $
* *
* ----------------------------------------------------------------- * -----------------------------------------------------------------
* *
@ -34,8 +34,8 @@
* *
* Authors : Joakim Eriksson, Niclas Finne * Authors : Joakim Eriksson, Niclas Finne
* Created : 4 jul 2008 * Created : 4 jul 2008
* Updated : $Date: 2010/09/15 16:15:10 $ * Updated : $Date: 2010/10/07 21:13:00 $
* $Revision: 1.2 $ * $Revision: 1.3 $
*/ */
package se.sics.contiki.collect.gui; package se.sics.contiki.collect.gui;
@ -106,8 +106,11 @@ public class SerialConsole implements Visualizer {
historyCount = (historyCount + 1) % history.length; historyCount = (historyCount + 1) % history.length;
} }
historyPos = historyCount; historyPos = historyCount;
SerialConsole.this.server.sendToNode(command); if (SerialConsole.this.server.sendToNode(command)) {
commandField.setText(""); commandField.setText("");
} else {
addSerialData("*** failed to send command ***");
}
} catch (Exception ex) { } catch (Exception ex) {
System.err.println("could not send '" + command + "':"); System.err.println("could not send '" + command + "':");
ex.printStackTrace(); ex.printStackTrace();