-// $Id$
-
-/* tab:4
+/*
* "Copyright (c) 2000-2005 The Regents of the University of California.
* All rights reserved.
*
#include "crc.h"
#include "CC1000Const.h"
#include "Timer.h"
+#include "CC1000TimeSyncMessage.h"
/**
* A rewrite of the low-power-listening CC1000 radio stack.
* @author Jaein Jeong
* @author Joe Polastre
* @author David Gay
+ * @author Marco Langerwisch (Packet timestamping)
*/
-module CC1000SendReceiveP {
+module CC1000SendReceiveP @safe() {
provides {
interface Init;
interface StdControl;
interface Send;
interface Receive;
- interface RadioTimeStamping;
interface Packet;
interface ByteRadio;
interface PacketAcknowledgements;
+ interface LinkPacketMetadata;
+
+ interface PacketTimeStamp<T32khz, uint32_t> as PacketTimeStamp32khz;
+ interface PacketTimeStamp<TMilli, uint32_t> as PacketTimeStampMilli;
+ interface PacketTimeSyncOffset;
}
uses {
//interface PowerManagement;
interface CC1000Control;
interface HplCC1000Spi;
-
+ interface CC1000Squelch;
interface ReadNow<uint16_t> as RssiRx;
async command am_addr_t amAddress();
+
+ interface LocalTime<T32khz> as LocalTime32khz;
+ interface LocalTime<TMilli> as LocalTimeMilli;
}
}
implementation
{
+#ifdef PLATFORM_MICA2
+ // estimated calibration, 19.2 Kbps data, Manchester Encoding, time in jiffies (32768 Hz)
+ static const int8_t BIT_CORRECTION[8] = { 27, 28, 30, 32, 34, 36, 38, 40 };
+#else
+ // other platforms not calibrated yet
+ static const uint8_t BIT_CORRECTION[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+#endif
+
enum {
OFF_STATE,
uint16_t rxShiftBuf;
message_t rxBuf;
- message_t *rxBufPtr = &rxBuf;
+ message_t * ONE rxBufPtr = &rxBuf;
uint16_t preambleLength;
- message_t *txBufPtr;
+ message_t * ONE_NOK txBufPtr;
uint8_t nextTxByte;
const_uint8_t ackCode[5] = { 0xab, ACK_BYTE1, ACK_BYTE2, 0xaa, 0xaa };
/* Packet structure accessor functions. Note that everything is
* relative to the data field. */
- cc1000_header_t *getHeader(message_t *amsg) {
- return (cc1000_header_t *)(amsg->data - sizeof(cc1000_header_t));
+ cc1000_header_t * ONE getHeader(message_t * ONE amsg) {
+ return TCAST(cc1000_header_t * ONE, (uint8_t *)amsg + offsetof(message_t, data) - sizeof(cc1000_header_t));
}
- cc1000_footer_t *getFooter(message_t *amsg) {
+ cc1000_footer_t *getFooter(message_t * ONE amsg) {
return (cc1000_footer_t *)(amsg->footer);
}
- cc1000_metadata_t *getMetadata(message_t *amsg) {
- return (cc1000_metadata_t *)((uint8_t *)amsg->footer + sizeof(cc1000_footer_t));
+ cc1000_metadata_t * ONE getMetadata(message_t * ONE amsg) {
+ return TCAST(cc1000_metadata_t * ONE, (uint8_t *)amsg + offsetof(message_t, footer) + sizeof(cc1000_footer_t));
}
/* State transition functions */
return FAIL;
else {
cc1000_header_t *header = getHeader(msg);
+ cc1000_metadata_t *metadata = getMetadata(msg);
f.txBusy = TRUE;
header->length = len;
txBufPtr = msg;
+
+ metadata->timesync = FALSE;
+ metadata->timestamp = CC1000_INVALID_TIMESTAMP;
}
}
signal ByteRadio.rts(msg);
sendNextByte();
nextTxByte = SYNC_BYTE2;
enterTxDataState();
- signal RadioTimeStamping.transmittedSFD(0, txBufPtr);
}
void txData() {
cc1000_header_t *txHeader = getHeader(txBufPtr);
sendNextByte();
+
+ if (nextTxByte == SYNC_BYTE2) {
+ // SYNC_WORD has just been sent
+ uint32_t time32khz = call LocalTime32khz.get();
+ call PacketTimeStamp32khz.set(txBufPtr, time32khz);
+
+ if (call PacketTimeSyncOffset.isSet(txBufPtr)) {
+ timesync_radio_t *timesync = (timesync_radio_t*)((void*)txBufPtr + call PacketTimeSyncOffset.get(txBufPtr));
+ // set timesync event time as the offset between the event time and the SFD interrupt time (TEP 133)
+ *timesync -= time32khz;
+ }
+ }
if (count < txHeader->length + sizeof(message_header_t))
{
if (rxShiftBuf == ACK_WORD)
{
- getMetadata(txBufPtr)->ack = 1;
+ getMetadata(txBufPtr)->metadataBits |= CC1000_ACK_BIT;
enterTxDoneState();
return;
}
}
if (count >= MAX_ACK_WAIT)
{
- getMetadata(txBufPtr)->ack = 0;
+ getMetadata(txBufPtr)->metadataBits &= ~CC1000_ACK_BIT;
enterTxDoneState();
}
}
else if (count <= 6)
{
// TODO: Modify to be tolerant of bad bits in the preamble...
+ uint32_t time;
uint16_t tmp;
uint8_t i;
+ time = call LocalTime32khz.get();
+
// bit shift the data in with previous sample to find sync
tmp = rxShiftBuf;
rxShiftBuf = rxShiftBuf << 8 | in;
enterRxState();
signal ByteRadio.rx();
f.rxBitOffset = 7 - i;
- signal RadioTimeStamping.receivedSFD(0);
+ // correct receive time according to bit offset and set timestamp
+ time -= BIT_CORRECTION[f.rxBitOffset];
+ call PacketTimeStamp32khz.set(rxBufPtr, time);
+
call RssiRx.read();
}
}
rxShiftBuf = rxShiftBuf << 8 | in;
nextByte = rxShiftBuf >> f.rxBitOffset;
- ((uint8_t *)rxBufPtr)[count++] = nextByte;
+ ((uint8_t *COUNT(sizeof(message_t)))rxBufPtr)[count++] = nextByte;
// Adjust rxLength to correspond to the corresponding offset in message_t
rxLength += offsetof(message_t, data);
}
void packetReceiveDone() {
+ uint16_t snr;
+
+ snr = (uint16_t) getMetadata(rxBufPtr)->strength_or_preamble;
+ /* Higher signal strengths have lower voltages. So see if we're
+ CC1000_WHITE_BIT_THRESH *below* the noise floor. */
+ if ((snr + CC1000_WHITE_BIT_THRESH) < ((call CC1000Squelch.get()))) {
+ getMetadata(rxBufPtr)->metadataBits |= CC1000_WHITE_BIT;
+ }
+ else {
+ getMetadata(rxBufPtr)->metadataBits &= ~CC1000_WHITE_BIT;
+ }
+
post signalPacketReceived();
enterReceivedState();
}
/* Abstract packet layout */
command void Packet.clear(message_t *msg) {
- memset(msg, 0, sizeof(message_t));
+ memset(getHeader(msg), 0x0, sizeof(cc1000_header_t));
+ memset(getFooter(msg), 0x0, sizeof(cc1000_footer_t));
+ memset(getMetadata(msg), 0x0, sizeof(cc1000_metadata_t));
}
command uint8_t Packet.payloadLength(message_t *msg) {
command void* Packet.getPayload(message_t *msg, uint8_t len) {
if (len <= TOSH_DATA_LENGTH) {
- return (void*)msg->data;
+ return (void* COUNT_NOK(len))msg->data;
}
else {
return NULL;
}
async command bool PacketAcknowledgements.wasAcked(message_t *msg) {
- return getMetadata(msg)->ack;
+ return getMetadata(msg)->metadataBits & CC1000_ACK_BIT;
+ }
+
+ async command bool LinkPacketMetadata.highChannelQuality(message_t* msg) {
+ return getMetadata(msg)->metadataBits & CC1000_WHITE_BIT;
+ }
+
+ /***************** PacketTimeStamp32khz Commands ****************/
+ async command bool PacketTimeStamp32khz.isValid(message_t* msg)
+ {
+ return (getMetadata(msg)->timestamp != CC1000_INVALID_TIMESTAMP);
+ }
+
+ async command uint32_t PacketTimeStamp32khz.timestamp(message_t* msg)
+ {
+ return getMetadata(msg)->timestamp;
+ }
+
+ async command void PacketTimeStamp32khz.clear(message_t* msg)
+ {
+ getMetadata(msg)->timesync = FALSE;
+ getMetadata(msg)->timestamp = CC1000_INVALID_TIMESTAMP;
+ }
+
+ async command void PacketTimeStamp32khz.set(message_t* msg, uint32_t value)
+ {
+ getMetadata(msg)->timestamp = value;
+ }
+
+ /***************** PacketTimeStampMilli Commands ****************/
+ // over the air value is always T32khz
+ async command bool PacketTimeStampMilli.isValid(message_t* msg)
+ {
+ return call PacketTimeStamp32khz.isValid(msg);
+ }
+
+ async command uint32_t PacketTimeStampMilli.timestamp(message_t* msg)
+ {
+ int32_t offset = call PacketTimeStamp32khz.timestamp(msg) - call LocalTime32khz.get();
+ return (offset >> 5) + call LocalTimeMilli.get();
+ }
+
+ async command void PacketTimeStampMilli.clear(message_t* msg)
+ {
+ call PacketTimeStamp32khz.clear(msg);
+ }
+
+ async command void PacketTimeStampMilli.set(message_t* msg, uint32_t value)
+ {
+ int32_t offset = (value - call LocalTimeMilli.get()) << 5;
+ call PacketTimeStamp32khz.set(msg, offset + call LocalTime32khz.get());
+ }
+
+ /*----------------- PacketTimeSyncOffset -----------------*/
+ async command bool PacketTimeSyncOffset.isSet(message_t* msg)
+ {
+ return getMetadata(msg)->timesync;
+ }
+
+ async command uint8_t PacketTimeSyncOffset.get(message_t* msg)
+ {
+ return sizeof(cc1000_header_t) + getHeader(msg)->length - sizeof(timesync_radio_t);
+ }
+
+ async command void PacketTimeSyncOffset.set(message_t* msg)
+ {
+ getMetadata(msg)->timesync = TRUE;
+ }
+
+ async command void PacketTimeSyncOffset.cancel(message_t* msg)
+ {
+ getMetadata(msg)->timesync = FALSE;
}
- // Default events for radio send/receive coordinators do nothing.
- // Be very careful using these, or you'll break the stack.
- default async event void RadioTimeStamping.transmittedSFD(uint16_t time, message_t *msgBuff) { }
- default async event void RadioTimeStamping.receivedSFD(uint16_t time) { }
}