1、asynStandardInterfacesBase
asynStandardInterfacesBase是一个接口,用于使得在一个端口驱动程序初始化例程中必须被编写的代码量最少,这个端口驱动程序使用以上描述的标准asyn基于消息或基于寄存器的接口。没有asynStandardInterfacesBase,一个端口驱动程序需要为它支持的每个接口调用asynRegisterInterface(),以及可能地asynRegisterInterruptSource(),并且处理在这些调用中可能发生的任何错误。它也需要在其drvPvt结构体中为每个接口显式地包含若干字段。asynStandardInterfaceBase提供了一个接口,它允许端口驱动程序在其drvPvt结构体中包含一个结构体,并且在这个结构体中定义值。它接着调用一个函数来注册它支持的所有接口,并且注册其自身为那些接口中一个或多个接口上的一个中断源。这可以减少驱动程序初始化例程中代码行数为四分之一或者更多。
asynStandardInterfaces结构体
以下是asynStandardInterfaces结构体的定义。驱动程序通常在它们的drvPvt结构体中包含一个这种类型的结构体。当创建drvPvt时,如果这个结构体被初始化为全零,则所有所必需的是(在接口的.pinterfacee字段中)填入每个受支持接口的地址,并且为那些是中断源的接口设置CanInterrupt标记为1。
typedef struct asynStandardInterfaces {
asynInterface common;
asynInterface drvUser;
asynInterface option;
asynInterface octet;
int octetProcessEosIn;
int octetProcessEosOut;
int octetInterruptProcess;
int octetCanInterrupt;
void *octetInterruptPvt;
asynInterface uInt32Digital;
int uInt32DigitalCanInterrupt;
void *uInt32DigitalInterruptPvt;
asynInterface int32;
int int32CanInterrupt;
void *int32InterruptPvt;
asynInterface int64;
int int64CanInterrupt;
void *int64InterruptPvt;
asynInterface float64;
int float64CanInterrupt;
void *float64InterruptPvt;
asynInterface int8Array;
int int8ArrayCanInterrupt;
void *int8ArrayInterruptPvt;
asynInterface int16Array;
int int16ArrayCanInterrupt;
void *int16ArrayInterruptPvt;
asynInterface int32Array;
int int32ArrayCanInterrupt;
void *int32ArrayInterruptPvt;
asynInterface int64Array;
int int64ArrayCanInterrupt;
void *int64ArrayInterruptPvt;
asynInterface float32Array;
int float32ArrayCanInterrupt;
void *float32ArrayInterruptPvt;
asynInterface float64Array;
int float64ArrayCanInterrupt;
void *float64ArrayInterruptPvt;
asynInterface genericPointer;
int genericPointerCanInterrupt;
void *genericPointerInterruptPvt;
asynInterface Enum;
int enumCanInterrupt;
void *enumInterruptPvt;
} asynStandardInterfaces;
asynStandardInterfacesBase接口
以下是asynStandardInterfaceBase接口的定义。
typedef struct asynStandardInterfacesBase {
asynStatus (*initialize)(const char *portName, asynStandardInterfaces *pInterfaces,
asynUser *pasynUser, void *pPvt);
} asynStandardInterfacesBase;
epicsShareExtern asynStandardInterfacesBase *pasynStandardInterfacesBase;
asynStandardInterfaceBase只有一个方法initiliaze(),为在其.pinterface字段中有非NULL值的每个接口调用registerInterface或Base->initialize。它也为被定义好以及设置CanInterrput标记设为1的接口调用registerInterruptSource。传给initialize()方法的pasynUser参数只用于为这个方法提供返回一条错误消息(在pasynUser->errorMessage中)的位置,因此当这个方法返回时,进行调用的例程可以再次使用或者释放这个asynUser结构体。
以下是一个在使用这个asynStandardInterfaceBase接口的端口驱动程序中所需代码的示例。
#include <asynStandardInterfaces.h>
...
typedef struct drvADPvt {
...
/* 这个驱动程序实现的asyn接口 */
asynStandardInterfaces asynStdInterfaces;
/* 为了asynTrace连接到我们自己的asynUser */
asynUser *pasynUser;
...
} drvADPvt;
...
/* 每个asyn接口的函数指针的结构体*/
static asynCommon ifaceCommon = {
report,
connect,
disconnect
};
static asynInt32 ifaceInt32 = {
writeInt32,
readInt32,
getBounds
};
static asynInt64 ifaceInt64 = {
writeInt64,
readInt64,
getBounds
};
static asynFloat64 ifaceFloat64 = {
writeFloat64,
readFloat64
};
static asynOctet ifaceOctet = {
writeOctet,
NULL,
readOctet,
};
static asynDrvUser ifaceDrvUser = {
drvUserCreate,
drvUserGetType,
drvUserDestroy
};
static asynGenericPointer ifaceGenericPointer = {
writeADImage,
readADImage
};
...
int simDetectorConfig(const char *portName, int maxSizeX, int maxSizeY, int dataType)
{
drvADPvt *pPvt;
int status = asynSuccess;
char *functionName = "simDetectorConfig";
asynStandardInterfaces *pInterfaces;
pPvt = callocMustSucceed(1, sizeof(*pPvt), functionName);
pPvt->portName = epicsStrDup(portName);
status = pasynManager->registerPort(portName,
ASYN_MULTIDEVICE | ASYN_CANBLOCK,
1, /* autoconnect */
0, /* medium priority */
0); /* default stack size */
if (status != asynSuccess) {
printf("%s ERROR: Can't register port\n", functionName);
return(asynError);
}
/* Create asynUser for debugging */
pPvt->pasynUser = pasynManager->createAsynUser(0, 0);
pInterfaces = &pPvt->asynStdInterfaces;
/* Initialize interface pointers */
pInterfaces->common.pinterface = (void *)&ifaceCommon;
pInterfaces->drvUser.pinterface = (void *)&ifaceDrvUser;
pInterfaces->octet.pinterface = (void *)&ifaceOctet;
pInterfaces->int32.pinterface = (void *)&ifaceInt32;
pInterfaces->int64.pinterface = (void *)&ifaceInt64;
pInterfaces->float64.pinterface = (void *)&ifaceFloat64;
pInterfaces->genericPointer.pinterface = (void *)&ifaceGenericPointer;
/* Define which interfaces can generate interrupts */
pInterfaces->octetCanInterrupt = 1;
pInterfaces->int32CanInterrupt = 1;
pInterfaces->int64CanInterrupt = 1;
pInterfaces->float64CanInterrupt = 1;
pInterfaces->genericPointerCanInterrupt = 1;
status = pasynStandardInterfacesBase->initialize(portName, pInterfaces,
pPvt->pasynUser, pPvt);
if (status != asynSuccess) {
printf("%s ERROR: Can't register interfaces: %s.\n",
functionName, pPvt->pasynUser->errorMessage);
return(asynError);
}
...
}
二、标准Interpose接口
1) asynInterposeEos
如果端口驱动程序不提供EOS支持,这可以用于为asynOctet模拟EOS运行。如果指定了一个EOS,它在每个读入上查找eos。通过shell命令启动它:
asynInterposeEosConfig port addr processEosIn processEosOut
此处:
- port是这个端口的名称
- addr是地址
- processEosIn(0,1)表示(没有,有)实现eosIn命令
- processEosOut(0,1)表示(没有,有)实现eosOut命令
这个命令应该立即出现在初始化一个端口的命令之后。一些驱动程序提供配置选项来自动调用这个。
2) asynInterpsoseFlush
如果驱动程序不提供对flush的支持,这可以用于为asynOctet模拟flush运行。在超时描述发生前,它仅读取和丢弃字符直到没有更多字符到达。由以下shell命令启动它:
asynInterposeFlushConfig port addr timeout
此处:
- port是这个端口名
- addr是地址
- timeout是用于等待更多字符的时间
这个命令应该立即在初始化一个端口的命令之后出现。
3)asynInterposeCom
这提供了在使用RFC 2117协议的终端服务器上配置串口的功能。不是直接从iocsh配置它,而是如果制定了COM协议,由drvAsynIPPort驱动程序自动配置。它支持如drvAsynSerialPort相同选项,即:"baud", "bits", "parity", "stop", "crtscts"和"ixon"。
4) asynInterposeDelay
这可以用于在发送每个字符后再发送下个字符前等待一个指定的延时。一些设计不好的设备需要这个功能。由shell命令启动它:
asynInterposeDelay port addr delay
此处:
- port是这个端口的名称
- addr是地址
- delay是再发送每个字符后要等待的时间。
这个命令应该立即在初始化一个端口的命令之后出现。在运行时,可以用'delay'选项使用这个interpose层添加的asyn选项接口检查或更高这个延时。
asynShowOption port, address, "delay"
asynSetOption port, address, "delay", delay(sec)
5) asynInterposeEcho
这可以被用于在发送下个字符前等待由设备响应的每个字符。某些设计不好的设备需要这个功能。由shell命令启动它:
asynInterposeEcho port addr
此处:
- port是这个端口的名称
- add是地址
这个命令应该立即出现在初始化一个端口的命令之后。