/* * Change Logs: * Date Author Notes * 2024-05-24 Slyant the first version */ #include #include #include enum work_model { WORK_NORMAL = 0, WORK_TAKE, WORK_RELEASE, WORK_TAKE_RELEASE }; static rt_err_t rx_ind(rt_device_t dev, rt_size_t size) { uart_framework_t uf = dev->user_data; rt_sem_release(uf->rx_sem); return RT_EOK; } /** * @brief 创建 UART 框架 * * 根据给定的 UART 框架配置,创建并初始化 UART 框架。 * * @param cfg UART 框架配置指针 * * @return UART 框架指针,如果创建失败则返回 RT_NULL */ uart_framework_t uart_framework_create(struct uart_framework_cfg *cfg) { rt_err_t open_result; static int rx_sem_count = 0; static int rx_mut_count = 0; char ufsem_name[RT_NAME_MAX] = { 0 }; char ufmut_name[RT_NAME_MAX] = { 0 }; uart_framework_t uf = rt_calloc(1, sizeof(struct uart_framework)); if (uf == RT_NULL) return RT_NULL; uf->uart_device = rt_device_find(cfg->uart_name); if (uf->uart_device == RT_NULL || uf->uart_device->type != RT_Device_Class_Char) { rt_free(uf); return RT_NULL; } rt_snprintf(ufsem_name, RT_NAME_MAX, "ufsem%d", rx_sem_count++); uf->rx_sem = rt_sem_create(ufsem_name, 0, RT_IPC_FLAG_FIFO); if (uf->rx_sem == RT_NULL) { rt_free(uf); return RT_NULL; } rt_snprintf(ufmut_name, RT_NAME_MAX, "ufmut%d", rx_mut_count++); uf->dev_lock = rt_mutex_create(ufmut_name, RT_IPC_FLAG_FIFO); if (uf->dev_lock == RT_NULL) { rt_sem_delete(uf->rx_sem); rt_free(uf); return RT_NULL; } uf->rx_buf = rt_calloc(1, cfg->max_frame_size); if (uf->rx_buf == RT_NULL) { rt_sem_delete(uf->rx_sem); rt_mutex_delete(uf->dev_lock); rt_free(uf); return RT_NULL; } rt_memcpy(&uf->cfg, cfg, sizeof(struct uart_framework_cfg)); #ifdef RT_USING_SERIAL_V2 open_result = rt_device_open(uf->uart_device, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING); #else #ifdef RT_SERIAL_USING_DMA /* using DMA mode first */ open_result = rt_device_open(uf->uart_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_DMA_RX); /* using interrupt mode when DMA mode not supported */ if (open_result == RT_EOK) { } else if (open_result == -RT_EIO) #endif { open_result = rt_device_open(uf->uart_device, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX); } #endif RT_ASSERT(open_result == RT_EOK); if (uf->cfg.rx_ind) { rt_device_set_rx_indicate(uf->uart_device, uf->cfg.rx_ind); } else { if (uf->uart_device->user_data == RT_NULL) { uf->uart_device->user_data = uf; rt_device_set_rx_indicate(uf->uart_device, rx_ind); } } uf->is_waiting_response = RT_FALSE; return uf; } /** * @brief 发送数据 * * 根据给定的工作模式和 UART 框架,发送数据到 UART 设备,并进入等待响应状态。 * * @param model 工作模式 * @param uf UART 框架结构体指针 * @param data 数据指针 * @param size 数据大小 * * @return 实际发送的字节数 */ static rt_size_t _send(enum work_model model, uart_framework_t uf, rt_uint8_t *data, rt_size_t size) { while (rt_tick_get() - uf->send_tick < rt_tick_from_millisecond(uf->cfg.send_interval_ms)) { rt_thread_mdelay(10); } if (model == WORK_TAKE || model == WORK_TAKE_RELEASE) { rt_mutex_take(uf->dev_lock, RT_WAITING_FOREVER); rt_sem_control(uf->rx_sem, RT_IPC_CMD_RESET, 0); while (rt_device_read(uf->uart_device, 0, &uf->rx_ch, 1)) ; } if (uf->cfg.rs485_txd) uf->cfg.rs485_txd(); rt_size_t wsize = rt_device_write(uf->uart_device, 0, data, size); if (uf->cfg.rs485_rxd) uf->cfg.rs485_rxd(); uf->send_tick = rt_tick_get(); // 重置定时器 if (model == WORK_TAKE_RELEASE) { rt_mutex_release(uf->dev_lock); } uf->is_waiting_response = RT_TRUE; return wsize; } /** * @brief 接收串口数据 * * 根据指定的工作模型,从串口框架中接收数据后,退出等待响应状态。 * * @param model 工作模型 * @param uf 串口框架对象 * @param timeout_ms 超时时间(毫秒) * @param frame_handler 数据帧处理函数 * @param out 存储处理结果的缓冲区 * @param out_size 处理结果的实际长度 * @param out_max_size 缓冲区最大容量 * * @return 错误码,RT_EOK 表示成功,其他值表示错误 */ static rt_err_t _receive(enum work_model model, uart_framework_t uf, rt_uint32_t timeout_ms, rt_uint8_t *out, rt_size_t *out_size, rt_size_t out_max_size) { // rt_memset(uf->rx_buf, 0, uf->cfg.max_frame_size); uf->rx_size = 0; uf->last_tick = rt_tick_get(); while (1) { if (rt_sem_take(uf->rx_sem, rt_tick_from_millisecond(timeout_ms)) == RT_EOK) { if (model == WORK_TAKE_RELEASE) { rt_mutex_take(uf->dev_lock, RT_WAITING_FOREVER); } while (1) { while (rt_device_read(uf->uart_device, 0, &uf->rx_ch, 1)) { uf->last_tick = rt_tick_get(); // 重置定时器 if (uf->rx_size < uf->cfg.max_frame_size) { uf->rx_buf[uf->rx_size++] = uf->rx_ch; } } if (rt_tick_get() - uf->last_tick > rt_tick_from_millisecond(uf->cfg.frame_interval_ms)) { if (uf->rx_size > 0) { if (out) { rt_memcpy(out, uf->rx_buf, uf->rx_size > out_max_size ? out_max_size : uf->rx_size); } if (out_size) { *out_size = uf->rx_size; } if (model == WORK_RELEASE || model == WORK_TAKE_RELEASE) { rt_mutex_release(uf->dev_lock); } uf->is_waiting_response = RT_FALSE; return RT_EOK; } else { break; } } rt_thread_mdelay(10); } if (model == WORK_RELEASE || model == WORK_TAKE_RELEASE) { rt_mutex_release(uf->dev_lock); } } else { if (model == WORK_RELEASE) { rt_mutex_release(uf->dev_lock); } uf->is_waiting_response = RT_FALSE; return -RT_ETIMEOUT; } } } /** * @brief 发送数据到UART框架 * * 通过UART框架发送指定大小的数据。 * * @param uf UART框架对象指针 * @param data 要发送的数据指针 * @param size 数据大小 * * @return 发送的字节数 */ rt_size_t uart_framework_send(uart_framework_t uf, rt_uint8_t *data, rt_size_t size) { return _send(WORK_NORMAL, uf, data, size); } /** * @brief UART框架发送数据(独占) * * 通过UART框架发送指定大小的数据。 * * @param uf UART框架对象 * @param data 要发送的数据指针 * @param size 要发送的数据大小 * * @return 实际发送的数据大小 */ rt_size_t uart_framework_send_take(uart_framework_t uf, rt_uint8_t *data, rt_size_t size) { return _send(WORK_TAKE, uf, data, size); } /** * @brief UART框架发送数据(独占发送后释放) * * 通过UART框架发送指定大小的数据。 * * @param uf UART框架对象指针 * @param data 要发送的数据指针 * @param size 要发送的数据大小 * * @return 实际发送的字节数 */ rt_size_t uart_framework_send_take_release(uart_framework_t uf, rt_uint8_t *data, rt_size_t size) { return _send(WORK_TAKE_RELEASE, uf, data, size); } /** * @brief 接收UART框架数据 * * 在给定的超时时间内,从UART框架中接收数据,并调用帧处理器处理接收到的数据。 * * @param uf UART框架对象 * @param timeout_ms 超时时间(毫秒) * @param out 存储处理结果的缓冲区 * @param out_size 处理结果的实际长度 * @param out_max_size 缓冲区最大容量 * * @return 返回错误码,表示操作是否成功 */ rt_err_t uart_framework_receive(uart_framework_t uf, rt_uint32_t timeout_ms, rt_uint8_t *out, rt_size_t *out_size, rt_size_t out_max_size) { return _receive(WORK_NORMAL, uf, timeout_ms, out, out_size, out_max_size); } /** * @brief UART 框架接收数据(接收后释放独占) * * 从 UART 框架收数据,通过回调函数处理接收到的数据帧。 * * @param uf UART框架对象 * @param timeout_ms 超时时间(毫秒) * @param out 存储处理结果的缓冲区 * @param out_size 处理结果的实际长度 * @param out_max_size 缓冲区最大容量 * * @return 返回错误码,表示操作是否成功 */ rt_err_t uart_framework_receive_release(uart_framework_t uf, rt_uint32_t timeout_ms, rt_uint8_t *out, rt_size_t *out_size, rt_size_t out_max_size) { return _receive(WORK_RELEASE, uf, timeout_ms, out, out_size, out_max_size); } /** * @brief UART框架接收数据(独占接收后释放) * * 从UART框架中接收数据,并在处理完成后释放相关资源。 * * @param uf UART框架对象 * @param timeout_ms 超时时间(毫秒) * @param out 存储处理结果的缓冲区 * @param out_size 处理结果的实际长度 * @param out_max_size 缓冲区最大容量 * * @return 返回错误码,表示操作是否成功 */ rt_err_t uart_framework_receive_take_release(uart_framework_t uf, rt_uint32_t timeout_ms, rt_uint8_t *out, rt_size_t *out_size, rt_size_t out_max_size) { return _receive(WORK_TAKE_RELEASE, uf, timeout_ms, out, out_size, out_max_size); } /** * @brief 在非等待响应状态,接收串口数据 * * 在非等待响应状态,从串口框架中接收数据,并在用户回调函数中处理接收到的数据帧。 * * @param uf 串口框架对象 * @param frame_handler_callback 数据帧处理回调函数 * @param out 存储处理结果的缓冲区 * @param out_size 处理结果的实际长度 * @param out_max_size 缓冲区最大容量 * * @return 返回错误码,表示操作是否成功 */ rt_err_t uart_framework_receive_without_waiting_response(uart_framework_t uf, void (*frame_handler_callback)(rt_uint8_t *data, rt_size_t size), rt_uint8_t *out, rt_size_t *out_size, rt_size_t out_max_size) { if (uf->is_waiting_response == RT_FALSE) { if (rt_sem_trytake(uf->rx_sem) == RT_EOK) { rt_mutex_take(uf->dev_lock, RT_WAITING_FOREVER); uf->rx_size = 0; uf->last_tick = rt_tick_get(); while (1) { while (rt_device_read(uf->uart_device, 0, &uf->rx_ch, 1)) { uf->last_tick = rt_tick_get(); // 重置定时器 if (uf->rx_size < uf->cfg.max_frame_size) { uf->rx_buf[uf->rx_size++] = uf->rx_ch; } } if (rt_tick_get() - uf->last_tick > rt_tick_from_millisecond(uf->cfg.frame_interval_ms)) { if (uf->rx_size > 0) { if (out) { rt_memcpy(out, uf->rx_buf, uf->rx_size > out_max_size ? out_max_size : uf->rx_size); } if (out_size) { *out_size = uf->rx_size; } if (frame_handler_callback) { frame_handler_callback(uf->rx_buf, uf->rx_size); } rt_mutex_release(uf->dev_lock); return RT_EOK; } else { break; } } rt_thread_mdelay(10); } rt_mutex_release(uf->dev_lock); } } return -RT_ERROR; }