asyn驱动示例-int32driver

驱动程序源代码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

测试客户端界面如下:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值
OSZAR »