⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cc1000sendreceivep.nc

📁 tinyos-2.x.rar
💻 NC
📖 第 1 页 / 共 2 页
字号:
/*
 * "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"
#include "CC1000TimeSyncMessage.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
 * @author Marco Langerwisch (Packet timestamping)
 */
  
module CC1000SendReceiveP @safe() {
  provides {
    interface Init;
    interface StdControl;
    interface Send;
    interface Receive;
    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,

    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);
          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);

    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();
  }

  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))
      {
	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)
      {
	call HplCC1000Spi.rxMode();
	call CC1000Control.rxMode();
      }
    else if (count > 3)
      enterTxReadAckState();
  }

  void txReadAck(uint8_t in) {
    uint8_t i;

    sendNextByte();

    for (i = 0; i < 8; i ++)
      {
	rxShiftBuf <<= 1;
	if (in & 0x80)
	  rxShiftBuf |=  0x1;
	in <<= 1;

	if (rxShiftBuf == ACK_WORD)
	  {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -