iocsh命令
asynReport(level,portName)
asynInterposeFlushConfig(portName,addr,timeout)
asynInterposeEosConfig(portName,addr,processIn,processOut)
asynSetTraceMask(portName,addr,mask)
asynSetTraceIOMask(portName,addr,mask)
asynSetTraceInfoMask(portName,addr,mask)
asynSetTraceFile(portName,addr,filename)
asynSetTraceIOTruncateSize(portName,addr,size)
asynSetOption(portName,addr,key,val)
asynShowOption(portName,addr,key)
asynAutoConnect(portName,addr,yesNo)
asynSetAutoConnectTimeout(timeout)
asynWaitConnect(portName, timeout)
asynEnable(portName,addr,yesNo)
asynOctetConnect(entry,portName,addr,timeout,buffer_len,drvInfo)
asynOctetRead(entry,nread)
asynOctetWrite(entry,output)
asynOctetWriteRead(entry,output,nread)
asynOctetFlush(entry)
asynOctetSetInputEos(portName,addr,eos,drvInfo)
asynOctetGetInputEos(portName,addr,drvInfo)
asynOctetSetOutputEos(portName,addr,eos,drvInfo)
asynOctetGetOutputEos(portName,addr,drvInfo)
asynRegisterTimeStampSource(portName,functionName);
asynUnregisterTimeStampSource(portName)
asynReport:如果指定了portName,asynReport为指定端口调用asynCommon:report,如果没有指定portName, 为所有注册的驱动程序和InterposeInterface调用asynCommon:report。
asynInterposeFlushConfig:是一个通用的interposeInterface,它为没有实现flush的底层驱动程序实现了flush。它仅发出读取请求,直到没有剩下要读的字节。timeout是用于读取请求。
asynInterposeEosConfig:是一个通用interposeInterface,它为没有实现字符串末尾处理的底层驱动程序,实现了它。
asynSetTraceMask:为指定端口和地址调用asynTrace:setTraceMask。如果portName是0长度,则全局跟踪掩码被设置。
一个掩码确定能被显示的信息类型。各种选项可是被ORed到一起。当创建一个端口时,这个掩码的默认值是:ASYN_TRACE_ERRROR。
- ASYN_TRACE_ERROR:报告运行时错误,例如,超时。
- ASYN_TRACEIO_DEVICE:设备支持报告I/O活动。
- ASYN_TRACEIO_FILTER:在设备支持和底层驱动之间的任何层报告它对I/O进行的任何过滤。
- ASYN_TRACEIO_DRIVER:底层驱动报告I/O活动。
- ASYN_TRACE_FLOW:报告逻辑流。设备支持应该报告所有队列请求,进入的回调以及对驱动的所有调用。在设备支持和底层驱动之间的层应该报告它们对更低层驱动的所有调用。底层驱动报告它们对其它支持的调用。
- ASYN_TRACE_WARNING:报告警告,即,在ASYN_TRACE_ERROR和ASYN_TRACE_FLOW之间的情况。
asynSetTraceIOMask:为指定端口和地址调用asynTrace:setTraceIOMask。如果portName是0长度,则全局跟踪掩码被设置。另一个掩码,它决定打印多少消息缓存。各种选项能够被ORed到一起。创建这个端口时,这个掩码的默认值是ASYN_TRACEIO_NODATA。
- ASYN_TRACEIO_NODATA:不打印来自消息缓存的任何数据。
- ASYN_TRACEIO_ASCII:用"%s"格式打印。
- ASYN_TRACEIO_ESCAPE: 调用epicsStrPrintEscaped.
- ASYN_TRACEIO_HEX :用%2.2x打印每个字节。
asynSetTraceInfoMask:为指定端口和地址调用asynTrace:setTraceInfoMask。如果portName是0长度,则全局跟踪掩码被设置。一个掩码确定了在每条消息开头打印数目信息。不同选项可以被ORed在一起。创建一个端口时,这个掩码的默认值是ASYN_TRACEINFO_TIME。
- ASYN_TRACEINFO_TIME:打印这条消息的日期和时间。
- ASYN_TRACEINFO_PORT:打印[port, addr, reason],此处port是端口名,addr是asyn地址,而reason是pasynUser->reason。这些是asyn中3段"地址"信息。
- ASYN_TRACEINFO_SOURCE:打印文件名和行号,即[__FILE__, __LINE__],此处asynPrint或asynPrintIO状态发生的位置。
- ASYN_TRACEINFO_THREAD:打印线程名称,线程ID和线程优先级,即[epicsThreadGetNameSelf(), epicsThreadGetIdSelf(), epicsThreadGetPrioritySelf()]。
从asyn R4-35开始,可以用以+或|连接的整数或者符号名称指定asynSetTraceMask, asynSetTraceIOMask和asynSetTraceInfoMask。空白是被允许的,但需要引号。符号名称是像在asynDriver.h中定义的宏名称,但不是区分大小写的,并且前缀ASYN_, TRACE_, TRACEIO_和TRACEINFO_是可选的。示例:
asynSetTraceMask port,0,ASYN_TRACE_ERROR
asynSetTraceIOMask port,0,ascii+escape
asynSetTraceInfoMask port,0,1+port+TRACEINFO_SOURCE|ASYN_TRACEINFO_THREAD
asynSetTraceFile:asynSetTraceFile调用asynTrace:setTraceFile。按如下处理文件名:
- 未指定。一个NULL指针被传递给setTraceFile。后续消息被发送给errlog。
- 一个空字符串("")或"stderr":stderr被传递给setTraceFile。
- "stdout":stdout被传递给setTraceFile。
- 任何其它字符串:用选项"w"打开这个指定的文件,并且文件指针被传递给setTraceFile。
asynSetTraceIOTruncateSize:asynSetTraceIOTruncateSize调用asynTrace:setTraceIOTruncateSize。
asynSetOption:asynSetOption调用asynCommon:setOption。
asynShowOptin:asynShowOption调用asynCommon:getOption。
asynOctetXXX命令:提供了对asynOctetSyncIO方法的shell访问。entry是标识端口,地址的字符串常量。
此处:
- filename:一个指定文件名的ascii字符串。如果null或null字符串,则输出被发送到stdout。
- level:汇报级别。
- portName:一个指定驱动的portName的ascii字符串。
- addr:指定设备地址的整数。用于多设备端口,-1值标识端口自身。对于支持单设备的端口,忽略addr。
- mask:要设置的掩码。
- key:对应所需选项的键。
- val:对应这个选项的值。
- yesNo:值(0,1)表示(no, yes)。
- entry:一个字符串,标识asynOctetConnect请求。
- timeout:用毫秒整数指定timeout。默认是1。
- buffer_len:对应I/O的缓存长度。默认为160。注意:传递给asynOctetWrite的输出字符串可以有转义字符。buffer_len必须足够大来处理转义字符。例如,如果\x02出现在输出字符串中,它算作4个字符。
- drvInfo:通过接口asynDrvUser传递给驱动的字符串。
- nread:要读取最大数目的字节。默认=buffer_len。
- flush:(0,1)表示在读取前(不要,要)flush。默认0。
- output:输出字符串。
命令asynOctetConnect, asynOctetDisconnect, asynOctetRead, asynOctetWrite, asynOctetWriteRead, asynOctet允许从ioc shell对设备进行I/O。示例是:
以下示例展示了使用https://blog.csdn.net/yuyuyuliang00/article/details/132668739中的asyn驱动模块创建了一个端口驱动程序来测试以上列出的部分asyn诊断命令。
以下这个驱动程序的源代码:
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "cantProceed.h"
#include "epicsStdio.h"
#include "epicsThread.h"
#include "iocsh.h"
#include "asynDriver.h"
#include "asynOctet.h"
#include "asynInt32.h"
#include <epicsExport.h>
#define BUFFERSIZE 4096
static int VALUE = 0;
typedef struct deviceBuffer{
char buffer[BUFFERSIZE];
size_t nchars;
int value;
int low;
int high;
}deviceBuffer;
typedef struct deviceInfo{
deviceBuffer buffer;
int connected;
}deviceInfo;
typedef struct infoPvt{
deviceInfo device;
const char * portName;
int connected;
double delay;
asynInterface common;
asynInterface octet;
asynInterface int32;
char eos[2];
int eoslen;
void * pasynPvt;
void * pasynInt32Pvt;
}infoPvt;
static int infoDriverInit(const char * portName, double delay, int noAutoConnect, int low, int high);
/* 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 asynC = {report, connect, disconnect};
/* asynOctet */
static asynStatus infoWrite(void *drvPvt, asynUser *pasynUser,
const char *data, size_t numchars, size_t *nbytesTransfered);
static asynStatus infoRead(void *drvPvt, asynUser *pasynUser,
char *data, size_t maxchars, size_t *nbytesTransfered, int *eomReason);
static asynStatus infoFlush(void *drvPvt, asynUser *pasynUser);
static asynStatus setEos(void *drvPvt, asynUser *pasynUser, const char *eos, int eoslen);
static asynStatus getEos(void *drvPvt, asynUser *pasynUser, char *eos, int eossize, int *eoslen);
static asynOctet asynO;
/* asynInt32*/
static asynStatus intWrite(void *drvPvt, asynUser * pasynUser, epicsInt32 value);
static asynStatus intRead(void *drvPvt, asynUser * pasynUser, epicsInt32 *value);
static asynStatus getIntBounds(void *drvPvt, asynUser * pasynUser, epicsInt32 *low, epicsInt32 *high);
static asynInt32 asynI32;
static int infoDriverInit(const char * pn, double delay, int noAutoConnect, int low, int high)
{
infoPvt *pinfoPvt;
char *portName;
asynStatus status;
size_t nbytes;
int attributes;
nbytes = sizeof(infoPvt) + strlen(pn) + 1;
pinfoPvt = (infoPvt *)callocMustSucceed(nbytes, sizeof(char), "infoPvt");
portName = (char *)(pinfoPvt + 1);
strcpy(portName, pn);
pinfoPvt->device.buffer.low = low;
pinfoPvt->device.buffer.high = high;
pinfoPvt->device.buffer.value = (low + high) / 2;
pinfoPvt->portName = portName;
pinfoPvt->delay = delay;
pinfoPvt->common.interfaceType = asynCommonType;
pinfoPvt->common.pinterface = (void *)&asynC;
pinfoPvt->common.drvPvt = pinfoPvt;
attributes = 0;
if (delay > 0.0){
attributes |= ASYN_CANBLOCK;
}
status = pasynManager->registerPort(portName, attributes, !noAutoConnect, 0, 0);
if (status != asynSuccess){
printf("infoDriverInit registerDriver failed\n");
return 0;
}
status = pasynManager->registerInterface(portName, &pinfoPvt->common);
if (status != asynSuccess){
printf("infoDriverInit registerInterface failed");
return 0;
}
asynO.write = infoWrite;
asynO.read = infoRead;
asynO.flush = infoFlush;
asynO.setInputEos = setEos;
asynO.getInputEos = getEos;
pinfoPvt->octet.interfaceType = asynOctetType;
pinfoPvt->octet.pinterface = (void *)&asynO;
pinfoPvt->octet.drvPvt = pinfoPvt;
status = pasynOctetBase->initialize(portName, &pinfoPvt->octet, 1, 1, 0);
if (status == asynSuccess){
status = pasynManager->registerInterruptSource(
portName, &pinfoPvt->octet, &pinfoPvt->pasynPvt);
}
if (status != asynSuccess){
printf("infoDriverInit registerInterface asynOctet failed\n");
return 0;
}
asynI32.write = intWrite;
asynI32.read = intRead;
asynI32.getBounds = getIntBounds;
pinfoPvt->int32.interfaceType = asynInt32Type;
pinfoPvt->int32.pinterface = (void *)&asynI32;
pinfoPvt->int32.drvPvt = pinfoPvt;
status = pasynInt32Base->initialize(portName, &pinfoPvt->int32);
if (status == asynSuccess){
status = pasynManager->registerInterruptSource(
portName, &pinfoPvt->int32, &pinfoPvt->pasynInt32Pvt);
}
if (status != asynSuccess){
printf("infoDriverInit registerInterface asynInt32 failed\n");
return 0;
}
return 0;
}
static void report(void *drvPvt, FILE *fp, int details)
{
infoPvt * pinfoPvt = (infoPvt *)drvPvt;
int i,n;
fprintf(fp, "infoDriver connected:%s delay = %f\n",
pinfoPvt->connected ? "Yes": "NO",
pinfoPvt->delay);
}
static asynStatus connect(void *drvPvt, asynUser * pasynUser)
{
infoPvt *pinfoPvt = (infoPvt *)drvPvt;
deviceInfo *pdeviceInfo;
int addr;
asynStatus status;
status = pasynManager->getAddr(pasynUser, &addr);
if (status != asynSuccess) return status;
asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s infoDriver: connect addr %d\n",
pinfoPvt->portName, addr);
if (pinfoPvt->connected){
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s infoDriver: connect port already connected\n",
pinfoPvt->portName);
return asynError;
}
if (pinfoPvt->delay > 0.0){
epicsThreadSleep(pinfoPvt->delay * 10.);
}
pinfoPvt->connected = 1;
pinfoPvt->device.connected = 1;
pasynManager->exceptionConnect(pasynUser);
return asynSuccess;
}
static asynStatus disconnect(void *drvPvt, asynUser *pasynUser)
{
infoPvt *pinfoPvt = (infoPvt *)drvPvt;
deviceInfo *pdeviceInfo;
int addr;
asynStatus status;
status = pasynManager->getAddr(pasynUser, &addr);
if (status != asynSuccess) return status;
asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s infoDriver: disconnect addr %d\n",
pinfoPvt->portName, addr);
if (!pinfoPvt->connected){
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s infoDriver: disconnect port not connected\n",
pinfoPvt->portName);
return asynError;
}
pinfoPvt->connected = 0;
pinfoPvt->device.connected = 0;
pasynManager->exceptionDisconnect(pasynUser);
return asynSuccess;
}
static asynStatus infoWrite(void *drvPvt, asynUser *pasynUser,
const char *data, size_t nchars, size_t *nbytesTransfered)
{
infoPvt *pinfoPvt = (infoPvt *)drvPvt;
deviceInfo *pdeviceInfo;
deviceBuffer *pdeviceBuffer;
int addr;
asynStatus status;
//printf("infoWrite: %s\n", data);
status = pasynManager->getAddr(pasynUser, &addr);
if(status != asynSuccess) return status;
addr = 0;
asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s initDriver: write addr %d\n",
pinfoPvt->portName, addr);
pdeviceInfo = &pinfoPvt->device;
if (!pdeviceInfo->connected){
asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s infoDriver: write %d not connected\n", pinfoPvt->portName, addr);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver:write device %d not connected",
pinfoPvt->portName, addr);
return asynError;
}
if (pinfoPvt->delay > pasynUser->timeout){
if (pasynUser->timeout > 0.0) epicsThreadSleep(pasynUser->timeout);
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s initDriver write timeout\n", pinfoPvt->portName);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver write timeout", pinfoPvt->portName);
return asynTimeout;
}
pdeviceBuffer = &pdeviceInfo->buffer;
if(nchars > BUFFERSIZE) nchars = BUFFERSIZE;
if(nchars > 0){
memcpy(pdeviceBuffer, data, nchars);
}
asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, nchars,
"infoWrite nchars %lu\n", (unsigned long)nchars);
pdeviceBuffer->nchars = nchars;
if (pinfoPvt->delay > 0.0) {
epicsThreadSleep(pinfoPvt->delay);
}
*nbytesTransfered = nchars;
return status;
}
static asynStatus infoRead(void *drvPvt, asynUser *pasynUser, char *data,
size_t maxchars, size_t *nbytesTransfered,int *eomReason)
{
infoPvt *pinfoPvt = (infoPvt *)drvPvt;
deviceInfo *pdeviceInfo;
deviceBuffer *pdeviceBuffer;
char *pfrom, *pto;
char thisChar;
size_t nremaining;
size_t nout = 0;
int addr;
asynStatus status;
if (eomReason) *eomReason = 0;
if (nbytesTransfered) *nbytesTransfered = 0;
status = pasynManager->getAddr(pasynUser, &addr);
addr = 0;
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"%s infoDriver: read addr %d\n", pinfoPvt->portName, addr);
pdeviceInfo = &pinfoPvt->device;
if (!pdeviceInfo->connected){
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s infoDriver: read device %d not connected\n",
pinfoPvt->portName, addr);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver:read device %d not connected",
pinfoPvt->portName, addr);
return asynError;
}
if (pinfoPvt->delay > pasynUser->timeout){
if (pinfoPvt->delay > 0.0){
epicsThreadSleep(pasynUser->timeout);
}
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s infoDriver read timeout\n", pinfoPvt->portName);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver read timeout", pinfoPvt->portName);
return asynTimeout;
}
if (pinfoPvt->delay > 0.0){
epicsThreadSleep(pinfoPvt->delay);
}
pdeviceBuffer = &pdeviceInfo->buffer;
nremaining = pdeviceBuffer->nchars;
pdeviceBuffer->nchars = 0;
pfrom = pdeviceBuffer->buffer;
pto = data;
while (nremaining >0 && nout < maxchars){
thisChar = *pto++ = *pfrom++;
nremaining--;
nout++;
if (pinfoPvt->eoslen > 0){
if (thisChar == pinfoPvt->eos[0]){
if (pinfoPvt->eoslen == 1){
if (eomReason) * eomReason |= ASYN_EOM_EOS;
break;
}
}
if (nremaining == 0){
if (eomReason) *eomReason |= ASYN_EOM_CNT;
break;
}
if (* pfrom == pinfoPvt->eos[1]){
*pto++ = *pfrom++;
nremaining--;
nout++;
if (eomReason){
*eomReason |= ASYN_EOM_EOS;
if(nremaining == 0){
*eomReason |= ASYN_EOM_CNT;
break;
}
}
}
}
}
if (nbytesTransfered) *nbytesTransfered = nout;
if (eomReason){
if (*nbytesTransfered >= maxchars) *eomReason |= ASYN_EOM_CNT;
if (nremaining == 0) * eomReason |= ASYN_EOM_END;
}
pasynOctetBase->callInterruptUsers(pasynUser, pinfoPvt->pasynPvt, data,
nbytesTransfered, eomReason);
asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, nout,
"infoRead nbytesTransfered %lu\n", (unsigned long)*nbytesTransfered);
return status;
}
static asynStatus infoFlush(void *drvPvt, asynUser * pasynUser)
{
infoPvt *pinfoPvt = (infoPvt *)drvPvt;
deviceInfo *pdeviceInfo;
deviceBuffer * pdeviceBuffer;
int addr;
asynStatus status;
status = pasynManager->getAddr(pasynUser, &addr);
if (status != asynSuccess) return status;
addr = 0;
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"%s initDriver: flush addr %d\n",
pinfoPvt->portName, addr);
pdeviceInfo = &pinfoPvt->device;
if (!pdeviceInfo->connected){
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s initDriver:flush device %d not connected\n",
pinfoPvt->portName, addr);
return -1;
}
pdeviceBuffer = &pdeviceInfo->buffer;
asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s infoDriver\n", pinfoPvt->portName);
pdeviceBuffer->nchars = 0;
return asynSuccess;
}
static asynStatus setEos(void *drvPvt, asynUser * pasynUser, const char *eos, int eoslen)
{
infoPvt * pinfoPvt = (infoPvt *)drvPvt;
int i;
if (eoslen > 2 || eoslen < 0){
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"setEos illegal eoslen %d", eoslen);
return asynError;
}
pinfoPvt->eoslen = eoslen;
for (i = 0; i < eoslen; i++){
pinfoPvt->eos[i] = eos[i];
}
asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s setEos\n", pinfoPvt->portName);
return asynSuccess;
}
static asynStatus getEos(void *drvPvt, asynUser * pasynUser,char *eos, int eossize, int *eoslen)
{
infoPvt * pinfoPvt = (infoPvt *)drvPvt;
int i;
* eoslen = pinfoPvt->eoslen;
for (i = 0; i < *eoslen; i++){
eos[i] = pinfoPvt->eos[i];
}
asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s setEos\n",
pinfoPvt->portName);
return asynSuccess;
}
static asynStatus intWrite(void *drvPvt, asynUser * pasynUser, epicsInt32 value)
{
infoPvt *pinfoPvt = (infoPvt *)drvPvt;
deviceInfo *pdeviceInfo;
deviceBuffer *pdeviceBuffer;
int addr;
asynStatus status;
//printf("infoWrite: %s\n", data);
status = pasynManager->getAddr(pasynUser, &addr);
if(status != asynSuccess) return status;
addr = 0;
asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s initDriver: intWrite addr %d\n",
pinfoPvt->portName, addr);
pdeviceInfo = &pinfoPvt->device;
if (!pdeviceInfo->connected){
asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s infoDriver: intWrite %d not connected\n", pinfoPvt->portName, addr);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver:intWrite device %d not connected",
pinfoPvt->portName, addr);
return asynError;
}
if (pinfoPvt->delay > pasynUser->timeout){
if (pasynUser->timeout > 0.0) epicsThreadSleep(pasynUser->timeout);
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s initDriver intWrite timeout\n", pinfoPvt->portName);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver intWrite timeout", pinfoPvt->portName);
return asynTimeout;
}
pdeviceBuffer = &pdeviceInfo->buffer;
if (value < pdeviceBuffer->low){
pdeviceBuffer->value = pdeviceBuffer->low;
}
else if (value > pdeviceBuffer->high){
pdeviceBuffer->value = pdeviceBuffer->high;
}
else{
pdeviceBuffer->value = value;
}
asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, "Write to device", strlen("Write to device"),
"intWrite value = %d\n", pdeviceBuffer->value);
if (pinfoPvt->delay > 0.0) {
epicsThreadSleep(pinfoPvt->delay);
}
return status;
}
static asynStatus intRead(void *drvPvt, asynUser * pasynUser, epicsInt32 *value)
{
infoPvt *pinfoPvt = (infoPvt *)drvPvt;
deviceInfo *pdeviceInfo;
deviceBuffer *pdeviceBuffer;
int addr;
asynStatus status;
//printf("infoRead: %s\n", data);
status = pasynManager->getAddr(pasynUser, &addr);
if(status != asynSuccess) return status;
addr = 0;
asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s initDriver: intRead addr %d\n",
pinfoPvt->portName, addr);
pdeviceInfo = &pinfoPvt->device;
if (!pdeviceInfo->connected){
asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s infoDriver: intRead %d not connected\n", pinfoPvt->portName, addr);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver:intRead device %d not connected",
pinfoPvt->portName, addr);
return asynError;
}
if (pinfoPvt->delay > pasynUser->timeout){
if (pasynUser->timeout > 0.0) epicsThreadSleep(pasynUser->timeout);
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s initDriver intRead timeout\n", pinfoPvt->portName);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver intRead timeout", pinfoPvt->portName);
return asynTimeout;
}
pdeviceBuffer = &pdeviceInfo->buffer;
* value = pdeviceBuffer->value;
asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, "Read from device", strlen("Read from device"),
"intRead value = %d\n", pdeviceBuffer->value);
if (pinfoPvt->delay > 0.0) {
epicsThreadSleep(pinfoPvt->delay);
}
return status;
}
static asynStatus getIntBounds(void *drvPvt, asynUser * pasynUser, epicsInt32 *low, epicsInt32 *high)
{
infoPvt *pinfoPvt = (infoPvt *)drvPvt;
deviceInfo *pdeviceInfo;
deviceBuffer *pdeviceBuffer;
int addr;
asynStatus status;
//printf("getIntBounds: %s\n", data);
status = pasynManager->getAddr(pasynUser, &addr);
if(status != asynSuccess) return status;
addr = 0;
asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s initDriver: getIntBounds addr %d\n",
pinfoPvt->portName, addr);
pdeviceInfo = &pinfoPvt->device;
if (!pdeviceInfo->connected){
asynPrint(pasynUser, ASYN_TRACE_ERROR, "%s infoDriver: getIntBounds %d not connected\n", pinfoPvt->portName, addr);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver:getIntBounds device %d not connected",
pinfoPvt->portName, addr);
return asynError;
}
if (pinfoPvt->delay > pasynUser->timeout){
if (pasynUser->timeout > 0.0) epicsThreadSleep(pasynUser->timeout);
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s initDriver getIntBounds timeout\n", pinfoPvt->portName);
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s infoDriver getIntBounds timeout", pinfoPvt->portName);
return asynTimeout;
}
pdeviceBuffer = &pdeviceInfo->buffer;
* low = pdeviceBuffer->low;
* high = pdeviceBuffer->high;
asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, "get limits from device", strlen("get limits from device"),
"getIntBounds low = %d, high = %d\n", pdeviceBuffer->low, pdeviceBuffer->high);
return status;
}
// static int infoDriverInit(const char * portName, double delay, int noAutoConnect, int low, int high);
static const iocshArg infoDriverInitArg0 = { "portName", iocshArgString };
static const iocshArg infoDriverInitArg1 = { "delay", iocshArgDouble };
static const iocshArg infoDriverInitArg2 = { "noautoconnect", iocshArgInt };
static const iocshArg infoDriverInitArg3 = { "low", iocshArgInt };
static const iocshArg infoDriverInitArg4 = { "high", iocshArgInt };
static const iocshArg *infoDriverInitArgs[] = {
&infoDriverInitArg0,&infoDriverInitArg1,
&infoDriverInitArg2,&infoDriverInitArg3, &infoDriverInitArg4};
static const iocshFuncDef infoDriverInitFuncDef = {
"infoDriverInit", 5, infoDriverInitArgs};
static void infoDriverInitCallFunc(const iocshArgBuf *args)
{
infoDriverInit(args[0].sval,args[1].dval,args[2].ival,args[3].ival, args[4].ival);
}
static void infoDriverRegister(void)
{
static int firstTime = 1;
if (firstTime) {
firstTime = 0;
iocshRegister(&infoDriverInitFuncDef, infoDriverInitCallFunc);
}
}
epicsExportRegistrar(infoDriverRegister);
将以上程序添加到应用程序的dbd文件如下:device.dbd
registrar(infoDriverRegister)
将以上device.c和device.dbd文件添加到相同目录下Makefile中,并且添加所需的其它库文件:
...
# dbd文件
infoDriver_DBD += asyn.dbd
infoDriver_DBD += device.dbd
# 库文件
infoDriver_LIBS += asyn
# 源文件
infoDriver_SRCS += device.c
...
回到这个IOC的顶层目录,执行make命令,进行编译。
进入这个点IOC程序的启动目录中,在st.cmd脚本中按定义的格式调用infoDriverInit:
#!../../bin/linux-aarch64/infoDriver
#- You may have to change infoDriver to something else
#- everywhere it appears in this file
< envPaths
cd "${TOP}"
## Register all support components
dbLoadDatabase "dbd/infoDriver.dbd"
infoDriver_registerRecordDeviceDriver pdbbase
infoDriverInit("MyPort", 0.5, 0, 0, 1000)
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=Asyn:,R=AsynRecord,PORT=MyPort,ADDR=0,OMAX=0,IMAX=0")
cd "${TOP}/iocBoot/${IOC}"
iocInit
启动这个IOC程序:
root@orangepi5:/usr/local/EPICS/program/infoDriver/iocBoot/iocinfoDriver# ../../bin/linux-aarch64/infoDriver st.cmd
#!../../bin/linux-aarch64/infoDriver
< envPaths
epicsEnvSet("IOC","iocinfoDriver")
epicsEnvSet("TOP","/usr/local/EPICS/program/infoDriver")
epicsEnvSet("SUPPORT","/usr/local/EPICS/synApps/support")
epicsEnvSet("ASYN","/usr/local/EPICS/synApps/support/asyn")
epicsEnvSet("EPICS_BASE","/usr/local/EPICS/base")
cd "/usr/local/EPICS/program/infoDriver"
## Register all support components
dbLoadDatabase "dbd/infoDriver.dbd"
infoDriver_registerRecordDeviceDriver pdbbase
infoDriverInit("MyPort", 0.5, 0, 0, 1000)
cd "/usr/local/EPICS/program/infoDriver/iocBoot/iocinfoDriver"
iocInit
Starting iocInit
############################################################################
## EPICS R7.0.7
## Rev. 2023-05-26T09:07+0000
## Rev. Date build date/time:
############################################################################
iocRun: All initialization complete
epics>
在epics命令提示环境中测试以上部分asyn诊断命令:
epics> asynOctetConnect("myid","MyPort",0,1,20)
epics> asynOctetWrite("myid","HelloWorld")
epics> asynOctetRead("myid")
eomReason 0x4
HelloWorld
epics> asynOctetWriteRead("myid","This is a test")
eomReason 0x4
This is a test
epics> asynOctetDisconnect("myid")
epics> asynReport(1,"MyPort")
MyPort multiDevice:No canBlock:Yes autoConnect:Yes
enabled:Yes connected:Yes numberConnects 1
nDevices 0 nQueued 0 blocked:No
asynManagerLock:No synchronousLock:No
exceptionActive:No exceptionUsers 1 exceptionNotifys 0
traceMask:0x1 traceIOMask:0x0 traceInfoMask:0x1
infoDriver connected:Yes delay = 0.500000
epics> asynSetTraceMask("MyPort",-1, ASYN_TRACE_ERROR|ASYN_TRACE_FLOW)
epics> asynOctetWrite("myid","HelloWorld")
2023/09/05 12:55:25.521 MyPort asynManager::queueLockPort locking port
2023/09/05 12:55:25.522 MyPort asynManager::queueLockPort taking mutex 0x55702ab790
2023/09/05 12:55:25.522 MyPort asynManager::queueLockPort queueing request
2023/09/05 12:55:25.523 MyPort addr -1 queueRequest priority 0 not lockHolder
2023/09/05 12:55:25.524 MyPort schedule queueRequest timeout in 2.000000 seconds
2023/09/05 12:55:25.525 MyPort asynManager::queueLockPort waiting for event
2023/09/05 12:55:25.526 asynManager::portThread port=MyPort callback
2023/09/05 12:55:25.526 MyPort asynManager::queueLockPortCallback signaling begin event
2023/09/05 12:55:25.526 MyPort asynManager::queueLockPortCallback waiting for mutex from queueUnlockPort
2023/09/05 12:55:25.526 MyPort asynManager::queueLockPort got event from callback
2023/09/05 12:55:25.528 MyPort initDriver: write addr 0
2023/09/05 12:55:26.028 MyPort queueUnlockPort
2023/09/05 12:55:26.030 MyPort asynManager::queueUnlockPort waiting for event
2023/09/05 12:55:26.031 MyPort queueUnlockPort unlock mutex 0x55702ab790 complete.
epics> asynOctetRead("myid")
2023/09/05 12:56:12.292 MyPort asynManager::queueLockPort locking port
2023/09/05 12:56:12.293 MyPort asynManager::queueLockPort taking mutex 0x55702ab790
2023/09/05 12:56:12.293 MyPort asynManager::queueLockPort queueing request
2023/09/05 12:56:12.293 MyPort addr -1 queueRequest priority 0 not lockHolder
2023/09/05 12:56:12.294 MyPort schedule queueRequest timeout in 2.000000 seconds
2023/09/05 12:56:12.295 MyPort asynManager::queueLockPort waiting for event
2023/09/05 12:56:12.296 asynManager::portThread port=MyPort callback
2023/09/05 12:56:12.296 MyPort asynManager::queueLockPortCallback signaling begin event
2023/09/05 12:56:12.296 MyPort asynManager::queueLockPortCallback waiting for mutex from queueUnlockPort
2023/09/05 12:56:12.296 MyPort asynManager::queueLockPort got event from callback
2023/09/05 12:56:12.296 MyPort infoDriver: read addr 0
2023/09/05 12:56:12.797 MyPort queueUnlockPort
2023/09/05 12:56:12.797 MyPort asynManager::queueUnlockPort waiting for event
2023/09/05 12:56:12.798 MyPort queueUnlockPort unlock mutex 0x55702ab790 complete.
eomReason 0x4
HelloWorld
使用asyRecord.adl进行测试:
medm -x -macro "P=Asyn:,R=AsynRecord" asynRecord.adl
出现以下窗口:
选择More...菜单的asynOctet Interface I/O:
弹出以下窗口,在Out的ASCII文本框中输入一个字符串,这里为HelloWord,按回车,可以看到Input的ASCII文本框中显示读回的HelloWorld,并且EOM reason中显示字符串结束的原因。
选择More...菜单的Register Interface I/O,弹出以下窗口,将Interface下的菜单选中asynInt32,在Output文本框中输入一个数值68,按回车后,在Input文本框中回读到这个数值:
补充一个记录实例文件:
record(calc,"$(P)$(R)_P$(PORT)_A$(A)_calc") {
field(DESC, "Counter")
field(SCAN,"Passive")
field(CALC, "(A<99)?(A+1):0")
field(INPA,"$(P)$(R)_P$(PORT)_A$(A)_calc NPP NMS")
field(FLNK,"$(P)$(R)_P$(PORT)_A$(A)_so")
field(EGU, "Counts")
field(HOPR, "10")
field(FLNK,"$(P)$(R)_P$(PORT)_A$(A)_so")
}
record(stringout,"$(P)$(R)_P$(PORT)_A$(A)_so") {
field(DOL,"$(P)$(R)_P$(PORT)_A$(A)_calc NPP NMS")
field(OMSL,"closed_loop")
field(FLNK,"$(P)$(R)_P$(PORT)_A$(A)_si")
}
record(stringin,"$(P)$(R)_P$(PORT)_A$(A)_si") {
field(DTYP,"asynOctetWriteRead")
field(INP,"@asyn($(PORT),$(A)) $(P)$(R)_P$(PORT)_A$(A)_so")
}
以上实例文件运行过程为:当calc记录运行时,其从自己的VAL读取一个值,如果这个数值小于99就VAL增加1,否则VAL变为0,在运行结束前,通过FLNK使stringout记录运行,stringout从calc记录的VAL字段读取一个值,将其转换成字符串表示形式,存入到自己的VAL字段,并且在运行结束前,通过FLNK使得stringin记录运行,当stringin运行时,通过接口asynOctetWriteRead设备支持,将从stringout读取的字符串写入到端口驱动程序中,然后从端口驱动中回读字符串,写入到自己的VAL字段中。
将以下记录加载命令,添加到st.cmd启动脚本文件的iocInit前:
dbLoadRecords("db/test.db", "P=Test:,R=Client,PORT=MyPort,A=0")
重启这个IOC,用dbl命令查看加载的记录:
epics>dbl
Asyn:AsynRecord
Test:Client_PMyPort_A0_calc
Test:Client_PMyPort_A0_si
Test:Client_PMyPort_A0_so
用CSS进行以上记录运行的显示:
asynRegisterTimeStampSource:为指定端口调用pasynManager->registerTimeStampSource。时间戳源函数必须在这个程序的dbd文件中被定义为"函数"。
asynReisgerTimeStampSource:为指定端口调用pasynManager->unregisterTimeStampSource。这恢复成asynManager中默认的时间戳源函数。