Library for the nRF2401A Transceiver
Dependents: nRF2401A_Hello_World nRF2401A_Wireless_Accelerometer_joypad nRF2401A_Gameduino_Invaders
nRF2401A.cpp
- Committer:
- TheChrisyd
- Date:
- 2013-10-05
- Revision:
- 3:7ae3a5e53a1f
- Parent:
- 1:8c57f88ff574
- Child:
- 4:e8523ef6e472
File content as of revision 3:7ae3a5e53a1f:
/** *@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" 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); // ...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; // assure minimum wake up time while assuming tranceiver 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; }