Etherlab扫描和配置从站均由状态机相关代码完成,本文介绍其基本工作原理。
1、ec_fsm_master 结构体
ec_fsm_master是一个状态机实现过程中非常重要的结构体:
struct ec_fsm_master {
ec_master_t *master; /**< master the FSM runs on */
ec_datagram_t *datagram; /**< datagram used in the state machine */
unsigned int retries; /**< retries on datagram timeout. */
void (*state)(ec_fsm_master_t *); /**< master state function */
......
};
其中:
(1) 结构体成员*datagram为一个报文指针,指向master->fsm_datagram;
(2) 结构体成员(*state)为函数指针,状态切换中指向不同的状态机函数。
2、状态机报文
状态机使用master结构体的成员fsm_datagram作为状态机实现的载体。
2.1 初始化报文
在master.c中的ec_master_init()函数中完成fsm_datagram的初始化和分配内存空间:
int ec_master_init(ec_master_t *master, /**< EtherCAT master */
)
{
......
// init state machine datagram
ec_datagram_init(&master->fsm_datagram);
ret = ec_datagram_prealloc(&master->fsm_datagram, EC_MAX_DATA_SIZE);
......
}
2.2 指针赋值
在Fsm_master.c文件的ec_fsm_master_init()函数中将ec_fsm_master的结构体成员*datagram指向fsm_datagram:
void ec_fsm_master_init(
)
{
fsm->master = master;
fsm->datagram = datagram; //指向fsm_datagram
......
}
2.3 填充报文
在状态机函数中给fsm_datagram赋值,例如在ec_fsm_master_state_start()中读130寄存器的报文:
void ec_fsm_master_state_start(
ec_fsm_master_t fsm /*< Master state machine. */
)
{
fsm->idle = 1;
ec_datagram_brd(fsm->datagram, 0x0130, 2); //fsm_datagram为广播读130寄存器报文。
}
2.4 发送报文
在ec_master_idle_thread()函数中放入发送队列并发送出去:
if (fsm_exec) {
ec_master_queue_datagram(master, &master->fsm_datagram);
}
ecrt_master_send(master);
通过wireshark抓包工具抓到对应的报文如下:
3、函数调用关系
以IDLE状态为例,状态机周期性调用关系如下所示:
其中ec_master_idle_thread()的调用周期与系统滴答频率有关:
// send interval in IDLE phase
ec_master_set_send_interval(master, 1000000 / HZ);
4、子状态机
fsm_master状态机包含若干子状态机,例如从站扫描子状态机,当Etherlab扫描从站时,主状态机将一直停留在ec_fsm_master_state_scan_slave子状态,直到扫描完成,在此期间,状态机实际执行的是Fsm_slave_scan.c中的各函数(扫描从站)。