XBee modules

Dependencies:   DigiLogger

Fork of XBeeLib by Digi International Inc.

XBee/XBee.h

Committer:
hbujanda
Date:
2015-05-14
Revision:
2:2ee1b6d51df2
Parent:
1:794d1d3e4a08
Child:
3:8662ebe83570

File content as of revision 2:2ee1b6d51df2:

/**
 * Copyright (c) 2015 Digi International Inc.,
 * All rights not expressly granted are reserved.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 * =======================================================================
 */

#if !defined(__DIGI_RADIO_H_)
#define __DIGI_RADIO_H_

#include <stdint.h>
#include "config.h"
#include "Utils/Debug.h"
#include "Frames/AtCmdFrame.h"
#include "FrameHandlers/FrameHandler.h"
#include "FrameHandlers/FH_ModemStatus.h"
#include "FrameBuffer/FrameBuffer.h"
#include "Addresses.h"
#include "RemoteXBee/RemoteXBee.h"
#include "IO/IO.h"

#define MAX_FRAME_HANDLERS      4
#define RESET_TIMEOUT_MS        5000

#define DR_API_FRAME_OVERHEAD   4       /* Start of frame + frame len + checksum */
#define DR_MIN_API_FRAME_LEN    4
#define DR_START_OF_FRAME       0x7E
#define DR_ESCAPE_BYTE          0x7D
#define DR_XON_BYTE             0x11
#define DR_XOFF_BYTE            0x13
#define DR_ESCAPE_XOR_BYTE      0x20

/* TODO, verify these flags work in all modules */
#define DISABLE_RETRIES_AND_ROUTE_REPAIR    0x01
#define ENABLE_APS_ENCRYPTION               0x20
#define USE_EXTENDED_TX_TIMEOUT             0x40

namespace XBeeLib {

/**
 * @defgroup RadioStatus
 * @{
 */
/**
 * RadioStatus 
 */
enum RadioStatus {
    Success         = 0,    /**< Success */
    Failure         = -1,   /**< Failure */
    OpNotSupported  = -2,   /**< Option Not Supported */
};
/**
 * @}
 */

/**
 * @defgroup RadioType
 * @{
 */
/**
 * RadioType 
 */
enum RadioType {
    Unknown     = 0,        /**< Not detected yet */
    XB24_A_S1   = 0x17,     /**< S1 */
    XBP24_A_S1  = 0x18,     /**< S1 */
    XB24_B_S2   = 0x19,     /**< S2 */
    XBP24_B_S2  = 0x1A,     /**< S2 */
    XBP09_D     = 0x1B,     /**< S4 */
    XBP09_XC    = 0x1C,     /**< S3 */
    XBP08_D     = 0x1D,     /**< 868MHz S5 */
    XBP24_B_S2B = 0x1E,     /**< S2B */
    XB24_WF     = 0x1F,     /**< S6 */
    XBP24_C_SMT = 0x21,     /**< XBee PRO SMT S2C */
    XB24_C_SMT  = 0x22,     /**< XBee SMT S2C */
    XBP09_XC_B  = 0x23,     /**< S3B */
    XBP09_B     = 0x23,     /**< S3B */
    XB8         = 0x24,     /**< S8 */
    XB2B_WF_TH  = 0x27,     /**< S6B TH */
    XB2B_WF_SMT = 0x28,     /**< S6B SMT */
    XBP24_C_TH  = 0x2D,     /**< S2C TH */
    XB24_C_TH   = 0x2E,     /**< S2C TH */
};
/**
 * @}
 */

/**
 * @defgroup TxStatus
 * @{
 */
/**
 * TxStatus 
 */
enum TxStatus {
    TxStatusSuccess            = 0,     /**< Success */
    TxStatusAckFail            = 1,     /**< MAC ACK Failure */
    TxStatusCCAFail            = 2,     /**< CCA Failure */
    TxStatusInvDestEP          = 0x15,  /**< Invalid destination endpoint */
    TxStatusNwAckFail          = 0x21,  /**< Network ACK Failure */
    TxStatusNotJoinNw          = 0x22,  /**< Not Joined to Network */
    TxStatusSelfAddr           = 0x23,  /**< Self-addressed */
    TxStatusAddrNotFound       = 0x24,  /**< Address Not Found */
    TxStatusRouteNotFound      = 0x25,  /**< Route Not Found */
    TxStatusBroadSrcFail2Heard = 0x26,  /**< Broadcast source failed to hear a neighbor relay the message */
    TxStatusInvBindTableIdx    = 0x2B,  /**< Invalid binding table index */
    TxStatusResourceError      = 0x2C,  /**< Resource error lack of free buffers, timers, etc. */
    TxStatusAttBroadcWithAPS   = 0x2D,  /**< Attempted broadcast with APS transmission */
    TxStatusAttUnicWithAPSEE0  = 0x2E,  /**< Attempted unicast with APS transmission, but EE=0 */
    TxStatusResourceError2     = 0x31,  /**< TxStatusResourceError2 */
    TxStatusInternalError      = 0x32,  /**< Resource error lack of free buffers, timers, etc. */
    TxStatusPayloadTooLarge    = 0x74,  /**< Data payload too large */
    TxStatusIndirectMsgUnReq   = 0x75,  /**< Indirect message unrequested */
    TxStatusInvalidAddr        = 0xfe,  /**< Invalid Address (Error generated by the library) */
    TxStatusTimeout            = 0xff,  /**< Timeout (Error generated by the library) */
};
/**
 * @}
 */

/**
 * @defgroup PmMode
 * @{
 */
/**
 * PmMode 
 */
enum PmMode {
    SleepDisabled       = 0,  /**< SleepDisabled */
    PinSleep            = 1,  /**< PinSleep */
    PinDoze             = 2,  /**< PinDoze */
    CyclicSeleep        = 4,  /**< CyclicSeleep */
    CyclicSeleepPinW    = 5,  /**< CyclicSeleepPinW */
};
/**
 * @}
 */
 
 /**
 * @defgroup NetworkRole
 * @{
 */
/**
 * NetworkRole 
 */
enum NetworkRole {
    UnknownRole,            /**< Unknown Role */
    Coordinator,            /**< Coordinator */
    Router,                 /**< Router */
    EndDevice,              /**< EndDevice */
};
/**
 * @}
 */

/**
 * @defgroup RadioLocation
 * @{
 */
/**
 * RadioLocation 
 */
enum RadioLocation {
    RadioLocal     = 0,     /**< Local Radio */
    RadioRemote    = 1,     /**< Remote Radio */
};
/**
 * @}
 */
 
/** Parent Class for XBee modules, not to be directly used */
class XBee
{
    private:
    /** wait_for_module_to_reset - waits until a Modem Status packet with a reset status
     * is received, or the timeout expires.
     *
     *  @returns
     *     Success if a Modem Status was received,
     *     Failure otherwise
     */
    RadioStatus wait_for_module_to_reset(volatile uint16_t *rst_cnt_p, uint16_t init_rst_cnt);

    protected:
    /** timer used by local and remote objects */
    static Timer        _timer;

    /** buffer to store the received frames */
    static FrameBuffer _framebuf;

    public:
 
        /**
         * RadioMode 
         */
        enum RadioMode {
            ModeUnknown     = 0,  /**< Unknown */
            ModeAPI1        = 1,  /**< API1 */
            ModeAPI2        = 2,  /**< API2 */
            ModeTransparent = 3,  /**< Transparent */
            ModeBootloader  = 4,  /**< Bootloader */
        };

        /** Class constructor
         * @param tx the TX pin of the UART that will interface the XBee module
         * @param rx the RX pin of the UART that will interface the XBee module
         * @param reset the pin to which the XBee's reset line is attached to, use NC if not available
         * @param rts the RTS pin for the UART that will interface the XBee module, use NC if not available
         * @param cts the CTS pin for the UART that will interface the XBee module, use NC if not available
         * @param baud the baudrate for the UART that will interface the XBee module. Note that the module has to be already configured
         * to this baud rate (ATBD parameter). By default it is configured to 9600 bps
         * */
        XBee(PinName tx, PinName rx, PinName reset = NC, PinName rts = NC, PinName cts = NC, int baud = 9600);
 
        XBee(const XBee& other); /* Intentionally not implemented */
        /** Class destructor */
        virtual ~XBee();
        
        /** init-  initializes object
         * This function must be called just after creating the object so it initializes internal data.
         * @returns
         *         Success if the module has been properly initialized and is ready to process data.
         *         Failure otherwise.
         */
        RadioStatus init();

        /** get_addr64 - returns the 64bit address of the local device
         *
         *  @returns the 64bit address of the local device
         */
        uint64_t get_addr64() const;

        /** get_addr16 - returns the 16bit address of the local device
         *
         *  @returns the 16-bit address of the local device.
         */
        uint16_t get_addr16() const;

        /** get_network_address - gets the 16bit network address of the device
         *
         *  @param addr pointer where the device 16bit network address will be stored
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus get_network_address(uint16_t * const addr);

        /** hardware_reset - performs a hardware reset. The reset GPIO must have
         * been provided to the constructor
         *
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus hardware_reset();

        /** software_reset - performs a firmware reset
         *
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus software_reset();
 
        /** device_reset - performs a hardware reset if there is a GPIO connected to the 
         * reset line of the device. Otherwise, performs a firmware reset.
         *
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
#if defined(UNIT_TEST)
        virtual
#endif
        RadioStatus device_reset();

        /** get_radio_type - returns the type of radio, in most cases the hardware version
         *
         *  @returns the radio type
         */
        RadioType get_radio_type() const;

        /** set_tx_options - sets the transmit options byte, used with the transmit frames.
         *                   Valid flags are:
         *                       - DISABLE_RETRIES_AND_ROUTE_REPAIR
         *                       - ENABLE_APS_ENCRYPTION
         *                       - USE_EXTENDED_TX_TIMEOUT
         *
         *  @param options variable with the option flags
         */
        void set_tx_options(uint8_t options);

        /** set_broadcast_radius - sets the max number of hops for a broadcast msg.
         *                         When set to 0 uses the maximum possible.
         *
         *  @param bc_radius variable with the broadcast radious
         */
        void set_broadcast_radius(uint8_t bc_radius);

        /** get_tx_options - returns the tx options byte configured in the library.
         *
         *  @returns the tx options byte configured in the library.
         */
        uint8_t get_tx_options() const;
        
        /** get_bc_radius - returns the broadcast radius configured in the library.
         *
         *  @returns the broadcast radius configured in the library.
         */
        uint8_t get_bc_radius() const;

        /************************ Configuration member methods *************************/
        /** write_config - write settings to non volatile memory
         *
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus write_config();
       
        /** config_io_sample_destination - configures to which node a remote module will send its IO Samples to.
         * @Note: this will modify 'remote' DH and DL parameters, if the remote node is configured in transparent mode this could lead to unwanted behavior.
         * Consult the module's reference manual for more information.
         *
         *  @param remote remote device that will be sending the IO Samples
         *  @param destination remote device that will be receiving the IO Samples sent by 'remote'
         *  @returns the result of the data transfer
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus config_io_sample_destination(const RemoteXBee& remote, const RemoteXBee& destination);

        /** set_io_sample_rate - configures how often the IO Samples should be sent to the destination (see @ref send_io_sample_to).
         *
         *  @param remote remote device that will be sending the IO Samples
         *  @param seconds the IO Sample sending rate in seconds (granularity is of 1 millisecond). Maximum is 65.535 seconds.
         *  @returns the result of the data transfer
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus set_io_sample_rate(const RemoteXBee& remote, float seconds);

        /** set_power_level - sets the power level at which the radio will transmit
         *
         *  @param level power level at which the radio will transmit
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus set_power_level(uint8_t level);

        /** get_power_level - reads the power level configured in the radio
         *
         *  @param level pointer where the read power level will be stored
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus get_power_level(uint8_t * const level);
        
        /** get_hw_version - gets the hardware version of the radio
         *
         *  @returns the hardware version of the radio
         */
        uint16_t get_hw_version() const;
        
        /** get_fw_version - gets the firmware version of the radio
         *
         *  @returns the firmware version of the radio
         */
        uint16_t get_fw_version() const;

        /** set_node_identifier - configures the Node Identifier string
         *
         *  @param node_id NULL-terminated string with the Node Identifier that will be set on the module. Up to 20 characters length (21 with NULL-terminator).
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus set_node_identifier(const char * const node_id);

        /** get_node_identifier - reads the configured Node Identifier string
         *
         *  @param node_id Pointer to where to store the read Node Identifier, it must point to a buffer with at least 21-bytes length.
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus get_node_identifier(char * const node_id);

        /** start_node_discovery - starts a node discovery operation. The responses
         * have to be processes on the callback function that have to be registered
         * for that purpose
         *
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus start_node_discovery();

#define XBEEZB_ND_OPTION_APPEND_DD          (1 << 0)
#define XBEEZB_ND_OPTION_SELF_RESPONSE      (1 << 1)
#define XBEE802_ND_OPTION_SELF_RESPONSE     (1 << 0)

        /** config_node_discovery - configures the node discovery operation
         *
         *  @param timeout_ms max allowed time for devices in the network to answer
         *                    to the Node Discovery request
         *  @param  options node discovery options (flags)
         *              XBEE802_ND_OPTION_SELF_RESPONSE - to allow the module self responding (802.15.4 only)
         *              XBEEZB_ND_OPTION_SELF_RESPONSE - to allow the module self responding (ZigBee only)
         *              XBEEZB_ND_OPTION_APPEND_DD - to append the DD value to the response (ZigBee only)
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
         RadioStatus config_node_discovery(uint16_t timeout_ms, uint8_t options = 0);

         /** get_config_node_discovery - reads the configuration of the node discovery
          * settings
          *
          *  @param timeout_ms pointer where the node discovery time out value will be stored
          *  @param  options pointer whre the node discovery options (flags) will be saved
          *  @returns
          *     Success if the operation was successful,
          *     Failure otherwise
          */
         RadioStatus get_config_node_discovery(uint16_t * const timeout_ms, uint8_t * const options);

        /** set_timeout - sets the timeout in ms, used by sync methods
         *
         *  @param timeout_ms new timeout in ms
         */
        void set_timeout(uint16_t timeout_ms);
        
        /** get_timeout - gets the timeout in ms configured in the library. This value
         *                is used in sync commands
         *
         *  @returns the configured timeout value in ms
         */
        uint16_t get_timeout() const;

        /* ... */     

        /*********************** send_data member methods ************************/
        /** send_data - sends data to a remote device waiting for the packet
         *                   answer with the result of the operation
         *
         *  @param remote remote device
         *  @param data pointer to the data that will be sent
         *  @param len number of bytes that will be transmitted
         *  @returns the result of the data transfer
         *     TxStatusSuccess if the operation was successful,
         *     the error code otherwise
         */
        virtual TxStatus send_data(const RemoteXBee& remote, const uint8_t *const data, uint16_t len) = 0;
        
        /** send_data_broadcast - sends data to all devices in the network, using the 
         *                        broadcast address. The method waits for the packet
         *                        answer with the result of the operation
         *
         *  @param data pointer to the data that will be sent
         *  @param len number of bytes that will be transmitted
         *  @returns the result of the data transfer
         *     TxStatusSuccess if the operation was successful,
         *     the error code otherwise
         */
        TxStatus send_data_broadcast(const uint8_t *const data, uint16_t len);
        
        /** set_param - sets a parameter in the local radio by sending an AT command and waiting for the response.
         *
         *  @param param parameter to be set.
         *  @param data the parameter value (4 bytes) to be set.
         *  @returns the command response status.
         */
        AtCmdFrame::AtCmdResp set_param(const char * const param, uint32_t data);
        
        /** set_param - sets a parameter in the local radio by sending an AT command and waiting for the response.
         *
         *  @param param parameter to be set.
         *  @param data the parameter value byte array (len bytes) to be set. 
         *  @param len number of bytes of the parameter value. 
         *  @returns the command response status.
         */
        AtCmdFrame::AtCmdResp set_param(const char * const param, const uint8_t * data = NULL, uint16_t len = 0);
        
        /** get_param - gets a parameter from the local radio by sending an AT command and waiting for the response.
         *
         *  @param param parameter to be get.
         *  @param data pointer where the param value (4 bytes) will be stored. 
         *  @returns the command response status.
         */
        AtCmdFrame::AtCmdResp get_param(const char * const param, uint32_t * const data);
      
        /** get_param - gets a parameter from the local radio by sending an AT command and waiting for the response.
         *
         *  @param param parameter to be get.
         *  @param data pointer where the param value (n bytes) will be stored. 
         *  @param len pointer where the number of bytes of the param value will be stored. 
         *  @returns the command response status.
         */
        AtCmdFrame::AtCmdResp get_param(const char * const param, uint8_t * const data, uint16_t * const len);

        /** set_param - sets a parameter in a remote radio by sending an AT command and waiting for the response.
         *
         *  @param remote remote device
         *  @param param parameter to be set.
         *  @param data the parameter value (4 bytes) to be set.
         *  @returns the command response status.
         */
        virtual AtCmdFrame::AtCmdResp set_param(const RemoteXBee& remote, const char * const param, uint32_t data) = 0;
        
        /** set_param - sets a parameter in a remote radio by sending an AT command and waiting for the response.
         *
         *  @param remote remote device
         *  @param param parameter to be set.
         *  @param data the parameter value byte array (len bytes) to be set. 
         *  @param len number of bytes of the parameter value.
         *  @returns the command response status.
         */
        virtual AtCmdFrame::AtCmdResp set_param(const RemoteXBee& remote, const char * const param, const uint8_t * data = NULL, uint16_t len = 0) = 0;
        
        /** get_param - gets a parameter from a remote radio by sending an AT command and waiting for the response.
         *
         *  @param remote remote device
         *  @param param parameter to be get.
         *  @param data pointer where the param value (4 bytes) will be stored. 
         *  @returns the command response status.
         */
        virtual AtCmdFrame::AtCmdResp get_param(const RemoteXBee& remote, const char * const param, uint32_t * const data) = 0;
      
        /** get_param - gets a parameter from a remote radio by sending an AT command and waiting for the response.
         *
         *  @param remote remote device
         *  @param param parameter to be get.
         *  @param data pointer where the param value (n bytes) will be stored. 
         *  @param len pointer where the number of bytes of the param value will be stored. 
         *  @returns the command response status.
         */
        virtual AtCmdFrame::AtCmdResp get_param(const RemoteXBee& remote, const char * const param, uint8_t * const data, uint16_t * const len) = 0;

#if defined(ENABLE_PM_SUPPORT)
        /** set_pm_control - sets the operational mode of the Power Management on
         *                   the radio and registers the GPIOs used to handle the
         *                   Power Management
         *
         *  @param mode operational mode of the power management
         *  @param on_sleep pin used to detect the on/sleep status of the module
         *  @param sleep_rq pin used to request the module to go to sleep (when pin
         *         sleep mode is used
         *  @returns the result of the configuration operation
         *     Success if the operation was successful,
         *     Failure otherwise
         */
         RadioStatus set_pm_control(PmMode mode, PinName on_sleep = NC, PinName sleep_rq = NC);

        /** get_pm_mode - gets the power management mode programmed in the radio.
         *
         *  @param mode pointer where the read mode will be stored.
         *  @returns the result of the configuration operation
         *     Success if the operation was successful,
         *     Failure otherwise
         */
         RadioStatus get_pm_mode(PmMode *mode);

        /** config_pm_timing - configures the power management timing parameters.
         *
         *  @param before_sleep_ms number of miliseconds of inactivity before the radio will
         *                         automatically go to sleep again (when using cyclic sleep).
         *  @param total_sleep_period_ms time interval in ms the radio will be sleeping. Once
         *                               this time passes, the radio will wakeup, will check for
         *                               packets and will wait before_sleep_ms of inactivity
         *                               before entering again in sleep mode.
         *  @returns the result of the configuration operation
         *     Success if the operation was successful,
         *     Failure otherwise
         */
         RadioStatus config_pm_timing(uint32_t before_sleep_ms, uint32_t total_sleep_period_ms);

        /** enter_sleep_mode - sets the radio into low power mode. If the pm working mode
         *                     is pin-sleep, then it will use the GPIO, otherwise, it will
         *                     use the serial interface.
         *
         *  @note the method does not wait until the radio enters in sleep mode, it returns
         *        without making any verification.
         *  @returns the result of the operation
         *     Success if the operation was successful,
         *     Failure otherwise
         */
         RadioStatus enter_sleep_mode();

        /** exit_sleep_mode - for the pm mode called pin-sleep, sets the radio into active power
         *                    using the corresponding GPIO.
         *
         */
         void exit_sleep_mode();

        /** is_sleeping - checks if the radio is sleeping or if its active.
         *
         *  @returns true if the radio is sleeping, false otherwisw
         */
         bool is_sleeping();
         
        /** register_wakeup_cb - registers the callback function that will be called
         *                       when the radio wakes up from sleep mode.
         *
         *  @param f function pointer with the callback function
         */
        void register_wakeup_cb(void (*f)(void));

        /** unregister_wakeup_cb - removes the wakeup callback */
        void unregister_wakeup_cb();
#endif  /* defined(ENABLE_PM_SUPPORT) */

        /** process_rx_frames - method that process the frames queued in the reception
         *                      buffer. Calls the process_frame_data method of the frame
         *                      handlers registered
         *
         *  @returns Number of dropped frames since latest call to this method.
         */
        uint32_t process_rx_frames();

        /** register_modem_status_cb - registers the callback function that will be called
         * when a Modem Status packet is received
         *
         *  @param function function pointer with the callback function
         */
        void register_modem_status_cb(modem_status_cb_t function);

        /** unregister_modem_status_cb - removes the Modem Status reception callback */
        void unregister_modem_status_cb();

    protected:

        enum RadioProtocol {
            None,
            ZigBee,
            Raw_802_15_4,
#ifdef EXTRA_XBEE_PROTOCOLS
            XBeeWiFi,
            DigiMesh,
            SmartEnergy,
            DigiPoint,
            ZNet,
#endif
        };
        /** send_byte_escaping_if - sends a byte, through the serial interface, to 
         * the radio, escaping the byte if the working mode of the radio is API2.
         *
         *  @param line PWM line being set
         *  @param data the byte that will be send to radio
         */
        void send_byte_escaping_if(uint8_t data);
    
        /** uart_read_cb - serial interface callback, called when data is received on
         * the serial port. The function parses the incoming data and, when a good
         * frame is detected, saves it in the frame list
         */
        void uart_read_cb();
    
        /** get_this_api_frame - searches in the FrameBuffer for an incoming frame
         *                       with frameid equal to id and frame type equal to type
         *                       or type2. If after timeout the frame hast not been found,
         *                       returns.
         *
         *  @param id id of the frame we are looking for.
         *  @param type tye type we expect the frame to be.
         *  @param type2 alternative valid type, if provided.
         *  @returns a pointer to the frame found in the FrameBuffer or a null pointer if 
         *           the frame has not been found and the timeout expired.
         */
        ApiFrame * get_this_api_frame(uint8_t id, ApiFrame::ApiFrameType type, 
                    ApiFrame::ApiFrameType type2 = ApiFrame::Invalid);

        /** send_api_frame - method to send, over the serial port, an API frame
         * 
         * @param frame pointer to the frame that will be sent.
         */
#if defined(UNIT_TEST)
        virtual
#endif
        void send_api_frame(ApiFrame *frame);

        /** update_radio_status - method called when a modem status frame is received
         *  to update the internal status variables of the library.
         *  @note This is not a pure virtual function because it can be called while 
         *        the object is being constructed and we need the implementation of the
         *        base class.         
         *
         *  @param status byte with the status received in the modem status frame
         */
        virtual void radio_status_update(AtCmdFrame::ModemStatus modem_status);
        
        /** Method used internaly by the derived classes to transmit data to 
         * remote nodes, waiting for the answer from the device
         *
         *  @param frame frame that will be sent to the radio (have to be a
         *         proper transmit frame
         *  @returns the result of the data transfer
         *     TxStatusSuccess if the operation was successful,
         *     the error code otherwise
         */
        TxStatus send_data(ApiFrame *frame);

        /** send_at_cmd - sends an AT command to the radio and waits for the response.
         *
         *  @param frame api frame with the command and command params.
         *  @param buf pointer where the param response (n bytes) will be stored. 
         *  @param len pointer where the number of bytes of the param response will be stored. 
         *  @param radio_location radio location, either RadioLocal or RadioRemote. 
         *  @param reverse reverse the byte ordering of the response saved in buf. 
         *  @returns the command response status.
         */
        AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame,
                    uint8_t *const buf, uint16_t *const len, RadioLocation radio_location = RadioLocal, bool reverse = true);
                    
        /* send_at_cmd - methods used internally by other methods */
        AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame);
        AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame, uint8_t *data);
        AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame, uint16_t *data);
        AtCmdFrame::AtCmdResp send_at_cmd(AtCmdFrame *frame, uint32_t *data);
        
#if defined(ENABLE_PM_SUPPORT)
        /** Sets the radio into low power mode. This method is used by enter_sleep_mode() */
        RadioStatus sleep_now();
#endif  /* defined(ENABLE_PM_SUPPORT) */

        /** register_frame_handler - registers an object to handle incoming frames from
         *                           the radio.
         *  @note For any type of frame more than one handler can be registered and all
         *        of them are called, sequentially, when a frame of that type arrives.
         *
         *  @param handler pointer to the frame handler object
         *  @returns the result of the registration
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus register_frame_handler(FrameHandler *const handler);

        /** unregister_frame_handler - removes a previously registered frame handler
         *
         *  @param handler pointer to the frame handler object
         *  @returns the result of the unregister operation
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus unregister_frame_handler(FrameHandler *const handler);

        /** get_radio_protocol - returns the RF protocol that the connected module uses
         *                       based on its firmware and hardware versions
         *
         *  @returns a RadioProtocol enum.
         */
        RadioProtocol get_radio_protocol(void) const;

        /** get_iosample - forces an io_sample read (reads all digital and analog inputs)
         *
         *  @param remote remote device
         *  @param io_sample buffer where the io_sample response is copied
         *  @param len pointer where the length of the io_sample response is stored
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus get_iosample(const RemoteXBee& remote, uint8_t * const io_sample, uint16_t * const len);

        void _get_remote_node_by_id(const char * const node_id, uint64_t * addr64, uint16_t * addr16);

        /** check_radio_flow_control - checks that the radio has the CTS "D7" and RTS "D6" pins configured
         *                       according to the serial hardware flow control selected by the user
         *
         *  @returns true if check success.
         */
        bool check_radio_flow_control();

        /** serial hardware flow control selected by the user (RTSCTS, RTS,CTS) */
        SerialBase::Flow _serial_flow_type;

        /** Operating mode of the module (API1, API2,...) */
        RadioMode   _mode;

        /** Type of radio, mainly the hardware version, but may differ in some cases */
        RadioType   _type;
        
        /** Hardware version value of the radio */
        uint16_t    _hw_version;

        /** Firmware version value of the radio */
        uint16_t    _fw_version;

        /** Timeout in ms for sync operations (when we wait for a response) */
        uint16_t    _timeout_ms;     

        /** Device 64 bit address (SH, SL) */
        uint64_t      _dev_addr64;

        /** Device 16 bit address (MY) */        
        uint16_t    _dev_addr16;
       
        /** Serial Interface, use RawSerial as we dont use the streams */
        RawSerial   *_uart;

        /** IO connected to the radio reset line */
        DigitalOut  *_reset;         
        
        /** Transmit options byte */
        uint8_t     _tx_options;

        /** Broadcast radius, number of hops a broadcast transmission can occur.
         *  When set to 0 it will use the maximum */
        uint8_t     _bc_radius;
        /** Array of frame handler pointers. We use an array instead of a vector or other 
         *  data structure to save memory and avoid dynamic memory allocation, to avoid 
         *  memory fragmentation */
        FrameHandler *_fhandlers[MAX_FRAME_HANDLERS];

        /** Hardware reset counter, automatically updated by the library */
        volatile uint16_t    _hw_reset_cnt;

        /** Watchdog reset counter, automatically updated by the library */
        volatile uint16_t    _wd_reset_cnt;

        uint16_t    _reset_timeout;

        /** Frame handler used for the Modem Status packets. Automatically registered when a callback
         *  function is registered */
        FH_ModemStatus  *_modem_status_handler;

        /** Latest modem status received */
        AtCmdFrame::ModemStatus _modem_status;

        /** Library is initializing */
        bool _initializing;

#if defined(ENABLE_PM_SUPPORT)
        /* Power Management mode used by the radio */
        PmMode      _pm_mode;
        /** IO connected to the radio on_sleep line */
        InterruptIn *_on_sleep;         
        /** IO connected to the radio sleep_req line */
        DigitalOut  *_sleep_req;
#endif
};

}   /* namespace XBeeLib */

#endif /* defined(__DIGI_RADIO_H_) */