diff --git a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFT.cpp b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFT.cpp index b67e8fb..3f4c7a3 100644 --- a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFT.cpp +++ b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFT.cpp @@ -14,12 +14,11 @@ // Needed to get headers in ecmc right... #define ECMC_IS_PLUGIN -#define ECMC_PLUGIN_ERROR_FFT_BASE 100 -#define ECMC_PLUGIN_ERROR_FFT_ALLOC_FAIL 101 -#define ECMC_PLUGIN_ERROR_FFT_DATATYPE_NOT_SUPPORTED 102 - #include "ecmcFFT.h" - +#include "ecmcFFTDefs.h" +#include "ecmcPluginClient.h" +#include "ecmcAsynPortDriver.h" +#include "kissfft/kissfft.hh" // New data callback from ecmc static int printMissingObjError = 1; @@ -40,49 +39,104 @@ void f_dataUpdatedCallback(uint8_t* data, size_t size, ecmcEcDataType dt, void* } -// ecmc FFT class -ecmcFFT::ecmcFFT(ecmcDataItem* dataItem, ecmcAsynPortDriver* asynPort, size_t nfft) { +/** ecmc FFT class + *can throw: + * bad_alloc + * invalid_argument + * runtime_error +*/ +ecmcFFT::ecmcFFT(int fftIndex, // index of this object + char* configStr) { + dataSourceStr_ = NULL; + dataBuffer_ = NULL; + dataItem_ = NULL; bufferSizeBytes_ = 0; bytesInBuffer_ = 0; - dataItem_ = dataItem; - asynPort_ = asynPort; - nfft_ = nfft; - dataBuffer_ = NULL; - errorId_ = 0; + dbgMode_ = 0; + callbackHandle_ = -1; + objectId_ = fftIndex; + nfft_ = ECMC_PLUGIN_DEFAULT_NFFT; // samples in fft (must be n^2) + asynPort_ = (ecmcAsynPortDriver*) getEcmcAsynPortDriver(); + if(!asynPort_) { + throw std::runtime_error("Asyn port NULL"); + } + + parseConfigStr(configStr); + connectToDataSource(); - // Allocate buffer bufferSizeBytes_ = nfft_ * dataItem_->getEcmcDataElementSize(); - dataBuffer_ = new uint8_t[bufferSizeBytes_]; - - if(!dataBuffer_) { - printf("%s/%s:%d: Error: Failed allocate dataBuffer of size %d (0x%x).\n", - __FILE__, __FUNCTION__, __LINE__, bufferSizeBytes_, ECMC_PLUGIN_ERROR_FFT_ALLOC_FAIL); - errorId_ = ECMC_PLUGIN_ERROR_FFT_ALLOC_FAIL; - return; - } - + dataBuffer_ = new uint8_t[bufferSizeBytes_]; clearBuffer(); - - if( !dataTypeSupported(dataItem_->getEcmcDataType()) ) { - errorId_ = ECMC_PLUGIN_ERROR_FFT_DATATYPE_NOT_SUPPORTED; - return; - } - - errorId_ = connectToDataSource(); - if(errorId_) { - return; - } } ecmcFFT::~ecmcFFT() { if(dataBuffer_) { delete[] dataBuffer_; } + // De regeister callback when unload + if(callbackHandle_ >= 0) { + dataItem_->deregDataUpdatedCallback(callbackHandle_); + } + if(dataSourceStr_) { + free(dataSourceStr_); + } +} + +int ecmcFFT::parseConfigStr(char *configStr) { + + // check config parameters + if (configStr && configStr[0]) { + char *pOptions = strdup(configStr); + char *pThisOption = pOptions; + char *pNextOption = pOptions; + + while (pNextOption && pNextOption[0]) { + pNextOption = strchr(pNextOption, ';'); + if (pNextOption) { + *pNextOption = '\0'; /* Terminate */ + pNextOption++; /* Jump to (possible) next */ + } + + // ECMC_PLUGIN_DBG_OPTION_CMD + if (!strncmp(pThisOption, ECMC_PLUGIN_DBG_OPTION_CMD, strlen(ECMC_PLUGIN_DBG_OPTION_CMD))) { + pThisOption += strlen(ECMC_PLUGIN_DBG_OPTION_CMD); + dbgMode_ = atoi(pThisOption); + } + + // ECMC_PLUGIN_SOURCE_OPTION_CMD + else if (!strncmp(pThisOption, ECMC_PLUGIN_SOURCE_OPTION_CMD, strlen(ECMC_PLUGIN_SOURCE_OPTION_CMD))) { + pThisOption += strlen(ECMC_PLUGIN_SOURCE_OPTION_CMD); + // get string to next ';' + dataSourceStr_=strdup(pThisOption); + } + pThisOption = pNextOption; + } + free(pOptions); + } + if(!dataSourceStr_) { + throw std::invalid_argument( "Data source not defined."); + } } int ecmcFFT::connectToDataSource() { - //Register data callback - return dataItem_->regDataUpdatedCallback(f_dataUpdatedCallback, this); + // Get dataItem + dataItem_ = (ecmcDataItem*) getEcmcDataItem(dataSourceStr_); + if(!dataItem_) { + throw std::runtime_error("Data item NULL"); + } + + // Register data callback + callbackHandle_ = dataItem_->regDataUpdatedCallback(f_dataUpdatedCallback, this); + if (callbackHandle_ < 0) { + callbackHandle_ = -1; + throw std::runtime_error( "Failed to register data source callback."); + } + + // Check data source + if( !dataTypeSupported(dataItem_->getEcmcDataType()) ) { + throw std::invalid_argument( "Data type not supported"); + } + return 0; } void ecmcFFT::dataUpdatedCallback(uint8_t* data, @@ -93,10 +147,11 @@ void ecmcFFT::dataUpdatedCallback(uint8_t* data, return; } - //printData(data,size,dt); + printf("fft id: %d, data: ",objectId_); + printData(data,size,dt); if(bytesInBuffer_ == bufferSizeBytes_) { - printf("Buffer full (%d bytes appended).\n",bytesInBuffer_); + printf("Buffer full (%zu bytes appended).\n",bytesInBuffer_); } // Start to fill buffer @@ -124,7 +179,6 @@ void ecmcFFT::printData(uint8_t* data, size_t dataElementSize = getEcDataTypeByteSize(dt); uint8_t *pData = data; - for(unsigned int i = 0; i < size / dataElementSize; ++i) { switch(dt) { case ECMC_EC_U8: diff --git a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFT.h b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFT.h index a98a7f2..bc0d35e 100644 --- a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFT.h +++ b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFT.h @@ -17,12 +17,12 @@ #include "ecmcDataItem.h" #include "ecmcAsynPortDriver.h" #include "inttypes.h" +#include class ecmcFFT { public: - ecmcFFT(ecmcDataItem *dataItem, - ecmcAsynPortDriver* asynPort, - size_t nfft = ECMC_PLUGIN_DEFAULT_NFFT); + ecmcFFT(int fftIndex, // index of this object + char* configStr); ~ecmcFFT(); @@ -33,8 +33,8 @@ class ecmcFFT { size_t size, ecmcEcDataType dt); private: + int parseConfigStr(char *configStr); int connectToDataSource(); - void clearBuffer(); ecmcDataItem *dataItem_; ecmcAsynPortDriver *asynPort_; @@ -43,20 +43,26 @@ class ecmcFFT { size_t bufferSizeBytes_; size_t bytesInBuffer_; int errorId_; + int callbackHandle_; + int dbgMode_; //Allow dbg printouts + char* dataSourceStr_; + // A unique object id for this fft (if plugin is more than once) + int objectId_; static int dataTypeSupported(ecmcEcDataType dt); //Some utility functions - static uint8_t getUint8(uint8_t* data); - static int8_t getInt8(uint8_t* data); - static uint16_t getUint16(uint8_t* data); - static int16_t getInt16(uint8_t* data); - static uint32_t getUint32(uint8_t* data); - static int32_t getInt32(uint8_t* data); - static uint64_t getUint64(uint8_t* data); - static int64_t getInt64(uint8_t* data); - static float getFloat32(uint8_t* data); - static double getFloat64(uint8_t* data); - static size_t getEcDataTypeByteSize(ecmcEcDataType dt); + static uint8_t getUint8(uint8_t* data); + static int8_t getInt8(uint8_t* data); + static uint16_t getUint16(uint8_t* data); + static int16_t getInt16(uint8_t* data); + static uint32_t getUint32(uint8_t* data); + static int32_t getInt32(uint8_t* data); + static uint64_t getUint64(uint8_t* data); + static int64_t getInt64(uint8_t* data); + static float getFloat32(uint8_t* data); + static double getFloat64(uint8_t* data); + + static size_t getEcDataTypeByteSize(ecmcEcDataType dt); static void printData(uint8_t* data, size_t size, diff --git a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTDefs.h b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTDefs.h new file mode 100644 index 0000000..bca4205 --- /dev/null +++ b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTDefs.h @@ -0,0 +1,24 @@ +/*************************************************************************\ +* Copyright (c) 2019 European Spallation Source ERIC +* ecmc is distributed subject to a Software License Agreement found +* in file LICENSE that is included with this distribution. +* +* ecmcFFTDefs.h +* +* Created on: Mar 22, 2020 +* Author: anderssandstrom +* Credits to https://github.com/sgreg/dynamic-loading +* +\*************************************************************************/ + +#ifndef ECMC_FFT_DEFS_H_ +#define ECMC_FFT_DEFS_H_ + +// Options +#define ECMC_PLUGIN_DBG_OPTION_CMD "DBG_PRINT=" +#define ECMC_PLUGIN_SOURCE_OPTION_CMD "SOURCE=" + +// Just one error code in "c" part of plugin +#define ECMC_PLUGIN_FFT_ERROR_CODE 1 + +#endif /* ECMC_FFT_DEFS_H_ */ diff --git a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTWrap.cpp b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTWrap.cpp index c1f4466..be6e2c1 100644 --- a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTWrap.cpp +++ b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTWrap.cpp @@ -14,43 +14,40 @@ // Needed to get headers in ecmc right... #define ECMC_IS_PLUGIN +#include +#include #include "ecmcFFTWrap.h" #include "ecmcFFT.h" -#include "ecmcAsynPortDriver.h" -#include "ecmcPluginClient.h" +#include "ecmcFFTDefs.h" -static ecmcFFT* fft = NULL; -static ecmcDataItem* dataItem = NULL; -static ecmcAsynPortDriver* ecmcAsynPort = NULL; -static int dbgModeOption = 0; +static std::vector ffts; +static int fftObjCounter = 0; -int createFFT(char* source, int dbgMode) { - dbgModeOption = dbgMode; - // Get ecmcDataItem for source - dataItem = (ecmcDataItem*)getEcmcDataItem(source); - if(!dataItem) { - PRINT_IF_DBG_MODE("%s/%s:%d: Error: dataItem=NULL (source %s not found) (0x%x).\n", - __FILE__, __FUNCTION__, __LINE__, source, - ECMC_PLUGIN_ERROR_DATA_SOURCE_NULL); - return ECMC_PLUGIN_ERROR_DATA_SOURCE_NULL; - } - - // Get ecmcAsynPort - ecmcAsynPort = (ecmcAsynPortDriver*)getEcmcAsynPortDriver(); - if(!ecmcAsynPort) { - PRINT_IF_DBG_MODE("%s/%s:%d: Error: ecmcAsynPort NULL (0x%x).\n", - __FILE__, __FUNCTION__, __LINE__, ECMC_PLUGIN_ERROR_ASYNPORT_NULL); - return ECMC_PLUGIN_ERROR_ASYNPORT_NULL; - } +int createFFT(char* configStr) { // create new ecmcFFT object - fft = new ecmcFFT(dataItem, ecmcAsynPort); - if(!fft) { - PRINT_IF_DBG_MODE("%s/%s:%d: Error: ecmcFFT NULL (0x%x).\n", - __FILE__, __FUNCTION__, __LINE__, ECMC_PLUGIN_ERROR_FFT_NULL); - return ECMC_PLUGIN_ERROR_FFT_NULL; - } + ecmcFFT* fft = NULL; + try { + fft = new ecmcFFT(fftObjCounter, configStr); + } + catch(std::exception& e) { + if(fft) { + delete fft; + } + printf("Exception: %s.",e.what()); + return ECMC_PLUGIN_FFT_ERROR_CODE; + } - // Register callback - return fft->getErrorId(); + ffts.push_back(fft); + fftObjCounter++; + + return 0; +} + +void deleteAllFFTs() { + for(std::vector::iterator pfft = ffts.begin(); pfft != ffts.end(); ++pfft) { + if(*pfft) { + delete *pfft; + } + } } diff --git a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTWrap.h b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTWrap.h index f95fb84..32e8cd1 100644 --- a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTWrap.h +++ b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcFFTWrap.h @@ -16,23 +16,8 @@ extern "C" { # endif // ifdef __cplusplus -//Error codes -#define ECMC_PLUGIN_ERROR_WRAP_BASE 10 -#define ECMC_PLUGIN_ERROR_CONFIG_STR_PARSE_FAIL (ECMC_PLUGIN_ERROR_WRAP_BASE + 1) -#define ECMC_PLUGIN_ERROR_NO_SOURCE (ECMC_PLUGIN_ERROR_WRAP_BASE + 2) -#define ECMC_PLUGIN_ERROR_DATA_SOURCE_NULL (ECMC_PLUGIN_ERROR_WRAP_BASE + 3) -#define ECMC_PLUGIN_ERROR_ASYNPORT_NULL (ECMC_PLUGIN_ERROR_WRAP_BASE + 4) -#define ECMC_PLUGIN_ERROR_FFT_NULL (ECMC_PLUGIN_ERROR_WRAP_BASE + 5) - -#define PRINT_IF_DBG_MODE(fmt, ...) \ - { \ - if(dbgModeOption){ \ - printf(fmt, ## __VA_ARGS__); \ - } \ - } \ - - -int createFFT(char *source, int dbgMode); +int createFFT(char *source); +void deleteAllFFTs(); # ifdef __cplusplus } diff --git a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcPluginFFT.c b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcPluginFFT.c index 4073057..8014893 100644 --- a/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcPluginFFT.c +++ b/ecmcPlugin_FFT-loc/ecmcPlugin_FFTApp/src/ecmcPluginFFT.c @@ -23,17 +23,11 @@ extern "C" { #include #include "ecmcPluginDefs.h" -#include "ecmcPluginClient.h" +#include "ecmcFFTDefs.h" #include "ecmcFFTWrap.h" -//Options -#define ECMC_PLUGIN_DBG_OPTION_CMD "DBG_PRINT=" -#define ECMC_PLUGIN_SOURCE_OPTION_CMD "SOURCE=" - static int lastEcmcError = 0; -static char* confStr = NULL; -static int dbgModeOption = 0; -static char* source = NULL; +static char* lastConfStr = NULL; /** Optional. * Will be called once after successfull load into ecmc. @@ -42,52 +36,9 @@ static char* source = NULL; **/ int adv_exampleConstruct(char *configStr) { - PRINT_IF_DBG_MODE("%s/%s:%d: ConfigStr=\"%s\"...\n",__FILE__, __FUNCTION__, __LINE__,configStr); - // check config parameters - if (configStr && configStr[0]) { - char *pOptions = strdup(configStr); - char *pThisOption = pOptions; - char *pNextOption = pOptions; - PRINT_IF_DBG_MODE("%s/%s:%d: Error: "ECMC_PLUGIN_SOURCE_OPTION_CMD"NULL.\n", - __FILE__, __FUNCTION__, __LINE__); - while (pNextOption && pNextOption[0]) { - pNextOption = strchr(pNextOption, ';'); - if (pNextOption) { - *pNextOption = '\0'; /* Terminate */ - pNextOption++; /* Jump to (possible) next */ - } - - // ECMC_PLUGIN_DBG_OPTION_CMD - if (!strncmp(pThisOption, ECMC_PLUGIN_DBG_OPTION_CMD, strlen(ECMC_PLUGIN_DBG_OPTION_CMD))) { - pThisOption += strlen(ECMC_PLUGIN_DBG_OPTION_CMD); - dbgModeOption = atoi(pThisOption); - } - - // ECMC_PLUGIN_SOURCE_OPTION_CMD - else if (!strncmp(pThisOption, ECMC_PLUGIN_SOURCE_OPTION_CMD, strlen(ECMC_PLUGIN_SOURCE_OPTION_CMD))) { - pThisOption += strlen(ECMC_PLUGIN_SOURCE_OPTION_CMD); - // get string to next ';' - source=strdup(pThisOption); - } - pThisOption = pNextOption; - } - free(pOptions); - } - - //printout options - PRINT_IF_DBG_MODE("%s/%s:%d: %s%d, %s\"%s\"\n",__FILE__, - __FUNCTION__, __LINE__,ECMC_PLUGIN_DBG_OPTION_CMD, - dbgModeOption, ECMC_PLUGIN_SOURCE_OPTION_CMD, source); - - // Check that SOURCE are defined - if(!source) { - PRINT_IF_DBG_MODE("%s/%s:%d: Error: "ECMC_PLUGIN_SOURCE_OPTION_CMD"NULL (0x%x).\n", - __FILE__, __FUNCTION__, __LINE__, ECMC_PLUGIN_ERROR_NO_SOURCE); - return ECMC_PLUGIN_ERROR_NO_SOURCE; - } - // create FFT object and register data callback - return createFFT(source, dbgModeOption); + lastConfStr = strdup(configStr); + return createFFT(configStr); } /** Optional function. @@ -95,14 +46,9 @@ int adv_exampleConstruct(char *configStr) **/ void adv_exampleDestruct(void) { - PRINT_IF_DBG_MODE("%s/%s:%d...\n",__FILE__, __FUNCTION__, __LINE__); - - if(source) { - free(source); - } - - if(confStr){ - free(confStr); + deleteAllFFTs(); + if(lastConfStr){ + free(lastConfStr); } } @@ -131,7 +77,6 @@ int adv_exampleEnterRT(){ * Return value other than 0 will be considered error. **/ int adv_exampleExitRT(void){ - PRINT_IF_DBG_MODE("%s/%s:%d...\n",__FILE__, __FUNCTION__, __LINE__); return 0; }