Move parse of cfgStr to ecmcFFT, allow several ecmcFFT objects, use exceptions for errors.

This commit is contained in:
Anders Sandström
2020-04-04 19:25:31 +02:00
parent ef993123fe
commit 453365794c
6 changed files with 174 additions and 163 deletions
@@ -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;
}