Move parse of cfgStr to ecmcFFT, allow several ecmcFFT objects, use exceptions for errors.
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
#include "ecmcDataItem.h"
|
||||
#include "ecmcAsynPortDriver.h"
|
||||
#include "inttypes.h"
|
||||
#include <stdexcept>
|
||||
|
||||
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,
|
||||
|
||||
@@ -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_ */
|
||||
@@ -14,43 +14,40 @@
|
||||
// Needed to get headers in ecmc right...
|
||||
#define ECMC_IS_PLUGIN
|
||||
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
#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<ecmcFFT*> 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<ecmcFFT*>::iterator pfft = ffts.begin(); pfft != ffts.end(); ++pfft) {
|
||||
if(*pfft) {
|
||||
delete *pfft;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -23,17 +23,11 @@ extern "C" {
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user