asyn驱动示例-int32driver

news2024/11/26 7:31:00

驱动程序源代码int32Driver.c:

#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ctype.h>

#include <cantProceed.h>
#include <epicsStdio.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <epicsThread.h>
#include <iocsh.h>

#include <asynDriver.h>
#include <asynDrvUser.h>
#include <asynInt32.h>
#include <asynFloat64.h>

#include <epicsExport.h>

#define NCHANNELS   4           //设备支持4个通道

//#define DEBUG

typedef struct chanPvt{         //通道的结构体
    epicsInt32  value;
    void        *asynInt32Pvt;  //?每个通
}chanPvt;

// 端口驱动使用的结构体
typedef struct int32drvPvt{
    const char      *portName;          //端口名
    epicsMutexId    lock;               //访问端口中channel和interruptDelay成员时需要锁定这个互斥锁
    epicsEventId    waitWork;           //interruptThread线程等待运行的事件
    int             connected;          //端口是否连接
    double          interruptDelay;     //interruptThread线程运行间隙
    asynInterface   ifCommon;           //支持asynCommon接口
    asynInterface   ifDrvUser;          //支持asynDrvUser接口
    asynInterface   ifInt32;            //支持asynInt32接口
    asynInterface   ifFloat64;          //支持asynFloat64接口
    epicsInt32      low;                //通道值下限
    epicsInt32      high;               //通道值上限
    void            *asynInt32Pvt;      //用于asynInt32中断
    void            *asynFloat64Pvt;    //用于asynFloat64中断
    chanPvt         channel[NCHANNELS]; //通道结构体数组
}int32drvPvt;

/* 端口驱动程序的初始化 */
static int int32DriverInit(const char* dn, int low, int high, double delay);
/* 获取地址 */
static asynStatus getAddr(int32drvPvt *pint32drvPvt, asynUser *pasynUser,
                        int *paddr, int portOK);
/* 中断线程运行的程序 */
static void interruptThread(void *drvPvt);

/* asynCommon接口方法 */
static void report(void *drvPvt, FILE *fp, int details);
static asynStatus connect(void *drvPvt, asynUser *pasynUser);
static asynStatus disconnect(void *drvPvt, asynUser *pasynUser);
static asynCommon common = {report, connect, disconnect};

/* asynDrvUser接口方法 */
static asynStatus create(void *drvPvt, asynUser *pasynUser,
                const char *drvInfo, const char **pptypeName, size_t *psize);
static asynStatus getType(void *drvPvt, asynUser *pasynUser,
                const char **pptypeName, size_t *psize);
static asynStatus destroy(void *drvPvt, asynUser *pasynUser);
static asynDrvUser drvUser = {create, getType, destroy};

/* asynInt32接口方法*/
static asynStatus int32Write(void *drvPvt, asynUser *pasynUser, epicsInt32 value);
static asynStatus int32Read(void *drvPvt, asynUser *pasynUser, epicsInt32 *value);
static asynStatus int32GetBounds(void *drvPvt, asynUser *pasynUser, epicsInt32 *low, epicsInt32 *high);

/* asynFloat64接口方法*/
static asynStatus float64Write(void *drvPvt, asynUser *pasynUser, epicsFloat64 value);
static asynStatus float64Read(void *drvPvt, asynUser *pasynUser, epicsFloat64 *value);


static int int32DriverInit(const char* dn, int low, int high, double delay)
{
    int32drvPvt     *pint32drvPvt;
    char            *portName;
    asynStatus      status;
    size_t          nbytes;
    int             addr;
    asynInt32       *pasynInt32;
    asynFloat64     *pasynFloat64;

    /* 计算整个驱动专用数据所需的空间:int32drvPvt结构体+asynInt32结构体+asynFloat64结构体+端口名称字符串*/
    nbytes          = sizeof(int32drvPvt) + sizeof(asynInt32) + sizeof(asynFloat64);
    nbytes          += strlen(dn) + 1;
    /* 分配结构体空间 */
    pint32drvPvt    = callocMustSucceed(nbytes, sizeof(char), "int32DriverInit");
    /* asynInt32接口结构体的首地址 */
    pasynInt32      = (asynInt32 *)(pint32drvPvt + 1);
    /* asynFloat64接口结构体的首地址 */
    pasynFloat64    = (asynFloat64 *)(pasynInt32 + 1);
    /* 端口名称首地址 */
    portName        = (char *)(pasynFloat64 + 1);
    /* 复制字符串 */
    strcpy(portName, dn);

    pint32drvPvt->portName = portName;
    pint32drvPvt->lock = epicsMutexCreate();
    pint32drvPvt->waitWork = epicsEventCreate(epicsEventEmpty);

    /* 对应asynCommon的asynInterface结构体赋值*/
    pint32drvPvt->ifCommon.interfaceType = asynCommonType;
    pint32drvPvt->ifCommon.pinterface = (void *)&common;
    pint32drvPvt->ifCommon.drvPvt = (void *)pint32drvPvt;

    /* 对应asynDrvUser的asynInterface结构体赋值*/
    pint32drvPvt->ifDrvUser.interfaceType = asynDrvUserType;
    pint32drvPvt->ifDrvUser.pinterface = (void *)&drvUser;
    pint32drvPvt->ifDrvUser.drvPvt = (void *)pint32drvPvt;

    pint32drvPvt->low   = low;
    pint32drvPvt->high  = high;
    /* 
        注册一个端口程序:多设备,可阻塞,并且自动连接 
            这个方法被驱动调用。为每个端口实例进行一次调用。attriubtes是一个位集合。当前定义了两个位: ASYN_MULTIDEVICE 和 ASYN_CANBLOCK.
            驱动必须正确地指定这些。autoconnect其(0,1)对应(no, yes), 为端口和连接此端口地所有设备提供初始值。仅在ASYN_CANBLOCK=1时priority和stacksize才有作用
            在此种情况下,asynManager用epicsThreadCreate()创建这个端口时使用这些值。
            如果priority 为 0,将分配默认值epicsThreadPriorityMedium
            如果stackSize 为0, 将分配默认值 epicsThreadGetStackSize(epicsThreadStackMedium)
            portName参数指定了了名称,asyn代码的上层通过这个名称指向这个通信接口实例。
            registerPort方法对name参数指向的字符串进行内部复制。
            asynStatus registerPort(const char *portName,
                              int attributes,int autoConnect,
                              unsigned int priority,unsigned int stackSize);
    */
    status = pasynManager->registerPort(portName, ASYN_MULTIDEVICE | ASYN_CANBLOCK, 1, 0, 0);
    if (status != asynSuccess){
        printf("int32DriverInit:registerPort failed\n");
        return 0;
    }

    /* 注册支持的接口asynCommon 
        端口驱动为每个支持的接口调用这个方法。
            此方法不会复制这个asynInterface到pasynInterface参数指向的位置。
            调用者必须在一个位置存储这个asynInterface,并且为这个端口的生命周期维护这个位置。
            通常通过在'driver private'结构体中放置这个asynInterface结构体做这件事
            asynStatus  registerInterface(const char *portName,
                              asynInterface *pasynInterface);
    */
    status = pasynManager->registerInterface(portName, &pint32drvPvt->ifCommon);
    if (status != asynSuccess){
        printf("int32DriverInit:registerInterface:asynCommon failed\n");
        return 0;
    }

    /* 注册支持的接口asynDrvUser */
    status = pasynManager->registerInterface(portName, &pint32drvPvt->ifDrvUser);
    if (status != asynSuccess){
        printf("int32DriverInit:registerInterface:asynDrvUser failed\n");
        return 0;
    }

    /* 设置asynInt32接口 */
    pasynInt32->write   = int32Write;
    pasynInt32->read    = int32Read;
    pasynInt32->getBounds  = int32GetBounds;
    pint32drvPvt->ifInt32.interfaceType = asynInt32Type;
    pint32drvPvt->ifInt32.pinterface    = pasynInt32;
    pint32drvPvt->ifInt32.drvPvt        = pint32drvPvt;
    status = pasynInt32Base->initialize(portName, &pint32drvPvt->ifInt32);
    if (status != asynSuccess){
        printf("int32DriverInit:pasynIn32Base->initialize failed\n");
        return 0;
    }

    /* 设置asynFloat64接口 */
    pasynFloat64->write = float64Write;
    pasynFloat64->read  = float64Read;
    pint32drvPvt->ifFloat64.interfaceType   = asynFloat64Type;
    pint32drvPvt->ifFloat64.pinterface      = pasynFloat64;
    pint32drvPvt->ifFloat64.drvPvt          = pint32drvPvt;
    status = pasynFloat64Base->initialize(portName, &pint32drvPvt->ifFloat64);
    if (status != asynSuccess){
        printf("int32DriverInit:pasynFloat64Base->initialize failed\n");
        return 0;
    }

    // 模拟中断延时
    pint32drvPvt->interruptDelay = delay;
    // 设置通道结构体初始值
    for (addr = 0; addr < NCHANNELS; addr++){
        pint32drvPvt->channel[addr].value = pint32drvPvt->low + addr;
    }

    // 为asynInt32接口注册中断源
    status = pasynManager->registerInterruptSource(portName, &pint32drvPvt->ifInt32,
            &pint32drvPvt->asynInt32Pvt);
    if (status != asynSuccess){
        printf("int32DriverInit:registerInterruptSource for asynInt32 failed");
        return 0;
    }
    // 为asynFloat64接口注册中断源
    status = pasynManager->registerInterruptSource(portName, &pint32drvPvt->ifFloat64,
            &pint32drvPvt->asynFloat64Pvt);
    if (status != asynSuccess){
        printf("int32DriverInit:registerInterruptSource for asynFloat64 failed");
        return 0;
    }
#ifdef DEBUG
    printf("structure int32drvPvt to  start the interruptThread\n");
#endif
    epicsThreadCreate("int32Driver", epicsThreadPriorityHigh,
                epicsThreadGetStackSize(epicsThreadStackSmall),
                (EPICSTHREADFUNC)interruptThread, (void *)pint32drvPvt);

#ifdef DEBUG
    printf("structure int32drvPvt started the interruptThread\n");
#endif

    if (pint32drvPvt->interruptDelay >= 0.01){
        epicsEventSignal(pint32drvPvt->waitWork);
    }
    
    return 0;
}

/*
    获取地址, 如果portOK不为0,则地址有效范围-1<=addr<NCHANNELS,
    如果portOK为0,地址有效范围地址有效范围0<=addr<NCHANNELS
*/
static asynStatus getAddr(int32drvPvt *pint32drvPvt, asynUser *pasynUser, int *paddr, int portOK)
{
    asynStatus status;

    status = pasynManager->getAddr(pasynUser, paddr);
    if (status != asynSuccess) return status;

    if (portOK != 0){
        if (*paddr >= -1 && *paddr < NCHANNELS) return asynSuccess;
    }
    else{
        if (*paddr >= 0 && *paddr < NCHANNELS) return asynSuccess;
    }

    asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s addr %d is illegal; Must be >= %d and < %d\n",
          pint32drvPvt->portName, *paddr, (portOK ? -1: 0), NCHANNELS);
    epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
        "%s addr %d is illegal; Must be >= %d and < %d",
          pint32drvPvt->portName, *paddr, (portOK ?-1:0), NCHANNELS);
    return asynError;
}


/* asynCommon:report 显示端口是否连接,中断延时时间以及端口连接情况下,每个通道中的值 */
static void report(void *drvPvt, FILE *fp, int details)
{
    int32drvPvt *pint32drvPvt = (int32drvPvt *)drvPvt;
    int addr;

    fprintf(fp, "   int32Driver: connected: %s interrputDelay:%.2f\n",
            (pint32drvPvt->connected ? "Yes" : "No"),
             pint32drvPvt->interruptDelay);

    if (pint32drvPvt->connected){
        for (addr = 0; addr < NCHANNELS; addr++){
            fprintf(fp, "addr:%d value:%d\n", addr, pint32drvPvt->channel[addr].value);
        }
    }
}
/* asynCommon:connect  */
static asynStatus connect(void *drvPvt,  asynUser *pasynUser)
{
    int32drvPvt *pint32drvPvt = (int32drvPvt *)drvPvt;
    int         addr;
    asynStatus  status;

    status = getAddr(pint32drvPvt, pasynUser, &addr, 1);
    if (status != asynSuccess){
        asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:int32Driver:connect getAddr failed\n", pint32drvPvt->portName);
        return status;
    }

    if (addr >= 0 && addr < NCHANNELS){
        pasynManager->exceptionConnect(pasynUser);
        return asynSuccess;
    }

    if (pint32drvPvt->connected){
        asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:int32Driver port already connected\n", pint32drvPvt->portName);
        return asynError;
    }

    pint32drvPvt->connected = 1;
    pasynManager->exceptionConnect(pasynUser);

    return asynSuccess;
}

/* asynCommon:disconnect */
static asynStatus disconnect(void *drvPvt, asynUser *pasynUser)
{
    int32drvPvt *pint32drvPvt = (int32drvPvt *)drvPvt;
    int addr;
    asynStatus status;

    status = getAddr(pint32drvPvt, pasynUser, &addr, 1);
    if (status != asynSuccess){
        asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:int32Driver:disconnect getAddr failed\n", pint32drvPvt->portName);
        return status;
    }
    asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s:int32Driver:disconnect addr %d\n", pint32drvPvt->portName, addr);

    if (addr >= 0 && addr < NCHANNELS){
        pasynManager->exceptionDisconnect(pasynUser);
        return asynSuccess;
    }

    if (!pint32drvPvt->connected){
        asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s int32Driver:disconnect port not connected\n",
            pint32drvPvt->portName);
        return asynError;
    }

    pint32drvPvt->connected = 0;
    pasynManager->exceptionDisconnect(pasynUser);
    return asynSuccess;
}

static asynStatus int32Write(void *drvPvt, asynUser *pasynUser, epicsInt32 value)
{
    int32drvPvt     *pint32drvPvt = (int32drvPvt *)drvPvt;
    int             addr;
    ELLLIST         *pclientList;
    asynStatus      status;
    interruptNode   *pnode;
    asynInt32Interrupt      *pinterrupt;

    status = getAddr(pint32drvPvt,  pasynUser,  &addr, 0);
    if (status != asynSuccess){
        asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s:int32Driver:int32Write:getAddr failed\n", pint32drvPvt->portName);
        return status;
    }

    asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s int32Driver:int32Write value %d to addr %d\n", pint32drvPvt->portName, value, addr);

    if (!pint32drvPvt->connected){
        asynPrint(pasynUser, ASYN_TRACE_ERROR,
                "%s int32Driver:int32Write port not connected\n", pint32drvPvt->portName);
        epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
            "%s int32Driver:int32Write port not connected", pint32drvPvt->portName);
        return asynError;
    }

    epicsMutexMustLock(pint32drvPvt->lock);
    pint32drvPvt->channel[addr].value = value;
    epicsMutexUnlock(pint32drvPvt->lock);

    asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
            "%s int32Driver addr %d write %d\n", pint32drvPvt->portName, addr, value);


    printf("int32Write start interrupt ...\n");
    pasynManager->interruptStart(pint32drvPvt->asynInt32Pvt, &pclientList);
    pnode = (interruptNode *)ellFirst(pclientList);
    while (pnode){
        pinterrupt = pnode->drvPvt;

        if (pinterrupt->addr == addr){
           pinterrupt->callback(pinterrupt->userPvt, pinterrupt->pasynUser,
                 pint32drvPvt->channel[addr].value);
        }
        pnode = (interruptNode *)ellNext(&pnode->node);
    }

    pasynManager->interruptEnd(pint32drvPvt->asynInt32Pvt);
    printf("int32Write finish interrupt ...\n");

    return asynSuccess;
}


static asynStatus int32Read(void *drvPvt, asynUser *pasynUser, epicsInt32 *value)
{
    int32drvPvt * pint32drvPvt = (int32drvPvt *)drvPvt;
    int         addr;
    asynStatus status;

    status = getAddr(pint32drvPvt, pasynUser, &addr, 0);
    if (status != asynSuccess) return status;

    asynPrint(pasynUser, ASYN_TRACE_FLOW,
            "%s int32Driver:readInt32 value from addr %d\n", pint32drvPvt->portName, addr);

    if (!pint32drvPvt->connected){
        asynPrint(pasynUser, ASYN_TRACE_ERROR,
            "%s int32Driver:readInt32 port not connected\n", pint32drvPvt->portName);
        epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
            "%s int32Driver:readInt32 port not connected", pint32drvPvt->portName);
        return asynError;
    }

    epicsMutexMustLock(pint32drvPvt->lock);
    * value = pint32drvPvt->channel[addr].value;
    epicsMutexUnlock(pint32drvPvt->lock);

    return asynSuccess;
}

static asynStatus int32GetBounds(void *drvPvt, asynUser *pasynUser,
                                epicsInt32 *low, epicsInt32 *high)
{
    int32drvPvt *pint32drvPvt = (int32drvPvt *)drvPvt;

    *low = pint32drvPvt->low;
    *high = pint32drvPvt->high;

    asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s int32Driver:int32GetBounds low %d high %d\n",
            pint32drvPvt->portName, *low, *high);

    return asynSuccess;
}

static asynStatus float64Write(void *drvPvt, asynUser *pasynUser, epicsFloat64 value)
{
    int32drvPvt *pint32drvPvt = (int32drvPvt *)drvPvt;
    int         addr;
    asynStatus  status;
    ELLLIST     *pclientList;
    interruptNode *pnode;
    asynFloat64Interrupt *pinterrupt;
    double oldvalue;

    status = getAddr(pint32drvPvt, pasynUser, &addr, 0);
    if (status != asynSuccess) return status;

    epicsMutexMustLock(pint32drvPvt->lock);
    oldvalue = pint32drvPvt->interruptDelay;
    pint32drvPvt->interruptDelay = value;
    epicsMutexUnlock(pint32drvPvt->lock);

    asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
            "%s int32Driver:float64Write %f\n", pint32drvPvt->portName, value);

    if (!pint32drvPvt->connected){
        asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s int32Driver:float64Write port not connected\n", pint32drvPvt->portName);
        epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s int32Driver:float64Write port not connected", pint32drvPvt->portName);
        return asynError;
    }

    if (oldvalue < 0.01 && value >= 0.01){
        epicsEventSignal(pint32drvPvt->waitWork);
    }

    pasynManager->interruptStart(pint32drvPvt->asynFloat64Pvt, &pclientList);
    pnode = (interruptNode *)ellFirst(pclientList);

    while (pnode){
        pinterrupt = pnode->drvPvt;
        if (addr == pinterrupt->addr && pinterrupt->pasynUser->reason == 1){
            pinterrupt->callback(pinterrupt->userPvt, pinterrupt->pasynUser, value);
            break;
        }
        pnode = (interruptNode *)ellNext(&pnode->node);
    }

    pasynManager->interruptEnd(pint32drvPvt->asynFloat64Pvt);

    return asynSuccess;
}

static asynStatus float64Read(void *drvPvt, asynUser *pasynUser, epicsFloat64 *value)
{
    int32drvPvt *pint32drvPvt = (int32drvPvt *)drvPvt;
    int     addr;
    asynStatus status;

    status = getAddr(pint32drvPvt, pasynUser, &addr, 0);
    if (status != asynSuccess) return status;

    asynPrint(pasynUser, ASYN_TRACE_FLOW,
                "%s int32Driver:float64Read\n", pint32drvPvt->portName);

    if (!pint32drvPvt->connected){
        asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s int32Driver:float64Read port not connected\n", pint32drvPvt->portName);
        epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s int32Driver:float64Read port not connected", pint32drvPvt->portName);
        return asynError;
    }

    epicsMutexMustLock(pint32drvPvt->lock);
    *value = pint32drvPvt->interruptDelay;
    epicsMutexUnlock(pint32drvPvt->lock);

    asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
            "%s int32Driver:float64Read %f value\n",
            pint32drvPvt->portName, *value);

    return asynSuccess;
}

static void interruptThread(void *drvPvt)
{
    int         addr;
    epicsInt32  value;
    ELLLIST     *pclientList;
    interruptNode *pnode;
    asynInt32Interrupt  *pinterrupt;

    int32drvPvt *pint32drvPvt = (int32drvPvt *)drvPvt;

    printf("In interruptThread\n");
    while(1){
#ifdef DEBUG
        printf("wait for the event: waitWork");
#endif
        epicsEventMustWait(pint32drvPvt->waitWork);
#ifdef DEBUG
        printf("get the  event :waitWork");
#endif
        while (1){
#ifdef DEBUG
            printf("to change the values of channels\n");
#endif
            if (pint32drvPvt->interruptDelay <= 0.001) break;
            for (addr = 0; addr < NCHANNELS; addr++){
                chanPvt *pchannel = &pint32drvPvt->channel[addr];
                epicsMutexMustLock(pint32drvPvt->lock);
                value = pchannel->value;
                if (value >= pint32drvPvt->high){
                    value = pint32drvPvt->low;
                }
                else{
                    value++;
                }

                pchannel->value = value;
                epicsMutexUnlock(pint32drvPvt->lock);
            }
#ifdef DEBUG
            printf("changed the values of channels\n");
#endif
            pasynManager->interruptStart(pint32drvPvt->asynInt32Pvt, &pclientList);
            pnode = (interruptNode *)ellFirst(pclientList);

            while (pnode){
                pinterrupt = pnode->drvPvt;
                addr = pinterrupt->addr;
                pinterrupt->callback(pinterrupt->userPvt, pinterrupt->pasynUser,
                            pint32drvPvt->channel[addr].value);
                pnode = (interruptNode *)ellNext(&pnode->node);
            }
            pasynManager->interruptEnd(pint32drvPvt->asynInt32Pvt);
            epicsThreadSleep(pint32drvPvt->interruptDelay);
        }
    }
}

static const char *testDriverReason = "testDriverReason";
static const char *skipWhite(const char *pstart)
{
    const char * p = pstart;
    while (*p && isspace((int)*p)) p++;

    return p;
}

//static asynStatus create(void *drvPvt, asynUser *pasynUser, const char *drvInfo, const char **pptypeName, size_t *psize)
static asynStatus create(void *drvPvt, asynUser *pasynUser,
                const char *drvInfo, const char **pptypeName, size_t *psize)
{
    const char *pnext;
    long reason = 0;

    if (!drvInfo){
        reason = 0;
     }
    else{
        char *endp;

        pnext = skipWhite(drvInfo);
        if (strlen(pnext) == 0){
            reason = 0;
        }
        else{
            pnext = strstr(pnext, "reason");
            if (!pnext) goto error;
            pnext += strlen("reason");
            pnext = skipWhite(pnext);
            if (*pnext!='(') goto error;
            pnext++;
            pnext = skipWhite(pnext);
            errno = 0;
            reason = strtol(pnext, &endp, 0);

            if (errno){
                printf("strtol failed %s\n", strerror(errno));
                goto error;
            }
        }
        pasynUser->reason = reason;
        if (pptypeName) *pptypeName = testDriverReason;
        if (psize) *psize = sizeof(int);

        return asynSuccess;
    }
error:
    printf("asynDrvUser failed. got |%s| expecting reason(<int>)\n", drvInfo);
    epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
                "asynDrvUser failed. got |%s| expecting reason(<int>\n)", drvInfo);

    return asynError;
}

static asynStatus getType(void *drvPvt, asynUser * pasynUser, const char **pptypeName, size_t *psize)
{
    *pptypeName = testDriverReason;
    *psize = sizeof(int);
    return asynSuccess;
}

static asynStatus destroy(void *drvPvt, asynUser *pasynUser)
{
    return asynSuccess;
}

static const iocshArg int32DriverInitArg0 = {"portName", iocshArgString};
static const iocshArg int32DriverInitArg1 = {"low", iocshArgInt};
static const iocshArg int32DriverInitArg2 = {"high",iocshArgInt};
static const iocshArg int32DriverInitArg3 = {"delay",iocshArgDouble};
static const iocshArg *int32DriverInitArgs[] = {
    &int32DriverInitArg0, &int32DriverInitArg1, &int32DriverInitArg2,&int32DriverInitArg3
};

static const iocshFuncDef int32DriverInitFuncDef = {
    "int32DriverInit", 4, int32DriverInitArgs
};
static void int32DriverInitCallFunc(const iocshArgBuf *args)
{
    int32DriverInit(args[0].sval, args[1].ival, args[2].ival, args[3].dval);
}

static void int32DriverRegister(void)
{
    static int firstTime = 1;

    if (firstTime){
        firstTime = 0;
        iocshRegister(&int32DriverInitFuncDef, int32DriverInitCallFunc);
    }
}

epicsExportRegistrar(int32DriverRegister);

数据库文件如下int32.db:

record(ao,"$(P)$(R)SetRateInt32") {
     field(DTYP,"asynFloat64")
     field(OUT,"@asyn($(PORT),0,1.0) reason(1)")
     field(PREC,"1")
}

record(ai, "$(P)$(R)SetRateInt32_RBV")
{
    field(DTYP,"asynFloat64")
    field(SCAN,"I/O Intr")
    field(INP,"@asyn($(PORT)  , 0 , 1.0)reason(1)")
    field(PREC,"1")
}

record(ao,"$(P)$(R)AO$(N)") {
    field(DTYP,"asynInt32")
    field(OUT,"@asyn($(PORT),$(N),1.0) ")
    field(LINR,"LINEAR")
    field(EGUF,"100.0")
    field(EGUL,"-100.0")
    field(PREC,"3")
}

record(ai,"$(P)$(R)AI$(N)") {
    field(SCAN,"I/O Intr")
    field(DTYP,"asynInt32")
    field(INP,"@asyn($(PORT)  , $(N) , 1.0) ")
    field(LINR,"LINEAR")
    field(EGUF,"100.0")
    field(EGUL,"-100.0")
    field(PREC,"3")
}

record(longout,"$(P)$(R)LoInt32_$(N)") {
    field(DTYP,"asynInt32")
    field(OUT,"@asyn($(PORT),$(N),1.0)")
}

record(mbbo,"$(P)$(R)MbboInt32_$(N)") {
    field(DTYP,"asynInt32")
    field(OUT,"@asyn($(PORT),$(N),1.0) ")
    field(NOBT,"4")
    field(SHFT,"0")
    field(ZRST,"zero")
    field(ONST,"one")
    field(TWST,"two")
    field(THST,"three")
    field(FRST,"four")
    field(FVST,"five")
    field(SXST,"six")
    field(SVST,"seven")
    field(EIST,"eight")
    field(NIST,"nine")
    field(TEST,"ten")
    field(ELST,"eleven")
    field(TVST,"twelve")
    field(TTST,"thirteen")
    field(FTST,"fourteen")
    field(FFST,"fifteen")
    field(ZRVL,"0x0")
    field(ONVL,"0x1")
    field(TWVL,"0x2")
    field(THVL,"0x3")
    field(FRVL,"0x4")
    field(FVVL,"0x5")
    field(SXVL,"0x6")
    field(SVVL,"0x7")
    field(EIVL,"0x8")
    field(NIVL,"0x9")
    field(TEVL,"0xa")
    field(ELVL,"0xb")
    field(TVVL,"0xc")
    field(TTVL,"0xd")
    field(FTVL,"0xe")
    field(FFVL,"0xf")
}
record(longin,"$(P)$(R)LiInt32_$(N)") {
    field(SCAN,"I/O Intr")
    field(DTYP,"asynInt32")
    field(INP,"@asyn($(PORT),$(N),1.0)")
}

record(mbbi,"$(P)$(R)MbbiInt32_$(N)") {
    field(SCAN,"I/O Intr")
    field(DTYP,"asynInt32")
    field(INP,"@asyn($(PORT), $(N),1.0) ")
    field(NOBT,"4")
    field(SHFT,"0")
    field(ZRST,"zero")
    field(ONST,"one")
    field(TWST,"two")
    field(THST,"three")
    field(FRST,"four")
    field(FVST,"five")
    field(SXST,"six")
    field(SVST,"seven")
    field(EIST,"eight")
    field(NIST,"nine")
    field(TEST,"ten")
    field(ELST,"eleven")
    field(TVST,"twelve")
    field(TTST,"thirteen")
    field(FTST,"fourteen")
    field(FFST,"fifteen")
    field(ZRVL,"0x0")
    field(ONVL,"0x1")
    field(TWVL,"0x2")
    field(THVL,"0x3")
    field(FRVL,"0x4")
    field(FVVL,"0x5")
    field(SXVL,"0x6")
    field(SVVL,"0x7")
    field(EIVL,"0x8")
    field(NIVL,"0x9")
    field(TEVL,"0xa")
    field(ELVL,"0xb")
    field(TVVL,"0xc")
    field(TTVL,"0xd")
    field(FTVL,"0xe")
    field(FFVL,"0xf")
}

启动脚本如下:

#!../../bin/linux-x86_64/intDriver

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

< envPaths

cd "${TOP}"

## Register all support components
dbLoadDatabase "dbd/intDriver.dbd"
intDriver_registerRecordDeviceDriver pdbbase
int32DriverInit("INT32", 0, 16, 0.5)

## Load record instances
dbLoadRecords("db/int32.db","P=ASYN:,R=INT32:,N=0,PORT=INT32")
dbLoadRecords("db/int32.db","P=ASYN:,R=INT32:,N=1,PORT=INT32")
dbLoadRecords("db/int32.db","P=ASYN:,R=INT32:,N=2,PORT=INT32")
dbLoadRecords("db/int32.db","P=ASYN:,R=INT32:,N=3,PORT=INT32")
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=ASYN:,R=INT32, PORT=INT32, ADDR=0,OMAX=0,IMAX=0")

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

测试客户端界面如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2219811.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

官龙村捐赠图书整理有感

今天&#xff08;2024年10月20日&#xff09;&#xff0c;我有幸参加了在深圳南山区西丽官龙村举行的义工活动&#xff0c;主要任务是整理捐赠的图书&#xff0c;并根据小学和中学的需求进行分类打包。这次活动不仅让我体会到了劳动的辛苦&#xff0c;更让我感受到了助人为乐的…

【AIGC】第一性原理下的ChatGPT提示词Prompt设计:系统信息与用户信息的深度融合

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;第一性原理与ChatGPT提示词Prompt设计应用第一性原理于ChatGPT提示词Prompt设计系统信息和用户信息的融合实际应用结论 &#x1f4af;系统信息与用户信息的定义和重要性系…

鸿蒙中富文本编辑与展示

富文本在鸿蒙系统如何展示和编辑的&#xff1f;在文章开头我们提出这个疑问&#xff0c;带着疑问来阅读这篇文章。 富文本用途可以展示图文混排的内容&#xff0c;在日常App 中非常常见&#xff0c;比如微博的发布与展示&#xff0c;朋友圈的发布与展示&#xff0c;都在使用富文…

C++高阶:红黑树实现

目录 一.红黑树的概念 1.1红黑树的规则 1.2红黑树的效率 二.红黑树的实现 2.1红黑树的结构 2.2红黑树的插入 2.2.1插入的大致过程 2.2.2情况一&#xff1a;变色 ​编辑 2.2.3情况二&#xff1a;单旋变色 2.2.4情况三&#xff1a;双旋变色 2.3插入代码实现 2.4红黑树的…

【网络安全】简单P1:通过开发者工具解锁专业版和企业版功能

未经许可,不得转载。 文章目录 前言发现过程前言 在探索一个SaaS平台的过程中,我发现了一个漏洞,使得我能够在无需订阅的情况下解锁高级(专业/企业)功能。 发现过程 我使用一个没有任何高级功能的基本用户账户进行常规登录。在浏览平台时,我注意到某些按钮和功能上带有…

【C++STL】list的基本介绍与使用方式

✨ Blog’s 主页: 白乐天_ξ( ✿&#xff1e;◡❛) &#x1f308; 个人Motto&#xff1a;他强任他强&#xff0c;清风拂山冈&#xff01; &#x1f525; 所属专栏&#xff1a;C深入学习笔记 &#x1f4ab; 欢迎来到我的学习笔记&#xff01; 一、list的介绍 文档内容以及大致翻…

ROS笔记之kill掉所有ros节点rosnode

ROS笔记之kill掉所有ros节点rosnode 文章目录 ROS笔记之kill掉所有ros节点rosnode1. 杀死所有 ROS 节点&#xff08;不包括 rosmaster&#xff09;2. 杀死 rosmaster3. 验证所有节点和 rosmaster 是否已终止4. roscore 和 rosmaster 是同一个概念吗&#xff1f;5. 为什么执行 k…

【踩坑日记36】ModuleNotFoundError: No module named ‘taming‘

问题描述 ModuleNotFoundError: No module named ‘taming‘问题分析 未正确安装taming-transformers包 问题解决 从github网站中安装taming-transformers包&#xff1a; 从github网站中下载taming-transformers代码 git clone https://github.com/CompVis/taming-transfo…

微机原理与接口技术知识点总结——绪论

1.1、计算机发展概述 早期计算机的用途主要是用于算数&#xff0c;一直到20世纪电子领域基础研究的突破&#xff0c;也就是电子计算机的诞生&#xff0c;计算机才变得如此广泛。以微电子技术为基础制造的电子计算机已经完全取代了机械计算机和机电计算机&#xff0c;因此电子计…

第二十二届GOPS全球运维大会2024一日感

第二十二届GOPS全球运维大会将于2024年4月25-26日在南山区深圳湾万丽酒店召开。大会将为期2天&#xff0c;侧重大模型、AIOps、DevOps、可观测、SRE、云原生等热门技术领域。 GOPS是我一直关注的一场技术峰会&#xff0c;主要是它的侧重点在运维方面&#xff0c;这和我本身的职…

【C++干货篇】——类和对象的魅力(二)

【C干货篇】——类和对象的魅力&#xff08;二&#xff09; 1.类的默认成员函数 默认成员函数就是用户没有显式实现&#xff0c;编译器会⾃动⽣成的成员函数称为默认成员函数。 ⼀个类&#xff0c;我们不写的情况下编译器会默认⽣成以下6个默认成员函数&#xff0c;需要注意的…

从 Microsoft 官网下载 Windows 10

方法一&#xff1a; 打开 Microsoft 官网&#xff1a; 打开开发人员工具&#xff08;按 F12 或右键点击“检查”&#xff09;。 点击“电脑模拟手机”按钮&#xff0c;即下图&#xff1a; 点击后重新加载此网页&#xff0c;即可看到下载选项。

[k8s理论知识]3.docker基础(二)隔离技术

容器其实是一种沙盒技术&#xff0c;其核心是通过约束和修改进程的动态表现&#xff0c;为其创建一个边界。这个边界确保了应用与应用之间不会相互干扰&#xff0c;同时可以方便在不同的环境中迁移&#xff0c;这是PaaS最理想的状态。 程序是代码的可执行镜像&#xff0c;通常…

springboot项目get请求遇到:Message Request header is too large报错。

一、错误日志 HTTP Status 400 – Bad Request Type Exception ReportMessage Request header is too largeDescription The server cannot or will not process the request due to something that is perceived to be a client error (e.g., malformed request syntax, inva…

Django学习-ORM_常用字段及字段选项

字段选项&#xff1a; 注意&#xff1a;当我们新增数据的时候&#xff0c;如果没有新增设置了default的字段&#xff0c;此时会使用default设置的默认值填充到新增的数据中

数字后端零基础入门系列 | Innovus零基础LAB学习Day2

今天开始更新数字IC后端设计实现中Innovus零基础Lab学习后续内容。 数字后端零基础入门系列 | Innovus零基础LAB学习Day1 ####LAB5-2 这个章节的目标也很明确——学习掌握工具的一些常用快捷键。 这里只需要掌握以下几个快捷键即可。其他小编我也不会&#xff0c;也用不着。…

【初识数据库】

目录 一、数据库简介 1.什么是数据库 2.数据库与数据结构有啥关系 3.为什么要使用数据库 二、数据库服务器、数据库和表的关系 三、客户端与服务器的通讯方式 1.C/S架构 2.B/S架构 3.命令提示符 4.MySQL架构 一、数据库简介 1.什么是数据库 组织和保存数据的应用程序…

【JavaEE初阶】深入理解网络编程—使用UDP协议API实现回显服务器

前言 &#x1f31f;&#x1f31f;本期讲解关于TCP/UDP协议的原理理解~~~ &#x1f308;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 &#x1f525; 你的点赞就是小编不断更新的最大动力 &#x1f386;那么废话不…

centors7安装docker启动ubuntu

在centors上升级glibc为2.18&#xff0c;使用yum最新源直接安装不行&#xff0c;使用源码安装还不行&#xff0c;因为必须使用2.18版本glic&#xff0c;采用先安装docker&#xff0c;在启动新的Ubuntu&#xff0c;在ubuntu里配置自己的环境 1. centors安装docker 查看docker的…

专业学习|马尔可夫链(概念、变体以及例题)

一、马尔可夫链的概念及组成 &#xff08;一&#xff09;学习资料分享 来源&#xff1a;024-一张图&#xff0c;但讲懂马尔可夫决策过程_哔哩哔哩_bilibili 马尔可夫链提供了一种建模随机过程的方法&#xff0c;具有广泛的应用。在实际问题中&#xff0c;通过转移概率矩阵及初…