跳到主要内容

诊断

通过 PnSServiceGetDiag / PnSServiceGetAlarms 读诊断与报警(与 C# device.Diagnostics 同一组能力)。

配合事件使用

建议通过 事件 驱动异常处理,而非自行轮询。 直接读取诊断适用于界面显示等场景。

运行态(IsConnected / GetState / GetErrorCode)见 属性与状态机。过程数据读写见 过程数据

功能概览

功能说明
诊断快照链路、帧计数、看门狗、抖动、报警观测
IOPS过程数据质量
现场问题对照按症状选字段
报警活动列表 / 历史 / 确认

诊断快照

类别字段类型说明
可用性okint诊断是否可用。0 = 设备未启动,读 message
可用性shared_memory_mappedint过程数据是否已就绪
可用性messagechar[256]不可用时的原因;可用时为空
链路statechar[32]运行状态文案
链路link_upint网卡链路是否 Up
链路connectedint周期数据是否正常
链路active_iocr_countuint32_t已激活的 IO 连接数
链路iocr_active / iocr_healthyuint32_tIO 连接激活 / 健康位图
计数heartbeat / cycle_counteruint64_t心跳 / 周期循环计数
计数last_erroruint64_t最近错误码(0 = 无)
计数rx_frames / tx_framesuint64_t收 / 发总帧数
计数rx_rt_frames / tx_rt_framesuint64_t收 / 发 RT 周期帧
计数dropped_frames / invalid_framesuint64_t被丢弃 / 非法帧
计数watchdog_tripsuint64_t看门狗超时次数
计数last_rx_tsc / last_tx_tscuint64_t最近收 / 发帧 TSC
过程区input_area_lengthuint32_t输入区长度(字节)
过程区output_area_lengthuint32_t输出区长度(字节)
周期stack_cyclesuint64_t周期计数
周期stack_frames_rx / stack_frames_txuint64_t收 / 发帧
周期stack_missed_ticksuint64_t错过的节拍
周期stack_max_jitter_usuint64_t最大抖动(微秒)
报警观测stack_alarm_rx_countuint64_t收到控制器报警总数
报警观测stack_alarm_tx_ack_okuint64_t本机报警被确认次数
报警观测stack_alarm_tx_ack_failuint64_t本机报警确认失败次数
报警观测stack_alarm_ack_pendinguint64_t在途报警(0/1)
报警观测stack_alarm_maint_stateuint64_t维护请求状态
报警观测stack_alarm_last_arepuint32_t最近控制器报警:Arep
报警观测stack_alarm_last_slotuint32_t最近控制器报警:槽位
报警观测stack_alarm_last_subslotuint32_t最近控制器报警:子槽位
报警观测stack_alarm_last_typeuint32_t最近控制器报警:类型
报警观测stack_alarm_last_sequint32_t最近控制器报警:序列号
报警观测stack_alarm_last_usiuint32_t最近控制器报警:USI
报警观测stack_alarm_last_lenuint32_t最近控制器报警:负载长度
错误error_codeint错误码原值(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_validintI 是否收到过输入数据 / Q 写过已送达控制器(掉线、未送出 = 0)
input_data_goodint输入 IOPS 全 GOOD
output_data_goodint输出 IOPS 全 GOOD
output_consumedint输出 IOCS 全 GOOD
all_goodint上面三项同时成立
iops_bad_countintIOPS 非 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);

现场问题对照

现场症状看哪些字段
网线没插好GetDiaglink_up
周期数据通不通GetDiagconnected
看门狗反复跳watchdog_trips
帧在丢dropped_frames + invalid_frames
周期稳不稳stack_max_jitter_us + stack_missed_ticks
数据质量GetIoStatusall_good / iops_bad_count
控制器报警没消化stack_alarm_ack_pending / stack_alarm_tx_ack_fail
本机有没有活动报警GetAlarms / GetAlarmCount

报警

上限 PNS_SERVICE_MAX_ALARMS = 64。

  • 两段式:p_itemsNULLitems_cap=0 仅查询数量。
  • 实际条数大于容量时,已填充条目有效,*p_count 回写实际数量,返回 PNS_ERR_INVALID_PARAM
  • 空列表不是失败。
成员说明
PnSServiceGetAlarms当前活动报警
PnSServiceGetAlarmHistory历史(最近 500 条,时间升序)
PnSServiceGetAlarmCount活动报警总数。与 GetAlarms 同源
PnSServiceGetCriticalAlarmCountCritical 报警数
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
字段类型说明
idchar[128]报警 ID(如 PnS.LinkDown
severitychar[32]严重度:Info / Warning / Error / Critical
messagechar[512]报警消息
occurred_atchar[64]最近一次发生时间(ISO-8601 文本)
countint发生次数(≥1)
sourcechar[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 秒。复位后会话仍可用。