Emulation support for the TI CC1101 sub-GHz transceiver

This commit is contained in:
Adam Dunkels 2013-08-29 19:48:54 +02:00 committed by Niclas Finne
parent f2facc2cfb
commit 9bd6a1d03d
1 changed files with 827 additions and 0 deletions

View File

@ -0,0 +1,827 @@
/*
* 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 se.sics.mspsim.chip;
import java.util.ArrayList;
import java.util.List;
import se.sics.mspsim.core.IOPort;
import se.sics.mspsim.core.IOPort.PinState;
import se.sics.mspsim.core.MSP430Core;
import se.sics.mspsim.core.TimeEvent;
import se.sics.mspsim.core.USARTListener;
import se.sics.mspsim.core.USARTSource;
public class CC1101 extends Radio802154 implements USARTListener {
protected boolean DEBUG = true;
/* cc1101-const.h: Configuration registers */
public static final int CC1101_IOCFG1 = 0x01;
public static final int CC1101_IOCFG0 = 0x02;
public static final int CC1101_FIFOTHR = 0x03;
public static final int CC1101_SYNC1 = 0x04;
public static final int CC1101_SYNC0 = 0x05;
public static final int CC1101_PKTLEN = 0x06;
public static final int CC1101_PKTCTRL1 = 0x07;
public static final int CC1101_PKTCTRL0 = 0x08;
public static final int CC1101_ADDR = 0x09;
public static final int CC1101_CHANNR = 0x0A;
public static final int CC1101_FSCTRL1 = 0x0B;
public static final int CC1101_FSCTRL0 = 0x0C;
public static final int CC1101_FREQ2 = 0x0D;
public static final int CC1101_FREQ1 = 0x0E;
public static final int CC1101_FREQ0 = 0x0F;
public static final int CC1101_MDMCFG4 = 0x10;
public static final int CC1101_MDMCFG3 = 0x11;
public static final int CC1101_MDMCFG2 = 0x12;
public static final int CC1101_MDMCFG1 = 0x13;
public static final int CC1101_MDMCFG0 = 0x14;
public static final int CC1101_DEVIATN = 0x15;
public static final int CC1101_MCSM2 = 0x16;
public static final int CC1101_MCSM1 = 0x17;
public static final int CC1101_MCSM0 = 0x18;
public static final int CC1101_FOCCFG = 0x19;
public static final int CC1101_BSCFG = 0x1A;
public static final int CC1101_AGCCTRL2 = 0x1B;
public static final int CC1101_AGCCTRL1 = 0x1C;
public static final int CC1101_AGCCTRL0 = 0x1D;
public static final int CC1101_WOREVT1 = 0x1E;
public static final int CC1101_WOREVT0 = 0x1F;
public static final int CC1101_WORCTRL = 0x20;
public static final int CC1101_FREND1 = 0x21;
public static final int CC1101_FREND0 = 0x22;
public static final int CC1101_FSCAL3 = 0x23;
public static final int CC1101_FSCAL2 = 0x24;
public static final int CC1101_FSCAL1 = 0x25;
public static final int CC1101_FSCAL0 = 0x26;
public static final int CC1101_RCCTRL1 = 0x27;
public static final int CC1101_RCCTRL0 = 0x28;
public static final int CC1101_FSTEST = 0x29;
public static final int CC1101_PTEST = 0x2A;
public static final int CC1101_AGCTEST = 0x2B;
public static final int CC1101_TEST2 = 0x2C;
public static final int CC1101_TEST1 = 0x2D;
public static final int CC1101_TEST0 = 0x2E;
public static final int CC1101_PARTNUM = 0x30;
public static final int CC1101_VERSION = 0x31;
public static final int CC1101_FREQEST = 0x32;
public static final int CC1101_LQI = 0x33;
public static final int CC1101_RSSI = 0x34;
public static final int CC1101_MARCSTATE = 0x35;
public static final int CC1101_WORTIME1 = 0x36;
public static final int CC1101_WORTIME0 = 0x37;
public static final int CC1101_PKTSTATUS = 0x38;
public static final int CC1101_VCO_VC_DAC = 0x39;
public static final int CC1101_TXBYTES = 0x3A;
public static final int CC1101_RXBYTES = 0x3B;
public static final int CC1101_RCCTRL1_STATUS = 0x3C;
public static final int CC1101_RCCTRL0_STATUS = 0x3D;
public static final int CC1101_PATABLE = 0x3E;
public static final int CC1101_PA_M30 = 0x03;
public static final int CC1101_PA_M20 = 0x0E;
public static final int CC1101_PA_M15 = 0x1E;
public static final int CC1101_PA_M10 = 0x27;
public static final int CC1101_PA_M6 = 0x38;
public static final int CC1101_PA_0 = 0x8E;
public static final int CC1101_PA_5 = 0x84;
public static final int CC1101_PA_7 = 0xCC;
public static final int CC1101_PA_10 = 0xC3;
public static final int CC1101_PA_11 = 0xC0;
public final static int CC1101_TXFIFO = 0x3F;
public final static int CC1101_RXFIFO = 0x3F;
/* Strobe commands */
public static final int CC1101_SRES = 0x30;
public static final int CC1101_SFSTXON = 0x31;
public static final int CC1101_SXOFF = 0x32;
public static final int CC1101_SCAL = 0x33;
public static final int CC1101_SRX = 0x34;
public static final int CC1101_STX = 0x35;
public static final int CC1101_SIDLE = 0x36;
public static final int CC1101_SAFC = 0x37;
public static final int CC1101_SWOR = 0x38;
public static final int CC1101_SPWD = 0x39;
public static final int CC1101_SFRX = 0x3A;
public static final int CC1101_SFTX = 0x3B;
public static final int CC1101_SWORRST = 0x3C;
public static final int CC1101_SNOP = 0x3D;
public static enum CC1101RadioState {
CC1101_STATE_SLEEP(0x00)/* 0 */,
CC1101_STATE_IDLE(0x01),
CC1101_STATE_XOFF(0x02),
CC1101_STATE_VCOON_MC(0x03),
CC1101_STATE_REGON_MC(0x04),
CC1101_STATE_MANCAL(0x05),
CC1101_STATE_VCOON(0x06),
CC1101_STATE_REGON(0x07),
CC1101_STATE_STARTCAL(0x08),
CC1101_STATE_BWBOOST(0x09),
CC1101_STATE_FS_LOCK(0x0A),
CC1101_STATE_IFADCON(0x0B),
CC1101_STATE_ENDCAL(0x0C),
CC1101_STATE_RX(0x0D) /* 13 */,
CC1101_STATE_RX_END(0x0E),
CC1101_STATE_RX_RST(0x0F),
CC1101_STATE_TXRX_SWITCH(0x10),
CC1101_STATE_RXFIFO_OVERFLOW(0x11),
CC1101_STATE_FSTXON(0x12),
CC1101_STATE_TX(0x13),
CC1101_STATE_TX_END(0x14),
CC1101_STATE_RXTX_SWITCH(0x15),
CC1101_STATE_TXFIFO_UNDERFLOW(0x16);
private final int state;
CC1101RadioState(int stateNo) {
state = stateNo;
}
public int getStateAsInt() {
return state | (0b10 << 5); /* TODO 2 pin state not implemented */
}
};
private TimeEvent sendEvent = new TimeEvent(0, "CC1101 Send") {
public void execute(long t) {
txNext();
}
};
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 StateListener stateListener = null;
private ReceiverListener receiverListener = null;
private int currentRssiReg = 0;
private CC1101RadioState state = null;
protected List<Byte> txfifo = new ArrayList<Byte>();
protected List<Byte> rxfifo = new ArrayList<Byte>();
protected int[] registers = new int[64];
protected int[] memory = new int[512];
private boolean chipSelect;
private IOPort gdo0Port = null;
private int gdo0Pin = -1;
private IOPort gdo2Port = null;
private int gdo2Pin = -1;
private int channel = 0;
public CC1101(MSP430Core cpu) {
super("CC1101", "Radio", cpu);
reset();
}
public void log(String str) {
if (DEBUG) {
System.out.println(str);
}
}
public void strobe(int cmd) {
switch (cmd) {
case CC1101_SRES:
log("CC1101_SRES not implemented");
reset();
break;
case CC1101_SFSTXON:
log("CC1101_SFSTXON not implemented");
break;
case CC1101_SXOFF:
log("CC1101_SXOFF not implemented");
break;
case CC1101_SCAL:
setState(CC1101RadioState.CC1101_STATE_IDLE);
break;
case CC1101_SRX:
setState(CC1101RadioState.CC1101_STATE_RX);
break;
case CC1101_STX:
int len = (int) (0xff&txfifo.get(0));
txFooterCountdown = 1 + len + 1/*len*/;
if (DEBUG) {
System.out.println("TX started: len = " + len + ", txFooterCountdown = " + txFooterCountdown);
}
txNext();
setState(CC1101RadioState.CC1101_STATE_TX);
break;
case CC1101_SIDLE:
setState(CC1101RadioState.CC1101_STATE_IDLE);
break;
case CC1101_SAFC:
log("CC1101_SAFC not implemented");
break;
case CC1101_SWOR:
log("CC1101_SWOR not implemented");
break;
case CC1101_SPWD:
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);
break;
case CC1101_SFRX:
rxfifo.clear();
rxExpectedLen = -1;
rxGotSynchByte = false;
setGDO0(false);
/*printRXFIFO();*/
break;
case CC1101_SFTX:
txfifo.clear();
txFooterCountdown = -1;
/*printTXFIFO();*/
break;
case CC1101_SWORRST:
log("CC1101_SWORRST not implemented");
break;
case CC1101_SNOP:
log("CC1101_SNOP not implemented");
break;
default:
System.out.printf("strobe(0x%02x)\n", cmd);
break;
}
}
public int getLQI() {
return 0; /* TODO */
};
public void setLQI(int lqi) {
}
/* SPI */
public final static int SPI_READ_BIT = 0x80;
public final static int SPI_BURST_BIT = 0x40;
private boolean spiBurstMode = false;
private boolean spiReadMode = false;
private boolean spiGotAddress = false;
private int spiAddress;
public static boolean spiIsBurst(int data) {
return (data & SPI_BURST_BIT) == SPI_BURST_BIT;
}
public static boolean spiIsRead(int data) {
return (data & SPI_READ_BIT) == SPI_READ_BIT;
}
public static boolean spiIsStrobe(int data) {
data = data & 0x3f;
return data >= 0x30 && data <= 0x3d;
}
private void spiResetState() {
spiBurstMode = false;
spiReadMode = false;
spiGotAddress = false;
spiAddress = 0xFF;
}
public void dataReceived(USARTSource source, int data) {
if (spiGotAddress) {
if (!spiBurstMode) {
/* Single access mode */
if (spiReadMode) {
source.byteReceived(getReg(spiAddress));
} else {
source.byteReceived(setReg(spiAddress, data));
}
spiResetState();
} else {
/* Burst mode */
if (spiReadMode) {
source.byteReceived(getReg(spiAddress));
} else {
source.byteReceived(setReg(spiAddress, data));
}
if (spiAddress != CC1101_TXFIFO && spiAddress != CC1101_PATABLE) {
spiAddress++;
}
}
return;
}
/* Read/write. Burst/single. */
spiBurstMode = spiIsBurst(data);
spiReadMode = spiIsRead(data);
/* Is this a strobe command? */
if (!spiBurstMode && spiIsStrobe(data)) {
/* Strobe command */
strobe(data);
source.byteReceived(0);
spiResetState();
return;
}
spiAddress = data & 0x3f;
spiGotAddress = true;
/* Return MARCSTATE */
source.byteReceived(getMarcstate());
return;
}
public int setReg(int address, int data) {
switch (address) {
case CC1101_TXFIFO:
txfifo.add((byte) data);
/*printTXFIFO();*/
return txfifo.size();
case CC1101_CHANNR:
channel = data;
if (channelListener != null) {
channelListener.channelChanged(channel);
}
return 0;
}
log(String.format("setReg(0x%02x) 0x%02x", address, data));
int oldValue = registers[address];
registers[address] = data;
configurationChanged(address, oldValue, data);
return oldValue;
}
public int getReg(int address) {
/* MSP430Core.profiler.printStackTrace(System.out); */
switch (address) {
case CC1101_MARCSTATE:
return getMarcstate();
case CC1101_RXBYTES:
/*log("getReg(CC1101_RXBYTES) " + rxfifo.size());*/
return rxfifo.size();
case CC1101_TXBYTES:
/*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;
}
return status;
case CC1101_RSSI:
return currentRssiReg;
case CC1101_RXFIFO:
if (rxfifo.size() > 0) {
int ret = (int) rxfifo.remove(0);
/*printRXFIFO();*/
return ret;
}
System.err.println("Warning: reading from empty RXFIFO");
return -1;
}
log(String.format("getReg(0x%02x) 0x%02x", address, registers[address]));
return registers[address];
}
public boolean isReadyToReceive() {
/* TODO Implement me */
if (getState() == CC1101RadioState.CC1101_STATE_IDLE) {
return false;
}
if (getState() == CC1101RadioState.CC1101_STATE_SLEEP) {
return false;
}
return true;
}
/* txFooterCountdown: send CRC footer in these many bytes */
protected int txFooterCountdown = -1;
/* TX/RX states */
public static final int NUM_PREAMBLE = 4;
public static final int NUM_SYNCH = 4;
public static final byte SYNCH_BYTE_LAST = (byte) 0x91;
private boolean txSentSynchByte = false;
private int txSendSynchByteCnt = 0;
private boolean txSentFirstCRC = false;
void txNext() {
if (txFooterCountdown < 0) {
System.out.println("Warning: Aborting transmit since txFooterCountdown=" + txFooterCountdown);
return;
}
/* Send preamble and synch bytes */
if (!txSentSynchByte) {
/* Send NUM_PREAMBLE preamble bytes */
if (txSendSynchByteCnt < NUM_PREAMBLE) {
txSendSynchByteCnt++;
if (rfListener != null) {
rfListener.receivedByte((byte) (0xaa));
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
return;
}
/* Send NUM_SYNCH-1 synch bytes */
if (txSendSynchByteCnt < NUM_PREAMBLE + NUM_SYNCH - 1) {
txSendSynchByteCnt++;
if (rfListener != null) {
rfListener.receivedByte((byte) (SYNCH_BYTE_LAST + 1));
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
return;
}
/* Send last synch byte */
if (txSendSynchByteCnt < NUM_PREAMBLE + NUM_SYNCH) {
txSendSynchByteCnt++;
if (rfListener != null) {
rfListener.receivedByte((byte) (SYNCH_BYTE_LAST));
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
txSentSynchByte = true;
return;
}
txSentFirstCRC = false;
}
if (txSentFirstCRC) {
/* send second CRC byte */
if (rfListener != null) {
rfListener.receivedByte((byte) (0xef));
}
if (!txfifo.isEmpty()) {
System.out.println("Warning: TXFIFO not empty after sending CRC bytes");
}
setStateRX();
txSentSynchByte = false;
txSendSynchByteCnt = 0;
txSentFirstCRC = false;
return;
}
txFooterCountdown--;
if (txFooterCountdown == 0) {
/* countdown is zero, send first CRC byte */
if (rfListener != null) {
rfListener.receivedByte((byte) (0xee));
}
txSentFirstCRC = true;
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
return;
}
/* Send payload byte (including first FIFO length byte) */
if (txfifo.isEmpty()) {
System.out.println("Warning: TXFIFO is empty, sending zero-byte, txFooterCountdown=" + txFooterCountdown);
if (rfListener != null) {
rfListener.receivedByte((byte) 0);
}
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
setState(CC1101RadioState.CC1101_STATE_TXFIFO_UNDERFLOW);
return;
}
if (rfListener != null) {
rfListener.receivedByte((byte) (txfifo.get(0).intValue()));
}
txfifo.remove(0);
cpu.scheduleTimeEventMillis(sendEvent, SYMBOL_PERIOD * 2);
/*printTXFIFO();*/
}
public void setGDO0(IOPort port, int pin) {
gdo0Port = port;
gdo0Pin = pin;
}
public void setGDO0(boolean active) {
/* TODO Read active low/high configuration */
if (active) {
if (gdo0Port != null) {
gdo0Port.setPinState(gdo0Pin, IOPort.PinState.HI);
}
if (gdo0Listener != null) {
gdo0Listener.event(IOPort.PinState.HI);
}
} else {
if (gdo0Port != null) {
gdo0Port.setPinState(gdo0Pin, IOPort.PinState.LOW);
}
if (gdo0Listener != null) {
gdo0Listener.event(IOPort.PinState.LOW);
}
}
}
public interface GDOListener {
public void event(PinState state);
}
private GDOListener gdo0Listener = null;
public void setGDO0Listener(GDOListener l) {
gdo0Listener = l;
}
public void setGDO2(IOPort port, int pin) {
gdo2Port = port;
gdo2Pin = pin;
}
public void setGDO2(boolean active) {
if (gdo2Port == null) {
return;
}
gdo2Port.setPinState(gdo2Pin, active ? IOPort.PinState.LOW
: IOPort.PinState.HI);
}
private void printRXFIFO() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("RXFIFO[%03d]: ", rxfifo.size()));
for (int i = 0; i < rxfifo.size(); i++) {
sb.append(String.format("%02x", rxfifo.get(i)));
}
log(sb.toString() + "\n");
}
private void printTXFIFO() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("TXFIFO[%03d]: ", txfifo.size()));
for (int i = 0; i < txfifo.size(); i++) {
sb.append(String.format("%02x", txfifo.get(i)));
}
log(sb.toString() + "\n");
}
public CC1101RadioState getState() {
return state;
}
public interface StateListener {
public void newState(CC1101RadioState state);
}
public void setStateListener(StateListener listener) {
stateListener = listener;
}
public interface ReceiverListener {
public void newState(boolean on);
}
public void setReceiverListener(ReceiverListener listener) {
receiverListener = listener;
}
boolean receiverOn = false;
boolean setState(CC1101RadioState newState) {
if (newState != CC1101RadioState.CC1101_STATE_IDLE
&& newState != CC1101RadioState.CC1101_STATE_RX
&& newState != CC1101RadioState.CC1101_STATE_TX) {
log("setState(" + newState + ")");
}
state = newState;
/* Notify state listener */
if (stateListener != null) {
stateListener.newState(state);
}
if (receiverListener != null && isReadyToReceive() != receiverOn) {
receiverOn = isReadyToReceive();
receiverListener.newState(receiverOn);
}
return true;
}
boolean rxGotSynchByte = false;
private int rxExpectedLen = -1;
public void receivedByte(byte data) {
if (!rxGotSynchByte) {
/* Await synch byte */
if (data == SYNCH_BYTE_LAST) {
rxGotSynchByte = true;
setGDO0(true);
}
return;
}
if (rxExpectedLen < 0) {
rxExpectedLen = 1/*len*/ + (int) data/*payload*/ + 2/*CRC*/;
}
rxExpectedLen--;
if (rxExpectedLen == 0) {
setGDO0(false);
rxExpectedLen = -1;
rxGotSynchByte = false;
}
rxfifo.add(data);
/*printRXFIFO();*/
}
public String info() {
return "CC1101 info: [not implemented]";
}
public int getRegister(int register) {
return registers[register];
}
public void setRegister(int register, int data) {
registers[register] = data;
}
public void setRSSI(int power) {
currentRssiReg = power;
}
public int getRSSI() {
return currentRssiReg;
}
public int getActiveFrequency() {
return (int) 0; /* Not implemented */
}
public int getActiveChannel() {
return channel;
}
public int getOutputPowerIndicator() {
return 1;
}
public double getFrequency() {
return 0; /* Not implemented */
}
public void notifyReset() {
super.notifyReset();
setChipSelect(false);
}
public int getOutputPower() {
return 1;
}
public int getOutputPowerMax() {
return 1;
}
public int getOutputPowerIndicatorMax() {
return 1;
}
/*****************************************************************************
* Chip APIs
*****************************************************************************/
public int getModeMax() {
return 0;
}
/* return data in register at the correct position */
public int getConfiguration(int parameter) {
return registers[parameter];
}
public boolean getChipSelect() {
return chipSelect;
}
public void setChipSelect(boolean select) {
chipSelect = select;
if (!chipSelect) {
spiResetState();
}
if (DEBUG) {
/*log("Chip select: " + chipSelect);*/
}
}
void setStateRX() {
setState(CC1101RadioState.CC1101_STATE_RX);
}
void reset() {
setState(CC1101RadioState.CC1101_STATE_IDLE);
registers[CC1101_PARTNUM] = 0;
registers[CC1101_VERSION] = 6;
}
public int getMarcstate() {
return getState().getStateAsInt();
}
private boolean lastWasRead = false;
public void setLastInstructionWasRead(boolean wasRead) {
lastWasRead = wasRead;
}
public int getStatusByte() {
int status = 0;
/* Bit 7: RF ready */
if (true) {
status += 0; /* XXX Always ready! */
}
/* Bit 4-6: simplified state */
status = status << 3;
if (state == CC1101RadioState.CC1101_STATE_IDLE) {
status += 0;
} else if (state == CC1101RadioState.CC1101_STATE_RX ||
state == CC1101RadioState.CC1101_STATE_RX_END ||
state == CC1101RadioState.CC1101_STATE_RX_RST) {
status += 1;
} else if (state == CC1101RadioState.CC1101_STATE_TX ||
state == CC1101RadioState.CC1101_STATE_TX_END) {
status += 2;
} else if (state == CC1101RadioState.CC1101_STATE_FSTXON) {
status += 3;
} else if (state == CC1101RadioState.CC1101_STATE_ENDCAL ||
state == CC1101RadioState.CC1101_STATE_MANCAL ||
state == CC1101RadioState.CC1101_STATE_STARTCAL) {
status += 4;
} else if (state == CC1101RadioState.CC1101_STATE_RXTX_SWITCH ||
state == CC1101RadioState.CC1101_STATE_TXRX_SWITCH) {
status += 5;
} else if (state == CC1101RadioState.CC1101_STATE_RXFIFO_OVERFLOW) {
status += 6;
} else if (state == CC1101RadioState.CC1101_STATE_TXFIFO_UNDERFLOW) {
status += 7;
}
/* Bit 0-3 */
status = status << 4;
if (lastWasRead) {
/* Return available bytes in RXFIFO */
int available = rxfifo.size();
if (available > 15) {
status += 15;
} else {
status += available;
}
} else {
/* Return available bytes in TXFIFO */
int available = 64 - txfifo.size();
if (available > 15) {
status += 15;
} else {
status += available;
}
}
return status;
}
}