new radio driver (allows for transmissions longer than one tick)

This commit is contained in:
fros4943 2006-10-02 15:18:55 +00:00
parent c69f9298a4
commit 2ae5b09f30

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: ContikiRadio.java,v 1.2 2006/09/26 13:08:05 fros4943 Exp $
* $Id: ContikiRadio.java,v 1.3 2006/10/02 15:18:55 fros4943 Exp $
*/
package se.sics.cooja.contikimote.interfaces;
@ -41,21 +41,27 @@ import se.sics.cooja.contikimote.ContikiMoteInterface;
import se.sics.cooja.interfaces.Radio;
/**
* This class represents a radio transciever.
* This class represents a radio transciever. In order to simulate different
* transmission rates, the underlying Contiki system can be locked in either
* transmission or reception states (using multi-threading). When a transmission
* is initiated, it will automatically lock the Contiki system. When a packet is
* received by this radio the Contiki system, the entitiy transfering the packet may explicitly
* lock the radio in receiving mode. After some time it should then deliver the
* packet.
*
* It needs read/write access to the following core variables:
* <ul>
* <li>char simSentPacket (1=mote has new outgoing data, else no new outgoing
* data)
* <li>char simReceivedPacket (1=mote has new incoming data, else no new
* incoming data)
* <li>char simEtherBusy (1=ether is busy, MAC may try to resend later, else
* not busy)
* <li>int simReceivedPacketSize (size of new received data packet)
* <li>int simSentPacketSize (size of new sent data packet)
* <li>byte[] simSentPacketData (data of new sent data packet)
* <li>byte[] simReceivedPacketData (data of new received data packet)
* <li>char simTransmitting (1=mote radio is transmitting)
* <li>char simReceiving (1=mote radio is receiving)
* <p>
* <li>int simInSize (size of received data packet)
* <li>byte[] simInDataBuffer (data of received data packet)
* <p>
* <li>int simOutSize (size of transmitted data packet)
* <li>byte[] simOutDataBuffer (data of transmitted data packet)
* <p>
* <li>char simRadioHWOn (radio hardware status (on/off))
* <li>int simSignalStrength (heard radio signal strength)
* </ul>
* <p>
* Dependency core interfaces are:
@ -63,13 +69,6 @@ import se.sics.cooja.interfaces.Radio;
* <li>radio_interface
* </ul>
* <p>
* This observable is changed and notifies observers whenever either the send
* status or listen status is changed. If current listen status is HEARS_PACKET
* just before a mote tick, the current packet data is transferred to the core.
* Otherwise no data will be transferred. If core has sent a packet, current
* sent status will be set to SENT_SOMETHING when returning from the mote tick
* that sent the packet. This status will be reset to SENT_NOTHING just before
* next tick.
*
* @author Fredrik Osterlind
*/
@ -86,17 +85,23 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface {
private final boolean RAISES_EXTERNAL_INTERRUPT;
private double energyActiveRadioPerTick = -1;
private int mySendState = SENT_NOTHING;
private int myListenState = HEARS_NOTHING;
private double energyListeningRadioPerTick = -1;
private byte[] packetToMote = null;
private byte[] packetFromMote = null;
private boolean radioOn = true;
private double myEnergyConsumption=0.0;
private double myEnergyConsumption = 0.0;
private boolean transmitting = false;
private int transmissionEndTime = 0;
private int receptionEndTime = 0;
private RadioEvent lastEvent = RadioEvent.UNKNOWN;
private int lastEventTime = 0;
/**
* Creates an interface to the radio at mote.
@ -108,21 +113,27 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface {
*/
public ContikiRadio(Mote mote) {
// Read class configurations of this mote type
ENERGY_CONSUMPTION_RADIO_mA = mote.getType().getConfig().getDoubleValue(ContikiRadio.class, "ACTIVE_CONSUMPTION_mA");
RAISES_EXTERNAL_INTERRUPT = mote.getType().getConfig().getBooleanValue(ContikiRadio.class, "EXTERNAL_INTERRUPT_bool");
ENERGY_CONSUMPTION_RADIO_mA = mote.getType().getConfig().getDoubleValue(
ContikiRadio.class, "ACTIVE_CONSUMPTION_mA");
RAISES_EXTERNAL_INTERRUPT = mote.getType().getConfig().getBooleanValue(
ContikiRadio.class, "EXTERNAL_INTERRUPT_bool");
this.myMote = mote;
this.myMoteMemory = (SectionMoteMemory) mote.getMemory();
if (energyActiveRadioPerTick < 0)
energyActiveRadioPerTick = ENERGY_CONSUMPTION_RADIO_mA * mote.getSimulation().getTickTimeInSeconds();
// Calculate energy consumption of a listening radio
if (energyListeningRadioPerTick < 0)
energyListeningRadioPerTick = ENERGY_CONSUMPTION_RADIO_mA
* mote.getSimulation().getTickTimeInSeconds();
radioOn = myMoteMemory.getByteValueOf("simRadioHWOn") == 1;
}
public static String[] getCoreInterfaceDependencies() {
return new String[] { "radio_interface" };
}
public byte[] getLastPacketSent() {
public byte[] getLastPacketTransmitted() {
return packetFromMote;
}
@ -130,109 +141,179 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface {
return packetToMote;
}
public void receivePacket(byte[] data) {
public boolean isTransmitting() {
return transmitting;
}
public int getTransmissionEndTime() {
return transmissionEndTime;
}
public boolean isReceiving() {
if (isLockedAtReceiving())
return true;
return myMoteMemory.getIntValueOf("simInSize") != 0;
}
public RadioEvent getLastEvent() {
return lastEvent;
}
/**
* @return True if locked at transmitting
*/
private boolean isLockedAtTransmitting() {
return myMoteMemory.getByteValueOf("simTransmitting") == 1;
}
/**
* @return True if locked at receiving
*/
private boolean isLockedAtReceiving() {
return myMoteMemory.getByteValueOf("simReceiving") == 1;
}
/**
* Locks underlying Contiki system in receiving mode. This may, but does not
* have to, be used during a simulated data transfer that takes longer than
* one tick to complete. The system is unlocked by delivering the received
* data to the mote.
*
* @see #receivePacket(byte[])
*/
private void lockInReceivingMode() {
// If mote is inactive, try to wake it up
if (myMote.getState() != Mote.State.ACTIVE) {
if (RAISES_EXTERNAL_INTERRUPT)
myMote.setState(Mote.State.ACTIVE);
if (myMote.getState() != Mote.State.ACTIVE)
return;
}
// Lock core radio in receiving loop
myMoteMemory.setByteValueOf("simReceiving", (byte) 1);
lastEventTime = myMote.getSimulation().getSimulationTime();
lastEvent = RadioEvent.RECEPTION_STARTED;
this.setChanged();
this.notifyObservers();
}
public void receivePacket(byte[] data, int endTime) {
lockInReceivingMode();
receptionEndTime = endTime;
packetToMote = data;
}
public int getSendState() {
return mySendState;
}
public int getListenState() {
return myListenState;
}
public void setListenState(int newStatus) {
if (newStatus != myListenState) {
myListenState = newStatus;
this.setChanged();
this.notifyObservers(myMote.getInterfaces().getPosition());
}
// If mote is inactive, wake it up
private void deliverPacket() {
// If mote is inactive, try to wake it up
if (myMote.getState() != Mote.State.ACTIVE) {
if (RAISES_EXTERNAL_INTERRUPT)
myMote.setState(Mote.State.ACTIVE);
if (myMote.getState() != Mote.State.ACTIVE)
return;
}
public void advanceListenState() {
if (myListenState == HEARS_NOTHING) {
setListenState(HEARS_PACKET);
} else
setListenState(HEARS_NOISE);
// Unlock (if locked)
myMoteMemory.setByteValueOf("simReceiving", (byte) 0);
// Set data
myMoteMemory.setIntValueOf("simInSize", packetToMote.length);
myMoteMemory.setByteArray("simInDataBuffer", packetToMote);
lastEventTime = myMote.getSimulation().getSimulationTime();
lastEvent = RadioEvent.RECEPTION_FINISHED;
this.setChanged();
this.notifyObservers();
}
/**
* Resets receive status. If a packet, or part of a packet, has been received
* but not yet taken care of in the Contiki system, this will be removed.
*/
public void interferReception() {
// Unlock (if locked)
myMoteMemory.setByteValueOf("simReceiving", (byte) 0);
// Reset data
myMoteMemory.setIntValueOf("simInSize", 0);
lastEvent = RadioEvent.RECEPTION_INTERFERED;
lastEventTime = myMote.getSimulation().getSimulationTime();
this.setChanged();
this.notifyObservers();
}
public double getCurrentSignalStrength() {
return myMoteMemory.getIntValueOf("simSignalStrength");
}
public void setCurrentSignalStrength(double signalStrength) {
myMoteMemory.setIntValueOf("simSignalStrength", (int) signalStrength);
}
public void doActionsBeforeTick() {
// If radio hardware is turned off, we don't need to do anything..
// Do nothing
if (isLockedAtReceiving() && myMote.getSimulation().getSimulationTime() >= receptionEndTime)
deliverPacket();
}
public void doActionsAfterTick() {
// Check if radio hardware status changed
if (radioOn != (myMoteMemory.getByteValueOf("simRadioHWOn") == 1)) {
// Radio changed
radioOn = !radioOn;
if (!radioOn) {
// Reset status
myMoteMemory.setByteValueOf("simReceiving", (byte) 0);
myMoteMemory.setIntValueOf("simInSize", 0);
myMoteMemory.setByteValueOf("simTransmitting", (byte) 0);
myMoteMemory.setIntValueOf("simOutSize", 0);
transmitting = false;
lastEvent = RadioEvent.HW_OFF;
} else
lastEvent = RadioEvent.HW_ON;
lastEventTime = myMote.getSimulation().getSimulationTime();
this.setChanged();
this.notifyObservers();
}
if (!radioOn) {
myEnergyConsumption = 0.0;
return;
}
myEnergyConsumption = energyActiveRadioPerTick;
myEnergyConsumption = energyListeningRadioPerTick;
// Set ether status
if (getListenState() == HEARS_PACKET ||
getListenState() == HEARS_NOISE ||
getSendState() == SENT_SOMETHING) {
myMoteMemory.setByteValueOf("simEtherBusy", (byte) 1);
} else {
myMoteMemory.setByteValueOf("simEtherBusy", (byte) 0);
}
// Are we transmitting but should stop?
if (transmitting && myMote.getSimulation().getSimulationTime() >= transmissionEndTime) {
myMoteMemory.setByteValueOf("simTransmitting", (byte) 0);
myMoteMemory.setIntValueOf("simOutSize", 0);
transmitting = false;
if (getListenState() == HEARS_NOTHING) {
// Haven't heard anything, nothing to do
} else if (getListenState() == HEARS_PACKET) {
// Heard only one packet, transfer to mote ok
myMoteMemory.setByteValueOf("simReceivedPacket", (byte) 1);
myMoteMemory.setIntValueOf("simReceivedPacketSize", packetToMote.length);
myMoteMemory.setByteArray("simReceivedPacketData", packetToMote);
} else if (getListenState() == HEARS_NOISE) {
// Heard several packets or noise, transfer failed
}
// Reset send flag
setSendStatus(SENT_NOTHING);
}
public void doActionsAfterTick() {
// Check new radio hardware status
if (myMoteMemory.getByteValueOf("simRadioHWOn") == 1) {
radioOn = true;
} else {
radioOn = false;
return;
}
// Reset listen flag
setListenState(HEARS_NOTHING);
if (fetchPacketFromCore()) {
setSendStatus(SENT_SOMETHING);
}
}
private void setSendStatus(int newStatus) {
if (newStatus != mySendState) {
mySendState = newStatus;
lastEventTime = myMote.getSimulation().getSimulationTime();
lastEvent = RadioEvent.TRANSMISSION_FINISHED;
// TODO Memory consumption of transmitted packet?
this.setChanged();
this.notifyObservers(myMote.getInterfaces().getPosition());
}
this.notifyObservers();
}
private boolean fetchPacketFromCore() {
if (myMoteMemory.getByteValueOf("simSentPacket") == 1) {
// TODO Increase energy consumption, we are sending a packet...
// Check if a new transmission should be started
if (!transmitting && myMoteMemory.getByteValueOf("simTransmitting") == 1) {
transmitting = true;
int size = myMoteMemory.getIntValueOf("simOutSize");
packetFromMote = myMoteMemory.getByteArray("simOutDataBuffer", size);
transmissionEndTime = myMote.getSimulation().getSimulationTime() + 100; // TODO What's the duration?
myMoteMemory.setByteValueOf("simSentPacket", (byte) 0);
int size = myMoteMemory.getIntValueOf("simSentPacketSize");
packetFromMote = myMoteMemory.getByteArray("simSentPacketData", size);
myMoteMemory.setIntValueOf("simSentPacketSize", 0);
return true;
lastEventTime = myMote.getSimulation().getSimulationTime();
lastEvent = RadioEvent.TRANSMISSION_STARTED;
this.setChanged();
this.notifyObservers();
}
return false;
}
public JPanel getInterfaceVisualizer() {
@ -240,41 +321,30 @@ public class ContikiRadio extends Radio implements ContikiMoteInterface {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
final JLabel listenLabel = new JLabel();
final JLabel sendLabel = new JLabel();
final JLabel statusLabel = new JLabel("");
final JLabel lastEventLabel = new JLabel("");
if (getListenState() == HEARS_NOISE)
listenLabel.setText("Current listen status: hears noise");
else if (getListenState() == HEARS_NOTHING)
listenLabel.setText("Current listen status: hears nothing");
else if (getListenState() == HEARS_PACKET)
listenLabel.setText("Current listen status: hears a packet");
if (getSendState() == SENT_NOTHING)
sendLabel.setText("Current sending status: sent nothing");
else if (getSendState() == SENT_SOMETHING)
sendLabel.setText("Current sending status: sent a packet");
panel.add(listenLabel);
panel.add(sendLabel);
panel.add(statusLabel);
panel.add(lastEventLabel);
Observer observer;
this.addObserver(observer = new Observer() {
public void update(Observable obs, Object obj) {
if (getListenState() == HEARS_NOISE)
listenLabel.setText("Current listen status: hears noise");
else if (getListenState() == HEARS_NOTHING)
listenLabel.setText("Current listen status: hears nothing");
else if (getListenState() == HEARS_PACKET)
listenLabel.setText("Current listen status: hears a packet");
if (isTransmitting())
statusLabel.setText("Transmitting packet now!");
else if (isReceiving())
statusLabel.setText("Receiving packet now!");
else if (radioOn)
statusLabel.setText("Listening...");
else
statusLabel.setText("HW turned off");
if (getSendState() == SENT_NOTHING)
sendLabel.setText("Current sending status: sent nothing");
else if (getSendState() == SENT_SOMETHING)
sendLabel.setText("Current sending status: sent a packet");
lastEventLabel.setText("Last event (time=" + lastEventTime + "): " + lastEvent);
}
});
observer.update(null, null);
// Saving observer reference for releaseInterfaceVisualizer
panel.putClientProperty("intf_obs", observer);