Contiki 2.6

cc1020.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 2006, Freie Universitaet Berlin. All rights reserved.
00003  * 
00004  * These sources were developed at the Freie Universitaet Berlin, Computer
00005  * Systems and Telematics group.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions 
00009  * are met:
00010  * - Redistributions of source code must retain the above copyright
00011  * notice, this list of conditions and the following disclaimer.
00012  *
00013  * - Redistributions in binary form must reproduce the above copyright
00014  * notice, this list of conditions and the following disclaimer in the
00015  * documentation and/or other materials provided with the distribution.
00016  *
00017  * - Neither the name of Freie Universitaet Berlin (FUB) nor the names of its
00018  * contributors may be used to endorse or promote products derived from
00019  * this software without specific prior written permission.
00020  *
00021  * This software is provided by FUB and the contributors on an "as is"
00022  * basis, without any representations or warranties of any kind, express
00023  * or implied including, but not limited to, representations or
00024  * warranties of non-infringement, merchantability or fitness for a
00025  * particular purpose. In no event shall FUB or contributors be liable
00026  * for any direct, indirect, incidental, special, exemplary, or
00027  * consequential damages (including, but not limited to, procurement of
00028  * substitute goods or services; loss of use, data, or profits; or
00029  * business interruption) however caused and on any theory of liability,
00030  * whether in contract, strict liability, or tort (including negligence
00031  * or otherwise) arising in any way out of the use of this software, 
00032  * even if advised of the possibility of such damage.
00033  *
00034  * This implementation was originally developed by the CST group at the FUB.
00035  */
00036 
00037 /**
00038  * \file        cc1020.c
00039  * \author      FUB ScatterWeb Developers, Michael Baar, Nicolas Tsiftes
00040  **/
00041 
00042 #include <stdio.h>
00043 #include <string.h>
00044 
00045 #include "contiki.h"
00046 #include "contiki-msb430.h"
00047 #include "cc1020-internal.h"
00048 #include "cc1020.h"
00049 #include "lib/random.h"
00050 #include "lib/crc16.h"
00051 #include "net/rime/rimestats.h"
00052 #include "dev/dma.h"
00053 #include "sys/energest.h"
00054 #include "isr_compat.h"
00055 
00056 #define DEBUG 0
00057 #if DEBUG
00058 #include <stdio.h>
00059 #define PRINTF(...) printf(__VA_ARGS__)
00060 #else
00061 #define PRINTF(...)
00062 #endif
00063 
00064 #define SEND_TIMEOUT 10
00065 
00066 static int cc1020_calibrate(void);
00067 static int cc1020_setupTX(int);
00068 static int cc1020_setupRX(int);
00069 static void cc1020_setupPD(void);
00070 static void cc1020_wakeupTX(int);
00071 static void cc1020_wakeupRX(int);
00072 static uint8_t cc1020_read_reg(uint8_t addr);
00073 static void cc1020_write_reg(uint8_t addr, uint8_t adata);
00074 static void cc1020_load_config(const uint8_t *);
00075 static void cc1020_reset(void);
00076 
00077 static const uint8_t syncword[SYNCWORD_SIZE] = {0xD3, 0x91};
00078 
00079 /* current mode of cc1020 chip */
00080 static volatile enum cc1020_state cc1020_state = CC1020_OFF;
00081 static volatile uint8_t cc1020_rxbuf[HDR_SIZE + CC1020_BUFFERSIZE];
00082 static uint8_t cc1020_txbuf[PREAMBLE_SIZE + SYNCWORD_SIZE + HDR_SIZE +
00083                            CC1020_BUFFERSIZE + TAIL_SIZE];
00084 
00085 /* number of bytes in receive and transmit buffers respectively. */
00086 static uint8_t cc1020_rxlen;
00087 static uint8_t cc1020_txlen;
00088 
00089 /* received signal strength indicator reading for last received packet */
00090 static volatile uint8_t rssi;
00091 
00092 /* callback when a packet has been received */
00093 static uint8_t cc1020_pa_power = PA_POWER;
00094 
00095 static volatile char dma_done;
00096 
00097 /* Radio driver AAPI functions. */
00098 static int cc1020_init(void);
00099 static int cc1020_prepare(const void *payload, unsigned short payload_len);
00100 static int cc1020_transmit(unsigned short transmit_len);
00101 static int cc1020_send(const void *payload, unsigned short payload_len);
00102 static int cc1020_read(void *buf, unsigned short buf_len);
00103 static int cc1020_channel_clear(void);
00104 static int cc1020_receiving_packet(void);
00105 static int cc1020_pending_packet(void);
00106 static int cc1020_on(void);
00107 static int cc1020_off(void);
00108 
00109 const struct radio_driver cc1020_driver =
00110   {
00111     cc1020_init,
00112     cc1020_prepare,
00113     cc1020_transmit,
00114     cc1020_send,
00115     cc1020_read,
00116     cc1020_channel_clear,
00117     cc1020_receiving_packet,
00118     cc1020_pending_packet,
00119     cc1020_on,
00120     cc1020_off
00121   };
00122 
00123 #define MS_DELAY(x) clock_delay(354 * (x))
00124 
00125 PROCESS(cc1020_receiver_process, "CC1020 receiver");
00126 
00127 static void
00128 dma_callback(void)
00129 {
00130   dma_done = 1;
00131 }
00132 
00133 static void
00134 reset_receiver(void)
00135 {
00136   /* reset receiver */
00137   cc1020_rxlen = 0;
00138 
00139   if((cc1020_state & CC1020_TURN_OFF) && (cc1020_txlen == 0)) {
00140     cc1020_off();
00141   } else {
00142     CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_SEARCHING);
00143     cc1020_set_rx();
00144     ENABLE_RX_IRQ();
00145   }
00146 }
00147 
00148 static int
00149 cc1020_init(void)
00150 {
00151   cc1020_setupPD();
00152   cc1020_reset();
00153   cc1020_load_config(cc1020_config_19200);
00154 
00155   /* init tx buffer with preamble + syncword */
00156   memset(cc1020_txbuf, PREAMBLE, PREAMBLE_SIZE);
00157   cc1020_txbuf[PREAMBLE_SIZE] = syncword[0];
00158   cc1020_txbuf[PREAMBLE_SIZE + 1] = syncword[1];
00159 
00160   /* calibrate receiver */
00161   cc1020_wakeupRX(RX_CURRENT);
00162   if(!cc1020_calibrate()) {
00163     PRINTF("cc1020: rx calibration failed\n");
00164     return -1;
00165   }
00166 
00167   /* calibrate transmitter */
00168   cc1020_wakeupTX(TX_CURRENT);
00169   if(!cc1020_calibrate()) {
00170     PRINTF("cc1020: tx calibration failed\n");
00171     return -1;
00172   }
00173 
00174   /* power down */
00175   cc1020_setupPD();
00176 
00177   process_start(&cc1020_receiver_process, NULL);
00178   dma_subscribe(0, dma_callback);
00179 
00180   return 0;
00181 }
00182 
00183 void
00184 cc1020_set_rx(void)
00185 {
00186   int s;
00187 
00188   s = splhigh();
00189 
00190   /* Reset SEL for P3[1-3] (CC DIO, DIO, DCLK) and P3[4-5] (Camera Rx+Tx) */
00191   P3SEL &= ~0x3E;
00192   IFG1 &= ~(UTXIE0 | URXIE0);   /* Clear interrupt flags */
00193   ME1 &= ~(UTXE0 | URXE0);      /* Disable Uart0 Tx + Rx */
00194   UCTL0 = SWRST;                /* U0 into reset state. */
00195   UCTL0 |= CHAR | SYNC;         /* 8-bit character, SPI, Slave mode */
00196 
00197   /* CKPH works also, but not CKPH+CKPL or none of them!! */
00198   UTCTL0 = CKPL | STC;
00199   URCTL0 = 0x00;
00200   UBR00 = 0x00;                 /* No baudrate divider  */
00201   UBR10 = 0x00;                 /* settings for a spi */
00202   UMCTL0 = 0x00;                /* slave. */
00203   ME1 |= URXE0;         /* Enable USART0 RXD, disabling does not yield any powersavings */
00204   P3SEL |= 0x0A;                /* Select rx line and clk */
00205   UCTL0 &= ~SWRST;              /* Clear reset bit */
00206   splx(s);
00207 
00208   /* configure driver */
00209   cc1020_rxlen = 0;             /* receive buffer position to start */
00210   CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_SEARCHING); /* driver state to receive mode */
00211 
00212   /* configure radio */
00213   ENERGEST_ON(ENERGEST_TYPE_LISTEN);
00214   cc1020_wakeupRX(RX_CURRENT);
00215   cc1020_setupRX(RX_CURRENT);
00216   LNA_POWER_ON();               /* enable amplifier */
00217 
00218   /* activate */
00219   IE1 |= URXIE0;                /* enable interrupt */
00220 }
00221 
00222 void
00223 cc1020_set_tx(void)
00224 {
00225   int s;
00226 
00227   /* configure radio rx */
00228   ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
00229   LNA_POWER_OFF();              /* power down LNA */
00230   s = splhigh();
00231   DISABLE_RX_IRQ();
00232   P3SEL &= ~0x02;               /* Ensure Rx line is off */
00233   splx(s);
00234 
00235   /* configure radio tx */
00236   ENERGEST_ON(ENERGEST_TYPE_TRANSMIT);
00237   cc1020_wakeupTX(TX_CURRENT);
00238   cc1020_setupTX(TX_CURRENT);
00239   P3SEL |= 0x0C;                /* select Tx line and clk */
00240   U0CTL |= SWRST;               /* UART to reset mode */
00241   IFG1 &= ~UTXIFG0;             /* Reset IFG. */
00242 
00243   /* configure driver */
00244   CC1020_SET_OPSTATE(CC1020_TX);
00245 }
00246 
00247 void
00248 cc1020_set_power(uint8_t pa_power)
00249 {
00250   cc1020_pa_power = pa_power;
00251 }
00252 
00253 static int
00254 cc1020_prepare(const void *payload, unsigned short payload_len)
00255 {
00256   return -1;
00257 }
00258 
00259 static int
00260 cc1020_transmit(unsigned short transmit_len)
00261 {
00262   return 0;
00263 }
00264 
00265 static int
00266 cc1020_send(const void *buf, unsigned short len)
00267 {
00268   int normal_header = HDR_SIZE + len;
00269   uint16_t rxcrc = 0xffff; /* For checksum purposes */
00270   rtimer_clock_t timeout_time;
00271 
00272   timeout_time = RTIMER_NOW() + RTIMER_SECOND / 1000 * SEND_TIMEOUT;
00273   while(cc1020_state & CC1020_RX_RECEIVING) {
00274     if(RTIMER_CLOCK_LT(timeout_time, RTIMER_NOW())) {
00275       PRINTF("cc1020: transmission blocked by reception in progress\n");
00276       return RADIO_TX_ERR;
00277     }
00278   }
00279   
00280   if(cc1020_state == CC1020_OFF) {
00281     return RADIO_TX_ERR;
00282   }
00283 
00284   if(len > CC1020_BUFFERSIZE) {
00285     return RADIO_TX_ERR;
00286   }
00287 
00288   /* The preamble and the sync word are already in buffer. */
00289   cc1020_txlen = PREAMBLE_SIZE + SYNCWORD_SIZE;
00290 
00291   /* header */
00292   cc1020_txbuf[cc1020_txlen++] = 0x00;   
00293   cc1020_txbuf[cc1020_txlen++] = normal_header + CRC_SIZE;
00294   
00295   /* Adding the checksum on header and data */
00296   rxcrc = crc16_add(normal_header & 0xff, rxcrc); 
00297   rxcrc = crc16_add((normal_header >> 8) & 0xff, rxcrc);
00298 
00299   rxcrc = crc16_data(buf, len, rxcrc);  
00300   
00301   /* data to send */
00302   memcpy((char *)cc1020_txbuf + cc1020_txlen, buf, len);
00303   cc1020_txlen += len;
00304 
00305   /* Send checksum */
00306   cc1020_txbuf[cc1020_txlen++] = rxcrc >> 8;
00307   cc1020_txbuf[cc1020_txlen++] = rxcrc & 0xff;
00308    
00309   /* suffix */
00310   cc1020_txbuf[cc1020_txlen++] = TAIL;
00311   cc1020_txbuf[cc1020_txlen++] = TAIL; 
00312 
00313   /* Switch to transceive mode. */
00314   cc1020_set_tx();
00315 
00316   /* Initiate radio transfer. */
00317   dma_done = 0;
00318   dma_transfer((unsigned char *)&TXBUF0, cc1020_txbuf, cc1020_txlen);
00319   while(!dma_done);
00320 
00321   ENERGEST_OFF(ENERGEST_TYPE_TRANSMIT);
00322   RIMESTATS_ADD(lltx);
00323 
00324   /* clean up */
00325   cc1020_txlen = 0;
00326   if(cc1020_state & CC1020_TURN_OFF) {
00327     cc1020_off();
00328   } else {
00329     cc1020_set_rx();
00330   }
00331 
00332   return RADIO_TX_OK;
00333 }
00334 
00335 static int
00336 cc1020_read(void *buf, unsigned short size)
00337 {
00338   unsigned len;
00339 
00340   if(cc1020_rxlen <= HDR_SIZE) {
00341     return 0;
00342   }
00343 
00344   len = cc1020_rxlen - HDR_SIZE;
00345   if(len > size) {
00346     RIMESTATS_ADD(toolong);
00347     return -1;
00348   }
00349 
00350   memcpy(buf, (char *)cc1020_rxbuf + HDR_SIZE, len);
00351   RIMESTATS_ADD(llrx);
00352   reset_receiver();
00353 
00354   return len;
00355 }
00356 
00357 static int
00358 cc1020_channel_clear(void)
00359 {
00360   return (cc1020_read_reg(CC1020_STATUS) & CARRIER_SENSE);
00361 }
00362 
00363 static int
00364 cc1020_receiving_packet(void)
00365 {
00366   return cc1020_state & CC1020_RX_RECEIVING;
00367 }
00368 
00369 static int
00370 cc1020_pending_packet(void)
00371 {
00372   return cc1020_state & CC1020_RX_PROCESSING;
00373 }
00374 
00375 int
00376 cc1020_on(void)
00377 {
00378   if(cc1020_state == CC1020_OFF) {
00379     cc1020_set_rx();
00380   } else if(cc1020_state & CC1020_TURN_OFF) {
00381     cc1020_state &= ~CC1020_TURN_OFF;
00382     cc1020_set_rx();
00383   }
00384 
00385   return 1;
00386 }
00387 
00388 int
00389 cc1020_off(void)
00390 {
00391   int s;
00392 
00393   if(cc1020_state != CC1020_OFF) {
00394     if(cc1020_state & CC1020_RX_SEARCHING) {
00395       /* Discard the current read buffer when the radio is shutting down. */
00396       cc1020_rxlen = 0;
00397 
00398       LNA_POWER_OFF();          /* power down lna */
00399       s = splhigh();
00400       DISABLE_RX_IRQ();
00401       cc1020_state = CC1020_OFF;
00402       splx(s);
00403       cc1020_setupPD();         /* power down radio */
00404       ENERGEST_OFF(ENERGEST_TYPE_LISTEN);
00405       cc1020_state = CC1020_OFF;
00406     } else {
00407       cc1020_state |= CC1020_TURN_OFF;
00408     }
00409   }
00410   return 1;
00411 }
00412 
00413 uint8_t
00414 cc1020_get_rssi(void)
00415 {
00416   return (cc1020_read_reg(CC1020_RSS) & 0x7F);
00417 }
00418 
00419 uint8_t
00420 cc1020_get_packet_rssi(void)
00421 {
00422   return rssi;
00423 }
00424 
00425 PROCESS_THREAD(cc1020_receiver_process, ev, data)
00426 {
00427   int len;
00428 
00429   PROCESS_BEGIN();
00430 
00431   while(1) {
00432     ev = PROCESS_EVENT_NONE;
00433     PROCESS_YIELD_UNTIL(ev == PROCESS_EVENT_POLL);      
00434 
00435     /* Verify the checksum. */
00436     uint16_t expected_crc = 0xffff;
00437     uint16_t actual_crc;
00438 
00439     actual_crc = (cc1020_rxbuf[cc1020_rxlen - CRC_SIZE] << 8) |
00440                   cc1020_rxbuf[cc1020_rxlen - CRC_SIZE + 1];
00441     cc1020_rxlen -= CRC_SIZE;
00442       
00443     expected_crc = crc16_add(cc1020_rxlen & 0xff, expected_crc);
00444     expected_crc = crc16_add((cc1020_rxlen >> 8) & 0xff, expected_crc);
00445     expected_crc = crc16_data((char *)&cc1020_rxbuf[HDR_SIZE],
00446                         cc1020_rxlen - HDR_SIZE, expected_crc);
00447 
00448     if(expected_crc == actual_crc) {
00449       len = cc1020_read(packetbuf_dataptr(), PACKETBUF_SIZE);
00450       packetbuf_set_datalen(len);
00451       NETSTACK_RDC.input();
00452     } else {
00453       RIMESTATS_ADD(badcrc);
00454       reset_receiver();
00455     }
00456   }
00457 
00458   PROCESS_END();
00459 }
00460 
00461 ISR(UART0RX, cc1020_rxhandler)
00462 {
00463   static signed char syncbs;
00464   static union {
00465     struct {
00466       uint8_t b2;
00467       uint8_t b1;
00468       uint8_t b4;
00469       uint8_t b3;
00470     };
00471     struct {
00472       uint16_t i1;
00473       uint16_t i2;
00474     };
00475   } shiftbuf;
00476   static unsigned char pktlen;
00477 
00478   if(cc1020_state & CC1020_RX_SEARCHING) {
00479     shiftbuf.b1 = shiftbuf.b2;
00480     shiftbuf.b2 = shiftbuf.b3;
00481     shiftbuf.b3 = shiftbuf.b4;
00482     shiftbuf.b4 = RXBUF0;
00483     if(shiftbuf.i1 == 0xAAD3 && shiftbuf.b3 == 0x91) {
00484       /* 0  AA D3 91 00 | FF 00 | */
00485       syncbs = 0;
00486       cc1020_rxbuf[cc1020_rxlen++] = shiftbuf.b4;
00487     } else if(shiftbuf.i1 == 0x5569 && shiftbuf.i2 == 0xC880) {
00488       /* 1  55 69 C8 80 | 7F 80 | */
00489       syncbs = -1;
00490     } else if(shiftbuf.i1 == 0xAAB4 && shiftbuf.i2 == 0xE440) {
00491       /* 2  AA B4 E4 40 | 3F C0 | */
00492       syncbs = -2;
00493     } else if(shiftbuf.i1 == 0x555A && shiftbuf.i2 == 0x7220) {
00494       /* 3  55 5A 72 20 | 1F E0 | */
00495       syncbs = -3;
00496     } else if(shiftbuf.i1 == 0xAAAD && shiftbuf.i2 == 0x3910) {
00497       /* 4  AA AD 39 10 | 0F F0 | */
00498       syncbs = -4;
00499     } else if(shiftbuf.i1 == 0x5556 && shiftbuf.i2 == 0x9C88) {
00500       /* 5  55 56 9C 88 | 07 F8 | */
00501       syncbs = +3;
00502     } else if(shiftbuf.i1 == 0xAAAB && shiftbuf.i2 == 0x4E44) {
00503       /* 6  AA AB 4E 44 | 03 FC | */
00504       syncbs = +2;
00505     } else if(shiftbuf.i1 == 0x5555 && shiftbuf.i2 == 0xA722) {
00506       /* 7  55 55 A7 22 | 01 FE | */
00507       syncbs = +1;
00508     } else {
00509       return;
00510     }
00511     rssi = cc1020_get_rssi();
00512     CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_RECEIVING);
00513   } else if(cc1020_state & CC1020_RX_RECEIVING) {
00514     if(syncbs == 0) {
00515       cc1020_rxbuf[cc1020_rxlen] = RXBUF0;
00516     } else {
00517       shiftbuf.b3 = shiftbuf.b4;
00518       shiftbuf.b4 = RXBUF0;
00519       if(syncbs < 0) {
00520         shiftbuf.i1 = shiftbuf.i2 << -syncbs;
00521         cc1020_rxbuf[cc1020_rxlen] = shiftbuf.b1;
00522       } else {
00523         shiftbuf.i1 = shiftbuf.i2 >> syncbs;
00524         cc1020_rxbuf[cc1020_rxlen] = shiftbuf.b2;
00525       }
00526     }
00527 
00528     cc1020_rxlen++;
00529          
00530     if(cc1020_rxlen == HDR_SIZE) {
00531       pktlen = ((struct cc1020_header *)cc1020_rxbuf)->length;
00532       if(pktlen == 0 || pktlen > sizeof (cc1020_rxbuf)) {
00533         cc1020_rxlen = 0;
00534         CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_SEARCHING);
00535       }
00536     } else if(cc1020_rxlen > HDR_SIZE) {
00537       if(cc1020_rxlen == pktlen) {
00538         /* Disable interrupts while processing the packet. */
00539         DISABLE_RX_IRQ();
00540         CC1020_SET_OPSTATE(CC1020_RX | CC1020_RX_PROCESSING);
00541         _BIC_SR_IRQ(LPM3_bits);
00542         process_poll(&cc1020_receiver_process);
00543       }
00544     }
00545   } 
00546 }
00547 
00548 static void
00549 cc1020_write_reg(uint8_t addr, uint8_t adata)
00550 {
00551   unsigned int i;
00552   uint8_t data;
00553 
00554   data = addr << 1;
00555   PSEL_ON;
00556 
00557   /* Send address bits  */
00558   for(i = 0; i < 7; i++) {
00559     PCLK_LOW;
00560     if(data & 0x80) {
00561       PDI_HIGH;
00562     } else {
00563       PDI_LOW;
00564     }
00565     data = data << 1;
00566     PCLK_HIGH;
00567     nop();
00568   }
00569 
00570   /* Send read/write bit  */
00571   /* Ignore bit in data, always use 1  */
00572   PCLK_LOW;
00573   PDI_HIGH;
00574   PCLK_HIGH;
00575   nop();
00576   data = adata;
00577 
00578   /* Send data bits  */
00579   for(i = 0; i < 8; i++) {
00580     PCLK_LOW;
00581     if(data & 0x80) {
00582       PDI_HIGH;
00583     } else {
00584       PDI_LOW;
00585     }
00586     data = data << 1;
00587     PCLK_HIGH;
00588     nop();
00589   }
00590 
00591   PCLK_LOW;
00592   PSEL_OFF;
00593 }
00594 
00595 static uint8_t
00596 cc1020_read_reg(uint8_t addr)
00597 {
00598   unsigned int i;
00599   uint8_t data;
00600 
00601   data = addr << 1;
00602   PSEL_ON;
00603 
00604   /* Send address bits  */
00605   for(i = 0; i < 7; i++) {
00606     PCLK_LOW;
00607     if(data & 0x80) {
00608       PDI_HIGH;
00609     } else {
00610       PDI_LOW;
00611     }
00612     data = data << 1;
00613     PCLK_HIGH;
00614     nop();
00615   }
00616 
00617   /* Send read/write bit  */
00618   /* Ignore bit in data, always use 0  */
00619   PCLK_LOW;
00620   PDI_LOW;
00621   PCLK_HIGH;
00622   nop();
00623   PCLK_LOW;
00624 
00625   /* Receive data bits        */
00626   for(i = 0; i < 8; i++) {
00627     nop();
00628     PCLK_HIGH;
00629     nop();
00630     data = data << 1;
00631     if(PDO) {
00632       data++;
00633     }
00634     PCLK_LOW;
00635   }
00636 
00637   PSEL_OFF;
00638 
00639   return data;
00640 }
00641 
00642 static void
00643 cc1020_load_config(const uint8_t * config)
00644 {
00645   int i;
00646 
00647   for(i = 0; i < 0x28; i++)
00648     cc1020_write_reg(i, config[i]);
00649 }
00650 
00651 static void
00652 cc1020_reset(void)
00653 {
00654   /* Reset CC1020 */
00655   cc1020_write_reg(CC1020_MAIN, 0x0FU & ~0x01U);
00656 
00657   /* Bring CC1020 out of reset */
00658   cc1020_write_reg(CC1020_MAIN, 0x1F);
00659 }
00660 
00661 static int
00662 cc1020_calibrate(void)
00663 {
00664   unsigned int timeout_cnt;
00665 
00666   /* Turn off PA to avoid spurs during calibration in TX mode */
00667   cc1020_write_reg(CC1020_PA_POWER, 0x00);
00668 
00669   /* Start calibration */
00670   cc1020_write_reg(CC1020_CALIBRATE, 0xB5);
00671   while((cc1020_read_reg(CC1020_STATUS) & CAL_COMPLETE) == 0);
00672 
00673   /* Monitor lock */
00674   for(timeout_cnt = LOCK_TIMEOUT; timeout_cnt > 0; timeout_cnt--) {
00675     if(cc1020_read_reg(CC1020_STATUS) & LOCK_CONTINUOUS) {
00676         break;
00677     }
00678   }
00679 
00680   /* Restore PA_POWER */
00681   cc1020_write_reg(CC1020_PA_POWER, cc1020_pa_power);
00682 
00683   /* Return state of LOCK_CONTINUOUS bit */
00684   return (cc1020_read_reg(CC1020_STATUS) & LOCK_CONTINUOUS) == LOCK_CONTINUOUS;
00685 }
00686 
00687 static int
00688 cc1020_lock(void)
00689 {
00690   char lock_status;
00691   int i;
00692 
00693   /* Monitor LOCK, lasts 420 - 510 cycles @ 4505600 = 93 us - 113 us */
00694   for(i = LOCK_TIMEOUT; i > 0; i--) {
00695     lock_status = cc1020_read_reg(CC1020_STATUS) & LOCK_CONTINUOUS;
00696     if(lock_status) {
00697       break;
00698     }
00699   }
00700 
00701   if(lock_status == LOCK_CONTINUOUS) {
00702     return LOCK_OK;
00703   }
00704 
00705   return cc1020_calibrate() ? LOCK_RECAL_OK : LOCK_NOK;
00706 }
00707 
00708 static int
00709 cc1020_setupRX(int analog)
00710 {
00711   char lock_status;
00712 
00713   /* Switch into RX, switch to freq. reg A */
00714   cc1020_write_reg(CC1020_MAIN, 0x01);
00715   lock_status = cc1020_lock();
00716 
00717   /* Switch RX part of CC1020 on */
00718   cc1020_write_reg(CC1020_INTERFACE, 0x02);
00719 
00720   /* Return LOCK status to application */
00721   return lock_status;
00722 }
00723 
00724 static int
00725 cc1020_setupTX(int analog)
00726 {
00727   char lock_status;
00728 
00729   /* Switch into TX, switch to freq. reg B */
00730   cc1020_write_reg(CC1020_MAIN, 0xC1);
00731   lock_status = cc1020_lock();
00732 
00733   /* Restore PA_POWER */
00734   cc1020_write_reg(CC1020_PA_POWER, cc1020_pa_power);
00735 
00736   /* Turn OFF DCLK squelch in TX */
00737   cc1020_write_reg(CC1020_INTERFACE, 0x01);
00738 
00739   /* Return LOCK status to application */
00740   return lock_status;
00741 }
00742 
00743 static void
00744 cc1020_setupPD(void)
00745 {
00746   /*
00747    *  Power down components and reset all registers except MAIN
00748    *  to their default values.
00749    */
00750   cc1020_write_reg(CC1020_MAIN,
00751         RESET_N | BIAS_PD | FS_PD | XOSC_PD | PD_MODE_1);
00752 
00753   /* Turn off the power amplifier. */
00754   cc1020_write_reg(CC1020_PA_POWER, 0x00);
00755 
00756   cc1020_write_reg(CC1020_POWERDOWN, 0x1F);
00757 }
00758 
00759 static void
00760 cc1020_wakeupRX(int analog)
00761 {
00762   /* Turn on crystal oscillator core. */
00763   cc1020_write_reg(CC1020_MAIN, 0x1B);
00764 
00765   /* Setup bias current adjustment. */
00766   cc1020_write_reg(CC1020_ANALOG, analog);
00767 
00768   /*
00769    * Wait for the crystal oscillator to stabilize.
00770    * This typically takes 2-5 ms.
00771    */
00772   MS_DELAY(5);
00773 
00774   /* Turn on bias generator. */
00775   cc1020_write_reg(CC1020_MAIN, 0x19);
00776 
00777   /* Turn on frequency synthesizer. */
00778   cc1020_write_reg(CC1020_MAIN, 0x11);
00779 }
00780 
00781 static void
00782 cc1020_wakeupTX(int analog)
00783 {
00784   /* Turn on crystal oscillator core. */
00785   cc1020_write_reg(CC1020_MAIN, 0xDB);
00786 
00787   /* Setup bias current adjustment. */
00788   cc1020_write_reg(CC1020_ANALOG, analog);
00789 
00790   /*
00791    * Wait for the crystal oscillator to stabilize.
00792    * This typically takes 2-5 ms.
00793    */
00794   MS_DELAY(5);
00795 
00796   /* Turn on bias generator. */
00797   cc1020_write_reg(CC1020_MAIN, 0xD9);
00798 
00799   /* Turn on frequency synthesizer. */
00800   MS_DELAY(1);
00801   cc1020_write_reg(CC1020_MAIN, 0xD1);
00802 }
00803