作为初识 EPICS 和硬件控制的新手,每天都要面对许多从未见过的挑战,也会解决很多挑战。这是我对个人经验的记录,为将来在遇到同样的问题时提供参考。
系统架构
此处不介绍架构的详细信息。粗略来说,中间的 Proxy 将 EPICS 协议和 GraphQL 协议互相转化。详情参见<a href={'./an-epics-proxy'}>此处。
挑战
本节记录我遇到的所有挑战,有些很简单但却卡了我一段时间。
基础镜像
最优的容器基础镜像是 Alpine。但是将 Alpine 和 EPICS 整合起来会导致一些问题。
最先出现的问题是 libc。Alpine 自带的 musl-libc 和 EPICS 基于的 glibc 不一样。虽然有个为 Alpine 编译的 glibc,下一个问题还是无解。
EPICS 使用 libstdc++,Alpine 上的 libstdc++基于 musl-libc。EPICS 还使用 Alpine 上的 glibc。最终 libstdc++会错误地认为它处于 glibc 环境中。因此从 EPICS 到 libstdc++到 glibc 的 link 或 call 会失败。唯一的解决方法是使用基于 glibc 的 libstdc++。但还没人做过这个工作。如果让我去解决这个问题,我倾向与用 musl-libc 重写 EPICS,因为这样更轻量化且与 Alpine 的理念更吻合。
综上所述,现阶段最优的基础镜像是 CentOS 7/8。
不同宿主间的通信
在 CA 客户端和 IOC 服务器间的通信对我来说是最反直觉的部分。EPICS 采用"UDP broadcasting"技术可以在事先不知道对方 IP 的情况下建立通信。
但是这个方法仅限于双方都在同一个唯一的子网。例如当 CA 客户端在 2 个子网分别有不同的 IP 地址,如 10.0.0.1 和 192.168.1.1 时,就不能保证一定能找到 IP 为 192.168.1.100 的 IOC。
当架构无法优化时,就必须向 CA 客户端提供 IOC 的地址,以便让客户端知道在哪里寻找 IOC。这时候需要在 CA 客户端启动时设置EPICS_CA_ADDR_LIST
变量,例如:
export EPICS_CA_ADDR_LIST=192.168.1.100
# CA connect here
但是,更好的方案通常会缩减必要的配置。在此处,更好的方案时让 CA 客户端和 IOC 服务器在唯一子网中。在我的架构中,这意味着所有 web 服务、IOC 和 Proxy 都必须在同一内网。这在 IOC 的数量较小时可行,但在其数量较大时,就必须划分不同的子网方便管理。因此,就需要引入另一个中间层沟通 Proxy 和 web 服务。此时 Proxy 可以仅拥有一个 IP。