12. Integrating EPICS in GDA¶
Integration of EPICS within GDA covers:
configuration of Java Channel Access (JCA);
the creation of Scannables and Detectors that talk to EPICS as a Channel Access client allowing devices to be incorporated into a full Data Acquisition system;
12.1. Configure JCA¶
GDA uses Channel Access for Java (CAJ) - 100% pure Java implementation of the EPICS Channel Access JCA library - to communicate with EPICS IOCs.
To enable GDA access to EPICS Processing Variables (PVs), GDA servers (or clients, if clients need to talk to PVs directly) must be started with a property gov.aps.jca.JCALibrary.properties setting, for example:
-Dgov.aps.jca.JCALibrary.properties=${gda.config}/properties/<mode>/JCALibrary.properties
The property file JCALibrary.properties
should contain the following properties (corresponding to EPICS Channel Access environment 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
Among these, the properties that are most often changed are:
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
for communicating with EPICS IOC running on your localhost and using CA server port of 6064.
GDA will also set com.cosylab.epics.caj.CAJContext.event_dispatcher to gov.aps.jca.event.SplitQueuedEventDispatcher
The last two properties are CAJ specific. In most cases, you do not need to set them as the defaults are sufficient. However, if required, you can use these properties to customise CAJ’s internal byte buffer size and thread pool size.
At Diamond, we run an EPICS simulation server on dasc-epics.diamond.ac.uk
for off beamline development of GDA software. Its IP address is 172.23.7.113, server port is 6064, repeater port is 6065.
12.2. Fastest method to get/put in a script¶
To get the value of pv test:sensor1:
from gda.epics import CAClient ca = CAClient() val = ca.caget("test:sensor1")
returns String values,
To put to pv test:sensor1 a value of 1:
from gda.epics import CAClient ca = CAClient() ca.caput("test:sensor", 1.0) ca.caput("test:sensor", "1.0")
accepts native types and String
12.3. More performant method to get/put in a script¶
Create an object once and reuse:
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()
variations of caget/caput exist for different types
caput can accept a listener or timeout
12.4. Using CAClient to make a Scannable¶
Defined class in 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 getPosition(self): return self.ca.caget() def asynchronousMoveTo(self,position): pass def isBusy(self): return False
Import the class definition and create the scannable:
import epics_scannables sensor1 = epics_scannables.SimpleEPICSMonitor('sensor1', 'test:sensor1', 'mm', '%.4f') .... pos sensor1 scan motor1 1. 10. 1. sensor1
12.5. Access EPICS in Java¶
A cut down Java Scannable class to get/put a double field:
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 getPosition(){ return controller.cagetDouble(channel); ... }
12.6. A General Purpose Class EpicsScannable¶
Use in script to get/set test: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"
Add to system using 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>
12.7. Particular device classes in GDA¶
Add to system using Spring:
<bean id="m1_motor" class="gda.device.motor.EpicsMotor"> <property name="pvName" value="test:m1"/> </bean> ... <bean id="m1" class="gda.device.scannable.ScannableMotor"> <property name="motor" ref="m1_motor" /> </bean>