跳到主要内容

C# API

Darra PnSlave 的 .NET 类库。产品名 PnSlave;程序集暂名 DarraPnet,命名空间 DarraPnet.Pnet(标识符本波不改)。目标框架 netstandard2.0,是 6 语言 SDK 的基准实现。

using DarraPnet.Pnet;

SDK 只负责【使用】——连接过程映像 + 启停会话 + I/Q 读写。站点名、网卡、槽位由 GUI 导出运行配置 XML,交给 Service 加载。应用不要写用户周期:周期由驱动 / 服务持有。

推荐 — 高性能走结构体 / PDO.In·PDO.Out;快速原型走地址化 IW2 / QW0

快速开始

实时主路径:Connect() 映射 \Device\DarraRT_Pnet_GlobalIO,读写直接拷过程映像。不探测 HTTP,不打开 \\.\DarraRT_Pnet(B1 句柄独占)。

var dev = DarraPnet.Connect(); // 实时主路径,映射 GlobalIO
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
// WriteInt16("QW0", 5) → NotSupported
dev.Stop(); // 在连只 unmap,不 POST /api/stop

HTTP 备用一行:DarraPnet.Connect("127.0.0.1")(探测 GET /api/info,失败抛 PnetServiceException)。仅 GUI / 远程诊断 / 报警 / I&M 用;实时 IO 仍优先共享内存。

不要 new DarraPnet(...)。native 直连(A1)Start() fail-fast:D_1003 pnet_wrapper_init 与 SDK 私有配置布局不匹配。LoadConfig 只供配置解析 / 变量联想建表。

Connect / Start / Stop

成员类型类别读写说明
Connect()DarraPnet设备静态实时主路径。不经 Web API,不探测 HTTP。Start 映射 GlobalIO
Connect(string host, int port = DefaultServicePort)DarraPnet设备静态HTTP 备用。创建时探测 GET /api/info。host 只应填 127.0.0.1
Start()PnetErrorCode设备映射 GlobalIO;已映射幂等返回 Success。Section 打不开才备用 HTTP 挂接
Stop()void设备卸载映射。主站在连(Connected == true)只 unmap, POST /api/stop,不撕 AR。Stop 后本实例不可复用
Dispose()void设备等价 Stop + 释放(幂等)
DefaultServicePortint设备只读HTTP 备用端口 18840(编译期常量)
IsServiceModebool设备只读是否 Connect 会话(实时 / HTTP 备用均为 true)
IsRunningbool设备只读本会话是否已成功 Start(本地标志;运行态以 Connected / State 为准)

生命周期:Connect → Start → [I/Q 读写] → Stop / Dispose。数据用属性(非 GetXxx),状态返回枚举。

运行态

优先读共享内存头;未映射才走 GET /api/status

成员类型类别读写说明
Connectedbool设备只读是否已与 IO 控制器建立周期数据交换。映射后读 GlobalIO 头;否则透出服务端 connected
StatePnetState设备只读运行态枚举。服务不可达如实 Unknown,不伪装 None
ErrorCodePnetRuntimeErrorCode设备只读最近一次运行错误(枚举)。未识别值 Unknown
ErrorCodeRawint设备只读运行错误原值(0 = 无错误)。未识别值仍经本属性透传
ErrorMessagestring设备只读运行错误中文消息
LastServiceErrorstring设备只读最近一次 HTTP 备用错误(成功调用清空)

Connected == true 才表示周期数据在换。IsRunning 只说明本实例已 Start,不等于主站已连。

地址化 I / Q

西门子风格地址,公共解析器 PnetAddress.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)PnetErrorCodeIO写位。仅 I;写 Q 返回 NotSupported
WriteInt16(string address, short value)PnetErrorCodeIO写字(IW2,大端)。写 QW0NotSupported
WriteInt32(string address, int value)PnetErrorCodeIO写双字(ID4,大端)。写 Q → NotSupported
ReadBool(string address, out bool value)PnetErrorCodeIO只读读位(I 影子 / Q 控制器值)
ReadInt16(string address, out short value)PnetErrorCodeIO只读读字(IW2 / QW0,大端)
ReadInt32(string address, out int value)PnetErrorCodeIO只读读双字(ID4 / QD4,大端)

地址化读写返回 PnetErrorCode不抛出。未 Start 返回 InvalidHandle

前 4 字节回写是主站行为。 从站不要把 Q 抄回 I,也不要写用户周期做回声。测法:写 I,再读 Q,看主站是否把前 4 字节同步过来。

PDO

通过 dev.PDO 访问(Pdo 是同一实例的别名)。与地址化读写同源同区。无用户周期 API。

方向(2026-08-22 纠正旧倒置):

调用方向读写
PDO.Write(ref tx)结构体 → I(设备 → 控制器)只写
PDO.Read(ref rx)Q → 结构体(控制器 → 设备)只读
PDO.Out[i]写 I 字节可写
PDO.In[i]读 Q 字节只读
PDO.Outputsget = 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 / SetBitSetBit 仅 Out)。

InputsMapping

将 Q 区映射为结构体快照。无 live 指针(每次从过程映像解码)。可选 1 ms 内部轮询 OnChanged——这是 SDK 内部定时器,不是用户周期 API。

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", PnetAddressArea.Input); // "IW1"
short b;
dev.ReadInt16(qAddr, out b);
dev.WriteInt16(iAddr, 123);
成员类型类别读写说明
PDO / PdoPnetPdoPDO只读PDO 子对象(同一实例)
PDO.Write<T>(ref T data)PnetErrorCodePDO结构体 → I
PDO.Read<T>(ref T data)PnetErrorCodePDO只读Q → 结构体
PDO.OutPdoArrayInstancePDOOut[offset] 写 I
PDO.InPdoArrayInstancePDO只读In[offset] 读 Q
PDO.Outputsbyte[]PDO读写get = I 影子;set = 写 I
PDO.Inputsbyte[]PDO只读当前 Q 快照
PDO.InputsMapping<T>()InputPdoInstance<T>PDO只读Q → 结构体快照
PDO.InputsMapping<T>(onChanged)InputPdoInstance<T>PDO只读同上 + 内部 1 ms 变化回调
PDO.GetFieldAddress<T>(name)stringPDO只读字段 → Q 区地址
PDO.GetFieldAddress<T>(name, area)stringPDO只读字段 → I / Q 地址
WriteStruct<T>(ref T data)PnetErrorCodePDOPDO.Write 转发
ReadStruct<T>(ref T data)PnetErrorCodePDO只读PDO.Read 转发

失败码

两类码不要混用。

调用返回码 PnetErrorCodeStart / 地址化读写 / PDO.Read·Write 的返回值。IO 路径不抛异常。

含义
Success (0)成功
InvalidArgument地址非法 / 空缓冲
InvalidHandleStart 或已 Stop
NotConnected无 AR / 未进入数据交换
NativeError栈 / 服务端错误
LengthMismatch长度越界
NotFound地址 / 条目不存在
Busy上一次操作未完成
NotSupported写 Q 等不支持的操作
NativeDllNotFoundnative DLL 未加载
PlatformNotSupported仅 Windows x64
ServiceUnreachableHTTP 备用探测 / 请求失败

运行态码 PnetRuntimeErrorCode(属性 ErrorCode):共享内存头 / GET /api/statuserrorCodeOk=0 / ErrInit=-1 / ErrCfg=-2 / ErrThread=-3 / ErrRunning=-4 / ErrPdi=-5 / ErrDap=-6 / Unknown=-10000。

HTTP 备用 Connect("127.0.0.1") 探测失败、以及 Section 打不开后 HTTP Start 失败,抛 PnetServiceException(带 PnetErrorCode + 原因)。实时主路径 Connect() 创建时不抛。

完整示例

using System.Runtime.InteropServices;
using DarraPnet.Pnet;

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct PdoData
{
public short Status;
public short Command;
}

var dev = DarraPnet.Connect();
if (dev.Start() != PnetErrorCode.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;
PnetRuntimeErrorCode err = dev.ErrorCode;

dev.Stop(); // 在连只 unmap

相关