设备 API 结构
PROFINET IO Device 的 C 入口,用来启动设备、写 Q / 读 I、看运行态和诊断。句柄是 pns_service_handle_t。
本 SDK 只做 PROFINET IO Device,不提供其它现场总线协议的入口。
API 结构
静态 pns_* 不必会话。会话函数第一个参数是 session。诊断函数编成一组,对应 C# device.Diagnostics。
static
├── pns_is_service_ready / pns_service_connected / pns_service_state
├── pns_service_wait_reason / pns_service_status_message
└── pns_last_error / pns_last_error_code / pns_runtime_error_message
pns_service_handle_t session
│
├── PnSServiceConnectRealtime / PnSServiceStart / PnSServiceStop / PnSServiceClose
│
├── 过程数据 In(读 I,模块输入,只读)
│ ├── PnSProcessDataInputsMapping / PnSProcessDataInputsMappingRO // 0 拷贝:映射一次,字段自己变(I 只读;RO = 只读视图)
│ ├── PnSProcessDataInI8 / PnSProcessDataInU8 / PnSProcessDataInI16 / PnSProcessDataInU16
│ ├── PnSProcessDataInI32 / PnSProcessDataInU32 / PnSProcessDataInI64 / PnSProcessDataInU64
│ ├── PnSProcessDataInF32 / PnSProcessDataInF64
│ ├── PnSProcessDataInBool / PnSProcessDataInBit
│ ├── PnSProcessDataReadStruct / PnSProcessDataCopyInputsTo // 快照
│ └── PnSServiceRead / ReadArea / ReadBool / ReadInt16 / ReadInt32
├── 过程数据 Out(写 Q,模块输出,可写)
│ ├── PnSProcessDataOutputsMapping // 0 拷贝:改字节即改过程映像
│ ├── PnSProcessDataOutI8 / PnSProcessDataOutU8 / PnSProcessDataOutI16 / PnSProcessDataOutU16
│ ├── PnSProcessDataOutI32 / PnSProcessDataOutU32 / PnSProcessDataOutI64 / PnSProcessDataOutU64
│ ├── PnSProcessDataOutF32 / PnSProcessDataOutF64
│ ├── PnSProcessDataOutBool / PnSProcessDataOutBit
│ ├── PnSProcessDataWriteStruct / PnSProcessDataCopyToOutputs // 快照
│ └── PnSServiceWrite / WriteArea / WriteBool / WriteInt16 / WriteInt32
│
├── 事件
│ ├── PnSServiceOnConnectedChanged
│ ├── PnSServiceOnStateChanged
│ ├── PnSServiceOnErrorOccurred
│ └── PnSServiceOnLogged
│
├── PnSServiceIsConnected / GetState / GetWaitReason / GetEverConnected / GetErrorCode
│
├── 诊断(对应 C# device.Diagnostics)
│ ├── PnSServiceGetDiag
│ ├── PnSServiceGetIoStatus
│ ├── PnSServiceGetAlarms / GetAlarmHistory
│ └── PnSServiceGetRecords
│
└── PnSServiceGetIm
写 Q(模块输出,设备 → 控制器),读 I(模块输入,控制器 → 设备)。
用法
启停
#include "pns.h"
pns_service_handle_t session = NULL;
if (PnSServiceConnectRealtime(&session) != PNS_OK)
return 1;
if (PnSServiceStart(session) != PNS_OK)
return 1;
while (running)
{
if (!PnSServiceIsConnected(session))
{
/* PnSServiceGetWaitReason(session) */
continue;
}
PnSServiceWriteBool(session, "Q0.0", true); /* 写 Q */
{
bool from_plc = false;
PnSServiceReadBool(session, "I0.0", &from_plc); /* 读 I */
}
}
PnSServiceStop(session);
PnSServiceClose(session);
看状态不必建会话:pns_is_service_ready / pns_service_connected / pns_service_wait_reason。
过程数据
| 方式 | 访问 | 说明 |
|---|---|---|
| 过程数据 | PnSProcessDataInputsMapping / PnSProcessDataInputsMappingRO / PnSProcessDataOutputsMapping | 0 拷贝:映射一次(I 只读视图用 RO) |
| 过程数据 | PnSProcessDataIn* / PnSProcessDataOut* | 快照 / 类型化偏移 |
标识
PnSServiceGetIm 填 pns_service_im_info_t。I&M1–I&M3 已由原生栈启用并如实回读,I&M4 未启用。字段缺失保持空,不虚构;主站没写过时读到的是栈的出厂占位值,不是空串。
| 字段 | 说明 |
|---|---|
station_name | 站点名 |
vendor_id | 厂商 ID |
device_id | 设备 ID |
order_id | 订货号 |
serial_number | 序列号 |
hardware_revision | 硬件版本 |
software_revision | 软件版本 |
product_name | 产品名 |
im_supported | 已启用的 I&M 记录集 |
im14_supported | I&M1–4 是否启用(0 / 1) |
im_note | 标识说明 |
project_order_number | 工程订货号 |
project_hardware_release | 工程硬件版本 |
project_software_release | 工程软件版本 |
im1_tag_function | I&M1 功能标签 |
im1_tag_location | I&M1 安装位置 |
im2_date | I&M2 日期 |
im3_descriptor | I&M3 描述 |
im4_signature_hex | 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);
过程数据读写
结构体按声明顺序紧排。字 / 双字为大端。详见 过程数据。
金路径是 0 拷贝:映射一次,源头变字段自己变。多字节字段是网络大端(线上字节序),要宿主数值走「自动转换」的类型化访问器。
#pragma pack(push, 1)
typedef struct {
uint8_t a;
int16_t b;
uint8_t flag;
} from_plc_t;
#pragma pack(pop)
volatile uint8_t *q = NULL;
const uint8_t *i = NULL;
size_t ni = 0, nq = 0;
if (PnSProcessDataInputsMappingRO(session, &i, &ni) != PNS_OK ||
PnSProcessDataOutputsMapping(session, &q, &nq) != PNS_OK ||
i == NULL || q == NULL) /* 失败时 *p = NULL */
{
/* 过程映像不可用 */
}
const from_plc_t *inp = (const from_plc_t *)i; /* I 只读视图 */
from_plc_t *outp = (from_plc_t *)q;
uint8_t present = inp->a; /* 总线刷新后自己变 */
outp->a = 1; /* 直接落 Q 过程映像 */
/* 快照:拷出来不会自己变 */
from_plc_t rx;
PnSProcessDataReadStruct(session, &rx, (uint16_t)sizeof(rx));
PnSProcessDataOutU8(session, 0, 0x11);
uint8_t v = 0;
PnSProcessDataInU8(session, 0, &v);
诊断与报警
通过 PnSServiceGetDiag / PnSServiceGetAlarms 读诊断(与 C# device.Diagnostics 同一组能力)。详见 诊断。事件见 事件。
pns_service_diag_t snap;
if (PnSServiceGetDiag(session, &snap) == PNS_OK && !snap.ok)
printf("%s\n", snap.message);
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);
}