跳到主要内容

Darra_Profinet_Slave 全栈跨层契约交叉审计报告

审计轮: 2026-08-14 (全栈审计 wave · 跨层契约交叉审计 agent) 范围: Darra_Profinet_Slave 全仓 (排除 bin/obj/out/_archive/_Stage/其他参考/ThirdParty 内容本体; ThirdParty 仅作语义对照取证) 性质: 只读审计, 不修代码。本文只落档证据与分级, 修复由其他 agent 按文件域执行。 六轴审计: ① 端口/端点 ② 配置 schema 端到端 ③ 命名 ④ 0x/十进制口径 ⑤ 文档一致性 ⑥ 版本。

0. 结论速览

级别数量主题
P0 跨层语义反转1输入/输出方向语义在 GSDML/控制面(标准) 与 驱动/服务数据面(反转) 之间交叉 — 见 §2.1
P1 文档与代码冲突/内部矛盾3十六进制规范 vs 用户新裁定 0x; rt-class-1.md 两种方向口径并存; 共存契约 BindForm 过时
P2 口径错位4IOPS/IOCS 每子槽语义; 报警严重度枚举两套; INF 版本治理; quickstart 示例路径
P3 信息/登记2"IO" 第三方向不存在于配置链; 设计文档版本单源与 BindForm 表述
PASS 轴端口 18840 单源 / 0x-十进制生成器→验证器→C 解析器 / JSON camelCase / 版本 1.0.0 全链 (细节见各节)

1. 端口/端点轴

检查项各层证据结论
服务 HTTP API 端口 18840 单源服务常量 PnetApiServer.FixedPort = 18840 (PnetApiServer.cs:111); 客户端常量 GuiClient.FixedPort = 18840 + DefaultBaseUrl = http://127.0.0.1:18840 (GuiClient.cs:56/59); GUI 常量 PnetApiPort = 18840 (MainForm.cs:531); appsettings.json 注释声明"不提供 Api:Port 键"; docs/docs/index.md / 设计文档.md §3 一致✅ PASS, 全仓单源一致, 仅本地回环
18821 (DarraLink) 是否误用全仓 18821 仅 2 处命中, 均为注释"仿 DarraLink 18821 固定端口原则" (PnetApiServer.cs:7/110, SDK DarraPnet.cs:339), 无任何代码使用✅ PASS, 与 DarraLink 无耦合
驱动设备路径 \\.\DarraRT_Pnetappsettings.json:38 DriverDevicePath = "\\\\.\\DarraRT_Pnet"; PnetConfigService.cs:60 默认值同; PnetDriverBridge.cs:355 DevicePath = @"\\.\DarraRT_Pnet"; 设计文档.md:230 一致✅ PASS, 三处同值
命名 Section \Device\DarraRT_Pnet_GlobalIOPnetDriverBridge.cs:358 SectionName; PnetRuntime.cs:26; 设计文档.md:252 一致✅ PASS
其余端口变体 (1884x/1882x/1844x)全仓 grep 无其他固定端口✅ PASS

2. 配置 schema 端到端轴

链路: PnetProject (GUI 模型)device-config.dpnet (JSON 持久化)ConfigWriter 运行配置 XML服务 PnetConfigService.LoadBuildIocrConfigs (IOCR)/api/io 元数据GUI 数据测试显示

2.1 ★ P0 — 输入/输出方向语义跨层反转 (GSDML/控制面 vs 驱动/服务数据面)

同一份 XML 的 InputLength 在控制面与数据面被映射到相反的协议方向:

Input 的语义证据
GUI 模型枚举注释输入 = 从站 → PLC (标准)GsdmlWriter.cs:38-43 PnetIoDirection.Input, Output 注释 "输入 (从站 -> PLC) / 输出 (PLC -> 从站)"
GSDML 输出Direction==Input → <Input> 元素 (GSDML 规范: 从站 → 控制器)GsdmlWriter.cs:576-600 AddDirection(PnetIoDirection.Input, "Input")
运行配置 XMLIoItem Direction="Input" / InputLength = Σ Input 条目ConfigWriter.cs:333 / 311-317
文档口径concepts.md:21-26 "Input: 从站 → 控制器"; :90-91 "PPM(Provider)=从站→控制器 输入区数据; CPM(Consumer)=控制器→从站 输出区数据"; rt-class-1.md:45 "PPM 发输入数据, CPM 收输出数据"标准语义
上游 p-net (ThirdParty)PNET_DIR_INPUT 子模块 → PF_DIRECTION_INPUT + IOPS (Provider=发送方); C 核心 pnet_wrapper.c:186-210 由 input_len>0PNET_DIR_INPUT标准语义, 控制面据此插子模块
服务 BuildIocrConfigs (数据面)ΣInputLength → IOCR[0] = CPM (0x0200, 控制器→设备, 写"输入区"); ΣOutputLength → IOCR[1] = PPM (0x0100, 设备→控制器, 读"输出区")PnetRuntime.cs:2112-2128 + 2181-2221
驱动CPM (控制器→设备) 收帧写入共享内存"输入区"; PPM (设备→控制器) 从"输出区"组帧发送DarraRT_Pnet_Iocr.c:4-7
/api/ioInputHex = "输入区数据 (应用从 PDI 收, 控制器 → 设备)"; OutputHex = "设备 → 控制器"PnetApiModels.cs:56-57/68-69
GUI 数据测试"输入区: inputHex (控制器 → 设备, CPM); 输出区: outputHex (设备 → 控制器, PPM)"DataTestView.cs:8-10
SDK 服务模式补偿映射注释: "SDK I 区 → 服务端 OutputArea (PPM 设备→控制器); SDK Q/DB 区 → 服务端 InputArea (CPM 控制器→设备)"SDK DarraPnet.cs:1382-1387

判定: 控制面 (上游栈 + GSDML + 文档) 全部采用标准语义 (Input=从站→控制器=PPM); 数据面 (服务 IOCR 构建 + 驱动 + /api/io + 数据测试 UI) 命名反转 (CPM 区叫"输入区")。后果:

  1. GSDML <Input> 声明的大小 = Σ Input 条目, 但运行时设备实际发送 (PPM) 的大小 = Σ OutputLength。真实控制器 (TIA) 按 GSDML 期望收 N 发 M, 设备侧 CPM 窗口 = N、PPM 发送 = M — 输入/输出 CR 尺寸交叉。Input≠Output 的不对称工程在参数化/CConnect 阶段必然失配; 对称工程 (N==M) 侥幸不暴露。
  2. 驱动 CPM/PPM 帧方向本身正确 (0x0100=PPM/0x0200=CPM 各层一致), 错的是区名与 InputLength/OutputLength 的挂接方向
  3. 服务内部用 p-net 的 output API 处理"输入区" (PnetRuntime.cs:1820-1822 pnet_output_set_iocs 语义), 用 input API 处理"输出区" (PnetRuntime.cs:1927-1929), 是桥接补偿 — 说明两层语义冲突已被意识到但未在配置链源头归一。

修复方向建议 (供修复 agent): 以标准语义为准 (GUI 模型注释 / GSDML / 上游栈 / concepts.md 四方一致), 改 BuildIocrConfigs 的挂接 (ΣInputLength → PPM 0x0100 发送区, ΣOutputLength → CPM 0x0200 接收区) 并同步驱动共享内存区名与 /api/io、DataTestView、SDK 注释。涉及文件域: PnetRuntime.cs / DarraRT_Pnet_{Iocr,Shared,Frame}.c/h / PnetApiModels.cs / DataTestView.cs / SDK DarraPnet.cs — 与 r2-input-consistency / q1-device-input-official-mask agent 的文件域可能重叠, 派修前先对文件域分配表。

2.2 各跳字段核对 (方向问题除外, 均 PASS)

字段证据结论
模型 → XMLStationName/DeviceName/VendorID(0x%04X)/DeviceID(0x%04X)/HardwareRelease/SoftwareReleaseConfigWriter.cs:275-285; 往返校验 VerifyRoundTrip 逐字段比对 (87-250)
模型 → XMLModuleIdentNumber/SubmoduleIdentNumber 属性 0x 固定 8 位; Slot/Subslot 属性十进制ConfigWriter.cs:313-324
模型 → XMLIoItem Direction="Input"/"Output"、Offset/Length 十进制属性 + Name 元素ConfigWriter.cs:331-337✅ (Direction 语义见 §2.1)
XML → 服务 LoadParseHex16 支持 0x 前缀; SendClock 毫秒 → CycleMs (钳 1..1000, 三层统一 audit-2026-08-13); <DeviceName> → ProductNamePnetConfigService.cs:451-493
配置分层优先级 环境变量 DARRA_PNET_* > XML > appsettings; 6 键 PnetEnvKeys 单一权威; DriverAdapterName 最终化 = NetworkInterfaceName (单一网口收敛)PnetConfigService.cs:168-330
XML → 服务过程映像过程映像区大小由 SlotLayout 子模块 InputLength/OutputLength 累加推导 (与 BuildIocrConfigs 同规则), 弃 256/256 静态默认PnetConfigService.cs:505-551 (audit-2026-08-14)✅ (方向挂接见 §2.1)
XML 缺失服务拒绝启动 (如实抛异常), 不静默空跑PnetConfigService.cs:255-270
XML 路径相对路径按 AppContext.BaseDirectory 解析 + 落 Info 日志; GUI 下发落盘契约 C:\DARRA\Profinet_Slave\config\runtime-config.xml (MainForm.cs:1416-1444 双候选: GUI 目录 ../config 优先)PnetConfigService.cs:236-253; MainForm.cs
IOCR 构建CPM/PPM DataLength = Σ 子模块长度; 超 1440 (PnetDriverAbi.MaxIoData) 如实报错; 周期 µs = CycleMs×1000 钳制PnetRuntime.cs:2112-2227✅ (方向见 §2.1)
/api/io 元数据InputLength/OutputLength (字节) + hex 大写文本 + FormatVersion=1 + IoEpochPnetApiModels.cs:50-94; PnetApiServer.cs:586-596 Convert.ToHexString (大写)
/api/io → GUI 数据测试区大小权威 = 元数据 InputLength/OutputLength, hex 解析长度仅兜底; 16 字节/行网格; KB=字节/1024DataTestView.cs:527-556
JSON 序列化契约服务端 camelCase (JsonOptions, PnetApiServer.cs:1458-1460) ↔ SDK 最小解析器按 camelCase 键消费 (DarraPnet.cs:1930-1960)
枚举方向 "IO"全配置链 (GUI 模型/XML/C 解析器 pnet_config.c:1208-1221) 仅 Input/Output; "IO" 仅存在于 SDK 派生 (InOut, 双长度>0, DarraPnet.cs:1319-1321) 与原生常量 (PNET_DIR_IO / PNET_DIR_NO_IO, PnetNative.cs:91-99)✅ 一致, 登记
C 解析器 Direction仅 "Input"(0)/"Output"(1), 其他字符串报错 "IoItem.Direction 非法"pnet_config.c:1208-1221

3. 命名轴 (三层命名)

用法结论
驱动组件/服务名 (netcfg/sc)DarraRT_PnetINF AddService = DarraRT_Pnet (:39); install-pnet.ps1 $ComponentName='DarraRT_Pnet' (:42); GUI 注册表探测 SYSTEM\CurrentControlSet\Services\DarraRT_Pnet (MainForm.cs:528, SplashScreen.cs:206)✅ 正确 (服务键 = 组件名)
NDIS 协议注册名 (BindForm)DarraRTPnet (去下划线)DARRT_PNET_NDIS_PROTOCOL_NAME = L"DarraRTPnet" (DarraRT_Pnet_Internal.h:62); Nic.c:636-644 注释: netcfg 按组件 ID 剥下划线生成 BindForm, NDIS Linkage 写在 Services\DarraRTPnet✅ 正确 (roundPNETCOMPAT2), 但文档未跟上 (§5)
HW ID / catdarrart_pnet (小写)INF :9/:23-26
Windows 服务DarraPnetServiceServiceInstaller.cs:55/61
原生 DLLdarra_pnet.dll (小写)CMake OUTPUT_NAME "darra_pnet" (Darra_Pnet_Core/CMakeLists.txt:72-73); PnetNative.cs:36 DllPath = "darra_pnet.dll" (2026-08-12 大小写修复, .197 大小写敏感卷); PnetRuntime.cs:1587 按 darra_pnet*.dll 探测✅ 一致 (文档/docs 用展示名 DarraPnet.dll 属别名)
设备对象\\.\DarraRT_Pnet / \Device\DarraRT_Pnet_GlobalIO§1

4. 0x/十进制口径轴

环节口径证据结论
GUI 输入归一纯数字按十六进制解读 (1 → 0x0001), 0x/0X 同义, 失焦归一 0x 小写前缀 + 大写 + 固定 4 位DeviceView.cs:350-384
模型ushort/uint 原生值GsdmlWriter.cs:163-169
GSDML 生成 (表 A)VendorID/DeviceID 0x%04X; ModuleIdentNumber/SubmoduleIdentNumber 0x%08XGsdmlWriter.cs:335-336/407/538/556/671-673
GSDML 生成 (表 B)SubslotNumber "0x8000"/"0x8001"; FixedInSubslots 0x{subslot:X}0x (注释: 本仓用户裁定统一 0x 输出); FixedInSlots "0" 十进制 (XSD 拒绝 0x)GsdmlWriter.cs:413-414/437-448/481-501/542✅ (与验证器一致, 但与规范文档冲突 → §5 P1-2)
GSDML 生成 (表 C)PhysicalSlots "0..N" 十进制; MinDeviceInterval/SendClock = ms×32 (31.25µs 时基, 下限 32); MaxInputLength/OutputLength 十进制GsdmlWriter.cs:406/452-453/493/679-683
验证器表 A 四标识号强制 0x; 表 B 槽号类双格式 (十进制或 0x, 值域 ≤65535) 均不判错; 表 C 十进制ValidationService.cs:748-820✅ 与生成器输出自洽
核心 GSDML 解析器只解析 4 标识号 (严格 0x)GSDML_十六进制属性规范.md §8 (pnet_gsdml.c)
核心测试期望 SubslotNumber="0x8000" / FixedInSubslots="0x1" / MinDeviceInterval="32" (V4 已修)test_pnet_gsdml.c:66/83-96✅ 与生成器一致
运行配置轨VendorID/DeviceID 0x%04X 元素; 标识号 0x%08X 属性; 长度/偏移/槽号十进制; 服务 ParseHex16/ParseHex32 解析; TEST_Config _三端闭环断言 0x 前缀ConfigWriter.cs:284-285/313-335; PnetConfigService.cs:566-582; _三端闭环.cs:287-297
端到端判定生成器 → 验证器 → 解析器 → 测试期望 无转换回退本节全表✅ PASS (仅规范文档口径滞后, §5)

5. 文档一致性轴

#级别文档过时/冲突点代码现状
D1P1docs/GSDML_十六进制属性规范.md§0/§3/§8 钉死"表 B (SubslotNumber/FixedInSubslots) 项目统一口径 = 十进制" (对齐西门子导出); §7 V1/V2 描述的也是"生成器输出十进制、校验器误判"旧状态代码 (GsdmlWriter.cs:444-449/540-542) 已按用户新裁定统一 0x 输出 ("本仓用户裁定统一 0x 输出, 保留现状"), 核心测试 test_pnet_gsdml.c 期望 0x。规范文档与新裁定相反 — 后续 agent 按文档改码会把 0x 回退成十进制
D2P1docs/docs/protocol/rt-class-1.mdL41-42 (0x0100=PPM/0x0200=CPM, 与驱动一致) vs L45 "PPM(Provider)发输入数据,CPM(Consumer)收输出数据" + L56-57 "PPM: 输入数据/CPM: 输出数据" (标准语义, 与驱动区名相反) — 同一文档两套方向口径并存驱动: CPM→"输入区", PPM→"输出区" (§2.1)。文档内部 L45/56-57 与 L73-77 亦自相矛盾
D3P1docs/PNET_ETH_共存契约.md① §2.1 K1c: Services\DarraRT_Pnet\Linkage "NDIS 绑定时自动派生" — roundPNETCOMPAT2 后 NDIS 按注册名写 Services\DarraRTPnet\Linkage (Internal.h:56-57); ② §2.3: DeviceView.cs:437Class\{4D36E972...}\Linkage\UpperBind 判绑定 — 该查询已按 2026-08-14 用户裁定移除 (DeviceView.cs:22-26 "选中即绑定, OS 绑定状态查询已移除"); ③ §4 token 表无 DarraRTPnet 分类文档需补 BindForm 键域 + 更新 §2.3
D4P2docs/docs/guide/quickstart.md:98示例路径 C:\Darra\Profinet\device.xml 与产品实际契约不符实际: GUI 建议名 pnet-<站点名>-config.xml, 部署契约 C:\DARRA\Profinet_Slave\config\runtime-config.xml
D5P2设计文档.md:9"版本号单源 version/ 目录"sync-versions.ps1 头注释: "单源 = CMakeLists.txt 的 project(DarraProfinet VERSION)" (version/*.txt 是被同步产物) — 两文档互斥
D6P3设计文档.md:230"NDIS 协议驱动 DarraRT_Pnet" 未区分组件名 vs BindForm 注册名 DarraRTPnet表述不精确, 易引导后续代码把注册名写回带下划线 (1168 根因复发)
D7P3docs/GSDML_TIA_导入合规报告.md §5R2 (writer 错误注释)/R3 (PNIO_Version V2.4)/R5 (站点名校验缺口)/R6 (缺 CertificationInfo) 已全部在代码中修复 (V2.32/ValidateAndNormalizeStationName/CertificationInfo 均现存在); R4 VendorID 0x0001 默认测试值仍属实报告为历史快照, 各 R 项状态需标注"已修"避免重复派修

6. 版本轴

证据结论
CMakeLists.txt (声明单源)project(DarraProfinet VERSION 1.0.0)根 CMakeLists.txt:3
version/core.txt / driver.txt / sdk.txt1.0.0 ×3version/ 目录✅ 与 CMake 同步
GUIVersionText = "v1.0.0" (MainForm.cs:76); Designer 默认 Caption "v1.0.0" (:584); csproj Version 1.0.0; 在线时显示服务 Version 补 v 前缀MainForm.cs:1018-1026
服务ProductVersion = "1.0.0" (PnetApiServer.cs:128), csproj Version 1.0.0
SDKCSharp csproj Version 1.0.0
INF DriverVer08/12/2026,1.0.0.3DarraRT_Pnet.inf:10⚠ P2: INF 走独立版本轨 (每次 sys 字节变升号, roundPNETCOMPAT2 升 1.0.0.3, 注释有完整理由), 但 version/driver.txt=1.0.0 不反映 INF 版本, sync-versions.ps1 自称"单源"却不覆盖 INF — 版本治理口径漂移, 建议在 sync-versions.ps1 或 INF 注释互指

7. 附: 其余跨层观察 (登记, 不构成断链)

  1. IOPS/IOCS 粒度 (P2): PnetProcessImage_inputSize/_outputSize (数据字节数) 分配 IOPS/IOCS 缓冲 (PnetProcessImage.cs:160-164), 运行时整区 GOOD/BAD 填充 (PnetRuntime.cs:225-228); 而 IoSnapshot 注释与 PROFINET 语义为"每子槽 1 字节"。当前子模块级状态被整区状态取代 — 服务无每子槽粒度 (上游 API 本身是每子槽 1 字节, pnet_wrapper.c:246-248)。多子槽工程时 IOPS 区长度 (数据长) ≠ 子槽数, 与标准口径错位。
  2. 报警严重度枚举 (P2): GUI 模型 PnetAlarmSeverity = Info/Warning/Critical (3 值, 2026-08-09 裁定严重度不再编辑, 保留兼容) vs 服务 PnetAlarmSeverity = Info/Warning/Error/Critical (4 值); PnetApiModels.cs:102 注释称 "PnetAlarmSeverity 口径" 跨层同名不同值。API 消费者 (GUI 报警展示) 遇 "Error" 需确认本地化覆盖。
  3. 自动选卡废止 (P3): PnetConfig.cs 注释"自动选卡已移除 (2026-08-14 用户裁定)", "自动"/AUTO/* 由 ValidateConfiguredNic 启动期报错 — 与 DeviceView"选中即绑定"一致; 需确认共存契约/设计文档无"自动选卡"残留承诺 (grep 见 PnetConfigService.cs:21-26, 文档未再提)。
  4. FrameId 硬编码: BuildIocrConfigs 固定 0x0100/0x0200, 注释如实标注"真实 AR 建立后控制器协商的 FrameId 可能不同" (PnetRuntime.cs:2077-2081) — 已诚实标注, 登记。

本报告由跨层契约交叉审计 agent 只读落档 (2026-08-14)。P0 §2.1 方向反转是全栈最优先修复项, 派修前须与 r2-input-consistency / q1-device-input-official-mask 等活跃 agent 做文件域隔离 (涉及 PnetRuntime.cs、驱动 Iocr/Frame/Shared、PnetApiModels.cs、DataTestView.cs、SDK DarraPnet.cs、rt-class-1.md、concepts.md)。