#endif
/**
- * CC2420 header. An I-frame (interoperability frame) header has an
- * extra network byte specified by 6LowPAN
+ * CC2420 header definition.
+ *
+ * An I-frame (interoperability frame) header has an extra network
+ * byte specified by 6LowPAN
+ *
+ * Length = length of the header + payload of the packet, minus the size
+ * of the length byte itself (1). This is what allows for variable
+ * length packets.
+ *
+ * FCF = Frame Control Field, defined in the 802.15.4 specs and the
+ * CC2420 datasheet.
+ *
+ * DSN = Data Sequence Number, a number incremented for each packet sent
+ * by a particular node. This is used in acknowledging that packet,
+ * and also filtering out duplicate packets.
+ *
+ * DestPan = The destination PAN (personal area network) ID, so your
+ * network can sit side by side with another TinyOS network and not
+ * interfere.
+ *
+ * Dest = The destination address of this packet. 0xFFFF is the broadcast
+ * address.
+ *
+ * Src = The local node ID that generated the message.
+ *
+ * Network = The TinyOS network ID, for interoperability with other types
+ * of 802.15.4 networks.
+ *
+ * Type = TinyOS AM type. When you create a new AMSenderC(AM_MYMSG),
+ * the AM_MYMSG definition is the type of packet.
+ *
+ * TOSH_DATA_LENGTH defaults to 28, it represents the maximum size of
+ * the payload portion of the packet, and is specified in the
+ * tos/types/message.h file.
+ *
+ * All of these fields will be filled in automatically by the radio stack
+ * when you attempt to send a message.
*/
typedef nx_struct cc2420_header_t {
nxle_uint8_t length;
message_t* msg,
uint8_t len) {
cc2420_header_t* header = call CC2420PacketBody.getHeader( msg );
+
+ if (len > call Packet.maxPayloadLength()) {
+ return ESIZE;
+ }
+
header->type = id;
header->dest = addr;
header->destpan = call CC2420Config.getPanAddr();
TimeSyncPacketMilli = CC2420TimeSyncMessageP;
Packet = CC2420TimeSyncMessageP;
- CC2420TimeSyncMessageP.SubSend -> CC2420ActiveMessageC.AMSend;
- CC2420TimeSyncMessageP.SubPacket -> CC2420ActiveMessageC.Packet;
+ // use the AMSenderC infrastructure to avoid concurrent send clashes
+ components AMQueueP, ActiveMessageC;
+ CC2420TimeSyncMessageP.SubSend -> AMQueueP.Send[unique(UQ_AMQUEUE_SEND)];
+ CC2420TimeSyncMessageP.AMPacket -> ActiveMessageC;
+ CC2420TimeSyncMessageP.SubPacket -> ActiveMessageC;
CC2420TimeSyncMessageP.PacketTimeStamp32khz -> CC2420PacketC;
CC2420TimeSyncMessageP.PacketTimeStampMilli -> CC2420PacketC;
uses
{
- interface AMSend as SubSend[uint8_t id];
+ interface Send as SubSend;
+ interface AMPacket;
interface Packet as SubPacket;
interface PacketTimeStamp<T32khz,uint32_t> as PacketTimeStamp32khz;
void * timesync = msg->data + len;
*(timesync_radio_t*)timesync = event_time;
- err = call SubSend.send[id](addr, msg, len + sizeof(timesync_radio_t));
+ call AMPacket.setDestination(msg, addr);
+ call AMPacket.setType(msg, id);
+ err = call SubSend.send(msg, len + sizeof(timesync_radio_t));
call PacketTimeSyncOffset.set(msg);
return err;
}
command error_t TimeSyncAMSend32khz.cancel[am_id_t id](message_t* msg)
{
call PacketTimeSyncOffset.cancel(msg);
- return call SubSend.cancel[id](msg);
+ return call SubSend.cancel(msg);
}
default event void TimeSyncAMSend32khz.sendDone[am_id_t id](message_t* msg, error_t error) {}
command uint8_t TimeSyncAMSend32khz.maxPayloadLength[am_id_t id]()
{
- return call SubSend.maxPayloadLength[id]() - sizeof(timesync_radio_t);
+ return call SubSend.maxPayloadLength() - sizeof(timesync_radio_t);
}
command void* TimeSyncAMSend32khz.getPayload[am_id_t id](message_t* msg, uint8_t len)
{
- return call SubSend.getPayload[id](msg, len + sizeof(timesync_radio_t));
+ return call SubSend.getPayload(msg, len + sizeof(timesync_radio_t));
}
/*----------------- TimeSyncAMSendMilli -----------------*/
}
/*----------------- SubSend.sendDone -------------------*/
- event void SubSend.sendDone[am_id_t id](message_t* msg, error_t error)
+ event void SubSend.sendDone(message_t* msg, error_t error)
{
+ am_id_t id = call AMPacket.type(msg);
signal TimeSyncAMSend32khz.sendDone[id](msg, error);
signal TimeSyncAMSendMilli.sendDone[id](msg, error);
}
/****************** Prototypes ****************/
task void startDone_task();
- task void startDone_task();
task void stopDone_task();
task void sendDone_task();
metadata->ack = FALSE;
metadata->rssi = 0;
metadata->lqi = 0;
- metadata->timesync = FALSE;
+ //metadata->timesync = FALSE;
metadata->timestamp = CC2420_INVALID_TIMESTAMP;
ccaOn = TRUE;
return 0;
}
- return (DUTY_ON_TIME * (10000 - dutyCycle)) / dutyCycle;
+ return ((uint32_t)DUTY_ON_TIME * (10000 - dutyCycle)) / dutyCycle;
}
/**
return 10000;
}
- return getActualDutyCycle((DUTY_ON_TIME * 10000)
+ return getActualDutyCycle(((uint32_t)DUTY_ON_TIME * 10000)
/ (sleepInterval + DUTY_ON_TIME));
}
reset_state();
m_state = S_STARTED;
atomic receivingPacket = FALSE;
+ /* Note:
+ We use the falling edge because the FIFOP polarity is reversed.
+ This is done in CC2420Power.startOscillator from CC2420ControlP.nc.
+ */
call InterruptFIFOP.enableFallingEdge();
}
return SUCCESS;
call SpiResource.release();
}
- if ( m_timestamp_size ) {
- if ( rxFrameLength > 10 ) {
- call PacketTimeStamp.set(m_p_rx_buf, m_timestamp_queue[ m_timestamp_head ]);
+ //new packet is buffered up, or we don't have timestamp in fifo, or ack
+ if ( ( m_missed_packets && call FIFO.get() ) || !call FIFOP.get()
+ || !m_timestamp_size
+ || rxFrameLength <= 10) {
+ call PacketTimeStamp.clear(m_p_rx_buf);
+ }
+ else {
+ if (m_timestamp_size==1)
+ call PacketTimeStamp.set(m_p_rx_buf, m_timestamp_queue[ m_timestamp_head ]);
m_timestamp_head = ( m_timestamp_head + 1 ) % TIMESTAMP_QUEUE_SIZE;
m_timestamp_size--;
- }
- } else {
- call PacketTimeStamp.clear(m_p_rx_buf);
+
+ if (m_timestamp_size>0) {
+ call PacketTimeStamp.clear(m_p_rx_buf);
+ m_timestamp_head = 0;
+ m_timestamp_size = 0;
+ }
}
-
+
// We may have received an ack that should be processed by Transmit
// buf[rxFrameLength] >> 7 checks the CRC
if ( ( buf[ rxFrameLength ] >> 7 ) && rx_buf ) {
provides interface CC2420Register as MANAND;
provides interface CC2420Register as MANOR;
provides interface CC2420Register as AGCCTRL;
+ provides interface CC2420Register as RXFIFO_REGISTER;
// ram
provides interface CC2420Ram as IEEEADR;
MANAND = Spi.Reg[ CC2420_MANAND ];
MANOR = Spi.Reg[ CC2420_MANOR ];
AGCCTRL = Spi.Reg[ CC2420_AGCCTRL ];
+ RXFIFO_REGISTER = Spi.Reg[ CC2420_RXFIFO ];
// ram
IEEEADR = Spi.Ram[ CC2420_RAM_IEEEADR ];
}
- inline uint32_t time16to32(uint16_t time, uint32_t recent_time)
+ inline uint32_t getTime32(uint16_t time)
{
- if ((recent_time&0xFFFF)<time)
- return ((recent_time-0x10000UL)&0xFFFF0000UL)|time;
- else
- return (recent_time&0xFFFF0000UL)|time;
+ uint32_t recent_time=call BackoffTimer.getNow();
+ return recent_time + (int16_t)(time - recent_time);
}
/**
* would have picked up and executed had our microcontroller been fast enough.
*/
async event void CaptureSFD.captured( uint16_t time ) {
- uint32_t time32 = time16to32(time, call BackoffTimer.getNow());
+ uint32_t time32;
+ uint8_t sfd_state = 0;
atomic {
+ time32 = getTime32(time);
switch( m_state ) {
case S_SFD:
m_state = S_EFD;
sfdHigh = TRUE;
+ // in case we got stuck in the receive SFD interrupts, we can reset
+ // the state here since we know that we are not receiving anymore
+ m_receiving = FALSE;
call CaptureSFD.captureFallingEdge();
call PacketTimeStamp.set(m_msg, time32);
if (call PacketTimeSyncOffset.isSet(m_msg)) {
- nx_uint8_t *taddr = m_msg->data + (call PacketTimeSyncOffset.get(m_msg) - sizeof(cc2420_header_t));
- timesync_radio_t *timesync = (timesync_radio_t*)taddr;
+ uint8_t absOffset = sizeof(message_header_t)-sizeof(cc2420_header_t)+call PacketTimeSyncOffset.get(m_msg);
+ timesync_radio_t *timesync = (timesync_radio_t *)((nx_uint8_t*)m_msg+absOffset);
// set timesync event time as the offset between the event time and the SFD interrupt time (TEP 133)
*timesync -= time32;
call CSN.clr();
- call TXFIFO_RAM.write( call PacketTimeSyncOffset.get(m_msg), (uint8_t*)timesync, sizeof(timesync_radio_t) );
+ call TXFIFO_RAM.write( absOffset, (uint8_t*)timesync, sizeof(timesync_radio_t) );
call CSN.set();
+ //restoring the event time to the original value
+ *timesync += time32;
}
if ( (call CC2420PacketBody.getHeader( m_msg ))->fcf & ( 1 << IEEE154_FCF_ACK_REQ ) ) {
releaseSpiResource();
call BackoffTimer.stop();
-
- if ( ( ( (call CC2420PacketBody.getHeader( m_msg ))->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7 ) == IEEE154_TYPE_DATA ) {
- call PacketTimeStamp.set(m_msg, time32);
- }
-
if ( call SFD.get() ) {
break;
}
/** Fall Through because the next interrupt was already received */
-
+
case S_EFD:
sfdHigh = FALSE;
call CaptureSFD.captureRisingEdge();
/** Fall Through because the next interrupt was already received */
default:
- if ( !m_receiving ) {
+ /* this is the SFD for received messages */
+ if ( !m_receiving && sfdHigh == FALSE ) {
sfdHigh = TRUE;
call CaptureSFD.captureFallingEdge();
+ // safe the SFD pin status for later use
+ sfd_state = call SFD.get();
call CC2420Receive.sfd( time32 );
m_receiving = TRUE;
m_prev_time = time;
// wait for the next interrupt before moving on
return;
}
+ // if SFD.get() = 0, then an other interrupt happened since we
+ // reconfigured CaptureSFD! Fall through
}
- sfdHigh = FALSE;
- call CaptureSFD.captureRisingEdge();
- m_receiving = FALSE;
- if ( time - m_prev_time < 10 ) {
- call CC2420Receive.sfd_dropped();
- if (m_msg)
- call PacketTimeStamp.clear(m_msg);
+ if ( sfdHigh == TRUE ) {
+ sfdHigh = FALSE;
+ call CaptureSFD.captureRisingEdge();
+ m_receiving = FALSE;
+ /* if sfd_state is 1, then we fell through, but at the time of
+ * saving the time stamp the SFD was still high. Thus, the timestamp
+ * is valid.
+ * if the sfd_state is 0, then either we fell through and SFD
+ * was low while we safed the time stamp, or we didn't fall through.
+ * Thus, we check for the time between the two interrupts.
+ * FIXME: Why 10 tics? Seams like some magic number...
+ */
+ if ((sfd_state == 0) && (time - m_prev_time < 10) ) {
+ call CC2420Receive.sfd_dropped();
+ if (m_msg)
+ call PacketTimeStamp.clear(m_msg);
+ }
+ break;
}
- break;
-
}
}
}