* @author Jonathan Hui <jhui@archrock.com>
* @author David Moss
* @author Jung Il Choi
+ * @author JeongGil Ko
+ * @author Razvan Musaloiu-E
* @version $Revision$ $Date$
*/
-module CC2420ReceiveP {
+#include "IEEE802154.h"
+#include "message.h"
+#include "AM.h"
+
+module CC2420ReceiveP @safe() {
provides interface Init;
provides interface StdControl;
uses interface CC2420Packet;
uses interface CC2420PacketBody;
uses interface CC2420Config;
-
+ uses interface PacketTimeStamp<T32khz,uint32_t>;
+
+ uses interface CC2420Strobe as SRXDEC;
+ uses interface CC2420Register as SECCTRL0;
+ uses interface CC2420Register as SECCTRL1;
+ uses interface CC2420Ram as KEY0;
+ uses interface CC2420Ram as KEY1;
+ uses interface CC2420Ram as RXNONCE;
+ uses interface CC2420Ram as RXFIFO_RAM;
+ uses interface CC2420Strobe as SNOP;
+
uses interface Leds;
}
S_STOPPED,
S_STARTED,
S_RX_LENGTH,
+ S_RX_DEC,
+ S_RX_DEC_WAIT,
S_RX_FCF,
S_RX_PAYLOAD,
} cc2420_receive_state_t;
SACK_HEADER_LENGTH = 7,
};
- uint16_t m_timestamp_queue[ TIMESTAMP_QUEUE_SIZE ];
-
+ uint32_t m_timestamp_queue[ TIMESTAMP_QUEUE_SIZE ];
+
uint8_t m_timestamp_head;
uint8_t m_timestamp_size;
/** Number of packets we missed because we were doing something else */
+#ifdef CC2420_HW_SECURITY
+ norace uint8_t m_missed_packets;
+#else
uint8_t m_missed_packets;
-
+#endif
+
/** TRUE if we are receiving a valid packet into the stack */
bool receivingPacket;
norace uint8_t m_bytes_left;
- norace message_t* m_p_rx_buf;
+ norace message_t* ONE_NOK m_p_rx_buf;
message_t m_rx_buf;
-
+#ifdef CC2420_HW_SECURITY
+ norace cc2420_receive_state_t m_state;
+ norace uint8_t packetLength = 0;
+ norace uint8_t pos = 0;
+ norace uint8_t secHdrPos = 0;
+ uint8_t nonceValue[16] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
+ norace uint8_t skip;
+ norace uint8_t securityOn = 0;
+ norace uint8_t authentication = 0;
+ norace uint8_t micLength = 0;
+ uint8_t flush_flag = 0;
+ uint16_t startTime = 0;
+
+ void beginDec();
+ void dec();
+#else
cc2420_receive_state_t m_state;
-
+#endif
+
/***************** Prototypes ****************/
void reset_state();
void beginReceive();
void receive();
void waitForNextPacket();
void flush();
-
+ bool passesAddressCheck(message_t * ONE msg);
+
task void receiveDone_task();
-
+
/***************** Init Commands ****************/
command error_t Init.init() {
m_p_rx_buf = &m_rx_buf;
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;
return SUCCESS;
}
- /***************** Receive Commands ****************/
- command void* Receive.getPayload(message_t* m, uint8_t* len) {
- if (len != NULL) {
- *len = ((uint8_t*) (call CC2420PacketBody.getHeader( m_p_rx_buf )))[0];
- }
- return m->data;
- }
-
- command uint8_t Receive.payloadLength(message_t* m) {
- uint8_t* buf = (uint8_t*)(call CC2420PacketBody.getHeader( m_p_rx_buf ));
- return buf[0];
- }
-
-
/***************** CC2420Receive Commands ****************/
/**
* Start frame delimiter signifies the beginning/end of a packet
* See the CC2420 datasheet for details.
*/
- async command void CC2420Receive.sfd( uint16_t time ) {
+ async command void CC2420Receive.sfd( uint32_t time ) {
if ( m_timestamp_size < TIMESTAMP_QUEUE_SIZE ) {
uint8_t tail = ( ( m_timestamp_head + m_timestamp_size ) %
TIMESTAMP_QUEUE_SIZE );
/***************** InterruptFIFOP Events ****************/
async event void InterruptFIFOP.fired() {
if ( m_state == S_STARTED ) {
+#ifndef CC2420_HW_SECURITY
+ m_state = S_RX_LENGTH;
beginReceive();
-
+#else
+ m_state = S_RX_DEC;
+ atomic receivingPacket = TRUE;
+ beginDec();
+#endif
} else {
m_missed_packets++;
}
}
+
+ /*****************Decryption Options*********************/
+#ifdef CC2420_HW_SECURITY
+ task void waitTask(){
+
+ if(SECURITYLOCK == 1){
+ post waitTask();
+ }else{
+ m_state = S_RX_DEC;
+ beginDec();
+ }
+ }
+
+ void beginDec(){
+ if(call SpiResource.isOwner()) {
+ dec();
+ } else if (call SpiResource.immediateRequest() == SUCCESS) {
+ dec();
+ } else {
+ call SpiResource.request();
+ }
+ }
+
+ norace uint8_t decLoopCount = 0;
+
+ task void waitDecTask(){
+
+ cc2420_status_t status;
+
+ call CSN.clr();
+ status = call SNOP.strobe();
+ call CSN.set();
+
+ atomic decLoopCount ++;
+
+ if(decLoopCount > 10){
+ call CSN.clr();
+ atomic call SECCTRL0.write((0 << CC2420_SECCTRL0_SEC_MODE) |
+ (0 << CC2420_SECCTRL0_SEC_M) |
+ (0 << CC2420_SECCTRL0_SEC_RXKEYSEL) |
+ (1 << CC2420_SECCTRL0_SEC_CBC_HEAD) |
+ (1 << CC2420_SECCTRL0_RXFIFO_PROTECTION)) ;
+ call CSN.set();
+ SECURITYLOCK = 0;
+ call SpiResource.release();
+ atomic flush_flag = 1;
+ beginReceive();
+ }else if(status & CC2420_STATUS_ENC_BUSY){
+ post waitDecTask();
+ }else{
+ call CSN.clr();
+ atomic call SECCTRL0.write((0 << CC2420_SECCTRL0_SEC_MODE) |
+ (0 << CC2420_SECCTRL0_SEC_M) |
+ (0 << CC2420_SECCTRL0_SEC_RXKEYSEL) |
+ (1 << CC2420_SECCTRL0_SEC_CBC_HEAD) |
+ (1 << CC2420_SECCTRL0_RXFIFO_PROTECTION)) ;
+ call CSN.set();
+ SECURITYLOCK = 0;
+ call SpiResource.release();
+ beginReceive();
+ }
+
+ }
+
+ void waitDec(){
+ cc2420_status_t status;
+ call CSN.clr();
+ status = call SNOP.strobe();
+ call CSN.set();
+
+ if(status & CC2420_STATUS_ENC_BUSY){
+ atomic decLoopCount = 1;
+ post waitDecTask();
+ }else{
+ call CSN.clr();
+ atomic call SECCTRL0.write((0 << CC2420_SECCTRL0_SEC_MODE) |
+ (0 << CC2420_SECCTRL0_SEC_M) |
+ (0 << CC2420_SECCTRL0_SEC_RXKEYSEL) |
+ (1 << CC2420_SECCTRL0_SEC_CBC_HEAD) |
+ (1 << CC2420_SECCTRL0_RXFIFO_PROTECTION)) ;
+ call CSN.set();
+ SECURITYLOCK = 0;
+ call SpiResource.release();
+ beginReceive();
+ }
+ }
+
+ void dec(){
+ cc2420_header_t header;
+ security_header_t secHdr;
+ uint8_t mode, key, temp, crc;
+
+ atomic pos = (packetLength+pos)%RXFIFO_SIZE;
+ atomic secHdrPos = (pos+10)%RXFIFO_SIZE;
+
+ if (pos + 3 > RXFIFO_SIZE){
+ temp = RXFIFO_SIZE - pos;
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(pos,(uint8_t*)&header, temp);
+ call CSN.set();
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(0,(uint8_t*)&header+temp, 3-temp);
+ call CSN.set();
+ }else{
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(pos,(uint8_t*)&header, 3);
+ call CSN.set();
+ }
+
+ packetLength = header.length+1;
+
+ if(packetLength == 6){ // ACK packet
+ m_state = S_RX_LENGTH;
+ call SpiResource.release();
+ beginReceive();
+ return;
+ }
+
+ if (pos + sizeof(cc2420_header_t) > RXFIFO_SIZE){
+ temp = RXFIFO_SIZE - pos;
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(pos,(uint8_t*)&header, temp);
+ call CSN.set();
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(0,(uint8_t*)&header+temp, sizeof(cc2420_header_t)-temp);
+ call CSN.set();
+ }else{
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(pos,(uint8_t*)&header, sizeof(cc2420_header_t));
+ call CSN.set();
+ }
+
+ if (pos+header.length+1 > RXFIFO_SIZE){
+ temp = header.length - (RXFIFO_SIZE - pos);
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(temp,&crc, 1);
+ call CSN.set();
+ }else{
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(pos+header.length,&crc, 1);
+ call CSN.set();
+ }
+
+ if(header.length+1 > RXFIFO_SIZE || !(crc << 7)){
+ atomic flush_flag = 1;
+ m_state = S_RX_LENGTH;
+ call SpiResource.release();
+ beginReceive();
+ return;
+ }
+ if( (header.fcf & (1 << IEEE154_FCF_SECURITY_ENABLED)) && (crc << 7) ){
+ if(call CC2420Config.isAddressRecognitionEnabled()){
+ if(!(header.dest==call CC2420Config.getShortAddr() || header.dest==AM_BROADCAST_ADDR)){
+ packetLength = header.length + 1;
+ m_state = S_RX_LENGTH;
+ call SpiResource.release();
+ beginReceive();
+ return;
+ }
+ }
+ if(SECURITYLOCK == 1){
+ call SpiResource.release();
+ post waitTask();
+ return;
+ }else{
+ //We are going to decrypt so lock the registers
+ atomic SECURITYLOCK = 1;
+
+ if (secHdrPos + sizeof(security_header_t) > RXFIFO_SIZE){
+ temp = RXFIFO_SIZE - secHdrPos;
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(secHdrPos,(uint8_t*)&secHdr, temp);
+ call CSN.set();
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(0,(uint8_t*)&secHdr+temp, sizeof(security_header_t) - temp);
+ call CSN.set();
+ } else {
+ call CSN.clr();
+ atomic call RXFIFO_RAM.read(secHdrPos,(uint8_t*)&secHdr, sizeof(security_header_t));
+ call CSN.set();
+ }
+
+ key = secHdr.keyID[0];
+
+ if (secHdr.secLevel == NO_SEC){
+ mode = CC2420_NO_SEC;
+ micLength = 0;
+ }else if (secHdr.secLevel == CBC_MAC_4){
+ mode = CC2420_CBC_MAC;
+ micLength = 4;
+ }else if (secHdr.secLevel == CBC_MAC_8){
+ mode = CC2420_CBC_MAC;
+ micLength = 8;
+ }else if (secHdr.secLevel == CBC_MAC_16){
+ mode = CC2420_CBC_MAC;
+ micLength = 16;
+ }else if (secHdr.secLevel == CTR){
+ mode = CC2420_CTR;
+ micLength = 0;
+ }else if (secHdr.secLevel == CCM_4){
+ mode = CC2420_CCM;
+ micLength = 4;
+ }else if (secHdr.secLevel == CCM_8){
+ mode = CC2420_CCM;
+ micLength = 8;
+ }else if (secHdr.secLevel == CCM_16){
+ mode = CC2420_CCM;
+ micLength = 16;
+ }else{
+ atomic SECURITYLOCK = 0;
+ packetLength = header.length + 1;
+ m_state = S_RX_LENGTH;
+ call SpiResource.release();
+ beginReceive();
+ return;
+ }
+
+ if(mode < 4 && mode > 0) { // if mode is valid
-
+ securityOn = 1;
+
+ memcpy(&nonceValue[3], &(secHdr.frameCounter), 4);
+ skip = secHdr.reserved;
+
+ if(mode == CC2420_CBC_MAC || mode == CC2420_CCM){
+ authentication = 1;
+ call CSN.clr();
+ atomic call SECCTRL0.write((mode << CC2420_SECCTRL0_SEC_MODE) |
+ ((micLength-2)/2 << CC2420_SECCTRL0_SEC_M) |
+ (key << CC2420_SECCTRL0_SEC_RXKEYSEL) |
+ (1 << CC2420_SECCTRL0_SEC_CBC_HEAD) |
+ (1 << CC2420_SECCTRL0_RXFIFO_PROTECTION)) ;
+ call CSN.set();
+ }else{
+ call CSN.clr();
+ atomic call SECCTRL0.write((mode << CC2420_SECCTRL0_SEC_MODE) |
+ (1 << CC2420_SECCTRL0_SEC_M) |
+ (key << CC2420_SECCTRL0_SEC_RXKEYSEL) |
+ (1 << CC2420_SECCTRL0_SEC_CBC_HEAD) |
+ (1 << CC2420_SECCTRL0_RXFIFO_PROTECTION)) ;
+ call CSN.set();
+ }
+
+ call CSN.clr();
+#ifndef TFRAMES_ENABLED
+ atomic call SECCTRL1.write(skip+11+sizeof(security_header_t))+((skip+11+sizeof(security_header_t))<<8);
+#else
+ atomic call SECCTRL1.write(skip+10+sizeof(security_header_t))+((skip+10+sizeof(security_header_t))<<8);
+#endif
+ call CSN.set();
+
+ call CSN.clr();
+ atomic call RXNONCE.write(0, nonceValue, 16);
+ call CSN.set();
+
+ call CSN.clr();
+ atomic call SRXDEC.strobe();
+ call CSN.set();
+
+ atomic decLoopCount = 0;
+ post waitDecTask();
+ return;
+
+ }else{
+ atomic SECURITYLOCK = 0;
+ packetLength = header.length + 1;
+ m_state = S_RX_LENGTH;
+ call SpiResource.release();
+ beginReceive();
+ return;
+ }
+ }
+ }else{
+ packetLength = header.length + 1;
+ m_state = S_RX_LENGTH;
+ call SpiResource.release();
+ beginReceive();
+ return;
+ }
+ }
+#endif
/***************** SpiResource Events ****************/
event void SpiResource.granted() {
+#ifdef CC2420_HW_SECURITY
+ if(m_state == S_RX_DEC){
+ dec();
+ }else{
+ receive();
+ }
+#else
receive();
+#endif
}
/***************** RXFIFO Events ****************/
async event void RXFIFO.readDone( uint8_t* rx_buf, uint8_t rx_len,
error_t error ) {
cc2420_header_t* header = call CC2420PacketBody.getHeader( m_p_rx_buf );
- cc2420_metadata_t* metadata = call CC2420PacketBody.getMetadata( m_p_rx_buf );
- uint8_t* buf = (uint8_t*) header;
+ uint8_t tmpLen __DEPUTY_UNUSED__ = sizeof(message_t) - (offsetof(message_t, data) - sizeof(cc2420_header_t));
+ uint8_t* COUNT(tmpLen) buf = TCAST(uint8_t* COUNT(tmpLen), header);
rxFrameLength = buf[ 0 ];
switch( m_state ) {
case S_RX_LENGTH:
m_state = S_RX_FCF;
- if ( rxFrameLength + 1 > m_bytes_left ) {
+#ifdef CC2420_HW_SECURITY
+ packetLength = rxFrameLength+1;
+#endif
+ if ( rxFrameLength + 1 > m_bytes_left
+#ifdef CC2420_HW_SECURITY
+ || flush_flag == 1
+#endif
+ ) {
// Length of this packet is bigger than the RXFIFO, flush it out.
flush();
*/
if(call CC2420Config.isAutoAckEnabled() && !call CC2420Config.isHwAutoAckDefault()) {
if (((( header->fcf >> IEEE154_FCF_ACK_REQ ) & 0x01) == 1)
- && (header->dest == call CC2420Config.getShortAddr())
+ && ((header->dest == call CC2420Config.getShortAddr())
+ || (header->dest == AM_BROADCAST_ADDR))
&& ((( header->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7) == IEEE154_TYPE_DATA)) {
// CSn flippage cuts off our FIFO; SACK and begin reading again
call CSN.set();
call SACK.strobe();
call CSN.set();
call CSN.clr();
- call RXFIFO.beginRead(buf + 1 + SACK_HEADER_LENGTH,
- rxFrameLength - SACK_HEADER_LENGTH);
+ call RXFIFO.beginRead(buf + 1 + SACK_HEADER_LENGTH,
+ rxFrameLength - SACK_HEADER_LENGTH);
return;
}
}
-
// Didn't flip CSn, we're ok to continue reading.
call RXFIFO.continueRead(buf + 1 + SACK_HEADER_LENGTH,
- rxFrameLength - SACK_HEADER_LENGTH);
+ rxFrameLength - SACK_HEADER_LENGTH);
break;
-
+
case S_RX_PAYLOAD:
+
call CSN.set();
-
if(!m_missed_packets) {
// Release the SPI only if there are no more frames to download
call SpiResource.release();
}
- if ( m_timestamp_size ) {
- if ( rxFrameLength > 10 ) {
- metadata->time = 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 {
- metadata->time = 0xffff;
+
+ 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 ) {
*/
task void receiveDone_task() {
cc2420_metadata_t* metadata = call CC2420PacketBody.getMetadata( m_p_rx_buf );
- uint8_t* buf = (uint8_t*) call CC2420PacketBody.getHeader( m_p_rx_buf );;
-
- metadata->crc = buf[ rxFrameLength ] >> 7;
- metadata->rssi = buf[ rxFrameLength - 1 ];
- metadata->lqi = buf[ rxFrameLength ] & 0x7f;
- m_p_rx_buf = signal Receive.receive( m_p_rx_buf, m_p_rx_buf->data,
- rxFrameLength );
+ cc2420_header_t* header = call CC2420PacketBody.getHeader( m_p_rx_buf);
+ uint8_t length = header->length;
+ uint8_t tmpLen __DEPUTY_UNUSED__ = sizeof(message_t) - (offsetof(message_t, data) - sizeof(cc2420_header_t));
+ uint8_t* COUNT(tmpLen) buf = TCAST(uint8_t* COUNT(tmpLen), header);
+ metadata->crc = buf[ length ] >> 7;
+ metadata->lqi = buf[ length ] & 0x7f;
+ metadata->rssi = buf[ length - 1 ];
+
+ if (passesAddressCheck(m_p_rx_buf) && length >= CC2420_SIZE) {
+#ifdef CC2420_HW_SECURITY
+ if(securityOn == 1){
+ if(m_missed_packets > 0){
+ m_missed_packets --;
+ }
+ if(authentication){
+ length -= micLength;
+ }
+ }
+ micLength = 0;
+ securityOn = 0;
+ authentication = 0;
+#endif
+ m_p_rx_buf = signal Receive.receive( m_p_rx_buf, m_p_rx_buf->data,
+ length - CC2420_SIZE);
+ }
atomic receivingPacket = FALSE;
waitForNextPacket();
}
-
+
/****************** CC2420Config Events ****************/
event void CC2420Config.syncDone( error_t error ) {
}
*/
void beginReceive() {
m_state = S_RX_LENGTH;
-
atomic receivingPacket = TRUE;
if(call SpiResource.isOwner()) {
receive();
* Flush out the Rx FIFO
*/
void flush() {
+#ifdef CC2420_HW_SECURITY
+ flush_flag = 0;
+ pos =0;
+ packetLength =0;
+ micLength = 0;
+ securityOn = 0;
+ authentication = 0;
+#endif
reset_state();
+
call CSN.set();
call CSN.clr();
call SFLUSHRX.strobe();
}
atomic receivingPacket = FALSE;
+
+ /*
+ * The FIFOP pin here is high when there are 0 bytes in the RX FIFO
+ * and goes low as soon as there are bytes in the RX FIFO. The pin
+ * is inverted from what the datasheet says, and its threshold is 127.
+ * Whenever the FIFOP line goes low, as you can see from the interrupt
+ * handler elsewhere in this module, it means we received a new packet.
+ * If the line stays low without generating an interrupt, that means
+ * there's still more data to be received.
+ */
+
if ( ( m_missed_packets && call FIFO.get() ) || !call FIFOP.get() ) {
// A new packet is buffered up and ready to go
if ( m_missed_packets ) {
m_missed_packets--;
}
-
- beginReceive();
-
+#ifdef CC2420_HW_SECURITY
+ call SpiResource.release();
+ m_state = S_RX_DEC;
+ beginDec();
+#else
+ beginReceive();
+#endif
+
} else {
// Wait for the next packet to arrive
m_state = S_STARTED;
m_missed_packets = 0;
}
+ /**
+ * @return TRUE if the given message passes address recognition
+ */
+ bool passesAddressCheck(message_t *msg) {
+ cc2420_header_t *header = call CC2420PacketBody.getHeader( msg );
+
+ if(!(call CC2420Config.isAddressRecognitionEnabled())) {
+ return TRUE;
+ }
+
+ return (header->dest == call CC2420Config.getShortAddr()
+ || header->dest == AM_BROADCAST_ADDR);
+ }
+
}