Rockchip系列之LED状态灯 串口收发数据流程以及控制状态显示(3)

简介: Rockchip系列之LED状态灯 串口收发数据流程以及控制状态显示(3)

在前几篇文章中,我介绍了如何在Rockchip RK3568平台上使用LED状态灯,以及如何通过设备树和内核驱动来控制它们。在本文中,将进一步介绍如何在内核驱动中添加一些功能,使得LED状态灯能够根据串口的收发数据的情况来变化,从而显示串口的活动状态。

逻辑分析

要实现这个功能,需要修改内核驱动中的两个函数:serial8250_rx_chars和serial8250_tx_chars。这两个函数分别负责处理串口的接收和发送数据的操作。需要在这两个函数中添加一些代码,来记录每次发送或接收数据的设备名,并根据设备名来控制LED状态灯的亮灭。还需要引入一个外部函数led_control_set_leds_by_str,来方便地设置LED状态灯的状态。

以kernel/drivers/tty/serial/8250/8250_port.c为例,看看如何修改这两个函数:

+++ b/kernel/drivers/tty/serial/8250/8250_port.c
@@ -61,7 +61,7 @@
 #endif
 
 #define BOTH_EMPTY     (UART_LSR_TEMT | UART_LSR_THRE)
-
+extern int led_control_set_leds_by_str(const char *buf);
 /*
  * Here we define the default xmit fifo size used for each type of UART.
  */
@@ -1761,18 +1761,62 @@ EXPORT_SYMBOL_GPL(serial8250_read_char);
  */
 unsigned char serial8250_rx_chars(struct uart_8250_port *up, unsigned char lsr)
 {
-       struct uart_port *port = &up->port;
-       int max_count = 256;
-
-       do {
-               serial8250_read_char(up, lsr);
-               if (--max_count == 0)
-                       break;
-               lsr = serial_in(up, UART_LSR);
-       } while (lsr & (UART_LSR_DR | UART_LSR_BI));
-
-       tty_flip_buffer_push(&port->state->port);
-       return lsr;
+        struct uart_port *port = &up->port;
+        int max_count = 256;
+        char led_ctrl_str[16];
+        // 添加一个变量来保存当前的设备名
+        const char *dev_name = up->port.name;
+       // 打印接收到的数据
+        //printk("Received data: %s:%s\n", dev_name, up->port.state->xmit.buf);
+        printk("Received data: %s\n", dev_name);
+       // 根据设备名来执行不同的操作
+        switch (dev_name[4]) { // 取设备名的第五个字符,即 ttySx 中的 x
+        case '3':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 5, 1, 0);
+                led_control_set_leds_by_str(led_ctrl_str);
+                mdelay(10);//msleep(100); // 延时 1 秒
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 5, 1, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        case '4':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 6, 1, 0);
+                led_control_set_leds_by_str(led_ctrl_str);
+                mdelay(10);//msleep(100); // 延时 1 秒
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 6, 1, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        case '5':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 7, 1, 0);
+                led_control_set_leds_by_str(led_ctrl_str);
+                mdelay(10);//msleep(100); // 延时 1 秒
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 7, 1, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        case '7':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 8, 1, 0);
+                led_control_set_leds_by_str(led_ctrl_str);
+                mdelay(10);//msleep(100); // 延时 1 秒
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 8, 1, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        default:
+                // 其他设备名不做任何操作
+                break;
+        }
+
+        do {
+                serial8250_read_char(up, lsr);
+                if (--max_count == 0)
+                        break;
+                lsr = serial_in(up, UART_LSR);
+        } while (lsr & (UART_LSR_DR | UART_LSR_BI));
+
+        tty_flip_buffer_push(&port->state->port);
+
+
+
+
+        return lsr;
 }
 EXPORT_SYMBOL_GPL(serial8250_rx_chars);
 
@@ -1781,6 +1825,45 @@ void serial8250_tx_chars(struct uart_8250_port *up)
        struct uart_port *port = &up->port;
        struct circ_buf *xmit = &port->state->xmit;
        int count;
+        char led_ctrl_str[16];
+        // 添加一个变量来保存当前的设备名
+        const char *dev_name = up->port.name;
+        // 打印接发送的数据
+        printk("Send data: %s\n", dev_name);
+        // 根据设备名来执行不同的操作
+        switch (dev_name[4]) { // 取设备名的第五个字符,即 ttySx 中的 x
+        case '3':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 5, 0, 0);
+                led_control_set_leds_by_str(led_ctrl_str);
+                mdelay(10);//msleep(100); // 延时 1 秒
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 5, 0, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        case '4':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 6, 0, 0);
+                led_control_set_leds_by_str(led_ctrl_str);
+                mdelay(10);//msleep(100); // 延时 1 秒
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 6, 0, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        case '5':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 7, 0, 0);
+                led_control_set_leds_by_str(led_ctrl_str);
+                mdelay(10);//msleep(100); // 延时 1 秒
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 7, 0, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        case '7':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 8, 0, 0);
+                led_control_set_leds_by_str(led_ctrl_str);
+                mdelay(10);//msleep(100); // 延时 1 秒
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 8, 0, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        default:
+                // 其他设备名不做任何操作
+                break;
+        }
 
        if (port->x_char) {
                serial_out(up, UART_TX, port->x_char);

这里需要注意以下几点:

  • 在文件开头引入了一个外部函数led_control_set_leds_by_str,用来设置LED状态灯的状态,该函数的定义在kernel/drivers/leds/led_control.c中。
  • (重点重点)在serial8250_rx_chars函数中,在接收数据之前,定义一个字符数组led_ctrl_str,用来存放LED状态灯的控制字符串。
  • 获取当前的设备名,并打印一条日志信息。
  • 根据设备名的第五个字符(即ttySx中的x)来执行不同的操作。如果是'3',表示是ttyS3串口,那么就设置第5组LED的绿色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是'4',表示是ttyS4串口,那么就设置第6组LED的绿色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是'5',表示是ttyS5串口,那么就设置第7组LED的绿色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是'7',表示是ttyS7串口,那么就设置第8组LED的绿色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是其他字符,那么就不做任何操作。这样就实现了每次接收数据时,对应的LED会闪烁一下的效果。
  • (重点重点)在serial8250_tx_chars函数中,在发送数据之前,定义一个字符数组led_ctrl_str,用来存放LED状态灯的控制字符串。
  • 获取当前的设备名,并打印一条日志信息。
  • 根据设备名的第五个字符(即ttySx中的x)来执行不同的操作。如果是'3',表示是ttyS3串口,那么就设置第5组LED的红色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是'4',表示是ttyS4串口,那么就设置第6组LED的红色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是'5',表示是ttyS5串口,那么就设置第7组LED的红色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是'7',表示是ttyS7串口,那么就设置第8组LED的红色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是其他字符,那么就不做任何操作。这样就实现了每次发送数据时,对应的LED会闪烁一下的效果。(前面一样的)

测试效果

要测试这个功能,需要在RK3568平台上编译并加载修改后的内核驱动。然后可以使用minicom或其他串口工具来发送或接收数据,观察LED状态灯的变化。例如,可以在RK3568平台上执行以下命令:

 

 minicom -D /dev/ttyS3 #linux推荐这么搞
# 或者
 echo / cat 
# 都ok,android比较方便怎么测都可以。我用我自己写的接口测试

 

这样就会打开ttyS3串口,并与另一台设备进行通信。可以看到,每次发送或接收数据时,对应的LED状态灯会闪烁一下,表示串口的活动状态,同时查看内核日志可以看到收发数据的。

总结

本文介绍了如何在内核驱动中添加一些功能,使得LED状态灯能够根据串口的收发数据的情况来变化,从而显示串口的活动状态。修改了内核驱动中的serial8250_rx_chars和serial8250_tx_chars函数,添加了一些代码,来记录每次发送或接收数据的设备名,并根据设备名来控制LED状态灯的亮灭。还引入了一个外部函数led_control_set_leds_by_str,来方便地设置LED状态灯的状态。

希望本文对你有所帮助。如果你有任何问题或建议,请在评论区留言。谢谢!

相关文章
|
Linux
如何使用 Linux `date` 命令来指定时区?
如何使用 Linux `date` 命令来指定时区?
2491 0
|
人工智能 网络安全 开发工具
vscode代码推送到github库菜鸡专用教程
vscode代码推送到github库菜鸡专用教程
|
Ubuntu 网络协议 Linux
Linux(20) Ubuntu 20.04 网络接口自动切换路由配置
Linux(20) Ubuntu 20.04 网络接口自动切换路由配置
1628 0
|
JavaScript 算法 前端开发
为什么npm run serve正常,npm run build就报错:digital envelope routines::unsupported
通过本文的分析,我们详细介绍了 `npm run serve`正常但 `npm run build`时报错:`digital envelope routines::unsupported`的原因及解决方案。主要从检查Node.js版本、更新依赖、检查依赖库、配置文件及环境变量等方面进行了深入探讨。希望本文能帮助开发者解决这一问题,确保项目顺利构建和部署。
1912 6
|
Shell Linux 测试技术
Android App性能评测分析-cpu占用篇
1、前言 很多时候在使用APP的时候,手机可能会发热发烫。这是因为CPU使用率过高,CPU过于繁忙,会使整个手机无法响应用户,整体性能降低,用户体验就会很差,也容易引起ANR等等一系列问题。
6637 0
|
Linux 芯片 Ubuntu
Linux驱动入门 —— 利用引脚号操作GPIO进行LED点灯
Linux驱动入门 —— 利用引脚号操作GPIO进行LED点灯
|
安全 Linux Shell
Linux系统之间实现免密码登录(SSH无密码登录
【8月更文挑战第21天】要在Linux系统间实现SSH免密码登录,需先在源机器生成SSH密钥对,然后将公钥复制到目标机器的`.ssh/authorized_keys`文件中。可通过`ssh-keygen`命令生成密钥,并使用`ssh-copy-id`命令传输公钥。最后测试SSH连接,确保能无密码登录。若目标机器缺少相关目录或文件,需手动创建并设置适当权限。完成这些步骤后,即可实现安全便捷的免密码登录。
1468 0
stm32f407探索者开发板(十三)——JLINK在线调试_软件调试_方法与技巧
stm32f407探索者开发板(十三)——JLINK在线调试_软件调试_方法与技巧
1507 0
|
存储 缓存 Windows
释放C盘空间:WinSXS文件夹真实性大小判断及释放占用空间
WinSXS文件夹存储了不同版本的系统组件和动态链接库(DLL),包括各个Windows更新、Service Pack和功能更新安装后保留的旧版文件。即使新版本已经安装并投入使用,旧版本文件仍被保存以确保与依赖旧版本的应用程序兼容。
3583 0
释放C盘空间:WinSXS文件夹真实性大小判断及释放占用空间

热门文章

最新文章