Library for the nRF2401A Transceiver
Dependents: nRF2401A_Hello_World nRF2401A_Wireless_Accelerometer_joypad nRF2401A_Gameduino_Invaders
nRF2401A.cpp
- Committer:
- TheChrisyd
- Date:
- 2014-03-09
- Revision:
- 9:7245524e37e4
- Parent:
- 7:22f69cf045d9
File content as of revision 9:7245524e37e4:
/** *@section DESCRIPTION * mbed nRF2401A Library *@section LICENSE * Copyright (c) 2011, Per Söderstam * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * @file "nRF2401A.cpp" */ #include "nRF2401A.h" #define Ts 1 /**< Setup time from data to rising clock edge on write (accualy 500 ns). */ #define Th 1 /**< Hold time from rising clock to data toggle/falling clock (accualy 500 ns). */ #define Tcs2data 5 /**< Min delay from CS assert to data, in us. */ #define Tce2data 5 /**< Min delay from CE assert to data, in us. */ #define Td 1 /**< Minimum delay between edges (actually 50 ns). */ #define Tpd2cfgm 3 /**< Minimum delay from power up of tranciever to configuration. */ #define Tsby2txSB 195 /**< Minimum delay from tx initation to air, in us. */ #define Tsby2rx 202 /**< Minimum delay from stanby to rx mode, in us. */ #define Thmin 5 /**< */ #define Tclk2data 1 /**< */ #define MAXIMUM_ADDR_LENGTH 40 /**< */ nRF2401A::nRF2401A(PinName ce, PinName cs, PinName dr1, PinName clk1, PinName data) : _ce(DigitalOut(ce)), _cs(DigitalOut(cs)), _dr1(DigitalIn(dr1)), _clk1(DigitalOut(clk1)), _data(DigitalInOut(data)), _state(nRF2401A::STANDBY), _rx_handler((nRF2401A_rx_handler_t) 0), _rx_handler_arg((void *) 0), _dr1_isr(InterruptIn(dr1)) { // init member variables _data.output(); // set defaults _ctrl_packet_buf.crc_config = NO_CRC; _ctrl_packet_buf.rf_data_rate = BIT_RATE_250KBITS; _ctrl_packet_buf.rf_channel = 0x02; _ctrl_packet_buf.channel_1_data_payload_len = 0x20; // setup... _ctrl_packet = (uint8_t *) &_ctrl_packet_buf; _dr1_isr.rise(this, &nRF2401A::dataReadyHandler); // ...tranceiver in standby... _ce = 0; _cs = 0; // ...and clear receive buffer for (int i = 0; i < 16; i++) _data_buf[i] = 0x0; // ...set imutable control fields... _ctrl_packet_buf.enable_dual_channel_mode = 0x0; // single channel receive _ctrl_packet_buf.communication_mode = 0x1; // ShockBurst mode _ctrl_packet_buf.xo_frequency = 0x3; // 16 MHz crystal _ctrl_packet_buf.rf_power = 0x3; // 0 dBm (1 mW) output power // ...start in RX mode _ctrl_packet_buf.txr_switch = nRF2401A::RX_MODE; _state = nRF2401A::RX ; // assure minimum wake up time while assuming tranceiver powers up with uP wait_ms(Tpd2cfgm); return; } /* Public functions */ /* Print control packet * Print the control packet to a serial port * @param arg Pointer to the port to transmit on * @return bool for correct parameters supplied */ bool nRF2401A::printControlPacket(Serial& port) { bool ok = false; if (port != NULL) { for(int i = 0; i < sizeof(_ctrl_packet_buf); i++) { port.printf("%02x ", _ctrl_packet[i]); } port.printf("\n\r"); ok = true; } return ok; } /* Print data packet * Print the data packet to a serial port * @param arg Pointer to the port to transmit on * @return bool for correct parameters supplied */ bool nRF2401A::printDataPacket(Serial& port) { bool ok = false; if (port != NULL) { for(int i = 0; i < sizeof(_data_buf); i++) { port.printf("%02x ", _data_buf[i]); } port.printf("\r"); ok = true; } return ok; } /* Send the control packet to the nRF2401A. * This function transfer the control packet image to the nRF2401A. * @return bool for successfull flushing of the packet */ bool nRF2401A::flushControlPacket() { bool flush = false; switch (_state) { case nRF2401A::RX: pushCtrl(_ctrl_packet, 15 << 3 ); _state = nRF2401A::RX; _ce = 1; _cs = 0; flush = true; break; case nRF2401A::STANDBY: pushCtrl(_ctrl_packet, 15 << 3 ); _state = nRF2401A::STANDBY; _ce = 0; _cs = 0; flush = true; break; case nRF2401A::TX: default: _ce = 0; _cs = 0; } return flush; } /* Register a receive action callback. * Attach a callback that will be called when the tranceiver intercept a * message. This callback will be called in the context of an interrupt * routine and should act accordingly. * @param handler The callback, of type nRF2401_rx_handler_t. * @param arg Pointer to data supplied to the handler at call time. * @return Reference to the invoked object (for chaining operations). */ bool nRF2401A::attachRXHandler(nRF2401A_rx_handler_t handler, void *arg) { bool ok = false; if (handler != NULL) { _rx_handler = handler; _rx_handler_arg = arg; ok = true; } return ok; } /* Set the payload length, in bits. * Set the control packet field for length, in number of bits, of the message payload. * @param n Number of bits of the message payload. * @return void */ void nRF2401A::setDataPayloadLength(uint8_t n) { _ctrl_packet_buf.channel_1_data_payload_len = n; } /* Set the address of channel 1. * The channel address is a up to 40 bit number identifying the tranceiver. * @param addr4 Bits 39-32 of the address. * @param addr4 Bits 31-24 of the address. * @param addr4 Bits 23-16 of the address. * @param addr4 Bits 15-8 of the address. * @param addr4 Bits 7-0 of the address. * @param n_bits Number of bits used in the address. * @return bool for correct settings supplied */ bool nRF2401A::setAddress(uint8_t addr4, uint8_t addr3, uint8_t addr2, uint8_t addr1, uint8_t addr0, uint8_t n_bits) { bool ok = false; if (n_bits <= MAXIMUM_ADDR_LENGTH) { _ctrl_packet_buf.channel_1_address[0] = addr4; _ctrl_packet_buf.channel_1_address[1] = addr3; _ctrl_packet_buf.channel_1_address[2] = addr2; _ctrl_packet_buf.channel_1_address[3] = addr1; _ctrl_packet_buf.channel_1_address[4] = addr0; _ctrl_packet_buf.channel_address_len = n_bits; ok = true; } return ok; } /* Set CRC use. * Set the CRC mode field of the control packet. Defaults to no CRC. * @param mode The CRC mode of choise. * @return bool for correct parameter supplied */ bool nRF2401A::setCRCMode(CRC_T mode) { bool ok = false; if (mode < INVALID_CRC) { _ctrl_packet_buf.crc_config = mode; ok = true; } return ok; } /* Set RF power use. * Set the RF power field of the control packet. Defaults to full power. * @param power The RF power of choise. * @return bool for correct parameter supplied */ bool nRF2401A::setRFpower(RF_POWER_T power) { bool ok = false; if (power < INVALID_POWER) { _ctrl_packet_buf.rf_power = power; ok = true; } return ok; } /* Set tranceiver data rate. * Sets the data rate field to either 250 kbit/s or 1 Mbit/s data transfer rate. * Defaults to 250 kbit/s. * @param mode The data rate of choise. * @return bool for correct parameter supplied */ bool nRF2401A::setDataRate(DATA_RATE_T data_rate) { bool ok = false; if ( data_rate < INVALID_RATE) { _ctrl_packet_buf.rf_data_rate = data_rate; ok = true; } return ok; } /** Set RF channel. * Sets the control packet field for channel number. Channel numbers are from 0 to 127 * representing channel frequencies equal to (2400 + channel number) MHz. Defaults to channel 1. * @param ch Channel number, from the range [0, 127]. * @return boolean to confirm valid parameters have been supplied */ bool nRF2401A::setChannel(uint8_t ch) { bool result = false; if (ch < 128) { _ctrl_packet_buf.rf_channel = ch; result = true; } return result; } /* Read a message. * This routine will transfer the data from the receive buffer to the buffer * supplied. It will transfer a number of Bytes equal to the specified length. * @param msg_buf Message buffer. * @param msg_len Length of message, in bytes. * @return boolean to confirm if valid parameters have been supplied */ bool nRF2401A::readMsg( uint8_t *msg_buf, uint8_t msg_len ) { bool result = false; if ((msg_buf != NULL) && (msg_len <= DATA_BUFFER_SIZE)) { for(int i = 0; i < msg_len; i++) { msg_buf[i] = _data_buf[i]; } result = true; } return result; } /* Read a byte from message. * This routine will transfer the data from the receive buffer to the buffer * supplied. It will transfer one Bytes at index buf_index. * @param msg_buf Message body. * @param buf_index index of byte to be read. * @return one Byte of the message buffer */ uint8_t nRF2401A::readMsg_byte( uint8_t buf_index ) { return _data_buf[buf_index]; } /** Send a message. * This routine will transfer the data from the supplied buffer and send * it to the specified address using the current control packet settings. * @param addr The address to send to. * @param addr_len Length of address, in bits. * @param msg_buf Message body. * @param msg_len Length of message, in bits. * @return Reference to the invoked object (for chaining operations). */ bool nRF2401A::sendMsg(nRF2401A::address_t addr, uint8_t addr_len, uint8_t *msg_buf, uint8_t msg_len) { bool sent = false; if ((msg_buf != NULL) && (addr_len <= MAXIMUM_ADDR_LENGTH)) { // point to start of address byte in address uint8_t *aligned_addr = &addr[sizeof(address_t) - (addr_len / 8)]; // wait for tx completion int Toa = (_ctrl_packet_buf.rf_data_rate == nRF2401A::BIT_RATE_1MBITS ? 1 : 4) * (addr_len + msg_len + 1 + 16); switch (_state) { case nRF2401A::STANDBY: //come out of standby into RX mode standby_mode(true); case nRF2401A::TX: //wait while in tx mode while (_state == nRF2401A::TX ) { } case nRF2401A::RX: // switch to transmit transmit_mode(); // push out the bits _data = nRF2401A::TX_MODE; wait_us(Ts); _clk1 = 1; wait_us(Th); _clk1 = 0; // wait Td wait_us(Td); // deassert CS/CE and done... _cs = 0; _ce = 0; // zero control and data lines _clk1 = 0; _data = 0; // wait Td wait_us(Td); // assert CE and wait Tcs2data _ce = 1; wait_us(Tce2data); // push out the address bits for (int i = 0; i < addr_len; i++) { _data = ((0x80 >> (i % 8)) & aligned_addr[i / 8]) ? 0x1 : 0x0; wait_us(Ts); _clk1 = 1; wait_us(Th); _clk1 = 0; } // push out the message bits for (int i = 0; i < msg_len; i++) { _data = ((0x80 >> (i % 8)) & msg_buf[i / 8]) ? 0x1 : 0x0; wait_us(Ts); _clk1 = 1; wait_us(Th); _clk1 = 0; } // reset data _data = 0; // deassert CE will initiate transmission _ce = 0; wait_us(Tsby2txSB + Toa); // switch back to receive receive_mode(); sent = true; break; } } return sent; } /* Put the tranceiver into, or bring out of standby. * Tx mode 10.5mA, RX mode 18mA, Standby 400nA. * @param active set standby state */ nRF2401A::STATE_T nRF2401A::standby_mode(bool active) { switch (_state) { case nRF2401A::TX: //wait while in tx mode while (_state == nRF2401A::TX ) { } case nRF2401A::RX: if (!active) { _state = nRF2401A::STANDBY; _ce = 0; _cs = 0; wait_us(Tsby2rx); } break; case nRF2401A::STANDBY: if (active) { _state = nRF2401A::RX; _ce = 1; _cs = 0; } break; } return _state; } /* Private functions */ /* transmit_mode * * put the transceiver into transmit mode */ void nRF2401A::transmit_mode( void ) { _ce = 0; _cs = 0; wait_us(Td); // assert CS/CE and wait Tcs2data _ce = 0; _cs = 1; wait_us(Tcs2data); _state = nRF2401A::TX; } /* receive_mode * * put the transceiver into receive mode */ void nRF2401A::receive_mode( void ) { wait_us(Td); // assert CS/CE and wait Tcs2data _cs = 1; wait_us(Tcs2data); // push out the bits _data = nRF2401A::RX_MODE; wait_us(Ts); _clk1 = 1; wait_us(Th); _clk1 = 0; // wait Td wait_us(Td); _data = 0; // deassert CS/CE and done... _cs = 0; // wait Td to avoid simultaineous control high wait_us(Td); _ce = 1; // done _state = nRF2401A::RX; } /* dataReadyHandler * * handle the incoming data and call callback */ void nRF2401A::dataReadyHandler(void) { switch (_state) { case nRF2401A::RX: pull(_data_buf); if (_rx_handler != (nRF2401A_rx_handler_t) 0) _rx_handler(_rx_handler_arg); break; default: // todo: error msg break; } return; } /* pull * * Pull the data from the transceiver */ int nRF2401A::pull(uint8_t *buf) { int n = 0; // read from data pin _data.input(); // init signals, go to standby _ce = 1; _cs = 0; _clk1 = 0; // ensure time from DR wait_us(Td); while (_dr1 == 1) { _clk1 = 1; wait_us(Thmin); if(_data.read()) buf[n / 8] |= (0x80 >> (n % 8)); else buf[n / 8] &= ~(0x80 >> (n % 8)); n++; _clk1 = 0; wait_us(Thmin); } // return to active _ce = 1; // reset data pin direction _data.output(); return n; } /* pushCtrl * * Push the data to the transceiver */ void nRF2401A::pushCtrl(uint8_t *buf, uint8_t n_bits, bool is_ctrl) { DigitalOut &ctrl_pin = is_ctrl ? _cs : _ce; // set data to output _data.output(); // zero control and data lines _cs = 0; _ce = 0; _clk1 = 0; _data = 0; // wait Td wait_us(Td); // assert CS/CE and wait Tcs2data ctrl_pin = 1; wait_us(Tcs2data); // push out the bits for (int i = 0; i < n_bits; i++) { _data = ((0x80 >> (i % 8)) & buf[i / 8]) ? 0x1 : 0x0; wait_us(Ts); _clk1 = 1; wait_us(Th); _clk1 = 0; } _data = 0; // wait Td wait_us(Td); // deassert CS/CE and done... ctrl_pin = 0; return; }