Merge pull request #335 from adamdunkels/push/cooja-updates
Cooja updates
This commit is contained in:
commit
a372bac787
|
@ -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);
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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());*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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>>();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(" ");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue