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 d6a95d517..d96686529 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 @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: SkyMoteType.java,v 1.9 2009/04/20 16:12:01 fros4943 Exp $ + * $Id: SkyMoteType.java,v 1.10 2009/08/11 17:09:34 fros4943 Exp $ */ package se.sics.cooja.mspmote; @@ -49,6 +49,7 @@ import se.sics.cooja.mspmote.interfaces.MspClock; import se.sics.cooja.mspmote.interfaces.MspMoteID; import se.sics.cooja.mspmote.interfaces.SkyButton; import se.sics.cooja.mspmote.interfaces.SkyByteRadio; +import se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem; import se.sics.cooja.mspmote.interfaces.SkyFlash; import se.sics.cooja.mspmote.interfaces.SkyLED; import se.sics.cooja.mspmote.interfaces.SkySerial; @@ -198,6 +199,7 @@ public class SkyMoteType extends MspMoteType { MspMoteID.class, SkyButton.class, SkyFlash.class, + SkyCoffeeFilesystem.class, SkyByteRadio.class, SkySerial.class, SkyLED.class diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/CoojaM25P80.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/CoojaM25P80.java index 18d50d999..dd8d4a5a1 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/CoojaM25P80.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/CoojaM25P80.java @@ -26,24 +26,38 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: CoojaM25P80.java,v 1.1 2008/04/01 08:07:04 fros4943 Exp $ + * $Id: CoojaM25P80.java,v 1.2 2009/08/11 17:09:16 fros4943 Exp $ */ package se.sics.cooja.mspmote.interfaces; import java.io.IOException; +import java.util.Arrays; + import org.apache.log4j.Logger; +import se.sics.coffee.CoffeeConfiguration; +import se.sics.coffee.CoffeeImage; import se.sics.mspsim.chip.M25P80; import se.sics.mspsim.core.*; -public class CoojaM25P80 extends M25P80 { +public class CoojaM25P80 extends M25P80 implements CoffeeImage { private static Logger logger = Logger.getLogger(CoojaM25P80.class); public static int SIZE = 1024*1024; private byte[] data = new byte[SIZE]; private long pos; + private static CoffeeConfiguration COFFEE_CONF; + static { + /* XXX Current implementation only allows for a single coffee configuration */ + try { + COFFEE_CONF = new CoffeeConfiguration("sky.properties"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + public CoojaM25P80(MSP430Core cpu) { super(cpu); pos = 0; @@ -62,4 +76,36 @@ public class CoojaM25P80 extends M25P80 { System.arraycopy(b, 0, data, (int) pos, b.length); } + /** + * XXX Coffee specific: uses start offset + * @see se.sics.coffee.CoffeeImage#erase(int, int) + */ + public void erase(int size, int offset) throws IOException { + Arrays.fill(data, CoffeeConfiguration.startOffset + offset, size, (byte)0); + } + + /** + * XXX Coffee specific: uses start offset + * @see se.sics.coffee.CoffeeImage#getConfiguration() + */ + public CoffeeConfiguration getConfiguration() { + return COFFEE_CONF; + } + + /** + * XXX Coffee specific: uses start offset + * @see se.sics.coffee.CoffeeImage#read(byte[], int, int) + */ + public void read(byte[] bytes, int size, int offset) throws IOException { + System.arraycopy(data, CoffeeConfiguration.startOffset + offset, bytes, 0, size); + } + + /** + * XXX Coffee specific: uses start offset + * @see se.sics.coffee.CoffeeImage#write(byte[], int, int) + */ + public void write(byte[] bytes, int size, int offset) throws IOException { + System.arraycopy(bytes, 0, data, CoffeeConfiguration.startOffset + offset, size); + } + } diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyCoffeeFilesystem.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyCoffeeFilesystem.java new file mode 100644 index 000000000..06739ad40 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyCoffeeFilesystem.java @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2009, Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: SkyCoffeeFilesystem.java,v 1.1 2009/08/11 17:09:16 fros4943 Exp $ + */ + +package se.sics.cooja.mspmote.interfaces; + +import java.awt.BorderLayout; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.io.File; +import java.io.IOException; +import java.util.Collection; + +import javax.swing.Box; +import javax.swing.JButton; +import javax.swing.JFileChooser; +import javax.swing.JLabel; +import javax.swing.JOptionPane; +import javax.swing.JPanel; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.table.AbstractTableModel; + +import org.apache.log4j.Logger; +import org.jdom.Element; + +import se.sics.coffee.CoffeeFS; +import se.sics.coffee.CoffeeFile; +import se.sics.cooja.ClassDescription; +import se.sics.cooja.GUI; +import se.sics.cooja.Mote; +import se.sics.cooja.MoteInterface; +import se.sics.cooja.dialogs.TableColumnAdjuster; + +/** + * Mote user interface to Coffee manager. + * Requires users to manually update the filesystem before filesystem operations. + * + * @author Fredrik Osterlind, Nicolas Tsiftes + */ +@ClassDescription("Coffee Filesystem") +public class SkyCoffeeFilesystem extends MoteInterface { + private static Logger logger = Logger.getLogger(SkyCoffeeFilesystem.class); + + private Mote mote; + + private CoffeeFS coffeeFS = null; + private CoffeeFile[] files = new CoffeeFile[0]; + + private static final int COLUMN_NAME = 0; + private static final int COLUMN_SIZE = 1; + private static final int COLUMN_SAVE = 2; + private static final int COLUMN_REMOVE = 3; + private static final String[] COLUMN_NAMES = { + "Filename", + "Size", + "Save", + "Remove" + }; + private JTable filesTable; + + public SkyCoffeeFilesystem(Mote mote) { + this.mote = mote; + + /* Coffee configuration is already loaded statically */ + + filesTable = new JTable(tableModel); + filesTable.setFillsViewportHeight(true); + filesTable.setFont(new Font("Monospaced", Font.PLAIN, 12)); + TableColumnAdjuster adjuster = new TableColumnAdjuster(filesTable); + adjuster.setDynamicAdjustment(true); + adjuster.packColumns(); + } + + public double energyConsumption() { + return 0; + } + + public Collection getConfigXML() { + return null; + } + public void setConfigXML(Collection configXML, boolean visAvailable) { + } + + private void updateFS() { + if (SwingUtilities.isEventDispatchThread()) { + /* Don't call me in EDT */ + new Thread(new Runnable() { + public void run() { + updateFS(); + } + }).start(); + return; + } + + /* Create new filesystem instance */ + try { + SkyFlash flash = mote.getInterfaces().getInterfaceOfType(SkyFlash.class); + coffeeFS = new CoffeeFS(flash.m24p80); + } catch (IOException e) { + coffeeFS = null; + } + + final CoffeeFile[] tmpFiles = coffeeFS.getFiles().values().toArray(new CoffeeFile[0]); + for (CoffeeFile file : tmpFiles) { + file.getName(); + try { + file.getLength(); + } catch (IOException e) { + } + } + + EventQueue.invokeLater(new Runnable() { + public void run() { + /* Update table */ + files = tmpFiles; + ((AbstractTableModel)filesTable.getModel()).fireTableDataChanged(); + } + }); + } + + public JPanel getInterfaceVisualizer() { + JPanel main = new JPanel(new BorderLayout()); + + updateFS(); /* Update filesystem */ + if (coffeeFS == null) { + main = new JPanel(); + main.add(new JLabel("Error when parsing Coffee filesystem")); + return main; + } + + /* Files listing */ + JPanel panel = new JPanel(new BorderLayout()); + panel.add(filesTable.getTableHeader(), BorderLayout.NORTH); + panel.add(filesTable, BorderLayout.CENTER); + main.add(panel, BorderLayout.CENTER); + filesTable.repaint(); + + + /* Update (force) */ + Box box = Box.createHorizontalBox(); + JButton update = new JButton("Update filesystem"); + update.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + logger.info("Updating Coffee filesystem"); + updateFS(); + } + }); + box.add(update); + + /* Insert */ + JButton insert = new JButton("Insert file"); + insert.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + + JFileChooser fileChooser = new JFileChooser(); + int reply = fileChooser.showOpenDialog(GUI.getTopParentContainer()); + if (reply != JFileChooser.APPROVE_OPTION) { + return; + } + + final File file = fileChooser.getSelectedFile(); + new Thread(new Runnable() { + public void run() { + logger.info("Adding file: " + file.getName()); + try { + coffeeFS.insertFile(file); + } catch (IOException e1) { + logger.fatal("Coffee exception: " + e1.getMessage(), e1); + return; + } + updateFS(); + } + }).start(); + } + }); + box.add(insert); + + main.add(box, BorderLayout.SOUTH); + + return main; + } + + public void releaseInterfaceVisualizer(JPanel panel) { + } + + private AbstractTableModel tableModel = new AbstractTableModel() { + public String getColumnName(int col) { + return COLUMN_NAMES[col].toString(); + } + public int getRowCount() { + return files.length; + } + public int getColumnCount() { + return COLUMN_NAMES.length; + } + public Object getValueAt(int row, int col) { + if (col == COLUMN_NAME) { + return files[row].getName(); + } + if (col == COLUMN_SIZE) { + try { + return files[row].getLength() + " bytes"; + } catch (IOException e) { + return "? bytes"; + } + } + return new Boolean(false); + } + public boolean isCellEditable(int row, int col){ + return getColumnClass(col) == Boolean.class; + } + public void setValueAt(Object value, final int row, int col) { + if (col == COLUMN_SAVE) { + JFileChooser fc = new JFileChooser(); + int returnVal = fc.showSaveDialog(GUI.getTopParentContainer()); + if (returnVal != JFileChooser.APPROVE_OPTION) { + return; + } + + final File saveFile = fc.getSelectedFile(); + if (saveFile.exists()) { + String s1 = "Overwrite"; + String s2 = "Cancel"; + Object[] options = { s1, s2 }; + int n = JOptionPane.showOptionDialog( + GUI.getTopParentContainer(), + "A file with the same name already exists.\nDo you want to remove it?", + "Overwrite existing file?", JOptionPane.YES_NO_OPTION, + JOptionPane.QUESTION_MESSAGE, null, options, s1); + if (n != JOptionPane.YES_OPTION) { + return; + } + } + + if (saveFile.exists() && !saveFile.canWrite()) { + logger.fatal("No write access to file: " + saveFile); + return; + } + + new Thread(new Runnable() { + public void run() { + try { + logger.info("Saving to file: " + saveFile.getName()); + boolean ok = coffeeFS.extractFile(files[row].getName(), saveFile); + if (!ok) { + logger.warn("Error when saving to file: " + saveFile.getName()); + } + } catch (Exception e) { + logger.fatal("Coffee exception: " + e.getMessage(), e); + } + updateFS(); + } + }).start(); + return; + } + + if (col == COLUMN_REMOVE) { + int reply = JOptionPane.showConfirmDialog( + GUI.getTopParentContainer(), + "Remove \"" + files[row].getName() + "\" from filesystem?"); + if (reply != JOptionPane.YES_OPTION) { + return; + } + + /* Remove file */ + new Thread(new Runnable() { + public void run() { + try { + logger.info("Removing file: " + files[row].getName()); + coffeeFS.removeFile(files[row].getName()); + } catch (Exception e) { + logger.fatal("Coffee exception: " + e.getMessage(), e); + } + updateFS(); + } + }).start(); + return; + } + } + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + }; +} diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyFlash.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyFlash.java index b21045d53..d56d7a3f7 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyFlash.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/interfaces/SkyFlash.java @@ -26,7 +26,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: SkyFlash.java,v 1.5 2009/06/17 13:05:27 fros4943 Exp $ + * $Id: SkyFlash.java,v 1.6 2009/08/11 17:09:16 fros4943 Exp $ */ package se.sics.cooja.mspmote.interfaces; @@ -53,7 +53,7 @@ public class SkyFlash extends MoteInterface { public int SIZE = 1024*1024; private SkyMote mote = null; - private CoojaM25P80 m24p80 = null; + protected CoojaM25P80 m24p80 = null; public SkyFlash(Mote mote) { this.mote = (SkyMote) mote;