Library for the nRF2401A Transceiver
Dependents: nRF2401A_Hello_World nRF2401A_Wireless_Accelerometer_joypad nRF2401A_Gameduino_Invaders
Diff: nRF2401A.cpp
- Revision:
- 9:7245524e37e4
- Parent:
- 7:22f69cf045d9
--- a/nRF2401A.cpp Sat Oct 26 21:55:20 2013 +0000 +++ b/nRF2401A.cpp Sun Mar 09 11:57:33 2014 +0000 @@ -26,13 +26,26 @@ #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)), + : + _ce(DigitalOut(ce)), _cs(DigitalOut(cs)), _dr1(DigitalIn(dr1)), _clk1(DigitalOut(clk1)), @@ -41,9 +54,14 @@ _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); @@ -67,136 +85,316 @@ return; } -// Public functions +/* Public functions */ -void nRF2401A::printControlPacket(Serial& port) +/* 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) { - for(int i = 0; i < sizeof(_ctrl_packet_buf); i++) - port.printf("%02x ", _ctrl_packet[i]); - port.printf("\n\r"); - return; + 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; } -void nRF2401A::printDataPacket(Serial& port) +/* 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) { - for(int i = 0; i < sizeof(_data_buf); i++) - port.printf("%02x ", _data_buf[i]); - port.printf("\r"); - return; + 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; } -nRF2401A& nRF2401A::flushControlPacket() { +/* 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 *this; + return flush; } -nRF2401A& nRF2401A::attachRXHandler(nRF2401A_rx_handler_t handler, void *arg) +/* 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) { - _rx_handler = handler; - _rx_handler_arg = arg; - return *this; + bool ok = false; + if (handler != NULL) + { + _rx_handler = handler; + _rx_handler_arg = arg; + ok = true; + } + return ok; } -nRF2401A& nRF2401A::readMsg( uint8_t *msg_buf, uint8_t msg_len ) { - for(int i = 0; i < msg_len; i++) +/* 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) { - msg_buf[i] = _data_buf[i]; + _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 *this; + return ok; } -nRF2401A& nRF2401A::readMsg_byte( uint8_t *msg_buf, uint8_t buf_index ) { - *msg_buf = _data_buf[buf_index]; - return *this; +/* 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; } -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); +/* 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; +} - switch (_state) { - case nRF2401A::STANDBY: - //come out of standby into RX mode - standby_mode(true); - case nRF2401A::TX: - //add a 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; +/* 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]; +} - // 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; +/** 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; - } - // 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); + // wait Td + wait_us(Td); + // deassert CS/CE and done... + _cs = 0; + _ce = 0; + + // zero control and data lines _clk1 = 0; - } - // reset data - _data = 0; - // deassert CE will initiate transmission - _ce = 0; - wait_us(Tsby2txSB + Toa); + _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(); - break; + // switch back to receive + receive_mode(); + sent = true; + break; + } } - return *this; + return sent; } - -nRF2401A& nRF2401A::standby_mode(bool active) { +/* 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 @@ -207,6 +405,7 @@ _state = nRF2401A::STANDBY; _ce = 0; _cs = 0; + wait_us(Tsby2rx); } break; case nRF2401A::STANDBY: @@ -217,11 +416,15 @@ } break; } - return *this; + return _state; } -// Private functions +/* Private functions */ +/* transmit_mode + * + * put the transceiver into transmit mode + */ void nRF2401A::transmit_mode( void ) { _ce = 0; _cs = 0; @@ -233,6 +436,10 @@ _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 @@ -256,7 +463,10 @@ _state = nRF2401A::RX; } - +/* dataReadyHandler + * + * handle the incoming data and call callback + */ void nRF2401A::dataReadyHandler(void) { switch (_state) { case nRF2401A::RX: @@ -271,6 +481,10 @@ return; } +/* pull + * + * Pull the data from the transceiver + */ int nRF2401A::pull(uint8_t *buf) { int n = 0; @@ -302,6 +516,10 @@ 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;