Library for the nRF2401A Transceiver

Dependents:   nRF2401A_Hello_World nRF2401A_Wireless_Accelerometer_joypad nRF2401A_Gameduino_Invaders

nRF2401A.h

Committer:
TheChrisyd
Date:
2014-03-09
Revision:
9:7245524e37e4
Parent:
8:fb7cb88e80a4

File content as of revision 9:7245524e37e4:

/** 
 *@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.h"
 */
 
#ifndef _nRF2401A_H
#define _nRF2401A_H

#include <mbed.h>
#include <inttypes.h>

#define DATA_BUFFER_SIZE 32


/** 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 *);

/** nRF2401 Class 
 *
 *  A class supporting the nRF2401A nordic 2.4Ghz transciever
 * Supports shock burts mode only.
 * multi channel mode is not supported as it is not on the breakout header.
 *
 * Example:
 * @code
 * #include "mbed.h"
 * #include "nRF2401A.h"
 * 
 * // comment these out depending on the job of the mbed. If your only using one mbed leave both uncommented. 
 * 
 * #define TX
 * #define RX
 * 
 * // If using the FRDM-KL25Z uncomment this line 
 * //#define FRDMKL25Z
 * 
 * Serial pc(USBTX, USBRX);
 * DigitalOut  myled(LED1);
 * 
 * #ifdef TX
 * #ifdef FRDMKL25Z
 * nRF2401A    rf1(PTD0, PTD5, PTA13, PTC12, PTC13); //ce, cs, dr1, clk1, data
 * #else
 * nRF2401A    rf1(p10, p11, p12, p13, p14);
 * #endif
 * #endif
 * 
 * #ifdef RX
 * #ifdef FRDMKL25Z
 * nRF2401A    rf2(PTD0, PTD5, PTA13, PTC12, PTC13);
 * #else
 * nRF2401A    rf2(p25, p24, p23, p22, p21);
 * #endif
 * 
 * bool rx_recieved = false;
 * 
 * void nRF2401A_rx (void *arg) 
 * {
 *      rx_recieved = true;
 * }
 * #endif
 * int main() 
 * {
 *     wait(0.005);
 *     pc.printf("Hello nRF2401A\n\r");
 *     
 * #ifdef TX  
 *     // initialise the nRF2401A with payload size and address 
 *     rf1.setAddress(0x0, 0x0, 0xa6, 0xa6, 0xa6, 3 << 3);
 *     
 *     rf1.printControlPacket(pc);
 *     rf1.flushControlPacket();
 *     
 *     // initialise variables to use for tranmission 
 *     nRF2401A::address_t rf2_addr = {0x0, 0x0, 0x53, 0x53, 0x53};
 *     uint8_t msg[] = {0x01, 0x01, 0x01, 0x01};
 *     uint32_t *msg32 = (uint32_t *) msg;
 * #endif
 * 
 * #ifdef RX   
 *     // initialise the nRF2401A with payload size and address  
 *     rf2.setAddress(0x0, 0x0, 0x53, 0x53, 0x53, 3 << 3);
 *        
 *     rf2.printControlPacket(pc);
 *     rf2.flushControlPacket();   
 *     
 *     // attach receive callback 
 *     rf2.attachRXHandler(&nRF2401A_rx, 0);
 * #endif
 *       
 *     while(1) 
 *     {
 *     
 * #ifdef TX  
 *         myled = 0;
 *         wait(0.25);  
 *         
 *         // send the message to the nRF2401A 
 *         rf1.sendMsg(rf2_addr, 3 << 3, msg, 4 << 3);
 *         *msg32 += 1;
 *         
 *         myled = 1;
 *         wait(0.25);
 * #endif
 * 
 *         
 * #ifdef RX  
 *         if (rx_recieved)
 *         {      
 *             // send the read buffer directly to the serial port 
 *             rf2.printDataPacket(pc);
 *             
 *             // send a single byte from the read buffer to the serial port 
 *             uint8_t rx_msg = 0;
 *             rx_msg = rf2.readMsg_byte( 0 );
 *             pc.printf("\n\r%d\n\r", rx_msg);
 *             
 *             // read the read buffer , then send to the serial port 
 *             uint8_t rx_buffer[32] = {0};
 *             rf2.readMsg( &rx_buffer[0], 32);
 *             for(int i = 0; i < sizeof(rx_buffer); i++)
 *             {
 *                 pc.printf("%02x ", rx_buffer[i]);
 *             }
 *             pc.printf("\r\n");
 *             
 *             // clear flags and flash the led 
 *             rx_recieved = false;
 *             myled = !myled;
 *         }
 * #endif 
 *       
 *     }
 * }
 * 
 * @endcode
 */


/**
 *
 *
 */
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. for the KL25Z, the Data Ready pin must be on ports A or C
 * @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; }
        
        
 /** 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. */
            INVALID_CRC     /* must be last in the list for error check in setCRCMode */
        } CRC_T;       
         
/** Transceiver state
 * type covering the states of the transceiver
 */
        typedef enum
        { 
            RX,         /**< The tranceiver is in receive mode. Default mode. */
            TX,         /**< The tranceiver is transmitting. */
            STANDBY,    /**< The tranceiver goes into stanby mode. */
            INVALID_STATE
        } STATE_T;       
               
/** Data rate settings.
 * Type covering the allowed settings for the tranceiver data rate.
 */
        typedef enum
        {
            BIT_RATE_250KBITS = 0x0,    /**< 250kbits data rate default */
            BIT_RATE_1MBITS = 0x1,      /**< 1Mbit data rate */
            INVALID_RATE                /* must be last in the list for error check on set data rate */  
        } DATA_RATE_T;

/** RF power settings
 * Type covering the allowed settings for RF power
 */
        typedef enum
        {
            MINUS_TWENTY_DB = 0,     /**< -20dB */
            MINUS_TEN_DB    = 1,     /**< -10dB */
            MINUS_FIVE_DB   = 2,     /**< -5dB */
            ZERO_DB         = 3,     /**< 0dB */
            INVALID_POWER            /* must be last in the list for error check on set RF power */
        } RF_POWER_T;

/** Put the tranceiver into, or bring out of standby.
 * Tx mode 10.5mA, RX mode 18mA, Standby 400nA.
 * @param active set standby state
 */
        STATE_T standby_mode(bool active = true);
        
/**
 *
 */
        typedef uint8_t address_t[5];
        
 /** 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 printControlPacket(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 printDataPacket(Serial& port);
           
/** 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 flushControlPacket();
         
/** 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 attachRXHandler(nRF2401A_rx_handler_t handler, void *arg);
 
/** 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 setDataPayloadLength(uint8_t 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 Reference to the invoked object (for chaining operations).
 */
        bool setAddress(uint8_t addr4, uint8_t addr3, uint8_t addr2, uint8_t addr1, uint8_t addr0, uint8_t n_bits);

/** 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 setCRCMode(CRC_T mode); 
 
 /** Set RF power use.
 * Set the RF power field of the control packet. Defaults to full power.
 * @param power The RF power of choice.
 * @return bool for correct parameter supplied
 */
        bool setRFpower(RF_POWER_T power); 
 
/** 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 setDataRate(DATA_RATE_T data_rate);

        
/** 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 setChannel(uint8_t ch);

/** 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 readMsg( uint8_t *msg_buf, uint8_t msg_len );

/** 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 readMsg_byte( uint8_t buf_index ); //uint8_t *msg_buf, 
         
/** 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 sendMsg(address_t addr, uint8_t addr_len, uint8_t *msg_buf, uint8_t msg_len);
    
    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 
        { 
            RX_MODE = 0x1, 
            TX_MODE = 0x0 
        } TXR_T;
             
/** 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[DATA_BUFFER_SIZE];  /**< */       
        
        STATE_T  _state;
        
        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;
  
/** 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 tranceiver.
 * Read until DR1 goes low.
 * @param buf Data buffer.
 * @return Number of bits read.
 */
        int pull(uint8_t *buf);
 /** Set the tranceiver into transmit mode
 */ 
        void transmit_mode( void );
 /** Set the tranceiver into receive mode
 */       
        void receive_mode( void );
};

#endif