-/* $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;
+ }
+}