Tools: remove collect-view

This commit is contained in:
Simon Duquennoy 2017-12-22 05:11:02 -08:00
parent 0971088260
commit 88ae175c9a
30 changed files with 0 additions and 7138 deletions

2
.gitignore vendored
View File

@ -20,8 +20,6 @@ tools/tunslip6
build
tools/coffee-manager/build/
tools/coffee-manager/coffee.jar
tools/collect-view/build/
tools/collect-view/dist/
COOJA.testlog
# platform build artifacts

View File

@ -1,78 +0,0 @@
<?xml version="1.0"?>
<project name="Sensor Data Collect with Contiki" default="dist" basedir=".">
<property name="java" location="src"/>
<property name="build" location="build"/>
<property name="lib" location="lib"/>
<property name="dist" location="dist"/>
<property name="contiki" location="../.."/>
<property name="archive" value="collect-view.jar"/>
<property name="main" value="org.contikios.contiki.collect.CollectServer"/>
<property name="args" value="" />
<path id="classpath">
<fileset dir="${lib}" includes="**/*.jar"/>
</path>
<manifestclasspath property="jar.classpath" jarfile="${archive}">
<classpath refid="classpath" />
</manifestclasspath>
<target name="init">
<tstamp/>
<mkdir dir="${build}"/>
<mkdir dir="${dist}"/>
</target>
<target name="compile" depends="init">
<javac srcdir="${java}" destdir="${build}" classpathref="classpath"
debug="true" includeantruntime="false" />
</target>
<target name="jar" depends="compile">
<jar destfile="${dist}/${archive}" basedir="${build}">
<manifest>
<attribute name="Main-Class" value="${main}"/>
<attribute name="Class-Path" value="${jar.classpath}" />
</manifest>
</jar>
<mkdir dir="${dist}/lib"/>
<copy todir="${dist}/lib">
<fileset dir="${lib}"/>
</copy>
</target>
<condition property="collect-view-shell.exists">
<available file="${dist}/collect-view-shell.ihex"/>
</condition>
<target name="collect-view-shell.ihex" unless="collect-view-shell.exists" depends="init">
<exec dir="${contiki}/examples/collect" executable="make">
<arg value="TARGET=sky"/>
<arg value="collect-view-shell.ihex"/>
</exec>
<copy todir="${dist}" file="${contiki}/examples/collect/collect-view-shell.ihex"/>
</target>
<target name="dist" depends="jar,collect-view-shell.ihex">
<copy todir="${dist}" file="collect-init.script"/>
<mkdir dir="${dist}/tools"/>
<copy todir="${dist}/tools">
<fileset dir="${contiki}/tools/sky"/>
</copy>
<copy file="${contiki}/tools/cygwin/cygwin1.dll" todir="${dist}/tools"/>
<chmod dir="${dist}/tools" perm="a+x" includes="**/*"/>
</target>
<target name="run" depends="dist">
<java fork="yes" dir="${dist}" jar="${dist}/${archive}">
<arg line="${args}"/>
</java>
</target>
<target name="clean">
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>

View File

@ -1,6 +0,0 @@
echo ~K
echo killall
sleep 2
echo mac 0
sleep 2
echo time %TIME% | null

View File

@ -1,164 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* CommandConnection
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 5 oct 2010
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.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");
if (!isOpen) {
isOpen = true;
serialOpened();
}
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) {
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

@ -1,50 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* Configurable
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 24 sep 2010
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect;
import java.util.Properties;
/**
*
*/
public interface Configurable {
public void updateConfig(Properties config);
}

View File

@ -1,86 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* Link
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect;
/**
*
*/
public class Link {
public final Node node;
private double etx;
private int quality = 100;
private long lastActive = 0L;
public Link(Node node) {
this.node = node;
this.lastActive = System.currentTimeMillis();
}
public Node getNode() {
return node;
}
public int getQuality() {
return quality;
}
public void setQuality(int quality) {
this.quality = quality;
}
public double getETX() {
return etx;
}
public void setETX(double etx) {
this.etx = etx;
}
public long getLastActive() {
return lastActive;
}
public void setLastActive(long time) {
this.lastActive = time;
}
}

View File

@ -1,226 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* Motelist
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 4 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect;
import java.awt.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.JOptionPane;
/**
*
*/
public class MoteFinder {
public static final String MOTELIST_WINDOWS = "./tools/motelist-windows.exe";
public static final String MOTELIST_LINUX = "./tools/motelist-linux";
public static final String MOTELIST_MACOS = "./tools/motelist-macos";
private final Pattern motePattern;
private final boolean isWindows;
private final boolean isMacos;
private Process moteListProcess;
// private boolean hasVerifiedProcess;
private ArrayList<String> comList = new ArrayList<String>();
private ArrayList<String> moteList = new ArrayList<String>();
public MoteFinder() {
String osName = System.getProperty("os.name", "").toLowerCase();
isWindows = osName.startsWith("win");
isMacos = osName.startsWith("mac");
motePattern = Pattern.compile("\\s(COM|/dev/[a-zA-Z]+|/dev/tty.usbserial-)(\\d+|[A-Z0-9]+)\\s");
}
public String[] getMotes() throws IOException {
searchForMotes();
return getMoteList();
}
public String[] getComPorts() throws IOException {
searchForMotes();
return getComList();
}
private void searchForMotes() throws IOException {
comList.clear();
moteList.clear();
// hasVerifiedProcess = false;
/* Connect to COM using external serialdump application */
String fullCommand;
if (isWindows) {
fullCommand = MOTELIST_WINDOWS;
} else if (isMacos) {
fullCommand = MOTELIST_MACOS;
} else {
fullCommand = MOTELIST_LINUX;
}
try {
String[] cmd = new String[] { fullCommand };
moteListProcess = Runtime.getRuntime().exec(cmd);
final BufferedReader input = new BufferedReader(new InputStreamReader(moteListProcess.getInputStream()));
final BufferedReader err = new BufferedReader(new InputStreamReader(moteListProcess.getErrorStream()));
/* Start thread listening on stdout */
Thread readInput = new Thread(new Runnable() {
public void run() {
String line;
try {
while ((line = input.readLine()) != null) {
parseIncomingLine(line);
}
input.close();
} catch (IOException e) {
System.err.println("Exception when reading from motelist");
e.printStackTrace();
}
}
}, "read motelist thread");
/* Start thread listening on stderr */
Thread readError = new Thread(new Runnable() {
public void run() {
String line;
try {
while ((line = err.readLine()) != null) {
System.err.println("Motelist error stream> " + line);
}
err.close();
} catch (IOException e) {
System.err.println("Exception when reading from motelist error stream: " + e);
}
}
}, "read motelist error stream thread");
readInput.start();
readError.start();
// Wait for the motelist program to finish executing
readInput.join();
} catch (Exception e) {
throw (IOException) new IOException("Failed to execute '" + fullCommand + "'").initCause(e);
}
}
private String[] getComList() {
return comList.toArray(new String[comList.size()]);
}
private String[] getMoteList() {
return moteList.toArray(new String[moteList.size()]);
}
public void close() {
if (moteListProcess != null) {
moteListProcess.destroy();
moteListProcess = null;
}
}
protected void parseIncomingLine(String line) {
if (line.contains("No devices found") || line.startsWith("Reference")) {
// No Sky connected or title before connected motes
// hasVerifiedProcess = true;
} else if (line.startsWith("-------")) {
// Separator
} else {
Matcher matcher = motePattern.matcher(line);
if (matcher.find()) {
String dev = matcher.group(1);
String no = matcher.group(2);
String comPort = dev + no;
String moteID = comPort;
if (isWindows) {
// Special handling of mote id under Windows
int moteNumber = Integer.parseInt(no);
moteID = Integer.toString(moteNumber - 1);
}
comList.add(comPort);
moteList.add(moteID);
} else {
System.err.println("Motelist> " + line);
}
}
}
public static String selectComPort(Component parent) {
MoteFinder finder = new MoteFinder();
try {
String[] motes = finder.getComPorts();
if (motes == null || motes.length == 0) {
JOptionPane.showMessageDialog(parent, "Could not find any connected motes.", "No mote found", JOptionPane.ERROR_MESSAGE);
return null;
} else if (motes.length == 1) {
// Only one node found
return motes[0];
} else {
// Several motes found
return (String) JOptionPane.showInputDialog(
parent, "Found multiple connected motes. Please select serial port:",
"Select serial port", JOptionPane.QUESTION_MESSAGE, null, motes, motes[0]);
}
} catch (IOException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(parent, "Failed to search for connected motes:\n" + e, "Error", JOptionPane.ERROR_MESSAGE);
return null;
} finally {
finder.close();
}
}
public static void main(String[] args) throws IOException {
MoteFinder finder = new MoteFinder();
String[] comPorts = args.length > 0 && "-v".equals(args[0]) ?
finder.getMotes() : finder.getComPorts();
finder.close();
if (comPorts == null || comPorts.length == 0) {
System.out.println("No motes connected");
} else {
for(String port: comPorts) {
System.out.println("Found Sky at " + port);
}
}
}
}

View File

@ -1,280 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* MoteProgrammer
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 10 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.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.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
/**
*
*/
public class MoteProgrammer {
private MoteProgrammerProcess[] processes;
private String[] motes;
private String firmwareFile;
private Window parent;
private JProgressBar progressBar;
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 String[] getMotes() {
return motes;
}
public void setMotes(String[] 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");
progressBar = new JProgressBar(0, 100);
progressBar.setValue(0);
progressBar.setString("Programming...");
progressBar.setStringPainted(true);
progressBar.setIndeterminate(true);
dialog.getContentPane().add(progressBar, BorderLayout.NORTH);
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.getMoteID() + "> 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;
final String doneMessage = "Programming finished with " + errors + " errors.";
log(doneMessage, null);
if (closeButton != null) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progressBar.setValue(100);
progressBar.setIndeterminate(false);
progressBar.setString(doneMessage);
closeButton.setText("Close");
}});
}
synchronized (this) {
notifyAll();
}
}
}
}
protected boolean handleLogLine(MoteProgrammerProcess moteProgrammerProcess,
String line, boolean stderr, final Throwable e) {
log("Mote@" + moteProgrammerProcess.getMoteID() + "> " + 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 <firmware> [mote]");
System.exit(1);
}
mp.setFirmwareFile(args[0]);
if (args.length == 2) {
mp.setMotes(new String[] { args[1] });
} else {
mp.searchForMotes();
}
if (!mp.hasMotes()) {
System.err.println("No motes connected");
System.exit(1);
}
mp.programMotes();
}
}

View File

@ -1,226 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* MoteProgrammerProcess
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 10 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.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 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(String moteID, String firmwareFile) {
this.moteID = moteID;
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 String getMoteID() {
return moteID;
}
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@" + moteID + "> " + line);
} else {
System.out.println("Programmer@" + moteID + "> " + 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();
}
}

View File

@ -1,217 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* Node
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect;
import java.util.ArrayList;
import java.util.Hashtable;
/**
*
*/
public class Node implements Comparable<Node> {
private static final boolean SINGLE_LINK = true;
private SensorDataAggregator sensorDataAggregator;
private ArrayList<SensorData> sensorDataList = new ArrayList<SensorData>();
private ArrayList<Link> links = new ArrayList<Link>();
private final String id;
private final String name;
private Hashtable<String,Object> objectTable;
private long lastActive;
public Node(String nodeID) {
this(nodeID, nodeID);
}
public Node(String nodeID, String nodeName) {
this.id = nodeID;
this.name = nodeName;
sensorDataAggregator = new SensorDataAggregator(this);
}
public final String getID() {
return id;
}
public final String getName() {
return name;
}
public long getLastActive() {
return lastActive;
}
public void setLastActive(long lastActive) {
this.lastActive = lastActive;
}
@Override
public int compareTo(Node o) {
String i1 = id;
String i2 = o.getID();
// Shorter id first (4.0 before 10.0)
if (i1.length() == i2.length()) {
return i1.compareTo(i2);
}
return i1.length() - i2.length();
}
public String toString() {
return name;
}
// -------------------------------------------------------------------
// Attributes
// -------------------------------------------------------------------
public Object getAttribute(String key) {
return getAttribute(key, null);
}
public Object getAttribute(String key, Object defaultValue) {
if (objectTable == null) {
return null;
}
Object val = objectTable.get(key);
return val == null ? defaultValue : val;
}
public void setAttribute(String key, Object value) {
if (objectTable == null) {
objectTable = new Hashtable<String,Object>();
}
objectTable.put(key, value);
}
public void clearAttributes() {
if (objectTable != null) {
objectTable.clear();
}
}
// -------------------------------------------------------------------
// SensorData
// -------------------------------------------------------------------
public SensorDataAggregator getSensorDataAggregator() {
return sensorDataAggregator;
}
public SensorData[] getAllSensorData() {
return sensorDataList.toArray(new SensorData[sensorDataList.size()]);
}
public void removeAllSensorData() {
sensorDataList.clear();
sensorDataAggregator.clear();
}
public SensorData getSensorData(int index) {
return sensorDataList.get(index);
}
public int getSensorDataCount() {
return sensorDataList.size();
}
public boolean addSensorData(SensorData data) {
if (sensorDataList.size() > 0) {
SensorData last = sensorDataList.get(sensorDataList.size() - 1);
if (data.getNodeTime() < last.getNodeTime()) {
// Sensor data already added
System.out.println("SensorData: ignoring (time " + (data.getNodeTime() - last.getNodeTime())
+ "msec): " + data);
return false;
}
}
sensorDataList.add(data);
sensorDataAggregator.addSensorData(data);
return true;
}
// -------------------------------------------------------------------
// Links
// -------------------------------------------------------------------
public Link getLink(Node node) {
for(Link l: links) {
if (l.node == node) {
return l;
}
}
// Add new link
Link l = new Link(node);
if (SINGLE_LINK) {
links.clear();
}
links.add(l);
return l;
}
public Link getLink(int index) {
return links.get(index);
}
public int getLinkCount() {
return links.size();
}
public void removeLink(Node node) {
for (int i = 0, n = links.size(); i < n; i++) {
Link l = links.get(i);
if (l.node == node) {
links.remove(i);
break;
}
}
}
public void clearLinks() {
links.clear();
}
}

View File

@ -1,243 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* SensorData
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
* Updated : $Date: 2011/01/09 21:06:10 $
* $Revision: 1.2 $
*/
package org.contikios.contiki.collect;
import java.util.Arrays;
/**
*
*/
public class SensorData implements SensorInfo {
private final Node node;
private final int[] values;
private final long nodeTime;
private final long systemTime;
private int seqno;
private boolean isDuplicate;
public SensorData(Node node, int[] values, long systemTime) {
this.node = node;
this.values = values;
this.nodeTime = ((values[TIMESTAMP1] << 16) + values[TIMESTAMP2]) * 1000L;
this.systemTime = systemTime;
this.seqno = values[SEQNO];
}
public Node getNode() {
return node;
}
public String getNodeID() {
return node.getID();
}
public boolean isDuplicate() {
return isDuplicate;
}
public void setDuplicate(boolean isDuplicate) {
this.isDuplicate = isDuplicate;
}
public int getSeqno() {
return seqno;
}
public void setSeqno(int seqno) {
this.seqno = seqno;
}
public int getValue(int index) {
return values[index];
}
public int getValueCount() {
return values.length;
}
public long getNodeTime() {
return nodeTime;
}
public long getSystemTime() {
return systemTime;
}
public String toString() {
StringBuilder sb = new StringBuilder();
if (systemTime > 0L) {
sb.append(systemTime).append(' ');
}
for (int i = 0, n = values.length; i < n; i++) {
if (i > 0) sb.append(' ');
sb.append(values[i]);
}
return sb.toString();
}
public static SensorData parseSensorData(CollectServer server, String line) {
return parseSensorData(server, line, 0);
}
public static SensorData parseSensorData(CollectServer server, String line, long systemTime) {
String[] components = line.trim().split("[ \t]+");
// Check if COOJA log
if (components.length == VALUES_COUNT + 2 && components[1].startsWith("ID:")) {
if (!components[2].equals("" + VALUES_COUNT)) {
// Ignore non sensor data
return null;
}
try {
systemTime = Long.parseLong(components[0]);
components = Arrays.copyOfRange(components, 2, components.length);
} catch (NumberFormatException e) {
// First column does not seem to be system time
}
} else if (components[0].length() > 8) {
// Sensor data prefixed with system time
try {
systemTime = Long.parseLong(components[0]);
components = Arrays.copyOfRange(components, 1, components.length);
} catch (NumberFormatException e) {
// First column does not seem to be system time
}
}
if (components.length != SensorData.VALUES_COUNT) {
return null;
}
// Sensor data line (probably)
int[] data = parseToInt(components);
if (data == null || data[0] != VALUES_COUNT) {
System.err.println("Failed to parse data line: '" + line + "'");
return null;
}
String nodeID = mapNodeID(data[NODE_ID]);
Node node = server.addNode(nodeID);
return new SensorData(node, data, systemTime);
}
public static String mapNodeID(int nodeID) {
return "" + (nodeID & 0xff) + '.' + ((nodeID >> 8) & 0xff);
}
private static int[] parseToInt(String[] text) {
try {
int[] data = new int[text.length];
for (int i = 0, n = data.length; i < n; i++) {
data[i] = Integer.parseInt(text[i]);
}
return data;
} catch (NumberFormatException e) {
return null;
}
}
public double getCPUPower() {
return (values[TIME_CPU] * POWER_CPU) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getLPMPower() {
return (values[TIME_LPM] * POWER_LPM) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getListenPower() {
return (values[TIME_LISTEN] * POWER_LISTEN) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getTransmitPower() {
return (values[TIME_TRANSMIT] * POWER_TRANSMIT) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getAveragePower() {
return (values[TIME_CPU] * POWER_CPU + values[TIME_LPM] * POWER_LPM
+ values[TIME_LISTEN] * POWER_LISTEN + values[TIME_TRANSMIT] * POWER_TRANSMIT)
/ (values[TIME_CPU] + values[TIME_LPM]);
}
public long getPowerMeasureTime() {
return (1000L * (values[TIME_CPU] + values[TIME_LPM])) / TICKS_PER_SECOND;
}
public double getTemperature() {
return -39.6 + 0.01 * values[TEMPERATURE];
}
public double getBatteryVoltage() {
return values[BATTERY_VOLTAGE] * 2 * 2.5 / 4096.0;
}
public double getBatteryIndicator() {
return values[BATTERY_INDICATOR];
}
public double getRadioIntensity() {
return values[RSSI];
}
public double getLatency() {
return values[LATENCY] / 32678.0;
}
public double getHumidity() {
double v = -4.0 + 405.0 * values[HUMIDITY] / 10000.0;
if(v > 100) {
return 100;
}
return v;
}
public double getLight1() {
return 10.0 * values[LIGHT1] / 7.0;
}
public double getLight2() {
return 46.0 * values[LIGHT2] / 10.0;
}
public String getBestNeighborID() {
return values[BEST_NEIGHBOR] > 0 ? mapNodeID(values[BEST_NEIGHBOR]): null;
}
public double getBestNeighborETX() {
return values[BEST_NEIGHBOR_ETX] / 8.0;
}
}

View File

@ -1,320 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* SensorDataAggregator
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 20 aug 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect;
/**
*
*/
public class SensorDataAggregator implements SensorInfo {
private final Node node;
private long[] values;
private int minSeqno = Integer.MAX_VALUE;
private int maxSeqno = Integer.MIN_VALUE;
private int seqnoDelta = 0;
private int dataCount;
private int duplicates = 0;
private int lost = 0;
private int nodeRestartCount = 0;
private int nextHopChangeCount = 0;
private int lastNextHop = -1;
private long shortestPeriod = Long.MAX_VALUE;
private long longestPeriod = 0;
public SensorDataAggregator(Node node) {
this.node = node;
this.values = new long[VALUES_COUNT];
}
public Node getNode() {
return node;
}
public String getNodeID() {
return node.getID();
}
public long getValue(int index) {
return values[index];
}
public double getAverageValue(int index) {
return dataCount > 0 ? (double)values[index] / (double)dataCount : 0;
}
public int getValueCount() {
return values.length;
}
public int getDataCount() {
return dataCount;
}
public void addSensorData(SensorData data) {
int seqn = data.getValue(SEQNO);
int s = seqn + seqnoDelta;
int bestNeighbor = data.getValue(BEST_NEIGHBOR);
if (lastNextHop != bestNeighbor && lastNextHop >= 0) {
nextHopChangeCount++;
}
lastNextHop = bestNeighbor;
if (s <= maxSeqno) {
// Check for duplicates among the last 5 packets
for(int n = node.getSensorDataCount() - 1, i = n > 5 ? n - 5 : 0; i < n; i++) {
SensorData sd = node.getSensorData(i);
if (sd.getValue(SEQNO) != seqn || sd == data || sd.getValueCount() != data.getValueCount()) {
// Not a duplicate
} else if (Math.abs(data.getNodeTime() - sd.getNodeTime()) > 180000) {
// Too long time between packets. Not a duplicate.
// System.err.println("Too long time between packets with same seqno from "
// + data.getNode() + ": "
// + (Math.abs(data.getNodeTime() - sd.getNodeTime()) / 1000)
// + " sec, " + (n - i) + " packets ago");
} else {
data.setDuplicate(true);
// Verify that the packet is a duplicate
for(int j = DATA_LEN2, m = data.getValueCount(); j < m; j++) {
if (sd.getValue(j) != data.getValue(j)) {
data.setDuplicate(false);
// System.out.println("NOT Duplicate: " + data.getNode() + " ("
// + (n - i) + ": "
// + ((data.getNodeTime() - sd.getNodeTime()) / 1000) + "sek): "
// + seqn + " value[" + j + "]: " + sd.getValue(j) + " != "
// + data.getValue(j));
break;
}
}
if (data.isDuplicate()) {
// System.out.println("Duplicate: " + data.getNode() + ": " + seqn
// + ": "
// + (Math.abs(data.getNodeTime() - sd.getNodeTime()) / 1000)
// + " sec, " + (n - i) + " packets ago");
duplicates++;
break;
}
}
}
}
if (!data.isDuplicate()) {
for (int i = 0, n = Math.min(VALUES_COUNT, data.getValueCount()); i < n; i++) {
values[i] += data.getValue(i);
}
if (node.getSensorDataCount() > 1) {
long timeDiff = data.getNodeTime() - node.getSensorData(node.getSensorDataCount() - 2).getNodeTime();
if (timeDiff > longestPeriod) {
longestPeriod = timeDiff;
}
if (timeDiff < shortestPeriod) {
shortestPeriod = timeDiff;
}
}
if (dataCount == 0) {
// First packet from node.
} else if (maxSeqno - s > 2) {
// Handle sequence number overflow.
seqnoDelta = maxSeqno + 1;
s = seqnoDelta + seqn;
if (seqn > 127) {
// Sequence number restarted at 128 (to separate node restarts
// from sequence number overflow).
seqn -= 128;
seqnoDelta -= 128;
s -= 128;
} else {
// Sequence number restarted at 0. This is usually an indication that
// the node restarted.
nodeRestartCount++;
}
if (seqn > 0) {
lost += seqn;
}
} else if (s > maxSeqno + 1){
lost += s - (maxSeqno + 1);
}
if (s < minSeqno) minSeqno = s;
if (s > maxSeqno) maxSeqno = s;
dataCount++;
}
data.setSeqno(s);
}
public void clear() {
for (int i = 0, n = values.length; i < n; i++) {
values[i] = 0L;
}
dataCount = 0;
duplicates = 0;
lost = 0;
nodeRestartCount = 0;
nextHopChangeCount = 0;
lastNextHop = 0;
minSeqno = Integer.MAX_VALUE;
maxSeqno = Integer.MIN_VALUE;
seqnoDelta = 0;
shortestPeriod = Long.MAX_VALUE;
longestPeriod = 0;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0, n = values.length; i < n; i++) {
if (i > 0) sb.append(' ');
sb.append(values[i]);
}
return sb.toString();
}
public double getCPUPower() {
return (values[TIME_CPU] * POWER_CPU) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getLPMPower() {
return (values[TIME_LPM] * POWER_LPM) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getListenPower() {
return (values[TIME_LISTEN] * POWER_LISTEN) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getTransmitPower() {
return (values[TIME_TRANSMIT] * POWER_TRANSMIT) / (values[TIME_CPU] + values[TIME_LPM]);
}
public double getAveragePower() {
return (values[TIME_CPU] * POWER_CPU + values[TIME_LPM] * POWER_LPM
+ values[TIME_LISTEN] * POWER_LISTEN + values[TIME_TRANSMIT] * POWER_TRANSMIT)
/ (values[TIME_CPU] + values[TIME_LPM]);
}
public double getAverageDutyCycle(int index) {
return (double)(values[index]) / (double)(values[TIME_CPU] + values[TIME_LPM]);
}
public long getPowerMeasureTime() {
return (1000L * (values[TIME_CPU] + values[TIME_LPM])) / TICKS_PER_SECOND;
}
public double getAverageTemperature() {
return dataCount > 0 ? (-39.6 + 0.01 * (values[TEMPERATURE] / dataCount)) : 0.0;
}
public double getAverageRtmetric() {
return getAverageValue(RTMETRIC);
}
public double getAverageRadioIntensity() {
return getAverageValue(RSSI);
}
public double getAverageLatency() {
return getAverageValue(LATENCY) / 4096.0;
}
public double getAverageHumidity() {
double v = 0.0;
if (dataCount > 0) {
v = -4.0 + 405.0 * (values[HUMIDITY] / dataCount) / 10000.0;
}
return v > 100 ? 100 : v;
}
public double getAverageLight1() {
return 10.0 * getAverageValue(LIGHT1) / 7.0;
}
public double getAverageLight2() {
return 46.0 * getAverageValue(LIGHT2) / 10.0;
}
public double getAverageBestNeighborETX() {
return getAverageValue(BEST_NEIGHBOR_ETX) / 8.0;
}
public int getPacketCount() {
return node.getSensorDataCount();
}
public int getNextHopChangeCount() {
return nextHopChangeCount;
}
public int getEstimatedRestarts() {
return nodeRestartCount;
}
public int getEstimatedLostCount() {
return lost;
}
public int getDuplicateCount() {
return duplicates;
}
public int getMinSeqno() {
return minSeqno;
}
public int getMaxSeqno() {
return maxSeqno;
}
public long getAveragePeriod() {
if (dataCount > 1) {
long first = node.getSensorData(0).getNodeTime();
long last = node.getSensorData(node.getSensorDataCount() - 1).getNodeTime();
return (last - first) / dataCount;
}
return 0;
}
public long getShortestPeriod() {
return shortestPeriod < Long.MAX_VALUE ? shortestPeriod : 0;
}
public long getLongestPeriod() {
return longestPeriod;
}
}

View File

@ -1,85 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* SensorInfo
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 20 aug 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect;
/**
*
*/
public interface SensorInfo {
public static final long TICKS_PER_SECOND = 4096L;
public static final double VOLTAGE = 3;
public static final double POWER_CPU = 1.800 * VOLTAGE; /* mW */
public static final double POWER_LPM = 0.0545 * VOLTAGE; /* mW */
public static final double POWER_TRANSMIT = 17.7 * VOLTAGE; /* mW */
public static final double POWER_LISTEN = 20.0 * VOLTAGE; /* mW */
public static final int DATA_LEN = 0;
public static final int TIMESTAMP1 = 1;
public static final int TIMESTAMP2 = 2;
public static final int TIMESYNCTIMESTAMP = 3;
public static final int NODE_ID = 4;
public static final int SEQNO = 5;
public static final int HOPS = 6;
public static final int LATENCY = 7;
public static final int DATA_LEN2 = 8;
public static final int CLOCK = 9;
public static final int TIMESYNCHTIME = 10;
public static final int TIME_CPU = 11;
public static final int TIME_LPM = 12;
public static final int TIME_TRANSMIT = 13;
public static final int TIME_LISTEN = 14;
public static final int BEST_NEIGHBOR = 15;
public static final int BEST_NEIGHBOR_ETX = 16;
public static final int RTMETRIC = 17;
public static final int NUM_NEIGHBORS = 18;
public static final int BEACON_INTERVAL = 19;
public static final int BATTERY_VOLTAGE = 20;
public static final int BATTERY_INDICATOR = 21;
public static final int LIGHT1 = 22;
public static final int LIGHT2 = 23;
public static final int TEMPERATURE = 24;
public static final int HUMIDITY = 25;
public static final int RSSI = 26;
public static final int VALUES_COUNT = 30;
}

View File

@ -1,145 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* SerialConnection
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 5 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect;
import java.io.PrintWriter;
/**
*
*/
public abstract class SerialConnection {
protected final SerialConnectionListener listener;
protected boolean isSerialOutputSupported = true;
protected String comPort;
protected boolean isOpen;
protected boolean isClosed = true;
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() {
return isOpen;
}
public boolean isClosed() {
return isClosed;
}
public abstract String getConnectionName();
public String getComPort() {
return comPort;
}
public void setComPort(String comPort) {
this.comPort = comPort;
}
public String getLastError() {
return lastError;
}
protected PrintWriter getSerialOutput() {
return serialOutput;
}
protected void setSerialOutput(PrintWriter serialOutput) {
this.serialOutput = serialOutput;
}
public void writeSerialData(String data) {
PrintWriter serialOutput = this.serialOutput;
if (serialOutput != null) {
serialOutput.println(data);
serialOutput.flush();
}
}
public abstract void open(String comPort);
public final void close() {
isClosed = true;
lastError = null;
closeConnection();
}
protected final void closeConnection() {
isOpen = false;
if (serialOutput != null) {
serialOutput.close();
serialOutput = null;
}
doClose();
serialClosed();
}
protected abstract void doClose();
protected final void serialData(String line) {
listener.serialData(this, line);
}
protected final void serialOpened() {
listener.serialOpened(this);
}
protected final void serialClosed() {
listener.serialClosed(this);
}
}

View File

@ -1,49 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* SerialConnectionListener
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 5 oct 2010
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect;
public interface SerialConnectionListener {
public void serialData(SerialConnection connection, String line);
public void serialOpened(SerialConnection connection);
public void serialClosed(SerialConnection connection);
}

View File

@ -1,107 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* SerialDumpConnection
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 5 oct 2010
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.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 static final String SERIALDUMP_MACOS = "./tools/serialdump-macos";
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 if (osName.startsWith("mac")) {
fullCommand = SERIALDUMP_MACOS + " " + "-b115200" + " " + 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

@ -1,120 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* StdinConnection
*
* Authors : Niclas Finne
* Created : 5 oct 2010
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.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

@ -1,130 +0,0 @@
/*
* Copyright (c) 2012, 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.
*
* -----------------------------------------------------------------
*
* TCPClientConnection
*
* Authors : Niclas Finne
*/
package org.contikios.contiki.collect;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
/**
*
*/
public class TCPClientConnection extends SerialConnection {
private final String host;
private final int port;
private Socket client;
private BufferedReader in;
private PrintStream out;
public TCPClientConnection(SerialConnectionListener listener, String host, int port) {
super(listener);
this.host = host;
this.port = port;
}
@Override
public String getConnectionName() {
return "<tcp://" + host + ':' + port + '>';
}
@Override
public void open(String comPort) {
close();
this.comPort = comPort == null ? "" : comPort;
isClosed = false;
try {
client = new Socket(host, port);
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintStream(client.getOutputStream());
System.out.println("Opened TCP connection to " + host + ':' + port);
/* Start thread listening on UDP */
Thread readInput = new Thread(new Runnable() {
public void run() {
try {
String line;
while (isOpen && (line = in.readLine()) != null) {
serialData(line);
}
} catch (IOException e) {
lastError = "Error when reading from SerialConnection TCP: " + e;
System.err.println(lastError);
if (!isClosed) {
e.printStackTrace();
closeConnection();
}
} finally {
System.out.println("SerialConnection TCP terminated.");
closeConnection();
}
}
}, "TCP thread");
isOpen = true;
serialOpened();
readInput.start();
} catch (Exception e) {
lastError = "Failed to open TCP connection to " + host + ':' + port + ": " + e;
System.err.println(lastError);
e.printStackTrace();
closeConnection();
}
}
@Override
protected void doClose() {
try {
if (in != null) {
in.close();
in = null;
}
if (out != null) {
out.close();
out = null;
}
if (client != null) {
client.close();
client = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@ -1,140 +0,0 @@
/*
* Copyright (c) 2011, 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.
*
* -----------------------------------------------------------------
*
* UDPConnection
*
* Authors : Niclas Finne
* Created : 1 June 2011
*/
package org.contikios.contiki.collect;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.io.*;
/**
*
*/
public class UDPConnection extends SerialConnection {
private final int port;
private DatagramSocket serverSocket;
public UDPConnection(SerialConnectionListener listener, int port) {
super(listener);
this.port = port;
}
@Override
public String getConnectionName() {
return "<UDP:" + port + ">";
}
@Override
public void open(String comPort) {
close();
this.comPort = comPort == null ? "" : comPort;
isClosed = false;
try {
serverSocket = new DatagramSocket(port);
System.out.println("Opened UDP port: " + port);
/* Start thread listening on UDP */
Thread readInput = new Thread(new Runnable() {
public void run() {
byte[] data = new byte[1024];
try {
while (isOpen) {
DatagramPacket packet = new DatagramPacket(data, data.length);
serverSocket.receive(packet);
InetAddress addr = packet.getAddress();
System.out.println("UDP: received " + packet.getLength() + " bytes from " + addr.getHostAddress() + ":" + packet.getPort());
StringWriter strOut = new StringWriter();
PrintWriter out = new PrintWriter(strOut);
int payloadLen = packet.getLength() - 2;
out.printf("%d", 8 + payloadLen / 2);
/* Timestamp. Ignore time synch for now. */
long time = System.currentTimeMillis() / 1000;
out.printf(" %d %d 0",
((time >> 16) & 0xffff), time & 0xffff);
byte[] payload = packet.getData();
int seqno = payload[0] & 0xff;
int hops = 0; /* how to get TTL / hot limit in Java??? */
byte[] address = addr.getAddress();
/* Ignore latency for now */
out.printf(" %d %d %d %d",
((address[14] & 0xff) +
((address[15] & 0xff) << 8))&0xffff, seqno, hops, 0);
int d = 0;
for(int i = 0; i < payloadLen ; i += 2) {
d = (payload[i + 2] & 0xff) + ((payload[i + 3] & 0xff) << 8);
out.printf(" %d", d & 0xffff);
}
String line = strOut.toString();
serialData(line);
}
System.out.println("SerialConnection UDP terminated.");
closeConnection();
} catch (IOException e) {
lastError = "Error when reading from SerialConnection UDP: " + e;
System.err.println(lastError);
if (!isClosed) {
e.printStackTrace();
closeConnection();
}
}
}
}, "UDP thread");
isOpen = true;
serialOpened();
readInput.start();
} catch (Exception e) {
lastError = "Failed to open UDP server at port " + port + ": " + e;
System.err.println(lastError);
e.printStackTrace();
closeConnection();
}
}
@Override
protected void doClose() {
if (serverSocket != null) {
serverSocket.close();
serverSocket = null;
}
}
}

View File

@ -1,57 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* Visualizer
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect;
import java.awt.Component;
/**
*
*/
public interface Visualizer {
public String getCategory();
public String getTitle();
public Component getPanel();
public void nodesSelected(Node[] node);
public void nodeAdded(Node node);
public void nodeDataReceived(SensorData sensorData);
public void clearNodeData();
}

View File

@ -1,224 +0,0 @@
/*
* 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.
*
* -----------------------------------------------------------------
*
* PacketChartPanel
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 6 sep 2010
*/
package org.contikios.contiki.collect.gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Minute;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.contikios.contiki.collect.CollectServer;
import org.contikios.contiki.collect.Node;
import org.contikios.contiki.collect.SensorData;
import org.contikios.contiki.collect.Visualizer;
/**
*
*/
public abstract class AggregatedTimeChartPanel<T> extends JPanel implements Visualizer {
private static final long serialVersionUID = 2100788758213434540L;
protected final CollectServer server;
protected final String category;
protected final String title;
protected final TimeSeries series;
protected final JFreeChart chart;
protected final ChartPanel chartPanel;
private Node[] selectedNodes;
private HashMap<Node,T> selectedMap = new HashMap<Node,T>();
public AggregatedTimeChartPanel(CollectServer server, String category, String title,
String timeAxisLabel, String valueAxisLabel) {
super(new BorderLayout());
this.server = server;
this.category = category;
this.title = title;
this.series = new TimeSeries(title, Minute.class);
TimeSeriesCollection timeSeries = new TimeSeriesCollection(series);
this.chart = ChartFactory.createTimeSeriesChart(
title, timeAxisLabel, valueAxisLabel, timeSeries,
false, true, false
);
this.chartPanel = new ChartPanel(chart);
this.chartPanel.setPreferredSize(new Dimension(500, 270));
setBaseShapeVisible(false);
add(chartPanel, BorderLayout.CENTER);
}
@Override
public String getCategory() {
return category;
}
@Override
public String getTitle() {
return title;
}
@Override
public Component getPanel() {
return this;
}
@Override
public void nodeAdded(Node node) {
// Ignore
}
@Override
public void nodesSelected(Node[] nodes) {
if (isVisible()) {
updateSelected(nodes);
}
}
private void updateSelected(Node[] nodes) {
if (this.selectedNodes != nodes) {
this.selectedNodes = nodes;
this.selectedMap.clear();
if (nodes != null) {
for(Node node : nodes) {
this.selectedMap.put(node, createState(node));
}
}
updateCharts();
}
}
@Override
public void nodeDataReceived(SensorData data) {
if (isVisible() && selectedMap.get(data.getNode()) != null) {
updateCharts();
}
}
@Override
public void clearNodeData() {
if (isVisible()) {
updateCharts();
}
}
private void updateCharts() {
int duplicates = 0;
int total = 0;
series.clear();
if (this.selectedNodes != null && server.getSensorDataCount() > 0) {
long minute = server.getSensorData(0).getNodeTime() / 60000;
long lastMinute = minute;
int count = 0;
clearState(selectedMap);
for(int i = 0; i < server.getSensorDataCount(); i++) {
SensorData sd = server.getSensorData(i);
T nodeState = selectedMap.get(sd.getNode());
if (nodeState != null) {
if (sd.isDuplicate()) {
duplicates++;
} else {
long min = sd.getNodeTime() / 60000;
if (min != minute) {
if (lastMinute < minute) {
series.add(new Minute(new Date(lastMinute * 60000L)), 0);
if (lastMinute < minute - 1) {
series.add(new Minute(new Date((minute - 1) * 60000L)), 0);
}
}
series.add(new Minute(new Date(minute * 60000L)), getTotalDataValue(count));
count = 0;
lastMinute = minute + 1;
minute = min;
}
count += getSensorDataValue(sd, nodeState);
}
total++;
}
}
}
chart.setTitle(getTitle(selectedMap.size(), total, duplicates));
}
protected String getTitle(int nodeCount, int dataCount, int duplicateCount) {
return title;
}
protected abstract T createState(Node node);
protected void clearState(Map<Node,T> map) {
}
protected int getTotalDataValue(int value) {
return value;
}
protected abstract int getSensorDataValue(SensorData sd, T nodeState);
public boolean getBaseShapeVisible() {
return ((XYLineAndShapeRenderer)this.chart.getXYPlot().getRenderer()).getBaseShapesVisible();
}
public void setBaseShapeVisible(boolean visible) {
((XYLineAndShapeRenderer)this.chart.getXYPlot().getRenderer()).setBaseShapesVisible(visible);
}
public double getRangeMinimumSize() {
return chart.getXYPlot().getRangeAxis().getAutoRangeMinimumSize();
}
public void setRangeMinimumSize(double size) {
chart.getXYPlot().getRangeAxis().setAutoRangeMinimumSize(size);
}
public void setVisible(boolean visible) {
updateSelected(visible ? server.getSelectedNodes() : null);
super.setVisible(visible);
}
}

View File

@ -1,234 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* PowerPanel
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 5 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.BarRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.contikios.contiki.collect.CollectServer;
import org.contikios.contiki.collect.Node;
import org.contikios.contiki.collect.SensorData;
import org.contikios.contiki.collect.Visualizer;
/**
*
*/
public abstract class BarChartPanel extends JPanel implements Visualizer {
private static final long serialVersionUID = 7664283678708048061L;
protected final CollectServer server;
protected final String category;
protected final String title;
protected final String[] categories;
protected final JFreeChart chart;
protected final ChartPanel chartPanel;
protected final DefaultCategoryDataset dataset;
private boolean isShowingAllNodes = false;
private int categoryOrder = 0;
protected BarChartPanel(CollectServer server, String category, String title,
String chartTitle, String domainAxisLabel, String valueAxisLabel,
String[] categories) {
this(server, category, title, chartTitle, domainAxisLabel, valueAxisLabel, categories, true);
}
protected BarChartPanel(CollectServer server, String category, String title,
String chartTitle, String domainAxisLabel, String valueAxisLabel,
String[] categories, boolean stackedChart) {
super(new BorderLayout());
this.server = server;
this.category = category;
this.title = title;
this.categories = categories;
/* Create chart with power of all nodes */
dataset = new DefaultCategoryDataset();
if (stackedChart) {
this.chart = ChartFactory.createStackedBarChart(chartTitle,
domainAxisLabel, valueAxisLabel, dataset, PlotOrientation.VERTICAL,
categories.length > 1, true, false);
} else {
this.chart = ChartFactory.createBarChart(chartTitle,
domainAxisLabel, valueAxisLabel, dataset, PlotOrientation.VERTICAL,
categories.length > 1, true, false);
if (categories.length > 1) {
CategoryPlot plot = chart.getCategoryPlot();
BarRenderer renderer = (BarRenderer) plot.getRenderer();
renderer.setItemMargin(0);
}
}
this.chartPanel = new ChartPanel(chart, false);
this.chartPanel.setPreferredSize(new Dimension(500, 270));
if (categories.length > 1) {
this.chartPanel.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
categoryOrder++;
updateCharts();
}
});
}
CategoryPlot plot = (CategoryPlot) chart.getPlot();
BarRenderer renderer = (BarRenderer) plot.getRenderer();
if (categories.length < 3) {
renderer.setDrawBarOutline(false);
GradientPaint gp = new GradientPaint(0.0f, 0.0f, Color.RED,
0.0f, 0.0f, new Color(128, 0, 0));
renderer.setSeriesPaint(0, gp);
if (categories.length > 1) {
gp = new GradientPaint(0.0f, 0.0f, Color.BLUE,
0.0f, 0.0f, new Color(0, 0, 128));
renderer.setSeriesPaint(1, gp);
}
} else {
renderer.setDrawBarOutline(true);
}
add(chartPanel, BorderLayout.CENTER);
}
@Override
public String getCategory() {
return category;
}
@Override
public String getTitle() {
return title;
}
@Override
public Component getPanel() {
return this;
}
public boolean isShowingAllNodes() {
return isShowingAllNodes;
}
public void setShowingAllNodes(boolean isShowingAllNodes) {
if (this.isShowingAllNodes != isShowingAllNodes) {
this.isShowingAllNodes = isShowingAllNodes;
if (isVisible()) {
updateCharts();
}
}
}
@Override
public void nodeAdded(Node node) {
if (isVisible()) {
int count = node.getSensorDataCount();
if (count > 0 || isShowingAllNodes) {
addNode(node);
}
if (count > 0) {
addSensorData(node.getSensorData(count - 1));
}
}
}
@Override
public void nodesSelected(Node[] nodes) {
}
@Override
public void nodeDataReceived(SensorData data) {
if (isVisible()) {
addSensorData(data);
}
}
@Override
public void clearNodeData() {
if (isVisible()) {
updateCharts();
}
}
private void updateCharts() {
dataset.clear();
Node[] nodes = server.getNodes();
if (nodes != null) {
for (int i = 0, n = nodes.length; i < n; i++) {
int count = nodes[i].getSensorDataCount();
if (count > 0 || isShowingAllNodes) {
addNode(nodes[i]);
}
if (count > 0) {
addSensorData(nodes[i].getSensorData(count - 1));
}
}
}
}
private void addNode(Node node) {
String name = node.getName();
for (int j = 0, m = categories.length; j < m; j++) {
dataset.addValue(0, categories[(j + categoryOrder) % categories.length], name);
}
}
public void setVisible(boolean visible) {
if (visible) {
updateCharts();
} else {
dataset.clear();
}
super.setVisible(visible);
}
protected abstract void addSensorData(SensorData data);
}

View File

@ -1,851 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* MapPanel
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
* Updated : $Date: 2010/11/23 16:21:48 $
* $Revision: 1.4 $
*/
package org.contikios.contiki.collect.gui;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Properties;
import java.util.logging.Logger;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFormattedTextField;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.basic.BasicGraphicsUtils;
import org.contikios.contiki.collect.CollectServer;
import org.contikios.contiki.collect.Configurable;
import org.contikios.contiki.collect.Link;
import org.contikios.contiki.collect.Node;
import org.contikios.contiki.collect.SensorData;
import org.contikios.contiki.collect.Visualizer;
/**
*
*/
public class MapPanel extends JPanel implements Configurable, Visualizer, ActionListener, MouseListener, MouseMotionListener {
private static final long serialVersionUID = -8256619482599309425L;
private static final Logger log =
Logger.getLogger(MapPanel.class.getName());
private static final boolean VISUAL_DRAG = true;
private static final Color LINK_COLOR = new Color(0x40, 0x40, 0xf0, 0xff);
private static final int delta = 7;
private final CollectServer server;
private final String category;
private final boolean isMap;
private String title;
private Timer timer;
private JPopupMenu popupMenu;
private JCheckBoxMenuItem layoutItem;
private JCheckBoxMenuItem lockedItem;
private JMenuItem shakeItem;
// private JCheckBoxMenuItem dragItem;
private JCheckBoxMenuItem backgroundItem;
private JCheckBoxMenuItem showNetworkItem;
private JCheckBoxMenuItem configItem;
private JMenuItem resetNetworkItem;
private MapNode popupNode;
private Hashtable<String,MapNode> nodeTable = new Hashtable<String,MapNode>();
private MapNode[] nodeList = new MapNode[0];
private boolean updateNodeList;
private MapNode selectedNode;
private ArrayList<MapNode> selectedMapNodes = new ArrayList<MapNode>();
private Node[] selectedNodes;
private MapNode draggedNode;
private long draggedTime;
private ImageIcon mapImage;
private String mapName;
private boolean showBackground;
private int layoutRepel = 100;
private int layoutAttract = 50;
private int layoutGravity = 1;
private double etxFactor = 1.0;
private boolean isLayoutActive = true;
private boolean hideNetwork = false;
protected JPanel configPanel;
public MapPanel(CollectServer server, String title, String category, boolean isMap) {
super(null);
this.server = server;
this.title = title;
this.category = category;
this.isMap = isMap;
setPreferredSize(new Dimension(300, 200));
popupMenu = new JPopupMenu(getTitle());
if (!isMap) {
layoutItem = createCheckBoxMenuItem(popupMenu, "Update Layout", isLayoutActive);
popupMenu.add(layoutItem);
lockedItem = createCheckBoxMenuItem(popupMenu, "Fixed Node Position", false);
shakeItem = createMenuItem(popupMenu, "Shake Nodes");
popupMenu.addSeparator();
}
showNetworkItem = createCheckBoxMenuItem(popupMenu, "Show Network Info", true);
resetNetworkItem = createMenuItem(popupMenu, "Reset Network");
popupMenu.addSeparator();
if (isMap) {
backgroundItem = createCheckBoxMenuItem(popupMenu, "Show Background", false);
backgroundItem.setEnabled(false);
} else {
configItem = createCheckBoxMenuItem(popupMenu, "Show Layout Settings", false);
}
// popupMenu.addSeparator();
// dragItem = new JCheckBoxMenuItem("Visible Drag", true);
// popupMenu.add(dragItem);
setBackground(Color.white);
addMouseListener(this);
addMouseMotionListener(this);
if (!isMap) {
timer = new Timer(100, this);
configPanel = new JPanel(new GridLayout(0, 1));
configPanel.setBorder(LineBorder.createBlackLineBorder());
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 1000, 1000 - layoutAttract);
slider.setBorder(new TitledBorder("Attract Factor: " + (1000 - layoutAttract)));
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider)e.getSource();
layoutAttract = 1000 - slider.getValue();
((TitledBorder)slider.getBorder()).setTitle("Attract Factor: " + slider.getValue());
}
});
configPanel.add(slider);
slider = new JSlider(JSlider.HORIZONTAL, 0, 1000, layoutRepel);
slider.setBorder(new TitledBorder("Repel Range: " + layoutRepel));
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider)e.getSource();
layoutRepel = slider.getValue();
((TitledBorder)slider.getBorder()).setTitle("Repel Range: " + layoutRepel);
}
});
configPanel.add(slider);
slider = new JSlider(JSlider.HORIZONTAL, 0, 100, layoutGravity);
slider.setBorder(new TitledBorder("Gravity: " + layoutGravity));
slider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
JSlider slider = (JSlider)e.getSource();
layoutGravity = slider.getValue();
((TitledBorder)slider.getBorder()).setTitle("Gravity: " + layoutGravity);
}
});
configPanel.add(slider);
final JFormattedTextField etxField = new JFormattedTextField(new Double(etxFactor));
etxField.setBorder(BorderFactory.createTitledBorder("ETX factor"));
etxField.setColumns(5);
etxField.addPropertyChangeListener("value", new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
etxFactor = ((Number)etxField.getValue()).doubleValue();
repaint();
}
});
configPanel.add(etxField);
configPanel.setVisible(false);
add(configPanel);
addComponentListener(new ComponentAdapter() {
public void componentResized(ComponentEvent ev) {
if (configPanel.isVisible()) {
updateConfigLayout();
}
}
});
}
}
public String getMapBackground() {
return isMap ? mapName : null;
}
public boolean setMapBackground(String image) {
if (!isMap) {
return false;
}
if (image == null) {
mapImage = null;
mapName = null;
backgroundItem.setEnabled(false);
backgroundItem.setSelected(false);
showBackground = false;
repaint();
return true;
}
ImageIcon ii = new ImageIcon(image);
if (ii.getIconWidth() <= 0 || ii.getIconHeight() <= 0) {
log.warning("could not find image '" + image + '\'');
return false;
}
mapImage = ii;
mapName = image;
setPreferredSize(new Dimension(ii.getIconWidth(), ii.getIconHeight()));
showBackground = true;
backgroundItem.setEnabled(true);
backgroundItem.setSelected(true);
repaint();
return true;
}
private JCheckBoxMenuItem createCheckBoxMenuItem(JPopupMenu menu, String title, boolean isSelected) {
JCheckBoxMenuItem item = new JCheckBoxMenuItem(title, isSelected);
item.addActionListener(this);
menu.add(item);
return item;
}
private JMenuItem createMenuItem(JPopupMenu menu, String title) {
JMenuItem item = new JMenuItem(title);
item.addActionListener(this);
menu.add(item);
return item;
}
public void setVisible(boolean visible) {
if (visible) {
clear();
if (timer != null) {
timer.start();
}
} else {
if (timer != null) {
timer.stop();
}
}
super.setVisible(visible);
}
public void clear() {
setCursor(Cursor.getDefaultCursor());
draggedNode = null;
updateSelected();
}
// -------------------------------------------------------------------
// Node handling
// -------------------------------------------------------------------
public Node getNode(String id) {
MapNode node = nodeTable.get(id);
return node != null ? node.node : null;
}
public MapNode getMapNode(String id) {
return nodeTable.get(id);
}
private MapNode addMapNode(Node nd) {
String id = nd.getID();
MapNode node = nodeTable.get(id);
if (node == null) {
node = new MapNode(this, nd);
node.y = 10 + (int) (Math.random() * (Math.max(100, getHeight()) - 20));
node.x = 10 + (int) (Math.random() * (Math.max(100, getWidth()) - 30));
String location = server.getConfig(isMap ? id : ("collect.map." + id));
if (location != null) {
try {
String[] pos = location.split(",");
node.x = Integer.parseInt(pos[0].trim());
node.y = Integer.parseInt(pos[1].trim());
node.hasFixedLocation = !isMap;
} catch (Exception e) {
System.err.println("could not parse node location: " + location);
e.printStackTrace();
}
}
nodeTable.put(id, node);
updateNodeList = true;
}
return node;
}
private MapNode[] getNodeList() {
if (updateNodeList) {
synchronized (nodeTable) {
updateNodeList = false;
nodeList = nodeTable.values().toArray(new MapNode[nodeTable.size()]);
}
}
return nodeList;
}
// -------------------------------------------------------------------
// Visualizer
// -------------------------------------------------------------------
@Override
public String getCategory() {
return category;
}
@Override
public String getTitle() {
return title;
}
@Override
public Component getPanel() {
return this;
}
@Override
public void nodesSelected(Node[] nodes) {
if (selectedNodes != nodes) {
selectedNodes = nodes;
if (isVisible()) {
updateSelected();
}
}
}
private void updateSelected() {
if (selectedMapNodes.size() > 0) {
for(MapNode node : selectedMapNodes) {
node.isSelected = false;
}
selectedMapNodes.clear();
}
if (selectedNodes == null || selectedNodes.length == 0) {
selectedNode = null;
} else {
for (Node node : selectedNodes) {
MapNode mapNode = addMapNode(node);
selectedMapNodes.add(mapNode);
mapNode.isSelected = true;
}
selectedNode = selectedMapNodes.get(0);
}
repaint();
}
@Override
public void nodeAdded(Node nd) {
addMapNode(nd);
if (isVisible()) {
repaint();
}
}
@Override
public void nodeDataReceived(SensorData sensorData) {
if (isVisible()) {
repaint();
}
}
@Override
public void clearNodeData() {
nodeTable.clear();
updateNodeList = true;
nodesSelected(null);
if (isVisible()) {
repaint();
}
}
// -------------------------------------------------------------------
// Graphics
// -------------------------------------------------------------------
@Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
FontMetrics fm = g.getFontMetrics();
int fnHeight = fm.getHeight();
int fnDescent = fm.getDescent();
int width = getWidth();
int height = getHeight();
g.setColor(getBackground());
g.fillRect(0, 0, width, height);
if (showBackground && isMap) {
mapImage.paintIcon(this, g, 0, 0);
}
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
// Display legend
if (!hideNetwork) {
int legendWidth = fm.stringWidth("ETX");
g.setColor(Color.black);
g.drawString("ETX", width - legendWidth - 10, 10 + fnHeight - fnDescent);
g.drawRect(width - legendWidth - 30, 8, legendWidth + 24, fnHeight + 4);
g.setColor(LINK_COLOR);
g2d.drawLine(width - legendWidth - 25, 10 + fnHeight / 2,
width - legendWidth - 15, 10 + fnHeight / 2);
}
MapNode[] nodes = getNodeList();
if (!isMap || !hideNetwork) {
g.setColor(LINK_COLOR);
for (MapNode n : nodes) {
for (int j = 0, mu = n.node.getLinkCount(); j < mu; j++) {
Link link = n.node.getLink(j);
MapNode linkNode = addMapNode(link.node);
int x2 = linkNode.x;
int y2 = linkNode.y;
g2d.drawLine(n.x, n.y, x2, y2);
drawArrow(g, n.x, n.y, x2, y2, 3);
if (!hideNetwork) {
int xn1, xn2, yn1, yn2;
if (n.x <= x2) {
xn1 = n.x; xn2 = x2;
yn1 = n.y; yn2 = y2;
} else {
xn1 = x2; xn2 = n.x;
yn1 = y2; yn2 = n.y;
}
int dx = xn1 + (xn2 - xn1) / 2 + 4;
int dy = yn1 + (yn2 - yn1) / 2 - fnDescent;
if (yn2 < yn1) {
dy += fnHeight - fnDescent;
}
g.drawString(
Double.toString(((int) (link.getETX() * etxFactor * 100 + 0.5)) / 100.0),
dx, dy);
}
}
}
}
for (MapNode n : nodes) {
n.paint(g, n.x, n.y);
g.setColor(Color.black);
if (n.isSelected) {
BasicGraphicsUtils.drawDashedRect(g, n.x - delta, n.y - delta,
2 * delta, 2 * delta);
}
if (selectedNode != null && selectedNode.message != null) {
g.drawString(selectedNode.message, 10, 10);
}
}
}
private Polygon arrowPoly = new Polygon();
private void drawArrow(Graphics g, int xSource, int ySource, int xDest, int yDest, int delta) {
double dx = xSource - xDest;
double dy = ySource - yDest;
double dir = Math.atan2(dx, dy);
double len = Math.sqrt(dx * dx + dy * dy);
dx /= len;
dy /= len;
len -= delta;
xDest = xSource - (int) (dx * len);
yDest = ySource - (int) (dy * len);
g.drawLine(xDest, yDest, xSource, ySource);
final int size = 8;
arrowPoly.reset();
arrowPoly.addPoint(xDest, yDest);
arrowPoly.addPoint(xDest + xCor(size, dir + 0.5), yDest + yCor(size, dir + 0.5));
arrowPoly.addPoint(xDest + xCor(size, dir - 0.5), yDest + yCor(size, dir - 0.5));
arrowPoly.addPoint(xDest, yDest);
g.fillPolygon(arrowPoly);
}
private int yCor(int len, double dir) {
return (int)(0.5 + len * Math.cos(dir));
}
private int xCor(int len, double dir) {
return (int)(0.5 + len * Math.sin(dir));
}
// -------------------------------------------------------------------
// ActionListener
// -------------------------------------------------------------------
public void actionPerformed(ActionEvent e) {
Object source = e.getSource();
if (!isMap && source == timer) {
if (isLayoutActive) {
updateNodeLayout();
repaint();
}
} else if (!isMap && source == lockedItem) {
if (popupNode != null) {
boolean wasFixed = popupNode.hasFixedLocation;
popupNode.hasFixedLocation = lockedItem.isSelected();
if (wasFixed && !popupNode.hasFixedLocation) {
server.removeConfig("collect.map." + popupNode.node.getID());
} else if (!wasFixed && popupNode.hasFixedLocation) {
server.setConfig("collect.map." + popupNode.node.getID(),
"" + popupNode.x + ',' + popupNode.y);
}
repaint();
}
} else if (!isMap && source == layoutItem) {
isLayoutActive = layoutItem.isSelected();
} else if (!isMap && source == shakeItem) {
for(MapNode n : getNodeList()) {
if (!n.hasFixedLocation) {
n.x += Math.random() * 100 - 50;
n.y += Math.random() * 100 - 50;
}
}
} else if (!isMap && source == configItem) {
if (configItem.isSelected()) {
configPanel.setSize(getPreferredSize());
configPanel.validate();
updateConfigLayout();
configPanel.setVisible(true);
} else {
configPanel.setVisible(false);
}
repaint();
} else if (source == showNetworkItem) {
hideNetwork = !showNetworkItem.isSelected();
repaint();
} else if (source == resetNetworkItem) {
for(MapNode n : getNodeList()) {
n.node.clearLinks();
}
repaint();
} else if (isMap && source == backgroundItem) {
showBackground = mapImage != null && backgroundItem.isSelected();
repaint();
}
}
private void updateNodeLayout() {
MapNode[] nodes = getNodeList();
for (MapNode n : nodes) {
// Attract connected nodes
for(int i = 0, jn = n.node.getLinkCount(); i < jn; i++) {
Link link = n.node.getLink(i);
MapNode n2 = addMapNode(link.node);
double vx = n2.x - n.x;
double vy = n2.y - n.y;
double dist = Math.sqrt(vx * vx + vy * vy);
dist = dist == 0 ? 0.00001 : dist;
double etx = link.getETX() * etxFactor;
if (etx > 5) etx = 5;
double factor = (etx * layoutAttract - dist) / (dist * 3);
double dx = factor * vx;
double dy = factor * vy;
n2.dx += dx;
n2.dy += dy;
n.dx -= dx;
n.dy -= dy;
}
// Repel nodes that are too close
double dx = 0, dy = 0;
for (MapNode n2 : nodes) {
if (n == n2) {
continue;
}
double vx = n.x - n2.x;
double vy = n.y - n2.y;
double dist = vx * vx + vy * vy;
if (dist == 0) {
dx += Math.random() * 5;
dy += Math.random() * 5;
} else if (dist < layoutRepel * layoutRepel) {
dx += vx / dist;
dy += vy / dist;
}
}
double dist = dx * dx + dy * dy;
if (dist > 0) {
dist = Math.sqrt(dist) / 2;
n.dx += dx / dist;
n.dy += dy / dist;
}
n.dy += layoutGravity;
}
// Update the node positions
int width = getWidth();
int height = getHeight();
for(MapNode n : nodes) {
if (!n.hasFixedLocation && n != draggedNode) {
n.x += Math.max(-5, Math.min(5, n.dx));
n.y += Math.max(-5, Math.min(5, n.dy));
if (n.x < 0) {
n.x = 0;
} else if (n.x > width) {
n.x = width;
}
if (n.y < 0) {
n.y = 0;
} else if (n.y > height) {
n.y = height;
}
}
n.dx /= 2;
n.dy /= 2;
}
}
private void updateConfigLayout() {
configPanel.setLocation(getWidth() - configPanel.getWidth() - 10,
getHeight() - configPanel.getHeight() - 10);
}
// -------------------------------------------------------------------
// Mouselistener
// -------------------------------------------------------------------
private MapNode getNodeAt(int mx, int my) {
for(MapNode n : getNodeList()) {
if (mx >= (n.x - delta)
&& mx <= (n.x + delta)
&& my >= (n.y - delta)
&& my <= (n.y + delta)) {
return n;
}
}
return null;
}
public void mouseClicked(MouseEvent e) {
int mx = e.getX();
int my = e.getY();
if (e.getButton() == MouseEvent.BUTTON1) {
MapNode node = getNodeAt(mx, my);
if (node != selectedNode) {
server.selectNodes(node == null ? null : new Node[] { node.node });
}
}
showPopup(e);
}
public void mousePressed(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
MapNode aNode = getNodeAt(e.getX(), e.getY());
if (aNode != selectedNode) {
server.selectNodes(aNode != null ? new Node[] { aNode.node } : null);
}
draggedNode = aNode;
draggedTime = System.currentTimeMillis();
} else if (selectedNode != null) {
if (draggedTime < 0) {
setCursor(Cursor.getDefaultCursor());
draggedTime = 0;
}
selectedNode = draggedNode = null;
server.selectNodes(null);
}
showPopup(e);
}
public void mouseReleased(MouseEvent e) {
if (draggedNode != null && e.getButton() == MouseEvent.BUTTON1) {
if ((draggedTime > 0) &&
(System.currentTimeMillis() - draggedTime) < 300) {
// Do not drag if mouse is only moved during click
} else {
draggedNode.x = e.getX();
draggedNode.y = e.getY();
setCursor(Cursor.getDefaultCursor());
if (!isMap && draggedNode.hasFixedLocation) {
/* Update fixed location */
server.setConfig("collect.map." + draggedNode.node.getID(),
"" + draggedNode.x + ',' + draggedNode.y);
}
draggedTime = 0;
draggedNode = null;
repaint();
}
}
showPopup(e);
}
private void showPopup(MouseEvent e) {
if (e.isPopupTrigger()
&& (e.getModifiers() & (MouseEvent.SHIFT_MASK|MouseEvent.CTRL_MASK)) == 0) {
popupNode = getNodeAt(e.getX(), e.getY());
if (!isMap) {
lockedItem.setEnabled(popupNode != null);
lockedItem.setSelected(popupNode != null ? popupNode.hasFixedLocation : false);
}
popupMenu.show(this, e.getX(), e.getY());
}
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
// -------------------------------------------------------------------
// MouseMotion
// -------------------------------------------------------------------
public void mouseDragged(MouseEvent e) {
if (draggedNode == null) {
// Do nothing
} else if (draggedTime > 0) {
if ((System.currentTimeMillis() - draggedTime) > 300) {
// No mouse click, time to drag the node
draggedTime = -1;
setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
} else if (VISUAL_DRAG /* && dragItem.isSelected() */) {
draggedNode.x = e.getX();
draggedNode.y = e.getY();
repaint();
}
}
public void mouseMoved(MouseEvent e) {
}
// -------------------------------------------------------------------
// MapNode
// -------------------------------------------------------------------
private static class MapNode {
public final Node node;
public int x;
public int y;
public double dx;
public double dy;
public boolean hasFixedLocation;
public boolean isSelected;
public String message;
MapNode(MapPanel panel, Node node) {
this.node = node;
}
public void paint(Graphics g, int x, int y) {
final int od = 3;
g.setColor(Color.black);
g.drawString(node.getID(), x + od * 2 + 3, y + 4);
if (hasFixedLocation) {
g.setColor(Color.red);
}
g.fillOval(x - od, y - od, od * 2 + 1, od * 2 + 1);
}
} // end of inner class MapNode
@Override
public void updateConfig(Properties config) {
if (isMap) {
for (MapNode n : getNodeList()) {
config.put(n.node.getID(), "" + n.x + ',' + n.y);
}
}
}
}

View File

@ -1,304 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* NodeControl
*
* Authors : Niclas Finne
* Created : 27 sep 2010
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFormattedTextField;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextPane;
import javax.swing.border.LineBorder;
import org.contikios.contiki.collect.CollectServer;
import org.contikios.contiki.collect.Node;
import org.contikios.contiki.collect.SensorData;
import org.contikios.contiki.collect.Visualizer;
/**
*
*/
public class NodeControl implements Visualizer {
private final static String SET_TIME_COMMAND = "time %TIME% | null";
private final CollectServer server;
private final String category;
private final JPanel panel;
private final JLabel statusLabel;
private final JSeparator statusSeparator;
public NodeControl(CollectServer server, String category) {
this.server = server;
this.category = category;
this.panel = new JPanel(new BorderLayout());
final JFormattedTextField intervalField = new JFormattedTextField(new Integer(60));
final JFormattedTextField randomField = new JFormattedTextField(new Integer(60));
final JFormattedTextField reportsField = new JFormattedTextField(new Integer(0));
final JFormattedTextField rexmitsField = new JFormattedTextField(new Integer(31));
statusLabel = new JLabel("", JLabel.CENTER);
statusLabel.setOpaque(true);
statusLabel.setBackground(Color.white);
statusLabel.setBorder(LineBorder.createBlackLineBorder());
statusLabel.setVisible(false);
statusSeparator = new JSeparator();
statusSeparator.setVisible(false);
JButton stopButton = createCommandButton("Send stop to nodes", "netcmd killall");
JButton sendButton = new JButton("Send command to nodes");
sendButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int interval = (Integer)intervalField.getValue();
int random = (Integer)randomField.getValue();
int reports = (Integer)reportsField.getValue();
int rexmits = (Integer)rexmitsField.getValue();
sendCommand("netcmd { repeat " + reports + " " + interval
+ " { randwait " + random + " collect-view-data | send " + rexmits + " } }");
}
});
JButton collectButton = createCommandButton("Start Collect",
"~K", "killall",
"mac 0", SET_TIME_COMMAND,
"collect | timestamp | binprint &");
JButton stopCollectButton = createCommandButton("Stop Collect", "~K", "killall");
JPanel controlPanel = new JPanel(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 0.5;
c.insets.left = c.insets.right = c.insets.bottom = 3;
c.anchor = GridBagConstraints.WEST;
c.gridy = 0;
c.gridwidth = 3;
controlPanel.add(statusLabel, c);
c.gridy++;
controlPanel.add(statusSeparator, c);
c.insets.top = 10;
c.gridy++;
c.gridwidth = 1;
controlPanel.add(new JLabel("Program Connected Nodes", JLabel.RIGHT), c);
c.gridwidth = 3;
c.fill = GridBagConstraints.NONE;
controlPanel.add(new JButton(server.getMoteProgramAction()), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridy++;
c.gridwidth = 1;
controlPanel.add(new JLabel("Serial Connection", JLabel.RIGHT), c);
c.gridwidth = 3;
c.fill = GridBagConstraints.NONE;
controlPanel.add(new JButton(server.getConnectSerialAction()), c);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridy++;
controlPanel.add(new JSeparator(), c);
c.gridy++;
c.gridwidth = 1;
controlPanel.add(new JLabel("Base Station Control", JLabel.RIGHT), c);
c.gridwidth = 2;
JPanel basePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));
basePanel.add(collectButton);
basePanel.add(stopCollectButton);
c.insets.left -= 5;
controlPanel.add(basePanel, c);
c.insets.left += 5;
c.gridy++;
c.gridwidth = 3;
controlPanel.add(new JSeparator(), c);
c.gridy++;
JLabel label = new JLabel("Collect Settings", JLabel.CENTER);
controlPanel.add(label, c);
c.gridwidth = 1;
c.gridy++;
controlPanel.add(label = new JLabel("Report interval", JLabel.RIGHT), c);
label.setLabelFor(intervalField);
controlPanel.add(intervalField, c);
controlPanel.add(new JLabel("seconds"), c);
c.insets.top = 3;
c.gridy++;
controlPanel.add(label = new JLabel("Report randomness", JLabel.RIGHT), c);
label.setLabelFor(randomField);
controlPanel.add(randomField, c);
controlPanel.add(new JLabel("seconds"), c);
c.gridy++;
controlPanel.add(label = new JLabel("Hop-by-hop retransmissions", JLabel.RIGHT), c);
label.setLabelFor(rexmitsField);
controlPanel.add(rexmitsField, c);
controlPanel.add(new JLabel("retransmissions (0 - 31)"), c);
c.gridy++;
controlPanel.add(new JLabel("Number of reports", JLabel.RIGHT), c);
label.setLabelFor(reportsField);
controlPanel.add(reportsField, c);
controlPanel.add(new JLabel("(0 = report forever)"), c);
c.gridy++;
c.gridwidth = 3;
c.insets.bottom = 10;
JPanel nodePanel = new JPanel();
nodePanel.add(sendButton);
nodePanel.add(stopButton);
controlPanel.add(nodePanel, c);
c.gridy++;
controlPanel.add(new JSeparator(), c);
panel.add(controlPanel, BorderLayout.NORTH);
JTextPane helpPane = new JTextPane();
helpPane.setContentType("text/html");
helpPane.setEditable(false);
helpPane.setText("<html>" +
"<h3>Quick Startup Instructions</h3>" +
"<lu>" +
"<li> Connect nodes to USB. Press the <strong>Program Nodes...</strong> button." +
"<li> Disconnect all except one node. " +
"Press the <strong>Connect to Serial</strong> button." +
"<li> Press the <strong>Start Collect</strong> button." +
"<li> Press the <strong>Send command to nodes</strong> button." +
"</lu>" +
"</html>");
helpPane.setBackground(panel.getBackground());
JScrollPane helpScroll = new JScrollPane(helpPane,
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
helpScroll.setBorder(BorderFactory.createEmptyBorder(3, 10, 10, 10));
panel.add(helpScroll, BorderLayout.CENTER);
}
private JButton createCommandButton(String name, final String... command) {
JButton button = new JButton(name);
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)) {
setStatus("Sent command '" + command + "'", false);
return true;
}
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);
statusSeparator.setVisible(true);
}
public String getCategory() {
return category;
}
public String getTitle() {
return "Node Control";
}
public Component getPanel() {
return panel;
}
public void nodesSelected(Node[] node) {
}
public void nodeAdded(Node node) {
}
public void nodeDataReceived(SensorData sensorData) {
}
public void clearNodeData() {
}
}

View File

@ -1,650 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* NodeInfoPanel
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 6 sep 2010
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect.gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Comparator;
import java.util.Properties;
import javax.swing.AbstractAction;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableRowSorter;
import org.contikios.contiki.collect.CollectServer;
import org.contikios.contiki.collect.Configurable;
import org.contikios.contiki.collect.Node;
import org.contikios.contiki.collect.SensorData;
import org.contikios.contiki.collect.SensorInfo;
import org.contikios.contiki.collect.Visualizer;
/**
*
*/
public class NodeInfoPanel extends JPanel implements Visualizer, Configurable {
private static final long serialVersionUID = -1060893468047793431L;
private static Comparator<Number> NUMBER_COMPARATOR = new Comparator<Number>() {
public int compare(Number o1, Number o2) {
double v1 = o1.doubleValue();
double v2 = o2.doubleValue();
return (v1 < v2 ? -1 : (v1 == v2 ? 0 : 1));
}
};
private final CollectServer server;
private final String category;
private final JTable table;
private final NodeModel nodeModel;
@SuppressWarnings("serial")
public NodeInfoPanel(CollectServer server, String category) {
super(new BorderLayout());
this.server = server;
this.category = category;
TableData[] columns = new TableData[] {
new TableData("Node", Node.class) {
public Object getValue(Node node) {
return node;
}
},
new TableData("Received", "Packets Received", Number.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getPacketCount();
}
},
new TableData("Dups", "Duplicate Packets Received", Number.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getDuplicateCount();
}
},
new TableData("Lost", "Estimated Lost Packets", Number.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getEstimatedLostCount();
}
},
new TableData("Hops", "Average Hops to Sink", Double.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getAverageValue(SensorData.HOPS);
}
},
new TableData("Rtmetric", "Average Routing Metric", Double.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getAverageRtmetric();
}
},
new TableData("ETX", "Average ETX to Next Hop", Double.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getAverageBestNeighborETX();
}
},
new TableData("Churn", "Next Hop Change Count", Number.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getNextHopChangeCount();
}
},
new TableData("Beacon Interval", "Average Beacon Interval", Long.class) {
public Object getValue(Node node) {
return (long)(node.getSensorDataAggregator().getAverageValue(SensorData.BEACON_INTERVAL) * 1000);
}
},
new TableData("Reboots", "Estimated Node Restart Count", Number.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getEstimatedRestarts();
}
},
// Power
new TableData("CPU Power", "Average CPU Power Consumption", Double.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getCPUPower();
}
},
new TableData("LPM Power", "Average LPM Power Consumption", Double.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getLPMPower();
}
},
new TableData("Listen Power", "Average Radio Listen Power Consumption", Double.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getListenPower();
}
},
new TableData("Transmit Power", "Average Radio Transmit Power Consumption", Double.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getTransmitPower();
}
},
new TableData("Power", "Average Power Consumption", Double.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getAveragePower();
}
},
new TableData("On-time", "Power Measure Time", Long.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getPowerMeasureTime();
}
},
new TableData("Listen Duty Cycle", "Average Radio Listen Duty Cycle (%)", Double.class) {
public Object getValue(Node node) {
return 100 * node.getSensorDataAggregator().getAverageDutyCycle(SensorInfo.TIME_LISTEN);
}
},
new TableData("Transmit Duty Cycle", "Average Radio Transmit Duty Cycle (%)", Double.class) {
public Object getValue(Node node) {
return 100 * node.getSensorDataAggregator().getAverageDutyCycle(SensorInfo.TIME_TRANSMIT);
}
},
// Inter-packet times
new TableData("Avg Inter-packet Time", Long.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getAveragePeriod();
}
},
new TableData("Min Inter-packet Time", Long.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getShortestPeriod();
}
},
new TableData("Max Inter-packet Time", Long.class) {
public Object getValue(Node node) {
return node.getSensorDataAggregator().getLongestPeriod();
}
}
};
nodeModel = new NodeModel(columns);
table = new JTable(nodeModel) {
private static final long serialVersionUID = 1L;
private Font fontForAverage;
protected JTableHeader createDefaultTableHeader() {
return new JTableHeader(columnModel) {
private static final long serialVersionUID = 1L;
public String getToolTipText(MouseEvent e) {
int index = columnModel.getColumnIndexAtX(e.getX());
int modelIndex = index < 0 ? index : columnModel.getColumn(index).getModelIndex();
return modelIndex < 0 ? null : nodeModel.getColumnToolTip(modelIndex);
}
};
}
public Component prepareRenderer(TableCellRenderer renderer, int rowIndex, int vColIndex) {
Component c = super.prepareRenderer(renderer, rowIndex, vColIndex);
int row = convertRowIndexToModel(rowIndex);
if (row == nodeModel.getRowCount() - 1) {
if (fontForAverage == null) {
fontForAverage = c.getFont().deriveFont(Font.BOLD);
}
// Last line is average
c.setFont(fontForAverage);
}
return c;
}
};
// Do not sort column when clicking between the columns (resizing)
TableRowSorter<NodeModel> sorter = new TableRowSorter<NodeModel>(nodeModel) {
public void toggleSortOrder(int column) {
if(table.getTableHeader().getCursor().getType() != Cursor.E_RESIZE_CURSOR) {
super.toggleSortOrder(column);
}
}
};
for(int c = 0; c < columns.length; c++) {
if (columns[c].dataClass == Number.class) {
sorter.setComparator(c, NUMBER_COMPARATOR);
}
}
table.setRowSorter(sorter);
// Pack the column when double clicking between columns (resizing)
table.getTableHeader().addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if(e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e) &&
table.getTableHeader().getCursor().getType() == Cursor.E_RESIZE_CURSOR) {
int index = table.getColumnModel().getColumnIndexAtX(e.getX() - 3);
if (index >= 0) {
packColumn(table, index);
}
}
}
});
// Add right aligned renderer for node name
DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
renderer.setHorizontalAlignment(JLabel.RIGHT);
table.setDefaultRenderer(Node.class, renderer);
// Add renderer for time
renderer = new DefaultTableCellRenderer() {
private static final long serialVersionUID = 1L;
public void setValue(Object value) {
long time = (Long) value;
setText(time > 0 ? getTimeAsString(time) : null);
}
};
renderer.setHorizontalAlignment(JLabel.RIGHT);
table.setDefaultRenderer(Long.class, renderer);
// Add renderer for double
renderer = new DefaultTableCellRenderer() {
private static final long serialVersionUID = 1L;
public void setValue(Object value) {
if (value == null) {
setText(null);
} else {
double v = ((Number) value).doubleValue() + 0.0005;
int dec = ((int)(v * 1000)) % 1000;
setText((long)v + "." + (dec > 99 ? "" : "0") + (dec > 9 ? "" : "0") + dec);
}
}
};
renderer.setHorizontalAlignment(JLabel.RIGHT);
table.setDefaultRenderer(Double.class, renderer);
// Add renderer for mixed integers and doubles
renderer = new DefaultTableCellRenderer() {
private static final long serialVersionUID = 1L;
public void setValue(Object value) {
if (value == null) {
setText(null);
} else if (value instanceof Integer) {
setText(value.toString());
} else {
double v = ((Number) value).doubleValue() + 0.0005;
int dec = ((int)(v * 1000)) % 1000;
setText((long)v + "." + (dec > 99 ? "" : "0") + (dec > 9 ? "" : "0") + dec);
}
}
};
renderer.setHorizontalAlignment(JLabel.RIGHT);
table.setDefaultRenderer(Number.class, renderer);
table.setFillsViewportHeight(true);
table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
for (int i = 0, n = table.getColumnCount(); i < n; i++) {
packColumn(table, i);
}
String savedColumnData = server.getConfig("collect.nodeinfo.table");
if (savedColumnData != null) {
String[] columnList = savedColumnData.split("[ ,]");
for(int i = 1; i < columns.length; i++) {
columns[i].setVisible(false);
}
for(int i = 0; i < columnList.length; i++) {
int c = Integer.parseInt(columnList[i]);
int index = table.convertColumnIndexToView(c);
if (index >= 0) {
table.getColumnModel().moveColumn(index, i);
}
columns[c].setVisible(true);
}
}
JPopupMenu popupMenu = new JPopupMenu();
// The first column (the node name) should always be visible.
for(int i = 1; i < columns.length; i++) {
popupMenu.add(new JCheckBoxMenuItem(columns[i].init(table, i)));
}
table.setComponentPopupMenu(popupMenu);
add(new JScrollPane(table), BorderLayout.CENTER);
}
public void updateConfig(Properties config) {
StringBuilder sb = new StringBuilder();
for(int i = 0, n = table.getColumnCount(); i < n; i++) {
int index = table.convertColumnIndexToModel(i);
if (index >= 0) {
if (sb.length() > 0) {
sb.append(',');
}
sb.append(index);
}
}
config.setProperty("collect.nodeinfo.table", sb.toString());
}
@Override
public Component getPanel() {
return this;
}
@Override
public String getCategory() {
return category;
}
@Override
public String getTitle() {
return "Node Info";
}
@Override
public void nodeAdded(Node node) {
nodeModel.setNodes(server.getNodes());
}
@Override
public void nodeDataReceived(SensorData sensorData) {
nodeModel.updateNode(sensorData.getNode());
}
@Override
public void clearNodeData() {
nodeModel.setNodes(null);
}
@Override
public void nodesSelected(Node[] nodes) {
// Ignore
}
@Override
public void setVisible(boolean visible) {
nodeModel.setNodes(visible ? server.getNodes() : null);
super.setVisible(visible);
}
private String getTimeAsString(long time) {
StringBuilder sb = new StringBuilder();
time /= 1000;
if (time > 24 * 60 * 60) {
long days = time / (24 * 60 * 60);
sb.append(days).append(days > 1 ? " days, " : " day, ");
time -= days * 24 * 60 * 60;
}
if (time > 60 * 60) {
long hours = time / (60 * 60);
sb.append(hours).append(hours > 1 ? " hours, " : " hour, ");
time -= hours * 60 * 60;
}
long sec = time % 60;
sb.append(time / 60).append(" min, ");
if (sec < 10) {
sb.append('0');
}
sb.append(sec).append(" sec");
return sb.toString();
}
private static void packColumn(JTable table, int columnIndex) {
TableColumn tableColumn = table.getColumnModel().getColumn(columnIndex);
Object value = tableColumn.getHeaderValue();
TableCellRenderer columnRenderer = tableColumn.getHeaderRenderer();
if (columnRenderer == null) {
columnRenderer = table.getTableHeader().getDefaultRenderer();
}
Component c = columnRenderer.getTableCellRendererComponent(table, value, false, false, -1, columnIndex);
int width = c.getPreferredSize().width + 6;
int intercellSpacing = table.getIntercellSpacing().width;
for(int i = 0, n = table.getRowCount(); i < n; i++) {
TableCellRenderer cellRenderer = table.getCellRenderer(i, columnIndex);
value = table.getValueAt(i, columnIndex);
c = cellRenderer.getTableCellRendererComponent(table, value, false, false, i, columnIndex);
int w = c.getPreferredSize().width + intercellSpacing + 2;
if (w > width) {
width = w;
}
}
table.getTableHeader().setResizingColumn(tableColumn);
tableColumn.setWidth(width);
tableColumn.setPreferredWidth(width);
}
private static class NodeModel extends AbstractTableModel {
private static final long serialVersionUID = 1692207305977527004L;
private final TableData[] columns;
private Node[] nodes;
public NodeModel(TableData[] columns) {
this.columns = columns;
}
public void recalculateAverage() {
for(TableData td : columns) {
td.clearAverageCache();
}
int row = getRowCount() - 1;
fireTableRowsUpdated(row, row);
}
public Object getValueAt(int row, int col) {
int count = nodes == null ? 0 : nodes.length;
if (row == count) {
return columns[col].getAverageValue(nodes);
}
return columns[col].getValue(nodes[row]);
}
public Class<?> getColumnClass(int col) {
return columns[col].dataClass;
}
public String getColumnName(int col) {
return columns[col].name;
}
public String getColumnToolTip(int col) {
Object v = columns[col].getValue(TableData.SHORT_DESCRIPTION);
return v == null ? null : v.toString();
}
public int getColumnCount() {
return columns.length;
}
public int getRowCount() {
return (nodes == null ? 0 : nodes.length) + 1;
}
public void setNodes(Node[] nodes) {
if (this.nodes != null && this.nodes.length > 0) {
fireTableRowsDeleted(0, this.nodes.length - 1);
}
this.nodes = nodes;
if (this.nodes != null && this.nodes.length > 0) {
fireTableRowsInserted(0, this.nodes.length - 1);
}
recalculateAverage();
}
public void updateNode(Node node) {
if (this.nodes != null) {
for(int row = 0; row < this.nodes.length; row++) {
if (this.nodes[row] == node) {
fireTableRowsUpdated(row, row);
recalculateAverage();
break;
}
}
}
}
}
public static abstract class TableData extends AbstractAction {
private static final long serialVersionUID = -3045755073722516926L;
private final static Node AVERAGE_NODE = new Node("99999999.9", "Avg");
public final String name;
public final Class<?> dataClass;
private JTable table;
private TableColumn tableColumn;
private int modelIndex = -1;
private Object averageCache;
protected TableData(String name, Class<?> dataClass) {
this(name, name, dataClass);
}
protected TableData(String name, String description, Class<?> dataClass) {
super(name);
this.name = name;
this.dataClass = dataClass;
putValue(SHORT_DESCRIPTION, description);
setVisible(true);
}
TableData init(JTable table, int modelIndex) {
this.table = table;
this.modelIndex = modelIndex;
if (!isVisible()) {
// The column should initially be hidden
setColumnVisible(false);
}
return this;
}
public boolean isVisible() {
return Boolean.TRUE.equals(getValue(SELECTED_KEY));
}
public TableData setVisible(boolean isVisible) {
putValue(SELECTED_KEY, isVisible);
return this;
}
public void actionPerformed(ActionEvent event) {
if (modelIndex >= 0) {
setColumnVisible(isVisible());
}
}
private void setColumnVisible(boolean isVisible) {
if (isVisible) {
if (tableColumn != null) {
int count = table.getColumnCount();
table.addColumn(tableColumn);
tableColumn = null;
packColumn(table, count);
int newIndex = 0;
for(int i = 0; i < modelIndex; i++) {
if (table.convertColumnIndexToView(i) >= 0) {
// The new column should be after this visible column
newIndex++;
}
}
if (newIndex < count) {
table.getColumnModel().moveColumn(count, newIndex);
}
}
} else {
int columnIndex = table.convertColumnIndexToView(modelIndex);
if (columnIndex >= 0 ) {
tableColumn = table.getColumnModel().getColumn(columnIndex);
table.removeColumn(tableColumn);
}
}
}
public final Object getAverageValue(Node[] nodes) {
Object tmp = averageCache;
if (tmp != null) {
return tmp;
}
if (dataClass == Long.class || dataClass == Double.class
|| dataClass == Number.class) {
double average = 0.0;
if (nodes != null && nodes.length > 0) {
int count = 0;
for(Node node : nodes) {
if (node.getSensorDataAggregator().getDataCount() > 0) {
average += ((Number) getValue(node)).doubleValue();
count++;
}
}
if (count > 0) {
average = average / count;
}
}
if (dataClass == Long.class) {
tmp = (long) (average + 0.5);
} else {
tmp = average;
}
} else if (dataClass == Node.class) {
tmp = AVERAGE_NODE;
}
averageCache = tmp;
return tmp;
}
public final void clearAverageCache() {
averageCache = null;
}
public abstract Object getValue(Node node);
}
}

View File

@ -1,224 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* SerialConsole
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 4 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect.gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import org.contikios.contiki.collect.CollectServer;
import org.contikios.contiki.collect.Node;
import org.contikios.contiki.collect.SensorData;
import org.contikios.contiki.collect.Visualizer;
/**
*
*/
public class SerialConsole implements Visualizer {
private final CollectServer server;
private final String category;
private JPanel panel;
private JTextArea logArea;
private JTextField commandField;
private String[] history = new String[50];
private int historyPos = 0;
private int historyCount = 0;
public SerialConsole(CollectServer server, String category) {
this.server = server;
this.category = category;
panel = new JPanel(new BorderLayout());
logArea = new JTextArea(4, 30);
logArea.setEditable(false);
panel.add(new JScrollPane(logArea), BorderLayout.CENTER);
JPopupMenu popupMenu = new JPopupMenu();
JMenuItem clearItem = new JMenuItem("Clear");
clearItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
logArea.setText("");
}
});
popupMenu.add(clearItem);
logArea.setComponentPopupMenu(popupMenu);
commandField = new JTextField();
commandField.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String command = trim(commandField.getText());
if (command != null) {
try {
int previous = historyCount - 1;
if (previous < 0) previous += history.length;
if (!command.equals(history[previous])) {
history[historyCount] = command;
historyCount = (historyCount + 1) % history.length;
}
historyPos = historyCount;
if (SerialConsole.this.server.sendToNode(command)) {
commandField.setText("");
} else {
addSerialData("*** failed to send command ***");
}
} catch (Exception ex) {
System.err.println("could not send '" + command + "':");
ex.printStackTrace();
JOptionPane.showMessageDialog(panel,
"could not send '" + command + "':\n"
+ ex, "ERROR",
JOptionPane.ERROR_MESSAGE);
}
} else {
commandField.getToolkit().beep();
}
}
});
commandField.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_UP: {
int nextPos = (historyPos + history.length - 1) % history.length;
if (nextPos == historyCount || history[nextPos] == null) {
commandField.getToolkit().beep();
} else {
String cmd = trim(commandField.getText());
if (cmd != null) {
history[historyPos] = cmd;
}
historyPos = nextPos;
commandField.setText(history[historyPos]);
}
break;
}
case KeyEvent.VK_DOWN: {
int nextPos = (historyPos + 1) % history.length;
if (nextPos == historyCount) {
historyPos = nextPos;
commandField.setText("");
} else if (historyPos == historyCount || history[nextPos] == null) {
commandField.getToolkit().beep();
} else {
String cmd = trim(commandField.getText());
if (cmd != null) {
history[historyPos] = cmd;
}
historyPos = nextPos;
commandField.setText(history[historyPos]);
}
break;
}
}
}
});
panel.add(commandField, BorderLayout.SOUTH);
}
@Override
public Component getPanel() {
return panel;
}
@Override
public String getCategory() {
return category;
}
@Override
public String getTitle() {
return "Serial Console";
}
@Override
public void nodeAdded(Node node) {
// Ignore
}
@Override
public void nodeDataReceived(SensorData sensorData) {
// Ignore
}
@Override
public void clearNodeData() {
// Ignore
}
@Override
public void nodesSelected(Node[] node) {
// Ignore
}
public void addSerialData(final String text) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
String current = logArea.getText();
int len = current.length();
if (len > 4096) {
current = current.substring(len - 4096);
}
current = len > 0 ? (current + '\n' + text) : text;
logArea.setText(current);
logArea.setCaretPosition(current.length());
}
});
}
private String trim(String text) {
return (text != null) && ((text = text.trim()).length() > 0) ? text : null;
}
}

View File

@ -1,328 +0,0 @@
/*
* 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.
*
*
* -----------------------------------------------------------------
*
* TimeChartPanel
*
* Authors : Joakim Eriksson, Niclas Finne
* Created : 3 jul 2008
* Updated : $Date: 2010/11/03 14:53:05 $
* $Revision: 1.1 $
*/
package org.contikios.contiki.collect.gui;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.util.Date;
import javax.swing.JPanel;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Second;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.contikios.contiki.collect.CollectServer;
import org.contikios.contiki.collect.Node;
import org.contikios.contiki.collect.SensorData;
import org.contikios.contiki.collect.Visualizer;
/**
*
*/
public abstract class TimeChartPanel extends JPanel implements Visualizer {
private static final long serialVersionUID = -607864439709540641L;
protected final CollectServer server;
protected final String category;
protected final String title;
protected final TimeSeriesCollection timeSeries;
protected final JFreeChart chart;
protected final ChartPanel chartPanel;
private Node[] selectedNodes;
private double minValue;
private double maxValue;
private int rangeTick = 0;
private boolean hasGlobalRange;
private int maxItemCount;
public TimeChartPanel(CollectServer server, String category, String title,
String chartTitle, String timeAxisLabel, String valueAxisLabel) {
super(new BorderLayout());
this.server = server;
this.category = category;
this.title = title;
this.timeSeries = new TimeSeriesCollection();
this.chart = ChartFactory.createTimeSeriesChart(
chartTitle, timeAxisLabel, valueAxisLabel, timeSeries,
true, true, false
);
this.chartPanel = new ChartPanel(chart);
this.chartPanel.setPreferredSize(new Dimension(500, 270));
setBaseShapeVisible(true);
setMaxItemCount(server.getDefaultMaxItemCount());
add(chartPanel, BorderLayout.CENTER);
}
@Override
public String getCategory() {
return category;
}
@Override
public String getTitle() {
return title;
}
@Override
public Component getPanel() {
return this;
}
@Override
public void nodeAdded(Node node) {
// Ignore
}
@Override
public void nodesSelected(Node[] nodes) {
if (this.selectedNodes != nodes) {
this.selectedNodes = nodes;
if (isVisible()) {
updateCharts();
}
}
}
@Override
public void nodeDataReceived(SensorData data) {
if (hasGlobalRange) {
boolean update = false;
if (minValue > maxValue) {
update = true;
} else {
double value = getSensorDataValue(data);
if (value < minValue) {
minValue = value;
update = true;
}
if (value > maxValue) {
maxValue = value;
update = true;
}
}
if (update && isVisible()) {
updateGlobalRange();
}
}
if (isVisible() && selectedNodes != null && selectedNodes.length == timeSeries.getSeriesCount()) {
Node node = data.getNode();
for (int i = 0, n = selectedNodes.length; i < n; i++) {
if (node == selectedNodes[i]) {
TimeSeries series = timeSeries.getSeries(i);
int groupSize = getGroupSize(node);
if (groupSize > 1) {
series.clear();
updateSeries(series, node, groupSize);
} else {
series.addOrUpdate(new Second(new Date(data.getNodeTime())), getSensorDataValue(data));
}
chartPanel.repaint();
break;
}
}
}
}
@Override
public void clearNodeData() {
if (isVisible()) {
updateCharts();
}
}
private void updateCharts() {
timeSeries.removeAllSeries();
if (this.selectedNodes != null) {
for(Node node: this.selectedNodes) {
TimeSeries series = new TimeSeries(node.getName(), Second.class);
// Reduce the number of items by grouping them and use the average for each group
int groupSize = getGroupSize(node);
if (groupSize > 1) {
updateSeries(series, node, groupSize);
} else {
for (int i = 0, n = node.getSensorDataCount(); i < n; i++) {
SensorData data = node.getSensorData(i);
series.addOrUpdate(new Second(new Date(data.getNodeTime())), getSensorDataValue(data));
}
}
timeSeries.addSeries(series);
}
}
}
protected int getGroupSize(Node node) {
if (maxItemCount > 0) {
int sensorDataCount = node.getSensorDataCount();
if (sensorDataCount > maxItemCount) {
int groupSize = sensorDataCount / maxItemCount;
if (sensorDataCount / groupSize >= maxItemCount) {
groupSize++;
}
return groupSize;
}
}
return 1;
}
protected void updateSeries(TimeSeries series, Node node, int groupSize) {
for (int i = 0, n = node.getSensorDataCount(); i < n; i += groupSize) {
double value = 0.0;
long time = 0L;
for (int j = 0; j < groupSize; j++) {
SensorData data = node.getSensorData(i);
value += getSensorDataValue(data);
time += data.getNodeTime() / 1000L;
}
series.addOrUpdate(new Second(new Date((time / groupSize) * 1000L)), value / groupSize);
}
}
public boolean getBaseShapeVisible() {
return ((XYLineAndShapeRenderer)this.chart.getXYPlot().getRenderer()).getBaseShapesVisible();
}
public void setBaseShapeVisible(boolean visible) {
((XYLineAndShapeRenderer)this.chart.getXYPlot().getRenderer()).setBaseShapesVisible(visible);
}
public int getRangeTick() {
return rangeTick;
}
public void setRangeTick(int rangeTick) {
this.rangeTick = rangeTick;
}
public double getRangeMinimumSize() {
return chart.getXYPlot().getRangeAxis().getAutoRangeMinimumSize();
}
public void setRangeMinimumSize(double size) {
chart.getXYPlot().getRangeAxis().setAutoRangeMinimumSize(size);
}
public boolean hasGlobalRange() {
return hasGlobalRange;
}
public void setGlobalRange(boolean hasGlobalRange) {
if (this.hasGlobalRange != hasGlobalRange) {
this.hasGlobalRange = hasGlobalRange;
if (hasGlobalRange) {
minValue = Double.MAX_VALUE;
maxValue = Double.MIN_NORMAL;
if (isVisible()) {
updateGlobalRange();
}
} else {
chart.getXYPlot().getRangeAxis().setAutoRange(true);
}
}
}
private void updateGlobalRange() {
if (hasGlobalRange) {
if (minValue > maxValue) {
for (int i = 0, n = server.getSensorDataCount(); i < n; i++) {
double value = getSensorDataValue(server.getSensorData(i));
if (value < minValue) minValue = value;
if (value > maxValue) maxValue = value;
}
}
if (minValue < maxValue) {
double minSize = getRangeMinimumSize();
double min = minValue;
double max = maxValue;
if (max - min < minSize) {
double d = (minSize - (max - min)) / 2;
min -= d;
max += d;
}
if (rangeTick > 0) {
min = ((int) (min - rangeTick / 2) / rangeTick) * rangeTick;
// max = ((int) (max + rangeTick / 2) / rangeTick) * rangeTick;
}
chart.getXYPlot().getRangeAxis().setRange(min, max);
}
}
}
/**
* Returns the maximal number of chart items to display for each node.
*
* @return the maximal number of chart items to display for each node or <code>0</code>
* for unlimited number of chart items.
*/
public int getMaxItemCount() {
return maxItemCount;
}
/**
* Sets the maximal number of chart items to display for each node. Items will be
* grouped and replaced by the average value when needed.
*
* @param maxItemCount - the maximal number of chart items to display for each node or
* <code>0</code> for unlimited number (default)
*/
public void setMaxItemCount(int maxItemCount) {
this.maxItemCount = maxItemCount;
if (isVisible()) {
updateCharts();
}
}
public void setVisible(boolean visible) {
if (visible) {
updateGlobalRange();
updateCharts();
} else {
timeSeries.removeAllSeries();
}
super.setVisible(visible);
}
protected abstract double getSensorDataValue(SensorData data);
}