当前位置:网站首页>synApps -- Autosave
synApps -- Autosave
2022-08-08 18:25:00 【yuyuyuliang00】
内容表
概要
Autosave在一台服务器上自动地保存EPICS过程变量(PVs)的值到文件,并且重启IOC(输入输出控制器)时恢复那些值。Autosave时一l种两部分操作:运行时保存和启动时恢复。运行时部分(save_restore任务或线程)有在IOC启动脚本中的命令启动,并且在IOC运行期间一直存在。它主要作业是在一台服务器上保存PV值,但它也支持手动恢复和其它管理操作。启动时部分(dbrestore.c)在iocInit过程中通过一个EPICS initHook被调用。它从由运行时部分所写的文件恢复PV值,并且在iocInit()返回后不再存在。
在autosave软件外,autosave模块还包括了一个客户端程序asVerify,去比较所写的autosave文件和当前PV值。这个程序也能够写一个autosave文件,能够从这个autosave文件中恢复PV值。因为asVerify的其中一个用法是从一个遇到问题(例如,save_restore任务崩溃了)的IOC获取PV值。asVerify一次只能连接一个PV。这使得asVerify非常慢。在一次试验中,它花了两分钟验证一个包含了5000个PVs的.sav文件。
Autosave也包括一个称为configMenu的工具,用于创建、保存、查找、恢复以及验证IOC配置(即是,PV值集合)。configMenu基本上相当于EPICS备份和恢复工具BURT,但它使用autosave文件,并且由EPICS PVs驱动,因此,它能够手动被软件客户端和被其它IOC core使用。
Autosave也包含一个称为autosaveBuild的工具,产生autosave_request文件,其作为EPICS函数dbLoadRecords()和dbLoadTemplate()操作的部分。此工具需要EPICS 3.14.12.5以及以上或者带有补丁的更早版本3.14。
重要的细节差别
1) 启动时,autosave使用dbStaticLib来写PVS,就像dbLoadRecords()。因而,启动时恢复不发生记录运行,并且它不定义一个记录的值(不设置UDF为0)。
例外:数组不能被dbStaticLib写,因此autosave在运行时使用数据库访问写数组。它仍然不发生运行,虽然它应该使得记录的UDF字段被设置为0。
2)运行时(在iocInit完成了),autosave使用通道访问读写。在运行时恢复与启动时恢复不同的结果,因为记录运行会发生。在autosave 5.6前,总是使用数据库访问读写数组,这引起记录运行。从autosave 5.6开始,用通道访问进行数组的运行时恢复。
3) 启动时恢复能够在两个时刻之一或者两个时刻都发生,在记录初始化前("pass 0"),和在记录初始化后("pass 1")。(记录初始化包括设备支持初始化)。对于大多数PV‘s,你不需要关注它;只要告诉autosave在两个时刻都恢复,并且autosave将做所要求的任何事情来写这个值。你不能根据一个PV接一个PV做这个恢复时选项,你只能指定何时恢复一整个文件的PVs。
设备支持初始化过程中,如果你想要被恢复值可供设备支持可用,你必须在pass 0过程中使这个值被恢复。(注意:不能在此时恢复数组,因为一般还未为数组分配存储区)。如果你想要这个被恢复至重写由记录/设备初始化写的值,你必须在pass 1过程中使这个值被恢复。
Motor-record位置(VAL或DVAL)只应该在记录初始化前被恢复(即是,在pass 0过程中),因为这就是在其下编写motor-record设备支持。
在围绕autosave构建的传说中,只应该在记录初始化前被恢复的PV's被称为"positions"。所有其它PV’s被称为"settings"。因而,你会遇到一个名为"auto-positions.req"的文件,并且现在你将知道在此文件中的PVs是打算在autosave的pass 0过程中被恢复。
4)你可以保存PVs而不恢复它们,以及恢复它们而不保存它们,但你不能选择个别PVs,只能选择整个文件的PVs。
5) 你能够对用户指定时间启用和禁用自动化保存。(如果用户忽略再次启用保存,你可以安排在指定时间后发生启用)。在自动化保存被禁用时,手动保存(configMenu)未被禁用。
如何使用autosave
可以用很多方式使用此软件。由于在同步辐射束线中常使用它来周期性保存PVs并且在重启时恢复它们,这里将描述要使用它,你必须做什么。
一个在束线如何使用autosave的完整示例可以在synApps xxx模块中找到。在此模块中的相关文件如下:
- xxx/configure/RELEASE:查找"AUTOSAVE"
- xxx/xxxApp/src/Makefile:查找"autosave"和"asSupport.dbd"
- xxx/iocBoot/iocvxWorks/save_restore.cmd:整个文件。
- xxx/iocBoot/iocvxWorks/auto_positions.req:整个文件。
- xxx/iocBoot/iocvxWorks/auto_settings.req:整个文件。
- xxx/iocBoot/iocvxWorks/st.cmd:查找save_restore.cmd和create_monitor_set。
- xxx/iocBoot/iocvxWorks/autosave:一个保存autosave .sav文件的目录
这是用于部署autosave的循序渐进的方案。其中一些步骤是可选的:
1、Build(构建,需要)
构建模块并且在一个IOC的构建中包含产生的库libautosave.a和数据库定义文件asSupport.dbd。例如添加
AUTOSAVE=<path to the autosave module>
到xxx/configure/RELEASE,添加
xxx_LIBS += autosae
到xxxApp/src/Makefile,并且添加
include "asSupport.dbd"
到iocxxxInclude.dbd。
2、编写请求文件(可选的,但这是目的和最常见用法)
创建"指定你想要保存和恢复其值的PVs的request"文件(例如,auto_settings.req, auto_positions.req)。保存的文件对应于请求文件,其后缀由"req"被替代成".sav"。这是一个示例请求文件:
xxx.m1.VAL
xxx.m2.VAL
请求文件也可以包含宏变量,其值将在引起此请求文件被处理的调用中被定义。例如,以上也可以被写成如下,由命令create_monitor_set("auto_settings.req",30,"P=xxx:")定义宏P:
$(P)m1.VAL
$(P)m2.VAL
请求文件可以包含其它请求文件(允许嵌套包含)并且可以对被包含文件执行宏替换,用以下语法:
file <request_file> <macro-substitution_string>
例如:
file motor_settings.req P=xxx:,M=m1
我尝试防止语法中可预见的变化,使得带嵌入空白和/或引号的"file"命令,不带逗号的宏字符串以及空的宏字符串将按想要的解析。一般忽略引号,空白隐含一个逗号,但否则被忽略,并且在第二个非空字符串序列后的所有字符(即文件名后)被当作宏替换字符串。对整行进行宏替换,因此参数化被包含的文件以及PV名称是可能的。定义一个用空替换其目标的宏也是可能的。
注意:从autosave 5.1开始,在于file命令相同行上有一个注释是非法的。做此种更改来允许在宏定义中使用'#'字符。
大部分synApps模块包含了auto-request文件,其用于被包含在一个ioc的autosave-request文件(s)中。
例如,calc/calcApp/Db/scalcout_settings.req包含你想要为一个scalcout记录自动保存字段的列表。这个文件被包含在calc/calcApp/Db/UserStringCalcs10_settings.req中,其接着被包含在了xxx/iocBoot/iocvxWorks/auto_settings.req中。
从版本4.3开始,autosave从在EPICS数据库中包含的info节点产生请求文件。关于此话题的更多信息,件以下函数makeAutosaveFiles()。
注意:从synApps版本5.2.1开始,synApps包含能够从被包含在命令和数据库文件中信息产生auto-request文件的软件。见synApps/support/utils/makeAutosaveFiles.py。
从autosave 5.5版本开始,autosave包含从dbLoadRecords()和dbLoadTemplate()产生autosave-request文件的软件。见autosaveBuild。
3、设置request-file路径(可选的,推荐)
使用一次或多次set_requestfile_path()调用指定搜索请求文件的一个或多个目录
对于使用cdCommands的系统:
set_requestfile_path(startup,"")
set_requestfile_path(startup,"autosave")
set_requestfile_path(area_detector,"ADApp/Db")
对于使用envPaths的系统:
set_requestfile_path(“$(TOP)/iocBoot/$(IOC)”,"")
set_requestfile_path(“$(TOP)/iocBoot/$(IOC)”,"autosave")
set_requestfile_path(“$(AREA_DETECTOR)”,"ADApp/Db")
4、设置NFS主机(可选的,只在vxWorks和RTEMS上可用)
通过调用以下函数指定NFS主机,在恢复时将从其读取保存文件,以及在保存时将写它们到哪里。
save_restoreSet_NFSHost("oxygen","192.168.3.2")
当autosave管理其自己的NFS挂载时,由于这个命令指挥它去做,它通过卸载并且重启挂载这个文件系统能够修复陈旧文件。
5、使用NFS(在vxWorks上需要)
使用NFS,如以上描述首选地,或者通过在你的启动命令脚本中包括一个nfsMount()命令。只用NFS测试了save_restore,并且可能对vxWorks的netDrv无效。
当autosave运行在除了vxWorks和RTEMS外的操作系统下,它只是使用操作系统或者管理员提供的任何挂载。
6、设置save/restore路径(可选,但这是目的和最常见使用)
在create_xxx_set命令前通过在你的启动脚本中调用以下指定目录路径的函数指定你想要.sav文件被写入的目录
set_savefile_path("/full/path")
如果你使用NFS(强烈推荐),确保此路径不包含符号链接。在我的经验中,vxWorks不能通过符号链接写。(我不明白这种限制的所有细节。如果符号链接包含绝对路径名,它们可能是正常的)。
从autosavev4.3开始,你也可以用EPICS PV指定一个autosave .sav文件要被写入的路径和/或文件名。
7、赋予ioc对autosave目录的写权限(所需)
赋给IOC对save文件被写入目录的写权限。如果你忘记了这步,save_restore可能能够写save文件,但由于save_restore将不被允许更改它们的长度,这些文件将被损坏。Save_restore尝试探测这种情况,但如果文件长度必须增长,它不能解决。
如果你使用autosaveBuild,你必须赋予autosave对这个将包含autosave写请求文件的目录的写权限。
8、指定恢复文件(可选的,但这是目的和最常用法)
使用命令ser_pass<N>_restoreFile()指定哪些文件将在记录初始化前(pass 0)要被恢复以及哪些文件在记录初始化后(pass 1)要被恢复,如在以下示例中:
set_pass0_restoreFile("auto_settings.sav", "P=xxx:")
set_pass1_restoreFile("auto_settings.sav", "P=xxx:")
(注意:macrostring是可选的,并且autosave 5.4的一个新特性)
把这些命令放在启动文件iocInit前。在4.4版本前,如果未指定恢复文件,autosave会尝试恢复"auto_positions.sav"和"auto_settings.sav"。从4.5版本开始,只恢复在set_passn_restoreFile()调用中指定的文件。
如果传给set_passn_restoreFile()的第一个参数是一个不以"/"开头的字符串,autosave将前置在set_savefile_path中指定的路径。指定一个恢复文件的最常用法是只指定其不带任何路径信息的名称。
从autosave 5.4开始,如果你指定一个完整路径(一个以"/"开头的字符串),autosave将不在它前面前置任何东西。(但在这种情况中,autosave将不写这个文件一个恢复时备份)。
要完全禁用启动时恢复,删除或注释掉所有set_passn_restoreFile()调用。
对恢复阶段的注意:
1、在初始化后不能通过dbStatic调用恢复链接字段。如果你想要保存/恢复对链接字段有效,你必须在一个pass-0文件中指定它们。
2、对motor记录的设备支持使用字段DVAL的值,只在从硬件读取的值是0时,才在pass 0过程中被恢复。如果从硬件读取的值是非零,使用它替代这个被恢复至。
3、在pass 0过程中不能恢复数组。
4、在.dbd文中类型为DBF_NOACCESS,并且被记录支持设置成某个其它DBF类型的标量PV‘s不能在pass 0阶段被恢复。
5、在错误阶段尝试恢复PV's不是一个错误。用auto_settings.req和auto_positions.req实现的默认策略是为除了不应该在pass 1中被恢复的所有PV's都使用两个阶段。(Motor位置不在pass 1中被恢复,因为这样做会重写从硬件读取的任何值。)
9、装载initHook例程(启动时恢复所需)
装载一个iitHooks副本,它调用reboot_restore()来恢复保存的PV值。推荐在这个发行版中国包含的initHooks副本。如果按以上描述的构建这个ioc的可执行文件,这将自动发生。
10、选择save-file选项(可选,推荐)
1) 告诉save_restore写过时的备份文件。在启动时,写一个从其恢复PV’s的".sav"文件的备份副本。这个文件可以被命名为xxx.sav.bu,并且在每次重启后被重写,或者被命名为xxx.sav_YYYYMMDD-HH:MM:SS,此处"YY...."是日期。过时的备份文件不会被重写。如果你想要过时的备份文件,在你的st.cmd文件中对iocInit()调用前放入以下一行:
save_restoreSet_DatedBackupFiles(1)
注意:如果在pass 0和pass 1中一个保存文件都被恢复,启动备份文件将只在pass 0过程中被写。
2) 告诉save_restore要保存序列文件。命令:
save_restoreSet_NumSeqFiles(3)
save_restoreSet_SeqPeriodInSeconds(600)
将使得save_restore以10分钟间隔维持每个.sav文件的三个副本。注意:如果autosave文件写.sav文件失败,在它再次成功前它将停止产生顺序副本。
3)指定一次失败的.sav-file写和再次尝试写之间的时间延时。默认延时是60秒。如果在延时期间,list-PV's变化了,将写这些新值。
save_restoreSet_RetrySeconds(60)
4) 指定autosave是否应该周期地重新尝试连接其初始连接尝试失败地PVs。当前,此连接重试间隔被以60秒硬编码了。
save_restoreSet_CAReconnect(1)
5) 以秒单位指定在强制save-file写之间的时间间隔。(-1表示永远)。这是用于即使正常触发机制损坏也要写保存文件。
save_restoreSet_CallbackTimeout(-1)
11、启动save任务(保存文件需要)
通过调用create_XXX_set()调用这个软件的"保存"部分作为EPICS启动顺序组成,例如,添加这种形式的行:
create_monitor_set("auto_positions.req", 5, "P=xxx:")
create_monitor_set("auto_settings.req", 30, "P=xxx:")
到你的EPICS启动文件iocInit之后。传给create_monitor_set()的第三个参数是一个宏替代字符串,如以上在请求文件讨论中描述。如果提供了,这个宏替换字符串补充为读取这个保存集的请求文件的include-file指令中提供的任何宏字符串。
注意:如果你想要启动不创建一个保存集的保存任务,你可以不带参数调用create_monitor_set()。
宏字符串也可以用于重写.sav文件将被写入的默认路径和名称。如果包含了宏SAVEPATHPV=<pv-name>,autosave将写.sav文件到从EPICS PV <pv-name>读取的路径,替代写入在save_savefile_path()中指定的路径。如果包含了宏SAVENAMEPV=<pv-name>,autosave将写.sav文件到从EPICS PV <pv-name>读取的文件名。(默认,.sav文件名是request-file名称,.req被.sav替代。)
注意:如果在宏字符串中出现了SAVEPATHPV或SAVENAMEPV,autosave将不尝试为保存集保存备份或者顺序文件。
对于每个create_monitor_set(<name>.req, <time>, <macro>)命令,save_restore进程将每<time>秒写文件<name>.sav和<name>.savB,如果在文件<name>.req中指定名称的任何PVs从上次写以来更改了值。其它create_xxx_set()命令做相同事情,但用不同条件触发相同保存操作。
注意:在2.7版本之前,create_monitor_set()使用一个类型double的参数指定周期(以秒为单位)。这在vxWorks下PowerPC处理器上不起作用,因此用于此和类似函数的参数被更改为int。
如果你的IOC花费很长时间启动,你想要保存的PVs在save_restore任务第一次查看它们时将没有正确的值。(如果你恢复大量常数组,这更加可能。)在vxWorks下,你可以通过在create_monitor_set()前放置taskDelay(<number_of_60_Hz_clock_ticks>)避免这个。
autosaveBuild(自动的request-file产生)
注意:这个功能需要EPICS base版本高于3.14.12.5,或者对更早版本EPICS base 3.14打一个补丁。要在autosave中启用此代码,你必须编辑asApp/src/Makefile,并且去除这行的注释:
#USR_CFLAGS += -DDBLOADRECORDSHOOKREGISTER
在synApps中很多数据库有相关联的autosave-request文件。例如,calc模块包含editSseq.db和editSseq_settings.req。当添加一个新数据库到一个IOC时,添加相关联的请求文件到auto_settings.req和/或auto_positions.req是一个常见做法。为了明确,st.cmd包含这个:
dbLoadRecords("$(CALC)/calcApp/Db/editSseq.db","P=xxxL:,Q=ES:")
并且auto_settings.req包含这个:
file editSseq_settings.req P=xxxL:,Q=ES:
单独维护这些条目是枯燥和易错的,因此autosave能够为你做request-file部分。要做这件事,你告诉autosave在调用dbLoadRecords()(注意dbLoadTemplate()调用dbLoadRecord)时安排被调用,你告诉它如何从一个数据库文件名称产生一个request-file名称,并且你传给它你想要它构建的请求文件的名称。你可以用以下命令做这件事:
autosaveBuild("built_settings.req","_settings.req",1)
这告诉autosave做以下事情:
1) 开始构建文件built_settings.req。如果这是提到built_settings.req的第一次调用,擦除这个文件。
2) 通过从数据库文件名删除".db"或"vdb"或".template"并且添加后缀"_settings.req"产生request-file文件名。
3)如果第三个参数是1(0)启动(禁用)自动化构建。
当自动化构建被启用,autosave将产生request-file名称并且在它的request-file路径中搜索那些文件。如果它查找到一个请求文件,它将添加适合的行到built_settings.req。
这做的所有是写文件built_settings.req。如果你想要使用它,你必须添加以下行到auto_settings.req:
file built_settings.req P=$(P)
选项
1) 通过多次调用autosaveBuild(),你可以指定多个request-file后缀:
autosaveBuild("built_settings.req","_settings.req",1)
autosaveBuild("built_settings.req",".req",1)
在这些调用后,对应adc.db的request-file名称可以是abc_settings.req或者abc.req。如果二者都被找到,对应二者的行将都被添加到built_settings.req。
2) 你可以单独地禁用文件/后缀组合:
autosaveBuild("built_settings.req","_settings.req",0)
禁用搜索以"_settings.req"结尾的请求文件用于built_settings.req。
autosaveBuild("built_settings.req","*",0)
禁用为built_settings.req搜索所有请求文件。
3) 你也可以自己添加一行到built_settings.req中
appendToFile("built_settings.req",'$(P)userStringSeqEnable')
注意单引号的使用。这是用于icosh,因为它将不接收展开宏$(P)的错误,而单引号告诉它不进行宏展开。
asVerify
autosave不是完全防弹的。大部分APS线站每年至少出现一次autosave相关的问题。如果autosave失败,你使用asVerify可能发现它或者解决它。这个客户端程序读取一个autosave .sav文件并且独立地验证它包含的值与当前PV值一致。这个程序也用于为指定的PVs列表写一个.sav文件。PVs列表通常是一个autosave .sav文件,但一个每行包含一个PV名称的文件将也有作用。这是asVerify的命令行:
用法:asVerify [-vrd] <autosave_file>
- -v(详细)打印所有PV‘s,否则只打印器值不同的PV’s。
- -r (restore_file) 使得一个名为'<restore_file>.asVerify'的恢复文件被写。
- -d (调试) 提高调试等级1
- -rv(或-vr)二者都做。
示例:
asVerify auto_settings.sav
只报告其值不同于保存值的PV。
asVerify -v auto_settings.sav
报告所有PVs,用'***'标记不同。
asVerify -vr auto_settings.sav
报告所有PVs,并且写一个恢复文件。
asVerify auto_settings.sav
caput <myStatusPV> $?
写找到的不同数目到一个PV
注意asVerify不能读取一个autosave请求文件;它将理解在这个文件中包含的任何PV名称,但它不能解析"file"命令,执行宏替代或者包含其它请求文件。
从autosave R5.6.1开始,能够从IOC console调用asVerify:
asVerify(char * fileName, int verbose, char *restoreFileName)
示例:
asVerify("auto_settings.sav")
这将打印不同。
asVerify("auto_settings.sav", 0, "junk.sav")
这将打印不同,并且在IOC的当前目录中写"junk.sav"。
configMenu
configMenu是一个用于在一个运行的IOC上创建,保存,查找和验证EPICS PVs("配置")集合的工具。它基本相当于EPICS备份和恢复工具BURT,但它保存配置为autosave文件,并且有EPICS PVs驱动并且向EPICS PVs报告,因此它能够被手动使用,由任何CA客户端或者由IOC-resident代码驱动。configMenu操作能够被一个对一个EPICS PV的ca_put_callback驱动,因此一个配置的装载和保存可以作为一个更大操作顺序的组成部分被驱动。例如,能够进行ca_put_callback的任何EPICS记录能够装载或保存一个配置并且在可能触发其它执行前等待这个操作结束。
在autosave R5-7中新特性:一个configMenu实例能够处理的配置数目曾经是10个,但现在没有限制了。如果找到了多于10个配置,你可以浏览这个列表,一次10个配置。
示例
假设我们想要配置一个3 sscan记录的集合来执行很多不同扫描类型之一。这是实现一个扫描类型菜单所需要的步骤,并且给了用户一个用于创建扫描类型和装载它们的GUI窗口。(在以下,scan1是这个configMenu实例的名称。它装载和保存的文件将被命名为"scan1_<config Name>.cfg"。)
1) 用以下内容创建一个我将称为"scan1Menu.req"的autosave请求文件:
file configMenu.req P=$(P),CONFIG=$(CONFIG)
file scan_settings.req P=$(P),S=scan2
file scan_settings.req P=$(P),S=scan1
file scan_settings.req P=$(P),S=scanH
只在运行时要写scan1 config文件时才需要这个。
2) 添加以下行到st.cmd:
dbLoadRecords("$(AUTOSAVE)/asApp/Db/configMenu.db","P=xxx:,CONFIG=scan1")
这在iocInit前出现。通过指定宏ENABLE_SAVE=0,你可以禁用scan1 config文件的保存。
create_manual_set("scan1Menu.req","P=xxx:,CONFIG=scan1,CONFIGMENU=1")
这在iocInit后出现,并且只在你想要在运行时要写scan1 config文件时,或者如果你需要对要被装载的scan1 config文件执行宏替换,才需要这个。宏CONFIGMENU告诉autosave不要为这个save集写备份(.savB)和顺序(.sav1, sav2等)文件。
3) 添加一个MEDM相关的显示条目来产生一个configMenu*.adl窗口。
label="scan1Menu"
name="configMenu.adl"
args="P=xxx:,CONFIG=scan1"
4) 如果在配置中的所有PVs都被自动保存了,并且你想要当前配置名和描述,以及enableSave选择也被自动化,添加以下行到auto_settings.req:
file configMenu_settings.req P=$(P),CONFIG=scan1
我不确定这是一个好主意,因为不确保自动保存的值与在.cfg文件中的值相同。(例如,用户可能已经装载了一个.cfg文件并且接着做了一些修改。)但重启这个ioc并且没有让所有东西照原样回来对用户来说是令人不安的,所以我通常做这件事。
这是一个用户所看到的示例:
在configMenu_small.adl,由枚举PV, $(P)$(CONFIG)Menu(例如:xxx:scan1Menu)选择和显示配置菜单。这个窗口不能引起一个配置被重写。当菜单重新填充或者选择了新的一页时,MEDM将不自动获取新名称用于由$(P)$(CONFIG)Menu显示。这必须手动做,通过关闭和重新打开这个窗口,这就是"Refresh menu choices"按钮所做的。
先前,$(P)$(CONFIG)Menu是一个用于从CA客户端软件驱动configMenu的快捷PV,因为它选择了一个配置并且使得这个配置被装载。如果配置名称不在被显示页面上,这不再其作用。从R5-7开始,CA客户端通过写配置的名称到$(P)$(CONFIG)Menu:name能够安全地装载一个配置。
configMenu.adl和configMenu_more.adl以单独地PVs展示菜单选项,对此不需要手动刷新,并且提供了用于装载和保存配置以及用于浏览可用配置文件列表的按钮。
configMenu_more.adl也显示描述PVs。当通过搜索config文件填充菜单时,从那些文件提取描述。否则,如果configMenuNames.req被包含在了一个autosave-request文件中,名称和描述将在启动时被恢复。如果enable PV(标签为"permit save?")有值为"No",将不显示"save"按钮,并且使用者将不能保存配置文件。
细节:
1、在窗口configMenu.adl中配置名称将对应其名称相同的autosave “.cfg”文件,但非字母数字字符被'_'替代(例如:scan1_align_extrance_slit.cfg)。一个".cfg"文件完全像一个".sav"文件,".cfg"扩展名纯粹使得容易找到它们并且与".sav"文件区别。
你不要想产生两个其名称只在非字母数字字符中才有不同的配置;configMenu将把它们当成相同配置。
2、configMenu_small.adl有一个在config文件菜单更改时的问题:MEDM不监视菜单(枚举)字符串,因此当它们改变时必须关闭和重新打开这个窗口。这就是"Refresh menu choices"按钮所为了的。(指定事件类型标记DBE_PROPERTY的通道访问客户端,当它们订阅一个枚举PV时,当枚举字符串发生变化时,将不被通道)。
3、从R5-7开始,configMenu能够保存来自其它IOCs的所有类型PVs/恢复所有类型PVs到其它IOCs。如果你configMenu用于远程PVs,你应该通过在save_restore.cmd中包含以下行告诉autosave周期地重新尝试连接。
save_restoreSet_CAReconnect(1)
4、当configMenu重写一个已有的.cfg文件,它进行当前版本的备份,命名filename_YYMMDD-HHMMSS。例如:在2013年4月1日写了scan1_blank.cfg_130401-140546。
5、你可以装载包含宏的.cfg文件。例如,通过按以下指定宏
create_manual_set("SGMenu.req","P=xxx:,CONFIG=SG,CONFIGMENU=1,H=softGlue:")
此处P和H的定义与它们在softGlue.cmd中定义一致,在没有对任何softGlue实例修改下,能够装载softGlue标准示例电路。
6、configMenu需要列出一个目录来为.cfg文件搜房autosave目录。
有关保存文件
在一个保存文件中PV值已经被转成了字符串,在大都数情况中,只要通过以字符串被读取--例如,ca_get(DBR_STRING, ...)。大部分数据类型使用通道访问被读取和使用dbStaticLib调用被写。四种数据类型受到特别关注:
1) double:以double读取,被用格式"%.14g"转成字符串。(否则,记录的PREC字段回限制精度)
2) float:与double相同,但格式是"%.7g"。
3) menu和enum:菜单和枚举是整数数据类型,但值被限制为集合(0,1,...,N),此处'N'取决于这个PV,但通常是15或者更小。EPICS关联一个字符串与在这个集合中每个数值,并且允许客户端使用数值或者字符串。对于菜单PV's,在一个.dbd文件中指定字符串;对于枚举PV's,在一个数据库文件中指定字符串,并且在运行时能够修改它们。
通道访问不区分这些类型,所有autosave也不区分。Autosave不能以字符串写枚举,因为在必须修改枚举字符串的时候,它们可能还未被定义。
4) 任何类型的数组:使用数据库访问读取数组。通道访问不能只读取一个数组定义的部分,dbStaticLib不能写数组。(但asVerify使用通道访问读取数组。)从autosave 5.6开始,启动时,autosave使用数据库访问写数组,但在运行时,它使用通道访问。
这是一个示例保存文件,末尾括号中是注释,不是这个文件的组成部分。
# save/restore V4.9 Automatically generated - DO NOT MODIFY - 060720-154526
! 1 channel(s) not connected - or not all gets were successful
xxx:SR_ao.DISP 0 (uchar)
xxx:SR_ao.PREC 1 (short)
xxx:SR_bo.IVOV 2 (ushort)
xxx:SR_ao.SCAN 3 (enum - saved/restored as a short)
xxx:SR_ao.VAL 4.1234567890123 (double, printed with format "%.14g")
xxx:SR_scaler.RATE 1.234568 (float, printed with format "%.7g")
xxx:SR_ao.DESC description (string)
xxx:myCalc.CALC$ 123456789+123456789+123456789+123456789+123456789 (long string)
xxx:SR_ao.OUT xxx:SR_bo.VAL NPP NMS (link)
xxx:SR_ao.RVAL 4 (long)
xxx:SR_bi.SVAL 2 (ulong)
#i_dont_exist.VAL Search Issued (no such PV)
xxx:SR_char_array @[email protected] { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" }
xxx:SR_double_array @[email protected] { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" }
xxx:SR_float_array @[email protected] { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" }
xxx:SR_long_array @[email protected] { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" }
xxx:SR_short_array @[email protected] { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" }
xxx:SR_string_array @[email protected] { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" }
xxx:SR_uchar_array @[email protected] { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" }
xxx:SR_ulong_array @[email protected] { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" }
xxx:SR_ushort_array @[email protected] { "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" }
<END>
保存文件不是为了被手动编辑。如果你要编辑一个保存文件,比必须以文件<END>后跟一个或任意字符(通常\n或者\r\n)结束它。如果文件不是以这个文本结束,在文件正被写时,reboot_restore()将认为这个crate坏了,或者其它不好的事情发生了,并且将不使用这个文件。当一个保存文件被成功地创建了,除非一个正常地".savB"备份文件存在,否则save_restore将不重写这个文件。类似地,除非成功地写了保存文件,否则它将不重写".savB"。
你可以用'#'开头一行来注释点在一个.sav文件中这行。
模块内容
asApp/src
- save_restore.c:根据预置规则在一个文件服务器上文件中保存PV值。
- dbrestore.c:在启动时使用dbStaticLib恢复PV值。
- initHooks.c:在启动过程中正确时间调用恢复例程。
- fGetDateStr.c:Frank Lenkszus的日期字符串例程。
- save_restore.h, fGetDataStr.h, configMenuClient.h:头文件。
- verify.c:比较一个autosave文件与当前PV值。由asVerify和configMenu使用。
- asVerify.c:客户端工具,比较自动保存的文件与当前PV值。也能写一个autosave文件。
- configMenuSub.c:由configMenu数据库使用的aSub例程。
asApp/Db
- auto_settings.req, auto_positions_req:示例请求文件。
- save_restoreStatus.db:包含save_restore使用来报告状态的记录的数据库。
- infoExample.db:包含一个用info节点指定要被自动保存字段的记录的数据库。
- SR_test.db:用于自动保存和asVerify的测试数据库。
- configMenu.db, configMenu*.req:对管理/配置一个PVs集合的支持。
asApp/op/adl(也../ui, ../edl, ../opi)
save_restoreStatus*.adl, save_restoreStatusLegend.adl, save_restoreStatus_more.adl, save_restoreStatus_tiny.adl, SR_X_Status.adl:save_restore状态的MEDM窗口。
configMenu*.adl:对管理/配置一个PVs集合的支持。
用户可调用函数
/*
比较在IOC中PV值和写在filename(其应该是一个autosave恢复文件,或者至少像一个
这样的文件)中的值。如果restoreFileName为空,写一个新的恢复文件。这个函数能够在
iocInit之后任何时间调用。
*/
int asVerify(char *fileName, int verbose, char *restoreFileName)
/*
为请求文件创建一个保存集。当用相同request-file名称调用函数manual_save()时,
将写这个保存文件。
有关宏字符串的信息见以上"Start the save task"。
可以在iocInit之后任何时间调用这个函数。
*/
int create_manual_set(char *request_file, char *macrostring)
/*
为请求文件创建一个保存集。每period秒如果从上次写以来在保存集中任何PV被提交(被更改值)将写这个保存文件。
有关宏字符串的信息见以上"Start the save task"。
可以在iocInit之后任何时间调用这个函数。
*/
int create_monitor_set(char *request_file, int period, char *macrostring)
/*
为这个请求文件创建一个保存集。将每period秒写这个保存文件。
有关宏字符串的信息见以上"Start the save task"。
可以在iocInit之后任何时间调用这个函数。
*/
int create_periodic_set(char *request_file, int period, char *macrostring)
/*
为这个请求文件创建一个保存集。当由trigger_channel指定的PV被提交时,将写这个保存文件。
通常这在PV的值变化时发生。
有关宏字符串的信息见以上"Start the save task"。
可以在iocInit之后任何时间调用这个函数。
*/
int create_triggered_set(char *request_file, char *trigger_channel, char *macrostring)
/*
如果save_file指向一个在内存中存在的保存集,则在保存集中的PV's将被从内存中值恢复。否则,
这个函数恢复在<saveRestorePath>/<save_file>中的PV's并且创建一个新的备份文件"<saveRestorePath>/<save_file>.bu"。效果可能不同于启动时恢复,因为调用caput()而不是dbPutX()
调用。记录运行将源于对process-passive字段的caput()'s。
在已经调用了create_*_set()函数之一后任何时间能够调用这个函数。在创建任何保存集前,你想要调用这个函数,你可以用一个空的request-file名称调用create_*_set()。autosave将抱怨这个,但它不会认为你时一个坏人。
*/
int fdbrestore(char *save_file)
/*
(iocsh版本)这个函数从文件<saveRestorePath>/<save_file>恢复,其可以看起来就像一个保存文件,但其不需要以<END>结尾。将不写备份文件。作用将不同于启动时恢复,因为使用caput()调用替代静态数据库访问dbPut*()调用。记录运行将源于对Process-passive字段的caput()'s。
在调用了create_*_set()函数之后任何时间可以调用这个函数。在创建任何保存集前,如果你想要调用这个函数,你可以用一个空request-file名称调用create_*_set()。autosave将不喜欢你做这件事,但它将抱怨。
*/
int fdbrestoreX(char *save_file)
/*
(c代码客户端版本)这个函数作用与以上iocsh版本相同。如果macrostring不是NULL,它包含的宏定义将被应用到filename的内容。如果callbackFunction不为NULL,它指定一个类型void f(int status,void * puser)的函数,当这个保存操作结束时,将调用这个函数。这是configMenu实现的组成部分。
*/
int fdbrestoreX(char *filename, char *macrostring, callbackFunc callbackFunction, void *puser)
/*
如果曾为request_file调用了create_*_set(),则在那个调用中提供了宏替换字符串被autosave记录,并且用这个函数被恢复。这是configMenu实现的组成部分,并且它允许.cfg文件包含宏。
*/
char *getMacroString(char *request_file)
/*
搜索整个EPICS数据库(即是,被装载到一个IOC的所有EPICS记录)查找名为'autosaveFields'和'autosaveFields_pass0'的info节点;从相关联的info值构建PV名称列表,
并且分别写PVs名称到文件'info_settings.req'和'info_positions.req'。
在EPICS数据库中info节点类似于一个字段specification,但它有词info而不是field;
并且它有任何名称,而不是在记录一个字段的名称。这是一个包含有两个节点的单个记录的EPICS数据库:
record(ao, "$(P)test1") {
field(DTYP, "Soft Channel")
info(autosaveFields, "PREC EGU DESC")
info(autosaveFields_pass0, "VAL")
}
从这些信息,makeAutosaveFiles()将写以下两个文件:
info_settings.req
$(P)test1.PREC
$(P)test1.EGU
$(P)test1.DESC
info_positions.req
$(P)test1.VAL
可以在iocInit()之后任何时间调用这个函数。
也见:
1、在EPICS Application Development's Guide中第14章 "Static Database Access"
2、makeAutosaveFileFromDbInfo()
*/
void makeAutosaveFiles(void)
/*
搜索整个EPICS数据库(即,装载到IOC中所有EPICS记录)查找名为info_name的'info'节点;
从找到的相关联的info_values创建一个PV名称的列表,并且写PV名称到文件fileBaseName。
如果fileBaseName不包含字符串'.req',将在它末尾添加这个字符串。更多信息见makeAutosaveFiles()。能够在iocInit()之后任何时间调用这个函数。
*/
void makeAutosaveFileFromDbInfo(char *fileBaseName, char *info_name)
/*
(iocsh版本)使得对应请求文件的当前PV值被保存。在一个create_xxx_set()命令中指名的任何请求文件将被手动保存。
*/
int manual_save(char *request_file)
/*
(对应c代码客户端的版本)使得对应请求文件的当前PV值被保存。在create_xxx_set()命令中指名的
任何请求文件将手动地被保存。如果save_file非NULL并且不是空,它指定将被写的文件名称。
如果callbackFunction非NULL,它指定一个类型void f(int status, void *puser)的函数,
当保存操作结束时,将调用这个函数。这是configMenu实现的组成部分。
*/
int manual_save(char *request_file, char *save_file, callbackFunc callbackFunction, void *puser);
/*
这只应该被从initHooks调用,因为只在iocInit过程中特定时刻被调用时,它才功能正常。
*/
int reboot_restore(char *save_file, initHookState init_state)
/*
这个函数使你能够更改与一个由create_manual_set()创建的保存集相关联的PV's。
注意:不要太期待remove/reload函数。在执行另一个前,你必须等待一个完全结束
(save_restore任务必须做完它的服务循环)。如果你在前一个函数完全结束前,你调用一个函数,
我不知道将发生什么。
*/
int reload_manual_set(char * request_file, char *macrostring)
/*
这个函数使你能够更改与一个由create_monitor_set()创建的保存集相关联的PV's和周期。
*/
int reload_monitor_set(char * request_file, int period, char *macrostring)
/*
这个函数使你能够更改与一个由create_periodic_set()创建的保存集相关联的PV's和周期。
*/
int reload_periodic_set(char *request_file, int period, char *macrostring)
/*
这个函数允许你更改与一个由create_trigged_set()创建的保存集相关联的PV's和触发通道。
*/
int reload_triggered_set(char *request_file, char *trigger_channel, char *macrostring)
/*
如果已经为request_file创建了一个保存集,这个函数将删除它。
*/
int remove_data_set(char *request_file)
/*
设置save_restoreDatedBackupfiles的值(初始1)。如果0,重启时写的备份文件将有后缀'.bu',
并且每次重启将被重写。如果非0,每次重启将留下它自己的备份文件。
这个函数可以在任何时间被调用。
*/
void save_restoreSet_DatedBackupFiles(int ok)
/*
启用周期过时的备份。如果periodInMinutes<=0,禁用周期过时备份。当启用时,autosave将为有资格备份的那些保存集写名称如"auto_settings.sav_b_180131-122100"的文件。如果保存集的文件路径或它们的文件名不是来自一个PV,并且它们不是configMenu保存集,它们有资格备份。
这个函数能够在任何时间被调用。
*/
void save_restoreSet_periodicDatedBackups(int periodInMinutes)
/*
设置save_restoreDebug的值(初始0)。增加来获取更多信息消息打印到console。
这个函数能够在任何时间被调用。
*/
void save_restoreSet_Debug(int debug_level)
/*
指定用于创建新的.sav文件的文件权限。这个整数值将完全如传入被提供给系统调用open()和调用fchmod()。一般用八进制设置文件权限,诸如0640,并且save_restoreSet_FilePermissions()将通过以一个八进制数值输出到这个console来确认传给它的任何数值。
在iocInit后任何时候能够调用这个函数。
*/
void save_restoreSet_FilePermissions(int permissions)
/*
设置save_restoreIncompleteSetOk的值(初始1)。如果设成0,除非保存文件是完美的,否则在启动时将不恢复保存文件,并且除非在列表中每个PV存在一个有效连接和值,否则在保存时将不重写它们。
在任何时候能够调用这个函数。
*/
void save_restoreSet_IncompleteSetsOk(int ok)
/*
指定NFS主机的名称和IP地址。如果二者都已经指定了,并且调用了set_savefile_path()指定文件路径了,save_restore将管理它自己的NFS挂载。这使得save_restore能够从NFS主机的一次重启和从修改了save_restore目录的某类恢复。
*/
void save_restoreSet_NFSHost(char *hostname, char *address)
/*
设置save_restoreNumSeqFiles的值(初始3)。这是要被维护的顺序备份文件的数目。numSeqFiles必须在0和10(包括)之间。
这个函数可以在任何时候被调用。
*/
void save_restoreSet_NumSeqFiles(int numSeqFiles)
/*
设置save_restoreRetrySeconds的值(初始60,最小10).如果.sav-file写失败,它将在这个间隔后重试。可以在任何时候调用这个函数。
*/
void save_restoreSet_RetrySeconds(int seconds)
/*
设置save_restoreSeqPeriodInSeconds(初始60)。用这个周期写顺序的备份文件。period必须是10或者更大。可以在任何时候调用这个函数。
*/
void save_restoreSet_SeqPeriodInSeconds(int period)
/*
指定要用于构建PV's名称使用的前缀,save_restore用这些名称报告它的状态。如果你想要按它运行更新状态PVs,你必须调用这个函数并且装载数据库save_restoreStatus.db,在两个命令中都指定相同的前缀。
*/
void save_restoreSet_status_prefix(char *prefix)
/*
指定save_restore是否应该向一个预加载EPICS PV's集合报告它的状态(被包含在数据库save_restoreStatus.db中)。如果这个参数是'0',则将不使用状态PV's。在第一次调用create_xxx_set()前应该调用这个函数。
*/
void save_restoreSet_UseStatusPVs(int ok)
/*
列出当前受到save_restore管理任务的所有保存集。如果(verbose!=0),也列出列出PV's。
*/
void save_restoreShow(int verbose)
/*
在create_xxx_set()前调用,这个函数指定要在request-file名称前添加的路径。无论path是否以'/'结束或者pathsub是否以'/'开始,pathsub(如果存在)将用一个分割'/'添加到path之后(如果存在)。如果结果不是以'/'结尾,则向其末尾添加一个'/'。
通过若干次调用这个例程,你可以指定若干目录来搜索请求文件。将按照set_requestfile_path()调用顺序,搜索目录。如果你没有调用过这个例程,将搜索机器的当前工作目录。如果你调用过它,只在你显式地请求当前目录("./")才搜索它。
*/
int set_requestfile_path(char *path, char *pathsub)
/*
这个函数指定在iocInit过程中在记录初始化前一个要被恢复的保存文件。使用对这个函数的调用,可以指定不限数目的文件。如果文件名以"/"开始,autosave将按指定的使用它;否则,autosave将在前面添加对set_savefilepath()指定的文件路径。第二个参数是可选的。
示例:set_pass0_restoreFile("auto_settingsl.sav","P=xxx:")
*/
int set_pass0_restoreFile(char *save_file, char *macroSubstitutions)
/*
这个函数指定在iocInit过程中在记录初始化前一个要被恢复的保存文件。使用对这个函数的调用,可以指定不限数目的文件。如果文件名以"/"开始,autosave将按指定的使用它;否则,autosave将在前面添加对set_savefilepath()指定的文件路径。第二个参数是可选的。
示例:set_pass1_restoreFile("auto_settingsl.sav","P=xxx:")
*/
int set_pass1_restoreFile(char *save_file, char *macroSubstitutions)
/*
如果已经为请求文件创建了一个保存集,这个函数将更改这个保存文件名称。
*/
int set_savefile_name(char *request_file, char *save_file)
/*
在iocInit()前调用,这个函数指定要在save-file和restore-file名称前添加的路径。
pathsub(如果存在),无论path是否以'/'结束或者pathsub以'/'开始,将用一个分隔'/'添加在path(如果存在)后面。如果结果不是以'/'结尾,将在其后添加一个'/'。
如果save_restore是管理它自己的NFS挂载点,这个函数指定挂载点,如果满足所有其它要求,
调用它将产生一个NFS挂载。如果一个有效NFS挂载已经存在,文件系统将被卸载并且接着用新路径名挂载。这个函数可以在任何时候调用。
*/
int set_savefile_path(char *path, char *pathsub)
/*
设置save_restore任务的优先级。
*/
int set_saveTask_priority(int priority)
用法示例
---------- begin excerpt from st.cmd ----------------------
.
.
.
dbLoadDatabase("$(TOP)/dbd/iocxxxVX.dbd")
iocxxxVX_registerRecordDeviceDriver(pdbbase)
.
.
.
### autoSaveRestore setup
save_restoreSet_Debug(0)
# status-PV prefix, so save_restore can find its status PV's.
save_restoreSet_status_prefix("xxx:")
# ok to restore a save set that had missing values (no CA connection to PV)?
# ok to save a file if some CA connections are bad?
save_restoreSet_IncompleteSetsOk(1)
# In the restore operation, a copy of the save file will be written. The
# file name can look like "auto_settings.sav.bu", and be overwritten every
# reboot, or it can look like "auto_settings.sav_020306-083522" (this is what
# is meant by a dated backup file) and every reboot will write a new copy.
save_restoreSet_DatedBackupFiles(1)
# specify where save files should go
set_savefile_path(startup, "autosave");
## specify where request files can be found
# current directory
set_requestfile_path(startup, "")
# We want to include request files that are stored with the databases they
# support — e.g., in stdApp/Db, mcaApp/Db, etc. The variables std and mca
# are defined in cdCommands. The path is searched in the order in which
# directories are specified.
set_requestfile_path(startup)
set_requestfile_path(std, "stdApp/Db")
set_requestfile_path(motor, "motorApp/Db")
set_requestfile_path(mca, "mcaApp/Db")
set_requestfile_path(ip, "ipApp/Db")
set_requestfile_path(ip330, "ip330App/Db")
# [...]
# Specify what save files should be restored when.
# Up to eight files can be specified for each pass.
set_pass0_restoreFile("auto_positions.sav")
set_pass0_restoreFile("auto_settings.sav")
set_pass1_restoreFile("auto_settings.sav")
set_pass0_restoreFile("info_positions.sav")
set_pass0_restoreFile("info_settings.sav")
set_pass1_restoreFile("info_settings.sav")
# [...]
# Number of sequenced backup files (e.g., 'auto_settings.sav0') to write
save_restoreSet_NumSeqFiles(3)
# Time interval between sequenced backups
save_restoreSet_SeqPeriodInSeconds(600)
# Time between failed .sav-file write and the retry.
save_restoreSet_RetrySeconds(60)
# Ok to retry connecting to PVs whose initial connection attempt failed?
save_restoreSet_CAReconnect(1)
# Time interval in seconds between forced save-file writes. (-1 means forever).
# This is intended to get save files written even if the normal trigger mechanism is broken.
save_restoreSet_CallbackTimeout(-1)
# NFS host name and IP address
save_restoreSet_NFSHost("oxygen", "164.54.52.4")
dbLoadRecords("$(AUTOSAVE)/asApp/Db/save_restoreStatus.db", "P=xxx:")
.
.
.
iocInit
.
.
.
### Start up the save_restore task and tell it what to do.
# The task is actually named "save_restore".
#
# save positions every five seconds
create_monitor_set("auto_positions.req", 5, "P=xxx:")
# save other things every thirty seconds
create_monitor_set("auto_settings.req", 30, "P=xxx:")
# Handle autosave 'commands' contained in loaded databases.
makeAutosaveFiles()
create_monitor_set("info_positions.req", 5, "P=xxx:")
create_monitor_set("info_settings.req", 30, "P=xxx:")
.
.
.
---------- end excerpt from st.cmd ----------------------
边栏推荐
猜你喜欢
随机推荐
hdu1042 N! (large number)
CS231n: 11 Generative Models
Shell编程之循环语句与函数
MySQL:Update高并发下变慢的案例及其涉及的特性
21天学习挑战赛——机器学习01
uniapp parent component uses prop to pass asynchronous data to child components
性能问题从发现到优化一般思路
蒲公英R300A 4G路由器,远程监控PLC教程
2022年6月电子学会考级试卷真题解析(含答案和所有文档下载)
2022年美术生就业前景解析
浅谈C语言简单实现二分查找
视图,索引
精彩来袭!鲲鹏开发者创享日·长沙站来啦
QT With OpenGL(泛光)(Bloom)
This error is reported when the shake database is started. Is there a problem with the configuration?
Laravel 5.8笔记
【761. Special binary sequence】
Shell正则表达式
牛客2022 暑期多校6 B Eezie and Pie(树上差分 + 倍增求第 kth 祖先板子)
OpenSSH生成的私钥如何在putty中使用?