/** 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(); } }
/** 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); }
/** 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; }
/** 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(); }
/** 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); }
/** 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(); }
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); }