RK3568------Openharmony 4.0-Release HDF串口驱动BUG改进方案
前言
因为目前项目进入XTS认证阶段,遇到的都是具有特殊性问题,所以就没有频率很高的发布文章。今天发布的内容主要针对《RK3568------Openharmony 4.0-Release HDF串口驱动(USB转串口) 下》一文中串口通讯遇到的BUG改进方案做一个解析与分享。
一、HDF串口驱动的BUG解析
源码: uart_adapter.c
- 假如我们在
HCS中定义多个串口设备
,并且串口设备名称的前缀格式不同
,当我们通过接口获取到HCS中属性的driver_name后,将这个driver_name写入到全局变量数组
中后,会形成一个错误的设备名称,因为这种处理方式的现象是将多个串口写入同一个变量
中,这在逻辑上是不对的,正常的逻辑应该是一个串口设备就应该对应一个设备名称。
- 这里是一个伪实现函数
- 这里串口属性配置不全,可能会导致接收不到数据情况
- 读的逻辑与下面写的逻辑不一致,不是一次全部读出
二、HDF串口驱动的BUG改进
改进代码:链接: uart_adapter.c
- 创建一个结构体,存储文件描述符与设备名称,保证一个串口设备对应一个名称
- 因为是在内核里的操作,所以我采用重新打开文件描述符的方案来修改读写的模式
static int32_t UartAdapterSetTransMode(struct UartHost *host, enum UartTransMode mode)
{
// 这里是一个伪函数,没有实现功能,因为是在内核里的操作,所以我采用重新打开文件描述符的方案
char name[UART_PATHNAME_LEN] = {0};
struct file *fp = NULL;
mm_segment_t oldfs;
struct UartPriv *uartpriv = NULL;
int open_mode;
if (host == NULL) {
HDF_LOGE("UartAdapterSetTransMode: host is null!");
return HDF_ERR_INVALID_OBJECT;
}
uartpriv = (struct UartPriv *)host->priv;
if (sprintf_s(name, UART_PATHNAME_LEN - 1, "/dev/%s%d", uartpriv->g_driverName, host->num) < 0) {
return HDF_FAILURE;
}
// 确定打开标志
if(mode == UART_MODE_RD_BLOCK){
open_mode = O_RDWR | O_NOCTTY;
}else{
open_mode = O_RDWR | O_NOCTTY | O_NONBLOCK;
}
fp = uartpriv->fp;
oldfs = get_fs();
set_fs(KERNEL_DS);
// 关闭文件描述符
if (!IS_ERR(fp) && fp) {
filp_close(fp, NULL);
}
// 重新打开文件描述符
fp = filp_open(name, open_mode, 0600); /* 0600 : file mode */
if (IS_ERR(fp)) {
HDF_LOGE("UartAdapterSetTransMode: filp_open %s fail!", name);
set_fs(oldfs);
return HDF_FAILURE;
}
set_fs(oldfs);
uartpriv->fp = fp;
return HDF_SUCCESS;
}
- 重写配置串口的属性
termios.c_cflag |= CLOCAL | CREAD;
termios.c_cflag &= ~CSIZE;
termios.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
termios.c_iflag &= ~(IXON | IXOFF | IXANY);
termios.c_oflag &= ~OPOST;
4.重写读的逻辑
static int32_t UartAdapterRead(struct UartHost *host, uint8_t *data, uint32_t size)
{
loff_t pos = 0;
int ret;
struct file *fp = NULL;
char *p = (char *)data;
mm_segment_t oldfs;
uint32_t tmp = 0;
struct UartPriv *uartpriv = NULL;
if (host == NULL || host->priv == NULL || data == NULL || size == 0) {
HDF_LOGE("UartAdapterRead: invalid parameters!");
return HDF_ERR_INVALID_OBJECT;
}
uartpriv = (struct UartPriv *)host->priv;
fp = uartpriv->fp;
oldfs = get_fs();
set_fs(KERNEL_DS);
while (tmp < size) {
ret = vfs_read(fp, p + tmp, size - tmp, &pos);
if (ret < 0) {
HDF_LOGE("UartAdapterRead: vfs_read fail ret: %d!", ret);
if (tmp == 0)
tmp = ret ;
break;
}
if (ret == 0)
break ;
tmp += ret;
}
set_fs(oldfs);
return tmp;
}
总结
本人之前一直从事应用开发,借着这次电鸿的契机进行系统级开发的学习,将我在工作中的遇到的问题及解决思路记录并分享,希望可以与诸君共勉
目前网上技术讨论群大都是鸿蒙的应用开发,总结此类文章也是希望将同样进行鸿蒙设备开发的同僚召集到一起,一起讨论学习。如果有同样在进行鸿蒙设备开发的朋友,可以加我的联系方式,期待您的消息
个人微信