Library for the nRF2401A Transceiver
Dependents: nRF2401A_Hello_World nRF2401A_Wireless_Accelerometer_joypad nRF2401A_Gameduino_Invaders
Diff: nRF2401A.h
- Revision:
- 0:17cb4be1e37f
- Child:
- 1:8c57f88ff574
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nRF2401A.h Fri Oct 04 16:14:49 2013 +0000 @@ -0,0 +1,340 @@ +/* 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 <mbed.h> +#include <inttypes.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 Thmin 5 /**< */ +#define Tclk2data 1 /**< */ + +/** Servo control class, based on a PwmOut + * + * Example: + * @code + * #include "mbed.h" + * #include "nRF2401A.h" + * + * DigitalOut myled(LED1); + * nRF2401A rf1(p10, p11, p12, p13, p14); + * nRF2401A rf2(p21, p22, p23, p24, p25); + * + * Serial pc(USBTX, USBRX); + * + * int main() { + * + * wait(0.005); + * + * pc.printf("Hello nRF2401A\n\r"); + * + * rf1.setDataPayloadLength(4 << 3) + * .setAddress(0x0, 0x0, 0xa6, 0xa6, 0xa6, 3 << 3) + * .setCRCMode(nRF2401A::NO_CRC) + * .setDataRate(nRF2401A::BIT_RATE_250KBITS) + * .setChannel(0x02); + * + * rf1.printControlPacket(pc); + * + * rf2.setDataPayloadLength(4 << 3) + * .setAddress(0x0, 0x0, 0x53, 0x53, 0x53, 3 << 3) + * .setCRCMode(nRF2401A::NO_CRC) + * .setDataRate(nRF2401A::BIT_RATE_250KBITS) + * .setChannel(0x02); + * + * rf2.printControlPacket(pc); + * + * rf1.flushControlPacket(); + * rf2.flushControlPacket(); + * + * nRF2401A::address_t rf2_addr = {0x0, 0x0, 0x53, 0x53, 0x53}; + * uint8_t msg[] = {0x01, 0x01, 0x01, 0x01}; + * uint32_t *msg32 = (uint32_t *) msg; + * + * while(1) { + * + * rf1.sendMsg(rf2_addr, 3 << 3, msg, 4 << 3); + * *msg32 += 1; + * + * myled = 1; + * wait(0.25); + * + * rf2.printDataPacket(pc); + * + * myled = 0; + * wait(0.25); + * } + * } + * @endcode + */ + +/** ISR handler prototype for receiving messages. + * A function of this type is registered and called when the DR pin on the + * nRF tranciever signals the reception of a message. The void * argument + * is likewise supplied when registering and is returned at call time. + */ +typedef void (*nRF2401A_rx_handler_t)(void *); + +/** + * + * + */ +class nRF2401A +{ + public: + /** Class constructor. + * The constructor assigns the specified pinout, attatch the + * DR1 to a pin interrupt and sets up inmutable control packet + * fields. + * \param ce Chip Enable (CE) pin of the nRF2401A. + * \param c2 Chip Select (CS) pin of the nRF2401A. + * \param dr1 Data Ready 1 (DR1) pin of the nRF2401A. + * \param clk1 Clock 1 (CLK1) pin of the nRF2401A. + * \param data Data (DATA) pin of the nRF2401A. + */ + nRF2401A(PinName ce, + PinName cs, + PinName dr1, + PinName clk1, + PinName data); + + /** Class destructor. + * Pretty much useless in the embedded world... + */ + virtual ~nRF2401A() { return; } + + /** 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 Reference to the invoked object (for chaining operations). + */ + nRF2401A& setDataPayloadLength(uint8_t n) + { + _ctrl_packet_buf.channel_1_data_payload_len = n; + return *this; + } + + /** Set the address of channel 1. + * The channel address is a up to 40 bit number identifying the tranciever. + * \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 Reference to the invoked object (for chaining operations). + */ + nRF2401A& setAddress(uint8_t addr4, uint8_t addr3, uint8_t addr2, uint8_t addr1, uint8_t addr0, uint8_t n_bits) + { + _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; + + return *this; + } + + /** CRC settings. + * Type covering the allowed settings for use of CRC. + */ + typedef enum + { + NO_CRC = 0x0, /**< Do not use CRC. */ + CRC_8 = 0x1, /**< Use a 8-bit CRC. */ + CRC_16 = 0x3 /**< Use a 16-bit CRC. */ + } CRC_T; + + /** Set CRC use. + * Set the CRC mode field of the control packet. + * \param mode The CRC mode of choise. + * \return Reference to the invoked object (for chaining operations). + */ + nRF2401A& setCRCMode(CRC_T mode) + { + _ctrl_packet_buf.crc_config = mode; + return *this; + } + + /** Data rate settings. + * Type covering the allowed settings for the tranciever data rate. + */ + typedef enum + { + BIT_RATE_250KBITS = 0x0, /**< */ + BIT_RATE_1MBITS = 0x1 /**< */ + } DATA_RATE_T; + + /** Set tranciever data rate. + * Sets the data rate field to either 250 kbit/s or 1 Mbit/s data transfer rate. + * \param mode The data rate of choise. + * \return Reference to the invoked object (for chaining operations). + */ + nRF2401A& setDataRate(DATA_RATE_T data_rate) + { + _ctrl_packet_buf.rf_data_rate = data_rate; + return *this; + } + + /** 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. + * \param ch Channel number, from the range [0, 127]. + * \return Reference to the invoked object (for chaining operations). + */ + nRF2401A& setChannel(uint8_t ch) + { + _ctrl_packet_buf.rf_channel = ch; + return *this; + } + + /** Send the control packet to the nRF2401A. + * This function transfer the control packet image to the nRF2401A. + * \return Reference to the invoked object (for chaining operations). + */ + nRF2401A& flushControlPacket(); + + /** + * + */ + void activate(bool active = true); + + /** + * + */ + typedef uint8_t address_t[5]; + + /** 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). + */ + nRF2401A& sendMsg(address_t addr, uint8_t addr_len, uint8_t *msg_buf, uint8_t msg_len); + + /** Register a receive action callback. + * Attach a callback that will be called when the tranciever 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). + */ + nRF2401A& attachRXHandler(nRF2401A_rx_handler_t handler, void *arg); + + void printControlPacket(Serial& port); + void printDataPacket(Serial& port); + + private: + + DigitalOut _ce; /**< Chip Enable pin. */ + DigitalOut _cs; /**< Chip select pin. */ + DigitalIn _dr1; /**< Data Ready 1 pin. */ + DigitalOut _clk1; /**< Clock 1 pin. */ + DigitalInOut _data; /**< Data pin. */ + + /** + * + */ + typedef enum + { + UNDEF, /**< The start state. */ + RX, /**< The tranciever is in receive mode. */ + TX, /**< The tranciever is transmitting. */ + STANDBY /**< The tranciever goes into stanby mode. */ + } STATE_T; + + STATE_T _state; + + /** Contol packet data. + * + */ + struct nRF2401A_ctrl_packet_t + { + uint8_t channel_2_data_payload_len; /**< */ + uint8_t channel_1_data_payload_len; /**< */ + uint8_t channel_2_address[5]; /**< */ + uint8_t channel_1_address[5]; /**< */ + + uint8_t crc_config : 2; /**< */ + uint8_t channel_address_len : 6; /**< */ + + uint8_t rf_power : 2; /**< */ + uint8_t xo_frequency : 3; /**< */ + uint8_t rf_data_rate : 1; /**< */ + uint8_t communication_mode : 1; /**< */ + uint8_t enable_dual_channel_mode : 1; /**< */ + + uint8_t txr_switch : 1; /**< */ + uint8_t rf_channel : 7; /**< */ + + } _ctrl_packet_buf; /**< */ + + uint8_t *_ctrl_packet; /**< */ + + uint8_t _data_buf[32]; /**< */ + + nRF2401A_rx_handler_t _rx_handler; /**< */ + void *_rx_handler_arg; /**< */ + + /** Receive ISR. + * This handler is attached to the rising flank of the DR1 pin. It + * will thus be called when the nRF2401A receives a packet in ShockBurst + * mode (the mode used). It will in turn call the attached handler. + */ + void dataReadyHandler(void); + + /** + * + */ + InterruptIn _dr1_isr; + + /* + * + */ + typedef enum { RX_MODE = 0x1, TX_MODE = 0x0 } TXR_T; + + /** Write to the data bus. + * Write n_bits bits on the DATA line. + * \param buf Data buffer. + * \param n_bits Number of bits to transfer. + * \param is_ctrl True if the tranfered data is control word, false if data. + */ + void pushCtrl(uint8_t *buf, uint8_t n_bits, bool is_ctrl = true); + + /** Read a message from the tranciever. + * Read until DR1 goes low. + * \param buf Data buffer. + * \return Number of bits read. + */ + int pull(uint8_t *buf); +}; \ No newline at end of file