/**
 * @file lin_types.h
 * @brief LIN slave data layer implementation
 */

#ifndef LIN_OPEN_LIN_TYPES_H_
#define LIN_OPEN_LIN_TYPES_H_


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

#define LD_BROADCAST                    0x7FU       /*!< Broadcast NAD */
#define LD_FUNCTIONAL_NAD               0x7EU       /*!< Functional NAD */
#define LIN_DEBUG

#define l_true true
#define l_false false

#ifndef lin_memcpy
#include <string.h>
#define lin_memcpy memcpy
#endif



#define LIN_INVALID_SCH_INDEX 0xFF

#define LIN_IFC_STATUS_PID_MASK 0xFF00U
#define LIN_IFC_STATUS_PID_SHIFT 8U
#define LIN_IFC_STATUS_ERROR_IN_RESP 0x0001U
#define LIN_IFC_STATUS_SUCCESS 0x0002U
#define LIN_IFC_STATUS_OVERRUN 0x0004U
#define LIN_IFC_STATUS_GO_TO_SLEEP 0x0008U
#define LIN_IFC_STATUS_BUS_ACTIVITY 0x0010U
#define LIN_IFC_STATUS_EVENT_COLLISION 0x0020U
#define LIN_IFC_STATUS_SLAVE_CONFIGURED 0x0040U

/* ld_raw_tx_status */
#define LD_QUEUE_EMPTY 0x00U
#define LD_QUEUE_AVAILABLE 0x01U
#define LD_QUEUE_FULL 0x02U
#define LD_TRANSMIT_ERROR 0x03U

/* ld_raw_rx_status */
#define LD_NO_DATA 0x00U
#define LD_DATA_AVAILABLE 0x01U
#define LD_RECEIVE_ERROR 0x02U


#define LD_IN_PROGRESS 0x00U
#define LD_COMPLETED 0x01U
#define LD_FAILED 0x02U
#define LD_N_AS_TIMEOUT 0x03U
#define LD_N_CR_TIMEOUT 0x04U
#define LD_WRONG_SN 0x05U


#define LD_SERVICE_IDLE 0x00U
#define LD_SERVICE_BUSY 0x01U
#define LD_REQUEST_FINISHED 0x02U
#define LD_SERVICE_ERROR 0x03U


/* Define wildcards */
#define LD_BROADCAST                    0x7FU       /*!< Broadcast NAD */
#define LD_FUNCTIONAL_NAD               0x7EU       /*!< Functional NAD */
#define LD_ANY_SUPPLIER                 0x7FFFU     /*!< Supplier */
#define LD_ANY_FUNCTION                 0xFFFFU     /*!< Function */
#define LD_ANY_MESSAGE                  0xFFFFU     /*!< Message */

/* Identification */
#define LD_NEGATIVE_RESPONSE              0x1U      /*!< Negative response */
#define LD_POSITIVE_RESPONSE              0x2U      /*!< Positive response */
#define LD_NO_RESPONSE                    0x3U      /*!< No response */


#define LD_READ_OK                        0x00U      /*!< Read by identifier success */
#define LD_LENGTH_TOO_SHORT               0x01U      /*!< Read by identifier length too short */

#define LD_SET_OK                         0x00U      /*!< Assign NAD success */
#define LD_LENGTH_NOT_CORRECT              0x01U      /*!< Assign NAD not supported */
#define LD_DATA_ERROR                     0x02U      /*!< Assign NAD data error */

#define LIN_PRODUCT_ID                  0x00U       /*!< Node product identifier */
#define LIN_SERIAL_NUMBER               0x01U       /*!< Serial number */


#define LIN_SERVICE_ASSIGN_NAD                0xB0U      /*!< Assign NAD service */
#define LIN_SERVICE_ASSIGN_FRAME_ID           0xB1U      /*!< Assign frame id service */
#define LIN_SERVICE_READ_BY_IDENTIFY          0xB2U      /*!< Read by identify service */
#define LIN_SERVICE_CONDITIONAL_CHANGE_NAD    0xB3U      /*!< Conditional change NAD service */
#define LIN_SERVICE_SAVE_CONFIGURATION        0xB6U      /*!< Save configuration service */
#define LIN_SERVICE_ASSIGN_FRAME_ID_RANGE     0xB7U      /*!< Assign frame id range service */





#define LIN_RES_NEGATIVE                    0x7FU       /*!< Negative response */
#define LIN_GENERAL_REJECT                  0x10U       /*!< Error code raised when request for service not supported comes */
#define LIN_SERVICE_NOT_SUPPORTED           0x11U       /*!< Error code in negative response for not supported service */
#define LIN_SUBFUNCTION_NOT_SUPPORTED       0x12U       /*!< Error code in negative response for not supported sub function */

typedef bool l_bool;
typedef uint8_t l_u8 ;
typedef uint16_t l_u16;
typedef l_u8 lin_pid_t;
typedef l_u8 lin_checksum_t;
typedef uint32_t l_ifc_handle;
typedef uint32_t l_irqmask;

/**
 * @brief LIN core layer error code
 */
typedef enum {
	LIN_CORE_NO_ERROR,           /*!< LIN_NO_ERROR */
    LIN_CORE_PRE_RX_ERROR,       /*!< call rx api failed */
    LIN_CORE_PRE_TX_ERROR,       /*!< call tx api failed */
    LIN_CORE_FRAME_BIT_ERROR,    /*!< bit or frame error */
    LIN_CORE_CHECKSUM_ERROR,     /*!< checksum error */
    LIN_CORE_TIMEOUT_ERROR,      /*!< timeout error */
    LIN_CORE_OTHERS_ERROR,       /*!< other error */
} lin_error_t;

/**
 * @brief LIN core state machine
 */
typedef enum {
	LIN_FRAME_SM_IDLE,      /*!< state idle */
	LIN_FRAME_SM_PID,       /*!< received pid, for slave */
	LIN_FRAME_SM_TX,        /*!< state tx */
	LIN_FRAME_SM_RX,        /*!< state rx */
} lin_frame_sm_t;

/**
 * @brief lin frame type
 */
typedef enum
{
    LIN_FRAME_TYPE_UNCD    = 0x00U,   /*!< Unconditional frame */
    LIN_FRAME_TYPE_EVENT   = 0x01U,   /*!< Event triggered frame */
    LIN_FRAME_TYPE_SPRDC   = 0x2U,    /*!< Sporadic frame */
    LIN_FRAME_TYPE_DIAG    = 0x3U,    /*!< Diag frame */
} lin_frame_type_t;


/**
 * @brief lin core layer error callback
 */
typedef void (*lin_core_error_callback_t)(l_ifc_handle inst,l_u8 id,lin_error_t error_code);

/**
 * @brief lin frame direction
 */
typedef enum
{
    LIN_DIR_PUBLISH = 0x00U,                /*!< LIN_DIR_PUBLISH */
    LIN_DIR_SUBSCRIBE = 0x01U,              /*!< LIN_DIR_SUBSCRIBE */
    LIN_DIR_SUBSCRIBE_IGNORE_DATA = 0x02U   /*!< LIN_DIR_SUBSCRIBE_IGNORE_DATA, unused*/
} lin_frame_dir_t;

/**
 * @brief lin frame checksum type
 */
typedef enum
{
    LIN_FRAME_CHECKSUM_ENHANCED = 0x00U,   /*!< LIN_CHECKSUM_ENHANCED */
    LIN_FRAME_CHECKSUM_CLASSIC = 0x01U,   /*!< LIN_CHECKSUM_CLASSIC */
} lin_frame_checksum_t;

/**
 * @brief lin signal type
 */
typedef enum
{
    LIN_SIGNAL_TYPE_SCALAR = 0x00U,   /*!< LIN_SIGNAL_TYPE_SCALAR */
    LIN_SIGNAL_TYPE_ARRAY = 0x01U,   /*!< LIN_SIGNAL_TYPE_ARRAY */
}lin_signal_type_t;

/**
 * @brief lin signal object
 */
typedef struct
{
    lin_signal_type_t signalType;  /*!< signal type */
    l_u16 flagBitOffset;           /*!< signal flag bit offset */
    l_u16 bufOffset;               /*!< signal buffer offset */
    l_u8 bitLen;                  /*!< signal bit length */
}lin_signal_t;



/**
 * @brief lin frame object
 */
typedef struct 
{
    lin_frame_type_t frameType;    /*!< frame type */
    l_u8 bufLen;                   /*!< frame buffer length, same as frame size */
    l_u16 flagBitOffset;           /*!< frame flag bit offset */
    l_u8 id;                       /*!< frame id */
    l_u8 subIdIndex;               /*!< sub id index in frameList, used for event frame in slave node */
    lin_frame_checksum_t checksumType; /*!< frame checksum type */
    lin_frame_dir_t dir;           /*!< frame direction */
    const l_u8* signalList;        /*!< signal list,maybe null, it's ok*/
    const l_u8* signalOffset;      /*!< signal offset list,signal offset in frame*/
    l_u8 signalNum;                /*!< signal number */
    l_bool idChangeable;           /*!< id changeable for slave,configurable_frames_20*/
    l_u8 idRamIndex;               /*!< idRamIndex in idList,start from 1, 0 for NAD */
}lin_frame_t;

/**
 * @brief signal handle, high 16bit is ifc index, low 16bit is signal index
 */
typedef uint32_t l_signal_handle;
/**
 * @brief flag handle, highest 8bit is ifc index, 8bit is flag type, low 16bit is flag index
 */
typedef uint32_t l_flag_handle;
/**
 * @brief schedule handle
 */
typedef uint8_t l_schedule_handle;


/**
 * @brief lin sch slot object,for master node
 */
typedef struct
{
    /* data */
    lin_frame_type_t frameType;  /*!< frame type */
    union{
        struct{
            l_u16 frameIndex;    /*!< frame index in frameList */
        } uncd;
        struct{
            l_u16 frameIndex;    /*!< frame index in frameList */
            l_u8 diagType;       /*!< 0:diag,1:sleep,2:cmd(unsupported) */
        } diag;
        struct{
            l_schedule_handle resolveSch; /*!< valid when frameType is event */
            l_u16 frameIndex;    /*!< frame index in frameList */
        } event;
        struct{
            const l_u8* frameList;       /*!< frame list,valid when frame type is LIN_FRAME_TYPE_SPRDC*/
            l_u16 frameNum;              /*!< frameNum index in frameList or length of frameList in LIN_FRAME_TYPE_SPRDC*/   
        } sprdc;
    };
   
    l_u8 delay;                  /*!< delay ms */   
 
   
}lin_sch_slot_t;

/**
 * @brief lin schedule type
 */
typedef enum
{
	LIN_SCH_TYPE_NORMAL = 0x00U,    /*!< LIN_SCH_TYPE_NORMAL */
	LIN_SCH_TYPE_COLLISION_RESOLVED = 0x01U,   /*!< LIN_SCH_TYPE_COLLISION_RESOLVED */
	LIN_SCH_TYPE_MASTER_REQUEST = 0x02U,   /*!< LIN_SCH_TYPE_MASTER_REQUEST */
	LIN_SCH_TYPE_SLAVE_RESPONSE = 0x03U,   /*!< LIN_SCH_TYPE_SLAVE_RESPONSE */
    LIN_SCH_TYPE_SLEEP = 0x04U,   /*!< LIN_SCH_TYPE_SLEEP */
}lin_sch_type;

/**
 * @brief lin schedule object
 */
struct lin_sch_t{
    const lin_sch_slot_t *slotList; /*!< slot list */
    l_u16 numSlot;                  /*!< slot number */
    lin_sch_type schType;           /*!< schedule type */
};


/**
 * @brief lin node type
 */
typedef enum
{
    LIN_NODE_MASTER = 0x00U,    /*!< LIN_NODE_MASTER */
    LIN_NODE_SLAVE  = 0x01U     /*!< LIN_NODE_SLAVE */
} lin_node_type_t;

/**
 * @brief lin master config object
 */
typedef struct
{
    l_u8 masterReqSchIndex;    /*!< masterReq sch table index */
    l_u8 slaveRespSchIndex;    /*!< slaveResp sch table index */
    l_u8 sleepSchIndex;        /*!< sleep sch table index */
    l_u8 timeBase;             /*!< time base */
    l_u16 schTimeout;          /*!< schedule timeout(ms) for waiting slave response */
}lin_master_config_t;


/**
 * @brief serial number object
 */
typedef struct
{
    l_u8 serial0;  /*!< Serial 0 */
    l_u8 serial1;  /*!< Serial 1 */
    l_u8 serial2;  /*!< Serial 2 */
    l_u8 serial3;  /*!< Serial 3 */
} lin_serial_number_t;

/**
 * @brief product id object
 */
typedef struct
{
    l_u16   supplierId;        /*!< Supplier ID */
    l_u16   functionId;        /*!< Function ID */
    l_u8    variant;            /*!< Variant value */
} lin_product_id_t;


/**
 * @brief lin slave config object
 */
typedef struct
{
    l_u8 initNad;                                      /*!< Initial NAD */
    l_u8 configNad;                                    /*!< Configured NAD */
    lin_product_id_t product_id;                       /*!< Product ID */ 
    lin_serial_number_t sn;                            /*!< Serial number */ 
    l_u16                   p2Min;                     /*!< P2 min */
    l_u16                   stMin;                     /*!< ST min */
    l_u16                   nAsTimeout;                /*!< N_As timeout */
    l_u16                   nCrTimeout;                /*!< N_Cr timeout */
}lin_slave_config_t;


/**
 * @brief lin transport layer config object
 */
typedef struct
{
    l_u8 txQueueSize;           /*!< tx queue size */
    l_u8 rxQueueSize;           /*!< rx queue size */
    l_u16 rxMaxFrameLength;     /*!< rx max frame length, depends on rx queue size*/
    l_u8* idList;               /*!< id list ram pointer for slave*/
    l_u8 idNum;                 /*!< id num for slave, nad(1) + configure_frames number */
}lin_tp_config_t;


/**
 * @brief lin global config object
 */
typedef struct
{   
    lin_node_type_t nodeType;       /*!< node type , master or slave */
    l_u8 hwInst;                    /*!< hardware instance */
    const lin_frame_t* frameList;   /*!< frame list */ 
    l_u8 frameNum;                  /*!< frame number */
    const lin_signal_t* signalList; /*!< signal list */
    l_u8 signalNum;                 /*!< signal number */
    const lin_master_config_t* masterCfg;   /*!< master config for master*/
    const lin_slave_config_t* slaveCfg;     /*!< slave config for slave*/
    const lin_tp_config_t* tpCfg;           /*!< transport layer config when tp enable */
    l_u16 baudRate;
    l_u16 maxIdleTimeoutMs;                  /*!< max idle timeout(ms) */
    lin_core_error_callback_t coreErrorCb;  /*!< core error callback */

}lin_config_t;

/**
 * @brief lin diag state machine
 */
typedef enum 
{
    LIN_DIAG_IDLE,
    LIN_DIAG_TX_PHY,
    LIN_DIAG_TX_FUNC,
    LIN_DIAG_TX_TMP_FUNC,
    LIN_DIAG_RX_PHY,
    LIN_DIAG_RX_FUNC,           /*!< use for slave node*/
    LIN_DIAG_RX_TMP_FUNC,
}lin_diag_state_t;

/**
 * @brief lin master transport layer state
 */
typedef struct
{
    l_bool diagOnly;       /*!< diag only */
}lin_master_tp_state_t;

/**
 * @brief lin master state
 */
typedef struct
{
    lin_master_tp_state_t* masterTpState;   /*!< master transport layer state, when tp enable*/
    l_schedule_handle activeSch;            /*!< active schedule */
    l_u8 activeSlot;                        /*!< active slot */
    l_schedule_handle previousSch;          /*!< previous schedule */
    l_u8 previousSlot;                      /*!< previous slot */
    l_bool collPending;                     /*!< collision pending */
    l_bool sleepPending;                    /*!< sleep pending */
    int tick;                               /*!< tick count */
	const lin_frame_t* rxFrame;             /*!< rx frame, need copy rx to buffer */
}lin_master_state_t;

/**
 * @brief lin slave state
 */
typedef struct
{
   l_bool nadConfigured;                    /*!< nad configured */
}lin_slave_state_t;

/**
 * @brief tp queue item
 */
typedef struct
{
    l_u8 data[8];
}lin_tp_item_t;

/**
 * @brief lin transport layer timeout direction
 */
typedef enum
{
    LIN_TP_TIMEOUT_IDLE,
    LIN_TP_TIMEOUT_TX,
    LIN_TP_TIMEOUT_RX,
    LIN_TP_TIMEOUT_SCH,
}lin_tp_timeout_dir_t;

/**
 * @brief lin transport layer queue
 */
typedef struct
{
	l_u8 readIdx;
	l_u8 writeIdx;
	l_u8 queueSize;
	lin_tp_item_t* items;
}lin_tp_queue_t;

/**
 * @brief lin transport layer state
 */
typedef struct
{
	l_u8 txStatus;              /*!< tx status for ld_raw_tx_status */
    l_u8 rxStatus;              /*!< rx status for ld_raw_rx_status */
    l_u8 txMsgStatus;           /*!< tx message status for ld_tx_status */
    l_u8 rxMsgStatus;           /*!< rx message status for ld_rx_status */    

    l_u16 * recvLen;            /*!< received length, store for ld_receive_message*/
    l_u8 * recvNad;             /*!< received nad, store for ld_receive_message*/
    l_u8 * recvData;            /*!< received data, store for ld_receive_message*/

    lin_tp_queue_t rxQueue;     /*!< rx queue */
    lin_tp_queue_t txQueue;     /*!< tx queue */

    int pendRecvCnt;            /*!< pending receive count for FF/CF*/
    int frameCnt;               /*!< frame count for FF/CF */
    l_bool hasRecvMsg;          /*!< has received message for ld_receive_message*/
    l_bool ffReceived;          /*!< FF received for ld_receive_message*/
    l_u8 ownNodeNad;            /*!< own node nad */

    lin_diag_state_t diagState; /*!< diag state */
    int timeout;                /*!< timeout count */
    lin_tp_timeout_dir_t timeoutDir; /*!< timeout direction */

    l_u8 serviceStatus;         /*!< service status for ld_is_ready */
    l_u8 lastRSID;              /*!< last RSID for ld_check_response*/
    l_u8 lastCode;              /*!< last code for ld_check_response */
}lin_tp_state_t;


/**
 * @brief lin frame status
 */
typedef struct
{
    l_u8 frameCnt;              /*!< frame count */
    l_u8 frameId;               /*!< frame id */
    l_bool saveConfig;          /*!< save config */     
    l_bool eventColl;           /*!< event collision */
    l_bool busActive;           /*!< bus active */
    l_bool goToSleep;           /*!< go to sleep */
    l_bool succTransfer;        /*!< success transfer */
    l_bool errorInResp;         /*!< error in response */
}lin_frame_status_t;

/**
 * @brief LIN transport layer event
 */
typedef enum {
    LIN_TP_RX_DATA_DONE,
	LIN_TP_RX_ERROR,
    LIN_TP_TX_DATA_PRE,
    LIN_TP_TX_DATA_NRC78_DONE,  /*!< use for slave node*/
    LIN_TP_TX_DATA_DONE,
    LIN_TP_TX_ERROR,
} lin_tp_event_t;




#endif /* OPEN_LIN_OPEN_LIN_TYPES_H_ */
