diff --git a/platform/cooja/Makefile.cooja b/platform/cooja/Makefile.cooja index 1426bf7cc..047ca9d99 100644 --- a/platform/cooja/Makefile.cooja +++ b/platform/cooja/Makefile.cooja @@ -51,7 +51,8 @@ COOJA_BASE = simEnvChange.c cooja_mt.c cooja_mtarch.c rtimer-arch.c slip.c watch COOJA_INTFS = beep.c button-sensor.c ip.c leds-arch.c moteid.c \ pir-sensor.c rs232.c vib-sensor.c \ - clock.c log.c cfs-cooja.c cooja-radio.c + clock.c log.c cfs-cooja.c cooja-radio.c \ + eeprom.c COOJA_CORE = random.c sensors.c leds.c symbols.c diff --git a/platform/cooja/contiki-cooja-main.c b/platform/cooja/contiki-cooja-main.c index 035f9ee6b..3c8f98440 100644 --- a/platform/cooja/contiki-cooja-main.c +++ b/platform/cooja/contiki-cooja-main.c @@ -114,7 +114,8 @@ SIM_INTERFACE_NAME(pir_interface); SIM_INTERFACE_NAME(clock_interface); SIM_INTERFACE_NAME(leds_interface); SIM_INTERFACE_NAME(cfs_interface); -SIM_INTERFACES(&vib_interface, &moteid_interface, &rs232_interface, &simlog_interface, &beep_interface, &radio_interface, &button_interface, &pir_interface, &clock_interface, &leds_interface, &cfs_interface); +SIM_INTERFACE_NAME(eeprom_interface); +SIM_INTERFACES(&vib_interface, &moteid_interface, &rs232_interface, &simlog_interface, &beep_interface, &radio_interface, &button_interface, &pir_interface, &clock_interface, &leds_interface, &cfs_interface, &eeprom_interface); /* Example: manually add mote interfaces */ //SIM_INTERFACE_NAME(dummy_interface); //SIM_INTERFACES(..., &dummy_interface); @@ -320,6 +321,9 @@ contiki_init() } #endif /* WITH_UIP6 */ + /* Initialize eeprom */ + eeprom_init(); + /* Start serial process */ serial_line_init(); diff --git a/platform/cooja/dev/eeprom.c b/platform/cooja/dev/eeprom.c new file mode 100644 index 000000000..8a40fa3d8 --- /dev/null +++ b/platform/cooja/dev/eeprom.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2014, 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. + * + */ + +#include "dev/eeprom.h" + +#include "lib/simEnvChange.h" + +const struct simInterface eeprom_interface; + +#define EEPROM_BUF_SIZE 1024 /* Configure EEPROM size here and in ContikiEeprom.java */ + +unsigned char simEEPROMData[EEPROM_BUF_SIZE]; +char simEEPROMChanged = 0; +int simEEPROMRead = 0; +int simEEPROMWritten = 0; + +void +eeprom_init(void) +{ +} + +void +eeprom_read(eeprom_addr_t addr, unsigned char *buf, int len) +{ + if (addr >= EEPROM_BUF_SIZE) { + return; + } + + if(addr + len >= EEPROM_BUF_SIZE) { + len = EEPROM_BUF_SIZE - addr; + } + + memcpy(buf, &simEEPROMData[addr], len); + + simEEPROMChanged = 1; + simEEPROMRead += len; +} + +void +eeprom_write(eeprom_addr_t addr, unsigned char *buf, int len) +{ + if (addr >= EEPROM_BUF_SIZE) { + return; + } + + if(addr + len >= EEPROM_BUF_SIZE) { + len = EEPROM_BUF_SIZE - addr; + } + + + memcpy(&simEEPROMData[addr], buf, len); + + simEEPROMChanged = 1; + simEEPROMWritten += len; + +} + +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsBeforeTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ +static void +doInterfaceActionsAfterTick(void) +{ +} +/*-----------------------------------------------------------------------------------*/ + +SIM_INTERFACE(eeprom_interface, + doInterfaceActionsBeforeTick, + doInterfaceActionsAfterTick); diff --git a/tools/cooja/config/cooja_default.config b/tools/cooja/config/cooja_default.config index a48c89e2d..212f48003 100644 --- a/tools/cooja/config/cooja_default.config +++ b/tools/cooja/config/cooja_default.config @@ -1,6 +1,6 @@ org.contikios.cooja.contikimote.interfaces.ContikiRadio.RADIO_TRANSMISSION_RATE_kbps = 250 -org.contikios.cooja.contikimote.ContikiMoteType.MOTE_INTERFACES = org.contikios.cooja.interfaces.Position org.contikios.cooja.interfaces.Battery org.contikios.cooja.contikimote.interfaces.ContikiVib org.contikios.cooja.contikimote.interfaces.ContikiMoteID org.contikios.cooja.contikimote.interfaces.ContikiRS232 org.contikios.cooja.contikimote.interfaces.ContikiBeeper org.contikios.cooja.interfaces.RimeAddress org.contikios.cooja.contikimote.interfaces.ContikiIPAddress org.contikios.cooja.contikimote.interfaces.ContikiRadio org.contikios.cooja.contikimote.interfaces.ContikiButton org.contikios.cooja.contikimote.interfaces.ContikiPIR org.contikios.cooja.contikimote.interfaces.ContikiClock org.contikios.cooja.contikimote.interfaces.ContikiLED org.contikios.cooja.contikimote.interfaces.ContikiCFS org.contikios.cooja.interfaces.Mote2MoteRelations org.contikios.cooja.interfaces.MoteAttributes +org.contikios.cooja.contikimote.ContikiMoteType.MOTE_INTERFACES = org.contikios.cooja.interfaces.Position org.contikios.cooja.interfaces.Battery org.contikios.cooja.contikimote.interfaces.ContikiVib org.contikios.cooja.contikimote.interfaces.ContikiMoteID org.contikios.cooja.contikimote.interfaces.ContikiRS232 org.contikios.cooja.contikimote.interfaces.ContikiBeeper org.contikios.cooja.interfaces.RimeAddress org.contikios.cooja.contikimote.interfaces.ContikiIPAddress org.contikios.cooja.contikimote.interfaces.ContikiRadio org.contikios.cooja.contikimote.interfaces.ContikiButton org.contikios.cooja.contikimote.interfaces.ContikiPIR org.contikios.cooja.contikimote.interfaces.ContikiClock org.contikios.cooja.contikimote.interfaces.ContikiLED org.contikios.cooja.contikimote.interfaces.ContikiCFS org.contikios.cooja.contikimote.interfaces.ContikiEEPROM org.contikios.cooja.interfaces.Mote2MoteRelations org.contikios.cooja.interfaces.MoteAttributes org.contikios.cooja.contikimote.ContikiMoteType.C_SOURCES = org.contikios.cooja.Cooja.MOTETYPES = org.contikios.cooja.motes.ImportAppMoteType org.contikios.cooja.motes.DisturberMoteType org.contikios.cooja.contikimote.ContikiMoteType org.contikios.cooja.Cooja.PLUGINS = org.contikios.cooja.plugins.Visualizer org.contikios.cooja.plugins.LogListener org.contikios.cooja.plugins.TimeLine org.contikios.cooja.plugins.MoteInformation org.contikios.cooja.plugins.MoteInterfaceViewer org.contikios.cooja.plugins.VariableWatcher org.contikios.cooja.plugins.EventListener org.contikios.cooja.plugins.RadioLogger org.contikios.cooja.plugins.ScriptRunner org.contikios.cooja.plugins.Notes org.contikios.cooja.plugins.BufferListener org.contikios.cooja.plugins.DGRMConfigurator org.contikios.cooja.plugins.BaseRSSIconf diff --git a/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiEEPROM.java b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiEEPROM.java new file mode 100644 index 000000000..a1b1d5e56 --- /dev/null +++ b/tools/cooja/java/org/contikios/cooja/contikimote/interfaces/ContikiEEPROM.java @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2014, 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. + * + */ + +package org.contikios.cooja.contikimote.interfaces; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.*; +import java.util.*; +import javax.swing.*; +import javax.xml.bind.DatatypeConverter; +import org.apache.log4j.Logger; +import org.jdom.Element; + +import org.contikios.cooja.*; +import org.contikios.cooja.contikimote.ContikiMoteInterface; +import org.contikios.cooja.interfaces.PolledAfterActiveTicks; + +/** + * Contiki EEPROM interface + * + * Contiki variables: + *
+ * + * Core interface: + *
+ * This observable notifies when the eeprom is used (read/write).
+ *
+ * @author Claes Jakobsson (based on ContikiCFS by Fredrik Osterlind)
+ */
+@ClassDescription("EEPROM")
+public class ContikiEEPROM extends MoteInterface implements ContikiMoteInterface, PolledAfterActiveTicks {
+ private static Logger logger = Logger.getLogger(ContikiEEPROM.class);
+
+ public int EEPROM_SIZE = 1024; /* Configure EEPROM size here and in eeprom.c. Should really be multiple of 16 */
+ private Mote mote = null;
+ private SectionMoteMemory moteMem = null;
+
+ private int lastRead = 0;
+ private int lastWritten = 0;
+
+ /**
+ * Creates an interface to the EEPROM at mote.
+ *
+ * @param mote Mote
+ * @see Mote
+ * @see org.contikios.cooja.MoteInterfaceHandler
+ */
+ public ContikiEEPROM(Mote mote) {
+ this.mote = mote;
+ this.moteMem = (SectionMoteMemory) mote.getMemory();
+ }
+
+ public static String[] getCoreInterfaceDependencies() {
+ return new String[]{"eeprom_interface"};
+ }
+
+ public void doActionsAfterTick() {
+ if (moteMem.getByteValueOf("simEEPROMChanged") == 1) {
+ lastRead = moteMem.getIntValueOf("simEEPROMRead");
+ lastWritten = moteMem.getIntValueOf("simEEPROMWritten");
+
+ moteMem.setIntValueOf("simEEPROMRead", 0);
+ moteMem.setIntValueOf("simEEPROMWritten", 0);
+ moteMem.setByteValueOf("simEEPROMChanged", (byte) 0);
+
+ this.setChanged();
+ this.notifyObservers(mote);
+ }
+ }
+
+ /**
+ * Set EEPROM data.
+ *
+ * @param data Data
+ * @return True if operation successful
+ */
+ public boolean setEEPROMData(byte[] data) {
+ if (data.length > EEPROM_SIZE) {
+ logger.fatal("Error. EEPROM data too large, skipping");
+ return false;
+ }
+
+ moteMem.setByteArray("simEEPROMData", data);
+ return true;
+ }
+
+ /**
+ * Get EEPROM data.
+ *
+ * @return Filesystem data
+ */
+ public byte[] getEEPROMData() {
+ return moteMem.getByteArray("simEEPROMData", EEPROM_SIZE);
+ }
+
+ /**
+ * @return Read bytes count last change.
+ */
+ public int getLastReadCount() {
+ return lastRead;
+ }
+
+ /**
+ * @return Written bytes count last change.
+ */
+ public int getLastWrittenCount() {
+ return lastWritten;
+ }
+
+ String byteArrayToPrintableCharacters(byte[] data, int offset, int length) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = offset; i < offset + length; i++) {
+ sb.append(data[i] > 31 && data[i] < 128 ? (char) data[i] : '.');
+ }
+ return sb.toString();
+ }
+
+ String byteArrayToHexList(byte[] data, int offset, int length) {
+ StringBuilder sb = new StringBuilder();
+
+ for (int i = 0; i < length; i++) {
+ byte h = (byte) ((int) data[offset + i] >> 4);
+ byte l = (byte) ((int) data[offset + i] & 0xf);
+ sb.append((char)(h < 10 ? 0x30 + h : 0x61 + h - 10));
+ sb.append((char)(l < 10 ? 0x30 + l : 0x61 + l - 10));
+ sb.append(' ');
+ if (i % 8 == 7 && i != length - 1) {
+ sb.append(' ');
+ }
+ }
+
+ return sb.toString();
+ }
+
+ void redrawDataView(JTextArea textArea) {
+ StringBuilder sb = new StringBuilder();
+ Formatter fmt = new Formatter(sb);
+ byte[] data = getEEPROMData();
+
+ for (int i = 0; i < EEPROM_SIZE; i+= 16) {
+ fmt.format("%04d %s | %s |\n", i, byteArrayToHexList(data, i, 16), byteArrayToPrintableCharacters(data, i, 16));
+ }
+
+ textArea.setText(sb.toString());
+ textArea.setCaretPosition(0);
+ }
+
+ public JPanel getInterfaceVisualizer() {
+ JPanel panel = new JPanel();
+ panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
+
+ final JLabel lastTimeLabel = new JLabel("Last change at: ?");
+ final JLabel lastReadLabel = new JLabel("Last change read bytes: 0");
+ final JLabel lastWrittenLabel = new JLabel("Last change wrote bytes: 0");
+ final JButton uploadButton = new JButton("Upload binary file");
+ final JButton clearButton = new JButton("Reset EEPROM to zero");
+ final JTextArea dataViewArea = new JTextArea();
+ final JScrollPane dataViewScrollPane = new JScrollPane(dataViewArea);
+
+ panel.add(lastTimeLabel);
+ panel.add(lastReadLabel);
+ panel.add(lastWrittenLabel);
+ panel.add(uploadButton);
+ panel.add(clearButton);
+
+ panel.add(dataViewScrollPane);
+
+ uploadButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ byte[] eepromData = readDialogEEPROMBytes(null);
+
+ // Write file data to EEPROM
+ if (eepromData != null) {
+ if (setEEPROMData(eepromData)) {
+ logger.info("Done! (" + eepromData.length + " bytes written to EEPROM)");
+ }
+
+ redrawDataView(dataViewArea);
+ }
+ }
+ });
+
+ clearButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ byte[] eepromData = new byte[EEPROM_SIZE];
+
+ if (setEEPROMData(eepromData)) {
+ logger.info("Done! (EEPROM reset to zero)");
+ }
+
+ redrawDataView(dataViewArea);
+ }
+ });
+
+ Observer observer;
+ this.addObserver(observer = new Observer() {
+ public void update(Observable obs, Object obj) {
+ long currentTime = mote.getSimulation().getSimulationTime();
+ lastTimeLabel.setText("Last change at time: " + currentTime);
+ lastReadLabel.setText("Last change read bytes: " + getLastReadCount());
+ lastWrittenLabel.setText("Last change wrote bytes: " + getLastWrittenCount());
+
+ redrawDataView(dataViewArea);
+ }
+ });
+
+ // Saving observer reference for releaseInterfaceVisualizer
+ panel.putClientProperty("intf_obs", observer);
+
+ panel.setMinimumSize(new Dimension(140, 60));
+ panel.setPreferredSize(new Dimension(140, 60));
+
+ dataViewArea.setLineWrap(false);
+ dataViewArea.setEditable(false);
+ dataViewArea.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
+ dataViewScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+ dataViewScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+
+ redrawDataView(dataViewArea);
+
+ 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