|
|
早上一起床,家庭微信群中外公分享了一个视频号链接,标题和作者就是一股浓浓的营销号风格——"唱出了50,60,70后的心声#正能量",作者:“人生品不透的茶8072”。看来是瞄准老年人作为目标群体啊。
点进去是一个AI生成的老奶奶在唱歌,歌词大概为:“记得小时候,晚上点灯都用油。犁耙耕地都是牛,上学放学自己走。”
评论区大概是这样一个状况。
ID:“感悟”(头像荷花):唱的就是我啊。👍👍👍
ID:“平安吉祥”(头像为中老年妇女):这首歌唱的非常真实全是大突话

看着这个AI视频,听着AI歌曲,我脑海里回血起5年前看过一本小说——《这不是娱乐》,作者是“睡觉会变白”。上架于2021年6月1日,是都市类型的。
这本书是一本比较有意思的娱乐文。它讲述了在未来世界里,娱乐业的消亡——真人演员被AI生成的虚拟人所代替。
这个故事当然可以写的很长,虚拟人是怎么慢慢替代真人的?这个过程中又会发生哪些波澜壮阔的冲突?
但是作者没有这样子处理,这是他宣泄情绪之作,他只用了60W字,故事在刚要展开的时候就戛然而止。
在后记中白白写道:
娱乐文本质上就是怀旧,原创作品的除外。
怀旧的东西我在《1983》里写的太多,不想重复。
而且写完《1983》后,我发现自己越来越有书里提到的那种:信息茧房、人为的把心态变老、排斥新生事物等等。
这样很不好,所以便有了这本书。
老读者都能感受到,本书的节奏飞快,字数不多,信息量巨大,因为就没打算写太长。
主线是干翻娱乐圈,干完了就该完本,没必要再水。重建不重建的,意义不大,就那点破事儿。
女主没怎么写,因为舍弃了日常内容。叠楼的作用在书里也提过,一块精神自留地,顺便跟现世有一个参照。
其次,我也不否认成绩因素。
订阅太烂了,不仅没有增长,反而越来越少。大部分人还是习惯传统套路的娱乐文,我这种的太偏门。
所以能陪到最后的朋友们,由衷感谢了。
娱乐文呢,过去那点事已经写完了,现在和未来也写完了,对我个人而言,娱乐文没什么好写的了。
下本书应该会隔很久,我得集中精力相亲,解决我的终身大事,毕竟也老大不小的了。
就这样吧。

一曲终了,我划拉了一下手机,退出了视频。
我知道小说里描绘的那个情况,就快要发生了。
不仅仅是老年人爱看AI视频,年轻人也爱看。
B站的BV号为`BV19n4y1f7Dh`
包括还有AI歌曲。
从前的伊丽莎白鼠(B站up主),那都是古法鬼畜。
现在新的丁曲,那都是活字印刷术。

最后还有AI编程。以前那都是古法手工编程。
前面几年AI只能写一些小模块。
今年AI给我带来了真得完全不一样的体验。
在2025年的最后一个月,我尝试了vibe coding。
基本上这个月来我的代码全部由AI生成。古法编程占比20%不到。剩下的都由AI来完成。
它已经能够使用grep去搜索代码,自己理解需求,自己修改。
为此我写了一个python脚本,让mdk能够编译
编译后的报错文件生成在build_log.txt
根据这些消息,现在的AI已经能自己编译,自己修改代码了。
你只需要告诉它用`python fbtools.py build`可以编译代码。编译后的日志输出在哪个文档。
另外我特别喜欢AI写的注释,下面来展示一下AI帮我写的驱动,代码质量已经和我自己古法编程差不多,而且注释写的特别详细:
[C] 纯文本查看 复制代码 /*
* Copyright (c) 2025 by Lu Xianfan.
* @FilePath : dev_uart.c
* @Author : lxf
* @Date : 2025-12-24 09:08:16
* @LastEditors : [email]lxf_zjnb@qq.com[/email]
* @LastEditTime : 2025-12-29 15:26:26
* @Brief : UART设备驱动实现
* @features :
* - 非阻塞异步收发(基于HAL中断模式)
* - 乒乓缓冲区管理(支持连续收发)
* - RS485软件收发切换
* - IDLE中断接收(支持变长数据包)
* - 发送完成自动流控(支持队列发送)
* - 三种接收模式: 标准/零拷贝/流式 (互斥使用,自动冲突检测)
*
* @usage :
* @code
* device_t *uart = device_open("usart2");
* if (!uart) {
* return -1;
* }
*
* // ========== 方式1: 标准模式(带拷贝,简单) ==========
* // 发送数据(非阻塞)
* uint8_t tx_buf[] = "Hello UART!";
* device_write(uart, tx_buf, 0, sizeof(tx_buf));
*
* // 接收数据(非阻塞,自动释放缓冲区)
* uint8_t rx_buf[256];
* int32_t len = device_read(uart, rx_buf, 0, sizeof(rx_buf));
* if (len > 0) {
* process_data(rx_buf, len); // ✅ 无需调用 RX_DONE!
* }
*
* // ========== 方式2: 零拷贝模式(高性能) ==========
* // 接收
* struct dev_uart_buf rx_buf;
* if (device_ioctl(uart, IOCTL_UART_GET_RX_BUF, &rx_buf) == E_OK) {
* process_data(rx_buf.ptr, rx_buf.size); // 直接使用数据
* device_ioctl(uart, IOCTL_UART_RX_DONE, NULL); // 释放缓冲区
* }
*
* // 发送
* struct dev_uart_buf tx_buf;
* if (device_ioctl(uart, IOCTL_UART_GET_TX_BUF, &tx_buf) == E_OK) {
* memcpy(tx_buf.ptr, my_data, my_len); // 或直接配置 DMA
* tx_msg->pos = my_len; // 设置发送长度
* device_ioctl(uart, IOCTL_UART_TX_DONE, NULL); // 触发发送
* }
*
* // ========== 方式3: 流式模式(协议栈适配,零拷贝) ==========
* // 逐字节读取,驱动层维护游标,跨包读取
* // 适用于 Modbus 等需要单字节接收的协议栈
* uint8_t byte;
* if (device_ioctl(uart, IOCTL_UART_GET_BYTE, &byte) == E_OK) {
* // 成功读取一个字节
* }
*
* device_close(uart);
* @endcode
*
* @warning 接收模式冲突检测 - 三种接收方式互斥,只能选择一种!
* 混合使用会返回 E_BUSY / -1 错误。详见 dev_uart.h 文件头说明。
*
* @performance :
* ┌─────────────────┬──────────────────┬─────────────────┐
* │ 模式 │ 拷贝次数 │ 性能 │
* ├─────────────────┼──────────────────┼─────────────────┤
* │ 标准模式(回显) │ 2次(RX+TX各1次) │ 一般 │
* │ 零拷贝模式 │ 1次(仅RX→TX) │ 优秀 │
* │ 流式模式 │ 0次(直接访问) │ 协议栈优化 │
* └─────────────────┴──────────────────┴─────────────────┘
*
* 标准模式: 数据流 硬件→rxpp→应用层→txpp→硬件 (2次memcpy)
* 零拷贝模式: 数据流 硬件→rxpp→txpp→硬件 (1次memcpy)
* 流式模式: 数据流 硬件→rxpp→协议栈 (0次memcpy,游标管理)
*
* @transmit_flow :
* device_write("ABC")
* └─> memcpy(拷贝到txpp乒乓缓冲) [第1次拷贝]
* └─> ptransmitter==NULL? 立即发送 : 排队等待
* └─> HAL_UART_Transmit_IT("ABC")
* └─> TC中断
* └─> HAL_UART_TxCpltCallback()
* └─> device_irq_process(TX_COMPLETE)
* └─> 释放缓冲区 + 启动下一次发送
*
* @receive_flow :
* HAL_UARTEx_ReceiveToIdle_IT(启动接收)
* └─> 硬件接收数据到rxpp->pbuf
* └─> IDLE中断或缓冲区满
* └─> HAL_UARTEx_RxEventCallback()
* └─> device_irq_process(RX_COMPLETE)
* └─> 切换乒乓缓冲区, 驱动层自动重启接收
* └─> 应用层获取数据:
* ├─ 标准模式: device_read() memcpy到应用层 [第2次拷贝]
* ├─ 零拷贝模式: IOCTL_GET_RX_BUF 直接访问rxpp
* │ └─> device_ioctl(RX_DONE) 释放缓冲区
* └─ 流式模式: IOCTL_GET_BYTE 游标读取,跨包消费
*/
/*---------- includes ----------*/
#include "options.h"
#include "dev_uart.h"
#include "driver.h"
#include "device.h"
/*---------- macro ----------*/
/* 默认配置 */
#if !defined(CONFIG_UART_BUF_SIZE_RX)
#define CONFIG_UART_BUF_SIZE_RX 256
#endif
#if !defined(CONFIG_UART_BUF_SIZE_TX)
#define CONFIG_UART_BUF_SIZE_TX 256
#endif
/*---------- type define ----------*/
/*---------- variable prototype ----------*/
/*---------- function prototype ----------*/
static fp_err_t _dev_uart_open(driver_t **pdrv);
static void _dev_uart_close(driver_t **pdrv);
static int32_t _dev_uart_write(driver_t **pdrv, void *buf, uint32_t addition, uint32_t len);
static int32_t _dev_uart_read(driver_t **pdrv, void *buf, uint32_t addition, uint32_t len);
static fp_err_t _dev_uart_ioctl(driver_t **pdrv, uint32_t cmd, void *args);
static fp_err_t _dev_uart_irq_handler(driver_t **pdrv, uint32_t irq_event, void *args, uint32_t length);
/* 内部辅助函数 - IOCTL 查表回调 */
static fp_err_t ioctl_get_rx_buf(struct dev_uart_describe *self, void *arg);
static fp_err_t ioctl_get_tx_buf(struct dev_uart_describe *self, void *arg);
static fp_err_t ioctl_rx_done(struct dev_uart_describe *self, void *arg);
static fp_err_t ioctl_tx_done(struct dev_uart_describe *self, void *arg);
static fp_err_t ioctl_get_byte(struct dev_uart_describe *self, void *arg);
/*---------- variable ----------*/
DRIVER_DEFINED(
dev_uart, _dev_uart_open, _dev_uart_close, _dev_uart_write, _dev_uart_read, _dev_uart_ioctl, _dev_uart_irq_handler);
// clang-format off
static struct protocol_callback ioctl_cbs[] = {
{ IOCTL_UART_GET_RX_BUF, ioctl_get_rx_buf },
{ IOCTL_UART_GET_TX_BUF, ioctl_get_tx_buf },
{ IOCTL_UART_RX_DONE, ioctl_rx_done },
{ IOCTL_UART_TX_DONE, ioctl_tx_done },
{ IOCTL_UART_GET_BYTE, ioctl_get_byte },
};
// clang-format on
/*---------- function ----------*/
/**
* @brief 打开UART设备,分配缓冲区并初始化硬件
*/
static fp_err_t _dev_uart_open(driver_t **pdrv)
{
struct dev_uart_describe *pdesc = NULL;
fp_err_t err = E_WRONG_ARGS;
uint8_t *rxbuf = NULL, *txbuf = NULL;
uint32_t rxwantsz = 0, txwantsz = 0;
assert(pdrv != NULL);
pdesc = container_of(pdrv, device_t, pdrv)->pdesc;
do {
if (!pdesc) {
break;
}
/* 如果未设置缓冲区大小 */
if (pdesc->config.bufsz_rx == 0 || pdesc->config.bufsz_tx == 0) {
break;
}
/* 1. 分配缓冲区 */
err = E_NO_MEMORY;
if (pdesc->config.flags & DEV_UART_FLAG_PKT_MODE) {
/* DMA模式:一次性分配两个 dev_uart_msg 结构体 */
rxwantsz = (offsetof(struct dev_uart_msg, pbuf) + pdesc->config.bufsz_rx);
txwantsz = (offsetof(struct dev_uart_msg, pbuf) + pdesc->config.bufsz_tx);
rxbuf = malloc(rxwantsz * 2);
txbuf = malloc(txwantsz * 2);
if (!rxbuf || !txbuf) {
free(rxbuf);
free(txbuf);
break;
}
/* 初始化乒乓缓冲,管理完整的 struct dev_uart_msg */
pingpong_buffer_init(&pdesc->rxpp, rxbuf, rxbuf + rxwantsz);
pingpong_buffer_init(&pdesc->txpp, txbuf, txbuf + txwantsz);
/* preveiver 指向当前写入缓冲区 */
pingpong_buffer_get_write_buf(&pdesc->rxpp, (void **)&pdesc->preveiver);
}
/* 5. 调用底层硬件初始化 */
if (pdesc->ops && pdesc->ops->init) {
if (pdesc->ops->init(pdesc, &pdesc->config) != E_OK) {
err = E_ERROR;
break;
}
}
/* 6. 启动首次接收 */
if (pdesc->config.flags & DEV_UART_FLAG_PKT_MODE) {
if (pdesc->ops && pdesc->ops->start_receive) {
if (pdesc->ops->start_receive(pdesc, pdesc->preveiver->pbuf, pdesc->config.bufsz_rx) != E_OK) {
err = E_ERROR;
break;
}
}
}
err = E_OK;
} while (0);
/* 失败时释放已分配的资源 */
if (err != E_OK) {
if (txbuf) {
free(txbuf);
}
if (rxbuf) {
free(rxbuf);
}
}
return err;
}
/**
* @brief 关闭UART设备,释放资源
*/
static void _dev_uart_close(driver_t **pdrv)
{
struct dev_uart_describe *pdesc = NULL;
pdesc = container_of(pdrv, device_t, pdrv)->pdesc;
if (pdesc) {
if (pdesc->ops->deinit) {
pdesc->ops->deinit(pdesc);
}
/* 释放缓冲区 */
if (pdesc->config.flags & DEV_UART_FLAG_PKT_MODE) {
free(pdesc->txpp.buffer[0]);
free(pdesc->rxpp.buffer[0]);
}
}
}
/**
* @brief 串口发送
*/
static int32_t _dev_uart_write(driver_t **pdrv, void *buf, uint32_t addition, uint32_t len)
{
struct dev_uart_describe *pdesc = NULL;
uint8_t *pdata = (uint8_t *)buf;
uint32_t i;
fp_err_t err = E_WRONG_ARGS;
pdesc = container_of(pdrv, device_t, pdrv)->pdesc;
do {
if (!pdesc || !buf || len == 0 || !pdesc->ops) {
break;
}
if (len > pdesc->config.bufsz_tx) {
break;
}
/* RS485模式:切换到发送 */
if (pdesc->config.flags & DEV_UART_FLAG_SWRS485) {
if (pdesc->ops->control) {
pdesc->ops->control(pdesc, UART_CTRL_SET_RS485_TX, NULL);
}
}
/* DEV_UART_FLAG_PKT_MODE: 拷贝到乒乓缓冲并触发发送 */
if (pdesc->config.flags & DEV_UART_FLAG_PKT_MODE) {
struct dev_uart_msg *tx_msg = NULL;
/* 1. 拷贝数据到发送缓冲区 */
pingpong_buffer_get_write_buf(&pdesc->txpp, (void **)&tx_msg);
if (tx_msg) {
tx_msg->pos = len;
memcpy(tx_msg->pbuf, buf, len);
pingpong_buffer_set_write_done(&pdesc->txpp);
/* 2. 如果发送空闲,立即启动发送 */
if (pdesc->ptransmitter == NULL) {
pingpong_buffer_get_read_buf(&pdesc->txpp, (void **)&pdesc->ptransmitter);
if (pdesc->ptransmitter && pdesc->ops->start_transmit) {
pdesc->ops->start_transmit(pdesc, pdesc->ptransmitter->pbuf, pdesc->ptransmitter->pos);
}
}
}
}
err = E_OK;
} while (0);
return E_OK;
}
/**
* @brief 从接收缓冲区读取数据(带拷贝模式)
* @note 读取后自动释放缓冲区,无需调用 RX_DONE
* @retval >0 读取的字节数
* @retval 0 无数据
* @retval -1 接收模式冲突(已使用其他接收模式)
*/
static int32_t _dev_uart_read(driver_t **pdrv, void *buf, uint32_t addition, uint32_t len)
{
struct dev_uart_describe *pdesc = NULL;
pdesc = container_of(pdrv, device_t, pdrv)->pdesc;
int32_t retval = 0;
do {
if (!pdesc || !buf) {
break;
}
/* 检测接收模式冲突 */
if (pdesc->config.rx_mode != UART_RX_MODE_NONE && pdesc->config.rx_mode != UART_RX_MODE_STANDARD) {
retval = -1; /* 模式冲突 */
break;
}
pdesc->config.rx_mode = UART_RX_MODE_STANDARD;
/* PKT_MODE: 从乒乓缓冲区读取数据 */
if (pdesc->config.flags & DEV_UART_FLAG_PKT_MODE) {
struct dev_uart_msg *read_msg = NULL;
/* 尝试获取读取缓冲区 */
if (pingpong_buffer_get_read_buf(&pdesc->rxpp, (void **)&read_msg)) {
/* 计算实际拷贝长度 */
uint32_t copy_len = (read_msg->pos < len) ? read_msg->pos : len;
/* 拷贝数据到应用层缓冲区 */
memcpy(buf, read_msg->pbuf, copy_len);
retval = copy_len;
/* 自动释放已读缓冲区,无需应用层调用 RX_DONE */
pingpong_buffer_set_read_done(&pdesc->rxpp);
}
}
} while (0);
return retval;
}
/**
* @brief IOCTL命令处理
*/
static fp_err_t _dev_uart_ioctl(driver_t **pdrv, uint32_t cmd, void *args)
{
fp_err_t err = E_WRONG_ARGS;
struct dev_uart_describe *pdesc = NULL;
fp_err_t (*cb)(struct dev_uart_describe *, void *) = NULL;
pdesc = container_of(pdrv, device_t, pdrv)->pdesc;
do {
if (!pdesc) {
break;
}
/* 查表找到对应的回调函数 */
cb = (fp_err_t (*)(struct dev_uart_describe *, void *))protocol_callback_find(
cmd, ioctl_cbs, ARRAY_SIZE(ioctl_cbs));
if (!cb) {
break;
}
/* 执行回调 */
err = cb(pdesc, args);
} while (0);
return err;
}
/**
* @brief UART中断事件处理
* @param irq_event 中断事件类型(UART_EVENT_XXX)
*/
static fp_err_t _dev_uart_irq_handler(driver_t **pdrv, uint32_t irq_event, void *args, uint32_t length)
{
struct dev_uart_describe *pdesc = NULL;
fp_err_t err = E_WRONG_ARGS;
pdesc = container_of(pdrv, device_t, pdrv)->pdesc;
do {
if (!pdesc) {
break;
}
/* 接收完成(所有数据接收完成或缓冲区满) */
if (irq_event == DEV_UART_EVENT_RX_COMPLETE) {
/* 切换乒乓缓冲区 */
if (pdesc->config.flags & DEV_UART_FLAG_PKT_MODE) {
pdesc->preveiver->pos = length;
pingpong_buffer_set_write_done(&pdesc->rxpp);
pingpong_buffer_get_write_buf(&pdesc->rxpp, (void **)&pdesc->preveiver);
/* 驱动层主动重启接收 */
if (pdesc->ops->start_receive) {
pdesc->ops->start_receive(pdesc, pdesc->preveiver->pbuf, pdesc->config.bufsz_rx);
}
}
} else if (irq_event == DEV_UART_EVENT_RX_ERROR) {
/* 接收错误: 重启接收(不切换缓冲区) */
if (pdesc->config.flags & DEV_UART_FLAG_PKT_MODE) {
if (pdesc->ops->start_receive) {
pdesc->ops->start_receive(pdesc, pdesc->preveiver->pbuf, pdesc->config.bufsz_rx);
}
}
} else if (irq_event == DEV_UART_EVENT_TX_COMPLETE) {
/* 发送完成: 释放已发送缓冲区并启动下一次发送 */
if (pdesc->config.flags & DEV_UART_FLAG_PKT_MODE) {
/* 1. 释放已发送的缓冲区 */
pingpong_buffer_set_read_done(&pdesc->txpp);
pdesc->ptransmitter = NULL;
/* 2. RS485模式: 切换回接收 */
if (pdesc->config.flags & DEV_UART_FLAG_SWRS485) {
if (pdesc->ops->control) {
pdesc->ops->control(pdesc, UART_CTRL_SET_RS485_RX, NULL);
}
}
/* 3. 自动启动下一次发送(如果有待发送数据) */
pingpong_buffer_get_read_buf(&pdesc->txpp, (void **)&pdesc->ptransmitter);
if (pdesc->ptransmitter && pdesc->ops->start_transmit) {
/* RS485模式: 再次切换到发送 */
if (pdesc->config.flags & DEV_UART_FLAG_SWRS485) {
if (pdesc->ops->control) {
pdesc->ops->control(pdesc, UART_CTRL_SET_RS485_TX, NULL);
}
}
pdesc->ops->start_transmit(pdesc, pdesc->ptransmitter->pbuf, pdesc->ptransmitter->pos);
}
}
}
err = E_OK;
} while (0);
return err;
}
/**
* @brief IOCTL: 获取接收缓冲区(零拷贝模式)
* @retval E_OK 成功
* @retval E_WRONG_ARGS 参数错误
* @retval E_BUSY 接收模式冲突(已使用其他接收模式)
*/
static fp_err_t ioctl_get_rx_buf(struct dev_uart_describe *self, void *arg)
{
fp_err_t err = E_WRONG_ARGS;
do {
if (!self || !arg) {
break;
}
/* 检测接收模式冲突 */
if (self->config.rx_mode != UART_RX_MODE_NONE && self->config.rx_mode != UART_RX_MODE_ZERO_COPY) {
err = E_BUSY;
break;
}
self->config.rx_mode = UART_RX_MODE_ZERO_COPY;
if (self->config.flags & DEV_UART_FLAG_PKT_MODE) {
struct dev_uart_msg *read_msg = NULL;
if (pingpong_buffer_get_read_buf(&self->rxpp, (void **)&read_msg)) {
struct dev_uart_buf *buf = (struct dev_uart_buf *)arg;
buf->ptr = read_msg->pbuf;
buf->size = read_msg->pos;
err = E_OK;
}
}
} while (0);
return err;
}
/**
* @brief IOCTL: 获取发送缓冲区(零拷贝模式)
*/
static fp_err_t ioctl_get_tx_buf(struct dev_uart_describe *self, void *arg)
{
fp_err_t err = E_WRONG_ARGS;
do {
if (!self || !arg) {
break;
}
if (self->config.flags & DEV_UART_FLAG_PKT_MODE) {
struct dev_uart_msg *tx_msg = NULL;
if (pingpong_buffer_get_write_buf(&self->txpp, (void **)&tx_msg)) {
struct dev_uart_buf *buf = (struct dev_uart_buf *)arg;
buf->ptr = tx_msg->pbuf;
buf->size = self->config.bufsz_tx;
err = E_OK;
}
}
} while (0);
return err;
}
/**
* @brief IOCTL: 接收完成(零拷贝模式-释放缓冲区)
*/
static fp_err_t ioctl_rx_done(struct dev_uart_describe *self, void *arg)
{
fp_err_t err = E_WRONG_ARGS;
do {
if (!self) {
break;
}
if (self->config.flags & DEV_UART_FLAG_PKT_MODE) {
pingpong_buffer_set_read_done(&self->rxpp);
err = E_OK;
}
} while (0);
return err;
}
/**
* @brief IOCTL: 发送完成(零拷贝模式-触发发送)
*/
static fp_err_t ioctl_tx_done(struct dev_uart_describe *self, void *arg)
{
fp_err_t err = E_WRONG_ARGS;
do {
if (!self) {
break;
}
if (self->config.flags & DEV_UART_FLAG_PKT_MODE) {
struct dev_uart_msg *tx_msg = NULL;
pingpong_buffer_get_write_buf(&self->txpp, (void **)&tx_msg);
if (tx_msg) {
/* 标记写入完成 */
pingpong_buffer_set_write_done(&self->txpp);
/* 启动发送 */
if (self->ptransmitter == NULL) {
pingpong_buffer_get_read_buf(&self->txpp, (void **)&self->ptransmitter);
if (self->ptransmitter && self->ops->start_transmit) {
self->ops->start_transmit(self, self->ptransmitter->pbuf, self->ptransmitter->pos);
}
}
err = E_OK;
}
}
} while (0);
return err;
}
/**
* @brief IOCTL: 获取单字节(流式模式-用于协议栈)
* @note 驱动层维护游标,跨包读取,适合 Modbus 等需要单字节接收的协议栈
* @retval E_OK 成功读取一个字节
* @retval E_EMPTY 无数据可读
* @retval E_BUSY 接收模式冲突(已使用其他接收模式)
*/
static fp_err_t ioctl_get_byte(struct dev_uart_describe *self, void *arg)
{
fp_err_t err = E_EMPTY;
struct dev_uart_msg *msg = NULL;
uint8_t *byte = (uint8_t *)arg;
do {
if (!self || !byte) {
err = E_WRONG_ARGS;
break;
}
/* 检测接收模式冲突 */
if (self->config.rx_mode != UART_RX_MODE_NONE && self->config.rx_mode != UART_RX_MODE_STREAM) {
err = E_BUSY;
break;
}
self->config.rx_mode = UART_RX_MODE_STREAM;
if (!(self->config.flags & DEV_UART_FLAG_PKT_MODE)) {
break;
}
/* 1. 如果没有当前消息,尝试获取一个 */
if (self->stream.current_msg == NULL) {
if (!pingpong_buffer_get_read_buf(&self->rxpp, (void **)&msg)) {
err = E_EMPTY; /* 无数据 */
break;
}
self->stream.current_msg = msg;
self->stream.read_pos = 0;
}
/* 2. 检查当前消息是否读完 */
if (self->stream.read_pos >= self->stream.current_msg->pos) {
/* 读完这个包,释放并尝试获取下一个 */
pingpong_buffer_set_read_done(&self->rxpp);
self->stream.current_msg = NULL;
if (!pingpong_buffer_get_read_buf(&self->rxpp, (void **)&msg)) {
err = E_EMPTY; /* 无更多数据 */
break;
}
self->stream.current_msg = msg;
self->stream.read_pos = 0;
}
/* 3. 读取一个字节,游标后移 */
*byte = self->stream.current_msg->pbuf[self->stream.read_pos++];
err = E_OK;
} while (0);
return err;
}
/*---------- end of file ----------*/
[C] 纯文本查看 复制代码 /*
* Copyright (c) 2025 by Lu Xianfan.
* @FilePath : dev_uart.h
* @Author : lxf
* @Date : 2025-12-24 09:08:24
* @LastEditors : [email]lxf_zjnb@qq.com[/email]
* @LastEditTime : 2025-12-25 16:28:23
* @Brief : UART设备驱动框架
* @features :
* - 非阻塞异步收发(基于HAL中断模式)
* - 乒乓缓冲区管理(支持连续收发)
* - IDLE中断接收(支持变长数据包)
* - RS485软件收发切换
* - 发送完成自动流控(支持队列发送)
*
* @architecture :
* ┌─────────────────────────────────────────────┐
* │ 应用层 │
* │ device_open/write/read/ioctl/close │
* └─────────────────┬───────────────────────────┘
* │
* ┌─────────────────▼───────────────────────────┐
* │ dev_uart驱动层 │
* │ - _dev_uart_write 拷贝到txpp │
* │ - _dev_uart_read 从rxpp读取 │
* │ - _dev_uart_irq_handler 处理TX/RX事件 │
* │ - 接收完成后自动重启接收 │
* └─────────────────┬───────────────────────────┘
* │
* ┌─────────────────▼───────────────────────────┐
* │ bsp_uart硬件抽象层 │
* │ - uart_init HAL初始化 │
* │ - uart_start_transmit 启动发送 │
* │ - uart_start_receive 启动接收 │
* │ - HAL_xxxCallback 中断回调 │
* └─────────────────┬───────────────────────────┘
* │
* ┌─────────────────▼───────────────────────────┐
* │ STM32 HAL库 │
* └─────────────────────────────────────────────┘
*
* ============================================================================
* @warning 接收模式冲突检测 - 三种接收方式互斥,只能选择一种!
* ============================================================================
*
* UART驱动提供三种接收方式,共享同一个 rxpp 乒乓缓冲,混合使用会导致数据竞争:
*
* ┌────────────────┬─────────────────────────────────────────────────────────┐
* │ 接收模式 │ 使用方法 │
* ├────────────────┼─────────────────────────────────────────────────────────┤
* │ STANDARD │ device_read(uart, buf, 0, len) │
* │ (标准模式) │ 批量读取,自动释放缓冲区 │
* │ │ 适用: 一般应用,简单数据处理 │
* ├────────────────┼─────────────────────────────────────────────────────────┤
* │ ZERO_COPY │ device_ioctl(uart, IOCTL_UART_GET_RX_BUF, &rx_buf) │
* │ (零拷贝模式) │ process_data(rx_buf.ptr, rx_buf.size) │
* │ │ device_ioctl(uart, IOCTL_UART_RX_DONE, NULL) │
* │ │ 适用: 大数据量,回显,DMA转发 │
* ├────────────────┼─────────────────────────────────────────────────────────┤
* │ STREAM │ device_ioctl(uart, IOCTL_UART_GET_BYTE, &byte) │
* │ (流式模式) │ 逐字节读取,驱动层维护游标,跨包读取 │
* │ │ 适用: Modbus/其他需要单字节接收的协议栈 │
* └────────────────┴─────────────────────────────────────────────────────────┘
*
* 冲突检测机制:
* - 首次调用任一接收接口时,自动锁定对应模式
* - 后续调用其他模式的接口时,返回 E_BUSY / -1 错误
* - 模式锁定状态保存在 config.rx_mode 中
*
* 示例:
* @code
* device_t *uart = device_open("usart2");
*
* // 正确: 只使用 STREAM 模式
* uint8_t byte;
* device_ioctl(uart, IOCTL_UART_GET_BYTE, &byte); // 锁定 STREAM 模式
*
* // 错误: 混合使用模式
* device_read(uart, buf, 0, len); // 返回 -1 (模式冲突)
* @endcode
*/
#ifndef __DEV_UART_H__
#define __DEV_UART_H__
#ifdef __cplusplus
extern "C" {
#endif
/*---------- includes ----------*/
#include "define.h"
#include <stdint.h>
#include <stdbool.h>
#include "device.h"
#include "pingpong.h"
/*---------- macro ----------*/
/* IOCTL 命令定义 */
#define IOCTL_UART_GET_RX_BUF (IOCTL_USER_START + 0x00) /* 获取接收缓冲区(零拷贝) */
#define IOCTL_UART_GET_TX_BUF (IOCTL_USER_START + 0x01) /* 获取发送缓冲区(零拷贝) */
#define IOCTL_UART_RX_DONE (IOCTL_USER_START + 0x02) /* 接收完成(零拷贝模式-释放缓冲区) */
#define IOCTL_UART_TX_DONE (IOCTL_USER_START + 0x03) /* 发送完成(零拷贝模式-触发发送) */
#define IOCTL_UART_GET_BYTE (IOCTL_USER_START + 0x04) /* 获取单字节(流式模式-用于协议栈) */
/* UART 标志位 */
#define DEV_UART_FLAG_SWRS485 (1 << 0) /* 软件RS485模式,收发切换由软件控制 */
#define DEV_UART_FLAG_PKT_MODE (1 << 1) /* 使用整包收发模式(IDLE或者DMA),内部采用乒乓缓冲 */
/*---------- type define ----------*/
/*---------- variable prototype ----------*/
/*---------- function prototype ----------*/
struct dev_uart_describe; /* 前向声明 */
/**
* @brief UART 接收模式 (用于 config.rx_mode,三种模式互斥,只能选择一种)
* @note 三种接收方式共享同一个 rxpp 乒乓缓冲,混合使用会导致数据竞争
*
* @verbatim
* 模式1: UART_RX_MODE_STANDARD - 标准模式(带拷贝,简单易用)
* device_read(uart, buf, 0, len) → 批量读取,自动释放缓冲区
* 适用场景: 一般应用,简单数据处理
*
* 模式2: UART_RX_MODE_ZERO_COPY - 零拷贝模式(高性能)
* device_ioctl(uart, IOCTL_UART_GET_RX_BUF, &rx_buf) → 获取缓冲区
* process_data(rx_buf.ptr, rx_buf.size) → 直接处理
* device_ioctl(uart, IOCTL_UART_RX_DONE, NULL) → 释放缓冲区
* 适用场景: 大数据量,回显,DMA转发
*
* 模式3: UART_RX_MODE_STREAM - 单字节流式模式(协议栈适配)
* device_ioctl(uart, IOCTL_UART_GET_BYTE, &byte) → 逐字节读取
* 驱动层维护游标,跨包读取
* 适用场景: Modbus/其他需要单字节接收的协议栈
* @endverbatim
*
* @warning 三种模式互斥,只能选择一种!混合使用会返回 E_BUSY 错误
*/
enum uart_rx_mode {
UART_RX_MODE_NONE = 0, /* 未使用接收功能 */
UART_RX_MODE_STANDARD, /* 标准模式: device_read() */
UART_RX_MODE_ZERO_COPY, /* 零拷贝模式: IOCTL_GET_RX_BUF/DONE */
UART_RX_MODE_STREAM, /* 流式模式: IOCTL_GET_BYTE */
};
/**
* @brief UART 硬件控制命令 (ops->control 使用)
*/
enum {
UART_CTRL_SET_RS485_TX, /* RS485 切换到发送模式 */
UART_CTRL_SET_RS485_RX, /* RS485 切换到接收模式 */
};
/**
* @brief UART 中断事件类型 (IRQ Handler 入参)
*/
enum {
DEV_UART_EVENT_TX_COMPLETE, /* 发送物理完成 (TC) - 所有位发完,用于RS485切向 */
DEV_UART_EVENT_RX_COMPLETE, /* 接收完成 - IDLE中断或DMA完成 */
DEV_UART_EVENT_RX_ERROR, /* 接收错误 - ORE/FE/NE/PE等错误,需要重启接收 */
};
/**
* @brief UART 缓冲区描述(用于零拷贝模式)
*/
struct dev_uart_buf {
uint8_t *ptr; /* 缓冲区指针 */
uint32_t size; /* 缥冲区大小或数据长度 */
};
/**
* @brief UART 配置结构体
*/
struct dev_uart_config {
uint32_t baudrate; /* 波特率: 9600, 19200, 38400, 57600, 115200等 */
uint32_t databits; /* 数据位: 8, 9 */
uint32_t stopbits; /* 停止位: 1, 2 */
uint32_t parity; /* 校验位: 0=None, 1=Odd, 2=Even */
uint32_t bufsz_rx; /* 软件接收FIFO大小 */
uint32_t bufsz_tx; /* 软件发送FIFO大小 */
uint32_t flags; /* UART标志位: DEV_UART_FLAG_XXX */
enum uart_rx_mode rx_mode; /* 接收模式: UART_RX_MODE_XXX (默认 STANDARD) */
};
/**
* @brief UART 底层硬件操作接口
*/
struct dev_uart_ops {
/**
* @brief 硬件初始化
* @param self UART设备描述符指针
* @param cfg 配置参数
* @return E_OK=成功,其他=失败
*/
fp_err_t (*init)(struct dev_uart_describe *self, struct dev_uart_config *cfg);
/**
* @brief 硬件反初始化
* @param {dev_uart_describe} *self UART设备描述符指针
* @return {*}
*/
void (*deinit)(struct dev_uart_describe *self);
/**
* @brief 控制操作(开关中断、RS485方向控制等)
* @param self UART设备描述符指针
* @param cmd 控制命令
* @param arg 命令参数
* @return E_OK=成功,其他=失败
*/
fp_err_t (*control)(struct dev_uart_describe *self, uint32_t cmd, void *arg);
/**
* @brief 启动异步发送
* @param self UART设备描述符指针
* @param buf 要发送的数据缓冲区
* @param len 发送长度
* @note 发送完成后会触发DEV_UART_EVENT_TX_COMPLETE事件
*/
void (*start_transmit)(struct dev_uart_describe *self, uint8_t *buf, uint32_t len);
/**
* @brief 启动异步接收
* @param self UART设备描述符指针
* @param buf 接收缓冲区
* @param len 缓冲区大小
* @return E_OK=成功,其他=失败
* @note 接收完成后会触发DEV_UART_EVENT_RX_COMPLETE事件
*/
fp_err_t (*start_receive)(struct dev_uart_describe *self, uint8_t *buf, uint32_t len);
};
struct dev_uart_msg {
uint32_t pos;
uint8_t pbuf[];
};
/**
* @brief UART 设备描述符
*/
struct dev_uart_describe {
struct dev_uart_config config; /* 配置参数 */
struct dev_uart_ops *ops; /* 底层硬件操作接口指针 */
void *hw_handle; /* 硬件接口 */
/* 私有变量不需要用户初始化 */
struct dev_uart_msg *preveiver; /* 指向当前接收的 dev_uart_msg */
struct dev_uart_msg *ptransmitter; /* 指向当前发送的 dev_uart_msg */
struct pingpong_buffer txpp; /* 发送乒乓缓冲 */
struct pingpong_buffer rxpp; /* 接收乒乓缓冲 */
/* 流式单字节读取状态 (UART_RX_MODE_STREAM 模式使用) */
struct {
struct dev_uart_msg *current_msg; /* 当前正在读取的消息包 */
uint32_t read_pos; /* 当前读取位置(游标) */
} stream;
};
/*---------- end of file ----------*/
#ifdef __cplusplus
}
#endif
#endif

总之,我对程序员未来的生存空间不带乐观了。大部分应用层代码都可以通过AI实现了。
(像我这样的初级程序员,不知道未来何去何从)
|
|