9. 将EPICS集成到GDA中

../_images/epics_logo.png

EPICS

在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_dispatchergov.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>