diff --git a/src/drv/drvRs232.c b/src/drv/drvRs232.c index b9a93e3e6..4ea3718c1 100644 --- a/src/drv/drvRs232.c +++ b/src/drv/drvRs232.c @@ -1,8 +1,4 @@ -/* - * drvRs232.c - * share/src/drv $Id$ - */ - +/* share/src/drv $Id$ */ /* * Author: John Winans * Date: 04-13-92 @@ -35,6 +31,8 @@ * */ +#define DRVRS232_C + #include #include #include @@ -51,6 +49,8 @@ #include #include #include +#include +#include #include #include #include @@ -58,7 +58,11 @@ #include #include -static msgDrvBlock drv232Block; +int drv232Debug = 1; + +static void callbackAbortSerial(); +static void dogAbortSerial(); + /****************************************************************************** * ******************************************************************************/ @@ -81,12 +85,13 @@ report() * ******************************************************************************/ static long -init(parm) -int parm; +init(pparms) +msgDrvIniParm *pparms; { printf("Init for RS-232 driver\n"); return(OK); } + /****************************************************************************** * * This function is called to allocate any structures needed to hold @@ -96,35 +101,53 @@ int parm; * ******************************************************************************/ static long -genXact(pparmBlock, plink, pmsgXact) -msgParmBlock *pparmBlock; -struct link *plink; -msgXact *pmsgXact; +genXact(p) +msgDrvGenXParm *p; { - long stat = ERROR; + long stat = -1; + char message[100]; + dev232Link *pdev232Link; -printf("rs232-genXact entered\n"); +printf("RS-232 genXact entered for link %d, addr %d, parm %s\n", p->plink->value.gpibio.link, p->plink->value.gpibio.addr, p->plink->value.gpibio.parm); - pmsgXact->phwpvt = pparmBlock->pmsgHwpvt; - while ((pmsgXact->phwpvt != NULL) && (stat == ERROR)) + p->pmsgXact->phwpvt = p->pmsgXact->pparmBlock->pmsgHwpvt; + pdev232Link = (dev232Link *)(p->pmsgXact->phwpvt->pmsgLink->p); + + while ((p->pmsgXact->phwpvt != NULL) && (stat == -1)) { - if ((((dev232Link *)(pmsgXact->phwpvt->pmsgLink->p))->link == plink->value.gpibio.link) - && (((dev232Link *)(pmsgXact->phwpvt->pmsgLink->p))->port == plink->value.gpibio.addr)) - stat = OK; + if ((pdev232Link->link == p->plink->value.gpibio.link) + && (pdev232Link->port == p->plink->value.gpibio.addr)) + { + if (pdev232Link->pparmBlock != p->pmsgXact->pparmBlock) + { + sprintf(message, "%s: Two different devices on same RS-232 port\n", p->pmsgXact->prec->name); + errMessage(S_db_badField, message); + return(ERROR); + } + else + stat = 0; /* Found the correct hwpvt structure */ + } else - pmsgXact->phwpvt = pparmBlock->pmsgHwpvt->next; + p->pmsgXact->phwpvt = p->pmsgXact->phwpvt->next; } - if (stat != OK) + if (stat != 0) { /* Could not find a msgHwpvt for the right link, create a new one */ - if ((pmsgXact->phwpvt = drvMsg_genHwpvt(pparmBlock, plink)) == NULL) + if ((p->pmsgXact->phwpvt = drvMsg_genHwpvt(p->pmsgXact->pparmBlock, p->plink)) == NULL) return(ERROR); } - pmsgXact->finishProc = NULL; - pmsgXact->psyncSem = NULL; + p->pmsgXact->callback.callback = NULL; + p->pmsgXact->psyncSem = NULL; + if (sscanf(p->plink->value.gpibio.parm,"%d", &(p->pmsgXact->parm)) != 1) + { + p->pmsgXact->prec->pact = TRUE; + sprintf("%s: invalid parameter string >%s<\n", p->pmsgXact->prec->name, p->plink->value.gpibio.parm); + errMessage(S_db_badField, message); + return(ERROR); + } return(OK); } - + /****************************************************************************** * * This function is called to allocate any structures needed to hold @@ -134,30 +157,29 @@ printf("rs232-genXact entered\n"); * ******************************************************************************/ static long -genHwpvt(pparmBlock, plink, pmsgHwpvt) -msgParmBlock *pparmBlock; -struct link *plink; /* I/O link structure from record */ -msgHwpvt *pmsgHwpvt; +genHwpvt(p) +msgDrvGenHParm *p; { int stat = ERROR; printf("rs232-genHwpvt entered\n"); - pmsgHwpvt->pmsgLink = drv232Block.pmsgLink; - while ((pmsgHwpvt->pmsgLink != NULL) && (stat == ERROR)) + p->pmsgHwpvt->pmsgLink = drv232Block.pmsgLink; + while ((p->pmsgHwpvt->pmsgLink != NULL) && (stat == ERROR)) { - if ((((dev232Link *)(pmsgHwpvt->pmsgLink->p))->link == plink->value.gpibio.link) - && (((dev232Link *)(pmsgHwpvt->pmsgLink->p))->port == plink->value.gpibio.addr)) + if ((((dev232Link *)(p->pmsgHwpvt->pmsgLink->p))->link == p->plink->value.gpibio.link) + && (((dev232Link *)(p->pmsgHwpvt->pmsgLink->p))->port == p->plink->value.gpibio.addr)) stat = OK; else - pmsgHwpvt->pmsgLink = pmsgHwpvt->pmsgLink->next; + p->pmsgHwpvt->pmsgLink = p->pmsgHwpvt->pmsgLink->next; } if (stat != OK) { - if ((pmsgHwpvt->pmsgLink = drvMsg_genLink(pparmBlock->pdrvBlock, plink)) == NULL) + if ((p->pmsgHwpvt->pmsgLink = drvMsg_genLink(p->pparmBlock, p->plink)) == NULL) return(ERROR); } return(OK); } + /****************************************************************************** * * This function is called to allocate any structures needed to hold @@ -165,182 +187,344 @@ printf("rs232-genHwpvt entered\n"); * ******************************************************************************/ static long -genLink(pmsgLink, plink, opCode) -msgLink *pmsgLink; -struct link *plink; -int opCode; +genLink(p) +msgDrvGenLParm *p; { char name[20]; + char message[100]; + dev232Link *pdev232Link; - switch (opCode) { +printf("In RS-232's genLink, link = %d, addr = %d\n", p->plink->value.gpibio.link,p->plink->value.gpibio.addr); + + switch (p->op) { case MSG_GENLINK_CREATE: - if ((pmsgLink->p = malloc(sizeof(dev232Link))) == NULL) + if ((p->pmsgLink->p = malloc(sizeof(dev232Link))) == NULL) return(ERROR); - ((dev232Link *)(pmsgLink->p))->link = plink->value.gpibio.link; - ((dev232Link *)(pmsgLink->p))->port = plink->value.gpibio.addr; + pdev232Link = (dev232Link *)(p->pmsgLink->p); + + pdev232Link->link = p->plink->value.gpibio.link; + pdev232Link->port = p->plink->value.gpibio.addr; + pdev232Link->pparmBlock = p->pparmBlock; + + if ((pdev232Link->doggie = wdCreate()) == NULL) + { + printf("RS-232 driver can't create a watchdog\n"); + /* errMessage(******, message); */ + return(ERROR); + } + + sprintf(name, "/tyCo/%d", p->plink->value.gpibio.addr); +printf ("in genlink opening >%s<, baud %d\n", name, ((dev232ParmBlock *)(p->pparmBlock->p))->baud); + + if ((((dev232Link *)(p->pmsgLink->p))->ttyFd = open(name, O_RDWR, 0)) != -1) + { +printf("Successful open w/fd=%d\n", pdev232Link->ttyFd); + /* set baud rate and unbuffered mode */ + (void) ioctl (pdev232Link->ttyFd, FIOBAUDRATE, ((dev232ParmBlock *)(p->pparmBlock->p))->baud); + (void) ioctl (pdev232Link->ttyFd, FIOSETOPTIONS, ((dev232ParmBlock *)(p->pparmBlock->p))->ttyOptions); + + pdev232Link->callback.callback = callbackAbortSerial; + pdev232Link->callback.priority = priorityHigh; + pdev232Link->callback.user = (void *) pdev232Link; - sprintf(name, "/tyCo/%d", plink->value.gpibio.addr); - if ((((dev232Link *)(pmsgLink->p))->ttyFd = open(name, O_RDWR, 0)) != -1) return(OK); - - free(pmsgLink->p); - return(ERROR); + } + else + { + printf("RS-232 genLink failed to open the tty port\n"); + free(p->pmsgLink->p); + return(ERROR); + } case MSG_GENLINK_ABORT: - return(free(pmsgLink->p)); +printf("RS-232 genLink called with abort status\n"); + pdev232Link = (dev232Link *)(p->pmsgLink->p); + /* free(p->pmsgLink->p); Don't forget to take it out of the list */ + return(OK); } return(ERROR); } + /****************************************************************************** * - * This function is called to verify the validity of the link information - * given in a link.value structure (defined in link.h) + * This function is called to allow the device to indicate that a device-related + * event has occurred. If an event had occurred, it would have to place the + * address of a valid transaction structure in pxact. This xact structure + * will then be processed by the message link task as indicated by the + * return code of this function. * + * MSG_EVENT_NONE = no event has occurred, pxact not filled in. + * MSG_EVENT_WRITE = event occurred, process the writeOp assoc'd w/pxact. + * MSG_EVENT_READ = event occurred, process the readOp assoc'd w/pxact. + * + * Note that MSG_EVENT_READ only makes sense when returned with a transaction + * that has deferred readback specified for its readOp function. Because if + * it is NOT a deferred readback, it will be done immediately after the writeOp. + * Even if that writeOp was due to a MSG_EVENT_WRITE from this function. + * ******************************************************************************/ static long -checkLink() -{ - return(ERROR); -} -static long -checkEvent(pdrvBlock, pmsgLink, pxact) -msgDrvBlock *pdrvBlock; -msgLink *pmsgLink; -msgXact *pxact; +checkEvent(p) +msgChkEParm *p; { return(MSG_EVENT_NONE); } - - -#if FALSE -/****************************************************************************** - * - * Check to see if a link number is valid or not. - * - * Return -1 if invalid link number. - * 0 if valid link number and is currently open. - * 1 if valid link number, but not open. - * - ******************************************************************************/ -int -checkLink(link) -int link; +static void +dogAbortSerial(pdev232Link) +dev232Link *pdev232Link; { - if ((link < 1) || (link >= NUM_TY_LINKS)) - return(-1); + logMsg("RS-232 driver watch-dog timeout on link %d, port %d, fd=%d\n", pdev232Link->link, pdev232Link->port, pdev232Link->ttyFd); - if (rsLink[link] == NULL) - return(1); - else - return(0); + /* Annoying vxWorks implementation... can't IOCTL from here */ + callbackRequest(&(pdev232Link->callback)); } -drv232Write() +static void +callbackAbortSerial(p) +CALLBACK *p; { - /* Perform the transaction operation */ - xact->status = XACT_OK; /* All well, so far */ + ((dev232Link *)(p->user))->dogAbort = TRUE; - len = xact->txLen; - if (len == -1) - len = strlen(xact->txMsg); - - if(len > 0) - { - if (write(rsLink[link].ttyFd, xact->txMsg, len) != len) - { - printf("write error to link %d\n", link); - xact->status = XACT_IOERR; - } - } -} -drv232Read() -{ - if ((xact->rxLen > 0) && (xact->status == XACT_OK)) - { - if (xact->rxEoi != -1) - { - len = xact->rxLen; - ch = xact->rxMsg; - eoi = xact->rxEoi & 0xff; - *ch = eoi + 1; /* make sure gets into loop on first */ - while (len > 0) - { - read(rsLink[link].ttyFd, ch, 1); - if (*ch == eoi) - break; - ch++; - len--; - } - if (*ch != eoi) - xact->status = XACT_LENGTH; - } - else - { /* Read xact->rxLen bytes from the device */ - len = xact->rxLen; - while(len) - len -= read(rsLink[link].ttyFd, xact->rxMsg, len); - } - } + ioctl(((dev232Link *)(p->user))->ttyFd, FIOCANCEL); + /* I am not sure if I should really do this, but... */ + ioctl(((dev232Link *)(p->user))->ttyFd, FIOFLUSH); } -/* create an interactive RS232 transaction from the console */ - -static SEM_ID iSem; -static int firstFlag = 1; -rsx(l, ch) -int l; -unsigned char *ch; +/****************************************************************************** + * + * This function is used to write a string of characters out to an RS-232 + * device. + * + ******************************************************************************/ +static long +drvWrite(pxact, pwrParm) +msgXact *pxact; +msgStrParm *pwrParm; { - struct xact232 xact; - unsigned char rxBuf[100]; + dev232Link *pdev232Link = (dev232Link *)(pxact->phwpvt->pmsgLink->p); + int len; + char *out; + char in; - if (firstFlag) + if (wdStart(pdev232Link->doggie, ((dev232ParmBlock *)(pxact->pparmBlock->p))->dmaTimeout, dogAbortSerial, pdev232Link) == ERROR) { - iSem = semBCreate(SEM_Q_PRIORITY, SEM_EMPTY); - firstFlag = 0; + printf("RS-232 driver can not start watchdog timer\n"); + /* errMessage(***,message); */ + pxact->status = XACT_IOERR; + return(pxact->status); } - xact.finishProc = NULL; - xact.psyncSem = &iSem; - xact.link = l; - xact.txMsg = ch; - xact.txLen = -1; + if (((dev232ParmBlock *)(pxact->pparmBlock->p))->flags & ECHO) + { /* ping-pong the characters out */ - xact.rxMsg = rxBuf; - xact.rxEoi = '\r'; - xact.rxLen = sizeof(rxBuf); + /*BUG ??? This will only work if we are sure that the RX buffer is clean */ + ioctl(pdev232Link->ttyFd, FIORFLUSH); - rxBuf[0] = '\0'; - if (qXact(&xact, RS_Q_LOW) == ERROR) - return(ERROR); + out = pwrParm->buf; + while ((*out != '\0') && (pxact->status == XACT_OK)) + { + if (drv232Debug > 5) + printf("out >%c<\n", *out); + if (write(pdev232Link->ttyFd, out, 1) != 1) + { + printf("RS-232 write error on link %d, port %d\n", pdev232Link->link, pdev232Link->port); + pxact->status = XACT_IOERR; + } + else + { + if (read(pdev232Link->ttyFd, &in, 1) != 1) + { +printf("Read problem encountered in echo reading mode of a write operation\n"); + if (pdev232Link->dogAbort) + pxact->status = XACT_TIMEOUT; + else + pxact->status = XACT_IOERR; + } + else + { + if (*out != in) + printf("echo response out of sync! sent >%c< got >%c<\n", *out, in); + + if (drv232Debug > 5) + printf("in >%c<\n", in); + + if ((*out == '\r') && (((dev232ParmBlock *)(pxact->pparmBlock->p))->flags & CRLF)) + { + if (read(pdev232Link->ttyFd, &in, 1) != 1) + { +printf("Read problem encountered in echo reading mode of a write operation\n"); + if (pdev232Link->dogAbort) + pxact->status = XACT_TIMEOUT; + else + pxact->status = XACT_IOERR; + } + else + { + if (drv232Debug > 5) + printf("in >%c<\n", in); + } + } + } + } + out++; + } + } + else + { + if (pwrParm->len == -1) + len = strlen(pwrParm->buf); + else + len = pwrParm->len; - semTake(iSem, WAIT_FOREVER); + if (drv232Debug > 4) + printf("block-writing >%s<\n", pwrParm->buf); - printf("Sent >%s< got >%s<\n", ch, rxBuf); - return(xact.status); + if (write(pdev232Link->ttyFd, pwrParm->buf, len) != len) + { + printf("RS-232 write error on link %d, port %d\n", pdev232Link->link, pdev232Link->port); + pxact->status = XACT_IOERR; + } + } + if (wdCancel(pdev232Link->doggie) == ERROR) + printf("Can not cancel RS-232 watchdog timer\n"); + + return(pxact->status); +} + +/****************************************************************************** + * + * This function is used to read a string of characters from an RS-232 device. + * + ******************************************************************************/ +static long +drvRead(pxact, prdParm) +msgXact *pxact; +msgStrParm *prdParm; +{ + dev232Link *pdev232Link = (dev232Link *)(pxact->phwpvt->pmsgLink->p); + int len; + int clen; + char *ch; + int flags; + int eoi; + dev232ParmBlock *pdev232ParmBlock = (dev232ParmBlock *)(pxact->pparmBlock->p); + + pdev232Link->dogAbort = FALSE; + if (wdStart(pdev232Link->doggie, pdev232ParmBlock->dmaTimeout, dogAbortSerial, pdev232Link) == ERROR) + { + printf("RS-232 driver can not start watchdog timer\n"); + /* errMessage(***,message); */ + pxact->status = XACT_IOERR; + return(pxact->status); + } + + ch = prdParm->buf; + len = prdParm->len - 1; + + flags = pdev232ParmBlock->flags; +/* BUG -- This should have a timeout check specified in here */ + if ((pdev232ParmBlock->eoi != -1) || (flags & KILL_CRLF)) + { + eoi = 0; + while ((!eoi) && (len > 0)) + { + if (read(pdev232Link->ttyFd, ch, 1) != 1) + { +printf("Read problem encountered in eoi/KILL_CRLF reading mode\n"); + if (pdev232Link->dogAbort) + pxact->status = XACT_TIMEOUT; + else + pxact->status = XACT_IOERR; + eoi = 1; + } + else + { + if (drv232Debug > 6) + printf("in >%c<\n", *ch); + + if (*ch == pdev232ParmBlock->eoi) + eoi = 1; + + if (!(flags & KILL_CRLF) || ((*ch != '\n') && (*ch != '\r'))) + { + ch++; + len--; /* To count the \n's and \r's or not to count... */ + } + } + } + if (len == 0) + { + printf("buffer length overrun during read operation\n"); + pxact->status = XACT_LENGTH; + } + + *ch = '\0'; + } + else + { /* Read xact->rxLen bytes from the device */ + while(len) + { + clen = read(pdev232Link->ttyFd, ch, len); + if (pdev232Link->dogAbort) + { +printf("Read problem encountered in raw mode\n"); + pxact->status = XACT_TIMEOUT; + len = 0; + } + else + { + len -= clen; + ch += clen; + } + } + *ch = '\0'; + } + if (drv232Debug) + printf("drvRead: got >%s<\n", prdParm->buf); + + if (wdCancel(pdev232Link->doggie) == ERROR) + printf("Can not cancel RS-232 watchdog timer, dogAbort=%d \n", pdev232Link->dogAbort); + + return(pxact->status); +} + +static long +drvIoctl(cmd, pparm) +int cmd; +void *pparm; +{ + switch (cmd) { + case MSGIOCTL_REPORT: + return(report()); + case MSGIOCTL_INIT: + return(init(pparm)); + case MSGIOCTL_INITREC: + printf("drv232Block.drvIoctl got a MSGIOCTL_INITREC request!\n"); + return(ERROR); + case MSGIOCTL_GENXACT: + return(genXact(pparm)); + case MSGIOCTL_GENHWPVT: + return(genHwpvt(pparm)); + case MSGIOCTL_GENLINK: + return(genLink(pparm)); + case MSGIOCTL_CHECKEVENT: + return(checkEvent(pparm)); + } + return(ERROR); } -#endif - - -static msgDrvBlock drv232Block = { - report, - init, - NULL, - genXact, - genHwpvt, - genLink, - checkLink, - checkEvent, - NULL, +msgDrvBlock drv232Block = { "RS232", RSLINK_PRI, RSLINK_OPT, RSLINK_STACK, - NULL + NULL, + drvWrite, + drvRead, + drvIoctl };