Exemple #1
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;
}
Exemple #2
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;
}
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);
}
Exemple #4
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);
}
Exemple #5
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);
}