This driver derives from asynPortDriver. By its essence, the parameter value access is delegated to the Python module, provided by user.
IOC shell command to configure a python port:
/* * portName: The name of the asyn port driver to be created. * moduleName: The python module to import. * numParams: The number of parameters in this driver. */ asynPythonDriverConfigure(const char *portName, const char *pythonModule, int numParams)
Note
The last argument numParams can be omitted for asyn 4.32+.
PythonDriver
is a base class that implements the connection between EPICS database and asynPortDriver parameter table. There are two steps for the derived class to define this connection.
Suppose we have an EPICS template file test.template,:
record(ai, "RAND") { field (DTYP, "asynFloat64") field (INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))RAND") field (PREC, "4") field (SCAN, "I/O Intr") info (pyname, "rand") }
The key is the info (pyname, "rand") field, that defines the variable name which we will refer to in our Python class.
In the Python module test.py, class TestPythonDriver
,
import time import random import threading from PythonDriver import PythonDriver class TestPythonDriver(PythonDriver): __db__ = "test.template" def __init__(self): self.tid = threading.Thread(target=self.simTask) self.tid.start() def simTask(self): while True: self.rand = random.random() self.update() time.sleep(1) # create an instance driver = TestPythonDriver()
The __db__ class attribute links Python class to EPICS database. The base class in turn creates class attributes for each records having info (pyname, "") specified. In this example, rand will be accessible just like a normal numeric value. Call base class method update
to update the value.
In the startup script,
## add python module paths epicsEnvSet PYTHONPATH,${TOP}/python:${ASYNPYTHON}/python ... asynPythonDriverConfigure("PY2", "test", 1) ## Load record instances dbLoadRecords("${TOP}/db/test.template", "PORT=PY2,ADDR=0,TIMEOUT=1")
The driver from testAsynPortDriver has been ported. The original EPICS database is copied, with addition of info(pyname,"") fields. Only that the C++ file testAsynPortDriver.cpp has been written in Python scope.py.
cd iocs make cd scopeIOC/iocBoot/iocscope ./start_epics
Launch MEDM:
medm -x -macro P=MTEST:,R=SCOPE: testAsynPortDriver.adl
- For input records, ai, longin, stringin, the SCAN field can only be I/O Intr. That means these records have to be updated by the driver and then call
self.update
. - The first call of asynPythonDriverConfigure creates the main Python interpreter, and subsequent calls create Python sub-interpreters, in order to isolate the modules. And watch out the bug and caveats about sub-interpreter.