static void interruptCallbackInput(void *drvPvt, asynUser *pasynUser, epicsInt32 value) { devInt32Pvt *pPvt = (devInt32Pvt *)drvPvt; dbCommon *pr = pPvt->pr; int count, size = sizeof(epicsInt32); if (pPvt->bipolar && (value & pPvt->signBit)) value |= ~pPvt->mask; asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE, "%s devAsynInt32::interruptCallbackInput new value=%d\n", pr->name, value); /* There is a problem. A driver could be calling us with a value after * this record has registered for callbacks but before EPICS has set interruptAccept, * which means that scanIoRequest will return immediately. * This is very bad, because if we have pushed a value into the ring buffer * it won't get popped off because the record won't process. The values * read the next time the record processes would then be stale. * We previously worked around this problem by waiting here for interruptAccept. * But that does not work if the callback is coming from the thread that is executing * iocInit, which can happen with synchronous drivers (ASYN_CANBLOCK=0) that do callbacks * when a value is written to them, which can happen in initRecord for an output record. * Instead we just return. There will then be nothing in the ring buffer, so the first * read will do a read from the driver, which should be OK. */ if (!interruptAccept) return; /* Note that we put a lock around epicsRingBytesPut and Get because we potentially have * more than one reader, since the reader is whatever thread is processing the record */ epicsMutexLock(pPvt->mutexId); count = epicsRingBytesPut(pPvt->ringBuffer, (char *)&value, size); if (count != size) { /* There was no room in the ring buffer. In the past we just threw away * the new value. However, it is better to remove the oldest value from the * ring buffer and add the new one. That way the final value the record receives * is guaranteed to be the most recent value */ epicsInt32 dummy; count = epicsRingBytesGet(pPvt->ringBuffer, (char *)&dummy, size); if (count != size) { asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, "%s devAsynInt32 interruptCallbackInput error, ring read failed\n", pPvt->pr->name); } count = epicsRingBytesPut(pPvt->ringBuffer, (char *)&value, size); if (count != size) { asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR, "%s devAsynInt32 interruptCallbackInput error, ring put failed\n", pPvt->pr->name); } pPvt->ringBufferOverflows++; } else { /* We only need to request the record to process if we added a * new element to the ring buffer, not if we just replaced an element. */ scanIoRequest(pPvt->ioScanPvt); } epicsMutexUnlock(pPvt->mutexId); }
static void interruptCallbackOutput(void *drvPvt, asynUser *pasynUser, epicsInt32 value) { devInt32Pvt *pPvt = (devInt32Pvt *)drvPvt; dbCommon *pr = pPvt->pr; int count, size = sizeof(epicsInt32); asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE, "%s devAsynInt32::interruptCallbackOutput new value=%d\n", pr->name, value); epicsMutexLock(pPvt->mutexId); count = epicsRingBytesPut(pPvt->ringBuffer, (char *)&value, size); if (count != size) { pPvt->ringBufferOverflows++; } epicsMutexUnlock(pPvt->mutexId); scanOnce(pr); }
LOCAL long devBoGP307_write_bo(boRecord *precord) { devGP307dpvt *pdevGP307dpvt = (devGP307dpvt*)precord->dpvt; drvGP307Config *pdrvGP307Config = (drvGP307Config*)pdevGP307dpvt->pdrvGP307Config; GP307_read *pGP307_read = (GP307_read*) pdrvGP307Config->pGP307_read; drvGP307CallbackQueueBuf vdrvGP307CallbackQueueBuf; drvGP307CallbackQueueBuf *pdrvGP307CallbackQueueBuf = &vdrvGP307CallbackQueueBuf; GP307_read *pBufGP307_read = &pdrvGP307CallbackQueueBuf->vGP307_read; int nbytes; asynStatus vasynStatus; if(precord->pact) { /* post prcoessing */ switch(pGP307_read->command_from_postCallback) { case GP307CMD_ONDG: case GP307CMD_OFFDG: case GP307CMD_ONIG0: case GP307CMD_OFFIG0: case GP307CMD_ONIG1: case GP307CMD_OFFIG1: break; /* nothing to do */ default: /* disable record function forever */ precord->pact = TRUE; precord->udf = TRUE; return 0; } precord->udf =FALSE; return 2; /* don't do any conversion */ } /* pre-prcoessing */ precord->pact = TRUE; epicsMutexLock(pdrvGP307Config->lock); pdrvGP307Config->cbCount++; pBufGP307_read->status = pGP307_read->status; epicsMutexUnlock(pdrvGP307Config->lock); pdrvGP307CallbackQueueBuf->userPvt = (void*)pdrvGP307Config; pdrvGP307CallbackQueueBuf->precord = (dbCommon*) precord; switch(pdevGP307dpvt->param) { case GP307DEVPARAM_DGONOFF: if(precord->rval) pdrvGP307CallbackQueueBuf->command = GP307CMD_ONDG; else pdrvGP307CallbackQueueBuf->command = GP307CMD_OFFDG; break; case GP307DEVPARAM_IG0ONOFF: if(precord->rval) pdrvGP307CallbackQueueBuf->command = GP307CMD_ONIG0; else pdrvGP307CallbackQueueBuf->command = GP307CMD_OFFIG0; break; case GP307DEVPARAM_IG1ONOFF: if(precord->rval) pdrvGP307CallbackQueueBuf->command = GP307CMD_ONIG1; else pdrvGP307CallbackQueueBuf->command = GP307CMD_OFFIG1; break; default: /* disable record function forever */ precord->pact = TRUE; precord->udf = TRUE; return 0; } /* put the callback queue */ nbytes = epicsRingBytesPut(pdrvGP307Config->queueCallbackRingBytesId, (char*)pdrvGP307CallbackQueueBuf, sizeof(drvGP307CallbackQueueBuf)); vasynStatus = pasynManager->queueRequest(pdrvGP307Config->pasynGP307User, asynQueuePriorityLow, pdrvGP307Config->cbTimeout); if(vasynStatus == asynError) { epicsMutexLock(pdrvGP307Config->lock); pdrvGP307Config->asynRequestLostCount++; epicsMutexUnlock(pdrvGP307Config->lock); } return 0; }
LOCAL long devMbbiGP307_read_mbbi(mbbiRecord *precord) { devGP307dpvt *pdevGP307dpvt = (devGP307dpvt*)precord->dpvt; drvGP307Config *pdrvGP307Config = (drvGP307Config*)pdevGP307dpvt->pdrvGP307Config; GP307_read *pGP307_read = (GP307_read*)pdrvGP307Config->pGP307_read; drvGP307CallbackQueueBuf vdrvGP307CallbackQueueBuf; drvGP307CallbackQueueBuf *pdrvGP307CallbackQueueBuf = &vdrvGP307CallbackQueueBuf; GP307_read *pBufGP307_read = &pdrvGP307CallbackQueueBuf->vGP307_read; int nbytes; asynStatus vasynStatus; if(precord->pact) { /* post processing */ switch(pGP307_read->command_from_postCallback) { case GP307CMD_DGS: epicsMutexLock(pdrvGP307Config->lock); precord->rval = (pGP307_read->status & GP307STATUS_DGONOFF_MASK)?((unsigned long)0x01):((unsigned long)0x00); epicsMutexUnlock(pdrvGP307Config->lock); break; case GP307CMD_READPCS: epicsMutexLock(pdrvGP307Config->lock); precord->rval = (unsigned long) pGP307_read->pcs; epicsMutexUnlock(pdrvGP307Config->lock); break; default: /* disable record function forever */ precord->pact = TRUE; precord->udf = TRUE; return 0; } precord->val = precord->rval; precord->udf = FALSE; return 2; /* don't do any conversion */ } /* pre-processing */ precord->pact = TRUE; epicsMutexLock(pdrvGP307Config->lock); pdrvGP307Config->cbCount++; pBufGP307_read->status = pGP307_read->status; epicsMutexUnlock(pdrvGP307Config->lock); pdrvGP307CallbackQueueBuf->userPvt = (void*)pdrvGP307Config; pdrvGP307CallbackQueueBuf->precord = (dbCommon*)precord; switch(pdevGP307dpvt->param) { case GP307DEVPARAM_READDGS: pdrvGP307CallbackQueueBuf->command = GP307CMD_DGS; break; case GP307DEVPARAM_READPCS: pdrvGP307CallbackQueueBuf->command = GP307CMD_READPCS; break; default: /* disable record function forever */ precord->pact = TRUE; precord->udf = TRUE; return 0; } /* put the callback queue */ nbytes = epicsRingBytesPut(pdrvGP307Config->queueCallbackRingBytesId, (char*)pdrvGP307CallbackQueueBuf, sizeof(drvGP307CallbackQueueBuf)); vasynStatus = pasynManager->queueRequest(pdrvGP307Config->pasynGP307User, asynQueuePriorityLow, pdrvGP307Config->cbTimeout); if(vasynStatus == asynError) { epicsMutexLock(pdrvGP307Config->lock); pdrvGP307Config->asynRequestLostCount++; epicsMutexUnlock(pdrvGP307Config->lock); } return 0; }
/** This function computes the sums, diffs and positions, and does callbacks * \param[in] raw Array of raw current readings */ void drvQuadEM::computePositions(epicsFloat64 raw[QE_MAX_INPUTS]) { int i; int count; int numAverage; int ringOverflows; int geometry; epicsFloat64 currentOffset[QE_MAX_INPUTS]; epicsFloat64 currentScale[QE_MAX_INPUTS]; epicsFloat64 positionOffset[2]; epicsFloat64 positionScale[2]; epicsInt32 intData[QE_MAX_DATA]; epicsFloat64 doubleData[QE_MAX_DATA]; epicsFloat64 denom; static const char *functionName = "computePositions"; getIntegerParam(P_Geometry, &geometry); // If the ring buffer is full then remove the oldest entry if (epicsRingBytesFreeBytes(ringBuffer_) < (int)sizeof(doubleData)) { count = epicsRingBytesGet(ringBuffer_, (char *)&doubleData, sizeof(doubleData)); ringCount_--; getIntegerParam(P_RingOverflows, &ringOverflows); ringOverflows++; setIntegerParam(P_RingOverflows, ringOverflows); } for (i=0; i<QE_MAX_INPUTS; i++) { getDoubleParam(i, P_CurrentOffset, ¤tOffset[i]); getDoubleParam(i, P_CurrentScale, ¤tScale[i]); doubleData[i] = raw[i]*currentScale[i] - currentOffset[i]; } for (i=0; i<2; i++) { getDoubleParam(i, P_PositionOffset, &positionOffset[i]); getDoubleParam(i, P_PositionScale, &positionScale[i]); } doubleData[QESumAll] = doubleData[QECurrent1] + doubleData[QECurrent2] + doubleData[QECurrent3] + doubleData[QECurrent4]; if (geometry == QEGeometrySquare) { doubleData[QESumX] = doubleData[QESumAll]; doubleData[QESumY] = doubleData[QESumAll]; doubleData[QEDiffX] = (doubleData[QECurrent2] + doubleData[QECurrent3]) - (doubleData[QECurrent1] + doubleData[QECurrent4]); doubleData[QEDiffY] = (doubleData[QECurrent1] + doubleData[QECurrent2]) - (doubleData[QECurrent3] + doubleData[QECurrent4]); } else { doubleData[QESumX] = doubleData[QECurrent1] + doubleData[QECurrent2]; doubleData[QESumY] = doubleData[QECurrent3] + doubleData[QECurrent4]; doubleData[QEDiffX] = doubleData[QECurrent2] - doubleData[QECurrent1]; doubleData[QEDiffY] = doubleData[QECurrent4] - doubleData[QECurrent3]; } denom = doubleData[QESumX]; if (denom == 0.) denom = 1.; doubleData[QEPositionX] = (positionScale[0] * doubleData[QEDiffX] / denom) - positionOffset[0]; denom = doubleData[QESumY]; if (denom == 0.) denom = 1.; doubleData[QEPositionY] = (positionScale[1] * doubleData[QEDiffY] / denom) - positionOffset[1]; count = epicsRingBytesPut(ringBuffer_, (char *)&doubleData, sizeof(doubleData)); ringCount_++; if (count != sizeof(doubleData)) { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: error writing ring buffer, count=%d, should be %d\n", driverName, functionName, count, (int)sizeof(doubleData)); } getIntegerParam(P_NumAverage, &numAverage); if (numAverage > 0) { if (ringCount_ >= numAverage) { triggerCallbacks(); } } for (i=0; i<QE_MAX_DATA; i++) { intData[i] = (epicsInt32)doubleData[i]; setDoubleParam(i, P_DoubleData, doubleData[i]); callParamCallbacks(i); } doCallbacksInt32Array(intData, QE_MAX_DATA, P_IntArrayData, 0); }