diff --git a/examples/sky-shell/build.xml b/examples/sky-shell/build.xml
index d2179a9aa..e55d97059 100644
--- a/examples/sky-shell/build.xml
+++ b/examples/sky-shell/build.xml
@@ -27,13 +27,13 @@
-
+
@@ -42,10 +42,7 @@
-
-
-
-
+
diff --git a/examples/sky-shell/src/se/sics/contiki/collect/CollectServer.java b/examples/sky-shell/src/se/sics/contiki/collect/CollectServer.java
index 396429db3..163693213 100644
--- a/examples/sky-shell/src/se/sics/contiki/collect/CollectServer.java
+++ b/examples/sky-shell/src/se/sics/contiki/collect/CollectServer.java
@@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: CollectServer.java,v 1.3 2008/07/10 00:19:20 nifi Exp $
+ * $Id: CollectServer.java,v 1.4 2008/07/10 14:52:59 nifi Exp $
*
* -----------------------------------------------------------------
*
@@ -34,8 +34,8 @@
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
- * Updated : $Date: 2008/07/10 00:19:20 $
- * $Revision: 1.3 $
+ * Updated : $Date: 2008/07/10 14:52:59 $
+ * $Revision: 1.4 $
*/
package se.sics.contiki.collect;
@@ -89,13 +89,12 @@ import se.sics.contiki.collect.gui.TimeChartPanel;
public class CollectServer {
public static final String WINDOW_TITLE = "Sensor Data Collect with Contiki";
- public static final double TICKS_PER_SECOND = 4096; /* TODO Convert from TimerB ticks to seconds */
- public static final double UPDATE_PERIOD = 1; /* TODO Set update period (1 second?) */
public static final String CONFIG_FILE = "collect.conf";
public static final String SENSORDATA_FILE = "sensordata.log";
public static final String CONFIG_DATA_FILE = "collect-data.conf";
public static final String INIT_SCRIPT = "collect-init.script";
+ public static final String FIRMWARE_FILE = "sky-shell.ihex";
private Properties config = new Properties();
@@ -110,6 +109,7 @@ public class CollectServer {
private JFrame window;
private JTabbedPane mainPanel;
+ private JMenuItem serialItem;
private Visualizer[] visualizers;
private MapPanel mapPanel;
@@ -158,9 +158,6 @@ public class CollectServer {
nodeModel = new DefaultListModel();
nodeList = new JList(nodeModel);
nodeList.setPrototypeCellValue("Node 88888");
-// DefaultListCellRenderer l = new DefaultListCellRenderer();
-// l.setHorizontalAlignment(DefaultListCellRenderer.RIGHT);
-// nodeList.setCellRenderer(l);
nodeList.addListSelectionListener(new ListSelectionListener() {
@Override
@@ -207,11 +204,11 @@ public class CollectServer {
mapPanel,
new BarChartPanel(this, "Instantaneous Power", "Instantaneous Power Consumption", null, "Power (mW)",
new String[] { "LPM", "CPU", "Radio listen", "Radio transmit" }) {
- {
+ {
ValueAxis axis = chart.getCategoryPlot().getRangeAxis();
axis.setLowerBound(0.0);
axis.setUpperBound(75.0);
- }
+ }
protected void addSensorData(SensorData data) {
Node node = data.getNode();
String nodeName = node.getName();
@@ -293,7 +290,14 @@ public class CollectServer {
JMenu fileMenu = new JMenu("File");
fileMenu.setMnemonic(KeyEvent.VK_F);
menuBar.add(fileMenu);
+ serialItem = new JMenuItem("Connect to serial");
+ serialItem.addActionListener(new SerialItemHandler());
+ fileMenu.add(serialItem);
+ JMenuItem item = new JMenuItem("Program Sky nodes...");
+ item.addActionListener(new ProgramItemHandler());
+ fileMenu.add(item);
+ fileMenu.addSeparator();
final JMenuItem clearMapItem = new JMenuItem("Remove Map Background");
clearMapItem.addActionListener(new ActionListener() {
@@ -306,7 +310,7 @@ public class CollectServer {
});
clearMapItem.setEnabled(mapPanel.getMapBackground() != null);
- JMenuItem item = new JMenuItem("Select Map Background...");
+ item = new JMenuItem("Select Map Background...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
@@ -404,12 +408,6 @@ public class CollectServer {
}
});
- if (comPort == null) {
- comPort = MoteFinder.selectComPort(window);
-// if (comPort == null) {
-// exit();
-// }
- }
serialConnection = new SerialConnection() {
private boolean hasOpened;
@@ -448,25 +446,27 @@ public class CollectServer {
} else {
prefix = "Failed to connect to " + getComPort() + '\n';
}
- 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) {
+ 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) {
+ } 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);
}
- }
- // Try to open com port again
- if (comPort != null) {
- open(comPort);
}
}
}
@@ -478,7 +478,20 @@ public class CollectServer {
};
if (comPort != null) {
- serialConnection.open(comPort);
+ serialConnection.setComPort(comPort);
+ }
+ connectToSerial();
+ }
+
+ protected void connectToSerial() {
+ if (!serialConnection.isOpen()) {
+ String comPort = serialConnection.getComPort();
+ if (comPort == null) {
+ comPort = MoteFinder.selectComPort(window);
+ }
+ if (comPort != null) {
+ serialConnection.open(comPort);
+ }
}
}
@@ -551,7 +564,9 @@ public class CollectServer {
} else {
window.setTitle(WINDOW_TITLE + " (" + message + ')');
}
+ serialItem.setText(serialConnection.isOpen() ? "Disconnect from serial" : "Connect to serial");
}
+
});
}
@@ -860,6 +875,77 @@ public class CollectServer {
this.sensorDataOutput = null;
}
+ protected class SerialItemHandler implements ActionListener, Runnable {
+
+ private boolean isRunning;
+
+ public void actionPerformed(ActionEvent e) {
+ if (!isRunning) {
+ isRunning = true;
+ new Thread(this, "serial").start();
+ }
+ }
+
+ public void run() {
+ try {
+ if (serialConnection != null && serialConnection.isOpen()) {
+ serialConnection.close();
+ } else {
+ connectToSerial();
+ }
+ } finally {
+ isRunning = false;
+ }
+ }
+
+ }
+
+ protected class ProgramItemHandler implements ActionListener, Runnable {
+
+ private boolean isRunning = false;
+ public void actionPerformed(ActionEvent e) {
+ if (!isRunning) {
+ isRunning = true;
+ new Thread(this, "program thread").start();
+ }
+ }
+
+ @Override
+ public void run() {
+ try {
+ MoteProgrammer mp = new MoteProgrammer();
+ mp.setParentComponent(window);
+ mp.setFirmwareFile(FIRMWARE_FILE);
+ mp.searchForMotes();
+ int[] motes = mp.getMotes();
+ if (motes == null || motes.length == 0) {
+ JOptionPane.showMessageDialog(window, "Could not find any connected Sky nodes", "Error", JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ int reply = JOptionPane.showConfirmDialog(window, "Found " + motes.length + " connected Sky nodes.\n"
+ + "Do you want to upload the firmware " + FIRMWARE_FILE + '?');
+ if (reply == JFileChooser.APPROVE_OPTION) {
+ boolean wasOpen = serialConnection.isOpen();
+ serialConnection.close();
+ if (wasOpen) {
+ Thread.sleep(1000);
+ }
+ mp.programMotes();
+ mp.waitForProcess();
+ if (wasOpen) {
+ connectToSerial();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ JOptionPane.showMessageDialog(window, "Programming failed: " + e, "Error", JOptionPane.ERROR_MESSAGE);
+ } finally {
+ isRunning = false;
+ }
+ }
+
+ }
+
// -------------------------------------------------------------------
// Main
// -------------------------------------------------------------------
diff --git a/examples/sky-shell/src/se/sics/contiki/collect/MoteProgrammer.java b/examples/sky-shell/src/se/sics/contiki/collect/MoteProgrammer.java
new file mode 100644
index 000000000..2cb0c0cbb
--- /dev/null
+++ b/examples/sky-shell/src/se/sics/contiki/collect/MoteProgrammer.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2008, 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: MoteProgrammer.java,v 1.1 2008/07/10 14:52:59 nifi Exp $
+ *
+ * -----------------------------------------------------------------
+ *
+ * MoteProgrammer
+ *
+ * Authors : Joakim Eriksson, Niclas Finne
+ * Created : 10 jul 2008
+ * Updated : $Date: 2008/07/10 14:52:59 $
+ * $Revision: 1.1 $
+ */
+
+package se.sics.contiki.collect;
+import java.awt.BorderLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.io.IOException;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.SwingUtilities;
+
+/**
+ *
+ */
+public class MoteProgrammer {
+
+ private MoteProgrammerProcess[] processes;
+ private int[] motes;
+ private String firmwareFile;
+
+ private Window parent;
+ protected JTextArea logTextArea;
+ protected JDialog dialog;
+ protected JButton closeButton;
+ private boolean isDone;
+
+ public MoteProgrammer() {
+ }
+
+ public Window getParentComponent() {
+ return parent;
+ }
+
+ public void setParentComponent(Window parent) {
+ this.parent = parent;
+ }
+
+ public boolean hasMotes() {
+ return motes != null && motes.length > 0;
+ }
+
+ public int[] getMotes() {
+ return motes;
+ }
+
+ public void setMotes(int[] motes) {
+ this.motes = motes;
+ }
+
+ public void searchForMotes() throws IOException {
+ MoteFinder finder = new MoteFinder();
+ motes = finder.getMotes();
+ finder.close();
+ }
+
+ public String getFirmwareFile() {
+ return firmwareFile;
+ }
+
+ public void setFirmwareFile(String firmwareFile) {
+ this.firmwareFile = firmwareFile;
+ }
+
+ public void programMotes() throws IOException {
+ if (firmwareFile == null) {
+ throw new IllegalStateException("no firmware");
+ }
+ if (!hasMotes()) {
+ throw new IllegalStateException("no motes");
+ }
+ File fp = new File(firmwareFile);
+ if (!fp.canRead()) {
+ throw new IllegalStateException("can not read firmware file '" + fp.getAbsolutePath() + '\'');
+ }
+ if (parent != null) {
+ // Use GUI
+ dialog = new JDialog(parent, "Mote Programmer");
+ logTextArea = new JTextArea(28, 80);
+ logTextArea.setEditable(false);
+ logTextArea.setLineWrap(true);
+ dialog.getContentPane().add(new JScrollPane(logTextArea), BorderLayout.CENTER);
+ JPanel panel = new JPanel();
+ closeButton = new JButton("Cancel");
+ closeButton.addActionListener(new ActionListener() {
+
+ public void actionPerformed(ActionEvent e) {
+ MoteProgrammer.this.close();
+ }
+
+ });
+ panel.add(closeButton);
+ dialog.getContentPane().add(panel, BorderLayout.SOUTH);
+ dialog.pack();
+ dialog.setLocationRelativeTo(parent);
+ dialog.setVisible(true);
+ }
+ processes = new MoteProgrammerProcess[motes.length];
+ isDone = false;
+ try {
+ log("Programming " + motes.length + " motes with '" + firmwareFile + '\'', null);
+ for (int i = 0, n = processes.length; i < n; i++) {
+ processes[i] = new MoteProgrammerProcess(motes[i], firmwareFile) {
+ protected void logLine(String line, boolean stderr, Throwable e) {
+ if (!handleLogLine(this, line, stderr, e)) {
+ super.logLine(line, stderr, e);
+ }
+ }
+ protected void processEnded() {
+ handleProcessEnded(this);
+ }
+ };
+ processes[i].start();
+ }
+ } catch (Exception e) {
+ throw (IOException) new IOException("Failed to program motes").initCause(e);
+ }
+ }
+
+ public synchronized void waitForProcess() throws InterruptedException {
+ while (!isDone) {
+ wait();
+ }
+ }
+
+ public void close() {
+ MoteProgrammerProcess[] processes = this.processes;
+ if (processes != null) {
+ this.processes = null;
+ for (int i = 0, n = processes.length; i < n; i++) {
+ if (processes[i] != null) {
+ processes[i].stop();
+ }
+ }
+ }
+ if (dialog != null) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ dialog.setVisible(false);
+ }
+ });
+ }
+ isDone = true;
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+
+ protected void handleProcessEnded(MoteProgrammerProcess process) {
+ // Another process has finished
+ log("Mote@" + process.getMote() + "> finished" + (process.hasError() ? " with errors": ""), null);
+ MoteProgrammerProcess[] processes = this.processes;
+ if (processes != null) {
+ int running = 0;
+ int errors = 0;
+ for(MoteProgrammerProcess p: processes) {
+ if (p.isRunning()) {
+ running++;
+ } else if (p.hasError()) {
+ errors++;
+ }
+ }
+ if (running == 0) {
+ // All processes has finished
+ isDone = true;
+
+ log("Programming finished with " + errors + " errors.", null);
+ if (closeButton != null) {
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ closeButton.setText("Close");
+ }});
+ }
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+ }
+ }
+
+ protected boolean handleLogLine(MoteProgrammerProcess moteProgrammerProcess,
+ String line, boolean stderr, final Throwable e) {
+ log("Mote@" + moteProgrammerProcess.getMote() + "> " + line, e);
+ return true;
+ }
+
+ private void log(String line, final Throwable e) {
+ System.err.println(line);
+ if (e != null) {
+ e.printStackTrace();
+ line += "\n " + e;
+ }
+ final String text = line;
+ SwingUtilities.invokeLater(new Runnable() {
+ public void run() {
+ int len = logTextArea.getDocument().getLength();
+ if (len == 0) {
+ logTextArea.append(text);
+ } else {
+ logTextArea.append('\n' + text);
+ len++;
+ }
+ logTextArea.setCaretPosition(len + text.length());
+ }
+ });
+ }
+
+ public static void main(String[] args) throws IOException {
+ MoteProgrammer mp = new MoteProgrammer();
+ if (args.length < 1 || args.length > 2) {
+ System.err.println("Usage: MoteProgrammer [mote]");
+ System.exit(1);
+ }
+ mp.setFirmwareFile(args[0]);
+ if (args.length == 2) {
+ mp.setMotes(new int[] { Integer.parseInt(args[1]) });
+ } else {
+ mp.searchForMotes();
+ }
+ if (!mp.hasMotes()) {
+ System.err.println("No motes connected");
+ System.exit(1);
+ }
+ mp.programMotes();
+ }
+
+}
diff --git a/examples/sky-shell/src/se/sics/contiki/collect/MoteProgrammerProcess.java b/examples/sky-shell/src/se/sics/contiki/collect/MoteProgrammerProcess.java
new file mode 100644
index 000000000..c576633ba
--- /dev/null
+++ b/examples/sky-shell/src/se/sics/contiki/collect/MoteProgrammerProcess.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2008, 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: MoteProgrammerProcess.java,v 1.1 2008/07/10 14:52:59 nifi Exp $
+ *
+ * -----------------------------------------------------------------
+ *
+ * MoteProgrammerProcess
+ *
+ * Authors : Joakim Eriksson, Niclas Finne
+ * Created : 10 jul 2008
+ * Updated : $Date: 2008/07/10 14:52:59 $
+ * $Revision: 1.1 $
+ */
+
+package se.sics.contiki.collect;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+/**
+ *
+ */
+public class MoteProgrammerProcess {
+
+ public static final String BSL_WINDOWS = "./tools/msp430-bsl-windows.exe";
+ public static final String BSL_LINUX = "./tools/msp430-bsl-linux";
+
+ private final int mote;
+ private final String moteID;
+ private final String firmwareFile;
+ private final String[][] commandSet;
+ private int retry = 3;
+
+ private Process currentProcess;
+ private Thread commandThread;
+ private boolean isRunning;
+ private boolean hasError;
+
+ public MoteProgrammerProcess(int mote, String firmwareFile) {
+ this.mote = mote;
+ this.moteID = "" + (mote - 1);
+ this.firmwareFile = firmwareFile;
+ String osName = System.getProperty("os.name").toLowerCase();
+ String bslCommand;
+ if (osName.startsWith("win")) {
+ bslCommand = BSL_WINDOWS;
+ } else {
+ bslCommand = BSL_LINUX;
+ }
+ commandSet = new String[][] {
+ { bslCommand, "--telosb", "-c", moteID, "-e" },
+ { bslCommand, "--telosb", "-c", moteID, "-I", "-p", firmwareFile },
+ { bslCommand, "--telosb", "-c", moteID, "-r" }
+ };
+ }
+
+ public int getMote() {
+ return mote;
+ }
+
+ public String getFirmwareFile() {
+ return firmwareFile;
+ }
+
+ public int getRetry() {
+ return retry;
+ }
+
+ public void setRetry(int retry) {
+ this.retry = retry;
+ }
+
+ public boolean isRunning() {
+ return isRunning;
+ }
+
+ public boolean hasError() {
+ return hasError;
+ }
+
+ public void start() {
+ if (isRunning) {
+ // Already running
+ return;
+ }
+ isRunning = true;
+ commandThread = new Thread(new Runnable() {
+ public void run() {
+ try {
+ int count = 0;
+ do {
+ if (count > 0) {
+ logLine("An error occurred. Retrying.", true, null);
+ }
+ count++;
+ hasError = false;
+ for (int j = 0, m = commandSet.length; j < m && isRunning && !hasError; j++) {
+ runCommand(commandSet[j]);
+ Thread.sleep(2000);
+ }
+ } while (isRunning && hasError && count < retry);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ isRunning = false;
+ processEnded();
+ }
+ }
+ });
+ commandThread.start();
+ }
+
+ public void stop() {
+ isRunning = false;
+ Process process = currentProcess;
+ if (process != null) {
+ process.destroy();
+ }
+ }
+
+ public void waitForProcess() throws InterruptedException {
+ if (isRunning && commandThread != null) {
+ commandThread.join();
+ }
+ }
+
+ protected void processEnded() {
+ }
+
+ private void runCommand(String[] cmd) throws IOException, InterruptedException {
+ if (currentProcess != null) {
+ currentProcess.destroy();
+ }
+ currentProcess = Runtime.getRuntime().exec(cmd);
+ final BufferedReader input = new BufferedReader(new InputStreamReader(currentProcess.getInputStream()));
+ final BufferedReader err = new BufferedReader(new InputStreamReader(currentProcess.getErrorStream()));
+
+ /* Start thread listening on stdout */
+ Thread readInput = new Thread(new Runnable() {
+ public void run() {
+ String line;
+ try {
+ while ((line = input.readLine()) != null) {
+ handleLine(line, false);
+ }
+ input.close();
+ } catch (IOException e) {
+ logLine("Error reading from command", false, e);
+ }
+ }
+ }, "read stdout thread");
+
+ /* Start thread listening on stderr */
+ Thread readError = new Thread(new Runnable() {
+ public void run() {
+ String line;
+ try {
+ while ((line = err.readLine()) != null) {
+ handleLine(line, true);
+ }
+ err.close();
+ } catch (IOException e) {
+ logLine("Error reading from command", true, e);
+ }
+ }
+ }, "read stderr thread");
+
+ readInput.start();
+ readError.start();
+
+ // Wait for the bsl program to finish executing
+ readInput.join();
+ currentProcess = null;
+ }
+
+ private void handleLine(String line, boolean stderr) {
+ if (line.toLowerCase().contains("error")) {
+ hasError = true;
+ }
+ logLine(line, stderr, null);
+ }
+
+ protected void logLine(String line, boolean stderr, Throwable e) {
+ if (stderr) {
+ System.err.println("Programmer@" + mote + "> " + line);
+ } else {
+ System.out.println("Programmer@" + mote + "> " + line);
+ }
+ if (e != null) {
+ e.printStackTrace();
+ }
+ }
+
+ protected String toString(String[] cmd) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0, n = cmd.length; i < n; i++) {
+ if (i > 0) sb.append(' ');
+ sb.append(cmd[i]);
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/examples/sky-shell/src/se/sics/contiki/collect/SerialConnection.java b/examples/sky-shell/src/se/sics/contiki/collect/SerialConnection.java
index cceca4ef8..6f080e675 100644
--- a/examples/sky-shell/src/se/sics/contiki/collect/SerialConnection.java
+++ b/examples/sky-shell/src/se/sics/contiki/collect/SerialConnection.java
@@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: SerialConnection.java,v 1.1 2008/07/09 23:18:06 nifi Exp $
+ * $Id: SerialConnection.java,v 1.2 2008/07/10 14:52:59 nifi Exp $
*
* -----------------------------------------------------------------
*
@@ -34,8 +34,8 @@
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 5 jul 2008
- * Updated : $Date: 2008/07/09 23:18:06 $
- * $Revision: 1.1 $
+ * Updated : $Date: 2008/07/10 14:52:59 $
+ * $Revision: 1.2 $
*/
package se.sics.contiki.collect;
@@ -56,9 +56,9 @@ public abstract class SerialConnection {
private String comPort;
private Process serialDumpProcess;
private PrintWriter serialOutput;
- private boolean isRunning;
- private boolean isOpen;
- private String lastError;
+ protected boolean isOpen;
+ protected boolean isClosed = true;
+ protected String lastError;
public boolean isOpen() {
return isOpen;
@@ -68,14 +68,21 @@ public abstract class SerialConnection {
return comPort;
}
+ public void setComPort(String comPort) {
+ this.comPort = comPort;
+ }
+
public String getLastError() {
return lastError;
}
public void open(String comPort) {
+ if (comPort == null) {
+ 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;
@@ -85,7 +92,7 @@ public abstract class SerialConnection {
fullCommand = SERIALDUMP_LINUX + " " + "-b115200" + " " + comPort;
}
- isRunning = true;
+ isClosed = false;
try {
String[] cmd = fullCommand.split(" ");
@@ -161,13 +168,13 @@ public abstract class SerialConnection {
}
public void close() {
- isOpen = false;
- isRunning = false;
+ isClosed = true;
lastError = null;
closeConnection();
}
protected void closeConnection() {
+ isOpen = false;
if (serialOutput != null) {
serialOutput.close();
serialOutput = null;
@@ -176,10 +183,7 @@ public abstract class SerialConnection {
serialDumpProcess.destroy();
serialDumpProcess = null;
}
- if (isRunning) {
- isRunning = false;
- serialClosed();
- }
+ serialClosed();
}
protected abstract void serialData(String line);