[Tinyos-2-commits] CVS: tinyos-2.x/tos/chips/cc1000_lpl ByteRadio.nc, NONE, 1.1.2.1 CC1000ActiveMessageC.nc, NONE, 1.1.2.1 CC1000ActiveMessageP.nc, NONE, 1.1.2.1 CC1000Const.h, NONE, 1.1.2.1 CC1000Control.nc, NONE, 1.1.2.1 CC1000ControlP.nc, NONE, 1.1.2.1 CC1000CsmaP.nc, NONE, 1.1.2.1 CC1000CsmaRadioC.nc, NONE, 1.1.2.1 CC1000LowPowerListening.h, NONE, 1.1.2.1 CC1000LowPowerListeningC.nc, NONE, 1.1.2.1 CC1000LowPowerListeningP.nc, NONE, 1.1.2.1 CC1000Msg.h, NONE, 1.1.2.1 CC1000RssiP.nc, NONE, 1.1.2.1 CC1000SendReceiveP.nc, NONE, 1.1.2.1 CC1000Squelch.nc, NONE, 1.1.2.1 CC1000SquelchP.nc, NONE, 1.1.2.1 CsmaControl.nc, NONE, 1.1.2.1 HplCC1000.nc, NONE, 1.1.2.1 HplCC1000Spi.nc, NONE, 1.1.2.1 LowPowerListening.nc, NONE, 1.1.2.1

David Gay idgay at users.sourceforge.net
Sun Oct 29 17:44:37 PST 2006


Update of /cvsroot/tinyos/tinyos-2.x/tos/chips/cc1000_lpl
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv21365

Added Files:
      Tag: tinyos-2_0_devel-BRANCH
	ByteRadio.nc CC1000ActiveMessageC.nc CC1000ActiveMessageP.nc 
	CC1000Const.h CC1000Control.nc CC1000ControlP.nc 
	CC1000CsmaP.nc CC1000CsmaRadioC.nc CC1000LowPowerListening.h 
	CC1000LowPowerListeningC.nc CC1000LowPowerListeningP.nc 
	CC1000Msg.h CC1000RssiP.nc CC1000SendReceiveP.nc 
	CC1000Squelch.nc CC1000SquelchP.nc CsmaControl.nc HplCC1000.nc 
	HplCC1000Spi.nc LowPowerListening.nc 
Log Message:
cc1000 lpl (repeated send) stack from David Moss


--- NEW FILE: ByteRadio.nc ---
/* $Id: ByteRadio.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay Exp $
 * Copyright (c) 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.
 */
/**
 * Radio logic is split between Csma (media-access control, low-power
 * listening and general control) and SendReceive (packet reception and
 * transmission). This interface specifies the interaction between these
 * two components.
 *
 * @author David Gay
 */
  
interface ByteRadio
{
  /**
   * SendReceive wants to send a packet.
   * @param msg Message to be sent.
   */
  event void rts(message_t *msg);

  /**
   * Access to the media granted. Start sending. SendReceive must signal
   * sendDone when transmission is complete. Note: the media-access-contro
   * layer must have enabled listening before calling cts().
   */
  async command void cts();

  /**
   * Between the rts() and sendDone() events, this must return the
   * message under transmission.
   * @return Message being transmitted.
   */
  async command message_t *getTxMessage();

  /**
   * Transmission complete.
   */
  async event void sendDone();

  /**
   * Set message preamble length.
   * @param bytes Preamble length in bytes
   */
  async command void setPreambleLength(uint16_t bytes);

  /**
   * Get message preamble length.
   * @return Preamble length in bytes
   */
  async command uint16_t getPreambleLength();

  /**
   * Enable listening for incoming packets.
   */
  async command void listen();

  /**
   * Disable listening for incoming packets.
   */
  async command void off();

  /**
   * SendReceive signals this event for every radio-byte-time while
   * listening is enabled and a message isn't being received or
   * transmitted.
   * @param preamble TRUE if a message preamble byte has been received
   */
  async event void idleByte(bool preamble);

  /**
   * Detect if SendReceive is attempting to sync with an incoming packet.
   * During sync, idleByte events are not signaled. If sync is successful,
   * an rx() event will be signaled, if it fails, idleByte events will
   * resume. If syncing() returns TRUE, the last idleByte() event must
   * have had preamble = TRUE.
   *
   * @return TRUE if a sync attempt is in progress, FALSE if not.
   */
  async command bool syncing();

  /**
   * A message is being received
   */
  async event void rx();

  /**
   * Message reception is complete.
   */
  async event void rxDone();
}

--- NEW FILE: CC1000ActiveMessageC.nc ---
// $Id: CC1000ActiveMessageC.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay Exp $

/*									tab:4
 * "Copyright (c) 2004-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) 2004-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.
 */

/**
 *
 * The Active Message layer for the CC1000 radio. This configuration
 * just layers the AM dispatch (CC1000ActiveMessageM) on top of the
 * underlying CC1000 radio packet (CC1000CsmaRadioC), which is
 * inherently an AM packet (acknowledgements based on AM destination
 * addr and group).
 * 
 * @author Philip Levis
 * @date June 19 2005
 */

configuration CC1000ActiveMessageC {
  provides {
    interface SplitControl;
    interface AMSend[am_id_t id];
    interface Receive[am_id_t id];
    interface Receive as Snoop[am_id_t id];
    interface AMPacket;
    interface Packet;
    interface PacketAcknowledgements;
    interface LowPowerListening;
  }
}
implementation {

  components CC1000ActiveMessageP as AM, CC1000CsmaRadioC as Radio;
  components ActiveMessageAddressC as Address;
  components CC1000LowPowerListeningC as Lpl;
  
  SplitControl = Radio;
  Packet       = Radio;
  PacketAcknowledgements = Radio;
  LowPowerListening = Radio;

  AMSend   = AM;
  Receive  = AM.Receive;
  Snoop    = AM.Snoop;
  AMPacket = AM;

  AM.SubSend    -> Lpl.Send;
  AM.SubReceive -> Lpl.Receive;
  AM.amAddress -> Address;
  AM.Packet     -> Radio;
}

--- NEW FILE: CC1000ActiveMessageP.nc ---
// $Id: CC1000ActiveMessageP.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay Exp $

/*									tab:4
 * "Copyright (c) 2004-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) 2004-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.
 */
/**
 * Implementation component for CC1000ActiveMessageC.
 *
 * @author Philip Levis
 * @date June 19 2006
 */

module CC1000ActiveMessageP {
  provides {
    interface AMSend[am_id_t id];
    interface Receive[am_id_t id];
    interface Receive as Snoop[am_id_t id];
    interface AMPacket;
  }
  uses {
    interface Send as SubSend;
    interface Receive as SubReceive;
    interface Packet as Packet;
    command am_addr_t amAddress();
  }
}
implementation {

  cc1000_header_t* getHeader(message_t* amsg) {
    return (cc1000_header_t*)(amsg->data - sizeof(cc1000_header_t));
  }
  
  command error_t AMSend.send[am_id_t id](am_addr_t addr,
					  message_t* amsg,
					  uint8_t len) {
    cc1000_header_t* header = getHeader(amsg);
    header->type = id;
    header->dest = addr;
    header->source = call AMPacket.address();
    header->group = TOS_AM_GROUP;
    return call SubSend.send(amsg, len);
  }

  command error_t AMSend.cancel[am_id_t id](message_t* msg) {
    return call SubSend.cancel(msg);
  }

  event void SubSend.sendDone(message_t* msg, error_t result) {
    signal AMSend.sendDone[call AMPacket.type(msg)](msg, result);
  }

  command uint8_t AMSend.maxPayloadLength[am_id_t id]() {
    return call Packet.maxPayloadLength();
  }

  command void* AMSend.getPayload[am_id_t id](message_t* m) {
    return call Packet.getPayload(m, NULL);
  }

  /* Receiving a packet */

  event message_t* SubReceive.receive(message_t* msg, void* payload, uint8_t len) {
    if (call AMPacket.isForMe(msg)) {
      return signal Receive.receive[call AMPacket.type(msg)](msg, payload, len);
    }
    else {
      return signal Snoop.receive[call AMPacket.type(msg)](msg, payload, len);
    }
  }
  
  command void* Receive.getPayload[am_id_t id](message_t* m, uint8_t* len) {
    return call Packet.getPayload(m, len);
  }

  command uint8_t Receive.payloadLength[am_id_t id](message_t* m) {
    return call Packet.payloadLength(m);
  }
  
  command void* Snoop.getPayload[am_id_t id](message_t* m, uint8_t* len) {
    return call Packet.getPayload(m, len);
  }

  command uint8_t Snoop.payloadLength[am_id_t id](message_t* m) {
    return call Packet.payloadLength(m);
  }

  command am_addr_t AMPacket.address() {
    return call amAddress();
  }
 
  command am_addr_t AMPacket.destination(message_t* amsg) {
    cc1000_header_t* header = getHeader(amsg);
    return header->dest;
  }

  command am_addr_t AMPacket.source(message_t* amsg) {
    cc1000_header_t* header = getHeader(amsg);
    return header->source;
  }

  command void AMPacket.setDestination(message_t* amsg, am_addr_t addr) {
    cc1000_header_t* header = getHeader(amsg);
    header->dest = addr;
  }

  command void AMPacket.setSource(message_t* amsg, am_addr_t addr) {
    cc1000_header_t* header = getHeader(amsg);
    header->source = addr;
  }
  
  command bool AMPacket.isForMe(message_t* amsg) {
    return (call AMPacket.destination(amsg) == call AMPacket.address() ||
	    call AMPacket.destination(amsg) == AM_BROADCAST_ADDR);
  }

  command am_id_t AMPacket.type(message_t* amsg) {
    cc1000_header_t* header = getHeader(amsg);
    return header->type;
  }

  command void AMPacket.setType(message_t* amsg, am_id_t type) {
    cc1000_header_t* header = getHeader(amsg);
    header->type = type;
  }
  
  //command am_group_t AMPacket.group(message_t* amsg) {
  //  return amsg->header.group;
  //}
  
 default event message_t* Receive.receive[am_id_t id](message_t* msg, void* payload, uint8_t len) {
    return msg;
  }
  
  default event message_t* Snoop.receive[am_id_t id](message_t* msg, void* payload, uint8_t len) {
    return msg;
  }

 default event void AMSend.sendDone[uint8_t id](message_t* msg, error_t err) {
   return;
 }

  

}

--- NEW FILE: CC1000Const.h ---
// $Id: CC1000Const.h,v 1.1.2.1 2006/10/30 01:44:34 idgay Exp $

/* -*- Mode: C; c-basic-indent: 2; indent-tabs-mode: nil -*- */ 
/*									tab:4
 *  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.  By
 *  downloading, copying, installing or using the software you agree to
 *  this license.  If you do not agree to this license, do not download,
 *  install, copy or use the software.
 *
 *  Intel Open Source License 
 *
 *  Copyright (c) 2002 Intel Corporation 
 *  All rights reserved. 
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are
 *  met:
 * 
 *	Redistributions of source code must retain the above copyright
 *  notice, this list of conditions and the following disclaimer.
 *	Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *      Neither the name of the Intel Corporation nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 *  PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE INTEL OR ITS
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * 
 */

/*
 * Constants for CC1000 radio
 *
 * @author Phil Buonadonna
 */

#ifndef CC1000CONST_H
#define CC1000CONST_H

/* Constants defined for CC1K */
/* Register addresses */

enum {
  CC1K_MAIN =           0x00,
  CC1K_FREQ_2A =        0x01,
  CC1K_FREQ_1A =        0x02,
  CC1K_FREQ_0A =        0x03,
  CC1K_FREQ_2B =        0x04,
  CC1K_FREQ_1B =        0x05,
  CC1K_FREQ_0B =        0x06,
  CC1K_FSEP1 =          0x07,
  CC1K_FSEP0 =          0x08,
  CC1K_CURRENT =        0x09,
  CC1K_FRONT_END =      0x0A, //10
  CC1K_PA_POW =         0x0B, //11
  CC1K_PLL =            0x0C, //12
  CC1K_LOCK =           0x0D, //13
  CC1K_CAL =            0x0E, //14
  CC1K_MODEM2 =         0x0F, //15
  CC1K_MODEM1 =         0x10, //16
  CC1K_MODEM0 =         0x11, //17
  CC1K_MATCH =          0x12, //18
  CC1K_FSCTRL =         0x13, //19
  CC1K_FSHAPE7 =        0x14, //20
  CC1K_FSHAPE6 =        0x15, //21
  CC1K_FSHAPE5 =        0x16, //22
  CC1K_FSHAPE4 =        0x17, //23
  CC1K_FSHAPE3 =        0x18, //24
  CC1K_FSHAPE2 =        0x19, //25
  CC1K_FSHAPE1 =        0x1A, //26
  CC1K_FSDELAY =        0x1B, //27
  CC1K_PRESCALER =      0x1C, //28
  CC1K_TEST6 =          0x40, //64
  CC1K_TEST5 =          0x41, //66
  CC1K_TEST4 =          0x42, //67
  CC1K_TEST3 =          0x43, //68
  CC1K_TEST2 =          0x44, //69
  CC1K_TEST1 =          0x45, //70
  CC1K_TEST0 =          0x46, //71

  // MAIN Register Bit Posititions
  CC1K_RXTX =		7,
  CC1K_F_REG =		6,
  CC1K_RX_PD =		5,
  CC1K_TX_PD =		4,
  CC1K_FS_PD =		3,
  CC1K_CORE_PD =	2,
  CC1K_BIAS_PD =	1,
  CC1K_RESET_N =	0,

  // CURRENT Register Bit Positions
  CC1K_VCO_CURRENT =	4,
  CC1K_LO_DRIVE =	2,
  CC1K_PA_DRIVE =	0,

  // FRONT_END Register Bit Positions
  CC1K_BUF_CURRENT =	5,
  CC1K_LNA_CURRENT =	3,
  CC1K_IF_RSSI =	1,
  CC1K_XOSC_BYPASS =	0,

  // PA_POW Register Bit Positions
  CC1K_PA_HIGHPOWER =	4,
  CC1K_PA_LOWPOWER =	0,

  // PLL Register Bit Positions
  CC1K_EXT_FILTER =	7,
  CC1K_REFDIV =		3,
  CC1K_ALARM_DISABLE =	2,
  CC1K_ALARM_H =	1,
  CC1K_ALARM_L =	0,

  // LOCK Register Bit Positions
  CC1K_LOCK_SELECT =		4,
  CC1K_PLL_LOCK_ACCURACY =	3,
  CC1K_PLL_LOCK_LENGTH =	2,
  CC1K_LOCK_INSTANT =		1,
  CC1K_LOCK_CONTINUOUS =	0,

  // CAL Register Bit Positions
  CC1K_CAL_START =	7,
  CC1K_CAL_DUAL =	6,
  CC1K_CAL_WAIT =	5,
  CC1K_CAL_CURRENT =	4,
  CC1K_CAL_COMPLETE =	3,
  CC1K_CAL_ITERATE =	0,

  // MODEM2 Register Bit Positions
  CC1K_PEAKDETECT =		7,
  CC1K_PEAK_LEVEL_OFFSET =	0,

  // MODEM1 Register Bit Positions
  CC1K_MLIMIT =		5,
  CC1K_LOCK_AVG_IN =	4,
  CC1K_LOCK_AVG_MODE =	3,
  CC1K_SETTLING =	1,
  CC1K_MODEM_RESET_N =	0,

  // MODEM0 Register Bit Positions
  CC1K_BAUDRATE =	4,
  CC1K_DATA_FORMAT =	2,
  CC1K_XOSC_FREQ =	0,

  // MATCH Register Bit Positions
  CC1K_RX_MATCH =	4,
  CC1K_TX_MATCH =	0,

  // FSCTLR Register Bit Positions
  CC1K_DITHER1 =	3,
  CC1K_DITHER0 =	2,
  CC1K_SHAPE =		1,
  CC1K_FS_RESET_N =	0,

  // PRESCALER Register Bit Positions
  CC1K_PRE_SWING =	6,
  CC1K_PRE_CURRENT =	4,
  CC1K_IF_INPUT =	3,
  CC1K_IF_FRONT =	2,

  // TEST6 Register Bit Positions
  CC1K_LOOPFILTER_TP1 =	7,
  CC1K_LOOPFILTER_TP2 =	6,
  CC1K_CHP_OVERRIDE =	5,
  CC1K_CHP_CO =		0,

  // TEST5 Register Bit Positions
  CC1K_CHP_DISABLE =	5,
  CC1K_VCO_OVERRIDE =	4,
  CC1K_VCO_AO =		0,

  // TEST3 Register Bit Positions
  CC1K_BREAK_LOOP =	4,
  CC1K_CAL_DAC_OPEN =	0,


  /* 
   * CC1K Register Parameters Table
   *
   * This table follows the same format order as the CC1K register 
   * set EXCEPT for the last entry in the table which is the 
   * CURRENT register value for TX mode.
   *  
   * NOTE: To save RAM space, this table resides in program memory (flash). 
   * This has two important implications:
   *	1) You can't write to it (duh!)
   *	2) You must read it using the PRG_RDB(addr) macro. IT CANNOT BE ACCESSED AS AN ORDINARY C ARRAY.  
   * 
   * Add/remove individual entries below to suit your RF tastes.
   * 
   */
  CC1K_433_002_MHZ =	0x00,
  CC1K_915_998_MHZ =	0x01,
  CC1K_434_845_MHZ =    0x02,
  CC1K_914_077_MHZ =    0x03,
  CC1K_315_178_MHZ =    0x04,

  //#define CC1K_SquelchInit        0x02F8 // 0.90V using the bandgap reference
  CC1K_SquelchInit =        0x120,
  CC1K_SquelchTableSize =   9,
  CC1K_MaxRSSISamples =     5,
  CC1K_Settling =           1,
  CC1K_ValidPrecursor =     2,
  CC1K_SquelchIntervalFast = 128,
  CC1K_SquelchIntervalSlow = 2560,
  CC1K_SquelchCount =       30,
  CC1K_SquelchBuffer =      12,

  CC1K_LPL_PACKET_TIME =    16,

  CC1K_LPL_CHECK_TIME =     16, /* In tenth's of milliseconds, this should
				  be an approximation of the on-time for
			          a LPL check rather than the total check
			          time. */
  CC1K_LPL_MIN_INTERVAL =    5, /* In milliseconds, the minimum interval
				   between low-power-listening checks */
  CC1K_LPL_MAX_INTERVAL =    10000,  /* In milliseconds, the maximum interval
				       between low-power-listening checks.
				       Arbitrary value, but must be at
				       most 32767 because of the way
				       sleep interval is stored in outgoing
				       messages */
				       
	CC1000_MIN_BACKOFF = 2,
	CC1000_BACKOFF_PERIOD = 2,
};

#ifdef CC1K_DEFAULT_FREQ
#define CC1K_DEF_PRESET (CC1K_DEFAULT_FREQ)
#endif
#ifdef CC1K_MANUAL_FREQ
#define CC1K_DEF_FREQ (CC1K_MANUAL_FREQ)
#endif

#ifndef CC1K_DEF_PRESET
#define CC1K_DEF_PRESET	(CC1K_914_077_MHZ)
#endif 

static const_uint8_t CC1K_Params[6][20] = {
  // (0) 433.002 MHz channel, 19.2 Kbps data, Manchester Encoding, High Side LO
  { // MAIN   0x00
    0x31,
    // FREQ2A,FREQ1A,FREQ0A  0x01-0x03
    0x58,0x00,0x00,					
    // FREQ2B,FREQ1B,FREQ0B  0x04-0x06
    0x57,0xf6,0x85,    //XBOW
    // FSEP1, FSEP0     0x07-0x08
    0X03,0x55,
    // CURRENT RX MODE VALUE   0x09 also see below
    4 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE,	
    // FRONT_END  0x0a
    1 << CC1K_IF_RSSI,
    // PA_POW  0x0b
    0x0 << CC1K_PA_HIGHPOWER | 0xf << CC1K_PA_LOWPOWER, 
    // PLL  0x0c
    12 << CC1K_REFDIV,		
    // LOCK  0x0d
    0xe << CC1K_LOCK_SELECT,
    // CAL  0x0e
    1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE,	
    // MODEM2  0x0f
    0 << CC1K_PEAKDETECT | 28 << CC1K_PEAK_LEVEL_OFFSET,
    // MODEM1  0x10
    3 << CC1K_MLIMIT | 1 << CC1K_LOCK_AVG_MODE | CC1K_Settling << CC1K_SETTLING | 1 << CC1K_MODEM_RESET_N, 
    // MODEM0  0x11
    5 << CC1K_BAUDRATE | 1 << CC1K_DATA_FORMAT | 1 << CC1K_XOSC_FREQ,
    // MATCH  0x12
    0x7 << CC1K_RX_MATCH | 0x0 << CC1K_TX_MATCH,
    // tx current (extra)
    8 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE,
  },

  // 1 915.9988 MHz channel, 19.2 Kbps data, Manchester Encoding, High Side LO
  { // MAIN   0x00 
    0x31,
    // FREQ2A,FREQ1A,FREQ0A  0x01-0x03
    0x7c,0x00,0x00,					
    // FREQ2B,FREQ1B,FREQ0B  0x04-0x06
    0x7b,0xf9,0xae,					
    // FSEP1, FSEP0     0x07-0x8
    0x02,0x38,
    // CURRENT RX MODE VALUE   0x09 also see below
    8 << CC1K_VCO_CURRENT | 3 << CC1K_LO_DRIVE,
    //0x8C,	
    // FRONT_END  0x0a
    1 << CC1K_BUF_CURRENT | 2 << CC1K_LNA_CURRENT | 1 << CC1K_IF_RSSI,
    //0x32,
    // PA_POW  0x0b
    0x8 << CC1K_PA_HIGHPOWER | 0x0 << CC1K_PA_LOWPOWER, 
    //0xff,
    // PLL  0xc
    8 << CC1K_REFDIV,		
    //0x40,
    // LOCK  0xd
    0x1 << CC1K_LOCK_SELECT,
    //0x10,
    // CAL  0xe
    1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE,	
    //0x26,
    // MODEM2  0xf
    1 << CC1K_PEAKDETECT | 33 << CC1K_PEAK_LEVEL_OFFSET,
    //0xA1,
    // MODEM1  0x10
    3 << CC1K_MLIMIT | 1 << CC1K_LOCK_AVG_MODE | CC1K_Settling << CC1K_SETTLING | 1 << CC1K_MODEM_RESET_N, 
    //0x6f, 
    // MODEM0  0x11
    5 << CC1K_BAUDRATE | 1 << CC1K_DATA_FORMAT | 1 << CC1K_XOSC_FREQ,
    //0x55,
    // MATCH 0x12
    0x1 << CC1K_RX_MATCH | 0x0 << CC1K_TX_MATCH,
    // tx current (extra)
    15 << CC1K_VCO_CURRENT | 3 << CC1K_PA_DRIVE,
  },

  // 2 434.845200 MHz channel, 19.2 Kbps data, Manchester Encoding, High Side LO
  { // MAIN   0x00
    0x31,
    // FREQ2A,FREQ1A,FREQ0A  0x01-0x03
    0x51,0x00,0x00,					
    // FREQ2B,FREQ1B,FREQ0B  0x04-0x06
    0x50,0xf7,0x4F,    //XBOW
    // FSEP1, FSEP0     0x07-0x08
    0X03,0x0E,
    // CURRENT RX MODE VALUE   0x09 also see below
    4 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE,	
    // FRONT_END  0x0a
    1 << CC1K_IF_RSSI,
    // PA_POW  0x0b
    0x0 << CC1K_PA_HIGHPOWER | 0xf << CC1K_PA_LOWPOWER, 
    // PLL  0x0c
    11 << CC1K_REFDIV,		
    // LOCK  0x0d
    0xe << CC1K_LOCK_SELECT,
    // CAL  0x0e
    1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE,	
    // MODEM2  0x0f
    1 << CC1K_PEAKDETECT | 33 << CC1K_PEAK_LEVEL_OFFSET,
    // MODEM1  0x10
    3 << CC1K_MLIMIT | 1 << CC1K_LOCK_AVG_MODE | CC1K_Settling << CC1K_SETTLING | 1 << CC1K_MODEM_RESET_N, 
    // MODEM0  0x11
    5 << CC1K_BAUDRATE | 1 << CC1K_DATA_FORMAT | 1 << CC1K_XOSC_FREQ,
    // MATCH  0x12
    0x7 << CC1K_RX_MATCH | 0x0 << CC1K_TX_MATCH,
    // tx current (extra)
    8 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE,
  },

 
  // 3 914.077 MHz channel, 19.2 Kbps data, Manchester Encoding, High Side LO
  { // MAIN   0x00 
    0x31,
    // FREQ2A,FREQ1A,FREQ0A  0x01-0x03
    0x5c,0xe0,0x00,					
    // FREQ2B,FREQ1B,FREQ0B  0x04-0x06
    0x5c,0xdb,0x42,					
    // FSEP1, FSEP0     0x07-0x8
    0x01,0xAA,
    // CURRENT RX MODE VALUE   0x09 also see below
    8 << CC1K_VCO_CURRENT | 3 << CC1K_LO_DRIVE,
    //0x8C,	
    // FRONT_END  0x0a
    1 << CC1K_BUF_CURRENT | 2 << CC1K_LNA_CURRENT | 1 << CC1K_IF_RSSI,
    //0x32,
    // PA_POW  0x0b
    0x8 << CC1K_PA_HIGHPOWER | 0x0 << CC1K_PA_LOWPOWER, 
    //0xff,
    // PLL  0xc
    6 << CC1K_REFDIV,		
    //0x40,
    // LOCK  0xd
    0x1 << CC1K_LOCK_SELECT,
    //0x10,
    // CAL  0xe
    1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE,	
    //0x26,
    // MODEM2  0xf
    1 << CC1K_PEAKDETECT | 33 << CC1K_PEAK_LEVEL_OFFSET,
    //0xA1,
    // MODEM1  0x10
    3 << CC1K_MLIMIT | 1 << CC1K_LOCK_AVG_MODE | CC1K_Settling << CC1K_SETTLING | 1 << CC1K_MODEM_RESET_N, 
    //0x6f, 
    // MODEM0  0x11
    5 << CC1K_BAUDRATE | 1 << CC1K_DATA_FORMAT | 1 << CC1K_XOSC_FREQ,
    //0x55,
    // MATCH 0x12
    0x1 << CC1K_RX_MATCH | 0x0 << CC1K_TX_MATCH,
    // tx current (extra)
    15 << CC1K_VCO_CURRENT | 3 << CC1K_PA_DRIVE,
  },

  // 4 315.178985 MHz channel, 38.4 Kbps data, Manchester Encoding, High Side LO
  { // MAIN   0x00
    0x31,
    // FREQ2A,FREQ1A,FREQ0A  0x01-0x03
    0x45,0x60,0x00,					
    // FREQ2B,FREQ1B,FREQ0B  0x04-0x06
    0x45,0x55,0xBB,
    // FSEP1, FSEP0     0x07-0x08
    0X03,0x9C,
    // CURRENT RX MODE VALUE   0x09 also see below
    8 << CC1K_VCO_CURRENT | 0 << CC1K_LO_DRIVE,	
    // FRONT_END  0x0a
    1 << CC1K_IF_RSSI,
    // PA_POW  0x0b
    0x0 << CC1K_PA_HIGHPOWER | 0xf << CC1K_PA_LOWPOWER, 
    // PLL  0x0c
    13 << CC1K_REFDIV,		
    // LOCK  0x0d
    0xe << CC1K_LOCK_SELECT,
    // CAL  0x0e
    1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE,	
    // MODEM2  0x0f
    1 << CC1K_PEAKDETECT | 33 << CC1K_PEAK_LEVEL_OFFSET,
    // MODEM1  0x10
    3 << CC1K_MLIMIT | 1 << CC1K_LOCK_AVG_MODE | CC1K_Settling << CC1K_SETTLING | 1 << CC1K_MODEM_RESET_N, 
    // MODEM0  0x11
    5 << CC1K_BAUDRATE | 1 << CC1K_DATA_FORMAT | 0 << CC1K_XOSC_FREQ,
    // MATCH  0x12
    0x7 << CC1K_RX_MATCH | 0x0 << CC1K_TX_MATCH,
    // tx current (extra)
    8 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE,
  },

  // 5 Spare
  { // MAIN   0x00
    0x31,
    // FREQ2A,FREQ1A,FREQ0A  0x01-0x03
    0x58,0x00,0x00,					
    // FREQ2B,FREQ1B,FREQ0B  0x04-0x06
    0x57,0xf6,0x85,    //XBOW
    // FSEP1, FSEP0     0x07-0x08
    0X03,0x55,
    // CURRENT RX MODE VALUE   0x09 also see below
    8 << CC1K_VCO_CURRENT | 4 << CC1K_LO_DRIVE,	
    // FRONT_END  0x0a
    1 << CC1K_IF_RSSI,
    // PA_POW  0x0b
    0x0 << CC1K_PA_HIGHPOWER | 0xf << CC1K_PA_LOWPOWER, 
    // PLL  0x0c
    12 << CC1K_REFDIV,		
    // LOCK  0x0d
    0xe << CC1K_LOCK_SELECT,
    // CAL  0x0e
    1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE,	
    // MODEM2  0x0f
    1 << CC1K_PEAKDETECT | 33 << CC1K_PEAK_LEVEL_OFFSET,
    // MODEM1  0x10
    3 << CC1K_MLIMIT | 1 << CC1K_LOCK_AVG_MODE | CC1K_Settling << CC1K_SETTLING | 1 << CC1K_MODEM_RESET_N,    // MODEM0  0x11
    5 << CC1K_BAUDRATE | 1 << CC1K_DATA_FORMAT | 1 << CC1K_XOSC_FREQ,
    // MATCH  0x12
    0x7 << CC1K_RX_MATCH | 0x0 << CC1K_TX_MATCH,
    // tx current (extra)
    8 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE,
  },
};

#define UQ_CC1000_RSSI "CC1000RssiP.Rssi"

#endif /* CC1000CONST_H */

--- NEW FILE: CC1000Control.nc ---
/* $Id: CC1000Control.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay 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.
 */
/**
 * CC1000 internal radio control interface.
 * @author Philip Buonadonna
 * @aythor Jaein Jeong
 */
interface CC1000Control
{
  /**
   * Initialise the radio to its default state.
   */
  command void init();

  /**
   * Tune the radio to one of the frequencies available in the CC1K_Params
   * table.  Calling Tune will allso reset the rfpower and LockVal
   * selections to the table values.
   * 
   * @param freq The index into the CC1K_Params table that holds the
   * desired preset frequency parameters.
   */
  command void tunePreset(uint8_t freq); 

  /**
   * Tune the radio to a given frequency. Since the CC1000 uses a digital
   * frequency synthesizer, it cannot tune to just an arbitrary frequency.
   * This routine will determine the closest achievable channel, compute
   * the necessary parameters and tune the radio.
   * 
   * @param The desired channel frequency, in Hz.
   * 
   * @return The actual computed channel frequency, in Hz.  A return value
   * of '0' indicates that no frequency was computed and the radio was not
   * tuned.
   */
  command uint32_t tuneManual(uint32_t DesiredFreq);

  /**
   * Turn the CC1000 off
   */
  async command void off();

  /**
   * Shift the CC1000 Radio into transmit mode.
   */
  async command void txMode();

  /**
   * Shift the CC1000 Radio in receive mode.
   */
  async command void rxMode();

  /**
   * Turn off the bias power on the CC1000 radio, but leave the core and
   * crystal oscillator powered.  This will result in approximately a 750
   * uA power savings.
   */
  async command void coreOn();			

  /**
   * Turn the bias power on. This function must be followed by a call to
   * either rxMode() or txMode() to place the radio in a recieve/transmit
   * state respectively. There is approximately a 200us delay when
   * restoring bias power.
   */
  async command void biasOn();

  /**
   * Set the transmit RF power value.  The input value is simply an
   * arbitrary index that is programmed into the CC1000 registers.  Consult
   * the CC1000 datasheet for the resulting power output/current
   * consumption values.
   *
   * @param power A power index between 1 and 255.
   */
  command void setRFPower(uint8_t power);	

  /**
   * Get the present RF power index.
   *
   * @return The power index value.
   */
  command uint8_t getRFPower();		

  /** 
   * Select the signal to monitor at the CHP_OUT pin of the CC1000.  See
   * the CC1000 data sheet for the available signals.
   * 
   * @param LockVal The index of the signal to monitor at the CHP_OUT pin
   */
  command void selectLock(uint8_t LockVal); 

  /**
   * Get the binary value from the CHP_OUT pin.  Analog signals cannot be
   * read using function.
   *
   * @return 1 - Pin is high or 0 - Pin is low
   */
  command uint8_t getLock();

  /**
   * Returns whether the present frequency set is using high-side LO
   * injection or not.  This information is used to determine if the data
   * from the CC1000 needs to be inverted or not.
   *
   * @return TRUE if high-side LO injection is being used (i.e. data does NOT need to be inverted
   * at the receiver.
   */
  command bool getLOStatus();
}

--- NEW FILE: CC1000ControlP.nc ---
/* $Id: CC1000ControlP.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay 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 "CC1000Const.h"
#include "Timer.h"

/**
 * This module provides the CONTROL functionality for the Chipcon1000
 * series radio.  It exports a custom interface to control CC1000
 * operation.
 *
 * @author Philip Buonadonna
 * @author Jaein Jeong
 * @author David Gay
 */
module CC1000ControlP {
  provides {
    interface CC1000Control;
  }
  uses {
    interface HplCC1000 as CC;
    interface BusyWait<TMicro, uint16_t>;
  }
}
implementation
{
  uint8_t txCurrent, rxCurrent, power;

  enum {
    IF = 150000,
    FREQ_MIN = 4194304,
    FREQ_MAX = 16751615
  };

  const_uint32_t fRefTbl[9] = {2457600,
			       2106514,
			       1843200,
			       1638400,
			       1474560,
			       1340509,
			       1228800,
			       1134277,
			       1053257};
  
  const_uint16_t corTbl[9] = {1213,
			      1416,
			      1618,
			      1820,
			      2022,
			      2224,
			      2427,
			      2629,
			      2831};
  
  const_uint16_t fSepTbl[9] = {0x1AA,
			       0x1F1,
			       0x238,
			       0x280,
			       0x2C7,
			       0x30E,
			       0x355,
			       0x39C,
			       0x3E3};
  
  void calibrateNow() {
    // start cal
    call CC.write(CC1K_CAL,
		  1 << CC1K_CAL_START |
		  1 << CC1K_CAL_WAIT |
		  6 << CC1K_CAL_ITERATE);
    while ((call CC.read(CC1K_CAL) & 1 << CC1K_CAL_COMPLETE) == 0)
      ;

    //exit cal mode
    call CC.write(CC1K_CAL, 1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE);
  }

  void calibrate() {
    call CC.write(CC1K_PA_POW, 0x00);  // turn off rf amp
    call CC.write(CC1K_TEST4, 0x3f);   // chip rate >= 38.4kb

    // RX - configure main freq A
    call CC.write(CC1K_MAIN, 1 << CC1K_TX_PD | 1 << CC1K_RESET_N);

    calibrateNow();

    // TX - configure main freq B
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RXTX |
		  1 << CC1K_F_REG |
		  1 << CC1K_RX_PD | 
		  1 << CC1K_RESET_N);
    // Set TX current
    call CC.write(CC1K_CURRENT, txCurrent);
    call CC.write(CC1K_PA_POW, 0);

    calibrateNow();
  }

  /*
   * cc1000ComputeFreq(uint32_t desiredFreq);
   *
   * Compute an achievable frequency and the necessary CC1K parameters from
   * a given desired frequency (Hz). The function returns the actual achieved
   * channel frequency in Hz.
   *
   * This routine assumes the following:
   *  - Crystal Freq: 14.7456 MHz
   *  - LO Injection: High
   *  - Separation: 64 KHz
   *  - IF: 150 KHz
   * 
   * Approximate costs for this function:
   *  - ~870 bytes FLASH
   *  - ~32 bytes RAM
   *  - 9400 cycles
   */
  uint32_t cc1000SetFrequency(uint32_t desiredFreq) {
    uint32_t ActualChannel = 0;
    uint32_t RXFreq = 0, TXFreq = 0;
    int32_t Offset = 0x7fffffff;
    uint16_t FSep = 0;
    uint8_t RefDiv = 0;
    uint8_t i, match, frontend;

    for (i = 0; i < 9; i++)
      {
	uint32_t NRef = desiredFreq + IF;
	uint32_t FRef = read_uint32_t(&fRefTbl[i]);
	uint32_t Channel = 0;
	uint32_t RXCalc = 0, TXCalc = 0;
	int32_t  diff;

	NRef = ((desiredFreq + IF)  <<  2) / FRef;
	if (NRef & 0x1)
	  NRef++;

	if (NRef & 0x2)
	  {
	    RXCalc = 16384 >> 1;
	    Channel = FRef >> 1;
	  }

	NRef >>= 2;

	RXCalc += (NRef * 16384) - 8192;
	if ((RXCalc < FREQ_MIN) || (RXCalc > FREQ_MAX)) 
	  continue;
    
	TXCalc = RXCalc - read_uint16_t(&corTbl[i]);
	if (TXCalc < FREQ_MIN || TXCalc > FREQ_MAX)
	  continue;

	Channel += NRef * FRef;
	Channel -= IF;

	diff = Channel - desiredFreq;
	if (diff < 0)
	  diff = -diff;

	if (diff < Offset)
	  {
	    RXFreq = RXCalc;
	    TXFreq = TXCalc;
	    ActualChannel = Channel;
	    FSep = read_uint16_t(&fSepTbl[i]);
	    RefDiv = i + 6;
	    Offset = diff;
	  }
      }

    if (RefDiv != 0)
      {
	call CC.write(CC1K_FREQ_0A, RXFreq);
	call CC.write(CC1K_FREQ_1A, RXFreq >> 8);
	call CC.write(CC1K_FREQ_2A, RXFreq >> 16);

	call CC.write(CC1K_FREQ_0B, TXFreq);
	call CC.write(CC1K_FREQ_1B, TXFreq >> 8);
	call CC.write(CC1K_FREQ_2B, TXFreq >> 16);

	call CC.write(CC1K_FSEP0, FSep);
	call CC.write(CC1K_FSEP1, FSep >> 8);

	if (ActualChannel < 500000000)
	  {
	    if (ActualChannel < 400000000)
	      {
		rxCurrent = 8 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE;
		txCurrent = 9 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE;
	      }
	    else
	      {
		rxCurrent = 4 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE;
		txCurrent = 8 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE;
	      }
	    frontend = 1 << CC1K_IF_RSSI;
	    match = 7 << CC1K_RX_MATCH;
	  }
	else
	  {
	    rxCurrent = 8 << CC1K_VCO_CURRENT | 3 << CC1K_LO_DRIVE;
	    txCurrent = 15 << CC1K_VCO_CURRENT | 3 << CC1K_PA_DRIVE;

	    frontend =
	      1 << CC1K_BUF_CURRENT | 2 << CC1K_LNA_CURRENT | 
	      1 << CC1K_IF_RSSI;
	    match = 2 << CC1K_RX_MATCH; // datasheet says to use 1...
	  }
	call CC.write(CC1K_CURRENT, rxCurrent);
	call CC.write(CC1K_MATCH, match);
	call CC.write(CC1K_FRONT_END, frontend);
	call CC.write(CC1K_PLL, RefDiv << CC1K_REFDIV);
      }

    return ActualChannel;
  }

  command void CC1000Control.init() {
    call CC.init();

    // wake up xtal and reset unit
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RX_PD | 1 << CC1K_TX_PD | 
		  1 << CC1K_FS_PD | 1 << CC1K_BIAS_PD); 
    // clear reset.
    call CC1000Control.coreOn();
    call BusyWait.wait(2000);

    // Set default parameter values
    // POWER: 0dbm (~900MHz), 6dbm (~430MHz)
    power = 8 << CC1K_PA_HIGHPOWER | 0 << CC1K_PA_LOWPOWER;
    call CC.write(CC1K_PA_POW, power);

    // select Manchester Violation for CHP_OUT
    call CC.write(CC1K_LOCK_SELECT, 9 << CC1K_LOCK_SELECT);

    // Default modem values = 19.2 Kbps (38.4 kBaud), Manchester encoded
    call CC.write(CC1K_MODEM2, 0);
    call CC.write(CC1K_MODEM1, 
		  3 << CC1K_MLIMIT |
		  1 << CC1K_LOCK_AVG_MODE | 
		  3 << CC1K_SETTLING |
		  1 << CC1K_MODEM_RESET_N);
    call CC.write(CC1K_MODEM0, 
		  5 << CC1K_BAUDRATE |
		  1 << CC1K_DATA_FORMAT | 
		  1 << CC1K_XOSC_FREQ);

    call CC.write(CC1K_FSCTRL, 1 << CC1K_FS_RESET_N);

#ifdef CC1K_DEF_FREQ
    call CC1000Control.tuneManual(CC1K_DEF_FREQ);
#else
    call CC1000Control.tunePreset(CC1K_DEF_PRESET);
#endif
    call CC1000Control.off();
  }

  command void CC1000Control.tunePreset(uint8_t freq) {
    int i;

    // FREQA, FREQB, FSEP, CURRENT(RX), FRONT_END, POWER, PLL
    for (i = CC1K_FREQ_2A; i <= CC1K_PLL; i++)
      call CC.write(i, read_uint8_t(&CC1K_Params[freq][i]));
    call CC.write(CC1K_MATCH, read_uint8_t(&CC1K_Params[freq][CC1K_MATCH]));
    rxCurrent = read_uint8_t(&CC1K_Params[freq][CC1K_CURRENT]);
    txCurrent = read_uint8_t(&CC1K_Params[freq][CC1K_MATCH + 1]);
    power = read_uint8_t(&CC1K_Params[freq][CC1K_PA_POW]);

    calibrate();
  }

  command uint32_t CC1000Control.tuneManual(uint32_t DesiredFreq) {
    uint32_t actualFreq;

    actualFreq = cc1000SetFrequency(DesiredFreq);

    calibrate();

    return actualFreq;
  }

  async command void CC1000Control.txMode() {
    // MAIN register to TX mode
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RXTX |
		  1 << CC1K_F_REG |
		  1 << CC1K_RX_PD | 
		  1 << CC1K_RESET_N);
    // Set the TX mode VCO Current
    call CC.write(CC1K_CURRENT, txCurrent);
    call BusyWait.wait(250);
    call CC.write(CC1K_PA_POW, power);
    call BusyWait.wait(20);
  }

  async command void CC1000Control.rxMode() {
    // MAIN register to RX mode
    // Powerup Freqency Synthesizer and Receiver
    call CC.write(CC1K_CURRENT, rxCurrent);
    call CC.write(CC1K_PA_POW, 0); // turn off power amp
    call CC.write(CC1K_MAIN, 1 << CC1K_TX_PD | 1 << CC1K_RESET_N);
    call BusyWait.wait(125);
  }

  async command void CC1000Control.coreOn() {
    // MAIN register to SLEEP mode
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RX_PD |
		  1 << CC1K_TX_PD | 
		  1 << CC1K_FS_PD |
		  1 << CC1K_BIAS_PD |
		  1 << CC1K_RESET_N);
  }

  async command void CC1000Control.biasOn() {
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RX_PD |
		  1 << CC1K_TX_PD | 
		  1 << CC1K_FS_PD | 
		  1 << CC1K_RESET_N);
  }


  async command void CC1000Control.off() {
    // MAIN register to power down mode. Shut everything off
    call CC.write(CC1K_MAIN,
		  1 << CC1K_RX_PD |
		  1 << CC1K_TX_PD | 
		  1 << CC1K_FS_PD |
		  1 << CC1K_CORE_PD |
		  1 << CC1K_BIAS_PD |
		  1 << CC1K_RESET_N);
    call CC.write(CC1K_PA_POW, 0);  // turn off rf amp
  }

  command void CC1000Control.setRFPower(uint8_t newPower) {
    power = newPower;
  }

  command uint8_t CC1000Control.getRFPower() {
    return power;
  }

  command void CC1000Control.selectLock(uint8_t fn) {
    // Select function of CHP_OUT pin (readable via getLock)
    call CC.write(CC1K_LOCK, fn << CC1K_LOCK_SELECT);
  }

  command uint8_t CC1000Control.getLock() {
    return call CC.getLOCK(); 
  }

  command bool CC1000Control.getLOStatus() {
    // We use a high-side LO (local oscillator) frequency -> data will be
    // inverted. See cc1000ComputeFreq and CC1000 datasheet p.23.
    return TRUE;
  }
}

--- NEW FILE: CC1000CsmaP.nc ---
// $Id: CC1000CsmaP.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay Exp $

/*                                                                        tab:4
 * "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 CSMA and low-power listening logic. Actual
 * packet transmission and reception is in SendReceive.
 * <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 CC1000CsmaP {
  provides {
    interface Init;
    interface SplitControl;
    interface CsmaControl;
    interface CsmaBackoff;
    interface LowPowerListening;
  }
  uses {
    interface Init as ByteRadioInit;
    interface StdControl as ByteRadioControl;
    interface ByteRadio;

    //interface PowerManagement;
    interface CC1000Control;
    interface CC1000Squelch;
    interface Random;
    interface Timer<TMilli> as WakeupTimer;
    interface BusyWait<TMicro, uint16_t>;

    interface ReadNow<uint16_t> as RssiNoiseFloor;
    interface ReadNow<uint16_t> as RssiCheckChannel;
    interface ReadNow<uint16_t> as RssiPulseCheck;
    async command void cancelRssi();
  }
}
implementation 
{
  enum {
    DISABLED_STATE,
    IDLE_STATE,
    RX_STATE,
    TX_STATE,
    POWERDOWN_STATE,
    PULSECHECK_STATE
  };

  enum {
    TIME_AFTER_CHECK =  30,
  };

  uint8_t radioState = DISABLED_STATE;
  struct {
    uint8_t ccaOff : 1;
    uint8_t txPending : 1;
  } f; // f for flags
  uint8_t count;
  uint8_t clearCount;

  int16_t macDelay;

  uint16_t sleepTime;

  uint16_t rssiForSquelch;

  task void setWakeupTask();

  cc1000_metadata_t *getMetadata(message_t *amsg) {
    return (cc1000_metadata_t *)((uint8_t *)amsg->footer + sizeof(cc1000_footer_t));
  }
  
  void enterIdleState() {
    call cancelRssi();
    radioState = IDLE_STATE;
  }

  void enterIdleStateSetWakeup() {
    enterIdleState();
    post setWakeupTask();
  }

  void enterDisabledState() {
    call cancelRssi();
    radioState = DISABLED_STATE;
  }

  void enterPowerDownState() {
    call cancelRssi();
    radioState = POWERDOWN_STATE;
  }

  void enterPulseCheckState() {
    radioState = PULSECHECK_STATE;
    count = 0;
  }

  void enterRxState() {
    call cancelRssi();
    radioState = RX_STATE;
  }

  void enterTxState() {
    radioState = TX_STATE;
  }

  /* Basic radio power control */

  void radioOn() {
    call CC1000Control.coreOn();
    call BusyWait.wait(2000);
    call CC1000Control.biasOn();
    call BusyWait.wait(200);
    atomic call ByteRadio.listen();
  }

  void radioOff() {
    call CC1000Control.off();
    call ByteRadio.off();
  }

  void setPreambleLength(message_t *msg);

  /* Initialisation, startup and stopping */
  /*--------------------------------------*/

  command error_t Init.init() {
    call ByteRadioInit.init();
    call CC1000Control.init();

    return SUCCESS;
  }

  task void startStopDone() {
    uint8_t s;

    // Save a byte of RAM by sharing start/stopDone task
    atomic s = radioState;
    if (s == DISABLED_STATE)
      signal SplitControl.stopDone(SUCCESS);
    else
      signal SplitControl.startDone(SUCCESS);
  }

  command error_t SplitControl.start() {
    atomic 
      if (radioState == DISABLED_STATE)
        {
          call ByteRadioControl.start();
          enterIdleStateSetWakeup();
          f.txPending = FALSE;
        }
      else
        return SUCCESS;

    radioOn();

    post startStopDone();

    return SUCCESS;
  }

  command error_t SplitControl.stop() {
    atomic 
      {
        call ByteRadioControl.stop();
        enterDisabledState();
        radioOff();
      }
    call WakeupTimer.stop();
    post startStopDone();
    return SUCCESS;
  }

  /* Wakeup timer */
  /*-------------*/

  /* All timer setting code is placed in setWakeup, for consistency. */
  void setWakeup() {
    switch (radioState)
      {
      case IDLE_STATE:
        /* Timer already running means that we have a noise floor
           measurement scheduled. If we just set a new alarm here, we
           might indefinitely delay noise floor measurements if we're,
           e,g, transmitting frequently. */
        if (!call WakeupTimer.isRunning())
          if (call CC1000Squelch.settled())
            {
              if (sleepTime == 0)
                call WakeupTimer.startOneShot(CC1K_SquelchIntervalSlow);
              else
                // timeout for receiving a message after an lpl check
                // indicates channel activity.
                call WakeupTimer.startOneShot(TIME_AFTER_CHECK);
            }
          else
            call WakeupTimer.startOneShot(CC1K_SquelchIntervalFast);
        break;
      case PULSECHECK_STATE:
        // Radio warm-up time.
        call WakeupTimer.startOneShot(1);
        break;
      case POWERDOWN_STATE:
        // low-power listening check interval
        call WakeupTimer.startOneShot(sleepTime);
        break;
      }
  }

  task void setWakeupTask() {
    atomic setWakeup();
  }

  event void WakeupTimer.fired() {
    atomic 
      {
        switch (radioState)
          {
          case IDLE_STATE:
            /* If we appear to be receiving a packet we don't check the
               noise floor. For LPL, this means that going to sleep will
               be delayed by another TIME_AFTER_CHECK ms. */
            if (!call ByteRadio.syncing())
              {
                call cancelRssi();
                call RssiNoiseFloor.read();
              }
            break;

          case POWERDOWN_STATE:
            // Turn radio on, wait for 1ms
            enterPulseCheckState();
            call CC1000Control.biasOn();
            break;

          case PULSECHECK_STATE:
            // Switch to RX mode and get RSSI output
            call CC1000Control.rxMode();
            call RssiPulseCheck.read();
            call BusyWait.wait(80);
            return; // don't set wakeup timer
          }
        setWakeup();
      }
  }

  /* Low-power listening stuff */
  /*---------------------------*/

  /* Should we go to sleep, or turn the radio fully on? */
  task void sleepCheck() {
    bool turnOn = FALSE;

    atomic
      if (f.txPending || !sleepTime)
        {
          if (radioState == PULSECHECK_STATE || radioState == POWERDOWN_STATE)
            {
              enterIdleStateSetWakeup();
              turnOn = TRUE;
            }
        }
      else if (call CC1000Squelch.settled() && !call ByteRadio.syncing())
        {
          radioOff();
          enterPowerDownState();
          setWakeup();
        }

    if (turnOn)
      radioOn();
  }

  task void adjustSquelch();

  async event void RssiPulseCheck.readDone(error_t result, uint16_t data) {
    if (result != SUCCESS)
      {
        /* Just give up on this interval. */
        post sleepCheck();
        return;
      }

    /* We got some RSSI data for our LPL check. Decide whether to:
       - go back to sleep (quiet)
       - wake up (channel active)
       - get more RSSI data
    */
    if (data > call CC1000Squelch.get() - (call CC1000Squelch.get() >> 2))
      {
        post sleepCheck();
        // don't be too agressive (ignore really quiet thresholds).
        if (data < call CC1000Squelch.get() + (call CC1000Squelch.get() >> 3))
          {
            // adjust the noise floor level, go back to sleep.
            rssiForSquelch = data;
            post adjustSquelch();
          }
      }
    else if (count++ > 5)
      {
        //go to the idle state since no outliers were found
        enterIdleStateSetWakeup();
        call ByteRadio.listen();
      }
    else
      {
        call RssiPulseCheck.read();
        call BusyWait.wait(80);
      }
  }

  /* CSMA */
  /*------*/

  event void ByteRadio.rts(message_t *msg) {
    atomic
      {
        f.txPending = TRUE;

        if (radioState == POWERDOWN_STATE)
          post sleepCheck();
        if (!f.ccaOff)
          macDelay = signal CsmaBackoff.initial(call ByteRadio.getTxMessage());
        else
          macDelay = 1;

        setPreambleLength(msg);
      }
  }

  async event void ByteRadio.sendDone() {
    f.txPending = FALSE;
    enterIdleStateSetWakeup();
  }

  void congestion() {
    macDelay = signal CsmaBackoff.congestion(call ByteRadio.getTxMessage());
  }

  async event void ByteRadio.idleByte(bool preamble) {
    if (f.txPending)
      {
        if (!f.ccaOff && preamble)
          congestion();
        else if (macDelay && !--macDelay)
          {
            call cancelRssi();
            count = 0;
            call RssiCheckChannel.read();
          }
      }
  }

  async event void RssiCheckChannel.readDone(error_t result, uint16_t data) {
    if (result != SUCCESS)
      {
        /* We'll retry the transmission at the next SPI event. */
        atomic macDelay = 1;
        return;
      }

    count++;
    if (data > call CC1000Squelch.get() + CC1K_SquelchBuffer)
      clearCount++;
    else
      clearCount = 0;

    // if the channel is clear or CCA is disabled, GO GO GO!
    if (clearCount >= 1 || f.ccaOff)
      {
        enterTxState();
        call ByteRadio.cts();
      }
    else if (count == CC1K_MaxRSSISamples)
      congestion();
    else 
      call RssiCheckChannel.read();
  }

  /* Message being received. We basically just go inactive. */
  /*--------------------------------------------------------*/

  async event void ByteRadio.rx() {
    enterRxState();
  }

  async event void ByteRadio.rxDone() {
    if (radioState == RX_STATE)
      enterIdleStateSetWakeup();
  }

  /* Noise floor */
  /*-------------*/

  task void adjustSquelch() {
    uint16_t squelchData;

    atomic squelchData = rssiForSquelch;
    call CC1000Squelch.adjust(squelchData);
  }

  async event void RssiNoiseFloor.readDone(error_t result, uint16_t data) {
    if (result != SUCCESS)
      {
        /* We just ignore failed noise floor measurements */
        post sleepCheck();
        return;
      }

    rssiForSquelch = data;
    post adjustSquelch();
    post sleepCheck();
  }

  /* Options */
  /*---------*/

  async command error_t CsmaControl.enableCca() {
    atomic f.ccaOff = FALSE;
    return SUCCESS;
  }

  async command error_t CsmaControl.disableCca() {
    atomic f.ccaOff = TRUE;
    return SUCCESS;
  }

  /* Default MAC backoff parameters */
  /*--------------------------------*/

  default async event uint16_t CsmaBackoff.initial(message_t *m) { 
    // initially back off [1,32] bytes (approx 2/3 packet)
    return (call Random.rand16() & 0x1F) + 1;
  }

  default async event uint16_t CsmaBackoff.congestion(message_t *m) { 
    return (call Random.rand16() & 0xF) + 1;
  }

  /* LowPowerListening setup */
  /* ----------------------- */

  uint16_t validateSleepInterval(uint16_t sleepIntervalMs) {
    if (sleepIntervalMs < CC1K_LPL_MIN_INTERVAL)
      return 0;
    else if (sleepIntervalMs > CC1K_LPL_MAX_INTERVAL)
      return CC1K_LPL_MAX_INTERVAL;
    else
      return sleepIntervalMs;
  }

  uint16_t dutyToSleep(uint16_t dutyCycle) {
    /* Scaling factors on CC1K_LPL_CHECK_TIME and dutyCycle are identical */
    uint16_t interval = (1000 * CC1K_LPL_CHECK_TIME) / dutyCycle;

    return interval < CC1K_LPL_MIN_INTERVAL ? 0 : interval;
  }

  uint16_t sleepToDuty(uint16_t sleepInterval) {
    if (sleepInterval < CC1K_LPL_MIN_INTERVAL)
      return 10000;

    /* Scaling factors on CC1K_LPL_CHECK_TIME and dutyCycle are identical */
    return (1000 * CC1K_LPL_CHECK_TIME) / sleepInterval;
  }

  command void LowPowerListening.setLocalSleepInterval(uint16_t s) {
    sleepTime = validateSleepInterval(s);
  }

  command uint16_t LowPowerListening.getLocalSleepInterval() {
    return sleepTime;
  }

  command void LowPowerListening.setLocalDutyCycle(uint16_t d) {
    return call LowPowerListening.setLocalSleepInterval(dutyToSleep(d));
  }

  command uint16_t LowPowerListening.getLocalDutyCycle() {
    return sleepToDuty(call LowPowerListening.getLocalSleepInterval());
  }

  command void LowPowerListening.setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs) {
    cc1000_metadata_t *meta = getMetadata(msg);

    meta->strength_or_preamble = -(int16_t)validateSleepInterval(sleepIntervalMs) - 1;
  }

  command uint16_t LowPowerListening.getRxSleepInterval(message_t *msg) {
    cc1000_metadata_t *meta = getMetadata(msg);

    if (meta->strength_or_preamble >= 0)
      return sleepTime;
    else
      return -(meta->strength_or_preamble + 1);
  }

  command void LowPowerListening.setRxDutyCycle(message_t *msg, uint16_t d) {
    return call LowPowerListening.setRxSleepInterval(msg, dutyToSleep(d));
  }

  command uint16_t LowPowerListening.getRxDutyCycle(message_t *msg) {
    return sleepToDuty(call LowPowerListening.getRxSleepInterval(msg));
  }

  command uint16_t LowPowerListening.dutyCycleToSleepInterval(uint16_t d) {
    return dutyToSleep(d);
  }

  command uint16_t LowPowerListening.sleepIntervalToDutyCycle(uint16_t s) {
    return sleepToDuty(s);
  }

  void setPreambleLength(message_t *msg) {
    cc1000_metadata_t *meta = getMetadata(msg);
    uint16_t s;
    uint32_t plen;

    if (meta->strength_or_preamble >= 0)
      s = sleepTime;
    else
      s = -(meta->strength_or_preamble + 1);
    meta->strength_or_preamble = 0; /* Destroy setting */

    if (s == 0)
      plen = 6;
    else
      plen = (((s * 614UL) >> 8) / 6) + 22; 
    // ~ (s * 2.4)/6 + 22
    // TODO remove the divide.  It's there so we still have a long preamble, but
    // 6 times shorter than the regular preamble. This will increase
    // delivery time while modulating the channel long enough to get detected.
    
    call ByteRadio.setPreambleLength(plen);
  }
}

--- NEW FILE: CC1000CsmaRadioC.nc ---
/* $Id: CC1000CsmaRadioC.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay 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.
 */

/**
 * A low-power-listening CC1000 radio stack.
 *
 * Radio logic is split between Csma (media-access control, low-power
 * listening and general control) and SendReceive (packet reception and
 * transmission). 
 *
 * CC1000RssiP (RSSI sharing), CC1000SquelchP (noise-floor estimation)
 * and CC1000ControlP (radio configuration) provide supporting roles.
 *
 * This code has some degree of platform-independence, via the HplCC1000,
 * RssiAdc and HplCC1000Spi interfaces which must be provided by the
 * platform. However, these interfaces may still reflect some
 * particularities of the mica2 hardware implementation.
 *
 * @author Joe Polastre
 * @author David Gay
 */

#include "CC1000Const.h"
#include "message.h"

configuration CC1000CsmaRadioC {
  provides {
    interface SplitControl;
    interface Send;
    interface Receive;

    interface Packet;    
    interface CsmaControl;
    interface CsmaBackoff;
    interface RadioTimeStamping;
    interface PacketAcknowledgements;

    interface LowPowerListening;
  }
}
implementation {
  components CC1000CsmaP as Csma;
  components CC1000SendReceiveP as SendReceive;
  components CC1000RssiP as Rssi;
  components CC1000SquelchP as Squelch;
  components CC1000ControlP as Control;
  components HplCC1000C as Hpl;
  components CC1000LowPowerListeningC;

  components MainC, RandomC, new TimerMilliC(), ActiveMessageAddressC, BusyWaitMicroC;

  MainC.SoftwareInit -> Csma;
  MainC.SoftwareInit -> Squelch;

  SplitControl = Csma;
  Send = SendReceive;
  Receive = SendReceive;
  Packet = SendReceive;

  CsmaControl = Csma;
  CsmaBackoff = Csma;
  LowPowerListening = Csma;
  RadioTimeStamping = SendReceive;
  PacketAcknowledgements = SendReceive;

  Csma.CC1000Control -> Control;
  Csma.Random -> RandomC;
  Csma.CC1000Squelch -> Squelch;
  Csma.WakeupTimer -> TimerMilliC;
  Csma.ByteRadio -> SendReceive;
  Csma.ByteRadioInit -> SendReceive;
  Csma.ByteRadioControl -> SendReceive;
  
  SendReceive.CC1000Control -> Control;
  SendReceive.HplCC1000Spi -> Hpl;
  SendReceive.amAddress -> ActiveMessageAddressC;
  SendReceive.RssiRx -> Rssi.Rssi[unique(UQ_CC1000_RSSI)];
  
  Csma.RssiNoiseFloor -> Rssi.Rssi[unique(UQ_CC1000_RSSI)];
  Csma.RssiCheckChannel -> Rssi.Rssi[unique(UQ_CC1000_RSSI)];
  Csma.RssiPulseCheck -> Rssi.Rssi[unique(UQ_CC1000_RSSI)];
  Csma.cancelRssi -> Rssi;
  Csma.BusyWait -> BusyWaitMicroC;

  Rssi.ActualRssi -> Hpl;
  Rssi.Resource -> Hpl;
  Control.CC -> Hpl;
  Control.BusyWait -> BusyWaitMicroC;
}

--- NEW FILE: CC1000LowPowerListening.h ---
/*
 * Copyright (c) 2005-2006 Rincon Research Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the Arch Rock Corporation nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE
 */
 
 /**
  * @author David Moss
  */
#ifndef CC1000LOWPOWERLISTENING_H
#define CC1000LOWPOWERLISTENING_H

/**
 * The default duty period is usually 0, which is the equivalent of
 * ONE_MESSAGE (below), which tells the node to transmit the message
 * one time without expecting receiver duty cycling.
 */
#ifndef DEFAULT_TRANSMIT_PERIOD
#define DEFAULT_TRANSMIT_PERIOD 0
#endif

/**
 * Value used to indicate the message being sent should be transmitted
 * one time
 */
#ifndef ONE_MESSAGE
#define ONE_MESSAGE 0
#endif

#endif


--- NEW FILE: CC1000LowPowerListeningC.nc ---
/*
 * Copyright (c) 2005-2006 Rincon Research Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the Arch Rock Corporation nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE
 */

/**
 * Low Power Listening for the CC1000
 * @author David Moss
 */
 
#include "CC1000LowPowerListening.h"

configuration CC1000LowPowerListeningC {
  provides {
    interface Send;
    interface Receive;
    interface CsmaBackoff[am_id_t amId];
  }
}

implementation {
  components MainC,
      CC1000ActiveMessageC,
      CC1000LowPowerListeningP,
      CC1000CsmaRadioC,
      RandomC,
      new StateC() as SendStateC,
      new StateC() as RadioPowerStateC,
      new TimerMilliC() as SendDoneTimerC;
  
  Send = CC1000LowPowerListeningP;
  Receive = CC1000LowPowerListeningP;
  CsmaBackoff = CC1000LowPowerListeningP;
  
  MainC.SoftwareInit -> CC1000LowPowerListeningP;
   
  CC1000LowPowerListeningP.AMPacket -> CC1000ActiveMessageC;
  CC1000LowPowerListeningP.Random -> RandomC;
  CC1000LowPowerListeningP.SendState -> SendStateC;
  CC1000LowPowerListeningP.RadioPowerState -> RadioPowerStateC;
  CC1000LowPowerListeningP.SendDoneTimer -> SendDoneTimerC;
  CC1000LowPowerListeningP.SubSend -> CC1000CsmaRadioC;
  CC1000LowPowerListeningP.SubReceive -> CC1000CsmaRadioC;
  CC1000LowPowerListeningP.SubControl -> CC1000CsmaRadioC;
  CC1000LowPowerListeningP.PacketAcknowledgements -> CC1000CsmaRadioC;
  CC1000LowPowerListeningP.SubBackoff -> CC1000CsmaRadioC;
  CC1000LowPowerListeningP.CsmaControl -> CC1000CsmaRadioC;
  CC1000LowPowerListeningP.LowPowerListening -> CC1000CsmaRadioC;
  
}


--- NEW FILE: CC1000LowPowerListeningP.nc ---
/*
 * Copyright (c) 2005-2006 Rincon Research Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the Arch Rock Corporation nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE
 */

/**
 * Low Power Listening for the CC1000
 *
 * @author David Moss
 */

#include "CC1000LowPowerListening.h"

module CC1000LowPowerListeningP {
  provides {
    interface Init;
    interface Send;
    interface Receive;
    interface CsmaBackoff[am_id_t amId];
  }
  
  uses {
    interface LowPowerListening;
    interface CsmaBackoff as SubBackoff;
    interface CsmaControl;
    interface Leds;
    interface Send as SubSend;
    interface Receive as SubReceive;
    interface AMPacket;
    interface SplitControl as SubControl;
    interface PacketAcknowledgements;
    interface State as SendState;
    interface State as RadioPowerState;
    interface Random;
    interface Timer<TMilli> as SendDoneTimer;
  }
}

implementation {
  
  /** The message currently being sent */
  message_t *currentSendMsg;
  
  /** The length of the current send message */
  uint8_t currentSendLen;
 
  /** Tx DSN to ensure multiple transmitted messages get across only once */ 
  uint8_t txDsn;
  
  /** The last received broadcast DSN. TODO is this the best way? */
  uint8_t lastRxDsn;

  /** TRUE if the first message of the current LPL delivery has been sent */
  norace bool firstMessageSent;
  
  /**
   * Radio State
   */
  enum {
    S_OFF,
    S_ON,
  };
  
  /**
   * Send States
   */
  enum {
    S_IDLE,
    S_SENDING,
  };
  
  
  /***************** Prototypes ***************/
  task void send();
  task void startRadio();
  task void stopRadio();
  
  cc1000_header_t *getHeader(message_t *msg);
  cc1000_metadata_t *getMetadata(message_t* msg);
  uint16_t getActualDutyCycle(uint16_t dutyCycle);
  void signalDone(error_t error);
  
  /***************** Init Commands ***************/
  command error_t Init.init() {
    txDsn = call Random.rand16();
    return SUCCESS;
  }
  
  
  /***************** SubBackoff Events ****************/
  async event uint16_t SubBackoff.initial(message_t* m) {
    if(call SendState.getState() == S_SENDING
        && getMetadata(m)->strength_or_preamble > ONE_MESSAGE
        && firstMessageSent) {
      call CsmaControl.disableCca();
      return 1;
      
    } else {
      return signal CsmaBackoff.initial[getHeader(m)->type](m);
    }
  }

  async event uint16_t SubBackoff.congestion(message_t* m) {
    if(call SendState.getState() == S_SENDING
        && getMetadata(m)->strength_or_preamble > ONE_MESSAGE
        && firstMessageSent) {
      call CsmaControl.disableCca();
      return 1;
      
    } else {
      return signal CsmaBackoff.congestion[getHeader(m)->type](m);
    }
  }
  
  /***************** Send Commands ***************/
  /**
   * Each call to this send command gives the message a single
   * DSN that does not change for every copy of the message
   * sent out.  For messages that are not acknowledged, such as
   * a broadcast address message, the receiving end does not
   * signal receive() more than once for that message.
   */
  command error_t Send.send(message_t *msg, uint8_t len) {
    if(call RadioPowerState.getState() == S_OFF) {
      // Everything is off right now, start SplitControl and try again
      return EOFF;
    }
    
    if(call SendState.requestState(S_SENDING) == SUCCESS) {
      currentSendMsg = msg;
      currentSendLen = len;
      (getHeader(msg))->dsn = ++txDsn;
      
      firstMessageSent = FALSE;
      if(call LowPowerListening.getRxSleepInterval(currentSendMsg) 
          > ONE_MESSAGE) {
          
        // Send it repetitively within our transmit window
        call PacketAcknowledgements.requestAck(currentSendMsg);
        call SendDoneTimer.startOneShot(
            call LowPowerListening.getRxSleepInterval(currentSendMsg) * 2);
      }
      
      // If the radio is off, the CC1000Csma will automatically turn it on
      post send();
      return SUCCESS;
    }
    
    return FAIL;
  }

  command error_t Send.cancel(message_t *msg) {
    if(currentSendMsg == msg) {
      call SendState.toIdle();
      return SUCCESS;
    }
    
    return FAIL;
  }
  
  
  command uint8_t Send.maxPayloadLength() {
    return call SubSend.maxPayloadLength();
  }

  command void *Send.getPayload(message_t* msg) {
    return call SubSend.getPayload(msg);
  }
  
  /***************** Receive Commands ***************/
  command void *Receive.getPayload(message_t* msg, uint8_t* len) {
    return call SubReceive.getPayload(msg, len);
  }

  command uint8_t Receive.payloadLength(message_t* msg) {
    return call SubReceive.payloadLength(msg);
  }

  
  /***************** SubControl Events ***************/
  event void SubControl.startDone(error_t error) {
    if(!error) {
      call RadioPowerState.forceState(S_ON);
    }
  }
    
  event void SubControl.stopDone(error_t error) {
    if(!error) {
      call RadioPowerState.forceState(S_OFF);
    }
  }
  
  /***************** SubSend Events ***************/
  event void SubSend.sendDone(message_t* msg, error_t error) {
    if(call SendState.getState() == S_SENDING  
        && call SendDoneTimer.isRunning()) {
      if(call PacketAcknowledgements.wasAcked(msg)) {
        signalDone(error);
        
      } else {
        post send();
      }
      
      return;
    }
    
    signalDone(error);
  }
  
  /***************** SubReceive Events ***************/
  /**
   * If the received message is new, we signal the receive event and
   * start the off timer.  If the last message we received had the same
   * DSN as this message, then the chances are pretty good
   * that this message should be ignored, especially if the destination address
   * as the broadcast address
   *
   * TODO
   * What happens if a unicast Tx doesn't get Rx's ack, and resends that
   * message?
   */
  event message_t *SubReceive.receive(message_t* msg, void* payload, 
      uint8_t len) {
    
    if((getHeader(msg))->dsn == lastRxDsn 
        && call AMPacket.destination(msg) == AM_BROADCAST_ADDR) {
      // Already got this broadcast message.
      // TODO should we do something similar with unicast messages?
      return msg;

    } else {
      lastRxDsn = (getHeader(msg))->dsn;
      return signal Receive.receive(msg, payload, len);
    }
  }
  
  /***************** Timer Events ****************/  
  /**
   * When this timer is running, that means we're sending repeating messages
   * to a node that is receive check duty cycling.
   */
  event void SendDoneTimer.fired() {
    if(call SendState.getState() == S_SENDING) {
      // The next time SubSend.sendDone is signaled, send is complete.
      call SendState.toIdle();
    }
  }
  
  /***************** Tasks ***************/
  task void send() {
    if(call SubSend.send(currentSendMsg, currentSendLen) != SUCCESS) {
      post send();
    }
  }
  
  task void startRadio() {
    if(call SubControl.start() != SUCCESS) {
      post startRadio();
    }
  }
  
  task void stopRadio() {
    if(call SubControl.stop() != SUCCESS) {
      post stopRadio();
    }
  }
  
  /***************** Functions ***************/  
  /**
   * Check the bounds on a given duty cycle
   * We're never over 100%, and we're never at 0%
   */
  uint16_t getActualDutyCycle(uint16_t dutyCycle) {
    if(dutyCycle > 10000) {
      return 10000;
    } else if(dutyCycle == 0) {
      return 1;
    }
    
    return dutyCycle;
  }
  
  cc1000_header_t *getHeader(message_t *msg) {
    return (cc1000_header_t *)(msg->data - sizeof( cc1000_header_t ));
  }
  
  cc1000_metadata_t *getMetadata(message_t* msg) {
    return (cc1000_metadata_t*)msg->metadata;
  }
  
  void signalDone(error_t error) {
    call CsmaControl.enableCca();
    call SendState.toIdle();
    // TODO check for broadcast destination
    signal Send.sendDone(currentSendMsg, error);
    currentSendMsg = NULL;
  }
  
  
    
  /***************** Defaults ****************/
  default async event uint16_t CsmaBackoff.initial[am_id_t amId](message_t *m) {
    return ( call Random.rand16() % (0x1F * CC1000_BACKOFF_PERIOD) 
        + CC1000_MIN_BACKOFF);
  }

  default async event uint16_t CsmaBackoff.congestion[am_id_t amId](message_t *m) {
    return ( call Random.rand16() % (0x7 * CC1000_BACKOFF_PERIOD) 
        + CC1000_MIN_BACKOFF);
  }
}


--- NEW FILE: CC1000Msg.h ---
#ifndef CC1K_RADIO_MSG_H
#define CC1K_RADIO_MSG_H

#include "AM.h"

typedef nx_struct CC1KHeader {
  nx_am_addr_t dest;
  nx_am_addr_t source;
  nx_uint8_t length;
  nx_am_group_t group;
  nx_uint8_t dsn;
  nx_am_id_t type;
} cc1000_header_t;

typedef nx_struct CC1KFooter {
  nxle_uint16_t crc;  
} cc1000_footer_t;

typedef nx_struct CC1KMetadata {
  nx_int16_t strength_or_preamble; /* negative when used for preamble length */
  nx_uint8_t ack;
  nx_uint16_t time;
  nx_uint8_t sendSecurityMode;
  nx_uint8_t receiveSecurityMode;  
} cc1000_metadata_t;

#endif

--- NEW FILE: CC1000RssiP.nc ---
/* $Id: CC1000RssiP.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay 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.
 */

/**
 *   RSSI fun. It's used for lots of things, and a request to read it
 *   for one purpose may have to be discarded if conditions change. For
 *   example, if we've initiated a noise-floor measure, but start 
 *   receiving a packet, we have to:<ul>
 *   <li>cancel the noise-floor measure (we don't know if the value will
 *     reflect the received packet or the previous idle state)
 *   <li>start an RSSI measurement so that we can report signal strength
 *     to the application
 *   </ul><p>
 *   This module hides the complexities of cancellation from the rest of
 *   the stack.
 */

module CC1000RssiP
{
  provides {
    interface ReadNow<uint16_t> as Rssi[uint8_t reason];
    async command void cancel();
  }
  uses {
    interface Resource;
    interface ReadNow<uint16_t> as ActualRssi;
  }
}
implementation
{
  enum {
    IDLE = unique(UQ_CC1000_RSSI),
    CANCELLED = unique(UQ_CC1000_RSSI)
  };

  /* All commands are called within atomic sections */
  uint8_t currentOp = IDLE;
  uint8_t nextOp;

  async command void cancel() {
    if (currentOp != IDLE)
      currentOp = CANCELLED;
  }

  event void Resource.granted() {
    call ActualRssi.read();
  }

  async command error_t Rssi.read[uint8_t reason]() {
    if (currentOp == IDLE)
      {
	currentOp = reason;
	if (call Resource.immediateRequest() == SUCCESS)
	  call ActualRssi.read();
	else
	  call Resource.request();
      }
    else
      nextOp = reason;
    return SUCCESS;
  }

  void startNextOp() {
    currentOp = nextOp;
    if (nextOp != IDLE)
      {
	nextOp = IDLE;
	call ActualRssi.read();
      }
    else
      call Resource.release();
  }

  async event void ActualRssi.readDone(error_t result, uint16_t data) {
    atomic
      {
	/* The code assumes that RSSI measurements are 10-bits 
	   (legacy effect) */
	signal Rssi.readDone[currentOp](result, data >> 6);
	startNextOp();
      }
  }

  default async event void Rssi.readDone[uint8_t reason](error_t result, uint16_t data) { }
}

--- NEW FILE: CC1000SendReceiveP.nc ---
// $Id: CC1000SendReceiveP.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay Exp $

/*									tab:4
 * "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;
  }
  uses {
    //interface PowerManagement;
    interface CC1000Control;
    interface HplCC1000Spi;

    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 *rxBufPtr = &rxBuf;

  uint16_t preambleLength;
  message_t *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_footer_t *getFooter(message_t *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));
  }
  
  /* 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)
      {
	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)
	  {
	    getMetadata(txBufPtr)->ack = 1;
	    enterTxDoneState();
	    return;
	  }
      }
    if (count >= MAX_ACK_WAIT)
      {
	getMetadata(txBufPtr)->ack = 0;
	enterTxDoneState();
      }
  }

  task void signalPacketSent() {
    message_t *pBuf;

    atomic
      {
	pBuf = txBufPtr;
	f.txBusy = FALSE;
	enterListenState();
      }
    signal Send.sendDone(pBuf, SUCCESS);
  }

  void txDone() {
    post signalPacketSent();
    signal ByteRadio.sendDone();
  }

  /* Receive */
  /*---------*/

  void packetReceived();
  void packetReceiveDone();

  async command void ByteRadio.listen() {
    enterListenState();
    call CC1000Control.rxMode();
    call HplCC1000Spi.rxMode();
    call HplCC1000Spi.enableIntr();
  }

  async command void ByteRadio.off() {
    enterInactiveState();
    call HplCC1000Spi.disableIntr();
  }

  void listenData(uint8_t in) {
    bool preamble = in == 0xaa || in == 0x55;

    // Look for enough preamble bytes
    if (preamble)
      {
	count++;
	if (count > CC1K_ValidPrecursor)
	  enterSyncState();
      }
    else
      count = 0;

    signal ByteRadio.idleByte(preamble);
  }

  void syncData(uint8_t in) {
    // draw in the preamble bytes and look for a sync byte
    // save the data in a short with last byte received as msbyte
    //    and current byte received as the lsbyte.
    // use a bit shift compare to find the byte boundary for the sync byte
    // retain the shift value and use it to collect all of the packet data
    // check for data inversion, and restore proper polarity 
    // XXX-PB: Don't do this.

    if (in == 0xaa || in == 0x55)
      // It is actually possible to have the LAST BIT of the incoming
      // data be part of the Sync Byte.  SO, we need to store that
      // However, the next byte should definitely not have this pattern.
      // XXX-PB: Do we need to check for excessive preamble?
      rxShiftBuf = in << 8;
    else if (count++ == 0)
      rxShiftBuf |= in;
    else if (count <= 6)
      {
	// TODO: Modify to be tolerant of bad bits in the preamble...
	uint16_t tmp;
	uint8_t i;

	// bit shift the data in with previous sample to find sync
	tmp = rxShiftBuf;
	rxShiftBuf = rxShiftBuf << 8 | in;

	for(i = 0; i < 8; i++)
	  {
	    tmp <<= 1;
	    if (in & 0x80)
	      tmp  |=  0x1;
	    in <<= 1;
	    // check for sync bytes
	    if (tmp == SYNC_WORD)
	      {
		enterRxState();
		signal ByteRadio.rx();
		f.rxBitOffset = 7 - i;
		signal RadioTimeStamping.receivedSFD(0);
		call RssiRx.read();
	      }
	  }
      }
    else // We didn't find it after a reasonable number of tries, so....
      enterListenState();
  }
  
  async event void RssiRx.readDone(error_t result, uint16_t data) {
    cc1000_metadata_t *rxMetadata = getMetadata(rxBufPtr);

    if (result != SUCCESS)
      rxMetadata->strength_or_preamble = 0;
    else
      rxMetadata->strength_or_preamble = data;
  }

  void rxData(uint8_t in) {
    uint8_t nextByte;
    cc1000_header_t *rxHeader = getHeader(rxBufPtr);
    uint8_t rxLength = rxHeader->length;

    // Reject invalid length packets
    if (rxLength > TOSH_DATA_LENGTH)
      {
	// The packet's screwed up, so just dump it
	enterListenState();
	signal ByteRadio.rxDone();
	return;
      }

    rxShiftBuf = rxShiftBuf << 8 | in;
    nextByte = rxShiftBuf >> f.rxBitOffset;
    ((uint8_t *)rxBufPtr)[count++] = nextByte;

    // Adjust rxLength to correspond to the corresponding offset in message_t
    rxLength += offsetof(message_t, data);
    if (count <= rxLength)
      runningCrc = crcByte(runningCrc, nextByte);

    // Jump to CRC when we reach the end of data
    if (count == rxLength) {
      count = offsetof(message_t, footer) + offsetof(cc1000_footer_t, crc);
    }

    if (count == (offsetof(message_t, footer) + sizeof(cc1000_footer_t)))
      packetReceived();
  }

  void packetReceived() {
    cc1000_footer_t *rxFooter = getFooter(rxBufPtr);
    cc1000_header_t *rxHeader = getHeader(rxBufPtr);
    // Packet filtering based on bad CRC's is done at higher layers.
    // So sayeth the TOS weenies.
    rxFooter->crc = (rxFooter->crc == runningCrc);

    if (f.ack &&
	rxFooter->crc &&
	rxHeader->dest == call amAddress())
      {
	enterAckState();
	call CC1000Control.txMode();
	call HplCC1000Spi.txMode();
	call HplCC1000Spi.writeByte(0xaa);
      }
    else
      packetReceiveDone();
  }

  void ackData(uint8_t in) {
    if (++count >= ACK_LENGTH)
      { 
	call CC1000Control.rxMode();
	call HplCC1000Spi.rxMode();
	packetReceiveDone();
      }
    else if (count >= ACK_LENGTH - sizeof ackCode)
      call HplCC1000Spi.writeByte(read_uint8_t(&ackCode[count + sizeof ackCode - ACK_LENGTH]));
  }

  task void signalPacketReceived() {
    message_t *pBuf;
    cc1000_header_t *pHeader;
    atomic
      {
	if (radioState != RECEIVED_STATE)
	  return;

	pBuf = rxBufPtr;
      }
    pHeader = getHeader(pBuf);
    pBuf = signal Receive.receive(pBuf, pBuf->data, pHeader->length);
    atomic
      {
	if (pBuf) 
	  rxBufPtr = pBuf;
	if (radioState == RECEIVED_STATE) // receiver might've done something
	  enterListenState();
	signal ByteRadio.rxDone();
      }
  }

  void packetReceiveDone() {
    post signalPacketReceived();
    enterReceivedState();
  }

  async event void HplCC1000Spi.dataReady(uint8_t data) {
    if (f.invert)
      data = ~data;

    switch (radioState)
      {
      default: break;
      case TXPREAMBLE_STATE: txPreamble(); break;
      case TXSYNC_STATE: txSync(); break;
      case TXDATA_STATE: txData(); break;
      case TXCRC_STATE: txCrc(); break;
      case TXFLUSH_STATE: txFlush(); break;
      case TXWAITFORACK_STATE: txWaitForAck(); break;
      case TXREADACK_STATE: txReadAck(data); break;
      case TXDONE_STATE: txDone(); break;

      case LISTEN_STATE: listenData(data); break;
      case SYNC_STATE: syncData(data); break;
      case RX_STATE: rxData(data); break;
      case SENDING_ACK: ackData(data); break;
      }
  }

  /* Interaction with rest of stack */
  /*--------------------------------*/

  async command void ByteRadio.setPreambleLength(uint16_t bytes) {
    atomic preambleLength = bytes;
  }

  async command uint16_t ByteRadio.getPreambleLength() {
    atomic return preambleLength;
  }

  async command message_t *ByteRadio.getTxMessage() {
    return txBufPtr;
  }

  async command bool ByteRadio.syncing() {
    return radioState == SYNC_STATE;
  }

  /* Abstract packet layout */

  command void Packet.clear(message_t *msg) {
    memset(msg, 0, sizeof(message_t));
  }

  command uint8_t Packet.payloadLength(message_t *msg) {
    cc1000_header_t *header = getHeader(msg);
    return header->length;
  }
 
  command void Packet.setPayloadLength(message_t *msg, uint8_t len) {
    getHeader(msg)->length  = len;
  }
  
  command uint8_t Packet.maxPayloadLength() {
    return TOSH_DATA_LENGTH;
  }

  command void* Packet.getPayload(message_t *msg, uint8_t *len) {
    if (len != NULL) {
      cc1000_header_t *header = getHeader(msg);

      *len = header->length;
    }
    return (void*)msg->data;
  }

  async command error_t PacketAcknowledgements.requestAck(message_t *msg) {
    return SUCCESS;		/* We always ack. */
  }

  async command error_t PacketAcknowledgements.noAck(message_t *msg) {
    return FAIL;		/* We always ack */
  }

  command void* Receive.getPayload(message_t *m, uint8_t *len) {
    return call Packet.getPayload(m, len);
  }

  command uint8_t Receive.payloadLength(message_t *m) {
    return call Packet.payloadLength(m);
  }

  command uint8_t Send.maxPayloadLength() {
    return call Packet.maxPayloadLength();
  }

  command void* Send.getPayload(message_t *m) {
    return call Packet.getPayload(m, NULL);
  }

  async command bool PacketAcknowledgements.wasAcked(message_t *msg) {
    return getMetadata(msg)->ack;
  }
  // 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) { }
}

--- NEW FILE: CC1000Squelch.nc ---
/* $Id: CC1000Squelch.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay 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.
 */

/**
 * CC1000 internal noise floor (aka squelch value) interface
 * @author David Gay
 */
interface CC1000Squelch
{
  /**
   * Adjust noise floor based on new noise measurement
   * @param data noise measurement
   */
  command void adjust(uint16_t data);

  /**
   * Return current estimated noise floor
   * @return Noise floor value
   */
  async command uint16_t get();

  /**
   * Check if noise floor estimate is considered stable (typically after
   * some number of measurements)
   * @return TRUE if noise floor estimate considered stable, FALSE otherwise
   */
  command bool settled();
}

--- NEW FILE: CC1000SquelchP.nc ---
/* $Id: CC1000SquelchP.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay 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 "CC1000Const.h"

/**
 * Clear threshold estimation based on RSSI measurements.
 *
 * @author Philip Buonadonna
 * @author Jaein Jeong
 * @author Joe Polastre
 * @author David Gay
 */
  
module CC1000SquelchP
{
  provides {
    interface Init;
    interface CC1000Squelch;
  }
}
implementation
{
  uint16_t clearThreshold = CC1K_SquelchInit;
  uint16_t squelchTable[CC1K_SquelchTableSize];
  uint8_t squelchIndex, squelchCount;

  command error_t Init.init() {
    uint8_t i;

    for (i = 0; i < CC1K_SquelchTableSize; i++)
      squelchTable[i] = CC1K_SquelchInit;

    return SUCCESS;
  }

  command void CC1000Squelch.adjust(uint16_t data) {
    uint16_t squelchTab[CC1K_SquelchTableSize];
    uint8_t i, j, min; 
    uint32_t newThreshold;

    squelchTable[squelchIndex++] = data;
    if (squelchIndex >= CC1K_SquelchTableSize)
      squelchIndex = 0;
    if (squelchCount <= CC1K_SquelchCount)
      squelchCount++;  

    // Find 3rd highest (aka lowest signal strength) value
    memcpy(squelchTab, squelchTable, sizeof squelchTable);
    for (j = 0; ; j++)
      {
	min = 0;
	for (i = 1; i < CC1K_SquelchTableSize; i++)
	  if (squelchTab[i] > squelchTab[min])
	    min = i;
	if (j == 3)
	  break;
	squelchTab[min] = 0;
      }

    newThreshold = ((uint32_t)clearThreshold << 5) +
      ((uint32_t)squelchTab[min] << 1);
    atomic clearThreshold = newThreshold / 34;
  }

  async command uint16_t CC1000Squelch.get() {
    return clearThreshold;
  }

  command bool CC1000Squelch.settled() {
    return squelchCount > CC1K_SquelchCount;
  }
}

--- NEW FILE: CsmaControl.nc ---
/*									tab:4
 * "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."
 *
 */
/**
 * Interface for activating/deactivating congestion control.
 *
 * @author Philip Levis
 * @author Joe Polastre
 * @date   August 31 2005
 */
interface CsmaControl {
  /**
   * Enable congestion control.
   * @return SUCCESS if congestion control enabled, FAIL otherwise.
   */
  async command error_t enableCca();

  /**
   * Disable congestion control.
   * @return SUCCESS if congestion control disabled, FAIL otherwise.
   */
  async command error_t disableCca();
}

--- NEW FILE: HplCC1000.nc ---
// $Id: HplCC1000.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 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-2003 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.
 */
/*
 * Authors:		Jason Hill, David Gay, Philip Levis
 * Date last modified:  6/25/02
 *
 *
 */

/**
 * Low-level CC1000 radio-access operations that must be provided by a
 * platform wishing to use this CC1000 implementation.
 *
 * @author Jason Hill
 * @author David Gay
 * @author Philip Levis
 */


interface HplCC1000 {
  /**
   * Initialize CC1K pins
   */
  command void init();

  /**
   * Write a value to a CC1000 register.
   * @param addr Which CC1000 register
   * @param data Value to write
   */
  async command void write(uint8_t addr, uint8_t data);

  /**
   * Read a value from a CC1000 register.
   * @param addr Which CC1000 register
   * @return Value of register
   */
  async command uint8_t read(uint8_t addr);

  /**
   * Read the state of the CHP_OUT pin
   * @return State of CHP_OUT as a boolean (TRUE for high)
   */
  async command bool getLOCK();
}

--- NEW FILE: HplCC1000Spi.nc ---
// $Id: HplCC1000Spi.nc,v 1.1.2.1 2006/10/30 01:44:34 idgay Exp $

/*									tab:4
 * "Copyright (c) 2000-2003 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-2003 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.
 */
/**
 * Interface to the CC1000 chip's serial bus. This isn't really an SPI,
 * but the mica2 interface was done using the Atmega128 SPI hardware. Hence
 * the name.
 *
 * @author Jaein Jeong
 * @author Philip buonadonna
 */
interface HplCC1000Spi
{
  /**
   * Write a byte to the CC1000 bus.
   * @param data Byte to write.
   */
  async command void writeByte(uint8_t data);

  /**
   * Is write buffer busy with the last transmission?
   * @return TRUE if the buffer is busy, FALSE otherwise.
   */
  async command bool isBufBusy();

  /**
   * Get the last byte received from the CC1000 bus.
   * @return Last byte received.
   */
  async command uint8_t readByte();

  /**
   * Enable dataReady events on every byte sent or received from the CC1000
   * bus. After this is called, dataReady events will be signaled every
   * 8 CC1000 data clocks.
   */
  async command void enableIntr();

  /**
   * Disable CC1000 bus interrupts.
   */
  async command void disableIntr();

  /**
   * Initialise the interface to the CC1000 bus.
   */
  async command void initSlave();

  /**
   * Switch the interface to the CC1000 bus "transmit" mode.
   */
  async command void txMode();

  /**
   * Switch the interface to the CC1000 bus to "receive" mode.
   */
  async command void rxMode();

  /**
   * If enableIntr() is called, this event will be signaled every 8 CC1000
   * data clocks. 
   * @param data In "receive" mode, the last value received from the CC1000 
   *   bus.
   */
  async event void dataReady(uint8_t data);
}

--- NEW FILE: LowPowerListening.nc ---
/*
 * Copyright (c) 2005-2006 Rincon Research Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the
 *   distribution.
 * - Neither the name of the Arch Rock Corporation nor the names of
 *   its contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * ARCHED ROCK OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE
 */
 
/**
 * Low Power Listening interface
 *
 * @author David Moss
 * @author Jonathan Hui
 */
 
interface LowPowerListening {

  /**
   * Set this this node's radio sleep interval, in milliseconds.
   * Once every interval, the node will sleep and perform an Rx check 
   * on the radio.  Setting the sleep interval to 0 will keep the radio
   * always on.
   *
   * This is the equivalent of setting the local duty cycle rate.
   *
   * @param sleepIntervalMs the length of this node's Rx check interval, in [ms]
   */
  command void setLocalSleepInterval(uint16_t sleepIntervalMs);
  
  /**
   * @return the local node's sleep interval, in [ms]
   */
  command uint16_t getLocalSleepInterval();
  
  /**
   * Set this node's radio duty cycle rate, in units of [percentage*100].
   * For example, to get a 0.05% duty cycle,
   * <code>
   *   call LowPowerListening.setDutyCycle(5);  // or equivalently...
   *   call LowPowerListening.setDutyCycle(00005);  // for better readability?
   * </code>
   *
   * For a 100% duty cycle (always on),
   * <code>
   *   call LowPowerListening.setDutyCycle(10000);
   * </code>
   *
   * This is the equivalent of setting the local sleep interval explicitly.
   * 
   * @param dutyCycle The duty cycle percentage, in units of [percentage*100]
   */
  command void setLocalDutyCycle(uint16_t dutyCycle);
  
  /**
   * @return this node's radio duty cycle rate, in units of [percentage*100]
   */
  command uint16_t getLocalDutyCycle();
  
  
  /**
   * Configure this outgoing message so it can be transmitted to a neighbor mote
   * with the specified Rx sleep interval.
   * @param msg Pointer to the message that will be sent
   * @param sleepInterval The receiving node's sleep interval, in [ms]
   */
  command void setRxSleepInterval(message_t *msg, uint16_t sleepIntervalMs);
  
  /**
   * @return the destination node's sleep interval configured in this message
   */
  command uint16_t getRxSleepInterval(message_t *msg);
  
  /**
   * Configure this outgoing message so it can be transmitted to a neighbor mote
   * with the specified Rx duty cycle rate.
   * Duty cycle is in units of [percentage*100], i.e. 0.25% duty cycle = 25.
   * 
   * @param msg Pointer to the message that will be sent
   * @param dutyCycle The duty cycle of the receiving mote, in units of 
   *     [percentage*100]
   */
  command void setRxDutyCycle(message_t *msg, uint16_t dutyCycle);
  
  /**
   * @return the destination node's duty cycle configured in this message
   *     in units of [percentage*100]
   */
  command uint16_t getRxDutyCycle(message_t *msg);
  
  /**
   * Convert a duty cycle, in units of [percentage*100], to
   * the sleep interval of the mote in milliseconds
   * @param dutyCycle The duty cycle in units of [percentage*100]
   * @return The equivalent sleep interval, in units of [ms]
   */
  command uint16_t dutyCycleToSleepInterval(uint16_t dutyCycle);
  
  /**
   * Convert a sleep interval, in units of [ms], to a duty cycle
   * in units of [percentage*100]
   * @param sleepInterval The sleep interval in units of [ms]
   * @return The duty cycle in units of [percentage*100]
   */
  command uint16_t sleepIntervalToDutyCycle(uint16_t sleepInterval);
  
}



More information about the Tinyos-2-commits mailing list