/** * @file ethercat_slave.cpp * @brief EtherCAT 从站周期处理实现。 */ #include "comm/ethercat_slave.h" #include "comm/esc_lan9252.h" #include "sys/config.h" #include "sys/task_manager.h" #include "main.h" #if CONFIG_ETHERCAT_ENABLE PdoBuffer EthercatSlave::s_inputs[2] = {}; PdoBuffer EthercatSlave::s_outputs[2] = {}; volatile uint8_t EthercatSlave::s_inputReadIndex = 0U; volatile uint8_t EthercatSlave::s_outputWriteIndex = 0U; void EthercatSlave::init() { EscLan9252::init(); if (EscLan9252::selfTest()) { /* ESC 自检通过:TODO 启用周期同步 */ } s_inputReadIndex = 0U; s_outputWriteIndex = 0U; } __attribute__((section(".ramfunc"))) void EthercatSlave::periodicIsr() { /* 1. 读取输入 PDO 到另一块缓冲(当前可读缓冲的配对) */ const uint8_t write_idx = s_inputReadIndex ^ 1U; EscLan9252::readPdi(0x0000U, s_inputs[write_idx].data, CONFIG_ETHERCAT_PDO_SIZE); s_inputs[write_idx].len = CONFIG_ETHERCAT_PDO_SIZE; /* 2. 写入输出 PDO(从应用层未写入的那个缓冲读取) */ const uint8_t out_read_idx = s_outputWriteIndex ^ 1U; EscLan9252::writePdi(0x0000U, s_outputs[out_read_idx].data, s_outputs[out_read_idx].len); /* 3. 翻转输入缓冲指针,使新完成的缓冲成为可读缓冲 */ s_inputReadIndex = write_idx; /* 4. 置位非实时任务,通知主循环处理应用层 PDO 映射 */ TaskManager::set(1UL << TASK_ETHERCAT_PROCESS); } const PdoBuffer* EthercatSlave::getLatestInputs() { /* s_inputReadIndex 始终指向最新完成的输入缓冲 */ return &s_inputs[s_inputReadIndex]; } void EthercatSlave::setOutputs(const PdoBuffer *outputs) { if (outputs == nullptr) { return; } /* 写入应用层缓冲(ISR 当前不读取的那个) */ const uint8_t write_idx = s_outputWriteIndex ^ 1U; s_outputs[write_idx] = *outputs; s_outputWriteIndex = write_idx; } void EthercatSlave::process() { /* 应用层 PDO 映射入口(非实时,由主循环 TASK_ETHERCAT_PROCESS 调用)。 * TODO: 将 getLatestInputs() 数据映射到应用对象字典;将应用输出填入 setOutputs()。 */ } #endif /* CONFIG_ETHERCAT_ENABLE */