asynStatus sendCmd(asynUser *pasynUser, myData *pPvt, char* cmd ) { char buffer[BUFFER_SIZE]; int nread, nwrite, eomReason; asynStatus status; buffer[0] = 0; status = pasynOctetSyncIO->writeRead( pasynUser, cmd, strlen(cmd), buffer, BUFFER_SIZE, pPvt->readTimeout, &nwrite, &nread, &eomReason ); switch (status) { case asynTimeout: asynPrint(pasynUser, ASYN_TRACE_ERROR, "testPmacAsynIPPort: TIMEOUT\n"); /* no break - fall throught to asynSuccess */ case asynSuccess: asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,cmd,strlen(cmd), "testPmacAsynIPPort: %s write %d:\n",pPvt->portName,strlen(cmd)); asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,buffer,nread, "testPmacAsynIPPort: %s read %d:\n",pPvt->portName,nread); break; default: asynPrint(pasynUser, ASYN_TRACE_ERROR, "testPmacAsynIPPort: writeRead error on: %s: write %d: %s, status=%d error=%s\n", pPvt->portName, strlen(cmd), cmd, status, pasynUser->errorMessage); break; } return status; }
static int readCvtio(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3) { stringinRecord *precord = (stringinRecord*)pgpibDpvt->precord; asynUser *pasynUser = pgpibDpvt->pasynUser; gpibCmd *pgpibCmd = gpibCmdGet(pgpibDpvt); asynOctet *pasynOctet = pgpibDpvt->pasynOctet; void *asynOctetPvt = pgpibDpvt->asynOctetPvt; asynStatus status; size_t nchars = 0, lenmsg = 0; pgpibDpvt->msgInputLen = 0; assert(pgpibCmd->cmd); lenmsg = strlen(pgpibCmd->cmd); status = pasynOctet->write(asynOctetPvt,pasynUser, pgpibCmd->cmd,lenmsg,&nchars); if(nchars==lenmsg) { asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,pgpibCmd->cmd,nchars, "%s readCvtio\n",precord->name); } else { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s write status \"%s\" requested %d but sent %d bytes\n", precord->name,pasynUser->errorMessage,lenmsg,nchars); return -1; } if(!pgpibDpvt->msg) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s pgpibDpvt->msg is null\n",precord->name); nchars = 0; return -1; } else { status = pasynOctet->read(asynOctetPvt,pasynUser, pgpibDpvt->msg,pgpibCmd->msgLen,&nchars,0); } asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s readCvtio nchars %d\n", precord->name,nchars); if(nchars > 0) { asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,pgpibDpvt->msg,nchars, "%s readCvtio\n",precord->name); } else { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s read status \"%s\" nin %d\n", precord->name, pasynUser->errorMessage,nchars); pgpibDpvt->msgInputLen = 0; return -1; } pgpibDpvt->msgInputLen = nchars; if(nchars<pgpibCmd->msgLen) pgpibDpvt->msg[nchars] = 0; readString(pgpibDpvt,P1,P2,P3); return 0; }
static asynStatus gpibPortGetEos(void *pdrvPvt,asynUser *pasynUser, char *eos, int eossize, int *eoslen) { niport *pniport = (niport *)pdrvPvt; int addr = 0; asynStatus status; status = pasynManager->getAddr(pasynUser,&addr); if(status!=asynSuccess) return status; if(eossize<1) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s addr %d gpibPortGetEos eossize %d too small\n", pniport->portName,addr,eossize); *eoslen = 0; return asynError; } if(pniport->eos==-1) { *eoslen = 0; } else { eos[0] = (unsigned int)pniport->eos; *eoslen = 1; } asynPrintIO(pasynUser, ASYN_TRACE_FLOW, eos, *eoslen, "%s addr %d gpibPortGetEos eoslen %d\n",pniport->portName,addr,eoslen); return asynSuccess; }
static asynStatus gpibPortWrite(void *pdrvPvt,asynUser *pasynUser, const char *data,int numchars,int *nbytesTransfered) { niport *pniport = (niport *)pdrvPvt; int actual = 0; double timeout = pasynUser->timeout; int addr = 0; asynStatus status; status = pasynManager->getAddr(pasynUser,&addr); if(status!=asynSuccess) return status; asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s addr %d gpibPortWrite nchar %d\n", pniport->portName,addr,numchars); pniport->errorMessage[0] = 0; status = writeGpib(pniport,data,numchars,&actual,addr,timeout); if(status!=asynSuccess) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s writeGpib failed %s",pniport->portName,pniport->errorMessage); } else if(actual!=numchars) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s requested %d but sent %d bytes",pniport->portName,numchars,actual); status = asynError; } asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER, data,actual,"%s addr %d gpibPortWrite\n",pniport->portName,addr); *nbytesTransfered = actual; return status; }
static asynStatus readIt(asynUser *pasynUser, char *buffer, size_t buffer_len, double timeout, size_t *nbytesTransfered,int *eomReason) { asynStatus status, unlockStatus; ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; pasynUser->timeout = timeout; status = pasynManager->queueLockPort(pasynUser); if(status!=asynSuccess) { return status; } status = pioPvt->pasynOctet->read( pioPvt->octetPvt,pasynUser,buffer,buffer_len,nbytesTransfered,eomReason); if(status==asynSuccess) { asynPrintIO(pasynUser, ASYN_TRACEIO_DEVICE, buffer,*nbytesTransfered,"asynOctetSyncIO read:\n"); } unlockStatus = pasynManager->queueUnlockPort(pasynUser); if (unlockStatus != asynSuccess) { return unlockStatus; } return status; }
/* * asynOctet methods */ static asynStatus writeIt(void *drvPvt, asynUser *pasynUser, const char *data, size_t numchars,size_t *nbytesTransfered) { usbController_t *usb = (usbController_t *)drvPvt; double cmdstr[3]; unsigned char cmd[3]; assert(usb); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s write.\n", usb->usbDeviceName); asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, numchars, "%s write %d\n", usb->usbDeviceName, numchars); if (usb->dev == NULL) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s disconnected:", usb->usbDeviceName); return asynError; } if (sscanf(data, "%lf %lf %lf", &cmdstr[0], &cmdstr[1], &cmdstr[2])!=3) return asynError; cmd[0] = cmdstr[0]; cmd[1] = cmdstr[1]; cmd[2] = cmdstr[2]; if (numchars!=3) numchars = 3; *nbytesTransfered = 0; *nbytesTransfered = libusb_control_transfer(usb->handle, 0x40, 6, 0x100, 0, cmd, (uint16_t)numchars, 0); if (*nbytesTransfered>=numchars) return asynSuccess; else return asynError; return asynSuccess; }
static int writeCvtio(gpibDpvt *pgpibDpvt,int P1, int P2, char **P3) { stringoutRecord *precord = (stringoutRecord*)pgpibDpvt->precord; asynUser *pasynUser = pgpibDpvt->pasynUser; asynOctet *pasynOctet = pgpibDpvt->pasynOctet; void *asynOctetPvt = pgpibDpvt->asynOctetPvt; asynStatus status; size_t nsent = 0, lenmsg = 0; pgpibDpvt->msgInputLen = 0; lenmsg = writeString(pgpibDpvt,P1,P2,P3); if(lenmsg <= 0) return -1; status = pasynOctet->write(asynOctetPvt,pasynUser, pgpibDpvt->msg,lenmsg,&nsent); if(nsent==lenmsg) { asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,pgpibDpvt->msg,lenmsg, "%s writeCvtio\n",precord->name); } else { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s write status \"%s\" requested %d but sent %d bytes\n", precord->name,pasynUser->errorMessage,lenmsg,nsent); return -1; } return 0; }
static asynStatus writeIt(asynUser *pasynUser,const char *message,size_t nbytes) { devPvt *pdevPvt = (devPvt *)pasynUser->userPvt; dbCommon *precord = pdevPvt->precord; asynOctet *poctet = pdevPvt->poctet; void *octetPvt = pdevPvt->octetPvt; asynStatus status; size_t nbytesTransfered; status = poctet->write(octetPvt,pasynUser,message,nbytes,&nbytesTransfered); if(status!=asynSuccess) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s devTestBlock: writeIt failed %s\n", precord->name,pasynUser->errorMessage); recGblSetSevr(precord, WRITE_ALARM, INVALID_ALARM); return status; } if(nbytes != nbytesTransfered) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s devTestBlock: writeIt requested %lu but sent %lu bytes\n", precord->name,(unsigned long)nbytes,(unsigned long)nbytesTransfered); recGblSetSevr(precord, WRITE_ALARM, MINOR_ALARM); return asynError; } asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,message,nbytes, "%s devTestBlock: writeIt\n",precord->name); return status; }
static asynStatus gpibPortAddressedCmd(void *pdrvPvt,asynUser *pasynUser, const char *data, int length) { niport *pniport = (niport *)pdrvPvt; double timeout = pasynUser->timeout; int addr = 0; int actual; asynStatus status; char cmdbuf[2] = {IBUNT,IBUNL}; status = pasynManager->getAddr(pasynUser,&addr); if(status!=asynSuccess) return status; asynPrint(pasynUser,ASYN_TRACE_FLOW, "%s addr %d gpibPortAddressedCmd nchar %d\n", pniport->portName,addr,length); pniport->errorMessage[0] = 0; status = writeAddr(pniport,0,addr,timeout,transferStateIdle); if(status==asynSuccess) { status=writeCmd(pniport,data,length,timeout,transferStateIdle); } if(status!=asynSuccess) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s writeGpib failed %s",pniport->portName,pniport->errorMessage); } actual = length - pniport->bytesRemainingCmd; asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER, data,actual,"%s gpibPortAddressedCmd\n",pniport->portName); if(status!=asynSuccess) return status; writeCmd(pniport,cmdbuf,2,timeout,transferStateIdle); return status; }
static asynStatus writeRead(asynUser *pasynUser, const char *write_buffer, size_t write_buffer_len, char *read_buffer, size_t read_buffer_len, double timeout, size_t *nbytesOut, size_t *nbytesIn,int *eomReason) { asynStatus status, unlockStatus; ioPvt *pioPvt = (ioPvt *)pasynUser->userPvt; pasynUser->timeout = timeout; status = pasynManager->queueLockPort(pasynUser); if(status!=asynSuccess) { return status; } status = pioPvt->pasynOctet->flush(pioPvt->octetPvt,pasynUser); if(status!=asynSuccess) { goto bad; } status = pioPvt->pasynOctet->write( pioPvt->octetPvt,pasynUser,write_buffer,write_buffer_len,nbytesOut); if(status!=asynSuccess) { goto bad; } else { asynPrintIO(pasynUser, ASYN_TRACEIO_DEVICE, write_buffer,*nbytesOut,"asynOctetSyncIO wrote:\n"); } status = pioPvt->pasynOctet->read( pioPvt->octetPvt,pasynUser,read_buffer,read_buffer_len,nbytesIn,eomReason); if(status!=asynSuccess) { goto bad; } else { asynPrintIO(pasynUser, ASYN_TRACEIO_DEVICE, read_buffer,*nbytesIn,"asynOctetSyncIO read:\n"); } bad: unlockStatus = pasynManager->queueUnlockPort(pasynUser); if (unlockStatus != asynSuccess) { return unlockStatus; } return status; }
static asynStatus readIt(void *ppvt, asynUser *pasynUser, char *data, size_t maxchars, size_t *nbytesTransfered, int *eomReason) { interposePvt *pinterposePvt = (interposePvt *)ppvt; int eom; size_t nRead, nCheck; char *iac; char *base = data; int unstuffed = 0; asynStatus status; status = pinterposePvt->pasynOctetDrv->read(pinterposePvt->drvPvt, pasynUser, data, maxchars, &nRead, &eom); if (status != asynSuccess) return status; nCheck = nRead; while ((iac = memchr(data, C_IAC, nCheck)) != NULL) { int c; unstuffed = 1; eom &= ~ASYN_EOM_CNT; if (iac == data + nCheck - 1) { c = nextChar(pinterposePvt, pasynUser); iac--; } else { c = *(iac + 1) & 0xFF; nRead--; } if (c != C_IAC) { epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "Missing IAC"); return asynError; } nCheck -= (iac - data) + 2; data = iac + 1; if (nCheck == 0) break; memmove(data, data + 1, nCheck); } if (unstuffed) asynPrintIO(pasynUser, ASYN_TRACEIO_FILTER, base, nRead, "nRead %d after IAC unstuffing", (int)nRead); if (nRead == maxchars) eom |= ASYN_EOM_CNT; *nbytesTransfered = nRead; if (eomReason) *eomReason = eom; return asynSuccess; }
static asynStatus gpibPortUniversalCmd(void *pdrvPvt, asynUser *pasynUser, int cmd) { niport *pniport = (niport *)pdrvPvt; double timeout = pasynUser->timeout; asynStatus status; char buffer[1]; asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s gpibPortUniversalCmd %2.2x\n", pniport->portName,cmd); pniport->errorMessage[0] = 0; buffer[0] = cmd; status = writeCmd(pniport,buffer,1,timeout,transferStateIdle); if(status!=asynSuccess) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s writeGpib failed %s",pniport->portName,pniport->errorMessage); } asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER, buffer,1,"%s gpibPortUniversalCmd\n",pniport->portName); return status; }
static asynStatus readIt(asynUser *pasynUser,char *message, size_t maxBytes, size_t *nBytesRead) { devPvt *pdevPvt = (devPvt *)pasynUser->userPvt; dbCommon *precord = pdevPvt->precord; asynOctet *poctet = pdevPvt->poctet; void *octetPvt = pdevPvt->octetPvt; asynStatus status; int eomReason; status = poctet->read(octetPvt,pasynUser,message,maxBytes, nBytesRead,&eomReason); if(status!=asynSuccess) { asynPrint(pasynUser,ASYN_TRACE_ERROR, "%s devTestBlock: readIt failed %s\n", precord->name,pasynUser->errorMessage); recGblSetSevr(precord, READ_ALARM, INVALID_ALARM); return status; } asynPrintIO(pasynUser,ASYN_TRACEIO_DEVICE,message,*nBytesRead, "%s devTestBlock: readIt eomReason %d\n",precord->name,eomReason); return status; }
static asynStatus gpibPortRead(void *pdrvPvt,asynUser *pasynUser, char *data,int maxchars,int *nbytesTransfered,int *eomReason) { niport *pniport = (niport *)pdrvPvt; int actual = 0; double timeout = pasynUser->timeout; int addr = 0; asynStatus status; status = pasynManager->getAddr(pasynUser,&addr); if(status!=asynSuccess) return status; asynPrint(pasynUser,ASYN_TRACE_FLOW,"%s addr %d gpibPortRead\n", pniport->portName,addr); pniport->errorMessage[0] = 0; status = readGpib(pniport,data,maxchars,&actual,addr,timeout,eomReason); if(status!=asynSuccess) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s readGpib failed %s",pniport->portName,pniport->errorMessage); } asynPrintIO(pasynUser,ASYN_TRACEIO_DRIVER, data,actual,"%s addr %d gpibPortRead\n",pniport->portName,addr); *nbytesTransfered = actual; return status; }
/* * Read from the serial line */ static asynStatus readIt(void *drvPvt, asynUser *pasynUser, char *data, size_t maxchars,size_t *nbytesTransfered,int *gotEom) { ttyController_t *tty = (ttyController_t *)drvPvt; int thisRead; int nRead = 0; int timerStarted = 0; asynStatus status = asynSuccess; assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s read.\n", tty->serialDeviceName); if (tty->fd < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s disconnected:", tty->serialDeviceName); return asynError; } if (maxchars <= 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s maxchars %d Why <=0?",tty->serialDeviceName,(int)maxchars); return asynError; } if (tty->readTimeout != pasynUser->timeout) { #ifndef vxWorks /* * Must set flags if we're transitioning * between blocking and non-blocking. */ if ((pasynUser->timeout == 0) || (tty->readTimeout == 0)) { int newFlags = (pasynUser->timeout == 0) ? O_NONBLOCK : 0; if (fcntl(tty->fd, F_SETFL, newFlags) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set %s file flags: %s", tty->serialDeviceName, strerror(errno)); closeConnection(pasynUser,tty); return asynError; } } /* * Set TERMIOS timeout */ if (pasynUser->timeout > 0) { int t = (pasynUser->timeout * 10) + 1; if (t > 255) t = 255; tty->termios.c_cc[VMIN] = 0; tty->termios.c_cc[VTIME] = t; } else if (pasynUser->timeout == 0) { tty->termios.c_cc[VMIN] = 0; tty->termios.c_cc[VTIME] = 0; } else { tty->termios.c_cc[VMIN] = 1; tty->termios.c_cc[VTIME] = 0; } if (tcsetattr(tty->fd, TCSANOW, &tty->termios) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set \"%s\" c_cc[VTIME]: %s", tty->serialDeviceName, strerror(errno)); closeConnection(pasynUser,tty); return asynError; } #endif tty->readTimeout = pasynUser->timeout; } tty->timeoutFlag = 0; if (gotEom) *gotEom = 0; for (;;) { #ifdef vxWorks /* * vxWorks has neither poll() nor termios but does have the * ability to cancel an operation in progress. If the read * timeout is zero we have to check for characters explicitly * since we don't want to start a timer with 0 delay. */ if (tty->readTimeout == 0) { int nready; ioctl(tty->fd, FIONREAD, (int)&nready); if (nready == 0) { tty->timeoutFlag = 1; break; } } #endif if (!timerStarted && (tty->readTimeout > 0)) { epicsTimerStartDelay(tty->timer, tty->readTimeout); timerStarted = 1; } thisRead = read(tty->fd, data, maxchars); if (thisRead > 0) { asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, thisRead, "%s read %d\n", tty->serialDeviceName, thisRead); nRead = thisRead; tty->nRead += thisRead; break; } else { if ((thisRead < 0) && (errno != EWOULDBLOCK) && (errno != EINTR) && (errno != EAGAIN)) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s read error: %s", tty->serialDeviceName, strerror(errno)); closeConnection(pasynUser,tty); status = asynError; break; } if (tty->readTimeout == 0) tty->timeoutFlag = 1; } if (tty->timeoutFlag) break; } if (timerStarted) epicsTimerCancel(tty->timer); if (tty->timeoutFlag && (status == asynSuccess)) status = asynTimeout; *nbytesTransfered = nRead; /* If there is room add a null byte */ if (nRead < maxchars) data[nRead] = 0; else if (gotEom) *gotEom = ASYN_EOM_CNT; asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s read %lu, return %d\n", tty->serialDeviceName, (unsigned long)*nbytesTransfered, status); return status; }
/* * Write to the serial line */ static asynStatus writeIt(void *drvPvt, asynUser *pasynUser, const char *data, size_t numchars,size_t *nbytesTransfered) { ttyController_t *tty = (ttyController_t *)drvPvt; int thisWrite; int nleft = numchars; int timerStarted = 0; asynStatus status = asynSuccess; assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s write.\n", tty->serialDeviceName); asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, numchars, "%s write %lu\n", tty->serialDeviceName, (unsigned long)numchars); if (tty->fd < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s disconnected:", tty->serialDeviceName); return asynError; } if (numchars == 0) { *nbytesTransfered = 0; return asynSuccess; } if (tty->writeTimeout != pasynUser->timeout) { #ifndef vxWorks /* * Must set flags if we're transitioning * between blocking and non-blocking. */ if ((pasynUser->timeout == 0) || (tty->writeTimeout == 0)) { int newFlags = (pasynUser->timeout == 0) ? O_NONBLOCK : 0; if (fcntl(tty->fd, F_SETFL, newFlags) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set %s file flags: %s", tty->serialDeviceName, strerror(errno)); closeConnection(pasynUser,tty); return asynError; } } #endif tty->writeTimeout = pasynUser->timeout; } tty->timeoutFlag = 0; nleft = numchars; #ifdef vxWorks if (tty->writeTimeout >= 0) #else if (tty->writeTimeout > 0) #endif { epicsTimerStartDelay(tty->timer, tty->writeTimeout); timerStarted = 1; } for (;;) { thisWrite = write(tty->fd, (char *)data, nleft); if (thisWrite > 0) { tty->nWritten += thisWrite; nleft -= thisWrite; if (nleft == 0) break; data += thisWrite; } if (tty->timeoutFlag || (tty->writeTimeout == 0)) { status = asynTimeout; break; } if ((thisWrite < 0) && (errno != EWOULDBLOCK) && (errno != EINTR) && (errno != EAGAIN)) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s write error: %s", tty->serialDeviceName, strerror(errno)); closeConnection(pasynUser,tty); status = asynError; break; } } if (timerStarted) epicsTimerCancel(tty->timer); *nbytesTransfered = numchars - nleft; asynPrint(pasynUser, ASYN_TRACE_FLOW, "wrote %lu to %s, return %s\n", (unsigned long)*nbytesTransfered, tty->serialDeviceName, pasynManager->strStatus(status)); return status; }
/** This thread is woken up by an interrupt or a request to read status * It loops calling readFIFO until acquiring_ goes to false. * readFIFO only reads a limited amount of FIFO data at once in order * to avoid blocking the device support threads. */ void drvSIS3801::readFIFOThread() { int count; int signal; int chan; int nChans; int status; int i; bool acquiring; // We have a separate flag because we need to continue processing one last // time even if acquiring_ goes to false because acquisition was manually stopped epicsUInt32 scalerPresets[SIS38XX_MAX_SIGNALS]; epicsUInt32 *pOut=NULL; epicsTimeStamp t1, t2; static const char* functionName="readFIFOThread"; while(true) { epicsEventWait(readFIFOEventId_); // We got an event, which can come from acquisition starting, or FIFO full interrupt asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: got readFIFOEvent, eventType=%d, interrupt status=0x%8.8x\n", driverName, functionName, eventType_, registers_->csr_reg & 0xFFF00000); lock(); acquiring = acquiring_; unlock(); while (acquiring) { lock(); for (i=0; i<maxSignals_; i++) getIntegerParam(i, scalerPresets_, (int *)&scalerPresets[i]); getIntegerParam(mcaNumChannels_, &nChans); asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: scaler presets[0]=%d, scalerData[0]=%d\n", driverName, functionName, scalerPresets[0], scalerData_[0]); signal = nextSignal_; chan = nextChan_; count = 0; // This block of code can be slow and does not require the asynPortDriver lock because we are not // accessing object data that could change. // It does require the FIFO lock so no one resets the FIFO while it executes epicsMutexLock(fifoLockId_); unlock(); epicsTimeGetCurrent(&t1); /* Read out FIFO. It would be more efficient not to check the empty * flag on each transfer, using the almost empty flag. But this has gotten * too complex, and is unlikely to save time on new boards with lots of * memory. */ if (acquireMode_== ACQUIRE_MODE_MCS) { // Copy the data from the FIFO to the mcsBuffer pOut = mcsData_ + signal*maxChans_ + chan; asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: pOut=%p, signal=%d, chan=%d\n", driverName, functionName, pOut, signal, chan); while (((registers_->csr_reg & STATUS_M_FIFO_FLAG_EMPTY)==0) && (chan < nChans) && acquiring_) { *pOut = registers_->fifo_reg; signal++; count++; if (signal >= maxSignals_) { signal = 0; chan++; pOut = mcsData_ + chan; } else { pOut += maxChans_; } } } else if (acquireMode_ == ACQUIRE_MODE_SCALER) { while ((registers_->csr_reg & STATUS_M_FIFO_FLAG_EMPTY)==0 && acquiring_) { scalerData_[signal] += registers_->fifo_reg; signal++; count++; if (signal >= maxSignals_) { for (i=0; i<maxSignals_; i++) { if ((scalerPresets[i] != 0) && (scalerData_[i] >= scalerPresets[i])) acquiring = false; } asynPrintIO(pasynUserSelf, ASYN_TRACEIO_DRIVER, (const char*)scalerData_, maxSignals_*sizeof(epicsUInt32), "%s:%s:\n", driverName, functionName); if (!acquiring) break; signal = 0; } } } epicsTimeGetCurrent(&t2); asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: read FIFO (%d) in %fs, acquiring=%d\n", driverName, functionName, count, epicsTimeDiffInSeconds(&t2, &t1), acquiring_); // Release the FIFO lock, we are done accessing the FIFO epicsMutexUnlock(fifoLockId_); // Take the lock since we are now changing object data lock(); nextChan_ = chan; nextSignal_ = signal; if (acquireMode_ == ACQUIRE_MODE_MCS) { asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: pOut=%p,signal=%d, chan=%d\n", driverName, functionName, pOut, signal, chan); checkMCSDone(); } else if (acquireMode_ == ACQUIRE_MODE_SCALER) { if (!acquiring) acquiring_ = false; if (!acquiring_) { asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: scaler done, doing callbacks\n", driverName, functionName); stopScaler(); setIntegerParam(scalerDone_, 1); callParamCallbacks(); } } /* Reenable interrupts in case we were woken up by an interrupt for FIFO almost full */ enableInterrupts(); acquiring = acquiring_; // Release the lock unlock(); // If we are still acquiring then sleep for a short time, but wake up if there is an interrupt if (acquiring) { status = epicsEventWaitWithTimeout(readFIFOEventId_, epicsThreadSleepQuantum()); if (status == epicsEventWaitOK) asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: got interrupt in epicsEventWaitWithTimeout, eventType=%d\n", driverName, functionName, eventType_); } } } }
/* * Read from the serial line */ static asynStatus readIt(void *drvPvt, asynUser *pasynUser, char *data, size_t maxchars,size_t *nbytesTransfered,int *gotEom) { ttyController_t *tty = (ttyController_t *)drvPvt; int thisRead; int nRead = 0; int timerStarted = 0; COMMTIMEOUTS ctimeout; BOOL ret; DWORD error; asynStatus status = asynSuccess; assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s read.\n", tty->serialDeviceName); if (tty->commHandle == INVALID_HANDLE_VALUE) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s disconnected:", tty->serialDeviceName); return asynError; } if (maxchars <= 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s maxchars %d Why <=0?",tty->serialDeviceName,(int)maxchars); return asynError; } if (tty->readTimeout != pasynUser->timeout) { if (pasynUser->timeout >= 0) { ctimeout.ReadIntervalTimeout = (int)(pasynUser->timeout*1000.); ctimeout.ReadTotalTimeoutMultiplier = 1; ctimeout.ReadTotalTimeoutConstant = (int)(pasynUser->timeout*1000.); ctimeout.WriteTotalTimeoutMultiplier = 1; ctimeout.WriteTotalTimeoutConstant = (int)(pasynUser->timeout*1000.); ret = SetCommTimeouts(tty->commHandle, &ctimeout); if (ret == 0) { error = GetLastError(); epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set \"%s\" timeout: %f, error=%d", tty->serialDeviceName, pasynUser->timeout, error); return asynError; } tty->readTimeout = pasynUser->timeout; } } tty->timeoutFlag = 0; if (gotEom) *gotEom = 0; for (;;) { if (!timerStarted && (tty->readTimeout > 0)) { epicsTimerStartDelay(tty->timer, tty->readTimeout); timerStarted = 1; } ret = ReadFile( tty->commHandle, // handle of file to read data, // pointer to buffer that receives data 1, // number of bytes to read &thisRead, // pointer to number of bytes read NULL // pointer to structure for data ); if (ret == 0) { error = GetLastError(); epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s read error: %d", tty->serialDeviceName, error); status = asynError; break; } if (thisRead > 0) { asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, thisRead, "%s read %d\n", tty->serialDeviceName, thisRead); nRead = thisRead; tty->nRead += thisRead; break; } if (tty->timeoutFlag) break; if (tty->readTimeout == 0) /* Timeout of 0 means return immediately */ break; } if (timerStarted) epicsTimerCancel(tty->timer); if (tty->timeoutFlag && (status == asynSuccess)) status = asynTimeout; *nbytesTransfered = nRead; /* If there is room add a null byte */ if (nRead < (int)maxchars) data[nRead] = 0; else if (gotEom) *gotEom = ASYN_EOM_CNT; asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s read %d, return %d\n", tty->serialDeviceName, *nbytesTransfered, status); return status; }
/* * Write to the serial line */ static asynStatus writeIt(void *drvPvt, asynUser *pasynUser, const char *data, size_t numchars,size_t *nbytesTransfered) { ttyController_t *tty = (ttyController_t *)drvPvt; int thisWrite; int nleft = (int)numchars; int timerStarted = 0; BOOL ret; DWORD error; asynStatus status = asynSuccess; assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s write.\n", tty->serialDeviceName); asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, numchars, "%s write %d\n", tty->serialDeviceName, numchars); if (tty->commHandle == INVALID_HANDLE_VALUE) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s disconnected:", tty->serialDeviceName); return asynError; } if (numchars == 0) { *nbytesTransfered = 0; return asynSuccess; } if (tty->writeTimeout != pasynUser->timeout) { tty->writeTimeout = pasynUser->timeout; } tty->timeoutFlag = 0; nleft = (int)numchars; if (tty->writeTimeout > 0) { epicsTimerStartDelay(tty->timer, tty->writeTimeout); timerStarted = 1; } for (;;) { ret = WriteFile(tty->commHandle, // handle to file to write to data, // pointer to data to write to file nleft, // number of bytes to write &thisWrite, // pointer to number of bytes written NULL // pointer to structure for overlapped I/O ); if (ret == 0) { error = GetLastError(); epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s write error: %d", tty->serialDeviceName, error); closeConnection(pasynUser,tty); status = asynError; break; } tty->nWritten += thisWrite; nleft -= thisWrite; if (nleft == 0) break; data += thisWrite; if (tty->timeoutFlag || (tty->writeTimeout == 0)) { status = asynTimeout; break; } } if (timerStarted) epicsTimerCancel(tty->timer); *nbytesTransfered = numchars - nleft; asynPrint(pasynUser, ASYN_TRACE_FLOW, "wrote %lu to %s, return %s\n", (unsigned long)*nbytesTransfered, tty->serialDeviceName, pasynManager->strStatus(status)); return status; }
/* * Read from the TCP port */ static asynStatus readIt(void *drvPvt, asynUser *pasynUser, char *data, size_t maxchars,size_t *nbytesTransfered,int *gotEom) { ttyController_t *tty = (ttyController_t *)drvPvt; int thisRead; int readPollmsec; int reason = 0; epicsTimeStamp startTime; epicsTimeStamp endTime; asynStatus status = asynSuccess; assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s read.\n", tty->IPDeviceName); if (tty->fd == INVALID_SOCKET) { if (tty->flags & FLAG_CONNECT_PER_TRANSACTION) { if ((status = connectIt(drvPvt, pasynUser)) != asynSuccess) return status; } else { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s disconnected:", tty->IPDeviceName); return asynError; } } if (maxchars <= 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s maxchars %d. Why <=0?",tty->IPDeviceName,(int)maxchars); return asynError; } readPollmsec = (int) (pasynUser->timeout * 1000.0); if (readPollmsec == 0) readPollmsec = 1; if (readPollmsec < 0) readPollmsec = -1; #ifdef USE_SOCKTIMEOUT { struct timeval tv; tv.tv_sec = readPollmsec / 1000; tv.tv_usec = (readPollmsec % 1000) * 1000; if (setsockopt(tty->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof tv) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set %s socket receive timeout: %s", tty->IPDeviceName, strerror(SOCKERRNO)); status = asynError; } } #endif if (gotEom) *gotEom = 0; #ifdef USE_POLL { struct pollfd pollfd; pollfd.fd = tty->fd; pollfd.events = POLLIN; epicsTimeGetCurrent(&startTime); while (poll(&pollfd, 1, readPollmsec) < 0) { if (errno != EINTR) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Poll() failed: %s", strerror(errno)); return asynError; } epicsTimeGetCurrent(&endTime); if (epicsTimeDiffInSeconds(&endTime, &startTime)*1000. > readPollmsec) break; } } #endif if (tty->socketType == SOCK_DGRAM) { /* We use recvfrom() for SOCK_DRAM so we can print the source address with ASYN_TRACEIO_DRIVER */ osiSockAddr oa; unsigned int addrlen = sizeof(oa.ia); thisRead = recvfrom(tty->fd, data, (int)maxchars, 0, &oa.sa, &addrlen); if (thisRead > 0) { if (pasynTrace->getTraceMask(pasynUser) & ASYN_TRACEIO_DRIVER) { char inetBuff[32]; ipAddrToDottedIP(&oa.ia, inetBuff, sizeof(inetBuff)); asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, thisRead, "%s (from %s) read %d\n", tty->IPDeviceName, inetBuff, thisRead); } tty->nRead += (unsigned long)thisRead; } } else { thisRead = recv(tty->fd, data, (int)maxchars, 0); if (thisRead > 0) { asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, thisRead, "%s read %d\n", tty->IPDeviceName, thisRead); tty->nRead += (unsigned long)thisRead; } } if (thisRead < 0) { int should_close = (tty->userFlags & USERFLAG_CLOSE_ON_READ_TIMEOUT) || ((SOCKERRNO != SOCK_EWOULDBLOCK) && (SOCKERRNO != SOCK_EINTR)); if (should_close) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s read error: %s", tty->IPDeviceName, strerror(SOCKERRNO)); closeConnection(pasynUser,tty,"Read error"); status = asynError; } else { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s timeout: %s", tty->IPDeviceName, strerror(SOCKERRNO)); status = asynTimeout; } } /* If recv() returns 0 on a SOCK_STREAM (TCP) socket, the connection has closed */ if ((thisRead == 0) && (tty->socketType == SOCK_STREAM)) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s connection closed", tty->IPDeviceName); closeConnection(pasynUser,tty,"Read from broken connection"); reason |= ASYN_EOM_END; } if (thisRead < 0) thisRead = 0; *nbytesTransfered = thisRead; /* If there is room add a null byte */ if (thisRead < (int) maxchars) data[thisRead] = 0; else reason |= ASYN_EOM_CNT; if (gotEom) *gotEom = reason; return status; }
/* * Write to the TCP port */ static asynStatus writeIt(void *drvPvt, asynUser *pasynUser, const char *data, size_t numchars,size_t *nbytesTransfered) { ttyController_t *tty = (ttyController_t *)drvPvt; int thisWrite; asynStatus status = asynSuccess; int writePollmsec; int epicsTimeStatus; epicsTimeStamp startTime; epicsTimeStamp endTime; int haveStartTime; assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s write.\n", tty->IPDeviceName); asynPrintIO(pasynUser, ASYN_TRACEIO_DRIVER, data, numchars, "%s write %lu\n", tty->IPDeviceName, (unsigned long)numchars); *nbytesTransfered = 0; if (tty->fd == INVALID_SOCKET) { if (tty->flags & FLAG_CONNECT_PER_TRANSACTION) { if ((status = connectIt(drvPvt, pasynUser)) != asynSuccess) return status; } else { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "%s disconnected:", tty->IPDeviceName); return asynError; } } if (numchars == 0) return asynSuccess; writePollmsec = (int) (pasynUser->timeout * 1000.0); if (writePollmsec == 0) writePollmsec = 1; if (writePollmsec < 0) writePollmsec = -1; #ifdef USE_SOCKTIMEOUT { struct timeval tv; tv.tv_sec = writePollmsec / 1000; tv.tv_usec = (writePollmsec % 1000) * 1000; if (setsockopt(tty->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof tv) < 0) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Can't set %s socket send timeout: %s", tty->IPDeviceName, strerror(SOCKERRNO)); return asynError; } } #endif haveStartTime = 0; for (;;) { #ifdef USE_POLL struct pollfd pollfd; pollfd.fd = tty->fd; pollfd.events = POLLOUT; epicsTimeGetCurrent(&startTime); while (poll(&pollfd, 1, writePollmsec) < 0) { if (errno != EINTR) { epicsSnprintf(pasynUser->errorMessage,pasynUser->errorMessageSize, "Poll() failed: %s", strerror(errno)); return asynError; } epicsTimeGetCurrent(&endTime); if (epicsTimeDiffInSeconds(&endTime, &startTime)*1000 > writePollmsec) break; } #endif for (;;) { if (tty->socketType == SOCK_DGRAM) { thisWrite = sendto(tty->fd, (char *)data, (int)numchars, 0, &tty->farAddr.oa.sa, (int)tty->farAddrSize); } else { thisWrite = send(tty->fd, (char *)data, (int)numchars, 0); } if (thisWrite >= 0) break; if (SOCKERRNO == SOCK_EWOULDBLOCK || SOCKERRNO == SOCK_EINTR) { if (!haveStartTime) { epicsTimeStatus = epicsTimeGetCurrent(&startTime); assert(epicsTimeStatus == epicsTimeOK); haveStartTime = 1; } else if (pasynUser->timeout >= 0) { epicsTimeStatus = epicsTimeGetCurrent(&endTime); assert(epicsTimeStatus == epicsTimeOK); if (epicsTimeDiffInSeconds(&endTime, &startTime) > pasynUser->timeout) { thisWrite = 0; break; } } epicsThreadSleep(SEND_RETRY_DELAY); } else break; } if (thisWrite > 0) { tty->nWritten += (unsigned long)thisWrite; *nbytesTransfered += thisWrite; numchars -= thisWrite; if (numchars == 0) break; data += thisWrite; } else if (thisWrite == 0) { status = asynTimeout; break; } else { epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize, "%s write error: %s", tty->IPDeviceName, strerror(SOCKERRNO)); closeConnection(pasynUser,tty,"Write error"); status = asynError; break; } } asynPrint(pasynUser, ASYN_TRACE_FLOW, "wrote %lu to %s, return %s.\n", (unsigned long)*nbytesTransfered, tty->IPDeviceName, pasynManager->strStatus(status)); return status; }