Updated the CC1101 and the CC1120 emulation code to the latest version

This commit is contained in:
Adam Dunkels 2015-03-24 15:17:50 +01:00 committed by Niclas Finne
parent bda5832550
commit 79cbf9f00c
2 changed files with 231 additions and 53 deletions

View File

@ -39,7 +39,7 @@ import se.sics.mspsim.core.USARTListener;
import se.sics.mspsim.core.USARTSource;
public class CC1101 extends Radio802154 implements USARTListener {
protected boolean DEBUG = true;
protected boolean DEBUG = false;
/* cc1101-const.h: Configuration registers */
public static final int CC1101_IOCFG1 = 0x01;
@ -133,6 +133,9 @@ public class CC1101 extends Radio802154 implements USARTListener {
public static final int CC1101_SWORRST = 0x3C;
public static final int CC1101_SNOP = 0x3D;
public static final int CC1101_PKTSTATUS_CS_BIT = (1 << 6);
public static final int CC1101_PKTSTATUS_CCA_BIT = (1 << 4);
public static enum CC1101RadioState {
CC1101_STATE_SLEEP(0x00)/* 0 */,
CC1101_STATE_IDLE(0x01),
@ -174,15 +177,18 @@ public class CC1101 extends Radio802154 implements USARTListener {
}
};
public final static double SYMBOL_PERIOD = 0.016; /* TODO XXX 16 us */
public final static double FREQUENCY_CHANNEL_0 = 902; /* MHz */
public final static double FREQUENCY_CHANNEL_WIDTH = 0.125; /* MHz */
public final static int CCA_THRESHOLD = -95;
private boolean triggerGDO0onSynch = false;
private boolean triggerGDO0onFifoThreshold = true;
private StateListener stateListener = null;
private ReceiverListener receiverListener = null;
private boolean currentRssiValid;
private int currentRssiReg = 0;
private CC1101RadioState state = null;
@ -207,6 +213,24 @@ public class CC1101 extends Radio802154 implements USARTListener {
reset();
}
public long getBitRate() {
/* This function returns the current bit rate of the radio. It
should use the CC1101 configuration registers to figure out
the actual bit rate, but this code simply checks for two
specific configurations that correspond to known bit
rates. */
if(registers[CC1101_MDMCFG3] == 0xf8) {
return 50000;
} else if(registers[CC1101_MDMCFG3] == 0x3b) {
return 250000;
}
return 250000;
}
public double getInterByteDelayMs() {
return 1000.0 / (getBitRate() / 8.0);
}
public void log(String str) {
if (DEBUG) {
System.out.println(str);
@ -233,7 +257,38 @@ public class CC1101 extends Radio802154 implements USARTListener {
break;
case CC1101_SRX:
setState(CC1101RadioState.CC1101_STATE_RX);
if(getState() == CC1101RadioState.CC1101_STATE_IDLE ||
getState() == CC1101RadioState.CC1101_STATE_SLEEP) {
log("CC1101 from idle to rx, should wait");
TimeEvent goToRX = new TimeEvent(0, "CC1101 go to RX") {
public void execute(long t) {
if(getState() == CC1101RadioState.CC1101_STATE_RX) {
/* Radio already in RX, ignore */
return;
}
rxfifo.clear();
rxExpectedLen = -1;
rxGotSynchByte = false;
setGDO0(false);
setState(CC1101RadioState.CC1101_STATE_RX);
}
};
int RXTIME = 190;
cpu.scheduleTimeEventMillis(goToRX, RXTIME / 1000.0);
TimeEvent rssiValid = new TimeEvent(0, "CC1101 set RSSI valid") {
public void execute(long t) {
log("RSSI is now valid");
currentRssiValid = true;
}
};
log("RSSI is not valid");
int RSSITIME = 380;
cpu.scheduleTimeEventMillis(rssiValid, RSSITIME / 1000.0);
// setState(CC1101RadioState.CC1101_STATE_RX);
} else {
setStateRX();
}
break;
case CC1101_STX:
@ -248,6 +303,7 @@ public class CC1101 extends Radio802154 implements USARTListener {
case CC1101_SIDLE:
setState(CC1101RadioState.CC1101_STATE_IDLE);
currentRssiValid = false;
break;
case CC1101_SAFC:
@ -259,11 +315,11 @@ public class CC1101 extends Radio802154 implements USARTListener {
break;
case CC1101_SPWD:
log("CC1101_SPWD almost implemented");
// log("CC1101_SPWD almost implemented");
/* TODO XXX
* Wait until CS is de-asserted. (We should at least wait
* receiving or transmitting.)*/
setState(CC1101RadioState.CC1101_STATE_IDLE);
setState(CC1101RadioState.CC1101_STATE_SLEEP);
break;
case CC1101_SFRX:
@ -285,7 +341,7 @@ public class CC1101 extends Radio802154 implements USARTListener {
break;
case CC1101_SNOP:
log("CC1101_SNOP not implemented");
// log("CC1101_SNOP not implemented");
break;
default:
@ -398,6 +454,8 @@ public class CC1101 extends Radio802154 implements USARTListener {
public int getReg(int address) {
/* MSP430Core.profiler.printStackTrace(System.out); */
switch (address) {
case CC1101_CHANNR:
return channel;
case CC1101_MARCSTATE:
return getMarcstate();
case CC1101_RXBYTES:
@ -407,13 +465,14 @@ public class CC1101 extends Radio802154 implements USARTListener {
/*log("getReg(CC1101_TXBYTES) " + txfifo.size());*/
return txfifo.size();
case CC1101_PKTSTATUS:
int status;
final int CCA_BIT = (1<<4);
if(currentRssiReg < CCA_THRESHOLD) {
status = CCA_BIT;
} else {
status = 0;
}
int status = 0;
if(currentRssiValid) {
if(currentRssiReg < CCA_THRESHOLD) {
status |= CC1101_PKTSTATUS_CCA_BIT;
} else {
status |= CC1101_PKTSTATUS_CS_BIT;
}
}
return status;
case CC1101_RSSI:
return currentRssiReg;
@ -421,6 +480,9 @@ public class CC1101 extends Radio802154 implements USARTListener {
if (rxfifo.size() > 0) {
int ret = (int) rxfifo.remove(0);
/*printRXFIFO();*/
if (triggerGDO0onFifoThreshold && rxfifo.size() == 0) {
setGDO0(false);
}
return ret;
}
System.err.println("Warning: reading from empty RXFIFO");
@ -468,7 +530,7 @@ public class CC1101 extends Radio802154 implements USARTListener {
if (rfListener != null) {
rfListener.receivedByte((byte) (0xaa));
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, getInterByteDelayMs());
return;
}
/* Send NUM_SYNCH-1 synch bytes */
@ -477,7 +539,7 @@ public class CC1101 extends Radio802154 implements USARTListener {
if (rfListener != null) {
rfListener.receivedByte((byte) (SYNCH_BYTE_LAST + 1));
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, getInterByteDelayMs());
return;
}
/* Send last synch byte */
@ -486,7 +548,7 @@ public class CC1101 extends Radio802154 implements USARTListener {
if (rfListener != null) {
rfListener.receivedByte((byte) (SYNCH_BYTE_LAST));
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, getInterByteDelayMs());
txSentSynchByte = true;
return;
@ -518,7 +580,7 @@ public class CC1101 extends Radio802154 implements USARTListener {
rfListener.receivedByte((byte) (0xee));
}
txSentFirstCRC = true;
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, getInterByteDelayMs());
return;
}
@ -528,7 +590,8 @@ public class CC1101 extends Radio802154 implements USARTListener {
if (rfListener != null) {
rfListener.receivedByte((byte) 0);
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, getInterByteDelayMs());
setState(CC1101RadioState.CC1101_STATE_TXFIFO_UNDERFLOW);
return;
}
@ -537,7 +600,7 @@ public class CC1101 extends Radio802154 implements USARTListener {
rfListener.receivedByte((byte) (txfifo.get(0).intValue()));
}
txfifo.remove(0);
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, getInterByteDelayMs());
/*printTXFIFO();*/
}
@ -643,11 +706,16 @@ public class CC1101 extends Radio802154 implements USARTListener {
boolean rxGotSynchByte = false;
private int rxExpectedLen = -1;
public void receivedByte(byte data) {
if(state != CC1101RadioState.CC1101_STATE_RX) {
return;
}
if (!rxGotSynchByte) {
/* Await synch byte */
if (data == SYNCH_BYTE_LAST) {
rxGotSynchByte = true;
setGDO0(true);
if(triggerGDO0onSynch) {
setGDO0(true);
}
}
return;
}
@ -663,7 +731,16 @@ public class CC1101 extends Radio802154 implements USARTListener {
rxGotSynchByte = false;
}
rxfifo.add(data);
if (rxfifo.size() < 64) {
rxfifo.add(data);
if (triggerGDO0onFifoThreshold && rxfifo.size() >= 3 && rxExpectedLen > 0) {
setGDO0(true);
}
} else {
log("rxfifo overflow " + rxfifo.size());
setState(CC1101RadioState.CC1101_STATE_RXFIFO_OVERFLOW);
}
/*printRXFIFO();*/
}
@ -749,10 +826,11 @@ public class CC1101 extends Radio802154 implements USARTListener {
void setStateRX() {
setState(CC1101RadioState.CC1101_STATE_RX);
currentRssiValid = true;
}
void reset() {
setState(CC1101RadioState.CC1101_STATE_IDLE);
setState(CC1101RadioState.CC1101_STATE_SLEEP);
registers[CC1101_PARTNUM] = 0;
registers[CC1101_VERSION] = 6;

View File

@ -252,6 +252,9 @@ public class CC1120 extends Radio802154 implements USARTListener {
public final static int CCA_THRESHOLD = -95;
private boolean triggerGDO0onSynch = false;
private boolean triggerGDO0onFifoThreshold = false;
public static enum CC1120RadioState {
CC1120_STATE_SLEEP(0b00000)/* 0 */,
CC1120_STATE_IDLE(0b00001),
@ -297,7 +300,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
protected boolean DEBUG = false;
public final static double SYMBOL_PERIOD = 0.016; /* TODO XXX 16 us */
public final static double BITRATE_BYTE_DURATION = 0.16; /* ms. Duration per byte transmitted, corresponds to 50kbit/s */
public final static double FREQUENCY_CHANNEL_0 = 902; /* MHz */
public final static double FREQUENCY_CHANNEL_WIDTH = 0.125; /* MHz */
@ -355,7 +358,42 @@ public class CC1120 extends Radio802154 implements USARTListener {
break;
case CC1120_SRX:
setState(CC1120RadioState.CC1120_STATE_RX);
if(getState() == CC1120RadioState.CC1120_STATE_IDLE ||
getState() == CC1120RadioState.CC1120_STATE_SLEEP) {
TimeEvent goToRX = new TimeEvent(0, "CC1120 go to RX") {
public void execute(long t) {
if(getState() == CC1120RadioState.CC1120_STATE_RX) {
/* Radio already in RX, ignore */
return;
}
rxfifo.clear();
rxExpectedLen = -1;
rxGotSynchByte = false;
setGDO0(false);
setState(CC1120RadioState.CC1120_STATE_RX);
}
};
/* The time to activate RX depends on SETTLING_CFG's FS_AUTOCAL settings.
* Calibrated from trxeb1120 platform. */
double stateDelay;
int settling = getRegister(CC1120_SETTLING_CFG);
settling = (settling >> 3) & 0b11; /* bit 4:3 */
if (settling == 0) {
stateDelay = 0.20;
} else if (settling == 1) {
stateDelay = 0.50;
} else {
/* not implemented: assuming calibration */
stateDelay = 0.50;
}
cpu.scheduleTimeEventMillis(goToRX, stateDelay);
} else {
setStateRX();
}
break;
case CC1120_STX:
@ -381,7 +419,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
break;
case CC1120_SPWD:
System.out.println("CC1120_SPWD almost implemented");
/*System.out.println("CC1120_SPWD almost implemented");*/
/* TODO XXX
* Wait until CS is de-asserted. (We should at least wait until radio is done
* receiving or transmitting.)*/
@ -526,6 +564,9 @@ public class CC1120 extends Radio802154 implements USARTListener {
return;
}
int setReg(int address, int data, boolean extended) {
/*System.err.println(String.format("setReg(0x%02x, %s) 0x%02x", address,
extended ? "extended" : "normal", data));*/
switch (address) {
case CC1120_TXFIFO:
txfifo.add((byte) data);
@ -540,16 +581,45 @@ public class CC1120 extends Radio802154 implements USARTListener {
case CC1120_FREQ0:
nextFreq0 = data;
return 0;
case CC1120_IOCFG0:
if (data == 65 || data == 1) {
/* CC1120_SETTING_IOCFG0 (IOCFG_GPIO_CFG_RXFIFO_THR_PKT)
* or
* CC1120_SETTING_IOCFG0 (IOCFG_GPIO_CFG_RXFIFO_THR_PKT | IOCFG_GPIO_CFG_INVERT) */
triggerGDO0onFifoThreshold = true;
} else {
/* Assuming:
* CC1120_SETTING_IOCFG0 (IOCFG_GPIO_CFG_PKT_SYNC_RXTX | IOCFG_GPIO_CFG_INVERT) */
triggerGDO0onSynch = true;
}
return 0;
}
System.out.println(String.format("setReg(0x%02x, %s) 0x%02x", address,
extended ? "extended" : "normal", data));
if (extended) {
int oldValue = extendedRegisters[address];
extendedRegisters[address] = data;
configurationChanged(address, oldValue, data);
return oldValue;
}
switch (address) {
case CC1120_DRATE0:
if (data != 0x99) {
System.err.println("Warning: incompatible CC1120 data rate. Only 50kbit/s (0x99) is currently supported. CC1120_DRATE0: " + Integer.toHexString(data));
}
return 0;
case CC1120_DRATE1:
if (data != 0x99) {
System.err.println("Warning: incompatible CC1120 data rate. Only 50kbit/s (0x99) is currently supported. CC1120_DRATE1: " + Integer.toHexString(data));
}
return 0;
case CC1120_DRATE2:
if (data != 0x99) {
System.err.println("Warning: incompatible CC1120 data rate. Only 50kbit/s (0x99) is currently supported. CC1120_DRATE2: " + Integer.toHexString(data));
}
return 0;
}
int oldValue = registers[address];
registers[address] = data;
configurationChanged(address, oldValue, data);
@ -572,7 +642,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
ret += (0b1111 & currentRssiReg0); /* RSSI_3_0 */
ret = ret << 1;
if(getRSSI() < CCA_THRESHOLD) {
if(currentRssi > CCA_THRESHOLD) {
ret += 1; /* Carrier detected */
} else {
ret += 0; /* No carrier detected */
@ -593,18 +663,23 @@ public class CC1120 extends Radio802154 implements USARTListener {
if (rxfifo.size() > 0) {
int ret = (int) rxfifo.remove(0);
/* printRXFIFO(); */
if (triggerGDO0onFifoThreshold && rxfifo.size() == 0) {
setGDO0(false);
}
return ret;
}
System.err.println("Warning: reading from empty RXFIFO");
/* RXFIFO underflow */
setState(CC1120RadioState.CC1120_STATE_RX_FIFO_ERR);
return -1;
}
if (address != CC1120.CC1120_MARCSTATE) {
System.out
.println(String.format("getReg(0x%02x, %s) 0x%02x",
/*System.out.println(String.format("getReg(0x%02x, %s) 0x%02x",
address, extended ? "extended" : "normal",
extended ? extendedRegisters[address]
: registers[address]));
: registers[address]));*/
}
if (extended) {
@ -632,6 +707,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
public static final int NUM_PREAMBLE = 4;
public static final int NUM_SYNCH = 4;
public static final byte SYNCH_BYTE_LAST = (byte) 0xDE;
private boolean txPreambleDelay = false;
private boolean txSentSynchByte = false;
private int txSendSynchByteCnt = 0;
private boolean txSentFirstCRC = false;
@ -641,6 +717,13 @@ public class CC1120 extends Radio802154 implements USARTListener {
return;
}
/* Delay */
if (!txPreambleDelay) {
cpu.scheduleTimeEventMillis(sendEvent, 0.75);
txPreambleDelay = true;
return;
}
/* Send preamble and synch bytes */
if (!txSentSynchByte) {
/* Send NUM_PREAMBLE preamble bytes */
@ -649,7 +732,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
if (rfListener != null) {
rfListener.receivedByte((byte) (0xaa));
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, BITRATE_BYTE_DURATION);
return;
}
/* Send NUM_SYNCH-1 synch bytes */
@ -658,7 +741,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
if (rfListener != null) {
rfListener.receivedByte((byte) (SYNCH_BYTE_LAST + 1));
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, BITRATE_BYTE_DURATION);
return;
}
/* Send last synch byte */
@ -667,7 +750,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
if (rfListener != null) {
rfListener.receivedByte((byte) (SYNCH_BYTE_LAST));
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, BITRATE_BYTE_DURATION);
txSentSynchByte = true;
return;
@ -685,6 +768,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
System.out.println("Warning: TXFIFO not empty after sending CRC bytes");
}
setStateRX();
txPreambleDelay = false;
txSentSynchByte = false;
txSendSynchByteCnt = 0;
txSentFirstCRC = false;
@ -699,7 +783,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
rfListener.receivedByte((byte) (0xee));
}
txSentFirstCRC = true;
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, BITRATE_BYTE_DURATION);
return;
}
@ -709,7 +793,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
if (rfListener != null) {
rfListener.receivedByte((byte) 0);
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, BITRATE_BYTE_DURATION);
return;
}
@ -717,7 +801,7 @@ public class CC1120 extends Radio802154 implements USARTListener {
rfListener.receivedByte((byte) (txfifo.get(0).intValue()));
}
txfifo.remove(0);
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
cpu.scheduleTimeEventMillis(sendEvent, BITRATE_BYTE_DURATION);
/* printTXFIFO(); */
}
@ -777,11 +861,11 @@ public class CC1120 extends Radio802154 implements USARTListener {
}
boolean receiverOn = false;
boolean setState(CC1120RadioState newState) {
boolean setState(final CC1120RadioState newState) {
if (newState != CC1120RadioState.CC1120_STATE_IDLE
&& newState != CC1120RadioState.CC1120_STATE_RX
&& newState != CC1120RadioState.CC1120_STATE_TX) {
System.out.println("setState(" + newState + ")");
/*System.out.println("setState(" + newState + ")");*/
}
if (changeFrequencyNextState
@ -807,12 +891,13 @@ public class CC1120 extends Radio802154 implements USARTListener {
/* Notify state listener */
if (stateListener != null) {
stateListener.newState(state);
stateListener.newState(state);
}
if (receiverListener != null && isReadyToReceive() != receiverOn) {
receiverOn = isReadyToReceive();
receiverListener.newState(receiverOn);
receiverOn = isReadyToReceive();
receiverListener.newState(receiverOn);
}
return true;
}
@ -823,7 +908,10 @@ public class CC1120 extends Radio802154 implements USARTListener {
/* Await synch byte */
if (data == SYNCH_BYTE_LAST) {
rxGotSynchByte = true;
setGDO0(true);
if(triggerGDO0onSynch) {
setGDO0(true);
}
}
return;
}
@ -834,12 +922,22 @@ public class CC1120 extends Radio802154 implements USARTListener {
rxExpectedLen--;
if (rxExpectedLen == 0) {
setGDO0(false);
setGDO0(false); /* triggerGDO0onFifoThreshold, triggerGDO0onSynch */
rxExpectedLen = -1;
rxGotSynchByte = false;
}
rxfifo.add(data);
if (rxfifo.size() < 128) {
/* printRXFIFO(); */
rxfifo.add(data);
if (triggerGDO0onFifoThreshold && rxfifo.size() >= 3 && rxExpectedLen > 0) {
setGDO0(true);
}
} else {
/* RXFIFO overflow */
setState(CC1120RadioState.CC1120_STATE_RX_FIFO_ERR);
}
/* printRXFIFO(); */
}
@ -855,12 +953,14 @@ public class CC1120 extends Radio802154 implements USARTListener {
registers[register] = data;
}
public void setRSSI(int power) {
currentRssiReg1 = 0xff&power;
}
public int getRSSI() {
return currentRssiReg1;
}
private int currentRssi = -100;
public void setRSSI(int power) {
currentRssi = power;
currentRssiReg1 = 0xff&power;
}
public int getRSSI() {
return currentRssiReg1;
}
public int getActiveFrequency() {
return (int) (1000 * Math.round(frequency)); /* kHz */