Ortec974A EPICS IOC程序

这篇具有很好参考价值的文章主要介绍了Ortec974A EPICS IOC程序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Ortec974A设备介绍,请见Ortec -- 974A 四通道100-MHz计时器/计数器_ortec974a_EPICS Technical的博客-CSDN博客

1) 创建一个用户存放这个IOC程序结构的目录:

root@orangepi4-lts:/usr/local/EPICS/program# mkdir ortec974A
root@orangepi4-lts:/usr/local/EPICS/program# cd ortec974A/
root@orangepi4-lts:/usr/local/EPICS/program/ortec974A# ls

2)使用makeBaseApp.pl构建这个IOC程序架构:

root@orangepi4-lts:/usr/local/EPICS/program/ortec974A# makeBaseApp.pl -t ioc ortec974A
root@orangepi4-lts:/usr/local/EPICS/program/ortec974A# makeBaseApp.pl -i -t ioc ortec974A
Using target architecture linux-aarch64 (only one available)
The following applications are available:
    ortec974A
What application should the IOC(s) boot?
The default uses the IOC's name, even if not listed above.
Application name?
root@orangepi4-lts:/usr/local/EPICS/program/ortec974A# ls
configure  iocBoot  Makefile  ortec974AApp

3)编辑configure/RELEASE文件,添加这个IOC程序所需要的其它依赖模块:

...
SUPPORT=/usr/local/EPICS/synApps/support
ASYN=$(SUPPORT)/asyn
AUTOSAVE=$(SUPPORT)/autosave
CALC=$(SUPPORT)/calc
SCALER=$(SUPPORT)/scaler
...

4) 进入源文件目录ortec974AApp/src目录下:

a) 编写974A驱动程序源文件:

// drvOrtec974A.cpp
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>
#include <math.h>

#include <asynPortDriver.h>
#include <asynOctetSyncIO.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <epicsTime.h>
#include <errlog.h>
#include <iocsh.h>
#include <epicsExport.h> /* Defines epicsExportSharedSymbols */

#include "devScalerAsyn.h"

#define MAX_CHANNELS 4

#define timeOut 0.1
static const char *driverName= "Scaler974A";

class Scaler974A:public asynPortDriver
{
public:
    Scaler974A(const char *portName, const char *serialPort, int serialAddr, int poll);
    virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
    virtual asynStatus readInt32Array(asynUser *pasynUser,epicsInt32 *value, size_t nElements, size_t *nIn);
    virtual void report(FILE *fp, int details);
    void eventThread();

private:
    int scalerReset;
    int scalerChannels;
    int scalerRead;
    int scalerReadSingle;
    int scalerPreset;
    int scalerArm;
    int scalerDone;
    double polltime;
    epicsEventId eventId;
    asynUser *pasynUserScaler;
    asynStatus sendCommand(const char *command, char *statusString, size_t maxStatusLen, size_t *statusLen);
};

static void eventThreadC(void *pPvt)
{
    Scaler974A *pScaler974A = (Scaler974A *)pPvt;
    pScaler974A->eventThread();
}

Scaler974A::Scaler974A(const char *portName, const char *serialPort, int serialAddr, int poll)
    :asynPortDriver(portName, MAX_CHANNELS,
                    asynInt32Mask | asynInt32ArrayMask | asynDrvUserMask,
                    asynInt32Mask,
                    /* Should also be ASYN_CANBLOCK, but device support does not work with asynchronous devices */
                    ASYN_MULTIDEVICE,1,0,0)
{
    int i;
    asynStatus status;
    static const char *functionName="Scaler974A";

    if (poll==0) poll=100;
    this->polltime=poll / 1000.;
    this->eventId = epicsEventCreate(epicsEventEmpty);
    status = pasynOctetSyncIO->connect(serialPort, serialAddr, &this->pasynUserScaler, NULL);
    if (status != asynSuccess) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s: error connecting to port %s address %d\n",
            driverName, functionName, serialPort, serialAddr);
        return;
    }

    createParam(SCALER_RESET_COMMAND_STRING,        asynParamInt32,     &this->scalerReset);
    createParam(SCALER_CHANNELS_COMMAND_STRING,     asynParamInt32,     &this->scalerChannels);
    createParam(SCALER_READ_COMMAND_STRING,         asynParamInt32Array,&this->scalerRead);
    createParam(SCALER_READ_SINGLE_COMMAND_STRING,  asynParamInt32,     &this->scalerReadSingle);
    createParam(SCALER_PRESET_COMMAND_STRING,       asynParamInt32,     &this->scalerPreset);
    createParam(SCALER_ARM_COMMAND_STRING,          asynParamInt32,     &this->scalerArm);
    createParam(SCALER_DONE_COMMAND_STRING,         asynParamInt32,     &this->scalerDone);

    setIntegerParam(scalerChannels, MAX_CHANNELS);
    setIntegerParam(scalerDone, 1);
    for (i=0; i<MAX_CHANNELS; i++) setIntegerParam(i, scalerReadSingle, 0);

    epicsThreadCreate("Scaler974A",
                      epicsThreadPriorityMedium,
                      epicsThreadGetStackSize(epicsThreadStackMedium),
                      (EPICSTHREADFUNC)eventThreadC,this);
}


asynStatus Scaler974A::sendCommand(const char *command, char *statusString, size_t maxStatusLen, size_t *statusLen)
{
    size_t nWrite;
    asynStatus status;
    double timeout = 1.0;
    int eomReason;
    static const char *functionName = "sendCommand";

/*
 * asynStatus (*writeRead)(asynUser *pasynUser,
                  const char *write_buffer, size_t write_buffer_len,
                  char *read_buffer, size_t read_buffer_len,
                  double timeout,
                  size_t *nbytesOut, size_t *nbytesIn, int *eomReason);
                  要写的字符串,要写的字符串长度,读出缓存,要读的字节数目,超时时间,实际写出的字节数,实际读入的字符数,结束原因

                  asynStatus (*write)(asynUser *pasynUser,  char const *buffer, size_t buffer_len,
                  double timeout,size_t *nbytesTransfered);

                    asynStatus (*read)(asynUser *pasynUser, char *buffer, size_t buffer_len,
                  double timeout, size_t *nbytesTransfered,int *eomReason);
 *
 * */
        status = pasynOctetSyncIO->write(this->pasynUserScaler, command, strlen(command),  timeout, &nWrite);
//      printf("In sendCommand write status: %d,write content:%s,write length:%d\n", status, command, nWrite);
        if (status != asynSuccess) goto done;

        epicsThreadSleep(.1);

        status = pasynOctetSyncIO->read(this->pasynUserScaler,statusString, maxStatusLen, timeout, statusLen, &eomReason);
//      printf("In sendCommand read status: %d, statusString:%s\n", status, statusString);

    done:
    if (status != asynSuccess) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                  "%s:%s: writing command %s, error=%s\n",
                  driverName, functionName, command, this->pasynUserScaler->errorMessage);
    }
    return(status);
}

asynStatus Scaler974A::writeInt32(asynUser *pasynUser, epicsInt32 value)
{
    int function = pasynUser->reason;
    char response[256];
    size_t responseLen;
    asynStatus status = asynSuccess;

    static const char *functionName="writeInt32";
    setIntegerParam(function, value);

    if(function==this->scalerReset)
    {
        this->sendCommand("STOP\r", response, sizeof(response), &responseLen);
        //printf("STOP:%s\n", response);
        this->sendCommand("CLEAR_ALL\r", response, sizeof(response), &responseLen);
        //printf("CLEAR_ALL:%s\n", response);
        asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s:%s scalerReset\n",driverName, functionName);
    }
    else if(function==this->scalerArm)
    {
        if(value !=0)
        {
                /* Start counting */
            this->sendCommand("START\r", response, sizeof(response), &responseLen);
//          printf("START:%s\n", response);
            setIntegerParam(scalerDone, 0);
            epicsEventSignal(this->eventId);
        }
        else
        {
                /* Stop counting */
            status = this->sendCommand("STOP\r", response, sizeof(response), &responseLen);
//          printf("STOP:%s\n", response);
            setIntegerParam(scalerDone, 1);
        }
        asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s:%s scalerArm=%d\n", driverName, functionName,value);
    }
    else if(function==this->scalerPreset)
    {
        int m,n;
        char newstr[25];

        n=(int)log10(double(value));
        m=(int)(value/pow(10.0,n));

        sprintf(newstr, "SET_COUNT_PRESET %d,%d\r", m, n);
        this->sendCommand(newstr, response, sizeof(response), &responseLen);
//      printf("SET_COUNT_PRESET:%s\n", response);

        asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s;%s scalerPreset channel", driverName, functionName);
    }
    else
    {
        asynPrint(pasynUser,ASYN_TRACE_ERROR,"%s:%s got illegal function %d\n", driverName, functionName, function);
    }
    callParamCallbacks();
    return(status);
}

asynStatus Scaler974A::readInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t maxChannel, size_t *nIn)
{
    static const char *functionName="readInt32Array";
    int function = pasynUser->reason;
    int temp;
    int i;

    if (maxChannel > MAX_CHANNELS) maxChannel = MAX_CHANNELS;
    *nIn = maxChannel;

    if (function==scalerRead)
    {
        for (i=0; i<(int)maxChannel; i++)
        {
            getIntegerParam(i, scalerReadSingle, &temp);
            value[i] = temp;
        }
        asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
            "%s:%s: value=%d %d %d %d\n",
            driverName, functionName, value[0], value[1], value[2], value[3]);
    } else {
        asynPrint(pasynUser,ASYN_TRACE_ERROR,"%s:%s got illegal function %d\n", driverName, functionName,  function);
        return(asynError);
    }
    return(asynSuccess);
}

void Scaler974A::report(FILE *fp, int details)
{
    asynPortDriver::report(fp, details);
}

void Scaler974A::eventThread()
{
    int done, presetCount;
    char response[100], statusString[256];
    size_t responseLen, statusLen;
    int counts[MAX_CHANNELS];
    int i;
    asynStatus status;
    static const char *functionName="eventThread";

    while(1)
    {
        epicsEventMustWait(this->eventId);
        while(1)
        {
            status = this->sendCommand("SHOW_COUNTS\r", statusString, sizeof(statusString), &statusLen);

            sscanf(statusString, "%d;%d;%d;%d;",
                   &counts[0], &counts[1], &counts[2], &counts[3]);
//          printf("%d;%d;%d;%d\n", counts[0],counts[1],counts[2],counts[3]);
            asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
                "%s:%s status=%d, counts=%d %d %d %d\n",
                driverName, functionName, status, counts[0], counts[1], counts[2], counts[3]);
            this->lock();
            /* Get value of done in case scaler was stopped by scalerArm(0) */
            getIntegerParam(scalerDone, &done);
            getIntegerParam(scalerPreset, &presetCount);
            if (!done && (counts[0] >= presetCount)) done = 1;
            setIntegerParam(scalerDone, done);
            for (i=0; i<MAX_CHANNELS; i++) {
                setIntegerParam(i, scalerReadSingle, counts[i]);
                callParamCallbacks(i, i);
            }
            this->unlock();
            if (done) break;
            epicsThreadSleep(this->polltime/1000.0);
        }
    }
}

extern "C" int initScaler974A(const char *portName, const char *serialPort, int serialAddr, int poll)
{
    new Scaler974A(portName, serialPort, serialAddr, poll);
    return(asynSuccess);
}

/* iocsh function */
static const iocshArg initArg0 = {"Port Name", iocshArgString};
static const iocshArg initArg1 = {"IPPort", iocshArgString};
static const iocshArg initArg2 = {"Addr", iocshArgString};
static const iocshArg initArg3 = {"Poll", iocshArgInt};
static const iocshArg *const initArgs[] = {&initArg0,
                                           &initArg1,
                                           &initArg2,
                                           &initArg3
                                          };
static const iocshFuncDef initFuncDef = {"initScaler974A",4, initArgs};
static void initCallFunc(const iocshArgBuf *args)
{
    initScaler974A(args[0].sval, args[1].sval, args[2].ival, args[3].ival);
}

void Scaler974ARegister(void)
{
    iocshRegister(&initFuncDef,initCallFunc);
}

extern "C" {
epicsExportRegistrar(Scaler974ARegister);
}

b) 添加一个dbd文件ortec974ASupport.dbd:

registrar(Scaler974ARegister)

c) 修改同一目录下Makefile文件,指定编译中需要包含的库文件和源文件:

TOP=../..

include $(TOP)/configure/CONFIG
#----------------------------------------
#  ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================

#=============================
# Build the IOC application

PROD_IOC = ortec974A
# ortec974A.dbd will be created and installed
DBD += ortec974A.dbd

# ortec974A.dbd will be made up from these files:
ortec974A_DBD += base.dbd
ortec974A_DBD += ortec974ASupport.dbd

# Include dbd files from all support applications:
#ortec974A_DBD += xxx.dbd

ortec974A_DBD += drvAsynIPPort.dbd
ortec974A_DBD += asyn.dbd
ortec974A_DBD += scalerSupport.dbd
ortec974A_DBD += calcSupport.dbd
ortec974A_DBD += asSupport.dbd


# Include dbd files from all support applications:
#ortec974A_DBD += xxx.dbd

# Add all the support libraries needed by this IOC
ortec974A_LIBS += asyn
ortec974A_LIBS += scaler
ortec974A_LIBS += calc
ortec974A_LIBS += autosave

# Add all the support libraries needed by this IOC
#ortec974A_LIBS += xxx

ortec974A_SRCS += drvOrtec974A.cpp
# ortec974A_registerRecordDeviceDriver.cpp derives from ortec974A.dbd
ortec974A_SRCS += ortec974A_registerRecordDeviceDriver.cpp

# Build the main IOC entry point on workstation OSs.
ortec974A_SRCS_DEFAULT += ortec974AMain.cpp
ortec974A_SRCS_vxWorks += -nil-

# Add support from base/src/vxWorks if needed
#ortec974A_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary

# Finally link to the EPICS Base libraries
ortec974A_LIBS += $(EPICS_BASE_IOC_LIBS)

#===========================

include $(TOP)/configure/RULES
#----------------------------------------
#  ADD RULES AFTER THIS LINE

5) 进入ortec974AApp/Db目录,编写一个用于自动保存的文件scaler4_settings.req:

$(P)$(S).TP
$(P)$(S).TP1
$(P)$(S).CONT
$(P)$(S).DLY1
$(P)$(S).RAT1
$(P)$(S).PREC
$(P)$(S).FREQ
$(P)$(S).RATE
$(P)$(S).DLY
$(P)$(S).COUT
file "scaler_channelN_settings.req", P=$(P), S=$(S), Ch=1
file "scaler_channelN_settings.req", P=$(P), S=$(S), Ch=2
file "scaler_channelN_settings.req", P=$(P), S=$(S), Ch=3
file "scaler_channelN_settings.req", P=$(P), S=$(S), Ch=4

在同一目录下的Makefile中添加一行:DB += scaler4_settings.req

6) 退出到这个IOC的顶层目录,执行make进行程序编译。

7)进入到启动目录iocBoot/iocortec974A,创建两个目录:

root@orangepi4-lts:/usr/local/EPICS/program/ortec974A/iocBoot/iocortec974A# mkdir -p req/ortec974A
root@orangepi4-lts:/usr/local/EPICS/program/ortec974A/iocBoot/iocortec974A# mkdir -p autosave/ortec974A

在req/ortec974A下编写一个用于自动保存的文件auto_settings.req,内容如下:

file scaler4_settings.req  P=$(P) S=$(S)

编写启动脚本:

#!../../bin/linux-aarch64/ortec974A

#- You may have to change ortec974A to something else
#- everywhere it appears in this file

< envPaths

cd "${TOP}"

## Register all support components
dbLoadDatabase "dbd/ortec974A.dbd"
ortec974A_registerRecordDeviceDriver pdbbase

drvAsynIPPortConfigure("ortec974A", "192.168.3.30:4001", 0, 0 ,1)

initScaler974A("tcportec974A","ortec974A",0,10)
dbLoadRecords("${SCALER}/db/scaler.db", "P=Ortec974A:,S=Scaler1,OUT=@asyn(tcportec974A 0 0),DTYP=Asyn Scaler,FREQ=10,TP=1,TP1=0.5,PR1=1,CONT=1")


set_requestfile_path("$(TOP)/db")
set_requestfile_path("$(SCALER)/db")
set_requestfile_path("$(TOP)/iocBoot/$(IOC)/req/ortec974A")

# 通过调用set_savefile_path函数指定你想要.sav文件被写到哪个目录中。
set_savefile_path("$(TOP)/iocBoot/$(IOC)/autosave/ortec974A")

# 使用set_pass<N>_restoreFile()函数
# 指定哪些save文件要在记录初始化前(pass 0)前被恢复,以及哪些save文件在记录初始化后(pass 1)被恢复
set_pass1_restoreFile("auto_settings.sav")

save_restoreSet_numSeqFiles(3)
save_restoreSet_SeqPeriodInSeconds(600)
save_restoreSet_RetrySeconds(60)
save_restoreSet_CAReconnect(1)
save_restoreSet_CallbackTimeout(-1)

dbLoadRecords("$(ASYN)/db/asynRecord.db","P=Ortec974A:Scaler1:,R=Asyn,PORT=ortec974A,ADDR=0,IMAX=100,OMAX=100")


cd "${TOP}/iocBoot/${IOC}"
iocInit

create_monitor_set("auto_settings.req",5,"P=Ortec974A:,S=Scaler1")

8) 用以上启动脚本启动这个IOC程序:

root@orangepi4-lts:/usr/local/EPICS/program/ortec974A/iocBoot/iocortec974A# ../../bin/linux-aarch64/ortec974A st.cmd

9)查看这个IOC加载的记录:

epics> dbl
Ortec974A:Scaler1:Asyn
Ortec974A:Scaler1

10) 用CSS编写操作客户端:

Ortec974A EPICS IOC程序,EPICS教程,Linux C,EPICS,C语言,linux11) 在97A的3号输入端口接入一个3MHz的TTL信号,将计数时间设置为1.0秒,点击Count按钮,进行1秒钟计数:

Ortec974A EPICS IOC程序,EPICS教程,Linux C,EPICS,C语言,linux

通道3能够读出计数器的正确计数值。 文章来源地址https://www.toymoban.com/news/detail-715124.html

到了这里,关于Ortec974A EPICS IOC程序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux从入门到精通】C语言模拟实现进度条小程序

        在Linux下,我们安装软件时会经常看到进度条,来告知我们安装的进度。我们不妨自己模拟实现一个进度条,看看其中的细节。模拟实现进度条并不困难,但其中的细节我们又不可忽视。 本篇文章会对模拟实现进度条进行详解 。 文章目录 一、进度条整体模板 二、输出缓

    2024年02月03日
    浏览(38)
  • Kali Linux 安装搭建 hadoop 平台 调用 wordcount 示例程序 详细教程

    目标: *安装虚拟机,在自己虚拟机上完成hadoop的伪分布式安装。(安装完成后要检查)* 安装SSH Server服务器:apt-get install openssh-server 更改默认的SSH密钥 cd /etc/ssh mkdir ssh_key_backup mv ssh_host_* ssh_key_backup 创建新密钥:dpkg-reconfigure openssh-server 允许 SSH Root 访问,修改SSH 配置文件

    2024年02月04日
    浏览(40)
  • C语言/C++随机数生成,程序运行时间计时器(含高精度计时器),包括Windows环境与Linux环境

      🎊【数据结构与算法】专题正在持续更新中,各种数据结构的创建原理与运用✨,经典算法的解析✨都在这儿,欢迎大家前往订阅本专题,获取更多详细信息哦🎏🎏🎏 🪔本系列专栏 -  数据结构与算法_勾栏听曲_0 🍻欢迎大家  🏹  点赞👍  评论📨  收藏⭐️ 📌个人

    2023年04月26日
    浏览(50)
  • EPICS synApps SSCAN模块

    1)代码 sscan记录 busy记录 recDynLink库 saveData数据存储客户端 scanparm记录 2)EPICS数据库 scan数据库 scanParms和alignParms数据库 3)MEDM显示窗口 scan*.adl scan*_help.adl 1) 一维扫描 a) 进行NPTS次 设置条件:例如,移动电机;等待结束 触发探测器:例如:启动计数器;等待结束 采集数据:

    2023年04月11日
    浏览(20)
  • Linux教程||Linux 系统启动过程

    linux启动时我们会看到许多启动信息。 Linux系统的启动过程并不是大家想象中的那么复杂,其过程可以分为5个阶段: 内核的引导。 运行init。 系统初始化。 建立终端 。 用户登录系统。 当计算机打开电源后,首先是BIOS开机自检,按照BIOS中设置的启动设备(通常是硬盘)来启

    2024年02月09日
    浏览(67)
  • EPICS libCom库(7) -- epicsString.h

    epicsString.h当前描述了:  1) int epicsStrnRawFromEscaped(char *dst, size_t dstlen, const char *src, size_t srclen); epicsStrnRawFromEscaped从字符串src最多复制strlen个字符到尺寸dstlen的缓存dst中,转换C风格转义序列为它们的二进制形式。一个zero字节终结输入字符串。只要dstlen非零,产生的字符串将是

    2024年02月11日
    浏览(21)
  • Linux教程——Linux命令基本格式(详解版)

    从这里开始,我们不会再见到图形界面了,因为对服务器来讲,图形界面会占用更多的系统资源,而且会安装更多的服务、开放更多的端口,这对服务器的稳定性和安全性都有负面影响。其实,服务器是一个连显示器都没有的家伙,要图形界面干十么? 说到这里,有很多人会

    2024年02月09日
    浏览(40)
  • Linux教程——常见Linux发行版本有哪些?

    新手往往会被 Linux 众多的发行版本搞得一头雾水,我们首先来解释一下这个问题。 从技术上来说,李纳斯•托瓦兹开发的 Linux 只是一个内核。内核指的是一个提供设备驱动、文件系统、进程管理、网络通信等功能的系统软件,内核并不是一套完整的操作系统,它只是操作系

    2024年02月08日
    浏览(37)
  • Linux入门教程||Linux文件基本属性

    Linux系统是一种典型的多用户系统,不同的用户处于不同的地位,拥有不同的权限。为了保护系统的安全性,Linux系统对不同的用户访问同一文件(包括目录文件)的权限做了不同的规定。 在Linux中我们可以使用 ll 或者 ls –l 命令来显示一个文件的属性以及文件所属的用户和

    2024年02月08日
    浏览(46)
  • Linux教程——Linux tar打包命令详解

    Linux 系统中,最常用的归档(打包)命令就是 tar,该命令可以将许多文件一起保存到一个单独的磁带或磁盘中进行归档。不仅如此,该命令还可以从归档文件中还原所需文件,也就是打包的反过程,称为解打包。 使用 tar 命令归档的包通常称为 tar 包(tar 包文件都是以“.t

    2024年02月12日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包