/**
 * \brief IQI's IO-Link Generic Device control interface
 * \copyright 2013-2014, IQ² Development GmbH, Neckartenzlingen. All rights reserved.
 */

#ifndef _iqi_dev_h
#define _iqi_dev_h

#include "iqi_define.h"

#define DEV_SEND_EVENT_TIMEOUT            2                                    // 2 sec
#define DEV_SET_PDIN_VALUE_TIMEOUT        2                                    // 2 sec
#define DEV_SET_PDIN_VALIDITY_TIMEOUT     2                                    // 2 sec
#define DEV_WAIT_OD_REQUEST_TIMEOUT       6                                    // 6 sec

typedef enum
{
  DEV_STATE_INACTIVE   = 0,
  DEV_STATE_SIO        = 1,
  DEV_STATE_STARTUP    = 2,
  DEV_STATE_PREOPERATE = 3,
  DEV_STATE_OPERATE    = 4
  
} dev_StateT;

typedef enum
{
  DEV_ODREQ_TYPE_WRITE     = 0,
  DEV_ODREQ_TYPE_WRITE_ERR = 1,
  DEV_ODREQ_TYPE_READ      = 2,
  DEV_ODREQ_TYPE_READ_ERR  = 3
  
} dev_ODReqT;

typedef enum
{
  OD_RSP_TYPE_AT_ONCE = 0,      // immediately response to master 
                                // without indication to application of external interface (PC),
                                // this value should be set to dev_ConfigT.ISDURspType
                                // in order to make iqInterface autonomously response to master 
                                // from configured ISDUs without external interface (PC)

  OD_RSP_TYPE_AUTO = 1,         // indicate ISDU requests to application of external interface (PC)
                                // via setting dev_StatusT.OD flag in generic device status (dev_GetStatus)
                                // and only after calling dev_GetODRequest 
                                // reset dev_StatusT.OD and response to master from configured ISDUs

  OD_RSP_TYPE_MANUAL = 2,       // indicate ISDU requests to application of external interface (PC)
                                // via setting dev_StatusT.OD flag in generic device status (dev_GetStatus),
                                // the ISDU request can be also read out by dev_GetODRequest, but
                                // the response data shall be sent manually from PC using dev_ODResponse 
                                // which triggers reset of dev_StatusT.OD and propogation of the response to master
  
} dev_ISDURspTypeT;
  
typedef struct
{ 
  uchar08 State        : 3; // 0 - 2 bits, see dev_StateT
  uchar08 PDOutInvalid : 1; // 3 bit     
  uchar08 PDInInvalid  : 1; // 4 bit  
  uchar08 Event        : 1; // 5 bit
  uchar08 OD           : 1; // 6 bit  
  uchar08 PDInSet      : 1; // 7 bit  
  uchar08 IQError      : 1; // 8 bit
  
} dev_StatusT;

typedef struct
{
  uchar08 Reserved0: 1;
  uchar08 IsRead:    1;
  uchar08 IsWrite:   1;
  uchar08 Reserved1:   1;
  uchar08 Reserved2:  4;
  uchar08 Reserved3:  8;
  
} dev_ISDU_Flag_BitsT;

typedef union
{
  dev_ISDU_Flag_BitsT Bits;
  uint16              Data;
} dev_ISDU_FlagT;

typedef struct
{
  // readonly version of device iqStack
  uint16 stackVersion;

  // Direct page
  uint16 masterCycleTime;                           // readonly written by master cycle time in operate, in ms: masterCycleTime/10
  uint16 minCycleTime;                              // less than MAX_CYCLE_TIME, in ms: minCycleTime/10
    
  IOLRevisionIDT revisionID;
  boolean isISDUSupported;
  uchar08 ODSizePreoperate;
  uchar08 ODSizeOperate;
  
  boolean isPDInLengthBytes;                        // TRUE - PDInLength in bytes, FALSE - in bits
  uchar08 PDInLength;
  boolean isPDOutLengthBytes;                       // TRUE - PDOutLength in bytes, FALSE - in bits
  uchar08 PDOutLength;

  uint16 deviceVendorID;
  ulong32 deviceID;                                 // 3 LSB bytes
  
  IOLBaudrateT supportedBaudrate;

  dev_ISDURspTypeT ISDURspType;                 // to allow ISDU requests availiable via dev_GetODRequest (OD_RSP_AFTER_APPL_CONFIRM)
                                                    // or make generic device immediately response to master (OD_RSP_IMMEDIATELY)
                                                    // without indication to application of external interface (PC)
                                                    // see comments dev_ISDURspTypeT
                                                    // after power reset is always OD_RSP_IMMEDIATELY

} dev_ConfigT;

/**
 * \brief Try to connect to iqInterface as IO-Link Generic Device on ports range
 *
 * \param[in]   ucFromPortNo        com port number search from
 * \param[in]   ucUntilPortNo       com port number until search
 * \param[out]  cpErrMsg            an error message (minimum 256 symbols!)
 *
 * \return the first successfully found IQI's comport number
 */
DLL_API
int16 dev_Connect(uchar08 ucFromPortNo,
                  uchar08 ucUntilPortNo,
                  char08 *cpErrMsg);

/**
 * \brief Try to connect to iqInterface as IO-Link Generic Device over TCP/IPv4/ethernet
 *
 * \param[in]   connection         TCP connection info, used only cpIqInterfaceIpAddr and uiPort
 * \param[in]   uiSendRecvTimoutMs TCP send/receive timout
 * \param[out]  cpErrMsg           an error message (minimum 256 symbols!)
 *
 * \return virtual port (TCP handle) of successfully connected IQI 
 *         to use in other functions or error
 */
DLL_API
int16 dev_EthernetConnect(enet_ConnectionT * connection, 
                          uint16 uiSendRecvTimoutMs, 
                          char08 *cpErrMsg);

/**
 * \brief Disconnect iqInterface as IO-Link Generic Device
 *
 * \param[in]   uiPortNo COM or virtual ethernet port number of iqInterface
 * \param[out]  cpErrMsg an error message (minimum 256 symbols!)
 *
 */
DLL_API
int16 dev_Disconnect(uint16 uiPortNo,
                     char08 *cpErrMsg);

/**
 * \brief Write to iqInterface its IO-Link generic device configuration
 *
 * \param[in]   uiPortNo COM or virtual ethernet port number of iqInterface
 * \param[in]   pConfig  IO-Link generic device configuration
 * \param[out]  cpErrMsg an error message (minimum 256 symbols!)
 *
 */
DLL_API
int16 dev_SetConfig(uint16 uiPortNo,
                    dev_ConfigT *pConfig,
                    char08 *cpErrMsg);

/**
 * \brief Read from iqInterface its IO-Link generic device configuration
 *
 * \param[in]   uiPortNo COM or virtual ethernet port number of iqInterface
 * \param[in]   pConfig  IO-Link generic device configuration
 * \param[out]  cpErrMsg an error message (minimum 256 symbols!)
 *
 */
DLL_API
int16 dev_GetConfig(uint16 uiPortNo,
                    dev_ConfigT *pConfig,
                    char08 *cpErrMsg);

/**
 * \brief Get IQI's generic device status and process data output from master, if available
 *
 * \param[in]   uiPortNo        COM or virtual ethernet port number of iqInterface
 * \param[out]  pStatus         a pointer to an IQI's generic device status
 * \param[out]  ucpPDOutBuf     a process data buffer
 * \param[in]   uiPDOutBufSize  a process data buffer size
 * \param[out]  cpErrMsg        an error message (minimum 256 symbols!)
 *
 * \return the actual size of readed process data output data bytes
 */
DLL_API
int16 dev_GetStatus(uint16 uiPortNo,
                    uchar08 *pStatus,
                    uchar08 *ucpPDOutBuf,
                    uint16 uiPDOutBufSize,
                    char08 *cpErrMsg);

/**
 * \brief Set process data input and its validity
 *
 * \param[in]   uiPortNo        COM or virtual ethernet port number of iqInterface
 * \param[in]   ucpPDInBuf      process data input buffer
 * \param[in]   uiBytesCount    a count of bytes to send
 * \param[in]   bValidity       a required validity flag, TRUE - valid, FALSE - invalid
 * \param[out]  cpErrMsg        an error message (minimum 256 symbols!)
 */
DLL_API
int16 dev_SetPDIn(uint16 uiPortNo,
                  uchar08 *ucpPDInBuf,
                  uint16 uiBytesCount,
                  boolean bValidity,
                  char08 *cpErrMsg);

/**
 * \brief Send IO-Link event to master
 *
 * \param[in]   uiPortNo        COM or virtual ethernet port number of iqInterface
 * \param[out]  ucQualifier     event qualifier
 * \param[in]   uiCode          event code
 * \param[out]  cpErrMsg        an error message (minimum 256 symbols!)
 */
DLL_API
int16 dev_SendEvent(uint16  uiPortNo,
                    uchar08 ucQualifier,
                    uint16  uiCode,
                    char08  *cpErrMsg);

/**
 * \brief Wait for ISDU request from master within DEV_WAIT_OD_REQUEST_TIMEOUT
 * 
 * In order that this function works the dev_ConfigT.ISDURspType** should be set to 
 * OD_RSP_TYPE_AUTO or OD_RSP_TYPE_MANUAL by dev_SetConfig()
 * The default setting for ISDURspType is OD_RSP_TYPE_AT_ONCE after iqInterface reset. 
 * In this case iqInterface responds immediately to master according to configured (saved) ISDU parameters
 * and this function is useless because it never gets a notification about ISDU request.
 *
 * In case of OD_RSP_TYPE_AUTO this function makes iqInterface respond with configured (saved) ISDU parameters 
 * and confirm ISDU request to master which will not receive ISDU response without call of this function.
 *
 * In case of OD_RSP_TYPE_MANUAL iqInterface does not response with configured ISDU parameters,
 * the function just returns last received and pending ISDU request, 
 * reponse should be sent by dev_ODResponse().
 * 
 * ISDU requests to direct page 1 are not indicated by this function,
 * because system manager of device stack is responsible for it.
 *
 * \param[in]   uiPortNo        COM or virtual ethernet port number of iqInterface
 * \param[out]  ucType          a pointer to type of received ISDU request (see dev_ODReqT)
 * \param[out]  uiIndex         a pointer to ISDU request index
 * \param[out]  ucSubindex      a pointer to ISDU request subindex
 * \param[out]  ucpBuf          a pointer to ISDU request data buffer
 * \param[in]   ucBufSize       ISDU request data buffer size
 * \param[out]  uipISDUErr      a pointer to ISDU error code 
 *                              in case of ucType == DEV_ODREQ_TYPE_WRITE_ERR/DEV_ODREQ_TYPE_READ_ERR
 * \param[out]  cpErrMsg        an error message (minimum 256 symbols!)
 *
 * \return the actual size of readed on-request data bytes
 */
DLL_API
int16 dev_GetODRequest(uint16  uiPortNo,   
                       uchar08 *ucType,
                       uint16  *uiIndex,
                       uchar08 *ucSubindex,
                       uchar08 *ucpBuf,
                       uint16  ucBufSize,
                       uint16  *uiISDUErrCode,
                       char08  *cpErrMsg);

/**
 * \brief Sends ISDU response in case of OD_RSP_TYPE_MANUAL
 *
 * \param[in]   uiPortNo        COM or virtual ethernet port number of iqInterface
 * \param[out]  ucType          type of responded ISDU request (see dev_ODReqT)
 * \param[out]  ucpBuf          a pointer to ISDU response data buffer
 * \param[in]   uiBytesCount    ISDU response data size
 * \param[out]  uipISDUErr      a pointer to ISDU error code 
 *                              in case of ucType == DEV_ODREQ_TYPE_WRITE_ERR/DEV_ODREQ_TYPE_READ_ERR
 * \param[out]  cpErrMsg        an error message (minimum 256 symbols!)
 */
DLL_API
int16 dev_ODResponse(uint16  uiPortNo,
                     uchar08 ucType,
                     uchar08 *ucpBuf,
                     uint16  uiBytesCount,
                     uint16  uiISDUErrCode,
                     char08  *cpErrMsg);

/**
 * \brief Remove all generic device ISDUs currently saved in IQI
 *
 * \param[in]   uiPortNo        COM or virtual ethernet port number of iqInterface
 * \param[out]  cpErrMsg        an error message (minimum 256 symbols!)
 */
DLL_API
int16 dev_RemoveAllISDU(uint16  uiPortNo,
                        char08  *cpErrMsg);
 
/**
 * \brief Add ISDU to generic device
 *
 * For one index there can be either only one ISDU parameter with subindex 0
 * or some ISDU parameters with subindexes strictly from 1 to their number (max 255)
 * without missing subindexes.
 *
 * \param[in]   uiPortNo        COM or virtual ethernet port number of iqInterface
 * \param[in]   uiFlag          flag of added ISDU (see dev_ISDU_FlagT)
 * \param[in]   uiIndex         an ISDU index
 * \param[in]   ucSubindex      an ISDU subindex
 * \param[in]   ucpBuf          a data buffer
 * \param[in]   ucBytesCount    size of value data to add
 * \param[out]  cpErrMsg        an error message (minimum 256 symbols!)
 */
DLL_API
int16 dev_AddISDU(uint16 uiPortNo,
                  uint16 uiFlag,
                  uint16 uiIndex,
                  uchar08 ucSubindex,
                  uchar08 *ucpBuf,
                  uint16 uiBytesCount,
                  char08  *cpErrMsg);

/**
 * \brief Set ISDU value, which has been added by dev_AddISDU before
 *
 * \param[in]   uiPortNo        COM or virtual ethernet port number of iqInterface
 * \param[in]   uiIndex         an ISDU index
 * \param[in]   ucSubindex      an ISDU subindex
 * \param[in]   ucpBuf          data buffer
 * \param[in]   ucBytesCount    size of value data to set
 * \param[out]  cpErrMsg        an error message (minimum 256 symbols!)
 */
DLL_API
int16 dev_SetISDUValue(uint16 uiPortNo,
                       uint16 uiIndex,
                       uchar08 ucSubindex,
                       uchar08 *ucpBuf,
                       uint16 uiBytesCount,
                       char08  *cpErrMsg);

/**
 * \brief Get ISDU value, which has been added by dev_AddISDU before
 *
 * \param[in]   uiPortNo        COM or virtual ethernet port number of iqInterface
 * \param[in]   uiIndex         an ISDU index
 * \param[in]   ucSubindex      an ISDU subindex
 * \param[out]  ucpBuf          data buffer
 * \param[in]   ucBufSize       data buffer size
 * \param[out]  cpErrMsg        an error message (minimum 256 symbols!)
 *
 * \return size of returned value data to ucpBuf
 */
DLL_API
int16 dev_GetISDUValue(uint16 uiPortNo,
                       uint16 uiIndex,
                       uchar08 ucSubindex,
                       uchar08 *ucpBuf,
                       uint16 uiBufSize,
                       char08  *cpErrMsg);

#endif
