Library for the nRF2401A Transceiver
Dependents: nRF2401A_Hello_World nRF2401A_Wireless_Accelerometer_joypad nRF2401A_Gameduino_Invaders
Diff: nRF2401A.cpp
- Revision:
- 0:17cb4be1e37f
- Child:
- 1:8c57f88ff574
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nRF2401A.cpp Fri Oct 04 16:14:49 2013 +0000 @@ -0,0 +1,306 @@ +/* mbed nRF2401A Library + * + * 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. + */ + +#include "nRF2401A.h" + + +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::UNDEF), + _rx_handler((nRF2401A_rx_handler_t) 0), + _rx_handler_arg((void *) 0), + _dr1_isr(InterruptIn(dr1)) { + + // init member variables + _data.output(); + // setup... + _ctrl_packet = (uint8_t *) &_ctrl_packet_buf; + _dr1_isr.rise(this, &nRF2401A::dataReadyHandler); + // ...tranciever 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; + // assure minimum wake up time while assuming tranciever powers up with uP + wait_ms(Tpd2cfgm); + + return; +} + +void nRF2401A::printControlPacket(Serial& port) +{ + for(int i = 0; i < sizeof(_ctrl_packet_buf); i++) + port.printf("%02x ", _ctrl_packet[i]); + port.printf("\n\r"); + return; +} + +void nRF2401A::printDataPacket(Serial& port) +{ + for(int i = 0; i < sizeof(_data_buf); i++) + port.printf("%02x ", _data_buf[i]); + port.printf("\r"); + return; +} + +nRF2401A& nRF2401A::attachRXHandler(nRF2401A_rx_handler_t handler, void *arg) { + + _rx_handler = handler; + _rx_handler_arg = arg; + + return *this; +} + +nRF2401A& nRF2401A::sendMsg(nRF2401A::address_t addr, uint8_t addr_len, uint8_t *msg_buf, uint8_t msg_len) { + + // 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::RX: + // switch to transmit + _ce = 0; + _cs = 0; + wait_us(Td); + // assert CS/CE and wait Tcs2data + _ce = 0; + _cs = 1; + wait_us(Tcs2data); + // 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 + 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 + break; + case nRF2401A::STANDBY: + case nRF2401A::TX: + case nRF2401A::UNDEF: + default: + // can only send in RX mode + break; + } + + return *this; +} + +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; +} + +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; +} + +void nRF2401A::activate(bool active) { + switch (_state) { + case nRF2401A::RX: + if (!active) { + _state = nRF2401A::STANDBY; + _ce = 0; + _cs = 0; + } + break; + case nRF2401A::STANDBY: + if (active) { + _state = nRF2401A::RX; + _ce = 1; + _cs = 0; + } + break; + case nRF2401A::TX: + case nRF2401A::UNDEF: + default: + break; + } + + return; +} + +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; +} + +nRF2401A& nRF2401A::flushControlPacket() { + switch (_state) { + case nRF2401A::UNDEF: + case nRF2401A::RX: + pushCtrl(_ctrl_packet, 15 << 3 ); + _state = nRF2401A::RX; + _ce = 1; + _cs = 0; + break; + case nRF2401A::STANDBY: + pushCtrl(_ctrl_packet, 15 << 3 ); + _state = nRF2401A::STANDBY; + _ce = 0; + _cs = 0; + break; + case nRF2401A::TX: + default: + _ce = 0; + _cs = 0; + } + + return *this; +} \ No newline at end of file