/**
 * 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 */
};
/**
 * @}
 */

/**
 * @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 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:
    /** buffer to store the received frames */
    static FrameBuffer _framebuf_app;
    static FrameBuffer _framebuf_syncr;

    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;

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

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

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

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

        /** enable_network_encryption - Enable network encryption.
         *
         *  @param enable whether to enable this feature or not
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus enable_network_encryption(bool enable);

        /** set_network_encryption_key - Sets the 128-bit AES key used for encryption and decryption. Setting it to 0 will cause the coordinator to transmit the network key in the clear to joining devices, and will cause joining devices to acquire the network key in the clear when joining.
         *  It is not recommended to set the key programmatically, because it could be read through the raw serial port bits.
         *  @param key pointer to the 128-bit AES key
         *  @param length size of the buffer pointed by 'key'
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
        RadioStatus set_network_encryption_key(const uint8_t * const key, const uint16_t length);

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

        /** is_node_discovery_in_progress - checks if node discovery is in progress.
         *  @returns true if node discovery is in progress, false otherwise
         */
        bool is_node_discovery_in_progress();

#define XBEEZB_ND_OPTION_APPEND_DD          (1 << 0)
#define XBEEZB_ND_OPTION_SELF_RESPONSE      (1 << 1)
#define XBEE802_ND_OPTION_SELF_RESPONSE     (1 << 0)
#define XBEEDM_ND_OPTION_APPEND_DD          (1 << 0)
#define XBEEDM_ND_OPTION_SELF_RESPONSE      (1 << 1)
#define XBEEDM_ND_OPTION_INCLUDE_RSSI       (1 << 2)

        /** config_node_discovery - configures the node discovery operation
         *
         *  @param backoff_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)
         *              XBEEDM_ND_OPTION_INCLUDE_RSSI - to include RSSI information in response (DigiMesh only)
         *              XBEEDM_ND_OPTION_SELF_RESPONSE - to allow the module self responding (DigiMesh only)
         *              XBEEDM_ND_OPTION_APPEND_DD - to append the DD value to the response (DigiMesh only)
         *  @returns
         *     Success if the operation was successful,
         *     Failure otherwise
         */
         RadioStatus config_node_discovery(uint16_t backoff_ms, uint8_t options = 0);

         /** get_config_node_discovery - reads the configuration of the node discovery
          * settings
          *
          *  @param backoff_ms pointer where the configured node discovery back-off time 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 backoff_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
         *
         *  @param remote remote device
         *  @param data pointer to the data that will be sent
         *  @param len number of bytes that will be transmitted
         *  @param syncr if true, method waits for the packet answer with the result of the operation
         *  @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, bool syncr = true) = 0;

        /** send_data_broadcast - sends data to all devices in the network, using the broadcast address.
         *
         *  @param data pointer to the data that will be sent
         *  @param len number of bytes that will be transmitted
         *  @param syncr if true, method waits for the packet answer with the result of the operation
         *  @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, bool syncr = true);

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

        /** process_rx_frames - method that processes 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:

#define EXTRA_XBEE_PROTOCOLS

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

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

        /** get_AI - reads the AI parameter.
         *
         *  @returns
         *      -1 if an error occurred when reading AI.
         *      0-0xFF the AI value.
         */
        int get_AI(void);

        /** get_node_discovery_timeout - gets the node discovery timeout
          *
          *  @param timeout_ms pointer where the node discovery timeout value will be stored
          *  @param wait_for_complete_timeout pointer where the function will store if the operator
          *                                   has to wait for the complete nd timeout after issuing 
          *                                   a directed nd request
          *  @returns
          *     Success if the operation was successful,
          *     Failure otherwise
          */
        virtual RadioStatus get_node_discovery_timeout(uint16_t * const timeout_ms) = 0;
        virtual RadioStatus get_node_discovery_timeout(uint16_t * const timeout_ms, bool * const wait_for_complete_timeout) = 0;

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

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

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

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

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

        /** Timer used for node discovery */
        Timer _nd_timer;

        /** node discovery timeout */
        int _nd_timeout;

        /** If a _get_remote_node_by_id() is in progress, this keeps the expected frame id */
        uint8_t _node_by_ni_frame_id;
};

}   /* namespace XBeeLib */

#endif /* defined(__DIGI_RADIO_H_) */



