一:在主站时会有三个线程 介绍
1.1:idle 线程 :用来周期性的发送消息,通过调用ecrt_master_send 函数。
1.2:operation 线程:实时性比较好,不直接调用ecrt_master_send 函数进行发送,而是通过 设置injection_seq_fsm 值,进行发送报文。
1.3:rt 线程:通过定时器周期性调用 ecrt_master_send函数,在ecrt_master_send 函数总不停地检测,
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;
}
rt 线程是在用户程序中调用的,以ethcat 的example 的为例子,在mini.c 文件中有创建定时器timer_setup(&timer, cyclic_task, 0);,周期性执行cyclic_task 函数,在cyclic_task 函数中会调用 ecrt_master_send 函数。
二:函数分析
/*1:生产者只需“提交任务”,消费者(发送线程)按固定节奏“批量处理任务”,这种模式在实时系统中广泛
*应用
*2:通过将数据报注入队列,系统自动在周期性发送流程中处理所有报文,无需模块各自调用发送函数
*/
int ecrt_master_send(ec_master_t *master)
{
ec_datagram_t *datagram, *n;
ec_device_index_t dev_idx;
/*需要发生那个报文是把injection_seq_fsm ++ 然后走到这里就让报文放到队里里面。然后接着周期性发送报文,注意本地发送的报文不一定是这次注入的报文。*/
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) {
datagram->state = EC_DATAGRAM_ERROR;
list_del_init(&datagram->queue);
}
}
if (!master->devices[dev_idx].dev) {
continue;
}
// query link state
ec_device_poll(&master->devices[dev_idx]);
// clear frame statistics
ec_device_clear_stats(&master->devices[dev_idx]);
continue;
}
// send frames 报文发送
ec_master_send_datagrams(master, dev_idx);
}
return 0;
}
三:举例说明:
1:rt 线程:
void rt_thread_entry() {
while (1) {
// 1. 执行主站状态机逻辑(可能生成新数据报)
ec_master_fsm_run(master);
// 2. 调用发送函数(周期性触发)
ecrt_master_send(master);
// 3. 等待下一个周期(如 1ms)
rt_sleep_until_next_cycle();
}
}
2:FSM 数据报注入示例
// FSM 生成配置命令后注入队列
void fsm_configure_slave(...) {
ec_datagram_init(&fsm_datagram, SLAVE_CONFIG_ADDR, sizeof(config_data));
memcpy(fsm_datagram.data, &config_data, sizeof(config_data));
ec_master_queue_datagram(master, &fsm_datagram);
master->injection_seq_fsm++; // 触发 RT 线程发送
}
3:用户程序注入:
// 用户应用程序注入异步读命令
void user_read_slave(...) {
ec_datagram_init(&user_datagram, SLAVE_READ_ADDR, sizeof(read_cmd));
memcpy(user_datagram.data, &read_cmd, sizeof(read_cmd));
ec_master_queue_datagram(master, &user_datagram);
}
2995

被折叠的 条评论
为什么被折叠?



