/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                 */
/* file: aLink.h                                                   */
/*                                                                 */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                 */
/* description: Definition for BrainStem packet FIFO queue.        */
/*                                                                 */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                 */
/* 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 _aLink_H_
#define _aLink_H_

#include "aDefs.h"
#include "aError.h"
#include "aPacket.h"
#include "aStream.h"

/////////////////////////////////////////////////////////////////////
/// BrainStem Link Interface

/** \defgroup aLink Link Interface
 * \ref aLink "aLink.h" provides the interface for creating and maintaining
 * the link to a BrainStem module, and the BrainStem network. It includes
 * facilities for starting and stopping links, as well as sending and receiving
 * BrainStem protocol packets.
 */


/////////////////////////////////////////////////////////////////////
/// Typedef #aLinkRef Opaque reference to a BrainStem link.
//typedef void* aLinkRef;

/// Typedef for aLinkRef for an opaque reference to BrainStem Link.
typedef uint32_t aLinkRef;

/////////////////////////////////////////////////////////////////////
/// Enum #linkStatus.

/////////////////////////////////////////////////////////////////////
/// Typedef #aHBCallbackProc.

/**
 * This callback is called from the link processing thread,
 * Implementations should get in and out of this callback as fast as
 * possible. Do not do anything lengthy here.
 * param bOn  The representation of an up or down beat.
 */
typedef void (*aHBCallbackProc) (bool bOn);

/////////////////////////////////////////////////////////////////////
/// Typedef #packetFilterProc.

/**
 * This callback is called from the link processing thread,
 * Implementations should get in and out of this callback as fast as
 * possible. Do not do anything lengthy here.
 * param packet Pointer to the current packet
 * param ref User supplied reference.
 * return Indicated wether the packet was accepted (True) or rejected (False).
 *     Accepted packets will be destroyed after returning.
 *     Rejected packets will be sent through normal BrainStem process.
 */
typedef bool (*packetFilterProc)(const aPacket* packet, void* ref);

/**
 * Represents the current state of the BrainStem link.
 */
typedef enum {
    STOPPED, /**< Link currently stopped. */
    INITIALIZING, /**< Starting communication with module. */
    RUNNING, /**< Link running. */
    STOPPING, /**< Link is in the process of stopping. */
    SYNCING, /**< Packet framing lost re-syncing. */
    INVALID_LINK_STREAM, /**< Link stream provided is not valid. */
    IO_ERROR, /**< Communication error occured on link, could not resync. */
    RESETTING, /**< Resetting the link connection */
    UNKNOWN_ERROR /**< Something really bad happened, but we couldn't determin what. */
} linkStatus;


#ifdef __cplusplus
extern "C" {
#endif

    /////////////////////////////////////////////////////////////////////
    /// Create a USB BrainStem link reference.
    
    /**
     * Creates a reference to a USB BrainStem link. The linkStream is now
     * maintained by the BrainStem link.  If the link already exists, the
     * use count for that link will be incremented and the linkRef for
     * that entry will be returned.
     *
     * Links created with this procedure must use aLink_Destroy to properly
     * dispose of the link reference and associated connections.
     *
     * \param serialNumber  Unique identifier of the device.
     *
     * \return aLinkRef identifier if successful or 0 otherwise.
     */
    aLIBEXPORT aLinkRef aLink_CreateUSB(const uint32_t serialNumber);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Create a Server BrainStem link reference.
    
    /**
     * Creates a reference to a  Server BrainStem link. The linkStream is now
     * maintained by the BrainStem link. Under the hood this functions
     * calls aLink_CreateUSB.  Once the reference is created it is intended
     * to be used in conjunction with aLink_CreateClient
     *
     * Links created with this procedure must use aLink_Destroy to properly
     * dispose of the link reference and associated connections.
     *
     * \param deviceId  aLinkRef handle for the primary-device that this server
     *                 shall reference.
     * \param assignedPort Variable to be filled with the server assigned port.
     * \param networkInterface  Network interface (IPv4 address) to be used for the server.
     *                  If isLocal == false AND this value == 0 or LOCALHOST_IP_ADDRESS
     *                  The variable will be filled with the auto selected interface.
     * \param isLocal Defines the servers exposure; True = Local; False = Exposed to internet.
     *                  Setting this variable to false will have firewall implications.
     *
     * \return aLinkRef identifier if successful or 0 otherwise.
     */
    aLIBEXPORT aLinkRef aLink_CreateServer(aLinkRef deviceId,
                                           uint16_t* assignedPort,
                                           uint32_t* networkInterface,
                                           const bool isLocal);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Create a Client BrainStem link reference.
    
    /**
     * Creates a reference to a  Client BrainStem link. The linkStream is now
     * maintained by the BrainStem link. 
     *
     * Links created with this procedure must use aLink_Destroy to properly
     * dispose of the link reference and associated connections.
     *
     * \param address  IPv4 address as to where the corresponding Server resides
     * \param port Port of the corresponding server resides.
     * \param ref Reference to an exiting link, for use with BrainStem I2C networking. 0 is ignored.
     *
     * \return aLinkRef identifier if successful or 0 otherwise.
     */
    aLIBEXPORT aLinkRef aLink_CreateClient(const uint32_t address,
                                           const uint16_t port,
                                           const aLinkRef ref);

    /**
     * Creates a reference to a BrainStem link. The linkStream is now
     * maintained by the BrainStem link.  If the link already exists, the 
     * use count for that link will be incremented and the linkRef for 
     * that entry will be returned.
     *
     * Links created with this procedure must use aLink_Destroy to properly
     * dispose of the link reference and associated connections.
     *
     * \param serialNumber the device serial number
     * \param address  the TCPIP address
     * \param port     the TCPIP port
     *
     * \return aLinkRef identifier if successful or 0 otherwise.
     */
    aLIBEXPORT aLinkRef aLink_CreateTCPIP(const uint32_t serialNumber,
                                          const uint32_t address,
                                          const uint16_t port);
    


    /**
     * Creates a reference to a BrainStem link. The linkStream is now
     * maintained by the BrainStem link.  If the link already exists, the
     * use count for that link will be incremented and the linkRef for
     * that entry will be returned.
     *
     * Links created with this procedure must use aLink_Destroy to properly
     * dispose of the link reference and associated connections.
     *
     * \param serialNumber  the device serial number
     * \param port  the Serial port in a character array
     * \param baud     the serial port baudrate
     *
     * \return aLinkRef identifier if successful or 0 otherwise.
     */
    aLIBEXPORT aLinkRef aLink_CreateSerial(const uint32_t serialNumber,
                                           const char* port,
                                           const uint32_t baud);

    /**
     * Creates a reference to a BrainStem link. -- *** DEPRECATED *** --
     * The linkStream is now maintained by the BrainStem link.
     * The aLink_Create(aStreamRef linkStream) is maintained for backward
     * compatibility, but linkStream CANNOT be NULL.  Once the linkStream
     * has been used in the create, caller must not use or delete the stream.
     * Each call to this routine will create an new link entry,
     * independent of any other link to the same device.
     *
     * Links created with this procedure must use aLink_Destroy to properly
     * dispose of the link reference and associated connections.
     *
     * \param linkStream  a StreamRef the transport stream (NON-NULL).
     *
     * \return aLinkRef identifier if successful or 0 otherwise.
     */
    aLIBEXPORT aLinkRef aLink_Create(aStreamRef linkStream);

    /////////////////////////////////////////////////////////////////////
    /// Create a BrainStem link reference heartbeat callback

    /**
     * Sets a callback for notification about heartbeats.
     * the callback should return quickly, it executes in the
     * link processing thread context.
     *
     * \param linkRef  Link to set the callback on.
     * \param hbCallBack  a aHBCallbackProc the callback procedure.
     *
     * \return aHBCallbackProc NULL if none was set or the previous one if set.
     */
    aLIBEXPORT aHBCallbackProc aLink_SetHBCallback(aLinkRef linkRef, aHBCallbackProc hbCallBack);

    
    /////////////////////////////////////////////////////////////////////
    /// Destroy a BrainStem link reference.
    
    /**
     * Destroys a Link reference. deallocating associated resources cleanly.
     *
     * Links created with aLink_Create must use aLink_Destroy to clean up
     * resources used by the link Ref.
     *
     * \param linkRef  a Pointer to a valid LinkRef. The linkRef will be set to
     *                  NULL on succesful completion of the Destroy call.
     * \return aStreamRef  Return value will always be NULL. The return
     *                       value has been left for backwards compatability.
     */
    aLIBEXPORT aErr aLink_Destroy(aLinkRef* linkRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Reset a connection to a BrainStem module.
    
    /**
     * Stop the active connection to the BrainStem if the Link contains a valid
     * stream Reference, and clear out the communication buffers, and restart
     * the link.
     *
     * \param linkRef  A valid LinkRef.
     * \return Function returns aErr values.
     * \retval aErrNone  the call completed successfully, a subsequent
     *                    call to aLink_GetStatus should return the current
     *                    state of the link.
     * \retval aErrParam  No valid LinkRef provided.
     */
    aLIBEXPORT aErr aLink_Reset(const aLinkRef linkRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Return the current status of the BrainStem link.
    
    /**
     * Return the current status of the BrainStem link.
     *
     * \param linkRef  A valid LinkRef.
     * \return linkStatus  See the possible linkStatus values.
     */
    aLIBEXPORT linkStatus aLink_GetStatus(const aLinkRef linkRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Return the first packet in the Link incomming FIFO.
    
    /**
     * Return the first packet in the Link incomming FIFO. This call is non blocking,
     * and will return immediately.
     *
     * \param linkRef  A valid LinkRef.
     * \return aPacket  Returns a BrainStem packet on success or NULL.
     */
    aLIBEXPORT aPacket* aLink_GetPacket(const aLinkRef linkRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Return the first packet in the Link incomming FIFO.
    
    /**
     * Return the first packet in the Link incomming FIFO. This call blocks waiting
     * for msTimeout milliseconds.
     *
     * \param linkRef  A valid LinkRef.
     * \param msTimeout  The maximum amount of time in milliseconds to wait for a packet.
     * \return aPacket  Returns a BrainStem packet on success or NULL.
     */
    aLIBEXPORT aPacket* aLink_AwaitPacket(const aLinkRef linkRef,
                                          const unsigned long msTimeout);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Return the first packet matched by proc in the Link incomming FIFO.
    
    /**
     * Return the first packet matched by proc in the Link incomming FIFO. This call
     * is non blocking and returns immediatly.
     *
     * \param linkRef  A valid LinkRef.
     * \param proc  The callback used for determining a matching packet.
     * \param vpRef  A resource passed to the callback proc.
     * \return aPacket  Returns the first packet that is matched by proc or NULL.
     */
    aLIBEXPORT aPacket* aLink_GetFirst(const aLinkRef linkRef,
                                       aPacketMatchPacketProc proc,
                                       const void* vpRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Return the first packet matched by proc in the Link incomming FIFO.
    
    /**
     * Return the first packet matched by proc in the Link incomming FIFO. This call
     * blocks for up to msTimeout milliseconds waiting for a matching packet.
     *
     * \param linkRef  A valid LinkRef.
     * \param proc  The callback used for determining a matching packet.
     * \param vpRef  A resource passed to the callback proc.
     * \param msTimeout  The maximum amount of time in milliseconds to wait for a
     *                    matching packet.
     * \return aPacket  Returns the first packet that is matched by proc or NULL.
     */
    aLIBEXPORT aPacket* aLink_AwaitFirst(const aLinkRef linkRef,
                                         aPacketMatchPacketProc proc,
                                         const void* vpRef,
                                         const unsigned long msTimeout);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Drain all matching packets from the incomming FIFO.
    
    /**
     * Drain all matching packets from the incomming FIFO. This call does not block.
     *
     * \param linkRef  A valid LinkRef.
     * \param proc  The callback used for determining a matching packet.
     * \param vpRef  A resource passed to the callback proc.
     * \return aPacket  Returns the first packet that is matched by proc or NULL.
     */
    aLIBEXPORT size_t aLink_DrainPackets(const aLinkRef linkRef,
                                         aPacketMatchPacketProc proc,
                                         const void* vpRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Put a packet into the outgoingBackend link FIFO.
    
    /**
     * Put a packet into the outgoingBackend link FIFO.
     *
     * \param linkRef  A valid LinkRef.
     * \param packet  A BrainStem packet.
     * \return Function returns aErr values.
     * \retval aErrNone  Call successfully added the packet.
     * \retval aErrParam Invalid LinkRef or packet.
     * \retval aErrResource Unable to create memory for packet in FIFO.
     */
    aLIBEXPORT aErr aLink_PutPacket(const aLinkRef linkRef, const aPacket* packet);
    
    
    /////////////////////////////////////////////////////////////////////
    /// User defined packet filter.
    
    /**
     * If implemented the users filter will be executed before all other packet types.
     * It is the users responsibility to properly ignore packets that it does not care about.
     * Directly calling this function will interfere with the BrainStem stream interface.
     *
     * \param linkRef  A valid LinkRef.
     * \param callback  User defined callback
     * \return Function returns aErr values.
     * \retval aErrNone  Call successfully filter installation.
     */
    aLIBEXPORT aErr aLink_InstallUserPacketFilter(const aLinkRef linkRef,
                                                  packetFilterProc callback,
                                                  void* ref);

    /////////////////////////////////////////////////////////////////////
    /// Pooled Packet Enable.

    /**
     * Enables pooling of outgoing BrainStem packets.
     * Allowing multiple packets to be packed into a single transaction frame.
     *
     * \param linkRef  A valid LinkRef.
     * \param enable True = Enables; False = Disables;
     * \return Function returns aErr values.
     * \retval aErrNone  Call successfully enabled pooled packets
     */
    aLIBEXPORT aErr aLink_EnablePooledPackets(const aLinkRef linkRef, const bool enable);
    
    /////////////////////////////////////////////////////////////////////
    /////////////////////////////////////////////////////////////////////

    /////////////////////////////////////////////////////////////////////
    /// Enum type of debug packet entry.
    typedef enum {
        PACKET_LOG_OUTBOUND     = 0x01, // packet sent to device
        PACKET_LOG_INBOUND      = 0x02, // packet from device
        PACKET_LOG_NOTE         = 0x03,
        PACKET_LOG_UNKNOWN_TYPE = 0x80, // unknown type of data
    } packetLogType;
    

    /////////////////////////////////////////////////////////////////////
    /// Packet debug routines

    /////////////////////////////////////////////////////////////////////
    /// Enable logging of packets to/from the device.
    
    /**
     * Enable logging of packets to/from the device.
     *
     * \param linkRef  A valid LinkRef.
     * \param log_size  Size of buffer to use for logging packets.
     * \return Function returns aErr values.
     * \retval aErrNone  Call successfully set log size.
     * \retval aErrParam Invalid LinkRef.
     * \retval aErrResource Unable to create memory for logging.
     */
    aLIBEXPORT aErr aLink_PacketDebug_SetLogSize(const aLinkRef linkRef, int32_t log_size);

    /////////////////////////////////////////////////////////////////////
    /// Enable logging of packets to/from the device.
    
    /**
     * Enable logging of packets to/from the device.
     *
     * \param linkRef  A valid LinkRef.
     * \return Function returns aErr values.
     * \retval aErrNone  Call successfully enabled logging.
     * \retval aErrParam Invalid LinkRef.
     * \retval aErrResource Unable to create memory for logging.
     */
    aLIBEXPORT aErr aLink_PacketDebug_Enable(const aLinkRef linkRef);

    
    /////////////////////////////////////////////////////////////////////
    /// Disable logging of packets to/from the device.
    
    /**
     * Disable logging of packets to/from the device.
     *
     * \param linkRef  A valid LinkRef.
     * \return Function returns aErr values.
     * \retval aErrNone  Call successfully disabled logging.
     * \retval aErrParam Invalid LinkRef.
     * \retval aErrNotReady Logging was never enabled.
     */
    aLIBEXPORT aErr aLink_PacketDebug_Disable(const aLinkRef linkRef);
    
    
    /////////////////////////////////////////////////////////////////////
    /// Read next entry from the log.
    
    /**
     * Read next entry from the log.
     *
     * \param linkRef  A valid LinkRef.
     * \param type  The type of data stored in the buffer upon return.
     * \param data_size  Data buffer size.
     * \param data  Buffer for data to be stored in upon return.
     * \return Function returns aErr values.
     * \retval aErrNone  Call successfully read next entry.
     * \retval aErrParam Invalid LinkRef.
     * \retval aErrNotReady Logging was never enabled.
     * \retval aErrOverrun Data in entry is larger than buffer supplied
     */
    aLIBEXPORT aErr aLink_PacketDebug_Read(const aLinkRef linkRef, packetLogType *type, uint32_t *data_size, uint8_t *data);

    aLIBEXPORT aErr aLink_PacketDebug_Write(const aLinkRef linkRef, packetLogType type, const uint32_t data_size, const uint8_t *data);
    
#ifdef __cplusplus
}
#endif

#endif /* _aLink_H_ */

