mothercup/mcm-ddc-ble/src/app_usart.c
2026-09-02 07:53:48 +08:00

584 lines
18 KiB
C

/**
* Copyright (c) 2025, NSING Technologies Inc.
*
* All rights reserved.
*
* This software is the exclusive property of NSING Technologies Inc. (Hereinafter
* referred to as NSING). This software, and the product of NSING described herein
* (Hereinafter referred to as the Product) are owned by NSING under the laws and treaties
* of the People's Republic of China and other applicable jurisdictions worldwide.
*
* NSING does not grant any license under its patents, copyrights, trademarks, or other
* intellectual property rights. Names and brands of third party may be mentioned or referred
* thereto (if any) for identification purposes only.
*
* NSING reserves the right to make changes, corrections, enhancements, modifications, and
* improvements to this software at any time without notice. Please contact NSING and obtain
* the latest version of this software before placing orders.
* Although NSING has attempted to provide accurate and reliable information, NSING assumes
* no responsibility for the accuracy and reliability of this software.
*
* It is the responsibility of the user of this software to properly design, program, and test
* the functionality and safety of any application made of this information and any resulting product.
* In no event shall NSING be liable for any direct, indirect, incidental, special,exemplary, or
* consequential damages arising in any way out of the use of this software or the Product.
*
* NSING Products are neither intended nor warranted for usage in systems or equipment, any
* malfunction or failure of which may cause loss of human life, bodily injury or severe property
* damage. Such applications are deemed, "Insecure Usage".
*
* All Insecure Usage shall be made at user's risk. User shall indemnify NSING and hold NSING
* harmless from and against all claims, costs, damages, and other liabilities, arising from or related
* to any customer's Insecure Usage.
* Any express or implied warranty with regard to this software or the Product, including,but not
* limited to, the warranties of merchantability, fitness for a particular purpose and non-infringement
* are disclaimed to the fullest extent permitted by law.
* Unless otherwise explicitly permitted by NSING, anyone may not duplicate, modify, transcribe
* or otherwise distribute this software for any purposes, in whole or in part.
*
* NSING products and technologies shall not be used for or incorporated into any products or systems
* whose manufacture, use, or sale is prohibited under any applicable domestic or foreign laws or regulations.
* User shall comply with any applicable export control laws and regulations promulgated and administered by
* the governments of any countries asserting jurisdiction over the parties or transactions.
**/
/**
* @file app_usart.c
* @author NSING Firmware Team
* @version v1.0.4
*
* @copyright Copyright (c) 2025, NSING Technologies Inc. All rights reserved.
*/
#include <string.h>
#include <stdio.h>
#include "global_func.h"
#include "app_usart.h"
#include "app_rdtss.h"
#include "ns_sleep.h"
#include "ns_log.h"
#include "ns_timer.h"
#include "ke_timer.h"
#include "app_ble.h"
#include "rdtss_task.h"
/** @addtogroup
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
uint8_t USART_rx_dma_buf[USART_RX_DMA_SIZE] = {0};
uint16_t rx_old_pos = 0;
uint8_t usart_rx_fifo_buf[USART_RX_FIFO_SIZE] = {0};
uint32_t usart_rx_fifo_in = 0;
uint32_t usart_rx_fifo_out = 0;
uint8_t usart_tx_fifo_buf[USART_TX_FIFO_SIZE] = {0};
uint32_t usart_tx_fifo_in = 0;
uint32_t usart_tx_fifo_out = 0;
uint8_t usart_sending = false;
uint8_t ble_sending = false;
uint16_t ble_att_mtu = (ATT_DEFAULT_MTU-3);
/* Private function prototypes -----------------------------------------------*/
void app_usart_tx_process(void);
/* Private functions ---------------------------------------------------------*/
/**
* @brief Configures the different system clocks.
*/
void RCC_Configuration_USART(void)
{
/* Enable GPIO clock */
GPIO_APBxClkCmd(USARTx_GPIO_CLK, ENABLE);
/* Enable USARTx Clock */
USART_APBxClkCmd(USARTx_CLK, ENABLE);
/* DMA clock enable */
RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA, ENABLE);
}
/**
* @brief Configures the different GPIO ports.
*/
void GPIO_Configuration_USART(void)
{
GPIO_InitType GPIO_InitStructure;
/* Initialize GPIO_InitStructure */
GPIO_InitStruct(&GPIO_InitStructure);
/* Configure USARTx Tx as alternate function push-pull */
GPIO_InitStructure.Pin = USARTx_TxPin;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.GPIO_Alternate = USARTx_Tx_GPIO_AF;
GPIO_InitPeripheral(USARTx_GPIO, &GPIO_InitStructure);
/* Configure USARTx Rx as alternate function push-pull */
GPIO_InitStructure.Pin = USARTx_RxPin;
GPIO_InitStructure.GPIO_Alternate = USARTx_Rx_GPIO_AF;
GPIO_InitPeripheral(USARTx_GPIO, &GPIO_InitStructure);
}
/**
* @brief Configures the DMA.
*/
void DMA_Configuration(void)
{
DMA_InitType DMA_InitStructure;
/* USARTx_Tx_DMA_Channel (triggered by USARTx Tx event) Config */
DMA_DeInit(USARTx_Tx_DMA_Channel);
DMA_RequestRemap(USARTx_Tx_DMA_REMAP, DMA, USARTx_Tx_DMA_Channel, ENABLE);
DMA_ConfigInt(USARTx_Tx_DMA_Channel,DMA_INT_TXC ,ENABLE);
/* USARTx RX DMA1 Channel (triggered by USARTx Rx event) Config */
DMA_DeInit(USARTx_Rx_DMA_Channel);
DMA_RequestRemap(USARTx_Rx_DMA_REMAP, DMA, USARTx_Rx_DMA_Channel, ENABLE);
DMA_ConfigInt(USARTx_Rx_DMA_Channel,DMA_INT_TXC|DMA_INT_HTX ,ENABLE);
DMA_InitStructure.PeriphAddr = USARTx_DAT_Base;
DMA_InitStructure.MemAddr = (uint32_t)USART_rx_dma_buf;
DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC;
DMA_InitStructure.BufSize = USART_RX_DMA_SIZE;
DMA_InitStructure.CircularMode = DMA_MODE_CIRCULAR;
DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.Priority = DMA_PRIORITY_VERY_HIGH;
DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;
DMA_Init(USARTx_Rx_DMA_Channel, &DMA_InitStructure);
}
/**
* @brief Configures the nested vectored interrupt controller.
*/
void NVIC_Configuration(void)
{
NVIC_InitType NVIC_InitStructure;
NVIC_DisableIRQ(DMA_Channel1_2_3_4_IRQn);
/* Enable the DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA_Channel1_2_3_4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_DisableIRQ(USARTx_IRQn);
/* Enable the DMA Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USARTx_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPriority = 3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief Configures the USART as 115200 8n1.
*/
void app_usart_configuration(void)
{
USART_InitType USART_InitStructure;
/* Configure and enable RCC */
RCC_Configuration_USART();
/* Configure GPIO for USART */
GPIO_Configuration_USART();
/* Configure the DMA */
DMA_Configuration();
NVIC_Configuration();
/* USARTx and USARTz configuration ------------------------------------------------------*/
USART_InitStructure.BaudRate = 115200; //921600
USART_InitStructure.WordLength = USART_WL_8B;
USART_InitStructure.StopBits = USART_STPB_1;
USART_InitStructure.Parity = USART_PE_NO;
USART_InitStructure.HardwareFlowControl = USART_HFCTRL_NONE;
USART_InitStructure.Mode = USART_MODE_RX | USART_MODE_TX;
/* Configure USARTx */
USART_Init(USARTx, &USART_InitStructure);
/* Enable USARTz Receive and Transmit interrupts */
USART_ConfigInt(USARTx, USART_INT_IDLEF, ENABLE);
/* Enable USARTx DMA Rx and TX request */
USART_EnableDMA(USARTx, USART_DMAREQ_RX | USART_DMAREQ_TX, ENABLE);
DMA_EnableChannel(USARTx_Rx_DMA_Channel, ENABLE);
/* Enable the USARTx */
USART_Enable(USARTx, ENABLE);
}
/**
* @brief enable or disable the usart dma
*/
void app_usart_dma_enable(FunctionalState Cmd)
{
if(Cmd == ENABLE)
{
ns_sleep_lock_acquire();
rx_old_pos = 0;
usart_tx_fifo_in = usart_tx_fifo_out = 0; //clean fifo
usart_rx_fifo_in = usart_rx_fifo_out = 0; //clean fifo
app_usart_configuration();
}
else{
ns_sleep_lock_release();
USART_Enable(USARTx, DISABLE);
DMA_EnableChannel(USARTx_Rx_DMA_Channel, DISABLE);
DMA_EnableChannel(USARTx_Tx_DMA_Channel, DISABLE);
/* Deinit IO of USART to save power */
GPIO_InitType GPIO_InitStructure;
/* Initialize GPIO_InitStructure */
GPIO_InitStruct(&GPIO_InitStructure);
/* Configure USARTx Tx as alternate function push-pull */
GPIO_InitStructure.Pin = USARTx_TxPin|USARTx_RxPin;
GPIO_InitStructure.GPIO_Mode = GPIO_MODE_ANALOG;
GPIO_InitStructure.GPIO_Alternate = GPIO_AF0;
GPIO_InitPeripheral(USARTx_GPIO, &GPIO_InitStructure);
}
}
/**
* @brief forward usart rx data too ble notify
*/
bool fg_rx_end = false;
void usart_forward_to_ble_loop(void)
{
uint32_t in_temp;
uint16_t ble_send_len;
uint16_t temp_len = USART_RX_FIFO_SIZE-usart_rx_fifo_out;
in_temp = usart_rx_fifo_in;
if(usart_rx_fifo_out < in_temp)
{
ble_send_len = in_temp-usart_rx_fifo_out;
}
else if(usart_rx_fifo_out > in_temp){
ble_send_len = (USART_RX_FIFO_SIZE-usart_rx_fifo_out + usart_rx_fifo_in);
fg_rx_end = true;
}
else if(usart_rx_fifo_out == in_temp){
// fifo empty, stop send loop
ble_sending = false;
return;
}
if ((app_env.max_mtu-3)> ble_att_mtu)
{
ble_att_mtu = (app_env.max_mtu-3);
}
if(ble_send_len > ble_att_mtu)
{
ble_send_len = ble_att_mtu;
}
ble_sending = true;
if (fg_rx_end && (ble_send_len > temp_len))
{
uint8_t temp_buf[512] = {0};
memcpy(&temp_buf[0],&usart_rx_fifo_buf[usart_rx_fifo_out],temp_len);
memcpy(&temp_buf[temp_len],&usart_rx_fifo_buf[0],(ble_send_len-temp_len));
#if (BLE_RDTSS_SERVER)
rdtss_send_notify(&temp_buf[0], ble_send_len);
#endif
usart_rx_fifo_out = (ble_send_len-temp_len)%USART_RX_FIFO_SIZE;
}
else
{
#if (BLE_RDTSS_SERVER)
rdtss_send_notify(&usart_rx_fifo_buf[usart_rx_fifo_out], ble_send_len);
#endif
usart_rx_fifo_out = (usart_rx_fifo_out+ble_send_len)%USART_RX_FIFO_SIZE;
}
fg_rx_end = false;
return;
}
/**
* @brief usart rx data enter fifo and active ble send first package if not active yet
*/
uint8_t app_usart_rx_data_fifo_enter(const uint8_t *p_data, uint16_t len)
{
uint32_t in_len;
//store data in fifo
while(len)
{
if(usart_rx_fifo_in >= usart_rx_fifo_out )
{
in_len = USART_RX_FIFO_SIZE-usart_rx_fifo_in;
if(in_len > len)
{
in_len = len;
}
memcpy(&usart_rx_fifo_buf[usart_rx_fifo_in],p_data,in_len);
len = len-in_len;
p_data += in_len;
usart_rx_fifo_in = (usart_rx_fifo_in + in_len)%USART_RX_FIFO_SIZE;
}
else if(usart_rx_fifo_in < usart_rx_fifo_out )
{
in_len = usart_rx_fifo_out-usart_rx_fifo_in-1;
if(in_len > len)
{
in_len = len;
}
memcpy(&usart_rx_fifo_buf[usart_rx_fifo_in],p_data,in_len);
len = len-in_len;
usart_rx_fifo_in = (usart_rx_fifo_in + in_len)%USART_RX_FIFO_SIZE;
//fifo full,drop the rest data
if(len)
{
NS_LOG_WARNING("F:%d,%d,%d\r\n",len,usart_rx_fifo_in,usart_rx_fifo_out);
}
break;
}
}
if(!ble_sending)
{
ke_timer_set(RDTSS_VAL_NTF_CFM, TASK_APP, 10);
}
return len;
}
/**
* @brief usart send data via dma
*/
uint8_t usart_tx_dma_send(uint8_t *p_data, uint16_t len)
{
DMA_InitType DMA_InitStructure;
if(usart_sending)
{
return false;
}
/* USARTx_Tx_DMA_Channel (triggered by USARTx Tx event) Config */
DMA_InitStructure.PeriphAddr = USARTx_DAT_Base;
DMA_InitStructure.MemAddr = (uint32_t)p_data;
DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST;
DMA_InitStructure.BufSize = len;
DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
DMA_InitStructure.Priority = DMA_PRIORITY_VERY_HIGH;
DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;
DMA_Init(USARTx_Tx_DMA_Channel, &DMA_InitStructure);
usart_sending = true;
DMA_EnableChannel(USARTx_Tx_DMA_Channel, ENABLE);
return true;
}
/**
* @brief usart send data in blocking mode
*/
void usart_tx_data_blocking(uint8_t *p_data, uint16_t len)
{
while(len--)
{
USART_SendData(USARTx, *p_data);
p_data++;
}
}
/**
* @brief usart tx fifo enter and active dma send out
*/
uint8_t app_usart_tx_fifo_enter(const uint8_t *p_data, uint16_t len)
{
uint32_t in_len, out_temp;
//store data in fifo
NS_LOG_DEBUG("%d,%d,%d\r\n",len,usart_tx_fifo_in,usart_tx_fifo_out);
out_temp = usart_tx_fifo_out;
while(len)
{
if(usart_tx_fifo_in >= out_temp )
{
in_len = USART_TX_FIFO_SIZE-usart_tx_fifo_in;
if(in_len > len)
{
in_len = len;
}
memcpy(&usart_tx_fifo_buf[usart_tx_fifo_in],p_data,in_len);
len = len-in_len;
p_data += in_len;
usart_tx_fifo_in = (usart_tx_fifo_in + in_len)%USART_TX_FIFO_SIZE;
}
else if(usart_tx_fifo_in < out_temp )
{
in_len = out_temp-usart_tx_fifo_in-1;
if(in_len > len)
{
in_len = len;
}
memcpy(&usart_tx_fifo_buf[usart_tx_fifo_in],p_data,in_len);
len = len-in_len;
usart_tx_fifo_in = (usart_tx_fifo_in + in_len)%USART_TX_FIFO_SIZE;
//fifo full,drop the rest data
if(len)
{
NS_LOG_WARNING("F:%d,%d,%d\r\n",len,usart_tx_fifo_in,out_temp);
}
break;
}
}
// ble treaming cut timer, active usart send after it.
ke_timer_set(APP_CUSTS_TEST_EVT, TASK_APP, 50);
return len;
}
/**
* @brief usart tx data from fifo
*/
void app_usart_tx_process(void)
{
uint32_t in_temp,len;
uint8_t *p_data;
in_temp = usart_tx_fifo_in;
if(usart_tx_fifo_out < in_temp)
{
len = in_temp-usart_tx_fifo_out;
p_data = &usart_tx_fifo_buf[usart_tx_fifo_out];
if(usart_tx_dma_send(p_data,len) == true)
{
usart_tx_fifo_out = in_temp;
}
}
else if(usart_tx_fifo_out > in_temp)
{
len = USART_TX_FIFO_SIZE-usart_tx_fifo_out;
p_data = &usart_tx_fifo_buf[usart_tx_fifo_out];
if(usart_tx_dma_send(p_data,len) == true)
{
usart_tx_fifo_out = 0;
}
}
}
/**
* @brief check the dma buffer which has been received
*/
void usart_rx_check_in_irq(void)
{
uint16_t rx_pos;
rx_pos = USART_RX_DMA_SIZE - DMA_GetCurrDataCounter(USARTx_Rx_DMA_Channel);
if(rx_pos < rx_old_pos)
{
app_usart_rx_data_fifo_enter(&USART_rx_dma_buf[rx_old_pos],(USART_RX_DMA_SIZE - rx_old_pos));
if(rx_pos > 0)
{
app_usart_rx_data_fifo_enter(&USART_rx_dma_buf[0],rx_pos);
}
rx_old_pos = rx_pos;
}
else if(rx_pos > rx_old_pos)
{
app_usart_rx_data_fifo_enter(&USART_rx_dma_buf[rx_old_pos],(rx_pos - rx_old_pos));
rx_old_pos = rx_pos;
}
else if(rx_pos != rx_old_pos)
{
//error
rx_old_pos = rx_pos;
}
}
/**
* @brief dma irq handler
*/
void DMA_Channel1_2_3_4_IRQHandler(void)
{
//TX
if(DMA_GetFlagStatus(DMA_FLAG_TC1, DMA))
{
//TX Transfer complete interrupt
usart_sending = false;
ke_msg_send_basic(APP_CUSTS_TEST_EVT, TASK_APP, TASK_APP);
DMA_ClearFlag(DMA_FLAG_TC1, DMA);
}
//RX
if(DMA_GetFlagStatus(DMA_FLAG_TC2, DMA))
{
//RX Transfer complete interrupt
DMA_ClearFlag(DMA_FLAG_TC2, DMA);
usart_rx_check_in_irq();
}
if(DMA_GetFlagStatus(DMA_FLAG_HT2, DMA))
{
//RX Half transfer interrupt
DMA_ClearFlag(DMA_FLAG_HT2, DMA);
usart_rx_check_in_irq();
}
}
/**
* @brief usart irq handler
*/
void USARTx_IRQHandler(void)
{
uint8_t temp;
//usart idlle interrupt
if(USART_GetFlagStatus(USARTx,USART_FLAG_IDLEF))
{
//read sts and data will clear rx idle interrupt
temp = USARTx->DAT;
usart_rx_check_in_irq();
(void)temp;
}
}
/**
* @}
*/