Merge pull request #335 from adamdunkels/push/cooja-updates

Cooja updates
This commit is contained in:
Fredrik Österlind 2013-08-18 23:55:18 -07:00
commit a372bac787
61 changed files with 4221 additions and 721 deletions

View file

@ -45,6 +45,10 @@
#include "net/rime/rimestats.h"
#include <string.h>
#if CONTIKI_TARGET_COOJA
#include "lib/simEnvChange.h"
#endif /* CONTIKI_TARGET_COOJA */
#define DEBUG 0
#if DEBUG
#include <stdio.h>
@ -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);

View file

@ -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 \

View file

@ -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
@ -63,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 */
@ -136,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

View file

@ -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) {

View file

@ -64,6 +64,9 @@ public class MicaZCompileDialog extends AbstractCompileDialog {
super(parent, simulation, moteType);
}
public Class<? extends MoteInterface>[] getAllMoteInterfaces() {
return ((MicaZMoteType)moteType).getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] getDefaultMoteInterfaces() {
return ((MicaZMoteType)moteType).getAllMoteInterfaceClasses();
}

View file

@ -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;
}
}

View file

@ -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

View file

@ -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<Element> getConfigXML() {
return null;
}
public void setConfigXML(Collection<Element> 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;
}
}

View file

@ -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<Element> getConfigXML() {
return null;
}
public void setConfigXML(Collection<Element> configXML, boolean visAvailable) {
}
public boolean isRadioOn() {
return cc1120.isReadyToReceive();
}
public boolean canReceiveFrom(CustomDataRadio radio) {
if (radio.getClass().equals(this.getClass())) {
return true;
}
return false;
}
}

View file

@ -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<Element> getConfigXML() {
return null;
}
public void setConfigXML(Collection<Element> 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;
}
}

View file

@ -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();
}
}

View file

@ -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<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
return getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] 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";
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}

View file

@ -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<? extends MoteInterface>[] 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<? extends MoteInterface>[] 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";
}
}

View file

@ -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();
}
}

View file

@ -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<? extends MoteInterface>[] 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<? extends MoteInterface>[] 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";
}
}

View file

@ -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();
}
}

View file

@ -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<? extends MoteInterface>[] 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<? extends MoteInterface>[] 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";
}
}

View file

@ -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();
}
}

View file

@ -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<? extends MoteInterface>[] 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<? extends MoteInterface>[] 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";
}
}

View file

@ -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();
}
}

View file

@ -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<? extends MoteInterface>[] 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<? extends MoteInterface>[] 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";
}
}

View file

@ -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();
}
}

View file

@ -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<? extends MoteInterface>[] 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<? extends MoteInterface>[] 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";
}
}

View file

@ -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<Element> getConfigXML() {
return null;
}
public void setConfigXML(Collection<Element> configXML, boolean visAvailable) {
}
}

View file

@ -198,6 +198,9 @@ public class ESBMoteType extends MspMoteType {
return true;
}
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
return getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
return new Class[] {
Position.class,

View file

@ -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();
}
}

View file

@ -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 {
@ -179,6 +182,22 @@ public class Exp5438MoteType extends MspMoteType {
return null;
}
public Class<? extends MoteInterface>[] 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<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
return new Class[] {
Position.class,
@ -189,6 +208,8 @@ public class Exp5438MoteType extends MspMoteType {
MspClock.class,
MspMoteID.class,
Msp802154Radio.class,
CC1101Radio.class,
CC1120Radio.class,
UsciA1Serial.class,
Exp5438LED.class,
/*Exp5438LCD.class,*/ /* TODO */

View file

@ -71,6 +71,9 @@ public class JCreateMoteType extends AbstractMspMoteType {
}
@Override
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
return getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
@SuppressWarnings("unchecked")
Class<? extends MoteInterface>[] list = createMoteInterfaceList(

View file

@ -71,8 +71,11 @@ public class MspCompileDialog extends AbstractCompileDialog {
addCompilationTipsTab(tabbedPane);
}
public Class<? extends MoteInterface>[] getAllMoteInterfaces() {
return ((MspMoteType)moteType).getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] getDefaultMoteInterfaces() {
return ((MspMoteType)moteType).getAllMoteInterfaceClasses();
return ((MspMoteType)moteType).getDefaultMoteInterfaceClasses();
}
private void addCompilationTipsTab(JTabbedPane parent) {

View file

@ -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();
}

View file

@ -320,6 +320,7 @@ public abstract class MspMoteType implements MoteType {
}
public abstract Class<? extends MoteInterface>[] getAllMoteInterfaceClasses();
public abstract Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses();
public abstract File getExpectedFirmwareFile(File source);
private static ELF loadELF(String filepath) throws IOException {

View file

@ -69,7 +69,9 @@ public class SentillaUSBMoteType extends AbstractMspMoteType {
return new SentillaUSBMote(this, simulation);
}
@Override
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
return getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
@SuppressWarnings("unchecked")
Class<? extends MoteInterface>[] list = createMoteInterfaceList(

View file

@ -202,6 +202,9 @@ public class SkyMoteType extends MspMoteType {
return null;
}
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
return getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
return new Class[] {
Position.class,

View file

@ -179,6 +179,9 @@ public class TyndallMoteType extends MspMoteType {
return null;
}
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
return getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
return new Class[] {
Position.class,

View file

@ -69,7 +69,9 @@ public class WismoteMoteType extends AbstractMspMoteType {
return new WismoteMote(this, simulation);
}
@Override
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
return getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
@SuppressWarnings("unchecked")
Class<? extends MoteInterface>[] list = createMoteInterfaceList(

View file

@ -70,7 +70,10 @@ public class Z1MoteType extends AbstractMspMoteType {
return new Z1Mote(this, simulation);
}
@Override
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
return getAllMoteInterfaceClasses();
}
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
@SuppressWarnings("unchecked")
Class<? extends MoteInterface>[] list = createMoteInterfaceList(

View file

@ -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;
}
}

View file

@ -83,6 +83,34 @@ public class MspMoteID extends MoteID {
}
moteID = newID;
/* Write node-unique infomem entry, used to configure node_id and node_mac */
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")) {
moteMem.setIntValueOf("node_id", moteID);

View file

@ -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;
}
}

View file

@ -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<Element> getConfigXML() {
ArrayList<Element> config = new ArrayList<Element>();
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<Element> 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() {

View file

@ -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;
}

View file

@ -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");
}
});
}

View file

@ -1556,6 +1556,9 @@ public class GUI extends Observable {
"MOTETYPES");
if (moteTypeClassNames != null) {
for (String moteTypeClassName : moteTypeClassNames) {
if (moteTypeClassName.trim().isEmpty()) {
continue;
}
Class<? extends MoteType> 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());*/

View file

@ -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);
}
}
/**

View file

@ -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()
);
}
});
}

View file

@ -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<Element> getConfigXML() {
return null;
ArrayList<Element> config = new ArrayList<Element>();
Element element;
/* Radio bitrate */
element = new Element("bitrate");
element.setText("" + RADIO_TRANSMISSION_RATE_kbps);
config.add(element);
return config;
}
public void setConfigXML(Collection<Element> configXML, boolean visAvailable) {
public void setConfigXML(Collection<Element> 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() {

View file

@ -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) {
@ -372,7 +413,7 @@ public abstract class AbstractCompileDialog extends JDialog {
((JCheckBox) c).setSelected(false);
}
if (moteType.getMoteInterfaceClasses() != null) {
for (Class<? extends MoteInterface> intfClass: getDefaultMoteInterfaces()) {
for (Class<? extends MoteInterface> intfClass: getAllMoteInterfaces()) {
addMoteInterface(intfClass, false);
}
for (Class<? extends MoteInterface> intf: moteType.getMoteInterfaceClasses()) {
@ -380,6 +421,9 @@ public abstract class AbstractCompileDialog extends JDialog {
}
} else {
/* Select default mote interfaces */
for (Class<? extends MoteInterface> intfClass: getAllMoteInterfaces()) {
addMoteInterface(intfClass, false);
}
for (Class<? extends MoteInterface> intfClass: getDefaultMoteInterfaces()) {
addMoteInterface(intfClass, true);
}
@ -387,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);
}
/**
@ -469,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 */
@ -539,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);
}
@ -695,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()) {
@ -714,6 +736,7 @@ public abstract class AbstractCompileDialog extends JDialog {
};
public abstract Class<? extends MoteInterface>[] getDefaultMoteInterfaces();
public abstract Class<? extends MoteInterface>[] getAllMoteInterfaces();
/**
* @return Currently selected mote interface classes

View file

@ -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) {
@ -199,24 +218,27 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog {
return ContikiMoteType.getExpectedFirmwareFile(source);
}
public Class<? extends MoteInterface>[] getAllMoteInterfaces() {
ProjectConfig projectConfig = moteType.getConfig();
String[] intfNames = projectConfig.getStringArrayValue(ContikiMoteType.class, "MOTE_INTERFACES");
ArrayList<Class<? extends MoteInterface>> classes = new ArrayList<Class<? extends MoteInterface>>();
/* Load mote interface classes */
for (String intfName : intfNames) {
Class<? extends MoteInterface> 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<? extends MoteInterface>[] getDefaultMoteInterfaces() {
ProjectConfig projectConfig = moteType.getConfig();
String[] intfNames = projectConfig.getStringArrayValue(ContikiMoteType.class, "MOTE_INTERFACES");
ArrayList<Class<? extends MoteInterface>> classes = new ArrayList<Class<? extends MoteInterface>>();
/* Load mote interface classes */
for (String intfName : intfNames) {
Class<? extends MoteInterface> 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) {

View file

@ -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());

View file

@ -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();

View file

@ -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);
}
/**

View file

@ -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<Class<? extends Parser>> bufferParsers =
new ArrayList<Class<? extends Parser>>();

View file

@ -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<Object, Object> wrapped = new RowFilter<Object, Object>() {
public boolean include(RowFilter.Entry<? extends Object, ? extends Object> 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 {
"<br><br>^ID:[2-5] Contiki<br><i>logs from motes 2 to 5 starting with 'Contiki'</i>";
}
/* Experimental feature: let other plugins learn if a log output would be filtered or not */
public boolean filterWouldAccept(LogOutputEvent ev) {
RowFilter<? super TableModel, ? super Integer> rowFilter = logFilter.getRowFilter();
if (rowFilter == null) {
/* No filter */
return true;
}
final LogData ld = new LogData(ev);
RowFilter.Entry<? extends TableModel, ? extends Integer> entry = new RowFilter.Entry<TableModel, Integer>() {
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);
}
}
}

View file

@ -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<TableModel> logFilter;
private ArrayList<RadioConnectionLog> connections = new ArrayList<RadioConnectionLog>();
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
"<html>" +
"Start time (us): " + conn.startTime +
@ -267,9 +295,9 @@ public class RadioLogger extends VisPlugin {
"<br><br>" +
"Duration (us): " + (conn.endTime - conn.startTime) +
"</html>";
} 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("</html>");
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<TableModel>(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<? extends RadioLoggerAnalyzerSuite> 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<Object, Object> filter = new RowFilter<Object, Object>() {
public boolean include(RowFilter.Entry<? extends Object, ? extends Object> 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<PacketAnalyzer> 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]);

View file

@ -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);
}

View file

@ -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<Mote> highlightedMotes = new ArrayList<Mote>();
@ -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<Object> source = new JComboBox<Object>();
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 = "<br>" + details.replace("\n", "<br>");
}
}
/* 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 = "<br>" + details.replace("\n", "<br>");
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 = "<br>" + details.replace("\n", "<br>");
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 = "<br>" + details.replace("\n", "<br>");
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<Element> 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 + "<br>";
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 + "<br>";
if (channel > 0) {
str += "Radio channel: " + channel;
}
String str = "Radio HW was turned " + (on?"on":"off") + "<br>";
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:<br>" + logEvent.getMessage() + "<br>";
}
}
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 {
"<b>Timeline</b>" +
"<p>The timeline shows simulation events over time. " +
"The timeline can be used to inspect activities of individual nodes as well as interactions between nodes." +
"<p>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." +
"<p>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." +
"<p>The <i>Events</i> 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). " +
"<p>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." +
"<p>To display a vertical time marker on the timeline, press and hold the mouse on the time ruler (top)." +
"<p>For more options for a given event, right-click the mouse for a popup menu." +
"<p><b>Radio traffic</b>" +
"<br>Shows radio traffic events. Transmissions are painted blue, receptions are green, and interfered radios are red." +
"<p><b>Radio state</b>" +
"<p><b>Radio channel</b>" +
"<br>Shows the current radio channel by colors." +
"<p><b>Radio on/off</b>" +
"<br>Shows whether the mote radio is on or off. When gray, the radio is on." +
"<p><b>LEDs</b>" +
"<br>Shows LED state: red, green, and blue. (Assumes all mote types have exactly three LEDs.)" +
"<p><b>Log outputs</b>" +
"<br>Shows log outputs, as also shown in " + GUI.getDescriptionOf(LogListener.class) +
"<p><b>Watchpoints</b>" +
"<br>Shows triggered watchpoints, currently only supported by MSPSim-based motes. To add watchpoints, use the Msp Code Watcher plugin.";
"<br>Shows triggered watchpoints, currently only supported by emulated motes. To add watchpoints, use the Msp Code Watcher plugin.";
}
}

View file

@ -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<? extends VisualizerSkin> 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<Element> config = new ArrayList<Element>();
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<Element> 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(" ");

View file

@ -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) {

View file

@ -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.