PnSService
PROFINET IO Device 的入口。启动设备、写 Q / 读 I、看运行态和诊断。crate 名 darra_pns,入口类型 PnSService。
本 SDK 只做 PROFINET IO Device,不提供其它现场总线协议的入口。
类结构
PnSService // 设备实例
│
├── process_data() → ProcessData // 写 Q / 读 I
│ ├── inputs_mapping::<T>() / outputs_mapping::<T>() // 0 拷贝,映射一次
│ ├── read_struct / write_struct // 快照,值不会自己变
│ ├── in_i8(offset) … in_bit(offset, bit) // 读 I(按项标量),只读
│ └── out_i8(offset, v) … out_bit(offset, bit, v) // 写 Q(按项标量),可写
├── events() → ServiceEvents // 运行态事件
│ ├── on_connected_changed // 周期交换通断
│ ├── on_state_changed // 运行态变化
│ ├── on_error_occurred // 运行错误
│ └── on_logged // 上面每条都会再打这条
├── variables() → PnSVariables // 变量联想
├── diagnostics() → Diagnostics // 诊断子对象(快照 / IOPS / 报警 / 记录)
│ ├── snapshot() // 诊断快照
│ ├── io_status() // IOPS / IOCS
│ ├── alarms() / alarm_history() // 本机报警 / 历史
│ └── records() // 用户区记录
│
├── connected() / state() / wait_reason() // 周期交换 / 运行态 / 等待原因
├── ever_connected() / error_code() // 曾经连上 / 运行错误
└── im_data() // I&M 标识
写 Q(模块输出,设备 → 控制器),读 I(模块输入,控制器 → 设备)。扁平方法
diag_snapshot()/alarms()仍可用,与diagnostics()同一数据。
diagnostics() 返回的 Diagnostics 没有在 crate 根重导出:要写出这个类型名就写全路径 darra_pns::service::Diagnostics(use darra_pns::Diagnostics; 编不过)。PnSService / ServiceResult / ServiceState / ProcessData 这些是重导出过的,直接 use darra_pns::… 就行。
用法
启停
use darra_pns::PnSService;
let mut device = PnSService::new();
device.start()?;
while running {
if !device.connected() {
// device.wait_reason()
continue;
}
device.write_bool("Q0.0", true)?; // 写 Q
let from_plc = device.read_bool("I0.0")?; // 读 I
let _ = from_plc;
}
device.stop()?;
看状态不必 new:PnSService::is_service_ready() / service_connected() / service_wait_reason()。
过程数据
| 方式 | 访问 | 说明 |
|---|---|---|
| 过程数据 | device.process_data().inputs_mapping::<T>() / outputs_mapping::<T>() | 0 拷贝,映射一次 |
| 过程数据 | device.process_data() | 快照 read_struct / write_struct、按项标量 in_i8(offset) / out_i16(offset, v) 系列 |
标识
let im = device.im_data()?;
let name = im.station_name;
let vendor = im.vendor_id;
let product = im.device_id;
过程数据读写
字 / 双字为大端。详见 过程数据。
金路径是 0 拷贝:映射一次,源头变字段自己变(T 须 #[repr(C, packed)])。
#[repr(C, packed)]
struct FromPlc {
a: u8,
b: i16,
flag: u8,
}
// 0 拷贝:映射一次
let inp = unsafe { device.process_data().inputs_mapping::<FromPlc>()? };
let outp = unsafe { device.process_data().outputs_mapping::<FromPlc>()? };
let present = inp.a; // 总线刷新后自己变
outp.a = 1; // 直接落 Q 过程映像
let _ = present;
device.process_data().out_u8(0, 0x11)?;
let v = device.process_data().in_u8(0)?;
快照走 read_struct / write_struct(结构体实现 ProcessDataPacked:必写 packed_size / unpack_from / pack_into 三个,另有一个带默认实现的 pack_to_vec,手写实现不必重复一份)—— 拷出来的实例不会自己变。
诊断与报警
通过 device.diagnostics() 读诊断(只读快照:链路、帧计数、看门狗、抖动与报警观测)。详见 诊断。事件见 事件。
let snap = device.diagnostics().snapshot()?;
if !snap.ok {
println!("{}", snap.message);
}
for a in device.diagnostics().alarms()? {
println!("{}", a.message);
}