* @author Jonathan Hui <jhui@archrock.com>
* @author David Moss
* @author Jung Il Choi Initial SACK implementation
+ * @author JeongGil Ko
+ * @author Razvan Musaloiu-E
* @version $Revision$ $Date$
*/
#include "CC2420.h"
+#include "CC2420TimeSyncMessage.h"
#include "crc.h"
#include "message.h"
-module CC2420TransmitP {
+module CC2420TransmitP @safe() {
provides interface Init;
provides interface StdControl;
provides interface CC2420Transmit as Send;
provides interface RadioBackoff;
- provides interface RadioTimeStamping as TimeStamp;
provides interface ReceiveIndicator as EnergyIndicator;
provides interface ReceiveIndicator as ByteIndicator;
uses interface Alarm<T32khz,uint32_t> as BackoffTimer;
uses interface CC2420Packet;
uses interface CC2420PacketBody;
+ uses interface PacketTimeStamp<T32khz,uint32_t>;
+ uses interface PacketTimeSyncOffset;
uses interface GpioCapture as CaptureSFD;
uses interface GeneralIO as CCA;
uses interface GeneralIO as CSN;
uses interface CC2420Strobe as SFLUSHTX;
uses interface CC2420Register as MDMCTRL1;
+ uses interface CC2420Strobe as STXENC;
+ uses interface CC2420Register as SECCTRL0;
+ uses interface CC2420Register as SECCTRL1;
+ uses interface CC2420Ram as KEY0;
+ uses interface CC2420Ram as KEY1;
+ uses interface CC2420Ram as TXNONCE;
+
uses interface CC2420Receive;
uses interface Leds;
}
enum {
CC2420_ABORT_PERIOD = 320
};
+
+#ifdef CC2420_HW_SECURITY
+ uint16_t startTime = 0;
+ norace uint8_t secCtrlMode = 0;
+ norace 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 uint16_t CTR_SECCTRL0, CTR_SECCTRL1;
+ uint8_t securityChecked = 0;
+
+ void securityCheck();
+#endif
norace message_t * ONE_NOK m_msg;
norace uint8_t m_tx_power;
cc2420_transmit_state_t m_state = S_STOPPED;
-
+
bool m_receiving = FALSE;
uint16_t m_prev_time;
}
-
+ inline uint32_t getTime32(uint16_t time)
+ {
+ uint32_t recent_time = call BackoffTimer.getNow();
+
+ return recent_time - (uint16_t)(recent_time - time);
+ }
+
/**
* The CaptureSFD event is actually an interrupt from the capture pin
* which is connected to timing circuitry and timer modules. This
* would have picked up and executed had our microcontroller been fast enough.
*/
async event void CaptureSFD.captured( uint16_t time ) {
+ 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();
- signal TimeStamp.transmittedSFD( time, m_msg );
+ call PacketTimeStamp.set(m_msg, time32);
+ if (call PacketTimeSyncOffset.isSet(m_msg)) {
+ 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( 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 ) ) {
// This is an ack packet, don't release the chip's SPI bus lock.
abortSpiRelease = TRUE;
releaseSpiResource();
call BackoffTimer.stop();
-
- if ( ( ( (call CC2420PacketBody.getHeader( m_msg ))->fcf >> IEEE154_FCF_FRAME_TYPE ) & 7 ) == IEEE154_TYPE_DATA ) {
- (call CC2420PacketBody.getMetadata( m_msg ))->time = time;
- }
-
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();
- signal TimeStamp.receivedSFD( time );
- call CC2420Receive.sfd( time );
+ // safe the SFD pin status for later use
+ sfd_state = call SFD.get();
+ call CC2420Receive.sfd( time32 );
m_receiving = TRUE;
m_prev_time = time;
if ( call SFD.get() ) {
// 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 ( 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;
-
}
}
}
uint8_t* ack_buf;
uint8_t length;
- if ( type == IEEE154_TYPE_ACK ) {
+ if ( type == IEEE154_TYPE_ACK && m_msg) {
ack_header = call CC2420PacketBody.getHeader( ack_msg );
msg_header = call CC2420PacketBody.getHeader( m_msg );
-
if ( m_state == S_ACK_WAIT && msg_header->dsn == ack_header->dsn ) {
call BackoffTimer.stop();
return FAIL;
}
+#ifdef CC2420_HW_SECURITY
+ securityChecked = 0;
+#endif
m_state = S_LOAD;
m_cca = cca;
m_msg = p_msg;
return SUCCESS;
}
-
+#ifdef CC2420_HW_SECURITY
+
+ task void waitTask(){
+ call Leds.led2Toggle();
+ if(SECURITYLOCK == 1){
+ post waitTask();
+ }else{
+ securityCheck();
+ }
+ }
+
+ void securityCheck(){
+
+ cc2420_header_t* msg_header;
+ cc2420_status_t status;
+ security_header_t* secHdr;
+ uint8_t mode;
+ uint8_t key;
+ uint8_t micLength;
+
+ msg_header = call CC2420PacketBody.getHeader( m_msg );
+
+ if(!(msg_header->fcf & (1 << IEEE154_FCF_SECURITY_ENABLED))){
+ // Security is not used for this packet
+ // Make sure to set mode to 0 and the others to the default values
+ CTR_SECCTRL0 = ((0 << CC2420_SECCTRL0_SEC_MODE) |
+ (1 << CC2420_SECCTRL0_SEC_M) |
+ (1 << CC2420_SECCTRL0_SEC_TXKEYSEL) |
+ (1 << CC2420_SECCTRL0_SEC_CBC_HEAD)) ;
+
+ call CSN.clr();
+ call SECCTRL0.write(CTR_SECCTRL0);
+ call CSN.set();
+
+ return;
+ }
+
+ if(SECURITYLOCK == 1){
+ post waitTask();
+ }else {
+ //Will perform encryption lock registers
+ atomic SECURITYLOCK = 1;
+
+ secHdr = (security_header_t*) &msg_header->secHdr;
+ memcpy(&nonceValue[3], &(secHdr->frameCounter), 4);
+
+ skip = secHdr->reserved;
+ key = secHdr->keyID[0]; // For now this is the only key selection mode.
+
+ if (secHdr->secLevel == NO_SEC){
+ mode = CC2420_NO_SEC;
+ micLength = 4;
+ }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 = 4;
+ }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{
+ return;
+ }
+
+ CTR_SECCTRL0 = ((mode << CC2420_SECCTRL0_SEC_MODE) |
+ ((micLength-2)/2 << CC2420_SECCTRL0_SEC_M) |
+ (key << CC2420_SECCTRL0_SEC_TXKEYSEL) |
+ (1 << CC2420_SECCTRL0_SEC_CBC_HEAD)) ;
+#ifndef TFRAMES_ENABLED
+ CTR_SECCTRL1 = (skip+11+sizeof(security_header_t)+((skip+11+sizeof(security_header_t))<<8));
+#else
+ CTR_SECCTRL1 = (skip+10+sizeof(security_header_t)+((skip+10+sizeof(security_header_t))<<8));
+#endif
+
+ call CSN.clr();
+ call SECCTRL0.write(CTR_SECCTRL0);
+ call CSN.set();
+
+ call CSN.clr();
+ call SECCTRL1.write(CTR_SECCTRL1);
+ call CSN.set();
+
+ call CSN.clr();
+ call TXNONCE.write(0, nonceValue, 16);
+ call CSN.set();
+
+ call CSN.clr();
+ status = call SNOP.strobe();
+ call CSN.set();
+
+ while(status & CC2420_STATUS_ENC_BUSY){
+ call CSN.clr();
+ status = call SNOP.strobe();
+ call CSN.set();
+ }
+
+ // Inline security will be activated by STXON or STXONCCA strobes
+
+ atomic SECURITYLOCK = 0;
+
+ }
+ }
+#endif
+
/**
* Attempt to send the packet we have loaded into the tx buffer on
* the radio chip. The STXONCCA will send the packet immediately if
*
* If the packet got sent, we should expect an SFD interrupt to take
* over, signifying the packet is getting sent.
+ *
+ * If security is enabled, STXONCCA or STXON will perform inline security
+ * options before transmitting the packet.
*/
void attemptSend() {
uint8_t status;
signal Send.sendDone( m_msg, ECANCEL );
return;
}
-
-
+#ifdef CC2420_HW_SECURITY
+ if(securityChecked != 1){
+ securityCheck();
+ }
+ securityChecked = 1;
+#endif
call CSN.clr();
-
status = m_cca ? call STXONCCA.strobe() : call STXON.strobe();
if ( !( status & CC2420_STATUS_TX_ACTIVE ) ) {
status = call SNOP.strobe();
congestion = FALSE;
}
}
-
+
m_state = congestion ? S_SAMPLE_CCA : S_SFD;
call CSN.set();
}
-
+
if ( congestion ) {
totalCcaChecks = 0;
releaseSpiResource();
m_tx_power = tx_power;
{
- uint8_t tmpLen = header->length - 1;
+ uint8_t tmpLen __DEPUTY_UNUSED__ = header->length - 1;
call TXFIFO.write(TCAST(uint8_t * COUNT(tmpLen), header), header->length - 1);
}
}
call ChipSpiResource.attemptRelease();
signal Send.sendDone( m_msg, err );
}
-
-
-
- /***************** Tasks ****************/
-
- /***************** Defaults ****************/
- default async event void TimeStamp.transmittedSFD( uint16_t time, message_t* p_msg ) {
- }
-
- default async event void TimeStamp.receivedSFD( uint16_t time ) {
- }
}