Esempio n. 1
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;
}
Esempio n. 2
0
/** Handles the logic for when NDFileCapture changes state, starting or stopping capturing or streaming NDArrays
  * to a file.
  * \param[in] capture Flag to start or stop capture; 1=start capture, 0=stop capture. */
asynStatus NDPluginFile::doCapture(int capture) 
{
    /* This function is called from write32 whenever capture is started or stopped */
    asynStatus status = asynSuccess;
    int fileWriteMode;
    NDArray *pArray = this->pArrays[0];
    NDArrayInfo_t arrayInfo;
    int i;
    int numCapture;
    static const char* functionName = "doCapture";

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

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

    switch(fileWriteMode) {
        case NDFileModeSingle:
            /* It is an error to set capture=1 in this mode, set to 0 */
            setIntegerParam(NDFileCapture, 0);
            break;
        case NDFileModeCapture:
            if (capture) {
                /* Capturing was just started */
                setIntegerParam(NDFileNumCaptured, 0);
                if (!pArray) {
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                        "%s::%s ERROR: No arrays collected: cannot allocate capture buffer\n",
                        driverName, functionName);
                    return(asynError);
                }
                pArray->getInfo(&arrayInfo);
                this->registerInitFrameInfo(pArray);
                this->pCapture = (NDArray **)calloc(numCapture, sizeof(NDArray *));
                if (!this->pCapture) {
                    asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                        "%s::%s ERROR: cannot allocate capture buffer\n",
                        driverName, functionName);
                    setIntegerParam(NDFileCapture, 0);
                    return(asynError);
                }
                for (i=0; i<numCapture; i++) {
                    pCapture[i] = new NDArray;
                    if (!this->pCapture[i]) {
                        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                            "%s::%s ERROR: cannot allocate capture buffer %d\n",
                            driverName, functionName, i);
                        setIntegerParam(NDFileCapture, 0);
                        freeCaptureBuffer(numCapture);
                        return(asynError);
                    }
                    this->pCapture[i]->dataSize = arrayInfo.totalBytes;
                    this->pCapture[i]->pData = malloc(arrayInfo.totalBytes);
                    this->pCapture[i]->ndims = pArray->ndims;
                    if (!this->pCapture[i]->pData) {
                        asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
                            "%s::%s ERROR: cannot allocate capture array for buffer %d\n",
                            driverName, functionName, i);
                        setIntegerParam(NDFileCapture, 0);
                        freeCaptureBuffer(numCapture);
                        return(asynError);
                    }
                }
            } else {
                /* Stop capturing, nothing to do, setting the parameter is all that is needed */
            }
            break;
        case NDFileModeStream:
            if (capture) {
                /* Streaming was just started */
                if (this->supportsMultipleArrays && !this->useAttrFilePrefix && !this->lazyOpen)
                    status = this->openFileBase(NDFileModeWrite | NDFileModeMultiple, pArray);
                setIntegerParam(NDFileNumCaptured, 0);
                setIntegerParam(NDWriteFile, 1);
            } else {
                /* Streaming was just stopped */
                if (this->supportsMultipleArrays)
                    status = this->closeFileBase();
                setIntegerParam(NDFileCapture, 0);
                setIntegerParam(NDWriteFile, 0);
            }
    }
    return(status);
}
Esempio n. 3
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;
    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);
}