Example #1
0
asynStatus NDPluginCircularBuff::calculateTrigger(NDArray *pArray, int *trig)
{
    NDAttribute *trigger;
    char triggerString[256];
    double triggerValue;
    double calcResult;
    int status;
    int preTrigger, postTrigger, currentImage, triggered;
    static const char *functionName="calculateTrigger";
    
    *trig = 0;
    
    getIntegerParam(NDCircBuffPreTrigger,   &preTrigger);
    getIntegerParam(NDCircBuffPostTrigger,  &postTrigger);
    getIntegerParam(NDCircBuffCurrentImage, &currentImage);
    getIntegerParam(NDCircBuffTriggered,    &triggered);   

    triggerCalcArgs_[0] = epicsNAN;
    triggerCalcArgs_[1] = epicsNAN;
    triggerCalcArgs_[2] = preTrigger;
    triggerCalcArgs_[3] = postTrigger;
    triggerCalcArgs_[4] = currentImage;
    triggerCalcArgs_[5] = triggered;

    getStringParam(NDCircBuffTriggerA, sizeof(triggerString), triggerString);
    trigger = pArray->pAttributeList->find(triggerString);
    if (trigger != NULL) {
        status = trigger->getValue(NDAttrFloat64, &triggerValue);
        if (status == asynSuccess) {
            triggerCalcArgs_[0] = triggerValue;
        }
    }
    getStringParam(NDCircBuffTriggerB, sizeof(triggerString), triggerString);
    trigger = pArray->pAttributeList->find(triggerString);
    if (trigger != NULL) {
        status = trigger->getValue(NDAttrFloat64, &triggerValue);
        if (status == asynSuccess) {
            triggerCalcArgs_[1] = triggerValue;
        }
    }
    
    setDoubleParam(NDCircBuffTriggerAVal, triggerCalcArgs_[0]);
    setDoubleParam(NDCircBuffTriggerBVal, triggerCalcArgs_[1]);
    status = calcPerform(triggerCalcArgs_, &calcResult, triggerCalcPostfix_);
    if (status) {
        asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
            "%s::%s error evaluating expression=%s\n",
            driverName, functionName, calcErrorStr(status));
        return asynError;
    }
    
    if (!isnan(calcResult) && !isinf(calcResult) && (calcResult != 0)) *trig = 1;
    setDoubleParam(NDCircBuffTriggerCalcVal, calcResult);

    return asynSuccess;
}
Example #2
0
/** Updates all attribute values in the list; calls NDAttribute::updateValue() for each attribute in the list.
  */
int NDAttributeList::updateValues()
{
  NDAttribute *pAttribute;
  NDAttributeListNode *pListNode;
  //const char *functionName = "NDAttributeList::updateValues";

  epicsMutexLock(this->lock);
  pListNode = (NDAttributeListNode *)ellFirst(&this->list);
  while (pListNode) {
    pAttribute = pListNode->pNDAttribute;
    pAttribute->updateValue();
    pListNode = (NDAttributeListNode *)ellNext(&pListNode->node);
  }
  epicsMutexUnlock(this->lock);
  return(ND_SUCCESS);
}
Example #3
0
/** Adds an attribute to the list.
  * This is a convenience function for adding attributes to a list.  
  * It first searches the list to see if there is an existing attribute
  * with the same name.  If there is it just changes the properties of the
  * existing attribute.  If not, it creates a new attribute with the
  * specified properties. 
  * IMPORTANT: This method is only capable of creating attributes
  * of the NDAttribute base class type, not derived class attributes.
  * To add attributes of a derived class to a list the NDAttributeList::add(NDAttribute*)
  * method must be used.
  * \param[in] pName The name of the attribute to be added. 
  * \param[in] pDescription The description of the attribute.
  * \param[in] dataType The data type of the attribute.
  * \param[in] pValue A pointer to the value for this attribute.
  *
  */
NDAttribute* NDAttributeList::add(const char *pName, const char *pDescription, NDAttrDataType_t dataType, void *pValue)
{
  //const char *functionName = "NDAttributeList::add";
  NDAttribute *pAttribute;

  epicsMutexLock(this->lock);
  pAttribute = this->find(pName);
  if (pAttribute) {
    pAttribute->setDescription(pDescription);
    pAttribute->setValue(dataType, pValue);
  } else {
    pAttribute = new NDAttribute(pName, pDescription, dataType, pValue);
    ellAdd(&this->list, &pAttribute->listNode.node);
  }
  epicsMutexUnlock(this->lock);
  return(pAttribute);
}
Example #4
0
/** Reports on the properties of the attribute list.
  * \param[in] details Level of report details desired; if >10 calls NDAttribute::report() for each attribute.
  */
int NDAttributeList::report(int details)
{
  NDAttribute *pAttribute;
  NDAttributeListNode *pListNode;
  
  epicsMutexLock(this->lock);
  printf("\n");
  printf("NDAttributeList: address=%p:\n", this);
  printf("  number of attributes=%d\n", this->count());
  if (details > 10) {
    pListNode = (NDAttributeListNode *) ellFirst(&this->list);
    while (pListNode) {
      pAttribute = (NDAttribute *)pListNode->pNDAttribute;
      pAttribute->report(details);
      pListNode = (NDAttributeListNode *) ellNext(&pListNode->node);
    }
  }
  epicsMutexUnlock(this->lock);
  return ND_SUCCESS;
}
Example #5
0
/** Look up filename related attributes in the NDArray.
 *  If file name or number is found in the NDArray, the values are replacing the existing ones
 *  in the parameter library. If not found the existing settings remain.
 */
asynStatus NDPluginFile::attrFileNameSet()
{
    asynStatus status = asynSuccess;
    NDAttribute *ndAttr;
    char attrFileName[MAX_FILENAME_LEN];
    epicsInt32 attrFileNumber;
    size_t attrFileNameLen;
    NDAttrDataType_t attrDataType;
    NDArray *pArray = this->pArrays[0];

    if (this->useAttrFilePrefix == false)
        return status;

    /* first check if the attribute contain a fileprefix to form part of the filename. */
    ndAttr = pArray->pAttributeList->find(FILEPLUGIN_NAME);
    if (ndAttr != NULL)
    {
        ndAttr->getValueInfo(&attrDataType, &attrFileNameLen);
        if (attrDataType == NDAttrString)
        {
            if (attrFileNameLen > MAX_FILENAME_LEN) attrFileNameLen = MAX_FILENAME_LEN;
            ndAttr->getValue(NDAttrString, attrFileName, attrFileNameLen);
            setStringParam(NDFileName, attrFileName);
        }
    }

    ndAttr = pArray->pAttributeList->find(FILEPLUGIN_NUMBER);
    if (ndAttr != NULL)
    {
        ndAttr->getValueInfo(&attrDataType, &attrFileNameLen);
        if (attrDataType == NDAttrInt32)
        {
            ndAttr->getValue(NDAttrInt32, &attrFileNumber, 0);
            setIntegerParam(NDFileNumber, attrFileNumber);
            // ensure auto increment is switched off when using attribute file numbers
            setIntegerParam(NDAutoIncrement, 0);
        }
    }
    return status;
}
Example #6
0
/** Decide whether or not this frame is intended to be processed by this plugin.
 * By default all frames are processed. The decision not to process a frame is
 * made based on the string value of the FILEPLUGIN_DESTINATION: if the value does not equal
 * either "all" or the ASYN port name of the current plugin the frame is not to be processed.
 * \param[in] pAttrList  A pointer to the current NDArray's attribute list.
 * \returns true if the frame is to be processed. false if the frame is not to be processed.
 */
bool NDPluginFile::attrIsProcessingRequired(NDAttributeList* pAttrList)
{
    char destPortName[MAX_FILENAME_LEN];
    NDAttribute *ndAttr;
    size_t destPortNameLen;
    NDAttrDataType_t attrDataType;

    ndAttr = pAttrList->find(FILEPLUGIN_DESTINATION);
    if (ndAttr != NULL)
    {
        ndAttr->getValueInfo(&attrDataType, &destPortNameLen);
        if (attrDataType == NDAttrString && destPortNameLen > 1)
        {
            if (destPortNameLen > MAX_FILENAME_LEN)
                destPortNameLen = MAX_FILENAME_LEN;
                ndAttr->getValue(NDAttrString, destPortName, destPortNameLen);
            if (epicsStrnCaseCmp(destPortName, "all", destPortNameLen>3?3:destPortNameLen) != 0 &&
                epicsStrnCaseCmp(destPortName, this->portName, destPortNameLen) != 0)
                return false;
        }
    }
    return true;
}
Example #7
0
/** Check whether an attribute asking the file to be closed has been set.
 *  if the value of FILEPLUGIN_CLOSE attribute is set to 1 then close the file.
 */
asynStatus NDPluginFile::attrFileCloseCheck()
{
    asynStatus status = asynSuccess;
    NDAttribute *NDattrFileClose;
    int getStatus = 0;
    int closeFile = 0;
    NDattrFileClose = this->pArrays[0]->pAttributeList->find(FILEPLUGIN_CLOSE);
    // Check for the existence of the parameter
    if (NDattrFileClose != NULL) {
        // Check NDAttribute value (0 = continue, anything else = close file)
        getStatus = NDattrFileClose->getValue(NDAttrInt32, &closeFile);
        if (getStatus == 0){
            if (closeFile != 0){
                // Force a file close
                this->closeFileBase();
                // We must also set the parameter to notify we have stopped capturing
                setIntegerParam(NDFileCapture, 0);
            }
        } else {
            status = asynError;
        }
    }
    return status;
}
Example #8
0
void NTNDArrayConverter::fromAttributes (NDArray *src)
{
    PVStructureArrayPtr dest(m_array->getAttribute());
    NDAttributeList *srcList = src->pAttributeList;
    NDAttribute *attr = NULL;
    StructureConstPtr structure(dest->getStructureArray()->getStructure());
    PVStructureArray::svector destVec(dest->reuse());

    destVec.resize(srcList->count());

    size_t i = 0;
    while((attr = srcList->next(attr)))
    {
        if(!destVec[i].get() || !destVec[i].unique())
            destVec[i] = PVDC->createPVStructure(structure);

        PVStructurePtr pvAttr(destVec[i]);

        pvAttr->getSubField<PVString>("name")->put(attr->getName());
        pvAttr->getSubField<PVString>("descriptor")->put(attr->getDescription());
        pvAttr->getSubField<PVString>("source")->put(attr->getSource());

        NDAttrSource_t sourceType;
        attr->getSourceInfo(&sourceType);
        pvAttr->getSubField<PVInt>("sourceType")->put(sourceType);

        switch(attr->getDataType())
        {
        case NDAttrInt8:      fromAttribute <PVByte,   int8_t>  (pvAttr, attr); break;
        case NDAttrUInt8:     fromAttribute <PVUByte,  uint8_t> (pvAttr, attr); break;
        case NDAttrInt16:     fromAttribute <PVShort,  int16_t> (pvAttr, attr); break;
        case NDAttrUInt16:    fromAttribute <PVUShort, uint16_t>(pvAttr, attr); break;
        case NDAttrInt32:     fromAttribute <PVInt,    int32_t> (pvAttr, attr); break;
        case NDAttrUInt32:    fromAttribute <PVUInt,   uint32_t>(pvAttr, attr); break;
        case NDAttrFloat32:   fromAttribute <PVFloat,  float>   (pvAttr, attr); break;
        case NDAttrFloat64:   fromAttribute <PVDouble, double>  (pvAttr, attr); break;
        case NDAttrString:    fromStringAttribute(pvAttr, attr); break;
        case NDAttrUndefined: fromUndefinedAttribute(pvAttr); break;
        default:              throw std::runtime_error("invalid attribute data type");
        }

        ++i;
    }

    dest->replace(freeze(destVec));
}
/** Base method for writing a file
  * Handles logic for NDFileModeSingle, NDFileModeCapture and NDFileModeStream when the derived class does or
  * does not support NDPulginFileMultiple. Calls writeFile in the derived class. */
asynStatus NDPluginFile::writeFileBase() 
{
    int status = asynSuccess;
    int fileWriteMode;
    int numCapture, numCaptured;
    int i;
    int deleteDriverFile;
    NDArray *pArray;
    NDAttribute *pAttribute;
    char driverFileName[MAX_FILENAME_LEN];
    char errorMessage[256];
    const char* functionName = "writeFileBase";

    /* Make sure there is a valid array */
    if (!this->pArrays[0]) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s: ERROR, must collect an array to get dimensions first\n",
            driverName, functionName);
        return(asynError);
    }
    
    getIntegerParam(NDFileWriteMode, &fileWriteMode);    
    getIntegerParam(NDFileNumCapture, &numCapture);    
    getIntegerParam(NDFileNumCaptured, &numCaptured);

    setIntegerParam(NDFileWriteStatus, NDFileWriteOK);
    setStringParam(NDFileWriteMessage, "");
    
    /* We unlock the overall mutex here because we want the callbacks to be able to queue new
     * frames without waiting while we write files here.  The only restriction is that the
     * callbacks must not modify any part of the class structure that we use here. */

    switch(fileWriteMode) {
        case NDFileModeSingle:
            setIntegerParam(NDWriteFile, 1);
            callParamCallbacks();
            status = this->openFileBase(NDFileModeWrite, this->pArrays[0]);
            if (status == asynSuccess) {
                this->unlock();
                epicsMutexLock(this->fileMutexId);
                status = this->writeFile(this->pArrays[0]);
                epicsMutexUnlock(this->fileMutexId);
                this->lock();
                if (status) {
                    epicsSnprintf(errorMessage, sizeof(errorMessage)-1, 
                        "Error writing file, status=%d", status);
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
                          "%s:%s %s\n", 
                          driverName, functionName, errorMessage);
                    setIntegerParam(NDFileWriteStatus, NDFileWriteError);
                    setStringParam(NDFileWriteMessage, errorMessage);
                } else {
                    status = this->closeFileBase(); 
                }
            }
            setIntegerParam(NDWriteFile, 0);
            callParamCallbacks();
            break;
        case NDFileModeCapture:
            /* Write the file */
            if (!this->pCapture) {
                asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                    "%s:%s: ERROR, no capture buffer present\n", 
                    driverName, functionName);
                setIntegerParam(NDFileWriteStatus, NDFileWriteError);
                setStringParam(NDFileWriteMessage, "ERROR, no capture buffer present");
                break;
            }
            setIntegerParam(NDWriteFile, 1);
            callParamCallbacks();
            if (this->supportsMultipleArrays)
                status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, this->pArrays[0]);
            if (status == asynSuccess) {
                for (i=0; i<numCaptured; i++) {
                    pArray = this->pCapture[i];
                    if (!this->supportsMultipleArrays)
                        status = this->openFileBase(NDFileModeWrite, pArray);
                    if (status == asynSuccess) {
                        this->unlock();
                        epicsMutexLock(this->fileMutexId);
                        status = this->writeFile(pArray);
                        epicsMutexUnlock(this->fileMutexId);
                        this->lock();
                        if (status) {
                            epicsSnprintf(errorMessage, sizeof(errorMessage)-1, 
                                "Error writing file, status=%d", status);
                            asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
                                  "%s:%s %s\n", 
                                  driverName, functionName, errorMessage);
                            setIntegerParam(NDFileWriteStatus, NDFileWriteError);
                            setStringParam(NDFileWriteMessage, errorMessage);
                        } else {
                            if (!this->supportsMultipleArrays)
                                status = this->closeFileBase();
                        }
                    }
                }
            }
            freeCaptureBuffer(numCapture);
            if ((status == asynSuccess) && this->supportsMultipleArrays) 
                status = this->closeFileBase();
            setIntegerParam(NDFileNumCaptured, 0);
            setIntegerParam(NDWriteFile, 0);
            callParamCallbacks();
            break;
        case NDFileModeStream:
            if (!this->supportsMultipleArrays)
                status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, this->pArrays[0]);
            if (status == asynSuccess) {
                this->unlock();
                epicsMutexLock(this->fileMutexId);
                status = this->writeFile(this->pArrays[0]);
                epicsMutexUnlock(this->fileMutexId);
                this->lock();
                if (status) {
                    epicsSnprintf(errorMessage, sizeof(errorMessage)-1, 
                        "Error writing file, status=%d", status);
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
                          "%s:%s %s\n", 
                          driverName, functionName, errorMessage);
                    setIntegerParam(NDFileWriteStatus, NDFileWriteError);
                    setStringParam(NDFileWriteMessage, errorMessage);
                } else {
                    if (!this->supportsMultipleArrays)
                        status = this->closeFileBase();
                }
            }
            break;
        default:
            asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                "%s:%s: ERROR, unknown fileWriteMode %d\n", 
                driverName, functionName, fileWriteMode);
            break;
    }
    
    /* Check to see if we should delete the original file
     * Only do this if all of the following conditions are met
     *  - DeleteOriginalFile is true
     *  - There were no errors above
     *  - The NDFullFileName attribute is present and contains a non-blank string
     */
    getIntegerParam(NDFileDeleteDriverFile, &deleteDriverFile);
    if ((status == asynSuccess) && deleteDriverFile) {
        pAttribute = this->pArrays[0]->pAttributeList->find("DriverFileName");
        if (pAttribute) {
            status = pAttribute->getValue(NDAttrString, driverFileName, sizeof(driverFileName));
            if ((status == asynSuccess) && (strlen(driverFileName) > 0)) {
                status = remove(driverFileName);
                if (status != 0) {
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
                              "%s:%s: error deleting file %s, error=%s\n",
                              driverName, functionName, driverFileName, strerror(errno));
                }
            }
        }
    }
    
    return((asynStatus)status);
}
Example #10
0
/** Convenience method returns information about an NDArray, including the total number of elements, 
  * the number of bytes per element, and the total number of bytes in the array.
  \param[out] pInfo Pointer to an NDArrayInfo_t structure, must have been allocated by caller. */
int NDArray::getInfo(NDArrayInfo_t *pInfo)
{
  int i;
  NDAttribute *pAttribute;

  switch(this->dataType) {
    case NDInt8:
      pInfo->bytesPerElement = sizeof(epicsInt8);
      break;
    case NDUInt8:
      pInfo->bytesPerElement = sizeof(epicsUInt8);
      break;
    case NDInt16:
      pInfo->bytesPerElement = sizeof(epicsInt16);
      break;
    case NDUInt16:
      pInfo->bytesPerElement = sizeof(epicsUInt16);
      break;
    case NDInt32:
      pInfo->bytesPerElement = sizeof(epicsInt32);
      break;
    case NDUInt32:
      pInfo->bytesPerElement = sizeof(epicsUInt32);
      break;
    case NDFloat32:
      pInfo->bytesPerElement = sizeof(epicsFloat32);
      break;
    case NDFloat64:
      pInfo->bytesPerElement = sizeof(epicsFloat64);
      break;
    default:
      return(ND_ERROR);
      break;
  }
  pInfo->nElements = 1;
  for (i=0; i<this->ndims; i++) pInfo->nElements *= this->dims[i].size;
  pInfo->totalBytes = pInfo->nElements * pInfo->bytesPerElement;
  pInfo->colorMode = NDColorModeMono;
  pAttribute = this->pAttributeList->find("ColorMode");
  if (pAttribute) pAttribute->getValue(NDAttrInt32, &pInfo->colorMode);
  pInfo->xDim        = 0;
  pInfo->yDim        = 0;
  pInfo->colorDim    = 0;
  pInfo->xSize       = 0;
  pInfo->ySize       = 0;
  pInfo->colorSize   = 0;
  pInfo->xStride     = 0;
  pInfo->yStride     = 0;
  pInfo->colorStride = 0;
  if (this->ndims > 0) {
    pInfo->xStride = 1;
    pInfo->xSize   = this->dims[0].size;
  }
  if (this->ndims > 1) {
    pInfo->yDim  = 1;
    pInfo->yStride = pInfo->xSize;
    pInfo->ySize   = this->dims[1].size;
  }
  if (this->ndims == 3) {
    switch (pInfo->colorMode) {
      case NDColorModeRGB1:
        pInfo->xDim    = 1;
        pInfo->yDim    = 2;
        pInfo->colorDim  = 0;
        pInfo->xStride   = this->dims[0].size;
        pInfo->yStride   = this->dims[0].size * this->dims[1].size;
        pInfo->colorStride = 1;
        break;
      case NDColorModeRGB2:
        pInfo->xDim    = 0;
        pInfo->yDim    = 2;
        pInfo->colorDim  = 1;
        pInfo->xStride   = 1;
        pInfo->yStride   = this->dims[0].size * this->dims[1].size;
        pInfo->colorStride = this->dims[0].size;
        break;
      case NDColorModeRGB3:
        pInfo->xDim    = 0;
        pInfo->yDim    = 1;
        pInfo->colorDim  = 2;
        pInfo->xStride   = 1;
        pInfo->yStride   = this->dims[0].size;
        pInfo->colorStride = this->dims[0].size * this->dims[1].size;
        break;
      default:
        break;
    }
    pInfo->xSize     = this->dims[pInfo->xDim].size;
    pInfo->ySize     = this->dims[pInfo->yDim].size;
    pInfo->colorSize = this->dims[pInfo->colorDim].size;
  }
  return(ND_SUCCESS);
}
Example #11
0
void* epics2hdf::getNDAttr(const char* attr_name, void* attr_val,
      hid_t *datatype)
{
   NDAttrDataType_t attrDataType;
   NDAttribute *pAttr;
   size_t attrDataSize;
   hid_t nd_hdf_type;

   if (strcmp(attr_name, "sysclock") == 0)
   {
      *datatype = H5T_NATIVE_DOUBLE;
      double *x;
      x = (double*) attr_val;
      *x = clock() / CLOCKS_PER_SEC;
   }
   else if (strcmp(attr_name, "timestamp") == 0)
   {
      *datatype = H5T_NATIVE_DOUBLE;
      double *x;
      x = (double*) attr_val;
      *x = pArray->timeStamp;
   }
   else if (strcmp(attr_name, "uniqueId") == 0)
   {
      *datatype = H5T_NATIVE_INT;
      int *x;
      x = (int*) attr_val;
      *x = pArray->uniqueId;
   }
   else if (strcmp(attr_name, "datetime") == 0)
   {
      //2003-04-01T13:01:02 is ISO format.
      time_t rawtime;

      struct tm *today;
      char tstr[128];
      time(&rawtime);
      today = localtime(&rawtime);
      sprintf(tstr, "%04i-%02i-%02iT%02i:%02i:%02i", today->tm_year + 1900,
            today->tm_mon + 1, today->tm_mday, today->tm_hour, today->tm_min,
            today->tm_sec);

      *datatype = H5T_STR_NULLTERM;
      strcpy((char*) attr_val, tstr);

   }
   else
   {
      pAttr = pArray->pAttributeList->find(attr_name);

      if (pAttr != NULL)
      {
         pAttr->getValueInfo(&attrDataType, &attrDataSize);
         nd_hdf_type = type_ndatr2hdf(attrDataType);

         *datatype = nd_hdf_type;

         if (nd_hdf_type >= 0)
         {

            pAttr->getValue(attrDataType, (char *) attr_val, attrDataSize);
         }
         else
         {
            printf("epics2hdf::getNDAttr bad NDAttr datatype %s\n", attr_name);
            *datatype = 0;
            strcpy((char*) attr_val, "Error: Unknown Attribute Datatype");

         }
      } //pAttr
      else
      {
         int attrCount;
         printf("epics2hdf::getNDAttr Could not find NDAttr %s\n", attr_name);
         *datatype = 0;
         strcpy((char*) attr_val, "Error: Unknown Attribute");
         // list the attributes
         printf("List of attributes in image\n");
         pAttr = pArray->pAttributeList->next(NULL);
         for (attrCount = 0; attrCount < pArray->pAttributeList->count();
               attrCount++)
         {

            printf("Attr: %s \n", pAttr->pName);
            pAttr = pArray->pAttributeList->next(pAttr);
         }

      } //pAttr
   }

   return (attr_val);
}
Example #12
0
/** Opens a TIFF file.
  * \param[in] fileName The name of the file to open.
  * \param[in] openMode Mask defining how the file should be opened; bits are 
  *            NDFileModeRead, NDFileModeWrite, NDFileModeAppend, NDFileModeMultiple
  * \param[in] pArray A pointer to an NDArray; this is used to determine the array and attribute properties.
  */
asynStatus NDFileTIFF::openFile(const char *fileName, NDFileOpenMode_t openMode, NDArray *pArray)
{
    /* When we create TIFF variables and dimensions, we get back an
     * ID for each one. */
    static const char *functionName = "openFile";
    size_t sizeX, sizeY, rowsPerStrip;
    int bitsPerSample=8, sampleFormat=SAMPLEFORMAT_INT, samplesPerPixel, photoMetric, planarConfig;
    int colorMode=NDColorModeMono;
    NDAttribute *pAttribute;
    char ManufacturerString[MAX_ATTRIBUTE_STRING_SIZE] = "Unknown";
    char ModelString[MAX_ATTRIBUTE_STRING_SIZE] = "Unknown";

    /* We don't support reading yet */
    if (openMode & NDFileModeRead) return(asynError);

    /* We don't support opening an existing file for appending yet */
    if (openMode & NDFileModeAppend) return(asynError);

   /* Create the file. */
    if ((this->output = TIFFOpen(fileName, "w")) == NULL ) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
        "%s:%s error opening file %s\n",
        driverName, functionName, fileName);
        return(asynError);
    }
    /* We do some special treatment based on colorMode */
    pAttribute = pArray->pAttributeList->find("ColorMode");
    if (pAttribute) pAttribute->getValue(NDAttrInt32, &colorMode);

    switch (pArray->dataType) {
        case NDInt8:
            sampleFormat = SAMPLEFORMAT_INT;
            bitsPerSample = 8;
            break;
        case NDUInt8:
            sampleFormat = SAMPLEFORMAT_UINT;
            bitsPerSample = 8;
            break;
        case NDInt16:
            sampleFormat = SAMPLEFORMAT_INT;
            bitsPerSample = 16;
            break;
        case NDUInt16:
            sampleFormat = SAMPLEFORMAT_UINT;
            bitsPerSample = 16;
            break;
        case NDInt32:
            sampleFormat = SAMPLEFORMAT_INT;
            bitsPerSample = 32;
            break;
        case NDUInt32:
            sampleFormat = SAMPLEFORMAT_UINT;
            bitsPerSample = 32;
            break;
        case NDFloat32:
            sampleFormat = SAMPLEFORMAT_IEEEFP;
            bitsPerSample = 32;
            break;
        case NDFloat64:
            sampleFormat = SAMPLEFORMAT_IEEEFP;
            bitsPerSample = 64;
            break;
    }
    if (pArray->ndims == 2) {
        sizeX = pArray->dims[0].size;
        sizeY = pArray->dims[1].size;
        rowsPerStrip = sizeY;
        samplesPerPixel = 1;
        photoMetric = PHOTOMETRIC_MINISBLACK;
        planarConfig = PLANARCONFIG_CONTIG;
        this->colorMode = NDColorModeMono;
    } else if ((pArray->ndims == 3) && (pArray->dims[0].size == 3) && (colorMode == NDColorModeRGB1)) {
        sizeX = pArray->dims[1].size;
        sizeY = pArray->dims[2].size;
        rowsPerStrip = sizeY;
        samplesPerPixel = 3;
        photoMetric = PHOTOMETRIC_RGB;
        planarConfig = PLANARCONFIG_CONTIG;
        this->colorMode = NDColorModeRGB1;
    } else if ((pArray->ndims == 3) && (pArray->dims[1].size == 3) && (colorMode == NDColorModeRGB2)) {
        sizeX = pArray->dims[0].size;
        sizeY = pArray->dims[2].size;
        rowsPerStrip = 1;
        samplesPerPixel = 3;
        photoMetric = PHOTOMETRIC_RGB;
        planarConfig = PLANARCONFIG_SEPARATE;
        this->colorMode = NDColorModeRGB2;
    } else if ((pArray->ndims == 3) && (pArray->dims[2].size == 3) && (colorMode == NDColorModeRGB3)) {
        sizeX = pArray->dims[0].size;
        sizeY = pArray->dims[1].size;
        rowsPerStrip = sizeY;
        samplesPerPixel = 3;
        photoMetric = PHOTOMETRIC_RGB;
        planarConfig = PLANARCONFIG_SEPARATE;
        this->colorMode = NDColorModeRGB3;
    } else {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
            "%s:%s: unsupported array structure\n",
            driverName, functionName);
        return(asynError);
    }

    /* this is in the unallocated 'reusable' range */
    static const int TIFFTAG_NDTIMESTAMP = 65000;
    static const TIFFFieldInfo fi = {
        TIFFTAG_NDTIMESTAMP,1,1,TIFF_DOUBLE,FIELD_CUSTOM,1,0,(char *)"NDTimeStamp"
    };
    TIFFMergeFieldInfo(output, &fi, 1);
    TIFFSetField(this->output, TIFFTAG_NDTIMESTAMP, pArray->timeStamp);
    TIFFSetField(this->output, TIFFTAG_BITSPERSAMPLE, bitsPerSample);
    TIFFSetField(this->output, TIFFTAG_SAMPLEFORMAT, sampleFormat);
    TIFFSetField(this->output, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
    TIFFSetField(this->output, TIFFTAG_PHOTOMETRIC, photoMetric);
    TIFFSetField(this->output, TIFFTAG_PLANARCONFIG, planarConfig);
    TIFFSetField(this->output, TIFFTAG_IMAGEWIDTH, (epicsUInt32)sizeX);
    TIFFSetField(this->output, TIFFTAG_IMAGELENGTH, (epicsUInt32)sizeY);
    TIFFSetField(this->output, TIFFTAG_ROWSPERSTRIP, (epicsUInt32)rowsPerStrip);
    TIFFSetField(this->output, TIFFTAG_MAKE, ManufacturerString);
    TIFFSetField(this->output, TIFFTAG_MODEL, ModelString);
    
    return(asynSuccess);
}
Example #13
0
int NDFileNexus::processNode(TiXmlNode *curNode, NDArray *pArray) {
  int status = 0;
  const char *nodeName;
  const char *nodeValue;
  const char *nodeOuttype;
  const char *nodeSource;
  const char *nodeType;
  //float data;
  int rank;
  NDDataType_t type;
  int ii;
  int dims[ND_ARRAY_MAX_DIMS];
  int numCapture;
  int fileWriteMode;
  NDAttrDataType_t attrDataType;
  NDAttribute *pAttr;
  size_t attrDataSize;
  size_t nodeTextLen;
  int wordSize;
  int dataOutType=NDInt8;
  size_t numWords;
  int numItems = 0;
  int addr =0;
  void *pValue;
  char nodeText[256];
  NXname dataclass;
  NXname dPath;
  static const char *functionName = "processNode";

  asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
            "Entering %s:%s\n", driverName, functionName );

  /* Must lock when accessing parameter library */
  this->lock();
  getIntegerParam(addr, NDFileWriteMode, &fileWriteMode);
  getIntegerParam(addr, NDFileNumCapture, &numCapture);
  this->unlock();

  nodeValue = curNode->Value();
  asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
            "%s:%s  Value=%s Type=%d\n", driverName, functionName,
            curNode->Value(), curNode->Type());
  nodeType = curNode->ToElement()->Attribute("type");
  NXstatus stat;
  if (strcmp (nodeValue, "NXroot") == 0) {
    this->iterateNodes(curNode, pArray);
  }  /*  only include all the NeXus base classes */
  else if ((strcmp (nodeValue, "NXentry") ==0) ||
           (strcmp (nodeValue, "NXinstrument") ==0) ||
           (strcmp (nodeValue, "NXsample") ==0) ||
           (strcmp (nodeValue, "NXmonitor") ==0) ||
           (strcmp (nodeValue, "NXsource") ==0) ||
           (strcmp (nodeValue, "NXuser") ==0) ||
           (strcmp (nodeValue, "NXdata") ==0) ||
           (strcmp (nodeValue, "NXdetector") ==0) ||
           (strcmp (nodeValue, "NXaperature") ==0) ||
           (strcmp (nodeValue, "NXattenuator") ==0) ||
           (strcmp (nodeValue, "NXbeam_stop") ==0) ||
           (strcmp (nodeValue, "NXbending_magnet") ==0) ||
           (strcmp (nodeValue, "NXcollimator") ==0) ||
           (strcmp (nodeValue, "NXcrystal") ==0) ||
           (strcmp (nodeValue, "NXdisk_chopper") ==0) ||
           (strcmp (nodeValue, "NXfermi_chopper") ==0) ||
           (strcmp (nodeValue, "NXfilter") ==0) ||
           (strcmp (nodeValue, "NXflipper") ==0) ||
           (strcmp (nodeValue, "NXguide") ==0) ||
           (strcmp (nodeValue, "NXinsertion_device") ==0) ||
           (strcmp (nodeValue, "NXmirror") ==0) ||
           (strcmp (nodeValue, "NXmoderator") ==0) ||
           (strcmp (nodeValue, "NXmonochromator") ==0) ||
           (strcmp (nodeValue, "NXpolarizer") ==0) ||
           (strcmp (nodeValue, "NXpositioner") ==0) ||
           (strcmp (nodeValue, "NXvelocity_selector") ==0) ||
           (strcmp (nodeValue, "NXevent_data") ==0) ||
           (strcmp (nodeValue, "NXprocess") ==0) ||
           (strcmp (nodeValue, "NXcharacterization") ==0) ||
           (strcmp (nodeValue, "NXlog") ==0) ||
           (strcmp (nodeValue, "NXnote") ==0) ||
           (strcmp (nodeValue, "NXbeam") ==0) ||
           (strcmp (nodeValue, "NXgeometry") ==0) ||
           (strcmp (nodeValue, "NXtranslation") ==0) ||
           (strcmp (nodeValue, "NXshape") ==0) ||
           (strcmp (nodeValue, "NXorientation") ==0) ||
           (strcmp (nodeValue, "NXenvironment") ==0) ||
           (strcmp (nodeValue, "NXsensor") ==0) ||
           (strcmp (nodeValue, "NXcapillary") ==0) ||
           (strcmp (nodeValue, "NXcollection") ==0) ||
           (strcmp (nodeValue, "NXdetector_group") ==0) ||
           (strcmp (nodeValue, "NXparameters") ==0) ||
           (strcmp (nodeValue, "NXsubentry") ==0) ||
           (strcmp (nodeValue, "NXxraylens") ==0) ||
           (nodeType && strcmp (nodeType, "UserGroup") == 0) ) {
  nodeName = curNode->ToElement()->Attribute("name");
  if (nodeName == NULL) {
    nodeName = nodeValue;
  }
  stat = NXmakegroup(this->nxFileHandle, (const char *)nodeName, (const char *)nodeValue);
  stat |= NXopengroup(this->nxFileHandle, (const char *)nodeName, (const char *)nodeValue);
  if (stat != NX_OK ) {
    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
              "%s:%s Error creating group %s %s\n",
              driverName, functionName, nodeName, nodeValue);
  }
  this->iterateNodes(curNode, pArray);
  stat = NXclosegroup(this->nxFileHandle);
  if (stat != NX_OK ) {
    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
              "%s:%s Error closing group %s %s\n",
              driverName, functionName, nodeName, nodeValue);
    }
  }
  else if (strcmp (nodeValue, "Attr") ==0) {
    nodeName = curNode->ToElement()->Attribute("name");
    nodeSource = curNode->ToElement()->Attribute("source");
    if (nodeType && strcmp(nodeType, "ND_ATTR") == 0 ) {
      pAttr = this->pFileAttributes->find(nodeSource);
      if (pAttr != NULL ){
        pAttr->getValueInfo(&attrDataType, &attrDataSize);
        this->getAttrTypeNSize(pAttr, &dataOutType, &wordSize);

        if (dataOutType > 0) {
          pValue = calloc( attrDataSize, wordSize );
          pAttr->getValue(attrDataType, (char *)pValue, attrDataSize*wordSize);

          NXputattr(this->nxFileHandle, nodeName, pValue, (int)(attrDataSize/wordSize), dataOutType);

          free(pValue);
        }
      }
      else {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                  "%s:%s Could not find attribute named %s\n",
                  driverName, functionName, nodeSource);
      }
    }
    else if (nodeType && strcmp(nodeType, "CONST") == 0 ) {
      this->findConstText( curNode, nodeText);
      nodeOuttype = curNode->ToElement()->Attribute("outtype");
      if (nodeOuttype == NULL){
        nodeOuttype = "NX_CHAR";
      }
      dataOutType = this->typeStringToVal((const char *)nodeOuttype);
      if ( dataOutType == NX_CHAR ) {
        nodeTextLen = strlen(nodeText);
      }
      else {
        nodeTextLen = 1;
      }
      pValue = allocConstValue( dataOutType, nodeTextLen);
      constTextToDataType(nodeText, dataOutType, pValue);
      NXputattr(this->nxFileHandle, nodeName, pValue, (int)nodeTextLen, dataOutType);
      free(pValue);

    }
    else if (nodeType) {
      asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                "%s:%s Node type %s for node %s is invalid\n",
                driverName, functionName, nodeType, nodeValue);
    }
  }

  else {
    nodeSource = curNode->ToElement()->Attribute("source");
    if (nodeType && strcmp(nodeType, "ND_ATTR") == 0 ) {
      pAttr = this->pFileAttributes->find(nodeSource);
      if ( pAttr != NULL) {
        pAttr->getValueInfo(&attrDataType, &attrDataSize);
        this->getAttrTypeNSize(pAttr, &dataOutType, &wordSize);

        if (dataOutType > 0) {
          pValue = calloc( attrDataSize, wordSize );
          pAttr->getValue(attrDataType, (char *)pValue, attrDataSize);

          numWords = attrDataSize/wordSize;
          NXmakedata( this->nxFileHandle, nodeValue, dataOutType, 1, (int *)&(numWords));
          NXopendata(this->nxFileHandle, nodeValue);
          NXputdata(this->nxFileHandle, (char *)pValue);
          free(pValue);
          this->iterateNodes(curNode, pArray);
          NXclosedata(this->nxFileHandle);
        }
      }
      else {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                  "%s:%s Could not add node %s could not find an attribute by that name\n",
                  driverName, functionName, nodeSource);
      }
    }
    else if (nodeType && strcmp(nodeType, "pArray") == 0 ){

      rank = pArray->ndims;
      type = pArray->dataType;
      for (ii=0; ii<rank; ii++) {
        dims[(rank-1) - ii] = (int)pArray->dims[ii].size;
      }

      switch(type) {
        case NDInt8:
          dataOutType = NX_INT8;
          wordSize = 1;
          break;
        case NDUInt8:
          dataOutType = NX_UINT8;
          wordSize = 1;
          break;
        case NDInt16:
          dataOutType = NX_INT16;
          wordSize = 2;
          break;
        case NDUInt16:
          dataOutType = NX_UINT16;
          wordSize = 2;
          break;
        case NDInt32:
          dataOutType = NX_INT32;
          wordSize = 4;
          break;
        case NDUInt32:
          dataOutType = NX_UINT32;
          wordSize = 4;
          break;
        case NDFloat32:
          dataOutType = NX_FLOAT32;
          wordSize = 4;
          break;
        case NDFloat64:
          dataOutType = NX_FLOAT64;
          wordSize = 8;
          break;
        }

        asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,
                  "%s:%s Starting to write data making group\n", driverName, functionName );

      if ( fileWriteMode == NDFileModeSingle ) {
          NXmakedata( this->nxFileHandle, nodeValue, dataOutType, rank, dims);
      }
      else if ((fileWriteMode == NDFileModeCapture) ||
               (fileWriteMode == NDFileModeStream)) {
        for (ii = 0; ii < rank; ii++) {
          dims[(rank) - ii] = dims[(rank-1) - ii];
        }
        rank = rank +1;
        dims[0] = numCapture;
        NXmakedata( this->nxFileHandle, nodeValue, dataOutType, rank, dims);
      }
      dPath[0] = '\0';
      dataclass[0] = '\0';

      NXopendata(this->nxFileHandle, nodeValue);
      // If you are having problems with NXgetgroupinfo in Visual Studio,
      // Checkout this link: http://trac.nexusformat.org/code/ticket/217
      // Fixed in Nexus 4.2.1
      //printf("%s:%s: calling NXgetgroupinfo!\n", driverName, functionName);
      NXgetgroupinfo(this->nxFileHandle, &numItems, dPath, dataclass);
      //printf("dPath=%s, nodeValue=%s\n", dPath, nodeValue );
      sprintf(this->dataName, "%s", nodeValue);
      sprintf(this->dataPath, "%c%s", '/', dPath);
      this->iterateNodes(curNode, pArray);
      NXclosedata(this->nxFileHandle);
    }
    else if (nodeType && strcmp(nodeType, "CONST") == 0 ){
      this->findConstText( curNode, nodeText);

      nodeOuttype = curNode->ToElement()->Attribute("outtype");
      if (nodeOuttype == NULL){
        nodeOuttype = "NX_CHAR";
      }
      dataOutType = this->typeStringToVal(nodeOuttype);
      if ( dataOutType == NX_CHAR ) {
        nodeTextLen = strlen(nodeText);
      }
      else {
        nodeTextLen = 1;
      }
      pValue = allocConstValue( dataOutType, nodeTextLen);
      constTextToDataType(nodeText, dataOutType, pValue);

      NXmakedata( this->nxFileHandle, nodeValue, dataOutType, 1, (int *)&nodeTextLen);
      NXopendata(this->nxFileHandle, nodeValue);
      NXputdata(this->nxFileHandle, pValue);
      free(pValue);
      this->iterateNodes(curNode, pArray);
      NXclosedata(this->nxFileHandle);
    }
    else if (nodeType) {
      asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                "%s:%s Node type %s for node %s is invalid\n",
                driverName, functionName, nodeType, nodeValue);
    }
    else {
      this->findConstText( curNode, nodeText);

      dataOutType = NX_CHAR;
      nodeTextLen = strlen(nodeText);

      if (nodeTextLen == 0) {
        sprintf(nodeText, "LEFT BLANK");
        nodeTextLen = strlen(nodeText);
      }

      pValue = allocConstValue( dataOutType, nodeTextLen);
      constTextToDataType(nodeText, dataOutType, pValue);

      NXmakedata( this->nxFileHandle, nodeValue, dataOutType, 1, (int *)&nodeTextLen);
      NXopendata(this->nxFileHandle, nodeValue);
      NXputdata(this->nxFileHandle, pValue);
      this->iterateNodes(curNode, pArray);
      NXclosedata(this->nxFileHandle);
    }
  }
  asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
            "Leaving %s:%s\n", driverName, functionName );
  return (status);
}
Example #14
0
/** Base method for writing a file
  * Handles logic for NDFileModeSingle, NDFileModeCapture and NDFileModeStream when the derived class does or
  * does not support NDPulginFileMultiple. Calls writeFile in the derived class. */
asynStatus NDPluginFile::writeFileBase() 
{
    int status = asynSuccess;
    int fileWriteMode;
    int numCapture, numCaptured;
    int i;
    bool doLazyOpen;
    int deleteDriverFile;
    NDArray *pArray;
    NDAttribute *pAttribute;
    char driverFileName[MAX_FILENAME_LEN];
    char errorMessage[256];
    static const char* functionName = "writeFileBase";

    /* Make sure there is a valid array */
    if (!this->pArrays[0]) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s::%s: ERROR, must collect an array to get dimensions first\n",
            driverName, functionName);
        return(asynError);
    }
    
    NDArray *pArrayOut = this->pArrays[0];
    // Must increase reference count on this array because another thread might decrement the count on pArrays[0]
    // when we have the mutex unlocked
    pArrayOut->reserve();

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

    setIntegerParam(NDFileWriteStatus, NDFileWriteOK);
    setStringParam(NDFileWriteMessage, "");
    
    /* We unlock the overall mutex here because we want the callbacks to be able to queue new
     * frames without waiting while we write files here.  The only restriction is that the
     * callbacks must not modify any part of the class structure that we use here. */

    switch(fileWriteMode) {
        case NDFileModeSingle:
            setIntegerParam(NDWriteFile, 1);
            callParamCallbacks();
            // Some file writing plugins (e.g. HDF5) use the value of NDFileNumCaptured 
            // even in single mode
            setIntegerParam(NDFileNumCaptured, 1);
            status = this->openFileBase(NDFileModeWrite, pArrayOut);
            if (status == asynSuccess) {
                this->unlock();
                epicsMutexLock(this->fileMutexId);
                status = this->writeFile(pArrayOut);
                epicsMutexUnlock(this->fileMutexId);
                this->lock();
                NDPluginDriver::endProcessCallbacks(pArrayOut, true, true);
                if (status) {
                    epicsSnprintf(errorMessage, sizeof(errorMessage)-1, 
                        "Error writing file, status=%d", status);
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
                          "%s::%s %s\n", 
                          driverName, functionName, errorMessage);
                    setIntegerParam(NDFileWriteStatus, NDFileWriteError);
                    setStringParam(NDFileWriteMessage, errorMessage);
                } else {
                    status = this->closeFileBase(); 
                }
            }
            setIntegerParam(NDWriteFile, 0);
            callParamCallbacks();
            break;
        case NDFileModeCapture:
            /* Write the file */
            if (!this->pCapture) {
                asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                    "%s::%s: ERROR, no capture buffer present\n", 
                    driverName, functionName);
                setIntegerParam(NDFileWriteStatus, NDFileWriteError);
                setStringParam(NDFileWriteMessage, "ERROR, no capture buffer present");
                break;
            }
            setIntegerParam(NDWriteFile, 1);
            callParamCallbacks();
            if (this->supportsMultipleArrays)
                status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, pArrayOut);
            if (status == asynSuccess) {
                for (i=0; i<numCaptured; i++) {
                    pArray = this->pCapture[i];
                    if (!this->supportsMultipleArrays)
                        status = this->openFileBase(NDFileModeWrite, pArray);
                    else
                        this->attrFileNameCheck();
                    if (status == asynSuccess) {
                        this->unlock();
                        epicsMutexLock(this->fileMutexId);
                        status = this->writeFile(pArray);
                        epicsMutexUnlock(this->fileMutexId);
                        this->lock();
                        NDPluginDriver::endProcessCallbacks(pArray, true, true);
                        if (status) {
                            epicsSnprintf(errorMessage, sizeof(errorMessage)-1, 
                                "Error writing file, status=%d", status);
                            asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
                                  "%s::%s %s\n", 
                                  driverName, functionName, errorMessage);
                            setIntegerParam(NDFileWriteStatus, NDFileWriteError);
                            setStringParam(NDFileWriteMessage, errorMessage);
                        } else {
                            if (!this->supportsMultipleArrays)
                                status = this->closeFileBase();
                        }
                    }
                }
            }
            freeCaptureBuffer(numCapture);
            if ((status == asynSuccess) && this->supportsMultipleArrays) 
                status = this->closeFileBase();
            this->registerInitFrameInfo(NULL);
            setIntegerParam(NDFileNumCaptured, 0);
            setIntegerParam(NDWriteFile, 0);
            callParamCallbacks();
            break;
        case NDFileModeStream:
            doLazyOpen = this->lazyOpen && (numCaptured == 0);
            if (!this->supportsMultipleArrays || doLazyOpen)
                status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, pArrayOut);
            else
                this->attrFileNameCheck();
            if (!this->isFrameValid(pArrayOut)) {
                setIntegerParam(NDFileWriteStatus, NDFileWriteError);
                setStringParam(NDFileWriteMessage, "Invalid frame. Ignoring.");
                status = asynError;
            }
            if (status == asynSuccess) {
                this->unlock();
                epicsMutexLock(this->fileMutexId);
                status = this->writeFile(pArrayOut);
                epicsMutexUnlock(this->fileMutexId);
                this->lock();
                NDPluginDriver::endProcessCallbacks(pArrayOut, true, true);
                if (status) {
                    epicsSnprintf(errorMessage, sizeof(errorMessage)-1,
                            "Error writing file, status=%d", status);
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                            "%s::%s %s\n",
                            driverName, functionName, errorMessage);
                    setIntegerParam(NDFileWriteStatus, NDFileWriteError);
                    setStringParam(NDFileWriteMessage, errorMessage);
                } else {
                    status = this->attrFileCloseCheck();
                    if (!this->supportsMultipleArrays)
                        status = this->closeFileBase();
                }
            }
            break;
        default:
            asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                "%s::%s: ERROR, unknown fileWriteMode %d\n", 
                driverName, functionName, fileWriteMode);
            break;
    }
    
    /* Check to see if we should delete the original file
     * Only do this if all of the following conditions are met
     *  - DeleteOriginalFile is true
     *  - There were no errors above
     *  - The NDFullFileName attribute is present and contains a non-blank string
     */
    getIntegerParam(NDFileDeleteDriverFile, &deleteDriverFile);
    if ((status == asynSuccess) && deleteDriverFile) {
        pAttribute = pArrayOut->pAttributeList->find("DriverFileName");
        if (pAttribute) {
            status = pAttribute->getValue(NDAttrString, driverFileName, sizeof(driverFileName));
            if ((status == asynSuccess) && (strlen(driverFileName) > 0)) {
                status = remove(driverFileName);
                if (status != 0) {
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
                              "%s::%s: error deleting file %s, error=%s\n",
                              driverName, functionName, driverFileName, strerror(errno));
                }
            }
        }
    }

    // Decrease reference count
    pArrayOut->release();

    return (asynStatus) status;
}
/** Format an NDArray as an AVFrame using the codec context c.
Use inPicture to wrap the data in pArray, use swscale to convert it to scPicture
using the output parameters stored in c. Special case for gray8 -> YUVx, can
use the data as is and add a neutral array for the colour info.
*/
int formatArray(NDArray *pArray, asynUser *pasynUser, AVFrame *inPicture,
		struct SwsContext **pCtx, AVCodecContext *c, AVFrame *scPicture) {
    static const char *functionName = "formatArray";
    int colorMode = NDColorModeMono;
	int width, height;
	PixelFormat pix_fmt;
	NDAttribute *pAttribute = NULL;
	int Int16;
	
	/* only support 8 and 16 bit data for now */
    switch (pArray->dataType) {
        case NDInt8:
        case NDUInt8:
            Int16 = 0;
            break;
        case NDInt16:
        case NDUInt16:       
            Int16 = 1; 
            break;
        default:
            asynPrint(pasynUser, ASYN_TRACE_ERROR, 
                "%s: only 8 or 16-bit data is supported\n", functionName);
        	return(asynError);
    }	

	/* Get the colormode of the array */	
    pAttribute = pArray->pAttributeList->find("ColorMode");
    if (pAttribute) pAttribute->getValue(NDAttrInt32, &colorMode);

    /* We do some special treatment based on colorMode */
    if ((pArray->ndims == 2) && (colorMode == NDColorModeMono)) {
        width  = (int) pArray->dims[0].size;
        height = (int) pArray->dims[1].size;
        if (Int16) {
            pix_fmt = PIX_FMT_GRAY16;
        } else if (width != c->width || height != c->height) {
        	pix_fmt = PIX_FMT_GRAY8;
        } else {
        	int stride;
            pix_fmt = PIX_FMT_GRAY8;
            /* special case for gray8, and planar outputs, don't need to scale, 
               can use a neutral array */
            switch (c->pix_fmt) {
    			case PIX_FMT_YUV420P:   //< planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
    			case PIX_FMT_YUV411P:   //< planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
    			case PIX_FMT_YUVJ420P:  //< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV420P and setting color_range
    			case PIX_FMT_NV12:      //< planar YUV 4:2:0, 12bpp, 1 plane for Y and 1 plane for the UV components, which are interleaved (first byte U and the following byte V)
    			case PIX_FMT_NV21:      //< as above, but U and V bytes are swapped
    				stride = 4;
    				break;
    			case PIX_FMT_YUV422P:   //< planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
    			case PIX_FMT_YUVJ422P:  //< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV422P and setting color_range
    			case PIX_FMT_YUV440P:   //< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
    			case PIX_FMT_YUVJ440P:  //< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of PIX_FMT_YUV440P and setting color_range    			
    				stride = 2;
    				break;    				
    			case PIX_FMT_YUV444P:   //< planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)    			
    			case PIX_FMT_YUVJ444P:  //< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of PIX_FMT_YUV444P and setting color_range
					stride = 1;
    				break;	
    			default:
    				stride = 0;
    				break;				
			}			
			if (stride) {	
	    	    scPicture->data[0] = (uint8_t*) pArray->pData;
    		    scPicture->data[1] = (uint8_t*) neutral;
    		    scPicture->data[2] = (uint8_t*) neutral;    	        	    
		        scPicture->linesize[0] = width;
		        scPicture->linesize[1] = width / stride;
		        scPicture->linesize[2] = width / stride;
				return(asynSuccess);		        
		    }
		}
        /* setup the input picture */
        inPicture->data[0] = (uint8_t*) pArray->pData;
        inPicture->linesize[0] = width * (Int16 + 1);
    } else if ((pArray->ndims == 3) && (pArray->dims[0].size == 3) && (colorMode == NDColorModeRGB1)) {
        width  = (int) pArray->dims[1].size;
        height = (int) pArray->dims[2].size;
        if (Int16) {
            pix_fmt = PIX_FMT_RGB48;
        } else {
            pix_fmt = PIX_FMT_RGB24;
        }    
        /* setup the input picture */
        inPicture->data[0] = (uint8_t*) pArray->pData;
        inPicture->linesize[0] = width * (Int16 + 1) * 3;          
    } else {
        asynPrint(pasynUser, ASYN_TRACE_ERROR, 
            "%s: unsupported array structure\n", functionName);
        return(asynError);
    }

	/* setup the swscale ctx */   
	*pCtx = sws_getCachedContext(*pCtx, width, height, pix_fmt,
                                  c->width, c->height, c->pix_fmt,
                                  SWS_BICUBIC, NULL, NULL, NULL);   
                                  
    if (*pCtx == NULL) {
        asynPrint(pasynUser, ASYN_TRACE_ERROR, 
            "%s: sws_getCachedContext failed\n", functionName);
        return(asynError);
    }
    /* scale the picture so we can pass it to the encoder */
    sws_scale(*pCtx, inPicture->data, inPicture->linesize, 0,
		      height, scPicture->data, scPicture->linesize);
	return(asynSuccess);
}
Example #16
0
/** Opens a JPEG file.
  * \param[in] fileName The name of the file to open.
  * \param[in] openMode Mask defining how the file should be opened; bits are 
  *            NDFileModeRead, NDFileModeWrite, NDFileModeAppend, NDFileModeMultiple
  * \param[in] pArray A pointer to an NDArray; this is used to determine the array and attribute properties.
  */
asynStatus NDFileJPEG::openFile(const char *fileName, NDFileOpenMode_t openMode, NDArray *pArray)
{
    static const char *functionName = "openFile";
    int colorMode = NDColorModeMono;
    NDAttribute *pAttribute;
    int quality;

    /* We don't support reading yet */
    if (openMode & NDFileModeRead) return(asynError);

    /* We don't support opening an existing file for appending yet */
    if (openMode & NDFileModeAppend) return(asynError);

    switch (pArray->dataType) {
        case NDInt8:
        case NDUInt8:
            break;
        default:
            asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
            "%s:%s: only 8-bit data is supported\n",
            driverName, functionName);
        return(asynError);

    }

    /* We do some special treatment based on colorMode */
    pAttribute = pArray->pAttributeList->find("ColorMode");
    if (pAttribute) pAttribute->getValue(NDAttrInt32, &colorMode);

    if (pArray->ndims == 2) {
        this->jpegInfo.image_width  = (JDIMENSION)pArray->dims[0].size;
        this->jpegInfo.image_height = (JDIMENSION)pArray->dims[1].size;
        this->jpegInfo.input_components = 1;
        this->jpegInfo.in_color_space = JCS_GRAYSCALE;
        this->colorMode = NDColorModeMono;
    } else if ((pArray->ndims == 3) && (pArray->dims[0].size == 3) && (colorMode == NDColorModeRGB1)) {
        this->jpegInfo.image_width  = (JDIMENSION)pArray->dims[1].size;
        this->jpegInfo.image_height = (JDIMENSION)pArray->dims[2].size;
        this->jpegInfo.input_components = 3;
        this->jpegInfo.in_color_space = JCS_RGB;
        this->colorMode = NDColorModeRGB1;
    } else if ((pArray->ndims == 3) && (pArray->dims[1].size == 3) && (colorMode == NDColorModeRGB2)) {
        this->jpegInfo.image_width  = (JDIMENSION)pArray->dims[0].size;
        this->jpegInfo.image_height = (JDIMENSION)pArray->dims[2].size;
        this->jpegInfo.input_components = 3;
        this->jpegInfo.in_color_space = JCS_RGB;
        this->colorMode = NDColorModeRGB2;
    } else if ((pArray->ndims == 3) && (pArray->dims[2].size == 3) && (colorMode == NDColorModeRGB3)) {
        this->jpegInfo.image_width  = (JDIMENSION)pArray->dims[0].size;
        this->jpegInfo.image_height = (JDIMENSION)pArray->dims[1].size;
        this->jpegInfo.input_components = 3;
        this->jpegInfo.in_color_space = JCS_RGB;
        this->colorMode = NDColorModeRGB3;
    } else {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
            "%s:%s: unsupported array structure\n",
            driverName, functionName);
        return(asynError);
    }

   /* Create the file. */
    if ((this->outFile = fopen(fileName, "wb")) == NULL ) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
        "%s:%s error opening file %s\n",
        driverName, functionName, fileName);
        return(asynError);
    }
    
    jpeg_set_defaults(&this->jpegInfo);

    /* Set the file quality */
    /* Must lock when accessing parameter library */
    this->lock();
    getIntegerParam(NDFileJPEGQuality, &quality);
    this->unlock();
    jpeg_set_quality(&this->jpegInfo, quality, TRUE);
    
    jpeg_start_compress(&this->jpegInfo, TRUE);
    return(asynSuccess);
}
Example #17
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 #18
0
/** 
  * \param[in] pArray  The NDArray from the callback.
  */
void NDPluginAttribute::processCallbacks(NDArray *pArray)
{
  /*
     * This function is called with the mutex already locked.  It unlocks it during long calculations when private
     * structures don't need to be protected.
     */

  int status = 0;
  int currentTSPoint;
  int numTSPoints;
  int TSAcquiring;
  double valueSum;
  int i;
  char attrName[MAX_ATTR_NAME_] = {0};
  NDAttribute *pAttribute = NULL;
  NDAttributeList *pAttrList = NULL;
  epicsFloat64 attrValue = 0.0;

  static const char *functionName = "NDPluginAttribute::processCallbacks";
  
  /* Call the base class method */
  NDPluginDriver::beginProcessCallbacks(pArray);
  
  /* Get the attributes for this driver */
  pAttrList = pArray->pAttributeList;
  
  getIntegerParam(NDPluginAttributeTSCurrentPoint, &currentTSPoint);
  getIntegerParam(NDPluginAttributeTSNumPoints,    &numTSPoints);
  getIntegerParam(NDPluginAttributeTSAcquiring,    &TSAcquiring);

  for (i=0; i<maxAttributes_; i++) {
    getStringParam(i, NDPluginAttributeAttrName, MAX_ATTR_NAME_, attrName);

    asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "Finding the attribute %s\n", attrName);

    if (strcmp(attrName, UNIQUE_ID_NAME_) == 0) {
      attrValue = (epicsFloat64) pArray->uniqueId;
    } else if (strcmp(attrName, TIMESTAMP_NAME_) == 0) {
      attrValue = pArray->timeStamp;
    } else if (strcmp(attrName, EPICS_TS_SEC_NAME_) == 0) {
      attrValue = (epicsFloat64)pArray->epicsTS.secPastEpoch;
    } else if (strcmp(attrName, EPICS_TS_NSEC_NAME_) == 0) {
      attrValue = (epicsFloat64)pArray->epicsTS.nsec;
    } else {
      pAttribute = pAttrList->find(attrName);
      if (pAttribute) {
        status = pAttribute->getValue(NDAttrFloat64, &attrValue);
        if (status != asynSuccess) {
          asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s: Error reading value for NDAttribute %s. \n", functionName, attrName);
          continue;
        }
        asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "Attribute %s value is %f\n", attrName, attrValue);
      } else {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s: Error finding NDAttribute %s. \n", functionName, attrName);
        continue;
      }
    }
    setDoubleParam(i, NDPluginAttributeVal, attrValue);
    getDoubleParam(i, NDPluginAttributeValSum, &valueSum);
    valueSum += attrValue;
    setDoubleParam(i, NDPluginAttributeValSum, valueSum);
    if (TSAcquiring) {
      pTSArray_[i][currentTSPoint] = attrValue;
    }
    callParamCallbacks(i);
  }
  if (TSAcquiring) {
    currentTSPoint++;
    setIntegerParam(NDPluginAttributeTSCurrentPoint, currentTSPoint);
    if (currentTSPoint >= numTSPoints) {
        doTimeSeriesCallbacks();
        setIntegerParam(NDPluginAttributeTSAcquiring, 0);
    }
  }
}
Example #19
0
/** Opens a Magick file.
  * \param[in] fileName The name of the file to open.
  * \param[in] openMode Mask defining how the file should be opened; bits are
  *            NDFileModeRead, NDFileModeWrite, NDFileModeAppend, NDFileModeMultiple
  * \param[in] pArray A pointer to an NDArray; this is used to determine the array and attribute properties.
  */
asynStatus NDFileMagick::openFile(const char *fileName, NDFileOpenMode_t openMode, NDArray *pArray)
{
    static const char *functionName = "openFile";
    NDAttribute *pAttribute;

    /* We don't support reading yet */
    if (openMode & NDFileModeRead) return(asynError);

    /* We don't support opening an existing file for appending yet */
    if (openMode & NDFileModeAppend) return(asynError);

    strncpy(this->fileName, fileName, sizeof(this->fileName));
    this->colorMode = NDColorModeMono;

    /* We do some special treatment based on colorMode */
    pAttribute = pArray->pAttributeList->find("ColorMode");
    if (pAttribute) pAttribute->getValue(NDAttrInt32, &this->colorMode);

    switch (pArray->dataType) {
    case NDInt8:
    case NDUInt8:
        this->storageType = CharPixel;
        break;
    case NDInt16:
    case NDUInt16:
        this->storageType = ShortPixel;
        break;
    case NDInt32:
    case NDUInt32:
        this->storageType = IntegerPixel;
        break;
    case NDFloat32:
        this->storageType = FloatPixel;
        break;
    case NDFloat64:
        this->storageType = DoublePixel;
        break;
    }
    if (pArray->ndims == 2) {
        sizeX = pArray->dims[0].size;
        sizeY = pArray->dims[1].size;
        this->colorMap = "R";
        this->imageType = GrayscaleType;
    } else if ((pArray->ndims == 3) && (pArray->dims[0].size == 3) && (this->colorMode == NDColorModeRGB1)) {
        sizeX = pArray->dims[1].size;
        sizeY = pArray->dims[2].size;
        this->colorMap = "RGB";
        this->imageType = TrueColorType;
    } else if ((pArray->ndims == 3) && (pArray->dims[1].size == 3) && (this->colorMode == NDColorModeRGB2)) {
        sizeX = pArray->dims[0].size;
        sizeY = pArray->dims[2].size;
        this->colorMap = "RGB";
        this->imageType = TrueColorType;
    } else if ((pArray->ndims == 3) && (pArray->dims[2].size == 3) && (this->colorMode == NDColorModeRGB3)) {
        sizeX = pArray->dims[0].size;
        sizeY = pArray->dims[1].size;
        this->colorMap = "RGB";
        this->imageType = TrueColorType;
    } else {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                  "%s:%s: unsupported array structure\n",
                  driverName, functionName);
        return(asynError);
    }

    return(asynSuccess);
}
Example #20
0
/** Callback function that is called by the NDArray driver with new NDArray data.
  * If the plugin is running then it attaches position data to the NDArray as NDAttributes
  * and then passes the array on.  If the plugin is not running then NDArrays are not
  * passed through to the next plugin(s) in the chain.
  * \param[in] pArray  The NDArray from the callback.
  */ 
void NDPosPlugin::processCallbacks(NDArray *pArray)
{
  int index = 0;
  int running = NDPOS_IDLE;
  int skip = 0;
  int mode = 0;
  int size = 0;
  int duplicates = 0;
  int dropped = 0;
  int expectedID = 0;
  int IDDifference = 0;
  epicsInt32 IDValue = 0;
  char IDName[MAX_STRING_SIZE];
  static const char *functionName = "NDPosPlugin::processCallbacks";

  // Call the base class method
  NDPluginDriver::processCallbacks(pArray);
  getIntegerParam(NDPos_Running, &running);
  // We must maintain the size of the list ourselves, as calling
  // size() on the list has a complexity of O(n) which causes a problem
  // once we get into tens of thousands of items.
  getIntegerParam(NDPos_CurrentQty, &size);
  // Only attach the position data to the array if we are running
  if (running == NDPOS_RUNNING){
    getIntegerParam(NDPos_CurrentIndex, &index);
    if (index >= size){
      // We've reached the end of our positions, stop to make sure we don't overflow
      setIntegerParam(NDPos_Running, NDPOS_IDLE);
      running = NDPOS_IDLE;
    } else {
      // Read the ID parameter from the NDArray.  If it cannot be found then abort
      getStringParam(NDPos_IDName, MAX_STRING_SIZE, IDName);
      // Check for IDName, if it is empty the we use the unique ID of the array
      if (strcmp(IDName, "") == 0){
        IDValue = pArray->uniqueId;
      } else {
        NDAttribute *IDAtt = pArray->pAttributeList->find(IDName);
        if (IDAtt){
          epicsInt32 IDValue;
          if (IDAtt->getValue(NDAttrInt32, &IDValue, sizeof(epicsInt32)) == ND_ERROR){
            // Error, unable to get the value from the ID attribute
            asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                      "%s::%s ERROR: could not retrieve expected ID from attribute [%s]\n",
                      driverName, functionName, IDName);
            setIntegerParam(NDPos_Running, NDPOS_IDLE);
            running = NDPOS_IDLE;
          }
        } else {
          // Error, unable to find the named ID attribute
          asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                    "%s::%s ERROR: could not find attribute [%s]\n",
                    driverName, functionName, IDName);
          setIntegerParam(NDPos_Running, NDPOS_IDLE);
          running = NDPOS_IDLE;
        }
      }
      if (running == NDPOS_RUNNING){
        // Check the ID is the same as the expected index
        getIntegerParam(NDPos_IDDifference, &IDDifference);
        getIntegerParam(NDPos_ExpectedID, &expectedID);
        if (expectedID < IDValue){
          asynPrint(this->pasynUserSelf, ASYN_TRACE_WARNING,
                    "%s::%s WARNING: possible frame drop detected: expected ID [%d] received ID [%d]\n",
                    driverName, functionName, expectedID, IDValue);
          // If expected is less than ID throw away positions and record dropped events
          getIntegerParam(NDPos_MissingFrames, &dropped);
          getIntegerParam(NDPos_Mode, &mode);
          if (mode == MODE_DISCARD){
            while ((expectedID < IDValue) && (size > 0)){
              // The index will stay the same, and we need to pop the value out of the position array
              positionArray.erase(positionArray.begin());
              size--;
              expectedID += IDDifference;
              dropped++;
            }
            // If the size has dropped to zero then we've run out of positions, abort
            if (size == 0){
              setIntegerParam(NDPos_Running, NDPOS_IDLE);
              running = NDPOS_IDLE;
            }
            setIntegerParam(NDPos_CurrentQty, size);
          } else if (mode == MODE_KEEP){
            while (expectedID < IDValue && (index < size)){
              index++;
              expectedID += IDDifference;
              dropped++;
            }
            // If the index has reached the size of the array then we've run out of positions, abort
            if (index == size){
              setIntegerParam(NDPos_Running, NDPOS_IDLE);
              running = NDPOS_IDLE;
            }
            setIntegerParam(NDPos_CurrentIndex, index);
          }
          setIntegerParam(NDPos_ExpectedID, expectedID);
          setIntegerParam(NDPos_MissingFrames, dropped);
        } else if (expectedID > IDValue){
          asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                    "%s::%s ERROR: dropping frame! possible duplicate detected: expected ID [%d] received ID [%d]\n",
                    driverName, functionName, expectedID, IDValue);
          // If expected is greater than ID then ignore the frame and record duplicate event
          getIntegerParam(NDPos_DuplicateFrames, &duplicates);
          duplicates++;
          setIntegerParam(NDPos_DuplicateFrames, duplicates);
          skip = 1;
        }
      }

      // Only perform the actual setting of positions if we aren't skipping
      if (skip == 0 && running == NDPOS_RUNNING){
        // We always keep the last array so read() can use it.
        // Release previous one. Reserve new one below during the copy.
        if (this->pArrays[0]){
          this->pArrays[0]->release();
          this->pArrays[0] = NULL;
        }
        // We must make a copy of the array as we are going to alter it
        this->pArrays[0] = this->pNDArrayPool->copy(pArray, this->pArrays[0], 1);
        if (this->pArrays[0]){
          std::list<std::map<std::string, double> >::iterator it = positionArray.begin();
          std::advance(it, index);
          //std::map<std::string, double> pos = positionArray[index];
          std::map<std::string, double> pos = *it;
          std::stringstream sspos;
          sspos << "[";
          bool firstTime = true;
          std::map<std::string, double>::iterator iter;
          for (iter = pos.begin(); iter != pos.end(); iter++){
            if (firstTime){
              firstTime = false;
            } else {
              sspos << ",";
            }
            sspos << iter->first << "=" << iter->second;
            // Create the NDAttribute with the position data
            NDAttribute *pAtt = new NDAttribute(iter->first.c_str(), "Position of NDArray", NDAttrSourceDriver, driverName, NDAttrFloat64, &(iter->second));
            // Add the NDAttribute to the NDArray
            this->pArrays[0]->pAttributeList->add(pAtt);
          }
          sspos << "]";
          setStringParam(NDPos_CurrentPos, sspos.str().c_str());

        } else {
          // We were unable to allocate the required buffer (memory or qty exceeded).
          // This results in us dropping a frame, note it and print an error
          asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                    "%s::%s ERROR: dropped frame! Could not allocate the required buffer\n",
                    driverName, functionName);
          // Note the frame drop
          getIntegerParam(NDPluginDriverDroppedArrays, &dropped);
          dropped++;
          setIntegerParam(NDPluginDriverDroppedArrays, dropped);
          skip = 1;
        }

        // Check the mode
        getIntegerParam(NDPos_Mode, &mode);
        if (mode == MODE_DISCARD){
          // The index will stay the same, and we need to pop the value out of the position array
          positionArray.erase(positionArray.begin());
          size--;
          setIntegerParam(NDPos_CurrentQty, size);
        } else if (mode == MODE_KEEP){
          index++;
          setIntegerParam(NDPos_CurrentIndex, index);
        }
        // Increment the expectedID by the difference
        expectedID += IDDifference;
        setIntegerParam(NDPos_ExpectedID, expectedID);
      }
    }
    // If the size has dropped to zero then we've run out of positions, abort
    if (size == 0){
      setIntegerParam(NDPos_Running, NDPOS_IDLE);
    }
    callParamCallbacks();
    if (skip == 0 && running == NDPOS_RUNNING){
      this->unlock();
      doCallbacksGenericPointer(this->pArrays[0], NDArrayData, 0);
      this->lock();
    }
  }
}
Example #21
0
/** Opens a TIFF file.
  * \param[in] fileName The name of the file to open.
  * \param[in] openMode Mask defining how the file should be opened; bits are 
  *            NDFileModeRead, NDFileModeWrite, NDFileModeAppend, NDFileModeMultiple
  * \param[in] pArray A pointer to an NDArray; this is used to determine the array and attribute properties.
  */
asynStatus NDFileTIFF::openFile(const char *fileName, NDFileOpenMode_t openMode, NDArray *pArray)
{
    /* When we create TIFF variables and dimensions, we get back an
     * ID for each one. */
    static const char *functionName = "openFile";
    size_t sizeX, sizeY, rowsPerStrip;
    int bitsPerSample=8, sampleFormat=SAMPLEFORMAT_INT, samplesPerPixel, photoMetric, planarConfig;
    int colorMode=NDColorModeMono;
    NDAttribute *pAttribute = NULL;
    char tagString[MAX_ATTRIBUTE_STRING_SIZE] = {0};
    char attrString[MAX_ATTRIBUTE_STRING_SIZE] = {0};

    /* We don't support reading yet */
    if (openMode & NDFileModeRead) return(asynError);

    /* We don't support opening an existing file for appending yet */
    if (openMode & NDFileModeAppend) return(asynError);

   /* Create the file. */
    if ((this->output = TIFFOpen(fileName, "w")) == NULL ) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
        "%s:%s error opening file %s\n",
        driverName, functionName, fileName);
        return(asynError);
    }
    /* We do some special treatment based on colorMode */
    pAttribute = pArray->pAttributeList->find("ColorMode");
    if (pAttribute) pAttribute->getValue(NDAttrInt32, &colorMode);

    switch (pArray->dataType) {
        case NDInt8:
            sampleFormat = SAMPLEFORMAT_INT;
            bitsPerSample = 8;
            break;
        case NDUInt8:
            sampleFormat = SAMPLEFORMAT_UINT;
            bitsPerSample = 8;
            break;
        case NDInt16:
            sampleFormat = SAMPLEFORMAT_INT;
            bitsPerSample = 16;
            break;
        case NDUInt16:
            sampleFormat = SAMPLEFORMAT_UINT;
            bitsPerSample = 16;
            break;
        case NDInt32:
            sampleFormat = SAMPLEFORMAT_INT;
            bitsPerSample = 32;
            break;
        case NDUInt32:
            sampleFormat = SAMPLEFORMAT_UINT;
            bitsPerSample = 32;
            break;
        case NDFloat32:
            sampleFormat = SAMPLEFORMAT_IEEEFP;
            bitsPerSample = 32;
            break;
        case NDFloat64:
            sampleFormat = SAMPLEFORMAT_IEEEFP;
            bitsPerSample = 64;
            break;
    }
    if (pArray->ndims == 2) {
        sizeX = pArray->dims[0].size;
        sizeY = pArray->dims[1].size;
        rowsPerStrip = sizeY;
        samplesPerPixel = 1;
        photoMetric = PHOTOMETRIC_MINISBLACK;
        planarConfig = PLANARCONFIG_CONTIG;
        this->colorMode = NDColorModeMono;
    } else if ((pArray->ndims == 3) && (pArray->dims[0].size == 3) && (colorMode == NDColorModeRGB1)) {
        sizeX = pArray->dims[1].size;
        sizeY = pArray->dims[2].size;
        rowsPerStrip = sizeY;
        samplesPerPixel = 3;
        photoMetric = PHOTOMETRIC_RGB;
        planarConfig = PLANARCONFIG_CONTIG;
        this->colorMode = NDColorModeRGB1;
    } else if ((pArray->ndims == 3) && (pArray->dims[1].size == 3) && (colorMode == NDColorModeRGB2)) {
        sizeX = pArray->dims[0].size;
        sizeY = pArray->dims[2].size;
        rowsPerStrip = 1;
        samplesPerPixel = 3;
        photoMetric = PHOTOMETRIC_RGB;
        planarConfig = PLANARCONFIG_SEPARATE;
        this->colorMode = NDColorModeRGB2;
    } else if ((pArray->ndims == 3) && (pArray->dims[2].size == 3) && (colorMode == NDColorModeRGB3)) {
        sizeX = pArray->dims[0].size;
        sizeY = pArray->dims[1].size;
        rowsPerStrip = sizeY;
        samplesPerPixel = 3;
        photoMetric = PHOTOMETRIC_RGB;
        planarConfig = PLANARCONFIG_SEPARATE;
        this->colorMode = NDColorModeRGB3;
    } else {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR, 
            "%s:%s: unsupported array structure\n",
            driverName, functionName);
        return(asynError);
    }

    /* this is in the unallocated 'reusable' range */
    static const int TIFFTAG_NDTIMESTAMP    = 65000;
    static const int TIFFTAG_UNIQUEID       = 65001;
    static const int TIFFTAG_EPICSTSSEC     = 65002;
    static const int TIFFTAG_EPICSTSNSEC    = 65003;
    static const TIFFFieldInfo NDTimeStampFI = {
        TIFFTAG_NDTIMESTAMP,1,1,TIFF_DOUBLE,FIELD_CUSTOM,1,0,(char *)"NDTimeStamp"
    };
    static const TIFFFieldInfo NDUniqueIdFI = {
        TIFFTAG_UNIQUEID,1,1,TIFF_LONG,FIELD_CUSTOM,1,0,(char *)"NDUniqueId"
    };
    static const TIFFFieldInfo EPICSTSSecFI = {
        TIFFTAG_EPICSTSSEC,1,1,TIFF_LONG,FIELD_CUSTOM,1,0,(char *)"EPICSTSSec"
    };
    static const TIFFFieldInfo EPICSTSNsecFI = {
        TIFFTAG_EPICSTSNSEC,1,1,TIFF_LONG,FIELD_CUSTOM,1,0,(char *)"EPICSTSNsec"
    };
    TIFFMergeFieldInfo(output, &NDTimeStampFI, 1);
    TIFFMergeFieldInfo(output, &NDUniqueIdFI, 1);
    TIFFMergeFieldInfo(output, &EPICSTSSecFI, 1);
    TIFFMergeFieldInfo(output, &EPICSTSNsecFI, 1);
    TIFFSetField(this->output, TIFFTAG_NDTIMESTAMP, pArray->timeStamp);
    TIFFSetField(this->output, TIFFTAG_UNIQUEID, pArray->uniqueId);
    TIFFSetField(this->output, TIFFTAG_EPICSTSSEC, pArray->epicsTS.secPastEpoch);
    TIFFSetField(this->output, TIFFTAG_EPICSTSNSEC, pArray->epicsTS.nsec);
    TIFFSetField(this->output, TIFFTAG_BITSPERSAMPLE, bitsPerSample);
    TIFFSetField(this->output, TIFFTAG_SAMPLEFORMAT, sampleFormat);
    TIFFSetField(this->output, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
    TIFFSetField(this->output, TIFFTAG_PHOTOMETRIC, photoMetric);
    TIFFSetField(this->output, TIFFTAG_PLANARCONFIG, planarConfig);
    TIFFSetField(this->output, TIFFTAG_IMAGEWIDTH, (epicsUInt32)sizeX);
    TIFFSetField(this->output, TIFFTAG_IMAGELENGTH, (epicsUInt32)sizeY);
    TIFFSetField(this->output, TIFFTAG_ROWSPERSTRIP, (epicsUInt32)rowsPerStrip);
    
    this->pFileAttributes->clear();
    this->getAttributes(this->pFileAttributes);
    pArray->pAttributeList->copy(this->pFileAttributes);
 
    pAttribute = this->pFileAttributes->find("Model");
    if (pAttribute) {
        pAttribute->getValue(NDAttrString, tagString);
        TIFFSetField(this->output, TIFFTAG_MODEL, tagString);
    } else {
        TIFFSetField(this->output, TIFFTAG_MODEL, "Unknown");
    }
    
    pAttribute = this->pFileAttributes->find("Manufacturer");
    if (pAttribute) {
        pAttribute->getValue(NDAttrString, tagString);
        TIFFSetField(this->output, TIFFTAG_MAKE, tagString);
    } else {
        TIFFSetField(this->output, TIFFTAG_MAKE, "Unknown");
    }

    TIFFSetField(this->output, TIFFTAG_SOFTWARE, "EPICS areaDetector");

    int count = 0;
    int tagId = TIFFTAG_START_;
   
    numAttributes_ = this->pFileAttributes->count();
    asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
        "%s:%s this->pFileAttributes->count(): %d\n",
        driverName, functionName, numAttributes_);

    fieldInfo_ = (TIFFFieldInfo**) malloc(numAttributes_ * sizeof(TIFFFieldInfo *));
    if (fieldInfo_ == NULL) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
            "%s:%s error, fieldInfo_ malloc failed. file: %s\n",
            driverName, functionName, fileName);
        return asynError;
    }
    for (int i=0; i<numAttributes_; ++i) {
        asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
            "%s:%s Initializing %d fieldInfo_ entry.\n",
            driverName, functionName, i);
        fieldInfo_[i] = NULL;
    }
    
    asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
        "%s:%s Looping over attributes...\n",
        driverName, functionName);

    pAttribute = this->pFileAttributes->next(NULL);
    while (pAttribute) {
        const char *attributeName = pAttribute->getName();
        //const char *attributeDescription = pAttribute->getDescription();
        const char *attributeSource = pAttribute->getSource();

        asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
          "%s:%s : attribute: %s, source: %s\n",
          driverName, functionName, attributeName, attributeSource);

        NDAttrDataType_t attrDataType;
        size_t attrSize;
        NDAttrValue value;
        pAttribute->getValueInfo(&attrDataType, &attrSize);
        memset(tagString, 0, MAX_ATTRIBUTE_STRING_SIZE);

        switch (attrDataType) {
            case NDAttrInt8:
            case NDAttrUInt8:
            case NDAttrInt16:
            case NDAttrUInt16:
            case NDAttrInt32:
            case NDAttrUInt32: {
                pAttribute->getValue(attrDataType, &value.i32);
                epicsSnprintf(tagString, MAX_ATTRIBUTE_STRING_SIZE, "%s:%d", attributeName, value.i32);
                break;
            }
            case NDAttrFloat32: {
                pAttribute->getValue(attrDataType, &value.f32);
                epicsSnprintf(tagString, MAX_ATTRIBUTE_STRING_SIZE, "%s:%f", attributeName, value.f32);
                break;
            }
            case NDAttrFloat64: {
                pAttribute->getValue(attrDataType, &value.f64);
                epicsSnprintf(tagString, MAX_ATTRIBUTE_STRING_SIZE, "%s:%f", attributeName, value.f64);
                break;
            }
            case NDAttrString: {
                memset(attrString, 0, MAX_ATTRIBUTE_STRING_SIZE);
                pAttribute->getValue(attrDataType, attrString, MAX_ATTRIBUTE_STRING_SIZE);
                epicsSnprintf(tagString, MAX_ATTRIBUTE_STRING_SIZE, "%s:%s", attributeName, attrString);
                break;
            }
            case NDAttrUndefined:
                break;
            default:
                asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                          "%s:%s error, unknown attrDataType=%d\n",
                          driverName, functionName, attrDataType);
                return asynError;
                break;
        }

        if (attrDataType != NDAttrUndefined) {
            asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
                "%s:%s : tagId: %d, tagString: %s\n",
                  driverName, functionName, tagId, tagString);
            fieldInfo_[count] = (TIFFFieldInfo*) malloc(sizeof(TIFFFieldInfo));
            populateAsciiFieldInfo(fieldInfo_[count], tagId, attributeName);
            TIFFMergeFieldInfo(output, fieldInfo_[count], 1);
            TIFFSetField(this->output, tagId, tagString);
            ++count;
            ++tagId;
            if ((tagId == TIFFTAG_END_) || (count > numAttributes_)) {
                asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                    "%s:%s error, Too many tags/attributes for file. tagId: %d, count: %d\n",
                    driverName, functionName, tagId, count);
                break;
            }
        }
        pAttribute = this->pFileAttributes->next(pAttribute);
    }
    
    return(asynSuccess);
}
/** 
  * \param[in] pArray  The NDArray from the callback.
  */
void NDPluginAttribute::processCallbacks(NDArray *pArray)
{
  /*
     * This function is called with the mutex already locked.  It unlocks it during long calculations when private
     * structures don't need to be protected.
     */

  int status = 0;
  int dataType;
  char attrName[MAX_ATTR_NAME_] = {0};
  NDAttribute *pAttribute = NULL;
  NDAttributeList *pAttrList = NULL;
  epicsFloat64 attrValue = 0.0;
  epicsFloat64 updatePeriod = 0.0;

  static const char *functionName = "NDPluginAttribute::processCallbacks";
  
  asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
      "Starting %s. currentPoint_: %d\n", functionName, currentPoint_);

  /* Get the time and decide if we update the array.*/
  getDoubleParam(NDPluginAttributeUpdatePeriod, &updatePeriod);
  epicsTimeGetCurrent(&nowTime_);
  nowTimeSecs_ = nowTime_.secPastEpoch + (nowTime_.nsec / 1.e9);
  if ((nowTimeSecs_ - lastTimeSecs_) < (updatePeriod / 1000.0)) {
    arrayUpdate_ = 0;
  } else {
    arrayUpdate_ = 1;
    lastTimeSecs_ = nowTimeSecs_;
  }
 
  /* Get all parameters while we have the mutex */
  getIntegerParam(NDPluginAttributeDataType,    &dataType);

  /* Call the base class method */
  NDPluginDriver::processCallbacks(pArray);
  
  /* Get the attributes for this driver */
  pAttrList = pArray->pAttributeList;
  getStringParam(NDPluginAttributeAttrName, MAX_ATTR_NAME_, attrName);
  
  asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "Finding the attribute %s\n", attrName);
  pAttribute = pAttrList->find(attrName);
  if (pAttribute) {
    status = pAttribute->getValue(NDAttrFloat64, &attrValue);
    asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "Attribute %s is %f\n", attrName, attrValue);
    if (status == asynSuccess) {
      setDoubleParam(NDPluginAttributeVal, attrValue);
      valueSum_ = valueSum_ + attrValue;
      setDoubleParam(NDPluginAttributeValSum, valueSum_);
      if (currentPoint_ < maxTimeSeries_) {
          pTimeSeries_[currentPoint_] = attrValue;
          ++currentPoint_;
      }
    }

    callParamCallbacks();
    if (arrayUpdate_) {
      doCallbacksFloat64Array(this->pTimeSeries_, currentPoint_, NDPluginAttributeArray, 0);
    }

  } else {
    asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s: Error reading NDAttribute %s. \n", functionName, attrName);
  }

  

}