chen
2024-11-08 cc432b761c884a0bd8e9d83db0a4e26109fc08b1
keil/include/components/uci/src/uci_uart_driver.c
对比新文件
@@ -0,0 +1,266 @@
/*
 * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and
 * its subsidiaries and affiliates (collectly called MKSEMI).
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into an MKSEMI
 *    integrated circuit in a product or a software update for such product,
 *    must reproduce the above copyright notice, this list of conditions and
 *    the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of MKSEMI nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    MKSEMI integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be
 *    reverse engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY MKSEMI "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL MKSEMI OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "wsf_queue.h"
#include "wsf_buf.h"
#include "mk_uart.h"
#include "mk_power.h"
#include "mk_misc.h"
#include "uwb_api.h"
#include "uci_tl_comm.h"
#include "uci_tl_task.h"
#include "board.h"
#if UCI_INTF_PORT == 0
#define UCI_PORT UART_ID0
static void uci_tl_up_req(void);
static void uci_tl_timer_notify(void);
static void uci_tl_setup(void);
static bool uci_tl_up_is_active(void);
static void uci_rx_header_callback(void *dev, uint32_t err_code);
static void rx_over_callback(void *dev, uint32_t err_code);
static void uci_tx_over_callback(void *dev, uint32_t err_code);
extern int uci_validate(uint8_t *buf);
uci_tl_dev_t g_uci_tl_dev = {
    .uci_tl_setup = &uci_tl_setup,
    .uci_tl_resume = &uci_tl_setup,
    .uci_tl_up_is_active = &uci_tl_up_is_active,
    .uci_tl_up_req = &uci_tl_up_req,
    .uci_tl_timer_notify = &uci_tl_timer_notify,
};
static struct UART_CFG_T uci_uart_cfg = {.parity = UART_PARITY_NONE,
                                         .stop = UART_STOP_BITS_1,
                                         .data = UART_DATA_BITS_8,
                                         .flow = UART_FLOW_CONTROL_NONE,
                                         .rx_level = UART_RXFIFO_CHAR_1,
                                         .tx_level = UART_TXFIFO_EMPTY,
                                         .baud = UCI_INTF_UART_BAUD,
                                         .dma_en = true,
                                         .int_rx = false,
                                         .int_tx = false};
static uint8_t recv_buff[UCI_RX_BUFF_SIZE] = {0};
static struct UCI_TL_MSG_T *tl_up_msg = NULL;
static bool tx_idle = true;
#if (UCI_INTF_UART_HS)
static bool rx_idle = true;
static void host2slave_gpio_callback(enum IO_PIN_T pin);
#endif
static void uci_tl_setup(void)
{
    uart_open(UCI_PORT, &uci_uart_cfg);
#if (UCI_INTF_UART_HS)
    /*Host to slave pin pull-up.   */
    io_pull_set(HOST2SLAVE_HS_GPIO, IO_PULL_UP, IO_PULL_UP_LEVEL0);
    /*Host to salve pin wake-up enalbe by low level.*/
    power_wakeup_enable((enum POWER_WAKEUP_SOURCE_T)HOST2SLAVE_HS_GPIO, POWER_WAKEUP_LEVEL_LOW);
    gpio_pin_set_dir(SLAVE2HOST_HS_GPIO, GPIO_DIR_OUT, 1);
    gpio_pin_set_dir(HOST2SLAVE_HS_GPIO, GPIO_DIR_IN, 0);
    rx_idle = true;
    gpio_enable_irq(HOST2SLAVE_HS_GPIO, GPIO_IRQ_TYPE_FALLING_EDGE, host2slave_gpio_callback);
#else
    uart_receive(UCI_PORT, recv_buff, UCI_HEADER_SIZE, uci_rx_header_callback);
#endif
}
static void uci_rx_header_callback(void *dev, uint32_t err_code)
{
    if (err_code != DMA_INT_TYPE_DONE)
    {
        uart_receive(UCI_PORT, recv_buff, UCI_HEADER_SIZE, uci_rx_header_callback);
        return;
    }
    if (uci_validate(recv_buff))
    {
        uint16_t payload_len = *(recv_buff + 3) & 0xFFU;
        if (payload_len)
        {
            WsfTimerStartMs(&g_uci_tl_dev.tl_timer, 50, WSF_TIMER_ONE_SHOT);
            uart_receive(UCI_PORT, recv_buff + UCI_HEADER_SIZE, payload_len, rx_over_callback);
        }
        else
        {
            rx_over_callback(dev, err_code);
        }
    }
    else
    {
        uart_receive(UCI_PORT, recv_buff, UCI_HEADER_SIZE, uci_rx_header_callback);
    }
}
static void rx_over_callback(void *dev, uint32_t err_code)
{
    if (err_code != DMA_INT_TYPE_DONE)
    {
        return;
    }
    WsfTimerStop(&g_uci_tl_dev.tl_timer);
    uint16_t frame_len = *(recv_buff + 3) + UCI_HEADER_SIZE;
    if (WsfQueueCount(&g_uci_tl_dev.tl_down_queue) < UCI_MAX_DL_ITEMS)
    {
        struct UCI_TL_MSG_T *p;
        if ((p = WsfBufAlloc((uint16_t)(frame_len + sizeof(struct UCI_TL_MSG_T)))) != NULL)
        {
            memcpy(p->msg, recv_buff, frame_len);
            p->msg_length = frame_len;
            WsfQueueEnq(&g_uci_tl_dev.tl_down_queue, p);
        }
        else
        {
            LOG_INFO(TRACE_MODULE_UCI, "No buff to queue cmd\r\n");
        }
    }
    /* Set UCI receive event */
    if (g_uci_tl_dev.uci_tl_down_notify != NULL)
    {
        g_uci_tl_dev.uci_tl_down_notify();
    }
    power_mode_clear(POWER_UNIT_UCI_RX);
#if (UCI_INTF_UART_HS)
    rx_idle = true;
    return;
#else
    uart_receive(UCI_PORT, recv_buff, UCI_HEADER_SIZE, uci_rx_header_callback);
#endif
}
static void uci_tx_over_callback(void *dev, uint32_t err_code)
{
    if (tl_up_msg)
    {
        WsfBufFree(tl_up_msg);
        tl_up_msg = NULL;
    }
    g_uci_tl_dev.uci_tl_up_done_notify();
}
#if (UCI_INTF_UART_HS)
static void host2slave_gpio_callback(enum IO_PIN_T pin)
{
    if (!gpio_pin_get_val(HOST2SLAVE_HS_GPIO) && rx_idle)
    {
        rx_idle = false;
        WsfTimerStartMs(&g_uci_tl_dev.tl_timer, UCI_HS_TIMEOUT_MS, WSF_TIMER_ONE_SHOT);
        uart_receive(UCI_PORT, recv_buff, UCI_HEADER_SIZE, uci_rx_header_callback);
        power_mode_request(POWER_UNIT_UCI_RX, POWER_MODE_SLEEP);
    }
}
#endif
static void uci_tl_up_req(void)
{
    if (!tx_idle)
    {
        return;
    }
    /* Get messages from the up queue */
    tl_up_msg = WsfQueueDeq(&g_uci_tl_dev.tl_up_queue);
    if (tl_up_msg != NULL)
    {
        if (tl_up_msg->msg_length == 0)
        {
            WsfBufFree(tl_up_msg);
            tl_up_msg = NULL;
            g_uci_tl_dev.uci_tl_up_done_notify();
        }
        else
        {
            tx_idle = false;
#if (UCI_INTF_UART_HS)
            gpio_pin_clr(SLAVE2HOST_HS_GPIO);
            // delay to send
            delay_us(UCI_INTF_UART_HS_DELAYED_SEND_US);
#endif
            uart_send(UCI_PORT, tl_up_msg->msg, tl_up_msg->msg_length, uci_tx_over_callback);
            power_mode_request(POWER_UNIT_UCI_TX, POWER_MODE_SLEEP);
        }
    }
    else
    {
        LOG_INFO(TRACE_MODULE_UCI, "Up queue is empty\r\n");
        g_uci_tl_dev.uci_tl_up_done_notify();
    }
}
static bool uci_tl_up_is_active(void)
{
    if (!uart_fifo_busy(UCI_PORT) && !tx_idle)
    {
#if (UCI_INTF_UART_HS)
        gpio_pin_set(SLAVE2HOST_HS_GPIO);
#endif
        tx_idle = true;
        power_mode_clear(POWER_UNIT_UCI_TX);
    }
    return !tx_idle;
}
static void uci_tl_timer_notify(void)
{
    power_mode_clear(POWER_UNIT_UCI_RX);
#if (UCI_INTF_UART_HS)
    rx_idle = true;
#endif
}
#endif