C# API
Darra Profinet Slave 的 .NET 类库。程序集 DarraPnS,命名空间 DarraPnS.PnSlave。目标框架 netstandard2.0,是 6 语言 SDK 的基准实现。
using DarraPnS.PnSlave;
SDK 负责连接、启停会话、I/Q 读写。站点名、网卡、槽位由 GUI 导出运行配置,交给服务加载。周期自由配置,最低 1 ms。
推荐 — 高性能走结构体 /
PDO.In·PDO.Out;快速原型走地址化IW2/QW0。
快速开始
var dev = DarraPnS.Connect();
dev.Start();
dev.PDO.Write(ref tx); // 结构体 → I(只写)
dev.PDO.Read(ref rx); // Q → 结构体(只读)
dev.WriteInt16("IW2", 123);
short q = 0; dev.ReadInt16("QW0", out q); // 读 Q
dev.Stop();
不要 new DarraPnS(...)。LoadConfig 只供配置解析 / 变量联想建表。
连接 / 启停
| 成员 | 类型 | 类别 | 读写 | 说明 |
|---|---|---|---|---|
Connect() | DarraPnS | 设备 | 静态 | 本机会话 |
Connect(string host, int port = DefaultServicePort) | DarraPnS | 设备 | 静态 | 指定本机服务。host 只应填 127.0.0.1 |
Start() | PnSErrorCode | 设备 | 写 | 启动会话;已启动则返回成功 |
Stop() | void | 设备 | 写 | 停止本会话。主站在连时不要拆应用关系。Stop 后本实例不可复用 |
Dispose() | void | 设备 | 写 | 等价 Stop + 释放(幂等) |
DefaultServicePort | int | 设备 | 只读 | 本机服务默认端口 |
IsServiceMode | bool | 设备 | 只读 | 是否服务会话 |
IsRunning | bool | 设备 | 只读 | 本会话是否已成功 Start(运行态以 Connected / State 为准) |
生命周期:Connect → Start → [I/Q 读写] → Stop / Dispose。数据用属性(非 GetXxx),状态返回枚举。
运行态
优先读运行态;服务不可达时见各属性说明。
| 成员 | 类型 | 类别 | 读写 | 说明 |
|---|---|---|---|---|
Connected | bool | 设备 | 只读 | 是否已与 IO 控制器建立周期数据交换 |
State | PnSState | 设备 | 只读 | 运行态枚举。服务不可达为 Unknown |
ErrorCode | PnSRuntimeErrorCode | 设备 | 只读 | 最近一次运行错误(枚举)。未识别值 Unknown |
ErrorCodeRaw | int | 设备 | 只读 | 运行错误原值(0 = 无错误)。未识别值仍经本属性透传 |
ErrorMessage | string | 设备 | 只读 | 运行错误中文消息 |
LastServiceError | string | 设备 | 只读 | 最近一次服务错误(成功调用清空) |
Connected == true 才表示周期数据在换。IsRunning 只说明本实例已 Start,不等于主站已连。
地址化 I / Q
西门子风格地址,公共解析器 PnSAddress.Parse 单源。字 / 双字偏移即字节偏移,不强制 2 / 4 对齐(IW3 合法)。字 / 双字为大端(PROFINET 网络序)。
| 区域 | 地址格式 | 方向 | 写 | 读 |
|---|---|---|---|---|
| I(输入面) | I0.0 / IB0 / IW2 / ID4 | 设备 → 控制器 | 发送 | 读回本地影子 |
| Q(输出面) | Q0.0 / QB0 / QW2 / QD4 | 控制器 → 设备 | 不支持(NotSupported) | 读控制器数据 |
dev.WriteInt16("IW2", 123); // 写 I
short q = 0;
dev.ReadInt16("QW0", out q); // 读 Q
// dev.WriteInt16("QW0", 5); // → NotSupported
| 成员 | 类型 | 类别 | 读写 | 说明 |
|---|---|---|---|---|
WriteBool(string address, bool value) | PnSErrorCode | IO | 写 | 写位。仅 I;写 Q 返回 NotSupported |
WriteInt16(string address, short value) | PnSErrorCode | IO | 写 | 写字(IW2,大端)。写 QW0 → NotSupported |
WriteInt32(string address, int value) | PnSErrorCode | IO | 写 | 写双字(ID4,大端)。写 Q → NotSupported |
ReadBool(string address, out bool value) | PnSErrorCode | IO | 只读 | 读位(I 影子 / Q 控制器值) |
ReadInt16(string address, out short value) | PnSErrorCode | IO | 只读 | 读字(IW2 / QW0,大端) |
ReadInt32(string address, out int value) | PnSErrorCode | IO | 只读 | 读双字(ID4 / QD4,大端) |
地址化读写返回 PnSErrorCode,不抛出。未 Start 返回 InvalidHandle。
PDO
通过 dev.PDO 访问(Pdo 是同一实例的别名)。与地址化读写同源同区。
方向(2026-08-22 纠正旧倒置):
| 调用 | 方向 | 读写 |
|---|---|---|
PDO.Write(ref tx) | 结构体 → I(设备 → 控制器) | 只写 |
PDO.Read(ref rx) | Q → 结构体(控制器 → 设备) | 只读 |
PDO.Out[i] | 写 I 字节 | 可写 |
PDO.In[i] | 读 Q 字节 | 只读 |
PDO.Outputs | get = I 影子;set = 整段写 I | 读写 |
PDO.Inputs | 当前 Q 快照(每次新拷) | 只读 |
结构体映射
结构体必须 [StructLayout(LayoutKind.Sequential, Pack = 1)]。字段按声明顺序紧排;bool 占 1 字节;字 / 双字 / 8 字节大端。支持数值、bool、枚举、定长 byte[](MarshalAs(ByValArray, SizeConst=N))、嵌套结构体。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PdoData
{
public byte A; // 偏移 0
public short B; // 偏移 1(大端)
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public byte[] D; // 偏移 3
}
PdoData tx = new PdoData { A = 1, B = -2, D = new byte[] { 9, 8, 7, 6 } };
dev.PDO.Write(ref tx); // 结构体 → I(只写)
PdoData rx = new PdoData();
dev.PDO.Read(ref rx); // Q → 结构体(只读)
也可 dev.WriteStruct(ref tx) / dev.ReadStruct(ref rx),与上同义。
In / Out
byte q0 = dev.PDO.In[0].Content; // 读 Q
dev.PDO.Out[0].Content = 0x11; // 写 I
short iw = dev.PDO.Out[2].AsInt16; // 大端字
dev.PDO.Out[2].AsInt16 = 123;
// dev.PDO.In[0].Content = 1; // 抛 InvalidOperationException(In 只读)
In[i] / Out[i] 的 i 是过程映像字节偏移。PdoDataItem 另有 AsUInt16 / AsInt32 / AsFloat / GetBit / SetBit(SetBit 仅 Out)。
InputsMapping
将 Q 区映射为结构体快照。无 live 指针(每次从过程数据拷贝)。可选 1 ms 内部轮询 OnChanged(SDK 内部定时器)。
InputPdoInstance<PdoData> mapped = dev.PDO.InputsMapping<PdoData>();
PdoData snap = mapped.ValueSnapshot;
var watch = dev.PDO.InputsMapping<PdoData>(e =>
{
// e.Previous / e.Current / e.Timestamp
});
OutputsMapping(ref T) 与 Write(ref T) 同义(结构体 → I)。
GetFieldAddress
字段名 → I/Q 地址,供地址化读写按字段访问。无参重载默认 Q(与 Read 同向)。
string qAddr = dev.PDO.GetFieldAddress<PdoData>("B"); // "QW1"
string iAddr = dev.PDO.GetFieldAddress<PdoData>("B", PnSAddressArea.Input); // "IW1"
short b;
dev.ReadInt16(qAddr, out b);
dev.WriteInt16(iAddr, 123);
| 成员 | 类型 | 类别 | 读写 | 说明 |
|---|---|---|---|---|
PDO / Pdo | PnSPdo | PDO | 只读 | PDO 子对象(同一实例) |
PDO.Write<T>(ref T data) | PnSErrorCode | PDO | 写 | 结构体 → I |
PDO.Read<T>(ref T data) | PnSErrorCode | PDO | 只读 | Q → 结构体 |
PDO.Out | PdoArrayInstance | PDO | 写 | Out[offset] 写 I |
PDO.In | PdoArrayInstance | PDO | 只读 | In[offset] 读 Q |
PDO.Outputs | byte[] | PDO | 读写 | get = I 影子;set = 写 I |
PDO.Inputs | byte[] | PDO | 只读 | 当前 Q 快照 |
PDO.InputsMapping<T>() | InputPdoInstance<T> | PDO | 只读 | Q → 结构体快照 |
PDO.InputsMapping<T>(onChanged) | InputPdoInstance<T> | PDO | 只读 | 同上 + 内部 1 ms 变化回调 |
PDO.GetFieldAddress<T>(name) | string | PDO | 只读 | 字段 → Q 区地址 |
PDO.GetFieldAddress<T>(name, area) | string | PDO | 只读 | 字段 → I / Q 地址 |
WriteStruct<T>(ref T data) | PnSErrorCode | PDO | 写 | PDO.Write 转发 |
ReadStruct<T>(ref T data) | PnSErrorCode | PDO | 只读 | PDO.Read 转发 |
失败码
两类码不要混用。
调用返回码 PnSErrorCode:Start / 地址化读写 / PDO.Read·Write 的返回值。IO 路径不抛异常。
| 值 | 含义 |
|---|---|
Success (0) | 成功 |
InvalidArgument | 地址非法 / 空缓冲 |
InvalidHandle | 未 Start 或已 Stop |
NotConnected | 无 AR / 未进入数据交换 |
NativeError | 栈 / 服务端错误 |
LengthMismatch | 长度越界 |
NotFound | 地址 / 条目不存在 |
Busy | 上一次操作未完成 |
NotSupported | 写 Q 等不支持的操作 |
NativeDllNotFound | native DLL 未加载 |
PlatformNotSupported | 仅 Windows x64 |
ServiceUnreachable | 服务不可达 |
运行态码 PnSRuntimeErrorCode(属性 ErrorCode):Ok=0 / ErrInit=-1 / ErrCfg=-2 / ErrThread=-3 / ErrRunning=-4 / ErrPdi=-5 / ErrDap=-6 / Unknown=-10000。
Connect("127.0.0.1") 或 Start 失败时可能抛 PnSServiceException(带 PnSErrorCode + 原因)。
完整示例
using System.Runtime.InteropServices;
using DarraPnS.PnSlave;
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PdoData
{
public short Status;
public short Command;
}
var dev = DarraPnS.Connect();
if (dev.Start() != PnSErrorCode.Success)
{
Console.WriteLine("启动失败: " + dev.LastServiceError);
return;
}
PdoData tx = new PdoData { Status = 123 };
dev.PDO.Write(ref tx); // 结构体 → I
dev.WriteInt16("IW2", 123); // 地址化写 I
PdoData rx = new PdoData();
dev.PDO.Read(ref rx); // Q → 结构体
short q = 0;
dev.ReadInt16("QW0", out q); // 地址化读 Q
bool onBus = dev.Connected;
PnSRuntimeErrorCode err = dev.ErrorCode;
dev.Stop();