event based mote interfaces + reimplemented cross level functionality for TR1001

This commit is contained in:
fros4943 2009-05-26 14:33:30 +00:00
parent c59fc91487
commit 1c22bf5151
4 changed files with 135 additions and 192 deletions

View file

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: SkyByteRadio.java,v 1.11 2009/05/04 15:34:00 fros4943 Exp $
* $Id: SkyByteRadio.java,v 1.12 2009/05/26 14:33:30 fros4943 Exp $
*/
package se.sics.cooja.mspmote.interfaces;
@ -74,7 +74,6 @@ public class SkyByteRadio extends Radio implements CustomDataRadio {
private boolean isTransmitting = false;
private boolean isReceiving = false;
// private boolean hasFailedReception = false;
private CC2420RadioByte lastOutgoingByte = null;
@ -84,10 +83,6 @@ public class SkyByteRadio extends Radio implements CustomDataRadio {
private RadioPacket lastIncomingPacket = null;
// private int mode;
//TODO: HW on/off
public SkyByteRadio(Mote mote) {
this.mote = (SkyMote) mote;
this.cc2420 = this.mote.skyNode.radio;
@ -167,15 +162,14 @@ public class SkyByteRadio extends Radio implements CustomDataRadio {
private byte[] crossBufferedData = null;
private TimeEvent receiveCrosslevelDataEvent = new TimeEvent(0) {
private TimeEvent deliverPacketDataEvent = new TimeEvent(0) {
public void execute(long t) {
if (crossBufferedData == null) {
return;
}
/*logger.info("Radio is now ready to receive the incoming data");*/
/*logger.info("Delivering buffered packet data now: " + mote.getSimulation().getSimulationTime());*/
for (byte b: crossBufferedData) {
cc2420.receivedByte(b);
}
@ -185,31 +179,32 @@ public class SkyByteRadio extends Radio implements CustomDataRadio {
private StateListener cc2420StateListener = new StateListener() {
public void newState(RadioState state) {
if (cc2420.getState() == CC2420.RadioState.RX_SFD_SEARCH) {
cc2420.setStateListener(null);
if (crossBufferedData == null) {
return;
}
/* Receive data very soon (just wait for a radio flush) */
mote.getSimulation().scheduleEvent(
receiveCrosslevelDataEvent,
mote.getSimulation().getSimulationTime()+1
);
if (cc2420.getState() != CC2420.RadioState.RX_SFD_SEARCH) {
return;
}
cc2420.setStateListener(null);
if (crossBufferedData == null) {
return;
}
/*logger.info("Radio was turned on! Short delay before transmitting buffered data: " + mote.getSimulation().getSimulationTime());*/
/* Deliver data after the radio drivers flush */
mote.getSimulation().scheduleEvent(
deliverPacketDataEvent,
mote.getSimulation().getSimulationTime()+Simulation.MILLISECOND/3
);
}
};
public void setReceivedPacket(RadioPacket packet) {
lastIncomingPacket = packet;
/* TODO Receiving all bytes at the same time ok? */
byte[] packetData = CC2420RadioPacketConverter.fromCoojaToCC2420(packet);
if (cc2420.getState() != CC2420.RadioState.RX_SFD_SEARCH) {
/*logger.info("Radio is not currently active. Let's wait some...");*/
/*logger.info("Radio is turned off. Buffering data.");*/
crossBufferedData = packetData;
cc2420.setStateListener(cc2420StateListener);
@ -218,6 +213,7 @@ public class SkyByteRadio extends Radio implements CustomDataRadio {
return;
}
/* Delivering data immediately */
for (byte b: packetData) {
cc2420.receivedByte(b);
}

View file

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: TR1001Radio.java,v 1.12 2009/04/16 14:28:12 fros4943 Exp $
* $Id: TR1001Radio.java,v 1.13 2009/05/26 14:33:30 fros4943 Exp $
*/
package se.sics.cooja.mspmote.interfaces;
@ -48,23 +48,27 @@ import se.sics.cooja.mspmote.ESBMote;
/**
* TR1001 radio interface on ESB platform. Assumes driver specifics such as
* preambles, synchbytes, GCR coding, CRC16.
*
*
* @author Fredrik Osterlind
*/
@ClassDescription("TR1001 Radio")
public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio {
public class TR1001Radio extends Radio implements USARTListener,
CustomDataRadio {
private static Logger logger = Logger.getLogger(TR1001Radio.class);
/**
* Minimum delay in CPU cycles between each byte fed to USART.
* Delay used when feeding packet data to radio chip (us). 416us corresponds
* to 19200 bit/s with encoding.
*/
public static final long CYCLES_BETWEEN_BYTES = 1200; /* ~19.200 bps */
public static final long DELAY_BETWEEN_BYTES = 3 * 416;
private ESBMote mote;
private boolean radioOn = true;
private boolean transmitting = false;
private boolean isTransmitting = false;
private boolean isReceiving = false;
private boolean isInterfered = false;
@ -74,7 +78,7 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
private USART radioUSART = null;
private RadioPacket packetToMote = null;
private RadioPacket lastIncomingPacket = null;
private RadioPacket packetFromMote = null;
@ -83,34 +87,22 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
private int outgoingDataLength = 0;
private int ticksSinceLastSend = -1;
/* Incoming byte-to-packet data buffer */
private Vector<Byte> bufferedBytes = new Vector<Byte>();
private Vector<Long> bufferedByteDelays = new Vector<Long>();
private int millisSinceLastSend = -1;
/* Outgoing byte data buffer */
private TR1001RadioByte tr1001ByteFromMote = null;
private TR1001RadioByte tr1001ByteToMote = null;
private TR1001RadioByte lastIncomingByte = null;
private long transmissionStartCycles = -1;
/* Incoming byte data buffer */
private byte lastDeliveredByte = -1;
private long lastDeliveredByteTimestamp = -1;
private long lastDeliveredByteDelay = -1;
private TR1001RadioPacketConverter tr1001PacketConverter = null;
private double signalStrength = 0;
/**
* Creates an interface to the TR1001 radio at mote.
*
*
* @param mote
* Radio's mote.
* @see Mote
@ -133,28 +125,34 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
}
public RadioPacket getLastPacketReceived() {
return packetToMote;
return lastIncomingPacket;
}
public void setReceivedPacket(RadioPacket packet) {
packetToMote = packet;
if (packetToMote.getPacketData() == null || packetToMote.getPacketData().length == 0) {
logger.fatal("Received null packet");
return;
}
if (isInterfered) {
logger.fatal("Received packet when interfered");
return;
}
lastIncomingPacket = packet;
/* Convert to TR1001 packet data */
TR1001RadioByte[] tr1001bytes = TR1001RadioPacketConverter.fromCoojaToTR1001(packetToMote);
/* Feed to the CPU "slowly" */
for (TR1001RadioByte b : tr1001bytes) {
receiveCustomData(b);
TR1001RadioByte[] byteArr = TR1001RadioPacketConverter.fromCoojaToTR1001(packet);
final ArrayList<TR1001RadioByte> byteList = new ArrayList<TR1001RadioByte>();
for (TR1001RadioByte b : byteArr) {
byteList.add(b);
}
/* Feed incoming bytes to radio "slowly" via time events */
TimeEvent receiveCrosslevelDataEvent = new TimeEvent(0) {
public void execute(long t) {
/* Stop receiving data when buffer is empty */
if (byteList.isEmpty() || isInterfered) {
return;
}
TR1001RadioByte b = byteList.remove(0);
radioUSART.byteReceived(b.getByte());
mote.getSimulation().scheduleEvent(this, t + DELAY_BETWEEN_BYTES);
}
};
receiveCrosslevelDataEvent.execute(mote.getSimulation().getSimulationTime());
}
/* Custom data radio support */
@ -163,84 +161,32 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
}
public Object getLastCustomDataReceived() {
return tr1001ByteToMote;
return lastIncomingByte;
}
public void receiveCustomData(Object data) {
if (data instanceof TR1001RadioByte) {
tr1001ByteToMote = ((TR1001RadioByte) data);
lastIncomingByte = ((TR1001RadioByte) data);
bufferedBytes.add(tr1001ByteToMote.getByte());
bufferedByteDelays.add(tr1001ByteToMote.getDelay());
if (radioUSART.isReceiveFlagCleared()) {
/*logger.info("----- TR1001 RECEIVED BYTE -----");*/
radioUSART.byteReceived(lastIncomingByte.getByte());
} else {
logger.warn("----- TR1001 RECEIVED BYTE DROPPED -----");
}
}
}
/**
* @return True if undelivered bytes exist.
*/
public boolean hasPendingBytes() {
return bufferedBytes.size() > 0;
}
/**
* If non-delivered bytes exist, tries to deliver one byte to the CPU by
* checking USART receive flag.
*
* @param cycles
* Current CPU cycles
*/
public void tryDeliverNextByte(long cycles) {
// Check that pending bytes exist
if (!hasPendingBytes()) {
return;
}
// Check if time to deliver byte
long nextByteDelay = bufferedByteDelays.firstElement();
if (cycles - lastDeliveredByteDelay < nextByteDelay) {
return;
}
lastDeliveredByte = bufferedBytes.firstElement();
bufferedBytes.remove(0);
bufferedByteDelays.remove(0);
if (radioUSART.isReceiveFlagCleared()) {
//logger.info(nextByteDelay + " < "
// + (cycles - receptionStartedCycles)
// + ":\tDelivering 0x" + Utils.hex8(lastDeliveredByte) + " (TODO="
// + bufferedBytes.size() + ")");
radioUSART.byteReceived(lastDeliveredByte);
} else {
/*logger.fatal(nextByteDelay + " < "
+ (cycles - receptionStartedCycles)
+ ":\tDROPPING 0x" + Utils.hex8(lastDeliveredByte) + " (TODO="
+ bufferedBytes.size() + ")");*/
}
lastDeliveredByteDelay = cycles;
// /* TODO BUG: Resends last byte, interrupt lost somewhere? */
// else if (cycles > lastDeliveredByteTimestamp + CYCLES_BETWEEN_BYTES) {
// logger.warn("0x" + Utils.hex16((int) cycles) + ":\tRedelivering 0x"
// + Utils.hex8(lastDeliveredByte) + " (TODO=" + bufferedBytes.size()
// + ")");
// radioUSART.byteReceived(lastDeliveredByte);
// lastDeliveredByteTimestamp = cycles;
// }
}
/* USART listener support */
public void dataReceived(USART source, int data) {
if (outgoingDataLength == 0 && !isTransmitting()) {
/* New transmission discovered */
/*logger.debug("----- NEW TR1001 TRANSMISSION DETECTED -----");*/
/*logger.info("----- NEW TR1001 TRANSMISSION DETECTED -----");*/
tr1001PacketConverter = new TR1001RadioPacketConverter();
transmitting = true;
isTransmitting = true;
transmissionStartCycles = mote.getCPU().cycles;
lastDeliveredByteTimestamp = transmissionStartCycles;
lastEvent = RadioEvent.TRANSMISSION_STARTED;
lastEventTime = mote.getSimulation().getSimulationTime();
@ -249,49 +195,51 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
}
// Remember recent radio activity
ticksSinceLastSend = 0;
mote.getSimulation().scheduleEvent(followupTransmissionEvent, mote.getSimulation().getSimulationTime()+1);
millisSinceLastSend = 0;
mote.getSimulation().scheduleEvent(
followupTransmissionEvent,
mote.getSimulation().getSimulationTime() + Simulation.MILLISECOND);
if (outgoingDataLength >= outgoingData.length) {
logger.fatal("Ignoring byte due to buffer overflow");
logger.warn("----- TR1001 DROPPING OUTGOING BYTE (buffer overflow) -----");
return;
}
// Deliver byte to radio medium as custom data
/*logger.debug("----- TR1001 DELIVERED BYTE -----");*/
/* logger.debug("----- TR1001 SENT BYTE -----"); */
lastEvent = RadioEvent.CUSTOM_DATA_TRANSMITTED;
tr1001ByteFromMote = new TR1001RadioByte((byte) data, mote.getCPU().cycles - lastDeliveredByteTimestamp);
tr1001ByteFromMote = new TR1001RadioByte((byte) data);
this.setChanged();
this.notifyObservers();
lastDeliveredByteTimestamp = mote.getCPU().cycles;
outgoingData[outgoingDataLength++] = tr1001ByteFromMote;
// Feed to application level immediately
boolean finished = tr1001PacketConverter.fromTR1001ToCoojaAccumulated(tr1001ByteFromMote);
boolean finished = tr1001PacketConverter
.fromTR1001ToCoojaAccumulated(tr1001ByteFromMote);
if (finished) {
/* Transmission finished - deliver packet immediately */
if (tr1001PacketConverter.accumulatedConversionIsOk()) {
packetFromMote = tr1001PacketConverter.getAccumulatedConvertedCoojaPacket();
/* Transmission finished - deliver packet immediately */
if (tr1001PacketConverter.accumulatedConversionIsOk()) {
packetFromMote = tr1001PacketConverter.getAccumulatedConvertedCoojaPacket();
/* Notify observers of new prepared packet */
/*logger.debug("----- TR1001 DELIVERED PACKET -----");*/
lastEvent = RadioEvent.PACKET_TRANSMITTED;
this.setChanged();
this.notifyObservers();
}
// Reset counters and wait for next packet
outgoingDataLength = 0;
ticksSinceLastSend = -1;
// Signal we are done transmitting
transmitting = false;
lastEvent = RadioEvent.TRANSMISSION_FINISHED;
/* Notify observers of new prepared packet */
/* logger.info("----- TR1001 DELIVERED PACKET -----"); */
lastEvent = RadioEvent.PACKET_TRANSMITTED;
this.setChanged();
this.notifyObservers();
}
/*logger.debug("----- TR1001 TRANSMISSION ENDED -----");*/
// Reset counters and wait for next packet
outgoingDataLength = 0;
millisSinceLastSend = -1;
// Signal we are done transmitting
isTransmitting = false;
lastEvent = RadioEvent.TRANSMISSION_FINISHED;
this.setChanged();
this.notifyObservers();
/* logger.info("----- TR1001 TRANSMISSION ENDED -----"); */
}
}
@ -300,11 +248,11 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
/* General radio support */
public boolean isTransmitting() {
return transmitting;
return isTransmitting;
}
public boolean isReceiving() {
return hasPendingBytes();
return isReceiving;
}
public boolean isInterfered() {
@ -317,18 +265,14 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
public void signalReceptionStart() {
lastEvent = RadioEvent.RECEPTION_STARTED;
/*receptionStartedCycles = mspMote.getCPU().cycles;*/
isReceiving = true;
this.setChanged();
this.notifyObservers();
}
public void signalReceptionEnd() {
// TODO Should be done according to serial port instead
// TODO Compare times with OS abstraction level
if (isInterfered()) {
isInterfered = false;
return;
}
isInterfered = false;
isReceiving = false;
lastEvent = RadioEvent.RECEPTION_FINISHED;
this.setChanged();
this.notifyObservers();
@ -341,12 +285,11 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
public void interfereAnyReception() {
if (!isInterfered()) {
isInterfered = true;
lastIncomingPacket = null;
bufferedBytes.clear();
bufferedByteDelays.clear();
lastEvent = RadioEvent.RECEPTION_INTERFERED;
lastEventTime = mote.getSimulation().getSimulationTime();
lastEvent = RadioEvent.RECEPTION_INTERFERED;
/*logger.info("----- TR1001 RECEPTION INTERFERED -----");*/
this.setChanged();
this.notifyObservers();
}
@ -382,19 +325,19 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
public void execute(long t) {
if (isTransmitting()) {
ticksSinceLastSend++;
millisSinceLastSend++;
// Detect transmission end due to inactivity
if (ticksSinceLastSend > 4) {
if (millisSinceLastSend > 5) {
/* Dropping packet due to inactivity */
packetFromMote = null;
/* Reset counters and wait for next packet */
outgoingDataLength = 0;
ticksSinceLastSend = -1;
millisSinceLastSend = -1;
/* Signal we are done transmitting */
transmitting = false;
isTransmitting = false;
lastEvent = RadioEvent.TRANSMISSION_FINISHED;
TR1001Radio.this.setChanged();
TR1001Radio.this.notifyObservers();
@ -403,7 +346,7 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
}
/* Reschedule as long as node is transmitting */
mote.getSimulation().scheduleEvent(this, t+1);
mote.getSimulation().scheduleEvent(this, t + Simulation.MILLISECOND);
}
}
};
@ -440,7 +383,9 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
updateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" + getCurrentOutputPowerIndicator() + "/" + getOutputPowerIndicatorMax() + ")");
powerLabel.setText(getCurrentOutputPower() + " dBm (indicator="
+ getCurrentOutputPowerIndicator() + "/"
+ getOutputPowerIndicatorMax() + ")");
ssLabel.setText(getCurrentSignalStrength() + " dBm");
}
});
@ -460,7 +405,9 @@ public class TR1001Radio extends Radio implements USARTListener, CustomDataRadio
lastEventLabel.setText(lastEvent + " @ time=" + lastEventTime);
powerLabel.setText(getCurrentOutputPower() + " dBm (indicator=" + getCurrentOutputPowerIndicator() + "/" + getOutputPowerIndicatorMax() + ")");
powerLabel.setText(getCurrentOutputPower() + " dBm (indicator="
+ getCurrentOutputPowerIndicator() + "/"
+ getOutputPowerIndicatorMax() + ")");
ssLabel.setText(getCurrentSignalStrength() + " dBm");
}
});

View file

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: TR1001RadioByte.java,v 1.1 2008/03/18 13:08:26 fros4943 Exp $
* $Id: TR1001RadioByte.java,v 1.2 2009/05/26 14:33:30 fros4943 Exp $
*/
package se.sics.cooja.mspmote.interfaces;
@ -40,14 +40,11 @@ public class TR1001RadioByte {
private byte b;
private long delay;
/**
* Creates new TR1001 radio byte
*/
public TR1001RadioByte(byte b, long delay) {
public TR1001RadioByte(byte b) {
this.b = b;
this.delay = delay;
}
/**
@ -57,11 +54,4 @@ public class TR1001RadioByte {
return b;
}
/**
* @return Cycle delay since previous byte
*/
public long getDelay() {
return delay;
}
}

View file

@ -26,14 +26,16 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: TR1001RadioPacketConverter.java,v 1.3 2008/03/18 16:55:44 fros4943 Exp $
* $Id: TR1001RadioPacketConverter.java,v 1.4 2009/05/26 14:33:30 fros4943 Exp $
*/
package se.sics.cooja.mspmote.interfaces;
import java.util.ArrayList;
import org.apache.log4j.Logger;
import se.sics.cooja.COOJARadioPacket;
import se.sics.cooja.ConvertedRadioPacket;
import se.sics.cooja.RadioPacket;
/**
@ -66,6 +68,7 @@ public class TR1001RadioPacketConverter {
final static int ESB_FOOTER_LENGTH = 2;
private ArrayList<TR1001RadioByte> originalData = new ArrayList<TR1001RadioByte>();
private enum AccumulatedConversionState {
TR1001_PREAMBLE, TR1001_SYNCH, ESB_LEN1, ESB_LEN2, ESB_DATA, ESB_CRC1, ESB_CRC2, ESB_POST,
@ -141,7 +144,7 @@ public class TR1001RadioPacketConverter {
TR1001RadioByte[] tr1001Bytes = new TR1001RadioByte[tr1001Frame.length];
for (int i=0; i < tr1001Frame.length; i++) {
tr1001Bytes[i] = new TR1001RadioByte(tr1001Frame[i], TR1001Radio.CYCLES_BETWEEN_BYTES);
tr1001Bytes[i] = new TR1001RadioByte(tr1001Frame[i]);
}
return tr1001Bytes;
}
@ -160,7 +163,7 @@ public class TR1001RadioPacketConverter {
* @param tr1001DataLength TR1001 specified packet length
* @return COOJA radio packet
*/
public static RadioPacket fromTR1001ToCooja(TR1001RadioByte[] tr1001Bytes, int tr1001DataLength) {
public static ConvertedRadioPacket fromTR1001ToCooja(TR1001RadioByte[] tr1001Bytes, int tr1001DataLength) {
byte[] tr1001Data = new byte[tr1001Bytes.length];
for (int i=0; i < tr1001Bytes.length; i++) {
@ -192,11 +195,11 @@ public class TR1001RadioPacketConverter {
System.arraycopy(decodedData, ESB_HEADER_LENGTH, packetData, 0,
dataLength);
return new COOJARadioPacket(packetData);
return new ConvertedRadioPacket(packetData, tr1001Data);
}
logger.fatal("Error when converting emulated to application level, returning null packet");
return null;
logger.warn("No cross-level conversion available: TR1001 GCR decoding failed");
return new ConvertedRadioPacket(new byte[0], tr1001Data);
}
/**
@ -241,7 +244,8 @@ public class TR1001RadioPacketConverter {
*/
public boolean fromTR1001ToCoojaAccumulated(TR1001RadioByte tr1001Byte) {
byte b = tr1001Byte.getByte();
originalData.add(tr1001Byte);
if (accumulatedConversionState == AccumulatedConversionState.TR1001_PREAMBLE) {
if (b == (byte) 0xaa || b == (byte) 0xff) {
return false;
@ -311,12 +315,18 @@ public class TR1001RadioPacketConverter {
/**
* @return Converted data (application level)
*/
public RadioPacket getAccumulatedConvertedCoojaPacket() {
public ConvertedRadioPacket getAccumulatedConvertedCoojaPacket() {
byte[] dataArrayByte = new byte[accumulatedConversionDataArray.length];
for (int i = 0; i < accumulatedConversionDataArray.length; i++) {
for (int i=0; i < accumulatedConversionDataArray.length; i++) {
dataArrayByte[i] = (byte) accumulatedConversionDataArray[i];
}
return new COOJARadioPacket(dataArrayByte);
byte[] originalArr = new byte[originalData.size()];
for (int i=0; i < originalArr.length; i++) {
originalArr[i] = (byte) originalData.get(i).getByte();
}
return new ConvertedRadioPacket(dataArrayByte, originalArr);
}
/**