EPICS asyn库
EPICS ASYN是一种设备支持库,属于EPICS(实验物理和工业控制系统)框架的模块之一。EPICS是一个用于控制和监控实验设备的分布式软件平台,广泛应用于加速器,实验物理设备等领域。ASYN模块的全称是异驱动支持(Asynchronous Driver Support),主要用于处理异步设备通信。
ASYN模拟的主要功能:
1、异步通信:它提供了支持异步和同步设备通信的接口。异步设备通信是串行通信,网络通信等类型的设备,它们的响应时间较慢或不能立即提供数据。
2、驱动层支持:ASYN提供一个统一的驱动框架,开发者可以基于这个框架开发设备的通信驱动,无论设备是通过串口,TCP/IP,GPIB,MODBUS等方式通信。
3、灵活的接口:ASYN支持多种协议和接口(如串口,GPIB,Ethernet等),并提供了读写数据,设备控制等操作的API。
4、支持设备参数管理:它为设备的参数(如波特率,数据格式等)提供了配置和管理的机制,便于设备驱动的开发和调试。
5、可扩展性:通过ASYN框架,开发者可以将不同类型的设备轻松集成到EPICS系统中,无需重复开发底层通信逻辑。
总结来说,EPICS ASYN是要给用于异步设备通信的驱动支持模块,极大地简化了设备和控制系统之间地集成工作,尤其是在需要处理不同通信协议和接口地场景下。
使用EPICS ASYN编写程序,主要用于控制异步设备或通信接口地设备。下面以一个基于EPICS ASYN的程序。
1、系统环境准备
确定操作系统上已经安装了EPICS base和ASYN模块。如果没有安装从EPICS官方网站下载并安装。
2、创建一个新的IOC应用程序
在编写ASYN驱动程序之前,首先创建一个新的IOC(输入/输出控制器)应用程序。
打开一个bash shell,进入你放置EPICS IOC应用程序的路劲并且为这个IOC创建一个文件夹:
root@orangepi5plus:/usr/local/EPICS/program# pwd
/usr/local/EPICS/program
root@orangepi5plus:/usr/local/EPICS/program# mkdir asyn-example
root@orangepi5plus:/usr/local/EPICS/program# cd asyn-example/
root@orangepi5plus:/usr/local/EPICS/program/asyn-example#
3、使用EPICS的makeBaseApp.pl工具创建新的IOC应用程序的基础框架:
root@orangepi5plus:/usr/local/EPICS/program/asyn-example# makeBaseApp.pl -t ioc asynExample1
root@orangepi5plus:/usr/local/EPICS/program/asyn-example# makeBaseApp.pl -i -t ioc asynExample1
Using target architecture linux-aarch64 (only one available)
The following applications are available:
asynExample1
What application should the IOC(s) boot?
The default uses the IOC's name, even if not listed above.
Application name?
root@orangepi5plus:/usr/local/EPICS/program/asyn-example# ls
asynExample1App configure iocBoot Makefile
3、配置Makefile和configure/RELEASE
确保ASYN模块能够正确编译和链接到你的应用程序中,你需要编辑asyn-example/configure/RELEASE文件,添加ASYN模块的路径:
...
SUPPORT=/usr/local/EPICS/synApps/support # 添加此行
ASYN=$(SUPPORT)/asyn # 添加此行
...
EPICS_BASE = /usr/local/EPICS/base
...
-include $(TOP)/../RELEASE.local
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
-include $(TOP)/configure/RELEASE.local
4、编写asyn驱动代码,在asyn-example/asynExample1App目录中找到src目录,并在其中床新的驱动文件,例如:TestAsynDriver.cpp:
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <cantProceed.h>
#include <epicsStdio.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <iocsh.h>
#include <asynPortDriver.h>
#include <epicsExport.h>
class TestAsynDriver:public asynPortDriver{
public:
TestAsynDriver(const char * portName);
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
private:
int counter_;
};
TestAsynDriver::TestAsynDriver(const char * portName)
:asynPortDriver(portName, 1,
asynInt32Mask | asynDrvUserMask,
asynInt32Mask,
0,1,0,0)
{
createParam("COUNTER", asynParamInt32, &counter_);
setIntegerParam(counter_, 0);
}
asynStatus TestAsynDriver::writeInt32(asynUser *pasynUser, epicsInt32 value)
{
int function = pasynUser->reason;
if (function == counter_){
printf("write %d \n", value);
setIntegerParam(counter_, value);
callParamCallbacks();
return asynSuccess;
}
return asynPortDriver::writeInt32(pasynUser, value);
}
asynStatus TestAsynDriver::readInt32(asynUser *pasynUser, epicsInt32 *value)
{
int function = pasynUser->reason;
if (function == counter_)
{
getIntegerParam(counter_, value);
printf("read %d\n", value);
return asynSuccess;
}
return asynPortDriver::readInt32(pasynUser, value);
}
extern "C" {
int TestAsynDriverConfigure(const char *portName)
{
new TestAsynDriver(portName);
return(asynSuccess);
}
/* EPICS iocsh shell commands */
static const iocshArg initArg0 = { "portName",iocshArgString};
static const iocshArg * const initArgs[] = {&initArg0};
static const iocshFuncDef initFuncDef = {"TestAsynDriverConfigure",1,initArgs};
static void initCallFunc(const iocshArgBuf *args)
{
TestAsynDriverConfigure(args[0].sval);
}
void TestAsynDriverRegister(void)
{
iocshRegister(&initFuncDef,initCallFunc);
}
epicsExportRegistrar(TestAsynDriverRegister);
}
在此目录下添加一个数据库定义文件TestAsynDriverSupport.dbd:
registrar("TestAsynDriverRegister")
在此目录下Makefile文件中,添加以下内容:
asynExample1_DBD += TestAsynDriverSupport.dbd
asynExample1_DBD += asyn.dbd
asynExample1_LIBS += asyn
asynExample1_SRCS += TestAsynDriver.cpp
5、添加记录类型支持,在在asyn-example/asynExample1App目录中找到Db目录,添加一个数据库实例文件counter.db:
record(longin, "$(P)$(R)COUNTER_RBV") {
field(DTYP, "asynInt32")
field(INP, "@asyn($(PORT),0,1)COUNTER")
field(SCAN, "I/O Intr")
}
record(longout, "$(P)$(R)COUNTER") {
field(DTYP, "asynInt32")
field(OUT, "@asyn($(PORT),0,1)COUNTER")
}
将这个文件名,添加到相同目录中Makefile文件中:
DB += counter.db
6、切换到这个IOC的顶层目录asyn-example中,执行make,进行编译。
7、进入启动目录asyn-example/iocBoot/iocasynExample1中,编辑启动脚本st.cmd:
#!../../bin/linux-aarch64/asynExample1
#- You may have to change asynExample1 to something else
#- everywhere it appears in this file
< envPaths
cd "${TOP}"
## Register all support components
dbLoadDatabase "dbd/asynExample1.dbd"
asynExample1_registerRecordDeviceDriver pdbbase
TestAsynDriverConfigure("TEST") # 添加此行
## Load record instances
dbLoadRecords("db/counter.db","P=TEST:,R=CH1:,PORT=TEST") # 添加此行
cd "${TOP}/iocBoot/${IOC}"
iocInit
8、启动这个IOC应用程序:
root@orangepi5plus:/usr/local/EPICS/program/asyn-example/iocBoot/iocasynExample1# ../../bin/linux-aarch64/asynExample1 st.cmd
9、用通道访问进行测试测试:
(base) [blctrl@localhost db]$ caput TEST:CH1:COUNTER 5
Old : TEST:CH1:COUNTER 0
New : TEST:CH1:COUNTER 5
(base) [blctrl@localhost db]$ caget TEST:CH1:COUNTER_RBV
TEST:CH1:COUNTER_RBV 5
(base) [blctrl@localhost db]$ caput TEST:CH1:COUNTER 100
Old : TEST:CH1:COUNTER 5
New : TEST:CH1:COUNTER 100
(base) [blctrl@localhost db]$ caget TEST:CH1:COUNTER_RBV
TEST:CH1:COUNTER_RBV 100