Ortec974A EPICS IOC程序

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 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include  /* 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; iwrite(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; iunlock();
            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_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程序_第1张图片11) 在97A的3号输入端口接入一个3MHz的TTL信号,将计数时间设置为1.0秒,点击Count按钮,进行1秒钟计数:

Ortec974A EPICS IOC程序_第2张图片

通道3能够读出计数器的正确计数值。 

你可能感兴趣的:(EPICS教程,Linux,C,EPICS,C语言,linux)