诊断
通过 PnSServiceGetDiag / PnSServiceGetAlarms 读诊断与报警(与 C# device.Diagnostics 同一组能力)。
配合事件使用
建议通过 事件 驱动异常处理,而非自行轮询。 直接读取诊断适用于界面显示等场景。
运行态(IsConnected / GetState / GetErrorCode)见 属性与状态机。过程数据读写见 过程数据。
功能概览
| 功能 | 说明 |
|---|---|
| 诊断快照 | 链路、帧计数、看门狗、抖动、报警观测 |
| IOPS | 过程数据质量 |
| 现场问题对照 | 按症状选字段 |
| 报警 | 活动列表 / 历史 / 确认 |
诊断快照
| 类别 | 字段 | 类型 | 说明 |
|---|---|---|---|
| 可用性 | ok | int | 诊断是否可用。0 = 设备未启动,读 message |
| 可用性 | shared_memory_mapped | int | 过程数据是否已就绪 |
| 可用性 | message | char[256] | 不可用时的原因;可用时为空 |
| 链路 | state | char[32] | 运行状态文案 |
| 链路 | link_up | int | 网卡链路是否 Up |
| 链路 | connected | int | 周期数据是否正常 |
| 链路 | active_iocr_count | uint32_t | 已激活的 IO 连接数 |
| 链路 | iocr_active / iocr_healthy | uint32_t | IO 连接激活 / 健康位图 |
| 计数 | heartbeat / cycle_counter | uint64_t | 心跳 / 周期循环计数 |
| 计数 | last_error | uint64_t | 最近错误码(0 = 无) |
| 计数 | rx_frames / tx_frames | uint64_t | 收 / 发总帧数 |
| 计数 | rx_rt_frames / tx_rt_frames | uint64_t | 收 / 发 RT 周期帧 |
| 计数 | dropped_frames / invalid_frames | uint64_t | 被丢弃 / 非法帧 |
| 计数 | watchdog_trips | uint64_t | 看门狗超时次数 |
| 计数 | last_rx_tsc / last_tx_tsc | uint64_t | 最近收 / 发帧 TSC |
| 过程区 | input_area_length | uint32_t | 输入区长度(字节) |
| 过程区 | output_area_length | uint32_t | 输出区长度(字节) |
| 周期 | stack_cycles | uint64_t | 周期计数 |
| 周期 | stack_frames_rx / stack_frames_tx | uint64_t | 收 / 发帧 |
| 周期 | stack_missed_ticks | uint64_t | 错过的节拍 |
| 周期 | stack_max_jitter_us | uint64_t | 最大抖动(微秒) |
| 报警观测 | stack_alarm_rx_count | uint64_t | 收到控制器报警总数 |
| 报警观测 | stack_alarm_tx_ack_ok | uint64_t | 本机报警被确认次数 |
| 报警观测 | stack_alarm_tx_ack_fail | uint64_t | 本机报警确认失败次数 |
| 报警观测 | stack_alarm_ack_pending | uint64_t | 在途报警(0/1) |
| 报警观测 | stack_alarm_maint_state | uint64_t | 维护请求状态 |
| 报警观测 | stack_alarm_last_arep | uint32_t | 最近控制器报警:Arep |
| 报警观测 | stack_alarm_last_slot | uint32_t | 最近控制器报警:槽位 |
| 报警观测 | stack_alarm_last_subslot | uint32_t | 最近控制器报警:子槽位 |
| 报警观测 | stack_alarm_last_type | uint32_t | 最近控制器报警:类型 |
| 报警观测 | stack_alarm_last_seq | uint32_t | 最近控制器报警:序列号 |
| 报警观测 | stack_alarm_last_usi | uint32_t | 最近控制器报警:USI |
| 报警观测 | stack_alarm_last_len | uint32_t | 最近控制器报警:负载长度 |
| 错误 | error_code | int | 错误码原值(0 = 无) |
PnSServiceGetDiag
pns_result_t PnSServiceGetDiag(
pns_service_handle_t session,
pns_service_diag_t * p_diag);
一次取回当前诊断快照,适合界面刷新和日志。设备尚未启动时 ok == 0,读 message,不视为异常。过程区长度以运行配置为准,不要写死。
示例:
pns_service_diag_t snap;
if (PnSServiceGetDiag(session, &snap) != PNS_OK)
return 1;
if (!snap.ok)
{
printf("%s\n", snap.message);
return 0;
}
printf("%s\n", snap.link_up ? "Up" : "Down");
printf("%s\n", snap.connected ? "周期交换正常" : "未建立");
printf("帧: %llu / %llu\n",
(unsigned long long)snap.rx_frames,
(unsigned long long)snap.tx_frames);
printf("看门狗: %llu\n", (unsigned long long)snap.watchdog_trips);
IOPS
PnSServiceGetIoStatus
pns_result_t PnSServiceGetIoStatus(
pns_service_handle_t session,
pns_service_io_status_t * p_status,
uint16_t * p_input_iops_len, uint8_t * p_input_iops,
uint16_t * p_input_iocs_len, uint8_t * p_input_iocs,
uint16_t * p_output_iops_len, uint8_t * p_output_iops,
uint16_t * p_output_iocs_len, uint8_t * p_output_iocs);
IOPS / IOCS 快照。0x80 = GOOD,0x00 = BAD。掉线如实全 BAD。未 Start 时长度 0、all_good = 0,返回 PNS_OK。缓冲可为 NULL 只取派生判据。
| 字段 | 类型 | 说明 |
|---|---|---|
input_valid / output_valid | int | I 是否收到过输入数据 / Q 写过且已送达控制器(掉线、未送出 = 0) |
input_data_good | int | 输入 IOPS 全 GOOD |
output_data_good | int | 输出 IOPS 全 GOOD |
output_consumed | int | 输出 IOCS 全 GOOD |
all_good | int | 上面三项同时成立 |
iops_bad_count | int | IOPS 非 GOOD 的字节数(输入 + 输出) |
示例:
pns_service_io_status_t st;
if (PnSServiceGetIoStatus(session, &st,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL) == PNS_OK
&& !st.all_good)
printf("IOPS BAD %d\n", st.iops_bad_count);
现场问题对照
| 现场症状 | 看哪些字段 |
|---|---|
| 网线没插好 | GetDiag 的 link_up |
| 周期数据通不通 | GetDiag 的 connected |
| 看门狗反复跳 | watchdog_trips |
| 帧在丢 | dropped_frames + invalid_frames |
| 周期稳不稳 | stack_max_jitter_us + stack_missed_ticks |
| 数据质量 | GetIoStatus 的 all_good / iops_bad_count |
| 控制器报警没消化 | stack_alarm_ack_pending / stack_alarm_tx_ack_fail |
| 本机有没有活动报警 | GetAlarms / GetAlarmCount |
报警
上限 PNS_SERVICE_MAX_ALARMS = 64。
- 两段式:
p_items传NULL且items_cap=0仅查询数量。 - 实际条数大于容量时,已填充条目有效,
*p_count回写实际数量,返回PNS_ERR_INVALID_PARAM。 - 空列表不是失败。
| 成员 | 说明 |
|---|---|
PnSServiceGetAlarms | 当前活动报警 |
PnSServiceGetAlarmHistory | 历史(最近 500 条,时间升序) |
PnSServiceGetAlarmCount | 活动报警总数。与 GetAlarms 同源 |
PnSServiceGetCriticalAlarmCount | Critical 报警数 |
PnSServiceAlarmAck | 确认一条。无此 ID → PNS_ERR_NOT_FOUND |
PnSServiceAlarmAckAll | 确认全部。0 条也是成功 |
PnSServiceGetAlarms
pns_result_t PnSServiceGetAlarms(
pns_service_handle_t session,
pns_service_alarm_item_t * p_items,
size_t items_cap,
size_t * p_count);
当前活动报警。无活动报警返回空列表,不是失败。
示例:
pns_service_alarm_item_t items[PNS_SERVICE_MAX_ALARMS];
size_t n = 0;
if (PnSServiceGetAlarms(session, items, PNS_SERVICE_MAX_ALARMS, &n) == PNS_OK)
{
size_t i;
for (i = 0; i < n; i++)
printf("%s\n", items[i].message);
}
PnSServiceGetAlarmHistory
pns_result_t PnSServiceGetAlarmHistory(
pns_service_handle_t session,
pns_service_alarm_item_t * p_items,
size_t items_cap,
size_t * p_count);
报警历史(最近 500 条,时间升序)。无历史返回空列表,不是失败。
示例:
pns_service_alarm_item_t items[64];
size_t n = 0;
PnSServiceGetAlarmHistory(session, items, 64, &n);
PnSServiceAlarmAck
pns_result_t PnSServiceAlarmAck(
pns_service_handle_t session,
const char * id);
确认一条活动报警。ID 取自 GetAlarms。空串返回 PNS_ERR_INVALID_PARAM;无此 ID 返回 PNS_ERR_NOT_FOUND。
示例:
PnSServiceAlarmAck(session, "PnS.LinkDown");
PnSServiceAlarmAckAll
pns_result_t PnSServiceAlarmAckAll(
pns_service_handle_t session,
int * p_acked_count);
确认全部活动报警。p_acked_count 可为 NULL。
返回值:
PNS_OK—*p_acked_count为被确认条数(0 = 无活动报警)
示例:
int n = 0;
PnSServiceAlarmAckAll(session, &n);
pns_service_alarm_item_t
| 字段 | 类型 | 说明 |
|---|---|---|
| id | char[128] | 报警 ID(如 PnS.LinkDown) |
| severity | char[32] | 严重度:Info / Warning / Error / Critical |
| message | char[512] | 报警消息 |
| occurred_at | char[64] | 最近一次发生时间(ISO-8601 文本) |
| count | int | 发生次数(≥1) |
| source | char[128] | 来源 |
I&M 标识
PnSServiceGetIm()
pns_result_t PnSServiceGetIm(
pns_service_handle_t session,
pns_service_im_info_t * p_im);
I&M1–I&M3 已由原生栈启用并如实回读,I&M4 未启用。字段缺失保持空,不虚构;主站没写过时读到的是栈的出厂占位值,不是空串。
示例:
pns_service_im_info_t im;
if (PnSServiceGetIm(session, &im) == PNS_OK)
printf("%s vendor=0x%04X device=0x%04X\n",
im.station_name, im.vendor_id, im.device_id);
应用记录
PnSServiceGetRecords()
pns_result_t PnSServiceGetRecords(
pns_service_handle_t session,
pns_service_user_record_t * p_items,
size_t items_cap,
size_t * p_count);
两段式口径同 GetAlarms。空列表不是失败。
复位
PnSServiceReset()
pns_result_t PnSServiceReset(
pns_service_handle_t session,
pns_service_reset_mode_t mode);
typedef enum pns_service_reset_mode
{
PNS_SERVICE_RESET_COMMUNICATION = 0, /* 软停再启,记录保留 */
PNS_SERVICE_RESET_FACTORY = 1 /* 销毁后全新启动,记录清空 */
} pns_service_reset_mode_t;
慢操作,超时 15 秒。复位后会话仍可用。