驱动程序源代码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
测试客户端界面如下: