static void waitTimeout(niport *pniport,double seconds) { epicsEventWaitStatus status; transferState_t saveState; if(seconds<0.0) { status = epicsEventWait(pniport->waitForInterrupt); } else { status = epicsEventWaitWithTimeout(pniport->waitForInterrupt,seconds); } if(status==epicsEventWaitOK) return; saveState = pniport->transferState; pniport->transferState = transferStateIdle; switch(saveState) { case transferStateRead: pniport->status=asynTimeout; printStatus(pniport,"waitTimeout transferStateRead\n"); break; case transferStateWrite: pniport->status=asynTimeout; printStatus(pniport,"waitTimeout transferStateWrite\n"); break; case transferStateCmd: pniport->status=asynTimeout; printStatus(pniport,"waitTimeout transferStateCmd\n"); break; default: pniport->status=asynTimeout; printStatus(pniport,"waitTimeout transferState ?\n"); } }
static pvStat wait_complete( pvEventType evtype, SS_ID ss, PVREQ **req, DBCHAN *dbch, PVMETA *meta, double tmo) { const char *call = evtype == pvEventGet ? "pvGet" : "pvPut"; while (*req) { switch (epicsEventWaitWithTimeout(ss->syncSem, tmo)) { case epicsEventWaitOK: break; case epicsEventWaitTimeout: *req = NULL; /* cancel the request */ completion_timeout(evtype, meta); return meta->status; case epicsEventWaitError: errlogSevPrintf(errlogFatal, "%s: epicsEventWaitWithTimeout() failure\n", call); *req = NULL; /* cancel the request */ completion_failure(evtype, meta); return meta->status; } } return check_connected(dbch, meta); }
/** Simulation task that runs as a separate thread. When the P_Run parameter is set to 1 * to rub the simulation it computes a 1 kHz sine wave with 1V amplitude and user-controllable * noise, and displays it on * a simulated scope. It computes waveforms for the X (time) and Y (volt) axes, and computes * statistics about the waveform. */ void testAsynPortDriver::simTask(void) { /* This thread computes the waveform and does callbacks with it */ double timePerDiv, voltsPerDiv, voltOffset, triggerDelay, noiseAmplitude; double updateTime, minValue, maxValue, meanValue; double time, timeStep; double noise, yScale; int run, i, maxPoints; double pi=4.0*atan(1.0); lock(); /* Loop forever */ while (1) { getDoubleParam(P_UpdateTime, &updateTime); getIntegerParam(P_Run, &run); // Release the lock while we wait for a command to start or wait for updateTime unlock(); if (run) epicsEventWaitWithTimeout(eventId_, updateTime); else (void) epicsEventWait(eventId_); // Take the lock again lock(); /* run could have changed while we were waiting */ getIntegerParam(P_Run, &run); if (!run) continue; getIntegerParam(P_MaxPoints, &maxPoints); getDoubleParam (P_TimePerDiv, &timePerDiv); getDoubleParam (P_VoltsPerDiv, &voltsPerDiv); getDoubleParam (P_VoltOffset, &voltOffset); getDoubleParam (P_TriggerDelay, &triggerDelay); getDoubleParam (P_NoiseAmplitude, &noiseAmplitude); time = triggerDelay; timeStep = timePerDiv * NUM_DIVISIONS / maxPoints; minValue = 1e6; maxValue = -1e6; meanValue = 0.; yScale = 1.0 / voltsPerDiv; for (i=0; i<maxPoints; i++) { noise = noiseAmplitude * (rand()/(double)RAND_MAX - 0.5); pData_[i] = AMPLITUDE * (sin(time*FREQUENCY*2*pi)) + noise; /* Compute statistics before doing the yOffset and yScale */ if (pData_[i] < minValue) minValue = pData_[i]; if (pData_[i] > maxValue) maxValue = pData_[i]; meanValue += pData_[i]; pData_[i] = NUM_DIVISIONS/2 + yScale * (voltOffset + pData_[i]); time += timeStep; } updateTimeStamp(); meanValue = meanValue/maxPoints; setDoubleParam(P_MinValue, minValue); setDoubleParam(P_MaxValue, maxValue); setDoubleParam(P_MeanValue, meanValue); callParamCallbacks(); doCallbacksFloat64Array(pData_, maxPoints, P_Waveform, 0); } }
static void ClockTimeSync(void *dummy) { taskwdInsert(0, NULL, NULL); for (epicsEventWaitWithTimeout(ClockTimePvt.loopEvent, ClockTimeSyncInterval); ClockTimePvt.synchronize == CLOCKTIME_SYNC; epicsEventWaitWithTimeout(ClockTimePvt.loopEvent, ClockTimeSyncInterval)) { epicsTimeStamp timeNow; int priority; if (generalTimeGetExceptPriority(&timeNow, &priority, LAST_RESORT_PRIORITY) == epicsTimeOK) { struct timespec clockNow; epicsTimeToTimespec(&clockNow, &timeNow); if (clock_settime(CLOCK_REALTIME, &clockNow)) { errlogPrintf("ClockTimeSync: clock_settime failed\n"); continue; } epicsMutexMustLock(ClockTimePvt.lock); if (!ClockTimePvt.synchronized) { ClockTimePvt.startTime = timeNow; ClockTimePvt.synchronized = 1; } ClockTimePvt.syncFromPriority = priority; ClockTimePvt.syncTime = timeNow; epicsMutexUnlock(ClockTimePvt.lock); } } ClockTimePvt.synchronized = 0; taskwdRemove(0); }
/** Array generation ask that runs as a separate thread. When the P_RunStop parameter is set to 1 * it periodically generates a burst of arrays. */ void testArrayRingBuffer::arrayGenTask(void) { double loopDelay; int runStop; int i, j; int burstLength; double burstDelay; int maxArrayLength; int arrayLength; lock(); /* Loop forever */ getIntegerParam(P_MaxArrayLength, &maxArrayLength); while (1) { getDoubleParam(P_LoopDelay, &loopDelay); getDoubleParam(P_BurstDelay, &burstDelay); getIntegerParam(P_RunStop, &runStop); // Release the lock while we wait for a command to start or wait for updateTime unlock(); if (runStop) epicsEventWaitWithTimeout(eventId_, loopDelay); else (void)epicsEventWait(eventId_); // Take the lock again lock(); /* runStop could have changed while we were waiting */ getIntegerParam(P_RunStop, &runStop); if (!runStop) continue; getIntegerParam(P_ArrayLength, &arrayLength); if (arrayLength > maxArrayLength) { arrayLength = maxArrayLength; setIntegerParam(P_ArrayLength, arrayLength); } getIntegerParam(P_BurstLength, &burstLength); for (i=0; i<burstLength; i++) { for (j=0; j<arrayLength; j++) { pData_[j] = i; } setIntegerParam(P_ScalarData, i); callParamCallbacks(); doCallbacksInt32Array(pData_, arrayLength, P_ArrayData, 0); if (burstDelay > 0.0) epicsThreadSleep(burstDelay); } } }
static void twdTask(void *arg) { struct tNode *pt; struct mNode *pm; while (twdCtl != twdctlExit) { if (twdCtl == twdctlRun) { epicsMutexMustLock(tLock); pt = (struct tNode *)ellFirst(&tList); while (pt) { int susp = epicsThreadIsSuspended(pt->tid); if (susp != pt->suspended) { epicsMutexMustLock(mLock); pm = (struct mNode *)ellFirst(&mList); while (pm) { if (pm->funcs->notify) { pm->funcs->notify(pm->usr, pt->tid, susp); } pm = (struct mNode *)ellNext(&pm->node); } epicsMutexUnlock(mLock); if (susp) { char tName[40]; epicsThreadGetName(pt->tid, tName, sizeof(tName)); errlogPrintf("Thread %s (%p) suspended\n", tName, (void *)pt->tid); if (pt->callback) { pt->callback(pt->usr); } } pt->suspended = susp; } pt = (struct tNode *)ellNext(&pt->node); } epicsMutexUnlock(tLock); } epicsEventWaitWithTimeout(loopEvent, TASKWD_DELAY); } epicsEventSignal(exitEvent); }
void FastCCD::dataStatsTask(void) { unsigned int status = 0; double timeout = 0.0; static const char *functionName = "dataStatsTask"; while(1) { //Read timeout for polling freq. this->lock(); timeout = dataStatsPollingPeriod; this->unlock(); if (timeout != 0.0) { status = epicsEventWaitWithTimeout(dataStatsEvent, timeout); } else { status = epicsEventWait(dataStatsEvent); } if (status == epicsEventWaitOK) { asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Got status event\n", driverName, functionName); } cin_data_stats_t stats; cin_data_compute_stats(&stats); setIntegerParam(FastCCDDroppedPck, (int)stats.dropped_packets); setIntegerParam(FastCCDBadPck, (int)stats.mallformed_packets); setIntegerParam(FastCCDLastFrame, stats.last_frame); setIntegerParam(FastCCDPacketBuffer, stats.packet_used); setIntegerParam(FastCCDFrameBuffer, stats.frame_used); setIntegerParam(FastCCDImageBuffer, stats.image_used); //setDoubleParam(FastCCDDataRate, stats.datarate); this->lock(); callParamCallbacks(); this->unlock(); } }
void callbackStop(void) { int i; if (cbCtl == ctlExit) return; cbCtl = ctlExit; for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) { callbackQueue[i].shutdown = 1; epicsEventSignal(callbackQueue[i].semWakeUp); } for (i = 0; i < NUM_CALLBACK_PRIORITIES; i++) { cbQueueSet *mySet = &callbackQueue[i]; while (epicsAtomicGetIntT(&mySet->threadsRunning)) { epicsEventSignal(mySet->semWakeUp); epicsEventWaitWithTimeout(startStopEvent, 0.1); } } }
int epicsThreadPoolWait(epicsThreadPool *pool, double timeout) { int ret = 0; epicsMutexMustLock(pool->guard); while (ellCount(&pool->jobs) > 0 || pool->threadsAreAwake > 0) { pool->observerCount++; epicsMutexUnlock(pool->guard); if (timeout < 0.0) { epicsEventMustWait(pool->observerWakeup); } else { switch (epicsEventWaitWithTimeout(pool->observerWakeup, timeout)) { case epicsEventWaitError: cantProceed("epicsThreadPoolWait: failed to wait for Event"); break; case epicsEventWaitTimeout: ret = S_pool_timeout; break; case epicsEventWaitOK: ret = 0; break; } } epicsMutexMustLock(pool->guard); pool->observerCount--; if (pool->observerCount) epicsEventSignal(pool->observerWakeup); if (ret != 0) break; } epicsMutexUnlock(pool->guard); return ret; }
asynStatus BISDetector::readSFRM(const char *fileName, epicsTimeStamp *pStartTime, double timeout, NDArray *pImage) { #define lineLen 80 #define maxLine 95 #define blockLen 512 #define dataOffset 8 FILE *file=NULL; int fileExists=0; struct stat statBuff; epicsTimeStamp tStart, tCheck; time_t acqStartTime; double deltaTime; int status=-1; const char *functionName = "readSFRM"; int offset, version, format; int nPixels; size_t nBytes, nRead=0; int headerBlocks; int numUnderflows, numOverflows1, numOverflows2; int nRows, nCols; int bytesPerPixel, underflowBytesPerPixel; int wordOrder, longOrder; int numExposures, bias, baselineOffset, orientation, overscan; epicsUInt16 *pOverflows1=NULL; epicsUInt32 *pOverflows2=NULL; epicsUInt16 *pUnderflows=NULL; int i; char *buffer=NULL; epicsUInt8 *byteBuffer; epicsUInt16 *i2Buffer; epicsUInt32 *pData = (epicsUInt32 *)pImage->pData; int n1=0, n2=0, nu=0; deltaTime = 0.; if (pStartTime) epicsTimeToTime_t(&acqStartTime, pStartTime); epicsTimeGetCurrent(&tStart); while (deltaTime <= timeout) { file = fopen(fileName, "rb"); if (file && (timeout != 0.)) { fileExists = 1; /* The file exists. Make sure it is a new file, not an old one. * We don't do this check if timeout==0 */ status = stat(fileName, &statBuff); if (status){ asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s error calling fstat, errno=%d %s\n", driverName, functionName, errno, fileName); fclose(file); return(asynError); } /* We allow up to 10 second clock skew between time on machine running this IOC * and the machine with the file system returning modification time */ if (difftime(statBuff.st_mtime, acqStartTime) > -10) break; fclose(file); file = NULL; } /* Sleep, but check for stop event, which can be used to abort a long acquisition */ unlock(); status = epicsEventWaitWithTimeout(this->stopEventId, FILE_READ_DELAY); lock(); if (status == epicsEventWaitOK) { return(asynError); } epicsTimeGetCurrent(&tCheck); deltaTime = epicsTimeDiffInSeconds(&tCheck, &tStart); } if (file == NULL) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s::%s timeout waiting for file to be created %s\n", driverName, functionName, fileName); if (fileExists) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, " file exists but is more than 10 seconds old, possible clock synchronization problem\n"); } return(asynError); } /* Allocate the buffer */ buffer = (char *)malloc(lineLen * maxLine); /* Read the first 3 lines of the header */ nBytes = fread(buffer, 1, 3*lineLen, file); offset = 0*lineLen + dataOffset; sscanf(buffer+offset, "%d", &format); offset = 1*lineLen + dataOffset; sscanf(buffer+offset, "%d", &version); offset = 2*lineLen + dataOffset; sscanf(buffer+offset, "%d", &headerBlocks); free(buffer); if ((format != 100) || (version < 11)) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: unsupported format=%d or version=%d\n", driverName, functionName, format, version); fclose(file); return(asynError); } /* Read the entire header now that we know how big it is */ buffer = (char *)malloc(headerBlocks*blockLen); fseek(file, 0, SEEK_SET); nBytes = fread(buffer, 1, headerBlocks*blockLen, file); offset = 20*lineLen + dataOffset; sscanf(buffer+offset, "%d%d%d", &numUnderflows, &numOverflows1, &numOverflows2); offset = 39*lineLen + dataOffset; sscanf(buffer+offset, "%d%d", &bytesPerPixel, &underflowBytesPerPixel); offset = 40*lineLen + dataOffset; sscanf(buffer+offset, "%d", &nRows); offset = 41*lineLen + dataOffset; sscanf(buffer+offset, "%d", &nCols); offset = 42*lineLen + dataOffset; sscanf(buffer+offset, "%d", &wordOrder); offset = 42*lineLen + dataOffset; sscanf(buffer+offset, "%d", &longOrder); offset = 79*lineLen + dataOffset; sscanf(buffer+offset, "%d%d%d%d%d", &numExposures, &bias, &baselineOffset, &orientation, &overscan); free(buffer); if ((wordOrder !=0) || (longOrder != 0)) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: unsupported wordOrder=%d or longOrder=%d\n", driverName, functionName, wordOrder, longOrder); fclose(file); return(asynError); } asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: file=%s, numUnderflows=%d, numOverflows1=%d, numOverflows2=%d, bytesPerPixel=%d, underflowBytesPerPixel=%d, nRows=%d, nCols=%d\n", driverName, functionName, fileName, numUnderflows, numOverflows1, numOverflows2, bytesPerPixel, underflowBytesPerPixel, nRows, nCols); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: numExposures=%d, bias=%d, baselineOffset=%d, orientation=%d, overscan=%d\n", driverName, functionName, numExposures, bias, baselineOffset, orientation, overscan); /* We have now read enough of the header to read the data and correct it */ nPixels = nRows*nCols; switch (bytesPerPixel) { case 1: nBytes = nPixels * 1; byteBuffer = (epicsUInt8 *)malloc(nBytes); nRead = fread(byteBuffer, 1, nBytes, file); for (i=0; i<nPixels; i++) pData[i] = byteBuffer[i]; free(byteBuffer); break; case 2: nBytes = nPixels * 2; i2Buffer = (epicsUInt16 *)malloc(nBytes); nRead = fread(i2Buffer, 1, nBytes, file); for (i=0; i<nPixels; i++) pData[i] = i2Buffer[i]; free(i2Buffer); break; case 4: nBytes = nPixels * 4; nRead = fread(pData, 1, nBytes, file); break; } if (nRead != nBytes) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error reading file %s, only read %lu/%lu bytes\n", driverName, functionName, fileName, (unsigned long)nRead, (unsigned long)nBytes); } /* Read the underflow and overflow tables */ if (numUnderflows > 0) { nBytes = ((numUnderflows * underflowBytesPerPixel + 15) / 16) * 16; pUnderflows = (epicsUInt16 *)malloc(nBytes); fread(pUnderflows, 1, nBytes, file); } if (numOverflows1 > 0) { nBytes = ((numOverflows1 * 2 + 15) / 16) * 16; pOverflows1 = (epicsUInt16 *)malloc(nBytes); fread(pOverflows1, 1, nBytes, file); } if (numOverflows2 > 0) { nBytes = ((numOverflows2 * 4 + 15) / 16) * 16; pOverflows2 = (epicsUInt32 *)malloc(nBytes); fread(pOverflows2, 1, nBytes, file); } fclose(file); if (numUnderflows == -1) baselineOffset = 0; for (i=0; i<nPixels; i++) { if ((bytesPerPixel == 1) && (pData[i] == 255)) { pData[i] = pOverflows1[n1++]; } if ((bytesPerPixel != 4) && (pData[i] == 65535)) { pData[i] = pOverflows2[n2++]; } if (pData[i] == 0) { if (numUnderflows > 0) { pData[i] = pUnderflows[nu++]; } //else printf("0 pixel=%d/%d\n", i, nPixels-1); } else if (baselineOffset != 0) { pData[i] += baselineOffset; } } free(pUnderflows); free(pOverflows1); free(pOverflows2); return(asynSuccess); }
static void NTPTimeSync(void *dummy) { taskwdInsert(0, NULL, NULL); for (epicsEventWaitWithTimeout(NTPTimePvt.loopEvent, NTPTimeSyncInterval); NTPTimePvt.synchronize; epicsEventWaitWithTimeout(NTPTimePvt.loopEvent, NTPTimeSyncInterval)) { int status; struct timespec timespecNow; epicsTimeStamp timeNow; epicsUInt32 tickNow; double diff; double ntpDelta; status = osdNTPGet(×pecNow); tickNow = osdTickGet(); if (status) { if (++NTPTimePvt.syncsFailed > NTPTimeSyncRetries && NTPTimePvt.synchronized) { errlogPrintf("NTPTimeSync: NTP requests failing - %s\n", strerror(errno)); NTPTimePvt.synchronized = 0; } continue; } if (timespecNow.tv_sec <= POSIX_TIME_AT_EPICS_EPOCH || epicsTimeFromTimespec(&timeNow, ×pecNow) == epicsTimeERROR) { errlogPrintf("NTPTimeSync: Bad time received from NTP server\n"); NTPTimePvt.synchronized = 0; continue; } ntpDelta = epicsTimeDiffInSeconds(&timeNow, &NTPTimePvt.syncTime); if (ntpDelta <= 0.0 && NTPTimePvt.synchronized) { errlogPrintf("NTPTimeSync: NTP time not increasing, delta = %g\n", ntpDelta); NTPTimePvt.synchronized = 0; continue; } NTPTimePvt.syncsFailed = 0; if (!NTPTimePvt.synchronized) { errlogPrintf("NTPTimeSync: Sync recovered.\n"); } epicsMutexMustLock(NTPTimePvt.lock); diff = epicsTimeDiffInSeconds(&timeNow, &NTPTimePvt.clockTime); if (diff >= 0.0) { NTPTimePvt.ticksToSkip = 0; } else { /* dont go back in time */ NTPTimePvt.ticksToSkip = -diff * osdTickRateGet(); } NTPTimePvt.clockTick = tickNow; NTPTimePvt.clockTime = timeNow; NTPTimePvt.synchronized = 1; epicsMutexUnlock(NTPTimePvt.lock); NTPTimePvt.tickRate = (tickNow - NTPTimePvt.syncTick) / ntpDelta; NTPTimePvt.syncTick = tickNow; NTPTimePvt.syncTime = timeNow; } NTPTimePvt.synchronized = 0; taskwdRemove(0); }
/** This thread controls handling of slow events - erase, acquire, change mode */ void mar345::mar345Task() { int status = asynSuccess; int numImages, numImagesCounter; int imageMode; int acquire; double acquirePeriod; double elapsedTime, delayTime; const char *functionName = "mar345Task"; this->lock(); /* Loop forever */ while (1) { setStringParam(ADStatusMessage, "Waiting for event"); 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 start event\n", driverName, functionName); status = epicsEventWait(this->startEventId); this->lock(); switch(this->mode) { case mar345ModeErase: this->erase(); this->mode = mar345ModeIdle; break; case mar345ModeAcquire: getIntegerParam(ADImageMode, &imageMode); getIntegerParam(ADNumImages, &numImages); if (numImages < 1) numImages = 1; if (imageMode == ADImageSingle) numImages=1; for (numImagesCounter=0; numImagesCounter<numImages || (imageMode == ADImageContinuous); numImagesCounter++) { if (epicsEventTryWait(this->abortEventId) == epicsEventWaitOK) break; setIntegerParam(ADNumImagesCounter, numImagesCounter); callParamCallbacks(); status = acquireFrame(); if (status) break; /* We get out of the loop in single shot mode or if acquire was set to 0 by client */ if (imageMode == ADImageSingle) setIntegerParam(ADAcquire, 0); getIntegerParam(ADAcquire, &acquire); if (!acquire) break; /* We are in continuous or multiple mode. * Sleep until the acquire period expires or acquire is set to stop */ epicsTimeGetCurrent(&this->acqEndTime); elapsedTime = epicsTimeDiffInSeconds(&this->acqEndTime, &this->acqStartTime); getDoubleParam(ADAcquirePeriod, &acquirePeriod); delayTime = acquirePeriod - elapsedTime; if (delayTime > 0.) { setIntegerParam(ADStatus, mar345StatusWaiting); callParamCallbacks(); this->unlock(); status = epicsEventWaitWithTimeout(this->abortEventId, delayTime); this->lock(); if (status == epicsEventWaitOK) break; } } this->mode = mar345ModeIdle; setIntegerParam(ADAcquire, 0); setIntegerParam(ADStatus, mar345StatusIdle); break; case mar345ModeChange: this->changeMode(); this->mode = mar345ModeIdle; break; default: break; } /* Call the callbacks to update any changes */ callParamCallbacks(); } }
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; }
/* * ss_entry() - Thread entry point for all state sets. * Provides the main loop for state set processing. */ static void ss_entry(void *arg) { SSCB *ss = (SSCB *)arg; PROG *sp = ss->prog; /* Attach to PV system; was already done for the first state set */ if (ss != sp->ss) { ss->threadId = epicsThreadGetIdSelf(); createOrAttachPvSystem(sp); } /* Register this thread with the EPICS watchdog (no callback func) */ taskwdInsert(ss->threadId, 0, 0); /* In safe mode, update local var buffer with global one before entering the event loop. Must do this using ss_read_all_buffer since CA and other state sets could already post events resp. pvPut. */ if (optTest(sp, OPT_SAFE)) ss_read_all_buffer(sp, ss); /* Initial state is the first one */ ss->currentState = 0; ss->nextState = -1; ss->prevState = -1; DEBUG("ss %s: entering main loop\n", ss->ssName); /* * ============= Main loop ============== */ while (TRUE) { boolean ev_trig; int transNum = 0; /* highest prio trans. # triggered */ STATE *st = ss->states + ss->currentState; double now; /* Set state to current state */ assert(ss->currentState >= 0); /* Set state set event mask to this state's event mask */ ss->mask = st->eventMask; /* If we've changed state, do any entry actions. Also do these * even if it's the same state if option to do so is enabled. */ if (st->entryFunc && (ss->prevState != ss->currentState || optTest(st, OPT_DOENTRYFROMSELF))) { st->entryFunc(ss); } /* Flush any outstanding DB requests */ pvSysFlush(sp->pvSys); /* Setting this semaphore here guarantees that a when() is * always executed at least once when a state is first entered. */ epicsEventSignal(ss->syncSem); pvTimeGetCurrentDouble(&now); /* Set time we entered this state if transition from a different * state or else if option not to do so is off for this state. */ if ((ss->currentState != ss->prevState) || !optTest(st, OPT_NORESETTIMERS)) { ss->timeEntered = now; } ss->wakeupTime = epicsINF; /* Loop until an event is triggered, i.e. when() returns TRUE */ do { /* Wake up on PV event, event flag, or expired delay */ DEBUG("before epicsEventWaitWithTimeout(ss=%d,timeout=%f)\n", ss - sp->ss, ss->wakeupTime - now); epicsEventWaitWithTimeout(ss->syncSem, ss->wakeupTime - now); DEBUG("after epicsEventWaitWithTimeout()\n"); /* Check whether we have been asked to exit */ if (sp->die) goto exit; /* Copy dirty variable values from CA buffer * to user (safe mode only). */ if (optTest(sp, OPT_SAFE)) ss_read_all_buffer(sp, ss); ss->wakeupTime = epicsINF; /* Check state change conditions */ ev_trig = st->eventFunc(ss, &transNum, &ss->nextState); /* Clear all event flags (old ef mode only) */ if (ev_trig && !optTest(sp, OPT_NEWEF)) { unsigned i; for (i = 0; i < NWORDS(sp->numEvFlags); i++) { sp->evFlags[i] &= ~ss->mask[i]; } } if (!ev_trig) pvTimeGetCurrentDouble(&now); } while (!ev_trig); /* Execute the state change action */ st->actionFunc(ss, transNum, &ss->nextState); /* Check whether we have been asked to exit */ if (sp->die) goto exit; /* If changing state, do exit actions */ if (st->exitFunc && (ss->currentState != ss->nextState || optTest(st, OPT_DOEXITTOSELF))) { st->exitFunc(ss); } /* Change to next state */ ss->prevState = ss->currentState; ss->currentState = ss->nextState; } /* Thread exit has been requested */ exit: taskwdRemove(ss->threadId); /* Declare ourselves dead */ if (ss != sp->ss) epicsEventSignal(ss->dead); }
static pvStat check_pending( pvEventType evtype, SS_ID ss, PVREQ **req, const char *varName, DBCHAN *dbch, PVMETA *meta, enum compType compType, double tmo) { const char *call = evtype == pvEventGet ? "pvGet" : "pvPut"; assert(evtype != pvEventMonitor); if (compType == SYNC) { if (tmo <= 0.0) { errlogSevPrintf(errlogMajor, "%s(%s,SYNC,%f): user error (timeout must be positive)\n", call, varName, tmo); return pvStatERROR; } while (*req) { /* a request is already pending (must be an async request) */ double before, after; pvStat status; pvTimeGetCurrentDouble(&before); switch (epicsEventWaitWithTimeout(ss->syncSem, tmo)) { case epicsEventWaitOK: status = check_connected(dbch, meta); if (status != pvStatOK) return status; pvTimeGetCurrentDouble(&after); tmo -= (after - before); if (tmo > 0.0) break; /* else: fall through to timeout */ case epicsEventWaitTimeout: errlogSevPrintf(errlogMajor, "%s(ss %s, var %s, pv %s): failed (timeout " "waiting for other %s requests to finish)\n", call, ss->ssName, varName, dbch->dbName, call ); completion_timeout(evtype, meta); return meta->status; case epicsEventWaitError: errlogSevPrintf(errlogFatal, "%s: epicsEventWaitWithTimeout() failure\n", call); completion_failure(evtype, meta); return meta->status; } } } else if (compType == ASYNC) { if (*req) { errlogSevPrintf(errlogMajor, "%s(ss %s, var %s, pv %s): user error " "(there is already a %s pending for this channel/" "state set combination)\n", call, ss->ssName, varName, dbch->dbName, call ); return pvStatERROR; } } return pvStatOK; }
/** This thread controls acquisition, reads image files to get the image data, * and does the callbacks to send it to higher layers */ void hdf5Driver::hdf5Task (void) { const char *functionName = "hdf5Task"; int status = asynSuccess; epicsTimeStamp startTime, endTime; int imageMode, currentFrame, colorMode; double acquirePeriod, elapsedTime, delay; this->lock(); for(;;) { int acquire; getIntegerParam(ADAcquire, &acquire); if (!acquire) { this->unlock(); // Wait for semaphore unlocked asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: waiting for acquire to start\n", driverName, functionName); status = epicsEventWait(this->mStartEventId); this->lock(); acquire = 1; setStringParam(ADStatusMessage, "Acquiring data"); setIntegerParam(ADNumImagesCounter, 0); } // Are there datasets loaded? if(!mDatasetsCount) { setStringParam(ADStatusMessage, "No datasets loaded"); goto error; } // Get acquisition parameters epicsTimeGetCurrent(&startTime); getIntegerParam(ADImageMode, &imageMode); getDoubleParam(ADAcquirePeriod, &acquirePeriod); getIntegerParam(HDF5CurrentFrame, ¤tFrame); setIntegerParam(ADStatus, ADStatusAcquire); callParamCallbacks(); // Get information to allocate NDArray size_t dims[2]; NDDataType_t dataType; if(getFrameInfo(currentFrame, dims, &dataType)) { setStringParam(ADStatusMessage, "Failed to get frame info"); goto error; } // Allocate NDArray NDArray *pImage; if(!(pImage = pNDArrayPool->alloc(2, dims, dataType, 0, NULL))) { setStringParam(ADStatusMessage, "Failed to allocate frame"); goto error; } // Copy data into NDArray if(getFrameData(currentFrame, pImage->pData)) { setStringParam(ADStatusMessage, "Failed to read frame data"); goto error; } // Set ColorMode colorMode = NDColorModeMono; pImage->pAttributeList->add("ColorMode", "Color mode", NDAttrInt32, &colorMode); // Call plugins callbacks int arrayCallbacks; getIntegerParam(NDArrayCallbacks, &arrayCallbacks); if (arrayCallbacks) { this->unlock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: calling imageData callback\n", driverName, functionName); doCallbacksGenericPointer(pImage, NDArrayData, 0); this->lock(); } pImage->release(); // Get the current parameters int lastFrame, imageCounter, numImages, numImagesCounter; getIntegerParam(HDF5LastFrame, &lastFrame); getIntegerParam(NDArrayCounter, &imageCounter); getIntegerParam(ADNumImages, &numImages); getIntegerParam(ADNumImagesCounter, &numImagesCounter); setIntegerParam(NDArrayCounter, ++imageCounter); setIntegerParam(ADNumImagesCounter, ++numImagesCounter); setIntegerParam(HDF5CurrentFrame, ++currentFrame); // Put the frame number and time stamp into the buffer pImage->uniqueId = imageCounter; pImage->timeStamp = startTime.secPastEpoch + startTime.nsec / 1.e9; updateTimeStamp(&pImage->epicsTS); // Prepare loop if necessary int loop; getIntegerParam(HDF5Loop, &loop); if (loop && currentFrame > lastFrame) { getIntegerParam(HDF5FirstFrame, ¤tFrame); setIntegerParam(HDF5CurrentFrame, currentFrame); } // See if acquisition is done if (imageMode == ADImageSingle || currentFrame > lastFrame || (imageMode == ADImageMultiple && numImagesCounter >= numImages)) { // First do callback on ADStatus setStringParam(ADStatusMessage, "Waiting for acquisition"); setIntegerParam(ADStatus, ADStatusIdle); acquire = 0; setIntegerParam(ADAcquire, acquire); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: acquisition completed\n", driverName, functionName); } callParamCallbacks(); // Delay next acquisition and check if received STOP signal if(acquire) { epicsTimeGetCurrent(&endTime); elapsedTime = epicsTimeDiffInSeconds(&endTime, &startTime); delay = acquirePeriod - elapsedTime; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: delay=%f\n", driverName, functionName, delay); if(delay > 0.0) { // Set the status to waiting to indicate we are in the delay setIntegerParam(ADStatus, ADStatusWaiting); callParamCallbacks(); this->unlock(); status = epicsEventWaitWithTimeout(mStopEventId, delay); this->lock(); if (status == epicsEventWaitOK) { acquire = 0; if (imageMode == ADImageContinuous) setIntegerParam(ADStatus, ADStatusIdle); else setIntegerParam(ADStatus, ADStatusAborted); callParamCallbacks(); } } } continue; error: setIntegerParam(ADAcquire, 0); setIntegerParam(ADStatus, ADStatusError); callParamCallbacks(); continue; } }
static int mySend(epicsMessageQueueId pmsg, void *message, unsigned int size, bool wait, bool haveTimeout, double timeout) { char *myInPtr, *nextPtr; struct threadNode *pthr; if(size > pmsg->maxMessageSize) return -1; /* * See if message can be sent */ epicsMutexLock(pmsg->mutex); if ((pmsg->numberOfSendersWaiting > 0) || (pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL))) { /* * Return if not allowed to wait */ if (!wait) { epicsMutexUnlock(pmsg->mutex); return -1; } /* * Wait */ struct threadNode threadNode; threadNode.evp = getEventNode(pmsg); threadNode.eventSent = false; ellAdd(&pmsg->sendQueue, &threadNode.link); pmsg->numberOfSendersWaiting++; epicsMutexUnlock(pmsg->mutex); if(haveTimeout) epicsEventWaitWithTimeout(threadNode.evp->event, timeout); else epicsEventWait(threadNode.evp->event); epicsMutexLock(pmsg->mutex); if(!threadNode.eventSent) ellDelete(&pmsg->sendQueue, &threadNode.link); pmsg->numberOfSendersWaiting--; ellAdd(&pmsg->eventFreeList, &threadNode.evp->link); if (pmsg->full && (ellFirst(&pmsg->receiveQueue) == NULL)) { epicsMutexUnlock(pmsg->mutex); return -1; } } /* * Copy message to waiting receiver */ if ((pthr = reinterpret_cast < struct threadNode * > ( ellGet(&pmsg->receiveQueue) ) ) != NULL) { if(size <= pthr->size) memcpy(pthr->buf, message, size); pthr->size = size; pthr->eventSent = true; epicsEventSignal(pthr->evp->event); epicsMutexUnlock(pmsg->mutex); return 0; } /* * Copy to queue */ myInPtr = (char *)pmsg->inPtr; if (myInPtr == pmsg->lastMessageSlot) nextPtr = pmsg->firstMessageSlot; else nextPtr = myInPtr + pmsg->slotSize; if (nextPtr == (char *)pmsg->outPtr) pmsg->full = true; *(volatile unsigned long *)myInPtr = size; memcpy((unsigned long *)myInPtr + 1, message, size); pmsg->inPtr = nextPtr; epicsMutexUnlock(pmsg->mutex); return 0; }
/* * logClientDestroy */ static void logClientDestroy (logClientId id) { enum epicsSocketSystemCallInterruptMechanismQueryInfo interruptInfo; logClient *pClient = (logClient *) id; epicsTimeStamp begin, current; double diff; /* command log client thread to shutdown - taking mutex here */ /* forces cache flush on SMP machines */ epicsMutexMustLock ( pClient->mutex ); pClient->shutdown = 1u; epicsMutexUnlock ( pClient->mutex ); /* unblock log client thread blocking in send() or connect() */ interruptInfo = epicsSocketSystemCallInterruptMechanismQuery (); switch ( interruptInfo ) { case esscimqi_socketCloseRequired: logClientClose ( pClient ); break; case esscimqi_socketBothShutdownRequired: shutdown ( pClient->sock, SHUT_WR ); break; case esscimqi_socketSigAlarmRequired: epicsSignalRaiseSigAlarm ( pClient->restartThreadId ); break; default: break; }; /* wait for confirmation that the thread exited - taking */ /* mutex here forces cache update on SMP machines */ epicsTimeGetCurrent ( & begin ); epicsMutexMustLock ( pClient->mutex ); do { epicsMutexUnlock ( pClient->mutex ); epicsEventWaitWithTimeout ( pClient->stateChangeNotify, LOG_SERVER_SHUTDOWN_TIMEOUT / 10.0 ); epicsTimeGetCurrent ( & current ); diff = epicsTimeDiffInSeconds ( & current, & begin ); epicsMutexMustLock ( pClient->mutex ); } while ( ! pClient->shutdownConfirm && diff < LOG_SERVER_SHUTDOWN_TIMEOUT ); epicsMutexUnlock ( pClient->mutex ); if ( ! pClient->shutdownConfirm ) { fprintf ( stderr, "log client shutdown: timed out stopping" " reconnect thread for \"%s\" after %.1f seconds - cleanup aborted\n", pClient->name, LOG_SERVER_SHUTDOWN_TIMEOUT ); return; } logClientClose ( pClient ); epicsMutexDestroy ( pClient->mutex ); epicsEventDestroy ( pClient->stateChangeNotify ); free ( pClient ); }
/* * logClientCreate() */ logClientId epicsShareAPI logClientCreate ( struct in_addr server_addr, unsigned short server_port) { epicsTimeStamp begin, current; logClient *pClient; double diff; pClient = calloc (1, sizeof (*pClient)); if (pClient==NULL) { return NULL; } pClient->addr.sin_family = AF_INET; pClient->addr.sin_addr = server_addr; pClient->addr.sin_port = htons(server_port); ipAddrToDottedIP (&pClient->addr, pClient->name, sizeof(pClient->name)); pClient->mutex = epicsMutexCreate (); if ( ! pClient->mutex ) { free ( pClient ); return NULL; } pClient->sock = INVALID_SOCKET; pClient->connected = 0u; pClient->connFailStatus = 0; pClient->shutdown = 0; pClient->shutdownConfirm = 0; epicsAtExit (logClientDestroy, (void*) pClient); pClient->stateChangeNotify = epicsEventCreate (epicsEventEmpty); if ( ! pClient->stateChangeNotify ) { epicsMutexDestroy ( pClient->mutex ); free ( pClient ); return NULL; } pClient->restartThreadId = epicsThreadCreate ( "logRestart", epicsThreadPriorityLow, epicsThreadGetStackSize(epicsThreadStackSmall), logClientRestart, pClient ); if ( pClient->restartThreadId == NULL ) { epicsMutexDestroy ( pClient->mutex ); epicsEventDestroy ( pClient->stateChangeNotify ); free (pClient); fprintf(stderr, "log client: unable to start log client connection watch dog thread\n"); return NULL; } /* * attempt to synchronize with circuit connect */ epicsTimeGetCurrent ( & begin ); epicsMutexMustLock ( pClient->mutex ); do { epicsMutexUnlock ( pClient->mutex ); epicsEventWaitWithTimeout ( pClient->stateChangeNotify, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT / 10.0 ); epicsTimeGetCurrent ( & current ); diff = epicsTimeDiffInSeconds ( & current, & begin ); epicsMutexMustLock ( pClient->mutex ); } while ( ! pClient->connected && diff < LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT ); epicsMutexUnlock ( pClient->mutex ); if ( ! pClient->connected ) { fprintf (stderr, "log client create: timed out synchronizing with circuit connect to \"%s\" after %.1f seconds\n", pClient->name, LOG_SERVER_CREATE_CONNECT_SYNC_TIMEOUT ); } return (void *) pClient; }
int NDPluginDLL::madSimCallback(genCamControllerEnum::callbackReasons reason, void *pp) { genCamController* cam=(genCamController*)pp; int k; unsigned short valx; unsigned short *datax; NDDataType_t dataType; int binX, binY, minX, minY, sizeX, sizeY, reverseX, reverseY; int maxSizeX, maxSizeY; NDDimension_t dimsOut[2]; NDArrayInfo_t arrayInfo; // which thread object is calling back. // need wither several callbacks, or we need to make this one threadsafe. int id; int status; NDArray *pImage; int dims[2]; //madSimPtr->lock(); id=cam->getThisID(); // pImage = madSimPtr->pArrays[0]; switch (reason) { case genCamControllerEnum::general: madSimPtr->lock(); madSimPtr->copyParamsFromDet(1); madSimPtr->callParamCallbacks(); madSimPtr->unlock(); break; case genCamControllerEnum::before_image: madSimPtr->lock(); if (is_debug_mess) printf("before image callback\n"); madSimPtr->getIntegerParam(genCamControllerEnum::ADSizeX, &dims[0]); madSimPtr->getIntegerParam(genCamControllerEnum::ADSizeY, &dims[1]); madSimPtr->pRaw->release(); if (is_debug_mess) printf("released praw\n"); do { madSimPtr->pRaw = madSimPtr-> pNDArrayPool-> alloc(2, dims, NDUInt16, 0, NULL); if (madSimPtr->pRaw == 0) { // printf("Could not alloc NDArray, try again afte 1s\n"); Sleep(1000); madSimPtr->setIntegerParam( genCamControllerEnum::ADStatus, genCamControllerEnum::ADStatusError); } } while((madSimPtr->pRaw)==0); if (is_debug_mess) { printf("allocated praw %i \n",(long)madSimPtr->pRaw->pData); //printf("references coiunts %i \n",madSimPtr->pRaw->referenceCount); } cam->putPtrParam(genCamControllerEnum::image_mem_ptr,madSimPtr->pRaw->pData); madSimPtr->unlock(); break; case genCamControllerEnum::add_image_attribute: // must have called before_image callback to set pRaw to new NDARRAY madSimPtr->pRaw->pAttributeList->add( (const char *)cam->attribute_name, (const char *)cam->attribute_description, (NDAttrDataType_t)cam->attribute_datatype, cam->attribute_pvalue); break; case genCamControllerEnum::new_image: madSimPtr->lock(); if (is_debug_mess) printf("new image callback\n"); madSimPtr->getIntegerParam(genCamControllerEnum::ADBinX, &binX); madSimPtr->getIntegerParam(genCamControllerEnum::ADBinY, &binY); madSimPtr->getIntegerParam(genCamControllerEnum::ADMinX, &minX); madSimPtr->getIntegerParam(genCamControllerEnum::ADMinY, &minY); madSimPtr->getIntegerParam(genCamControllerEnum::ADSizeX, &sizeX); madSimPtr->getIntegerParam(genCamControllerEnum::ADSizeY, &sizeY); madSimPtr->getIntegerParam(genCamControllerEnum::ADReverseX, &reverseX); madSimPtr->getIntegerParam(genCamControllerEnum::ADReverseY, &reverseY); madSimPtr->getIntegerParam(genCamControllerEnum::ADMaxSizeX, &maxSizeX); madSimPtr->getIntegerParam(genCamControllerEnum::ADMaxSizeY, &maxSizeY); madSimPtr->getIntegerParam(genCamControllerEnum::NDDataType, (int *)&dataType); /* Extract the region of interest with binning. * If the entire image is being used (no ROI or binning) that's OK because * convertImage detects that case and is very efficient */ madSimPtr->pRaw->initDimension(&dimsOut[0], sizeX); dimsOut[0].binning = binX; dimsOut[0].offset = minX; dimsOut[0].reverse = reverseX; madSimPtr->pRaw->initDimension(&dimsOut[1], sizeY); dimsOut[1].binning = binY; dimsOut[1].offset = minY; dimsOut[1].reverse = reverseY; /* We save the most recent image buffer so it can be used in the read() function. * Now release it before getting a new version. */ // if (madSimPtr->pArrays[0]) madSimPtr->pArrays[0]->release(); if (is_debug_mess) printf("mem ptr %i\n",(long)(madSimPtr->pRaw->pData)); if (is_debug_mess) for (k=0;k<16;k++) { datax= (unsigned short *)(madSimPtr->pRaw->pData); valx = datax[k * sizeX*sizeY / 16]; printf("pRaw data %i %i \n", k * sizeX*sizeY / 16, valx); } madSimPtr->pRaw->dims[0].size=sizeX; madSimPtr->pRaw->dims[0].offset=minX; madSimPtr->pRaw->dims[0].binning=binX; madSimPtr->pRaw->dims[0].reverse=reverseX; madSimPtr->pRaw->dims[1].size=sizeY; madSimPtr->pRaw->dims[1].offset=minY; madSimPtr->pRaw->dims[1].binning=binY; madSimPtr->pRaw->dims[1].reverse=reverseY; // madSimPtr->pRaw->dataSize = sizeY*sizeX*sizeof(unsigned short); madSimPtr->pRaw->dataType = NDUInt16; madSimPtr->pRaw->uniqueId=img_dumb_count; img_dumb_count++; //epicsMutexUnlock(madSimPtr->mutexId); // madSimPtr->doCallbacksGenericPointer(madSimPtr->pArrays[0], NDArrayData, 0); madSimPtr->doCallbacksGenericPointer(madSimPtr->pRaw, madSimPtr->NDArrayDataPub, 0); //for (k=0; k<10; k++) // printf(" %i ", * ((unsigned short *)(pImage->pData) +k)); madSimPtr->callParamCallbacks(); if (is_debug_mess) printf("image callback done\n"); madSimPtr->unlock(); break; case genCamControllerEnum::make_new_thread: madSimPtr->lock(); thread_suspend_counters[id] = 0; thread_name[id]=new char[128]; sprintf(thread_name[id],"Thread %i",id); /* Create the thread that updates the images */ status = (epicsThreadCreate(thread_name[id], epicsThreadPriorityMedium, epicsThreadGetStackSize(epicsThreadStackMedium), (EPICSTHREADFUNC)madTaskC, cam) == NULL); if (status) { printf("epicsThreadCreate failure for image task\n"); } else //printf("Thread Created\n"); resume_event[id]= epicsEventCreate(epicsEventEmpty); if (!resume_event[id]) printf("epicsEventCreate failure for stop event\n"); else //printf("Epics Event Created\n"); madSimPtr->unlock(); break; case genCamControllerEnum::exiting: break; case genCamControllerEnum::grab_mutex: madSimPtr->lock(); // epicsMutexLock(madSimPtr->mutexId); break; case genCamControllerEnum::release_mutex: madSimPtr->unlock(); // epicsMutexUnlock(madSimPtr->mutexId); break; case genCamControllerEnum::call_error: break; case genCamControllerEnum::thread_suspend: // a resume event incs counter. if the thread is not suspended it does not // need to be woken up./ If we get resume event, then thread suspends it may suspend // forever. IN this way we dont miss resume events. // thread_suspend_counters[id]=thread_suspend_counters[id]-1; //if (thread_suspend_counters[id] < 0) // thread_suspend_counters[id] = 0; //if (thread_suspend_counters[id]<=0)// this way we dont miss wake up events //epicsEventWait(resume_event[id]); // cannot suspend for more than 20sec epicsEventWaitWithTimeout(resume_event[id], ((double)(cam->sleepy_time))/1000.0 ); break; case genCamControllerEnum::thread_resume: //thread_suspend_counters[id] = thread_suspend_counters[id]+1; epicsEventSignal(resume_event[id]); break; case genCamControllerEnum::wakeup_everyone: for (k = 0; k<madSimPtr->num_controllers; k++) { epicsEventSignal(resume_event[ madSimPtr->controllers[k]->getThisID() ]); //thread_suspend_counters[ madSimPtr->controllers[k]->getThisID()] = // thread_suspend_counters[ madSimPtr->controllers[k]->getThisID() ]+1; } break; case genCamControllerEnum::sleep: // need the epics sleep!! epicsThreadSleep( ((double)(cam->sleepy_time))/1000.0 ); // in this way it can be awakened by a signal. //epicsEventWaitWithTimeout(resume_event[id],((double)(cam->sleepy_time))/1000.0 ); default: break; } //madSimPtr->unlock(); return 0; }
/** This thread computes new image data and does the callbacks to send it to higher layers */ void roper::roperTask() { int status = asynSuccess; int imageCounter; int numAcquisitions, numAcquisitionsCounter; int imageMode; int arrayCallbacks; int acquire, autoSave; NDArray *pImage; double acquireTime, acquirePeriod, delay; epicsTimeStamp startTime, endTime; double elapsedTime; const char *functionName = "roperTask"; VARIANT varArg; IDispatch *pDocFileDispatch; HRESULT hr; /* Initialize the COM system for this thread */ hr = INITIALIZE_COM; if (hr == S_FALSE) { /* COM was already initialized for this thread */ CoUninitialize(); } else if (hr != S_OK) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error initializing COM\n", driverName, functionName); } VariantInit(&varArg); 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) { setIntegerParam(ADStatus, ADStatusIdle); callParamCallbacks(); /* Release the lock while we wait for an event that says acquire has started, then lock again */ asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: waiting for acquire to start\n", driverName, functionName); this->unlock(); status = epicsEventWait(this->startEventId); this->lock(); getIntegerParam(ADAcquire, &acquire); setIntegerParam(RoperNumAcquisitionsCounter, 0); } /* We are acquiring. */ /* Get the current time */ epicsTimeGetCurrent(&startTime); /* Get the exposure parameters */ getDoubleParam(ADAcquireTime, &acquireTime); getDoubleParam(ADAcquirePeriod, &acquirePeriod); getIntegerParam(ADImageMode, &imageMode); getIntegerParam(RoperNumAcquisitions, &numAcquisitions); setIntegerParam(ADStatus, ADStatusAcquire); /* Open the shutter */ setShutter(ADShutterOpen); /* Call the callbacks to update any changes */ callParamCallbacks(); try { /* Collect the frame(s) */ /* Stop current exposure, if any */ this->pExpSetup->Stop(); this->pDocFile->Close(); switch (imageMode) { case RoperImageNormal: case RoperImageContinuous: pDocFileDispatch = pExpSetup->Start2(&varArg); break; case RoperImageFocus: pDocFileDispatch = pExpSetup->StartFocus2(&varArg); break; } pDocFile->AttachDispatch(pDocFileDispatch); /* Wait for acquisition to complete, but allow acquire stop events to be handled */ while (1) { this->unlock(); status = epicsEventWaitWithTimeout(this->stopEventId, ROPER_POLL_TIME); this->lock(); if (status == epicsEventWaitOK) { /* We got a stop event, abort acquisition */ this->pExpSetup->Stop(); acquire = 0; } else { acquire = this->getAcquireStatus(); } if (!acquire) { /* Close the shutter */ setShutter(ADShutterClosed); break; } } } catch(CException *pEx) { pEx->GetErrorMessage(this->errorMessage, sizeof(this->errorMessage)); asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: exception = %s\n", driverName, functionName, this->errorMessage); pEx->Delete(); } /* Get the current parameters */ getIntegerParam(NDAutoSave, &autoSave); getIntegerParam(NDArrayCounter, &imageCounter); getIntegerParam(RoperNumAcquisitionsCounter, &numAcquisitionsCounter); getIntegerParam(NDArrayCallbacks, &arrayCallbacks); imageCounter++; numAcquisitionsCounter++; setIntegerParam(NDArrayCounter, imageCounter); setIntegerParam(RoperNumAcquisitionsCounter, numAcquisitionsCounter); if (arrayCallbacks) { /* Get the data from the DocFile */ pImage = this->getData(); if (pImage) { /* Put the frame number and time stamp into the buffer */ pImage->uniqueId = imageCounter; pImage->timeStamp = startTime.secPastEpoch + startTime.nsec / 1.e9; /* 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 imageData callback\n", driverName, functionName); doCallbacksGenericPointer(pImage, NDArrayData, 0); this->lock(); pImage->release(); } } /* See if we should save the file */ if ((imageMode != RoperImageFocus) && autoSave) { setIntegerParam(ADStatus, ADStatusSaving); callParamCallbacks(); this->saveFile(); callParamCallbacks(); } /* See if acquisition is done */ if ((imageMode == RoperImageFocus) || ((imageMode == RoperImageNormal) && (numAcquisitionsCounter >= numAcquisitions))) { setIntegerParam(ADAcquire, 0); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: acquisition completed\n", driverName, functionName); } /* Call the callbacks to update any changes */ callParamCallbacks(); getIntegerParam(ADAcquire, &acquire); /* If we are acquiring then sleep for the acquire period minus elapsed time. */ if (acquire) { epicsTimeGetCurrent(&endTime); elapsedTime = epicsTimeDiffInSeconds(&endTime, &startTime); delay = acquirePeriod - elapsedTime; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: delay=%f\n", driverName, functionName, delay); if (delay >= 0.0) { /* We set the status to indicate we are in the period delay */ setIntegerParam(ADStatus, ADStatusWaiting); callParamCallbacks(); this->unlock(); status = epicsEventWaitWithTimeout(this->stopEventId, delay); this->lock(); } } } }
int main (int argc, char *argv[]) { int i; int result; /* CA result */ OutputT format = plain; /* User specified format */ RequestT request = get; /* User specified request type */ int isArray = 0; /* Flag for array operation */ int enumAsString = 0; /* Force ENUM values to be strings */ int count = 1; int opt; /* getopt() current option */ chtype dbrType = DBR_STRING; char *pend; EpicsStr *sbuf; double *dbuf; char *cbuf = 0; char *ebuf = 0; void *pbuf; int len = 0; int waitStatus; struct dbr_gr_enum bufGrEnum; int nPvs; /* Number of PVs */ pv* pvs; /* Array of PV structures */ LINE_BUFFER(stdout); /* Configure stdout buffering */ putenv("POSIXLY_CORRECT="); /* Behave correct on GNU getopt systems */ while ((opt = getopt(argc, argv, ":cnlhatsS#:w:p:F:")) != -1) { switch (opt) { case 'h': /* Print usage */ usage(); return 0; case 'n': /* Force interpret ENUM as index number */ enumAsNr = 1; enumAsString = 0; break; case 's': /* Force interpret ENUM as menu string */ enumAsString = 1; enumAsNr = 0; break; case 'S': /* Treat char array as (long) string */ charArrAsStr = 1; isArray = 0; break; case 't': /* Select terse output format */ format = terse; break; case 'l': /* Select long output format */ format = all; break; case 'a': /* Select array mode */ isArray = 1; charArrAsStr = 0; break; case 'c': /* Select put_callback mode */ request = callback; break; case 'w': /* Set CA timeout value */ if(epicsScanDouble(optarg, &caTimeout) != 1) { fprintf(stderr, "'%s' is not a valid timeout value " "- ignored. ('caput -h' for help.)\n", optarg); caTimeout = DEFAULT_TIMEOUT; } break; case '#': /* Array count */ if (sscanf(optarg,"%d", &count) != 1) { fprintf(stderr, "'%s' is not a valid array element count " "- ignored. ('caput -h' for help.)\n", optarg); count = 0; } break; case 'p': /* CA priority */ if (sscanf(optarg,"%u", &caPriority) != 1) { fprintf(stderr, "'%s' is not a valid CA priority " "- ignored. ('caget -h' for help.)\n", optarg); caPriority = DEFAULT_CA_PRIORITY; } if (caPriority > CA_PRIORITY_MAX) caPriority = CA_PRIORITY_MAX; break; case 'F': /* Store this for output and tool_lib formatting */ fieldSeparator = (char) *optarg; break; case '?': fprintf(stderr, "Unrecognized option: '-%c'. ('caput -h' for help.)\n", optopt); return 1; case ':': fprintf(stderr, "Option '-%c' requires an argument. ('caput -h' for help.)\n", optopt); return 1; default : usage(); return 1; } } nPvs = argc - optind; /* Remaining arg list are PV names and values */ if (nPvs < 1) { fprintf(stderr, "No pv name specified. ('caput -h' for help.)\n"); return 1; } if (nPvs == 1) { fprintf(stderr, "No value specified. ('caput -h' for help.)\n"); return 1; } nPvs = 1; /* One PV - the rest is value(s) */ epId = epicsEventCreate(epicsEventEmpty); /* Create empty EPICS event (semaphore) */ /* Start up Channel Access */ result = ca_context_create(ca_enable_preemptive_callback); if (result != ECA_NORMAL) { fprintf(stderr, "CA error %s occurred while trying " "to start channel access.\n", ca_message(result)); return 1; } /* Allocate PV structure array */ pvs = calloc (nPvs, sizeof(pv)); if (!pvs) { fprintf(stderr, "Memory allocation for channel structure failed.\n"); return 1; } /* Connect channels */ pvs[0].name = argv[optind] ; /* Copy PV name from command line */ result = connect_pvs(pvs, nPvs); /* If the connection fails, we're done */ if (result) { ca_context_destroy(); return result; } /* Get values from command line */ optind++; if (isArray) { optind++; /* In case of array skip first value (nr * of elements) - actual number of values is used */ count = argc - optind; } else { /* Concatenate the remaining line to one string * (sucks but is compatible to the former version) */ for (i = optind; i < argc; i++) { len += strlen(argv[i]); len++; } cbuf = calloc(len, sizeof(char)); if (!cbuf) { fprintf(stderr, "Memory allocation failed.\n"); return 1; } strcpy(cbuf, argv[optind]); if (argc > optind+1) { for (i = optind + 1; i < argc; i++) { strcat(cbuf, " "); strcat(cbuf, argv[i]); } } if ((argc - optind) >= 1) count = 1; argv[optind] = cbuf; } sbuf = calloc (count, sizeof(EpicsStr)); dbuf = calloc (count, sizeof(double)); if(!sbuf || !dbuf) { fprintf(stderr, "Memory allocation failed\n"); return 1; } /* ENUM? Special treatment */ if (ca_field_type(pvs[0].chid) == DBR_ENUM) { /* Get the ENUM strings */ result = ca_array_get (DBR_GR_ENUM, 1, pvs[0].chid, &bufGrEnum); result = ca_pend_io(caTimeout); if (result == ECA_TIMEOUT) { fprintf(stderr, "Read operation timed out: ENUM data was not read.\n"); return 1; } if (enumAsNr) { /* Interpret values as numbers */ for (i = 0; i < count; ++i) { dbuf[i] = epicsStrtod(*(argv+optind+i), &pend); if (*(argv+optind+i) == pend) { /* Conversion didn't work */ fprintf(stderr, "Enum index value '%s' is not a number.\n", *(argv+optind+i)); return 1; } if (dbuf[i] >= bufGrEnum.no_str) { fprintf(stderr, "Warning: enum index value '%s' may be too large.\n", *(argv+optind+i)); } } dbrType = DBR_DOUBLE; } else { /* Interpret values as strings */ for (i = 0; i < count; ++i) { epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr)); *( sbuf[i]+sizeof(EpicsStr)-1 ) = '\0'; dbrType = DBR_STRING; /* Compare to ENUM strings */ for (len = 0; len < bufGrEnum.no_str; len++) if (!strcmp(sbuf[i], bufGrEnum.strs[len])) break; if (len >= bufGrEnum.no_str) { /* Not a string? Try as number */ dbuf[i] = epicsStrtod(sbuf[i], &pend); if (sbuf[i] == pend || enumAsString) { fprintf(stderr, "Enum string value '%s' invalid.\n", sbuf[i]); return 1; } if (dbuf[i] >= bufGrEnum.no_str) { fprintf(stderr, "Warning: enum index value '%s' may be too large.\n", sbuf[i]); } dbrType = DBR_DOUBLE; } } } } else { /* Not an ENUM */ if (charArrAsStr) { dbrType = DBR_CHAR; ebuf = calloc(len, sizeof(char)); if(!ebuf) { fprintf(stderr, "Memory allocation failed\n"); return 1; } count = epicsStrnRawFromEscaped(ebuf, len, cbuf, len-1) + 1; } else { for (i = 0; i < count; ++i) { epicsStrnRawFromEscaped(sbuf[i], sizeof(EpicsStr), *(argv+optind+i), sizeof(EpicsStr)); *( sbuf[i]+sizeof(EpicsStr)-1 ) = '\0'; } dbrType = DBR_STRING; } } /* Read and print old data */ if (format != terse) { printf("Old : "); result = caget(pvs, nPvs, format, 0, 0); } /* Write new data */ if (dbrType == DBR_STRING) pbuf = sbuf; else if (dbrType == DBR_CHAR) pbuf = ebuf; else pbuf = dbuf; if (request == callback) { /* Use callback version of put */ pvs[0].status = ECA_NORMAL; /* All ok at the moment */ result = ca_array_put_callback ( dbrType, count, pvs[0].chid, pbuf, put_event_handler, (void *) pvs); } else { /* Use standard put with defined timeout */ result = ca_array_put (dbrType, count, pvs[0].chid, pbuf); } result = ca_pend_io(caTimeout); if (result == ECA_TIMEOUT) { fprintf(stderr, "Write operation timed out: Data was not written.\n"); return 1; } if (request == callback) { /* Also wait for callbacks */ waitStatus = epicsEventWaitWithTimeout( epId, caTimeout ); if (waitStatus) fprintf(stderr, "Write callback operation timed out\n"); /* retrieve status from callback */ result = pvs[0].status; } if (result != ECA_NORMAL) { fprintf(stderr, "Error occured writing data.\n"); return 1; } /* Read and print new data */ if (format != terse) printf("New : "); result = caget(pvs, nPvs, format, 0, 0); /* Shut down Channel Access */ ca_context_destroy(); return result; }
static int myReceive(epicsMessageQueueId pmsg, void *message, unsigned int size, bool wait, bool haveTimeout, double timeout) { char *myOutPtr; unsigned long l; struct threadNode *pthr; /* * If there's a message on the queue, copy it */ epicsMutexLock(pmsg->mutex); myOutPtr = (char *)pmsg->outPtr; if ((myOutPtr != pmsg->inPtr) || pmsg->full) { int ret; l = *(unsigned long *)myOutPtr; if (l <= size) { memcpy(message, (unsigned long *)myOutPtr + 1, l); ret = l; } else { ret = -1; } if (myOutPtr == pmsg->lastMessageSlot) pmsg->outPtr = pmsg->firstMessageSlot; else pmsg->outPtr += pmsg->slotSize; pmsg->full = false; /* * Wake up the oldest task waiting to send */ if ((pthr = reinterpret_cast < struct threadNode * > ( ellGet(&pmsg->sendQueue) ) ) != NULL) { pthr->eventSent = true; epicsEventSignal(pthr->evp->event); } epicsMutexUnlock(pmsg->mutex); return ret; } /* * Return if not allowed to wait */ if (!wait) { epicsMutexUnlock(pmsg->mutex); return -1; } /* * Wake up the oldest task waiting to send */ if ((pthr = reinterpret_cast < struct threadNode * > ( ellGet(&pmsg->sendQueue) ) ) != NULL) { pthr->eventSent = true; epicsEventSignal(pthr->evp->event); } /* * Wait for message to arrive */ struct threadNode threadNode; threadNode.evp = getEventNode(pmsg); threadNode.buf = message; threadNode.size = size; threadNode.eventSent = false; ellAdd(&pmsg->receiveQueue, &threadNode.link); epicsMutexUnlock(pmsg->mutex); if(haveTimeout) epicsEventWaitWithTimeout(threadNode.evp->event, timeout); else epicsEventWait(threadNode.evp->event); epicsMutexLock(pmsg->mutex); if(!threadNode.eventSent) ellDelete(&pmsg->receiveQueue, &threadNode.link); ellAdd(&pmsg->eventFreeList, &threadNode.evp->link); epicsMutexUnlock(pmsg->mutex); if(threadNode.eventSent && (threadNode.size <= size)) return threadNode.size; return -1; }
/** 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_); } } } }
int main(int argc,char **argv) { char *pval; double sleepSecs = 0.0; int clearEvery = 0; int indValue = 1; int indNumberCallback = 1; while((argc>1) && (argv[1][0] == '-')) { int i; char option; int narg; option = toupper((argv[1])[1]); pval = argv[2]; argc -= 1; narg = 1; if(option=='S') { sscanf(pval,"%lf",&sleepSecs); argc -= 1; ++narg; } else if(option=='C') { sscanf(pval,"%d",&clearEvery); argc -= 1; ++narg; } else if(option=='V') { verbose = 1; } else { usageExit(); } for(i=1; i<argc; i++) argv[i] = argv[i + narg]; } if(argc != 4) usageExit(); pvname = argv[1]; pvalue1 = argv[2]; pvalue2 = argv[3]; pevent = epicsEventCreate(epicsEventEmpty); SEVCHK(ca_context_create(ca_enable_preemptive_callback), "ca_task_initialize"); while(1) { SEVCHK(ca_search(pvname,&mychid),"ca_search_and_connect"); if(ca_pend_io(3.0)!=ECA_NORMAL) { epicsThreadSleep(5.0); continue; } while(1) { epicsEventWaitStatus status; if(indValue==0) { indValue = 1; pvalue = pvalue2; } else { indValue = 0; pvalue=pvalue1; } if(++indNumberCallback >= MAXnumberCallback) indNumberCallback=0; numberCallback[indNumberCallback] = ++expectedCallback; status = ca_array_put_callback(DBR_STRING,1,mychid, pvalue,putCallback,&numberCallback[indNumberCallback]); if(status!=ECA_NORMAL) { printf("ca_array_put_callback %s\n",ca_message(status)); epicsThreadSleep(2.0); continue; } if((clearEvery>0) && ((expectedCallback % clearEvery)==0)) { ca_flush_io(); epicsThreadSleep(sleepSecs); SEVCHK(ca_clear_channel(mychid),"ca_clear_channel"); ca_flush_io(); expectedCallback = 0; epicsThreadSleep(sleepSecs); if(verbose) { printTime(); printf("Issued ca_clear_channel expectedCallback %d\n", expectedCallback); } break; } ca_flush_io(); if(verbose) { printTime(); printf("Issued ca_put_callback expectedCallback %d\n", expectedCallback); } while(1) { status = epicsEventWaitWithTimeout(pevent,10.0); if(status==epicsEventWaitTimeout) { if(verbose) { printTime(); printf("timeout after 10 seconds\n"); } continue; } break; } if(status!=epicsEventWaitOK) { int i; printTime(); printf("eventWait status %d\n",status); for(i=0; i<MAXnumberCallback; i++) numberCallback[i]=0; } epicsThreadSleep(sleepSecs); } } ca_task_exit(); return(0); }
/* * Get value from a channel. * TODO: add optional timeout argument. */ epicsShareFunc pvStat epicsShareAPI seq_pvGet(SS_ID ss, VAR_ID varId, enum compType compType) { SPROG *sp = ss->sprog; CHAN *ch = sp->chan + varId; pvStat status; PVREQ *req; epicsEventId getSem = ss->getSemId[varId]; DBCHAN *dbch = ch->dbch; PVMETA *meta = metaPtr(ch,ss); double tmo = seq_sync_timeout; /* Anonymous PV and safe mode, just copy from shared buffer. Note that completion is always immediate, so no distinction between SYNC and ASYNC needed. See also pvGetComplete. */ if ((sp->options & OPT_SAFE) && !dbch) { /* Copy regardless of whether dirty flag is set or not */ ss_read_buffer(ss, ch, FALSE); return pvStatOK; } /* No named PV and traditional mode => user error */ if (!dbch) { errlogSevPrintf(errlogMajor, "pvGet(%s): user error (variable not assigned)\n", ch->varName ); return pvStatERROR; } if (compType == DEFAULT) { compType = (sp->options & OPT_ASYNC) ? ASYNC : SYNC; } if (compType == SYNC) { double before, after; pvTimeGetCurrentDouble(&before); switch (epicsEventWaitWithTimeout(getSem, tmo)) { case epicsEventWaitOK: status = check_connected(dbch, meta); if (status) return epicsEventSignal(getSem), status; pvTimeGetCurrentDouble(&after); tmo -= (after - before); break; case epicsEventWaitTimeout: errlogSevPrintf(errlogMajor, "pvGet(ss %s, var %s, pv %s): failed (timeout " "waiting for other get requests to finish)\n", ss->ssName, ch->varName, dbch->dbName ); return pvStatERROR; case epicsEventWaitError: /* try to recover */ ss->getReq[varId] = NULL; epicsEventSignal(getSem); errlogSevPrintf(errlogFatal, "pvGet: epicsEventWaitWithTimeout() failure\n"); return pvStatERROR; } } else if (compType == ASYNC) { switch (epicsEventTryWait(getSem)) { case epicsEventWaitOK: if (ss->getReq[varId] != NULL) { /* previous request timed out but user did not call pvGetComplete */ ss->getReq[varId] = NULL; } status = check_connected(dbch, meta); if (status) return epicsEventSignal(getSem), status; break; case epicsEventWaitTimeout: errlogSevPrintf(errlogMajor, "pvGet(ss %s, var %s, pv %s): user error " "(there is already a get pending for this variable/" "state set combination)\n", ss->ssName, ch->varName, dbch->dbName ); return pvStatERROR; case epicsEventWaitError: /* try to recover */ ss->getReq[varId] = NULL; epicsEventSignal(getSem); errlogSevPrintf(errlogFatal, "pvGet: epicsEventTryWait() failure\n"); return pvStatERROR; } } /* Allocate and initialize a pv request */ req = (PVREQ *)freeListMalloc(sp->pvReqPool); req->ss = ss; req->ch = ch; assert(ss->getReq[varId] == NULL); ss->getReq[varId] = req; /* Perform the PV get operation with a callback routine specified. Requesting more than db channel has available is ok. */ status = pvVarGetCallback( dbch->pvid, /* PV id */ ch->type->getType, /* request type */ ch->count, /* element count */ seq_get_handler, /* callback handler */ req); /* user arg */ if (status != pvStatOK) { meta->status = pvStatERROR; meta->severity = pvSevrMAJOR; meta->message = "get failure"; errlogSevPrintf(errlogFatal, "pvGet(var %s, pv %s): pvVarGetCallback() failure: %s\n", ch->varName, dbch->dbName, pvVarGetMess(dbch->pvid)); ss->getReq[varId] = NULL; freeListFree(sp->pvReqPool, req); epicsEventSignal(getSem); check_connected(dbch, meta); return status; } /* Synchronous: wait for completion */ if (compType == SYNC) { epicsEventWaitStatus event_status; pvSysFlush(sp->pvSys); event_status = epicsEventWaitWithTimeout(getSem, tmo); ss->getReq[varId] = NULL; epicsEventSignal(getSem); switch (event_status) { case epicsEventWaitOK: status = check_connected(dbch, meta); if (status) return status; if (sp->options & OPT_SAFE) /* Copy regardless of whether dirty flag is set or not */ ss_read_buffer(ss, ch, FALSE); break; case epicsEventWaitTimeout: meta->status = pvStatTIMEOUT; meta->severity = pvSevrMAJOR; meta->message = "get completion timeout"; return meta->status; case epicsEventWaitError: meta->status = pvStatERROR; meta->severity = pvSevrMAJOR; meta->message = "get completion failure"; return meta->status; } } return pvStatOK; }
/** * Readout thread function */ void ADSBIG::readoutTask(void) { epicsEventWaitStatus eventStatus; epicsFloat64 timeout = 0.001; bool error = false; size_t dims[2]; int nDims = 2; epicsInt32 sizeX = 0; epicsInt32 sizeY = 0; epicsInt32 minX = 0; epicsInt32 minY = 0; NDDataType_t dataType; epicsInt32 iDataType = 0; epicsUInt32 dataSize = 0; epicsTimeStamp nowTime; NDArray *pArray = NULL; epicsInt32 numImagesCounter = 0; epicsInt32 imageCounter = 0; PAR_ERROR cam_err = CE_NO_ERROR; const char* functionName = "ADSBIG::readoutTask"; asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Started Readout Thread.\n", functionName); while (1) { //Wait for a stop event, with a short timeout, to catch any that were done after last one. eventStatus = epicsEventWaitWithTimeout(m_stopEvent, timeout); if (eventStatus == epicsEventWaitOK) { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Got Stop Event Before Start Event.\n", functionName); } lock(); if (!error) { setStringParam(ADStatusMessage, "Idle"); } callParamCallbacks(); unlock(); eventStatus = epicsEventWait(m_startEvent); if (eventStatus == epicsEventWaitOK) { asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Got Start Event.\n", functionName); error = false; setStringParam(ADStatusMessage, " "); lock(); setIntegerParam(ADNumImagesCounter, 0); setIntegerParam(ADNumExposuresCounter, 0); //Sanity checks if ((p_Cam == NULL) || (p_Img == NULL)) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s NULL pointer.\n", functionName); break; } //printf("%s Time before acqusition: ", functionName); //epicsTime::getCurrent().show(0); //Read the frame sizes getIntegerParam(ADMinX, &minX); getIntegerParam(ADMinY, &minY); getIntegerParam(ADSizeX, &sizeX); getIntegerParam(ADSizeY, &sizeY); p_Cam->SetSubFrame(minX, minY, sizeX, sizeY); //Read what type of image we want - light field or dark field? int darkField = 0; getIntegerParam(ADSBIGDarkFieldParam, &darkField); if (darkField > 0) { cam_err = p_Cam->GrabSetup(p_Img, SBDF_DARK_ONLY); } else { cam_err = p_Cam->GrabSetup(p_Img, SBDF_LIGHT_ONLY); } if (cam_err != CE_NO_ERROR) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s. CSBIGCam::GrabSetup returned an error. %s\n", functionName, p_Cam->GetErrorString(cam_err).c_str()); error = true; setStringParam(ADStatusMessage, p_Cam->GetErrorString(cam_err).c_str()); } unsigned short binX = 0; unsigned short binY = 0; p_Img->GetBinning(binX, binY); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " binX: %d\n", binY); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " binY: %d\n", binX); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " PixelHeight: %f\n", p_Img->GetPixelHeight()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " PixelWidth: %f\n", p_Img->GetPixelWidth()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " Height: %d\n", p_Img->GetHeight()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " Width: %d\n", p_Img->GetWidth()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " Readout Mode: %d\n", p_Cam->GetReadoutMode()); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, " Dark Field: %d\n", darkField); if (!error) { //Do exposure callParamCallbacks(); unlock(); if (darkField > 0) { cam_err = p_Cam->GrabMain(p_Img, SBDF_DARK_ONLY); } else { cam_err = p_Cam->GrabMain(p_Img, SBDF_LIGHT_ONLY); } lock(); if (cam_err != CE_NO_ERROR) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s. CSBIGCam::GrabMain returned an error. %s\n", functionName, p_Cam->GetErrorString(cam_err).c_str()); error = true; setStringParam(ADStatusMessage, p_Cam->GetErrorString(cam_err).c_str()); } setDoubleParam(ADSBIGPercentCompleteParam, 100.0); if (!m_aborted) { unsigned short *pData = p_Img->GetImagePointer(); //printf("%s Time after acqusition: ", functionName); //epicsTime::getCurrent().show(0); //Update counters getIntegerParam(NDArrayCounter, &imageCounter); imageCounter++; setIntegerParam(NDArrayCounter, imageCounter); getIntegerParam(ADNumImagesCounter, &numImagesCounter); numImagesCounter++; setIntegerParam(ADNumImagesCounter, numImagesCounter); //NDArray callbacks int arrayCallbacks = 0; getIntegerParam(NDArrayCallbacks, &arrayCallbacks); getIntegerParam(NDDataType, &iDataType); dataType = static_cast<NDDataType_t>(iDataType); if (dataType == NDUInt8) { dataSize = sizeX*sizeY*sizeof(epicsUInt8); } else if (dataType == NDUInt16) { dataSize = sizeX*sizeY*sizeof(epicsUInt16); } else if (dataType == NDUInt32) { dataSize = sizeX*sizeY*sizeof(epicsUInt32); } else { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s. ERROR: We can't handle this data type. dataType: %d\n", functionName, dataType); error = true; dataSize = 0; } setIntegerParam(NDArraySize, dataSize); if (!error) { if (arrayCallbacks) { //Allocate an NDArray dims[0] = sizeX; dims[1] = sizeY; if ((pArray = this->pNDArrayPool->alloc(nDims, dims, dataType, 0, NULL)) == NULL) { asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s. ERROR: pArray is NULL.\n", functionName); } else { epicsTimeGetCurrent(&nowTime); pArray->uniqueId = imageCounter; pArray->timeStamp = nowTime.secPastEpoch + nowTime.nsec / 1.e9; updateTimeStamp(&pArray->epicsTS); //Get any attributes that have been defined for this driver this->getAttributes(pArray->pAttributeList); //We copy data because the SBIG class library holds onto the original buffer until the next acqusition asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s: Copying data. dataSize: %d\n", functionName, dataSize); memcpy(pArray->pData, pData, dataSize); unlock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s: Calling NDArray callback\n", functionName); doCallbacksGenericPointer(pArray, NDArrayData, 0); lock(); pArray->release(); } } setIntegerParam(ADStatus, ADStatusIdle); } else { setIntegerParam(ADStatus, ADStatusError); } } else { //end if (!m_aborted) setIntegerParam(ADStatus, ADStatusAborted); m_aborted = false; } } callParamCallbacks(); //Complete Acquire callback setIntegerParam(ADAcquire, 0); callParamCallbacks(); unlock(); asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s Completed acqusition.\n", functionName); } //end of start event } //end of while(1) asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, "%s: ERROR: Exiting ADSBIGReadoutTask main loop.\n", functionName); }
/** 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(); } }
static void MM4000Poller(MM4000Controller *pController) { /* This is the task that polls the MM4000 */ double timeout; AXIS_HDL pAxis; int status; int itera, j; int axisDone; int offset; int anyMoving; int comStatus; int forcedFastPolls=0; char *p, *tokSave; char statusAllString[BUFFER_SIZE]; char positionAllString[BUFFER_SIZE]; char buff[BUFFER_SIZE]; timeout = pController->idlePollPeriod; epicsEventSignal(pController->pollEventId); /* Force on poll at startup */ while (1) { if (timeout != 0.) status = epicsEventWaitWithTimeout(pController->pollEventId, timeout); else status = epicsEventWait(pController->pollEventId); if (status == epicsEventWaitOK) { /* We got an event, rather than a timeout. This is because other software * knows that an axis should have changed state (started moving, etc.). * Force a minimum number of fast polls, because the controller status * might not have changed the first few polls */ forcedFastPolls = 10; } anyMoving = 0; /* Lock all the controller's axis. */ for (itera = 0; itera < pController->numAxes; itera++) { pAxis = &pController->pAxis[itera]; if (!pAxis->mutexId) break; epicsMutexLock(pAxis->mutexId); } comStatus = sendAndReceive(pController, "MS;", statusAllString, sizeof(statusAllString)); if (comStatus == 0) comStatus = sendAndReceive(pController, "TP;", positionAllString, sizeof(positionAllString)); for (itera=0; itera < pController->numAxes; itera++) { pAxis = &pController->pAxis[itera]; if (!pAxis->mutexId) break; if (comStatus != 0) { PRINT(pAxis->logParam, MOTOR_ERROR, "MM4000Poller: error reading status=%d\n", comStatus); motorParam->setInteger(pAxis->params, motorAxisCommError, 1); } else { PARAMS params = pAxis->params; int intval, axisStatus; motorParam->setInteger(params, motorAxisCommError, 0); /* * Parse the status string * Status string format: 1MSx,2MSy,3MSz,... where x, y and z are the status * bytes for the motors */ offset = pAxis->axis*5 + 3; /* Offset in status string */ axisStatus = pAxis->axisStatus = statusAllString[offset]; if (axisStatus & MM4000_MOVING) { axisDone = 0; anyMoving = 1; } else axisDone = 1; motorParam->setInteger(params, motorAxisDone, axisDone); motorParam->setInteger(params, motorAxisHomeSignal, (axisStatus & MM4000_HOME)); motorParam->setInteger(params, motorAxisHighHardLimit, (axisStatus & MM4000_HIGH_LIMIT)); motorParam->setInteger(params, motorAxisLowHardLimit, (axisStatus & MM4000_LOW_LIMIT)); motorParam->setInteger(params, motorAxisDirection, (axisStatus & MM4000_DIRECTION)); motorParam->setInteger(params, motorAxisPowerOn, !(axisStatus & MM4000_POWER_OFF)); /* * Parse motor position * Position string format: 1TP5.012,2TP1.123,3TP-100.567,... * Skip to substring for this motor, convert to double */ strcpy(buff, positionAllString); tokSave = NULL; p = epicsStrtok_r(buff, ",", &tokSave); for (j=0; j < pAxis->axis; j++) p = epicsStrtok_r(NULL, ",", &tokSave); pAxis->currentPosition = atof(p+3); motorParam->setDouble(params, motorAxisPosition, (pAxis->currentPosition/pAxis->stepSize)); motorParam->setDouble(params, motorAxisEncoderPosn, (pAxis->currentPosition/pAxis->stepSize)); PRINT(pAxis->logParam, IODRIVER, "MM4000Poller: axis %d axisStatus=%x, position=%f\n", pAxis->axis, pAxis->axisStatus, pAxis->currentPosition); /* We would like a way to query the actual velocity, but this is not possible. If we could we could * set the direction, and Moving flags */ /* Check for controller error. */ comStatus = sendAndReceive(pController, "TE;", buff, sizeof(statusAllString)); if (buff[2] == '@') intval = 0; else { intval = 1; PRINT(pAxis->logParam, MOTOR_ERROR, "MM4000Poller: controller error %s\n", buff); } motorParam->setInteger(params, motorAxisProblem, intval); } motorParam->callCallback(pAxis->params); } /* Next axis */ /* UnLock all the controller's axis. */ for (itera = 0; itera < pController->numAxes; itera++) { pAxis = &pController->pAxis[itera]; if (!pAxis->mutexId) break; epicsMutexUnlock(pAxis->mutexId); } if (forcedFastPolls > 0) { timeout = pController->movingPollPeriod; forcedFastPolls--; } else if (anyMoving) timeout = pController->movingPollPeriod; else timeout = pController->idlePollPeriod; } /* End while */ }
void ReadASCII::rampThread(void) { //Ramps SP values when the ramp is on double wait, rate, target, curSP, newSP, SPRBV; int ramping, rampOn, lookUpOn; lock(); while (1) { //check running getIntegerParam(P_Ramping, &ramping); //check ramp mode getIntegerParam(P_RampOn, &rampOn); unlock(); if ((!ramping) || (!rampOn)) { //wait for run to change epicsEventWait(eventId_); lock(); continue; } lock(); //get SP:RBV getDoubleParam(P_SPRBV, &SPRBV); //get current SP getDoubleParam(P_SPOut, &curSP); //get target getDoubleParam(P_Target, &target); if ((abs(SPRBV - target) < EPSILON) && (abs(curSP - target) < EPSILON)) { setIntegerParam(P_Ramping, 0); continue; } callParamCallbacks(); unlock(); wait = 5.0; //default wait //wait epicsEventWaitWithTimeout(eventId_, wait); //check near final SP (Doesn't work as requires long time to write to Eurotherm) //if (diff < (wait * rate)) //{ // //wait less time // wait = diff / rate; //} lock(); //check rampOn (could have changed whilst waiting) getIntegerParam(P_RampOn, &rampOn); if (!rampOn) { //no longer ramping setIntegerParam(P_Ramping, 0); continue; } //rate may have changed whilst waiting getDoubleParam(P_RampRate, &rate); //SP may have changed getDoubleParam(P_SPOut, &curSP); //target may have changed double oldTarget = target; getDoubleParam(P_Target, &target); if (oldTarget != target) { //start back at current temp getDoubleParam(P_CurTemp, &curSP); setDoubleParam(P_SPOut, curSP); continue; } double diff = abs(target - curSP); if (diff < (wait * rate)) { newSP = target; }else{ if (curSP > target) rate = -rate; //update SP with wait*rate newSP = curSP + wait*rate; } setDoubleParam(P_SPOut, newSP); callParamCallbacks(); //check PID table in use getIntegerParam(P_LookUpOn, &lookUpOn); if (lookUpOn) { checkLookUp(newSP, curSP); } } }