diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1101Radio.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1101Radio.java new file mode 100644 index 000000000..6aadc4936 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1101Radio.java @@ -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 getConfigXML() { + return null; + } + + public void setConfigXML(Collection 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; + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1120Radio.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1120Radio.java new file mode 100644 index 000000000..990d1ee8b --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC1120Radio.java @@ -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 getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML, boolean visAvailable) { + } + + public boolean isRadioOn() { + return cc1120.isReadyToReceive(); + } + + public boolean canReceiveFrom(CustomDataRadio radio) { + if (radio.getClass().equals(this.getClass())) { + return true; + } + return false; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC2520Radio.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC2520Radio.java new file mode 100644 index 000000000..9d7aa5185 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC2520Radio.java @@ -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 getConfigXML() { + return null; + } + + public void setConfigXML(Collection 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; + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Mote.java new file mode 100644 index 000000000..bdc0972ee --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Mote.java @@ -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(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430MoteType.java new file mode 100644 index 000000000..f07540341 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430MoteType.java @@ -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[] getDefaultMoteInterfaceClasses() { + return getAllMoteInterfaceClasses(); + } + public Class[] 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"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Radio.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Radio.java new file mode 100644 index 000000000..7e8706598 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/CC430Radio.java @@ -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); + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120Mote.java new file mode 100644 index 000000000..2f390aab3 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120Mote.java @@ -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(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120MoteType.java new file mode 100644 index 000000000..af0d553db --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Eth1120MoteType.java @@ -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[] 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[] 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"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101Mote.java new file mode 100644 index 000000000..bc91c223b --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101Mote.java @@ -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(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101MoteType.java new file mode 100644 index 000000000..3ffdb9d05 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1101MoteType.java @@ -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[] 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[] 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"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120Mote.java new file mode 100644 index 000000000..94e78233e --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120Mote.java @@ -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(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120MoteType.java new file mode 100644 index 000000000..fce599a34 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp1120MoteType.java @@ -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[] 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[] 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"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420Mote.java new file mode 100644 index 000000000..6f084b8f9 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420Mote.java @@ -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(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420MoteType.java new file mode 100644 index 000000000..9424eceac --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Exp2420MoteType.java @@ -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[] 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[] 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"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120Mote.java new file mode 100644 index 000000000..ad39af355 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120Mote.java @@ -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(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120MoteType.java new file mode 100644 index 000000000..c7592be13 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb1120MoteType.java @@ -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[] 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[] 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"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520Mote.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520Mote.java new file mode 100644 index 000000000..5e9036594 --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520Mote.java @@ -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(); + } +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520MoteType.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520MoteType.java new file mode 100644 index 000000000..6ba84a2ad --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/Trxeb2520MoteType.java @@ -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[] 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[] 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"; + } + +} diff --git a/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/TrxebLEDs.java b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/TrxebLEDs.java new file mode 100644 index 000000000..63051195e --- /dev/null +++ b/tools/cooja/apps/mspsim/src/com/thingsquare/cooja/mspsim/TrxebLEDs.java @@ -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 getConfigXML() { + return null; + } + + public void setConfigXML(Collection configXML, boolean visAvailable) { + } + +}