赞
踩
现象:虚拟机中运行IgH master并绑定网卡后,主站由ORPHANED状态转换成IDLE状态,但无法收发数据报。
这是因为虚拟机用的是虚拟网卡,需通过iptables将数据包到转发到真实的网卡上,实现收发数据的目的。但IgH替换了网卡驱动程序,收到数据包后,处理流程没有走内核的网络协议栈,所以工作中tcp/ip层的iptables就不起作用,导致IgH无法正常收发报文。
虚拟机网络原理参考:ubuntu20.04 搭建kernel调试环境第六篇(下)-网络原理-CSDN博客
解决:物理机安装ubuntu用来测试IgH。
root@ubuntu:/home/gsf# echo 7 7 7 7 > /proc/sys/kernel/printk
- #define EC_MASTER_INFO(master, fmt, args...) \
- printk(KERN_INFO "EtherCAT %u: " fmt, master->index, ##args)
-
- #define EC_MASTER_WARN(master, fmt, args...) \
- printk(KERN_WARNING "EtherCAT WARNING %u: " fmt, master->index, ##args)
-
- #define EC_MASTER_ERR(master, fmt, args...) \
- printk(KERN_ERR "EtherCAT ERROR %u: " fmt, master->index, ##args)
root@ubuntu:/home/gsf# vim /etc/init.d/ethercat
- #MASTER_ARGS= 改成下面
-
- MASTER_ARGS="debug_level=2"
务必注意:注意,make modules_install install后,需要重新修改
DEBUG主要是输出一些收发报文的数据,比如:
- [73996.353863] EtherCAT DEBUG 0: ec_master_send_datagrams(device_index = 0)
- [73996.353863] EtherCAT DEBUG 0: Adding datagram 0x2E
- [73996.353864] EtherCAT DEBUG 0: frame size: 46
- [73996.353864] EtherCAT DEBUG 0: Sending frame:
- [73996.353864] EtherCAT DEBUG: FF FF FF FF FF FF 6C 24 08 29 52 19 88 A4 0E 10
- [73996.353867] EtherCAT DEBUG: 05 2E 01 00 20 01 02 00 00 00 02 00 00 00 00 00
- [73996.353869] EtherCAT DEBUG: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
- [73996.353871] EtherCAT DEBUG: 00 00 00 00 00 00 00 00 00 00 00 00
现象:IgH源码中加了很多打印,连接从站后,发现dmesg会失了部分日志。
下面的下图显示的是ec_master_idle_thread --> ecrt_master_send --> ec_master_send_datagrams发送数据报文时,增加的printk打印。
datagram->index用的是master->datagram_index++,初始化是master->datagram_index为0,所以所有主站发送的数据报文的index应该是从0递增的,最大值255(master->datagram_index是uint8_t类型),到最大值后又从0开始计数。
原因:主站初始化时,ec_master_idle_thread线程循环执行,循环时间比较短,见下面代码:
- ec_master_idle_thread函数:
-
- if (ec_fsm_master_idle(&master->fsm)) {
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1); --------------- 1个jiffies
-
- } else {
-
- schedule(); ---------切换到其他线程执行,如果系统空闲,会继续执行该线程
-
- }
不接从站,printk信息比较少,可以完整输出。接上从站,代码流程复杂,自己加了很多printk,由于循环时间短,每轮循环都有大量的信息,来不及输出,就丢失了部分log。
解决:
方法一:直接修改主站的循环周期
- ec_master_idle_thread函数:
-
- //ec_master_set_send_interval(master, 1000000 / HZ);
- ec_master_set_send_interval(master, 5000000); -------改动1,主站周期从4ms改成5s
-
- if (ec_fsm_master_idle(&master->fsm)) {
-
- // set_current_state(TASK_INTERRUPTIBLE);
- // schedule_timeout(1);
- msleep(100); ----------改动2,注掉上面2行
-
- } else {
-
- //schedule();
- msleep(100); ----------改动2,注掉上面1行
-
- }
方法二:间接修改主站的循环周期
因为ec_master_idle_thread 每个周期都会执行ecrt_master_send --> ec_master_send_datagrams发送数据报文,所以可以在发送报文时加个延时:
- ec_master_idle_thread函数:
-
- //ec_master_set_send_interval(master, 1000000 / HZ);
- ec_master_set_send_interval(master, 5000000); -------改动1,主站周期从4ms改成5s
-
-
- -----------------------------------------------------------------------------
-
-
- void ec_master_send_datagrams(
- ec_master_t *master, /**< EtherCAT master */
- ec_device_index_t device_index /**< Device index. */
- )
- {
-
-
- do {
- frame_data = NULL;
- follows_word = NULL;
- more_datagrams_waiting = 0;
-
- // fill current frame with datagrams
- list_for_each_entry(datagram, &master->datagram_queue, queue) {
- if (datagram->state != EC_DATAGRAM_QUEUED ||
- datagram->device_index != device_index) {
- continue;
- }
-
- ……
-
- list_add_tail(&datagram->sent, &sent_datagrams);
- datagram->index = master->datagram_index++;
-
- EC_MASTER_DBG(master, 2, "Adding datagram 0x%02X\n",
- datagram->index);
-
- msleep(100); ------------在这里加个延时
修改后,log是全的。报文从0开始,发送、接收是一一对应的:
IgH主站网卡没有插网线,意味着网卡的link_state处于down状态,ec_master_idle_thread周期性执行ecrt_master_send发送数据报文,在ecrt_master_send中如果网卡处于link down状态,则会设置报文为EC_DATAGRAM_ERROR,在这里加个printk(见下代码),log中过滤关键字EC_DATAGRAM_ERROR就可以了。
- void ecrt_master_send(ec_master_t *master)
- {
- ec_datagram_t *datagram, *n;
- ec_device_index_t dev_idx;
-
- if (master->injection_seq_rt != master->injection_seq_fsm) {
- // inject datagram produced by master FSM
- ec_master_queue_datagram(master, &master->fsm_datagram);
- master->injection_seq_rt = master->injection_seq_fsm;
- }
-
- ec_master_inject_external_datagrams(master);
-
- for (dev_idx = EC_DEVICE_MAIN; dev_idx < ec_master_num_devices(master);
- dev_idx++) {
- if (unlikely(!master->devices[dev_idx].link_state)) {
- // link is down, no datagram can be sent
- list_for_each_entry_safe(datagram, n,
- &master->datagram_queue, queue) {
- if (datagram->device_index == dev_idx) {
- //在这里加行log
- printk(KERN_ERR "geshifei %s %d: set datagram->state = EC_DATAGRAM_ERROR\n",__func__, __LINE__);
- datagram->state = EC_DATAGRAM_ERROR;
- list_del_init(&datagram->queue);
- }
- }
以IgH读从站状态的广播报文0x0130为例,打开DEBUG后,demsg看到的报文:
发送报文: [18773.590655] geshifei ec_master_send_datagrams 1059: Adding datagram datagram->index=0 响应报文: [18773.710617] EtherCAT DEBUG 0: Received frame: |
1)注意source mac被从站改动过,为什么改,不清楚,感觉没必要。
2)正常情况下,发送的报文WC = 0,响应报文的WC不为0(存在从站的情况下)
所以可通过上面两个特征来判断哪个是发送报文,哪个是接收报文。
datagram->index用的是master->datagram_index++,初始化是master->datagram_index为0,所以所有主站发送的数据报文的index应该是从0递增的,最大值255(master->datagram_index是uint8_t类型),到最大值后又从0开始计数。
响应的报文,不会(也不能)修改Index值,因为IgH主站程序收到响应报文后,需要根据报文的index去匹配对应的发送报文,然后将发送报文从内部的发送队列中删除。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。