4G_module/examples/uart/src/cm_demo_uart.c

434 lines
13 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*********************************************************
* @file cm_demo_uart.c
* @brief OpenCPU UART示例
* Copyright (c) 2021 China Mobile IOT.
* All rights reserved.
* created by zyf 2021/08/30
********************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "cm_uart.h"
#include "cm_demo_uart.h"
#include "cm_iomux.h"
#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include "cm_os.h"
#include "cm_mem.h"
#include "cm_common.h"
#include "cm_sys.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define UART_BUF_LEN 1024
/****************************************************************************
* Private Types
****************************************************************************/
typedef struct{
int msg_type;
} uart_event_msg_t;
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
void cm_demo_printf(char *str, ...);
static void cm_uart_recv_task(void *param);
static int __cm_cmd_engine(char * prefix,char * uart_buf,int* uart_buf_len,char **cmd_buf,int *cmd_len);
/****************************************************************************
* Private Data
****************************************************************************/
static int rx_rev_len = 0;
static char rx_rev_data[UART_BUF_LEN] = {0};
static osThreadId_t OC_Uart_TaskHandle = NULL; //串口数据接收、解析任务Handle
static void* g_uart_sem = NULL;
static osMessageQueueId_t uart_event_queue = NULL;
static osThreadId_t uart_event_thread = NULL;
cm_uart_cmd_recv_t gstUartCmdRecv = {0}; //串口命令缓冲区
extern osEventFlagsId_t cmd_task_flag;
/****************************************************************************
* Private Functions
****************************************************************************/
/* 用于测试串口事件,用户可参考 */
static void uart_event_task(void *arg)
{
uart_event_msg_t msg = {0};
while (1)
{
if (osMessageQueueGet(uart_event_queue, &msg, NULL, osWaitForever) == osOK)
{
//cm_log_printf(0, "uart event msg type = %d\n", msg.msg_type);
if (CM_UART_EVENT_TYPE_RX_OVERFLOW & msg.msg_type)
{
cm_log_printf(0, "CM_UART_EVENT_TYPE_RX_OVERFLOW... ...");
}
}
}
}
/* 用于测试串口事件,用户可参考 */
static int uart_event_task_create(void)
{
if (uart_event_queue == NULL)
{
uart_event_queue = osMessageQueueNew(10, sizeof(uart_event_msg_t), NULL);
}
if (uart_event_thread == NULL)
{
osThreadAttr_t attr1 = {
.name = "uart_event",
.priority = UART_TASK_PRIORITY,
.stack_size = 1024,
};
uart_event_thread = osThreadNew(uart_event_task, NULL, (const osThreadAttr_t*)&attr1);
}
return 0;
}
/* 解析指令函数用于SDK测试与串口配置无关 */
static int __cm_cmd_engine(char * prefix,char * uart_buf,int* uart_buf_len,char **cmd_buf,int *cmd_len)
{
char *p1 = NULL;
char *p2 = NULL;
char *p3 = NULL;
char *temp1 = NULL;
char *temp2 = NULL;
uart_buf[*uart_buf_len] = 0;//结尾
p1 = strstr(uart_buf, prefix);
if (p1 == 0)
{
*uart_buf_len = 0;
return -1;
}
p2 = strstr(p1, "\r\n");
if (p2 == 0)
{
*uart_buf_len = 0;
return -1;
}
*cmd_len = 0;
p3 = strchr(p1, ':');
if (p3 == 0)
{
*uart_buf_len = 0;
return -1;
}
cmd_buf[(*cmd_len)++] = cm_malloc(p3 - p1 + 1 + 1);
memset(cmd_buf[*cmd_len - 1], 0, p3 - p1 + 1);
if (cmd_buf[*cmd_len - 1] == 0)
{
*uart_buf_len = 0;
return -1;
}
memcpy(cmd_buf[*cmd_len - 1], p1, (int)(p3 - p1));
temp1 = p3;
while (1)
{
if (*cmd_len >= 20)
{
*uart_buf_len = 0;
for (int j = 0; j < *cmd_len; j++)
{
cm_free(cmd_buf[j]);
}
return -1;
}
temp2 = strchr(temp1 + 1, ':');
if (temp2 == 0)
{
break;
}
if ((temp2 - temp1) < 1)
{
for (int j = 0; j < *cmd_len; j++)
{
cm_free(cmd_buf[j]);
}
*uart_buf_len = 0;
return -1;
}
cmd_buf[(*cmd_len)++] = cm_malloc(temp2 - temp1 + 1);
if (cmd_buf[*cmd_len -1] == 0)
{
for(int j = 0; j < *cmd_len; j++)
{
cm_free(cmd_buf[j]);
}
*uart_buf_len = 0;
return -1;
}
memset(cmd_buf[*cmd_len - 1], 0, temp2 - temp1);
memcpy(cmd_buf[*cmd_len - 1], temp1 + 1, temp2 - temp1 - 1);
temp1 = temp2;
}
if ((p2 - temp1 - 1) < 1)
{
for (int j = 0; j < *cmd_len; j++)
{
cm_free(cmd_buf[j]);
}
*uart_buf_len = 0;
return -1;
}
cmd_buf[(*cmd_len)++] = cm_malloc(p2 - temp1 + 1);
memset(cmd_buf[*cmd_len - 1], 0, p2 - temp1);
memcpy(cmd_buf[*cmd_len - 1], temp1 + 1, p2 - 1 - temp1);
*uart_buf_len = 0;
return 0;
}
/* 回调函数中不可输出LOG、串口打印、执行复杂任务或消耗过多资源建议以信号量或消息队列形式控制其他线程执行任务 */
static void cm_serial_uart_callback(void *param, uint32_t type)
{
uart_event_msg_t msg = {0};
if (CM_UART_EVENT_TYPE_RX_ARRIVED & type)
{
/* 收到接收事件,触发其他线程执行读取数据 */
osSemaphoreRelease(g_uart_sem);
}
if (CM_UART_EVENT_TYPE_RX_OVERFLOW & type)
{
/* 收到溢出事件,触发其他线程处理溢出事件 */
msg.msg_type = type;
if (uart_event_queue != NULL)//向队列发送数据
{
osMessageQueuePut(uart_event_queue, &msg, 0, 0);
}
}
}
/* 串口接收示例,平时使用信号量挂起,当收到接收事件后,释放信号量以触发读取任务 */
static void cm_uart_recv_task(void *param)
{
int temp_len = 0;
cm_uart_cmd_recv_t* pstUartCmdRecv = &gstUartCmdRecv;
while (1)
{
if (g_uart_sem != NULL)
{
osSemaphoreAcquire(g_uart_sem, osWaitForever);//阻塞
}
if (rx_rev_len < UART_BUF_LEN)
{
temp_len = cm_uart_read(OPENCPU_MAIN_URAT, (void*)&rx_rev_data[rx_rev_len], UART_BUF_LEN - rx_rev_len, 1000);
rx_rev_len += temp_len;
}
/* 后续用于SDK测试用户可酌情参考*/
if (g_uart_sem != NULL && (strstr(rx_rev_data, "\r\n")))
{
//处理收到数据事件
if (gstUartCmdRecv.cmd_execute == 0)
{
gstUartCmdRecv.cmd_execute ++;
if (rx_rev_len != 0)
{
if (pstUartCmdRecv->cmd_execute != 0)
{
//OC指令参数的格式是否正确
char *trai_colon_pz = NULL;
trai_colon_pz = strrchr((const char * )rx_rev_data, ':');
if ((trai_colon_pz != NULL) && ((*(trai_colon_pz + 1) == '\0') || (*(trai_colon_pz + 1) == '\r') || (*(trai_colon_pz + 1) == '\n')))
{
cm_demo_printf("formate error\n");
memset((void*)rx_rev_data, 0, sizeof(rx_rev_data));
rx_rev_len = 0;
pstUartCmdRecv->cmd_execute = 0;
continue;
}
//解析命令,如果未检测到正确的命令格式,则丢弃本次数据
if (__cm_cmd_engine("CM", rx_rev_data, &rx_rev_len, (char **)(pstUartCmdRecv->buf), &pstUartCmdRecv->len) == -1)
{
cm_demo_printf("CM CMD error\n");
memset((void*)rx_rev_data, 0, sizeof(rx_rev_data));
rx_rev_len = 0;
pstUartCmdRecv->cmd_execute = 0;
}
else
{
//清空数据缓冲,并提示主任务开始执行命令
memset((void*)rx_rev_data, 0, sizeof(rx_rev_data));
rx_rev_len = 0;
osEventFlagsSet(cmd_task_flag, 0x00000001U);
}
}
}
}
else
{
memset((void*)rx_rev_data, 0, sizeof(rx_rev_data));
rx_rev_len = 0;
cm_demo_printf("Uart busy\n");
}
}
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/* 从测试串口打印字符串 */
void cm_demo_printf(char *str, ...)
{
static char s[600]; //This needs to be large enough to store the string TODO Change magic number
va_list args;
int len;
if ((str == NULL) || (strlen(str) == 0))
{
return;
}
va_start(args, str);
len = vsnprintf((char*)s, 600, str, args);
va_end(args);
cm_uart_write(OPENCPU_MAIN_URAT, s, len, 1000);
}
/* 若要修改测试串口可在cm_common.h中修改宏定义 */
void cm_demo_uart(void)
{
int32_t ret = -1;
/* 配置参数 */
cm_uart_cfg_t config =
{
CM_UART_BYTE_SIZE_8,
CM_UART_PARITY_NONE,
CM_UART_STOP_BIT_ONE,
CM_UART_FLOW_CTRL_NONE,
CM_UART_BAUDRATE_9600,
0 //配置为普通串口模式若要配置为低功耗模式可改为1
};
/* 事件参数 */
cm_uart_event_t event =
{
CM_UART_EVENT_TYPE_RX_ARRIVED|CM_UART_EVENT_TYPE_RX_OVERFLOW, //注册需要上报的事件类型
"uart0", //用户参数
cm_serial_uart_callback //上报事件的回调函数
};
cm_log_printf(0, "uart NUM = %d demo start... ...", OPENCPU_MAIN_URAT);
/* 配置引脚复用 */
cm_iomux_set_pin_func(OPENCPU_TEST_UARTTX_IOMUX);
cm_iomux_set_pin_func(OPENCPU_TEST_UARTRX_IOMUX);
/* 注册事件和回调函数 */
ret = cm_uart_register_event(OPENCPU_MAIN_URAT, &event);
if (ret != RET_SUCCESS)
{
cm_log_printf(0, "uart register event err,ret=%d\n", ret);
return;
}
/* 开启串口 */
ret = cm_uart_open(OPENCPU_MAIN_URAT, &config);
if (ret != RET_SUCCESS)
{
cm_log_printf(0, "uart init err,ret=%d\n", ret);
return;
}
/* 配置串口唤醒 */
#if CM_OPENCPU_MODEL_ML302A
if (OPENCPU_MAIN_URAT == CM_UART_DEV_1)
{
/* 配置uart唤醒功能使能边沿检测才具备唤醒功能仅主串口具有唤醒功能用于唤醒的数据并不能被uart接收请在唤醒后再进行uart数传 */
cm_iomux_set_pin_cmd(OPENCPU_UART_WEKEUP_PIN, CM_IOMUX_PINCMD1_LPMEDEG, CM_IOMUX_PINCMD1_FUNC1_LPM_EDGE_RISE);
}
#else
if (OPENCPU_MAIN_URAT == CM_UART_DEV_0)
{
/* 配置uart唤醒功能使能边沿检测才具备唤醒功能仅主串口具有唤醒功能用于唤醒的数据并不能被uart接收请在唤醒后再进行uart数传 */
cm_iomux_set_pin_cmd(OPENCPU_UART_WEKEUP_PIN, CM_IOMUX_PINCMD1_LPMEDEG, CM_IOMUX_PINCMD1_FUNC1_LPM_EDGE_RISE);
}
#endif
cm_log_printf(0, "cm_uart_register_event start... ...\n");
/* 以下为串口接收示例,不影响串口配置,用户可酌情参考 */
osThreadAttr_t uart_task_attr = {0};
uart_task_attr.name = "uart_task";
uart_task_attr.stack_size = 2048;
uart_task_attr.priority= UART_TASK_PRIORITY;
gstUartCmdRecv.cmd_execute = 0;
if (g_uart_sem == NULL)
{
g_uart_sem = osSemaphoreNew(1, 0, NULL);
}
OC_Uart_TaskHandle = osThreadNew(cm_uart_recv_task, 0, &uart_task_attr);
uart_event_task_create();
}
/* 关闭串口 */
void cm_test_uart_close(char **cmd, int len)
{
cm_uart_dev_e dev = atoi(cmd[2]);
if (0 == cm_uart_close(dev))
{
cm_demo_printf("uart%d close is ok\n", dev);
}
else
{
cm_demo_printf("uart%d close is error\n", dev);
}
}