From 37ebe133e9b7c50c3e28bc50d582c985fdd0bc49 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:25:03 +0200 Subject: [PATCH 01/26] increased maximum buffer size --- tools/cooja/java/se/sics/cooja/plugins/BufferListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java b/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java index 6508da8ba..66e4731bd 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java +++ b/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java @@ -130,7 +130,7 @@ public class BufferListener extends VisPlugin { private static final long TIME_MINUTE = 60*TIME_SECOND; private static final long TIME_HOUR = 60*TIME_MINUTE; - final static int MAX_BUFFER_SIZE = 128; + final static int MAX_BUFFER_SIZE = 2048; private static ArrayList> bufferParsers = new ArrayList>(); From bda04947e72f92672d63771141e9fca4ab4c8917 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:28:18 +0200 Subject: [PATCH 02/26] minor changes: methods that allow other plugins, e.g. the timeline, to learn about the currently used mote output filter, make mote-specific coloring on by default --- .../se/sics/cooja/plugins/LogListener.java | 118 ++++++++++++------ 1 file changed, 80 insertions(+), 38 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/LogListener.java b/tools/cooja/java/se/sics/cooja/plugins/LogListener.java index 5dd5660e6..0476699bd 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/LogListener.java +++ b/tools/cooja/java/se/sics/cooja/plugins/LogListener.java @@ -108,6 +108,19 @@ public class LogListener extends VisPlugin implements HasQuickHelp { private static final long serialVersionUID = 3294595371354857261L; private static Logger logger = Logger.getLogger(LogListener.class); + private final Color[] BG_COLORS = new Color[] { + new Color(200, 200, 200), + new Color(200, 200, 255), + new Color(200, 255, 200), + new Color(200, 255, 255), + new Color(255, 200, 200), + new Color(255, 255, 200), + new Color(255, 255, 255), + new Color(255, 220, 200), + new Color(220, 255, 220), + new Color(255, 200, 255), + }; + private final static int COLUMN_TIME = 0; private final static int COLUMN_FROM = 1; private final static int COLUMN_DATA = 2; @@ -119,11 +132,11 @@ public class LogListener extends VisPlugin implements HasQuickHelp { "#" }; - private static final long TIME_SECOND = 1000*Simulation.MILLISECOND; - private static final long TIME_MINUTE = 60*TIME_SECOND; - private static final long TIME_HOUR = 60*TIME_MINUTE; + public static final long TIME_SECOND = 1000*Simulation.MILLISECOND; + public static final long TIME_MINUTE = 60*TIME_SECOND; + public static final long TIME_HOUR = 60*TIME_MINUTE; - private boolean formatTimeString = false; + private boolean formatTimeString = true; private boolean hasHours = false; private final JTable logTable; @@ -140,7 +153,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp { private LogOutputListener logOutputListener; - private boolean backgroundColors = false; + private boolean backgroundColors = true; private JCheckBoxMenuItem colorCheckbox; private boolean inverseFilter = false; @@ -219,7 +232,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp { appendCheckBox = new JCheckBoxMenuItem(appendAction); fileMenu.add(appendCheckBox); - colorCheckbox = new JCheckBoxMenuItem("Mote-specific coloring"); + colorCheckbox = new JCheckBoxMenuItem("Mote-specific coloring", backgroundColors); showMenu.add(colorCheckbox); colorCheckbox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -309,18 +322,6 @@ public class LogListener extends VisPlugin implements HasQuickHelp { }; DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer() { private static final long serialVersionUID = -340743275865216182L; - private final Color[] BG_COLORS = new Color[] { - new Color(200, 200, 200), - new Color(200, 200, 255), - new Color(200, 255, 200), - new Color(200, 255, 255), - new Color(255, 200, 200), - new Color(255, 255, 200), - new Color(255, 255, 255), - new Color(255, 220, 200), - new Color(220, 255, 220), - new Color(255, 200, 255), - }; public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { @@ -331,12 +332,8 @@ public class LogListener extends VisPlugin implements HasQuickHelp { if (backgroundColors) { LogData d = logs.get(logTable.getRowSorter().convertRowIndexToModel(row)); - char last = d.getID().charAt(d.getID().length()-1); - if (last >= '0' && last <= '9') { - setBackground(BG_COLORS[last - '0']); - } else { - setBackground(null); - } + int color = (10+d.ev.getMote().getID())%10; + setBackground(BG_COLORS[color]); } else { setBackground(null); } @@ -674,7 +671,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp { } RowFilter wrapped = new RowFilter() { public boolean include(RowFilter.Entry entry) { - if (regexp != null) { + if (regexp != null) { boolean pass = regexp.include(entry); if (inverseFilter && pass) { return false; @@ -698,6 +695,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp { filterTextField.setBackground(Color.red); filterTextField.setToolTipText("Syntax error in regular expression: " + e.getMessage()); } + simulation.getGUI().getDesktopPane().repaint(); } public void trySelectTime(final long time) { @@ -732,19 +730,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp { public String getTime() { if (formatTimeString) { - long t = ev.getTime(); - long h = (t / TIME_HOUR); - t -= (t / TIME_HOUR)*TIME_HOUR; - long m = (t / TIME_MINUTE); - t -= (t / TIME_MINUTE)*TIME_MINUTE; - long s = (t / TIME_SECOND); - t -= (t / TIME_SECOND)*TIME_SECOND; - long ms = t / Simulation.MILLISECOND; - if (hasHours) { - return String.format("%d:%02d:%02d.%03d", h,m,s,ms); - } else { - return String.format("%02d:%02d.%03d", m,s,ms); - } + return getFormattedTime(ev.getTime()); } else { return "" + ev.getTime() / Simulation.MILLISECOND; } @@ -1031,4 +1017,60 @@ public class LogListener extends VisPlugin implements HasQuickHelp { "

^ID:[2-5] Contiki
logs from motes 2 to 5 starting with 'Contiki'"; } + /* Experimental feature: let other plugins learn if a log output would be filtered or not */ + public boolean filterWouldAccept(LogOutputEvent ev) { + RowFilter rowFilter = logFilter.getRowFilter(); + if (rowFilter == null) { + /* No filter */ + return true; + } + + final LogData ld = new LogData(ev); + RowFilter.Entry entry = new RowFilter.Entry() { + public TableModel getModel() { + return model; + } + public int getValueCount() { + return model.getColumnCount(); + } + public Object getValue(int index) { + if (index == COLUMN_TIME) { + return ld.getTime(); + } else if (index == COLUMN_FROM) { + return ld.getID(); + } else if (index == COLUMN_DATA) { + return ld.ev.getMessage(); + } else if (index == COLUMN_CONCAT) { + return ld.getID() + ' ' + ld.ev.getMessage(); + } + return null; + } + public Integer getIdentifier() { + return null; + } + }; + boolean show; + show = rowFilter.include(entry); + return show; + } + public Color getColorOfEntry(LogOutputEvent logEvent) { + int color = (10+logEvent.getMote().getID())%10; + return BG_COLORS[color]; + } + + public static String getFormattedTime(long t) { + long h = (t / LogListener.TIME_HOUR); + t -= (t / TIME_HOUR)*TIME_HOUR; + long m = (t / TIME_MINUTE); + t -= (t / TIME_MINUTE)*TIME_MINUTE; + long s = (t / TIME_SECOND); + t -= (t / TIME_SECOND)*TIME_SECOND; + long ms = t / Simulation.MILLISECOND; + if (h > 0) { + return String.format("%d:%02d:%02d.%03d", h,m,s,ms); + } else { + return String.format("%02d:%02d.%03d", m,s,ms); + } + } + } From 492cd5f721c30b689e6df136e51a3393414dae4a Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:32:23 +0200 Subject: [PATCH 03/26] added new optional features: time formatting, hide-duplicate-packets, hide-airshot-packets --- .../se/sics/cooja/plugins/RadioLogger.java | 261 ++++++++++++++---- 1 file changed, 213 insertions(+), 48 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/RadioLogger.java b/tools/cooja/java/se/sics/cooja/plugins/RadioLogger.java index a988b7d4b..f9614317a 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/RadioLogger.java +++ b/tools/cooja/java/se/sics/cooja/plugins/RadioLogger.java @@ -40,20 +40,24 @@ import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Observable; import java.util.Observer; import java.util.Properties; +import java.util.regex.PatternSyntaxException; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.ButtonGroup; +import javax.swing.JCheckBoxMenuItem; import javax.swing.JFileChooser; import javax.swing.JMenu; import javax.swing.JMenuBar; @@ -68,9 +72,12 @@ import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.KeyStroke; +import javax.swing.RowFilter; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; import org.apache.log4j.Logger; import org.jdom.Element; @@ -116,9 +123,11 @@ public class RadioLogger extends VisPlugin { private JSplitPane splitPane; private JTextPane verboseBox = null; + private boolean formatTimeString = true; + private final static String[] COLUMN_NAMES = { - "No.", - "Time", + "No. ", + "Time ms", "From", "To", "Data" @@ -126,6 +135,7 @@ public class RadioLogger extends VisPlugin { private final Simulation simulation; private final JTable dataTable; + private TableRowSorter logFilter; private ArrayList connections = new ArrayList(); private RadioMedium radioMedium; private Observer radioMediumObserver; @@ -149,7 +159,7 @@ public class RadioLogger extends VisPlugin { JMenu fileMenu = new JMenu("File"); JMenu editMenu = new JMenu("Edit"); JMenu analyzerMenu = new JMenu("Analyzer"); - JMenu payloadMenu = new JMenu("Payload"); + JMenu payloadMenu = new JMenu("View"); menuBar.add(fileMenu); menuBar.add(editMenu); @@ -169,11 +179,15 @@ public class RadioLogger extends VisPlugin { lowpanAnalyzersPcap.add(new IPHCPacketAnalyzer()); lowpanAnalyzersPcap.add(new IPv6PacketAnalyzer()); lowpanAnalyzersPcap.add(new ICMPv6Analyzer()); + model = new AbstractTableModel() { private static final long serialVersionUID = 1692207305977527004L; public String getColumnName(int col) { + if (col == COLUMN_TIME && formatTimeString) { + return "Time"; + } return COLUMN_NAMES[col]; } @@ -186,10 +200,19 @@ public class RadioLogger extends VisPlugin { } public Object getValueAt(int row, int col) { + if (row < 0 || row >= connections.size()) { + return ""; + } RadioConnectionLog conn = connections.get(row); if (col == COLUMN_NO) { - return Long.toString(row + 1); + if (!showDuplicates && conn.hides > 0) { + return (String) "" + (row + 1) + "+" + conn.hides; + } + return (String) "" + (row + 1); } else if (col == COLUMN_TIME) { + if (formatTimeString) { + return LogListener.getFormattedTime(conn.startTime); + } return Long.toString(conn.startTime / Simulation.MILLISECOND); } else if (col == COLUMN_FROM) { return "" + conn.connection.getSource().getMote().getID(); @@ -251,14 +274,19 @@ public class RadioLogger extends VisPlugin { public String getToolTipText(MouseEvent e) { java.awt.Point p = e.getPoint(); int rowIndex = rowAtPoint(p); + if (rowIndex < 0) { + return super.getToolTipText(e); + } + int modelRowIndex = convertRowIndexToModel(rowIndex); int colIndex = columnAtPoint(p); - int realColumnIndex = convertColumnIndexToModel(colIndex); - if (rowIndex < 0 || realColumnIndex < 0) { + int modelColumnIndex = convertColumnIndexToModel(colIndex); + if (modelRowIndex < 0 || modelColumnIndex < 0) { return super.getToolTipText(e); } - RadioConnectionLog conn = connections.get(rowIndex); - if (realColumnIndex == COLUMN_TIME) { + /* TODO This entry may represent several hidden connections */ + RadioConnectionLog conn = connections.get(modelRowIndex); + if (modelColumnIndex == COLUMN_TIME) { return "" + "Start time (us): " + conn.startTime + @@ -267,9 +295,9 @@ public class RadioLogger extends VisPlugin { "

" + "Duration (us): " + (conn.endTime - conn.startTime) + ""; - } else if (realColumnIndex == COLUMN_FROM) { + } else if (modelColumnIndex == COLUMN_FROM) { return conn.connection.getSource().getMote().toString(); - } else if (realColumnIndex == COLUMN_TO) { + } else if (modelColumnIndex == COLUMN_TO) { Radio[] dests = conn.connection.getDestinations(); if (dests.length == 0) { return "No destinations"; @@ -286,7 +314,7 @@ public class RadioLogger extends VisPlugin { } tip.append(""); return tip.toString(); - } else if (realColumnIndex == COLUMN_DATA) { + } else if (modelColumnIndex == COLUMN_DATA) { if (conn.tooltip == null) { prepareTooltipString(conn); } @@ -296,6 +324,21 @@ public class RadioLogger extends VisPlugin { } }; + /* Toggle time format */ + dataTable.getTableHeader().addMouseListener(new MouseAdapter() { + public void mouseClicked(MouseEvent e) { + int colIndex = dataTable.columnAtPoint(e.getPoint()); + int columnIndex = dataTable.convertColumnIndexToModel(colIndex); + if (columnIndex != COLUMN_TIME) { + return; + } + formatTimeString = !formatTimeString; + dataTable.getColumnModel().getColumn(COLUMN_TIME).setHeaderValue( + dataTable.getModel().getColumnName(COLUMN_TIME)); + repaint(); + } + }); + dataTable.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE) { @@ -314,11 +357,21 @@ public class RadioLogger extends VisPlugin { } }); + logFilter = new TableRowSorter(model); + for (int i = 0, n = model.getColumnCount(); i < n; i++) { + logFilter.setSortable(i, false); + } + dataTable.setRowSorter(logFilter); + dataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { int row = dataTable.getSelectedRow(); - if (row >= 0) { - RadioConnectionLog conn = connections.get(row); + if (row < 0) { + return; + } + int modelRowIndex = dataTable.convertRowIndexToModel(row); + if (modelRowIndex >= 0) { + RadioConnectionLog conn = connections.get(modelRowIndex); if (conn.tooltip == null) { prepareTooltipString(conn); } @@ -338,6 +391,16 @@ public class RadioLogger extends VisPlugin { editMenu.add(new JMenuItem(clearAction)); payloadMenu.add(new JMenuItem(aliasAction)); + payloadMenu.add(new JCheckBoxMenuItem(showDuplicatesAction) { + public boolean isSelected() { + return showDuplicates; + } + }); + payloadMenu.add(new JCheckBoxMenuItem(hideNoDestinationAction) { + public boolean isSelected() { + return hideNoDestinationPackets; + } + }); fileMenu.add(new JMenuItem(saveAction)); @@ -369,12 +432,14 @@ public class RadioLogger extends VisPlugin { group.add(rbMenuItem); analyzerMenu.add(rbMenuItem); - /* Load additional analyzers specified by projects (cooja.config) */ String[] projectAnalyzerSuites = gui.getProjectConfig().getStringArrayValue(RadioLogger.class, "ANALYZERS"); if (projectAnalyzerSuites != null) { for (String suiteName: projectAnalyzerSuites) { + if (suiteName == null || suiteName.trim().isEmpty()) { + continue; + } Class suiteClass = gui.tryLoadClass(RadioLogger.this, RadioLoggerAnalyzerSuite.class, suiteName); try { @@ -383,7 +448,7 @@ public class RadioLogger extends VisPlugin { rbMenuItem = new JRadioButtonMenuItem(createAnalyzerAction( suite.getDescription(), suiteName, suiteAnalyzers, false)); group.add(rbMenuItem); - popupMenu.add(rbMenuItem); + analyzerMenu.add(rbMenuItem); logger.debug("Loaded radio logger analyzers: " + suite.getDescription()); } catch (InstantiationException e1) { logger.warn("Failed to load analyzer suite '" + suiteName + "': " + e1.getMessage()); @@ -457,7 +522,7 @@ public class RadioLogger extends VisPlugin { if (isVisible) { dataTable.scrollRectToVisible(dataTable.getCellRect(dataTable.getRowCount() - 1, 0, true)); } - setTitle("Radio messages: " + dataTable.getRowCount() + " messages seen"); + setTitle("Radio messages: showing " + dataTable.getRowCount() + "/" + connections.size() + " packets"); } }); } @@ -471,6 +536,11 @@ public class RadioLogger extends VisPlugin { } } + public void startPlugin() { + super.startPlugin(); + rebuildAllEntries(); + } + private void searchSelectNext(String text, boolean reverse) { if (text.isEmpty()) { return; @@ -514,18 +584,75 @@ public class RadioLogger extends VisPlugin { public void trySelectTime(final long time) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { - for (int i=0; i < connections.size(); i++) { - if (connections.get(i).endTime < time) { - continue; - } - dataTable.scrollRectToVisible(dataTable.getCellRect(i, 0, true)); - dataTable.setRowSelectionInterval(i, i); + if (dataTable.getRowCount() == 0) { return; } + for (int ai=0; ai < model.getRowCount(); ai++) { + int index = dataTable.convertRowIndexToModel(ai); + if (connections.get(index).endTime < time) { + continue; + } + + dataTable.scrollRectToVisible(dataTable.getCellRect(ai, 0, true)); + dataTable.setRowSelectionInterval(ai, ai); + return; + } + dataTable.scrollRectToVisible(dataTable.getCellRect(dataTable.getRowCount()-1, 0, true)); + dataTable.setRowSelectionInterval(dataTable.getRowCount()-1, dataTable.getRowCount()-1); } }); } + private void applyFilter() { + for(RadioConnectionLog conn: connections) { + conn.data = null; + conn.tooltip = null; + conn.hides = 0; + conn.hiddenBy = null; + } + + try { + logFilter.setRowFilter(null); + RowFilter filter = new RowFilter() { + public boolean include(RowFilter.Entry entry) { + int row = (Integer) entry.getIdentifier(); + RadioConnectionLog current = connections.get(row); + byte[] currentData = current.packet.getPacketData(); + + if (!showDuplicates && row > 0) { + RadioConnectionLog previous = connections.get(row-1); + byte[] previousData = previous.packet.getPacketData(); + if (!showDuplicates && + Arrays.equals(previousData, currentData) && + previous.connection.getSource() == current.connection.getSource() && + Arrays.equals(previous.connection.getAllDestinations(), current.connection.getAllDestinations())) { + if (connections.get(row-1).hiddenBy == null) { + connections.get(row-1).hides++; + connections.get(row).hiddenBy = connections.get(row-1); + } else { + connections.get(row-1).hiddenBy.hides++; + connections.get(row).hiddenBy = connections.get(row-1).hiddenBy; + } + return false; + } + } + + if (hideNoDestinationPackets) { + if (current.connection.getDestinations().length == 0) { + return false; + } + } + + return true; + } + }; + logFilter.setRowFilter(filter); + } catch (PatternSyntaxException e) { + logFilter.setRowFilter(null); + logger.warn("Error when setting table filter: " + e.getMessage()); + } + } + private void prepareDataString(RadioConnectionLog conn) { byte[] data; if (conn.packet == null) { @@ -646,6 +773,19 @@ public class RadioLogger extends VisPlugin { element.addContent(Integer.toString(splitPane.getDividerLocation())); config.add(element); + if (formatTimeString) { + element = new Element("formatted_time"); + config.add(element); + } + + element = new Element("showdups"); + element.addContent(Boolean.toString(showDuplicates)); + config.add(element); + + element = new Element("hidenodests"); + element.addContent(Boolean.toString(hideNoDestinationPackets)); + config.add(element); + if (analyzerName != null && analyzers != null) { element = new Element("analyzers"); element.setAttribute("name", analyzerName); @@ -676,6 +816,12 @@ public class RadioLogger extends VisPlugin { aliases.put(payload, alias); } else if ("split".equals(name)) { splitPane.setDividerLocation(Integer.parseInt(element.getText())); + } else if ("formatted_time".equals(name)) { + formatTimeString = true; + } else if ("showdups".equals(name)) { + showDuplicates = Boolean.parseBoolean(element.getText()); + } else if ("hidenodests".equals(name)) { + hideNoDestinationPackets = Boolean.parseBoolean(element.getText()); } else if ("analyzers".equals(name)) { String analyzerName = element.getAttributeValue("name"); final Action action; @@ -697,6 +843,9 @@ public class RadioLogger extends VisPlugin { long endTime; RadioConnection connection; RadioPacket packet; + + RadioConnectionLog hiddenBy = null; + int hides = 0; String data = null; String tooltip = null; @@ -729,6 +878,18 @@ public class RadioLogger extends VisPlugin { return sb.toString(); } + private void rebuildAllEntries() { + applyFilter(); + + if (connections.size() > 0) { + model.fireTableRowsUpdated(0, connections.size() - 1); + } + verboseBox.setText(""); + + setTitle("Radio messages: showing " + dataTable.getRowCount() + "/" + connections.size() + " packets"); + simulation.getGUI().getDesktopPane().repaint(); + } + private Action createAnalyzerAction(String name, final String actionName, final ArrayList analyzerList, boolean selected) { Action action = new AbstractAction(name) { @@ -738,16 +899,7 @@ public class RadioLogger extends VisPlugin { if (analyzers != analyzerList) { analyzers = analyzerList; analyzerName = actionName; - if (connections.size() > 0) { - // Remove the cached values - for(int i = 0; i < connections.size(); i++) { - RadioConnectionLog conn = connections.get(i); - conn.data = null; - conn.tooltip = null; - } - model.fireTableRowsUpdated(0, connections.size() - 1); - } - verboseBox.setText(""); + rebuildAllEntries(); } } }; @@ -764,7 +916,7 @@ public class RadioLogger extends VisPlugin { if (size > 0) { connections.clear(); model.fireTableRowsDeleted(0, size - 1); - setTitle("Radio Logger: " + dataTable.getRowCount() + " packets"); + setTitle("Radio messages: showing " + dataTable.getRowCount() + "/" + connections.size() + " packets"); } } }; @@ -779,11 +931,8 @@ public class RadioLogger extends VisPlugin { StringBuilder sb = new StringBuilder(); for (int i: selectedRows) { - sb.append(i + 1).append('\t'); - sb.append(dataTable.getValueAt(i, COLUMN_TIME)).append('\t'); - sb.append(dataTable.getValueAt(i, COLUMN_FROM)).append('\t'); - sb.append(getDestString(connections.get(i))).append('\t'); - sb.append(dataTable.getValueAt(i, COLUMN_DATA)).append('\n'); + int iModel = dataTable.convertRowIndexToModel(i); + sb.append(connections.get(iModel).toString() + "\n"); } StringSelection stringSelection = new StringSelection(sb.toString()); @@ -799,11 +948,7 @@ public class RadioLogger extends VisPlugin { StringBuilder sb = new StringBuilder(); for(int i=0; i < connections.size(); i++) { - sb.append("" + (i + 1) + '\t'); - sb.append("" + dataTable.getValueAt(i, COLUMN_TIME) + '\t'); - sb.append("" + dataTable.getValueAt(i, COLUMN_FROM) + '\t'); - sb.append("" + getDestString(connections.get(i)) + '\t'); - sb.append("" + dataTable.getValueAt(i, COLUMN_DATA) + '\n'); + sb.append(connections.get(i).toString() + "\n"); } StringSelection stringSelection = new StringSelection(sb.toString()); @@ -844,11 +989,7 @@ public class RadioLogger extends VisPlugin { try { PrintWriter outStream = new PrintWriter(new FileWriter(saveFile)); for(int i=0; i < connections.size(); i++) { - outStream.print("" + (i + 1) + '\t'); - outStream.print("" + dataTable.getValueAt(i, COLUMN_TIME) + '\t'); - outStream.print("" + dataTable.getValueAt(i, COLUMN_FROM) + '\t'); - outStream.print("" + getDestString(connections.get(i)) + '\t'); - outStream.print("" + dataTable.getValueAt(i, COLUMN_DATA) + '\n'); + outStream.print(connections.get(i).toString() + "\n"); } outStream.close(); } catch (Exception ex) { @@ -864,6 +1005,9 @@ public class RadioLogger extends VisPlugin { public void actionPerformed(ActionEvent e) { int selectedRow = dataTable.getSelectedRow(); if (selectedRow < 0) return; + selectedRow = dataTable.convertRowIndexToModel(selectedRow); + if (selectedRow < 0) return; + long time = connections.get(selectedRow).startTime; Plugin[] plugins = simulation.getGUI().getStartedPlugins(); @@ -884,6 +1028,9 @@ public class RadioLogger extends VisPlugin { public void actionPerformed(ActionEvent e) { int selectedRow = dataTable.getSelectedRow(); if (selectedRow < 0) return; + selectedRow = dataTable.convertRowIndexToModel(selectedRow); + if (selectedRow < 0) return; + long time = connections.get(selectedRow).startTime; Plugin[] plugins = simulation.getGUI().getStartedPlugins(); @@ -917,6 +1064,8 @@ public class RadioLogger extends VisPlugin { public void actionPerformed(ActionEvent e) { int selectedRow = dataTable.getSelectedRow(); if (selectedRow < 0) return; + selectedRow = dataTable.convertRowIndexToModel(selectedRow); + if (selectedRow < 0) return; String current = ""; if (aliases != null && aliases.get(connections.get(selectedRow).data) != null) { @@ -961,6 +1110,22 @@ public class RadioLogger extends VisPlugin { } }; + private boolean showDuplicates = false; + private AbstractAction showDuplicatesAction = new AbstractAction("Show duplicates") { + public void actionPerformed(ActionEvent e) { + showDuplicates = !showDuplicates; + rebuildAllEntries(); + } + }; + + private boolean hideNoDestinationPackets = false; + private AbstractAction hideNoDestinationAction = new AbstractAction("Hide airshots") { + public void actionPerformed(ActionEvent e) { + hideNoDestinationPackets = !hideNoDestinationPackets; + rebuildAllEntries(); + } + }; + public String getConnectionsString() { StringBuilder sb = new StringBuilder(); RadioConnectionLog[] cs = connections.toArray(new RadioConnectionLog[0]); From 1b556148d8881bef74975a2d223c1dfb54ec843b Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:33:44 +0200 Subject: [PATCH 04/26] added 200% simulation speed alternative --- .../java/se/sics/cooja/plugins/SimControl.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/SimControl.java b/tools/cooja/java/se/sics/cooja/plugins/SimControl.java index 309bda1b4..3a617db60 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/SimControl.java +++ b/tools/cooja/java/se/sics/cooja/plugins/SimControl.java @@ -120,9 +120,13 @@ public class SimControl extends VisPlugin implements HasQuickHelp { speedlimitButtonGroup.add(limitMenuItem2); speedMenu.add(limitMenuItem2); JRadioButtonMenuItem limitMenuItem3 = new JRadioButtonMenuItem( - new ChangeMaxSpeedLimitAction("100%", 1.0)); - speedlimitButtonGroup.add(limitMenuItem3); - speedMenu.add(limitMenuItem3); + new ChangeMaxSpeedLimitAction("100%", 1.0)); + speedlimitButtonGroup.add(limitMenuItem3); + speedMenu.add(limitMenuItem3); + JRadioButtonMenuItem limitMenuItem200 = new JRadioButtonMenuItem( + new ChangeMaxSpeedLimitAction("200%", 2.0)); + speedlimitButtonGroup.add(limitMenuItem200); + speedMenu.add(limitMenuItem200); JRadioButtonMenuItem limitMenuItem4 = new JRadioButtonMenuItem( new ChangeMaxSpeedLimitAction("1000%", 10.0)); speedlimitButtonGroup.add(limitMenuItem4); @@ -135,7 +139,9 @@ public class SimControl extends VisPlugin implements HasQuickHelp { } else if (simulation.getSpeedLimit().doubleValue() == 0.10) { limitMenuItem2.setSelected(true); } else if (simulation.getSpeedLimit().doubleValue() == 1.0) { - limitMenuItem3.setSelected(true); + limitMenuItem3.setSelected(true); + } else if (simulation.getSpeedLimit().doubleValue() == 2.0) { + limitMenuItem200.setSelected(true); } else if (simulation.getSpeedLimit().doubleValue() == 10) { limitMenuItem4.setSelected(true); } From 1917ea574ff2c3841aa0ae7ba0e44995ae7e7712 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:34:52 +0200 Subject: [PATCH 05/26] added methods to more easily extract runtime statistics from simulation scripts --- .../apps/powertracker/java/PowerTracker.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tools/cooja/apps/powertracker/java/PowerTracker.java b/tools/cooja/apps/powertracker/java/PowerTracker.java index f67df3baa..35a6b8c2d 100644 --- a/tools/cooja/apps/powertracker/java/PowerTracker.java +++ b/tools/cooja/apps/powertracker/java/PowerTracker.java @@ -222,6 +222,15 @@ public class PowerTracker extends VisPlugin { repaintTimer.start(); } + public MoteTracker getMoteTrackerOf(Mote mote) { + for (MoteTracker mt : moteTrackers) { + if (mt.mote == mote) { + return mt; + } + } + return null; + } + private Action resetAction = new AbstractAction("Reset") { public void actionPerformed(ActionEvent e) { Runnable r = new Runnable() { @@ -288,7 +297,7 @@ public class PowerTracker extends VisPlugin { return sb.toString(); } - private static class MoteTracker implements Observer { + public static class MoteTracker implements Observer { /* last radio state */ private boolean radioWasOn; private RadioState lastRadioState; @@ -379,19 +388,19 @@ public class PowerTracker extends VisPlugin { radioInterfered += t; } - protected double getRadioOnRatio() { + public double getRadioOnRatio() { return 1.0*radioOn/duration; } - protected double getRadioTxRatio() { + public double getRadioTxRatio() { return 1.0*radioTx/duration; } - protected double getRadioInterferedRatio() { + public double getRadioInterferedRatio() { return 1.0*radioInterfered/duration; } - protected double getRadioRxRatio() { + public double getRadioRxRatio() { return 1.0*radioRx/duration; } From 4811d7f378a35d7e9ad1d9e2d68ad3af6bc1513a Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:36:14 +0200 Subject: [PATCH 06/26] made ip-address-to-string method public --- .../se/sics/cooja/interfaces/IPAddress.java | 107 ++++++++++-------- 1 file changed, 59 insertions(+), 48 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/interfaces/IPAddress.java b/tools/cooja/java/se/sics/cooja/interfaces/IPAddress.java index c8a887c99..e278efa17 100644 --- a/tools/cooja/java/se/sics/cooja/interfaces/IPAddress.java +++ b/tools/cooja/java/se/sics/cooja/interfaces/IPAddress.java @@ -122,55 +122,66 @@ public class IPAddress extends MoteInterface { return ipString; } + public byte[] getIPv6Address() { + byte[] ip = null; + + /* IpV6: Struct sizes and offsets */ + int ipv6NetworkInterfaceAddressOffset = moteMem.getByteValueOf("uip_ds6_netif_addr_list_offset"); + int ipv6AddressStructSize = moteMem.getByteValueOf("uip_ds6_addr_size"); + if (ipv6NetworkInterfaceAddressOffset == 0 || ipv6AddressStructSize == 0) { + return null; + } + + /* TODO No need to copy the entire array! */ + byte[] structData = moteMem.getByteArray("uip_ds6_if", + ipv6NetworkInterfaceAddressOffset+IPv6_MAX_ADDRESSES*ipv6AddressStructSize); + + ipv6AddressIndex = -1; + for (int addressIndex=0; addressIndex < IPv6_MAX_ADDRESSES; addressIndex++) { + int offset = ipv6NetworkInterfaceAddressOffset+addressIndex*ipv6AddressStructSize; + byte isUsed = structData[offset]; + if (isUsed == 0) { + continue; + } + byte[] addressData = new byte[16]; + System.arraycopy( + structData, offset+2/* ipaddr offset */, + addressData, 0, 16); + + if (addressData[0] == (byte)0xFE && addressData[1] == (byte)0x80) { + ipv6IsGlobal = false; + } else { + ipv6IsGlobal = true; + } + + ip = addressData; + ipv6AddressIndex = addressIndex; + if (ipv6IsGlobal) { + break; + } + } + if (ip == null) { + ip = new byte[16]; + ipv6AddressIndex = -1; + } + return ip; + } + + public static String getUncompressedIPv6AddressString(byte[] ip) { + StringBuilder sb = new StringBuilder(); + for (int i=0; i < 14; i+=2) { + sb.append(String.format("%02x%02x:", 0xFF&ip[i+0], 0xFF&ip[i+1])); + } + sb.append(String.format("%02x%02x", 0xFF&ip[14], 0xFF&ip[15])); + return sb.toString(); + } + public String getUncompressedIPv6Address() { - byte[] ip = null; - - /* IpV6: Struct sizes and offsets */ - int ipv6NetworkInterfaceAddressOffset = moteMem.getByteValueOf("uip_ds6_netif_addr_list_offset"); - int ipv6AddressStructSize = moteMem.getByteValueOf("uip_ds6_addr_size"); - if (ipv6NetworkInterfaceAddressOffset == 0 || ipv6AddressStructSize == 0) { - return ""; - } - - /* TODO No need to copy the entire array! */ - byte[] structData = moteMem.getByteArray("uip_ds6_if", - ipv6NetworkInterfaceAddressOffset+IPv6_MAX_ADDRESSES*ipv6AddressStructSize); - - ipv6AddressIndex = -1; - for (int addressIndex=0; addressIndex < IPv6_MAX_ADDRESSES; addressIndex++) { - int offset = ipv6NetworkInterfaceAddressOffset+addressIndex*ipv6AddressStructSize; - byte isUsed = structData[offset]; - if (isUsed == 0) { - continue; - } - byte[] addressData = new byte[16]; - System.arraycopy( - structData, offset+2/* ipaddr offset */, - addressData, 0, 16); - - if (addressData[0] == (byte)0xFE && addressData[1] == (byte)0x80) { - ipv6IsGlobal = false; - } else { - ipv6IsGlobal = true; - } - - ip = addressData; - ipv6AddressIndex = addressIndex; - if (ipv6IsGlobal) { - break; - } - } - if (ip == null) { - ip = new byte[16]; - ipv6AddressIndex = -1; - } - - StringBuilder sb = new StringBuilder(); - for (int i=0; i < 14; i+=2) { - sb.append(String.format("%02x%02x:", 0xFF&ip[i+0], 0xFF&ip[i+1])); - } - sb.append(String.format("%02x%02x", 0xFF&ip[14], 0xFF&ip[15])); - return sb.toString(); + byte[] ip = getIPv6Address(); + if (ip == null) { + return ""; + } + return getUncompressedIPv6AddressString(ip); } /** From eb1a147d7d392e8079f0b901936e7274724ade93 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:47:44 +0200 Subject: [PATCH 07/26] new feature: ability to show log listener's output in the timeline, using the mote output plugin's currently active filter --- .../java/se/sics/cooja/plugins/TimeLine.java | 527 ++++++++---------- 1 file changed, 230 insertions(+), 297 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/TimeLine.java b/tools/cooja/java/se/sics/cooja/plugins/TimeLine.java index cfd29ceea..e73e0f120 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/TimeLine.java +++ b/tools/cooja/java/se/sics/cooja/plugins/TimeLine.java @@ -31,7 +31,6 @@ package se.sics.cooja.plugins; import java.awt.Color; -import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; @@ -55,7 +54,6 @@ import java.util.Observer; import javax.swing.AbstractAction; import javax.swing.Action; -import javax.swing.Box; import javax.swing.JCheckBox; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComboBox; @@ -70,7 +68,6 @@ import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSlider; -import javax.swing.JSplitPane; import javax.swing.JToolTip; import javax.swing.KeyStroke; import javax.swing.Popup; @@ -89,7 +86,8 @@ import se.sics.cooja.HasQuickHelp; import se.sics.cooja.Mote; import se.sics.cooja.Plugin; import se.sics.cooja.PluginType; -import se.sics.cooja.SimEventCentral.MoteCountListener; +import se.sics.cooja.SimEventCentral.LogOutputEvent; +import se.sics.cooja.SimEventCentral.LogOutputListener; import se.sics.cooja.Simulation; import se.sics.cooja.VisPlugin; import se.sics.cooja.Watchpoint; @@ -132,13 +130,14 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { private int paintedMoteHeight = EVENT_PIXEL_HEIGHT; private Simulation simulation; - private MoteCountListener newMotesListener; + private LogOutputListener newMotesListener; + + /* Expermental features: Use currently active plugin to filter Timeline Log outputs */ + private LogListener logEventFilterPlugin = null; private JScrollPane timelineScrollPane; private MoteRuler timelineMoteRuler; private JComponent timeline; - private Box eventCheckboxes; - private JSplitPane splitPane; private Observer moteHighlightObserver = null; private ArrayList highlightedMotes = new ArrayList(); @@ -150,13 +149,20 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { private boolean showRadioRXTX = true; private boolean showRadioChannels = false; - private boolean showRadioHW = true; - private boolean showLEDs = true; + private boolean showRadioOnoff = true; + private boolean showLeds = true; private boolean showLogOutputs = false; private boolean showWatchpoints = false; private Point popupLocation = null; + private JCheckBox showWatchpointsCheckBox; + private JCheckBox showLogsCheckBox; + private JCheckBox showLedsCheckBox; + private JCheckBox showRadioOnoffCheckbox; + private JCheckBox showRadioChannelsCheckbox; + private JCheckBox showRadioTXRXCheckbox; + /** * @param simulation Simulation * @param gui GUI @@ -195,149 +201,85 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { return executionDetails; } }); - viewMenu.add(new JCheckBoxMenuItem(radioChannelsAction) { - private static final long serialVersionUID = 6830282466652559714L; - public boolean isSelected() { - return radioChannels; - } - }); fileMenu.add(new JMenuItem(saveDataAction)); fileMenu.add(new JMenuItem(statisticsAction)); editMenu.add(new JMenuItem(clearAction)); - JCheckBox eventCheckBox; - eventCheckBox = createEventCheckbox("Radio traffic", "Show radio transmissions, receptions, and collisions"); - eventCheckBox.setSelected(showRadioRXTX); - eventCheckBox.setName("showRadioRXTX"); - eventCheckBox.addActionListener(new ActionListener() { + showRadioTXRXCheckbox = createEventCheckbox("Radio traffic", "Show radio transmissions, receptions, and collisions"); + showRadioTXRXCheckbox.setName("showRadioRXTX"); + showRadioTXRXCheckbox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { showRadioRXTX = ((JCheckBox) e.getSource()).isSelected(); recalculateMoteHeight(); } }); - eventsMenu.add(eventCheckBox); - eventCheckBox = createEventCheckbox("Radio channel", "Show different radio channels"); - eventCheckBox.setSelected(showRadioChannels); - eventCheckBox.setName("showRadioChannels"); - eventCheckBox.addActionListener(new ActionListener() { + eventsMenu.add(showRadioTXRXCheckbox); + showRadioOnoffCheckbox = createEventCheckbox("Radio on/off", "Show radio hardware state"); + showRadioOnoffCheckbox.setSelected(showRadioOnoff); + showRadioOnoffCheckbox.setName("showRadioHW"); + showRadioOnoffCheckbox.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + showRadioOnoff = ((JCheckBox) e.getSource()).isSelected(); + recalculateMoteHeight(); + } + }); + eventsMenu.add(showRadioOnoffCheckbox); + showRadioChannelsCheckbox = createEventCheckbox("Radio channel", "Show different radio channels"); + showRadioChannelsCheckbox.setSelected(showRadioChannels); + showRadioChannelsCheckbox.setName("showRadioChannels"); + showRadioChannelsCheckbox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { showRadioChannels = ((JCheckBox) e.getSource()).isSelected(); recalculateMoteHeight(); } }); - /*eventCheckboxes.add(eventCheckBox);*/ - eventsMenu.add(eventCheckBox); - eventCheckBox = createEventCheckbox("Radio state", "Show radio hardware state"); - eventCheckBox.setSelected(showRadioHW); - eventCheckBox.setName("showRadioHW"); - eventCheckBox.addActionListener(new ActionListener() { + eventsMenu.add(showRadioChannelsCheckbox); + showLedsCheckBox = createEventCheckbox("LEDs", "Show LED state"); + showLedsCheckBox.setSelected(showLeds); + showLedsCheckBox.setName("showLEDs"); + showLedsCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { - showRadioHW = ((JCheckBox) e.getSource()).isSelected(); + showLeds = ((JCheckBox) e.getSource()).isSelected(); recalculateMoteHeight(); } }); - eventsMenu.add(eventCheckBox); - eventCheckBox = createEventCheckbox("LEDs", "Show LED state"); - eventCheckBox.setSelected(showLEDs); - eventCheckBox.setName("showLEDs"); - eventCheckBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showLEDs = ((JCheckBox) e.getSource()).isSelected(); - recalculateMoteHeight(); - } - }); - eventsMenu.add(eventCheckBox); - eventCheckBox = createEventCheckbox("Log output", "Show mote log output, such as by printf()'s"); - eventCheckBox.setSelected(showLogOutputs); - eventCheckBox.setName("showLogOutput"); - eventCheckBox.addActionListener(new ActionListener() { + eventsMenu.add(showLedsCheckBox); + showLogsCheckBox = createEventCheckbox("Log output", "Show mote log output, such as printf()'s"); + showLogsCheckBox.setSelected(showLogOutputs); + showLogsCheckBox.setName("showLogOutput"); + showLogsCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { showLogOutputs = ((JCheckBox) e.getSource()).isSelected(); + + /* Check whether there is an active log listener that is used to filter logs */ + logEventFilterPlugin = (LogListener) simulation.getGUI().getPlugin( + LogListener.class.getName()); + if (showLogOutputs) { + if (logEventFilterPlugin != null) { + logger.info("Filtering shown log outputs by use of " + GUI.getDescriptionOf(LogListener.class) + " plugin"); + } else { + logger.info("No active " + GUI.getDescriptionOf(LogListener.class) + " plugin, not filtering log outputs"); + } + } + recalculateMoteHeight(); } }); - /*eventCheckboxes.add(eventCheckBox);*/ - eventCheckBox = createEventCheckbox("Watchpoints", "Show code watchpoints (for MSPSim-based motes)"); - eventCheckBox.setSelected(showWatchpoints); - eventCheckBox.setName("showWatchpoints"); - eventCheckBox.addActionListener(new ActionListener() { + eventsMenu.add(showLogsCheckBox); + showWatchpointsCheckBox = createEventCheckbox("Watchpoints", "Show code watchpoints (for emulated motes)"); + showWatchpointsCheckBox.setSelected(showWatchpoints); + showWatchpointsCheckBox.setName("showWatchpoints"); + showWatchpointsCheckBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { showWatchpoints = ((JCheckBox) e.getSource()).isSelected(); recalculateMoteHeight(); } }); - eventsMenu.add(eventCheckBox); + eventsMenu.add(showWatchpointsCheckBox); /* Box: events to observe */ - eventCheckboxes = Box.createVerticalBox(); - /* - eventCheckboxes.add(new JButton(addMoteAction)); - eventCheckboxes.add(new JSeparator()); - - JCheckBox eventCheckBox; - eventCheckBox = createEventCheckbox("Radio RX/TX", "Show radio transmissions, receptions, and collisions"); - eventCheckBox.setSelected(showRadioRXTX); - eventCheckBox.setName("showRadioRXTX"); - eventCheckBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showRadioRXTX = ((JCheckBox) e.getSource()).isSelected(); - recalculateMoteHeight(); - } - }); - eventCheckboxes.add(eventCheckBox); - eventCheckBox = createEventCheckbox("Radio channels", "Show different radio channels"); - eventCheckBox.setSelected(showRadioChannels); - eventCheckBox.setName("showRadioChannels"); - eventCheckBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showRadioChannels = ((JCheckBox) e.getSource()).isSelected(); - recalculateMoteHeight(); - } - }); - - eventCheckBox = createEventCheckbox("Radio ON/OFF", "Show radio hardware state"); - eventCheckBox.setSelected(showRadioHW); - eventCheckBox.setName("showRadioHW"); - eventCheckBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showRadioHW = ((JCheckBox) e.getSource()).isSelected(); - recalculateMoteHeight(); - } - }); - eventCheckboxes.add(eventCheckBox); - eventCheckBox = createEventCheckbox("LEDs", "Show LED state"); - eventCheckBox.setSelected(showLEDs); - eventCheckBox.setName("showLEDs"); - eventCheckBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showLEDs = ((JCheckBox) e.getSource()).isSelected(); - recalculateMoteHeight(); - } - }); - eventCheckboxes.add(eventCheckBox); - eventCheckBox = createEventCheckbox("Log output", "Show mote log output, such as by printf()'s"); - eventCheckBox.setSelected(showLogOutputs); - eventCheckBox.setName("showLogOutput"); - eventCheckBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showLogOutputs = ((JCheckBox) e.getSource()).isSelected(); - recalculateMoteHeight(); - } - }); - - eventCheckBox = createEventCheckbox("Watchpoints", "Show code watchpoints (for MSPSim-based motes)"); - eventCheckBox.setSelected(showWatchpoints); - eventCheckBox.setName("showWatchpoints"); - eventCheckBox.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - showWatchpoints = ((JCheckBox) e.getSource()).isSelected(); - recalculateMoteHeight(); - } - }); - eventCheckboxes.add(eventCheckBox); - */ /* Panel: timeline canvas w. scroll pane and add mote button */ timeline = new Timeline(); timelineScrollPane = new JScrollPane( @@ -350,13 +292,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { timelineScrollPane.setRowHeaderView(timelineMoteRuler); timelineScrollPane.setBackground(Color.WHITE); - splitPane = new JSplitPane( - JSplitPane.HORIZONTAL_SPLIT, - new JScrollPane(eventCheckboxes), - timelineScrollPane - ); - splitPane.setOneTouchExpandable(true); - /* Zoom in/out via keyboard*/ getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyEvent.CTRL_DOWN_MASK), "zoomIn"); getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, KeyEvent.SHIFT_DOWN_MASK | KeyEvent.CTRL_DOWN_MASK), "zoomIn"); @@ -374,14 +309,30 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { numberMotesWasUpdated(); - /* Automatically add/delete motes */ - simulation.getEventCentral().addMoteCountListener(newMotesListener = new MoteCountListener() { + /* Automatically add/delete motes. + * This listener also observes mote log outputs. */ + simulation.getEventCentral().addLogOutputListener(newMotesListener = new LogOutputListener() { public void moteWasAdded(Mote mote) { addMote(mote); } public void moteWasRemoved(Mote mote) { removeMote(mote); } + public void removedLogOutput(LogOutputEvent ev) { + } + public void newLogOutput(LogOutputEvent ev) { + /* Log output */ + Mote mote = ev.getMote(); + LogEvent logEvent = new LogEvent(ev); + + /* TODO Optimize */ + for (MoteEvents moteEvents: allMoteEvents) { + if (moteEvents.mote == mote) { + moteEvents.addLog(logEvent); + break; + } + } + } }); for (Mote m: simulation.getMotes()) { addMote(m); @@ -427,6 +378,17 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { this.setSize(gui.getDesktopPane().getWidth(), 166); } + public void startPlugin() { + super.startPlugin(); + + showWatchpointsCheckBox.setSelected(showWatchpoints); + showLogsCheckBox.setSelected(showLogOutputs); + showLedsCheckBox.setSelected(showLeds); + showRadioOnoffCheckbox.setSelected(showRadioOnoff); + showRadioChannelsCheckbox.setSelected(showRadioChannels); + showRadioTXRXCheckbox.setSelected(showRadioRXTX); + } + private JCheckBox createEventCheckbox(String text, String tooltip) { JCheckBox checkBox = new JCheckBox(text, true); checkBox.setToolTipText(tooltip); @@ -503,7 +465,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { private static final long serialVersionUID = 7546685285707302865L; public void actionPerformed(ActionEvent e) { - JComboBox source = new JComboBox(); + JComboBox source = new JComboBox(); source.addItem("All motes"); for (Mote m: simulation.getMotes()) { source.addItem(m); @@ -876,8 +838,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } } - /* TODO Radio channels */ - if (radioHW) { for (MoteEvent ev: moteEvents.radioHWEvents) { if (!(ev instanceof RadioHWEvent)) continue; @@ -923,8 +883,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } } - /* TODO Watchpoints */ - output.append(stats.toString(logs, leds, radioHW, radioRXTX)); } @@ -976,7 +934,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { }); } - private Action radioLoggerAction = new AbstractAction("Show in Radio Logger") { + private Action radioLoggerAction = new AbstractAction("Show in " + GUI.getDescriptionOf(RadioLogger.class)) { private static final long serialVersionUID = 7690116136861949864L; public void actionPerformed(ActionEvent e) { if (popupLocation == null) { @@ -996,7 +954,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } } }; - private Action logListenerAction = new AbstractAction("Show in Log Listener") { + private Action logListenerAction = new AbstractAction("Show in " + GUI.getDescriptionOf(LogListener.class)) { private static final long serialVersionUID = -8626118368774023257L; public void actionPerformed(ActionEvent e) { if (popupLocation == null) { @@ -1017,7 +975,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } }; - private Action showInAllAction = new AbstractAction("Show in log listener and radio logger") { + private Action showInAllAction = new AbstractAction("Show in " + GUI.getDescriptionOf(LogListener.class) + " and " + GUI.getDescriptionOf(RadioLogger.class)) { private static final long serialVersionUID = -2458733078524773995L; public void actionPerformed(ActionEvent e) { logListenerAction.actionPerformed(null); @@ -1026,20 +984,12 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { }; private boolean executionDetails = false; - private boolean radioChannels = false; private Action executionDetailsAction = new AbstractAction("Show execution details in tooltips") { private static final long serialVersionUID = -8626118368774023257L; public void actionPerformed(ActionEvent e) { executionDetails = !executionDetails; } }; - private Action radioChannelsAction = new AbstractAction("Color radio state by active radio channel") { - private static final long serialVersionUID = -8626118368774023257L; - public void actionPerformed(ActionEvent e) { - radioChannels = !radioChannels; - repaint(); - } - }; private void numberMotesWasUpdated() { /* Plugin title */ @@ -1101,9 +1051,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } private void addMoteObservers(final Mote mote, final MoteEvents moteEvents) { - /* TODO Log: final Log moteLog = mote.getInterfaces().getLog(); */ - /* TODO Unknown state event */ - /* LEDs */ final LED moteLEDs = mote.getInterfaces().getLED(); if (moteLEDs != null) { @@ -1131,69 +1078,59 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { activeMoteObservers.add(new MoteObservation(mote, moteLEDs, observer)); } - /* Radio HW, RXTX */ + /* Radio OnOff, RXTX, and channels */ final Radio moteRadio = mote.getInterfaces().getRadio(); if (moteRadio != null) { + RadioChannelEvent startupChannel = new RadioChannelEvent( + simulation.getSimulationTime(), moteRadio.getChannel(), moteRadio.isRadioOn()); + moteEvents.addRadioChannel(startupChannel); RadioHWEvent startupHW = new RadioHWEvent( simulation.getSimulationTime(), moteRadio.isRadioOn()); - if (radioChannels) { - startupHW.channel = moteRadio.getChannel(); - } moteEvents.addRadioHW(startupHW); RadioRXTXEvent startupRXTX = new RadioRXTXEvent( simulation.getSimulationTime(), RXTXRadioEvent.IDLE); moteEvents.addRadioRXTX(startupRXTX); Observer observer = new Observer() { - int lastChannel = -1; - public void update(Observable o, Object arg) { - /* Radio HW events */ - if (radioChannels && moteRadio.getLastEvent() == RadioEvent.UNKNOWN) { - int nowChannel = moteRadio.getChannel(); - if (nowChannel == lastChannel) { - return; - } - lastChannel = nowChannel; + int lastChannel = -1; + public void update(Observable o, Object arg) { + RadioEvent radioEv = moteRadio.getLastEvent(); + String details = null; + if (executionDetails && mote instanceof AbstractEmulatedMote) { + details = ((AbstractEmulatedMote) mote).getExecutionDetails(); + if (details != null) { + details = "
" + details.replace("\n", "
"); + } + } + + /* Radio channel */ + int nowChannel = moteRadio.getChannel(); + if (nowChannel != lastChannel) { + lastChannel = nowChannel; + RadioChannelEvent ev = new RadioChannelEvent( + simulation.getSimulationTime(), nowChannel, moteRadio.isRadioOn()); + moteEvents.addRadioChannel(ev); + + ev.details = details; + } + + if (radioEv == RadioEvent.HW_ON || + radioEv == RadioEvent.HW_OFF) { RadioHWEvent ev = new RadioHWEvent( simulation.getSimulationTime(), moteRadio.isRadioOn()); - if (radioChannels) { - ev.channel = moteRadio.getChannel(); - } - moteEvents.addRadioHW(ev); - if (executionDetails && mote instanceof AbstractEmulatedMote) { - String details = ((AbstractEmulatedMote) mote).getExecutionDetails(); - if (details != null) { - details = "
" + details.replace("\n", "
"); - ev.details = details; - } - } - return; - } + ev.details = details; - if (moteRadio.getLastEvent() == RadioEvent.HW_ON || - moteRadio.getLastEvent() == RadioEvent.HW_OFF) { - RadioHWEvent ev = new RadioHWEvent( - simulation.getSimulationTime(), moteRadio.isRadioOn()); - if (radioChannels) { - ev.channel = moteRadio.getChannel(); - } - - moteEvents.addRadioHW(ev); - - if (executionDetails && mote instanceof AbstractEmulatedMote) { - String details = ((AbstractEmulatedMote) mote).getExecutionDetails(); - if (details != null) { - details = "
" + details.replace("\n", "
"); - ev.details = details; - } - } - return; + /* Also create another channel event here */ + lastChannel = nowChannel; + RadioChannelEvent ev2 = new RadioChannelEvent( + simulation.getSimulationTime(), nowChannel, moteRadio.isRadioOn()); + ev2.details = details; + moteEvents.addRadioChannel(ev2); } /* Radio RXTX events */ - RadioEvent radioEv = moteRadio.getLastEvent(); if (radioEv == RadioEvent.TRANSMISSION_STARTED || radioEv == RadioEvent.TRANSMISSION_FINISHED || radioEv == RadioEvent.RECEPTION_STARTED || @@ -1221,15 +1158,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { moteEvents.addRadioRXTX(ev); - if (executionDetails && mote instanceof AbstractEmulatedMote) { - String details = ((AbstractEmulatedMote) mote).getExecutionDetails(); - if (details != null) { - details = "
" + details.replace("\n", "
"); - ev.details = details; - } - } - - return; + ev.details = details; } } @@ -1239,7 +1168,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { activeMoteObservers.add(new MoteObservation(mote, moteRadio, observer)); } - /* XXX Experimental: Watchpoints */ + /* Watchpoints */ if (mote instanceof WatchpointMote) { final WatchpointMote watchpointMote = ((WatchpointMote)mote); WatchpointListener listener = new WatchpointListener() { @@ -1317,10 +1246,10 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { if (showRadioChannels) { h += EVENT_PIXEL_HEIGHT; } - if (showRadioHW) { + if (showRadioOnoff) { h += EVENT_PIXEL_HEIGHT; } - if (showLEDs) { + if (showLeds) { h += 3*LED_PIXEL_HEIGHT; } if (showLogOutputs) { @@ -1378,11 +1307,11 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { element = new Element("showRadioChannels"); config.add(element); } - if (showRadioHW) { + if (showRadioOnoff) { element = new Element("showRadioHW"); config.add(element); } - if (showLEDs) { + if (showLeds) { element = new Element("showLEDs"); config.add(element); } @@ -1399,14 +1328,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { element = new Element("executionDetails"); config.add(element); } - if (radioChannels) { - element = new Element("radioChannels"); - config.add(element); - } - - element = new Element("split"); - element.addContent("" + splitPane.getDividerLocation()); - config.add(element); element = new Element("zoomfactor"); element.addContent("" + currentPixelDivisor); @@ -1418,13 +1339,12 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { public boolean setConfigXML(Collection configXML, boolean visAvailable) { showRadioRXTX = false; showRadioChannels = false; - showRadioHW = false; - showLEDs = false; + showRadioOnoff = false; + showLeds = false; showLogOutputs = false; showWatchpoints = false; executionDetails = false; - radioChannels = false; /* Remove already registered motes */ MoteEvents[] allMoteEventsArr = allMoteEvents.toArray(new MoteEvents[0]); @@ -1442,19 +1362,16 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } else if ("showRadioChannels".equals(name)) { showRadioChannels = true; } else if ("showRadioHW".equals(name)) { - showRadioHW = true; + showRadioOnoff = true; } else if ("showLEDs".equals(name)) { - showLEDs = true; + showLeds = true; } else if ("showLogOutput".equals(name)) { showLogOutputs = true; } else if ("showWatchpoints".equals(name)) { showWatchpoints = true; + } else if ("executionDetails".equals(name)) { executionDetails = true; - } else if ("radioChannels".equals(name)) { - radioChannels = true; - } else if ("split".equals(name)) { - splitPane.setDividerLocation(Integer.parseInt(element.getText())); } else if ("zoom".equals(name)) { /* NB: Historically this is a one-based not zero-based index */ final int zl = Integer.parseInt(element.getText())-1; @@ -1466,22 +1383,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } } - /* XXX HACK: Update checkboxes according to config */ - for (Component c: eventCheckboxes.getComponents()) { - if (c.getName() == "showRadioRXTX") { - ((JCheckBox)c).setSelected(showRadioRXTX); - } else if (c.getName() == "showRadioChannels") { - ((JCheckBox)c).setSelected(showRadioChannels); - } else if (c.getName() == "showRadioHW") { - ((JCheckBox)c).setSelected(showRadioHW); - } else if (c.getName() == "showLEDs") { - ((JCheckBox)c).setSelected(showLEDs); - } else if (c.getName() == "showLogOutput") { - ((JCheckBox)c).setSelected(showLogOutputs); - } else if (c.getName() == "showWatchpoints") { - ((JCheckBox)c).setSelected(showWatchpoints); - } - } recalculateMoteHeight(); return true; @@ -1505,28 +1406,9 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { /* Popup menu */ final JPopupMenu popupMenu = new JPopupMenu(); - /* popupMenu.add(new JMenuItem(addMoteAction)); - - popupMenu.addSeparator(); - - popupMenu.add(new JMenuItem(zoomInAction)); - popupMenu.add(new JMenuItem(zoomOutAction)); - popupMenu.add(new JMenuItem(zoomSliderAction)); - - popupMenu.addSeparator(); - - popupMenu.add(new JMenuItem(saveDataAction)); - popupMenu.add(new JMenuItem(statisticsAction)); - popupMenu.add(new JMenuItem(clearAction)); - - popupMenu.addSeparator(); - */ - /* JMenu focusMenu = new JMenu("Show in");*/ popupMenu.add(new JMenuItem(showInAllAction)); - /* focusMenu.addSeparator(); */ popupMenu.add(new JMenuItem(logListenerAction)); popupMenu.add(new JMenuItem(radioLoggerAction)); - /* popupMenu.add(focusMenu);*/ JMenu advancedMenu = new JMenu("Advanced"); advancedMenu.add(new JCheckBoxMenuItem(executionDetailsAction) { @@ -1535,13 +1417,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { return executionDetails; } }); - advancedMenu.add(new JCheckBoxMenuItem(radioChannelsAction) { - private static final long serialVersionUID = 6830282466652559714L; - public boolean isSelected() { - return radioChannels; - } - }); - /* popupMenu.add(advancedMenu);*/ addMouseListener(new MouseAdapter() { long lastClick = -1; @@ -1741,7 +1616,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { /*logger.info("Painting interval: " + intervalStart + " -> " + intervalEnd);*/ if (bounds.x > Integer.MAX_VALUE - 1000) { - /* TODO Strange bounds */ + /* Strange bounds */ return; } @@ -1779,14 +1654,14 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } lineHeightOffset += EVENT_PIXEL_HEIGHT; } - if (showRadioHW) { + if (showRadioOnoff) { MoteEvent firstEvent = getFirstIntervalEvent(allMoteEvents.get(mIndex).radioHWEvents, intervalStart); if (firstEvent != null) { firstEvent.paintInterval(g, lineHeightOffset, intervalEnd); } lineHeightOffset += EVENT_PIXEL_HEIGHT; } - if (showLEDs) { + if (showLeds) { MoteEvent firstEvent = getFirstIntervalEvent(allMoteEvents.get(mIndex).ledEvents, intervalStart); if (firstEvent != null) { firstEvent.paintInterval(g, lineHeightOffset, intervalEnd); @@ -1931,13 +1806,13 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } evMatched++; } - if (showRadioHW) { + if (showRadioOnoff) { if (evMatched == evMouse) { events = allMoteEvents.get(mote).radioHWEvents; } evMatched++; } - if (showLEDs) { + if (showLeds) { if (evMatched == evMouse) { events = allMoteEvents.get(mote).ledEvents; } @@ -2167,16 +2042,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } } } - class RadioChannelEvent extends MoteEvent { - public RadioChannelEvent(long time) { - super(time); - } - public Color getEventColor() { - return Color.GRAY; /* TODO Implement me */ - } - } - /* TODO Which colors? */ private final static Color[] CHANNEL_COLORS = new Color[] { Color.decode("0x008080"), Color.decode("0x808080"), Color.decode("0xC00000"), Color.decode("0x000020"), Color.decode("0x202000"), Color.decode("0x200020"), @@ -2190,28 +2056,47 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { Color.decode("0x00FF00"), Color.decode("0x0000FF"), Color.decode("0xFFFF00"), Color.decode("0xFF00FF"), Color.decode("0x808000"), Color.decode("0x800080"), }; + class RadioChannelEvent extends MoteEvent { + int channel; + boolean radioOn; + public RadioChannelEvent(long time, int channel, boolean radioOn) { + super(time); + this.channel = channel; + this.radioOn = radioOn; + } + public Color getEventColor() { + if (channel >= 0) { + if (!radioOn) { + return null; + } + Color c = CHANNEL_COLORS[channel % CHANNEL_COLORS.length]; + return c; + } + return null; + } + public String toString() { + String str = "Radio channel " + channel + "
"; + return str; + } + } + class RadioHWEvent extends MoteEvent { boolean on; - int channel = -1; public RadioHWEvent(long time, boolean on) { super(time); this.on = on; } public RadioHWEvent(long time, boolean on, int channel) { this(time, on); - this.channel = channel; } public Color getEventColor() { - if (on && radioChannels && channel >= 0 && channel < CHANNEL_COLORS.length) { - return CHANNEL_COLORS[channel]; + if (on) { + return Color.GRAY; } - return on?Color.GRAY:null; + return null; } public String toString() { - String str = "Radio HW was turned " + (on?"on":"off") + " at time " + time + "
"; - if (channel > 0) { - str += "Radio channel: " + channel; - } + String str = "Radio HW was turned " + (on?"on":"off") + "
"; return str; } } @@ -2298,11 +2183,56 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } } class LogEvent extends MoteEvent { - public LogEvent(long time) { - super(time); + LogOutputEvent logEvent; + public LogEvent(LogOutputEvent ev) { + super(ev.getTime()); + this.logEvent = ev; } public Color getEventColor() { - return Color.GRAY; /* TODO Implement me */ + if (logEventFilterPlugin != null) { + /* Ask log listener for event color to use */ + return logEventFilterPlugin.getColorOfEntry(logEvent); + } + return Color.GRAY; + } + /* Default paint method */ + public void paintInterval(Graphics g, int lineHeightOffset, long end) { + LogEvent ev = this; + while (ev != null && ev.time < end) { + /* Ask active log listener whether this should be filtered */ + + if (logEventFilterPlugin != null) { + boolean show = logEventFilterPlugin.filterWouldAccept(ev.logEvent); + if (!show) { + /* Skip painting event */ + ev = (LogEvent) ev.next; + continue; + } + } + + Color color = ev.getEventColor(); + if (color == null) { + /* Skip painting event */ + ev = (LogEvent) ev.next; + continue; + } + + g.setColor(color); + g.fillRect( + (int)(ev.time/currentPixelDivisor), lineHeightOffset, + 4, EVENT_PIXEL_HEIGHT + ); + g.setColor(Color.BLACK); + g.fillRect( + (int)(ev.time/currentPixelDivisor), lineHeightOffset, + 1, EVENT_PIXEL_HEIGHT + ); + + ev = (LogEvent) ev.next; + } + } + public String toString() { + return "Mote " + logEvent.getMote() + " says:
" + logEvent.getMessage() + "
"; } } class WatchpointEvent extends MoteEvent { @@ -2434,7 +2364,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { } lastRadioChannelEvent = ev; - /* TODO XXX Requires MSPSim changes */ radioChannelEvents.add(ev); } public void addRadioHW(RadioHWEvent ev) { @@ -2530,19 +2459,23 @@ public class TimeLine extends VisPlugin implements HasQuickHelp { "Timeline" + "

The timeline shows simulation events over time. " + "The timeline can be used to inspect activities of individual nodes as well as interactions between nodes." + - "

For each mote, simulation events are shown on a colored line. Different colors correspond to different events. For more information about a particular event, hover the mouse above it." + + "

For each mote, simulation events are shown on a colored line. Different colors correspond to different events. For more information about a particular event, mouse click it." + "

The Events menu control what event types are shown in the timeline. " + - "Currently, four event types are supported (see below). " + + "Currently, six event types are supported (see below). " + "

All motes are by default shown in the timeline. Motes can be removed from the timeline by right-clicking the node ID on the left." + "

To display a vertical time marker on the timeline, press and hold the mouse on the time ruler (top)." + "

For more options for a given event, right-click the mouse for a popup menu." + "

Radio traffic" + "
Shows radio traffic events. Transmissions are painted blue, receptions are green, and interfered radios are red." + - "

Radio state" + + "

Radio channel" + + "
Shows the current radio channel by colors." + + "

Radio on/off" + "
Shows whether the mote radio is on or off. When gray, the radio is on." + "

LEDs" + "
Shows LED state: red, green, and blue. (Assumes all mote types have exactly three LEDs.)" + + "

Log outputs" + + "
Shows log outputs, as also shown in " + GUI.getDescriptionOf(LogListener.class) + "

Watchpoints" + - "
Shows triggered watchpoints, currently only supported by MSPSim-based motes. To add watchpoints, use the Msp Code Watcher plugin."; + "
Shows triggered watchpoints, currently only supported by emulated motes. To add watchpoints, use the Msp Code Watcher plugin."; } } From 9cb2fd84659bc88ae23c04d330f13ee1490cc0fd Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:52:20 +0200 Subject: [PATCH 08/26] allow saving .csc with contiki-relative paths when the .csc file is in a subdirectory of the referenced application --- tools/cooja/java/se/sics/cooja/GUI.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/cooja/java/se/sics/cooja/GUI.java b/tools/cooja/java/se/sics/cooja/GUI.java index 2d57a42cc..1883ba2da 100644 --- a/tools/cooja/java/se/sics/cooja/GUI.java +++ b/tools/cooja/java/se/sics/cooja/GUI.java @@ -1556,6 +1556,9 @@ public class GUI extends Observable { "MOTETYPES"); if (moteTypeClassNames != null) { for (String moteTypeClassName : moteTypeClassNames) { + if (moteTypeClassName.trim().isEmpty()) { + continue; + } Class moteTypeClass = tryLoadClass(this, MoteType.class, moteTypeClassName); @@ -4260,6 +4263,22 @@ public class GUI extends Observable { id += "/.."; } } + if (!fileCanonical.startsWith(configCanonical)) { + /* SPECIAL CASE: Allow two parent directories */ + File parent = new File(configCanonical).getParentFile(); + if (parent != null) { + configCanonical = parent.getCanonicalPath(); + id += "/.."; + } + } + if (!fileCanonical.startsWith(configCanonical)) { + /* SPECIAL CASE: Allow three parent directories */ + File parent = new File(configCanonical).getParentFile(); + if (parent != null) { + configCanonical = parent.getCanonicalPath(); + id += "/.."; + } + } if (!fileCanonical.startsWith(configCanonical)) { /* File is not in a config subdirectory */ /*logger.info("File is not in a config subdirectory: " + file.getAbsolutePath());*/ From 0b09084b9239e4741b0c466d355d5c0646776e8a Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:54:30 +0200 Subject: [PATCH 09/26] minor bugfix: simulation speed was not restored correctly --- tools/cooja/java/se/sics/cooja/Simulation.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/Simulation.java b/tools/cooja/java/se/sics/cooja/Simulation.java index 71c5bfc86..0286c8da6 100644 --- a/tools/cooja/java/se/sics/cooja/Simulation.java +++ b/tools/cooja/java/se/sics/cooja/Simulation.java @@ -659,7 +659,10 @@ public class Simulation extends Observable implements Runnable { availableMoteTypes, moteTypeClassName ); - if (newClass != null && !newClass.equals(moteTypeClassName)) { + if (newClass == null) { + throw new MoteType.MoteTypeCreationException("No mote type class selected"); + } + if (!newClass.equals(moteTypeClassName)) { logger.warn("Changing mote type class: " + moteTypeClassName + " -> " + newClass); moteTypeClassName = newClass; } @@ -989,7 +992,7 @@ public class Simulation extends Observable implements Runnable { * @param newSpeedLimit */ public void setSpeedLimit(final Double newSpeedLimit) { - invokeSimulationThread(new Runnable() { + Runnable r = new Runnable() { public void run() { if (newSpeedLimit == null) { speedLimitNone = true; @@ -1008,7 +1011,14 @@ public class Simulation extends Observable implements Runnable { Simulation.this.setChanged(); Simulation.this.notifyObservers(this); } - }); + }; + if (!isRunning()) { + /* Simulation is stopped, change speed immediately */ + r.run(); + } else { + /* Change speed from simulation thread */ + invokeSimulationThread(r); + } } /** From 1842fae903df4cbc7cd7c5ff6f6d2da47d9e59ad Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:56:25 +0200 Subject: [PATCH 10/26] write node id to infomem --- .../sics/cooja/mspmote/interfaces/MspMoteID.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/MspMoteID.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/MspMoteID.java index c8a535f76..137472936 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/MspMoteID.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/MspMoteID.java @@ -83,6 +83,22 @@ public class MspMoteID extends MoteID { } moteID = newID; + /* Write node-unique infomem entry, used to configure node_id and node_mac */ + if (mote.getMemory().getMemorySegment(0x1980, 10) != null) { + byte[] infomem = new byte[10]; + infomem[0] = (byte) 0xab; /* magic */ + infomem[1] = (byte) 0xcd; /* magic */ + infomem[2] = (byte) 0x02; + infomem[3] = (byte) 0x12; + infomem[4] = (byte) 0x74; + infomem[5] = (byte) 0x00; + infomem[6] = (byte) 0x00; + infomem[7] = (byte) 0x01; + infomem[8] = (byte) ((newID << 8) & 0xFF); + infomem[9] = (byte) (newID & 0xFF); + mote.getMemory().setMemorySegment(0x1980, infomem); + } + if (moteMem.variableExists("node_id")) { moteMem.setIntValueOf("node_id", moteID); From 5b7cc56cc58db255331ec1890b6d533b8dfa091b Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:57:17 +0200 Subject: [PATCH 11/26] guard amount of serial data being written to simulated contiki nodes --- .../contikimote/interfaces/ContikiRS232.java | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRS232.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRS232.java index c55160491..b39292dec 100644 --- a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRS232.java +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRS232.java @@ -70,6 +70,8 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll private ContikiMote mote = null; private SectionMoteMemory moteMem = null; + static final int SERIAL_BUF_SIZE = 1024; /* rs232.c:40 */ + /** * Creates an interface to the RS232 at mote. * @@ -109,6 +111,11 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll /* Append to existing buffer */ int oldSize = moteMem.getIntValueOf("simSerialReceivingLength"); int newSize = oldSize + dataToAppend.length; + if (newSize > SERIAL_BUF_SIZE) { + logger.fatal("ContikiRS232: dropping rs232 data #1, buffer full: " + oldSize + " -> " + newSize); + mote.requestImmediateWakeup(); + return; + } moteMem.setIntValueOf("simSerialReceivingLength", newSize); byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize); @@ -159,6 +166,11 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll /* Append to existing buffer */ int oldSize = moteMem.getIntValueOf("simSerialReceivingLength"); int newSize = oldSize + dataToAppend.length; + if (newSize > SERIAL_BUF_SIZE) { + logger.fatal("ContikiRS232: dropping rs232 data #2, buffer full: " + oldSize + " -> " + newSize); + mote.requestImmediateWakeup(); + return; + } moteMem.setIntValueOf("simSerialReceivingLength", newSize); byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize); @@ -212,6 +224,11 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll /* Append to existing buffer */ int oldSize = moteMem.getIntValueOf("simSerialReceivingLength"); int newSize = oldSize + dataToAppend.length; + if (newSize > SERIAL_BUF_SIZE) { + logger.fatal("ContikiRS232: dropping rs232 data #3, buffer full: " + oldSize + " -> " + newSize); + mote.requestImmediateWakeup(); + return; + } moteMem.setIntValueOf("simSerialReceivingLength", newSize); byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize); @@ -229,13 +246,26 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll mote.requestImmediateWakeup(); } }; + + /* Simulation thread: schedule immediately */ + if (mote.getSimulation().isSimulationThread()) { + mote.getSimulation().scheduleEvent( + pendingBytesEvent, + mote.getSimulation().getSimulationTime() + ); + return; + } + mote.getSimulation().invokeSimulationThread(new Runnable() { - public void run() { - mote.getSimulation().scheduleEvent( - pendingBytesEvent, - mote.getSimulation().getSimulationTime() - ); - } + public void run() { + if (pendingBytesEvent.isScheduled()) { + return; + } + mote.getSimulation().scheduleEvent( + pendingBytesEvent, + mote.getSimulation().getSimulationTime() + ); + } }); } From 21a901ad260047ee9627487bd45c455fc11ed835 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 12:57:58 +0200 Subject: [PATCH 12/26] removed unnecessary imports --- tools/cooja/java/se/sics/cooja/util/ArrayUtils.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/util/ArrayUtils.java b/tools/cooja/java/se/sics/cooja/util/ArrayUtils.java index 9f8002c67..3a84007e2 100644 --- a/tools/cooja/java/se/sics/cooja/util/ArrayUtils.java +++ b/tools/cooja/java/se/sics/cooja/util/ArrayUtils.java @@ -28,17 +28,12 @@ package se.sics.cooja.util; -import java.awt.Container; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.ByteBuffer; - -import javax.swing.JFileChooser; /** * Some utility methods for managing arrays. From 11d124882c499e7f8d4c71a429265f793803d1ae Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 13:00:00 +0200 Subject: [PATCH 13/26] made mote-to-mote relations optional, reordered how skins are painted to more easily decide which skin is painted first --- .../se/sics/cooja/plugins/Visualizer.java | 58 ++++++++++++++----- 1 file changed, 45 insertions(+), 13 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java b/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java index 410b6e66c..b7b02cb35 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java +++ b/tools/cooja/java/se/sics/cooja/plugins/Visualizer.java @@ -550,7 +550,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { try { VisualizerSkin newSkin = skinClass.newInstance(); newSkin.setActive(Visualizer.this.simulation, Visualizer.this); - currentSkins.add(newSkin); + currentSkins.add(0, newSkin); } catch (InstantiationException e1) { e1.printStackTrace(); } catch (IllegalAccessException e1) { @@ -700,7 +700,26 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { menu.setVisible(true); } + private boolean showMoteToMoteRelations = true; private void populateSkinMenu(MenuElement menu) { + /* Mote-to-mote relations */ + JCheckBoxMenuItem moteRelationsItem = new JCheckBoxMenuItem("Mote relations", showMoteToMoteRelations); + moteRelationsItem.addItemListener(new ItemListener() { + public void itemStateChanged(ItemEvent e) { + JCheckBoxMenuItem menuItem = ((JCheckBoxMenuItem)e.getItem()); + showMoteToMoteRelations = menuItem.isSelected(); + repaint(); + } + }); + if (menu instanceof JMenu) { + ((JMenu)menu).add(moteRelationsItem); + ((JMenu)menu).add(new JSeparator()); + } + if (menu instanceof JPopupMenu) { + ((JPopupMenu)menu).add(moteRelationsItem); + ((JPopupMenu)menu).add(new JSeparator()); + } + for (Class skinClass: visualizerSkins) { /* Should skin be enabled in this simulation? */ if (!isSkinCompatible(skinClass)) { @@ -998,16 +1017,18 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { Mote[] allMotes = simulation.getMotes(); /* Paint mote relations */ - MoteRelation[] relations = simulation.getGUI().getMoteRelations(); - for (MoteRelation r: relations) { - Position sourcePos = r.source.getInterfaces().getPosition(); - Position destPos = r.dest.getInterfaces().getPosition(); + if (showMoteToMoteRelations) { + MoteRelation[] relations = simulation.getGUI().getMoteRelations(); + for (MoteRelation r: relations) { + Position sourcePos = r.source.getInterfaces().getPosition(); + Position destPos = r.dest.getInterfaces().getPosition(); - Point sourcePoint = transformPositionToPixel(sourcePos); - Point destPoint = transformPositionToPixel(destPos); + Point sourcePoint = transformPositionToPixel(sourcePos); + Point destPoint = transformPositionToPixel(destPos); - g.setColor(r.color == null ? Color.black : r.color); - drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y, MOTE_RADIUS + 1); + g.setColor(r.color == null ? Color.black : r.color); + drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y, MOTE_RADIUS + 1); + } } for (Mote mote: allMotes) { @@ -1264,11 +1285,19 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { ArrayList config = new ArrayList(); Element element; + /* Show mote-to-mote relations */ + if (showMoteToMoteRelations) { + element = new Element("moterelations"); + element.setText("" + true); + config.add(element); + } + /* Skins */ - for (VisualizerSkin skin: currentSkins) { - element = new Element("skin"); - element.setText(skin.getClass().getName()); - config.add(element); + for (int i=currentSkins.size()-1; i >= 0; i--) { + VisualizerSkin skin = currentSkins.get(i); + element = new Element("skin"); + element.setText(skin.getClass().getName()); + config.add(element); } /* Viewport */ @@ -1298,6 +1327,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { public boolean setConfigXML(Collection configXML, boolean visAvailable) { loadedConfig = true; + showMoteToMoteRelations = false; for (Element element : configXML) { if (element.getName().equals("skin")) { @@ -1319,6 +1349,8 @@ public class Visualizer extends VisPlugin implements HasQuickHelp { if (wanted != null) { logger.warn("Could not load visualizer: " + element.getText()); } + } else if (element.getName().equals("moterelations")) { + showMoteToMoteRelations = true; } else if (element.getName().equals("viewport")) { try { String[] matrix = element.getText().split(" "); From 8a084926e228ce798b2b54448fc287b0c861f023 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 13:03:15 +0200 Subject: [PATCH 14/26] re-implemented stack overflow monitoring, and user can now manually override the stack addresses for use with custom linker scripts --- .../mspmote/plugins/MspStackWatcher.java | 254 +++++++++++++----- 1 file changed, 182 insertions(+), 72 deletions(-) diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspStackWatcher.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspStackWatcher.java index 61e394252..6e0fc6ebc 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspStackWatcher.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspStackWatcher.java @@ -31,126 +31,236 @@ package se.sics.cooja.mspmote.plugins; import java.awt.BorderLayout; -import java.awt.GridLayout; +import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.Observable; -import java.util.Observer; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; -import javax.swing.JButton; +import javax.swing.JLabel; import javax.swing.JOptionPane; -import javax.swing.JPanel; +import javax.swing.JToggleButton; +import javax.swing.SwingUtilities; import org.apache.log4j.Logger; +import org.jdom.Element; import se.sics.cooja.ClassDescription; import se.sics.cooja.GUI; import se.sics.cooja.Mote; import se.sics.cooja.MotePlugin; +import se.sics.cooja.MoteTimeEvent; import se.sics.cooja.PluginType; import se.sics.cooja.Simulation; import se.sics.cooja.SupportedArguments; import se.sics.cooja.VisPlugin; import se.sics.cooja.mspmote.MspMote; +import se.sics.cooja.mspmote.MspMoteType; import se.sics.mspsim.core.MSP430; +import se.sics.mspsim.core.Memory.AccessMode; +import se.sics.mspsim.core.RegisterMonitor; import se.sics.mspsim.ui.StackUI; -import se.sics.mspsim.util.Utils; @ClassDescription("Msp Stack Watcher") @PluginType(PluginType.MOTE_PLUGIN) -@SupportedArguments(motes = {MspMote.class}) +@SupportedArguments(motes = { MspMote.class }) public class MspStackWatcher extends VisPlugin implements MotePlugin { private static Logger logger = Logger.getLogger(MspStackWatcher.class); - private MspMote mspMote; - private MSP430 cpu; - private StackUI stackUI; - private Simulation simulation; - private Observer stackObserver = null; - private JButton startButton; - private JButton stopButton; + private MSP430 cpu; + private MspMote mspMote; + private StackUI stackUI; + private RegisterMonitor.Adapter registerMonitor = null; + + private JToggleButton toggleButton; + + private MoteTimeEvent increasePosTimeEvent; + + private Integer userOverriddenStack = null; + + private JLabel memLabel = new JLabel(""); + public MspStackWatcher(Mote mote, Simulation simulationToVisualize, GUI gui) { - super("Msp Stack Watcher", gui); + super("Msp Stack Watcher: " + mote, gui); this.mspMote = (MspMote) mote; cpu = mspMote.getCPU(); simulation = simulationToVisualize; getContentPane().setLayout(new BorderLayout()); - // Register as stack observable - if (stackObserver == null) { - mspMote.getStackOverflowObservable().addObserver(stackObserver = new Observer() { - public void update(Observable obs, Object obj) { - simulation.stopSimulation(); - JOptionPane.showMessageDialog( - MspStackWatcher.this, - "Bad memory access!\nSimulation stopped.\n" + - "\nCurrent stack pointer = 0x" + Utils.hex16(cpu.reg[MSP430.SP]) + - "\nStart of heap = 0x" + Utils.hex16(cpu.getDisAsm().getMap().heapStartAddress), - "Stack overflow", JOptionPane.ERROR_MESSAGE - ); + toggleButton = new JToggleButton("Click to monitor for stack overflows"); + toggleButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (toggleButton.isSelected()) { + toggleButton.setText("Monitoring for stack overflows"); + if (!activate(true)) { + toggleButton.setBackground(Color.RED); + toggleButton.setText("Monitoring for stack overflows - FAILED!"); + toggleButton.setSelected(false); + } + toggleButton.setBackground(null); + } else { + toggleButton.setBackground(null); + toggleButton.setText("Click to monitor for stack overflows"); + deactivate(); } - }); - } - - // Create stack overflow controls - startButton = new JButton("Stop simulation on stack overflow"); - startButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - startButton.setEnabled(false); - stopButton.setEnabled(true); - - mspMote.monitorStack(true); } }); - stopButton = new JButton("Cancel"); - stopButton.setEnabled(false); - stopButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - startButton.setEnabled(true); - stopButton.setEnabled(false); - - mspMote.monitorStack(false); - } - }); - - // Create nfi's stack viewer - stackUI = new StackUI(cpu); - stackUI.init("MSPSim stack", mspMote.registry); + /* Create Mspsim stack viewer */ + stackUI = new StackUI(cpu, -1); /* Needs manual updates */ + stackUI.init("Stack usage", mspMote.registry); stackUI.start(); + increasePosTimeEvent = new MoteTimeEvent(mspMote, 0) { + public void execute(long t) { + stackUI.requestIncreasePos(); + simulation.scheduleEvent(this, t + Simulation.MILLISECOND); + } + }; + simulation.scheduleEvent(increasePosTimeEvent, simulation.getSimulationTime()); - // Register as log listener - /*if (logObserver == null && mspMote.getInterfaces().getLog() != null) { - mspMote.getInterfaces().getLog().addObserver(logObserver = new Observer() { - public void update(Observable obs, Object obj) { - stackUI.addNote(mspMote.getInterfaces().getLog().getLastLogMessage()); - } - }); - }*/ - - JPanel controlPanel = new JPanel(new GridLayout(2,1)); - controlPanel.add(startButton); - controlPanel.add(stopButton); - + add(BorderLayout.NORTH, memLabel); add(BorderLayout.CENTER, stackUI); - add(BorderLayout.SOUTH, controlPanel); + add(BorderLayout.SOUTH, toggleButton); - setSize(240, 300); + setSize(400, 300); + } - // Tries to select this plugin + private boolean activate(boolean gui) { try { - setSelected(true); - } catch (java.beans.PropertyVetoException e) { - // Could not select + int stack = ((MspMoteType) mspMote.getType()).getELF().getMap().stackStartAddress; + + if (gui) { + String s = (String)JOptionPane.showInputDialog( + GUI.getTopParentContainer(), + "With default linker scripts the stack starts at 0x" + Integer.toHexString(stack) + ".\n" + + "If you are using a modified linker script, you may here correct the stack start address.", + "Enter stack start address", + JOptionPane.PLAIN_MESSAGE, + null, + null, + "0x" + Integer.toHexString(userOverriddenStack!=null?userOverriddenStack:stack)); + userOverriddenStack = null; + if (s != null) { + try { + int newStack = Integer.decode(s); + if (newStack != stack) { + userOverriddenStack = newStack; + } + } catch (Exception e) { + logger.error("Error parsing provided stack address: " + s, e); + return false; + } + } + } + if (userOverriddenStack != null) { + stack = userOverriddenStack; + } + + int heap = ((MspMoteType) mspMote.getType()).getELF().getMap().heapStartAddress; + if (stack < 0) { + stack = cpu.config.ramStart + cpu.config.ramSize; + } + logger.debug("SP starts at: 0x" + Integer.toHexString(stack)); + logger.debug("Heap starts at: 0x" + Integer.toHexString(heap)); + logger.debug("Available stack: " + (stack-heap) + " bytes"); + memLabel.setText(String.format("Stack 0x%x, heap 0x%x", stack, heap)); + + if (stack < 0 || heap < 0) { + return false; + } + + /*final int stackStartAddress = stack;*/ + final int heapStartAddress = heap; + registerMonitor = new RegisterMonitor.Adapter() { + int min = Integer.MAX_VALUE; + public void notifyWriteBefore(int register, final int sp, AccessMode mode) { + /*logger.debug("SP is now: 0x" + Integer.toHexString(sp));*/ + final int available = sp - heapStartAddress; + + if (available < min) { + min = available; + String details = mspMote.getExecutionDetails(); + if (details != null) { + logger.info(String.format(mspMote + ": Maximum stack usage: 0x%x, available stack 0x%x", sp, available)); + logger.info(details); + } + } + + if (available <= 0) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + JOptionPane.showMessageDialog(GUI.getTopParentContainer(), + String.format("Stack overflow!\n\n" + + "\tSP = 0x%05x\n" + + "\tHeap start = 0x%05x\n\n" + + "\tAvailable = %d\n", sp, heapStartAddress, available), + "Stack overflow on " + mspMote, + JOptionPane.ERROR_MESSAGE); + } + }); + simulation.stopSimulation(); + } + } + }; + cpu.addRegisterWriteMonitor(MSP430.SP, registerMonitor); + } catch (IOException e) { + logger.warn("Stack monitoring failed: " + e.getMessage(), e); + registerMonitor = null; + return false; + } + return true; + } + + private void deactivate() { + userOverriddenStack = null; + if (registerMonitor != null) { + cpu.removeRegisterWriteMonitor(MSP430.SP, registerMonitor); + registerMonitor = null; } } + public Collection getConfigXML() { + ArrayList config = new ArrayList(); + Element element; + + if (userOverriddenStack != null) { + element = new Element("stack"); + element.setText("0x" + Integer.toHexString(userOverriddenStack)); + config.add(element); + } + + element = new Element("monitoring"); + element.setText("" + toggleButton.isSelected()); + config.add(element); + + return config; + } + + public boolean setConfigXML(Collection configXML, + boolean visAvailable) { + for (Element element : configXML) { + if (element.getName().equals("monitoring")) { + boolean monitor = Boolean.parseBoolean(element.getText()); + if (monitor) { + if (activate(false)) { + toggleButton.setSelected(true); + } + } + } else if (element.getName().equals("stack")) { + userOverriddenStack = Integer.decode(element.getText()); + } + } + return true; + } + public void closePlugin() { - mspMote.getStackOverflowObservable().deleteObserver(stackObserver); + increasePosTimeEvent.remove(); stackUI.stop(); + deactivate(); } public Mote getMote() { From f59040375b0d6f9ad64dbf5d6b50741d16fa99f1 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 13:04:37 +0200 Subject: [PATCH 15/26] repaint labels periodically instead of every time data is sent over the serial connection --- .../java/SerialSocketServer.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tools/cooja/apps/serial_socket/java/SerialSocketServer.java b/tools/cooja/apps/serial_socket/java/SerialSocketServer.java index 5ec23184c..97c047479 100644 --- a/tools/cooja/apps/serial_socket/java/SerialSocketServer.java +++ b/tools/cooja/apps/serial_socket/java/SerialSocketServer.java @@ -30,6 +30,8 @@ import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -45,6 +47,7 @@ import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingUtilities; +import javax.swing.Timer; import org.apache.log4j.Logger; import org.jdom.Element; @@ -91,6 +94,8 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin { super("Serial Socket (SERVER) (" + mote + ")", gui, false); this.mote = mote; + updateTimer.start(); + LISTEN_PORT = 60000 + mote.getID(); /* GUI components */ @@ -156,12 +161,11 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin { /*logger.debug("out is null");*/ return; } + out.write(serialPort.getLastSerialData()); out.flush(); + outBytes++; - if (GUI.isVisualized()) { - outLabel.setText(outBytes + " bytes"); - } } catch (IOException e) { cleanupClient(); } @@ -188,10 +192,8 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin { for (int i=0; i < numRead; i++) { serialPort.writeByte(data[i]); } + inBytes += numRead; - if (GUI.isVisualized()) { - inLabel.setText(inBytes + " bytes"); - } } else { cleanupClient(); break; @@ -254,7 +256,9 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin { } } + private boolean closed = false; public void closePlugin() { + closed = true; cleanupClient(); serialPort.deleteSerialDataObserver(serialDataObserver); try { @@ -267,5 +271,17 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin { return mote; } + private static final int UPDATE_INTERVAL = 150; + private Timer updateTimer = new Timer(UPDATE_INTERVAL, new ActionListener() { + public void actionPerformed(ActionEvent e) { + if (closed) { + updateTimer.stop(); + return; + } + + inLabel.setText(inBytes + " bytes"); + outLabel.setText(outBytes + " bytes"); + } + }); } From 8e264badb791bd67d5f077e6ccf51faf3369622a Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 13:25:53 +0200 Subject: [PATCH 16/26] added new mote type method that returns the by-default used mote interfaces, as opposed to all compatible mote interfaces this allows the user to override default settings in the create-new-mote-type dialogs --- .../cooja/avrmote/MicaZCompileDialog.java | 3 ++ .../se/sics/cooja/mspmote/ESBMoteType.java | 3 ++ .../sics/cooja/mspmote/Exp5438MoteType.java | 18 +++++++++ .../sics/cooja/mspmote/JCreateMoteType.java | 3 ++ .../sics/cooja/mspmote/MspCompileDialog.java | 5 ++- .../se/sics/cooja/mspmote/MspMoteType.java | 1 + .../cooja/mspmote/SentillaUSBMoteType.java | 4 +- .../se/sics/cooja/mspmote/SkyMoteType.java | 3 ++ .../sics/cooja/mspmote/TyndallMoteType.java | 3 ++ .../sics/cooja/mspmote/WismoteMoteType.java | 4 +- .../src/se/sics/cooja/mspmote/Z1MoteType.java | 5 ++- .../cooja/dialogs/AbstractCompileDialog.java | 6 ++- .../dialogs/ContikiMoteCompileDialog.java | 37 ++++++++++--------- 13 files changed, 73 insertions(+), 22 deletions(-) diff --git a/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/MicaZCompileDialog.java b/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/MicaZCompileDialog.java index c11ed2862..21a91127f 100644 --- a/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/MicaZCompileDialog.java +++ b/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/MicaZCompileDialog.java @@ -64,6 +64,9 @@ public class MicaZCompileDialog extends AbstractCompileDialog { super(parent, simulation, moteType); } + public Class[] getAllMoteInterfaces() { + return ((MicaZMoteType)moteType).getAllMoteInterfaceClasses(); + } public Class[] getDefaultMoteInterfaces() { return ((MicaZMoteType)moteType).getAllMoteInterfaceClasses(); } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMoteType.java index 934f5f54f..91d256ab8 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/ESBMoteType.java @@ -198,6 +198,9 @@ public class ESBMoteType extends MspMoteType { return true; } + public Class[] getDefaultMoteInterfaceClasses() { + return getAllMoteInterfaceClasses(); + } public Class[] getAllMoteInterfaceClasses() { return new Class[] { Position.class, diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438MoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438MoteType.java index 2cb52bffa..a3ed5090f 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438MoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438MoteType.java @@ -179,6 +179,22 @@ public class Exp5438MoteType extends MspMoteType { return null; } + public Class[] getDefaultMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + Msp802154Radio.class, + UsciA1Serial.class, + Exp5438LED.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } public Class[] getAllMoteInterfaceClasses() { return new Class[] { Position.class, @@ -189,6 +205,8 @@ public class Exp5438MoteType extends MspMoteType { MspClock.class, MspMoteID.class, Msp802154Radio.class, + CC1101Radio.class, + CC1120Radio.class, UsciA1Serial.class, Exp5438LED.class, /*Exp5438LCD.class,*/ /* TODO */ diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/JCreateMoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/JCreateMoteType.java index e7a683460..764fbbd37 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/JCreateMoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/JCreateMoteType.java @@ -71,6 +71,9 @@ public class JCreateMoteType extends AbstractMspMoteType { } @Override + public Class[] getDefaultMoteInterfaceClasses() { + return getAllMoteInterfaceClasses(); + } public Class[] getAllMoteInterfaceClasses() { @SuppressWarnings("unchecked") Class[] list = createMoteInterfaceList( diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspCompileDialog.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspCompileDialog.java index 745053ab1..019505f89 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspCompileDialog.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspCompileDialog.java @@ -71,8 +71,11 @@ public class MspCompileDialog extends AbstractCompileDialog { addCompilationTipsTab(tabbedPane); } + public Class[] getAllMoteInterfaces() { + return ((MspMoteType)moteType).getAllMoteInterfaceClasses(); + } public Class[] getDefaultMoteInterfaces() { - return ((MspMoteType)moteType).getAllMoteInterfaceClasses(); + return ((MspMoteType)moteType).getDefaultMoteInterfaceClasses(); } private void addCompilationTipsTab(JTabbedPane parent) { diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteType.java index dea897e2c..d4af5e2f3 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMoteType.java @@ -320,6 +320,7 @@ public abstract class MspMoteType implements MoteType { } public abstract Class[] getAllMoteInterfaceClasses(); + public abstract Class[] getDefaultMoteInterfaceClasses(); public abstract File getExpectedFirmwareFile(File source); private static ELF loadELF(String filepath) throws IOException { diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/SentillaUSBMoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/SentillaUSBMoteType.java index 5ce424a81..112eee0b3 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/SentillaUSBMoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/SentillaUSBMoteType.java @@ -69,7 +69,9 @@ public class SentillaUSBMoteType extends AbstractMspMoteType { return new SentillaUSBMote(this, simulation); } - @Override + public Class[] getDefaultMoteInterfaceClasses() { + return getAllMoteInterfaceClasses(); + } public Class[] getAllMoteInterfaceClasses() { @SuppressWarnings("unchecked") Class[] list = createMoteInterfaceList( diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/SkyMoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/SkyMoteType.java index ec8453bc6..e5134f0b0 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/SkyMoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/SkyMoteType.java @@ -202,6 +202,9 @@ public class SkyMoteType extends MspMoteType { return null; } + public Class[] getDefaultMoteInterfaceClasses() { + return getAllMoteInterfaceClasses(); + } public Class[] getAllMoteInterfaceClasses() { return new Class[] { Position.class, diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/TyndallMoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/TyndallMoteType.java index 7bac0f5ac..ae401a316 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/TyndallMoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/TyndallMoteType.java @@ -179,6 +179,9 @@ public class TyndallMoteType extends MspMoteType { return null; } + public Class[] getDefaultMoteInterfaceClasses() { + return getAllMoteInterfaceClasses(); + } public Class[] getAllMoteInterfaceClasses() { return new Class[] { Position.class, diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/WismoteMoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/WismoteMoteType.java index 61659d1f2..80466398d 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/WismoteMoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/WismoteMoteType.java @@ -69,7 +69,9 @@ public class WismoteMoteType extends AbstractMspMoteType { return new WismoteMote(this, simulation); } - @Override + public Class[] getDefaultMoteInterfaceClasses() { + return getAllMoteInterfaceClasses(); + } public Class[] getAllMoteInterfaceClasses() { @SuppressWarnings("unchecked") Class[] list = createMoteInterfaceList( diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Z1MoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Z1MoteType.java index 7e1ab8510..aeeafd99a 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Z1MoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Z1MoteType.java @@ -70,7 +70,10 @@ public class Z1MoteType extends AbstractMspMoteType { return new Z1Mote(this, simulation); } - @Override + public Class[] getDefaultMoteInterfaceClasses() { + return getAllMoteInterfaceClasses(); + } + public Class[] getAllMoteInterfaceClasses() { @SuppressWarnings("unchecked") Class[] list = createMoteInterfaceList( diff --git a/tools/cooja/java/se/sics/cooja/dialogs/AbstractCompileDialog.java b/tools/cooja/java/se/sics/cooja/dialogs/AbstractCompileDialog.java index 814cc8d3c..2cf0d1f5b 100644 --- a/tools/cooja/java/se/sics/cooja/dialogs/AbstractCompileDialog.java +++ b/tools/cooja/java/se/sics/cooja/dialogs/AbstractCompileDialog.java @@ -372,7 +372,7 @@ public abstract class AbstractCompileDialog extends JDialog { ((JCheckBox) c).setSelected(false); } if (moteType.getMoteInterfaceClasses() != null) { - for (Class intfClass: getDefaultMoteInterfaces()) { + for (Class intfClass: getAllMoteInterfaces()) { addMoteInterface(intfClass, false); } for (Class intf: moteType.getMoteInterfaceClasses()) { @@ -380,6 +380,9 @@ public abstract class AbstractCompileDialog extends JDialog { } } else { /* Select default mote interfaces */ + for (Class intfClass: getAllMoteInterfaces()) { + addMoteInterface(intfClass, false); + } for (Class intfClass: getDefaultMoteInterfaces()) { addMoteInterface(intfClass, true); } @@ -714,6 +717,7 @@ public abstract class AbstractCompileDialog extends JDialog { }; public abstract Class[] getDefaultMoteInterfaces(); + public abstract Class[] getAllMoteInterfaces(); /** * @return Currently selected mote interface classes diff --git a/tools/cooja/java/se/sics/cooja/dialogs/ContikiMoteCompileDialog.java b/tools/cooja/java/se/sics/cooja/dialogs/ContikiMoteCompileDialog.java index cdd530924..3be902ce8 100644 --- a/tools/cooja/java/se/sics/cooja/dialogs/ContikiMoteCompileDialog.java +++ b/tools/cooja/java/se/sics/cooja/dialogs/ContikiMoteCompileDialog.java @@ -199,24 +199,27 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog { return ContikiMoteType.getExpectedFirmwareFile(source); } + public Class[] getAllMoteInterfaces() { + ProjectConfig projectConfig = moteType.getConfig(); + String[] intfNames = projectConfig.getStringArrayValue(ContikiMoteType.class, "MOTE_INTERFACES"); + ArrayList> classes = new ArrayList>(); + + /* Load mote interface classes */ + for (String intfName : intfNames) { + Class intfClass = + gui.tryLoadClass(this, MoteInterface.class, intfName); + + if (intfClass == null) { + logger.warn("Failed to load mote interface class: " + intfName); + continue; + } + + classes.add(intfClass); + } + return classes.toArray(new Class[0]); + } public Class[] getDefaultMoteInterfaces() { - ProjectConfig projectConfig = moteType.getConfig(); - String[] intfNames = projectConfig.getStringArrayValue(ContikiMoteType.class, "MOTE_INTERFACES"); - ArrayList> classes = new ArrayList>(); - - /* Load mote interface classes */ - for (String intfName : intfNames) { - Class intfClass = - gui.tryLoadClass(this, MoteInterface.class, intfName); - - if (intfClass == null) { - logger.warn("Failed to load mote interface class: " + intfName); - continue; - } - - classes.add(intfClass); - } - return classes.toArray(new Class[0]); + return getAllMoteInterfaces(); } private void addAdvancedTab(JTabbedPane parent) { From 9929cc2a10ec3fd37401b2344bf2d3770a5cb992 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 13:30:15 +0200 Subject: [PATCH 17/26] added new mote type method that returns the by default used mote interfaces, as opposed to all compatible mote interfaces this allows a user to override default settings in the create-new-mote-type dialogs --- .../cooja/avrmote/interfaces/MicaZRadio.java | 16 ++++++++++++---- .../mspmote/interfaces/Msp802154Radio.java | 7 +++++++ .../cooja/mspmote/interfaces/TR1001Radio.java | 8 ++++++++ .../sics/cooja/interfaces/CustomDataRadio.java | 2 ++ .../cooja/radiomediums/AbstractRadioMedium.java | 17 ++++++++++------- 5 files changed, 39 insertions(+), 11 deletions(-) diff --git a/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/interfaces/MicaZRadio.java b/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/interfaces/MicaZRadio.java index ba9192cd6..bf44ddc34 100644 --- a/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/interfaces/MicaZRadio.java +++ b/tools/cooja/apps/avrora/src/se/sics/cooja/avrmote/interfaces/MicaZRadio.java @@ -32,16 +32,17 @@ package se.sics.cooja.avrmote.interfaces; import org.apache.log4j.Logger; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.avrmote.MicaZMote; +import se.sics.cooja.emulatedmote.Radio802154; +import se.sics.cooja.interfaces.CustomDataRadio; import avrora.sim.FiniteStateMachine; import avrora.sim.FiniteStateMachine.Probe; import avrora.sim.platform.MicaZ; import avrora.sim.radio.CC2420Radio; import avrora.sim.radio.Medium; -import se.sics.cooja.*; -import se.sics.cooja.avrmote.MicaZMote; -import se.sics.cooja.emulatedmote.Radio802154; - /** * CC2420 to COOJA wrapper. * @@ -152,4 +153,11 @@ public class MicaZRadio extends Radio802154 { //System.out.println("MicaZ: Received: " + (b &0xff)); recv.nextByte(true, (byte)b); } + + public boolean canReceiveFrom(CustomDataRadio radio) { + if (radio.getClass().equals(this.getClass())) { + return true; + } + return false; + } } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/Msp802154Radio.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/Msp802154Radio.java index cc475ee23..266befe89 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/Msp802154Radio.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/Msp802154Radio.java @@ -423,4 +423,11 @@ public class Msp802154Radio extends Radio implements CustomDataRadio { } return true; } + + public boolean canReceiveFrom(CustomDataRadio radio) { + if (radio.getClass().equals(this.getClass())) { + return true; + } + return false; + } } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/TR1001Radio.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/TR1001Radio.java index 873c028b0..abef5d9f6 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/TR1001Radio.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/TR1001Radio.java @@ -357,4 +357,12 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio /* TODO Implement me */ return true; } + + public boolean canReceiveFrom(CustomDataRadio radio) { + if (radio.getClass().equals(this.getClass())) { + return true; + } + return false; + } + } diff --git a/tools/cooja/java/se/sics/cooja/interfaces/CustomDataRadio.java b/tools/cooja/java/se/sics/cooja/interfaces/CustomDataRadio.java index 7c7ce8f7c..1f64f5810 100644 --- a/tools/cooja/java/se/sics/cooja/interfaces/CustomDataRadio.java +++ b/tools/cooja/java/se/sics/cooja/interfaces/CustomDataRadio.java @@ -39,6 +39,8 @@ package se.sics.cooja.interfaces; */ public interface CustomDataRadio { + public boolean canReceiveFrom(CustomDataRadio radio); + public void receiveCustomData(Object data); public Object getLastCustomDataTransmitted(); diff --git a/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java b/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java index 903af3cfd..179332de0 100644 --- a/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java +++ b/tools/cooja/java/se/sics/cooja/radiomediums/AbstractRadioMedium.java @@ -341,8 +341,8 @@ public abstract class AbstractRadioMedium extends RadioMedium { } for (Radio dstRadio : connection.getAllDestinations()) { - - if (!radio.getClass().equals(dstRadio.getClass()) || !(radio instanceof CustomDataRadio)) { + if (!(dstRadio instanceof CustomDataRadio) || + !((CustomDataRadio) dstRadio).canReceiveFrom((CustomDataRadio)radio)) { /* Radios communicate via radio packets */ continue; } @@ -383,11 +383,14 @@ public abstract class AbstractRadioMedium extends RadioMedium { } for (Radio dstRadio : connection.getAllDestinations()) { - - if (radio.getClass().equals(dstRadio.getClass()) && radio instanceof CustomDataRadio) { - /* Radios instead communicate via custom data objects */ - continue; - } + + if ((radio instanceof CustomDataRadio) && + (dstRadio instanceof CustomDataRadio) && + ((CustomDataRadio) dstRadio).canReceiveFrom((CustomDataRadio)radio)) { + /* Radios instead communicate via custom data objects */ + continue; + } + /* Forward radio packet */ if (connection.getDestinationDelay(dstRadio) == 0) { From ba39d98a862a14e8ca01d4c8bcd3bd2acd508227 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Wed, 14 Aug 2013 13:56:39 +0200 Subject: [PATCH 18/26] store current radio transmission bitrate in .csc trigger radio event when device radio channel is changed --- .../contikimote/interfaces/ContikiRadio.java | 43 +++++++++++++------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java index 9c5d9de92..577e94046 100644 --- a/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java +++ b/tools/cooja/java/se/sics/cooja/contikimote/interfaces/ContikiRadio.java @@ -30,17 +30,8 @@ package se.sics.cooja.contikimote.interfaces; -import java.awt.BorderLayout; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; +import java.util.ArrayList; import java.util.Collection; -import java.util.Observable; -import java.util.Observer; - -import javax.swing.JButton; -import javax.swing.JLabel; -import javax.swing.JPanel; import org.apache.log4j.Logger; import org.jdom.Element; @@ -105,7 +96,7 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA /** * Transmission bitrate (kbps). */ - public final double RADIO_TRANSMISSION_RATE_kbps; + private double RADIO_TRANSMISSION_RATE_kbps; private RadioPacket packetToMote = null; @@ -125,6 +116,8 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA private int oldOutputPowerIndicator = -1; + private int oldRadioChannel = -1; + /** * Creates an interface to the radio at mote. * @@ -294,6 +287,14 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA this.notifyObservers(); } + /* Check if radio channel changed */ + if (getChannel() != oldRadioChannel) { + oldRadioChannel = getChannel(); + lastEvent = RadioEvent.UNKNOWN; + this.setChanged(); + this.notifyObservers(); + } + /* Ongoing transmission */ if (isTransmitting && now >= transmissionEndTime) { myMoteMemory.setIntValueOf("simOutSize", 0); @@ -345,10 +346,26 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA } public Collection getConfigXML() { - return null; + ArrayList config = new ArrayList(); + + Element element; + + /* Radio bitrate */ + element = new Element("bitrate"); + element.setText("" + RADIO_TRANSMISSION_RATE_kbps); + config.add(element); + + return config; } - public void setConfigXML(Collection configXML, boolean visAvailable) { + public void setConfigXML(Collection configXML, + boolean visAvailable) { + for (Element element : configXML) { + if (element.getName().equals("bitrate")) { + RADIO_TRANSMISSION_RATE_kbps = Double.parseDouble(element.getText()); + logger.info("Radio bitrate reconfigured to (kbps): " + RADIO_TRANSMISSION_RATE_kbps); + } + } } public Mote getMote() { From 92655159c872fc2e58c652901faf1cdd2e551cf3 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 15 Aug 2013 11:46:29 +0200 Subject: [PATCH 19/26] added a set of new mspsim-based mote types using CC1120, CC1101 and the Enc28j60 ethernet chip minor changes: removed some obsolete stack monitoring code, improved mspsim-cooja window handler integration --- tools/cooja/apps/mspsim/cooja.config | 2 +- .../se/sics/cooja/mspmote/Exp5438Mote.java | 37 +++++++- .../sics/cooja/mspmote/Exp5438MoteType.java | 3 + .../src/se/sics/cooja/mspmote/MspMote.java | 95 +++++++++---------- 4 files changed, 83 insertions(+), 54 deletions(-) diff --git a/tools/cooja/apps/mspsim/cooja.config b/tools/cooja/apps/mspsim/cooja.config index f875a4c97..875dd1236 100644 --- a/tools/cooja/apps/mspsim/cooja.config +++ b/tools/cooja/apps/mspsim/cooja.config @@ -1,3 +1,3 @@ -se.sics.cooja.GUI.MOTETYPES = + se.sics.cooja.mspmote.ESBMoteType se.sics.cooja.mspmote.SkyMoteType se.sics.cooja.mspmote.Z1MoteType se.sics.cooja.mspmote.WismoteMoteType se.sics.cooja.mspmote.Exp5438MoteType +se.sics.cooja.GUI.MOTETYPES = + se.sics.cooja.mspmote.ESBMoteType se.sics.cooja.mspmote.SkyMoteType se.sics.cooja.mspmote.Z1MoteType se.sics.cooja.mspmote.WismoteMoteType se.sics.cooja.mspmote.Exp5438MoteType se.sics.cooja.mspmote.SkyMoteType com.thingsquare.cooja.mspsim.CC430MoteType com.thingsquare.cooja.mspsim.Exp1120MoteType com.thingsquare.cooja.mspsim.Exp1101MoteType com.thingsquare.cooja.mspsim.Exp2420MoteType com.thingsquare.cooja.mspsim.Trxeb2520MoteType com.thingsquare.cooja.mspsim.Trxeb1120MoteType com.thingsquare.cooja.mspsim.Eth1120MoteType se.sics.cooja.GUI.JARFILES = + cooja_mspsim.jar mspsim.jar coffee.jar jipv6.jar se.sics.cooja.GUI.PLUGINS = + se.sics.cooja.mspmote.plugins.MspCLI se.sics.cooja.mspmote.plugins.MspCodeWatcher se.sics.cooja.mspmote.plugins.MspStackWatcher se.sics.cooja.mspmote.plugins.MspCycleWatcher diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438Mote.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438Mote.java index 117fa6662..3945774f8 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438Mote.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438Mote.java @@ -34,7 +34,12 @@ import java.io.File; import org.apache.log4j.Logger; import se.sics.cooja.Simulation; +import se.sics.mspsim.platform.GenericNode; +import se.sics.mspsim.platform.ti.Exp1101Node; +import se.sics.mspsim.platform.ti.Exp1120Node; import se.sics.mspsim.platform.ti.Exp5438Node; +import se.sics.mspsim.platform.ti.Trxeb1120Node; +import se.sics.mspsim.platform.ti.Trxeb2520Node; /** * @author Fredrik Osterlind @@ -42,15 +47,39 @@ import se.sics.mspsim.platform.ti.Exp5438Node; public class Exp5438Mote extends MspMote { private static Logger logger = Logger.getLogger(Exp5438Mote.class); - public Exp5438Node exp5438Node = null; - + public GenericNode exp5438Node = null; + private String desc = ""; + public Exp5438Mote(MspMoteType moteType, Simulation sim) { super(moteType, sim); } protected boolean initEmulator(File fileELF) { + /* Hack: Try to figure out what type of Mspsim-node we should be used by checking file extension */ + String filename = fileELF.getName(); + if (filename.endsWith(".exp1101")) { + exp5438Node = new Exp1101Node(); + desc = "Exp5438+CC1101"; + } else if (filename.endsWith(".exp1120")) { + exp5438Node = new Exp1120Node(); + desc = "Exp5438+CC1120"; + } else if (filename.endsWith(".trxeb2520")) { + exp5438Node = new Trxeb2520Node(); + desc = "Trxeb2520"; + } else if (filename.endsWith(".trxeb1120")) { + exp5438Node = new Trxeb1120Node(false); + desc = "Trxeb1120"; + } else if (filename.endsWith(".eth1120")) { + exp5438Node = new Trxeb1120Node(true); + desc = "Eth1120"; + } else if (filename.endsWith(".exp2420") || filename.endsWith(".exp5438")) { + exp5438Node = new Exp5438Node(); + desc = "Exp5438+CC2420"; + } else { + throw new IllegalStateException("unknown file extension, cannot figure out what Mspsim node type to use: " + filename); + } + try { - exp5438Node = new Exp5438Node(); registry = exp5438Node.getRegistry(); prepareMote(fileELF, exp5438Node); } catch (Exception e) { @@ -64,7 +93,7 @@ public class Exp5438Mote extends MspMote { } public String toString() { - return "Exp5438 " + getID(); + return desc + " " + getID(); } } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438MoteType.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438MoteType.java index a3ed5090f..443c75fa8 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438MoteType.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/Exp5438MoteType.java @@ -62,6 +62,9 @@ import se.sics.cooja.mspmote.interfaces.MspDebugOutput; import se.sics.cooja.mspmote.interfaces.MspMoteID; import se.sics.cooja.mspmote.interfaces.UsciA1Serial; +import com.thingsquare.cooja.mspsim.CC1101Radio; +import com.thingsquare.cooja.mspsim.CC1120Radio; + @ClassDescription("EXP430F5438 mote") @AbstractionLevelDescription("Emulated level") public class Exp5438MoteType extends MspMoteType { diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java index 7d6286ed9..aaec1f11d 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java @@ -30,13 +30,13 @@ package se.sics.cooja.mspmote; +import java.awt.Component; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.Hashtable; -import java.util.Observable; import org.apache.log4j.Logger; import org.jdom.Element; @@ -53,8 +53,8 @@ import se.sics.cooja.Watchpoint; import se.sics.cooja.WatchpointMote; import se.sics.cooja.interfaces.IPAddress; import se.sics.cooja.motes.AbstractEmulatedMote; -import se.sics.cooja.mspmote.interfaces.MspSerial; import se.sics.cooja.mspmote.interfaces.Msp802154Radio; +import se.sics.cooja.mspmote.interfaces.MspSerial; import se.sics.cooja.mspmote.plugins.CodeVisualizerSkin; import se.sics.cooja.mspmote.plugins.MspBreakpoint; import se.sics.cooja.plugins.Visualizer; @@ -65,7 +65,8 @@ import se.sics.mspsim.cli.LineOutputStream; import se.sics.mspsim.core.EmulationException; import se.sics.mspsim.core.MSP430; import se.sics.mspsim.platform.GenericNode; -import se.sics.mspsim.ui.JFrameWindowManager; +import se.sics.mspsim.ui.ManagedWindow; +import se.sics.mspsim.ui.WindowManager; import se.sics.mspsim.util.ComponentRegistry; import se.sics.mspsim.util.ConfigManager; import se.sics.mspsim.util.DebugInfo; @@ -95,10 +96,8 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc /* Stack monitoring variables */ private boolean stopNextInstruction = false; - private boolean monitorStackUsage = false; - private int stackPointerLow = Integer.MAX_VALUE; - private int heapStartAddress; - private StackOverflowObservable stackOverflowObservable = new StackOverflowObservable(); + + public GenericNode mspNode = null; public MspMote(MspMoteType moteType, Simulation simulation) { this.simulation = simulation; @@ -113,8 +112,43 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc initEmulator(myMoteType.getContikiFirmwareFile()); myMoteInterfaceHandler = createMoteInterfaceHandler(); - /* TODO Setup COOJA-specific window manager */ - registry.registerComponent("windowManager", new JFrameWindowManager()); + /* TODO Create COOJA-specific window manager */ + registry.removeComponent("windowManager"); + registry.registerComponent("windowManager", new WindowManager() { + public ManagedWindow createWindow(String name) { + return new ManagedWindow() { + public void setVisible(boolean b) { + logger.warn("setVisible() ignored"); + } + public void setTitle(String string) { + logger.warn("setTitle() ignored"); + } + public void setSize(int width, int height) { + logger.warn("setSize() ignored"); + } + public void setBounds(int x, int y, int width, int height) { + logger.warn("setBounds() ignored"); + } + public void removeAll() { + logger.warn("removeAll() ignored"); + } + public void pack() { + logger.warn("pack() ignored"); + } + public boolean isVisible() { + logger.warn("isVisible() return false"); + return false; + } + public String getTitle() { + logger.warn("getTitle() return \"\""); + return ""; + } + public void add(Component component) { + logger.warn("add() ignored"); + } + }; + } + }); try { debuggingInfo = ((MspMoteType)getType()).getFirmwareDebugInfo(); @@ -156,45 +190,6 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc myMemory = (MspMoteMemory) memory; } - /* Stack monitoring variables */ - public class StackOverflowObservable extends Observable { - public void signalStackOverflow() { - setChanged(); - notifyObservers(); - } - } - - /** - * Enable/disable stack monitoring - * - * @param monitoring Monitoring enabled - */ - public void monitorStack(boolean monitoring) { - this.monitorStackUsage = monitoring; - resetLowestStackPointer(); - } - - /** - * @return Lowest SP since stack monitoring was enabled - */ - public int getLowestStackPointer() { - return stackPointerLow; - } - - /** - * Resets lowest stack pointer variable - */ - public void resetLowestStackPointer() { - stackPointerLow = Integer.MAX_VALUE; - } - - /** - * @return Stack overflow observable - */ - public StackOverflowObservable getStackOverflowObservable() { - return stackOverflowObservable; - } - /** * Prepares CPU, memory and ELF module. * @@ -204,6 +199,9 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc */ protected void prepareMote(File fileELF, GenericNode node) throws IOException { this.commandHandler = new CommandHandler(System.out, System.err); + + this.mspNode = node; + node.setCommandHandler(commandHandler); ConfigManager config = new ConfigManager(); @@ -225,7 +223,6 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc MapEntry[] allEntries = map.getAllEntries(); myMemory = new MspMoteMemory(this, allEntries, myCpu); - heapStartAddress = map.heapStartAddress; myCpu.reset(); } From e5fe37336e84f6498f7a01c2ea5641323d858876 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 15 Aug 2013 11:49:31 +0200 Subject: [PATCH 20/26] enable reconfigurable mote interfaces some minor trying to fix a bug that occasionally hangs cooja when reconfiguring a mote type --- .../cooja/dialogs/AbstractCompileDialog.java | 87 +++++++++++-------- .../dialogs/ContikiMoteCompileDialog.java | 69 +++++++++------ 2 files changed, 97 insertions(+), 59 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/dialogs/AbstractCompileDialog.java b/tools/cooja/java/se/sics/cooja/dialogs/AbstractCompileDialog.java index 2cf0d1f5b..2ff2d9160 100644 --- a/tools/cooja/java/se/sics/cooja/dialogs/AbstractCompileDialog.java +++ b/tools/cooja/java/se/sics/cooja/dialogs/AbstractCompileDialog.java @@ -256,6 +256,12 @@ public abstract class AbstractCompileDialog extends JDialog { topPanel.add(sourcePanel); + + Action cancelAction = new AbstractAction("Cancel") { + public void actionPerformed(ActionEvent e) { + AbstractCompileDialog.this.dispose(); + } + }; Action compileAction = new AbstractAction("Compile") { private static final long serialVersionUID = 1L; public void actionPerformed(ActionEvent e) { @@ -345,6 +351,41 @@ public abstract class AbstractCompileDialog extends JDialog { } }); + descriptionField.requestFocus(); + descriptionField.select(0, descriptionField.getText().length()); + + /* Add listener only after restoring old config */ + contikiField.getDocument().addDocumentListener(contikiFieldListener); + + /* Final touches: respect window size, focus on description etc */ + Rectangle maxSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); + if (maxSize != null && + (getSize().getWidth() > maxSize.getWidth() || getSize().getHeight() > maxSize.getHeight())) { + Dimension newSize = new Dimension(); + newSize.height = Math.min((int) maxSize.getHeight(), (int) getSize().getHeight()); + newSize.width = Math.min((int) maxSize.getWidth(), (int) getSize().getWidth()); + /*logger.info("Resizing dialog: " + myDialog.getSize() + " -> " + newSize);*/ + setSize(newSize); + } + + /* Recompile at Ctrl+R */ + InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK, false), "recompile"); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0, false), "dispose"); + getRootPane().getActionMap().put("recompile", compileAction); + getRootPane().getActionMap().put("dispose", cancelAction); + + pack(); + setLocationRelativeTo(parent); + + new Thread() { + public void run() { + tryRestoreMoteType(); + }; + }.start(); + } + + private void tryRestoreMoteType() { /* Restore old configuration if mote type is already configured */ boolean restoredDialogState = false; if (moteType != null) { @@ -390,39 +431,14 @@ public abstract class AbstractCompileDialog extends JDialog { /* Restore compile commands */ if (moteType.getCompileCommands() != null) { - setCompileCommands(moteType.getCompileCommands()); - setDialogState(DialogState.AWAITING_COMPILATION); + setCompileCommands(moteType.getCompileCommands()); + setDialogState(DialogState.AWAITING_COMPILATION); restoredDialogState = true; } } if (!restoredDialogState) { setDialogState(DialogState.NO_SELECTION); } - - descriptionField.requestFocus(); - descriptionField.select(0, descriptionField.getText().length()); - - /* Add listener only after restoring old config */ - contikiField.getDocument().addDocumentListener(contikiFieldListener); - - /* Final touches: respect window size, focus on description etc */ - Rectangle maxSize = GraphicsEnvironment.getLocalGraphicsEnvironment().getMaximumWindowBounds(); - if (maxSize != null && - (getSize().getWidth() > maxSize.getWidth() || getSize().getHeight() > maxSize.getHeight())) { - Dimension newSize = new Dimension(); - newSize.height = Math.min((int) maxSize.getHeight(), (int) getSize().getHeight()); - newSize.width = Math.min((int) maxSize.getWidth(), (int) getSize().getWidth()); - /*logger.info("Resizing dialog: " + myDialog.getSize() + " -> " + newSize);*/ - setSize(newSize); - } - - /* Recompile at Ctrl+R */ - InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); - inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK, false), "recompile"); - getRootPane().getActionMap().put("recompile", compileAction); - - pack(); - setLocationRelativeTo(parent); } /** @@ -472,11 +488,15 @@ public abstract class AbstractCompileDialog extends JDialog { throw new Exception("No compile commands specified"); } - SwingUtilities.invokeLater(new Runnable() { - public void run() { - setDialogState(DialogState.IS_COMPILING); - } - }); + if (SwingUtilities.isEventDispatchThread()) { + setDialogState(DialogState.IS_COMPILING); + } else { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + setDialogState(DialogState.IS_COMPILING); + } + }); + } createNewCompilationTab(taskOutput); /* Add abort compilation menu item */ @@ -542,6 +562,7 @@ public abstract class AbstractCompileDialog extends JDialog { ); } catch (Exception ex) { logger.fatal("Exception when compiling: " + ex.getMessage()); + taskOutput.addMessage(ex.getMessage(), MessageList.ERROR); ex.printStackTrace(); compilationFailureAction.actionPerformed(null); } @@ -698,8 +719,6 @@ public abstract class AbstractCompileDialog extends JDialog { } private Action defaultAction = new AbstractAction("Use default") { - private static final long serialVersionUID = 2874355910493988933L; - public void actionPerformed(ActionEvent e) { /* Unselect all */ for (Component c : moteIntfBox.getComponents()) { diff --git a/tools/cooja/java/se/sics/cooja/dialogs/ContikiMoteCompileDialog.java b/tools/cooja/java/se/sics/cooja/dialogs/ContikiMoteCompileDialog.java index 3be902ce8..d87a0a6b7 100644 --- a/tools/cooja/java/se/sics/cooja/dialogs/ContikiMoteCompileDialog.java +++ b/tools/cooja/java/se/sics/cooja/dialogs/ContikiMoteCompileDialog.java @@ -36,6 +36,7 @@ import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import javax.swing.BorderFactory; @@ -103,28 +104,7 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog { addAdvancedTab(tabbedPane); } - public boolean canLoadFirmware(File file) { - /* Disallow loading firmwares without compilation */ - /* - if (file.getName().endsWith(ContikiMoteType.librarySuffix)) { - return true; - } - */ - - return false; - } - - public String getDefaultCompileCommands(File source) { - if (moteType == null) { - /* Not ready to compile yet */ - return ""; - } - - if (source == null || !source.exists()) { - /* Not ready to compile yet */ - return ""; - } - + private void updateForSource(File source) { if (moteType.getIdentifier() == null) { /* Generate mote type identifier */ moteType.setIdentifier( @@ -152,7 +132,7 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog { if (((ContikiMoteType)moteType).javaClassName == null) { logger.fatal("Could not allocate a core communicator."); - return ""; + return; } /* Prepare compiler environment */ @@ -167,8 +147,8 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog { ((ContikiMoteType)moteType).javaClassName ); CompileContiki.redefineCOOJASources( - moteType, - env + moteType, + env ); String[] envOneDimension = new String[env.length]; @@ -184,6 +164,45 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog { e.printStackTrace(); env = null; } + } + + public boolean canLoadFirmware(File file) { + /* Disallow loading firmwares without compilation */ + /* + if (file.getName().endsWith(ContikiMoteType.librarySuffix)) { + return true; + } + */ + + return false; + } + + public String getDefaultCompileCommands(final File source) { + if (moteType == null) { + /* Not ready to compile yet */ + return ""; + } + + if (source == null || !source.exists()) { + /* Not ready to compile yet */ + return ""; + } + + if (SwingUtilities.isEventDispatchThread()) { + updateForSource(source); + } else { + try { + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + updateForSource(source); + } + }); + } catch (InvocationTargetException e) { + logger.fatal("Error when updating for source " + source + ": " + e.getMessage(), e); + } catch (InterruptedException e) { + logger.fatal("Error when updating for source " + source + ": " + e.getMessage(), e); + } + } String defines = ""; if (((ContikiMoteType) moteType).getNetworkStack().getHeaderFile() != null) { From 871ea380d05e139451926c34b4f832e0db596650 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 15 Aug 2013 11:49:48 +0200 Subject: [PATCH 21/26] only show printable characters in mote output plugin --- tools/cooja/java/se/sics/cooja/dialogs/SerialUI.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/cooja/java/se/sics/cooja/dialogs/SerialUI.java b/tools/cooja/java/se/sics/cooja/dialogs/SerialUI.java index edc88ff5c..f8eaea3cf 100644 --- a/tools/cooja/java/se/sics/cooja/dialogs/SerialUI.java +++ b/tools/cooja/java/se/sics/cooja/dialogs/SerialUI.java @@ -110,7 +110,8 @@ public abstract class SerialUI extends Log implements SerialPort { newMessage.append((char) data); if (newMessage.length() > MAX_LENGTH) { /*logger.warn("Dropping too large log message (>" + MAX_LENGTH + " bytes).");*/ - lastLogMessage = "# [1024 bytes binary data]"; + lastLogMessage = "# [1024 bytes, no line ending]: " + newMessage.substring(0, 20) + "..."; + lastLogMessage = lastLogMessage.replaceAll("[^\\p{Print}]", ""); newMessage.setLength(0); this.setChanged(); this.notifyObservers(getMote()); From 3caf1bfab49c42a2ec3cbfec103dd54e5e684598 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 15 Aug 2013 11:56:12 +0200 Subject: [PATCH 22/26] cooja motes rimestats --- platform/cooja/Makefile.cooja | 2 +- platform/cooja/contiki-conf.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/platform/cooja/Makefile.cooja b/platform/cooja/Makefile.cooja index 46f775a9b..d8fa83d63 100644 --- a/platform/cooja/Makefile.cooja +++ b/platform/cooja/Makefile.cooja @@ -47,7 +47,7 @@ CONTIKI_TARGET_DIRS = . dev lib sys cfs net # (COOJA_SOURCEDIRS contains additional sources dirs set from simulator) vpath %.c $(COOJA_SOURCEDIRS) -COOJA_BASE = simEnvChange.c cooja_mt.c cooja_mtarch.c rtimer-arch.c slip.c watchdog.c +COOJA_BASE = simEnvChange.c cooja_mt.c cooja_mtarch.c rtimer-arch.c slip.c watchdog.c rimestats.c COOJA_INTFS = beep.c button-sensor.c ip.c leds-arch.c moteid.c \ pir-sensor.c rs232.c vib-sensor.c \ diff --git a/platform/cooja/contiki-conf.h b/platform/cooja/contiki-conf.h index 769a27ba7..f3580327b 100644 --- a/platform/cooja/contiki-conf.h +++ b/platform/cooja/contiki-conf.h @@ -36,6 +36,8 @@ #define PROFILE_CONF_ON 0 #define ENERGEST_CONF_ON 0 #define LOG_CONF_ENABLED 1 +#define RIMESTATS_CONF_ON 1 +#define RIMESTATS_CONF_ENABLED 1 #define COOJA 1 From 8041f66d8c37c6bead5bcd3ee2acdbbd7fd1a1df Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 15 Aug 2013 14:32:35 +0200 Subject: [PATCH 23/26] link-layer acks support for cooja motes --- core/net/mac/nullrdc.c | 26 +++++++++++++++++++++----- platform/cooja/contiki-conf.h | 6 +++--- platform/cooja/dev/cooja-radio.c | 6 +++++- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/core/net/mac/nullrdc.c b/core/net/mac/nullrdc.c index ff367cf63..6d4117953 100644 --- a/core/net/mac/nullrdc.c +++ b/core/net/mac/nullrdc.c @@ -45,6 +45,10 @@ #include "net/rime/rimestats.h" #include +#if CONTIKI_TARGET_COOJA +#include "lib/simEnvChange.h" +#endif /* CONTIKI_TARGET_COOJA */ + #define DEBUG 0 #if DEBUG #include @@ -172,7 +176,12 @@ send_one_packet(mac_callback_t sent, void *ptr) /* Check for ack */ wt = RTIMER_NOW(); watchdog_periodic(); - while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)); + while(RTIMER_CLOCK_LT(RTIMER_NOW(), wt + ACK_WAIT_TIME)) { +#if CONTIKI_TARGET_COOJA + simProcessRunValue = 1; + cooja_mt_yield(); +#endif /* CONTIKI_TARGET_COOJA */ + } ret = MAC_TX_NOACK; if(NETSTACK_RADIO.receiving_packet() || @@ -181,10 +190,17 @@ send_one_packet(mac_callback_t sent, void *ptr) int len; uint8_t ackbuf[ACK_LEN]; - wt = RTIMER_NOW(); - watchdog_periodic(); - while(RTIMER_CLOCK_LT(RTIMER_NOW(), - wt + AFTER_ACK_DETECTED_WAIT_TIME)); + if(AFTER_ACK_DETECTED_WAIT_TIME > 0) { + wt = RTIMER_NOW(); + watchdog_periodic(); + while(RTIMER_CLOCK_LT(RTIMER_NOW(), + wt + AFTER_ACK_DETECTED_WAIT_TIME)) { + #if CONTIKI_TARGET_COOJA + simProcessRunValue = 1; + cooja_mt_yield(); + #endif /* CONTIKI_TARGET_COOJA */ + } + } if(NETSTACK_RADIO.pending_packet()) { len = NETSTACK_RADIO.read(ackbuf, ACK_LEN); diff --git a/platform/cooja/contiki-conf.h b/platform/cooja/contiki-conf.h index f3580327b..51ff18bfb 100644 --- a/platform/cooja/contiki-conf.h +++ b/platform/cooja/contiki-conf.h @@ -65,10 +65,10 @@ /* Default network config */ #if WITH_UIP6 -#define NULLRDC_CONF_802154_AUTOACK 0 -#define NULLRDC_CONF_SEND_802154_ACK 0 +#define NULLRDC_CONF_802154_AUTOACK 1 +#define NULLRDC_CONF_SEND_802154_ACK 1 #define NULLRDC_CONF_ACK_WAIT_TIME RTIMER_SECOND / 500 -#define NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME RTIMER_SECOND / 250 +#define NULLRDC_CONF_AFTER_ACK_DETECTED_WAIT_TIME 0 /* Network setup for IPv6 */ diff --git a/platform/cooja/dev/cooja-radio.c b/platform/cooja/dev/cooja-radio.c index e7cdce6dd..d30bf61c6 100644 --- a/platform/cooja/dev/cooja-radio.c +++ b/platform/cooja/dev/cooja-radio.c @@ -162,10 +162,14 @@ radio_send(const void *payload, unsigned short payload_len) { int radiostate = simRadioHWOn; - /* Simulate turnaround time of 1ms */ + /* Simulate turnaround time of 2ms for packets, 1ms for acks*/ #if WITH_TURNAROUND simProcessRunValue = 1; cooja_mt_yield(); + if(payload_len > 3) { + simProcessRunValue = 1; + cooja_mt_yield(); + } #endif /* WITH_TURNAROUND */ if(!simRadioHWOn) { From 7c125ced9a89bc19a1cbc64473b9e83592ab8c0a Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Fri, 16 Aug 2013 12:02:16 +0200 Subject: [PATCH 24/26] a set of new cooja-mspsim mote types --- .../thingsquare/cooja/mspsim/CC1101Radio.java | 422 ++++++++++++++++++ .../thingsquare/cooja/mspsim/CC1120Radio.java | 421 +++++++++++++++++ .../thingsquare/cooja/mspsim/CC2520Radio.java | 377 ++++++++++++++++ .../thingsquare/cooja/mspsim/CC430Mote.java | 76 ++++ .../cooja/mspsim/CC430MoteType.java | 215 +++++++++ .../thingsquare/cooja/mspsim/CC430Radio.java | 50 +++ .../thingsquare/cooja/mspsim/Eth1120Mote.java | 26 ++ .../cooja/mspsim/Eth1120MoteType.java | 169 +++++++ .../thingsquare/cooja/mspsim/Exp1101Mote.java | 26 ++ .../cooja/mspsim/Exp1101MoteType.java | 171 +++++++ .../thingsquare/cooja/mspsim/Exp1120Mote.java | 26 ++ .../cooja/mspsim/Exp1120MoteType.java | 171 +++++++ .../thingsquare/cooja/mspsim/Exp2420Mote.java | 26 ++ .../cooja/mspsim/Exp2420MoteType.java | 172 +++++++ .../cooja/mspsim/Trxeb1120Mote.java | 26 ++ .../cooja/mspsim/Trxeb1120MoteType.java | 169 +++++++ .../cooja/mspsim/Trxeb2520Mote.java | 26 ++ .../cooja/mspsim/Trxeb2520MoteType.java | 170 +++++++ .../thingsquare/cooja/mspsim/TrxebLEDs.java | 174 ++++++++ 19 files changed, 2913 insertions(+) create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1101Radio.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1120Radio.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC2520Radio.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Mote.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430MoteType.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Radio.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120Mote.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120MoteType.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101Mote.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101MoteType.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120Mote.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120MoteType.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420Mote.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420MoteType.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120Mote.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120MoteType.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520Mote.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520MoteType.java create mode 100644 tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/TrxebLEDs.java diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1101Radio.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1101Radio.java new file mode 100644 index 000000000..6aadc4936 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1101Radio.java @@ -0,0 +1,422 @@ +/* + * Copyright (c) 2012, Thingsquare. + * 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. + * + */ + +package com.thingsquare.cooja.mspsim; + +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.RadioPacket; +import se.sics.cooja.Simulation; +import se.sics.cooja.interfaces.CustomDataRadio; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.Radio; +import se.sics.cooja.mspmote.MspMote; +import se.sics.cooja.mspmote.MspMoteTimeEvent; +import se.sics.mspsim.chip.CC1101; +import se.sics.mspsim.chip.CC1101.ReceiverListener; +import se.sics.mspsim.chip.ChannelListener; +import se.sics.mspsim.chip.RFListener; +import se.sics.mspsim.chip.Radio802154; + +/** + * @author Fredrik Osterlind + */ +@ClassDescription("TI CC1101") +public class CC1101Radio extends Radio implements CustomDataRadio { + private static Logger logger = Logger.getLogger(CC1101Radio.class); + + /** + * Cross-level: + * Inter-byte delay for delivering cross-level packet bytes. + */ + public static final long DELAY_BETWEEN_BYTES = + (long) (1000.0*Simulation.MILLISECOND/(250000.0/8.0)); /* us. Corresponds to 250kbit/s */ + + private RadioEvent lastEvent = RadioEvent.UNKNOWN; + + private final MspMote mote; + private final CC1101 cc1101; + + private boolean isInterfered = false; + private boolean isTransmitting = false; + private boolean isReceiving = false; + + private byte lastOutgoingByte; + private byte lastIncomingByte; + + private RadioPacket lastOutgoingPacket = null; + private RadioPacket lastIncomingPacket = null; + + public CC1101Radio(Mote m) { + this.mote = (MspMote)m; + Radio802154 r = this.mote.getCPU().getChip(Radio802154.class); + if (r == null || !(r instanceof CC1101)) { + throw new IllegalStateException("Mote is not equipped with an CC1101 radio"); + } + this.cc1101 = (CC1101) r; + + cc1101.addRFListener(new RFListener() { + int len = 0; + int expLen = 0; + byte[] buffer = new byte[256 + 15]; + private boolean gotSynchbyte = false; + public void receivedByte(byte data) { + if (!isTransmitting()) { + /* Start transmission */ + lastEvent = RadioEvent.TRANSMISSION_STARTED; + isTransmitting = true; + len = 0; + gotSynchbyte = false; + /*logger.debug("----- CC1101 TRANSMISSION STARTED -----");*/ + setChanged(); + notifyObservers(); + } + if (len >= buffer.length) { + /* Bad size packet, too large */ + logger.debug("Error: bad size: " + len + ", dropping outgoing byte: " + data); + return; + } + + /* send this byte to all nodes */ + lastOutgoingByte = data; + lastEvent = RadioEvent.CUSTOM_DATA_TRANSMITTED; + setChanged(); + notifyObservers(); + + /* Await synch byte */ + if (!gotSynchbyte) { + if (lastOutgoingByte == CC1101.SYNCH_BYTE_LAST) { + gotSynchbyte = true; + } + return; + } + + final int HEADERLEN = 1; /* 1x Length byte */ + final int FOOTERLEN = 2; /* TODO Fix CRC in Mspsim's CC1101.java */ + if (len == 0) { + expLen = (0xff&data) + HEADERLEN + FOOTERLEN; + } + buffer[len++] = data; + + if (len == expLen) { + /*logger.debug("----- CC1101 CUSTOM DATA TRANSMITTED -----");*/ + + final byte[] buf = new byte[expLen]; + System.arraycopy(buffer, 0, buf, 0, expLen); + lastOutgoingPacket = new RadioPacket() { + public byte[] getPacketData() { + return buf; + } + }; + + lastEvent = RadioEvent.PACKET_TRANSMITTED; + /*logger.debug("----- CC1101 PACKET TRANSMITTED -----");*/ + setChanged(); + notifyObservers(); + + /*logger.debug("----- CC1101 TRANSMISSION FINISHED -----");*/ + isTransmitting = false; + lastEvent = RadioEvent.TRANSMISSION_FINISHED; + setChanged(); + notifyObservers(); + len = 0; + } + } + }); + + cc1101.setReceiverListener(new ReceiverListener() { + public void newState(boolean on) { + if (cc1101.isReadyToReceive()) { + lastEvent = RadioEvent.HW_ON; + setChanged(); + notifyObservers(); + } else { + radioOff(); + } + } + }); + + cc1101.addChannelListener(new ChannelListener() { + public void channelChanged(int channel) { + /* XXX Currently assumes zero channel switch time */ + lastEvent = RadioEvent.UNKNOWN; + setChanged(); + notifyObservers(); + } + }); + } + + private void radioOff() { + /* Radio was turned off during transmission. + * May for example happen if watchdog triggers */ + if (isTransmitting()) { + logger.warn("Turning off radio while transmitting, ending packet prematurely"); + + /* Simulate end of packet */ + lastOutgoingPacket = new RadioPacket() { + public byte[] getPacketData() { + return new byte[0]; + } + }; + + lastEvent = RadioEvent.PACKET_TRANSMITTED; + /*logger.debug("----- CC1101 PACKET TRANSMITTED -----");*/ + setChanged(); + notifyObservers(); + + /* Register that transmission ended in radio medium */ + /*logger.debug("----- CC1101 TRANSMISSION FINISHED -----");*/ + isTransmitting = false; + lastEvent = RadioEvent.TRANSMISSION_FINISHED; + setChanged(); + notifyObservers(); + } + + lastEvent = RadioEvent.HW_OFF; + setChanged(); + notifyObservers(); + } + + /* Packet radio support */ + public RadioPacket getLastPacketTransmitted() { + return lastOutgoingPacket; + } + + public RadioPacket getLastPacketReceived() { + return lastIncomingPacket; + } + + public void setReceivedPacket(RadioPacket packet) { + lastIncomingPacket = packet; + + /* TODO XXX Need support in CC1101.java */ + /*if (!radio.isReadyToReceive()) { + logger.warn("Radio receiver not ready, dropping packet data"); + return; + }*/ + + /* Delivering packet bytes with delays */ + byte[] packetData = packet.getPacketData(); + long deliveryTime = getMote().getSimulation().getSimulationTime(); + for (byte b: packetData) { + if (isInterfered()) { + b = (byte) 0xFF; + } + + final byte byteToDeliver = b; + getMote().getSimulation().scheduleEvent(new MspMoteTimeEvent(mote, 0) { + public void execute(long t) { + super.execute(t); + cc1101.receivedByte(byteToDeliver); + mote.requestImmediateWakeup(); + } + }, deliveryTime); + deliveryTime += DELAY_BETWEEN_BYTES; + } + } + + /* Custom data radio support */ + public Object getLastCustomDataTransmitted() { + return lastOutgoingByte; + } + + public Object getLastCustomDataReceived() { + return lastIncomingByte; + } + + public void receiveCustomData(Object data) { + if (!(data instanceof Byte)) { + logger.fatal("Bad custom data: " + data); + return; + } + lastIncomingByte = (Byte) data; + + final byte inputByte; + if (isInterfered()) { + inputByte = (byte)0xFF; + } else { + inputByte = lastIncomingByte; + } + mote.getSimulation().scheduleEvent(new MspMoteTimeEvent(mote, 0) { + public void execute(long t) { + super.execute(t); + cc1101.receivedByte(inputByte); + mote.requestImmediateWakeup(); + } + }, mote.getSimulation().getSimulationTime()); + + } + + /* General radio support */ + public boolean isTransmitting() { + return isTransmitting; + } + + public boolean isReceiving() { + return isReceiving; + } + + public boolean isInterfered() { + return isInterfered; + } + + public int getChannel() { + return cc1101.getActiveChannel(); + } + + public int getFrequency() { + return cc1101.getActiveFrequency(); + } + + public void signalReceptionStart() { + isReceiving = true; + + lastEvent = RadioEvent.RECEPTION_STARTED; + /*logger.debug("----- CC1101 RECEPTION STARTED -----");*/ + setChanged(); + notifyObservers(); + } + + public void signalReceptionEnd() { + /* Deliver packet data */ + isReceiving = false; + isInterfered = false; + + lastEvent = RadioEvent.RECEPTION_FINISHED; + /*logger.debug("----- CC1101 RECEPTION FINISHED -----");*/ + setChanged(); + notifyObservers(); + } + + public RadioEvent getLastEvent() { + return lastEvent; + } + + public void interfereAnyReception() { + isInterfered = true; + isReceiving = false; + lastIncomingPacket = null; + + lastEvent = RadioEvent.RECEPTION_INTERFERED; + /*logger.debug("----- CC1101 RECEPTION INTERFERED -----");*/ + setChanged(); + notifyObservers(); + } + + public double getCurrentOutputPower() { + /* TODO XXX Need support in CC1101.java */ + return 1; + } + public int getCurrentOutputPowerIndicator() { + /* TODO XXX Need support in CC1101.java */ + return 10; + } + public int getOutputPowerIndicatorMax() { + /* TODO XXX Need support in CC1101.java */ + return 10; + } + + + /** + * Last 8 received signal strengths + */ + double currentSignalStrength = 0; + private double[] rssiLast = new double[8]; + private int rssiLastCounter = 0; + + public double getCurrentSignalStrength() { + return currentSignalStrength; + } + + public void setCurrentSignalStrength(final double signalStrength) { + if (signalStrength == currentSignalStrength) { + return; /* ignored */ + } + currentSignalStrength = signalStrength; + if (rssiLastCounter == 0) { + getMote().getSimulation().scheduleEvent(new MspMoteTimeEvent(mote, 0) { + public void execute(long t) { + super.execute(t); + + /* Update average */ + System.arraycopy(rssiLast, 1, rssiLast, 0, 7); + rssiLast[7] = currentSignalStrength; + double avg = 0; + for (double v: rssiLast) { + avg += v; + } + avg /= rssiLast.length; + + cc1101.setRSSI((int) avg); + + rssiLastCounter--; + if (rssiLastCounter > 0) { + mote.getSimulation().scheduleEvent(this, t+DELAY_BETWEEN_BYTES/2); + } + } + }, mote.getSimulation().getSimulationTime()); + } + rssiLastCounter = 8; + } + + public Mote getMote() { + return mote; + } + + public Position getPosition() { + return mote.getInterfaces().getPosition(); + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML, boolean visAvailable) { + } + + public boolean isRadioOn() { + return cc1101.isReadyToReceive(); + } + + public boolean canReceiveFrom(CustomDataRadio radio) { + if (radio.getClass().equals(this.getClass())) { + return true; + } + if (radio.getClass().equals(CC430Radio.class)) { + return true; + } + return false; + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1120Radio.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1120Radio.java new file mode 100644 index 000000000..990d1ee8b --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1120Radio.java @@ -0,0 +1,421 @@ +/* + * Copyright (c) 2012, Thingsquare. + * 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. + * + */ + +package com.thingsquare.cooja.mspsim; + +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.RadioPacket; +import se.sics.cooja.Simulation; +import se.sics.cooja.interfaces.CustomDataRadio; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.Radio; +import se.sics.cooja.mspmote.MspMote; +import se.sics.cooja.mspmote.MspMoteTimeEvent; +import se.sics.mspsim.chip.CC1120; +import se.sics.mspsim.chip.CC1120.ReceiverListener; +import se.sics.mspsim.chip.ChannelListener; +import se.sics.mspsim.chip.RFListener; +import se.sics.mspsim.chip.Radio802154; + +/** + * @author Fredrik Osterlind + */ +@ClassDescription("TI CC1120") +public class CC1120Radio extends Radio implements CustomDataRadio { + private static Logger logger = Logger.getLogger(CC1120Radio.class); + + /** + * Cross-level: + * Inter-byte delay for delivering cross-level packet bytes. + */ + /* TODO XXX Fix me as well as symbol duration in CC1120.java */ + public static final long DELAY_BETWEEN_BYTES = + (long) (1000.0*Simulation.MILLISECOND/(200000.0/8.0)); /* us. Corresponds to 200kbit/s */ + + private RadioEvent lastEvent = RadioEvent.UNKNOWN; + + private final MspMote mote; + private final CC1120 cc1120; + + private boolean isInterfered = false; + private boolean isTransmitting = false; + private boolean isReceiving = false; + + private byte lastOutgoingByte; + private byte lastIncomingByte; + + private RadioPacket lastOutgoingPacket = null; + private RadioPacket lastIncomingPacket = null; + + public CC1120Radio(Mote m) { + this.mote = (MspMote)m; + Radio802154 r = this.mote.getCPU().getChip(Radio802154.class); + if (r == null || !(r instanceof CC1120)) { + throw new IllegalStateException("Mote is not equipped with an CC1120 radio"); + } + this.cc1120 = (CC1120) r; + + cc1120.addRFListener(new RFListener() { + int len = 0; + int expLen = 0; + byte[] buffer = new byte[256 + 15]; + private boolean gotSynchbyte = false; + public void receivedByte(byte data) { + if (!isTransmitting()) { + /* Start transmission */ + lastEvent = RadioEvent.TRANSMISSION_STARTED; + isTransmitting = true; + len = 0; + gotSynchbyte = false; + /*logger.debug("----- CCC1120 TRANSMISSION STARTED -----");*/ + setChanged(); + notifyObservers(); + } + if (len >= buffer.length) { + /* Bad size packet, too large */ + logger.debug("Error: bad size: " + len + ", dropping outgoing byte: " + data); + return; + } + + /* send this byte to all nodes */ + lastOutgoingByte = data; + lastEvent = RadioEvent.CUSTOM_DATA_TRANSMITTED; + setChanged(); + notifyObservers(); + + /* Await synch byte */ + if (!gotSynchbyte) { + if (lastOutgoingByte == CC1120.SYNCH_BYTE_LAST) { + gotSynchbyte = true; + } + return; + } + + final int HEADERLEN = 1; /* 1x Length byte */ + final int FOOTERLEN = 2; /* TODO Fix CRC in Mspsim's CCC1120.java */ + if (len == 0) { + expLen = (0xff&data) + HEADERLEN + FOOTERLEN; + } + buffer[len++] = data; + + if (len == expLen) { + /*logger.debug("----- CCC1120 CUSTOM DATA TRANSMITTED -----");*/ + + final byte[] buf = new byte[expLen]; + System.arraycopy(buffer, 0, buf, 0, expLen); + lastOutgoingPacket = new RadioPacket() { + public byte[] getPacketData() { + return buf; + } + }; + + lastEvent = RadioEvent.PACKET_TRANSMITTED; + /*logger.debug("----- CCC1120 PACKET TRANSMITTED -----");*/ + setChanged(); + notifyObservers(); + + /*logger.debug("----- CCC1120 TRANSMISSION FINISHED -----");*/ + isTransmitting = false; + lastEvent = RadioEvent.TRANSMISSION_FINISHED; + setChanged(); + notifyObservers(); + len = 0; + } + } + }); + + cc1120.setReceiverListener(new ReceiverListener() { + public void newState(boolean on) { + if (cc1120.isReadyToReceive()) { + lastEvent = RadioEvent.HW_ON; + setChanged(); + notifyObservers(); + } else { + radioOff(); + } + } + }); + + cc1120.addChannelListener(new ChannelListener() { + public void channelChanged(int channel) { + /* XXX Currently assumes zero channel switch time */ + lastEvent = RadioEvent.UNKNOWN; + setChanged(); + notifyObservers(); + } + }); + } + + private void radioOff() { + /* Radio was turned off during transmission. + * May for example happen if watchdog triggers */ + if (isTransmitting()) { + logger.warn("Turning off radio while transmitting, ending packet prematurely"); + + /* Simulate end of packet */ + lastOutgoingPacket = new RadioPacket() { + public byte[] getPacketData() { + return new byte[0]; + } + }; + + lastEvent = RadioEvent.PACKET_TRANSMITTED; + /*logger.debug("----- CCC1120 PACKET TRANSMITTED -----");*/ + setChanged(); + notifyObservers(); + + /* Register that transmission ended in radio medium */ + /*logger.debug("----- CCC1120 TRANSMISSION FINISHED -----");*/ + isTransmitting = false; + lastEvent = RadioEvent.TRANSMISSION_FINISHED; + setChanged(); + notifyObservers(); + } + + lastEvent = RadioEvent.HW_OFF; + setChanged(); + notifyObservers(); + } + + /* Packet radio support */ + public RadioPacket getLastPacketTransmitted() { + return lastOutgoingPacket; + } + + public RadioPacket getLastPacketReceived() { + return lastIncomingPacket; + } + + public void setReceivedPacket(RadioPacket packet) { + lastIncomingPacket = packet; + + /* TODO XXX Need support in CCC1120.java */ + /*if (!radio.isReadyToReceive()) { + logger.warn("Radio receiver not ready, dropping packet data"); + return; + }*/ + + /* Delivering packet bytes with delays */ + byte[] packetData = packet.getPacketData(); + long deliveryTime = getMote().getSimulation().getSimulationTime(); + for (byte b: packetData) { + if (isInterfered()) { + b = (byte) 0xFF; + } + + final byte byteToDeliver = b; + getMote().getSimulation().scheduleEvent(new MspMoteTimeEvent(mote, 0) { + public void execute(long t) { + super.execute(t); + cc1120.receivedByte(byteToDeliver); + mote.requestImmediateWakeup(); + } + }, deliveryTime); + deliveryTime += DELAY_BETWEEN_BYTES; + } + } + + /* Custom data radio support */ + public Object getLastCustomDataTransmitted() { + return lastOutgoingByte; + } + + public Object getLastCustomDataReceived() { + return lastIncomingByte; + } + + public void receiveCustomData(Object data) { + if (!(data instanceof Byte)) { + logger.fatal("Bad custom data: " + data); + return; + } + lastIncomingByte = (Byte) data; + + final byte inputByte; + if (isInterfered()) { + inputByte = (byte)0xFF; + } else { + inputByte = lastIncomingByte; + } + mote.getSimulation().scheduleEvent(new MspMoteTimeEvent(mote, 0) { + public void execute(long t) { + super.execute(t); + cc1120.receivedByte(inputByte); + mote.requestImmediateWakeup(); + } + }, mote.getSimulation().getSimulationTime()); + + } + + /* General radio support */ + public boolean isTransmitting() { + return isTransmitting; + } + + public boolean isReceiving() { + return isReceiving; + } + + public boolean isInterfered() { + return isInterfered; + } + + public int getChannel() { + return cc1120.getActiveChannel()+1000; + } + + public int getFrequency() { + return cc1120.getActiveFrequency(); + } + + public void signalReceptionStart() { + isReceiving = true; + + lastEvent = RadioEvent.RECEPTION_STARTED; + /*logger.debug("----- CCC1120 RECEPTION STARTED -----");*/ + setChanged(); + notifyObservers(); + } + + public void signalReceptionEnd() { + /* Deliver packet data */ + isReceiving = false; + isInterfered = false; + + lastEvent = RadioEvent.RECEPTION_FINISHED; + /*logger.debug("----- CCC1120 RECEPTION FINISHED -----");*/ + setChanged(); + notifyObservers(); + } + + public RadioEvent getLastEvent() { + return lastEvent; + } + + public void interfereAnyReception() { + isInterfered = true; + isReceiving = false; + lastIncomingPacket = null; + + lastEvent = RadioEvent.RECEPTION_INTERFERED; + /*logger.debug("----- CCC1120 RECEPTION INTERFERED -----");*/ + setChanged(); + notifyObservers(); + } + + public double getCurrentOutputPower() { + /* TODO XXX Need support in CCC1120.java */ + return 1; + } + public int getCurrentOutputPowerIndicator() { + /* TODO XXX Need support in CCC1120.java */ + return 10; + } + public int getOutputPowerIndicatorMax() { + /* TODO XXX Need support in CCC1120.java */ + return 10; + } + + + /** + * Last 8 received signal strengths + */ + double currentSignalStrength = 0; + private double[] rssiLast = new double[8]; + private int rssiLastCounter = 0; + + public double getCurrentSignalStrength() { + return currentSignalStrength; + } + + public void setCurrentSignalStrength(final double signalStrength) { + if (signalStrength == currentSignalStrength) { + return; /* ignored */ + } + currentSignalStrength = signalStrength; + if (rssiLastCounter == 0) { + getMote().getSimulation().scheduleEvent(new MspMoteTimeEvent(mote, 0) { + public void execute(long t) { + super.execute(t); + + /* Update average */ + System.arraycopy(rssiLast, 1, rssiLast, 0, 7); + rssiLast[7] = currentSignalStrength; + double avg = 0; + for (double v: rssiLast) { + avg += v; + } + avg /= rssiLast.length; + + cc1120.setRSSI((int) avg); + + rssiLastCounter--; + if (rssiLastCounter > 0) { + mote.getSimulation().scheduleEvent(this, t+DELAY_BETWEEN_BYTES/2); + } + } + }, mote.getSimulation().getSimulationTime()); + } + rssiLastCounter = 8; + } + + public Mote getMote() { + return mote; + } + + public Position getPosition() { + return mote.getInterfaces().getPosition(); + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML, boolean visAvailable) { + } + + public boolean isRadioOn() { + return cc1120.isReadyToReceive(); + } + + public boolean canReceiveFrom(CustomDataRadio radio) { + if (radio.getClass().equals(this.getClass())) { + return true; + } + return false; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC2520Radio.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC2520Radio.java new file mode 100644 index 000000000..9d7aa5185 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC2520Radio.java @@ -0,0 +1,377 @@ +package com.thingsquare.cooja.mspsim; + +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.RadioPacket; +import se.sics.cooja.Simulation; +import se.sics.cooja.interfaces.CustomDataRadio; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.Radio; +import se.sics.cooja.mspmote.MspMote; +import se.sics.cooja.mspmote.MspMoteTimeEvent; +import se.sics.cooja.mspmote.interfaces.CC2420RadioPacketConverter; +import se.sics.mspsim.chip.CC2520; +import se.sics.mspsim.chip.ChannelListener; +import se.sics.mspsim.chip.RFListener; +import se.sics.mspsim.core.Chip; +import se.sics.mspsim.core.OperatingModeListener; + +/** + * MSPSim CC2520 radio to COOJA wrapper. + * + * @author Fredrik Osterlind + */ +@ClassDescription("IEEE CC2520 Radio") +public class CC2520Radio extends Radio implements CustomDataRadio { + private static Logger logger = Logger.getLogger(CC2520Radio.class); + + /** + * Cross-level: + * Inter-byte delay for delivering cross-level packet bytes. + */ + public static final long DELAY_BETWEEN_BYTES = + (long) (1000.0*Simulation.MILLISECOND/(250000.0/8.0)); /* us. Corresponds to 250kbit/s */ + + private RadioEvent lastEvent = RadioEvent.UNKNOWN; + + private final MspMote mote; + private final CC2520 radio; + + private boolean isInterfered = false; + private boolean isTransmitting = false; + private boolean isReceiving = false; + + private byte lastOutgoingByte; + private byte lastIncomingByte; + + private RadioPacket lastOutgoingPacket = null; + private RadioPacket lastIncomingPacket = null; + + public CC2520Radio(Mote m) { + this.mote = (MspMote)m; + this.radio = this.mote.getCPU().getChip(CC2520.class); + if (radio == null) { + throw new IllegalStateException("Mote is not equipped with an IEEE CC2520 radio"); + } + + radio.addRFListener(new RFListener() { + int len = 0; + int expLen = 0; + byte[] buffer = new byte[127 + 15]; + public void receivedByte(byte data) { + if (!isTransmitting()) { + lastEvent = RadioEvent.TRANSMISSION_STARTED; + isTransmitting = true; + len = 0; + /*logger.debug("----- CC2520 TRANSMISSION STARTED -----");*/ + setChanged(); + notifyObservers(); + } + + if (len >= buffer.length) { + /* Bad size packet, too large */ + logger.debug("Error: bad size: " + len + ", dropping outgoing byte: " + data); + return; + } + + /* send this byte to all nodes */ + lastOutgoingByte = data; + lastEvent = RadioEvent.CUSTOM_DATA_TRANSMITTED; + setChanged(); + notifyObservers(); + + buffer[len++] = data; + + if (len == 6) { +// System.out.println("## CC2520 Packet of length: " + data + " expected..."); + expLen = data + 6; + } + + if (len == expLen) { + /*logger.debug("----- CC2520 CUSTOM DATA TRANSMITTED -----");*/ + len -= 4; /* preamble */ + len -= 1; /* synch */ + len -= radio.getFooterLength(); /* footer */ + final byte[] packetdata = new byte[len]; + System.arraycopy(buffer, 4+1, packetdata, 0, len); + lastOutgoingPacket = new RadioPacket() { + public byte[] getPacketData() { + return packetdata; + } + }; + + /*logger.debug("----- CC2520 PACKET TRANSMITTED -----");*/ + setChanged(); + notifyObservers(); + + /*logger.debug("----- CC2520 TRANSMISSION FINISHED -----");*/ + isTransmitting = false; + lastEvent = RadioEvent.TRANSMISSION_FINISHED; + setChanged(); + notifyObservers(); + len = 0; + } + } + }); + + radio.addOperatingModeListener(new OperatingModeListener() { + public void modeChanged(Chip source, int mode) { + if (radio.isReadyToReceive()) { + lastEvent = RadioEvent.HW_ON; + setChanged(); + notifyObservers(); + } else { + radioOff(); + } + } + }); + + radio.addChannelListener(new ChannelListener() { + public void channelChanged(int channel) { + /* XXX Currently assumes zero channel switch time */ + lastEvent = RadioEvent.UNKNOWN; + setChanged(); + notifyObservers(); + } + }); + } + + private void radioOff() { + /* Radio was turned off during transmission. + * May for example happen if watchdog triggers */ + if (isTransmitting()) { + logger.warn("Turning off radio while transmitting, ending packet prematurely"); + + /* Simulate end of packet */ + lastOutgoingPacket = new RadioPacket() { + public byte[] getPacketData() { + return new byte[0]; + } + }; + + lastEvent = RadioEvent.PACKET_TRANSMITTED; + /*logger.debug("----- CC2520 PACKET TRANSMITTED -----");*/ + setChanged(); + notifyObservers(); + + /* Register that transmission ended in radio medium */ + /*logger.debug("----- CC2520 TRANSMISSION FINISHED -----");*/ + isTransmitting = false; + lastEvent = RadioEvent.TRANSMISSION_FINISHED; + setChanged(); + notifyObservers(); + } + + lastEvent = RadioEvent.HW_OFF; + setChanged(); + notifyObservers(); + } + + /* Packet radio support */ + public RadioPacket getLastPacketTransmitted() { + return lastOutgoingPacket; + } + + public RadioPacket getLastPacketReceived() { + return lastIncomingPacket; + } + + public void setReceivedPacket(RadioPacket packet) { + logger.fatal("TODO Implement me!"); + } + + /* Custom data radio support */ + public Object getLastCustomDataTransmitted() { + return lastOutgoingByte; + } + + public Object getLastCustomDataReceived() { + return lastIncomingByte; + } + + public void receiveCustomData(Object data) { + if (!(data instanceof Byte)) { + logger.fatal("Bad custom data: " + data); + return; + } + lastIncomingByte = (Byte) data; + + final byte inputByte; + if (isInterfered()) { + inputByte = (byte)0xFF; + } else { + inputByte = lastIncomingByte; + } + mote.getSimulation().scheduleEvent(new MspMoteTimeEvent(mote, 0) { + public void execute(long t) { + super.execute(t); + radio.receivedByte(inputByte); + mote.requestImmediateWakeup(); + } + }, mote.getSimulation().getSimulationTime()); + + } + + /* General radio support */ + public boolean isTransmitting() { + return isTransmitting; + } + + public boolean isReceiving() { + return isReceiving; + } + + public boolean isInterfered() { + return isInterfered; + } + + public int getChannel() { + return radio.getActiveChannel(); + } + + public int getFrequency() { + return radio.getActiveFrequency(); + } + + public void signalReceptionStart() { + isReceiving = true; + + lastEvent = RadioEvent.RECEPTION_STARTED; + /*logger.debug("----- CC2520 RECEPTION STARTED -----");*/ + setChanged(); + notifyObservers(); + } + + public void signalReceptionEnd() { + /* Deliver packet data */ + isReceiving = false; + isInterfered = false; + + lastEvent = RadioEvent.RECEPTION_FINISHED; + /*logger.debug("----- CC2520 RECEPTION FINISHED -----");*/ + setChanged(); + notifyObservers(); + } + + public RadioEvent getLastEvent() { + return lastEvent; + } + + public void interfereAnyReception() { + isInterfered = true; + isReceiving = false; + lastIncomingPacket = null; + + lastEvent = RadioEvent.RECEPTION_INTERFERED; + /*logger.debug("----- CC2520 RECEPTION INTERFERED -----");*/ + setChanged(); + notifyObservers(); + } + + public double getCurrentOutputPower() { + return radio.getOutputPower(); + } + + public int getCurrentOutputPowerIndicator() { + return 100; +// return radio.getOutputPowerIndicator(); + } + + public int getOutputPowerIndicatorMax() { + return 100; +// return 31; + } + + double currentSignalStrength = 0; + + /** + * Last 8 received signal strengths + */ + private double[] rssiLast = new double[8]; + private int rssiLastCounter = 0; + + public double getCurrentSignalStrength() { + return currentSignalStrength; + } + + public void setCurrentSignalStrength(final double signalStrength) { + if (signalStrength == currentSignalStrength) { + return; /* ignored */ + } + currentSignalStrength = signalStrength; + if (rssiLastCounter == 0) { + getMote().getSimulation().scheduleEvent(new MspMoteTimeEvent(mote, 0) { + public void execute(long t) { + super.execute(t); + + /* Update average */ + System.arraycopy(rssiLast, 1, rssiLast, 0, 7); + rssiLast[7] = currentSignalStrength; + double avg = 0; + for (double v: rssiLast) { + avg += v; + } + avg /= rssiLast.length; + + radio.setRSSI((int) avg); + + rssiLastCounter--; + if (rssiLastCounter > 0) { + mote.getSimulation().scheduleEvent(this, t+DELAY_BETWEEN_BYTES/2); + } + } + }, mote.getSimulation().getSimulationTime()); + } + rssiLastCounter = 8; + } + + + public void setLQI(int lqi){ + radio.setLQI(lqi); + } + + public int getLQI(){ + return radio.getLQI(); + } + + + public Mote getMote() { + return mote; + } + + public Position getPosition() { + return mote.getInterfaces().getPosition(); + } + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML, boolean visAvailable) { + } + + public boolean isRadioOn() { + if (radio.isReadyToReceive()) { + return true; + } + if (radio.getMode() == CC2520.MODE_POWER_OFF) { + return false; + } + if (radio.getMode() == CC2520.MODE_TXRX_OFF) { + return false; + } + return true; + } + + public boolean canReceiveFrom(CustomDataRadio radio) { + if (radio.getClass().equals(this.getClass())) { + return true; + } + return false; + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Mote.java new file mode 100644 index 000000000..bdc0972ee --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Mote.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * 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 copyright holder 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + * + */ + +package com.thingsquare.cooja.mspsim; + +import java.io.File; + +import org.apache.log4j.Logger; + +import se.sics.cooja.Simulation; +import se.sics.cooja.mspmote.MspMote; +import se.sics.cooja.mspmote.MspMoteType; +import se.sics.mspsim.platform.ti.CC430Node; + +/** + * @author Fredrik Osterlind + */ +public class CC430Mote extends MspMote { + private static Logger logger = Logger.getLogger(CC430Mote.class); + + public CC430Node cc430Node = null; + + public CC430Mote(MspMoteType moteType, Simulation sim) { + super(moteType, sim); + } + + protected boolean initEmulator(File fileELF) { + try { + cc430Node = new CC430Node(); + registry = cc430Node.getRegistry(); + + prepareMote(fileELF, cc430Node); + } catch (Exception e) { + logger.fatal("Error when creating CC430 mote: ", e); + return false; + } + return true; + } + + public void idUpdated(int newID) { + logger.fatal("idUpdated(" + newID + ") ignored"); + } + + public String toString() { + return "CC430 " + getID(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430MoteType.java new file mode 100644 index 000000000..f07540341 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430MoteType.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2012, Thingsquare, http://www.thingsquare.com/. + * 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 copyright holder 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 COPYRIGHT HOLDERS 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 + * COPYRIGHT HOLDER 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. + * + */ + +package com.thingsquare.cooja.mspsim; + +import java.awt.Container; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.io.File; +import java.net.URL; + +import javax.swing.Icon; +import javax.swing.ImageIcon; + +import org.apache.log4j.Logger; + +import se.sics.cooja.AbstractionLevelDescription; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.GUI; +import se.sics.cooja.MoteInterface; +import se.sics.cooja.MoteType; +import se.sics.cooja.Simulation; +import se.sics.cooja.dialogs.CompileContiki; +import se.sics.cooja.dialogs.MessageList; +import se.sics.cooja.dialogs.MessageList.MessageContainer; +import se.sics.cooja.interfaces.IPAddress; +import se.sics.cooja.interfaces.Mote2MoteRelations; +import se.sics.cooja.interfaces.MoteAttributes; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.RimeAddress; +import se.sics.cooja.mspmote.MspCompileDialog; +import se.sics.cooja.mspmote.MspMote; +import se.sics.cooja.mspmote.MspMoteType; +import se.sics.cooja.mspmote.interfaces.MspClock; +import se.sics.cooja.mspmote.interfaces.MspDebugOutput; +import se.sics.cooja.mspmote.interfaces.MspMoteID; +import se.sics.cooja.mspmote.interfaces.UsciA0Serial; + +@ClassDescription("CC430 mote") +@AbstractionLevelDescription("Emulated level") +public class CC430MoteType extends MspMoteType { + private static Logger logger = Logger.getLogger(CC430MoteType.class); + + protected MspMote createMote(Simulation simulation) { + return new CC430Mote(this, simulation); + } + + public boolean configureAndInit(Container parentContainer, Simulation simulation, boolean visAvailable) + throws MoteTypeCreationException { + + /* If visualized, show compile dialog and let user configure */ + if (visAvailable) { + + /* Create unique identifier */ + if (getIdentifier() == null) { + int counter = 0; + boolean identifierOK = false; + while (!identifierOK) { + identifierOK = true; + + counter++; + setIdentifier("cc430-" + counter); + + for (MoteType existingMoteType : simulation.getMoteTypes()) { + if (existingMoteType == this) { + continue; + } + if (existingMoteType.getIdentifier().equals(getIdentifier())) { + identifierOK = false; + break; + } + } + } + } + + /* Create initial description */ + if (getDescription() == null) { + setDescription("CC430 Mote Type #" + getIdentifier()); + } + + return MspCompileDialog.showDialog(parentContainer, simulation, this, "cc430"); + } + + /* Not visualized: Compile Contiki immediately */ + if (getIdentifier() == null) { + throw new MoteTypeCreationException("No identifier"); + } + + final MessageList compilationOutput = new MessageList(); + + if (getCompileCommands() != null) { + /* Handle multiple compilation commands one by one */ + String[] arr = getCompileCommands().split("\n"); + for (String cmd: arr) { + if (cmd.trim().isEmpty()) { + continue; + } + + try { + CompileContiki.compile( + cmd, + null, + null /* Do not observe output firmware file */, + getContikiSourceFile().getParentFile(), + null, + null, + compilationOutput, + true + ); + } catch (Exception e) { + MoteTypeCreationException newException = + new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); + newException = (MoteTypeCreationException) newException.initCause(e); + newException.setCompilationOutput(compilationOutput); + + /* Print last 10 compilation errors to console */ + MessageContainer[] messages = compilationOutput.getMessages(); + for (int i=messages.length-10; i < messages.length; i++) { + if (i < 0) { + continue; + } + logger.fatal(">> " + messages[i]); + } + + logger.fatal("Compilation error: " + e.getMessage()); + throw newException; + } + } + } + + if (getContikiFirmwareFile() == null || + !getContikiFirmwareFile().exists()) { + throw new MoteTypeCreationException("Contiki firmware file does not exist: " + getContikiFirmwareFile()); + } + return true; + } + + public Icon getMoteTypeIcon() { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + URL imageURL = this.getClass().getClassLoader().getResource("images/cc430.jpg"); + Image image = toolkit.getImage(imageURL); + MediaTracker tracker = new MediaTracker(GUI.getTopParentContainer()); + tracker.addImage(image, 1); + try { + tracker.waitForAll(); + } catch (InterruptedException ex) { + } + if (image.getHeight(GUI.getTopParentContainer()) > 0 && image.getWidth(GUI.getTopParentContainer()) > 0) { + image = image.getScaledInstance((200*image.getWidth(GUI.getTopParentContainer())/image.getHeight(GUI.getTopParentContainer())), 200, Image.SCALE_DEFAULT); + return new ImageIcon(image); + } + + return null; + } + + public Class[] getDefaultMoteInterfaceClasses() { + return getAllMoteInterfaceClasses(); + } + public Class[] getAllMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspDebugOutput.class, + MspClock.class, + MspMoteID.class, + UsciA0Serial.class, + CC430Radio.class, + }; + } + + public File getExpectedFirmwareFile(File source) { + File parentDir = source.getParentFile(); + String sourceNoExtension = source.getName().substring(0, source.getName().length()-2); + + return new File(parentDir, sourceNoExtension + ".cc430"); + } + + protected String getTargetName() { + return "cc430"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Radio.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Radio.java new file mode 100644 index 000000000..7e8706598 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Radio.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, Thingsquare. + * 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. + * + */ + +package com.thingsquare.cooja.mspsim; + +import org.apache.log4j.Logger; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.interfaces.CustomDataRadio; + +/** + * @author Fredrik Osterlind + */ +@ClassDescription("TI CC1101 (CC430)") +public class CC430Radio extends CC1101Radio implements CustomDataRadio { + private static Logger logger = Logger.getLogger(CC1101Radio.class); + + public CC430Radio(Mote m) { + super(m); + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120Mote.java new file mode 100644 index 000000000..2f390aab3 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120Mote.java @@ -0,0 +1,26 @@ +package com.thingsquare.cooja.mspsim; + +import java.io.File; + +import se.sics.cooja.Simulation; +import se.sics.cooja.mspmote.Exp5438Mote; +import se.sics.cooja.mspmote.MspMoteType; + +/** + * @author Fredrik Osterlind + */ +public class Eth1120Mote extends Exp5438Mote { + private String desc = ""; + + public Eth1120Mote(MspMoteType moteType, Simulation sim) { + super(moteType, sim); + } + + protected boolean initEmulator(File fileELF) { + return super.initEmulator(fileELF); + } + + public String toString() { + return desc + " " + getID(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120MoteType.java new file mode 100644 index 000000000..af0d553db --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120MoteType.java @@ -0,0 +1,169 @@ +package com.thingsquare.cooja.mspsim; + +import java.awt.Container; +import java.io.File; + +import org.apache.log4j.Logger; + +import se.sics.cooja.AbstractionLevelDescription; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.MoteInterface; +import se.sics.cooja.MoteType; +import se.sics.cooja.Simulation; +import se.sics.cooja.dialogs.CompileContiki; +import se.sics.cooja.dialogs.MessageList; +import se.sics.cooja.dialogs.MessageList.MessageContainer; +import se.sics.cooja.interfaces.IPAddress; +import se.sics.cooja.interfaces.Mote2MoteRelations; +import se.sics.cooja.interfaces.MoteAttributes; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.RimeAddress; +import se.sics.cooja.mspmote.Exp5438MoteType; +import se.sics.cooja.mspmote.MspCompileDialog; +import se.sics.cooja.mspmote.interfaces.Msp802154Radio; +import se.sics.cooja.mspmote.interfaces.MspClock; +import se.sics.cooja.mspmote.interfaces.MspDebugOutput; +import se.sics.cooja.mspmote.interfaces.MspMoteID; +import se.sics.cooja.mspmote.interfaces.UsciA1Serial; + +@ClassDescription("Eth1120") +@AbstractionLevelDescription("Emulated level") +public class Eth1120MoteType extends Exp5438MoteType { + private static Logger logger = Logger.getLogger(Eth1120MoteType.class); + + public boolean configureAndInit(Container parentContainer, Simulation simulation, boolean visAvailable) + throws MoteTypeCreationException { + + /* If visualized, show compile dialog and let user configure */ + if (visAvailable) { + + /* Create unique identifier */ + if (getIdentifier() == null) { + int counter = 0; + boolean identifierOK = false; + while (!identifierOK) { + identifierOK = true; + + counter++; + setIdentifier("eth1120#" + counter); + + for (MoteType existingMoteType : simulation.getMoteTypes()) { + if (existingMoteType == this) { + continue; + } + if (existingMoteType.getIdentifier().equals(getIdentifier())) { + identifierOK = false; + break; + } + } + } + } + + /* Create initial description */ + if (getDescription() == null) { + setDescription("Ethb1120 Mote Type " + getIdentifier()); + } + + return MspCompileDialog.showDialog(parentContainer, simulation, this, "eth1120"); + } + + /* Not visualized: Compile Contiki immediately */ + if (getIdentifier() == null) { + throw new MoteTypeCreationException("No identifier"); + } + + final MessageList compilationOutput = new MessageList(); + + if (getCompileCommands() != null) { + /* Handle multiple compilation commands one by one */ + String[] arr = getCompileCommands().split("\n"); + for (String cmd: arr) { + if (cmd.trim().isEmpty()) { + continue; + } + + try { + CompileContiki.compile( + cmd, + null, + null /* Do not observe output firmware file */, + getContikiSourceFile().getParentFile(), + null, + null, + compilationOutput, + true + ); + } catch (Exception e) { + MoteTypeCreationException newException = + new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); + newException = (MoteTypeCreationException) newException.initCause(e); + newException.setCompilationOutput(compilationOutput); + + /* Print last 10 compilation errors to console */ + MessageContainer[] messages = compilationOutput.getMessages(); + for (int i=messages.length-10; i < messages.length; i++) { + if (i < 0) { + continue; + } + logger.fatal(">> " + messages[i]); + } + + logger.fatal("Compilation error: " + e.getMessage()); + throw newException; + } + } + } + + if (getContikiFirmwareFile() == null || + !getContikiFirmwareFile().exists()) { + throw new MoteTypeCreationException("Contiki firmware file does not exist: " + getContikiFirmwareFile()); + } + return true; + } + + public Class[] getDefaultMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + CC1120Radio.class, + UsciA1Serial.class, + TrxebLEDs.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + public Class[] getAllMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + Msp802154Radio.class, + CC1120Radio.class, + UsciA1Serial.class, + TrxebLEDs.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + + public File getExpectedFirmwareFile(File source) { + File parentDir = source.getParentFile(); + String sourceNoExtension = source.getName().substring(0, source.getName().length()-2); + + return new File(parentDir, sourceNoExtension + ".eth1120"); + } + + protected String getTargetName() { + return "eth1120"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101Mote.java new file mode 100644 index 000000000..bc91c223b --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101Mote.java @@ -0,0 +1,26 @@ +package com.thingsquare.cooja.mspsim; + +import java.io.File; + +import se.sics.cooja.Simulation; +import se.sics.cooja.mspmote.Exp5438Mote; +import se.sics.cooja.mspmote.MspMoteType; + +/** + * @author Fredrik Osterlind + */ +public class Exp1101Mote extends Exp5438Mote { + private String desc = ""; + + public Exp1101Mote(MspMoteType moteType, Simulation sim) { + super(moteType, sim); + } + + protected boolean initEmulator(File fileELF) { + return super.initEmulator(fileELF); + } + + public String toString() { + return desc + " " + getID(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101MoteType.java new file mode 100644 index 000000000..3ffdb9d05 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101MoteType.java @@ -0,0 +1,171 @@ +package com.thingsquare.cooja.mspsim; + +import java.awt.Container; +import java.io.File; + +import org.apache.log4j.Logger; + +import se.sics.cooja.AbstractionLevelDescription; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.MoteInterface; +import se.sics.cooja.MoteType; +import se.sics.cooja.Simulation; +import se.sics.cooja.dialogs.CompileContiki; +import se.sics.cooja.dialogs.MessageList; +import se.sics.cooja.dialogs.MessageList.MessageContainer; +import se.sics.cooja.interfaces.IPAddress; +import se.sics.cooja.interfaces.Mote2MoteRelations; +import se.sics.cooja.interfaces.MoteAttributes; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.RimeAddress; +import se.sics.cooja.mspmote.Exp5438MoteType; +import se.sics.cooja.mspmote.MspCompileDialog; +import se.sics.cooja.mspmote.interfaces.Exp5438LED; +import se.sics.cooja.mspmote.interfaces.Msp802154Radio; +import se.sics.cooja.mspmote.interfaces.MspClock; +import se.sics.cooja.mspmote.interfaces.MspDebugOutput; +import se.sics.cooja.mspmote.interfaces.MspMoteID; +import se.sics.cooja.mspmote.interfaces.UsciA1Serial; + +@ClassDescription("Exp1101 mote (MSP430F5438)") +@AbstractionLevelDescription("Emulated level") +public class Exp1101MoteType extends Exp5438MoteType { + private static Logger logger = Logger.getLogger(Exp1101MoteType.class); + + public boolean configureAndInit(Container parentContainer, Simulation simulation, boolean visAvailable) + throws MoteTypeCreationException { + + /* If visualized, show compile dialog and let user configure */ + if (visAvailable) { + + /* Create unique identifier */ + if (getIdentifier() == null) { + int counter = 0; + boolean identifierOK = false; + while (!identifierOK) { + identifierOK = true; + + counter++; + setIdentifier("exp1101#" + counter); + + for (MoteType existingMoteType : simulation.getMoteTypes()) { + if (existingMoteType == this) { + continue; + } + if (existingMoteType.getIdentifier().equals(getIdentifier())) { + identifierOK = false; + break; + } + } + } + } + + /* Create initial description */ + if (getDescription() == null) { + setDescription("Exp1101 Mote Type " + getIdentifier()); + } + + return MspCompileDialog.showDialog(parentContainer, simulation, this, "exp1101"); + } + + /* Not visualized: Compile Contiki immediately */ + if (getIdentifier() == null) { + throw new MoteTypeCreationException("No identifier"); + } + + final MessageList compilationOutput = new MessageList(); + + if (getCompileCommands() != null) { + /* Handle multiple compilation commands one by one */ + String[] arr = getCompileCommands().split("\n"); + for (String cmd: arr) { + if (cmd.trim().isEmpty()) { + continue; + } + + try { + CompileContiki.compile( + cmd, + null, + null /* Do not observe output firmware file */, + getContikiSourceFile().getParentFile(), + null, + null, + compilationOutput, + true + ); + } catch (Exception e) { + MoteTypeCreationException newException = + new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); + newException = (MoteTypeCreationException) newException.initCause(e); + newException.setCompilationOutput(compilationOutput); + + /* Print last 10 compilation errors to console */ + MessageContainer[] messages = compilationOutput.getMessages(); + for (int i=messages.length-10; i < messages.length; i++) { + if (i < 0) { + continue; + } + logger.fatal(">> " + messages[i]); + } + + logger.fatal("Compilation error: " + e.getMessage()); + throw newException; + } + } + } + + if (getContikiFirmwareFile() == null || + !getContikiFirmwareFile().exists()) { + throw new MoteTypeCreationException("Contiki firmware file does not exist: " + getContikiFirmwareFile()); + } + return true; + } + + public Class[] getDefaultMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + CC1101Radio.class, + UsciA1Serial.class, + Exp5438LED.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + public Class[] getAllMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + Msp802154Radio.class, + CC1101Radio.class, + CC1101Radio.class, + UsciA1Serial.class, + Exp5438LED.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + + public File getExpectedFirmwareFile(File source) { + File parentDir = source.getParentFile(); + String sourceNoExtension = source.getName().substring(0, source.getName().length()-2); + + return new File(parentDir, sourceNoExtension + ".exp1101"); + } + + protected String getTargetName() { + return "exp1101"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120Mote.java new file mode 100644 index 000000000..94e78233e --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120Mote.java @@ -0,0 +1,26 @@ +package com.thingsquare.cooja.mspsim; + +import java.io.File; + +import se.sics.cooja.Simulation; +import se.sics.cooja.mspmote.Exp5438Mote; +import se.sics.cooja.mspmote.MspMoteType; + +/** + * @author Fredrik Osterlind + */ +public class Exp1120Mote extends Exp5438Mote { + private String desc = ""; + + public Exp1120Mote(MspMoteType moteType, Simulation sim) { + super(moteType, sim); + } + + protected boolean initEmulator(File fileELF) { + return super.initEmulator(fileELF); + } + + public String toString() { + return desc + " " + getID(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120MoteType.java new file mode 100644 index 000000000..fce599a34 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120MoteType.java @@ -0,0 +1,171 @@ +package com.thingsquare.cooja.mspsim; + +import java.awt.Container; +import java.io.File; + +import org.apache.log4j.Logger; + +import se.sics.cooja.AbstractionLevelDescription; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.MoteInterface; +import se.sics.cooja.MoteType; +import se.sics.cooja.Simulation; +import se.sics.cooja.dialogs.CompileContiki; +import se.sics.cooja.dialogs.MessageList; +import se.sics.cooja.dialogs.MessageList.MessageContainer; +import se.sics.cooja.interfaces.IPAddress; +import se.sics.cooja.interfaces.Mote2MoteRelations; +import se.sics.cooja.interfaces.MoteAttributes; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.RimeAddress; +import se.sics.cooja.mspmote.Exp5438MoteType; +import se.sics.cooja.mspmote.MspCompileDialog; +import se.sics.cooja.mspmote.interfaces.Exp5438LED; +import se.sics.cooja.mspmote.interfaces.Msp802154Radio; +import se.sics.cooja.mspmote.interfaces.MspClock; +import se.sics.cooja.mspmote.interfaces.MspDebugOutput; +import se.sics.cooja.mspmote.interfaces.MspMoteID; +import se.sics.cooja.mspmote.interfaces.UsciA1Serial; + +@ClassDescription("Exp1120 mote (MSP430F5438)") +@AbstractionLevelDescription("Emulated level") +public class Exp1120MoteType extends Exp5438MoteType { + private static Logger logger = Logger.getLogger(Exp1120MoteType.class); + + public boolean configureAndInit(Container parentContainer, Simulation simulation, boolean visAvailable) + throws MoteTypeCreationException { + + /* If visualized, show compile dialog and let user configure */ + if (visAvailable) { + + /* Create unique identifier */ + if (getIdentifier() == null) { + int counter = 0; + boolean identifierOK = false; + while (!identifierOK) { + identifierOK = true; + + counter++; + setIdentifier("exp1120#" + counter); + + for (MoteType existingMoteType : simulation.getMoteTypes()) { + if (existingMoteType == this) { + continue; + } + if (existingMoteType.getIdentifier().equals(getIdentifier())) { + identifierOK = false; + break; + } + } + } + } + + /* Create initial description */ + if (getDescription() == null) { + setDescription("Exp1120 Mote Type " + getIdentifier()); + } + + return MspCompileDialog.showDialog(parentContainer, simulation, this, "exp1120"); + } + + /* Not visualized: Compile Contiki immediately */ + if (getIdentifier() == null) { + throw new MoteTypeCreationException("No identifier"); + } + + final MessageList compilationOutput = new MessageList(); + + if (getCompileCommands() != null) { + /* Handle multiple compilation commands one by one */ + String[] arr = getCompileCommands().split("\n"); + for (String cmd: arr) { + if (cmd.trim().isEmpty()) { + continue; + } + + try { + CompileContiki.compile( + cmd, + null, + null /* Do not observe output firmware file */, + getContikiSourceFile().getParentFile(), + null, + null, + compilationOutput, + true + ); + } catch (Exception e) { + MoteTypeCreationException newException = + new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); + newException = (MoteTypeCreationException) newException.initCause(e); + newException.setCompilationOutput(compilationOutput); + + /* Print last 10 compilation errors to console */ + MessageContainer[] messages = compilationOutput.getMessages(); + for (int i=messages.length-10; i < messages.length; i++) { + if (i < 0) { + continue; + } + logger.fatal(">> " + messages[i]); + } + + logger.fatal("Compilation error: " + e.getMessage()); + throw newException; + } + } + } + + if (getContikiFirmwareFile() == null || + !getContikiFirmwareFile().exists()) { + throw new MoteTypeCreationException("Contiki firmware file does not exist: " + getContikiFirmwareFile()); + } + return true; + } + + public Class[] getDefaultMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + CC1120Radio.class, + UsciA1Serial.class, + Exp5438LED.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + public Class[] getAllMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + Msp802154Radio.class, + CC1101Radio.class, + CC1120Radio.class, + UsciA1Serial.class, + Exp5438LED.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + + public File getExpectedFirmwareFile(File source) { + File parentDir = source.getParentFile(); + String sourceNoExtension = source.getName().substring(0, source.getName().length()-2); + + return new File(parentDir, sourceNoExtension + ".exp1120"); + } + + protected String getTargetName() { + return "exp1120"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420Mote.java new file mode 100644 index 000000000..6f084b8f9 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420Mote.java @@ -0,0 +1,26 @@ +package com.thingsquare.cooja.mspsim; + +import java.io.File; + +import se.sics.cooja.Simulation; +import se.sics.cooja.mspmote.Exp5438Mote; +import se.sics.cooja.mspmote.MspMoteType; + +/** + * @author Fredrik Osterlind + */ +public class Exp2420Mote extends Exp5438Mote { + private String desc = ""; + + public Exp2420Mote(MspMoteType moteType, Simulation sim) { + super(moteType, sim); + } + + protected boolean initEmulator(File fileELF) { + return super.initEmulator(fileELF); + } + + public String toString() { + return desc + " " + getID(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420MoteType.java new file mode 100644 index 000000000..9424eceac --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420MoteType.java @@ -0,0 +1,172 @@ +package com.thingsquare.cooja.mspsim; + +import java.awt.Container; +import java.io.File; + +import org.apache.log4j.Logger; + +import se.sics.cooja.AbstractionLevelDescription; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.MoteInterface; +import se.sics.cooja.MoteType; +import se.sics.cooja.Simulation; +import se.sics.cooja.dialogs.CompileContiki; +import se.sics.cooja.dialogs.MessageList; +import se.sics.cooja.dialogs.MessageList.MessageContainer; +import se.sics.cooja.interfaces.IPAddress; +import se.sics.cooja.interfaces.Mote2MoteRelations; +import se.sics.cooja.interfaces.MoteAttributes; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.RimeAddress; +import se.sics.cooja.mspmote.Exp5438MoteType; +import se.sics.cooja.mspmote.MspCompileDialog; +import se.sics.cooja.mspmote.interfaces.Exp5438LED; +import se.sics.cooja.mspmote.interfaces.Msp802154Radio; +import se.sics.cooja.mspmote.interfaces.MspClock; +import se.sics.cooja.mspmote.interfaces.MspDebugOutput; +import se.sics.cooja.mspmote.interfaces.MspMoteID; +import se.sics.cooja.mspmote.interfaces.UsciA1Serial; + +@ClassDescription("Exp2420 mote (MSP430F5438)") +@AbstractionLevelDescription("Emulated level") +public class Exp2420MoteType extends Exp5438MoteType { + private static Logger logger = Logger.getLogger(Exp2420MoteType.class); + + public boolean configureAndInit(Container parentContainer, Simulation simulation, boolean visAvailable) + throws MoteTypeCreationException { + + /* If visualized, show compile dialog and let user configure */ + if (visAvailable) { + + /* Create unique identifier */ + if (getIdentifier() == null) { + int counter = 0; + boolean identifierOK = false; + while (!identifierOK) { + identifierOK = true; + + counter++; + setIdentifier("exp2420#" + counter); + + for (MoteType existingMoteType : simulation.getMoteTypes()) { + if (existingMoteType == this) { + continue; + } + if (existingMoteType.getIdentifier().equals(getIdentifier())) { + identifierOK = false; + break; + } + } + } + } + + /* Create initial description */ + if (getDescription() == null) { + setDescription("Exp2420 Mote Type " + getIdentifier()); + } + + return MspCompileDialog.showDialog(parentContainer, simulation, this, "exp2420"); + } + + /* Not visualized: Compile Contiki immediately */ + if (getIdentifier() == null) { + throw new MoteTypeCreationException("No identifier"); + } + + final MessageList compilationOutput = new MessageList(); + + if (getCompileCommands() != null) { + /* Handle multiple compilation commands one by one */ + String[] arr = getCompileCommands().split("\n"); + for (String cmd: arr) { + if (cmd.trim().isEmpty()) { + continue; + } + + try { + CompileContiki.compile( + cmd, + null, + null /* Do not observe output firmware file */, + getContikiSourceFile().getParentFile(), + null, + null, + compilationOutput, + true + ); + } catch (Exception e) { + MoteTypeCreationException newException = + new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); + newException = (MoteTypeCreationException) newException.initCause(e); + newException.setCompilationOutput(compilationOutput); + + /* Print last 10 compilation errors to console */ + MessageContainer[] messages = compilationOutput.getMessages(); + for (int i=messages.length-10; i < messages.length; i++) { + if (i < 0) { + continue; + } + logger.fatal(">> " + messages[i]); + } + + logger.fatal("Compilation error: " + e.getMessage()); + throw newException; + } + } + } + + if (getContikiFirmwareFile() == null || + !getContikiFirmwareFile().exists()) { + throw new MoteTypeCreationException("Contiki firmware file does not exist: " + getContikiFirmwareFile()); + } + return true; + } + + public Class[] getDefaultMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + Msp802154Radio.class, + UsciA1Serial.class, + Exp5438LED.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + public Class[] getAllMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + Msp802154Radio.class, + CC1101Radio.class, + CC1120Radio.class, + Msp802154Radio.class, + UsciA1Serial.class, + Exp5438LED.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + + public File getExpectedFirmwareFile(File source) { + File parentDir = source.getParentFile(); + String sourceNoExtension = source.getName().substring(0, source.getName().length()-2); + + return new File(parentDir, sourceNoExtension + ".exp2420"); + } + + protected String getTargetName() { + return "exp2420"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120Mote.java new file mode 100644 index 000000000..ad39af355 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120Mote.java @@ -0,0 +1,26 @@ +package com.thingsquare.cooja.mspsim; + +import java.io.File; + +import se.sics.cooja.Simulation; +import se.sics.cooja.mspmote.Exp5438Mote; +import se.sics.cooja.mspmote.MspMoteType; + +/** + * @author Fredrik Osterlind + */ +public class Trxeb1120Mote extends Exp5438Mote { + private String desc = ""; + + public Trxeb1120Mote(MspMoteType moteType, Simulation sim) { + super(moteType, sim); + } + + protected boolean initEmulator(File fileELF) { + return super.initEmulator(fileELF); + } + + public String toString() { + return desc + " " + getID(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120MoteType.java new file mode 100644 index 000000000..c7592be13 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120MoteType.java @@ -0,0 +1,169 @@ +package com.thingsquare.cooja.mspsim; + +import java.awt.Container; +import java.io.File; + +import org.apache.log4j.Logger; + +import se.sics.cooja.AbstractionLevelDescription; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.MoteInterface; +import se.sics.cooja.MoteType; +import se.sics.cooja.Simulation; +import se.sics.cooja.dialogs.CompileContiki; +import se.sics.cooja.dialogs.MessageList; +import se.sics.cooja.dialogs.MessageList.MessageContainer; +import se.sics.cooja.interfaces.IPAddress; +import se.sics.cooja.interfaces.Mote2MoteRelations; +import se.sics.cooja.interfaces.MoteAttributes; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.RimeAddress; +import se.sics.cooja.mspmote.Exp5438MoteType; +import se.sics.cooja.mspmote.MspCompileDialog; +import se.sics.cooja.mspmote.interfaces.Msp802154Radio; +import se.sics.cooja.mspmote.interfaces.MspClock; +import se.sics.cooja.mspmote.interfaces.MspDebugOutput; +import se.sics.cooja.mspmote.interfaces.MspMoteID; +import se.sics.cooja.mspmote.interfaces.UsciA1Serial; + +@ClassDescription("Trxeb1120") +@AbstractionLevelDescription("Emulated level") +public class Trxeb1120MoteType extends Exp5438MoteType { + private static Logger logger = Logger.getLogger(Trxeb1120MoteType.class); + + public boolean configureAndInit(Container parentContainer, Simulation simulation, boolean visAvailable) + throws MoteTypeCreationException { + + /* If visualized, show compile dialog and let user configure */ + if (visAvailable) { + + /* Create unique identifier */ + if (getIdentifier() == null) { + int counter = 0; + boolean identifierOK = false; + while (!identifierOK) { + identifierOK = true; + + counter++; + setIdentifier("trxeb1120#" + counter); + + for (MoteType existingMoteType : simulation.getMoteTypes()) { + if (existingMoteType == this) { + continue; + } + if (existingMoteType.getIdentifier().equals(getIdentifier())) { + identifierOK = false; + break; + } + } + } + } + + /* Create initial description */ + if (getDescription() == null) { + setDescription("Trxeb1120 Mote Type " + getIdentifier()); + } + + return MspCompileDialog.showDialog(parentContainer, simulation, this, "trxeb1120"); + } + + /* Not visualized: Compile Contiki immediately */ + if (getIdentifier() == null) { + throw new MoteTypeCreationException("No identifier"); + } + + final MessageList compilationOutput = new MessageList(); + + if (getCompileCommands() != null) { + /* Handle multiple compilation commands one by one */ + String[] arr = getCompileCommands().split("\n"); + for (String cmd: arr) { + if (cmd.trim().isEmpty()) { + continue; + } + + try { + CompileContiki.compile( + cmd, + null, + null /* Do not observe output firmware file */, + getContikiSourceFile().getParentFile(), + null, + null, + compilationOutput, + true + ); + } catch (Exception e) { + MoteTypeCreationException newException = + new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); + newException = (MoteTypeCreationException) newException.initCause(e); + newException.setCompilationOutput(compilationOutput); + + /* Print last 10 compilation errors to console */ + MessageContainer[] messages = compilationOutput.getMessages(); + for (int i=messages.length-10; i < messages.length; i++) { + if (i < 0) { + continue; + } + logger.fatal(">> " + messages[i]); + } + + logger.fatal("Compilation error: " + e.getMessage()); + throw newException; + } + } + } + + if (getContikiFirmwareFile() == null || + !getContikiFirmwareFile().exists()) { + throw new MoteTypeCreationException("Contiki firmware file does not exist: " + getContikiFirmwareFile()); + } + return true; + } + + public Class[] getDefaultMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + CC1120Radio.class, + UsciA1Serial.class, + TrxebLEDs.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + public Class[] getAllMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + Msp802154Radio.class, + CC1120Radio.class, + UsciA1Serial.class, + TrxebLEDs.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + + public File getExpectedFirmwareFile(File source) { + File parentDir = source.getParentFile(); + String sourceNoExtension = source.getName().substring(0, source.getName().length()-2); + + return new File(parentDir, sourceNoExtension + ".trxeb1120"); + } + + protected String getTargetName() { + return "trxeb1120"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520Mote.java new file mode 100644 index 000000000..5e9036594 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520Mote.java @@ -0,0 +1,26 @@ +package com.thingsquare.cooja.mspsim; + +import java.io.File; + +import se.sics.cooja.Simulation; +import se.sics.cooja.mspmote.Exp5438Mote; +import se.sics.cooja.mspmote.MspMoteType; + +/** + * @author Fredrik Osterlind + */ +public class Trxeb2520Mote extends Exp5438Mote { + private String desc = ""; + + public Trxeb2520Mote(MspMoteType moteType, Simulation sim) { + super(moteType, sim); + } + + protected boolean initEmulator(File fileELF) { + return super.initEmulator(fileELF); + } + + public String toString() { + return desc + " " + getID(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520MoteType.java new file mode 100644 index 000000000..6ba84a2ad --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520MoteType.java @@ -0,0 +1,170 @@ +package com.thingsquare.cooja.mspsim; + +import java.awt.Container; +import java.io.File; + +import org.apache.log4j.Logger; + +import se.sics.cooja.AbstractionLevelDescription; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.MoteInterface; +import se.sics.cooja.MoteType; +import se.sics.cooja.Simulation; +import se.sics.cooja.dialogs.CompileContiki; +import se.sics.cooja.dialogs.MessageList; +import se.sics.cooja.dialogs.MessageList.MessageContainer; +import se.sics.cooja.interfaces.IPAddress; +import se.sics.cooja.interfaces.Mote2MoteRelations; +import se.sics.cooja.interfaces.MoteAttributes; +import se.sics.cooja.interfaces.Position; +import se.sics.cooja.interfaces.RimeAddress; +import se.sics.cooja.mspmote.Exp5438MoteType; +import se.sics.cooja.mspmote.MspCompileDialog; +import se.sics.cooja.mspmote.interfaces.Exp5438LED; +import se.sics.cooja.mspmote.interfaces.Msp802154Radio; +import se.sics.cooja.mspmote.interfaces.MspClock; +import se.sics.cooja.mspmote.interfaces.MspDebugOutput; +import se.sics.cooja.mspmote.interfaces.MspMoteID; +import se.sics.cooja.mspmote.interfaces.UsciA1Serial; + +@ClassDescription("Trxeb2520") +@AbstractionLevelDescription("Emulated level") +public class Trxeb2520MoteType extends Exp5438MoteType { + private static Logger logger = Logger.getLogger(Trxeb2520MoteType.class); + + public boolean configureAndInit(Container parentContainer, Simulation simulation, boolean visAvailable) + throws MoteTypeCreationException { + + /* If visualized, show compile dialog and let user configure */ + if (visAvailable) { + + /* Create unique identifier */ + if (getIdentifier() == null) { + int counter = 0; + boolean identifierOK = false; + while (!identifierOK) { + identifierOK = true; + + counter++; + setIdentifier("trxeb2520#" + counter); + + for (MoteType existingMoteType : simulation.getMoteTypes()) { + if (existingMoteType == this) { + continue; + } + if (existingMoteType.getIdentifier().equals(getIdentifier())) { + identifierOK = false; + break; + } + } + } + } + + /* Create initial description */ + if (getDescription() == null) { + setDescription("Trxeb2520 Mote Type " + getIdentifier()); + } + + return MspCompileDialog.showDialog(parentContainer, simulation, this, "trxeb2520"); + } + + /* Not visualized: Compile Contiki immediately */ + if (getIdentifier() == null) { + throw new MoteTypeCreationException("No identifier"); + } + + final MessageList compilationOutput = new MessageList(); + + if (getCompileCommands() != null) { + /* Handle multiple compilation commands one by one */ + String[] arr = getCompileCommands().split("\n"); + for (String cmd: arr) { + if (cmd.trim().isEmpty()) { + continue; + } + + try { + CompileContiki.compile( + cmd, + null, + null /* Do not observe output firmware file */, + getContikiSourceFile().getParentFile(), + null, + null, + compilationOutput, + true + ); + } catch (Exception e) { + MoteTypeCreationException newException = + new MoteTypeCreationException("Mote type creation failed: " + e.getMessage()); + newException = (MoteTypeCreationException) newException.initCause(e); + newException.setCompilationOutput(compilationOutput); + + /* Print last 10 compilation errors to console */ + MessageContainer[] messages = compilationOutput.getMessages(); + for (int i=messages.length-10; i < messages.length; i++) { + if (i < 0) { + continue; + } + logger.fatal(">> " + messages[i]); + } + + logger.fatal("Compilation error: " + e.getMessage()); + throw newException; + } + } + } + + if (getContikiFirmwareFile() == null || + !getContikiFirmwareFile().exists()) { + throw new MoteTypeCreationException("Contiki firmware file does not exist: " + getContikiFirmwareFile()); + } + return true; + } + + public Class[] getDefaultMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + CC2520Radio.class, + UsciA1Serial.class, + TrxebLEDs.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + public Class[] getAllMoteInterfaceClasses() { + return new Class[] { + Position.class, + RimeAddress.class, + IPAddress.class, + Mote2MoteRelations.class, + MoteAttributes.class, + MspClock.class, + MspMoteID.class, + Msp802154Radio.class, + CC2520Radio.class, + UsciA1Serial.class, + TrxebLEDs.class, + /*Exp5438LCD.class,*/ /* TODO */ + MspDebugOutput.class + }; + } + + public File getExpectedFirmwareFile(File source) { + File parentDir = source.getParentFile(); + String sourceNoExtension = source.getName().substring(0, source.getName().length()-2); + + return new File(parentDir, sourceNoExtension + ".trxeb2520"); + } + + protected String getTargetName() { + return "trxeb2520"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/TrxebLEDs.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/TrxebLEDs.java new file mode 100644 index 000000000..63051195e --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/TrxebLEDs.java @@ -0,0 +1,174 @@ +package com.thingsquare.cooja.mspsim; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.util.Collection; +import java.util.Observable; +import java.util.Observer; + +import javax.swing.JPanel; + +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.cooja.ClassDescription; +import se.sics.cooja.Mote; +import se.sics.cooja.interfaces.LED; +import se.sics.cooja.mspmote.Exp5438Mote; +import se.sics.mspsim.core.IOPort; +import se.sics.mspsim.core.IOUnit; +import se.sics.mspsim.core.PortListener; + +/** + * @author Fredrik Osterlind + */ +@ClassDescription("Trxeb LEDs") +public class TrxebLEDs extends LED { + private static Logger logger = Logger.getLogger(TrxebLEDs.class); + + private Exp5438Mote mspMote; + + private boolean redOn = false; + private boolean yellowOn = false; + private boolean greenOn = false; + private boolean blueOn = false; + + private static final Color RED = new Color(255, 0, 0); + private static final Color DARK_RED = new Color(100, 0, 0); + private static final Color YELLOW = new Color(255, 255, 0); + private static final Color DARK_YELLOW = new Color(184,134,11); + private static final Color GREEN = new Color(0, 255, 0); + private static final Color DARK_GREEN = new Color(0, 100, 0); + private static final Color BLUE = new Color(0, 0, 255); + private static final Color DARK_BLUE = new Color(0, 0, 100); + + public TrxebLEDs(Mote mote) { + mspMote = (Exp5438Mote) mote; + + IOUnit unit = mspMote.getCPU().getIOUnit("P4"); + if (unit instanceof IOPort) { + ((IOPort) unit).addPortListener(new PortListener() { + public void portWrite(IOPort source, int data) { + redOn = (data & (1<<0)) == 0; + yellowOn = (data & (1<<1)) == 0; + greenOn = (data & (1<<2)) == 0; + blueOn = (data & (1<<3)) == 0; + setChanged(); + notifyObservers(); + } + }); + } + } + + public boolean isAnyOn() { + return redOn || yellowOn || greenOn || blueOn; + } + + public boolean isGreenOn() { + return greenOn; + } + + public boolean isRedOn() { + return redOn; + } + + public boolean isYellowOn() { + return yellowOn; + } + + public boolean isBlueOn() { + return blueOn; + } + + public JPanel getInterfaceVisualizer() { + final JPanel panel = new JPanel() { + private static final long serialVersionUID = 1L; + public void paintComponent(Graphics g) { + super.paintComponent(g); + + int x = 20; + int y = 25; + int d = 25; + + if (isRedOn()) { + g.setColor(RED); + g.fillOval(x, y, d, d); + g.setColor(Color.BLACK); + g.drawOval(x, y, d, d); + } else { + g.setColor(DARK_RED); + g.fillOval(x + 5, y + 5, d-10, d-10); + } + + x += 40; + + if (isYellowOn()) { + g.setColor(YELLOW); + g.fillOval(x, y, d, d); + g.setColor(Color.BLACK); + g.drawOval(x, y, d, d); + } else { + g.setColor(DARK_YELLOW); + g.fillOval(x + 5, y + 5, d-10, d-10); + } + + x += 40; + + if (isGreenOn()) { + g.setColor(GREEN); + g.fillOval(x, y, d, d); + g.setColor(Color.BLACK); + g.drawOval(x, y, d, d); + } else { + g.setColor(DARK_GREEN); + g.fillOval(x + 5, y + 5, d-10, d-10); + } + + x += 40; + + if (isBlueOn()) { + g.setColor(BLUE); + g.fillOval(x, y, d, d); + g.setColor(Color.BLACK); + g.drawOval(x, y, d, d); + } else { + g.setColor(DARK_BLUE); + g.fillOval(x + 5, y + 5, d-10, d-10); + } + } + }; + + Observer observer; + this.addObserver(observer = new Observer() { + public void update(Observable obs, Object obj) { + panel.repaint(); + } + }); + + // Saving observer reference for releaseInterfaceVisualizer + panel.putClientProperty("intf_obs", observer); + panel.setMinimumSize(new Dimension(140, 60)); + panel.setPreferredSize(new Dimension(140, 60)); + return panel; + } + + public void releaseInterfaceVisualizer(JPanel panel) { + Observer observer = (Observer) panel.getClientProperty("intf_obs"); + if (observer == null) { + logger.fatal("Error when releasing panel, observer is null"); + return; + } + + this.deleteObserver(observer); + } + + + public Collection getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML, boolean visAvailable) { + } + +} From 96968cb35ebb8e6545b738b2346b74437401290e Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Fri, 16 Aug 2013 15:02:08 +0200 Subject: [PATCH 25/26] bugfix: only write to infomem if empty --- .../cooja/mspmote/interfaces/MspMoteID.java | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/MspMoteID.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/MspMoteID.java index 137472936..2b1abcfac 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/MspMoteID.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/MspMoteID.java @@ -84,19 +84,31 @@ public class MspMoteID extends MoteID { moteID = newID; /* Write node-unique infomem entry, used to configure node_id and node_mac */ - if (mote.getMemory().getMemorySegment(0x1980, 10) != null) { - byte[] infomem = new byte[10]; - infomem[0] = (byte) 0xab; /* magic */ - infomem[1] = (byte) 0xcd; /* magic */ - infomem[2] = (byte) 0x02; - infomem[3] = (byte) 0x12; - infomem[4] = (byte) 0x74; - infomem[5] = (byte) 0x00; - infomem[6] = (byte) 0x00; - infomem[7] = (byte) 0x01; - infomem[8] = (byte) ((newID << 8) & 0xFF); - infomem[9] = (byte) (newID & 0xFF); - mote.getMemory().setMemorySegment(0x1980, infomem); + byte[] infomemCurrent = mote.getMemory().getMemorySegment(0x1980, 10); + if (infomemCurrent != null) { + /* Only write to infomem is nothing else resides there */ + boolean ffOnly = true; + for (byte b: infomemCurrent) { + if (b != (byte) 0xff) { + ffOnly = false; + break; + } + } + + if (ffOnly) { + byte[] infomem = new byte[10]; + infomem[0] = (byte) 0xab; /* magic */ + infomem[1] = (byte) 0xcd; /* magic */ + infomem[2] = (byte) 0x02; + infomem[3] = (byte) 0x12; + infomem[4] = (byte) 0x74; + infomem[5] = (byte) 0x00; + infomem[6] = (byte) 0x00; + infomem[7] = (byte) 0x01; + infomem[8] = (byte) ((newID << 8) & 0xFF); + infomem[9] = (byte) (newID & 0xFF); + mote.getMemory().setMemorySegment(0x1980, infomem); + } } if (moteMem.variableExists("node_id")) { From 150807f2e6a42a0653553bdfc3fea145ed5d6cea Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Fri, 16 Aug 2013 15:06:31 +0200 Subject: [PATCH 26/26] removed rpl configuration, instead using contiki default values --- platform/cooja/contiki-conf.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/platform/cooja/contiki-conf.h b/platform/cooja/contiki-conf.h index 51ff18bfb..e43a13ce7 100644 --- a/platform/cooja/contiki-conf.h +++ b/platform/cooja/contiki-conf.h @@ -138,11 +138,6 @@ #define TCPIP_CONF_ANNOTATE_TRANSMISSIONS 1 -#define RPL_CONF_DIO_INTERVAL_MIN 16 - -#define RPL_DIS_INTERVAL_CONF (5 * 60) -#define RPL_CONF_DAO_LATENCY (CLOCK_SECOND * 60) - #define UIP_CONF_ND6_SEND_RA 0 #define UIP_CONF_ND6_REACHABLE_TIME 600000 #define UIP_CONF_ND6_RETRANS_TIMER 10000