/**
 * @file        main.c
 *
 * @brief       Main program body
 *
 * @version     V1.0.0
 *
 * @date        2024-08-01
 *
 * @attention
 *
 *  Copyright (C) 2024-2025 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions
 *  and limitations under the License.
 */

/* Includes ***************************************************************/
#include "main.h"

/* Private includes *******************************************************/
#include "apm32f4xx_device_cfg.h"
#include "log.h"
#include <string.h>

/* Private macro **********************************************************/
#define CAN1_EXT_ID             0x333333U
#define CAN2_EXT_ID             0x444444U

/* Private typedef ********************************************************/

/* Private variables ******************************************************/
static const char* tag = "main";
uint8_t can1TxData[8];
uint8_t can1RxData[8];
uint8_t can2TxData[8];
uint8_t can2RxData[8];
__IO uint8_t can1RxFlag = 0U;
__IO uint8_t can2RxFlag = 0U;

/* Private function prototypes ********************************************/
static DAL_StatusTypeDef CAN1_Transfer(const void* buffer, uint32_t len);
static DAL_StatusTypeDef CAN2_Transfer(const void* buffer, uint32_t len);

/* External variables *****************************************************/
extern CAN_HandleTypeDef hcan1;
extern CAN_HandleTypeDef hcan2;

/* External functions *****************************************************/

/**
 * @brief   Main program
 *
 * @param   None
 *
 * @retval  None
 */
int main(void)
{
    uint8_t temp[8];
    uint8_t i;

    /* Device configuration */
    DAL_DeviceConfig();

    if (DAL_CAN_Start(&hcan1) != DAL_OK)
    {
        Error_Handler();
    }

    /* Activate CAN1 RX notification */
    if (DAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != DAL_OK)
    {
        Error_Handler();
    }

    if (DAL_CAN_Start(&hcan2) != DAL_OK)
    {
        Error_Handler();
    }
    
    /* Activate CAN2 RX notification */
    if (DAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING) != DAL_OK)
    {
        Error_Handler();
    }

    DAL_Delay(200);

    can1TxData[0] = 0x01U;
    can1TxData[1] = 0x02U;
    can1TxData[2] = 0x02U;
    can1TxData[3] = 0x03U;
    can1TxData[4] = 0x04U;
    can1TxData[5] = 0x05U;
    can1TxData[6] = 0x06U;
    can1TxData[7] = 0x07U;

    CAN1_Transfer(can1TxData, 8U);

    /* Infinite loop */
    while (1)
    {
        if (can1RxFlag == 1U)
        {
            memcpy(temp, can1RxData, sizeof(can1RxData));
            can1RxFlag = 0U;
            
            for (i = 0U; i < sizeof(can1RxData); i++)
            {
                LOGI(tag, "CAN1 RX DATA[%d]:0x%X\r\n", i, temp[i]);
            }
        }
        
        if (can2RxFlag == 1U)
        {
            memcpy(temp, can2RxData, sizeof(can2RxData));
            can2RxFlag = 0U;
            
            for (i = 0U; i < sizeof(can2RxData); i++)
            {
                LOGI(tag, "CAN2 RX DATA[%d]:0x%X\r\n", i, temp[i]);
            }

            can2TxData[0] = 0x11U;
            can2TxData[1] = 0x12U;
            can2TxData[2] = 0x12U;
            can2TxData[3] = 0x13U;
            can2TxData[4] = 0x14U;
            can2TxData[5] = 0x15U;
            can2TxData[6] = 0x16U;
            can2TxData[7] = 0x17U;
            CAN2_Transfer(can2TxData, 8U);
        }

        BOARD_LED_Toggle(LED2);
        DAL_Delay(500U);
    }
}

/**
 * @brief   CAN1 transmit
 *
 * @param   buffer: Pointer to data buffer to be transfer
 *
 * @param   len: length of data to be transfer
 *
 * @retval  DAL status
 */
static DAL_StatusTypeDef CAN1_Transfer(const void* buffer, uint32_t len)
{
    CAN_TxHeaderTypeDef txHeader = {0};
    uint32_t offset = 0U;
    uint32_t txMailbox = 0U;

    /* Transmission */
    txHeader.StdId              = 0x00U;
    txHeader.ExtId              = CAN1_EXT_ID;
    txHeader.RTR                = CAN_RTR_DATA;
    txHeader.IDE                = CAN_ID_EXT;
    
    while (len != 0U)
    {
        txHeader.DLC = len > 8U ? 8U : len;
        
        /* Request transmission */
        if (DAL_CAN_AddTxMessage(&hcan1, &txHeader, ((uint8_t*)buffer) + offset, &txMailbox) != DAL_OK)
        {
            return DAL_ERROR;
        }

        offset += txHeader.DLC;
        len -= txHeader.DLC;
    }

    return DAL_OK;
}

/**
 * @brief   CAN2 transmit
 *
 * @param   buffer: Pointer to data buffer to be transfer
 *
 * @param   len: length of data to be transfer
 *
 * @retval  DAL status
 */
static DAL_StatusTypeDef CAN2_Transfer(const void* buffer, uint32_t len)
{
    CAN_TxHeaderTypeDef txHeader = {0};
    uint32_t offset = 0U;
    uint32_t txMailbox = 0U;

    /* Transmission */
    txHeader.StdId              = 0x00U;
    txHeader.ExtId              = CAN2_EXT_ID;
    txHeader.RTR                = CAN_RTR_DATA;
    txHeader.IDE                = CAN_ID_EXT;
    
    while (len != 0U)
    {
        txHeader.DLC = len > 8U ? 8U : len;
        
        /* Request transmission */
        if (DAL_CAN_AddTxMessage(&hcan2, &txHeader, ((uint8_t*)buffer) + offset, &txMailbox) != DAL_OK)
        {
            return DAL_ERROR;
        }

        offset += txHeader.DLC;
        len -= txHeader.DLC;
    }

    return DAL_OK;
}

/**
 * @brief   Rx FIFO 0 message pending callback
 *
 * @param   hcan pointer to a CAN_HandleTypeDef structure that contains
 *          the configuration information for the specified CAN
 *
 * @retval  None
 */
void DAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    CAN_RxHeaderTypeDef rxHeader = {0};

    if (hcan->Instance == CAN1)
    {
        if (can1RxFlag == 0U)
        {
            memset(can1RxData, 0U, 8U);
            
            /* Get RX message */
            if (DAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, can1RxData) == DAL_OK)
            {
                can1RxFlag = 1U;
                /* Activate CAN RX notification again */
                DAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
            }
        }
    }

    if (hcan->Instance == CAN2)
    {
        if (can2RxFlag == 0U)
        {
            memset(can2RxData, 0U, 8U);
            
            /* Get RX message */
            if (DAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rxHeader, can2RxData) == DAL_OK)
            {
                can2RxFlag = 1U;
                /* Activate CAN RX notification again */
                DAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
            }
        }
    }
}
