诊断
通过 device.diagnostics() 读诊断与报警(diag_snapshot() / alarms() 仍可用)。
建议通过 事件 驱动异常处理,而非自行轮询。 直接读取诊断适用于界面显示。
运行态(connected / state / error_code)见 属性与状态机。过程数据读写见 过程数据。
功能概览
| 功能 | 说明 |
|---|---|
| 诊断快照 | 链路、帧计数、看门狗、抖动、报警观测 |
| 现场问题对照 | 按症状选字段 |
| IOPS / IOCS | 过程数据质量 |
| 报警 | 活动列表 / 历史 / 确认 |
| I&M 标识 | 订货号、序列号、站名 |
| 用户记录 | 槽位参数记录 |
| 复位 | 通信复位 / 工厂复位 |
诊断快照
| 类别 | 成员 | 类型 | 说明 |
|---|---|---|---|
| 可用性 | ok | bool | 诊断是否可用。false = 设备未启动,读 message |
| 可用性 | shared_memory_mapped | bool | 过程数据是否已就绪 |
| 可用性 | message | String | 不可用时的原因;可用时为空 |
| 可用性 | timestamp | String | 快照时刻(ISO-8601 原文) |
| 链路 | state | String | 运行状态文案 |
| 链路 | link_up | bool | 网卡链路是否 Up |
| 链路 | connected | bool | 周期数据是否正常 |
| 链路 | active_iocr_count | u32 | 已激活的 IO 连接数 |
| 链路 | iocr_active / iocr_healthy | u32 | IO 连接激活 / 健康位图 |
| 计数 | heartbeat / cycle_counter | u64 | 心跳 / 周期循环计数 |
| 计数 | last_error | u64 | 最近错误码(0 = 无) |
| 计数 | rx_frames / tx_frames | u64 | 收 / 发总帧数 |
| 计数 | rx_rt_frames / tx_rt_frames | u64 | 收 / 发 RT 周期帧 |
| 计数 | dropped_frames / invalid_frames | u64 | 被丢弃 / 非法帧 |
| 计数 | watchdog_trips | u64 | 看门狗超时次数 |
| 计数 | last_rx_tsc / last_tx_tsc | u64 | 最近收 / 发帧 TSC |
| 过程区 | input_area_length / output_area_length | u32 | I 区 / Q 区长度(字节) |
| 周期 | stack_cycles | u64 | 周期计数 |
| 周期 | stack_frames_rx / stack_frames_tx | u64 | 收 / 发帧 |
| 周期 | stack_missed_ticks | u64 | 错过的节拍 |
| 周期 | stack_max_jitter_us | u64 | 最大抖动(微秒) |
| 报警观测 | stack_alarm_rx_count | u64 | 收到控制器报警总数 |
| 报警观测 | stack_alarm_tx_ack_ok / stack_alarm_tx_ack_fail | u64 | 本机报警被确认 / 确认失败 |
| 报警观测 | stack_alarm_ack_pending | u64 | 在途报警(0/1) |
| 报警观测 | stack_alarm_maint_state | u64 | 维护请求状态 |
| 报警观测 | stack_alarm_last_* | u32 | 最近控制器报警:arep / slot / subslot / type / seq / usi / len |
| 错误 | error_code | i32 | 错误码原值(0 = 无) |
| 错误 | error_code_enum() | PnSRuntimeErrorCode | 上项的枚举形态。未识别值为 Unknown |
diag_snapshot()
pub fn diag_snapshot(&self) -> ServiceResult<DiagSnapshot>
一次取回当前诊断快照,适合界面刷新和日志。设备尚未启动时 ok == false,读 message,不视为异常。get_diag_snapshot / get_diag 是同一函数。
示例:
let snap = device.diag_snapshot()?;
if !snap.ok {
println!("{}", snap.message);
return Ok(());
}
println!("{}", if snap.link_up { "Up" } else { "Down" });
println!("{}", if snap.connected { "周期交换正常" } else { "未建立" });
println!("帧: {} / {}", snap.rx_frames, snap.tx_frames);
println!("看门狗: {}", snap.watchdog_trips);
现场问题对照
| 现场症状 | 看哪些字段 |
|---|---|
| 网线没插好 | snap.link_up |
| 周期数据通不通 | snap.connected |
| 看门狗反复跳 | snap.watchdog_trips |
| 帧在丢 | dropped_frames + invalid_frames |
| 周期稳不稳 | stack_max_jitter_us + stack_missed_ticks |
| 控制器报警没消化 | stack_alarm_ack_pending / stack_alarm_tx_ack_fail |
| 本机有没有活动报警 | alarms() / alarm_count() |
| 过程数据质量 | io_status() |
IOPS / IOCS
pub fn io_status(&self) -> IoStatus
过程数据好不好。0x80 = GOOD,0x00 = BAD。掉线如实全 BAD。未 start 或请求失败返回 IoStatus::empty()。
pub struct IoStatus {
pub input_iops: Vec<u8>,
pub input_iocs: Vec<u8>,
pub output_iops: Vec<u8>,
pub output_iocs: Vec<u8>,
pub input_valid: bool,
pub output_valid: bool,
}
impl IoStatus {
pub fn empty() -> Self;
pub fn is_good(ioxs: u8) -> bool; // 0x80 = GOOD
pub fn is_all_good_bytes(ioxs: &[u8]) -> bool; // 空 = false
pub fn input_data_good(&self) -> bool;
pub fn output_data_good(&self) -> bool;
pub fn output_consumed(&self) -> bool;
pub fn all_good(&self) -> bool;
}
示例:
if !device.io_status().all_good() {
println!("{:?}", device.io_status());
}
报警
空列表 = 无活动报警,不是失败。响应不是列表就报 BadResponse,不折成「无报警」。get_alarms / alarms 同一函数;get_alarm_history / alarm_history 同一函数。
pub struct AlarmItem {
pub id: String, // 如 PnS.LinkDown
pub severity: String, // Info / Warning / Error / Critical
pub message: String,
pub occurred_at: String, // ISO-8601 原文
pub count: u32, // ≥1
pub source: String,
}
alarms()
pub fn alarms(&self) -> ServiceResult<Vec<AlarmItem>>
当前活动报警。无活动报警返回空列表,不是失败。
示例:
for a in device.alarms()? {
println!("{} {} {}", a.id, a.severity, a.message);
}
alarm_history()
pub fn alarm_history(&self) -> ServiceResult<Vec<AlarmItem>>
报警历史(最近 500 条,时间升序)。无历史返回空列表,不是失败。
示例:
for a in device.alarm_history()? {
println!("{} {} {}", a.occurred_at, a.severity, a.message);
}
ack_alarm / acknowledge_alarm
pub fn ack_alarm(&self, id: &str) -> ServiceResult<()>
确认一条活动报警。ID 取自 alarms()。没有这条活动报警会返回错误。acknowledge_alarm 是同一函数。
示例:
device.ack_alarm("PnS.LinkDown")?;
ack_all_alarms / acknowledge_all_alarms
pub fn ack_all_alarms(&self) -> ServiceResult<u32>
确认全部活动报警。返回被确认条数(0 = 无活动报警)。acknowledge_all_alarms 是同一函数。
示例:
let n = device.ack_all_alarms()?;
I&M 标识
pub fn im_data(&self) -> ServiceResult<ImData>
订货号、序列号、站名。get_im_data 是同一函数。I&M1–I&M3 已由原生栈启用并如实回读,I&M4 未启用;主站没写过时读到的是栈的出厂占位值。缺字段保持空 / 0 / false,这次读到什么看 im14_supported 与 im_note。
pub struct ImData {
pub vendor_id: u32,
pub device_id: u32,
pub order_id: String,
pub serial_number: String,
pub hardware_revision: String,
pub software_revision: String,
pub station_name: String,
pub product_name: String,
pub im_supported: String,
pub im14_supported: bool,
pub im1_tag_function: String,
pub im1_tag_location: String,
pub im2_date: String,
pub im3_descriptor: String,
pub im4_signature_hex: String,
pub im_note: String,
pub project_order_number: String,
pub project_hardware_release: String,
pub project_software_release: String,
pub timestamp: String,
}
示例:
let im = device.im_data()?;
println!("{} {:04X} {:04X}", im.station_name, im.vendor_id, im.device_id);
用户记录
pub fn records(&self) -> ServiceResult<UserRecords>
get_records 是同一函数。缺字段默认 0 / 空。count 是服务端返回值,不按数组长度回填。
pub struct UserRecords {
pub records: Vec<UserRecord>,
pub count: i32,
pub timestamp: String,
}
pub struct UserRecord {
pub slot: u16,
pub subslot: u16,
pub index: u16,
pub length: u16,
pub data_hex: String,
}
复位
pub fn reset_device(&self, mode: &str) -> ServiceResult<()>
communication:软停再启(记录保留)factory:销毁后全新启动(记录清空)
非法 mode 返回 InvalidParam。这是慢操作,可能要等几秒。
示例:
device.reset_device("communication")?;