Library for the nRF2401A Transceiver

Dependents:   nRF2401A_Hello_World nRF2401A_Wireless_Accelerometer_joypad nRF2401A_Gameduino_Invaders

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;