#include "CANFD_Lib.h"
#include "RTE_CAN.h"
/**
 * @file        CAN_Signal_Tx.c
 * @brief       CAN发送文件
 * @details     CAN发送文件
 * @author      赵建智
 * @date        2022.04.25
 * @version     V1.0
 * @copyright   赵建智
 */

/**
 * @brief CAN报文外发诊断控制
 * @param[in] CanMsgTxOp 报文发送操作对象指针, 每路can都应有独立的结构体指针
 * @param[in] TX_enable 发送控制类型
 * @ref CANFD_N_TX_Enable 使能发送
 * @ref CANFD_N_TX_Disable 禁止发送
 * @warning 该接口只能由诊断调用.功能部分不可使用
 *
 * 示例
 @code
     CANFD_TX_DiagCtrlEnable(&CAN0_TX_Option,0x55);
 @endcode
 *
 * @since 1.0.0
 */
void CANFD_TX_DiagCtrlEnable(st_CanFDMsgTxOp *CanMsgTxOp, CANFD_TX_Status_t TX_enable)
{
    CanMsgTxOp->u8CAN_TX_ENABLE = TX_enable;
    CanMsgTxOp->u8CAN_TX_ENABLE |= 0x80u;
}
/**
 * @brief CAN报文外发诊断释放控制
 * @param[in] CanMsgTxOp 报文发送操作对象指针, 每路can都应有独立的结构体指针
 *
 * @warning 该接口只能由诊断调用.功能部分不可使用
 *
 * 示例
 @code
     CANFD_TX_DiagCtrlRelease(&CAN0_TX_Option);
 @endcode
 *
 * @since 1.0.0
 */
void CANFD_TX_DiagCtrlRelease(st_CanFDMsgTxOp *CanMsgTxOp)
{
    CanMsgTxOp->u8CAN_TX_ENABLE &= ~(0x01u << 7);
}
/**
 * @brief CAN报文外发控制
 * @param[in] CanMsgTxOp 报文发送操作对象指针, 每路can都应有独立的结构体指针
 * @param[in] TX_enable  报文外发状态控制
 * - CANFD_N_TX_Enable 使能发送
 * - CANFD_N_TX_Disable 禁止发送
 *
 * @warning None
 *
 * 示例
 @code
     CANFD_TX_SetEnable(&CAN0_TX_Option,CANFD_N_TX_Enable);
 @endcode
 *
 * @since 1.0.1
 */
void CANFD_TX_SetEnable(st_CanFDMsgTxOp *CanMsgTxOp, CANFD_TX_Status_t TX_enable)
{
    if ( (CanMsgTxOp->u8CAN_TX_ENABLE & 0x80u) == 0x80u )
    {
    }
    else
    {
        CanMsgTxOp->u8CAN_TX_ENABLE = ( canfdlib_uint8_t )TX_enable;
    }
}
/**
 * @brief CAN报文外发状态读取
 * @param[in] CanMsgTxOp 报文发送操作对象指针, 每路can都应有独立的结构体指针
 * @return  当前CAN通道TX状态
 * @ref  0X00U 禁止发送
 * @ref  0X55U/0xD5 允许发送
 * @warning NONE
 *
 * 示例
 @code
    CANFD_TX_Status_t CAN_CH_TX_Sts = CANFD_TX_ReadEnableSts(&CAN0_TX_Option);
 @endcode
 *
 * @since 1.0.1
 */
CANFD_TX_Status_t CANFD_TX_ReadEnableSts(st_CanFDMsgTxOp *CanMsgTxOp)
{
    return ( CANFD_TX_Status_t )CanMsgTxOp->u8CAN_TX_ENABLE;
}
/**
 * @brief CAN报文外发逻辑模块初始化
 * @param[in] CanMsgTxOp 报文发送操作对象指针, 每路can都应有独立的结构体指针
 * @param[in] Array 报文发送属性列表,按CAN通道区分,各自独立
 * @param[in] length 发送报文总数量,按CAN通道区分,各自独立
 * @param[in] pfunc 底层发送回调函数,每路can都应有独立的结构体指针
 *
 * @return  发送模块初始化结果
 * - CANFD_ERR_OK 初始化成功
 * - CANFD_ERR_ParaInit 初始化失败
 *
 * @warning 此函数必须先于CAN模块硬件驱动调用
 *
 * 示例
 @code
    #pragma alignvar(8)
    uint32_t pTXBuff [ CAN_TX_MSG_Block * ID_TOTAL_MAX ];
    void COM_CAN_Init(void)
    {
        memset(pTXBuff, 0, sizeof(pTXBuff));
        CAN_CH0_CanMsgTxOp.CanMsg=pTXBuff;
        CANFD_FUNC_ERR_t CAN_CH_TX_Ret = CanFD_TX_BuffInit(&CAN0_TX_Option,CAN_CH0_CANSendAttr,CAN_CH0_ID_SEND_TOTAL,Can0_Write);
    }
 @endcode
 *
 * @since 1.0.0
 */
CANFD_FUNC_ERR_t CanFD_TX_BuffInit(st_CanFDMsgTxOp *CanMsgTxOp, const st_CANFD_SendAttribute *Array, canfdlib_uint16_t length, HAL_CANFD_Send pfunc)
{
    canfdlib_uint8_t i             = 0u;
    canfdlib_uint8_t j             = 0u;
    CANFD_FUNC_ERR_t ret           = CANFD_ERR_OK;
    CanMsgTxOp->pCAN_SendAttribute = Array;
    /*     CanMsgTxOp->CanMsg             = ( st_CANFD_SendOperation             *)(( void             *)MemSpace); */
    CanMsgTxOp->Total_Msg       = length;
    CanMsgTxOp->Can_Write       = pfunc;
    CanMsgTxOp->u8CAN_TX_ENABLE = 0X00U;
    for ( i = 0u; i < CanMsgTxOp->Total_Msg; i++ )
    {
        CanMsgTxOp->CanMsg [ i ].u32MsgID     = CanMsgTxOp->pCAN_SendAttribute [ i ].u32MsgID;
        CanMsgTxOp->CanMsg [ i ].u32Timer     = CanMsgTxOp->pCAN_SendAttribute [ i ].u32MsgCycleOffset;
        CanMsgTxOp->CanMsg [ i ].u32MsgCycle  = CanMsgTxOp->pCAN_SendAttribute [ i ].u32MsgCycle;
        CanMsgTxOp->CanMsg [ i ].u32SendCnt   = CanMsgTxOp->pCAN_SendAttribute [ i ].u32InitSendCnt;
        CanMsgTxOp->CanMsg [ i ].u8MsgSTD_EXT = CanMsgTxOp->pCAN_SendAttribute [ i ].u8MsgSTD_EXT;
        CanMsgTxOp->CanMsg [ i ].u8MsgPro     = CanMsgTxOp->pCAN_SendAttribute [ i ].u8MsgPro;
        CanMsgTxOp->CanMsg [ i ].u16MsgDLC    = CAN0_FD_DLC_ChangeTo_Register(CanMsgTxOp->pCAN_SendAttribute [ i ].u8MsgDLC);
        CanMsgTxOp->CanMsg [ i ].u8TXMsgType  = CanMsgTxOp->pCAN_SendAttribute [ i ].u8TXMsgType;
        CanMsgTxOp->CanMsg [ i ].u8MsgRet     = 0u;

        /*
        发送周期是 0表示纯事件型报文    DIM counter 需要是0
        发送周期不是 0 分为如下两种
        1.周期报文  DIM 无意义 初始化成0
        2.周期事件型 DIM 初始化成0xffff
        */
        if ( CanMsgTxOp->pCAN_SendAttribute [ i ].u32MsgCycle != 0ul )
        {
            if ( CanMsgTxOp->pCAN_SendAttribute [ i ].u8TXMsgType == 0u )
            {
                CanMsgTxOp->CanMsg [ i ].u16TXMsgDIMcounter = 0xffffu;
            }
            else
            {
                CanMsgTxOp->CanMsg [ i ].u16TXMsgDIMcounter = 0xffffu;
            }
        }
        else
        {
            if ( CanMsgTxOp->pCAN_SendAttribute [ i ].u8TXMsgType != 0u )
            {
                CanMsgTxOp->CanMsg [ i ].u16TXMsgDIMcounter = 0u;
            }
            else
            {
                CanMsgTxOp->CanMsg [ i ].u16TXMsgDIMcounter = 0u;
                /*while (1u)*/
                {
                    ret = CANFD_ERR_ParaInit;
                    /*这里不应该达到,不应该有这个组合,写的不对,早死早超生吧*/
                    /*你在表格里定义了一个周期型的报文,你发送周期还给我填个0.
                     * 还是死这里吧.别出去霍霍人了.*/
                }
            }
        }

        for ( j = 0u; j < CanMsgTxOp->CanMsg [ i ].u16MsgDLC; j++ )
        {
            CanMsgTxOp->CanMsg [ i ].u8MsgBuff [ j ] = 0u;
        }
        if ( CanMsgTxOp->pCAN_SendAttribute [ i ].MsgBufferSet != (( void * )0) )
        {
            CanMsgTxOp->pCAN_SendAttribute [ i ].MsgBufferSet(CanMsgTxOp->CanMsg [ i ].u8MsgBuff);
        }
    }
    return ret;
}

void CanFD_Msg_TX_SetMsgBuffer(st_CanFDMsgTxOp *CanMsgTxOp, canfdlib_uint32_t u32TxMsgIdx, canfdlib_uint8_t CopyLength, canfdlib_uint8_t Msg [])
{
    canfdlib_uint8_t i = 0u;
    canfdlib_uint8_t j = 0u;

    if ( u32TxMsgIdx < CanMsgTxOp->Total_Msg )
    {

        for ( j = 0u; j < CopyLength; j++ )
        {
            CanMsgTxOp->CanMsg [ u32TxMsgIdx ].u8MsgBuff [ j ] = Msg [ j ];
        }
    }
}

/**
 * @brief CAN报文外发逻辑
 * @param[in] CanMsgTxOp 报文发送操作对象指针, 每路can都应有独立的结构体指针
 * @param[in] u32CbkCycle 报文发送逻辑调用周期,单位us.
 *
 * @warning 此函数必须先于CAN模块硬件驱动调用
 *
 * 示例
 @code
    CanFD_Write_Fun(&CAN0_TX_Option,50u);
 @endcode
 *
 * @since 1.0.0
 */
void CanFD_Write_Fun(st_CanFDMsgTxOp *CanMsgTxOp, canfdlib_uint32_t u32CbkCycle)
{
    canfdlib_uint8_t i = 0u;
    canfdlib_uint8_t j = 0u;
    st_CANFD_Msg     m_Msg;
    if ( (CanMsgTxOp->u8CAN_TX_ENABLE & 0x7Fu) == 0X55U )
    {
        for ( i = 0u; i < CanMsgTxOp->Total_Msg; i++ )
        {
            if ( CanMsgTxOp->CanMsg [ i ].u8TXMsgType == 0u )
            {
                if ( CanMsgTxOp->CanMsg [ i ].u32Timer < CanMsgTxOp->CanMsg [ i ].u32MsgCycle )
                {
                    CanMsgTxOp->CanMsg [ i ].u32Timer += u32CbkCycle;
                }
                else
                {
                    if ( CanMsgTxOp->CanMsg [ i ].u32SendCnt <= 0xffff0000ul )
                    {
                        CanMsgTxOp->CanMsg [ i ].u32SendCnt++;
                    }
                    if ( CanMsgTxOp->CanMsg [ i ].u8MsgRet == 0U )
                    {
                        for ( j = 0u; j < CanMsgTxOp->CanMsg [ i ].u16MsgDLC; j++ )
                        {
                            CanMsgTxOp->CanMsg [ i ].u8MsgBuff [ j ] = 0u;
                        }
                        if ( CanMsgTxOp->pCAN_SendAttribute [ i ].MsgBufferSet != (( void * )0) )
                        {
                            CanMsgTxOp->pCAN_SendAttribute [ i ].MsgBufferSet(CanMsgTxOp->CanMsg [ i ].u8MsgBuff);
                        }
                    }
                    /*  Below HW SEND INTERFACE */
                    m_Msg.MsgID  = CanMsgTxOp->CanMsg [ i ].u32MsgID;
                    m_Msg.MsgStd = CanMsgTxOp->CanMsg [ i ].u8MsgSTD_EXT;
                    m_Msg.MsgRTR = 0u;
                    m_Msg.MsgDLC = ( canfdlib_uint8_t )CanMsgTxOp->CanMsg [ i ].u16MsgDLC;
                    m_Msg.MsgPro = CanMsgTxOp->CanMsg [ i ].u8MsgPro;

                    for ( j = 0u; j < CanMsgTxOp->CanMsg [ i ].u16MsgDLC; j++ )
                    {
                        m_Msg.Msg [ j ] = Load_AttrBuff [ i ].sig.Msg [ j ];
                    }

                    if ( CanMsgTxOp->Can_Write != (( void * )0) )
                    {
                        CanMsgTxOp->CanMsg [ i ].u8MsgRet = CanMsgTxOp->Can_Write(&m_Msg);
                    }

                    if ( CanMsgTxOp->CanMsg [ i ].u8MsgRet == 0U )
                    {
                        CanMsgTxOp->CanMsg [ i ].u32Timer = 0u;
                    }
                    else
                    {
                        CanMsgTxOp->CanMsg [ i ].u32Timer -= u32CbkCycle;
                    }
                }
            }
            else
            {
                if ( CanMsgTxOp->CanMsg [ i ].u32MsgCycle != 0x00ul )
                {
                    if ( CanMsgTxOp->CanMsg [ i ].u16TXMsgDIMcounter != 0x00ul )
                    {
                        if ( (CanMsgTxOp->CanMsg [ i ].u16TXMsgDIMcounter != CanMsgTxOp->CanMsg [ i ].u32SendCnt) || (CanMsgTxOp->CanMsg [ i ].u16TXMsgDIMcounter == 0xffffu) )
                        {
                            if ( CanMsgTxOp->CanMsg [ i ].u32Timer < CanMsgTxOp->CanMsg [ i ].u32MsgCycle )
                            {
                                CanMsgTxOp->CanMsg [ i ].u32Timer += u32CbkCycle;
                            }
                            else
                            {
                                CanMsgTxOp->CanMsg [ i ].u32Timer = 0u;
                                if ( CanMsgTxOp->CanMsg [ i ].u32SendCnt <= 0xffff0000ul )
                                {
                                    CanMsgTxOp->CanMsg [ i ].u32SendCnt++;
                                }
                                for ( j = 0u; j < CanMsgTxOp->CanMsg [ i ].u16MsgDLC; j++ )
                                {
                                    CanMsgTxOp->CanMsg [ i ].u8MsgBuff [ j ] = 0u;
                                }
                                if ( CanMsgTxOp->pCAN_SendAttribute [ i ].MsgBufferSet != (( void * )0) )
                                {
                                    CanMsgTxOp->pCAN_SendAttribute [ i ].MsgBufferSet(CanMsgTxOp->CanMsg [ i ].u8MsgBuff);
                                }
                                /*  Below HW SEND INTERFACE */
                                m_Msg.MsgID  = CanMsgTxOp->CanMsg [ i ].u32MsgID;
                                m_Msg.MsgStd = CanMsgTxOp->CanMsg [ i ].u8MsgSTD_EXT;
                                m_Msg.MsgRTR = 0u;
                                m_Msg.MsgDLC = ( canfdlib_uint8_t )CanMsgTxOp->CanMsg [ i ].u16MsgDLC;
                                m_Msg.MsgPro = CanMsgTxOp->CanMsg [ i ].u8MsgPro;

                                for ( j = 0u; j < CanMsgTxOp->CanMsg [ i ].u16MsgDLC; j++ )
                                {
                                    m_Msg.Msg [ j ] = CanMsgTxOp->CanMsg [ i ].u8MsgBuff [ j ];
                                }
                                if ( CanMsgTxOp->Can_Write != (( void * )0) )
                                {
                                    CanMsgTxOp->CanMsg [ i ].u8MsgRet = CanMsgTxOp->Can_Write(&m_Msg);
                                }
                                if ( CanMsgTxOp->CanMsg [ i ].u8MsgRet == 0U )
                                {
                                    CanMsgTxOp->CanMsg [ i ].u32Timer = 0u;
                                }
                                else
                                {
                                    CanMsgTxOp->CanMsg [ i ].u32Timer -= u32CbkCycle;
                                }
                            }
                        }
                        else
                        {
                            if ( CanMsgTxOp->pCAN_SendAttribute [ i ].u32MsgCycle != 0ul )
                            {
                                CanMsgTxOp->CanMsg [ i ].u16TXMsgDIMcounter = 0xffffu;
                                CanMsgTxOp->CanMsg [ i ].u32MsgCycle        = CanMsgTxOp->pCAN_SendAttribute [ i ].u32MsgCycle;
                            }
                            else
                            {
                                CanMsgTxOp->CanMsg [ i ].u16TXMsgDIMcounter = 0u;
                                CanMsgTxOp->CanMsg [ i ].u32MsgCycle        = 0ul;
                            }
                            CanMsgTxOp->CanMsg [ i ].u32SendCnt = 0ul;
                        }
                    }
                }
            }
        }
    }
}

/**
* @brief CAN报文修改外发属性,重点针对周期事件型,变周期
* @param[in] CanMsgTxOp 报文发送操作对象指针, 每路can都应有独立的结构体指针
* @param[in] u32TxMsgIdx 要修改的报文序号,非报文ID,枚举里的ID名
* @param[in] u16TxMSgDIMcounter 要改变周期发多少帧
* @param[in] u32TxMsgCycle 期望改成多少周期
* @return  当前CAN通道TX状态
* @ref CANFD_ERR_OK 设置正确
* @ref CANFD_ERR_ParaInit 设置类型不正确,
* @ref CANFD_ERR_OUTRANGE 参数色值超限
* @warning 此函数改一次调用一次,持续调用就发不出去了
*
* 示例
@code
    //3号报文,以1ms周期发5帧,之后恢复到表格里默认的设置
    CANFD_FUNC_ERR_t CAN_Ret=CanFD_Msg_Tx_Overwrite(&CAN0_TX_Option,3u,5u,1000u);
@endcode
*
* @since 1.0.0
*/
CANFD_FUNC_ERR_t CanFD_Msg_Tx_Overwrite(st_CanFDMsgTxOp *CanMsgTxOp, canfdlib_uint32_t u32TxMsgIdx, canfdlib_uint16_t u16TxMSgDIMcounter, canfdlib_uint32_t u32TxMsgCycle)
{
    CANFD_FUNC_ERR_t Ret = CANFD_ERR_OK;
    if ( u32TxMsgIdx < CanMsgTxOp->Total_Msg )
    {
        if ( CanMsgTxOp->CanMsg [ u32TxMsgIdx ].u8TXMsgType != 0u )
        {
            CanMsgTxOp->CanMsg [ u32TxMsgIdx ].u16TXMsgDIMcounter = u16TxMSgDIMcounter;
            CanMsgTxOp->CanMsg [ u32TxMsgIdx ].u32MsgCycle        = u32TxMsgCycle;
            CanMsgTxOp->CanMsg [ u32TxMsgIdx ].u32SendCnt         = 0ul;
        }
        else
        {
            Ret = CANFD_ERR_ParaInit;
        }
    }
    else
    {
        Ret = CANFD_ERR_OUTRANGE;
    }
    return Ret;
}
/**
* @brief CAN报文修改指定外发报文定时器
* @param[in] CanMsgTxOp 报文发送操作对象指针, 每路can都应有独立的结构体指针
* @param[in] u32TxMsgIdx 要修改的报文序号,非报文ID,枚举里的ID名.
* @param[in] CurTimerCnt 当前ID的外发计时值.
* @return  当前输入参数是否正确
* @ref CANFD_ERR_OK 设置正确
* @ref CANFD_ERR_OUTRANGE 参数色值超限
* @warning 此函数改一次调用一次,持续调用就发不出去了
*
* 示例
@code
    //3号报文,当前外发计时变更为50 000 us
    CANFD_FUNC_ERR_t CAN_Ret=CanFD_Msg_TX_FastInitCycle(&CAN0_TX_Option,3u,50000ul);
@endcode
*
* @since 1.0.0
*/
CANFD_FUNC_ERR_t CanFD_Msg_TX_FastInitCycle(st_CanFDMsgTxOp *CanMsgTxOp, canfdlib_uint32_t u32TxMsgIdx, canfdlib_uint32_t CurTimerCnt)
{
    CANFD_FUNC_ERR_t Ret = CANFD_ERR_OK;
    if ( u32TxMsgIdx < CanMsgTxOp->Total_Msg )
    {
        CanMsgTxOp->CanMsg [ u32TxMsgIdx ].u32Timer = CurTimerCnt;
    }
    else
    {
        Ret = CANFD_ERR_OUTRANGE;
    }
    return Ret;
}
/**
* @brief CAN报文发送成功确认
* @param[in] CanMsgTxOp 报文发送操作对象指针, 每路can都应有独立的结构体指针
* @param[in] u32TxMsgIdx 要修改的报文序号,非报文ID,枚举里的ID名
* @warning 此函数需要对应buff发送成功时调用
*
* 示例
@code
    CanFD_Msg_TX_SUCCESS(&CAN0_TX_Option,3u);
@endcode
*
* @since 1.0.0
*/
void CanFD_Msg_TX_SUCCESS(st_CanFDMsgTxOp *CanMsgTxOp, canfdlib_uint32_t u32TxMsgIdx)
{
    if ( u32TxMsgIdx < CanMsgTxOp->Total_Msg )
    {
        if ( CanMsgTxOp->pCAN_SendAttribute [ u32TxMsgIdx ].MsgSuccess != (( void * )0) )
        {
            CanMsgTxOp->pCAN_SendAttribute [ u32TxMsgIdx ].MsgSuccess( );
        }
    }
}
/**
 * @brief CAN报文发送模块版本号
 * @return  CAN报文发送模块版本
 * @warning NONE
 * @since 1.0.0
 */
canfdlib_uint32_t Read_CANFD_TX_Version(void)
{
    return 0x0005uL;
}
#if defined(__ICCARM__) /**< IAR ARM Compiler */
const char Cur_TX_Module_Version [] = {"TX_VER=V1.0.0"};
#elif defined(__ghs__)         /**< Green Hills ARM Compiler */
const char Cur_TX_Module_Version [] = {"TX_VER=V1.0.0"};
#elif defined(__GNUC__)        /**< GNU Compiler Collection */
const char Cur_TX_Module_Version [] = {"TX_VER=V1.0.0"};
#elif defined(__DCC__)         /**< Wind River Diab Compiler */
const char Cur_TX_Module_Version [] = {"TX_VER=V1.0.0"};
#elif defined(__ARMCC_VERSION) /**< ARMC Compiler */
const char Cur_TX_Module_Version [] = {"TX_VER=V1.0.0"};
#elif defined(__HC12__)        /**< Codewarrior Compiler */
const char Cur_TX_Module_Version [] = {"TX_VER=V1.0.0"};
#else                          /**< VScode  */
const char Cur_TX_Module_Version [] = {"TX_VER=V1.0.0"};
#endif
