#include <HplRF230.h>
#include <Tasklet.h>
#include <RadioAssert.h>
+#include <TimeSyncMessage.h>
module RF230LayerP
{
interface BusyWait<TMicro, uint16_t>;
- interface RF230Config;
interface PacketField<uint8_t> as PacketLinkQuality;
interface PacketField<uint8_t> as PacketTransmitPower;
- interface PacketTimeStamp<TRF230, uint16_t>;
+ interface PacketField<uint8_t> as PacketRSSI;
+ interface PacketField<uint8_t> as PacketTimeSyncOffset;
+
+ interface PacketTimeStamp<TRF230, uint32_t>;
+ interface LocalTime<TRF230>;
+
+ interface RF230Config;
interface Tasklet;
interface RadioAlarm;
- async event void lastTouch(message_t* msg);
-
#ifdef RF230_DEBUG
interface DiagMsg;
#endif
enum
{
- SLEEP_WAKEUP_TIME = (uint16_t)(880 * RF230_ALARM_MICROSEC),
- CCA_REQUEST_TIME = (uint16_t)(140 * RF230_ALARM_MICROSEC),
+ SLEEP_WAKEUP_TIME = (uint16_t)(880 * RF230_ALARM_SEC / 1000000UL),
+ CCA_REQUEST_TIME = (uint16_t)(140 * RF230_ALARM_SEC / 1000000UL),
- TX_SFD_DELAY = (uint16_t)(176 * RF230_ALARM_MICROSEC),
- RX_SFD_DELAY = (uint16_t)(8 * RF230_ALARM_MICROSEC),
+ TX_SFD_DELAY = (uint16_t)(176 * RF230_ALARM_SEC / 1000000UL),
+ RX_SFD_DELAY = (uint16_t)(8 * RF230_ALARM_SEC / 1000000UL),
};
tasklet_async event void RadioAlarm.fired()
{
if( state == STATE_SLEEP_2_TRX_OFF )
- {
state = STATE_TRX_OFF;
- }
else if( cmd == CMD_CCA )
{
uint8_t cca;
}
else if( cmd == CMD_TURNON && state == STATE_TRX_OFF && isSpiAcquired() )
{
+ ASSERT( ! radioIrq );
+
+ readRegister(RF230_IRQ_STATUS); // clear the interrupt register
call IRQ.captureRisingEdge();
+
writeRegister(RF230_TRX_STATE, RF230_RX_ON);
state = STATE_TRX_OFF_2_RX_ON;
}
else if( (cmd == CMD_TURNOFF || cmd == CMD_STANDBY)
&& state == STATE_RX_ON && isSpiAcquired() )
{
- call IRQ.disable();
writeRegister(RF230_TRX_STATE, RF230_FORCE_TRX_OFF);
+
+ call IRQ.disable();
+ radioIrq = FALSE;
+
state = STATE_TRX_OFF;
}
uint8_t length;
uint8_t* data;
uint8_t header;
+ uint32_t time32;
+ void* timesync;
if( cmd != CMD_NONE || state != STATE_RX_ON || ! isSpiAcquired() || radioIrq )
return EBUSY;
- if( call RF230Config.requiresRssiCca(msg)
- && readRegister(RF230_PHY_RSSI) > ((rssiClear + rssiBusy) >> 3) )
- return EBUSY;
-
- writeRegister(RF230_TRX_STATE, RF230_PLL_ON);
-
- // do something useful, just to wait a little
length = (call PacketTransmitPower.isSet(msg) ?
call PacketTransmitPower.get(msg) : RF230_DEF_RFPOWER) & RF230_TX_PWR_MASK;
writeRegister(RF230_PHY_TX_PWR, RF230_TX_AUTO_CRC_ON | txPower);
}
+ if( call RF230Config.requiresRssiCca(msg)
+ && (readRegister(RF230_PHY_RSSI) & RF230_RSSI_MASK) > ((rssiClear + rssiBusy) >> 3) )
+ return EBUSY;
+
+ writeRegister(RF230_TRX_STATE, RF230_PLL_ON);
+
+ // do something useful, just to wait a little
+ time32 = call LocalTime.get();
+ timesync = call PacketTimeSyncOffset.isSet(msg) ? msg->data + call PacketTimeSyncOffset.get(msg) : 0;
+
// we have missed an incoming message in this short amount of time
if( (readRegister(RF230_TRX_STATUS) & RF230_TRX_STATUS_MASK) != RF230_PLL_ON )
{
length -= header;
- // first upload the header
+ // first upload the header to gain some time
do {
call HplRF230.spiSplitReadWrite(*(data++));
}
while( --header != 0 );
- call PacketTimeStamp.set(msg, time);
- signal lastTouch(msg);
+ time32 += (int16_t)(time) - (int16_t)(time32);
+
+ if( timesync != 0 )
+ *(timesync_relative_t*)timesync = (*(timesync_absolute_t*)timesync) - time32;
do {
call HplRF230.spiSplitReadWrite(*(data++));
call HplRF230.spiSplitRead();
call SELN.set();
- length = readRegister(RF230_TRX_STATUS);
-
- // go back to RX_ON state when finished
- writeRegister(RF230_TRX_STATE, RF230_RX_ON);
-
/*
* There is a very small window (~1 microsecond) when the RF230 went
* into PLL_ON state but was somehow not properly initialized because
* 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.
*/
- if( (length & RF230_TRX_STATUS_MASK) != RF230_BUSY_TX )
+
+ // go back to RX_ON state when finished
+ writeRegister(RF230_TRX_STATE, RF230_RX_ON);
+
+#ifdef RF230_DEBUG_MESSAGES
+ if( call DiagMsg.record() )
{
-#ifdef RF230_DEBUG
- if( call DiagMsg.record() )
- {
- call DiagMsg.str("assert tx");
- call DiagMsg.uint16(call RadioAlarm.getNow());
- call DiagMsg.hex8(readRegister(RF230_TRX_STATUS));
- call DiagMsg.hex8(readRegister(RF230_TRX_STATE));
- call DiagMsg.hex8(radioIrq);
- call DiagMsg.uint8(state);
- call DiagMsg.uint8(cmd);
- call DiagMsg.send();
- }
-#endif
- ASSERT( (length & RF230_TRX_STATUS_MASK) == RF230_PLL_ON );
- return FAIL;
+ length = call RF230Config.getLength(msg);
+
+ call DiagMsg.str("tx");
+ call DiagMsg.uint16(time);
+ call DiagMsg.uint8(length);
+ call DiagMsg.hex8s(data, length - 2);
+ call DiagMsg.send();
}
+#endif
+
+ if( timesync != 0 )
+ *(timesync_absolute_t*)timesync = (*(timesync_relative_t*)timesync) + time32;
- call PacketTimeStamp.set(msg, time);
+ call PacketTimeStamp.set(msg, time32);
// wait for the TRX_END interrupt
state = STATE_BUSY_TX_2_RX_ON;
}
default tasklet_async event void RadioSend.sendDone(error_t error) { }
+ default tasklet_async event void RadioSend.ready() { }
/*----------------- CCA -----------------*/
call SELN.set();
state = STATE_RX_ON;
+
+#ifdef RF230_DEBUG_MESSAGES
+ if( call DiagMsg.record() )
+ {
+ length = call RF230Config.getLength(rxMsg);
+
+ call DiagMsg.str("rx");
+ call DiagMsg.uint32(call PacketTimeStamp.isValid(rxMsg) ? call PacketTimeStamp.timestamp(rxMsg) : 0);
+ call DiagMsg.uint16(call RadioAlarm.getNow());
+ call DiagMsg.uint8(crc != 0);
+ call DiagMsg.uint8(length);
+ call DiagMsg.hex8s(call RF230Config.getPayload(rxMsg), length - 2);
+ call DiagMsg.send();
+ }
+#endif
+
cmd = CMD_NONE;
// signal only if it has passed the CRC check
if( isSpiAcquired() )
{
uint16_t time;
+ uint32_t time32;
uint8_t irq;
+ uint8_t temp;
atomic time = capturedTime;
radioIrq = FALSE;
#ifdef RF230_DEBUG
// TODO: handle this interrupt
-// ASSERT( ! (irq & RF230_IRQ_TRX_UR) );
if( irq & RF230_IRQ_TRX_UR )
{
if( call DiagMsg.record() )
{
ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );
- // the most likely place for busy channel
- rssiBusy += readRegister(RF230_PHY_RSSI) - (rssiBusy >> 2);
+ // 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
* CMD_TRANSMIT.
*/
if( irq == RF230_IRQ_RX_START ) // just to be cautious
- call PacketTimeStamp.set(rxMsg, time - RX_SFD_DELAY);
+ {
+ 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
- {
-#ifdef RF230_DEBUG
- if( call DiagMsg.record() )
- {
- call DiagMsg.str("assert irq");
- 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
- }
+ ASSERT( cmd == CMD_TURNOFF );
}
if( irq & RF230_IRQ_TRX_END )
else if( cmd == CMD_RECEIVE )
{
ASSERT( state == STATE_RX_ON || state == STATE_PLL_ON_2_RX_ON );
-
+#ifdef RF230_RSSI_ENERGY
+ if( irq == RF230_IRQ_TRX_END )
+ call PacketRSSI.set(rxMsg, readRegister(RF230_PHY_ED_LEVEL));
+ else
+ call PacketRSSI.clear(rxMsg);
+#endif
if( state == STATE_PLL_ON_2_RX_ON )
{
ASSERT( (readRegister(RF230_TRX_STATUS) & RF230_TRX_STATUS_MASK) == RF230_PLL_ON );
else
{
// the most likely place for clear channel (hope to avoid acks)
- rssiClear += readRegister(RF230_PHY_RSSI) - (rssiClear >> 2);
+ rssiClear += (readRegister(RF230_PHY_RSSI) & RF230_RSSI_MASK) - (rssiClear >> 2);
}
cmd = CMD_DOWNLOAD;
{
if( cmd == CMD_DOWNLOAD )
downloadMessage();
- else if( cmd <= CMD_TURNON && CMD_TURNOFF <= cmd )
+ else if( CMD_TURNOFF <= cmd && cmd <= CMD_TURNON )
changeState();
else if( cmd == CMD_CHANNEL )
changeChannel();