A Atmel RF2xx Radio Library for Mbed

Dependents:   xBedRadio MxSniffer

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MxRadio_radio_rf230.cpp Source File

MxRadio_radio_rf230.cpp

Go to the documentation of this file.
00001 /* Copyright (c) 2007-2010 Axel Wachtler
00002    All rights reserved.
00003 
00004    Redistribution and use in source and binary forms, with or without
00005    modification, are permitted provided that the following conditions
00006    are met:
00007 
00008  * Redistributions of source code must retain the above copyright
00009      notice, this list of conditions and the following disclaimer.
00010  * Redistributions in binary form must reproduce the above copyright
00011      notice, this list of conditions and the following disclaimer in the
00012      documentation and/or other materials provided with the distribution.
00013  * Neither the name of the authors nor the names of its contributors
00014      may be used to endorse or promote products derived from this software
00015      without specific prior written permission.
00016 
00017    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020    ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021    LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024    INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025    CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027    POSSIBILITY OF SUCH DAMAGE. */
00028 
00029 /* $Id$ */
00030 /**
00031  * @file
00032  * @brief
00033  * Implementation of high level radio functions for AT86RF230 chip
00034  *
00035  */
00036 
00037 /* === includes ============================================================ */
00038 #include <stdbool.h>
00039 
00040 
00041 #include <MxRadio.h>
00042 
00043 
00044 /* === functions ============================================================ */
00045 
00046 /* === internal functions ====================================================*/
00047 /**
00048  * @brief Error handler
00049  *
00050  * @param  err error value (see enumeration radio_error_t)
00051  * @ingroup grpRadio
00052  */
00053 
00054 void cMxRadio::radio_error(radio_error_t err)
00055 {
00056     usr_radio_error(err);
00057 }
00058 
00059 
00060 /**
00061  * @brief Frame reception
00062  *
00063  */
00064 void cMxRadio::radio_receive_frame(void)
00065 {
00066 
00067     uint8_t len, lqi, crc_fail;
00068     int8_t ed;
00069 
00070     /* @todo add RSSI_BASE_VALUE to get a dBm value */
00071     ed = (int8_t)trx_reg_read(RG_PHY_ED_LEVEL);
00072     len = trx_frame_read(radiostatus.rxframe, radiostatus.rxframesz, &lqi);
00073     len &= ~0x80;
00074 
00075 #if defined(SR_RX_CRC_VALID)
00076     crc_fail = trx_bit_read(SR_RX_CRC_VALID) ? 0 : 1;
00077 #else
00078     uint8_t *frm, i;
00079     uint16_t crc;
00080     crc = 0;
00081     frm = radiostatus.rxframe;
00082     for (i=0; i < len; i++)
00083     {
00084         crc = CRC_CCITT_UPDATE(crc, *frm++);
00085     }
00086     crc_fail = (crc == 0)? 0: 1;
00087 #endif
00088 radiostatus.rxframe = usr_radio_receive_frame(len, radiostatus.rxframe,
00089         lqi, ed, crc_fail);
00090 }
00091 
00092 /**
00093  * @brief IRQ handler for radio functions.
00094  *
00095  * This function is called in the transceiver interrupt routine.
00096  * Keep the implementation of the callback functions
00097  * (usr_radio_irq, usr_radio_receive_frame) short and efficient.
00098  *
00099  * @parm cause  value of the interrupt status register
00100  *
00101  */
00102 void cMxRadio::radio_irq_handler(uint8_t cause)
00103 {
00104     if (cause & TRX_IRQ_TRX_END)
00105     {
00106         if (STATE_RX == radiostatus.state ||
00107                 STATE_RXAUTO == radiostatus.state)
00108         {
00109             radio_receive_frame();
00110         }
00111         else if (STATE_TX == radiostatus.state)
00112         {
00113 #ifdef TRX_TX_PA_EI
00114 TRX_TX_PA_DI();
00115 #endif
00116 usr_radio_tx_done(TX_OK);
00117 radio_set_state(radiostatus.idle_state);
00118         }
00119         else if (STATE_TXAUTO == radiostatus.state)
00120         {
00121 #ifdef TRX_TX_PA_EI
00122             TRX_TX_PA_DI();
00123 #endif
00124             uint8_t trac_status = trx_bit_read(SR_TRAC_STATUS);
00125             radio_tx_done_t result;
00126             switch (trac_status)
00127             {
00128             case TRAC_SUCCESS:
00129 #if defined TRAC_SUCCESS_DATA_PENDING
00130             case TRAC_SUCCESS_DATA_PENDING:
00131 #endif
00132 #if defined TRAC_SUCCESS_WAIT_FOR_ACK
00133             case TRAC_SUCCESS_WAIT_FOR_ACK:
00134 #endif
00135                 result = TX_OK;
00136                 break;
00137 
00138             case TRAC_CHANNEL_ACCESS_FAILURE:
00139                 result = TX_CCA_FAIL;
00140                 break;
00141 
00142             case TRAC_NO_ACK:
00143                 result = TX_NO_ACK;
00144                 break;
00145 
00146             default:
00147                 result = TX_FAIL;
00148             }
00149             usr_radio_tx_done(result);
00150             radio_set_state(radiostatus.idle_state);
00151         }
00152     }
00153     usr_radio_irq(cause);
00154 }
00155 
00156 
00157 /* === external functions ====================================================*/
00158 
00159 void cMxRadio::radio_init(uint8_t * rxbuf, uint8_t rxbufsz)
00160 {
00161     trx_regval_t status;
00162     /* init cpu peripherals and global IRQ enable */
00163     radiostatus.rxframe = rxbuf;
00164     radiostatus.rxframesz = rxbufsz;
00165     trx_io_init(1000000);
00166     /* transceiver initialization */
00167 
00168     reset_pin=0;//TRX_RESET_LOW();
00169     sleep_pin=0;//TRX_SLPTR_LOW();
00170     DELAY_US(TRX_RESET_TIME_US);
00171 #if defined(CUSTOM_RESET_TIME_MS)
00172     DELAY_MS(CUSTOM_RESET_TIME_MS);
00173 #endif
00174     reset_pin=1;//TRX_RESET_HIGH();
00175 
00176 
00177 //  if (trx_reg_read(RG_MAN_ID_0)==31) //atmel
00178 //      m_myled=0;
00179     /* disable IRQ and clear any pending IRQs */
00180     trx_reg_write(RG_IRQ_MASK, 0);
00181 
00182     trx_reg_read(RG_IRQ_STATUS);
00183 
00184 #if RADIO_TYPE == RADIO_AT86RF212
00185     trx_reg_write(RG_TRX_CTRL_0, 0x19);
00186 #ifdef CHINABAND
00187     trx_reg_write(RG_CC_CTRL_1, CCBAND );
00188     trx_reg_write(RG_CC_CTRL_0, CCNUMBER);//channel 0
00189     trx_reg_write(RG_TRX_CTRL_2, TRX_OQPSK250);
00190     /*trx_bit_write(SR_OQPSK_SUB1_RC_EN,1);
00191     trx_bit_write(SR_BPSK_OQPSK,1);
00192     trx_bit_write(SR_SUB_MODE,1);
00193     trx_bit_write(SR_OQPSK_DATA_RATE,0);
00194     trx_bit_write(SR_CC_BAND,CCBAND);
00195      */
00196     DELAY_US(510);
00197 #endif
00198     trx_reg_write(RG_TRX_STATE, CMD_FORCE_TRX_OFF);
00199     DELAY_US(510);
00200 #else
00201     trx_bit_write(SR_TRX_CMD, CMD_TRX_OFF);
00202     DELAY_US(510);
00203 #endif
00204 
00205     do
00206     {
00207         status = trx_bit_read(SR_TRX_STATUS);
00208     }
00209     while (status != TRX_OFF);
00210     trx_bit_write(SR_TX_AUTO_CRC_ON, 1);
00211     trx_reg_write(RG_IRQ_MASK, TRX_IRQ_RX_START | TRX_IRQ_TRX_END);
00212 
00213     radiostatus.state = STATE_OFF;
00214     radiostatus.idle_state = STATE_OFF;
00215 }
00216 
00217 
00218 void cMxRadio::radio_force_state(radio_state_t state)
00219 {
00220     trx_bit_write(SR_TRX_CMD, CMD_FORCE_TRX_OFF);
00221     radio_set_state(state);
00222 }
00223 
00224 void cMxRadio::radio_set_state(volatile radio_state_t state)
00225 {
00226     volatile trx_regval_t cmd, expstatus, currstatus;
00227     uint8_t retries;
00228     bool do_sleep = false;
00229 
00230     switch(state)
00231     {
00232     case STATE_OFF:
00233 #ifdef TRX_TX_PA_EI
00234         TRX_TX_PA_DI();
00235 #endif
00236 #ifdef TRX_RX_LNA_EI
00237         TRX_RX_LNA_DI();
00238 #endif
00239         expstatus = TRX_OFF;
00240         cmd = CMD_TRX_OFF;
00241         break;
00242 
00243     case STATE_RX:
00244 #ifdef TRX_RX_LNA_EI
00245         if (radiostatus.rx_lna)
00246         {
00247             TRX_RX_LNA_EI();
00248         }
00249 #endif
00250 expstatus = RX_ON;
00251 cmd = CMD_RX_ON;
00252 break;
00253 
00254     case STATE_TX:
00255         expstatus = PLL_ON;
00256         cmd = CMD_PLL_ON;
00257         break;
00258 
00259     case STATE_RXAUTO:
00260 #ifdef TRX_RX_LNA_EI
00261 if (radiostatus.rx_lna)
00262 {
00263     TRX_RX_LNA_EI();
00264 }
00265 #endif
00266 expstatus = RX_AACK_ON;
00267 cmd = CMD_RX_AACK_ON;
00268 break;
00269 
00270     case STATE_TXAUTO:
00271         expstatus = TX_ARET_ON;
00272         cmd = CMD_TX_ARET_ON;
00273         break;
00274 
00275     case STATE_SLEEP:
00276 #ifdef TRX_TX_PA_EI
00277         TRX_TX_PA_DI();
00278 #endif
00279 #ifdef TRX_RX_LNA_EI
00280         TRX_RX_LNA_DI();
00281 #endif
00282         expstatus = TRX_OFF;
00283         cmd = CMD_FORCE_TRX_OFF;
00284         do_sleep = true;
00285         break;
00286 
00287     default:
00288         radio_error(GENERAL_ERROR);
00289         expstatus = TRX_OFF;
00290         cmd = CMD_TRX_OFF;
00291         break;
00292 
00293     }
00294 
00295     if (STATE_SLEEP == radiostatus.state)
00296     {
00297         if (do_sleep)
00298         {
00299             return;
00300         }
00301         sleep_pin=0;//TRX_SLPTR_LOW();
00302         /*
00303          * Give the xosc some time to start up.  Once it started, the
00304          * SPI interface is operational, and the transceiver state can
00305          * be polled.  The state reads as 0b0011111 ("state transition
00306          * in progress") while the transceiver is still in its startup
00307          * phase, which does not match any of the "expstatus" values,
00308          * so polling just continues.
00309          */
00310         DELAY_US(500);
00311 
00312         /*
00313          * The exact wake-up timing is very board-dependent.
00314          * Contributing parameters are the effective series resitance
00315          * of the crystal, and the external bypass capacitor that has
00316          * to be charged by the voltage regulator.  Give the crystal
00317          * oscillator some time to start up.  5 ms (100 * 50 us) ought
00318          * to be enough under all circumstances.
00319          */
00320         retries = 100;
00321         do
00322         {
00323             currstatus = trx_bit_read(SR_TRX_STATUS);
00324             /*
00325              * Sleep could only be entered from TRX_OFF, so that's
00326              * what is expected again.
00327              */
00328             if (TRX_OFF == currstatus)
00329             {
00330                 break;
00331             }
00332             DELAY_US(50);
00333         }
00334         while (--retries);
00335 
00336         if (currstatus != TRX_OFF)
00337         {
00338             /* radio didn't wake up */
00339             radio_error(STATE_SET_FAILED);
00340         }
00341     }
00342     trx_bit_write(SR_TRX_CMD, cmd);
00343 
00344     retries = 140;              /* enough to await an ongoing frame
00345      * reception */
00346     do
00347     {
00348         currstatus = trx_bit_read(SR_TRX_STATUS);
00349         if (expstatus == currstatus)
00350         {
00351             break;
00352         }
00353         /** @todo must wait longer for 790/868/900 MHz radios */
00354         DELAY_US(32);
00355     }
00356     while (--retries);
00357 
00358     if (expstatus != currstatus)
00359     {
00360         radio_error(STATE_SET_FAILED);
00361     }
00362 
00363     if (do_sleep)
00364     {
00365         sleep_pin=1;//TRX_SLPTR_HIGH();
00366     }
00367 
00368     radiostatus.state = state;
00369 }
00370 
00371 void cMxRadio::radio_set_param(radio_attribute_t attr, radio_param_t parm)
00372 {
00373     switch (attr)
00374     {
00375     case phyCurrentChannel:
00376         if (((int)parm.channel >= TRX_MIN_CHANNEL) &&
00377                 ((int)parm.channel <= TRX_MAX_CHANNEL))
00378         {
00379 #ifdef CHINABAND
00380             trx_reg_write(RG_CC_CTRL_1, CCBAND);
00381             trx_reg_write(RG_CC_CTRL_0, parm.channel*2+CCNUMBER);
00382 #else
00383             trx_bit_write(SR_CHANNEL, parm.channel);
00384 #endif
00385             radiostatus.channel = parm.channel;
00386         }
00387         else
00388         {
00389             radio_error(SET_PARM_FAILED);
00390         }
00391         break;
00392 
00393     case phyTransmitPower:
00394 #if RADIO_TYPE == RADIO_AT86RF212
00395 #ifdef CHINABAND
00396         if (parm.tx_pwr >= -11 && parm.tx_pwr <= 8)
00397         {
00398             /** @todo move this into a radio-specific header file */
00399             static const uint8_t pwrtable[] =
00400             {
00401                     0x0A, 0x09, 0x08,             /* -11...-9 dBm */
00402                     0x07, 0x06, 0x05,           /* -8...-6 dBm */
00403                     0x04, 0x03, 0x25,                   /* -5...-3 dBm */
00404                     0x46, 0xAC, 0xAB,                   /* -2...0 dBm */
00405                     0xAA,                         /* 1 dBm */
00406                     0xCA,                         /* 2 dBm */
00407                     0xEA,                         /* 3 dBm */
00408                     0xE9,                         /* 4 dBm */
00409                     0xE8,                         /* 5 dBm */
00410                     0xE6,                         /* 6 dBm */
00411                     0xE5,                         /* 7 dBm */
00412                     0xE4,                         /* 8 dBm */
00413             };
00414             radiostatus.tx_pwr = parm.tx_pwr;
00415             uint8_t idx = parm.tx_pwr + 11;
00416             uint8_t pwrval = pgm_read_byte(pwrtable[idx]);
00417             trx_reg_write(RG_PHY_TX_PWR, pwrval);
00418         }
00419         else
00420         {
00421             radio_error(SET_PARM_FAILED);
00422         }
00423 #endif//chinaband
00424 #else
00425         if (parm.tx_pwr >= -17 && parm.tx_pwr <= 3)
00426         {
00427             /** @todo move this into a radio-specific header file */
00428             static const uint8_t pwrtable[] =
00429             {
00430                     0x0F, 0x0F, 0x0F, 0x0F, 0x0F, /* -17...-13 dBm */
00431                     0x0E, 0x0E, 0x0E,             /* -12...-10 dBm */
00432                     0x0D, 0x0D,                   /* -9...-8 dBm */
00433                     0x0C, 0x0C,                   /* -7...-6 dBm */
00434                     0x0B,                         /* -5 dBm */
00435                     0x0A,                         /* -4 dBm */
00436                     0x09,                         /* -3 dBm */
00437                     0x08,                         /* -2 dBm */
00438                     0x07,                         /* -1 dBm */
00439                     0x06,                         /* 0 dBm */
00440                     0x04,                         /* 1 dBm */
00441                     0x02,                         /* 2 dBm */
00442                     0x00                          /* 3 dBm */
00443             };
00444             radiostatus.tx_pwr = parm.tx_pwr;
00445             uint8_t idx = parm.tx_pwr + 17;
00446             uint8_t pwrval = pwrtable[idx];
00447             trx_bit_write(SR_TX_PWR, pwrval);
00448 
00449         }
00450 
00451         else
00452         {
00453             radio_error(SET_PARM_FAILED);
00454         }
00455 
00456 #endif//rf212
00457         break;
00458     case phyCCAMode:
00459         if (parm.cca_mode <= 3)
00460         {
00461             radiostatus.cca_mode = parm.cca_mode;
00462             trx_bit_write(SR_CCA_MODE, radiostatus.cca_mode);
00463         }
00464         else
00465         {
00466             radio_error(SET_PARM_FAILED);
00467         }
00468         break;
00469 
00470     case phyIdleState:
00471         radiostatus.idle_state = parm.idle_state;
00472         radio_set_state(parm.idle_state);
00473         break;
00474 
00475     case phyChannelsSupported:
00476         break;
00477 
00478     case phyPanId:
00479         trx_set_panid(parm.pan_id);
00480         break;
00481 
00482     case phyShortAddr:
00483         trx_set_shortaddr(parm.short_addr);
00484         break;
00485 
00486     case phyLongAddr:
00487     {
00488         uint8_t regno, *ap;
00489         for (regno = RG_IEEE_ADDR_0, ap = (uint8_t *)parm.long_addr;
00490                 regno <= RG_IEEE_ADDR_7;
00491                 regno++, ap++)
00492             trx_reg_write(regno, *ap);
00493         break;
00494     }
00495 
00496     case phyDataRate:
00497         trx_set_datarate(parm.data_rate);
00498         break;
00499 
00500 #ifdef TRX_TX_PA_EI
00501     case phyTxPa:
00502         radiostatus.tx_pa = parm.tx_pa;
00503         break;
00504 #endif
00505 #ifdef TRX_RX_LNA_EI
00506     case phyRxLna:
00507         radiostatus.rx_lna = parm.rx_lna;
00508         break;
00509 #endif
00510 
00511     default:
00512         radio_error(SET_PARM_FAILED);
00513         break;
00514     }
00515 }
00516 
00517 
00518 void cMxRadio::radio_send_frame(uint8_t len, uint8_t *frm, uint8_t compcrc)
00519 {
00520 #ifdef TRX_TX_PA_EI
00521     if (radiostatus.tx_pa)
00522     {
00523         TRX_TX_PA_EI();
00524     }
00525 #endif
00526 /* this block should be made atomic */
00527     frm[2]++;
00528     sleep_pin=1;//TRX_SLPTR_HIGH();
00529     sleep_pin=0;//TRX_SLPTR_LOW();
00530     trx_frame_write(len, frm);
00531     /***********************************/
00532 }
00533 
00534 radio_cca_t cMxRadio::radio_do_cca(void)
00535 {
00536     uint8_t tmp, trxcmd, trxstatus;
00537     radio_cca_t ret = RADIO_CCA_FREE;
00538 
00539     trxcmd = trx_reg_read(RG_TRX_STATE);
00540     trx_reg_write(RG_TRX_STATE, CMD_RX_ON);
00541     tmp = 130;
00542     do
00543     {
00544         trxstatus = trx_bit_read(SR_TRX_STATUS);
00545         if ((RX_ON == trxstatus) || (BUSY_RX == trxstatus))
00546         {
00547             break;
00548         }
00549         DELAY_US(32); /* wait for one octett */
00550     }
00551     while(--tmp);
00552 
00553     trx_reg_write(RG_TRX_STATE, CMD_PLL_ON);
00554     trx_reg_write(RG_TRX_STATE, CMD_RX_ON);
00555 
00556     trx_bit_write(SR_CCA_REQUEST,1);
00557     DELAY_US(140);
00558     /* we need to read the whole status register
00559      * because CCA_DONE and CCA_STATUS are valid
00560      * only for one read, after the read they are reset
00561      */
00562     tmp = trx_reg_read(RG_TRX_STATUS);
00563 
00564     if(0 == (tmp & 0x80))
00565     {
00566         ret = RADIO_CCA_FAIL;
00567     }
00568     else if (tmp & 0x40)
00569     {
00570         ret = RADIO_CCA_FREE;
00571     }
00572     else
00573     {
00574         ret = RADIO_CCA_BUSY;
00575     }
00576 
00577     trx_reg_write(RG_TRX_STATE, trxcmd);
00578 
00579     return ret;
00580 }
00581 
00582 /* EOF */