/*
 * Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
 * All rights reserved.
 *
 * Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
 * exclusively with CVA's microcontroller products. This file can be freely
 * distributed within development tools that are supporting such microcontroller
 * products.
 *
 * THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
 * OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
 * CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
 * OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 */

#ifndef _ISOTP_H_
#define _ISOTP_H_

/*! \brief Contains public interface to various functions related
 *         to the ISO TP (ISO 15765-2)
 */

/*******************************************************************************
 * the includes
 ******************************************************************************/

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

/*******************************************************************************
 * the defines
 ******************************************************************************/

/*! \brief Defines all the return values
 */
#define ISOTP_RET_OK                   (0)
#define ISOTP_RET_ERROR                (-1)
#define ISOTP_RET_INPROGRESS           (-2)
#define ISOTP_RET_OVERFLOW             (-3)
#define ISOTP_RET_WRONG_SN             (-4)
#define ISOTP_RET_NO_DATA              (-5)
#define ISOTP_RET_TIMEOUT              (-6)
#define ISOTP_RET_LENGTH               (-7)

/*! \brief The default timeout to use when waiting for a response during a multi-frame send or receive.
 */
#define ISOTP_DEFAULT_RESPONSE_TIMEOUT (100)

/*! \brief The STmin parameter value specifies the minimum time gap allowed between
 *         the transmission of consecutive frame network protocol data units
 */
#define ISOTP_DEFAULT_ST_MIN           (0)

/*! \brief This parameter indicate how many FC N_PDU WTs can be transmitted by the
 *         receiver in a row.
 */
#define ISOTP_MAX_WFT_NUMBER           (1)

/*******************************************************************************
 * the typedefs
 ******************************************************************************/

/*! \brief The declaration of the buffer used for both send and receive
 */
typedef uint8_t *IsoTp_Buffer;

/*! \brief User implemented, print debug message
 */
typedef void (*IsoTp_DebugShim)(const char *message, ...);

/*! \brief User implemented, send can message
 */
typedef int8_t (*IsoTp_SendCanMsgShim)(const uint32_t arbitrationId, const uint8_t *pData, const uint8_t size);

/*! \brief User implemented, get millisecond
 */
typedef int64_t (*IsoTp_GetTimeShimMs)(void);

/*! \brief Defines all the parameters used to initialize ISOTP object
 */
typedef struct _IsoTp_Params_
{
    bool                 framePadding;
    uint8_t              blockSize;
    uint32_t             recvPhysId;
    uint32_t             recvFuncId;
    uint32_t             sendid;
    uint8_t             *sendBuf;
    uint16_t             sendBufSize;
    uint8_t             *recvBuf;
    uint16_t             recvBufSize;
    IsoTp_DebugShim      debug;
    IsoTp_SendCanMsgShim sendCanMsg;
    IsoTp_GetTimeShimMs  getTimeMs;
} IsoTp_Params;

/*! \brief Structure containing the data for linking an application to a CAN instance.
 *         The data stored in this structure is used internally and may be used by software programs
 *         using this library.
 */
typedef struct _IsoTpType_
{
    bool    framePadding; /*!< whether need frame padding */
    uint8_t blockSize;    /*!< Max number of messages the receiver can receive at one time, this value is affected by CAN driver queue length */

    uint32_t physId; /*!< physical addressing id */
    uint32_t funcId; /*!< functional addressing id */

    uint32_t     sendArbitrationId; /*! used to reply consecutive frame */
    IsoTp_Buffer sendBuffer;        /*!< send buffer */
    uint16_t     sendBufferSize;    /*!< the size of send buffer */
    uint16_t     sendSize;          /*!< the size of data to send */
    uint16_t     sendOffset;        /*!< the offset of current send process */

    uint8_t  sendSN;             /*!< serial number of send message */
    uint16_t sendBsRemain;       /*!< Remaining block size */
    uint8_t  sendSTMin;          /*!< Separation Time between consecutive frames, unit millisecond */
    uint8_t  sendWaitFrameCount; /*!< Maximum number of FC.Wait frame transmissions */
    int64_t  sendTimerSeptime;   /*!< Last time send consecutive frame */
    int64_t  sendTimerBlockSize; /*!< Time until transmission of the next FlowControl N_PDU start at sending FF, CF, receive FC end at receive FC */
    int      sendProtocolResult; /*!< the result of send protocol */
    uint8_t  sendStatus;         /*!< the send status */

    uint32_t     receiveArbitrationId; /*! used to determine whether physical or functional addressing */
    IsoTp_Buffer receiveBuffer;        /*!< message receive buffer */
    uint16_t     receiveBufferSize;    /*!< the size of RX buffer */
    uint16_t     receiveSize;          /*!< the size to receive */
    uint16_t     receiveOffset;        /*!< the offset of receive process */

    uint8_t receiveSN;             /*!< serial number of receive message */
    uint8_t receiveBlockSizeCount; /*!< Maximum number of FC.Wait frame transmissions */
    int64_t receiveTimerCr;        /*!< Time until reception of the next ConsecutiveFrame N_PDU start at sending FC, receive CF end at receive FC */
    int8_t  receiveProtocolResult; /*!< the result of receive protocol */
    uint8_t receiveStatus;         /*!< the receive status */

    IsoTp_DebugShim      debug;      /*!< the adapter of debug function */
    IsoTp_SendCanMsgShim sendCanMsg; /*!< the adapter of can-send-message function */
    IsoTp_GetTimeShimMs  getTimeMs;  /*!< the adapter of get-time-stamp function */

} IsoTpType;

/*******************************************************************************
 * the globals
 ******************************************************************************/

/*******************************************************************************
 * the function prototypes
 ******************************************************************************/

/*! \brief Initializes the ISO-TP library.
 *
 * This function intiliaze the ISO-TP  instance
 *
 * \param[in] obj : pointer to ISOTP instance
 * \param[in] pParams : pointer to the initialization parameters
 */
extern void IsoTp_Init(IsoTpType *obj, const IsoTp_Params *pParams);

/*! \brief Polling function
 *
 * Call this function periodically to handle timeouts, send consecutive frames, etc.
 *
 * \param[in] obj : pointer to ISOTP instance
 */
extern void IsoTp_Poll(IsoTpType *obj);

/*! \brief Handles incoming CAN messages.
 *
 * Determines whether an incoming message is a valid ISO-TP frame or not and handles it accordingly.
 *
 * \param[in] obj : pointer to ISOTP instance
 * \param[in] id : the incoming CAN frame ID
 * \param[in] pData : pointer to data of incoming CAN frame
 * \param[in] len : the length of data of incoming CAN frame
 */
extern void IsoTp_HandleIncomingCanMsg(IsoTpType *obj, uint32_t id, const uint8_t *pData, uint8_t len);

/*! \brief Sends ISO-TP frames via CAN, using the ID set in the initializing function.
 *
 * Single-frame messages will be sent immediately when calling this function.
 * Multi-frame messages will be sent consecutively when calling isotp_poll.
 *
 * \param[in] obj : pointer to ISOTP instance
 * \param[in] pPayload : the incoming CAN frame ID
 * \param[in] size : pointer to data of incoming CAN frame
 */
extern int8_t IsoTp_Send(IsoTpType *obj, const uint8_t pPayload[], uint16_t size);

/*! \brief Send with message ID
 *
 * With the exception that this function is used only for functional addressing.
 *
 * \param[in] obj : pointer to ISOTP instance
 * \param[in] id : the message ID to send
 * \param[in] pPayload : pointer to data to send
 * \param[in] size : the size of data to send
 */
extern int8_t IsoTp_SendWithId(IsoTpType *obj, uint32_t id, const uint8_t pPayload[], uint16_t size);

/*! \brief  Receives and parses the received data and copies the parsed data in to the internal buffer.
 *
 * This function receives and parses the received data and copies the parsed data in to the internal buffer.
 *
 * \param[in] obj : pointer to ISOTP instance
 * \param[out] IsFuncAddr : pointer the result of whether is functional addressing
 * \param[out] pPayload : pointer to the payload
 * \param[in] payloadSize : the payload size
 * \param[out] pOutSize : the size of actual output payload
 */
extern int8_t IsoTp_Receive(IsoTpType *obj, bool *IsFuncAddr, uint8_t *pPayload, uint16_t payloadSize, uint16_t *pOutSize);

#ifdef __cplusplus
}
#endif /* extern "C" */

#endif /* _ISOTP_H_ */
