📄 cc1000sendreceivep.nc
字号:
// $Id: CC1000SendReceiveP.nc,v 1.10 2008/06/11 00:46:23 razvanm Exp $/* * "Copyright (c) 2000-2005 The Regents of the University of California. * All rights reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose, without fee, and without written agreement is * hereby granted, provided that the above copyright notice, the following * two paragraphs and the author appear in all copies of this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS." * * Copyright (c) 2002-2005 Intel Corporation * All rights reserved. * * This file is distributed under the terms in the attached INTEL-LICENSE * file. If you do not find these files, copies can be found by writing to * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, * 94704. Attention: Intel License Inquiry. */#include "message.h"#include "crc.h"#include "CC1000Const.h"#include "Timer.h"/** * A rewrite of the low-power-listening CC1000 radio stack. * This file contains the send and receive logic for the CC1000 radio. * It does not do any media-access control. It requests the channel * via the ready-to-send event (rts) and starts transmission on reception * of the clear-to-send command (cts). It listens for packets if the * listen() command is called, and stops listening when off() is called. * <p> * This code has some degree of platform-independence, via the * CC1000Control, RSSIADC and SpiByteFifo interfaces which must be provided * by the platform. However, these interfaces may still reflect some * particularities of the mica2 hardware implementation. * * @author Philip Buonadonna * @author Jaein Jeong * @author Joe Polastre * @author David Gay */ module CC1000SendReceiveP { provides { interface Init; interface StdControl; interface Send; interface Receive; interface RadioTimeStamping; interface Packet; interface ByteRadio; interface PacketAcknowledgements; interface LinkPacketMetadata; } uses { //interface PowerManagement; interface CC1000Control; interface HplCC1000Spi; interface CC1000Squelch; interface ReadNow<uint16_t> as RssiRx; async command am_addr_t amAddress(); }}implementation { enum { OFF_STATE, INACTIVE_STATE, /* Not listening, but will accept sends */ LISTEN_STATE, /* Listening for packets */ /* Reception states */ SYNC_STATE, RX_STATE, RECEIVED_STATE, SENDING_ACK, /* Transmission states */ TXPREAMBLE_STATE, TXSYNC_STATE, TXDATA_STATE, TXCRC_STATE, TXFLUSH_STATE, TXWAITFORACK_STATE, TXREADACK_STATE, TXDONE_STATE, }; enum { SYNC_BYTE1 = 0x33, SYNC_BYTE2 = 0xcc, SYNC_WORD = SYNC_BYTE1 << 8 | SYNC_BYTE2, ACK_BYTE1 = 0xba, ACK_BYTE2 = 0x83, ACK_WORD = ACK_BYTE1 << 8 | ACK_BYTE2, ACK_LENGTH = 16, MAX_ACK_WAIT = 18 }; uint8_t radioState; struct { uint8_t ack : 1; /* acks enabled? */ uint8_t txBusy : 1; /* send pending? */ uint8_t invert : 1; /* data inverted? (see cc1000 datasheet) */ uint8_t rxBitOffset : 3; /* bit-offset of received bytes */ } f; // f for flags uint16_t count; uint16_t runningCrc; uint16_t rxShiftBuf; message_t rxBuf; message_t * ONE rxBufPtr = &rxBuf; uint16_t preambleLength; 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 * 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 * ONE amsg) { return (cc1000_footer_t *)(amsg->footer); } 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 */ /*----------------------------*/ void enterOffState() { radioState = OFF_STATE; } void enterInactiveState() { radioState = INACTIVE_STATE; } void enterListenState() { radioState = LISTEN_STATE; count = 0; } void enterSyncState() { radioState = SYNC_STATE; count = 0; rxShiftBuf = 0; } void enterRxState() { cc1000_header_t *header = getHeader(rxBufPtr); radioState = RX_STATE; header->length = sizeof rxBufPtr->data; count = sizeof(message_header_t) - sizeof(cc1000_header_t); runningCrc = 0; } void enterReceivedState() { radioState = RECEIVED_STATE; } void enterAckState() { radioState = SENDING_ACK; count = 0; } void enterTxPreambleState() { radioState = TXPREAMBLE_STATE; count = 0; runningCrc = 0; nextTxByte = 0xaa; } void enterTxSyncState() { radioState = TXSYNC_STATE; } void enterTxDataState() { radioState = TXDATA_STATE; // The count increment happens before the first byte is read from the // packet, so we subtract one from the real packet start point to // compensate. count = (sizeof(message_header_t) - sizeof(cc1000_header_t)) -1; } void enterTxCrcState() { radioState = TXCRC_STATE; } void enterTxFlushState() { radioState = TXFLUSH_STATE; count = 0; } void enterTxWaitForAckState() { radioState = TXWAITFORACK_STATE; count = 0; } void enterTxReadAckState() { radioState = TXREADACK_STATE; rxShiftBuf = 0; count = 0; } void enterTxDoneState() { radioState = TXDONE_STATE; } command error_t Init.init() { f.ack = TRUE; /* We always ack, for now at least */ call HplCC1000Spi.initSlave(); return SUCCESS; } command error_t StdControl.start() { atomic { enterInactiveState(); f.txBusy = FALSE; f.invert = call CC1000Control.getLOStatus(); } return SUCCESS; } command error_t StdControl.stop() { atomic enterOffState(); return SUCCESS; } /* Send side. Outside requests, SPI handlers for each state */ /*----------------------------------------------------------*/ command error_t Send.send(message_t *msg, uint8_t len) { atomic { if (f.txBusy || radioState == OFF_STATE) return FAIL; else { cc1000_header_t *header = getHeader(msg); f.txBusy = TRUE; header->length = len; txBufPtr = msg; } } signal ByteRadio.rts(msg); return SUCCESS; } async command void ByteRadio.cts() { /* We're set to go! Start with our exciting preamble... */ enterTxPreambleState(); call HplCC1000Spi.writeByte(0xaa); call CC1000Control.txMode(); call HplCC1000Spi.txMode(); } command error_t Send.cancel(message_t *msg) { /* We simply ignore cancellations. */ return FAIL; } void sendNextByte() { call HplCC1000Spi.writeByte(nextTxByte); count++; } void txPreamble() { sendNextByte(); if (count >= preambleLength) { nextTxByte = SYNC_BYTE1; enterTxSyncState(); } } void txSync() { sendNextByte(); nextTxByte = SYNC_BYTE2; enterTxDataState(); signal RadioTimeStamping.transmittedSFD(0, txBufPtr); } void txData() { cc1000_header_t *txHeader = getHeader(txBufPtr); sendNextByte(); if (count < txHeader->length + sizeof(message_header_t)) { nextTxByte = ((uint8_t *)txBufPtr)[count]; runningCrc = crcByte(runningCrc, nextTxByte); } else { nextTxByte = runningCrc; enterTxCrcState(); } } void txCrc() { sendNextByte(); nextTxByte = runningCrc >> 8; enterTxFlushState(); } void txFlush() { sendNextByte(); if (count > 3) if (f.ack) enterTxWaitForAckState(); else { call HplCC1000Spi.rxMode(); call CC1000Control.rxMode(); enterTxDoneState(); } } void txWaitForAck() { sendNextByte(); if (count == 1) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -