/** * @file ethercat_slave.h * @brief EtherCAT 从站周期处理接口与 PDO 双缓冲(ping-pong)结构。 * @note 周期 ISR 调用 periodicIsr() 完成输入 PDO 读取 + 输出 PDO 写入; * 应用层通过 getLatestInputs()/setOutputs() 与周期路径无锁交换数据。 */ #ifndef COMM_ETHERCAT_SLAVE_H #define COMM_ETHERCAT_SLAVE_H #include #include /** @brief 默认 PDO 大小(可按需调整)。 */ constexpr size_t CONFIG_ETHERCAT_PDO_SIZE = 32U; /** * @brief PDO 数据缓冲(输入/输出共用结构)。 * @note 周期 ISR 与应用层通过双缓冲无锁交换。 */ struct PdoBuffer { uint8_t data[CONFIG_ETHERCAT_PDO_SIZE] = {0}; /**< 数据载荷。 */ size_t len = 0U; /**< 有效数据长度。 */ }; /** * @brief EtherCAT 从站周期处理。 * @note 周期路径(periodicIsr)必须极简:读输入→写输出→翻转指针→置位任务。 */ class EthercatSlave { public: /** @brief 初始化 ESC 与双缓冲。 */ static void init(); /** * @brief 周期中断处理(由 SYNC0 EXTI 触发)。 * @note 放入 RAM 执行段(.ramfunc)以降低 Flash 等待带来的抖动。 * 流程:读输入 PDO → 写输出 PDO → 翻转输入缓冲指针 → 置位 TASK_ETHERCAT_PROCESS。 */ static void periodicIsr(); /** * @brief 获取最新输入 PDO(主循环调用,无锁)。 * @return const PdoBuffer* 最新输入缓冲只读指针;周期 ISR 不会修改该缓冲。 */ static const PdoBuffer* getLatestInputs(); /** * @brief 设置下次周期要发送的输出 PDO(主循环调用)。 * @param[in] outputs 输出数据指针(内容会被拷贝到内部输出缓冲)。 * @note 调用方在 ISR 不持有期间调用即可,内部使用乒乓缓冲避免竞争。 */ static void setOutputs(const PdoBuffer *outputs); /** * @brief 应用层 PDO 映射入口(非实时,由 TASK_ETHERCAT_PROCESS 调用)。 * @note 留接口,具体映射逻辑由协议栈后续实现。 */ static void process(); private: static PdoBuffer s_inputs[2]; /**< 输入双缓冲(pong-pong)。 */ static PdoBuffer s_outputs[2]; /**< 输出双缓冲(ping-pong)。 */ static volatile uint8_t s_inputReadIndex; /**< ISR 当前写入索引;getLatestInputs 读另一个。 */ static volatile uint8_t s_outputWriteIndex; /**< 应用层写入索引;ISR 读另一个。 */ }; #endif /* COMM_ETHERCAT_SLAVE_H */