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 "net/rime/rimestats.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#if CONTIKI_TARGET_COOJA
|
||||||
|
#include "lib/simEnvChange.h"
|
||||||
|
#endif /* CONTIKI_TARGET_COOJA */
|
||||||
|
|
||||||
#define DEBUG 0
|
#define DEBUG 0
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -172,7 +176,12 @@ send_one_packet(mac_callback_t sent, void *ptr)
|
||||||
/* Check for ack */
|
/* Check for ack */
|
||||||
wt = RTIMER_NOW();
|
wt = RTIMER_NOW();
|
||||||
watchdog_periodic();
|
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;
|
ret = MAC_TX_NOACK;
|
||||||
if(NETSTACK_RADIO.receiving_packet() ||
|
if(NETSTACK_RADIO.receiving_packet() ||
|
||||||
|
@ -181,10 +190,17 @@ send_one_packet(mac_callback_t sent, void *ptr)
|
||||||
int len;
|
int len;
|
||||||
uint8_t ackbuf[ACK_LEN];
|
uint8_t ackbuf[ACK_LEN];
|
||||||
|
|
||||||
wt = RTIMER_NOW();
|
if(AFTER_ACK_DETECTED_WAIT_TIME > 0) {
|
||||||
watchdog_periodic();
|
wt = RTIMER_NOW();
|
||||||
while(RTIMER_CLOCK_LT(RTIMER_NOW(),
|
watchdog_periodic();
|
||||||
wt + AFTER_ACK_DETECTED_WAIT_TIME));
|
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()) {
|
if(NETSTACK_RADIO.pending_packet()) {
|
||||||
len = NETSTACK_RADIO.read(ackbuf, ACK_LEN);
|
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)
|
# (COOJA_SOURCEDIRS contains additional sources dirs set from simulator)
|
||||||
vpath %.c $(COOJA_SOURCEDIRS)
|
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 \
|
COOJA_INTFS = beep.c button-sensor.c ip.c leds-arch.c moteid.c \
|
||||||
pir-sensor.c rs232.c vib-sensor.c \
|
pir-sensor.c rs232.c vib-sensor.c \
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
#define PROFILE_CONF_ON 0
|
#define PROFILE_CONF_ON 0
|
||||||
#define ENERGEST_CONF_ON 0
|
#define ENERGEST_CONF_ON 0
|
||||||
#define LOG_CONF_ENABLED 1
|
#define LOG_CONF_ENABLED 1
|
||||||
|
#define RIMESTATS_CONF_ON 1
|
||||||
|
#define RIMESTATS_CONF_ENABLED 1
|
||||||
|
|
||||||
#define COOJA 1
|
#define COOJA 1
|
||||||
|
|
||||||
|
@ -63,10 +65,10 @@
|
||||||
/* Default network config */
|
/* Default network config */
|
||||||
#if WITH_UIP6
|
#if WITH_UIP6
|
||||||
|
|
||||||
#define NULLRDC_CONF_802154_AUTOACK 0
|
#define NULLRDC_CONF_802154_AUTOACK 1
|
||||||
#define NULLRDC_CONF_SEND_802154_ACK 0
|
#define NULLRDC_CONF_SEND_802154_ACK 1
|
||||||
#define NULLRDC_CONF_ACK_WAIT_TIME RTIMER_SECOND / 500
|
#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 */
|
/* Network setup for IPv6 */
|
||||||
|
@ -136,11 +138,6 @@
|
||||||
|
|
||||||
#define TCPIP_CONF_ANNOTATE_TRANSMISSIONS 1
|
#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_SEND_RA 0
|
||||||
#define UIP_CONF_ND6_REACHABLE_TIME 600000
|
#define UIP_CONF_ND6_REACHABLE_TIME 600000
|
||||||
#define UIP_CONF_ND6_RETRANS_TIMER 10000
|
#define UIP_CONF_ND6_RETRANS_TIMER 10000
|
||||||
|
|
|
@ -162,10 +162,14 @@ radio_send(const void *payload, unsigned short payload_len)
|
||||||
{
|
{
|
||||||
int radiostate = simRadioHWOn;
|
int radiostate = simRadioHWOn;
|
||||||
|
|
||||||
/* Simulate turnaround time of 1ms */
|
/* Simulate turnaround time of 2ms for packets, 1ms for acks*/
|
||||||
#if WITH_TURNAROUND
|
#if WITH_TURNAROUND
|
||||||
simProcessRunValue = 1;
|
simProcessRunValue = 1;
|
||||||
cooja_mt_yield();
|
cooja_mt_yield();
|
||||||
|
if(payload_len > 3) {
|
||||||
|
simProcessRunValue = 1;
|
||||||
|
cooja_mt_yield();
|
||||||
|
}
|
||||||
#endif /* WITH_TURNAROUND */
|
#endif /* WITH_TURNAROUND */
|
||||||
|
|
||||||
if(!simRadioHWOn) {
|
if(!simRadioHWOn) {
|
||||||
|
|
|
@ -64,6 +64,9 @@ public class MicaZCompileDialog extends AbstractCompileDialog {
|
||||||
super(parent, simulation, moteType);
|
super(parent, simulation, moteType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<? extends MoteInterface>[] getAllMoteInterfaces() {
|
||||||
|
return ((MicaZMoteType)moteType).getAllMoteInterfaceClasses();
|
||||||
|
}
|
||||||
public Class<? extends MoteInterface>[] getDefaultMoteInterfaces() {
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaces() {
|
||||||
return ((MicaZMoteType)moteType).getAllMoteInterfaceClasses();
|
return ((MicaZMoteType)moteType).getAllMoteInterfaceClasses();
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,16 +32,17 @@ package se.sics.cooja.avrmote.interfaces;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
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;
|
||||||
import avrora.sim.FiniteStateMachine.Probe;
|
import avrora.sim.FiniteStateMachine.Probe;
|
||||||
import avrora.sim.platform.MicaZ;
|
import avrora.sim.platform.MicaZ;
|
||||||
import avrora.sim.radio.CC2420Radio;
|
import avrora.sim.radio.CC2420Radio;
|
||||||
import avrora.sim.radio.Medium;
|
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.
|
* CC2420 to COOJA wrapper.
|
||||||
*
|
*
|
||||||
|
@ -152,4 +153,11 @@ public class MicaZRadio extends Radio802154 {
|
||||||
//System.out.println("MicaZ: Received: " + (b &0xff));
|
//System.out.println("MicaZ: Received: " + (b &0xff));
|
||||||
recv.nextByte(true, (byte)b);
|
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.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
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
|
||||||
|
return getAllMoteInterfaceClasses();
|
||||||
|
}
|
||||||
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
||||||
return new Class[] {
|
return new Class[] {
|
||||||
Position.class,
|
Position.class,
|
||||||
|
|
|
@ -34,7 +34,12 @@ import java.io.File;
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import se.sics.cooja.Simulation;
|
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.Exp5438Node;
|
||||||
|
import se.sics.mspsim.platform.ti.Trxeb1120Node;
|
||||||
|
import se.sics.mspsim.platform.ti.Trxeb2520Node;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Fredrik Osterlind
|
* @author Fredrik Osterlind
|
||||||
|
@ -42,15 +47,39 @@ import se.sics.mspsim.platform.ti.Exp5438Node;
|
||||||
public class Exp5438Mote extends MspMote {
|
public class Exp5438Mote extends MspMote {
|
||||||
private static Logger logger = Logger.getLogger(Exp5438Mote.class);
|
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) {
|
public Exp5438Mote(MspMoteType moteType, Simulation sim) {
|
||||||
super(moteType, sim);
|
super(moteType, sim);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean initEmulator(File fileELF) {
|
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 {
|
try {
|
||||||
exp5438Node = new Exp5438Node();
|
|
||||||
registry = exp5438Node.getRegistry();
|
registry = exp5438Node.getRegistry();
|
||||||
prepareMote(fileELF, exp5438Node);
|
prepareMote(fileELF, exp5438Node);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -64,7 +93,7 @@ public class Exp5438Mote extends MspMote {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
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.MspMoteID;
|
||||||
import se.sics.cooja.mspmote.interfaces.UsciA1Serial;
|
import se.sics.cooja.mspmote.interfaces.UsciA1Serial;
|
||||||
|
|
||||||
|
import com.thingsquare.cooja.mspsim.CC1101Radio;
|
||||||
|
import com.thingsquare.cooja.mspsim.CC1120Radio;
|
||||||
|
|
||||||
@ClassDescription("EXP430F5438 mote")
|
@ClassDescription("EXP430F5438 mote")
|
||||||
@AbstractionLevelDescription("Emulated level")
|
@AbstractionLevelDescription("Emulated level")
|
||||||
public class Exp5438MoteType extends MspMoteType {
|
public class Exp5438MoteType extends MspMoteType {
|
||||||
|
@ -179,6 +182,22 @@ public class Exp5438MoteType extends MspMoteType {
|
||||||
return null;
|
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() {
|
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
||||||
return new Class[] {
|
return new Class[] {
|
||||||
Position.class,
|
Position.class,
|
||||||
|
@ -189,6 +208,8 @@ public class Exp5438MoteType extends MspMoteType {
|
||||||
MspClock.class,
|
MspClock.class,
|
||||||
MspMoteID.class,
|
MspMoteID.class,
|
||||||
Msp802154Radio.class,
|
Msp802154Radio.class,
|
||||||
|
CC1101Radio.class,
|
||||||
|
CC1120Radio.class,
|
||||||
UsciA1Serial.class,
|
UsciA1Serial.class,
|
||||||
Exp5438LED.class,
|
Exp5438LED.class,
|
||||||
/*Exp5438LCD.class,*/ /* TODO */
|
/*Exp5438LCD.class,*/ /* TODO */
|
||||||
|
|
|
@ -71,6 +71,9 @@ public class JCreateMoteType extends AbstractMspMoteType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
|
||||||
|
return getAllMoteInterfaceClasses();
|
||||||
|
}
|
||||||
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Class<? extends MoteInterface>[] list = createMoteInterfaceList(
|
Class<? extends MoteInterface>[] list = createMoteInterfaceList(
|
||||||
|
|
|
@ -71,8 +71,11 @@ public class MspCompileDialog extends AbstractCompileDialog {
|
||||||
addCompilationTipsTab(tabbedPane);
|
addCompilationTipsTab(tabbedPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<? extends MoteInterface>[] getAllMoteInterfaces() {
|
||||||
|
return ((MspMoteType)moteType).getAllMoteInterfaceClasses();
|
||||||
|
}
|
||||||
public Class<? extends MoteInterface>[] getDefaultMoteInterfaces() {
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaces() {
|
||||||
return ((MspMoteType)moteType).getAllMoteInterfaceClasses();
|
return ((MspMoteType)moteType).getDefaultMoteInterfaceClasses();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addCompilationTipsTab(JTabbedPane parent) {
|
private void addCompilationTipsTab(JTabbedPane parent) {
|
||||||
|
|
|
@ -30,13 +30,13 @@
|
||||||
|
|
||||||
package se.sics.cooja.mspmote;
|
package se.sics.cooja.mspmote;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Observable;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
@ -53,8 +53,8 @@ import se.sics.cooja.Watchpoint;
|
||||||
import se.sics.cooja.WatchpointMote;
|
import se.sics.cooja.WatchpointMote;
|
||||||
import se.sics.cooja.interfaces.IPAddress;
|
import se.sics.cooja.interfaces.IPAddress;
|
||||||
import se.sics.cooja.motes.AbstractEmulatedMote;
|
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.Msp802154Radio;
|
||||||
|
import se.sics.cooja.mspmote.interfaces.MspSerial;
|
||||||
import se.sics.cooja.mspmote.plugins.CodeVisualizerSkin;
|
import se.sics.cooja.mspmote.plugins.CodeVisualizerSkin;
|
||||||
import se.sics.cooja.mspmote.plugins.MspBreakpoint;
|
import se.sics.cooja.mspmote.plugins.MspBreakpoint;
|
||||||
import se.sics.cooja.plugins.Visualizer;
|
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.EmulationException;
|
||||||
import se.sics.mspsim.core.MSP430;
|
import se.sics.mspsim.core.MSP430;
|
||||||
import se.sics.mspsim.platform.GenericNode;
|
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.ComponentRegistry;
|
||||||
import se.sics.mspsim.util.ConfigManager;
|
import se.sics.mspsim.util.ConfigManager;
|
||||||
import se.sics.mspsim.util.DebugInfo;
|
import se.sics.mspsim.util.DebugInfo;
|
||||||
|
@ -95,10 +96,8 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
|
||||||
|
|
||||||
/* Stack monitoring variables */
|
/* Stack monitoring variables */
|
||||||
private boolean stopNextInstruction = false;
|
private boolean stopNextInstruction = false;
|
||||||
private boolean monitorStackUsage = false;
|
|
||||||
private int stackPointerLow = Integer.MAX_VALUE;
|
public GenericNode mspNode = null;
|
||||||
private int heapStartAddress;
|
|
||||||
private StackOverflowObservable stackOverflowObservable = new StackOverflowObservable();
|
|
||||||
|
|
||||||
public MspMote(MspMoteType moteType, Simulation simulation) {
|
public MspMote(MspMoteType moteType, Simulation simulation) {
|
||||||
this.simulation = simulation;
|
this.simulation = simulation;
|
||||||
|
@ -113,8 +112,43 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
|
||||||
initEmulator(myMoteType.getContikiFirmwareFile());
|
initEmulator(myMoteType.getContikiFirmwareFile());
|
||||||
myMoteInterfaceHandler = createMoteInterfaceHandler();
|
myMoteInterfaceHandler = createMoteInterfaceHandler();
|
||||||
|
|
||||||
/* TODO Setup COOJA-specific window manager */
|
/* TODO Create COOJA-specific window manager */
|
||||||
registry.registerComponent("windowManager", new JFrameWindowManager());
|
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 {
|
try {
|
||||||
debuggingInfo = ((MspMoteType)getType()).getFirmwareDebugInfo();
|
debuggingInfo = ((MspMoteType)getType()).getFirmwareDebugInfo();
|
||||||
|
@ -156,45 +190,6 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
|
||||||
myMemory = (MspMoteMemory) memory;
|
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.
|
* 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 {
|
protected void prepareMote(File fileELF, GenericNode node) throws IOException {
|
||||||
this.commandHandler = new CommandHandler(System.out, System.err);
|
this.commandHandler = new CommandHandler(System.out, System.err);
|
||||||
|
|
||||||
|
this.mspNode = node;
|
||||||
|
|
||||||
node.setCommandHandler(commandHandler);
|
node.setCommandHandler(commandHandler);
|
||||||
|
|
||||||
ConfigManager config = new ConfigManager();
|
ConfigManager config = new ConfigManager();
|
||||||
|
@ -225,7 +223,6 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
|
||||||
MapEntry[] allEntries = map.getAllEntries();
|
MapEntry[] allEntries = map.getAllEntries();
|
||||||
myMemory = new MspMoteMemory(this, allEntries, myCpu);
|
myMemory = new MspMoteMemory(this, allEntries, myCpu);
|
||||||
|
|
||||||
heapStartAddress = map.heapStartAddress;
|
|
||||||
myCpu.reset();
|
myCpu.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -320,6 +320,7 @@ public abstract class MspMoteType implements MoteType {
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Class<? extends MoteInterface>[] getAllMoteInterfaceClasses();
|
public abstract Class<? extends MoteInterface>[] getAllMoteInterfaceClasses();
|
||||||
|
public abstract Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses();
|
||||||
public abstract File getExpectedFirmwareFile(File source);
|
public abstract File getExpectedFirmwareFile(File source);
|
||||||
|
|
||||||
private static ELF loadELF(String filepath) throws IOException {
|
private static ELF loadELF(String filepath) throws IOException {
|
||||||
|
|
|
@ -69,7 +69,9 @@ public class SentillaUSBMoteType extends AbstractMspMoteType {
|
||||||
return new SentillaUSBMote(this, simulation);
|
return new SentillaUSBMote(this, simulation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
|
||||||
|
return getAllMoteInterfaceClasses();
|
||||||
|
}
|
||||||
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Class<? extends MoteInterface>[] list = createMoteInterfaceList(
|
Class<? extends MoteInterface>[] list = createMoteInterfaceList(
|
||||||
|
|
|
@ -202,6 +202,9 @@ public class SkyMoteType extends MspMoteType {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
|
||||||
|
return getAllMoteInterfaceClasses();
|
||||||
|
}
|
||||||
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
||||||
return new Class[] {
|
return new Class[] {
|
||||||
Position.class,
|
Position.class,
|
||||||
|
|
|
@ -179,6 +179,9 @@ public class TyndallMoteType extends MspMoteType {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
|
||||||
|
return getAllMoteInterfaceClasses();
|
||||||
|
}
|
||||||
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
||||||
return new Class[] {
|
return new Class[] {
|
||||||
Position.class,
|
Position.class,
|
||||||
|
|
|
@ -69,7 +69,9 @@ public class WismoteMoteType extends AbstractMspMoteType {
|
||||||
return new WismoteMote(this, simulation);
|
return new WismoteMote(this, simulation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
|
||||||
|
return getAllMoteInterfaceClasses();
|
||||||
|
}
|
||||||
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Class<? extends MoteInterface>[] list = createMoteInterfaceList(
|
Class<? extends MoteInterface>[] list = createMoteInterfaceList(
|
||||||
|
|
|
@ -70,7 +70,10 @@ public class Z1MoteType extends AbstractMspMoteType {
|
||||||
return new Z1Mote(this, simulation);
|
return new Z1Mote(this, simulation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaceClasses() {
|
||||||
|
return getAllMoteInterfaceClasses();
|
||||||
|
}
|
||||||
|
|
||||||
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
public Class<? extends MoteInterface>[] getAllMoteInterfaceClasses() {
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
Class<? extends MoteInterface>[] list = createMoteInterfaceList(
|
Class<? extends MoteInterface>[] list = createMoteInterfaceList(
|
||||||
|
|
|
@ -423,4 +423,11 @@ public class Msp802154Radio extends Radio implements CustomDataRadio {
|
||||||
}
|
}
|
||||||
return true;
|
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;
|
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")) {
|
if (moteMem.variableExists("node_id")) {
|
||||||
moteMem.setIntValueOf("node_id", moteID);
|
moteMem.setIntValueOf("node_id", moteID);
|
||||||
|
|
||||||
|
|
|
@ -357,4 +357,12 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
|
||||||
/* TODO Implement me */
|
/* TODO Implement me */
|
||||||
return true;
|
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;
|
package se.sics.cooja.mspmote.plugins;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.GridLayout;
|
import java.awt.Color;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.util.Observable;
|
import java.io.IOException;
|
||||||
import java.util.Observer;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
import javax.swing.JButton;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JToggleButton;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
|
import org.jdom.Element;
|
||||||
|
|
||||||
import se.sics.cooja.ClassDescription;
|
import se.sics.cooja.ClassDescription;
|
||||||
import se.sics.cooja.GUI;
|
import se.sics.cooja.GUI;
|
||||||
import se.sics.cooja.Mote;
|
import se.sics.cooja.Mote;
|
||||||
import se.sics.cooja.MotePlugin;
|
import se.sics.cooja.MotePlugin;
|
||||||
|
import se.sics.cooja.MoteTimeEvent;
|
||||||
import se.sics.cooja.PluginType;
|
import se.sics.cooja.PluginType;
|
||||||
import se.sics.cooja.Simulation;
|
import se.sics.cooja.Simulation;
|
||||||
import se.sics.cooja.SupportedArguments;
|
import se.sics.cooja.SupportedArguments;
|
||||||
import se.sics.cooja.VisPlugin;
|
import se.sics.cooja.VisPlugin;
|
||||||
import se.sics.cooja.mspmote.MspMote;
|
import se.sics.cooja.mspmote.MspMote;
|
||||||
|
import se.sics.cooja.mspmote.MspMoteType;
|
||||||
import se.sics.mspsim.core.MSP430;
|
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.ui.StackUI;
|
||||||
import se.sics.mspsim.util.Utils;
|
|
||||||
|
|
||||||
@ClassDescription("Msp Stack Watcher")
|
@ClassDescription("Msp Stack Watcher")
|
||||||
@PluginType(PluginType.MOTE_PLUGIN)
|
@PluginType(PluginType.MOTE_PLUGIN)
|
||||||
@SupportedArguments(motes = {MspMote.class})
|
@SupportedArguments(motes = { MspMote.class })
|
||||||
public class MspStackWatcher extends VisPlugin implements MotePlugin {
|
public class MspStackWatcher extends VisPlugin implements MotePlugin {
|
||||||
private static Logger logger = Logger.getLogger(MspStackWatcher.class);
|
private static Logger logger = Logger.getLogger(MspStackWatcher.class);
|
||||||
|
|
||||||
private MspMote mspMote;
|
|
||||||
private MSP430 cpu;
|
|
||||||
private StackUI stackUI;
|
|
||||||
|
|
||||||
private Simulation simulation;
|
private Simulation simulation;
|
||||||
private Observer stackObserver = null;
|
private MSP430 cpu;
|
||||||
private JButton startButton;
|
private MspMote mspMote;
|
||||||
private JButton stopButton;
|
|
||||||
|
|
||||||
|
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) {
|
public MspStackWatcher(Mote mote, Simulation simulationToVisualize, GUI gui) {
|
||||||
super("Msp Stack Watcher", gui);
|
super("Msp Stack Watcher: " + mote, gui);
|
||||||
this.mspMote = (MspMote) mote;
|
this.mspMote = (MspMote) mote;
|
||||||
cpu = mspMote.getCPU();
|
cpu = mspMote.getCPU();
|
||||||
simulation = simulationToVisualize;
|
simulation = simulationToVisualize;
|
||||||
|
|
||||||
getContentPane().setLayout(new BorderLayout());
|
getContentPane().setLayout(new BorderLayout());
|
||||||
|
|
||||||
// Register as stack observable
|
toggleButton = new JToggleButton("Click to monitor for stack overflows");
|
||||||
if (stackObserver == null) {
|
toggleButton.addActionListener(new ActionListener() {
|
||||||
mspMote.getStackOverflowObservable().addObserver(stackObserver = new Observer() {
|
public void actionPerformed(ActionEvent e) {
|
||||||
public void update(Observable obs, Object obj) {
|
if (toggleButton.isSelected()) {
|
||||||
simulation.stopSimulation();
|
toggleButton.setText("Monitoring for stack overflows");
|
||||||
JOptionPane.showMessageDialog(
|
if (!activate(true)) {
|
||||||
MspStackWatcher.this,
|
toggleButton.setBackground(Color.RED);
|
||||||
"Bad memory access!\nSimulation stopped.\n" +
|
toggleButton.setText("Monitoring for stack overflows - FAILED!");
|
||||||
"\nCurrent stack pointer = 0x" + Utils.hex16(cpu.reg[MSP430.SP]) +
|
toggleButton.setSelected(false);
|
||||||
"\nStart of heap = 0x" + Utils.hex16(cpu.getDisAsm().getMap().heapStartAddress),
|
}
|
||||||
"Stack overflow", JOptionPane.ERROR_MESSAGE
|
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");
|
/* Create Mspsim stack viewer */
|
||||||
stopButton.setEnabled(false);
|
stackUI = new StackUI(cpu, -1); /* Needs manual updates */
|
||||||
stopButton.addActionListener(new ActionListener() {
|
stackUI.init("Stack usage", mspMote.registry);
|
||||||
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);
|
|
||||||
stackUI.start();
|
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
|
add(BorderLayout.NORTH, memLabel);
|
||||||
/*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.CENTER, stackUI);
|
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 {
|
try {
|
||||||
setSelected(true);
|
int stack = ((MspMoteType) mspMote.getType()).getELF().getMap().stackStartAddress;
|
||||||
} catch (java.beans.PropertyVetoException e) {
|
|
||||||
// Could not select
|
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() {
|
public void closePlugin() {
|
||||||
mspMote.getStackOverflowObservable().deleteObserver(stackObserver);
|
increasePosTimeEvent.remove();
|
||||||
stackUI.stop();
|
stackUI.stop();
|
||||||
|
deactivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mote getMote() {
|
public Mote getMote() {
|
||||||
|
|
|
@ -222,6 +222,15 @@ public class PowerTracker extends VisPlugin {
|
||||||
repaintTimer.start();
|
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") {
|
private Action resetAction = new AbstractAction("Reset") {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
Runnable r = new Runnable() {
|
Runnable r = new Runnable() {
|
||||||
|
@ -288,7 +297,7 @@ public class PowerTracker extends VisPlugin {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class MoteTracker implements Observer {
|
public static class MoteTracker implements Observer {
|
||||||
/* last radio state */
|
/* last radio state */
|
||||||
private boolean radioWasOn;
|
private boolean radioWasOn;
|
||||||
private RadioState lastRadioState;
|
private RadioState lastRadioState;
|
||||||
|
@ -379,19 +388,19 @@ public class PowerTracker extends VisPlugin {
|
||||||
radioInterfered += t;
|
radioInterfered += t;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected double getRadioOnRatio() {
|
public double getRadioOnRatio() {
|
||||||
return 1.0*radioOn/duration;
|
return 1.0*radioOn/duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected double getRadioTxRatio() {
|
public double getRadioTxRatio() {
|
||||||
return 1.0*radioTx/duration;
|
return 1.0*radioTx/duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected double getRadioInterferedRatio() {
|
public double getRadioInterferedRatio() {
|
||||||
return 1.0*radioInterfered/duration;
|
return 1.0*radioInterfered/duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected double getRadioRxRatio() {
|
public double getRadioRxRatio() {
|
||||||
return 1.0*radioRx/duration;
|
return 1.0*radioRx/duration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.awt.BorderLayout;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -45,6 +47,7 @@ import javax.swing.JComponent;
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.Timer;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
@ -91,6 +94,8 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
super("Serial Socket (SERVER) (" + mote + ")", gui, false);
|
super("Serial Socket (SERVER) (" + mote + ")", gui, false);
|
||||||
this.mote = mote;
|
this.mote = mote;
|
||||||
|
|
||||||
|
updateTimer.start();
|
||||||
|
|
||||||
LISTEN_PORT = 60000 + mote.getID();
|
LISTEN_PORT = 60000 + mote.getID();
|
||||||
|
|
||||||
/* GUI components */
|
/* GUI components */
|
||||||
|
@ -156,12 +161,11 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
/*logger.debug("out is null");*/
|
/*logger.debug("out is null");*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write(serialPort.getLastSerialData());
|
out.write(serialPort.getLastSerialData());
|
||||||
out.flush();
|
out.flush();
|
||||||
|
|
||||||
outBytes++;
|
outBytes++;
|
||||||
if (GUI.isVisualized()) {
|
|
||||||
outLabel.setText(outBytes + " bytes");
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
cleanupClient();
|
cleanupClient();
|
||||||
}
|
}
|
||||||
|
@ -188,10 +192,8 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
for (int i=0; i < numRead; i++) {
|
for (int i=0; i < numRead; i++) {
|
||||||
serialPort.writeByte(data[i]);
|
serialPort.writeByte(data[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
inBytes += numRead;
|
inBytes += numRead;
|
||||||
if (GUI.isVisualized()) {
|
|
||||||
inLabel.setText(inBytes + " bytes");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
cleanupClient();
|
cleanupClient();
|
||||||
break;
|
break;
|
||||||
|
@ -254,7 +256,9 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean closed = false;
|
||||||
public void closePlugin() {
|
public void closePlugin() {
|
||||||
|
closed = true;
|
||||||
cleanupClient();
|
cleanupClient();
|
||||||
serialPort.deleteSerialDataObserver(serialDataObserver);
|
serialPort.deleteSerialDataObserver(serialDataObserver);
|
||||||
try {
|
try {
|
||||||
|
@ -267,5 +271,17 @@ public class SerialSocketServer extends VisPlugin implements MotePlugin {
|
||||||
return mote;
|
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");
|
"MOTETYPES");
|
||||||
if (moteTypeClassNames != null) {
|
if (moteTypeClassNames != null) {
|
||||||
for (String moteTypeClassName : moteTypeClassNames) {
|
for (String moteTypeClassName : moteTypeClassNames) {
|
||||||
|
if (moteTypeClassName.trim().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Class<? extends MoteType> moteTypeClass = tryLoadClass(this,
|
Class<? extends MoteType> moteTypeClass = tryLoadClass(this,
|
||||||
MoteType.class, moteTypeClassName);
|
MoteType.class, moteTypeClassName);
|
||||||
|
|
||||||
|
@ -4260,6 +4263,22 @@ public class GUI extends Observable {
|
||||||
id += "/..";
|
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)) {
|
if (!fileCanonical.startsWith(configCanonical)) {
|
||||||
/* File is not in a config subdirectory */
|
/* File is not in a config subdirectory */
|
||||||
/*logger.info("File is not in a config subdirectory: " + file.getAbsolutePath());*/
|
/*logger.info("File is not in a config subdirectory: " + file.getAbsolutePath());*/
|
||||||
|
|
|
@ -659,7 +659,10 @@ public class Simulation extends Observable implements Runnable {
|
||||||
availableMoteTypes,
|
availableMoteTypes,
|
||||||
moteTypeClassName
|
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);
|
logger.warn("Changing mote type class: " + moteTypeClassName + " -> " + newClass);
|
||||||
moteTypeClassName = newClass;
|
moteTypeClassName = newClass;
|
||||||
}
|
}
|
||||||
|
@ -989,7 +992,7 @@ public class Simulation extends Observable implements Runnable {
|
||||||
* @param newSpeedLimit
|
* @param newSpeedLimit
|
||||||
*/
|
*/
|
||||||
public void setSpeedLimit(final Double newSpeedLimit) {
|
public void setSpeedLimit(final Double newSpeedLimit) {
|
||||||
invokeSimulationThread(new Runnable() {
|
Runnable r = new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
if (newSpeedLimit == null) {
|
if (newSpeedLimit == null) {
|
||||||
speedLimitNone = true;
|
speedLimitNone = true;
|
||||||
|
@ -1008,7 +1011,14 @@ public class Simulation extends Observable implements Runnable {
|
||||||
Simulation.this.setChanged();
|
Simulation.this.setChanged();
|
||||||
Simulation.this.notifyObservers(this);
|
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 ContikiMote mote = null;
|
||||||
private SectionMoteMemory moteMem = null;
|
private SectionMoteMemory moteMem = null;
|
||||||
|
|
||||||
|
static final int SERIAL_BUF_SIZE = 1024; /* rs232.c:40 */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an interface to the RS232 at mote.
|
* Creates an interface to the RS232 at mote.
|
||||||
*
|
*
|
||||||
|
@ -109,6 +111,11 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll
|
||||||
/* Append to existing buffer */
|
/* Append to existing buffer */
|
||||||
int oldSize = moteMem.getIntValueOf("simSerialReceivingLength");
|
int oldSize = moteMem.getIntValueOf("simSerialReceivingLength");
|
||||||
int newSize = oldSize + dataToAppend.length;
|
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);
|
moteMem.setIntValueOf("simSerialReceivingLength", newSize);
|
||||||
|
|
||||||
byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize);
|
byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize);
|
||||||
|
@ -159,6 +166,11 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll
|
||||||
/* Append to existing buffer */
|
/* Append to existing buffer */
|
||||||
int oldSize = moteMem.getIntValueOf("simSerialReceivingLength");
|
int oldSize = moteMem.getIntValueOf("simSerialReceivingLength");
|
||||||
int newSize = oldSize + dataToAppend.length;
|
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);
|
moteMem.setIntValueOf("simSerialReceivingLength", newSize);
|
||||||
|
|
||||||
byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize);
|
byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize);
|
||||||
|
@ -212,6 +224,11 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll
|
||||||
/* Append to existing buffer */
|
/* Append to existing buffer */
|
||||||
int oldSize = moteMem.getIntValueOf("simSerialReceivingLength");
|
int oldSize = moteMem.getIntValueOf("simSerialReceivingLength");
|
||||||
int newSize = oldSize + dataToAppend.length;
|
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);
|
moteMem.setIntValueOf("simSerialReceivingLength", newSize);
|
||||||
|
|
||||||
byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize);
|
byte[] oldData = moteMem.getByteArray("simSerialReceivingData", oldSize);
|
||||||
|
@ -229,13 +246,26 @@ public class ContikiRS232 extends SerialUI implements ContikiMoteInterface, Poll
|
||||||
mote.requestImmediateWakeup();
|
mote.requestImmediateWakeup();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Simulation thread: schedule immediately */
|
||||||
|
if (mote.getSimulation().isSimulationThread()) {
|
||||||
|
mote.getSimulation().scheduleEvent(
|
||||||
|
pendingBytesEvent,
|
||||||
|
mote.getSimulation().getSimulationTime()
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mote.getSimulation().invokeSimulationThread(new Runnable() {
|
mote.getSimulation().invokeSimulationThread(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
mote.getSimulation().scheduleEvent(
|
if (pendingBytesEvent.isScheduled()) {
|
||||||
pendingBytesEvent,
|
return;
|
||||||
mote.getSimulation().getSimulationTime()
|
}
|
||||||
);
|
mote.getSimulation().scheduleEvent(
|
||||||
}
|
pendingBytesEvent,
|
||||||
|
mote.getSimulation().getSimulationTime()
|
||||||
|
);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,17 +30,8 @@
|
||||||
|
|
||||||
package se.sics.cooja.contikimote.interfaces;
|
package se.sics.cooja.contikimote.interfaces;
|
||||||
|
|
||||||
import java.awt.BorderLayout;
|
import java.util.ArrayList;
|
||||||
import java.awt.GridLayout;
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.util.Collection;
|
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.apache.log4j.Logger;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
@ -105,7 +96,7 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA
|
||||||
/**
|
/**
|
||||||
* Transmission bitrate (kbps).
|
* Transmission bitrate (kbps).
|
||||||
*/
|
*/
|
||||||
public final double RADIO_TRANSMISSION_RATE_kbps;
|
private double RADIO_TRANSMISSION_RATE_kbps;
|
||||||
|
|
||||||
private RadioPacket packetToMote = null;
|
private RadioPacket packetToMote = null;
|
||||||
|
|
||||||
|
@ -125,6 +116,8 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA
|
||||||
|
|
||||||
private int oldOutputPowerIndicator = -1;
|
private int oldOutputPowerIndicator = -1;
|
||||||
|
|
||||||
|
private int oldRadioChannel = -1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an interface to the radio at mote.
|
* Creates an interface to the radio at mote.
|
||||||
*
|
*
|
||||||
|
@ -294,6 +287,14 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA
|
||||||
this.notifyObservers();
|
this.notifyObservers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if radio channel changed */
|
||||||
|
if (getChannel() != oldRadioChannel) {
|
||||||
|
oldRadioChannel = getChannel();
|
||||||
|
lastEvent = RadioEvent.UNKNOWN;
|
||||||
|
this.setChanged();
|
||||||
|
this.notifyObservers();
|
||||||
|
}
|
||||||
|
|
||||||
/* Ongoing transmission */
|
/* Ongoing transmission */
|
||||||
if (isTransmitting && now >= transmissionEndTime) {
|
if (isTransmitting && now >= transmissionEndTime) {
|
||||||
myMoteMemory.setIntValueOf("simOutSize", 0);
|
myMoteMemory.setIntValueOf("simOutSize", 0);
|
||||||
|
@ -345,10 +346,26 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface, PolledA
|
||||||
}
|
}
|
||||||
|
|
||||||
public Collection<Element> getConfigXML() {
|
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() {
|
public Mote getMote() {
|
||||||
|
|
|
@ -256,6 +256,12 @@ public abstract class AbstractCompileDialog extends JDialog {
|
||||||
|
|
||||||
topPanel.add(sourcePanel);
|
topPanel.add(sourcePanel);
|
||||||
|
|
||||||
|
|
||||||
|
Action cancelAction = new AbstractAction("Cancel") {
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
AbstractCompileDialog.this.dispose();
|
||||||
|
}
|
||||||
|
};
|
||||||
Action compileAction = new AbstractAction("Compile") {
|
Action compileAction = new AbstractAction("Compile") {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
public void actionPerformed(ActionEvent e) {
|
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 */
|
/* Restore old configuration if mote type is already configured */
|
||||||
boolean restoredDialogState = false;
|
boolean restoredDialogState = false;
|
||||||
if (moteType != null) {
|
if (moteType != null) {
|
||||||
|
@ -372,7 +413,7 @@ public abstract class AbstractCompileDialog extends JDialog {
|
||||||
((JCheckBox) c).setSelected(false);
|
((JCheckBox) c).setSelected(false);
|
||||||
}
|
}
|
||||||
if (moteType.getMoteInterfaceClasses() != null) {
|
if (moteType.getMoteInterfaceClasses() != null) {
|
||||||
for (Class<? extends MoteInterface> intfClass: getDefaultMoteInterfaces()) {
|
for (Class<? extends MoteInterface> intfClass: getAllMoteInterfaces()) {
|
||||||
addMoteInterface(intfClass, false);
|
addMoteInterface(intfClass, false);
|
||||||
}
|
}
|
||||||
for (Class<? extends MoteInterface> intf: moteType.getMoteInterfaceClasses()) {
|
for (Class<? extends MoteInterface> intf: moteType.getMoteInterfaceClasses()) {
|
||||||
|
@ -380,6 +421,9 @@ public abstract class AbstractCompileDialog extends JDialog {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Select default mote interfaces */
|
/* Select default mote interfaces */
|
||||||
|
for (Class<? extends MoteInterface> intfClass: getAllMoteInterfaces()) {
|
||||||
|
addMoteInterface(intfClass, false);
|
||||||
|
}
|
||||||
for (Class<? extends MoteInterface> intfClass: getDefaultMoteInterfaces()) {
|
for (Class<? extends MoteInterface> intfClass: getDefaultMoteInterfaces()) {
|
||||||
addMoteInterface(intfClass, true);
|
addMoteInterface(intfClass, true);
|
||||||
}
|
}
|
||||||
|
@ -387,39 +431,14 @@ public abstract class AbstractCompileDialog extends JDialog {
|
||||||
|
|
||||||
/* Restore compile commands */
|
/* Restore compile commands */
|
||||||
if (moteType.getCompileCommands() != null) {
|
if (moteType.getCompileCommands() != null) {
|
||||||
setCompileCommands(moteType.getCompileCommands());
|
setCompileCommands(moteType.getCompileCommands());
|
||||||
setDialogState(DialogState.AWAITING_COMPILATION);
|
setDialogState(DialogState.AWAITING_COMPILATION);
|
||||||
restoredDialogState = true;
|
restoredDialogState = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!restoredDialogState) {
|
if (!restoredDialogState) {
|
||||||
setDialogState(DialogState.NO_SELECTION);
|
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");
|
throw new Exception("No compile commands specified");
|
||||||
}
|
}
|
||||||
|
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
if (SwingUtilities.isEventDispatchThread()) {
|
||||||
public void run() {
|
setDialogState(DialogState.IS_COMPILING);
|
||||||
setDialogState(DialogState.IS_COMPILING);
|
} else {
|
||||||
}
|
SwingUtilities.invokeAndWait(new Runnable() {
|
||||||
});
|
public void run() {
|
||||||
|
setDialogState(DialogState.IS_COMPILING);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
createNewCompilationTab(taskOutput);
|
createNewCompilationTab(taskOutput);
|
||||||
|
|
||||||
/* Add abort compilation menu item */
|
/* Add abort compilation menu item */
|
||||||
|
@ -539,6 +562,7 @@ public abstract class AbstractCompileDialog extends JDialog {
|
||||||
);
|
);
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
logger.fatal("Exception when compiling: " + ex.getMessage());
|
logger.fatal("Exception when compiling: " + ex.getMessage());
|
||||||
|
taskOutput.addMessage(ex.getMessage(), MessageList.ERROR);
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
compilationFailureAction.actionPerformed(null);
|
compilationFailureAction.actionPerformed(null);
|
||||||
}
|
}
|
||||||
|
@ -695,8 +719,6 @@ public abstract class AbstractCompileDialog extends JDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Action defaultAction = new AbstractAction("Use default") {
|
private Action defaultAction = new AbstractAction("Use default") {
|
||||||
private static final long serialVersionUID = 2874355910493988933L;
|
|
||||||
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
/* Unselect all */
|
/* Unselect all */
|
||||||
for (Component c : moteIntfBox.getComponents()) {
|
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>[] getDefaultMoteInterfaces();
|
||||||
|
public abstract Class<? extends MoteInterface>[] getAllMoteInterfaces();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Currently selected mote interface classes
|
* @return Currently selected mote interface classes
|
||||||
|
|
|
@ -36,6 +36,7 @@ import java.awt.Container;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.ActionListener;
|
import java.awt.event.ActionListener;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import javax.swing.BorderFactory;
|
import javax.swing.BorderFactory;
|
||||||
|
@ -103,28 +104,7 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog {
|
||||||
addAdvancedTab(tabbedPane);
|
addAdvancedTab(tabbedPane);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean canLoadFirmware(File file) {
|
private void updateForSource(File source) {
|
||||||
/* 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 "";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moteType.getIdentifier() == null) {
|
if (moteType.getIdentifier() == null) {
|
||||||
/* Generate mote type identifier */
|
/* Generate mote type identifier */
|
||||||
moteType.setIdentifier(
|
moteType.setIdentifier(
|
||||||
|
@ -152,7 +132,7 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog {
|
||||||
|
|
||||||
if (((ContikiMoteType)moteType).javaClassName == null) {
|
if (((ContikiMoteType)moteType).javaClassName == null) {
|
||||||
logger.fatal("Could not allocate a core communicator.");
|
logger.fatal("Could not allocate a core communicator.");
|
||||||
return "";
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Prepare compiler environment */
|
/* Prepare compiler environment */
|
||||||
|
@ -167,8 +147,8 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog {
|
||||||
((ContikiMoteType)moteType).javaClassName
|
((ContikiMoteType)moteType).javaClassName
|
||||||
);
|
);
|
||||||
CompileContiki.redefineCOOJASources(
|
CompileContiki.redefineCOOJASources(
|
||||||
moteType,
|
moteType,
|
||||||
env
|
env
|
||||||
);
|
);
|
||||||
|
|
||||||
String[] envOneDimension = new String[env.length];
|
String[] envOneDimension = new String[env.length];
|
||||||
|
@ -184,6 +164,45 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
env = null;
|
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 = "";
|
String defines = "";
|
||||||
if (((ContikiMoteType) moteType).getNetworkStack().getHeaderFile() != null) {
|
if (((ContikiMoteType) moteType).getNetworkStack().getHeaderFile() != null) {
|
||||||
|
@ -199,24 +218,27 @@ public class ContikiMoteCompileDialog extends AbstractCompileDialog {
|
||||||
return ContikiMoteType.getExpectedFirmwareFile(source);
|
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() {
|
public Class<? extends MoteInterface>[] getDefaultMoteInterfaces() {
|
||||||
ProjectConfig projectConfig = moteType.getConfig();
|
return getAllMoteInterfaces();
|
||||||
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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addAdvancedTab(JTabbedPane parent) {
|
private void addAdvancedTab(JTabbedPane parent) {
|
||||||
|
|
|
@ -110,7 +110,8 @@ public abstract class SerialUI extends Log implements SerialPort {
|
||||||
newMessage.append((char) data);
|
newMessage.append((char) data);
|
||||||
if (newMessage.length() > MAX_LENGTH) {
|
if (newMessage.length() > MAX_LENGTH) {
|
||||||
/*logger.warn("Dropping too large log message (>" + MAX_LENGTH + " bytes).");*/
|
/*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);
|
newMessage.setLength(0);
|
||||||
this.setChanged();
|
this.setChanged();
|
||||||
this.notifyObservers(getMote());
|
this.notifyObservers(getMote());
|
||||||
|
|
|
@ -39,6 +39,8 @@ package se.sics.cooja.interfaces;
|
||||||
*/
|
*/
|
||||||
public interface CustomDataRadio {
|
public interface CustomDataRadio {
|
||||||
|
|
||||||
|
public boolean canReceiveFrom(CustomDataRadio radio);
|
||||||
|
|
||||||
public void receiveCustomData(Object data);
|
public void receiveCustomData(Object data);
|
||||||
|
|
||||||
public Object getLastCustomDataTransmitted();
|
public Object getLastCustomDataTransmitted();
|
||||||
|
|
|
@ -122,55 +122,66 @@ public class IPAddress extends MoteInterface {
|
||||||
return ipString;
|
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() {
|
public String getUncompressedIPv6Address() {
|
||||||
byte[] ip = null;
|
byte[] ip = getIPv6Address();
|
||||||
|
if (ip == null) {
|
||||||
/* IpV6: Struct sizes and offsets */
|
return "";
|
||||||
int ipv6NetworkInterfaceAddressOffset = moteMem.getByteValueOf("uip_ds6_netif_addr_list_offset");
|
}
|
||||||
int ipv6AddressStructSize = moteMem.getByteValueOf("uip_ds6_addr_size");
|
return getUncompressedIPv6AddressString(ip);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -130,7 +130,7 @@ public class BufferListener extends VisPlugin {
|
||||||
private static final long TIME_MINUTE = 60*TIME_SECOND;
|
private static final long TIME_MINUTE = 60*TIME_SECOND;
|
||||||
private static final long TIME_HOUR = 60*TIME_MINUTE;
|
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 =
|
private static ArrayList<Class<? extends Parser>> bufferParsers =
|
||||||
new ArrayList<Class<? extends Parser>>();
|
new ArrayList<Class<? extends Parser>>();
|
||||||
|
|
|
@ -108,6 +108,19 @@ public class LogListener extends VisPlugin implements HasQuickHelp {
|
||||||
private static final long serialVersionUID = 3294595371354857261L;
|
private static final long serialVersionUID = 3294595371354857261L;
|
||||||
private static Logger logger = Logger.getLogger(LogListener.class);
|
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_TIME = 0;
|
||||||
private final static int COLUMN_FROM = 1;
|
private final static int COLUMN_FROM = 1;
|
||||||
private final static int COLUMN_DATA = 2;
|
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;
|
public static final long TIME_SECOND = 1000*Simulation.MILLISECOND;
|
||||||
private static final long TIME_MINUTE = 60*TIME_SECOND;
|
public static final long TIME_MINUTE = 60*TIME_SECOND;
|
||||||
private static final long TIME_HOUR = 60*TIME_MINUTE;
|
public static final long TIME_HOUR = 60*TIME_MINUTE;
|
||||||
|
|
||||||
private boolean formatTimeString = false;
|
private boolean formatTimeString = true;
|
||||||
private boolean hasHours = false;
|
private boolean hasHours = false;
|
||||||
|
|
||||||
private final JTable logTable;
|
private final JTable logTable;
|
||||||
|
@ -140,7 +153,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp {
|
||||||
|
|
||||||
private LogOutputListener logOutputListener;
|
private LogOutputListener logOutputListener;
|
||||||
|
|
||||||
private boolean backgroundColors = false;
|
private boolean backgroundColors = true;
|
||||||
private JCheckBoxMenuItem colorCheckbox;
|
private JCheckBoxMenuItem colorCheckbox;
|
||||||
|
|
||||||
private boolean inverseFilter = false;
|
private boolean inverseFilter = false;
|
||||||
|
@ -219,7 +232,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp {
|
||||||
appendCheckBox = new JCheckBoxMenuItem(appendAction);
|
appendCheckBox = new JCheckBoxMenuItem(appendAction);
|
||||||
fileMenu.add(appendCheckBox);
|
fileMenu.add(appendCheckBox);
|
||||||
|
|
||||||
colorCheckbox = new JCheckBoxMenuItem("Mote-specific coloring");
|
colorCheckbox = new JCheckBoxMenuItem("Mote-specific coloring", backgroundColors);
|
||||||
showMenu.add(colorCheckbox);
|
showMenu.add(colorCheckbox);
|
||||||
colorCheckbox.addActionListener(new ActionListener() {
|
colorCheckbox.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
@ -309,18 +322,6 @@ public class LogListener extends VisPlugin implements HasQuickHelp {
|
||||||
};
|
};
|
||||||
DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer() {
|
DefaultTableCellRenderer cellRenderer = new DefaultTableCellRenderer() {
|
||||||
private static final long serialVersionUID = -340743275865216182L;
|
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,
|
public Component getTableCellRendererComponent(JTable table,
|
||||||
Object value, boolean isSelected, boolean hasFocus, int row,
|
Object value, boolean isSelected, boolean hasFocus, int row,
|
||||||
int column) {
|
int column) {
|
||||||
|
@ -331,12 +332,8 @@ public class LogListener extends VisPlugin implements HasQuickHelp {
|
||||||
|
|
||||||
if (backgroundColors) {
|
if (backgroundColors) {
|
||||||
LogData d = logs.get(logTable.getRowSorter().convertRowIndexToModel(row));
|
LogData d = logs.get(logTable.getRowSorter().convertRowIndexToModel(row));
|
||||||
char last = d.getID().charAt(d.getID().length()-1);
|
int color = (10+d.ev.getMote().getID())%10;
|
||||||
if (last >= '0' && last <= '9') {
|
setBackground(BG_COLORS[color]);
|
||||||
setBackground(BG_COLORS[last - '0']);
|
|
||||||
} else {
|
|
||||||
setBackground(null);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
setBackground(null);
|
setBackground(null);
|
||||||
}
|
}
|
||||||
|
@ -674,7 +671,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp {
|
||||||
}
|
}
|
||||||
RowFilter<Object, Object> wrapped = new RowFilter<Object, Object>() {
|
RowFilter<Object, Object> wrapped = new RowFilter<Object, Object>() {
|
||||||
public boolean include(RowFilter.Entry<? extends Object, ? extends Object> entry) {
|
public boolean include(RowFilter.Entry<? extends Object, ? extends Object> entry) {
|
||||||
if (regexp != null) {
|
if (regexp != null) {
|
||||||
boolean pass = regexp.include(entry);
|
boolean pass = regexp.include(entry);
|
||||||
if (inverseFilter && pass) {
|
if (inverseFilter && pass) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -698,6 +695,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp {
|
||||||
filterTextField.setBackground(Color.red);
|
filterTextField.setBackground(Color.red);
|
||||||
filterTextField.setToolTipText("Syntax error in regular expression: " + e.getMessage());
|
filterTextField.setToolTipText("Syntax error in regular expression: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
simulation.getGUI().getDesktopPane().repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void trySelectTime(final long time) {
|
public void trySelectTime(final long time) {
|
||||||
|
@ -732,19 +730,7 @@ public class LogListener extends VisPlugin implements HasQuickHelp {
|
||||||
|
|
||||||
public String getTime() {
|
public String getTime() {
|
||||||
if (formatTimeString) {
|
if (formatTimeString) {
|
||||||
long t = ev.getTime();
|
return getFormattedTime(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);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return "" + ev.getTime() / Simulation.MILLISECOND;
|
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>";
|
"<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.ActionEvent;
|
||||||
import java.awt.event.KeyAdapter;
|
import java.awt.event.KeyAdapter;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Observable;
|
import java.util.Observable;
|
||||||
import java.util.Observer;
|
import java.util.Observer;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.regex.PatternSyntaxException;
|
||||||
|
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.ButtonGroup;
|
import javax.swing.ButtonGroup;
|
||||||
|
import javax.swing.JCheckBoxMenuItem;
|
||||||
import javax.swing.JFileChooser;
|
import javax.swing.JFileChooser;
|
||||||
import javax.swing.JMenu;
|
import javax.swing.JMenu;
|
||||||
import javax.swing.JMenuBar;
|
import javax.swing.JMenuBar;
|
||||||
|
@ -68,9 +72,12 @@ import javax.swing.JTable;
|
||||||
import javax.swing.JTextField;
|
import javax.swing.JTextField;
|
||||||
import javax.swing.JTextPane;
|
import javax.swing.JTextPane;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
|
import javax.swing.RowFilter;
|
||||||
import javax.swing.event.ListSelectionEvent;
|
import javax.swing.event.ListSelectionEvent;
|
||||||
import javax.swing.event.ListSelectionListener;
|
import javax.swing.event.ListSelectionListener;
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
import javax.swing.table.TableModel;
|
||||||
|
import javax.swing.table.TableRowSorter;
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
import org.apache.log4j.Logger;
|
||||||
import org.jdom.Element;
|
import org.jdom.Element;
|
||||||
|
@ -116,9 +123,11 @@ public class RadioLogger extends VisPlugin {
|
||||||
private JSplitPane splitPane;
|
private JSplitPane splitPane;
|
||||||
private JTextPane verboseBox = null;
|
private JTextPane verboseBox = null;
|
||||||
|
|
||||||
|
private boolean formatTimeString = true;
|
||||||
|
|
||||||
private final static String[] COLUMN_NAMES = {
|
private final static String[] COLUMN_NAMES = {
|
||||||
"No.",
|
"No. ",
|
||||||
"Time",
|
"Time ms",
|
||||||
"From",
|
"From",
|
||||||
"To",
|
"To",
|
||||||
"Data"
|
"Data"
|
||||||
|
@ -126,6 +135,7 @@ public class RadioLogger extends VisPlugin {
|
||||||
|
|
||||||
private final Simulation simulation;
|
private final Simulation simulation;
|
||||||
private final JTable dataTable;
|
private final JTable dataTable;
|
||||||
|
private TableRowSorter<TableModel> logFilter;
|
||||||
private ArrayList<RadioConnectionLog> connections = new ArrayList<RadioConnectionLog>();
|
private ArrayList<RadioConnectionLog> connections = new ArrayList<RadioConnectionLog>();
|
||||||
private RadioMedium radioMedium;
|
private RadioMedium radioMedium;
|
||||||
private Observer radioMediumObserver;
|
private Observer radioMediumObserver;
|
||||||
|
@ -149,7 +159,7 @@ public class RadioLogger extends VisPlugin {
|
||||||
JMenu fileMenu = new JMenu("File");
|
JMenu fileMenu = new JMenu("File");
|
||||||
JMenu editMenu = new JMenu("Edit");
|
JMenu editMenu = new JMenu("Edit");
|
||||||
JMenu analyzerMenu = new JMenu("Analyzer");
|
JMenu analyzerMenu = new JMenu("Analyzer");
|
||||||
JMenu payloadMenu = new JMenu("Payload");
|
JMenu payloadMenu = new JMenu("View");
|
||||||
|
|
||||||
menuBar.add(fileMenu);
|
menuBar.add(fileMenu);
|
||||||
menuBar.add(editMenu);
|
menuBar.add(editMenu);
|
||||||
|
@ -169,11 +179,15 @@ public class RadioLogger extends VisPlugin {
|
||||||
lowpanAnalyzersPcap.add(new IPHCPacketAnalyzer());
|
lowpanAnalyzersPcap.add(new IPHCPacketAnalyzer());
|
||||||
lowpanAnalyzersPcap.add(new IPv6PacketAnalyzer());
|
lowpanAnalyzersPcap.add(new IPv6PacketAnalyzer());
|
||||||
lowpanAnalyzersPcap.add(new ICMPv6Analyzer());
|
lowpanAnalyzersPcap.add(new ICMPv6Analyzer());
|
||||||
|
|
||||||
model = new AbstractTableModel() {
|
model = new AbstractTableModel() {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1692207305977527004L;
|
private static final long serialVersionUID = 1692207305977527004L;
|
||||||
|
|
||||||
public String getColumnName(int col) {
|
public String getColumnName(int col) {
|
||||||
|
if (col == COLUMN_TIME && formatTimeString) {
|
||||||
|
return "Time";
|
||||||
|
}
|
||||||
return COLUMN_NAMES[col];
|
return COLUMN_NAMES[col];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,10 +200,19 @@ public class RadioLogger extends VisPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object getValueAt(int row, int col) {
|
public Object getValueAt(int row, int col) {
|
||||||
|
if (row < 0 || row >= connections.size()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
RadioConnectionLog conn = connections.get(row);
|
RadioConnectionLog conn = connections.get(row);
|
||||||
if (col == COLUMN_NO) {
|
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) {
|
} else if (col == COLUMN_TIME) {
|
||||||
|
if (formatTimeString) {
|
||||||
|
return LogListener.getFormattedTime(conn.startTime);
|
||||||
|
}
|
||||||
return Long.toString(conn.startTime / Simulation.MILLISECOND);
|
return Long.toString(conn.startTime / Simulation.MILLISECOND);
|
||||||
} else if (col == COLUMN_FROM) {
|
} else if (col == COLUMN_FROM) {
|
||||||
return "" + conn.connection.getSource().getMote().getID();
|
return "" + conn.connection.getSource().getMote().getID();
|
||||||
|
@ -251,14 +274,19 @@ public class RadioLogger extends VisPlugin {
|
||||||
public String getToolTipText(MouseEvent e) {
|
public String getToolTipText(MouseEvent e) {
|
||||||
java.awt.Point p = e.getPoint();
|
java.awt.Point p = e.getPoint();
|
||||||
int rowIndex = rowAtPoint(p);
|
int rowIndex = rowAtPoint(p);
|
||||||
|
if (rowIndex < 0) {
|
||||||
|
return super.getToolTipText(e);
|
||||||
|
}
|
||||||
|
int modelRowIndex = convertRowIndexToModel(rowIndex);
|
||||||
int colIndex = columnAtPoint(p);
|
int colIndex = columnAtPoint(p);
|
||||||
int realColumnIndex = convertColumnIndexToModel(colIndex);
|
int modelColumnIndex = convertColumnIndexToModel(colIndex);
|
||||||
if (rowIndex < 0 || realColumnIndex < 0) {
|
if (modelRowIndex < 0 || modelColumnIndex < 0) {
|
||||||
return super.getToolTipText(e);
|
return super.getToolTipText(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
RadioConnectionLog conn = connections.get(rowIndex);
|
/* TODO This entry may represent several hidden connections */
|
||||||
if (realColumnIndex == COLUMN_TIME) {
|
RadioConnectionLog conn = connections.get(modelRowIndex);
|
||||||
|
if (modelColumnIndex == COLUMN_TIME) {
|
||||||
return
|
return
|
||||||
"<html>" +
|
"<html>" +
|
||||||
"Start time (us): " + conn.startTime +
|
"Start time (us): " + conn.startTime +
|
||||||
|
@ -267,9 +295,9 @@ public class RadioLogger extends VisPlugin {
|
||||||
"<br><br>" +
|
"<br><br>" +
|
||||||
"Duration (us): " + (conn.endTime - conn.startTime) +
|
"Duration (us): " + (conn.endTime - conn.startTime) +
|
||||||
"</html>";
|
"</html>";
|
||||||
} else if (realColumnIndex == COLUMN_FROM) {
|
} else if (modelColumnIndex == COLUMN_FROM) {
|
||||||
return conn.connection.getSource().getMote().toString();
|
return conn.connection.getSource().getMote().toString();
|
||||||
} else if (realColumnIndex == COLUMN_TO) {
|
} else if (modelColumnIndex == COLUMN_TO) {
|
||||||
Radio[] dests = conn.connection.getDestinations();
|
Radio[] dests = conn.connection.getDestinations();
|
||||||
if (dests.length == 0) {
|
if (dests.length == 0) {
|
||||||
return "No destinations";
|
return "No destinations";
|
||||||
|
@ -286,7 +314,7 @@ public class RadioLogger extends VisPlugin {
|
||||||
}
|
}
|
||||||
tip.append("</html>");
|
tip.append("</html>");
|
||||||
return tip.toString();
|
return tip.toString();
|
||||||
} else if (realColumnIndex == COLUMN_DATA) {
|
} else if (modelColumnIndex == COLUMN_DATA) {
|
||||||
if (conn.tooltip == null) {
|
if (conn.tooltip == null) {
|
||||||
prepareTooltipString(conn);
|
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() {
|
dataTable.addKeyListener(new KeyAdapter() {
|
||||||
public void keyPressed(KeyEvent e) {
|
public void keyPressed(KeyEvent e) {
|
||||||
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
|
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() {
|
dataTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||||
public void valueChanged(ListSelectionEvent e) {
|
public void valueChanged(ListSelectionEvent e) {
|
||||||
int row = dataTable.getSelectedRow();
|
int row = dataTable.getSelectedRow();
|
||||||
if (row >= 0) {
|
if (row < 0) {
|
||||||
RadioConnectionLog conn = connections.get(row);
|
return;
|
||||||
|
}
|
||||||
|
int modelRowIndex = dataTable.convertRowIndexToModel(row);
|
||||||
|
if (modelRowIndex >= 0) {
|
||||||
|
RadioConnectionLog conn = connections.get(modelRowIndex);
|
||||||
if (conn.tooltip == null) {
|
if (conn.tooltip == null) {
|
||||||
prepareTooltipString(conn);
|
prepareTooltipString(conn);
|
||||||
}
|
}
|
||||||
|
@ -338,6 +391,16 @@ public class RadioLogger extends VisPlugin {
|
||||||
editMenu.add(new JMenuItem(clearAction));
|
editMenu.add(new JMenuItem(clearAction));
|
||||||
|
|
||||||
payloadMenu.add(new JMenuItem(aliasAction));
|
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));
|
fileMenu.add(new JMenuItem(saveAction));
|
||||||
|
|
||||||
|
@ -369,12 +432,14 @@ public class RadioLogger extends VisPlugin {
|
||||||
group.add(rbMenuItem);
|
group.add(rbMenuItem);
|
||||||
analyzerMenu.add(rbMenuItem);
|
analyzerMenu.add(rbMenuItem);
|
||||||
|
|
||||||
|
|
||||||
/* Load additional analyzers specified by projects (cooja.config) */
|
/* Load additional analyzers specified by projects (cooja.config) */
|
||||||
String[] projectAnalyzerSuites =
|
String[] projectAnalyzerSuites =
|
||||||
gui.getProjectConfig().getStringArrayValue(RadioLogger.class, "ANALYZERS");
|
gui.getProjectConfig().getStringArrayValue(RadioLogger.class, "ANALYZERS");
|
||||||
if (projectAnalyzerSuites != null) {
|
if (projectAnalyzerSuites != null) {
|
||||||
for (String suiteName: projectAnalyzerSuites) {
|
for (String suiteName: projectAnalyzerSuites) {
|
||||||
|
if (suiteName == null || suiteName.trim().isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Class<? extends RadioLoggerAnalyzerSuite> suiteClass =
|
Class<? extends RadioLoggerAnalyzerSuite> suiteClass =
|
||||||
gui.tryLoadClass(RadioLogger.this, RadioLoggerAnalyzerSuite.class, suiteName);
|
gui.tryLoadClass(RadioLogger.this, RadioLoggerAnalyzerSuite.class, suiteName);
|
||||||
try {
|
try {
|
||||||
|
@ -383,7 +448,7 @@ public class RadioLogger extends VisPlugin {
|
||||||
rbMenuItem = new JRadioButtonMenuItem(createAnalyzerAction(
|
rbMenuItem = new JRadioButtonMenuItem(createAnalyzerAction(
|
||||||
suite.getDescription(), suiteName, suiteAnalyzers, false));
|
suite.getDescription(), suiteName, suiteAnalyzers, false));
|
||||||
group.add(rbMenuItem);
|
group.add(rbMenuItem);
|
||||||
popupMenu.add(rbMenuItem);
|
analyzerMenu.add(rbMenuItem);
|
||||||
logger.debug("Loaded radio logger analyzers: " + suite.getDescription());
|
logger.debug("Loaded radio logger analyzers: " + suite.getDescription());
|
||||||
} catch (InstantiationException e1) {
|
} catch (InstantiationException e1) {
|
||||||
logger.warn("Failed to load analyzer suite '" + suiteName + "': " + e1.getMessage());
|
logger.warn("Failed to load analyzer suite '" + suiteName + "': " + e1.getMessage());
|
||||||
|
@ -457,7 +522,7 @@ public class RadioLogger extends VisPlugin {
|
||||||
if (isVisible) {
|
if (isVisible) {
|
||||||
dataTable.scrollRectToVisible(dataTable.getCellRect(dataTable.getRowCount() - 1, 0, true));
|
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) {
|
private void searchSelectNext(String text, boolean reverse) {
|
||||||
if (text.isEmpty()) {
|
if (text.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
@ -514,18 +584,75 @@ public class RadioLogger extends VisPlugin {
|
||||||
public void trySelectTime(final long time) {
|
public void trySelectTime(final long time) {
|
||||||
java.awt.EventQueue.invokeLater(new Runnable() {
|
java.awt.EventQueue.invokeLater(new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
for (int i=0; i < connections.size(); i++) {
|
if (dataTable.getRowCount() == 0) {
|
||||||
if (connections.get(i).endTime < time) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
dataTable.scrollRectToVisible(dataTable.getCellRect(i, 0, true));
|
|
||||||
dataTable.setRowSelectionInterval(i, i);
|
|
||||||
return;
|
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) {
|
private void prepareDataString(RadioConnectionLog conn) {
|
||||||
byte[] data;
|
byte[] data;
|
||||||
if (conn.packet == null) {
|
if (conn.packet == null) {
|
||||||
|
@ -646,6 +773,19 @@ public class RadioLogger extends VisPlugin {
|
||||||
element.addContent(Integer.toString(splitPane.getDividerLocation()));
|
element.addContent(Integer.toString(splitPane.getDividerLocation()));
|
||||||
config.add(element);
|
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) {
|
if (analyzerName != null && analyzers != null) {
|
||||||
element = new Element("analyzers");
|
element = new Element("analyzers");
|
||||||
element.setAttribute("name", analyzerName);
|
element.setAttribute("name", analyzerName);
|
||||||
|
@ -676,6 +816,12 @@ public class RadioLogger extends VisPlugin {
|
||||||
aliases.put(payload, alias);
|
aliases.put(payload, alias);
|
||||||
} else if ("split".equals(name)) {
|
} else if ("split".equals(name)) {
|
||||||
splitPane.setDividerLocation(Integer.parseInt(element.getText()));
|
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)) {
|
} else if ("analyzers".equals(name)) {
|
||||||
String analyzerName = element.getAttributeValue("name");
|
String analyzerName = element.getAttributeValue("name");
|
||||||
final Action action;
|
final Action action;
|
||||||
|
@ -697,6 +843,9 @@ public class RadioLogger extends VisPlugin {
|
||||||
long endTime;
|
long endTime;
|
||||||
RadioConnection connection;
|
RadioConnection connection;
|
||||||
RadioPacket packet;
|
RadioPacket packet;
|
||||||
|
|
||||||
|
RadioConnectionLog hiddenBy = null;
|
||||||
|
int hides = 0;
|
||||||
|
|
||||||
String data = null;
|
String data = null;
|
||||||
String tooltip = null;
|
String tooltip = null;
|
||||||
|
@ -729,6 +878,18 @@ public class RadioLogger extends VisPlugin {
|
||||||
return sb.toString();
|
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,
|
private Action createAnalyzerAction(String name, final String actionName,
|
||||||
final ArrayList<PacketAnalyzer> analyzerList, boolean selected) {
|
final ArrayList<PacketAnalyzer> analyzerList, boolean selected) {
|
||||||
Action action = new AbstractAction(name) {
|
Action action = new AbstractAction(name) {
|
||||||
|
@ -738,16 +899,7 @@ public class RadioLogger extends VisPlugin {
|
||||||
if (analyzers != analyzerList) {
|
if (analyzers != analyzerList) {
|
||||||
analyzers = analyzerList;
|
analyzers = analyzerList;
|
||||||
analyzerName = actionName;
|
analyzerName = actionName;
|
||||||
if (connections.size() > 0) {
|
rebuildAllEntries();
|
||||||
// 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("");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -764,7 +916,7 @@ public class RadioLogger extends VisPlugin {
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
connections.clear();
|
connections.clear();
|
||||||
model.fireTableRowsDeleted(0, size - 1);
|
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();
|
StringBuilder sb = new StringBuilder();
|
||||||
for (int i: selectedRows) {
|
for (int i: selectedRows) {
|
||||||
sb.append(i + 1).append('\t');
|
int iModel = dataTable.convertRowIndexToModel(i);
|
||||||
sb.append(dataTable.getValueAt(i, COLUMN_TIME)).append('\t');
|
sb.append(connections.get(iModel).toString() + "\n");
|
||||||
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');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSelection stringSelection = new StringSelection(sb.toString());
|
StringSelection stringSelection = new StringSelection(sb.toString());
|
||||||
|
@ -799,11 +948,7 @@ public class RadioLogger extends VisPlugin {
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
for(int i=0; i < connections.size(); i++) {
|
for(int i=0; i < connections.size(); i++) {
|
||||||
sb.append("" + (i + 1) + '\t');
|
sb.append(connections.get(i).toString() + "\n");
|
||||||
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');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StringSelection stringSelection = new StringSelection(sb.toString());
|
StringSelection stringSelection = new StringSelection(sb.toString());
|
||||||
|
@ -844,11 +989,7 @@ public class RadioLogger extends VisPlugin {
|
||||||
try {
|
try {
|
||||||
PrintWriter outStream = new PrintWriter(new FileWriter(saveFile));
|
PrintWriter outStream = new PrintWriter(new FileWriter(saveFile));
|
||||||
for(int i=0; i < connections.size(); i++) {
|
for(int i=0; i < connections.size(); i++) {
|
||||||
outStream.print("" + (i + 1) + '\t');
|
outStream.print(connections.get(i).toString() + "\n");
|
||||||
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.close();
|
outStream.close();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
|
@ -864,6 +1005,9 @@ public class RadioLogger extends VisPlugin {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
int selectedRow = dataTable.getSelectedRow();
|
int selectedRow = dataTable.getSelectedRow();
|
||||||
if (selectedRow < 0) return;
|
if (selectedRow < 0) return;
|
||||||
|
selectedRow = dataTable.convertRowIndexToModel(selectedRow);
|
||||||
|
if (selectedRow < 0) return;
|
||||||
|
|
||||||
long time = connections.get(selectedRow).startTime;
|
long time = connections.get(selectedRow).startTime;
|
||||||
|
|
||||||
Plugin[] plugins = simulation.getGUI().getStartedPlugins();
|
Plugin[] plugins = simulation.getGUI().getStartedPlugins();
|
||||||
|
@ -884,6 +1028,9 @@ public class RadioLogger extends VisPlugin {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
int selectedRow = dataTable.getSelectedRow();
|
int selectedRow = dataTable.getSelectedRow();
|
||||||
if (selectedRow < 0) return;
|
if (selectedRow < 0) return;
|
||||||
|
selectedRow = dataTable.convertRowIndexToModel(selectedRow);
|
||||||
|
if (selectedRow < 0) return;
|
||||||
|
|
||||||
long time = connections.get(selectedRow).startTime;
|
long time = connections.get(selectedRow).startTime;
|
||||||
|
|
||||||
Plugin[] plugins = simulation.getGUI().getStartedPlugins();
|
Plugin[] plugins = simulation.getGUI().getStartedPlugins();
|
||||||
|
@ -917,6 +1064,8 @@ public class RadioLogger extends VisPlugin {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
int selectedRow = dataTable.getSelectedRow();
|
int selectedRow = dataTable.getSelectedRow();
|
||||||
if (selectedRow < 0) return;
|
if (selectedRow < 0) return;
|
||||||
|
selectedRow = dataTable.convertRowIndexToModel(selectedRow);
|
||||||
|
if (selectedRow < 0) return;
|
||||||
|
|
||||||
String current = "";
|
String current = "";
|
||||||
if (aliases != null && aliases.get(connections.get(selectedRow).data) != null) {
|
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() {
|
public String getConnectionsString() {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
RadioConnectionLog[] cs = connections.toArray(new RadioConnectionLog[0]);
|
RadioConnectionLog[] cs = connections.toArray(new RadioConnectionLog[0]);
|
||||||
|
|
|
@ -120,9 +120,13 @@ public class SimControl extends VisPlugin implements HasQuickHelp {
|
||||||
speedlimitButtonGroup.add(limitMenuItem2);
|
speedlimitButtonGroup.add(limitMenuItem2);
|
||||||
speedMenu.add(limitMenuItem2);
|
speedMenu.add(limitMenuItem2);
|
||||||
JRadioButtonMenuItem limitMenuItem3 = new JRadioButtonMenuItem(
|
JRadioButtonMenuItem limitMenuItem3 = new JRadioButtonMenuItem(
|
||||||
new ChangeMaxSpeedLimitAction("100%", 1.0));
|
new ChangeMaxSpeedLimitAction("100%", 1.0));
|
||||||
speedlimitButtonGroup.add(limitMenuItem3);
|
speedlimitButtonGroup.add(limitMenuItem3);
|
||||||
speedMenu.add(limitMenuItem3);
|
speedMenu.add(limitMenuItem3);
|
||||||
|
JRadioButtonMenuItem limitMenuItem200 = new JRadioButtonMenuItem(
|
||||||
|
new ChangeMaxSpeedLimitAction("200%", 2.0));
|
||||||
|
speedlimitButtonGroup.add(limitMenuItem200);
|
||||||
|
speedMenu.add(limitMenuItem200);
|
||||||
JRadioButtonMenuItem limitMenuItem4 = new JRadioButtonMenuItem(
|
JRadioButtonMenuItem limitMenuItem4 = new JRadioButtonMenuItem(
|
||||||
new ChangeMaxSpeedLimitAction("1000%", 10.0));
|
new ChangeMaxSpeedLimitAction("1000%", 10.0));
|
||||||
speedlimitButtonGroup.add(limitMenuItem4);
|
speedlimitButtonGroup.add(limitMenuItem4);
|
||||||
|
@ -135,7 +139,9 @@ public class SimControl extends VisPlugin implements HasQuickHelp {
|
||||||
} else if (simulation.getSpeedLimit().doubleValue() == 0.10) {
|
} else if (simulation.getSpeedLimit().doubleValue() == 0.10) {
|
||||||
limitMenuItem2.setSelected(true);
|
limitMenuItem2.setSelected(true);
|
||||||
} else if (simulation.getSpeedLimit().doubleValue() == 1.0) {
|
} 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) {
|
} else if (simulation.getSpeedLimit().doubleValue() == 10) {
|
||||||
limitMenuItem4.setSelected(true);
|
limitMenuItem4.setSelected(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
package se.sics.cooja.plugins;
|
package se.sics.cooja.plugins;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.awt.FontMetrics;
|
import java.awt.FontMetrics;
|
||||||
|
@ -55,7 +54,6 @@ import java.util.Observer;
|
||||||
|
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.Box;
|
|
||||||
import javax.swing.JCheckBox;
|
import javax.swing.JCheckBox;
|
||||||
import javax.swing.JCheckBoxMenuItem;
|
import javax.swing.JCheckBoxMenuItem;
|
||||||
import javax.swing.JComboBox;
|
import javax.swing.JComboBox;
|
||||||
|
@ -70,7 +68,6 @@ import javax.swing.JPanel;
|
||||||
import javax.swing.JPopupMenu;
|
import javax.swing.JPopupMenu;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JSlider;
|
import javax.swing.JSlider;
|
||||||
import javax.swing.JSplitPane;
|
|
||||||
import javax.swing.JToolTip;
|
import javax.swing.JToolTip;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.Popup;
|
import javax.swing.Popup;
|
||||||
|
@ -89,7 +86,8 @@ import se.sics.cooja.HasQuickHelp;
|
||||||
import se.sics.cooja.Mote;
|
import se.sics.cooja.Mote;
|
||||||
import se.sics.cooja.Plugin;
|
import se.sics.cooja.Plugin;
|
||||||
import se.sics.cooja.PluginType;
|
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.Simulation;
|
||||||
import se.sics.cooja.VisPlugin;
|
import se.sics.cooja.VisPlugin;
|
||||||
import se.sics.cooja.Watchpoint;
|
import se.sics.cooja.Watchpoint;
|
||||||
|
@ -132,13 +130,14 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
private int paintedMoteHeight = EVENT_PIXEL_HEIGHT;
|
private int paintedMoteHeight = EVENT_PIXEL_HEIGHT;
|
||||||
|
|
||||||
private Simulation simulation;
|
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 JScrollPane timelineScrollPane;
|
||||||
private MoteRuler timelineMoteRuler;
|
private MoteRuler timelineMoteRuler;
|
||||||
private JComponent timeline;
|
private JComponent timeline;
|
||||||
private Box eventCheckboxes;
|
|
||||||
private JSplitPane splitPane;
|
|
||||||
|
|
||||||
private Observer moteHighlightObserver = null;
|
private Observer moteHighlightObserver = null;
|
||||||
private ArrayList<Mote> highlightedMotes = new ArrayList<Mote>();
|
private ArrayList<Mote> highlightedMotes = new ArrayList<Mote>();
|
||||||
|
@ -150,13 +149,20 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
|
|
||||||
private boolean showRadioRXTX = true;
|
private boolean showRadioRXTX = true;
|
||||||
private boolean showRadioChannels = false;
|
private boolean showRadioChannels = false;
|
||||||
private boolean showRadioHW = true;
|
private boolean showRadioOnoff = true;
|
||||||
private boolean showLEDs = true;
|
private boolean showLeds = true;
|
||||||
private boolean showLogOutputs = false;
|
private boolean showLogOutputs = false;
|
||||||
private boolean showWatchpoints = false;
|
private boolean showWatchpoints = false;
|
||||||
|
|
||||||
private Point popupLocation = null;
|
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 simulation Simulation
|
||||||
* @param gui GUI
|
* @param gui GUI
|
||||||
|
@ -195,149 +201,85 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
return executionDetails;
|
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(saveDataAction));
|
||||||
fileMenu.add(new JMenuItem(statisticsAction));
|
fileMenu.add(new JMenuItem(statisticsAction));
|
||||||
editMenu.add(new JMenuItem(clearAction));
|
editMenu.add(new JMenuItem(clearAction));
|
||||||
|
|
||||||
JCheckBox eventCheckBox;
|
showRadioTXRXCheckbox = createEventCheckbox("Radio traffic", "Show radio transmissions, receptions, and collisions");
|
||||||
eventCheckBox = createEventCheckbox("Radio traffic", "Show radio transmissions, receptions, and collisions");
|
showRadioTXRXCheckbox.setName("showRadioRXTX");
|
||||||
eventCheckBox.setSelected(showRadioRXTX);
|
showRadioTXRXCheckbox.addActionListener(new ActionListener() {
|
||||||
eventCheckBox.setName("showRadioRXTX");
|
|
||||||
eventCheckBox.addActionListener(new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
showRadioRXTX = ((JCheckBox) e.getSource()).isSelected();
|
showRadioRXTX = ((JCheckBox) e.getSource()).isSelected();
|
||||||
recalculateMoteHeight();
|
recalculateMoteHeight();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
eventsMenu.add(eventCheckBox);
|
eventsMenu.add(showRadioTXRXCheckbox);
|
||||||
eventCheckBox = createEventCheckbox("Radio channel", "Show different radio channels");
|
showRadioOnoffCheckbox = createEventCheckbox("Radio on/off", "Show radio hardware state");
|
||||||
eventCheckBox.setSelected(showRadioChannels);
|
showRadioOnoffCheckbox.setSelected(showRadioOnoff);
|
||||||
eventCheckBox.setName("showRadioChannels");
|
showRadioOnoffCheckbox.setName("showRadioHW");
|
||||||
eventCheckBox.addActionListener(new ActionListener() {
|
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) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
showRadioChannels = ((JCheckBox) e.getSource()).isSelected();
|
showRadioChannels = ((JCheckBox) e.getSource()).isSelected();
|
||||||
recalculateMoteHeight();
|
recalculateMoteHeight();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
/*eventCheckboxes.add(eventCheckBox);*/
|
eventsMenu.add(showRadioChannelsCheckbox);
|
||||||
eventsMenu.add(eventCheckBox);
|
showLedsCheckBox = createEventCheckbox("LEDs", "Show LED state");
|
||||||
eventCheckBox = createEventCheckbox("Radio state", "Show radio hardware state");
|
showLedsCheckBox.setSelected(showLeds);
|
||||||
eventCheckBox.setSelected(showRadioHW);
|
showLedsCheckBox.setName("showLEDs");
|
||||||
eventCheckBox.setName("showRadioHW");
|
showLedsCheckBox.addActionListener(new ActionListener() {
|
||||||
eventCheckBox.addActionListener(new ActionListener() {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
showRadioHW = ((JCheckBox) e.getSource()).isSelected();
|
showLeds = ((JCheckBox) e.getSource()).isSelected();
|
||||||
recalculateMoteHeight();
|
recalculateMoteHeight();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
eventsMenu.add(eventCheckBox);
|
eventsMenu.add(showLedsCheckBox);
|
||||||
eventCheckBox = createEventCheckbox("LEDs", "Show LED state");
|
showLogsCheckBox = createEventCheckbox("Log output", "Show mote log output, such as printf()'s");
|
||||||
eventCheckBox.setSelected(showLEDs);
|
showLogsCheckBox.setSelected(showLogOutputs);
|
||||||
eventCheckBox.setName("showLEDs");
|
showLogsCheckBox.setName("showLogOutput");
|
||||||
eventCheckBox.addActionListener(new ActionListener() {
|
showLogsCheckBox.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() {
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
showLogOutputs = ((JCheckBox) e.getSource()).isSelected();
|
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();
|
recalculateMoteHeight();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
/*eventCheckboxes.add(eventCheckBox);*/
|
eventsMenu.add(showLogsCheckBox);
|
||||||
eventCheckBox = createEventCheckbox("Watchpoints", "Show code watchpoints (for MSPSim-based motes)");
|
showWatchpointsCheckBox = createEventCheckbox("Watchpoints", "Show code watchpoints (for emulated motes)");
|
||||||
eventCheckBox.setSelected(showWatchpoints);
|
showWatchpointsCheckBox.setSelected(showWatchpoints);
|
||||||
eventCheckBox.setName("showWatchpoints");
|
showWatchpointsCheckBox.setName("showWatchpoints");
|
||||||
eventCheckBox.addActionListener(new ActionListener() {
|
showWatchpointsCheckBox.addActionListener(new ActionListener() {
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
showWatchpoints = ((JCheckBox) e.getSource()).isSelected();
|
showWatchpoints = ((JCheckBox) e.getSource()).isSelected();
|
||||||
recalculateMoteHeight();
|
recalculateMoteHeight();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
eventsMenu.add(eventCheckBox);
|
eventsMenu.add(showWatchpointsCheckBox);
|
||||||
|
|
||||||
/* Box: events to observe */
|
/* 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 */
|
/* Panel: timeline canvas w. scroll pane and add mote button */
|
||||||
timeline = new Timeline();
|
timeline = new Timeline();
|
||||||
timelineScrollPane = new JScrollPane(
|
timelineScrollPane = new JScrollPane(
|
||||||
|
@ -350,13 +292,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
timelineScrollPane.setRowHeaderView(timelineMoteRuler);
|
timelineScrollPane.setRowHeaderView(timelineMoteRuler);
|
||||||
timelineScrollPane.setBackground(Color.WHITE);
|
timelineScrollPane.setBackground(Color.WHITE);
|
||||||
|
|
||||||
splitPane = new JSplitPane(
|
|
||||||
JSplitPane.HORIZONTAL_SPLIT,
|
|
||||||
new JScrollPane(eventCheckboxes),
|
|
||||||
timelineScrollPane
|
|
||||||
);
|
|
||||||
splitPane.setOneTouchExpandable(true);
|
|
||||||
|
|
||||||
/* Zoom in/out via keyboard*/
|
/* Zoom in/out via keyboard*/
|
||||||
getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, KeyEvent.CTRL_DOWN_MASK), "zoomIn");
|
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");
|
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();
|
numberMotesWasUpdated();
|
||||||
|
|
||||||
/* Automatically add/delete motes */
|
/* Automatically add/delete motes.
|
||||||
simulation.getEventCentral().addMoteCountListener(newMotesListener = new MoteCountListener() {
|
* This listener also observes mote log outputs. */
|
||||||
|
simulation.getEventCentral().addLogOutputListener(newMotesListener = new LogOutputListener() {
|
||||||
public void moteWasAdded(Mote mote) {
|
public void moteWasAdded(Mote mote) {
|
||||||
addMote(mote);
|
addMote(mote);
|
||||||
}
|
}
|
||||||
public void moteWasRemoved(Mote mote) {
|
public void moteWasRemoved(Mote mote) {
|
||||||
removeMote(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()) {
|
for (Mote m: simulation.getMotes()) {
|
||||||
addMote(m);
|
addMote(m);
|
||||||
|
@ -427,6 +378,17 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
this.setSize(gui.getDesktopPane().getWidth(), 166);
|
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) {
|
private JCheckBox createEventCheckbox(String text, String tooltip) {
|
||||||
JCheckBox checkBox = new JCheckBox(text, true);
|
JCheckBox checkBox = new JCheckBox(text, true);
|
||||||
checkBox.setToolTipText(tooltip);
|
checkBox.setToolTipText(tooltip);
|
||||||
|
@ -503,7 +465,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
private static final long serialVersionUID = 7546685285707302865L;
|
private static final long serialVersionUID = 7546685285707302865L;
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
|
||||||
JComboBox source = new JComboBox();
|
JComboBox<Object> source = new JComboBox<Object>();
|
||||||
source.addItem("All motes");
|
source.addItem("All motes");
|
||||||
for (Mote m: simulation.getMotes()) {
|
for (Mote m: simulation.getMotes()) {
|
||||||
source.addItem(m);
|
source.addItem(m);
|
||||||
|
@ -876,8 +838,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO Radio channels */
|
|
||||||
|
|
||||||
if (radioHW) {
|
if (radioHW) {
|
||||||
for (MoteEvent ev: moteEvents.radioHWEvents) {
|
for (MoteEvent ev: moteEvents.radioHWEvents) {
|
||||||
if (!(ev instanceof RadioHWEvent)) continue;
|
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));
|
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;
|
private static final long serialVersionUID = 7690116136861949864L;
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
if (popupLocation == null) {
|
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;
|
private static final long serialVersionUID = -8626118368774023257L;
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
if (popupLocation == null) {
|
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;
|
private static final long serialVersionUID = -2458733078524773995L;
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
logListenerAction.actionPerformed(null);
|
logListenerAction.actionPerformed(null);
|
||||||
|
@ -1026,20 +984,12 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
};
|
};
|
||||||
|
|
||||||
private boolean executionDetails = false;
|
private boolean executionDetails = false;
|
||||||
private boolean radioChannels = false;
|
|
||||||
private Action executionDetailsAction = new AbstractAction("Show execution details in tooltips") {
|
private Action executionDetailsAction = new AbstractAction("Show execution details in tooltips") {
|
||||||
private static final long serialVersionUID = -8626118368774023257L;
|
private static final long serialVersionUID = -8626118368774023257L;
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
executionDetails = !executionDetails;
|
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() {
|
private void numberMotesWasUpdated() {
|
||||||
/* Plugin title */
|
/* Plugin title */
|
||||||
|
@ -1101,9 +1051,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMoteObservers(final Mote mote, final MoteEvents moteEvents) {
|
private void addMoteObservers(final Mote mote, final MoteEvents moteEvents) {
|
||||||
/* TODO Log: final Log moteLog = mote.getInterfaces().getLog(); */
|
|
||||||
/* TODO Unknown state event */
|
|
||||||
|
|
||||||
/* LEDs */
|
/* LEDs */
|
||||||
final LED moteLEDs = mote.getInterfaces().getLED();
|
final LED moteLEDs = mote.getInterfaces().getLED();
|
||||||
if (moteLEDs != null) {
|
if (moteLEDs != null) {
|
||||||
|
@ -1131,69 +1078,59 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
activeMoteObservers.add(new MoteObservation(mote, moteLEDs, observer));
|
activeMoteObservers.add(new MoteObservation(mote, moteLEDs, observer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Radio HW, RXTX */
|
/* Radio OnOff, RXTX, and channels */
|
||||||
final Radio moteRadio = mote.getInterfaces().getRadio();
|
final Radio moteRadio = mote.getInterfaces().getRadio();
|
||||||
if (moteRadio != null) {
|
if (moteRadio != null) {
|
||||||
|
RadioChannelEvent startupChannel = new RadioChannelEvent(
|
||||||
|
simulation.getSimulationTime(), moteRadio.getChannel(), moteRadio.isRadioOn());
|
||||||
|
moteEvents.addRadioChannel(startupChannel);
|
||||||
RadioHWEvent startupHW = new RadioHWEvent(
|
RadioHWEvent startupHW = new RadioHWEvent(
|
||||||
simulation.getSimulationTime(), moteRadio.isRadioOn());
|
simulation.getSimulationTime(), moteRadio.isRadioOn());
|
||||||
if (radioChannels) {
|
|
||||||
startupHW.channel = moteRadio.getChannel();
|
|
||||||
}
|
|
||||||
moteEvents.addRadioHW(startupHW);
|
moteEvents.addRadioHW(startupHW);
|
||||||
RadioRXTXEvent startupRXTX = new RadioRXTXEvent(
|
RadioRXTXEvent startupRXTX = new RadioRXTXEvent(
|
||||||
simulation.getSimulationTime(), RXTXRadioEvent.IDLE);
|
simulation.getSimulationTime(), RXTXRadioEvent.IDLE);
|
||||||
moteEvents.addRadioRXTX(startupRXTX);
|
moteEvents.addRadioRXTX(startupRXTX);
|
||||||
Observer observer = new Observer() {
|
Observer observer = new Observer() {
|
||||||
int lastChannel = -1;
|
int lastChannel = -1;
|
||||||
public void update(Observable o, Object arg) {
|
public void update(Observable o, Object arg) {
|
||||||
/* Radio HW events */
|
RadioEvent radioEv = moteRadio.getLastEvent();
|
||||||
if (radioChannels && moteRadio.getLastEvent() == RadioEvent.UNKNOWN) {
|
|
||||||
int nowChannel = moteRadio.getChannel();
|
|
||||||
if (nowChannel == lastChannel) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
lastChannel = nowChannel;
|
|
||||||
|
|
||||||
|
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(
|
RadioHWEvent ev = new RadioHWEvent(
|
||||||
simulation.getSimulationTime(), moteRadio.isRadioOn());
|
simulation.getSimulationTime(), moteRadio.isRadioOn());
|
||||||
if (radioChannels) {
|
|
||||||
ev.channel = moteRadio.getChannel();
|
|
||||||
}
|
|
||||||
|
|
||||||
moteEvents.addRadioHW(ev);
|
moteEvents.addRadioHW(ev);
|
||||||
|
|
||||||
if (executionDetails && mote instanceof AbstractEmulatedMote) {
|
ev.details = details;
|
||||||
String details = ((AbstractEmulatedMote) mote).getExecutionDetails();
|
|
||||||
if (details != null) {
|
|
||||||
details = "<br>" + details.replace("\n", "<br>");
|
|
||||||
ev.details = details;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (moteRadio.getLastEvent() == RadioEvent.HW_ON ||
|
/* Also create another channel event here */
|
||||||
moteRadio.getLastEvent() == RadioEvent.HW_OFF) {
|
lastChannel = nowChannel;
|
||||||
RadioHWEvent ev = new RadioHWEvent(
|
RadioChannelEvent ev2 = new RadioChannelEvent(
|
||||||
simulation.getSimulationTime(), moteRadio.isRadioOn());
|
simulation.getSimulationTime(), nowChannel, moteRadio.isRadioOn());
|
||||||
if (radioChannels) {
|
ev2.details = details;
|
||||||
ev.channel = moteRadio.getChannel();
|
moteEvents.addRadioChannel(ev2);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Radio RXTX events */
|
/* Radio RXTX events */
|
||||||
RadioEvent radioEv = moteRadio.getLastEvent();
|
|
||||||
if (radioEv == RadioEvent.TRANSMISSION_STARTED ||
|
if (radioEv == RadioEvent.TRANSMISSION_STARTED ||
|
||||||
radioEv == RadioEvent.TRANSMISSION_FINISHED ||
|
radioEv == RadioEvent.TRANSMISSION_FINISHED ||
|
||||||
radioEv == RadioEvent.RECEPTION_STARTED ||
|
radioEv == RadioEvent.RECEPTION_STARTED ||
|
||||||
|
@ -1221,15 +1158,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
|
|
||||||
moteEvents.addRadioRXTX(ev);
|
moteEvents.addRadioRXTX(ev);
|
||||||
|
|
||||||
if (executionDetails && mote instanceof AbstractEmulatedMote) {
|
ev.details = details;
|
||||||
String details = ((AbstractEmulatedMote) mote).getExecutionDetails();
|
|
||||||
if (details != null) {
|
|
||||||
details = "<br>" + details.replace("\n", "<br>");
|
|
||||||
ev.details = details;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1239,7 +1168,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
activeMoteObservers.add(new MoteObservation(mote, moteRadio, observer));
|
activeMoteObservers.add(new MoteObservation(mote, moteRadio, observer));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX Experimental: Watchpoints */
|
/* Watchpoints */
|
||||||
if (mote instanceof WatchpointMote) {
|
if (mote instanceof WatchpointMote) {
|
||||||
final WatchpointMote watchpointMote = ((WatchpointMote)mote);
|
final WatchpointMote watchpointMote = ((WatchpointMote)mote);
|
||||||
WatchpointListener listener = new WatchpointListener() {
|
WatchpointListener listener = new WatchpointListener() {
|
||||||
|
@ -1317,10 +1246,10 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
if (showRadioChannels) {
|
if (showRadioChannels) {
|
||||||
h += EVENT_PIXEL_HEIGHT;
|
h += EVENT_PIXEL_HEIGHT;
|
||||||
}
|
}
|
||||||
if (showRadioHW) {
|
if (showRadioOnoff) {
|
||||||
h += EVENT_PIXEL_HEIGHT;
|
h += EVENT_PIXEL_HEIGHT;
|
||||||
}
|
}
|
||||||
if (showLEDs) {
|
if (showLeds) {
|
||||||
h += 3*LED_PIXEL_HEIGHT;
|
h += 3*LED_PIXEL_HEIGHT;
|
||||||
}
|
}
|
||||||
if (showLogOutputs) {
|
if (showLogOutputs) {
|
||||||
|
@ -1378,11 +1307,11 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
element = new Element("showRadioChannels");
|
element = new Element("showRadioChannels");
|
||||||
config.add(element);
|
config.add(element);
|
||||||
}
|
}
|
||||||
if (showRadioHW) {
|
if (showRadioOnoff) {
|
||||||
element = new Element("showRadioHW");
|
element = new Element("showRadioHW");
|
||||||
config.add(element);
|
config.add(element);
|
||||||
}
|
}
|
||||||
if (showLEDs) {
|
if (showLeds) {
|
||||||
element = new Element("showLEDs");
|
element = new Element("showLEDs");
|
||||||
config.add(element);
|
config.add(element);
|
||||||
}
|
}
|
||||||
|
@ -1399,14 +1328,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
element = new Element("executionDetails");
|
element = new Element("executionDetails");
|
||||||
config.add(element);
|
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 = new Element("zoomfactor");
|
||||||
element.addContent("" + currentPixelDivisor);
|
element.addContent("" + currentPixelDivisor);
|
||||||
|
@ -1418,13 +1339,12 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
||||||
showRadioRXTX = false;
|
showRadioRXTX = false;
|
||||||
showRadioChannels = false;
|
showRadioChannels = false;
|
||||||
showRadioHW = false;
|
showRadioOnoff = false;
|
||||||
showLEDs = false;
|
showLeds = false;
|
||||||
showLogOutputs = false;
|
showLogOutputs = false;
|
||||||
showWatchpoints = false;
|
showWatchpoints = false;
|
||||||
|
|
||||||
executionDetails = false;
|
executionDetails = false;
|
||||||
radioChannels = false;
|
|
||||||
|
|
||||||
/* Remove already registered motes */
|
/* Remove already registered motes */
|
||||||
MoteEvents[] allMoteEventsArr = allMoteEvents.toArray(new MoteEvents[0]);
|
MoteEvents[] allMoteEventsArr = allMoteEvents.toArray(new MoteEvents[0]);
|
||||||
|
@ -1442,19 +1362,16 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
} else if ("showRadioChannels".equals(name)) {
|
} else if ("showRadioChannels".equals(name)) {
|
||||||
showRadioChannels = true;
|
showRadioChannels = true;
|
||||||
} else if ("showRadioHW".equals(name)) {
|
} else if ("showRadioHW".equals(name)) {
|
||||||
showRadioHW = true;
|
showRadioOnoff = true;
|
||||||
} else if ("showLEDs".equals(name)) {
|
} else if ("showLEDs".equals(name)) {
|
||||||
showLEDs = true;
|
showLeds = true;
|
||||||
} else if ("showLogOutput".equals(name)) {
|
} else if ("showLogOutput".equals(name)) {
|
||||||
showLogOutputs = true;
|
showLogOutputs = true;
|
||||||
} else if ("showWatchpoints".equals(name)) {
|
} else if ("showWatchpoints".equals(name)) {
|
||||||
showWatchpoints = true;
|
showWatchpoints = true;
|
||||||
|
|
||||||
} else if ("executionDetails".equals(name)) {
|
} else if ("executionDetails".equals(name)) {
|
||||||
executionDetails = true;
|
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)) {
|
} else if ("zoom".equals(name)) {
|
||||||
/* NB: Historically this is a one-based not zero-based index */
|
/* NB: Historically this is a one-based not zero-based index */
|
||||||
final int zl = Integer.parseInt(element.getText())-1;
|
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();
|
recalculateMoteHeight();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1505,28 +1406,9 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
/* Popup menu */
|
/* Popup menu */
|
||||||
final JPopupMenu popupMenu = new JPopupMenu();
|
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));
|
popupMenu.add(new JMenuItem(showInAllAction));
|
||||||
/* focusMenu.addSeparator(); */
|
|
||||||
popupMenu.add(new JMenuItem(logListenerAction));
|
popupMenu.add(new JMenuItem(logListenerAction));
|
||||||
popupMenu.add(new JMenuItem(radioLoggerAction));
|
popupMenu.add(new JMenuItem(radioLoggerAction));
|
||||||
/* popupMenu.add(focusMenu);*/
|
|
||||||
|
|
||||||
JMenu advancedMenu = new JMenu("Advanced");
|
JMenu advancedMenu = new JMenu("Advanced");
|
||||||
advancedMenu.add(new JCheckBoxMenuItem(executionDetailsAction) {
|
advancedMenu.add(new JCheckBoxMenuItem(executionDetailsAction) {
|
||||||
|
@ -1535,13 +1417,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
return executionDetails;
|
return executionDetails;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
advancedMenu.add(new JCheckBoxMenuItem(radioChannelsAction) {
|
|
||||||
private static final long serialVersionUID = 6830282466652559714L;
|
|
||||||
public boolean isSelected() {
|
|
||||||
return radioChannels;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
/* popupMenu.add(advancedMenu);*/
|
|
||||||
|
|
||||||
addMouseListener(new MouseAdapter() {
|
addMouseListener(new MouseAdapter() {
|
||||||
long lastClick = -1;
|
long lastClick = -1;
|
||||||
|
@ -1741,7 +1616,7 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
|
|
||||||
/*logger.info("Painting interval: " + intervalStart + " -> " + intervalEnd);*/
|
/*logger.info("Painting interval: " + intervalStart + " -> " + intervalEnd);*/
|
||||||
if (bounds.x > Integer.MAX_VALUE - 1000) {
|
if (bounds.x > Integer.MAX_VALUE - 1000) {
|
||||||
/* TODO Strange bounds */
|
/* Strange bounds */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1779,14 +1654,14 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
}
|
}
|
||||||
lineHeightOffset += EVENT_PIXEL_HEIGHT;
|
lineHeightOffset += EVENT_PIXEL_HEIGHT;
|
||||||
}
|
}
|
||||||
if (showRadioHW) {
|
if (showRadioOnoff) {
|
||||||
MoteEvent firstEvent = getFirstIntervalEvent(allMoteEvents.get(mIndex).radioHWEvents, intervalStart);
|
MoteEvent firstEvent = getFirstIntervalEvent(allMoteEvents.get(mIndex).radioHWEvents, intervalStart);
|
||||||
if (firstEvent != null) {
|
if (firstEvent != null) {
|
||||||
firstEvent.paintInterval(g, lineHeightOffset, intervalEnd);
|
firstEvent.paintInterval(g, lineHeightOffset, intervalEnd);
|
||||||
}
|
}
|
||||||
lineHeightOffset += EVENT_PIXEL_HEIGHT;
|
lineHeightOffset += EVENT_PIXEL_HEIGHT;
|
||||||
}
|
}
|
||||||
if (showLEDs) {
|
if (showLeds) {
|
||||||
MoteEvent firstEvent = getFirstIntervalEvent(allMoteEvents.get(mIndex).ledEvents, intervalStart);
|
MoteEvent firstEvent = getFirstIntervalEvent(allMoteEvents.get(mIndex).ledEvents, intervalStart);
|
||||||
if (firstEvent != null) {
|
if (firstEvent != null) {
|
||||||
firstEvent.paintInterval(g, lineHeightOffset, intervalEnd);
|
firstEvent.paintInterval(g, lineHeightOffset, intervalEnd);
|
||||||
|
@ -1931,13 +1806,13 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
}
|
}
|
||||||
evMatched++;
|
evMatched++;
|
||||||
}
|
}
|
||||||
if (showRadioHW) {
|
if (showRadioOnoff) {
|
||||||
if (evMatched == evMouse) {
|
if (evMatched == evMouse) {
|
||||||
events = allMoteEvents.get(mote).radioHWEvents;
|
events = allMoteEvents.get(mote).radioHWEvents;
|
||||||
}
|
}
|
||||||
evMatched++;
|
evMatched++;
|
||||||
}
|
}
|
||||||
if (showLEDs) {
|
if (showLeds) {
|
||||||
if (evMatched == evMouse) {
|
if (evMatched == evMouse) {
|
||||||
events = allMoteEvents.get(mote).ledEvents;
|
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[] {
|
private final static Color[] CHANNEL_COLORS = new Color[] {
|
||||||
Color.decode("0x008080"), Color.decode("0x808080"), Color.decode("0xC00000"),
|
Color.decode("0x008080"), Color.decode("0x808080"), Color.decode("0xC00000"),
|
||||||
Color.decode("0x000020"), Color.decode("0x202000"), Color.decode("0x200020"),
|
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("0x00FF00"), Color.decode("0x0000FF"), Color.decode("0xFFFF00"),
|
||||||
Color.decode("0xFF00FF"), Color.decode("0x808000"), Color.decode("0x800080"),
|
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 {
|
class RadioHWEvent extends MoteEvent {
|
||||||
boolean on;
|
boolean on;
|
||||||
int channel = -1;
|
|
||||||
public RadioHWEvent(long time, boolean on) {
|
public RadioHWEvent(long time, boolean on) {
|
||||||
super(time);
|
super(time);
|
||||||
this.on = on;
|
this.on = on;
|
||||||
}
|
}
|
||||||
public RadioHWEvent(long time, boolean on, int channel) {
|
public RadioHWEvent(long time, boolean on, int channel) {
|
||||||
this(time, on);
|
this(time, on);
|
||||||
this.channel = channel;
|
|
||||||
}
|
}
|
||||||
public Color getEventColor() {
|
public Color getEventColor() {
|
||||||
if (on && radioChannels && channel >= 0 && channel < CHANNEL_COLORS.length) {
|
if (on) {
|
||||||
return CHANNEL_COLORS[channel];
|
return Color.GRAY;
|
||||||
}
|
}
|
||||||
return on?Color.GRAY:null;
|
return null;
|
||||||
}
|
}
|
||||||
public String toString() {
|
public String toString() {
|
||||||
String str = "Radio HW was turned " + (on?"on":"off") + " at time " + time + "<br>";
|
String str = "Radio HW was turned " + (on?"on":"off") + "<br>";
|
||||||
if (channel > 0) {
|
|
||||||
str += "Radio channel: " + channel;
|
|
||||||
}
|
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2298,11 +2183,56 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class LogEvent extends MoteEvent {
|
class LogEvent extends MoteEvent {
|
||||||
public LogEvent(long time) {
|
LogOutputEvent logEvent;
|
||||||
super(time);
|
public LogEvent(LogOutputEvent ev) {
|
||||||
|
super(ev.getTime());
|
||||||
|
this.logEvent = ev;
|
||||||
}
|
}
|
||||||
public Color getEventColor() {
|
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 {
|
class WatchpointEvent extends MoteEvent {
|
||||||
|
@ -2434,7 +2364,6 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
}
|
}
|
||||||
lastRadioChannelEvent = ev;
|
lastRadioChannelEvent = ev;
|
||||||
|
|
||||||
/* TODO XXX Requires MSPSim changes */
|
|
||||||
radioChannelEvents.add(ev);
|
radioChannelEvents.add(ev);
|
||||||
}
|
}
|
||||||
public void addRadioHW(RadioHWEvent ev) {
|
public void addRadioHW(RadioHWEvent ev) {
|
||||||
|
@ -2530,19 +2459,23 @@ public class TimeLine extends VisPlugin implements HasQuickHelp {
|
||||||
"<b>Timeline</b>" +
|
"<b>Timeline</b>" +
|
||||||
"<p>The timeline shows simulation events over time. " +
|
"<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." +
|
"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. " +
|
"<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>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>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>For more options for a given event, right-click the mouse for a popup menu." +
|
||||||
"<p><b>Radio traffic</b>" +
|
"<p><b>Radio traffic</b>" +
|
||||||
"<br>Shows radio traffic events. Transmissions are painted blue, receptions are green, and interfered radios are red." +
|
"<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." +
|
"<br>Shows whether the mote radio is on or off. When gray, the radio is on." +
|
||||||
"<p><b>LEDs</b>" +
|
"<p><b>LEDs</b>" +
|
||||||
"<br>Shows LED state: red, green, and blue. (Assumes all mote types have exactly three LEDs.)" +
|
"<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>" +
|
"<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 {
|
try {
|
||||||
VisualizerSkin newSkin = skinClass.newInstance();
|
VisualizerSkin newSkin = skinClass.newInstance();
|
||||||
newSkin.setActive(Visualizer.this.simulation, Visualizer.this);
|
newSkin.setActive(Visualizer.this.simulation, Visualizer.this);
|
||||||
currentSkins.add(newSkin);
|
currentSkins.add(0, newSkin);
|
||||||
} catch (InstantiationException e1) {
|
} catch (InstantiationException e1) {
|
||||||
e1.printStackTrace();
|
e1.printStackTrace();
|
||||||
} catch (IllegalAccessException e1) {
|
} catch (IllegalAccessException e1) {
|
||||||
|
@ -700,7 +700,26 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
|
||||||
menu.setVisible(true);
|
menu.setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean showMoteToMoteRelations = true;
|
||||||
private void populateSkinMenu(MenuElement menu) {
|
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) {
|
for (Class<? extends VisualizerSkin> skinClass: visualizerSkins) {
|
||||||
/* Should skin be enabled in this simulation? */
|
/* Should skin be enabled in this simulation? */
|
||||||
if (!isSkinCompatible(skinClass)) {
|
if (!isSkinCompatible(skinClass)) {
|
||||||
|
@ -998,16 +1017,18 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
|
||||||
Mote[] allMotes = simulation.getMotes();
|
Mote[] allMotes = simulation.getMotes();
|
||||||
|
|
||||||
/* Paint mote relations */
|
/* Paint mote relations */
|
||||||
MoteRelation[] relations = simulation.getGUI().getMoteRelations();
|
if (showMoteToMoteRelations) {
|
||||||
for (MoteRelation r: relations) {
|
MoteRelation[] relations = simulation.getGUI().getMoteRelations();
|
||||||
Position sourcePos = r.source.getInterfaces().getPosition();
|
for (MoteRelation r: relations) {
|
||||||
Position destPos = r.dest.getInterfaces().getPosition();
|
Position sourcePos = r.source.getInterfaces().getPosition();
|
||||||
|
Position destPos = r.dest.getInterfaces().getPosition();
|
||||||
|
|
||||||
Point sourcePoint = transformPositionToPixel(sourcePos);
|
Point sourcePoint = transformPositionToPixel(sourcePos);
|
||||||
Point destPoint = transformPositionToPixel(destPos);
|
Point destPoint = transformPositionToPixel(destPos);
|
||||||
|
|
||||||
g.setColor(r.color == null ? Color.black : r.color);
|
g.setColor(r.color == null ? Color.black : r.color);
|
||||||
drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y, MOTE_RADIUS + 1);
|
drawArrow(g, sourcePoint.x, sourcePoint.y, destPoint.x, destPoint.y, MOTE_RADIUS + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Mote mote: allMotes) {
|
for (Mote mote: allMotes) {
|
||||||
|
@ -1264,11 +1285,19 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
|
||||||
ArrayList<Element> config = new ArrayList<Element>();
|
ArrayList<Element> config = new ArrayList<Element>();
|
||||||
Element element;
|
Element element;
|
||||||
|
|
||||||
|
/* Show mote-to-mote relations */
|
||||||
|
if (showMoteToMoteRelations) {
|
||||||
|
element = new Element("moterelations");
|
||||||
|
element.setText("" + true);
|
||||||
|
config.add(element);
|
||||||
|
}
|
||||||
|
|
||||||
/* Skins */
|
/* Skins */
|
||||||
for (VisualizerSkin skin: currentSkins) {
|
for (int i=currentSkins.size()-1; i >= 0; i--) {
|
||||||
element = new Element("skin");
|
VisualizerSkin skin = currentSkins.get(i);
|
||||||
element.setText(skin.getClass().getName());
|
element = new Element("skin");
|
||||||
config.add(element);
|
element.setText(skin.getClass().getName());
|
||||||
|
config.add(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Viewport */
|
/* Viewport */
|
||||||
|
@ -1298,6 +1327,7 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
|
||||||
|
|
||||||
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
public boolean setConfigXML(Collection<Element> configXML, boolean visAvailable) {
|
||||||
loadedConfig = true;
|
loadedConfig = true;
|
||||||
|
showMoteToMoteRelations = false;
|
||||||
|
|
||||||
for (Element element : configXML) {
|
for (Element element : configXML) {
|
||||||
if (element.getName().equals("skin")) {
|
if (element.getName().equals("skin")) {
|
||||||
|
@ -1319,6 +1349,8 @@ public class Visualizer extends VisPlugin implements HasQuickHelp {
|
||||||
if (wanted != null) {
|
if (wanted != null) {
|
||||||
logger.warn("Could not load visualizer: " + element.getText());
|
logger.warn("Could not load visualizer: " + element.getText());
|
||||||
}
|
}
|
||||||
|
} else if (element.getName().equals("moterelations")) {
|
||||||
|
showMoteToMoteRelations = true;
|
||||||
} else if (element.getName().equals("viewport")) {
|
} else if (element.getName().equals("viewport")) {
|
||||||
try {
|
try {
|
||||||
String[] matrix = element.getText().split(" ");
|
String[] matrix = element.getText().split(" ");
|
||||||
|
|
|
@ -341,8 +341,8 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Radio dstRadio : connection.getAllDestinations()) {
|
for (Radio dstRadio : connection.getAllDestinations()) {
|
||||||
|
if (!(dstRadio instanceof CustomDataRadio) ||
|
||||||
if (!radio.getClass().equals(dstRadio.getClass()) || !(radio instanceof CustomDataRadio)) {
|
!((CustomDataRadio) dstRadio).canReceiveFrom((CustomDataRadio)radio)) {
|
||||||
/* Radios communicate via radio packets */
|
/* Radios communicate via radio packets */
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -383,11 +383,14 @@ public abstract class AbstractRadioMedium extends RadioMedium {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Radio dstRadio : connection.getAllDestinations()) {
|
for (Radio dstRadio : connection.getAllDestinations()) {
|
||||||
|
|
||||||
if (radio.getClass().equals(dstRadio.getClass()) && radio instanceof CustomDataRadio) {
|
if ((radio instanceof CustomDataRadio) &&
|
||||||
/* Radios instead communicate via custom data objects */
|
(dstRadio instanceof CustomDataRadio) &&
|
||||||
continue;
|
((CustomDataRadio) dstRadio).canReceiveFrom((CustomDataRadio)radio)) {
|
||||||
}
|
/* Radios instead communicate via custom data objects */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Forward radio packet */
|
/* Forward radio packet */
|
||||||
if (connection.getDestinationDelay(dstRadio) == 0) {
|
if (connection.getDestinationDelay(dstRadio) == 0) {
|
||||||
|
|
|
@ -28,17 +28,12 @@
|
||||||
|
|
||||||
package se.sics.cooja.util;
|
package se.sics.cooja.util;
|
||||||
|
|
||||||
import java.awt.Container;
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
import javax.swing.JFileChooser;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some utility methods for managing arrays.
|
* Some utility methods for managing arrays.
|
||||||
|
|
Loading…
Reference in a new issue