EPICS IOC练习1:实现读写外部数据文件

简介:本人对EPICS IOC的开发需求主要是针对device support。作为新手,在大量阅读EPICS的开发手册后,准备做几个小练习来熟悉IOC的开发过程。

练习1:编写device support处理ai和ao记录对外部文件中数据的读写

1 开发过程

1)创建IOC应用程序
  • mkdir RW_test
    cd RW_test
    makeBaseApp.pl -t ioc RW_test
    makeBaseApp.pl -i -t ioc RW_test
2)编写device support文件
  • 进入src目录
    cd RW_testApp/src

  • 编写devai.c用于读取文件数据
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <epicsExport.h>
    #include <devSup.h>
    #include <aiRecord.h>
    #include <recGbl.h>
    #include <dbAccess.h>
    #include <epicsTypes.h>
    #include <alarm.h>  
    
    // 定义设备支持函数原型
    static long init_record(aiRecord *pai);
    static long read_ai(aiRecord *pai);
    
    // 定义设备支持结构
    struct {
        long number;
        DEVSUPFUN report;
        DEVSUPFUN init;
        DEVSUPFUN init_record;
        DEVSUPFUN get_ioint_info;
        DEVSUPFUN read_ai;
        DEVSUPFUN special_linconv;
    } devAiFile = {
        6,
        NULL,
        NULL,
        init_record,
        NULL,
        read_ai,
        NULL
    };
    
    // 初始化记录
    static long init_record(aiRecord *pai) {
        // 检查链接类型是否为INST_IO
        if (pai->inp.type != INST_IO) {
            recGblRecordError(S_db_badField, (void *)pai, "devAiFile (init_record) Illegal INP field");
            return S_db_badField;
        }
    
        // 从INP字段中读取文件路径
        char *filename = pai->inp.value.instio.string;
        pai->dpvt = calloc(1, strlen(filename) + 1);
        if (pai->dpvt == NULL) {
            recGblSetSevr(pai, COMM_ALARM, INVALID_ALARM);
            return -1;
        }
        strcpy(pai->dpvt, filename);
        return 0;
    }
    
    // 读取数据
    static long read_ai(aiRecord *pai) {
        char *filename = (char *)pai->dpvt;
        FILE *file = fopen(filename, "r");
        if (!file) {
            recGblSetSevr(pai, READ_ALARM, INVALID_ALARM);
            return -1;
        }
    
        double value;
        if (fscanf(file, "%lf", &value) != 1) {
            fclose(file);
            recGblSetSevr(pai, READ_ALARM, INVALID_ALARM);
            return -1;
        }
    
        pai->val = value;
        pai->udf = FALSE;
        fclose(file);
    
        return 2; // 新值有效
    }
    
    // 注册设备支持
    epicsExportAddress(dset, devAiFile);
    
    ​

  • 编写devao.c用于写入数据
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <epicsExport.h>
    #include <devSup.h>
    #include <aoRecord.h>
    #include <recGbl.h>
    #include <dbAccess.h>
    #include <epicsTypes.h>
    #include <alarm.h>  
    
    // 定义设备支持函数原型
    static long init_record(aoRecord *pao);
    static long write_ao(aoRecord *pao);
    
    // 定义设备支持结构
    struct {
        long number;
        DEVSUPFUN report;
        DEVSUPFUN init;
        DEVSUPFUN init_record;
        DEVSUPFUN get_ioint_info;
        DEVSUPFUN write_ao;
        DEVSUPFUN special_linconv;
    } devAoFile = {
        6,
        NULL,
        NULL,
        init_record,
        NULL,
        write_ao,
        NULL
    };
      
    // 初始化记录
    static long init_record(aoRecord *pao) {
        // 检查链接类型是否为INST_IO
        if (pao->out.type != INST_IO) {
            recGblRecordError(S_db_badField, (void *)pao, "devAoFile (init_record) Illegal INP field");
            return S_db_badField;
        }
    
        // 从INP字段中读取文件路径
        char *filename = pao->out.value.instio.string;
        pao->dpvt = calloc(1, strlen(filename) + 1);
        if (pao->dpvt == NULL) {
            recGblSetSevr(pao, COMM_ALARM, INVALID_ALARM);
            return -1;
        }
        strcpy(pao->dpvt, filename);
        return 0;
    }
    
    // 读取数据
    static long write_ao(aoRecord *pao) {
        char *filename = (char *)pao->dpvt;
        FILE *file = fopen(filename, "w");
        if (!file) {
            recGblSetSevr(pao, WRITE_ALARM, INVALID_ALARM);
            return -1;
        }
    
        fprintf(file, "%f\n", pao->val);
    
        fclose(file);
    
        return 0;
    }
    
    // 注册设备支持
    epicsExportAddress(dset, devAoFile);
    
    

  • 编写devai.dbd
    device(ai,INST_IO,devAiFile,"devai")
    
  • 编写devao.dbd 
    device(ao, INST_IO, devAoFile, "devao")
  • 编写外部数据文件data.txt

    230
    
  • 修改Makefile文件
    ​# Include dbd files from all support applications:
    RW_test_DBD += devai.dbd
    RW_test_DBD += devao.dbd
    
    RW_test_SRCS += devai.c
    RW_test_SRCS += devao.c
    
    ​
3)编写数据库文件
  • 进入Db目录
    cd ..
    cd Db
    
  • 编写RW_test.db
    record(ai, "devai")
    {   
        field(DESC, "Read File")
        field(DTYP, "devai")
        field(INP, "@/.../RW_test/RW_testApp/src/data.txt")
    }
    
    record(ao, "devao")
    {
        field(DESC, "Write File")
        field(DTYP, "devao")
        field(OUT, "@/.../RW_test/RW_testApp/src/data.txt")
    }
    
  • 修改Makefile文件
    ​DB += RW_test.db
4)退回RW_test目录,执行make
5)编辑和执行启动文件
  • 进入启动文件目录并修改st.cmd的权限
    cd iocBoot/iocRW_test
    chmod +x st.cmd
  • 编辑st.cmd文件
    #!../../bin/linux-x86_64/RW_test
      
    #- You may have to change RW_test to something else
    #- everywhere it appears in this file
    
    < envPaths
    
    cd "${TOP}"
    
    ## Register all support components
    dbLoadDatabase "dbd/RW_test.dbd"
    RW_test_registerRecordDeviceDriver pdbbase
    
    ## Load record instances
    dbLoadRecords("db/RW_test.db","user=user")
    
    cd "${TOP}/iocBoot/${IOC}"
    iocInit
    
    ## Start any sequence programs
    #seq sncxxx,"user=user"
  • 执行st.cmd文件
    ./st.cmd
    
    #!../../bin/linux-x86_64/RW_test
    < envPaths
    epicsEnvSet("IOC","iocRW_test")
    epicsEnvSet("TOP","/HALFT/exer/RW_test")
    epicsEnvSet("EPICS_BASE","/HALFT/EPICS/epics-base-7.0")
    cd "/HALFT/exer/RW_test"
    ## Register all support components
    dbLoadDatabase "dbd/RW_test.dbd"
    RW_test_registerRecordDeviceDriver pdbbase
    ## Load record instances
    dbLoadRecords("db/RW_test.db","user=user")
    cd "/HALFT/exer/RW_test/iocBoot/iocRW_test"
    iocInit
    Starting iocInit
    ############################################################################
    ## EPICS R7.0.7.1-DEV
    ## Rev. 2023-09-25T20:50+0800
    ## Rev. Date build date/time: 
    ############################################################################
    iocRun: All initialization complete
    ## Start any sequence programs
    #seq sncxxx,"user=user"
    epics> dbl
    devai
    devao
    epics> 
    
6)验证是否读写成功 
  • 通过caput向devao写入数据
    命令:
    caput devao 400
    
    输出:
    Old : devao                          0
    New : devao                          400
    
    
  • 通过camonitor监视devao和devai的VAL
    命令:
    camonitor devao devai
    
    输出:
    devao                          2024-05-19 15:39:06.439376 400  
    devai                          2024-05-19 15:39:09.089002 400

  • 41
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值