1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/pkg/openwsn/patches/radio.c.patch
2014-05-14 15:06:50 +02:00

457 lines
13 KiB
Diff

*** stock_iot-lab_M3/openwsn/radio.c Thu Apr 24 11:19:40 2014
--- riot-openwsn-wip/openwsn/radio.c Thu Apr 24 16:55:54 2014
***************
*** 0 ****
--- 1,451 ----
+ /**
+ \brief AT86RF231-specific definition of the "radio" bsp module.
+
+ \author Thomas Watteyne <watteyne@eecs.berkeley.edu>, February 2012.
+ */
+
+
+ #include "board_ow.h"
+ #include "radio.h"
+ #include "at86rf231.h"
+ #include "spi.h"
+ #include "radiotimer.h"
+ #include "debugpins.h"
+ #include "leds_ow.h"
+
+ #define ENABLE_DEBUG (0)
+ #include "debug.h"
+
+
+ //=========================== defines =========================================
+
+ //=========================== variables =======================================
+
+ typedef struct {
+ radiotimer_capture_cbt startFrame_cb;
+ radiotimer_capture_cbt endFrame_cb;
+ radio_state_t state;
+ } radio_vars_t;
+
+ radio_vars_t radio_vars;
+
+ //=========================== prototypes ======================================
+
+ void radio_spiWriteReg(uint8_t reg_addr, uint8_t reg_setting);
+ uint8_t radio_spiReadReg(uint8_t reg_addr);
+ void radio_spiWriteTxFifo(uint8_t* bufToWrite, uint8_t lenToWrite);
+ void radio_spiReadRxFifo(uint8_t* pBufRead,
+ uint8_t* pLenRead,
+ uint8_t maxBufLen,
+ uint8_t* pLqi);
+ uint8_t radio_spiReadRadioInfo(void);
+
+ //=========================== public ==========================================
+
+ //===== admin
+
+ void radio_init() {
+
+ // clear variables
+ memset(&radio_vars,0,sizeof(radio_vars_t));
+
+ // change state
+ radio_vars.state = RADIOSTATE_STOPPED;
+
+ // configure the radio
+ radio_spiWriteReg(RG_TRX_STATE, CMD_FORCE_TRX_OFF); // turn radio off
+
+ radio_spiWriteReg(RG_IRQ_MASK,
+ (AT_IRQ_RX_START| AT_IRQ_TRX_END)); // tell radio to fire interrupt on TRX_END and RX_START
+ radio_spiReadReg(RG_IRQ_STATUS); // deassert the interrupt pin in case is high
+ radio_spiWriteReg(RG_ANT_DIV, RADIO_CHIP_ANTENNA); // use chip antenna
+ #define RG_TRX_CTRL_1 0x04
+ radio_spiWriteReg(RG_TRX_CTRL_1, 0x20); // have the radio calculate CRC
+ //busy wait until radio status is TRX_OFF
+ while((radio_spiReadReg(RG_TRX_STATUS) & 0x1F) != TRX_OFF);
+
+ // change state
+ radio_vars.state = RADIOSTATE_RFOFF;
+ }
+
+ void radio_setOverflowCb(radiotimer_compare_cbt cb) {
+ radiotimer_setOverflowCb(cb);
+ }
+
+ void radio_setCompareCb(radiotimer_compare_cbt cb) {
+ radiotimer_setCompareCb(cb);
+ }
+
+ void radio_setStartFrameCb(radiotimer_capture_cbt cb) {
+ radio_vars.startFrame_cb = cb;
+ }
+
+ void radio_setEndFrameCb(radiotimer_capture_cbt cb) {
+ radio_vars.endFrame_cb = cb;
+ }
+
+ //===== reset
+
+ void radio_reset() {
+ PORT_PIN_RADIO_RESET_LOW();
+ }
+
+ //===== timer
+
+ void radio_startTimer(PORT_TIMER_WIDTH period) {
+ radiotimer_start(period);
+ }
+
+ PORT_TIMER_WIDTH radio_getTimerValue() {
+ return radiotimer_getValue();
+ }
+
+ void radio_setTimerPeriod(PORT_TIMER_WIDTH period) {
+ radiotimer_setPeriod(period);
+ }
+
+ PORT_TIMER_WIDTH radio_getTimerPeriod() {
+ return radiotimer_getPeriod();
+ }
+
+ //===== RF admin
+
+ void radio_setFrequency(uint8_t frequency) {
+ // change state
+ radio_vars.state = RADIOSTATE_SETTING_FREQUENCY;
+
+ // configure the radio to the right frequecy
+ radio_spiWriteReg(RG_PHY_CC_CCA,0x20+frequency);
+
+ // change state
+ radio_vars.state = RADIOSTATE_FREQUENCY_SET;
+ }
+
+ void radio_rfOn() {
+ PORT_PIN_RADIO_RESET_LOW();
+ }
+
+ void radio_rfOff() {
+ DEBUG("%s\n",__PRETTY_FUNCTION__);
+ // change state
+ radio_vars.state = RADIOSTATE_TURNING_OFF;
+ radio_spiReadReg(RG_TRX_STATUS);
+ DEBUG("step 1\n");
+ // turn radio off
+ radio_spiWriteReg(RG_TRX_STATE, CMD_FORCE_TRX_OFF);
+ DEBUG("step 2\n");
+ radio_spiWriteReg(RG_TRX_STATE, CMD_TRX_OFF);
+
+ // busy wait until done
+ while((radio_spiReadReg(RG_TRX_STATUS) & 0x1F) != TRX_OFF);
+
+ DEBUG("step 3\n");
+ // wiggle debug pin
+ debugpins_radio_clr();
+ leds_radio_off();
+ DEBUG("step 4\n");
+ // change state
+ radio_vars.state = RADIOSTATE_RFOFF;
+ DEBUG("step 5\n");
+ }
+
+ //===== TX
+
+ void radio_loadPacket(uint8_t* packet, uint8_t len) {
+ // change state
+ radio_vars.state = RADIOSTATE_LOADING_PACKET;
+
+ // load packet in TXFIFO
+ radio_spiWriteTxFifo(packet,len);
+
+ // change state
+ radio_vars.state = RADIOSTATE_PACKET_LOADED;
+ }
+
+ void radio_txEnable() {
+ // change state
+ radio_vars.state = RADIOSTATE_ENABLING_TX;
+
+ // wiggle debug pin
+ debugpins_radio_set();
+ leds_radio_on();
+
+ // turn on radio's PLL
+ radio_spiWriteReg(RG_TRX_STATE, CMD_PLL_ON);
+
+ while((radio_spiReadReg(RG_TRX_STATUS) & 0x1F) != PLL_ON); // busy wait until done
+
+ // change state
+ radio_vars.state = RADIOSTATE_TX_ENABLED;
+ }
+
+ void radio_txNow() {
+ PORT_TIMER_WIDTH val;
+ // change state
+ radio_vars.state = RADIOSTATE_TRANSMITTING;
+ leds_radio_toggle();
+ // send packet by pulsing the SLP_TR_CNTL pin
+ PORT_PIN_RADIO_SLP_TR_CNTL_HIGH();
+ PORT_PIN_RADIO_SLP_TR_CNTL_LOW();
+
+ // The AT86RF231 does not generate an interrupt when the radio transmits the
+ // SFD, which messes up the MAC state machine. The danger is that, if we leave
+ // this funtion like this, any radio watchdog timer will expire.
+ // Instead, we cheat an mimick a start of frame event by calling
+ // ieee154e_startOfFrame from here. This also means that software can never catch
+ // a radio glitch by which #radio_txEnable would not be followed by a packet being
+ // transmitted (I've never seen that).
+ if (radio_vars.startFrame_cb!=NULL) {
+ // call the callback
+ val=radiotimer_getCapturedTime();
+ radio_vars.startFrame_cb(val);
+ }
+ DEBUG("SENT");
+ }
+
+ //===== RX
+
+ void radio_rxEnable() {
+ // change state
+ radio_vars.state = RADIOSTATE_ENABLING_RX;
+
+ // put radio in reception mode
+ radio_spiWriteReg(RG_TRX_STATE, CMD_RX_ON);
+
+ // wiggle debug pin
+ debugpins_radio_set();
+ leds_radio_on();
+
+ // busy wait until radio really listening
+ while((radio_spiReadReg(RG_TRX_STATUS) & 0x1F) != RX_ON);
+
+ // change state
+ radio_vars.state = RADIOSTATE_LISTENING;
+ }
+
+ void radio_rxNow() {
+ // nothing to do
+ }
+
+ void radio_getReceivedFrame(uint8_t* pBufRead,
+ uint8_t* pLenRead,
+ uint8_t maxBufLen,
+ int8_t* pRssi,
+ uint8_t* pLqi,
+ uint8_t* pCrc) {
+ uint8_t temp_reg_value;
+
+ //===== crc
+ temp_reg_value = radio_spiReadReg(RG_PHY_RSSI);
+ *pCrc = (temp_reg_value & 0x80)>>7; // msb is whether packet passed CRC
+
+ //===== rssi
+ // as per section 8.4.3 of the AT86RF231, the RSSI is calculate as:
+ // -91 + ED [dBm]
+ temp_reg_value = radio_spiReadReg(RG_PHY_ED_LEVEL);
+ *pRssi = -91 + temp_reg_value;
+
+ //===== packet
+ radio_spiReadRxFifo(pBufRead,
+ pLenRead,
+ maxBufLen,
+ pLqi);
+ }
+
+ //=========================== private =========================================
+
+
+ uint8_t radio_spiReadRadioInfo(void){
+ uint8_t spi_tx_buffer[3];
+ uint8_t spi_rx_buffer[3];
+
+ // prepare buffer to send over SPI
+ spi_tx_buffer[0] = (0x80 | 0x1E); // [b7] Read/Write: 1 (read)
+ // [b6] RAM/Register : 1 (register)
+ // [b5-0] address: 0x1E (Manufacturer ID, Lower 16 Bit)
+ spi_tx_buffer[1] = 0x00; // send a SNOP strobe just to get the reg value
+ spi_tx_buffer[2] = 0x00; // send a SNOP strobe just to get the reg value
+
+ // retrieve radio manufacturer ID over SPI
+ spi_txrx(spi_tx_buffer,
+ sizeof(spi_tx_buffer),
+ SPI_BUFFER,
+ spi_rx_buffer,
+ sizeof(spi_rx_buffer),
+ SPI_FIRST,
+ SPI_LAST);
+
+ return spi_rx_buffer[2];
+ }
+
+ void radio_spiWriteReg(uint8_t reg_addr, uint8_t reg_setting) {
+ uint8_t spi_tx_buffer[2];
+ uint8_t spi_rx_buffer[2];
+
+ spi_tx_buffer[0] = (0xC0 | reg_addr); // turn addess in a 'reg write' address
+ spi_tx_buffer[1] = reg_setting;
+
+ spi_txrx(spi_tx_buffer,
+ sizeof(spi_tx_buffer),
+ SPI_BUFFER,
+ (uint8_t*)spi_rx_buffer,
+ sizeof(spi_rx_buffer),
+ SPI_FIRST,
+ SPI_LAST);
+ }
+
+ uint8_t radio_spiReadReg(uint8_t reg_addr) {
+ uint8_t spi_tx_buffer[2];
+ uint8_t spi_rx_buffer[2];
+
+ spi_tx_buffer[0] = (0x80 | reg_addr); // turn addess in a 'reg read' address
+ spi_tx_buffer[1] = 0x00; // send a no_operation command just to get the reg value
+
+ spi_txrx(spi_tx_buffer,
+ sizeof(spi_tx_buffer),
+ SPI_BUFFER,
+ (uint8_t*)spi_rx_buffer,
+ sizeof(spi_rx_buffer),
+ SPI_FIRST,
+ SPI_LAST);
+
+
+ return spi_rx_buffer[1];
+ }
+
+ /** for testing purposes, remove if not needed anymore**/
+
+ void radio_spiWriteTxFifo(uint8_t* bufToWrite, uint8_t lenToWrite) {
+ uint8_t spi_tx_buffer[2];
+ uint8_t spi_rx_buffer[1+1+127]; // 1B SPI address, 1B length, max. 127B data
+
+ spi_tx_buffer[0] = 0x60; // SPI destination address for TXFIFO
+ spi_tx_buffer[1] = lenToWrite; // length byte
+
+ spi_txrx(spi_tx_buffer,
+ sizeof(spi_tx_buffer),
+ SPI_BUFFER,
+ spi_rx_buffer,
+ sizeof(spi_rx_buffer),
+ SPI_FIRST,
+ SPI_NOTLAST);
+
+ spi_txrx(bufToWrite,
+ lenToWrite,
+ SPI_BUFFER,
+ spi_rx_buffer,
+ sizeof(spi_rx_buffer),
+ SPI_NOTFIRST,
+ SPI_LAST);
+ }
+
+
+
+ void radio_spiReadRxFifo(uint8_t* pBufRead,
+ uint8_t* pLenRead,
+ uint8_t maxBufLen,
+ uint8_t* pLqi) {
+ // when reading the packet over SPI from the RX buffer, you get the following:
+ // - *[1B] dummy byte because of SPI
+ // - *[1B] length byte
+ // - [0-125B] packet (excluding CRC)
+ // - *[2B] CRC
+ // - *[1B] LQI
+ uint8_t spi_tx_buffer[125];
+ uint8_t spi_rx_buffer[3];
+
+ spi_tx_buffer[0] = 0x20;
+
+ // 2 first bytes
+ spi_txrx(spi_tx_buffer,
+ 2,
+ SPI_BUFFER,
+ spi_rx_buffer,
+ sizeof(spi_rx_buffer),
+ SPI_FIRST,
+ SPI_NOTLAST);
+
+ *pLenRead = spi_rx_buffer[1];
+
+ if (*pLenRead>2 && *pLenRead<=127) {
+ // valid length
+
+ //read packet
+ spi_txrx(spi_tx_buffer,
+ *pLenRead,
+ SPI_BUFFER,
+ pBufRead,
+ 125,
+ SPI_NOTFIRST,
+ SPI_NOTLAST);
+
+ // CRC (2B) and LQI (1B)
+ spi_txrx(spi_tx_buffer,
+ 2+1,
+ SPI_BUFFER,
+ spi_rx_buffer,
+ 3,
+ SPI_NOTFIRST,
+ SPI_LAST);
+
+ *pLqi = spi_rx_buffer[2];
+
+ } else {
+ // invalid length
+
+ // read a just byte to close spi
+ spi_txrx(spi_tx_buffer,
+ 1,
+ SPI_BUFFER,
+ spi_rx_buffer,
+ sizeof(spi_rx_buffer),
+ SPI_NOTFIRST,
+ SPI_LAST);
+ }
+ }
+
+ //=========================== callbacks =======================================
+
+ //=========================== interrupt handlers ==============================
+
+ kick_scheduler_t radio_isr() {
+ PORT_TIMER_WIDTH capturedTime;
+ uint8_t irq_status;
+
+ // capture the time
+ capturedTime = radiotimer_getCapturedTime();
+
+ // reading IRQ_STATUS causes radio's IRQ pin to go low
+ irq_status = radio_spiReadReg(RG_IRQ_STATUS);
+
+ // start of frame event
+ if (irq_status & AT_IRQ_RX_START) {
+ DEBUG("Start of frame.\n");
+ // change state
+ radio_vars.state = RADIOSTATE_RECEIVING;
+ if (radio_vars.startFrame_cb!=NULL) {
+ // call the callback
+ radio_vars.startFrame_cb(capturedTime);
+ // kick the OS
+ return KICK_SCHEDULER;
+ } else {
+ while(1);
+ }
+ }
+ // end of frame event
+ if (irq_status & AT_IRQ_TRX_END) {
+ DEBUG("End of Frame.\n");
+ // change state
+ radio_vars.state = RADIOSTATE_TXRX_DONE;
+ if (radio_vars.endFrame_cb!=NULL) {
+ // call the callback
+ radio_vars.endFrame_cb(capturedTime);
+ // kick the OS
+ return KICK_SCHEDULER;
+ } else {
+ while(1);
+ }
+ }
+
+ return DO_NOT_KICK_SCHEDULER;
+ }