/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                 */
/* file: Discover.h                                                */
/*                                                                 */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                 */
/* description: Discover header file                    		   */
/*                                                                 */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                 */
/* Copyright (c) 2018 Acroname Inc. - All Rights Reserved          */
/*                                                                 */
/* This file is part of the BrainStem release. See the license.txt */
/* file included with this package or go to                        */
/* https://acroname.com/software/brainstem-development-kit         */
/* for full license details.                                       */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifndef _aDiscover_H_
#define _aDiscover_H_

#include "aDefs.h"
#include "aError.h"

#define aDISCOVERY_DEFAULT_INTERFACE                        (0U)

/////////////////////////////////////////////////////////////////////
/// Link Discovery Interface.

/** \defgroup aDiscovery Link Discovery Interface
 * \ref aDiscovery "aDiscovery.h" provides an interface for locating BrainStem modules
 * accross multiple transports. It provides a way to find all modules
 * for a give transport as well as specific modules by serial number,
 * or first found.
 */

static const char* const DISCOVERY_BEACON_FILTER = "BrainStem2-Discovery";

/////////////////////////////////////////////////////////////////////
/// Enum #linkType.

/**
 * The linkType enum specifies the connection transport type.
 */
typedef enum {
    INVALID,        ///< - Undefined link type.
    USB,            ///< - USB link type.
    TCPIP,          ///< - TCPIP link type.
    SERIAL,         ///< - Serial link type.
    AETHER,         ///< -   aEther client link type.
    AETHER_USB,     ///< -   aEther USB server link type.
    AETHER_TCPIP,   ///< -   aEther TCPIP server link type.
    AETHER_SERIAL,  ///< -   aEther SERIAL server link type.
} linkType;


/////////////////////////////////////////////////////////////////////
/// Struct #linkSpec.

/**
 * The linkSpec contains the necessary information for connecting to a BrainStem
 * module.
 */
typedef struct linkSpec {
    /**
     * \name Module Specifics
     * @{
     */
    linkType type; /**< The transport type of this spec. */
    uint32_t serial_num; /**< The serial number of the module */
    uint32_t module; /**< The module address */
    uint32_t router; /**< The BrainStem network router address */
    uint32_t router_serial_num; /**< The BrainStem network router serial number */
    uint32_t model; /**< The model type */
    /** @} */

    
    /** \name Transport Specifics
     *
     * The transport specifics are contained in a union named \ref t.
     * The union contains either of two structs usb or ip.
     *
     * The USB struct contains a single element:
     *   - **usb_id** - *uint32_t* the usb_id of the BrainStem module.
     *   .
     *
     * The TCP/IP struct contains two elements:
     *   - **ip_address** - *uint32_t* the IP4 address of the module.
     *   - **ip_port** - *uint32_t* the TCP port for socket connection on the module.
     *   .
     * The Serial struct contains two elements:
     *   - **buadrate** - *uint32_t* the serial port baudrate
     *   - **port** - *char** the serial port path or name
     *
     * Address this member like ``spec.t.usb`` or ``spec.t.ip``
     * @{
     */
    union {
        struct {
            uint32_t usb_id;
        } usb;
        struct {
            uint32_t ip_address;
            uint32_t ip_port;
        } ip;
        struct {
            uint32_t baudrate;
            char port[100];
        } serial;
    } t; /**< transport union member. */
    /** @} */
} linkSpec;

/// Typedef #bContinueSearch

/**
* Semantic typdef for continuing the search for modules.
*/
typedef bool bContinueSearch;


/////////////////////////////////////////////////////////////////////
/// Typedef #aDiscoveryModuleFoundProc.

/**
 * This procedure is the callback to determine whether modules match the ones
 * we are looking for.
 *
 *  - **spec** - *linkSpec* passed into the continueSearch callback.
 *  - **bSuccess** - *bool* Filled with true if a module was found. false otherwise
 *  - **vpRef** - *void\* A reference to environment, or other element needed within the
 *              callback.
 *  - **return** *bContinueSearch* - Return true to continue, false to stop the search.
 */
typedef bContinueSearch (*aDiscoveryModuleFoundProc)(const linkSpec* spec,
                                                      bool* bSuccess,
                                                      void* vpRef);

#ifdef __cplusplus
extern "C" {
#endif

    
    
    
    
    /// Function #aDiscovery_EnumerateModules

    /**
     * Enumerates the discoverable modules for the given link type. Takes
     * a #aDiscoveryModuleFoundProc which will determine when to stop the
     * enumeration.
     *
     * \param type The trasport type on which search for devices. Valid #linkType "linktypes" are accepted
     * \param cbFound The #aDiscoveryModuleFoundProc to call for each module found.
     * \param vpCBRef The vpRef passed into the callback.
     * \param networkInterface Defines the network interface to use when multiple are present.
     *            A value of 0 or LOCALHOST_IP_ADDRESS will result in local searches only.
     *            Values other than this will have firewall implications.
     *
     * \return Returns the number of modules found.
     */
    aLIBEXPORT uint8_t aDiscovery_EnumerateModules(
                            const linkType type,
                            aDiscoveryModuleFoundProc cbFound,
                            void* vpCBRef,
                            const uint32_t networkInterface);
    
    
    /// Function #aDiscovery_Enumerate_aEtherModules
    
    /**
     * Enumerates the discoverable modules for the NETWORK linkType.
     * aDiscovery_EnumerateModules calls this function when the linkType = NETWORK
     * Takes a #aDiscoveryModuleFoundProc which will determine when to stop the
     * enumeration.
     *
     * \param cbFound The #aDiscoveryModuleFoundProc to call for each module found.
     * \param vpCBRef The vpRef passed into the callback.
     * \param networkInterface Defines the network interface to use when multiple are present.
     *            A value of 0 or LOCALHOST_IP_ADDRESS will result in local searches only.
     *            Values other than this will have firewall implications.
     *
     * \return Returns the number of modules found.
     */
    aLIBEXPORT uint8_t aDiscovery_Enumerate_aEtherModules(
                          aDiscoveryModuleFoundProc cbFound,
                          void* vpCBRef,
                          const uint32_t networkInterface);
    
    
    /// Function #aDiscovery_GetIPv4Interfaces
    
    /**
     * Populates a list with all of the available IPv4 Interfaces.
     *
     * \param list Array to be populated with interfaces
     * \param listSize The number of elements the array can store
     *
     * \return The number of interfaces that were added to the array
     */
    aLIBEXPORT uint32_t aDiscovery_GetIPv4Interfaces(
                            uint32_t list[],
                            uint32_t listSize);
    
    
    /// Function #aDiscovery_ConvertIPv4Interface
    
    /**
     * Converts a IPv4 integer to a string.  This is a simple wrapper around inet_ntop.
     *
     * \param networkInterface Array to be populated with interfaces
     *
     * \return The length of the character string that was created in the buffer (strnlen).
     */
    aLIBEXPORT int32_t aDiscovery_ConvertIPv4Interface(
                                    uint32_t networkInterface, 
                                    char buffer[],
                                    uint32_t bufferSize);

    
    /// Function #aDiscovery_FindModule

    /**
     * Finds the module with the given serial number on the given transport type.
     *
     * \param type The trasport type on which search for devices. Valid #linkType "linktypes" are accepted
     * \param serialNum The serial number of the Module to find.
     * \param networkInterface Defines the network interface to use when multiple are present.
     *            A value of 0 or LOCALHOST_IP_ADDRESS will result in local searches only.
     *            Values other than this will have firewall implications.
     * \return A pointer to the linkSpec for the requested module if found or NULL otherwise. This call
     *         Allocates memory that must be freed by a call to #aLinkSpec_Destroy.
     */
    aLIBEXPORT linkSpec* aDiscovery_FindModule(const linkType type,
                                               const uint32_t serialNum,
                                               const uint32_t networkInterface);

    /// Function #aDiscovery_FindFirstModule

    /**
     * Finds the first module found on the given transport.
     *
     * \param type The transport type on which search for devices. Valid #linkType "linktypes" are accepted
     * \param networkInterface Defines the network interface to use when multiple are present.
     *            A value of 0 or LOCALHOST_IP_ADDRESS will result in local searches only.
     *            Values other than this will have firewall implications.
     * \return A pointer to the linkSpec for the requested module if found or NULL otherwise. This call
     *         Allocates memory that must be freed by a call to #aLinkSpec_Destroy.
     */
    aLIBEXPORT linkSpec* aDiscovery_FindFirstModule(const linkType type,
                                                    const uint32_t networkInterface);
    
    
    /// Function #aLinkSpec_Create

    /**
     * Creates a linkSpec object with transport set to the given type.
     *
     * \param type The transport type on which search for devices. Valid #linkType "linktypes" are accepted
     *
     * \return A pointer to the linkSpec for the requested module or NULL if there was an error allocating memory.
     *         This call Allocates memory that must be freed by a call to #aLinkSpec_Destroy.
     */
    aLIBEXPORT linkSpec* aLinkSpec_Create(const linkType type);

    /// Function #aLinkSpec_Copy
    
    /**
     * Creates a copy of the provide link spec
     *
     * \param spec The link spec to be copied.
     *
     * \return A pointer to the linkSpec for the requested module or NULL if there was an error allocating memory.
     *         This call Allocates memory that must be freed by a call to #aLinkSpec_Destroy.
     */
    aLIBEXPORT linkSpec* aLinkSpec_Copy(const linkSpec spec);
    /// Function #aLinkSpec_Destroy

    /**
     * Destroys and clears the referenced linkSpec.
     *
     * \param spec A pointer to the linkSpec pointer previously allocated.
     *
     * \return aErrNone on success or an error if there was an error encountered deallocating the linkSpec.
     *
     */
    aLIBEXPORT aErr aLinkSpec_Destroy(linkSpec** spec);

#ifdef __cplusplus
}
#endif
#endif //_aDiscover_H_
