void callbackCancelDelayed(CALLBACK *pcallback) { epicsTimerId timer = (epicsTimerId)pcallback->timer; if (timer != 0) { epicsTimerCancel(timer); } }
static asynStatus disconnect(void *drvPvt, asynUser *pasynUser) { ttyController_t *tty = (ttyController_t *)drvPvt; assert(tty); asynPrint(pasynUser, ASYN_TRACE_FLOW, "%s disconnect\n", tty->serialDeviceName); epicsTimerCancel(tty->timer); closeConnection(pasynUser,tty); return asynSuccess; }
/* * 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; }
/* * 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; }
asynStatus mar345::acquireFrame() { asynStatus status=asynSuccess; epicsTimeStamp startTime, currentTime; int eraseMode; epicsEventWaitStatus waitStatus; int imageCounter; int arrayCallbacks; double acquireTime; double timeRemaining; int size, res; int shutterMode, useShutter; char tempFileName[MAX_FILENAME_LEN]; char fullFileName[MAX_FILENAME_LEN]; //const char *functionName = "acquireframe"; /* Get current values of some parameters */ getDoubleParam(ADAcquireTime, &acquireTime); getIntegerParam(ADShutterMode, &shutterMode); getIntegerParam(mar345Size, &size); getIntegerParam(mar345Res, &res); getIntegerParam(NDArrayCallbacks, &arrayCallbacks); getIntegerParam(mar345EraseMode, &eraseMode); if (shutterMode == ADShutterModeNone) useShutter=0; else useShutter=1; epicsTimeGetCurrent(&this->acqStartTime); createFileName(MAX_FILENAME_LEN, tempFileName); /* We need to append the extension */ epicsSnprintf(fullFileName, sizeof(fullFileName), "%s.mar%d", tempFileName, imageSizes[res][size]); /* Erase before exposure if set */ if (eraseMode == mar345EraseBefore) { status = this->erase(); if (status) return(status); } /* Set the the start time for the TimeRemaining counter */ epicsTimeGetCurrent(&startTime); timeRemaining = acquireTime; if (useShutter) setShutter(1); /* Wait for the exposure time using epicsEventWaitWithTimeout, * so we can abort */ epicsTimerStartDelay(this->timerId, acquireTime); setIntegerParam(ADStatus, mar345StatusExpose); callParamCallbacks(); while(1) { if (epicsEventTryWait(this->abortEventId) == epicsEventWaitOK) { status = asynError; break; } this->unlock(); waitStatus = epicsEventWaitWithTimeout(this->stopEventId, MAR345_POLL_DELAY); this->lock(); if (waitStatus == epicsEventWaitOK) { /* The acquisition was stopped before the time was complete */ epicsTimerCancel(this->timerId); break; } epicsTimeGetCurrent(¤tTime); timeRemaining = acquireTime - epicsTimeDiffInSeconds(¤tTime, &startTime); if (timeRemaining < 0.) timeRemaining = 0.; setDoubleParam(ADTimeRemaining, timeRemaining); callParamCallbacks(); } setDoubleParam(ADTimeRemaining, 0.0); if (useShutter) setShutter(0); setIntegerParam(ADStatus, mar345StatusIdle); callParamCallbacks(); // If the exposure was aborted return error if (status) return asynError; setIntegerParam(ADStatus, mar345StatusScan); callParamCallbacks(); epicsSnprintf(this->toServer, sizeof(this->toServer), "COMMAND SCAN %s", fullFileName); setStringParam(NDFullFileName, fullFileName); callParamCallbacks(); writeServer(this->toServer); status = waitForCompletion("SCAN_DATA Ended o.k.", MAR345_COMMAND_TIMEOUT); if (status) { return asynError; } getIntegerParam(NDArrayCounter, &imageCounter); imageCounter++; setIntegerParam(NDArrayCounter, imageCounter); /* Call the callbacks to update any changes */ callParamCallbacks(); /* If arrayCallbacks is set then read the file back in */ if (arrayCallbacks) { getImageData(); } /* Erase after scanning if set */ if (eraseMode == mar345EraseAfter) status = this->erase(); return status; }
/** This thread controls acquisition, reads SFRM files to get the image data, and * does the callbacks to send it to higher layers */ void BISDetector::BISTask() { int status = asynSuccess; int imageCounter; int numImages, numImagesCounter; int imageMode; int acquire; NDArray *pImage; double acquireTime, timeRemaining; ADShutterMode_t shutterMode; int frameType; int numDarks; double readSFRMTimeout; epicsTimeStamp startTime, currentTime; const char *functionName = "BISTask"; char fullFileName[MAX_FILENAME_LEN]; char statusMessage[MAX_MESSAGE_SIZE]; size_t dims[2]; int itemp; int arrayCallbacks; this->lock(); /* Loop forever */ while (1) { /* Is acquisition active? */ getIntegerParam(ADAcquire, &acquire); /* If we are not acquiring then wait for a semaphore that is given when acquisition is started */ if (!acquire) { setStringParam(ADStatusMessage, "Waiting for acquire command"); setIntegerParam(ADStatus, ADStatusIdle); callParamCallbacks(); /* Release the lock while we wait for an event that says acquire has started, then lock again */ this->unlock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: waiting for acquire to start\n", driverName, functionName); status = epicsEventWait(this->startEventId); this->lock(); setIntegerParam(ADNumImagesCounter, 0); } /* Get current values of some parameters */ getIntegerParam(ADFrameType, &frameType); /* Get the exposure parameters */ getDoubleParam(ADAcquireTime, &acquireTime); getIntegerParam(ADShutterMode, &itemp); shutterMode = (ADShutterMode_t)itemp; getDoubleParam(BISSFRMTimeout, &readSFRMTimeout); setIntegerParam(ADStatus, ADStatusAcquire); /* Create the full filename */ createFileName(sizeof(fullFileName), fullFileName); setStringParam(ADStatusMessage, "Starting exposure"); /* Call the callbacks to update any changes */ setStringParam(NDFullFileName, fullFileName); callParamCallbacks(); switch (frameType) { case BISFrameNormal: epicsSnprintf(this->toBIS, sizeof(this->toBIS), "[Scan /Filename=%s /scantime=%f /Rescan=0]", fullFileName, acquireTime); break; case BISFrameDark: getIntegerParam(BISNumDarks, &numDarks); epicsSnprintf(this->toBIS, sizeof(this->toBIS), "[Dark /AddTime=%f /Repetitions=%d]", acquireTime, numDarks); break; case BISFrameRaw: epicsSnprintf(this->toBIS, sizeof(this->toBIS), "[Scan /Filename=%s /scantime=%f /Rescan=0 /DarkFlood=0]", fullFileName, acquireTime); break; case BISFrameDoubleCorrelation: epicsSnprintf(this->toBIS, sizeof(this->toBIS), "[Scan /Filename=%s /scantime=%f /Rescan=1]", fullFileName, acquireTime); break; } /* Send the acquire command to BIS */ writeBIS(2.0); setStringParam(ADStatusMessage, "Waiting for Acquisition"); callParamCallbacks(); /* Set the the start time for the TimeRemaining counter */ epicsTimeGetCurrent(&startTime); timeRemaining = acquireTime; /* BIS will control the shutter if we are using the hardware shutter signal. * If we are using the EPICS shutter then tell it to open */ if (shutterMode == ADShutterModeEPICS) ADDriver::setShutter(1); /* Wait for the exposure time using epicsEventWaitWithTimeout, * so we can abort. */ epicsTimerStartDelay(this->timerId, acquireTime); while(1) { this->unlock(); status = epicsEventWaitWithTimeout(this->stopEventId, BIS_POLL_DELAY); this->lock(); if (status == epicsEventWaitOK) { /* The acquisition was stopped before the time was complete */ epicsTimerCancel(this->timerId); break; } epicsTimeGetCurrent(¤tTime); timeRemaining = acquireTime - epicsTimeDiffInSeconds(¤tTime, &startTime); if (timeRemaining < 0.) timeRemaining = 0.; setDoubleParam(ADTimeRemaining, timeRemaining); callParamCallbacks(); } if (shutterMode == ADShutterModeEPICS) ADDriver::setShutter(0); setDoubleParam(ADTimeRemaining, 0.0); callParamCallbacks(); this->unlock(); status = epicsEventWaitWithTimeout(this->readoutEventId, 5.0); this->lock(); /* If there was an error jump to bottom of loop */ if (status != epicsEventWaitOK) { setIntegerParam(ADAcquire, 0); asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error waiting for readout to complete\n", driverName, functionName); goto done; } getIntegerParam(NDArrayCallbacks, &arrayCallbacks); getIntegerParam(NDArrayCounter, &imageCounter); imageCounter++; setIntegerParam(NDArrayCounter, imageCounter); getIntegerParam(ADNumImagesCounter, &numImagesCounter); numImagesCounter++; setIntegerParam(ADNumImagesCounter, numImagesCounter); callParamCallbacks(); if (arrayCallbacks && frameType != BISFrameDark) { /* Get an image buffer from the pool */ getIntegerParam(ADSizeX, &itemp); dims[0] = itemp; getIntegerParam(ADSizeY, &itemp); dims[1] = itemp; pImage = this->pNDArrayPool->alloc(2, dims, NDInt32, 0, NULL); epicsSnprintf(statusMessage, sizeof(statusMessage), "Reading from File %s", fullFileName); setStringParam(ADStatusMessage, statusMessage); callParamCallbacks(); status = readSFRM(fullFileName, &startTime, acquireTime + readSFRMTimeout, pImage); /* If there was an error jump to bottom of loop */ if (status) { setIntegerParam(ADAcquire, 0); pImage->release(); goto done; } /* Put the frame number and time stamp into the buffer */ pImage->uniqueId = imageCounter; pImage->timeStamp = startTime.secPastEpoch + startTime.nsec / 1.e9; updateTimeStamp(&pImage->epicsTS); /* Get any attributes that have been defined for this driver */ this->getAttributes(pImage->pAttributeList); /* Call the NDArray callback */ /* Must release the lock here, or we can get into a deadlock, because we can * block on the plugin lock, and the plugin can be calling us */ this->unlock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: calling NDArray callback\n", driverName, functionName); doCallbacksGenericPointer(pImage, NDArrayData, 0); this->lock(); /* Free the image buffer */ pImage->release(); } getIntegerParam(ADImageMode, &imageMode); if (imageMode == ADImageMultiple) { getIntegerParam(ADNumImages, &numImages); if (numImagesCounter >= numImages) setIntegerParam(ADAcquire, 0); } if (imageMode == ADImageSingle) setIntegerParam(ADAcquire, 0); done: callParamCallbacks(); } }