📄 rf230driverlayerp.nc
字号:
call SLP_TR.clr();
#endif
time32 += (int16_t)(time) - (int16_t)(time32);
if( timesync != 0 )
*(timesync_relative_t*)timesync = (*(timesync_absolute_t*)timesync) - time32;
while( length-- != 0 )
call FastSpiByte.splitReadWrite(*(data++));
// wait for the SPI transfer to finish
call FastSpiByte.splitRead();
call SELN.set();
/*
* There is a very small window (~1 microsecond) when the RF230 went
* into PLL_ON state but was somehow not properly initialized because
* of an incoming message and could not go into BUSY_TX. I think the
* radio can even receive a message, and generate a TRX_UR interrupt
* because of concurrent access, but that message probably cannot be
* recovered.
*
* TODO: this needs to be verified, and make sure that the chip is
* not locked up in this case.
*/
// go back to RX_ON state when finished
writeRegister(RF230_TRX_STATE, RF230_RX_ON);
if( timesync != 0 )
*(timesync_absolute_t*)timesync = (*(timesync_relative_t*)timesync) + time32;
call PacketTimeStamp.set(msg, time32);
#ifdef RADIO_DEBUG_MESSAGES
if( call DiagMsg.record() )
{
length = getHeader(msg)->length;
call DiagMsg.chr('t');
call DiagMsg.uint32(call PacketTimeStamp.isValid(rxMsg) ? call PacketTimeStamp.timestamp(rxMsg) : 0);
call DiagMsg.uint16(call RadioAlarm.getNow());
call DiagMsg.int8(length);
call DiagMsg.hex8s(getPayload(msg), length - 2);
call DiagMsg.send();
}
#endif
// wait for the TRX_END interrupt
state = STATE_BUSY_TX_2_RX_ON;
cmd = CMD_TRANSMIT;
return SUCCESS;
}
default tasklet_async event void RadioSend.sendDone(error_t error) { }
default tasklet_async event void RadioSend.ready() { }
/*----------------- CCA -----------------*/
tasklet_async command error_t RadioCCA.request()
{
if( cmd != CMD_NONE || state != STATE_RX_ON || ! isSpiAcquired() || ! call RadioAlarm.isFree() )
return EBUSY;
// see Errata B7 of the datasheet
// writeRegister(RF230_TRX_STATE, RF230_PLL_ON);
// writeRegister(RF230_TRX_STATE, RF230_RX_ON);
writeRegister(RF230_PHY_CC_CCA, RF230_CCA_REQUEST | RF230_CCA_MODE_VALUE | channel);
call RadioAlarm.wait(CCA_REQUEST_TIME);
cmd = CMD_CCA;
return SUCCESS;
}
default tasklet_async event void RadioCCA.done(error_t error) { }
/*----------------- RECEIVE -----------------*/
inline void downloadMessage()
{
uint8_t length;
uint16_t crc;
call SELN.clr();
call FastSpiByte.write(RF230_CMD_FRAME_READ);
// read the length byte
length = call FastSpiByte.write(0);
// if correct length
if( length >= 3 && length <= call RadioPacket.maxPayloadLength() + 2 )
{
uint8_t read;
uint8_t* data;
// initiate the reading
call FastSpiByte.splitWrite(0);
data = getPayload(rxMsg);
getHeader(rxMsg)->length = length;
crc = 0;
// we do not store the CRC field
length -= 2;
read = call Config.headerPreloadLength();
if( length < read )
read = length;
length -= read;
do {
crc = RF230_CRCBYTE_COMMAND(crc, *(data++) = call FastSpiByte.splitReadWrite(0));
}
while( --read != 0 );
if( signal RadioReceive.header(rxMsg) )
{
while( length-- != 0 )
crc = RF230_CRCBYTE_COMMAND(crc, *(data++) = call FastSpiByte.splitReadWrite(0));
crc = RF230_CRCBYTE_COMMAND(crc, call FastSpiByte.splitReadWrite(0));
crc = RF230_CRCBYTE_COMMAND(crc, call FastSpiByte.splitReadWrite(0));
call PacketLinkQuality.set(rxMsg, call FastSpiByte.splitRead());
}
else
crc = 1;
}
else
crc = 1;
call SELN.set();
state = STATE_RX_ON;
#ifdef RADIO_DEBUG_MESSAGES
if( call DiagMsg.record() )
{
length = getHeader(rxMsg)->length;
call DiagMsg.chr('r');
call DiagMsg.uint32(call PacketTimeStamp.isValid(rxMsg) ? call PacketTimeStamp.timestamp(rxMsg) : 0);
call DiagMsg.uint16(call RadioAlarm.getNow());
call DiagMsg.int8(crc == 0 ? length : -length);
call DiagMsg.hex8s(getPayload(rxMsg), length - 2);
call DiagMsg.int8(call PacketRSSI.isSet(rxMsg) ? call PacketRSSI.get(rxMsg) : -1);
call DiagMsg.uint8(call PacketLinkQuality.isSet(rxMsg) ? call PacketLinkQuality.get(rxMsg) : 0);
call DiagMsg.send();
}
#endif
cmd = CMD_NONE;
// signal only if it has passed the CRC check
if( crc == 0 )
rxMsg = signal RadioReceive.receive(rxMsg);
}
/*----------------- IRQ -----------------*/
async event void IRQ.captured(uint16_t time)
{
ASSERT( ! radioIrq );
atomic
{
capturedTime = time;
radioIrq = TRUE;
}
call Tasklet.schedule();
}
void serviceRadio()
{
if( isSpiAcquired() )
{
uint16_t time;
uint32_t time32;
uint8_t irq;
uint8_t temp;
atomic time = capturedTime;
radioIrq = FALSE;
irq = readRegister(RF230_IRQ_STATUS);
#ifdef RADIO_DEBUG
// TODO: handle this interrupt
if( irq & RF230_IRQ_TRX_UR )
{
if( call DiagMsg.record() )
{
call DiagMsg.str("assert ur");
call DiagMsg.uint16(call RadioAlarm.getNow());
call DiagMsg.hex8(readRegister(RF230_TRX_STATUS));
call DiagMsg.hex8(readRegister(RF230_TRX_STATE));
call DiagMsg.hex8(irq);
call DiagMsg.uint8(state);
call DiagMsg.uint8(cmd);
call DiagMsg.send();
}
}
#endif
#ifdef RF230_RSSI_ENERGY
if( irq & RF230_IRQ_TRX_END )
{
if( irq == RF230_IRQ_TRX_END ||
(irq == (RF230_IRQ_RX_START | RF230_IRQ_TRX_END) && cmd == CMD_NONE) )
call PacketRSSI.set(rxMsg, readRegister(RF230_PHY_ED_LEVEL));
else
call PacketRSSI.clear(rxMsg);
}
#endif
if( irq & RF230_IRQ_PLL_LOCK )
{
if( cmd == CMD_TURNON || cmd == CMD_CHANNEL )
{
ASSERT( state == STATE_TRX_OFF_2_RX_ON );
state = STATE_RX_ON;
cmd = CMD_SIGNAL_DONE;
}
else if( cmd == CMD_TRANSMIT )
{
ASSERT( state == STATE_BUSY_TX_2_RX_ON );
}
else
ASSERT(FALSE);
}
if( irq & RF230_IRQ_RX_START )
{
if( cmd == CMD_CCA )
{
signal RadioCCA.done(FAIL);
cmd = CMD_NONE;
}
if( cmd == CMD_NONE )
{
ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );
// the most likely place for busy channel, with no TRX_END interrupt
if( irq == RF230_IRQ_RX_START )
{
temp = readRegister(RF230_PHY_RSSI) & RF230_RSSI_MASK;
rssiBusy += temp - (rssiBusy >> 2);
#ifndef RF230_RSSI_ENERGY
call PacketRSSI.set(rxMsg, temp);
}
else
{
call PacketRSSI.clear(rxMsg);
#endif
}
/*
* The timestamp corresponds to the first event which could not
* have been a PLL_LOCK because then cmd != CMD_NONE, so we must
* have received a message (and could also have received the
* TRX_END interrupt in the mean time, but that is fine. Also,
* we could not be after a transmission, because then cmd =
* CMD_TRANSMIT.
*/
if( irq == RF230_IRQ_RX_START ) // just to be cautious
{
time32 = call LocalTime.get();
time32 += (int16_t)(time - RX_SFD_DELAY) - (int16_t)(time32);
call PacketTimeStamp.set(rxMsg, time32);
}
else
call PacketTimeStamp.clear(rxMsg);
cmd = CMD_RECEIVE;
}
else
ASSERT( cmd == CMD_TURNOFF );
}
if( irq & RF230_IRQ_TRX_END )
{
if( cmd == CMD_TRANSMIT )
{
ASSERT( state == STATE_BUSY_TX_2_RX_ON );
state = STATE_RX_ON;
cmd = CMD_NONE;
signal RadioSend.sendDone(SUCCESS);
// TODO: we could have missed a received message
ASSERT( ! (irq & RF230_IRQ_RX_START) );
}
else if( cmd == CMD_RECEIVE )
{
ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );
if( state == STATE_PLL_ON_2_RX_ON )
{
ASSERT( (readRegister(RF230_TRX_STATUS) & RF230_TRX_STATUS_MASK) == RF230_PLL_ON );
writeRegister(RF230_TRX_STATE, RF230_RX_ON);
state = STATE_RX_ON;
}
else
{
// the most likely place for clear channel (hope to avoid acks)
rssiClear += (readRegister(RF230_PHY_RSSI) & RF230_RSSI_MASK) - (rssiClear >> 2);
}
cmd = CMD_DOWNLOAD;
}
else
ASSERT(FALSE);
}
}
}
default tasklet_async event bool RadioReceive.header(message_t* msg)
{
return TRUE;
}
default tasklet_async event message_t* RadioReceive.receive(message_t* msg)
{
return msg;
}
/*----------------- TASKLET -----------------*/
tasklet_async event void Tasklet.run()
{
if( radioIrq )
serviceRadio();
if( cmd != CMD_NONE )
{
if( cmd == CMD_DOWNLOAD )
downloadMessage();
else if( CMD_TURNOFF <= cmd && cmd <= CMD_TURNON )
changeState();
else if( cmd == CMD_CHANNEL )
changeChannel();
if( cmd == CMD_SIGNAL_DONE )
{
cmd = CMD_NONE;
signal RadioState.done();
}
}
if( cmd == CMD_NONE && state == STATE_RX_ON && ! radioIrq )
signal RadioSend.ready();
if( cmd == CMD_NONE )
call SpiResource.release();
}
/*----------------- RadioPacket -----------------*/
async command uint8_t RadioPacket.headerLength(message_t* msg)
{
return call Config.headerLength(msg) + sizeof(rf230_header_t);
}
async command uint8_t RadioPacket.payloadLength(message_t* msg)
{
return getHeader(msg)->length - 2;
}
async command void RadioPacket.setPayloadLength(message_t* msg, uint8_t length)
{
ASSERT( 1 <= length && length <= 125 );
ASSERT( call RadioPacket.headerLength(msg) + length + call RadioPacket.metadataLength(msg) <= sizeof(message_t) );
// we add the length of the CRC, which is automatically generated
getHeader(msg)->length = length + 2;
}
async command uint8_t RadioPacket.maxPayloadLength()
{
ASSERT( call Config.maxPayloadLength() <= 125 );
return call Config.maxPayloadLength() - sizeof(rf230_header_t);
}
async command uint8_t RadioPacket.metadataLength(message_t* msg)
{
return call Config.metadataLength(msg) + sizeof(rf230_metadata_t);
}
async command void RadioPacket.clear(message_t* msg)
{
// all flags are automatically cleared
}
/*----------------- PacketTransmitPower -----------------*/
async command bool PacketTransmitPower.isSet(message_t* msg)
{
return call TransmitPowerFlag.get(msg);
}
async command uint8_t PacketTransmitPower.get(message_t* msg)
{
return getMeta(msg)->power;
}
async command void PacketTransmitPower.clear(message_t* msg)
{
call TransmitPowerFlag.clear(msg);
}
async command void PacketTransmitPower.set(message_t* msg, uint8_t value)
{
call TransmitPowerFlag.set(msg);
getMeta(msg)->power = value;
}
/*----------------- PacketRSSI -----------------*/
async command bool PacketRSSI.isSet(message_t* msg)
{
return call RSSIFlag.get(msg);
}
async command uint8_t PacketRSSI.get(message_t* msg)
{
return getMeta(msg)->rssi;
}
async command void PacketRSSI.clear(message_t* msg)
{
call RSSIFlag.clear(msg);
}
async command void PacketRSSI.set(message_t* msg, uint8_t value)
{
// just to be safe if the user fails to clear the packet
call TransmitPowerFlag.clear(msg);
call RSSIFlag.set(msg);
getMeta(msg)->rssi = value;
}
/*----------------- PacketTimeSyncOffset -----------------*/
async command bool PacketTimeSyncOffset.isSet(message_t* msg)
{
return call TimeSyncFlag.get(msg);
}
async command uint8_t PacketTimeSyncOffset.get(message_t* msg)
{
return call RadioPacket.headerLength(msg) + call RadioPacket.payloadLength(msg) - sizeof(timesync_absolute_t);
}
async command void PacketTimeSyncOffset.clear(message_t* msg)
{
call TimeSyncFlag.clear(msg);
}
async command void PacketTimeSyncOffset.set(message_t* msg, uint8_t value)
{
// we do not store the value, the time sync field is always the last 4 bytes
ASSERT( call PacketTimeSyncOffset.get(msg) == value );
call TimeSyncFlag.set(msg);
}
/*----------------- PacketLinkQuality -----------------*/
async command bool PacketLinkQuality.isSet(message_t* msg)
{
return TRUE;
}
async command uint8_t PacketLinkQuality.get(message_t* msg)
{
return getMeta(msg)->lqi;
}
async command void PacketLinkQuality.clear(message_t* msg)
{
}
async command void PacketLinkQuality.set(message_t* msg, uint8_t value)
{
getMeta(msg)->lqi = value;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -