提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
根据大佬的教程自己进行了操作,本文对大佬的教程中涉及到的一些代码内容进行了补充说明
参考教程:EPICS简单实例1 – 向IOCSH注册自己的函数
一、创建一个IOC
创建一个IOC程序,将其命名为exer1(建立exer1文件夹,并在该目录下执行makeBaseApp.pl -t 操作)
具体的IOC的创建过程可以参考教程:【EPICS学习记录】根据官方教程创建一个IOC应用
创建完成后文件夹内容显示如下:
yifeng@yifeng:~$ cd EPICS/practice/exer1/
yifeng@yifeng:~/EPICS/practice/exer1$ ls -R
.:
configure exer1App iocBoot Makefile
./configure:
CONFIG CONFIG_SITE Makefile RELEASE RULES RULES_DIRS RULES.ioc RULES_TOP
./exer1App:
Db Makefile src
./exer1App/Db:
Makefile
./exer1App/src:
exer1Add.c exer1Add.dbd exer1Hello.c exer1Hello.dbd exer1Main.cpp Makefile
./iocBoot:
iocexer1 Makefile
./iocBoot/iocexer1:
Makefile st.cmd
二、创建函数文件
cd进入exer1App/src目录下,使用touch命令创建如下四个文件:
yifeng@yifeng:~/EPICS/practice/exer1/exer1App/src$ touch exer1Hello.c exer1Hello.dbd exer1Add.c exer1Add.dbd
yifeng@yifeng:~/EPICS/practice/exer1/exer1App/src$ ls
exer1Add.c exer1Add.dbd exer1Hello.c exer1Hello.dbd exer1Main.cpp Makefile
分别对四个文件的内容进行编辑:
- exer1Hello.c:
/* 展示如何向iocsh注册一条新命令的示例 */
# include <stdio.h>
# include <epicsExport.h>
# include <iocsh.h>
/* iocsh将能够直接调用这条命令。*/
void hello(const char * name)
{
if (name)
{
printf("Hello %s, from my fisrt exer1\n", name);
}
else{
printf("Hello from my exer1\n");
}
}
/* iocsh所需的信息 */
/*
定义这个参数的名称以及类型
*/
static const iocshArg helloArg0 = {"name", iocshArgString};
/* 定义参数数组,数组元素为iocshArg结构体的指针 */
static const iocshArg * helloArgs[] = {&helloArg0};
/* 这个函数的名称,这个函数需要的参数数目,以及其参数数组 */
static const iocshFuncDef helloFuncDef = {"hello", 1, helloArgs};
/* 由iocsh调用的包装器,选择hello需要的参数类型 */
static void helloCallFunc(const iocshArgBuf * args)
{
hello(args[0].sval);
}
/* 在启动时运行,注册程序 */
static void helloRegister(void)
{
//注册时,传给iocshRegister一个函数定义结构体iocshFuncDef的地址
//以及一个调用包装器
iocshRegister(&helloFuncDef, helloCallFunc);
}
/* 导出注册程序 */
epicsExportRegistrar(helloRegister);
- exer1Hello.dbd:
registrar(helloRegister)
- exer1Add.c:
# include <stdio.h>
# include <epicsExport.h>
# include <iocsh.h>
void add(int a, int b, const char * name, double time)
{
printf("a:%d\n",a);
printf("b:%d\n",b);
printf("%d + %d = %d\n", a, b , a+b);
if (name)
{
printf("Hello %s, from my fisrt exer1Add\n", name);
}
else{
printf("Hello from my exer1Add\n");
}
printf("time: %3.2f\n", time);
}
static const iocshArg addArg0 = {"a", iocshArgInt};
static const iocshArg addArg1 = {"b", iocshArgInt};
static const iocshArg addArg2 = {"name", iocshArgString};
static const iocshArg addArg3 = {"time", iocshArgDouble};
static const iocshArg * addArgs[] = {&addArg0, &addArg1,&addArg2,&addArg3};
static const iocshFuncDef addFuncDef = {"add", 4, addArgs};
static void addCallFunc(const iocshArgBuf * args)
{
add(args[0].ival, args[1].ival,args[2].sval,args[3].dval);
}
static void addRegister(void)
{
iocshRegister(&addFuncDef, addCallFunc);
}
epicsExportRegistrar(addRegister);
- exer1Add.dbd:
registrar(addRegister)
关于注册函数的说明:
- IOC shell
IOC Shell是EPICS中的一个交互式命令行工具,用于控制和调试IOC。它提供了一些内置的命令来操作设备和记录,例如查看和修改记录的值、启动和停止设备等。除了内置的命令,用户还可以通过使用iocshRegister()函数注册自定义的命令函数,以扩展IOC Shell的功能。
- iocshRegister()函数
iocshRegister()函数是用于注册IOC(Input/Output Controller)命令解释器(IOC Shell)命令的函数。它的作用是将自定义的命令函数与IOC Shell关联起来,使得在IOC Shell中可以使用这些自定义命令。
iocshRegister()函数通常在IOC中的驱动程序文件中使用,通过在IOC初始化函数中调用该函数将自定义的命令函数注册到IOC Shell中。具体的用法是将命令函数的地址和命令名称作为参数传递给iocshRegister()函数,例如:
static const iocshArg myCmdArg0 = { "arg0", iocshArgInt };
static const iocshArg myCmdArg1 = { "arg1", iocshArgString };
static const iocshArg * const myCmdArgs[] = { &myCmdArg0, &myCmdArg1 };
static const iocshFuncDef myCmdDef = { "myCmd", 2, myCmdArgs };
static void myCmdFunc(const iocshArgBuf *args)
{
// 命令函数实现
}
void myInitFunc()
{
iocshRegister(&myCmdDef, myCmdFunc);
}
上述代码中,myCmdFunc()是自定义的命令函数,使用iomemArgBuf结构传递参数。通过iocshFuncDef和iocshArg定义命令函数的参数信息。然后,将函数定义结构和命令函数地址作为参数传递给iocshRegister()函数来注册自定义命令。
注册后,可以在IOC Shell中使用myCmd命令调用自定义的命令函数,并传递相应的参数。例如,在IOC Shell中执行以下命令:
myCmd 10 "Hello"
这将调用myCmdFunc()函数,并将参数10和"Hello"传递给该函数进行处理。
总之,iocshRegister()函数的作用是将自定义的命令函数与IOC Shell关联起来,使得在IOC Shell中可以使用这些自定义命令。它通过在IOC的初始化函数中注册命令函数来实现命令的扩展和定制。
- epicsExportRegistrar()函数
epicsExportRegistrar()函数是用于注册IOC(Input/Output Controller)初始化函数的函数。它的作用是将初始化函数与IOC注册表关联起来,使得在IOC启动时能够自动调用初始化函数。
在EPICS中,初始化函数负责注册IOC中的各种设备和记录,并进行必要的配置和初始化。而epicsExportRegistrar()函数的作用就是告诉IOC注册表在IOC启动时应该调用哪个初始化函数。
epicsExportRegistrar()函数通常在IOC的驱动程序文件中使用,通过在初始化函数定义之前调用该函数,将初始化函数和IOC的启动过程连接起来。具体的用法是将初始化函数作为参数传递给epicsExportRegistrar()函数,例如:
void myInitFunc()
{
// 初始化代码
}
epicsExportRegistrar(myInitFunc);
上述代码中,myInitFunc()是自定义的初始化函数,通过调用epicsExportRegistrar()函数将其注册到IOC的初始化过程中。这样,在IOC启动时,IOC注册表会调用该初始化函数来执行相应的操作,以实现设备和记录的初始化和配置。
三、编译运行测试
编译前还需先设置Makefile文件调用上述文件
打开/exer1App/src目录下的Makefile文件并添加如下内容:
# Include dbd files from all support applications:
#exer1_DBD += xxx.dbd
exer1_DBD += exer1Hello.dbd
exer1_DBD += exer1Add.dbd
exer1_SRCS += exer1Hello.c
exer1_SRCS += exer1Add.c
回到exer1目录下,执行make编译
然后cd进入/iocBoot/iocexer1目录下,终端输入如下命令行修改st.cmd文件的权限,然后运行文件
chmod +x st.cmd
./st.cmd
接下来就可以在IOC shell中对函数进行调用
epics> help hello
hello name
epics> hello
Hello from my exer1
epics> hello(EPICS)
Hello EPICS, from my fisrt exer1
epics> hello EPICS
Hello EPICS, from my fisrt exer1
epics> help add
add a b name time
epics> add(1,2,blctrl, 5.0)
a:1
b:2
1 + 2 = 3
Hello blctrl, from my fisrt exer1Add
time: 5.00
epics> add 1 2 blctrl 5.0
a:1
b:2
1 + 2 = 3
Hello blctrl, from my fisrt exer1Add
time: 5.00
总结
本文全部是按照大佬的教程进行操作的,主要是添加了对两个注册函数的说明解释