| | |
| | | /* |
| | | * Copyright (c) 2019-2023 Beijing Hanwei Innovation Technology Ltd. Co. and |
| | | * Copyright (c) 2019-2025 Beijing Hanwei Innovation Technology Ltd. Co. and |
| | | * its subsidiaries and affiliates (collectly called MKSEMI). |
| | | * |
| | | * All rights reserved. |
| | |
| | | #include "uwb_api.h" |
| | | #include "uci_tl_comm.h" |
| | | #include "uci_tl_task.h" |
| | | #include "math.h" |
| | | |
| | | #include "board.h" |
| | | |
| | | #if UCI_INTF_PORT == 0 |
| | | #if (UCI_INTF_PORT == 0) && (UCI_INTF_UART_WITH_IDLE_DET == 0) |
| | | |
| | | #define FINE_TUNING_FACTOR (1.3) |
| | | |
| | | #if 1 |
| | | #define UCI_PORT UART_ID0 |
| | | #define UART_BASE (UART0) |
| | | #define RX_DMA_CH (DMA_CH4) |
| | | #else |
| | | #define UCI_PORT UART_ID1 |
| | | #define UART_BASE (UART1) |
| | | #define RX_DMA_CH (DMA_CH6) |
| | | #endif |
| | | |
| | | 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_rx_callback(void *dev, uint32_t err_code); |
| | | static void uci_tx_over_callback(void *dev, uint32_t err_code); |
| | | static void uci_tl_stop_rx(void); |
| | | static void uci_tl_restart_rx(void); |
| | | #if !UCI_INTF_UART_HS |
| | | static void uci_tl_reset(void); |
| | | #endif |
| | | |
| | | extern int uci_validate(uint8_t *buf); |
| | | |
| | | uci_tl_dev_t g_uci_tl_dev = { |
| | | .uci_tl_setup = &uci_tl_setup, |
| | | #if UCI_INTF_UART_HS |
| | | .uci_tl_resume = &uci_tl_setup, |
| | | #else |
| | | .uci_tl_resume = &uci_tl_reset, |
| | | #endif |
| | | .uci_tl_rx_stop = &uci_tl_stop_rx, |
| | | .uci_tl_rx_restart = &uci_tl_restart_rx, |
| | | .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, |
| | |
| | | .int_tx = false}; |
| | | |
| | | static uint8_t recv_buff[UCI_RX_BUFF_SIZE] = {0}; |
| | | |
| | | static struct DMA_LINK_DESC_T desc = { |
| | | .dst_addr = (uint32_t)&recv_buff[UCI_HEADER_SIZE], |
| | | .nxt = NULL, |
| | | .size = UCI_RX_BUFF_SIZE - UCI_HEADER_SIZE, |
| | | }; |
| | | |
| | | const static uint8_t retry_ntf[] = {0x60, 0x01, 0x00, 0x01, 0x0A}; |
| | | |
| | | static struct UCI_TL_MSG_T *tl_up_msg = NULL; |
| | | static bool tx_idle = true; |
| | | |
| | |
| | | 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); |
| | | memset(recv_buff, 0, UCI_HEADER_SIZE); |
| | | desc.size = UCI_RX_BUFF_SIZE - UCI_HEADER_SIZE; |
| | | uart_dma_receive_with_llp(UCI_PORT, recv_buff, UCI_HEADER_SIZE, &desc, uci_rx_callback); |
| | | #endif |
| | | } |
| | | |
| | | static void uci_rx_header_callback(void *dev, uint32_t err_code) |
| | | #if !UCI_INTF_UART_HS |
| | | static void uci_tl_reset(void) |
| | | { |
| | | if (err_code != DMA_INT_TYPE_DONE) |
| | | { |
| | | uart_receive(UCI_PORT, recv_buff, UCI_HEADER_SIZE, uci_rx_header_callback); |
| | | return; |
| | | } |
| | | uart_open(UCI_PORT, &uci_uart_cfg); |
| | | } |
| | | #endif |
| | | |
| | | if (uci_validate(recv_buff)) |
| | | static void uci_tl_send_ntf(const uint8_t *msg, uint16_t len) |
| | | { |
| | | struct UCI_TL_MSG_T *p = WsfBufAlloc((uint16_t)(len + sizeof(struct UCI_TL_MSG_T))); |
| | | |
| | | if (p != NULL) |
| | | { |
| | | 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); |
| | | p->msg_length = len; |
| | | memcpy(p->msg, msg, len); |
| | | WsfQueueEnq(&g_uci_tl_dev.tl_up_queue, p); |
| | | g_uci_tl_dev.uci_tl_up_done_notify(); |
| | | } |
| | | } |
| | | |
| | | static void rx_over_callback(void *dev, uint32_t err_code) |
| | | static void uci_rx_callback(void *dev, uint32_t err_code) |
| | | { |
| | | if (err_code != DMA_INT_TYPE_DONE) |
| | | uint16_t frame_len; |
| | | uint32_t lock; |
| | | |
| | | if (err_code != DMA_INT_TYPE_DONE || (UART_BASE->STATUS & UART_STATUS_OE_MSK)) |
| | | { |
| | | return; |
| | | uci_tl_send_ntf(retry_ntf, sizeof(retry_ntf)); |
| | | goto exit; |
| | | } |
| | | |
| | | WsfTimerStop(&g_uci_tl_dev.tl_timer); |
| | | if (((recv_buff[0] >> 5) & 0x0F) > 3) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_UCI, "Unkown MT field:%X\r\n", (recv_buff[0] >> 5) & 0x0F); |
| | | goto exit; |
| | | } |
| | | |
| | | uint16_t frame_len = *(recv_buff + 3) + UCI_HEADER_SIZE; |
| | | frame_len = (uint16_t)(((*(recv_buff + 2)) << 8) + *(recv_buff + 3) + UCI_HEADER_SIZE); |
| | | |
| | | if (frame_len > UCI_RX_BUFF_SIZE) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_UCI, "Message length(%d) is too long\r\n", frame_len); |
| | | goto exit; |
| | | } |
| | | |
| | | lock = int_lock(); |
| | | |
| | | while ((UART_BASE->STATUS & (1 << 0)) && (DMA->CH[RX_DMA_CH].DATA_SIZE != 0)) |
| | | { |
| | | } |
| | | UART_BASE->CTRL0 = UART_CTRL0_FIFO_ENABLE_MSK; |
| | | while (DMA->STATUS1 & (1 << RX_DMA_CH)) |
| | | { |
| | | } |
| | | |
| | | if (((DMA->CH[RX_DMA_CH].CFG & 0x000F0000) >> 16) == 1) |
| | | { |
| | | uint32_t remain; |
| | | |
| | | if (DMA->CH[RX_DMA_CH].DATA_SIZE == 0) |
| | | { |
| | | if (DMA->CH[RX_DMA_CH].CHAIN_PTR != 0) |
| | | { |
| | | // first transmission completed, second transmission has not started yet. |
| | | remain = frame_len - UCI_HEADER_SIZE; |
| | | desc.size = remain; |
| | | } |
| | | else |
| | | { |
| | | // second transmission completed. |
| | | remain = 0; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | // second transmission started, has not finished yet. |
| | | if (frame_len > (UCI_RX_BUFF_SIZE - DMA->CH[RX_DMA_CH].DATA_SIZE)) |
| | | { |
| | | remain = frame_len - (UCI_RX_BUFF_SIZE - DMA->CH[RX_DMA_CH].DATA_SIZE); |
| | | DMA->CH[RX_DMA_CH].DATA_SIZE = remain; |
| | | } |
| | | else |
| | | { |
| | | remain = 0; |
| | | } |
| | | } |
| | | |
| | | if (remain > 0) |
| | | { |
| | | UART_BASE->CTRL0 = UART_CTRL0_FIFO_ENABLE_MSK | UART_CTRL0_DMA_MODE_MSK; |
| | | int_unlock(lock); |
| | | |
| | | mk_timer_list_start_timer(&g_uci_tl_dev.tl_timer, UCI_HS_TIMEOUT_MS, MK_TIMER_ONE_SHOT); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | UART_BASE->CTRL0 = UART_CTRL0_FIFO_ENABLE_MSK | UART_CTRL0_DMA_MODE_MSK; |
| | | int_unlock(lock); |
| | | |
| | | if (WsfQueueCount(&g_uci_tl_dev.tl_down_queue) < UCI_MAX_DL_ITEMS) |
| | | { |
| | |
| | | g_uci_tl_dev.uci_tl_down_notify(); |
| | | } |
| | | |
| | | exit: |
| | | mk_timer_list_stop_timer(&g_uci_tl_dev.tl_timer); |
| | | uart_rx_force_abort_dma(UCI_PORT, NULL); |
| | | |
| | | 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); |
| | | memset(recv_buff, 0, UCI_HEADER_SIZE); |
| | | desc.size = UCI_RX_BUFF_SIZE - UCI_HEADER_SIZE; |
| | | uart_dma_receive_with_llp(UCI_PORT, recv_buff, UCI_HEADER_SIZE, &desc, uci_rx_callback); |
| | | #endif |
| | | } |
| | | |
| | |
| | | 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); |
| | | mk_timer_list_start_timer(&g_uci_tl_dev.tl_timer, UCI_HS_TIMEOUT_MS, MK_TIMER_ONE_SHOT); |
| | | memset(recv_buff, 0, UCI_HEADER_SIZE); |
| | | desc.size = UCI_RX_BUFF_SIZE - UCI_HEADER_SIZE; |
| | | uart_dma_receive_with_llp(UCI_PORT, recv_buff, UCI_HEADER_SIZE, &desc, uci_rx_callback); |
| | | power_mode_request(POWER_UNIT_UCI_RX, POWER_MODE_SLEEP); |
| | | } |
| | | } |
| | |
| | | |
| | | static bool uci_tl_up_is_active(void) |
| | | { |
| | | if (!uart_fifo_busy(UCI_PORT) && !tx_idle) |
| | | if (!uart_tx_in_progress(UCI_PORT) && !tx_idle) |
| | | { |
| | | #if (UCI_INTF_UART_HS) |
| | | gpio_pin_set(SLAVE2HOST_HS_GPIO); |
| | |
| | | |
| | | static void uci_tl_timer_notify(void) |
| | | { |
| | | LOG_INFO(TRACE_MODULE_UCI, "UCI message rx timeout\r\n"); |
| | | |
| | | mk_timer_list_stop_timer(&g_uci_tl_dev.tl_timer); |
| | | uart_rx_force_abort_dma(UCI_PORT, NULL); |
| | | |
| | | power_mode_clear(POWER_UNIT_UCI_RX); |
| | | |
| | | uci_tl_send_ntf(retry_ntf, sizeof(retry_ntf)); |
| | | |
| | | #if (UCI_INTF_UART_HS) |
| | | rx_idle = true; |
| | | return; |
| | | #else |
| | | memset(recv_buff, 0, UCI_HEADER_SIZE); |
| | | desc.size = UCI_RX_BUFF_SIZE - UCI_HEADER_SIZE; |
| | | uart_dma_receive_with_llp(UCI_PORT, recv_buff, UCI_HEADER_SIZE, &desc, uci_rx_callback); |
| | | #endif |
| | | } |
| | | |
| | | static void uci_tl_stop_rx(void) |
| | | { |
| | | #if (UCI_INTF_UART_HS) |
| | | #else |
| | | mk_timer_list_stop_timer(&g_uci_tl_dev.tl_timer); |
| | | uart_rx_force_abort_dma(UCI_PORT, NULL); |
| | | #endif |
| | | } |
| | | |
| | | static void uci_tl_restart_rx(void) |
| | | { |
| | | #if (UCI_INTF_UART_HS) |
| | | #else |
| | | memset(recv_buff, 0, UCI_HEADER_SIZE); |
| | | desc.size = UCI_RX_BUFF_SIZE - UCI_HEADER_SIZE; |
| | | uart_dma_receive_with_llp(UCI_PORT, recv_buff, UCI_HEADER_SIZE, &desc, uci_rx_callback); |
| | | #endif |
| | | } |
| | | |