• EPICS自定义设备支持--longin记录的异步设备支持编写


    本例展示如何编写一个异步设备支持例程。它进程了以下操作顺序:

    • 1、第一次被调用时,PACT是FALSE。它安排一个回调(longinCallback)例程,在由DISV字段指定的秒数后,它被调用。
    • 2、它打印一条声明那个proecssing已经开始的消息,设置PACT为TRUE,并且返回。记录processing例程不等结束这个processing而返回。
    • 3、当指定的时间用尽时,longinCallback被调用。它调用dbScanLock锁定这个记录,调用process并且调用dbScanUnlock解锁这个记录。它直接调用记录支持模块的process条目,它通过dbCommon中RSET字段找到process,而不是调用dbProcess。
    • 4、当process执行时,它再次调用read_longin。这时PACT是TRUE。
    • 5、read_longin打印一条声明processing结束并且返回一个0状态。
    • 6、当read_longin返回时,记录processing例程结束记录运行。

    到此,记录已经完全被运行了。下次运行一切从头开始。注意,由于这种形式的代码更可能使用callbackRequestProcessCallbackDelayed来执行所需的processing,这是某种程度上人为设计的示例。

    一般回调任务的使用请参考:CSDN讲解。

    1)创建一个目录lidriver用于保存这个IOC目录结构,并且使用makeBaseApp.pl脚本创建这个IOC应用程序目录结构和启动目录:

    1. root@orangepi5:/usr/local/EPICS/program/liasynchronous# ls
    2. configure iocBoot liadrvierApp Makefile

    2)进入lidriverApp/src目录,编写设备支持源文件以及对应的支持文件,并且编辑对应目录下的Makefile文件:

    a) devLiA.c

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include "alarm.h"
    7. #include "callback.h"
    8. #include "dbScan.h"
    9. #include "dbDefs.h"
    10. #include "dbAccess.h"
    11. #include "recGbl.h"
    12. #include "devSup.h"
    13. #include "longinRecord.h"
    14. #include "epicsExport.h"
    15. static void longinCallback(CALLBACK * pcallback)
    16. {
    17. dbCommon * precord;
    18. struct rset * prset;
    19. callbackGetUser(precord, pcallback);
    20. prset = (struct rset *)(precord->rset);
    21. dbScanLock(precord);
    22. (* prset->process)(precord);
    23. dbScanUnlock(precord);
    24. }
    25. static long init_record(dbCommon *pcommon);
    26. static long read_longin(longinRecord *prec);
    27. longindset devLiA = {
    28. {5, NULL, NULL, init_record, NULL},
    29. read_longin
    30. };
    31. epicsExportAddress(dset, devLiA);
    32. static long init_record(dbCommon *pcommon)
    33. {
    34. longinRecord *prec = (longinRecord *)pcommon;
    35. CALLBACK * pcallback;
    36. if (prec->inp.type != CONSTANT){
    37. recGblRecordError(S_db_badField, prec, "devLiA(init_record)illegal INP field");
    38. return S_db_badField;
    39. }
    40. pcallback = (CALLBACK *)(calloc(1, sizeof(CALLBACK)));
    41. callbackSetCallback(longinCallback, pcallback);
    42. callbackSetUser(prec, pcallback);
    43. prec->dpvt = pcallback;
    44. return 0;
    45. }
    46. static long readLocked(struct link *pinp, void *dummy)
    47. {
    48. longinRecord *prec = (longinRecord *) pinp->precord;
    49. long status = 0;
    50. int i;
    51. CALLBACK * pcallback = (CALLBACK *)prec->dpvt;
    52. if (prec->pact){
    53. i = prec->val + 1;
    54. if (i > prec->hihi){
    55. prec->val = prec->lolo;
    56. }
    57. else{
    58. prec->val = i;
    59. }
    60. prec->udf = FALSE;
    61. printf("Completed asynchronous processing: %s\n", prec->name);
    62. if (dbLinkIsConstant(&prec->tsel) &&
    63. prec->tse == epicsTimeEventDeviceTime)
    64. dbGetTimeStamp(pinp, &prec->time);
    65. return 0;
    66. }
    67. printf("Starting asynchronous processing: %s\n", prec->name);
    68. prec->pact = TRUE;
    69. callbackRequestDelayed(pcallback, prec->disv);
    70. return status;
    71. }
    72. static long read_longin(longinRecord *prec)
    73. {
    74. long status = dbLinkDoLocked(&prec->inp, readLocked, NULL);
    75. if (status == S_db_noLSET)
    76. status = readLocked(&prec->inp, NULL);
    77. return status;
    78. }

    b) devLiA.dbd

    device(longin, CONSTANT, devLiA, "Asynchronous")

    c) 将以上两个文件名添加到相同目录下的Makefile文件中

    1. ...
    2. liadrvier_DBD += devLiA.dbd
    3. liadrvier_SRCS += devLiA.c
    4. ...

    3)  在idriverApp/Db文件下,增加一个数据库实例文件longinA.db,并且编辑此路径下的Makefile文件:

    a)longinA.db

    1. record(longin, "$(P):LiA")
    2. {
    3. field(DESC, "Asynchronous Test")
    4. field(DTYP, "Asynchronous")
    5. field(PINI, "1")
    6. field(DISV, "2")
    7. field(INP, "0")
    8. field(HIHI, "50")
    9. field(LOLO, "0")
    10. }

    b)将上面的文件名添加到Makefile中

    1. ...
    2. DB += longinA.db
    3. ...

    4) 回到这个IOC的顶层目录liasynchronous ,执行make进行编译。

    5)进入启动目录iocBoot/iocliasynchronous,编译启动脚本st.cmd:

    1. #!../../bin/linux-aarch64/liadrvier
    2. #- You may have to change liadrvier to something else
    3. #- everywhere it appears in this file
    4. < envPaths
    5. cd "${TOP}"
    6. ## Register all support components
    7. dbLoadDatabase "dbd/liadrvier.dbd"
    8. liadrvier_registerRecordDeviceDriver pdbbase
    9. ## Load record instances
    10. dbLoadRecords("db/longinA.db","P=Test")
    11. cd "${TOP}/iocBoot/${IOC}"
    12. iocInit

    6)启动这个IOC,用dbl查看加载的记录实例:

    1. root@orangepi5:/usr/local/EPICS/program/liasynchronous/iocBoot/iocliadrvier# ../../bin/linux-aarch64/liadrvier st.cmd
    2. #!../../bin/linux-aarch64/liadrvier
    3. ...
    4. ############################################################################
    5. ## EPICS R7.0.7
    6. ## Rev. 2023-05-26T09:07+0000
    7. ## Rev. Date build date/time:
    8. ############################################################################
    9. Starting asynchronous processing: Test:LiA
    10. iocRun: All initialization complete
    11. epics> dbl
    12. Test:LiA

    7) 用通道访问命令测试:

    1. [blctrl@main-machine ~]$ caput Test:LiA 10; date ;camonitor Test:LiA
    2. Old : Test:LiA 1
    3. New : Test:LiA 10
    4. Thu Aug 31 00:46:41 EDT 2023
    5. Test:LiA 2023-08-31 00:45:31.597635 10
    6. Test:LiA 2023-08-31 00:46:43.158043 11

    在发出通道访问写命令后,Test:LiA记录值更新为10,2秒后,发生回调,修改记录值为11。

  • 相关阅读:
    正则基础入门学习
    教你如何通过内网穿透轻松实现PL/SQL远程连接Oracle数据库【内网穿透】
    C#8.0本质论第六章--类
    怎么下载微信视频号视频?
    【小程序】中WXS的语法详解
    vs如何读取mysql中的数据(顺便通过代码解决了中文乱码问题)
    C++14读写锁demo-读写操作都在子线程中
    【Golang星辰图】Go语言云计算SDK全攻略:深入Go云存储SDK实践
    [极致用户体验] 我做的《联机五子棋》是如何追求极致用户体验的?(上)
    MR案例 - 求年度最高气温
  • 原文地址:https://blog.csdn.net/yuyuyuliang00/article/details/132598685