A Atmel RF2xx Radio Library for Mbed
Dependents: xBedRadio MxSniffer
MxRadio_radio_rf230.cpp
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 */
Generated on Thu Jul 14 2022 01:09:40 by
1.7.2