# OPC DA

> 经典 OPC Data Access 服务器的客户端，走 COM/DCOM，在 32 位辅助进程中运行，用项 ID 寻址，并能扫描一台计算机上的服务器。

**OPC DA** 驱动是经典 OPC Data Access 服务器（1.0、2.05a 和 3.0 版）的客户端。较老的 PLC 网关、SCADA 系统和模拟器至今仍通过这类 COM 服务器发布数据。服务器用它所在的计算机和它的 ProgID 来指定，例如 `Matrikon.OPC.Simulation.1`，每个点位则用服务器的项 ID 来指定。在 [Connector](connector) 页面上添加这个驱动和它的设备。

## 设备 {#device}

| 字段 | 含义 | 默认值 |
| --- | --- | --- |
| **主机** | OPC DA 服务器所在计算机的名称或地址。留空表示本机，大多数经典服务器都运行在本机上。 | 空：本机 |
| **服务器 / 键** | 服务器的 ProgID，按厂商在 Windows 中注册的写法填写，例如 `Matrikon.OPC.Simulation.1`。 | `OPC.Server.1` |
| **轮询间隔（ms）** | 工作站读取该设备点位的频率，点位自己规定了间隔时以点位为准。 | 1000 |

设备地址由这两项拼成，例如 `opc.da://localhost/Matrikon.OPC.Simulation.1`。没有端口：COM 通过 Windows 自身的注册信息找到服务器。

## 点位寻址 {#tag-addressing}

点位用它的**项 ID** 寻址，以自由文本输入，照写下的样子原样发给服务器，例如 `Random.Real8` 或 `Channel1.Device1.Tag1`。项 ID 属于服务器本身，可从服务器的文档或一次扫描中列出。点位第一次读取某个项时，工作站把它加入该设备的一个组，并从现场设备读取，而不是从服务器的缓存读取。

## 数据类型 {#data-types}

**数据类型**选择器提供 OPC DA 项所持有的类型：Boolean、SByte、Byte、Int16、UInt16、Int32、UInt32、Int64、UInt64、Float、Double、String 和 DateTime。每次读取都会转换成点位的类型，所以请选择服务器为该项声明的类型，也就是扫描所提出的类型：一个 64 位实数项按 Float 读取会损失精度，按 Double 读取则能保留。点位类型容纳不了的值，例如不是数字的文本或数组，会让点位没有值。OPC DA 的日期不带时区，工作站按 UTC 读写它。

服务器返回的每个值都带有它的质量。质量良好（Good）的值会送到点位。质量不确定（Uncertain）或不良（Bad）的值会让点位没有值，读取失败的那一行诊断日志会用 OPC DA 规范的说法写出这个质量，例如 `Bad: not connected (0x0008)` 或 `Uncertain: last usable value (0x0044)`。读取失败的项会让它的点位没有值，设备的其他点位照常读取。

## 设备发现 {#discovery}

**发现设备**会列出一台计算机上注册的 OPC DA 服务器：在扫描目标里输入那台计算机的名称或地址，若是本机则留空。每个服务器都作为一个设备提供出来，并遍历它的地址空间：它持有的每个项都作为只读点位提供出来，带着服务器为它声明的类型：64 位实数为 Double，16 位无符号整数为 UInt16，上面的每种类型都照此对应，货币值为 Double。没有声明类型的项作为能读取任何值的 String 提供；类型没有点位能读取的项（例如数组）不提供，扫描会把它算进略过的内容。候选如何挑选和添加，见[设备发现](connector-discovery)。

扫描通过本计算机上注册的 OPC DA 的 proxy 和 stub 库，向 OPC 服务器枚举服务（OpcEnum）询问服务器。其中任何一个缺失时，扫描不列出任何内容，而是说明缺少什么，步骤见[安装 OPC Core Components](#installing-the-opc-core-components)。

## 写入 {#writes}

**访问**为读写或只写的点位可以被写，写到读取所用的那同一个项上。值按服务器持有该项的类型发送（服务器没有说明时，按点位自身的类型），由点位的值直接转换，不经过文本，所以任何语言的工作站都发送同一个数字。超出该项类型范围的整数在发送任何内容之前就被拒绝，绝不会被截成该类型能容纳的最接近的值。服务器拒绝的写入会以拒绝返回：工作站能说明的原因（不接受写入的项、该项不接受的值、服务器不认识的项、访问被拒绝）会带上原因，其他情况则带上服务器的错误代码，例如 `OPC DA 0x80004005`；无论哪种情况，服务器的代码都会写进诊断日志。OPC DA 没有命令：这个驱动的设备不提供任何命令。

## 32 位辅助进程 {#the-32-bit-helper}

OPC DA 服务器要通过 32 位的 COM 客户端访问，而 64 位的工作站无法加载它。因此这个驱动运行在它专用的辅助进程 `Lab.Desktop.DriverBridge.exe` 中：OPC DA 设备或扫描第一次需要它时，或工作站检查 OPC Core Components 时，由工作站启动，Connector 停止时关闭。驱动的用法没有任何变化：它的设备和点位像其他驱动一样被读取、写入、扫描并记入诊断日志。

辅助进程一旦停止，它的设备会显示错误“OPC DA 驱动的 32 位辅助进程已停止。工作站会重新启动它，设备会经由它重新连接。”（退出代码见事件页面），点位则失去值。工作站会重新启动辅助进程（它持续停止期间，间隔会逐渐变长），设备会经由它自动重新连接。辅助进程停止时正在途中的写入会以失败返回，并说明无法确定该值是否到达了现场设备。任何其他驱动和工作站的任何其他部分都不会随之停止。

## 开始之前 {#before-you-start}

- 工作站不安装任何 OPC 组件。OPC 服务器枚举服务（OpcEnum）以及 OPC DA 的 proxy 和 stub 库，随 OPC DA 服务器提供，或包含在 OPC Core Components 中。工作站会自行检查它们是否已注册，缺少其中任何一个时会说明如何安装：见[安装 OPC Core Components](#installing-the-opc-core-components)。
- 另一台计算机上的服务器经由 DCOM 访问，两台计算机都必须为工作站运行所用的 Windows 账户放行：DCOM 权限、防火墙规则，以及相同的账户或受信任的域。这项设置在 Windows 中完成，从不在工作站中完成：见[准备远程服务器](#prepare-a-remote-server)。
- 这个驱动只在 Windows 上运行。

## 安装 OPC Core Components {#installing-the-opc-core-components}

工作站会在 32 位辅助进程中自行检查本计算机是否为 32 位程序注册了 OPC 服务器枚举服务（OpcEnum）以及 OPC DA 的 proxy 和 stub 库：驱动页面、其某个设备的页面或代理第一次询问时检查，缺少其中任何一个时每 30 秒再检查一次。Connector 启动之前无法知道它们是否存在，因此不作任何提示。缺少其中任何一个时：

| 位置 | 显示内容 |
| --- | --- |
| 驱动页面 | 一条注意提示“本计算机缺少 OPC Core Components”，以及下面的步骤。其中的链接会在计算机的浏览器中打开 OPC Foundation 的页面。 |
| 每个设备的页面 | 同样的提示，在线的设备除外。 |
| 扫描 | 不列出任何内容并说明缺少什么：扫描结束时的那一行指向该提示，代理的 `device_discover` 用英文给出步骤。 |
| 连接失败的设备的最后一条错误 | 缺少什么以及同样的步骤，与驱动自身的原因一样用英文写出。 |
| 代理 | `driver_capabilities` 在 `prerequisite` 下给出这些步骤，`installed` 为 false。 |

安装步骤：

1. 重新运行 OPC DA 服务器的安装程序：它通常会一并安装这些组件。
2. 否则，打开 OPC Foundation 的页面 [Core Components](https://opcfoundation.org/developer-tools/samples-and-tools-classic/core-components/)，下载 OPC Core Components Redistributables。只有注册用户才能下载：如果页面提示您没有下载该文件的权限，请在同一页面用“Login”登录，或用“Create Account”创建账户。
3. 64 位 Windows 请选择 `opc-core-components-redistributable-<version>-x86-x64.msi`（其中也包含 32 位组件），以 `-x86.msi` 结尾的文件仅用于 32 位 Windows。
4. 以管理员身份运行，安装程序要求时重启计算机。

安装后 30 秒内，提示会消失，扫描会列出 OPC DA 服务器，这个驱动的设备按现有配置连接，无需重启 Ganter Lab。

## 准备远程服务器 {#prepare-a-remote-server}

本计算机上的服务器不需要再做什么。另一台计算机上的服务器要通过 DCOM 访问，而在两台计算机都配置好之前，DCOM 不允许来自另一台计算机的任何访问。配置在两台计算机的 Windows 中完成，由各自的管理员操作，从不在工作站中完成：

1. 在两台计算机上使用相同的 Windows 账户和相同的密码（即工作站运行所用的账户），或者使用两台计算机都认识的域账户。
2. 在服务器的计算机上运行 `dcomcnfg`，打开 **Component Services > Computers > My Computer > Properties > COM Security**。在 **Access Permissions** 和 **Launch and Activation Permissions** 下，在 **Edit Limits** 和 **Edit Default** 中都允许该账户的全部远程权限。在 **Access Permissions** 的 **Edit Limits** 中，还要允许 ANONYMOUS LOGON 的 **Remote Access**，OPC 服务器枚举器（OpcEnum）需要它。
3. 仍在那里，在 **My Computer > DCOM Config** 下打开 OPC 服务器和 OpcEnum 的 Properties，在它们的 Security 选项卡中用同一账户自定义三项权限。
4. 在工作站的计算机上也运行 `dcomcnfg`，在 **Access Permissions** 的 **Edit Limits** 中，允许 OPC 服务器运行所用账户的 **Remote Access**：服务器会回调工作站。
5. 在服务器的计算机上，在 Windows Defender 防火墙中允许入站 TCP 端口 135，以及 OPC 服务器和 OpcEnum（`OpcEnum.exe`）的程序，并在**服务**中确认 OpcEnum 正在运行并且自动启动。

只要 **Edit Limits** 拒绝该权限，修改 **Edit Default** 就不起作用：两者都要设置。DCOM 先在端口 135 上应答，然后通过 Windows 选择的端口传送调用，因此两台计算机之间的防火墙只开放 135 时，服务器仍然被阻止。

| Windows 的应答 | 设备页面显示的内容 |
| --- | --- |
| 拒绝访问（0x80070005） | “*主机* 通过 DCOM 拒绝了本工作站”，附上工作站运行所用的账户和第 1 到第 4 步 |
| RPC 服务器不可用（0x800706BA） | “*主机* 没有应答 DCOM”：计算机已关机或无法访问，它的防火墙阻止了 DCOM，或者 OpcEnum 没有在那里运行，附上第 5 步 |

每条提示都显示在设备错误的位置上，服务器连接后会自行消失。诊断日志和代理读到的是同样的英文步骤。本计算机上的服务器从不以这种方式显示。

如果厂区不允许使用 DCOM，可以在服务器的计算机上用一个以 OPC UA 提供该 OPC DA 服务器的包装器或隧道来完全避开 DCOM：工作站随后用 [OPC UA](driver-opc-ua) 驱动读取该服务器。
