]> oss.titaniummirror.com Git - tinyos-2.x.git/blobdiff - tos/chips/cc1000_lpl/CC1000ControlP.nc
Swapping HEAD and DEVEL branches
[tinyos-2.x.git] / tos / chips / cc1000_lpl / CC1000ControlP.nc
index cff7a950313a84e0e486034d05ebcac6f8ff2e3d..81c0f3c76bd52424a62a1c9071006ce4b5e432fd 100644 (file)
-/* $Id$\r
- * "Copyright (c) 2000-2005 The Regents of the University  of California.  \r
- * All rights reserved.\r
- *\r
- * Permission to use, copy, modify, and distribute this software and its\r
- * documentation for any purpose, without fee, and without written agreement is\r
- * hereby granted, provided that the above copyright notice, the following\r
- * two paragraphs and the author appear in all copies of this software.\r
- * \r
- * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR\r
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT\r
- * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF\r
- * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
- * \r
- * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,\r
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\r
- * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS\r
- * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO\r
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."\r
- *\r
- * Copyright (c) 2002-2005 Intel Corporation\r
- * All rights reserved.\r
- *\r
- * This file is distributed under the terms in the attached INTEL-LICENSE     \r
- * file. If you do not find these files, copies can be found by writing to\r
- * Intel Research Berkeley, 2150 Shattuck Avenue, Suite 1300, Berkeley, CA, \r
- * 94704.  Attention:  Intel License Inquiry.\r
- */\r
-#include "CC1000Const.h"\r
-#include "Timer.h"\r
-\r
-/**\r
- * This module provides the CONTROL functionality for the Chipcon1000\r
- * series radio.  It exports a custom interface to control CC1000\r
- * operation.\r
- *\r
- * @author Philip Buonadonna\r
- * @author Jaein Jeong\r
- * @author David Gay\r
- */\r
-module CC1000ControlP {\r
-  provides {\r
-    interface CC1000Control;\r
-  }\r
-  uses {\r
-    interface HplCC1000 as CC;\r
-    interface BusyWait<TMicro, uint16_t>;\r
-  }\r
-}\r
-implementation\r
-{\r
-  uint8_t txCurrent, rxCurrent, power;\r
-\r
-  enum {\r
-    IF = 150000,\r
-    FREQ_MIN = 4194304,\r
-    FREQ_MAX = 16751615\r
-  };\r
-\r
-  const_uint32_t fRefTbl[9] = {2457600,\r
-                              2106514,\r
-                              1843200,\r
-                              1638400,\r
-                              1474560,\r
-                              1340509,\r
-                              1228800,\r
-                              1134277,\r
-                              1053257};\r
-  \r
-  const_uint16_t corTbl[9] = {1213,\r
-                             1416,\r
-                             1618,\r
-                             1820,\r
-                             2022,\r
-                             2224,\r
-                             2427,\r
-                             2629,\r
-                             2831};\r
-  \r
-  const_uint16_t fSepTbl[9] = {0x1AA,\r
-                              0x1F1,\r
-                              0x238,\r
-                              0x280,\r
-                              0x2C7,\r
-                              0x30E,\r
-                              0x355,\r
-                              0x39C,\r
-                              0x3E3};\r
-  \r
-  void calibrateNow() {\r
-    // start cal\r
-    call CC.write(CC1K_CAL,\r
-                 1 << CC1K_CAL_START |\r
-                 1 << CC1K_CAL_WAIT |\r
-                 6 << CC1K_CAL_ITERATE);\r
-    while ((call CC.read(CC1K_CAL) & 1 << CC1K_CAL_COMPLETE) == 0)\r
-      ;\r
-\r
-    //exit cal mode\r
-    call CC.write(CC1K_CAL, 1 << CC1K_CAL_WAIT | 6 << CC1K_CAL_ITERATE);\r
-  }\r
-\r
-  void calibrate() {\r
-    call CC.write(CC1K_PA_POW, 0x00);  // turn off rf amp\r
-    call CC.write(CC1K_TEST4, 0x3f);   // chip rate >= 38.4kb\r
-\r
-    // RX - configure main freq A\r
-    call CC.write(CC1K_MAIN, 1 << CC1K_TX_PD | 1 << CC1K_RESET_N);\r
-\r
-    calibrateNow();\r
-\r
-    // TX - configure main freq B\r
-    call CC.write(CC1K_MAIN,\r
-                 1 << CC1K_RXTX |\r
-                 1 << CC1K_F_REG |\r
-                 1 << CC1K_RX_PD | \r
-                 1 << CC1K_RESET_N);\r
-    // Set TX current\r
-    call CC.write(CC1K_CURRENT, txCurrent);\r
-    call CC.write(CC1K_PA_POW, 0);\r
-\r
-    calibrateNow();\r
-  }\r
-\r
-  /*\r
-   * cc1000ComputeFreq(uint32_t desiredFreq);\r
-   *\r
-   * Compute an achievable frequency and the necessary CC1K parameters from\r
-   * a given desired frequency (Hz). The function returns the actual achieved\r
-   * channel frequency in Hz.\r
-   *\r
-   * This routine assumes the following:\r
-   *  - Crystal Freq: 14.7456 MHz\r
-   *  - LO Injection: High\r
-   *  - Separation: 64 KHz\r
-   *  - IF: 150 KHz\r
-   * \r
-   * Approximate costs for this function:\r
-   *  - ~870 bytes FLASH\r
-   *  - ~32 bytes RAM\r
-   *  - 9400 cycles\r
-   */\r
-  uint32_t cc1000SetFrequency(uint32_t desiredFreq) {\r
-    uint32_t ActualChannel = 0;\r
-    uint32_t RXFreq = 0, TXFreq = 0;\r
-    int32_t Offset = 0x7fffffff;\r
-    uint16_t FSep = 0;\r
-    uint8_t RefDiv = 0;\r
-    uint8_t i, match, frontend;\r
-\r
-    for (i = 0; i < 9; i++)\r
-      {\r
-       uint32_t NRef = desiredFreq + IF;\r
-       uint32_t FRef = read_uint32_t(&fRefTbl[i]);\r
-       uint32_t Channel = 0;\r
-       uint32_t RXCalc = 0, TXCalc = 0;\r
-       int32_t  diff;\r
-\r
-       NRef = ((desiredFreq + IF)  <<  2) / FRef;\r
-       if (NRef & 0x1)\r
-         NRef++;\r
-\r
-       if (NRef & 0x2)\r
-         {\r
-           RXCalc = 16384 >> 1;\r
-           Channel = FRef >> 1;\r
-         }\r
-\r
-       NRef >>= 2;\r
-\r
-       RXCalc += (NRef * 16384) - 8192;\r
-       if ((RXCalc < FREQ_MIN) || (RXCalc > FREQ_MAX)) \r
-         continue;\r
-    \r
-       TXCalc = RXCalc - read_uint16_t(&corTbl[i]);\r
-       if (TXCalc < FREQ_MIN || TXCalc > FREQ_MAX)\r
-         continue;\r
-\r
-       Channel += NRef * FRef;\r
-       Channel -= IF;\r
-\r
-       diff = Channel - desiredFreq;\r
-       if (diff < 0)\r
-         diff = -diff;\r
-\r
-       if (diff < Offset)\r
-         {\r
-           RXFreq = RXCalc;\r
-           TXFreq = TXCalc;\r
-           ActualChannel = Channel;\r
-           FSep = read_uint16_t(&fSepTbl[i]);\r
-           RefDiv = i + 6;\r
-           Offset = diff;\r
-         }\r
-      }\r
-\r
-    if (RefDiv != 0)\r
-      {\r
-       call CC.write(CC1K_FREQ_0A, RXFreq);\r
-       call CC.write(CC1K_FREQ_1A, RXFreq >> 8);\r
-       call CC.write(CC1K_FREQ_2A, RXFreq >> 16);\r
-\r
-       call CC.write(CC1K_FREQ_0B, TXFreq);\r
-       call CC.write(CC1K_FREQ_1B, TXFreq >> 8);\r
-       call CC.write(CC1K_FREQ_2B, TXFreq >> 16);\r
-\r
-       call CC.write(CC1K_FSEP0, FSep);\r
-       call CC.write(CC1K_FSEP1, FSep >> 8);\r
-\r
-       if (ActualChannel < 500000000)\r
-         {\r
-           if (ActualChannel < 400000000)\r
-             {\r
-               rxCurrent = 8 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE;\r
-               txCurrent = 9 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE;\r
-             }\r
-           else\r
-             {\r
-               rxCurrent = 4 << CC1K_VCO_CURRENT | 1 << CC1K_LO_DRIVE;\r
-               txCurrent = 8 << CC1K_VCO_CURRENT | 1 << CC1K_PA_DRIVE;\r
-             }\r
-           frontend = 1 << CC1K_IF_RSSI;\r
-           match = 7 << CC1K_RX_MATCH;\r
-         }\r
-       else\r
-         {\r
-           rxCurrent = 8 << CC1K_VCO_CURRENT | 3 << CC1K_LO_DRIVE;\r
-           txCurrent = 15 << CC1K_VCO_CURRENT | 3 << CC1K_PA_DRIVE;\r
-\r
-           frontend =\r
-             1 << CC1K_BUF_CURRENT | 2 << CC1K_LNA_CURRENT | \r
-             1 << CC1K_IF_RSSI;\r
-           match = 2 << CC1K_RX_MATCH; // datasheet says to use 1...\r
-         }\r
-       call CC.write(CC1K_CURRENT, rxCurrent);\r
-       call CC.write(CC1K_MATCH, match);\r
-       call CC.write(CC1K_FRONT_END, frontend);\r
-       call CC.write(CC1K_PLL, RefDiv << CC1K_REFDIV);\r
-      }\r
-\r
-    return ActualChannel;\r
-  }\r
-\r
-  command void CC1000Control.init() {\r
-    call CC.init();\r
-\r
-    // wake up xtal and reset unit\r
-    call CC.write(CC1K_MAIN,\r
-                 1 << CC1K_RX_PD | 1 << CC1K_TX_PD | \r
-                 1 << CC1K_FS_PD | 1 << CC1K_BIAS_PD); \r
-    // clear reset.\r
-    call CC1000Control.coreOn();\r
-    call BusyWait.wait(2000);\r
-\r
-    // Set default parameter values\r
-    // POWER: 0dbm (~900MHz), 6dbm (~430MHz)\r
-    power = 8 << CC1K_PA_HIGHPOWER | 0 << CC1K_PA_LOWPOWER;\r
-    call CC.write(CC1K_PA_POW, power);\r
-\r
-    // select Manchester Violation for CHP_OUT\r
-    call CC.write(CC1K_LOCK_SELECT, 9 << CC1K_LOCK_SELECT);\r
-\r
-    // Default modem values = 19.2 Kbps (38.4 kBaud), Manchester encoded\r
-    call CC.write(CC1K_MODEM2, 0);\r
-    call CC.write(CC1K_MODEM1, \r
-                 3 << CC1K_MLIMIT |\r
-                 1 << CC1K_LOCK_AVG_MODE | \r
-                 3 << CC1K_SETTLING |\r
-                 1 << CC1K_MODEM_RESET_N);\r
-    call CC.write(CC1K_MODEM0, \r
-                 5 << CC1K_BAUDRATE |\r
-                 1 << CC1K_DATA_FORMAT | \r
-                 1 << CC1K_XOSC_FREQ);\r
-\r
-    call CC.write(CC1K_FSCTRL, 1 << CC1K_FS_RESET_N);\r
-\r
-#ifdef CC1K_DEF_FREQ\r
-    call CC1000Control.tuneManual(CC1K_DEF_FREQ);\r
-#else\r
-    call CC1000Control.tunePreset(CC1K_DEF_PRESET);\r
-#endif\r
-    call CC1000Control.off();\r
-  }\r
-\r
-  command void CC1000Control.tunePreset(uint8_t freq) {\r
-    int i;\r
-\r
-    // FREQA, FREQB, FSEP, CURRENT(RX), FRONT_END, POWER, PLL\r
-    for (i = CC1K_FREQ_2A; i <= CC1K_PLL; i++)\r
-      call CC.write(i, read_uint8_t(&CC1K_Params[freq][i]));\r
-    call CC.write(CC1K_MATCH, read_uint8_t(&CC1K_Params[freq][CC1K_MATCH]));\r
-    rxCurrent = read_uint8_t(&CC1K_Params[freq][CC1K_CURRENT]);\r
-    txCurrent = read_uint8_t(&CC1K_Params[freq][CC1K_MATCH + 1]);\r
-    power = read_uint8_t(&CC1K_Params[freq][CC1K_PA_POW]);\r
-\r
-    calibrate();\r
-  }\r
-\r
-  command uint32_t CC1000Control.tuneManual(uint32_t DesiredFreq) {\r
-    uint32_t actualFreq;\r
-\r
-    actualFreq = cc1000SetFrequency(DesiredFreq);\r
-\r
-    calibrate();\r
-\r
-    return actualFreq;\r
-  }\r
-\r
-  async command void CC1000Control.txMode() {\r
-    // MAIN register to TX mode\r
-    call CC.write(CC1K_MAIN,\r
-                 1 << CC1K_RXTX |\r
-                 1 << CC1K_F_REG |\r
-                 1 << CC1K_RX_PD | \r
-                 1 << CC1K_RESET_N);\r
-    // Set the TX mode VCO Current\r
-    call CC.write(CC1K_CURRENT, txCurrent);\r
-    call BusyWait.wait(250);\r
-    call CC.write(CC1K_PA_POW, power);\r
-    call BusyWait.wait(20);\r
-  }\r
-\r
-  async command void CC1000Control.rxMode() {\r
-    // MAIN register to RX mode\r
-    // Powerup Freqency Synthesizer and Receiver\r
-    call CC.write(CC1K_CURRENT, rxCurrent);\r
-    call CC.write(CC1K_PA_POW, 0); // turn off power amp\r
-    call CC.write(CC1K_MAIN, 1 << CC1K_TX_PD | 1 << CC1K_RESET_N);\r
-    call BusyWait.wait(125);\r
-  }\r
-\r
-  async command void CC1000Control.coreOn() {\r
-    // MAIN register to SLEEP mode\r
-    call CC.write(CC1K_MAIN,\r
-                 1 << CC1K_RX_PD |\r
-                 1 << CC1K_TX_PD | \r
-                 1 << CC1K_FS_PD |\r
-                 1 << CC1K_BIAS_PD |\r
-                 1 << CC1K_RESET_N);\r
-  }\r
-\r
-  async command void CC1000Control.biasOn() {\r
-    call CC.write(CC1K_MAIN,\r
-                 1 << CC1K_RX_PD |\r
-                 1 << CC1K_TX_PD | \r
-                 1 << CC1K_FS_PD | \r
-                 1 << CC1K_RESET_N);\r
-  }\r
-\r
-\r
-  async command void CC1000Control.off() {\r
-    // MAIN register to power down mode. Shut everything off\r
-    call CC.write(CC1K_MAIN,\r
-                 1 << CC1K_RX_PD |\r
-                 1 << CC1K_TX_PD | \r
-                 1 << CC1K_FS_PD |\r
-                 1 << CC1K_CORE_PD |\r
-                 1 << CC1K_BIAS_PD |\r
-                 1 << CC1K_RESET_N);\r
-    call CC.write(CC1K_PA_POW, 0);  // turn off rf amp\r
-  }\r
-\r
-  command void CC1000Control.setRFPower(uint8_t newPower) {\r
-    power = newPower;\r
-  }\r
-\r
-  command uint8_t CC1000Control.getRFPower() {\r
-    return power;\r
-  }\r
-\r
-  command void CC1000Control.selectLock(uint8_t fn) {\r
-    // Select function of CHP_OUT pin (readable via getLock)\r
-    call CC.write(CC1K_LOCK, fn << CC1K_LOCK_SELECT);\r
-  }\r
-\r
-  command uint8_t CC1000Control.getLock() {\r
-    return call CC.getLOCK(); \r
-  }\r
-\r
-  command bool CC1000Control.getLOStatus() {\r
-    // We use a high-side LO (local oscillator) frequency -> data will be\r
-    // inverted. See cc1000ComputeFreq and CC1000 datasheet p.23.\r
-    return TRUE;\r
-  }\r
-}\r
+/* $Id$
+ * "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();
+    
+    call CC1000Control.rxMode();
+  }
+
+  /*
+   * 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;
+  }
+}