9. 将EPICS集成到GDA中¶

在GDA中整合EPICS的内容包括:
Java Channel Access(JCA)的配置;
钻石GDA.EPICS接口规范.模式和XML文件
创建可与EPICS对话的扫描仪和探测器,作为通道接入客户端,允许将设备合并到完整的数据采集系统中;
9.1. 配置JCA¶
GDA使用Java的通道访问 (CAJ )-EPICS Channel Access JCA库的100%纯Java实现-与EPICS IOC通信。
要启用对EPICS处理变量(PV)的GDA访问,必须使用属性启动GDA服务器(如果客户端需要直接与PV对话,则为客户端 gov.aps.jca.JCALibrary.properties 设置,例如:
-Dgov.aps.jca.JCALibrary.properties=${gda.config}/jca/live/JCALibrary.properties
属性文件 JCALibrary.properties
应包含以下属性(对应于 EPICS Channel Access enviroment variables ):
com.cosylab.epics.caj.CAJContext.addr_list = 172.23.111.255
com.cosylab.epics.caj.CAJContext.auto_addr_list = true
com.cosylab.epics.caj.CAJContext.connection_timeout = 30.0
com.cosylab.epics.caj.CAJContext.beacon_period = 15.0
com.cosylab.epics.caj.CAJContext.repeater_port = 5065
com.cosylab.epics.caj.CAJContext.server_port = 5064
com.cosylab.epics.caj.CAJContext.max_array_bytes = 4000000
#com.cosylab.epics.caj.CAJContext.event_dispatcher= gov.aps.jca.event.QueuedEventDispatcher
#com.cosylab.epics.caj.CAJContext.event_dispatcher= gov.aps.jca.event.LatestMonitorOnlyQueuedEventDispatcher
com.cosylab.epics.caj.CAJContext.event_dispatcher= gov.aps.jca.event.SplitQueuedEventDispatcher
com.cosylab.epics.caj.CAJContext.logger = com.cosylab.epics.caj.CAJContext
com.cosylab.epics.caj.impl.CachedByteBufferAllocator.buffer_size=32000
com.cosylab.epics.caj.impl.reactor.lf.LeaderFollowersThreadPool.thread_pool_size = 5
其中,最常更改的属性包括:
com.cosylab.epics.caj.CAJContext.addr_list = 172.0.0.1
com.cosylab.epics.caj.CAJContext.auto_addr_list = false
com.cosylab.epics.caj.CAJContext.repeater_port = 6065
com.cosylab.epics.caj.CAJContext.server_port = 6064
用于与本地主机上运行的EPICS IOC通信,并使用CA服务器端口6064。
GDA还将设置 com.cosylab.epics.caj.CAJContext.event_dispatcher 到 gov.aps.jca.event.SplitQueuedEventDispatcher
后两个属性是特定于CAJ的。在大多数情况下,您不需要设置它们,因为默认值就足够了。但是,如果需要,您可以使用这些属性来自定义CAJ的内部字节缓冲区大小和线程池大小。
在戴蒙德,我们在一台EPICS模拟服务器上运行 dasc-epics.diamond.ac.uk
用于GDA软件的离线开发。其IP地址为172.23.7.113,服务器端口为6064,中继端口为6065。
9.2. GDA-EPICS接口¶
虽然有可能 caget
发件人和 caput
对于GDA内的PV,就像在钻石控制台上一样,为EPICS控制系统与钻石数据采集系统的集成开发了GDA-EPICS接口规范。此规范在XML中描述 Schema
,它目前定义了此接口中可用的60多种类型的设备。对此接口使用架构定义的好处是:
它确保了GDA和EPICS之间接口的稳定性和兼容性,因为EPICS构建系统为接口生成的XML文件对于此模式始终有效,从而确保EPICS IOC服务的PV始终符合GDA的期望;
它提供了简单性和设备安全性,使我们能够仅暴露实验控制和数据采集过程所需的每个设备的PV子集;
它是直观和透明的,通过将PV集分组为逻辑单元作为设备,可以使用Java-XML数据绑定提供的特定于域的语言(例如MotorType)轻松访问这些设备;
允许以后根据开发需要添加新设备类型是可扩展的。
Java-XML数据绑定是使用 CASTOR source code generator 。目前,这是一个手动过程,只有在更新架构时才需要。要建立一个新的 epics-xxx.jar
,您需要在上面运行Ant Build build.xml 在里面 uk.ac.gda.epics/epics.jar.generator/Epics_Interface (Phase II)/
。请记住在中更改版本号 build.xml 根据顶部的说明,所以不要覆盖现有的EPICS JAR文件,以允许回滚的可能性。在新的 epics-xxx.jar
生成后,必须将其添加到EPICS插件的类路径中才能生效。
您可以查看支持的设备类型列表 here
9.3. 访问中的PV字符串 BLxxI-gda-interface.xml
文件¶
接口XML文件中定义的设备的PV名称可以通过上面生成的epics-xxx.jar中的接口类型类进行访问。例如,在EPICS访问类中 ADBaseImpl.java
,您可以通过先检索接口类型配置,然后检索 Temperature
元素为::
ADBaseType config = Configurator.getConfiguration(getDeviceName(), ADBaseType.class);
String pvString = config.getTemperature().getPv()
您可能已经注意到,我们在这里遵循了命名模式: <ADBase>
中的元素 BLxxI-gda-interface.xml
可以使用 ADBaseType
在epics-xxx.jar中,它用于 ADBaseImpl
班级。它们都共享相同的基本名称 ADBase
。这样,我们就可以很容易地从XML接口文件中找到要在Java类中使用的接口类型。
9.4. 获取/放入脚本的最快方法¶
要获取PV测试值:Sensor1::
from gda.epics import CAClient ca = CAClient() val = ca.caget("test:sensor1")
返回字符串值,
要进行PV测试:Sensor1的值为1::
from gda.epics import CAClient ca = CAClient() ca.caput("test:sensor", 1.0) ca.caput("test:sensor", "1.0")
接受本机类型和字符串
9.5. 获取/放入脚本的更具表现力的方法¶
只需创建一次对象即可重复使用:
from gda.epics import CAClient ca = CAClient("test:sensor1") val = ca.caget() ... some time later ca.caput(1.0) ... when done close the channel ca.clearup()
Caget/Caput因类型不同而不同
Caput可以接受监听程序或超时
9.6. 使用CAClient使可扫描¶
epics_scannables.py::中定义的类
from gda.device.scannable import ScannableMotionBase from gda.epics import CAClient class SimpleEPICSMonitor(ScannableMotionBase): def __init__(self, name, pvstring, unitstring, formatstring): self.setName(name); self.setInputNames([]) self.setExtraNames([name]) self.Units=[unitstring] self.setOutputFormat([formatstring]) self.ca=CAClient(pvstring) self.ca.configure() def rawGetPosition(self): return self.ca.caget() def rawAsynchronousMoveTo(self,position): pass def rawIsBusy(self): return False
导入类定义并创建可扫描的::
import epics_scannables sensor1 = epics_scannables.SimpleEPICSMonitor('sensor1', 'test:sensor1', 'mm', '%.4f') .... pos sensor1 scan motor1 1. 10. 1. sensor1
9.7. 用Java访问EPICS¶
用于获取/放置双精度字段的精简Java Scanable类::
public class SimpleDoubleScannable extends ScannableBase{ ... configure(){ controller = EpicsController.getInstance(); channel = controller.createChannel(pvName); ... asynchronousMoveTo(Object value){ busy = true; controller.caput(getChannel(), (Double) value, putListener); ... (In putListener putCompleted method set busy to false) ... boolean isBusy(){ return busy ... Object rawGetPosition(){ return controller.cagetDouble(channel); ... }
9.8. 一个可扫描的通用类EpicsScan¶
在脚本中使用以获取/设置测试:Sensor2::
from gda.device.scannable import EpicsScannable sensor2=EpicsScannable() sensor2.setName("sensor2") sensor2.setPvName("test:sensor2") sensor2.setUseNameAsInputName(True) sensor2.setUserUnits("mm") sensor2.configure() ... pos sensor2 pos sensor2 "1.2 mm" pos sensor2 "1.2 m"
使用Spring添加到系统::
<bean id="sensor3" class="gda.device.scannable.EpicsScannable"> <property name="PvName" value="test:sensor3"/> <property name="useNameAsInputName" value="true"/> <property name="userUnits" value="mm"/> </bean>
9.9. GDA中的特定设备类¶
使用Spring添加到系统::
<bean id="m1_motor" class="gda.device.motor.EpicsMotor"> <property name="pvName" value="test:m1"/> <property name="local" value="true"/> </bean> ... <bean id="m1" class="gda.device.scannable.ScannableMotor"> <property name="motor" ref="m1_motor" /> </bean>