From 60594fdef650b462b365d8347fbd95a4414f3a0a Mon Sep 17 00:00:00 2001 From: John Winans Date: Wed, 29 Apr 1992 15:22:54 +0000 Subject: [PATCH] much debugging and addition of record-specific conversions --- src/drv/drvMsg.c | 1111 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 1051 insertions(+), 60 deletions(-) diff --git a/src/drv/drvMsg.c b/src/drv/drvMsg.c index ccfb4db77..8dc42e7dd 100644 --- a/src/drv/drvMsg.c +++ b/src/drv/drvMsg.c @@ -42,37 +42,82 @@ #include #include +#include +#include +#include #include #include #include +#include #include #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include -static long reportMsg(), initMsg(); +int msgDebug = 1; + +static long drvMsg_initCallback(), drvMsg_write(), drvMsg_AiFmt(); +static long drvMsg_AoFmt(), drvMsg_proc(); +static long drvMsg_BiFmt(), drvMsg_BoFmt(), drvMsg_MiFmt(), drvMsg_MoFmt(); +static long drvMsg_LiFmt(), drvMsg_LoFmt(), drvMsg_SiFmt(), drvMsg_SoFmt(); +static long drvMsg_SiRaw(), drvMsg_SoRaw(); +static long drvMsg_CheckAck(); + +static void drvMsg_callbackFunc(); static int msgTask(); +static long (*(msgSupFun[]))() = { + NULL, /* MSG_OP_NOP */ + drvMsg_write, /* MSG_OP_WRITE */ + drvMsg_AiFmt, /* MSG_OP_FAI */ + drvMsg_AoFmt, /* MSG_OP_FAO */ + drvMsg_BiFmt, /* MSG_OP_FBI */ + drvMsg_BoFmt, /* MSG_OP_FBO */ + drvMsg_MiFmt, /* MSG_OP_FMI */ + drvMsg_MoFmt, /* MSG_OP_FMO */ + drvMsg_LiFmt, /* MSG_OP_FLI */ + drvMsg_LoFmt, /* MSG_OP_FLO */ + drvMsg_SiFmt, /* MSG_OP_FSI */ + drvMsg_SoFmt, /* MSG_OP_FSO */ + drvMsg_SiRaw, /* MSG_OP_RSI */ + drvMsg_SoRaw, /* MSG_OP_RSO */ + drvMsg_CheckAck /* MSG_OP_ACK */ +}; +#define NUM_VALID_OPS sizeof(msgSupFun)/sizeof(msgSupFun[0]) + /****************************************************************************** * * Driver entry table for the message based I/O driver * ******************************************************************************/ -struct drvet drvMsg = { 2, reportMsg, initMsg }; +struct drvet drvMsg = { 2, drvMsg_reportMsg, drvMsg_initMsg }; /****************************************************************************** * ******************************************************************************/ long -reportMsg(pdset) +drvMsg_reportMsg(pdset) msgDset *pdset; { printf("Message driver report\n"); - if (pdset->pparmBlock->pdrvBlock->report != NULL) - return((*(pdset->pparmBlock->pdrvBlock->report))(pdset)); + if (pdset->pparmBlock->pdrvBlock->drvIoctl != NULL) + return((*(pdset->pparmBlock->pdrvBlock->drvIoctl))(MSGIOCTL_REPORT, NULL)); return(OK); } @@ -82,14 +127,20 @@ msgDset *pdset; * ******************************************************************************/ long -initMsg(parm, pdset) +drvMsg_initMsg(parm, pdset) int parm; msgDset *pdset; { + + msgDrvIniParm initParms; + + initParms.parm = parm; + initParms.pdset = pdset; + printf("Message init routine entered\n"); - if(pdset->pparmBlock->pdrvBlock->init != NULL) - return((*(pdset->pparmBlock->pdrvBlock->init))(parm, pdset)); + if(pdset->pparmBlock->pdrvBlock->drvIoctl != NULL) + return((*(pdset->pparmBlock->pdrvBlock->drvIoctl))(MSGIOCTL_INIT, &initParms)); return(OK); } @@ -162,20 +213,30 @@ msgXact *pnode; * ******************************************************************************/ msgXact * -drvMsg_genXact(pparmBlock, plink) +drvMsg_genXact(pparmBlock, plink, prec) msgParmBlock *pparmBlock; struct link *plink; /* I/O link structure from record */ +struct dbCommon *prec; { - msgXact *pmsgXact; + msgXact *pmsgXact; + msgDrvGenXParm genXactParm; + char message[100]; /* allocate and fill in msg specific part */ if ((pmsgXact = malloc(sizeof (msgXact))) == NULL) + { + sprintf(message, "drvMsg_genXact:%s out of memory\n", prec->name); + errMessage(S_db_badField, message); return(NULL); - + } pmsgXact->pparmBlock = pparmBlock; + pmsgXact->prec = prec; + + genXactParm.plink = plink; + genXactParm.pmsgXact = pmsgXact; /* fill in communication-link specific portion and phwpvt */ - if ((*(pparmBlock->pdrvBlock->genXact))(pparmBlock, plink, pmsgXact) == ERROR) + if ((*(pparmBlock->pdrvBlock->drvIoctl))(MSGIOCTL_GENXACT, &genXactParm) == ERROR) { /* free-up the xact structure and clean up */ return(NULL); @@ -186,9 +247,9 @@ struct link *plink; /* I/O link structure from record */ /****************************************************************************** * * Generate a hardware private structure and initialize it. - * This is called by pparmBlock->pdrvBlock->genXact() when it finds that a - * hardware private structure is not present when a transaction structure is - * being initialized for it. + * This is called by pparmBlock->pdrvBlock->drvIoctl(MSGIOCTL_GENXACT) when it + * finds that a hardware private structure is not present when a transaction + * structure is being initialized for it. * ******************************************************************************/ msgHwpvt * @@ -196,8 +257,10 @@ drvMsg_genHwpvt(pparmBlock, plink) msgParmBlock *pparmBlock; struct link *plink; /* I/O link structure from record */ { - msgHwpvt *pmsgHwpvt; + msgHwpvt *pmsgHwpvt; + msgDrvGenHParm genHParms; +printf("In drvMsg_genHwpvt\n"); /* allocate and fill in msg specific part */ if((pmsgHwpvt = malloc(sizeof(msgHwpvt))) == NULL) return(NULL); @@ -209,9 +272,14 @@ struct link *plink; /* I/O link structure from record */ pmsgHwpvt->tmoVal = 0; pmsgHwpvt->tmoCount = 0; - if ((*(pparmBlock->pdrvBlock->genHwpvt))(pparmBlock, plink, pmsgHwpvt) == ERROR) + genHParms.pparmBlock = pparmBlock; + genHParms.plink = plink; + genHParms.pmsgHwpvt = pmsgHwpvt; + + if ((*(pparmBlock->pdrvBlock->drvIoctl))(MSGIOCTL_GENHWPVT, &genHParms) == ERROR) { - /* free up the hardware private structure and clean up */ + /* Free up the hardware private structure and clean up */ + /* It is still first on the list, so don't have to look for it */ return(NULL); } @@ -221,27 +289,30 @@ struct link *plink; /* I/O link structure from record */ /****************************************************************************** * * Generate a message queue link structure and start a task to manage it. - * This is called by pparmBlock->pdrvBlock->genHwpvt() when it finds that a - * specific link structure is not present that is needed when initializing a - * hardware private structure. + * This is called by pparmBlock->pdrvBlock->drvIoctl(MSGIOCTL_GENHWPVT) when + * it finds that a specific link structure is not present that is needed when + * initializing a hardware private structure. * ******************************************************************************/ msgLink * -drvMsg_genLink(pdrvBlock, plink) -msgDrvBlock *pdrvBlock; +drvMsg_genLink(pparmBlock, plink) +msgParmBlock *pparmBlock; struct link *plink; /* I/O link structure from record */ { + msgDrvGenLParm genlParms; msgLink *pmsgLink; char name[20]; long status; int j; + +printf("In drvMsg_genLink\n"); /* Allocate and fill in the msg specific part */ if ((pmsgLink = malloc(sizeof(msgLink))) == NULL) return(NULL); /* init all the prioritized transaction queues */ - for(j=0; jqueue[j].head = NULL; pmsgLink->queue[j].tail = NULL; @@ -250,17 +321,19 @@ struct link *plink; /* I/O link structure from record */ } pmsgLink->linkEventSem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY); + genlParms.pmsgLink = pmsgLink; + genlParms.plink = plink; + genlParms.op = MSG_GENLINK_CREATE; + genlParms.pparmBlock = pparmBlock; + /* do the driver-specific init */ - if ((*(pdrvBlock->genLink))(pmsgLink, plink, MSG_GENLINK_CREATE) == ERROR) + if ((*(pparmBlock->pdrvBlock->drvIoctl))(MSGIOCTL_GENLINK, &genlParms) == ERROR) { /* free the pmsgLink structure and clean up */ - return(NULL); } - - - sprintf(name, "%s", pdrvBlock->taskName); - if (taskSpawn(name, pdrvBlock->taskPri, pdrvBlock->taskOpt, pdrvBlock->taskStack, msgTask, pdrvBlock, pmsgLink) == ERROR) + sprintf(name, "%s", pparmBlock->pdrvBlock->taskName); + if (taskSpawn(name, pparmBlock->pdrvBlock->taskPri, pparmBlock->pdrvBlock->taskOpt, pparmBlock->pdrvBlock->taskStack, msgTask, pparmBlock->pdrvBlock, pmsgLink) == ERROR) { printf("Message driver: Failed to start link task %s\n", name); /* BUG --delete the FASTLOCK in here */ @@ -271,13 +344,84 @@ struct link *plink; /* I/O link structure from record */ if (status == ERROR) { - (*(pdrvBlock->genLink))(pmsgLink, plink, MSG_GENLINK_ABORT); + genlParms.op = MSG_GENLINK_ABORT; + + (*(pparmBlock->pdrvBlock->drvIoctl))(MSGIOCTL_GENLINK, &genlParms); free(pmsgLink); return(NULL); } return(pmsgLink); } +/****************************************************************************** + * + * Check to verify that a given parameter number is within range for the + * given device type. + * + ******************************************************************************/ +static long +checkParm(prec, recTyp) +struct dbCommon *prec; +char *recTyp; +{ + unsigned int parm; + char message[100]; + + if (prec->dpvt != NULL) + { + parm = ((msgXact *)(prec->dpvt))->parm; + if (parm >= ((msgXact *)(prec->dpvt))->pparmBlock->numCmds) + { + sprintf(message, "Message driver-checkParm:%s parm number %d invalid\n", prec->name, +parm); + errMessage(S_db_badField, message); + prec->pact = TRUE; + return(S_db_badField); + } + if ((((msgXact *)(prec->dpvt))->pparmBlock->pcmds)[parm].recTyp != (struct msgDset *)(prec->dset)) + { + sprintf(message, "Message driver-checkParm: %s parm number %d not valid for %s record type\n", prec->name, parm, recTyp); + errMessage(S_db_badField, message); + prec->pact = TRUE; + return(S_db_badField); + } + return(0); + } + return(S_db_badField); +} + +/****************************************************************************** + * + * Callback function used to complete async-record processing. + * + ******************************************************************************/ +static void +drvMsg_callbackFunc(pcallback) +CALLBACK *pcallback; +{ + dbScanLock(((msgXact *)(pcallback->user))->prec); + (*(struct rset *)(((msgXact *)(pcallback->user))->prec->rset)).process(((msgXact *)(pcallback->user))->prec); + dbScanUnlock(((msgXact *)(pcallback->user))->prec); +} + +/****************************************************************************** + * + * Function used to initialize the callback structure within the transaction + * structure. This sets it up so that it is used to perform the completion + * phase of the async record processing. + * + ******************************************************************************/ +static long +drvMsg_initCallback(prec) +struct dbCommon *prec; +{ + ((msgXact *)(prec->dpvt))->callback.callback = drvMsg_callbackFunc; + /* ((msgXact *)(prec->dpvt))->callback.priority = prec->prio; */ + ((msgXact *)(prec->dpvt))->callback.user = (void *)(prec->dpvt); + + return(OK); +} + /****************************************************************************** * * Queue a transaction for the link task. @@ -289,16 +433,16 @@ msgXact *xact; { msgLink *pmsgLink = xact->phwpvt->pmsgLink; -printf("xact(%08.8X, %d): devRs232drv xact request entered\n", xact, prio); - /* The link verification is done at record-init time & not needed here. */ - if ((prio < 0) || (prio >= MSG_NUM_PRIO)) + if ((prio < 0) || (prio >= NUM_CALLBACK_PRIORITIES)) { xact->status = XACT_BADPRIO; return(ERROR); } + xact->callback.priority = prio; /* Callback processing priority */ + FASTLOCK(&(pmsgLink->queue[prio].lock)); drvMsg_xactListAddTail(&(pmsgLink->queue[prio]), xact); FASTUNLOCK(&(pmsgLink->queue[prio].lock)); @@ -308,29 +452,63 @@ printf("xact(%08.8X, %d): devRs232drv xact request entered\n", xact, prio); } /****************************************************************************** + * + * Message-driver link-task. + * + * This function is spawned as a task during iocInit(). It waits on a semaphore + * that is given when either a message (transaction) is queued for a device + * associated with the link, or an event of some kind was detected from a device + * associated with the link. + * + * When the task wakes up, it checks to see if it was due to an event. If so, + * the support function that identified the event will also specify a + * transaction structure to process. If no event occurred, then the + * transaction request queues are checked. + * + * If a transaction was found, either due to an event or the work queues, it + * is processed. Processing a transaction consists of two optional phases. + * These phases are called the write and read phases, but either of them + * may do either writing, reading, or nothing. In the typical case, the + * first phase will do some writing (either setting a condition or soliciting a + * response) and the second phase will do some reading (reading back a solicited + * response) or nothing (in cases where no response will be generated to some + * write command.) * ******************************************************************************/ static int msgTask(pdrvBlock, pmsgLink) msgDrvBlock *pdrvBlock; msgLink *pmsgLink; { + int working; int prio; msgXact *xact; int event; msgCmd *pmsgCmd; + msgChkEParm checkEventParms; printf("Message driver link task %s started\n", pdrvBlock->taskName); + checkEventParms.pdrvBlock = pdrvBlock; + checkEventParms.pmsgLink = pmsgLink; + checkEventParms.pxact = &xact; + + working = 1; /* Force a first time check on events and xact queues */ + while (1) { - semTake(pmsgLink->linkEventSem, WAIT_FOREVER); + if (!working) + semTake(pmsgLink->linkEventSem, WAIT_FOREVER); - event = (*(pdrvBlock->checkEvent))(pdrvBlock, pmsgLink, &xact); + working = 0; + xact = NULL; + + /* Check to see if we woke up because of a device event */ + event = (*(pdrvBlock->drvIoctl))(MSGIOCTL_CHECKEVENT, &checkEventParms); if (event == MSG_EVENT_NONE) - { /* No events pending, check the request queues for work */ + { /* No device events pending, check the request queues for work */ prio = 0; - while ((xact == NULL) && prio < MSG_NUM_PRIO) + while ((xact == NULL) && prio < NUM_CALLBACK_PRIORITIES) { FASTLOCK(&(pmsgLink->queue[prio].lock)); if ((xact = pmsgLink->queue[prio].head) != NULL) @@ -340,40 +518,38 @@ msgLink *pmsgLink; } else FASTUNLOCK(&(pmsgLink->queue[prio].lock)); - } - if (xact != NULL) - { /* Perform the transaction operation */ - - xact->status = XACT_OK; /* All well, so far */ - pmsgCmd = &(xact->pparmBlock->pcmds[xact->parm]); - - if (pmsgCmd->writeOp != NULL) - { /* Perform the write operation of the transaction */ - -printf("Performing the write-operation\n"); - - (*(pmsgCmd->writeOp))(xact, pmsgCmd->wrParm); - } + prio++; } } if (xact != NULL) - { /* Perform the read operation of the transaction */ - + { + working = 1; + xact->status = XACT_OK; /* All well, so far */ pmsgCmd = &(xact->pparmBlock->pcmds[xact->parm]); - - if (pmsgCmd->readOp != NULL) + + if ((pmsgCmd->writeOp.op != MSG_OP_NOP) && ((event == MSG_EVENT_NONE)||(event & MSG_EVENT_WRITE))) + { /* Perform the write portion of a transaction operation */ + (*(xact->pparmBlock->doOp))(xact, &(pmsgCmd->writeOp)); + } + + if ((xact->status == XACT_OK) && (pmsgCmd->readOp.op != MSG_OP_NOP)) { /* There is a read opertaion spec'd, check to see if I can do it now */ if ((pmsgCmd->readDef == 0)||(event & MSG_EVENT_READ)) - { /* Not a deferred readback -or- it is and is time to do the read */ -printf("Performing the read-operation\n"); - (*(pmsgCmd->readOp))(xact, pmsgCmd->rdParm); + { /* Not a deferred readback parm -or- it is and is time to read */ + (*(xact->pparmBlock->doOp))(xact, &(pmsgCmd->readOp)); + + if (xact->callback.callback != NULL) + callbackRequest(xact); + + if (xact->psyncSem != NULL) + semGive(*(xact->psyncSem)); } /* else -- is a defered readback, must wait for readback event */ } else { /* There is no read operation specified, finish the xact opetation */ - if (xact->finishProc != NULL) + if (xact->callback.callback != NULL) callbackRequest(xact); if (xact->psyncSem != NULL) @@ -382,3 +558,818 @@ printf("Performing the read-operation\n"); } } } + +/****************************************************************************** + * + * This function encapsulates the calls made to the device-specific read and + * write functions. The idea here is that we can monitor and/or buffer I/O + * operations from here. + * + * For now, just call the device specific function. + * + ******************************************************************************/ +static long +drvWrite(pxact, pparm) +msgXact *pxact; +msgStrParm *pparm; +{ + return(pxact->pparmBlock->pdrvBlock->drvWrite(pxact, pparm)); +} + +static long +drvRead(pxact, pparm) +msgXact *pxact; +msgStrParm *pparm; +{ + return((*(pxact->pparmBlock->pdrvBlock->drvRead))(pxact, pparm)); +} + +/****************************************************************************** + * + * This function is called to handle the processing of a transaction. + * The idea here is that xact->pparmBlock->doOp could point to this + * function if there are not any custom operations, or to it's own + * function that could check to see if the operation is local/custom and + * then call this if it is not. + * + ******************************************************************************/ +long +drvMsg_xactWork(pxact, pop) +msgXact *pxact; +msgCmdOp *pop; +{ + if ((pop->op > 0) && (pop->op < NUM_VALID_OPS)) + return((*(msgSupFun[pop->op]))(pxact, pop->p)); + +printf("In drvMsg_xactWork, Invalid operation code -->%d encountered\n", pop->op); + pxact->status = XACT_BADCMD; + return(XACT_BADCMD); +} + +/****************************************************************************** + * + * Write a string to the device w/o any formatting. + * + ******************************************************************************/ +static long +drvMsg_write(pxact, pparm) +msgXact *pxact; +msgStrParm *pparm; +{ + return(drvWrite(pxact, pparm)); +} + +/****************************************************************************** + * + * Read a string and see if it contains the substring provided in the + * msgAkParm structure. This is useful to check the ack string from a + * device because it will cause the record to go into a VALID alarm + * state if the ACK does not match the provided string. + * + * If the provided substring is a zero-length string, it will match + * any possible ACK string. + * + ******************************************************************************/ +static long +drvMsg_CheckAck(pxact, packParm) +msgXact *pxact; +msgAkParm *packParm; +{ + msgStrParm strParm; +/* BUG -- the buffer size will have to be configurable */ + char buf[100]; + char *ach; + char *rch; + + strParm.buf = buf; + strParm.len = packParm->len; + + drvRead(pxact, &strParm); + if (msgDebug > 5) + printf("drvMsg_CheckAck comparing >%s< at %d against >%s<\n", buf, packParm->index, packParm->str); + + if (pxact->status == XACT_OK) + { + ach = &(packParm->str[packParm->index]); + rch = buf; + while (*ach != '\0') + { + if (*ach != *rch) + { + *ach = '\0'; /* stop the while loop */ + pxact->status = XACT_IOERR; + } + else + { + ach++; + rch++; + } + } + } + return(pxact->status); +} + +/****************************************************************************** + * + * Read a string and use the format string to extract the value field + * + ******************************************************************************/ +static long +drvMsg_AiFmt(pxact, pfiParm) +msgXact *pxact; +msgFiParm *pfiParm; +{ + msgStrParm strParm; +/* BUG -- some how the buffer length will have to be made configurable */ + char buf[100]; + + strParm.buf = buf; + strParm.len = pfiParm->len; + + drvRead(pxact, &strParm); + + if (pxact->status == XACT_OK) + { + if (sscanf(buf, pfiParm->format, &(((struct aiRecord *)(pxact->prec))->val)) != 1) + pxact->status = XACT_IOERR; + } + return(pxact->status); +} + +/****************************************************************************** + * + * Read a string and use the format string to extract the value field + * + * NOTE: The rval is filled in for the BI record so that conversion may + * take place in record support. + * + ******************************************************************************/ +static long +drvMsg_BiFmt(pxact, pfiParm) +msgXact *pxact; +msgFiParm *pfiParm; +{ + msgStrParm strParm; +/* BUG -- some how the buffer length will have to be made configurable */ + char buf[100]; + + strParm.buf = buf; + strParm.len = pfiParm->len; + + drvRead(pxact, &strParm); + + if (pxact->status == XACT_OK) + { + if (sscanf(buf, pfiParm->format, &(((struct biRecord *)(pxact->prec))->rval)) != 1) + pxact->status = XACT_IOERR; + } + return(pxact->status); +} + +/****************************************************************************** + * + * Read a string and use the format string to extract the value field + * + * NOTE: The rval is filled in for the MBBI record so that conversion may + * take place in record support. + * + ******************************************************************************/ +static long +drvMsg_MiFmt(pxact, pfiParm) +msgXact *pxact; +msgFiParm *pfiParm; +{ + msgStrParm strParm; +/* BUG -- some how the buffer length will have to be made configurable */ + char buf[100]; + + strParm.buf = buf; + strParm.len = pfiParm->len; + + drvRead(pxact, &strParm); + + if (pxact->status == XACT_OK) + { + if (sscanf(buf, pfiParm->format, &(((struct mbbiRecord *)(pxact->prec))->rval)) != 1) + pxact->status = XACT_IOERR; + } + return(pxact->status); +} + +/****************************************************************************** + * + * Read a string and use the format string to extract the value field + * + ******************************************************************************/ +static long +drvMsg_LiFmt(pxact, pfiParm) +msgXact *pxact; +msgFiParm *pfiParm; +{ + msgStrParm strParm; +/* BUG -- some how the buffer length will have to be made configurable */ + char buf[100]; + + strParm.buf = buf; + strParm.len = pfiParm->len; + + drvRead(pxact, &strParm); + + if (pxact->status == XACT_OK) + { + if (sscanf(buf, pfiParm->format, &(((struct longinRecord *)(pxact->prec))->val)) != 1) + pxact->status = XACT_IOERR; + } + return(pxact->status); +} + +/****************************************************************************** + * + * Read a string and use the format string to extract the value field + * + ******************************************************************************/ +static long +drvMsg_SiFmt(pxact, pfiParm) +msgXact *pxact; +msgFiParm *pfiParm; +{ + msgStrParm strParm; +/* BUG -- some how the buffer length will have to be made configurable */ + char buf[100]; + + strParm.buf = buf; + strParm.len = pfiParm->len; + + drvRead(pxact, &strParm); + + if (pxact->status == XACT_OK) + { + if (sscanf(buf, pfiParm->format, (((struct stringinRecord *)(pxact->prec))->val)) != 1) + pxact->status = XACT_IOERR; + } + return(pxact->status); +} + +/****************************************************************************** + * + * Read a string and use the format string to extract the value field + * + ******************************************************************************/ +static long +drvMsg_SiRaw(pxact, parm) +msgXact *pxact; +void *parm; +{ + msgStrParm strParm; + + strParm.buf = ((struct stringinRecord *)(pxact->prec))->val; + strParm.len = sizeof(((struct stringinRecord *)(pxact->prec))->val); + + drvRead(pxact, &strParm); + + return(pxact->status); +} + +/****************************************************************************** + * + * This function is used to write a string that includes the VAL field of an + * analog output record, to an RS-232 device. + * + ******************************************************************************/ +static long +drvMsg_AoFmt(pxact, pfoParm) +msgXact *pxact; +msgFoParm *pfoParm; +{ + msgStrParm wrParm; +/* BUG -- some how the buffer length will have to be made configurable */ + char buf[100]; + + wrParm.buf = buf; + + sprintf(buf, pfoParm->format, ((struct aoRecord *)(pxact->prec))->val); + wrParm.len = -1; /* write until reach NULL character */ + + drvWrite(pxact, &wrParm); + return(pxact->status); +} + +static long +drvMsg_BoFmt(pxact, pfoParm) +msgXact *pxact; +msgFoParm *pfoParm; +{ + msgStrParm wrParm; + char buf[100]; + + wrParm.buf = buf; + + sprintf(buf, pfoParm->format, ((struct boRecord *)(pxact->prec))->val); + wrParm.len = -1; /* write until reach NULL character */ + + drvWrite(pxact, &wrParm); + return(pxact->status); +} + +/****************************************************************************** + * + * NOTE: The formatting of the MBBO value uses the rval field so that the + * conversion from VAL to RVAL in the record (the movement of one of the + * onvl, twvl,... fields to the rval field during record processing.) + * + ******************************************************************************/ +static long +drvMsg_MoFmt(pxact, pfoParm) +msgXact *pxact; +msgFoParm *pfoParm; +{ + msgStrParm wrParm; + char buf[100]; + + wrParm.buf = buf; + + sprintf(buf, pfoParm->format, ((struct mbboRecord *)(pxact->prec))->rval); + wrParm.len = -1; /* write until reach NULL character */ + + drvWrite(pxact, &wrParm); + return(pxact->status); +} + +static long +drvMsg_LoFmt(pxact, pfoParm) +msgXact *pxact; +msgFoParm *pfoParm; +{ + msgStrParm wrParm; + char buf[100]; + + wrParm.buf = buf; + + sprintf(buf, pfoParm->format, ((struct longoutRecord *)(pxact->prec))->val); + wrParm.len = -1; /* write until reach NULL character */ + + drvWrite(pxact, &wrParm); + return(pxact->status); +} + +static long +drvMsg_SoFmt(pxact, pfoParm) +msgXact *pxact; +msgFoParm *pfoParm; +{ + msgStrParm wrParm; + char buf[100]; + + wrParm.buf = buf; + + sprintf(buf, pfoParm->format, ((struct stringoutRecord *)(pxact->prec))->val); + wrParm.len = -1; /* write until reach NULL character */ + + drvWrite(pxact, &wrParm); + return(pxact->status); +} + +static long +drvMsg_SoRaw(pxact, parm) +msgXact *pxact; +void *parm; +{ + msgStrParm wrParm; + + wrParm.buf = ((struct stringoutRecord *)(pxact->prec))->val; + wrParm.len = -1; /* write until reach NULL character */ + + drvWrite(pxact, &wrParm); + return(pxact->status); +} + +/****************************************************************************** + * + * The following functions are called from record support. They are used to + * queue a record's DPVT (xact structure) for processing by the message + * driver. + * + ******************************************************************************/ +/****************************************************************************** + * + * init record routine for AI + * + ******************************************************************************/ +long +drvMsg_initAi(pai) +struct aiRecord *pai; +{ + char message[100]; + long status; + + pai->dpvt = drvMsg_genXact(((struct msgDset *)(pai->dset))->pparmBlock, &(pai->inp), pai); + + if (pai->dpvt != NULL) + { + status = checkParm(pai, "AI"); + if (status == 0) + drvMsg_initCallback(pai); /* Init for async record completion callback */ + else + pai->pact = 1; /* mark so is never scanned */ + + return(status); + } + pai->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} +/****************************************************************************** + * + * Init record routine for AO + * + ******************************************************************************/ +long +drvMsg_initAo(pao) +struct aoRecord *pao; +{ + long status; + + pao->dpvt = drvMsg_genXact(((struct msgDset *)(pao->dset))->pparmBlock, &(pao->out), pao); + + if (pao->dpvt != NULL) + { + status = checkParm(pao, "AO"); + if (status == 0) + { + drvMsg_initCallback(pao); /* Init for async record completion callback */ + return(2); /* Don't convert RVAL to VAL at this time */ + } + else + pao->pact = 1; /* mark so is never scanned */ + + return(status); + } + pao->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} + +/****************************************************************************** + * + * init record routine for BI + * + ******************************************************************************/ +long +drvMsg_initBi(pbi) +struct biRecord *pbi; +{ + char message[100]; + long status; + + pbi->dpvt = drvMsg_genXact(((struct msgDset *)(pbi->dset))->pparmBlock, &(pbi->inp), pbi); + + if (pbi->dpvt != NULL) + { + status = checkParm(pbi, "BI"); + if (status == 0) + drvMsg_initCallback(pbi); /* Init for async record completion callback */ + else + pbi->pact = 1; /* mark so is never scanned */ + + return(status); + } + pbi->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} +/****************************************************************************** + * + * Init record routine for BO + * + ******************************************************************************/ +long +drvMsg_initBo(pbo) +struct boRecord *pbo; +{ + long status; + + pbo->dpvt = drvMsg_genXact(((struct msgDset *)(pbo->dset))->pparmBlock, &(pbo->out), pbo); + + if (pbo->dpvt != NULL) + { + status = checkParm(pbo, "BO"); + if (status == 0) + { + drvMsg_initCallback(pbo); /* Init for async record completion callback */ + return(2); /* Don't convert RVAL to VAL at this time */ + } + else + pbo->pact = 1; /* mark so is never scanned */ + + return(status); + } + pbo->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} + +/****************************************************************************** + * + * init record routine for MI + * + ******************************************************************************/ +long +drvMsg_initMi(pmi) +struct mbbiRecord *pmi; +{ + char message[100]; + long status; + + pmi->dpvt = drvMsg_genXact(((struct msgDset *)(pmi->dset))->pparmBlock, &(pmi->inp), pmi); + + if (pmi->dpvt != NULL) + { + status = checkParm(pmi, "MBBI"); + if (status == 0) + drvMsg_initCallback(pmi); /* Init for async record completion callback */ + else + pmi->pact = 1; /* mark so is never scanned */ + + return(status); + } + pmi->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} +/****************************************************************************** + * + * Init record routine for MO + * + ******************************************************************************/ +long +drvMsg_initMo(pmo) +struct mbboRecord *pmo; +{ + long status; + + pmo->dpvt = drvMsg_genXact(((struct msgDset *)(pmo->dset))->pparmBlock, &(pmo->out), pmo); + + if (pmo->dpvt != NULL) + { + status = checkParm(pmo, "MBBO"); + if (status == 0) + { + drvMsg_initCallback(pmo); /* Init for async record completion callback */ + return(2); /* Don't convert RVAL to VAL at this time */ + } + else + pmo->pact = 1; /* mark so is never scanned */ + + return(status); + } + pmo->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} + +/****************************************************************************** + * + * init record routine for LI + * + ******************************************************************************/ +long +drvMsg_initLi(pli) +struct longinRecord *pli; +{ + char message[100]; + long status; + + pli->dpvt = drvMsg_genXact(((struct msgDset *)(pli->dset))->pparmBlock, &(pli->inp), pli); + + if (pli->dpvt != NULL) + { + status = checkParm(pli, "LI"); + if (status == 0) + drvMsg_initCallback(pli); /* Init for async record completion callback */ + else + pli->pact = 1; /* mark so is never scanned */ + + return(status); + } + pli->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} +/****************************************************************************** + * + * init record routine for LO + * + ******************************************************************************/ +long +drvMsg_initLo(plo) +struct longoutRecord *plo; +{ + char message[100]; + long status; + + plo->dpvt = drvMsg_genXact(((struct msgDset *)(plo->dset))->pparmBlock, &(plo->out), plo); + + if (plo->dpvt != NULL) + { + status = checkParm(plo, "LO"); + if (status == 0) + drvMsg_initCallback(plo); /* Init for async record completion callback */ + else + plo->pact = 1; /* mark so is never scanned */ + + return(status); + } + plo->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} + +/****************************************************************************** + * + * init record routine for SI + * + ******************************************************************************/ +long +drvMsg_initSi(psi) +struct stringinRecord *psi; +{ + char message[100]; + long status; + + psi->dpvt = drvMsg_genXact(((struct msgDset *)(psi->dset))->pparmBlock, &(psi->inp), psi); + + if (psi->dpvt != NULL) + { + status = checkParm(psi, "SI"); + if (status == 0) + drvMsg_initCallback(psi); /* Init for async record completion callback */ + else + psi->pact = 1; /* mark so is never scanned */ + + return(status); + } + psi->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} +/****************************************************************************** + * + * init record routine for SO + * + ******************************************************************************/ +long +drvMsg_initSo(pso) +struct stringoutRecord *pso; +{ + char message[100]; + long status; + + pso->dpvt = drvMsg_genXact(((struct msgDset *)(pso->dset))->pparmBlock, &(pso->out), pso); + + if (pso->dpvt != NULL) + { + status = checkParm(pso, "SI"); + if (status == 0) + drvMsg_initCallback(pso); /* Init for async record completion callback */ + else + pso->pact = 1; /* mark so is never scanned */ + + return(status); + } + pso->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} + +/****************************************************************************** + * + * init record routine for WF + * + ******************************************************************************/ +long +drvMsg_initWf(pwf) +struct waveformRecord *pwf; +{ + char message[100]; + long status; + + pwf->dpvt = drvMsg_genXact(((struct msgDset *)(pwf->dset))->pparmBlock, &(pwf->inp), pwf); + + if (pwf->dpvt != NULL) + { + status = checkParm(pwf, "WAVEFORM"); + if (status == 0) + drvMsg_initCallback(pwf); /* Init for async record completion callback */ + else + pwf->pact = 1; /* mark so is never scanned */ + + return(status); + } + pwf->pact = 1; /* mark so is never scanned */ + return(S_db_badField); +} + +/****************************************************************************** + * + * Service routines to process a input records. + * + ******************************************************************************/ +long +drvMsg_procAi(pai) +struct aiRecord *pai; +{ + return(drvMsg_proc(pai, 2)); /* no conversion */ +} +long +drvMsg_procBi(pbi) +struct biRecord *pbi; +{ + return(drvMsg_proc(pbi, 0)); /* convert RVAL to VAL */ +} +long +drvMsg_procMi(pmi) +struct mbbiRecord *pmi; +{ + return(drvMsg_proc(pmi, 0)); /* convert RVAL to VAL */ +} +long +drvMsg_procLi(pli) +struct longinRecord *pli; +{ + return(drvMsg_proc(pli, 2)); /* no conversion */ +} +long +drvMsg_procSi(psi) +struct stringinRecord *psi; +{ + return(drvMsg_proc(psi, 2)); /* no conversion */ +} +long +drvMsg_procWf(pwf) +struct waveformRecord *pwf; +{ + return(drvMsg_proc(pwf, 2)); /* no conversion */ +} + +/****************************************************************************** + * + * Service routine to process output records. + * + * It does not make sense to return a conversion code to record support from + * processing an output record. + * + ******************************************************************************/ +long +drvMsg_procAo(pao) +struct aoRecord *pao; +{ + return(drvMsg_proc(pao, 0)); +} +long +drvMsg_procBo(pbo) +struct boRecord *pbo; +{ + return(drvMsg_proc(pbo, 0)); +} +long +drvMsg_procMo(pmo) +struct mbboRecord *pmo; +{ + return(drvMsg_proc(pmo, 0)); +} +long +drvMsg_procLo(plo) +struct longoutRecord *plo; +{ + return(drvMsg_proc(plo, 0)); +} +long +drvMsg_procSo(pso) +struct stringoutRecord *pso; +{ + return(drvMsg_proc(pso, 0)); +} + +/****************************************************************************** + * + * Service routine to process a record. + * + ******************************************************************************/ +static long +drvMsg_proc(prec, ret) +struct dbCommon *prec; /* record to process */ +int ret; /* If all goes well, return this value */ +{ + if (prec->pact) /* if already actively processing, finish up */ + { + if (((msgXact *)(prec->dpvt))->status != XACT_OK) + { /* something went wrong during I/O processing */ + if (msgDebug) + printf("Setting an alarm on record %s\n", prec->name); + + recGblSetSevr(prec, READ_ALARM, VALID_ALARM); + } + else + if (ret == 2) + prec->udf = FALSE; /* Set only if I return 2 (I filled in VAL) */ + + return(ret); + } + /* Not already actively processing, start things going */ + + prec->pact = TRUE; + if (drvMsg_qXact(prec->dpvt, prec->prio) == ERROR) + printf("Error during drvMsg_qXact\n"); + + return(ret); +}