Rockchip系列之LED状态灯 以太网收发数据包流程以及控制状态显示(2)

简介: Rockchip系列之LED状态灯 以太网收发数据包流程以及控制状态显示(2)

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

逻辑分析

要实现这个功能,需要修改内核驱动中kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c的两个函数:stmmac_xmit和stmmac_rx。这两个函数分别负责处理以太网的发送和接收数据包的操作。需要在这两个函数中添加一些代码,来记录每次发送或接收数据包的时间,并根据时间间隔来控制LED状态灯的亮灭。还需要引入前面添加的LED driver的一个外部函数led_control_set_leds_by_str,来方便地设置LED状态灯的状态。

看看如何修改这两个函数:

+++ b/kernel/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -58,6 +58,12 @@
 #define        STMMAC_ALIGN(x)         ALIGN(ALIGN(x, SMP_CACHE_BYTES), 16)
 #define        TSO_MAX_BUFF_SIZE       (SZ_16K - 1)
 
+#include <linux/timekeeping.h>
+
+static ktime_t xmit_last_exec_time;  // 将 last_exec_time 声明为全局静态变量
+static ktime_t rx_last_exec_time;  // 将 last_exec_time 声明为全局静态变量
+extern int led_control_set_leds_by_str(const char *buf);
+
 /* Module parameters */
 #define TX_TIMEO       5000
 static int watchdog = TX_TIMEO;
@@ -3047,6 +3053,44 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
        unsigned int enh_desc;
        unsigned int des;
 
+           ktime_t now;
+    s64 elapsed_time_ms;
+
+    now = ktime_get();
+    elapsed_time_ms = ktime_ms_delta(now, xmit_last_exec_time);
+
+    if (elapsed_time_ms >= 1000) {
+
+       char led_ctrl_str[16];
+        // 添加一个变量来保存当前的设备名
+        const char *dev_name = dev->name;//up->port.name;
+       printk("stmmac_xmit: Sending a packet. %s\n", dev->name);
+
+       // 根据设备名来执行不同的操作
+        switch (dev_name[3]) {
+        case '0':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 2, 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", 2, 0, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        case '1':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 1, 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", 1, 0, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+
+        default:
+                // 其他设备名不做任何操作
+                break;
+        }
+         // 更新上次执行时间
+        xmit_last_exec_time = now;
+    }
+
        tx_q = &priv->tx_queue[queue];
 
        if (priv->tx_path_in_lpi_mode)
@@ -3285,6 +3329,7 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv, u32 queue)
        unsigned int entry = rx_q->dirty_rx;
 
        int bfsize = priv->dma_buf_sz;
+       //printk("stmmac_rx: Receiving a packet.%d\n",bfsize);
 
        while (dirty-- > 0) {
                struct dma_desc *p;
@@ -3356,6 +3401,43 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
        int coe = priv->hw->rx_csum;
        unsigned int count = 0;
        bool xmac;
+       struct net_device *ndev = priv->dev;
+       //printk("stmmac_rx: Receiving a packet. %s\n", ndev->name);
+           ktime_t now;
+    s64 elapsed_time_ms;
+
+    now = ktime_get();
+    elapsed_time_ms = ktime_ms_delta(now, rx_last_exec_time);
+
+    if (elapsed_time_ms >= 1000) {
+       char led_ctrl_str[16];
+        // 添加一个变量来保存当前的设备名
+        const char *dev_name = ndev->name;//up->port.name;
+
+       // 根据设备名来执行不同的操作
+        switch (dev_name[3]) {
+        case '0':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 2, 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", 2, 1, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+        case '1':
+                snprintf(led_ctrl_str, sizeof(led_ctrl_str), "%d %d %d", 1, 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", 1, 1, 1);
+                led_control_set_leds_by_str(led_ctrl_str);
+                break;
+
+        default:
+                // 其他设备名不做任何操作
+                break;
+        }
+            // 更新上次执行时间
+        rx_last_exec_time = now;
+    }
 
        xmac = priv->plat->has_gmac4 || priv->plat->has_xgmac;
 
@@ -3369,6 +3451,8 @@ static int stmmac_rx(struct stmmac_priv *priv, int limit, u32 queue)
                        rx_head = (void *)rx_q->dma_rx;
 
                stmmac_display_ring(priv, rx_head, DMA_RX_SIZE, true);
+
+               printk("stmmac_rx11: Receiving a packet.\n");
        }
        while (count < limit) {
                int entry, status;
l

来简单解释下:

  • 在文件开头引入了<linux/timekeeping.h>头文件,用来获取当前的时间。
  • 定义了两个全局静态变量xmit_last_exec_time和rx_last_exec_time,用来记录上次发送或接收数据包的时间。
  • 声明了一个外部函数led_control_set_leds_by_str,用来设置LED状态灯的状态,该函数的定义在kernel/drivers/leds/led_control.c中。
  • (重点来了)在stmmac_xmit函数中,在发送数据包之前,获取当前的时间,并与xmit_last_exec_time比较,得到时间间隔。如果时间间隔大于等于1000毫秒,表示距离上次发送数据包已经超过1秒,那么就执行以下操作:
  • 定义一个字符数组led_ctrl_str,用来存放LED状态灯的控制字符串。
  • 获取当前的设备名,并打印一条日志信息。
  • 根据设备名的第四个字符(即网卡编号)来执行不同的操作。如果是'0',表示是eth0网卡,那么就设置第2组LED的红色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是'1',表示是eth1网卡,那么就设置第1组LED的红色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是其他字符,那么就不做任何操作。这样就实现了每次发送数据包时,对应的LED会闪烁一下的效果。
  • 更新xmit_last_exec_time为当前时间。
  • (重点来了)在stmmac_rx函数中,在接收数据包之前,获取当前的时间,并与rx_last_exec_time比较,得到时间间隔。如果时间间隔大于等于1000毫秒,表示距离上次接收数据包已经超过1秒,那么就执行以下操作:
  • 定义一个字符数组led_ctrl_str,用来存放LED状态灯的控制字符串。
  • 获取当前的设备名,并打印一条日志信息。
  • 根据设备名的第四个字符(即网卡编号)来执行不同的操作。如果是'0',表示是eth0网卡,那么就设置第2组LED的绿色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是'1',表示是eth1网卡,那么我们就设置第1组LED的绿色为关闭(即亮起),延时10毫秒,再设置为打开(即灭掉)。如果是其他字符,那么我们就不做任何操作。这样就实现了每次接收数据包时,对应的LED会闪烁一下的效果。(和上面一样的)
  • 更新rx_last_exec_time为当前时间。

测试效果

要测试这个功能,需要在RK3568平台上编译并加载修改后的内核驱动(LED driver必须加 不然调不到函数)。然后我们可以使用ping命令或其他网络工具来发送或接收数据包,观察LED状态灯的变化。例如,我们可以在RK3568平台上执行以下命令:

ping www.baidu.com

这样就会向www.baidu.com这个域名地址发送数据包,并接收回应。可以看到,每次发送或接收数据包时,对应的LED状态灯会闪烁一下,表示网络的活动状态。

LED灯闪烁不好拍 你们脑补就可以了。

下面是有网络数据交互时候的打印 , 正常情况下接了以太网 只要拿到IP , rx tx都会有一些数据(应该是发给网关的)

 

总结

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

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

相关文章
|
10天前
Rockchip系列之LED状态灯 串口收发数据流程以及控制状态显示(3)
Rockchip系列之LED状态灯 串口收发数据流程以及控制状态显示(3)
21 0
|
8月前
|
算法 芯片 异构计算
通过FPGA实现基于RS232串口的指令发送并控制显示器中目标位置
通过FPGA实现基于RS232串口的指令发送并控制显示器中目标位置
|
10天前
Rockchip系列之LED状态灯 CAN收发数据流程以及控制状态显示(4)
Rockchip系列之LED状态灯 CAN收发数据流程以及控制状态显示(4)
14 3
|
9月前
|
存储
深入理解AMBA总线(六)AHB-lite Slave响应和其它控制信号
深入理解AMBA总线(六)AHB-lite Slave响应和其它控制信号
305 0
|
10月前
I/O设备与主机信息传送的控制方式以及什么是中断
I/O设备与主机信息传送的控制方式以及什么是中断
153 0
|
测试技术
PCD235B101 3BHE032025R0101 用于定时和触发的附加总线线路
PCD235B101 3BHE032025R0101 用于定时和触发的附加总线线路
69 0
PCD235B101 3BHE032025R0101 用于定时和触发的附加总线线路
|
网络协议
基于wemos的手机TCP传输控制蜂鸣器源码
基于wemos的手机TCP传输控制蜂鸣器源码
91 0
|
开发工具 Perl
ZYNQ-调用自定义AXI接口呼吸灯IP
ZYNQ-调用自定义AXI接口呼吸灯IP
183 0
ZYNQ-调用自定义AXI接口呼吸灯IP
接收PC端的信息控制LED灯(中断法)
接收PC端的信息控制LED灯(中断法) 宏定义 初始化 中断 主函数
128 0
接收PC端的信息控制LED灯(查询法)
接收PC端的信息控制LED灯(查询法) 宏定义 初始化 主函数