Example #1
0
/** This method copies an NDArray object from the asynNDArrayDriver to an NDArray pointer passed in by the caller.
  * The destination NDArray address is passed by the caller in the genericPointer argument. The caller
  * must allocate the memory for the array, and pass the size in NDArray->dataSize.
  * The method will limit the amount of data copied to the actual array size or the
  * input dataSize, whichever is smaller.
  * \param[in] pasynUser Used to obtain the addr for the NDArray to be copied from, and for asynTrace output.
  * \param[out] genericPointer Pointer to an NDArray. The NDArray must have been previously allocated by the caller.
  * The NDArray from the asynNDArrayDriver will be copied into the NDArray pointed to by genericPointer.
  */
asynStatus asynNDArrayDriver::readGenericPointer(asynUser *pasynUser, void *genericPointer)
{
    NDArray *pArray = (NDArray *)genericPointer;
    NDArray *myArray;
    NDArrayInfo_t arrayInfo;
    int addr;
    asynStatus status = asynSuccess;
    const char* functionName = "readNDArray";

    status = getAddress(pasynUser, &addr); if (status != asynSuccess) return(status);
    this->lock();
    myArray = this->pArrays[addr];
    if (!myArray) {
        epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
                    "%s:%s: error, no valid array available, pData=%p",
                    driverName, functionName, pArray->pData);
        status = asynError;
    } else {
        this->pNDArrayPool->copy(myArray, pArray, 0);
        myArray->getInfo(&arrayInfo);
        if (arrayInfo.totalBytes > pArray->dataSize) arrayInfo.totalBytes = pArray->dataSize;
        memcpy(pArray->pData, myArray->pData, arrayInfo.totalBytes);
        pasynUser->timestamp = myArray->epicsTS;
    }
    if (!status)
        asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
              "%s:%s: error, maxBytes=%lu, data=%p\n",
              driverName, functionName, (unsigned long)arrayInfo.totalBytes, pArray->pData);
    this->unlock();
    return status;
}
/** Callback function that is called by the NDArray driver with new NDArray data.
  * Does image processing.
  * \param[in] pArray  The NDArray from the callback.
  */
void NDPluginProcess::processCallbacks(NDArray *pArray)
{
    /* This function does array processing.
     * It is called with the mutex already locked.  It unlocks it during long calculations when private
     * structures don't need to be protected.
     */
    size_t i;
    NDArray *pScratch=NULL;
    double  *data, newData, newFilter;
    NDArrayInfo arrayInfo;
    double  *background=NULL, *flatField=NULL, *filter=NULL;
    double  value;
    size_t  nElements;
    int     saveBackground, enableBackground, validBackground;
    int     saveFlatField,  enableFlatField,  validFlatField;
    double  scaleFlatField;
    int     enableOffsetScale, autoOffsetScale;
    double  offset, scale, minValue, maxValue;
    double  lowClip=0, highClip=0;
    int     enableLowClip, enableHighClip;
    int     resetFilter, autoResetFilter, filterCallbacks, doCallbacks=1;
    int     enableFilter, numFilter;
    int     dataType;
    int     anyProcess;
    double  oOffset, fOffset, rOffset, oScale, fScale;
    double  oc1, oc2, oc3, oc4;
    double  fc1, fc2, fc3, fc4;
    double  rc1, rc2;
    double  F1, F2, O1, O2;

    NDArray *pArrayOut = NULL;
    static const char* functionName = "processCallbacks";

    /* Call the base class method */
    NDPluginDriver::processCallbacks(pArray);

    /* Need to fetch all of these parameters while we still have the mutex */
    getIntegerParam(NDPluginProcessDataType,            &dataType);
    getIntegerParam(NDPluginProcessSaveBackground,      &saveBackground);
    getIntegerParam(NDPluginProcessEnableBackground,    &enableBackground);
    getIntegerParam(NDPluginProcessSaveFlatField,       &saveFlatField);
    getIntegerParam(NDPluginProcessEnableFlatField,     &enableFlatField);
    getDoubleParam (NDPluginProcessScaleFlatField,      &scaleFlatField);
    getIntegerParam(NDPluginProcessEnableOffsetScale,   &enableOffsetScale);
    getIntegerParam(NDPluginProcessAutoOffsetScale,     &autoOffsetScale);
    getIntegerParam(NDPluginProcessEnableLowClip,       &enableLowClip);
    getIntegerParam(NDPluginProcessEnableHighClip,      &enableHighClip);
    getIntegerParam(NDPluginProcessEnableFilter,        &enableFilter);
    getIntegerParam(NDPluginProcessResetFilter,         &resetFilter);
    getIntegerParam(NDPluginProcessAutoResetFilter,     &autoResetFilter);
    getIntegerParam(NDPluginProcessFilterCallbacks,     &filterCallbacks);

    if (enableOffsetScale) {
        getDoubleParam (NDPluginProcessScale,           &scale);
        getDoubleParam (NDPluginProcessOffset,          &offset);
    }
    if (enableLowClip) 
        getDoubleParam (NDPluginProcessLowClip,         &lowClip);
    if (enableHighClip) 
        getDoubleParam (NDPluginProcessHighClip,        &highClip);
    if (resetFilter) 
        setIntegerParam(NDPluginProcessResetFilter, 0);
    if (enableFilter) {
        getIntegerParam(NDPluginProcessNumFilter,       &numFilter);
        getDoubleParam (NDPluginProcessOOffset,         &oOffset);
        getDoubleParam (NDPluginProcessOScale,          &oScale);
        getDoubleParam (NDPluginProcessOC1,             &oc1);
        getDoubleParam (NDPluginProcessOC2,             &oc2);
        getDoubleParam (NDPluginProcessOC3,             &oc3);
        getDoubleParam (NDPluginProcessOC4,             &oc4);
        getDoubleParam (NDPluginProcessFOffset,         &fOffset);
        getDoubleParam (NDPluginProcessFScale,          &fScale);
        getDoubleParam (NDPluginProcessFC1,             &fc1);
        getDoubleParam (NDPluginProcessFC2,             &fc2);
        getDoubleParam (NDPluginProcessFC3,             &fc3);
        getDoubleParam (NDPluginProcessFC4,             &fc4);
        getDoubleParam (NDPluginProcessROffset,         &rOffset);
        getDoubleParam (NDPluginProcessRC1,             &rc1);
        getDoubleParam (NDPluginProcessRC2,             &rc2);
    }

    /* Release the lock now that we are only doing things that don't involve memory other thread
     * cannot access */
    this->unlock();
    /* Special case for automatic data type */
    if (dataType == -1) dataType = (int)pArray->dataType;
    
    pArray->getInfo(&arrayInfo);
    nElements = arrayInfo.nElements;

    validBackground = 0;
    if (this->pBackground && (nElements == this->nBackgroundElements)) validBackground = 1;
    setIntegerParam(NDPluginProcessValidBackground, validBackground);
    validFlatField = 0;
    if (this->pFlatField && (nElements == this->nFlatFieldElements)) validFlatField = 1;
    setIntegerParam(NDPluginProcessValidFlatField, validFlatField);

    if (validBackground && enableBackground)
        background = (double *)this->pBackground->pData;
    if (validFlatField && enableFlatField)
        flatField = (double *)this->pFlatField->pData;

    anyProcess = ((enableBackground && validBackground) ||
                  (enableFlatField && validFlatField)   ||
                   enableOffsetScale                    ||
                   autoOffsetScale                      ||
                   enableHighClip                       || 
                   enableLowClip                        ||
                   enableFilter);
    /* If no processing is to be done just convert the input array and do callbacks */
    if (!anyProcess) {
        /* Convert the array to the desired output data type */
        this->pNDArrayPool->convert(pArray, &pArrayOut, (NDDataType_t)dataType);
        goto doCallbacks;
    }
    
    /* Make a copy of the array converted to double, because we cannot modify the input array */
    this->pNDArrayPool->convert(pArray, &pScratch, NDFloat64);
    if (NULL == pScratch) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
            "%s:%s Processing aborted; cannot allocate an NDArray for storage of temporary data.\n", 
            driverName, functionName);
        goto doCallbacks;
    }
    data = (double *)pScratch->pData;

    if (nElements > 0) {
        minValue = data[0];
        maxValue = data[0];
    } else {
        minValue = 0;
        maxValue = 1;
    }
    for (i=0; i<nElements; i++) {
        value = data[i];
        if (autoOffsetScale) {
            if (data[i] < minValue) minValue = data[i];
            if (data[i] > maxValue) maxValue = data[i];
        }
        if (background) value -= background[i];
        if (flatField) {
            if (flatField[i] != 0.) 
                value *= scaleFlatField / flatField[i];
            else
                value = scaleFlatField;
        }
        if (enableOffsetScale) value = (value + offset)*scale;
        if (enableHighClip && (value > highClip)) value = highClip;
        if (enableLowClip  && (value < lowClip))  value = lowClip;
        data[i] = value;
    }
    
    if (enableFilter) {
        if (this->pFilter) {
            this->pFilter->getInfo(&arrayInfo);
            if (nElements != arrayInfo.nElements) {
                this->pFilter->release();
                this->pFilter = NULL;
            }
        }
        if (!this->pFilter) {
            /* There is not a current filter array */
            /* Make a copy of the current array, converted to double type */
            this->pNDArrayPool->convert(pScratch, &this->pFilter, NDFloat64);
            if (NULL == this->pFilter) {
                asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
                    "%s:%s Processing aborted; cannot allocate an NDArray to store the filter.\n", 
                    driverName,functionName);
                goto doCallbacks;
            }
            resetFilter = 1;
        }
        if ((this->numFiltered >= numFilter) && autoResetFilter)
          resetFilter = 1;
        if (resetFilter) {
            filter = (double *)this->pFilter->pData;
            for (i=0; i<nElements; i++) {
                newFilter = rOffset;
                if (rc1) newFilter += rc1*filter[i];
                if (rc2) newFilter += rc2*data[i];
                filter[i] = newFilter;
            }           
            this->numFiltered = 0;
        }
        /* Do the filtering */
        if (this->numFiltered < numFilter) this->numFiltered++;
        filter = (double *)this->pFilter->pData;
        O1 = oScale * (oc1 + oc2/this->numFiltered);
        O2 = oScale * (oc3 + oc4/this->numFiltered);
        F1 = fScale * (fc1 + fc2/this->numFiltered);
        F2 = fScale * (fc3 + fc4/this->numFiltered);
        for (i=0; i<nElements; i++) {
            newData   = oOffset;
            if (O1) newData += O1 * filter[i];
            if (O2) newData += O2 * data[i];
            newFilter = fOffset;
            if (F1) newFilter += F1 * filter[i];
            if (F2) newFilter += F2 * data[i];
            data[i] = newData;
            filter[i] = newFilter;
        }
        if ((this->numFiltered != numFilter) && filterCallbacks)
          doCallbacks = 0;
    }

    if (doCallbacks) {
      /* Convert the array to the desired output data type */
      this->pNDArrayPool->convert(pScratch, &pArrayOut, (NDDataType_t)dataType);
    }

    if (autoOffsetScale && (NULL != pArrayOut)) {
        pArrayOut->getInfo(&arrayInfo);
        double maxScale = pow(2., arrayInfo.bytesPerElement*8) - 1;
        scale = maxScale /(maxValue-minValue);
        offset = -minValue;
        setDoubleParam (NDPluginProcessScale,             scale);
        setDoubleParam (NDPluginProcessOffset,            offset);
        setDoubleParam (NDPluginProcessLowClip,           0);
        setDoubleParam (NDPluginProcessHighClip,          maxScale);
        setIntegerParam(NDPluginProcessEnableOffsetScale, 1);
        setIntegerParam(NDPluginProcessEnableLowClip,     1);
        setIntegerParam(NDPluginProcessEnableHighClip,    1);
    }

    doCallbacks:    
    /* We must exit with the mutex locked */
    this->lock();
    if (doCallbacks && (NULL != pArrayOut)) {
        /* Get the attributes from this driver */
        this->getAttributes(pArrayOut->pAttributeList);
        /* Call any clients who have registered for NDArray callbacks */
        this->unlock();
        doCallbacksGenericPointer( pArrayOut, NDArrayData, 0);
        this->lock();
        if (NULL != this->pArrays[0]) this->pArrays[0]->release();
        this->pArrays[0] = pArrayOut;
    }

    if (NULL != pScratch) pScratch->release();

    setIntegerParam(NDPluginProcessNumFiltered, this->numFiltered);
    callParamCallbacks();
    if (autoOffsetScale && this->pArrays[0] != NULL) {
        setIntegerParam(NDPluginProcessAutoOffsetScale, 0);
        callParamCallbacks();
    }
}
Example #3
0
/** Allocates a new NDArray object; the first 3 arguments are required.
  * \param[in] ndims The number of dimensions in the NDArray. 
  * \param[in] dims Array of dimensions, whose size must be at least ndims.
  * \param[in] dataType Data type of the NDArray data.
  * \param[in] dataSize Number of bytes to allocate for the array data; if 0 then
  * alloc() will compute the size required from ndims, dims, and dataType.
  * \param[in] pData Pointer to a data buffer; if NULL then alloc will allocate a new
  * array buffer; if not NULL then it is assumed to point to a valid buffer.
  * 
  * If pData is not NULL then dataSize must contain the actual number of bytes in the existing
  * array, and this array must be large enough to hold the array data. 
  * alloc() searches
  * its free list to find a free NDArray buffer. If is cannot find one then it will
  * allocate a new one and add it to the free list. If doing so would exceed maxBuffers
  * then alloc() will return an error. Similarly if allocating the memory required for
  * this NDArray would cause the cumulative memory allocated for the pool to exceed
  * maxMemory then an error will be returned. alloc() sets the reference count for the
  * returned NDArray to 1.
  */
NDArray* NDArrayPool::alloc(int ndims, size_t *dims, NDDataType_t dataType, size_t dataSize, void *pData)
{
  NDArray *pArray;
  NDArrayInfo_t arrayInfo;
  int i;
  const char* functionName = "NDArrayPool::alloc:";

  epicsMutexLock(listLock_);

  /* Find a free image */
  pArray = (NDArray *)ellFirst(&freeList_);

  if (!pArray) {
    /* We did not find a free image.
     * Allocate a new one if we have not exceeded the limit */
    if ((maxBuffers_ > 0) && (numBuffers_ >= maxBuffers_)) {
      printf("%s: error: reached limit of %d buffers (memory use=%ld/%ld bytes)\n",
             functionName, maxBuffers_, (long)memorySize_, (long)maxMemory_);
    } else {
      numBuffers_++;
      pArray = new NDArray;
      ellAdd(&freeList_, &pArray->node);
      numFree_++;
    }
  }

  if (pArray) {
    /* We have a frame */
    /* Initialize fields */
    pArray->pNDArrayPool = this;
    pArray->dataType = dataType;
    pArray->ndims = ndims;
    memset(pArray->dims, 0, sizeof(pArray->dims));
    for (i=0; i<ndims && i<ND_ARRAY_MAX_DIMS; i++) {
      pArray->dims[i].size = dims[i];
      pArray->dims[i].offset = 0;
      pArray->dims[i].binning = 1;
      pArray->dims[i].reverse = 0;
    }
    /* Erase the attributes if that global flag is set */
    if (eraseNDAttributes) pArray->pAttributeList->clear();
    pArray->getInfo(&arrayInfo);
    if (dataSize == 0) dataSize = arrayInfo.totalBytes;
    if (arrayInfo.totalBytes > dataSize) {
      printf("%s: ERROR: required size=%d passed size=%d is too small\n",
      functionName, (int)arrayInfo.totalBytes, (int)dataSize);
      pArray=NULL;
    }
  }

  if (pArray) {
    /* If the caller passed a valid buffer use that, trust that its size is correct */
    if (pData) {
      pArray->pData = pData;
    } else {
      /* See if the current buffer is big enough */
      if (pArray->dataSize < dataSize) {
        /* No, we need to free the current buffer and allocate a new one */
        /* See if there is enough room */
        if (pArray->pData) {
          memorySize_ -= pArray->dataSize;
          free(pArray->pData);
          pArray->pData = NULL;
          pArray->dataSize = 0;
        }
        if ((maxMemory_ > 0) && ((memorySize_ + dataSize) > maxMemory_)) {
          // We don't have enough memory to allocate the array
          // See if we can get memory by deleting arrays
          NDArray *freeArray = (NDArray *)ellFirst(&freeList_);
          while (freeArray && ((memorySize_ + dataSize) > maxMemory_)) {
            if (freeArray->pData) {
              memorySize_ -= freeArray->dataSize;
              free(freeArray->pData);
              freeArray->pData = NULL;
              freeArray->dataSize = 0;
            }
            // Next array
            freeArray = (NDArray *)ellNext(&freeArray->node);
          }
        }
        if ((maxMemory_ > 0) && ((memorySize_ + dataSize) > maxMemory_)) {
          printf("%s: error: reached limit of %ld memory (%d/%d buffers)\n",
                 functionName, (long)maxMemory_, numBuffers_, maxBuffers_);
          pArray = NULL;
        } else {
          pArray->pData = malloc(dataSize);
          if (pArray->pData) {
            pArray->dataSize = dataSize;
            memorySize_ += dataSize;
          } else {
            pArray = NULL;
          }
        }
      }
    }
    // If we don't have a valid memory buffer see pArray to NULL to indicate error
    if (pArray && (pArray->pData == NULL)) pArray = NULL;
  }
  if (pArray) {
    /* Set the reference count to 1, remove from free list */
    pArray->referenceCount = 1;
    ellDelete(&freeList_, &pArray->node);
    numFree_--;
  }
  epicsMutexUnlock(listLock_);
  return (pArray);
}
Example #4
0
/** Creates a new output NDArray from an input NDArray, performing
  * conversion operations.
  * The conversion can change the data type if dataTypeOut is different from
  * pIn->dataType. It can also change the dimensions. outDims may have different
  * values of size, binning, offset and reverse for each of its dimensions from input
  * array dimensions (pIn->dims).
  * \param[in] pIn The input array, source of the conversion.
  * \param[out] ppOut The output array, result of the conversion.
  * \param[in] dataTypeOut The data type of the output array.
  * \param[in] dimsOut The dimensions of the output array.
  */
int NDArrayPool::convert(NDArray *pIn,
                         NDArray **ppOut,
                         NDDataType_t dataTypeOut,
                         NDDimension_t *dimsOut)
{
  int dimsUnchanged;
  size_t dimSizeOut[ND_ARRAY_MAX_DIMS];
  NDDimension_t dimsOutCopy[ND_ARRAY_MAX_DIMS];
  int i;
  NDArray *pOut;
  NDArrayInfo_t arrayInfo;
  NDAttribute *pAttribute;
  int colorMode, colorModeMono = NDColorModeMono;
  const char *functionName = "convert";

  /* Initialize failure */
  *ppOut = NULL;

  /* Copy the input dimension array because we need to modify it
   * but don't want to affect caller */
  memcpy(dimsOutCopy, dimsOut, pIn->ndims*sizeof(NDDimension_t));
  /* Compute the dimensions of the output array */
  dimsUnchanged = 1;
  for (i=0; i<pIn->ndims; i++) {
    dimsOutCopy[i].size = dimsOutCopy[i].size/dimsOutCopy[i].binning;
    if (dimsOutCopy[i].size <= 0) {
      printf("%s:%s: ERROR, invalid output dimension, size=%d, binning=%d\n",
             driverName, functionName, (int)dimsOut[i].size, dimsOut[i].binning);
      return(ND_ERROR);
    }
    dimSizeOut[i] = dimsOutCopy[i].size;
    if ((pIn->dims[i].size  != dimsOutCopy[i].size) ||
      (dimsOutCopy[i].offset != 0) ||
      (dimsOutCopy[i].binning != 1) ||
      (dimsOutCopy[i].reverse != 0)) dimsUnchanged = 0;
  }

  /* We now know the datatype and dimensions of the output array.
   * Allocate it */
  pOut = alloc(pIn->ndims, dimSizeOut, dataTypeOut, 0, NULL);
  *ppOut = pOut;
  if (!pOut) {
    printf("%s:%s: ERROR, cannot allocate output array\n",
           driverName, functionName);
    return(ND_ERROR);
  }
  /* Copy fields from input to output */
  pOut->timeStamp = pIn->timeStamp;
  pOut->epicsTS = pIn->epicsTS;
  pOut->uniqueId = pIn->uniqueId;
  /* Replace the dimensions with those passed to this function */
  memcpy(pOut->dims, dimsOutCopy, pIn->ndims*sizeof(NDDimension_t));
  pIn->pAttributeList->copy(pOut->pAttributeList);

  pOut->getInfo(&arrayInfo);

  if (dimsUnchanged) {
    if (pIn->dataType == pOut->dataType) {
      /* The dimensions are the same and the data type is the same,
       * then just copy the input image to the output image */
      memcpy(pOut->pData, pIn->pData, arrayInfo.totalBytes);
      return ND_SUCCESS;
    } else {
      /* We need to convert data types */
      switch(pOut->dataType) {
        case NDInt8:
          convertTypeSwitch <epicsInt8> (pIn, pOut);
          break;
        case NDUInt8:
          convertTypeSwitch <epicsUInt8> (pIn, pOut);
          break;
        case NDInt16:
          convertTypeSwitch <epicsInt16> (pIn, pOut);
          break;
        case NDUInt16:
          convertTypeSwitch <epicsUInt16> (pIn, pOut);
          break;
        case NDInt32:
          convertTypeSwitch <epicsInt32> (pIn, pOut);
          break;
        case NDUInt32:
          convertTypeSwitch <epicsUInt32> (pIn, pOut);
          break;
        case NDFloat32:
          convertTypeSwitch <epicsFloat32> (pIn, pOut);
          break;
        case NDFloat64:
          convertTypeSwitch <epicsFloat64> (pIn, pOut);
          break;
        default:
          //status = ND_ERROR;
          break;
      }
    }
  } else {
    /* The input and output dimensions are not the same, so we are extracting a region
     * and/or binning */
    /* Clear entire output array */
    memset(pOut->pData, 0, arrayInfo.totalBytes);
    convertDimension(pIn, pOut, pIn->pData, pOut->pData, pIn->ndims-1);
  }

  /* Set fields in the output array */
  for (i=0; i<pIn->ndims; i++) {
    pOut->dims[i].offset = pIn->dims[i].offset + dimsOutCopy[i].offset;
    pOut->dims[i].binning = pIn->dims[i].binning * dimsOutCopy[i].binning;
    if (pIn->dims[i].reverse) pOut->dims[i].reverse = !pOut->dims[i].reverse;
  }

  /* If the frame is an RGBx frame and we have collapsed that dimension then change the colorMode */
  pAttribute = pOut->pAttributeList->find("ColorMode");
  if (pAttribute && pAttribute->getValue(NDAttrInt32, &colorMode)) {
    if      ((colorMode == NDColorModeRGB1) && (pOut->dims[0].size != 3)) 
      pAttribute->setValue(&colorModeMono);
    else if ((colorMode == NDColorModeRGB2) && (pOut->dims[1].size != 3)) 
      pAttribute->setValue(&colorModeMono);
    else if ((colorMode == NDColorModeRGB3) && (pOut->dims[2].size != 3))
      pAttribute->setValue(&colorModeMono);
  }
  return ND_SUCCESS;
}
Example #5
0
/** Callback function that is called by the NDArray driver with new NDArray data.
  * Draws overlays on top of the array.
  * \param[in] pArray  The NDArray from the callback.
  */
void NDPluginFastCCD::processCallbacks(NDArray *pArray)
{
    /* This function does the actual operations
     * It is called with the mutex already locked.  It unlocks it during long calculations when private
     * structures don't need to be protected.
     */

    NDArray *pOutput;

    /* Call the base class method */
    NDPluginDriver::processCallbacks(pArray);

    /* We always keep the last array so read() can use it.
     * Release previous one. */
    if (this->pArrays[0]) {
        this->pArrays[0]->release();
    }

    /* Copy the input array format but not the data */
    this->pArrays[0] = this->pNDArrayPool->copy(pArray, NULL, 1);
    pOutput = this->pArrays[0];
    
    /* Get information about the array needed later */
    pOutput->getInfo(&this->arrayInfo);

    /* Get paraemeters which we need for processing the image */
    int offset0, offset1, offset2, enabled, dpval, dataen;
    getIntegerParam(NDPluginFastCCDOffset0, &offset0);
    getIntegerParam(NDPluginFastCCDOffset1, &offset1);
    getIntegerParam(NDPluginFastCCDOffset2, &offset2);
    getIntegerParam(NDPluginFastCCDEnable, &enabled);
    getIntegerParam(NDPluginFastCCDEnableData, &dataen);
    getIntegerParam(NDPluginFastCCDDPVal, &dpval);

    /* This function is called with the lock taken, and it must be set when we exit.
     * The following code can be exected without the mutex because we are not accessing memory
     * that other threads can access. */
    this->unlock();

    if(((pOutput->dataType == NDUInt16) || (pOutput->dataType == NDInt16)) && enabled){
      // We can only process NDUnit16 images just pass if not. 

      // Get the data pointer
      epicsInt16 *data = (epicsInt16 *)pOutput->pData;
      epicsInt16 ctrl, sign;

      for(size_t i=0; i<pOutput->dims[1].size; i++){
        for(size_t j=0; j<pOutput->dims[0].size; j++){
          ctrl = *data & CIN_DATA_CTRL_MASK;
          if(dataen){
            *data = *data & CIN_DATA_DATA_MASK;
            if((ctrl & CIN_DATA_GAIN_8) == CIN_DATA_GAIN_8){
              // Minimum Gain just left shift 3 times
              *data = (*data << 3) - (epicsInt16)(offset2 << 3);
            } else if ((ctrl & CIN_DATA_GAIN_4) == CIN_DATA_GAIN_4) {
              // Gain
              *data = (*data << 2) - (epicsInt16)(offset1 << 2);
            } else if ((ctrl & CIN_DATA_DROPPED_PACKET_VAL) == CIN_DATA_DROPPED_PACKET_VAL) {
              // Dropped Packet
              *data = (epicsUInt16)dpval;
            } else {
              // Maximum gain
              *data = *data - (epicsInt16)offset0;
            } 
          } else {
            *data = ctrl;
          }
          data++; // Advance the pointer
        }
      }
    }

    this->lock();

    /* Get the attributes for this driver */
    this->getAttributes(this->pArrays[0]->pAttributeList);
    /* Call any clients who have registered for NDArray callbacks */
    this->unlock();
    doCallbacksGenericPointer(this->pArrays[0], NDArrayData, 0);
    this->lock();
    callParamCallbacks();
}
Example #6
0
/** Handles the logic for when NDFileCapture changes state, starting or stopping capturing or streaming NDArrays
  * to a file.
  * \param[in] capture Flag to start or stop capture; 1=start capture, 0=stop capture. */
asynStatus NDPluginFile::doCapture(int capture) 
{
    /* This function is called from write32 whenever capture is started or stopped */
    asynStatus status = asynSuccess;
    int fileWriteMode;
    NDArray *pArray = this->pArrays[0];
    NDArrayInfo_t arrayInfo;
    int i;
    int numCapture;
    static const char* functionName = "doCapture";

    /* Make sure there is a valid array if capture is set to 1 */
    if (!pArray && !this->lazyOpen) {
        if (capture == 0){
            /* No error here, but just return straight away as stop capture is non operation */
            return(asynSuccess);
        } else {
            asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                "%s::%s: ERROR, must collect an array to get dimensions first\n",
                driverName, functionName);
            return(asynError);
        }
    }
    
    /* Decide whether or not to use the NDAttribute named "fileprefix" to create the filename */
    if (pArray) {
        if( pArray->pAttributeList->find(FILEPLUGIN_NAME) != NULL)
            this->useAttrFilePrefix = true;
    }

    getIntegerParam(NDFileWriteMode, &fileWriteMode);    
    getIntegerParam(NDFileNumCapture, &numCapture);

    switch(fileWriteMode) {
        case NDFileModeSingle:
            /* It is an error to set capture=1 in this mode, set to 0 */
            setIntegerParam(NDFileCapture, 0);
            break;
        case NDFileModeCapture:
            if (capture) {
                /* Capturing was just started */
                setIntegerParam(NDFileNumCaptured, 0);
                if (!pArray) {
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                        "%s::%s ERROR: No arrays collected: cannot allocate capture buffer\n",
                        driverName, functionName);
                    return(asynError);
                }
                pArray->getInfo(&arrayInfo);
                this->registerInitFrameInfo(pArray);
                this->pCapture = (NDArray **)calloc(numCapture, sizeof(NDArray *));
                if (!this->pCapture) {
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                        "%s::%s ERROR: cannot allocate capture buffer\n",
                        driverName, functionName);
                    setIntegerParam(NDFileCapture, 0);
                    return(asynError);
                }
                for (i=0; i<numCapture; i++) {
                    pCapture[i] = new NDArray;
                    if (!this->pCapture[i]) {
                        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                            "%s::%s ERROR: cannot allocate capture buffer %d\n",
                            driverName, functionName, i);
                        setIntegerParam(NDFileCapture, 0);
                        freeCaptureBuffer(numCapture);
                        return(asynError);
                    }
                    this->pCapture[i]->dataSize = arrayInfo.totalBytes;
                    this->pCapture[i]->pData = malloc(arrayInfo.totalBytes);
                    this->pCapture[i]->ndims = pArray->ndims;
                    if (!this->pCapture[i]->pData) {
                        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                            "%s::%s ERROR: cannot allocate capture array for buffer %d\n",
                            driverName, functionName, i);
                        setIntegerParam(NDFileCapture, 0);
                        freeCaptureBuffer(numCapture);
                        return(asynError);
                    }
                }
            } else {
                /* Stop capturing, nothing to do, setting the parameter is all that is needed */
            }
            break;
        case NDFileModeStream:
            if (capture) {
                /* Streaming was just started */
                if (this->supportsMultipleArrays && !this->useAttrFilePrefix && !this->lazyOpen)
                    status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, pArray);
                setIntegerParam(NDFileNumCaptured, 0);
                setIntegerParam(NDWriteFile, 1);
            } else {
                /* Streaming was just stopped */
                if (this->supportsMultipleArrays)
                    status = this->closeFileBase();
                setIntegerParam(NDFileCapture, 0);
                setIntegerParam(NDWriteFile, 0);
            }
    }
    return(status);
}
Example #7
0
/** Callback function that is called by the NDArray driver with new NDArray data.
  * Draws overlays on top of the array.
  * \param[in] pArray  The NDArray from the callback.
  */
void NDPluginOverlay::processCallbacks(NDArray *pArray)
{
    /* This function draws overlays
     * It is called with the mutex already locked.  It unlocks it during long calculations when private
     * structures don't need to be protected.
     */

    int use;
    int itemp;
    int overlay;
    NDArray *pOutput;
    //static const char* functionName = "processCallbacks";

    /* Call the base class method */
    NDPluginDriver::processCallbacks(pArray);

    /* We always keep the last array so read() can use it.
     * Release previous one. */
    if (this->pArrays[0]) {
        this->pArrays[0]->release();
    }
    /* Copy the input array so we can modify it. */
    this->pArrays[0] = this->pNDArrayPool->copy(pArray, NULL, 1);
    pOutput = this->pArrays[0];
    
    /* Get information about the array needed later */
    pOutput->getInfo(&this->arrayInfo);
    setIntegerParam(NDPluginOverlayMaxSizeX, (int)arrayInfo.xSize);
    setIntegerParam(NDPluginOverlayMaxSizeY, (int)arrayInfo.ySize);
   
    /* Loop over the overlays in this driver */
    for (overlay=0; overlay<this->maxOverlays; overlay++) {
        pOverlay = &this->pOverlays[overlay];
        getIntegerParam(overlay, NDPluginOverlayUse, &use);
        asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER,
            "NDPluginOverlay::processCallbacks, overlay=%d, use=%d\n",
            overlay, use);
        if (!use) continue;
        /* Need to fetch all of these parameters while we still have the mutex */
        getIntegerParam(overlay, NDPluginOverlayPositionX,  &itemp); pOverlay->PositionX = itemp;
        pOverlay->PositionX = MAX(pOverlay->PositionX, 0);
        pOverlay->PositionX = MIN(pOverlay->PositionX, this->arrayInfo.xSize-1);
        getIntegerParam(overlay, NDPluginOverlayPositionY,  &itemp); pOverlay->PositionY = itemp;
        pOverlay->PositionY = MAX(pOverlay->PositionY, 0);
        pOverlay->PositionY = MIN(pOverlay->PositionY, this->arrayInfo.ySize-1);
        getIntegerParam(overlay, NDPluginOverlaySizeX,      &itemp); pOverlay->SizeX = itemp;
        getIntegerParam(overlay, NDPluginOverlaySizeY,      &itemp); pOverlay->SizeY = itemp;
        getIntegerParam(overlay, NDPluginOverlayWidthX,     &itemp); pOverlay->WidthX = itemp;
        getIntegerParam(overlay, NDPluginOverlayWidthY,     &itemp); pOverlay->WidthY = itemp;
        getIntegerParam(overlay, NDPluginOverlayShape,      &itemp); pOverlay->shape = (NDOverlayShape_t)itemp;
        getIntegerParam(overlay, NDPluginOverlayDrawMode,   &itemp); pOverlay->drawMode = (NDOverlayDrawMode_t)itemp;
        getIntegerParam(overlay, NDPluginOverlayRed,        &pOverlay->red);
        getIntegerParam(overlay, NDPluginOverlayGreen,      &pOverlay->green);
        getIntegerParam(overlay, NDPluginOverlayBlue,       &pOverlay->blue);
        getStringParam( overlay, NDPluginOverlayTimeStampFormat, sizeof(pOverlay->TimeStampFormat), pOverlay->TimeStampFormat);
        getIntegerParam(overlay, NDPluginOverlayFont,       &pOverlay->Font);
        getStringParam( overlay, NDPluginOverlayDisplayText, sizeof(pOverlay->DisplayText), pOverlay->DisplayText);

        pOverlay->DisplayText[sizeof(pOverlay->DisplayText)-1] = 0;

        /* This function is called with the lock taken, and it must be set when we exit.
         * The following code can be exected without the mutex because we are not accessing memory
         * that other threads can access. */
        this->unlock();
        this->doOverlay(pOutput, pOverlay);
        this->lock();
    }
    /* Get the attributes for this driver */
    this->getAttributes(this->pArrays[0]->pAttributeList);
    /* Call any clients who have registered for NDArray callbacks */
    this->unlock();
    doCallbacksGenericPointer(this->pArrays[0], NDArrayData, 0);
    this->lock();
    callParamCallbacks();
}
Example #8
0
NDArray *roper::getData()
{
    NDArray *pArray = NULL;
    VARIANT varData, varResult;
    short result;
    SAFEARRAY *pData;
    int dim;
    LONG lbound, ubound;
    size_t dims[ND_ARRAY_MAX_DIMS];
    int nDims;
    VARTYPE varType;
    NDDataType_t dataType;
    int docDataType;
    NDArrayInfo arrayInfo;
    void HUGEP *pVarData;
    bool typeMismatch;
    const char *functionName = "getData";
        
    VariantInit(&varData);
    VariantInit(&varResult);
    try {
        this->pDocFile->GetFrame(1, &varData);
        varResult = this->pDocFile->GetParam(DM_DATATYPE, &result);
        docDataType = varResult.lVal;
        pData = varData.parray;
        nDims = SafeArrayGetDim(pData);
        for (dim=0; dim<nDims; dim++) {
            SafeArrayGetLBound(pData, dim+1, &lbound);
            SafeArrayGetUBound(pData, dim+1, &ubound);
            dims[dim] = ubound - lbound + 1;
        }
        SafeArrayGetVartype(pData, &varType);
        typeMismatch = TRUE;
        switch (docDataType) {
            case X_BYTE:
                dataType = NDUInt8;
                typeMismatch = (varType != VT_UI1);
                break;
            case X_SHORT:
                dataType = NDInt16;
                typeMismatch = (varType != VT_I2);
                break;
            case X_UINT16:
                dataType = NDUInt16;
                typeMismatch = (varType != VT_I2);
                break;
            case X_LONG:
                dataType = NDInt32;
                typeMismatch = (varType != VT_I4);
                break;
            case X_ULONG:
                dataType = NDUInt32;
                typeMismatch = (varType != VT_I4);
                break;
            case X_FLOAT:
                dataType = NDFloat32;
                typeMismatch = (varType != VT_R4);
                break;
            case X_DOUBLE:
                dataType = NDFloat64;
                typeMismatch = (varType != VT_R8);
                break;
            default:
                asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                    "%s:%s: unknown data type = %d\n", 
                    driverName, functionName, docDataType);
                return(NULL);
        }
        if (typeMismatch) {
            asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                "%s:%s: data type mismatch: docDataType=%d, varType=%d\n", 
                driverName, functionName, docDataType, varType);
            return(NULL);
        }
        pArray = this->pNDArrayPool->alloc(nDims, dims, dataType, 0, NULL);
        pArray->getInfo(&arrayInfo);
        SafeArrayAccessData(pData, &pVarData);
        memcpy(pArray->pData, pVarData, arrayInfo.totalBytes);
        SafeArrayUnaccessData(pData);
        SafeArrayDestroy(pData);
        setIntegerParam(NDArraySize, arrayInfo.totalBytes);
        setIntegerParam(NDArraySizeX, (int)dims[0]);
        setIntegerParam(NDArraySizeY, (int)dims[1]);
        setIntegerParam(NDDataType, dataType);
    }
    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();
        return(NULL);
    }
        
    return(pArray);
}