示例#1
0
static void getCallbackValue(devInt32Pvt *pPvt)
{
    int count, size=sizeof(epicsInt32);

    epicsMutexLock(pPvt->mutexId);
    if (pPvt->ringBuffer && (epicsRingBytesUsedBytes(pPvt->ringBuffer) >= size)) {
        if (pPvt->ringBufferOverflows > 0) {
            asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
                "%s devAsynInt32 getCallbackValue error, %d ring buffer overflows\n",
                pPvt->pr->name, pPvt->ringBufferOverflows);
                pPvt->ringBufferOverflows = 0;
        }
        count = epicsRingBytesGet(pPvt->ringBuffer, (char *)&pPvt->value, size);
        if (count == size) {
            asynPrint(pPvt->pasynUser, ASYN_TRACEIO_DEVICE,
                "%s devAsynInt32::getCallbackValue from ringBuffer value=%d\n",pPvt->pr->name,pPvt->value);
            pPvt->gotValue = 1;
        }
        else 
            asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
                "%s devAsynInt32 getCallbackValue error, ring read failed\n",
                pPvt->pr->name);
    }
    epicsMutexUnlock(pPvt->mutexId);
}
示例#2
0
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);
}
示例#3
0
asynStatus drvQuadEM::doDataCallbacks()
{
    epicsFloat64 doubleData[QE_MAX_DATA];
    epicsFloat64 *pIn, *pOut;
    int numAverage;
    int numAveraged;
    int sampleSize = sizeof(doubleData);
    int count;
    epicsTimeStamp now;
    epicsFloat64 timeStamp;
    int arrayCounter;
    int i, j;
    size_t dims[2];
    NDArray *pArrayAll, *pArraySingle;
    static const char *functionName = "doDataCallbacks";
    
    getIntegerParam(P_NumAverage, &numAverage);
    while (1) {
        numAveraged = epicsRingBytesUsedBytes(ringBuffer_) / sampleSize;
        if (numAverage > 0) {
            if (numAveraged < numAverage) break;
            numAveraged = numAverage;
            setIntegerParam(P_NumAveraged, numAveraged);
        } else {
            setIntegerParam(P_NumAveraged, numAveraged);
            if (numAveraged < 1) break;
        }

        dims[0] = QE_MAX_DATA;
        dims[1] = numAveraged;

        epicsTimeGetCurrent(&now);
        getIntegerParam(NDArrayCounter, &arrayCounter);
        arrayCounter++;
        setIntegerParam(NDArrayCounter, arrayCounter);

        pArrayAll = pNDArrayPool->alloc(2, dims, NDFloat64, 0, 0);
        pArrayAll->uniqueId = arrayCounter;
        timeStamp = now.secPastEpoch + now.nsec / 1.e9;
        pArrayAll->timeStamp = timeStamp;
        getAttributes(pArrayAll->pAttributeList);

        count = epicsRingBytesGet(ringBuffer_, (char *)pArrayAll->pData, numAveraged * sampleSize);
        if (count != numAveraged * sampleSize) {
            asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
                "%s:%s: ring read failed\n",
                driverName, functionName);
            return asynError;
        }
        ringCount_ -= numAveraged;
        unlock();
        doCallbacksGenericPointer(pArrayAll, NDArrayData, QE_MAX_DATA);
        lock();
        // Copy data to arrays for each type of data, do callbacks on that.
        dims[0] = numAveraged;
        for (i=0; i<QE_MAX_DATA; i++) {
            pArraySingle = pNDArrayPool->alloc(1, dims, NDFloat64, 0, 0);
            pArraySingle->uniqueId = arrayCounter;
            pArraySingle->timeStamp = timeStamp;
            getAttributes(pArraySingle->pAttributeList);
            pIn = (epicsFloat64 *)pArrayAll->pData;
            pOut = (epicsFloat64 *)pArraySingle->pData;
            for (j=0; j<numAveraged; j++) {
                pOut[j] = pIn[i];
                pIn += QE_MAX_DATA;
            }
            unlock();
            doCallbacksGenericPointer(pArraySingle, NDArrayData, i);
            lock();
            pArraySingle->release();
        }   
        pArrayAll->release();
        callParamCallbacks();
        // We only loop once if numAverage==0
        if (numAverage == 0) break;
    }    
    setIntegerParam(P_RingOverflows, 0);
    callParamCallbacks();
    return asynSuccess;
}
示例#4
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, &currentOffset[i]);
        getDoubleParam(i, P_CurrentScale,  &currentScale[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);
}