跳到主要内容

PDO 输入输出

对齐 C#:GetIO / Mapping 已退场,请用 CopyInputFrame / WriteOutputFrame generation 整帧 API。

PDO 周期与邮箱的关系

邮箱通信自动附带在 PDO 周期中,不占用额外帧。邮箱响应延迟约 2 个 PDO 周期。

应用层不是零拷贝指针

C++ 主路径是 generation 整帧复制:读走 SlavePDO::CopyInputFrame,写走 SlavePDO::WriteOutputFrame(即 native CopySlaveInputPdo / WriteSlaveOutputPdo)。

内核 SHM 零拷贝只存在于驱动内部,不向应用层暴露指针InputDataPointer() / OutputDataPointer() / InputSpan()线程本地快照,不是 IOmap overlay;下一次同线程调用会使指针失效,改快照不会写回。不要把它们当成 C# 已退场的 GetInputDataSpan / Mapping<T>

主路径:generation 整帧

namespace darra::SlavePDO {
bool CopyInputFrame(dll_t& dll, uint16_t mi, uint16_t si, std::vector<uint8_t>& frame);
bool CopyOutputFrame(dll_t& dll, uint16_t mi, uint16_t si, std::vector<uint8_t>& frame);
bool WriteOutputFrame(dll_t& dll, uint16_t mi, uint16_t si, const uint8_t* data, uint32_t size);
}

WriteOutputFrame 是单 owner 完整帧入口,长度必须与当前 RxPDO 完全相等,无静默截断。局部/typed/bit/batch 更新走 PatchOutputFrame / MutateOutputFrame(1748/1749 版本化事务)。

示例:

#pragma pack(push, 1)
struct ServoInput { uint16_t statusWord; int32_t actualPosition; };
struct ServoOutput { uint16_t controlWord; int32_t targetPosition; };
#pragma pack(pop)

std::vector<uint8_t> inFrame;
if (darra::SlavePDO::CopyInputFrame(dll, master, 1, inFrame) &&
inFrame.size() >= sizeof(ServoInput)) {
ServoInput in{};
std::memcpy(&in, inFrame.data(), sizeof(in));
printf("位置: %d\n", in.actualPosition);
}

std::vector<uint8_t> outFrame;
if (darra::SlavePDO::CopyOutputFrame(dll, master, 1, outFrame) &&
outFrame.size() >= sizeof(ServoOutput)) {
ServoOutput out{};
out.controlWord = 0x000F;
out.targetPosition = 100000;
std::memcpy(outFrame.data(), &out, sizeof(out));
if (!darra::SlavePDO::WriteOutputFrame(
dll, master, 1, outFrame.data(),
static_cast<uint32_t>(outFrame.size()))) {
// 如实处理失败,不要假定已写入
}
}

Slave / SlavePdoAccess 上的 ReadInputDirect / WriteOutputDirect / SetOutputs 内部仍走上述整帧合同,不是第二套 API。

同一路径上的便捷包装

  • ReadInputValue<T> / WriteOutputValue<T>:从完整帧快照读,或版本化 patch 写
  • PDODataItem / PDOArrayInstance:带 dll_t 的构造走整帧;旧裸指针构造不要当 overlay
  • SlavePDOBatch::BatchRead / BatchWrite:一次快照或一次 MutateOutputFrame
  • PDOManager::BatchRead / BatchWrite:多从站整帧 copy / 无条件整帧写

已退场(不要再用)

旧写法现状
GetIO + reinterpret_cast<ServoInput*>(in_ptr)GetIO 已退场
slave.InputDataPointer() 当跨周期 IOmap线程本地快照,改了不写回
InputSpan() / AsSpan() 当 C# live SpanC# GetInputDataSpan 已退场;此处也不是 live IOmap
BindPdoStruct<T>() 零拷贝 overlayMapping 已退场;不要当过程映像指针

需要结构体视图时:先 CopyInputFramestd::vector<uint8_t>,再 memcpy 到 packed struct。不要假设能拿到跨周期仍有效的 IOmap 指针。

PDO 管理器 (主站级)

PDOManager 提供批量整帧、GetPDOStats、丢帧统计、组周期分频。周期 / 错误统计的唯一真实数据源是 GetPDOStats()

darra::PDOManager pdo_mgr(dll, master.MasterNumber());
darra::PDOPerformanceStats st;
if (pdo_mgr.GetPDOStats(1, st))
printf("从站1: 平均周期=%llu ns, 错误=%u\n", st.avg_cycle_ns, st.error_count);