/*
 * 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 _DBC_COMM_H_
#define _DBC_COMM_H_

/*! \brief Contains public interface to various functions related
 *         to the CAN communication using the CAN dbc file
 */

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

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

#ifdef __cplusplus
extern "C" {
#endif

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

/*! \brief The default value used for initialization
 */
#define CAN_MSG_DEFAULT {       \
    404,                        \
    {0, 0, 0, 0, 0, 0, 0, 0},   \
    8,                          \
    0,                          \
    0                           \
}

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

/*! \brief CAN message type definition
 *
 * The identifier field may have 11 bits for standard frames
 * (CAN specification 2.0A) or 29 bits for extended frames
 * (CAN specification 2.0B).
 */
typedef struct _DbcComm_CanMsgType_
{
    uint32_t id;       /*!< the CAN ID, 11 bits for standard frames (CAN SPEC 2.0A) or 29 bits for extended frames (CAN SPEC 2.0B) */
    uint8_t  data[8];  /*!< The data field has up to 8 bytes (64 bit) of message data */
    uint8_t  length;   /*!< The data length code denotes the number of data bytes, 0 to 8 (bytes) */
    uint8_t  extended; /*!< Extended Frame if set to 1, else Standard Frame. */
    uint8_t  remote;   /*!< Remote Frame if set to 1, else Data Frame. */
} DbcComm_CanMsgType;

/*! \brief Defines all the CAN node
 */
typedef enum
{
    DBCCOMM_NODE_0 = 0,
    DBCCOMM_NODE_1,
    DBCCOMM_NODE_2,
    DBCCOMM_NODE_3,
    DBCCOMM_NODE_4,
    DBCCOMM_NODE_5,
    DBCCOMM_NODE_6,
    DBCCOMM_NODE_7,
    DBCCOMM_NODE_8,

    DBCCOMM_NODE_NUM
} DbcComm_CanNodeType;

/*! \brief Forward declaration of DBCCOMM class
 */
struct _DbcCommType_;

/*! \brief Tx message information
 */
typedef struct _DbcComm_TxMsgInfoType_
{
    DbcComm_CanNodeType node;                                             /*!< the node for this message */
    uint32_t            id;                                               /*!< the CAN id of this message */
    float               period_ms;                                        /*!< Period for transmit messages, 0 for single-shot */
    void (*packMsg)(struct _DbcCommType_ *obj, DbcComm_CanMsgType *pMsg); /*!< pointer to the function to pack this message */
} DbcComm_TxMsgInfoType;

/*! \brief Rx message information
 */
typedef struct _DbcComm_RxMsgInfoType_
{
    DbcComm_CanNodeType node;                                                     /*!< the node for this message */
    uint32_t            id;                                                       /*!< the CAN id of this message */
    float               timeout_ms;                                               /*!< Time out threshold for receive messages, 0 for single-shot */
    void (*unpackMsg)(struct _DbcCommType_ *obj, const DbcComm_CanMsgType *pMsg); /*!< pointer to the function to unpack this message */
} DbcComm_RxMsgInfoType;

/*! \brief Tx message definition
 */
typedef struct _DbcComm_TxMsgType_
{
    uint32_t                     periodCntMax; /*!< the period count max value, determined by period*/
    uint32_t                     periodCnt;    /*!< the period counter */
    const DbcComm_TxMsgInfoType *pInfo;        /*!< the informatin of TX message */
} DbcComm_TxMsgType;

/*! \brief Rx message definition
 */
typedef struct _DbcComm_RxMsgType_
{
    uint16_t                     timeoutCntMax; /*!< the counter max value, determined by timeout period */
    uint16_t                     timeoutCnt;    /*!< the timeout counter */
    bool                         isTimeout;     /*!< whether is timeout */
    const DbcComm_RxMsgInfoType *pInfo;         /*!< the informatin of RX message */
} DbcComm_RxMsgType;

/*! \brief The adapter of CAN send implementation
 */
typedef void (*DbcComm_SendCanMsgShimType)(DbcComm_CanNodeType node, const DbcComm_CanMsgType *pMsg);

/*! \brief Type definition of TX message array
 */
typedef DbcComm_TxMsgType *DbcComm_TxMsgArray;

/*! \brief Type definition of RX message array
 */
typedef DbcComm_RxMsgType *DbcComm_RxMsgArray;

/*! \brief  Defines all the parameters used to initialize power CAN communication object
 */
typedef struct _DbcComm_ParamsType_
{
    float                      runFreq_kHz; /*!< Frequency to run this module */
    DbcComm_SendCanMsgShimType sendCanMsg;  /*!< function to implement CAN send */
} DbcComm_ParamsType;

/*! \brief  Defines all the inputs for DBCCOMM object
 */
struct _DbcComm_InputsType_;
typedef struct _DbcComm_InputsType_ DbcComm_InputsType;

/*! \brief  Defines all the outputs for DBCCOMM object
 */
struct _DbcComm_OutputsType_;
typedef struct _DbcComm_OutputsType_ DbcComm_OutputsType;

/*! \brief Defines the DBCCOMM object
 */
typedef struct _DbcCommType_
{
    bool                       enableNodeTx[DBCCOMM_NODE_NUM]; /*!< TX enable flag for all nodes */
    bool                       enableNodeRx[DBCCOMM_NODE_NUM]; /*!< RX enalbe flag for all nodes   */
    DbcComm_TxMsgArray         txMsgArray;                     /*!< TX message array */
    DbcComm_RxMsgArray         rxMsgArray;                     /*!< RX message array */
    uint16_t                   txMsgNum;                       /*!< Total TX message number */
    uint16_t                   rxMsgNum;                       /*!< Total RX message number */
    DbcComm_InputsType        *pInputs;                        /*!< pointer to the inputs */
    DbcComm_OutputsType       *pOutputs;                       /*!< pointer to the outputs */
    DbcComm_SendCanMsgShimType sendCanMsg;                     /*!< function to implement CAN send */

} DbcCommType;

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

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

/*! \brief  Initialize the DBCCOMM object
 *
 * This function initialize the DbcComm object using the given parameters
 *
 *  \param[in] obj : pointer to DbcComm instance
 *  \param[in] pParams :
 */
extern void DbcComm_Init(DbcCommType *obj, const DbcComm_ParamsType *pParams);

/*! \brief  Run the DBCCOMM
 *
 * This function process the DbcComm main logic
 *
 *  \param[in] obj : pointer to DbcComm instance
 */
extern void DbcComm_Run(DbcCommType *obj);

/*! \brief  Receive the can message
 *
 * This function receive the can message for dbc logic to analyze.
 *
 * \note IMPORTANT!!! This interface should be called in the same thread as DbcComm_Run
 *
 *  \param[in] obj : pointer to DbcComm instance
 *  \param[in] node : the CAN node to receive the message
 *  \param[in] pMsg : the pointer to the message to receive
 */
extern void DbcComm_ReceiveCanMsg(DbcCommType *obj, DbcComm_CanNodeType node, const DbcComm_CanMsgType *pMsg);

/*! \brief  Enable/Disable RX of the node
 *
 * This function enables or disables the RX of the given node
 *
 * \param[in] obj : pointer to DbcComm instance
 * \param[in] node : the node to operate
 * \param[in] enable : whether to enable or disable the RX function
 *                     - true : enable the RX
 *                     - false : disable the RX
 */
extern void DbcComm_EnableRx(DbcCommType *obj, DbcComm_CanNodeType node, bool enable);

/*! \brief  Enable/Disable TX of the node
 *
 * This function enables or disables the TX of the given node
 *
 * \param[in] obj : pointer to DbcComm instance
 * \param[in] node : the node to operate
 * \param[in] enable : whether to enable or disable the TX function
 *                     - true : enable the TX
 *                     - false : disable the TX
 */
extern void DbcComm_EnableTx(DbcCommType *obj, DbcComm_CanNodeType node, bool enable);

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

#endif /* _DBC_COMM_H_ */
