Initial commint (based on fft plugin, still sources left)

This commit is contained in:
Anders Sandstrom
2021-03-01 10:52:10 +01:00
commit f36c6b3f48
27 changed files with 2174 additions and 0 deletions

View File

@@ -0,0 +1,62 @@
#
# Copyright (c) 2019 European Spallation Source ERIC
#
# The program is free software: you can redistribute
# it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 2 of the
# License, or any newer version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see https://www.gnu.org/licenses/gpl-2.0.txt
#
#
# Author : anderssandstrom
# email : anderssandstrom@esss.se
# Date : 2020Mar22-1607-33CET
# version : 0.0.0
#
# template file is generated by ./e3TemplateGenerator.bash with bf03d40
# Please look at many other _module_.Makefile in e3-* repository
#
## The following lines are mandatory, please don't change them.
where_am_I := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
include $(E3_REQUIRE_TOOLS)/driver.makefile
include $(E3_REQUIRE_CONFIG)/DECOUPLE_FLAGS
ifneq ($(strip $(ASYN_DEP_VERSION)),)
asyn_VERSION=$(ASYN_DEP_VERSION)
endif
ifneq ($(strip $(ECMC_DEP_VERSION)),)
ecmc_VERSION=$(ECMC_DEP_VERSION)
endif
APP:=ecmc_plugin_fftApp
APPDB:=$(APP)/Db
APPSRC:=$(APP)/src
USR_CFLAGS += -shared -fPIC -Wall -Wextra
USR_LDFLAGS += -lstdc++
USR_INCLUDES += -I$(where_am_I)$(APPSRC)
TEMPLATES += $(wildcard $(APPDB)/*.db)
TEMPLATES += $(wildcard $(APPDB)/*.template)
SOURCES += $(APPSRC)/ecmcPluginFFT.c
SOURCES += $(APPSRC)/ecmcFFTWrap.cpp
SOURCES += $(APPSRC)/ecmcFFT.cpp
db:
.PHONY: db
vlibs:
.PHONY: vlibs
###

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,153 @@
/*************************************************************************\
* 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.
*
* ecmcFFT.h
*
* Created on: Mar 22, 2020
* Author: anderssandstrom
*
\*************************************************************************/
#ifndef ECMC_FFT_H_
#define ECMC_FFT_H_
#include <stdexcept>
#include "ecmcDataItem.h"
#include "ecmcAsynPortDriver.h"
#include "ecmcFFTDefs.h"
#include "inttypes.h"
#include <string>
#include "kissfft/kissfft.hh"
class ecmcFFT : public asynPortDriver {
public:
/** ecmc FFT class
* This object can throw:
* - bad_alloc
* - invalid_argument
* - runtime_error
* - out_of_range
*/
ecmcFFT(int fftIndex, // index of this object
char* configStr,
char* portName);
~ecmcFFT();
// Add data to buffer (called from "external" callback)
void dataUpdatedCallback(uint8_t* data,
size_t size,
ecmcEcDataType dt);
// Call just before realtime because then all data sources should be available
void connectToDataSource();
void setEnable(int enable);
void setModeFFT(FFT_MODE mode);
FFT_STATUS getStatusFFT();
void clearBuffers();
void triggFFT();
void doCalcWorker(); // Called from worker thread calc the results
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value,
size_t nElements, size_t *nIn);
virtual asynStatus readInt8Array(asynUser *pasynUser, epicsInt8 *value,
size_t nElements, size_t *nIn);
virtual asynStatus readFloat64(asynUser *pasynUser, epicsFloat64 *value);
private:
void parseConfigStr(char *configStr);
void addDataToBuffer(double data);
void calcFFT();
void scaleFFT();
void calcFFTAmp();
void calcFFTXAxis();
void removeDCOffset();
void removeLin();
void initAsyn();
void updateStatus(FFT_STATUS status); // Also updates asynparam
static int dataTypeSupported(ecmcEcDataType dt);
ecmcDataItem *dataItem_;
ecmcDataItemInfo *dataItemInfo_;
ecmcAsynPortDriver *asynPort_;
kissfft<double>* fftDouble_;
double* rawDataBuffer_; // Input data (real)
double* prepProcDataBuffer_; // Preprocessed data (real)
std::complex<double>* fftBufferInput_; // Result (complex)
std::complex<double>* fftBufferResult_; // Result (complex)
double* fftBufferResultAmp_; // Resulting amplitude (abs of fftBufferResult_)
double* fftBufferXAxis_; // FFT x axis with freqs
size_t elementsInBuffer_;
double ecmcSampleRateHz_;
int dataSourceLinked_; // To avoid link several times
// ecmc callback handle for use when deregister at unload
int callbackHandle_;
int fftWaitingForCalc_;
int destructs_;
int objectId_; // Unique object id
int triggOnce_;
int cycleCounter_;
int ignoreCycles_;
double scale_; // Config: Data set size
FFT_STATUS status_; // Status/state (NO_STAT, IDLE, ACQ, CALC)
// Config options
char* cfgDataSourceStr_; // Config: data source string
int cfgDbgMode_; // Config: allow dbg printouts
int cfgApplyScale_; // Config: apply scale 1/nfft
int cfgDcRemove_; // Config: remove dc (average)
int cfgLinRemove_; // Config: remove linear componet (by least square)
size_t cfgNfft_; // Config: Data set size
int cfgEnable_; // Config: Enable data acq./calc.
FFT_MODE cfgMode_; // Config: Mode continous or triggered.
double cfgFFTSampleRateHz_; // Config: Sample rate (defaults to ecmc rate)
double cfgScale_;
double cfgDataSampleRateHz_; // Config: Sample for data
// Asyn
int asynEnableId_; // Enable/disable acq./calcs
int asynRawDataId_; // Raw data (input) array (double)
int asynPPDataId_; // Pre-processed data array (double)
int asynFFTAmpId_; // FFT amplitude array (double)
int asynFFTModeId_; // FFT mode (cont/trigg)
int asynFFTStatId_; // FFT status (no_stat/idle/acq/calc)
int asynSourceId_; // SOURCE
int asynTriggId_; // Trigg new measurement
int asynFFTXAxisId_; // FFT X-axis frequencies
int asynNfftId_; // NFFT
int asynSRateId_; // Sample rate
int asynElementsInBuffer_; // Current buffer index
// Thread related
epicsEvent doCalcEvent_;
// Some generic 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 void printEcDataArray(uint8_t* data,
size_t size,
ecmcEcDataType dt,
int objId);
static void printComplexArray(std::complex<double>* fftBuff,
size_t elements,
int objId);
static std::string to_string(int value);
static int leastSquare(int n,
const double y[],
double* k,
double* m); // y=kx+m
};
#endif /* ECMC_FFT_H_ */

View File

@@ -0,0 +1,54 @@
/*************************************************************************\
* 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_PRINT_OPTION_CMD "DBG_PRINT="
#define ECMC_PLUGIN_SOURCE_OPTION_CMD "SOURCE="
#define ECMC_PLUGIN_NFFT_OPTION_CMD "NFFT="
//#define ECMC_PLUGIN_APPLY_SCALE_OPTION_CMD "APPLY_SCALE="
#define ECMC_PLUGIN_RM_DC_OPTION_CMD "RM_DC="
#define ECMC_PLUGIN_ENABLE_OPTION_CMD "ENABLE="
#define ECMC_PLUGIN_RATE_OPTION_CMD "RATE="
#define ECMC_PLUGIN_RM_LIN_OPTION_CMD "RM_LIN="
#define ECMC_PLUGIN_SCALE_OPTION_CMD "SCALE="
// CONT, TRIGG
#define ECMC_PLUGIN_MODE_OPTION_CMD "MODE="
#define ECMC_PLUGIN_MODE_CONT_OPTION "CONT"
#define ECMC_PLUGIN_MODE_TRIGG_OPTION "TRIGG"
typedef enum FFT_MODE{
NO_MODE = 0,
CONT = 1,
TRIGG = 2,
} FFT_MODE;
typedef enum FFT_STATUS{
NO_STAT = 0,
IDLE = 1, // Doing nothing, waiting for trigg
ACQ = 2, // Acquireing data
CALC = 3, // Calc FFT
} FFT_STATUS;
/** Just one error code in "c" part of plugin
(error handled with exceptions i c++ part) */
#define ECMC_PLUGIN_FFT_ERROR_CODE 1
// Default size (must be n²)
#define ECMC_PLUGIN_DEFAULT_NFFT 4096
#endif /* ECMC_FFT_DEFS_H_ */

View File

@@ -0,0 +1,133 @@
/*************************************************************************\
* 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.
*
* ecmcFFTWrap.cpp
*
* Created on: Mar 22, 2020
* Author: anderssandstrom
* Credits to https://github.com/sgreg/dynamic-loading
*
\*************************************************************************/
// Needed to get headers in ecmc right...
#define ECMC_IS_PLUGIN
#include <vector>
#include <stdexcept>
#include <string>
#include "ecmcFFTWrap.h"
#include "ecmcFFT.h"
#include "ecmcFFTDefs.h"
#define ECMC_PLUGIN_MAX_PORTNAME_CHARS 64
#define ECMC_PLUGIN_PORTNAME_PREFIX "PLUGIN.FFT"
static std::vector<ecmcFFT*> ffts;
static int fftObjCounter = 0;
static char portNameBuffer[ECMC_PLUGIN_MAX_PORTNAME_CHARS];
int createFFT(char* configStr) {
// create new ecmcFFT object
ecmcFFT* fft = NULL;
// create asynport name for new object ()
memset(portNameBuffer, 0, ECMC_PLUGIN_MAX_PORTNAME_CHARS);
snprintf (portNameBuffer, ECMC_PLUGIN_MAX_PORTNAME_CHARS,
ECMC_PLUGIN_PORTNAME_PREFIX "%d", fftObjCounter);
try {
fft = new ecmcFFT(fftObjCounter, configStr, portNameBuffer);
}
catch(std::exception& e) {
if(fft) {
delete fft;
}
printf("Exception: %s. Plugin will unload.\n",e.what());
return ECMC_PLUGIN_FFT_ERROR_CODE;
}
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);
}
}
}
int linkDataToFFTs() {
for(std::vector<ecmcFFT*>::iterator pfft = ffts.begin(); pfft != ffts.end(); ++pfft) {
if(*pfft) {
try {
(*pfft)->connectToDataSource();
}
catch(std::exception& e) {
printf("Exception: %s. Plugin will unload.\n",e.what());
return ECMC_PLUGIN_FFT_ERROR_CODE;
}
}
}
return 0;
}
int enableFFT(int fftIndex, int enable) {
try {
ffts.at(fftIndex)->setEnable(enable);
}
catch(std::exception& e) {
printf("Exception: %s. FFT index out of range.\n",e.what());
return ECMC_PLUGIN_FFT_ERROR_CODE;
}
return 0;
}
int clearFFT(int fftIndex) {
try {
ffts.at(fftIndex)->clearBuffers();
}
catch(std::exception& e) {
printf("Exception: %s. FFT index out of range.\n",e.what());
return ECMC_PLUGIN_FFT_ERROR_CODE;
}
return 0;
}
int triggFFT(int fftIndex) {
try {
ffts.at(fftIndex)->triggFFT();
}
catch(std::exception& e) {
printf("Exception: %s. FFT index out of range.\n",e.what());
return ECMC_PLUGIN_FFT_ERROR_CODE;
}
return 0;
}
int modeFFT(int fftIndex, FFT_MODE mode) {
try {
ffts.at(fftIndex)->setModeFFT(mode);
}
catch(std::exception& e) {
printf("Exception: %s. FFT index out of range.\n",e.what());
return ECMC_PLUGIN_FFT_ERROR_CODE;
}
return 0;
}
FFT_STATUS statFFT(int fftIndex) {
try {
return ffts.at(fftIndex)->getStatusFFT();
}
catch(std::exception& e) {
printf("Exception: %s. FFT index out of range.\n",e.what());
return NO_STAT;
}
return NO_STAT;
}

View File

@@ -0,0 +1,112 @@
/*************************************************************************\
* 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.
*
* ecmcFFTWrap.h
*
* Created on: Mar 22, 2020
* Author: anderssandstrom
*
\*************************************************************************/
#ifndef ECMC_FFT_WRAP_H_
#define ECMC_FFT_WRAP_H_
#include "ecmcFFTDefs.h"
# ifdef __cplusplus
extern "C" {
# endif // ifdef __cplusplus
/** \brief Create new FFT object
*
* The plugin supports creation of multiple FFT objects\n
* (if loaded several times).\n
* The different fft are adressed by fftindex (in other functions below).\n
* The first loaded fft get index 0 and then increases for each load.\n
* This function call will create the custom asynparameters dedicated for this plugin.\
* The configuration string needs to define a data source by:\n
* "SOURCE=<data source>;"\n
* Example:\n
* "SOURCE=ec0.s1.AI_1";\n
* \param[in] configStr Configuration string.\n
*
* \return 0 if success or otherwise an error code.\n
*/
int createFFT(char *configStr);
/** \brief Enable/disable FFT object
*
* Enable/disable FFT object. If disabled no data will be acquired\n
* and no calculations will be made.\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
* \param[in] enable enable/disable (1/0).\n
*
* \return 0 if success or otherwise an error code.\n
*/
int enableFFT(int fftIndex, int enable);
/** \brief Clear FFT object\n
*
* Clears buffers. After this command the acquistion can start from scratch.\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
*
* \return 0 if success or otherwise an error code.\n
*/
int clearFFT(int fftIndex);
/** \brief Set mode of FFT object
*
* The FFT object can measure in two differnt modes:\n
* CONT(1) : Continious measurement (Acq data, calc, then Acq data ..)\n
* TRIGG(2): Measurements are triggered from plc or over asyn and is only done once (untill next trigger)\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
* \param[in] mode Mode CONT(1) or TRIGG(2)\n
*
* \return 0 if success or otherwise an error code.\n
*/
int modeFFT(int fftIndex, FFT_MODE mode);
/** \brief Trigger FFT object\n
*
* If in triggered mode a new measurment cycle is initiated (fft will be cleared first).\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
*
* \return 0 if success or otherwise an error code.\n
*/
int triggFFT(int fftIndex);
/** \brief Get status of FFT object
*
* The FFT object can be in different states:\n
* NO_STAT(0): Invalid state (something is most likely wrong)\n
* IDLE(1) : Waiting for trigger in triggered mode\n
* ACQ(2) : Acquiring data (filling data buffer)\n
* CALC(3) : Calculating FFT results\n
* \param[in] fftIndex Index of fft (first loaded fft have index 0 then increases)\n
*
* \return Status of fft (if index is out of range NO_STAT will be returned).\n
*/
FFT_STATUS statFFT(int fftIndex);
/** \brief Link data to _all_ fft objects
*
* This tells the FFT lib to connect to ecmc to find it's data source.\n
* This function should be called just before entering realtime since then all\n
* data sources in ecmc will be definded (plc sources are compiled just before runtime\n
* so are only fist accesible now).\n
* \return 0 if success or otherwise an error code.\n
*/
int linkDataToFFTs();
/** \brief Deletes all created fft objects\n
*
* Should be called when destructs.\n
*/
void deleteAllFFTs();
# ifdef __cplusplus
}
# endif // ifdef __cplusplus
#endif /* ECMC_FFT_WRAP_H_ */

View File

@@ -0,0 +1,301 @@
/*************************************************************************\
* 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.
*
* ecmcPluginExample.cpp
*
* Created on: Mar 21, 2020
* Author: anderssandstrom
*
\*************************************************************************/
// Needed to get headers in ecmc right...
#define ECMC_IS_PLUGIN
#define ECMC_EXAMPLE_PLUGIN_VERSION 2
#ifdef __cplusplus
extern "C" {
#endif // ifdef __cplusplus
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ecmcPluginDefs.h"
#include "ecmcFFTDefs.h"
#include "ecmcFFTWrap.h"
static int lastEcmcError = 0;
static char* lastConfStr = NULL;
/** Optional.
* Will be called once after successfull load into ecmc.
* Return value other than 0 will be considered error.
* configStr can be used for configuration parameters.
**/
int fftConstruct(char *configStr)
{
//This module is allowed to load several times so no need to check if loaded
// create FFT object and register data callback
lastConfStr = strdup(configStr);
return createFFT(configStr);
}
/** Optional function.
* Will be called once at unload.
**/
void fftDestruct(void)
{
deleteAllFFTs();
if(lastConfStr){
free(lastConfStr);
}
}
/** Optional function.
* Will be called each realtime cycle if definded
* ecmcError: Error code of ecmc. Makes it posible for
* this plugin to react on ecmc errors
* Return value other than 0 will be considered to be an error code in ecmc.
**/
int fftRealtime(int ecmcError)
{
lastEcmcError = ecmcError;
return 0;
}
/** Link to data source here since all sources should be availabe at this stage
* (for example ecmc PLC variables are defined only at enter of realtime)
**/
int fftEnterRT(){
return linkDataToFFTs();
}
/** Optional function.
* Will be called once just before leaving realtime mode
* Return value other than 0 will be considered error.
**/
int fftExitRT(void){
return 0;
}
// Plc function for clear of buffers
double fft_clear(double index) {
return (double)clearFFT((int)index);
}
// Plc function for enable
double fft_enable(double index, double enable) {
return (double)enableFFT((int)index, (int)enable);
}
// Plc function for trigg new measurement (will clear buffers)
double fft_trigg(double index) {
return (double)triggFFT((int)index);
}
// Plc function for enable
double fft_mode(double index, double mode) {
return (double)modeFFT((int)index, (FFT_MODE)((int)mode));
}
// Plc function for enable
double fft_stat(double index) {
return (double)statFFT((int)index);
}
// Register data for plugin so ecmc know what to use
struct ecmcPluginData pluginDataDef = {
// Allways use ECMC_PLUG_VERSION_MAGIC
.ifVersion = ECMC_PLUG_VERSION_MAGIC,
// Name
.name = "ecmcPlugin_FFT",
// Description
.desc = "FFT plugin for use with ecmc.",
// Option description
.optionDesc = "\n "ECMC_PLUGIN_DBG_PRINT_OPTION_CMD"<1/0> : Enables/disables printouts from plugin, default = disabled.\n"
" "ECMC_PLUGIN_SOURCE_OPTION_CMD"<source> : Sets source variable for FFT (example: ec0.s1.AI_1).\n"
" "ECMC_PLUGIN_NFFT_OPTION_CMD"<nfft> : Data points to collect, default = 4096.\n"
" "ECMC_PLUGIN_SCALE_OPTION_CMD"scalefactor : Apply scale to source data, default = 1.0.\n"
" "ECMC_PLUGIN_RM_DC_OPTION_CMD"<1/0> : Remove DC offset of input data (SOURCE), default = disabled.\n"
" "ECMC_PLUGIN_RM_LIN_OPTION_CMD"<1/0> : Remove linear component in data (SOURCE) by least square, default = disabled.\n"
" "ECMC_PLUGIN_ENABLE_OPTION_CMD"<1/0> : Enable data acq. and calcs (can be controlled over asyn), default = disabled.\n"
" "ECMC_PLUGIN_MODE_OPTION_CMD"<CONT/TRIGG> : Continious or triggered mode, defaults to TRIGG\n"
" "ECMC_PLUGIN_RATE_OPTION_CMD"<rate in hz> : fft data sample rate in hz (must be lower than ecmc rate and (ecmc_rate/fft_rate)=integer), default = ecmc rate."
,
// Plugin version
.version = ECMC_EXAMPLE_PLUGIN_VERSION,
// Optional construct func, called once at load. NULL if not definded.
.constructFnc = fftConstruct,
// Optional destruct func, called once at unload. NULL if not definded.
.destructFnc = fftDestruct,
// Optional func that will be called each rt cycle. NULL if not definded.
.realtimeFnc = fftRealtime,
// Optional func that will be called once just before enter realtime mode
.realtimeEnterFnc = fftEnterRT,
// Optional func that will be called once just before exit realtime mode
.realtimeExitFnc = fftExitRT,
// PLC funcs
.funcs[0] =
{ /*----fft_clear----*/
// Function name (this is the name you use in ecmc plc-code)
.funcName = "fft_clear",
// Function description
.funcDesc = "double fft_clear(index) : Clear/reset fft[index].",
/**
* 7 different prototypes allowed (only doubles since reg in plc).
* Only funcArg${argCount} func shall be assigned the rest set to NULL.
**/
.funcArg0 = NULL,
.funcArg1 = fft_clear,
.funcArg2 = NULL,
.funcArg3 = NULL,
.funcArg4 = NULL,
.funcArg5 = NULL,
.funcArg6 = NULL,
.funcArg7 = NULL,
.funcArg8 = NULL,
.funcArg9 = NULL,
.funcArg10 = NULL,
.funcGenericObj = NULL,
},
.funcs[1] =
{ /*----fft_enable----*/
// Function name (this is the name you use in ecmc plc-code)
.funcName = "fft_enable",
// Function description
.funcDesc = "double fft_enable(index, enable) : Set enable for fft[index].",
/**
* 7 different prototypes allowed (only doubles since reg in plc).
* Only funcArg${argCount} func shall be assigned the rest set to NULL.
**/
.funcArg0 = NULL,
.funcArg1 = NULL,
.funcArg2 = fft_enable,
.funcArg3 = NULL,
.funcArg4 = NULL,
.funcArg5 = NULL,
.funcArg6 = NULL,
.funcArg7 = NULL,
.funcArg8 = NULL,
.funcArg9 = NULL,
.funcArg10 = NULL,
.funcGenericObj = NULL,
},
.funcs[2] =
{ /*----fft_trigg----*/
// Function name (this is the name you use in ecmc plc-code)
.funcName = "fft_trigg",
// Function description
.funcDesc = "double fft_trigg(index) : Trigg new measurement for fft[index]. Will clear buffers.",
/**
* 7 different prototypes allowed (only doubles since reg in plc).
* Only funcArg${argCount} func shall be assigned the rest set to NULL.
**/
.funcArg0 = NULL,
.funcArg1 = fft_trigg,
.funcArg2 = NULL,
.funcArg3 = NULL,
.funcArg4 = NULL,
.funcArg5 = NULL,
.funcArg6 = NULL,
.funcArg7 = NULL,
.funcArg8 = NULL,
.funcArg9 = NULL,
.funcArg10 = NULL,
.funcGenericObj = NULL,
},
.funcs[3] =
{ /*----fft_mode----*/
// Function name (this is the name you use in ecmc plc-code)
.funcName = "fft_mode",
// Function description
.funcDesc = "double fft_mode(index, mode) : Set mode Cont(1)/Trigg(2) for fft[index].",
/**
* 7 different prototypes allowed (only doubles since reg in plc).
* Only funcArg${argCount} func shall be assigned the rest set to NULL.
**/
.funcArg0 = NULL,
.funcArg1 = NULL,
.funcArg2 = fft_mode,
.funcArg3 = NULL,
.funcArg4 = NULL,
.funcArg5 = NULL,
.funcArg6 = NULL,
.funcArg7 = NULL,
.funcArg8 = NULL,
.funcArg9 = NULL,
.funcArg10 = NULL,
.funcGenericObj = NULL,
},
.funcs[4] =
{ /*----fft_stat----*/
// Function name (this is the name you use in ecmc plc-code)
.funcName = "fft_stat",
// Function description
.funcDesc = "double fft_stat(index) : Get status of fft (NO_STAT, IDLE, ACQ, CALC) for fft[index].",
/**
* 7 different prototypes allowed (only doubles since reg in plc).
* Only funcArg${argCount} func shall be assigned the rest set to NULL.
**/
.funcArg0 = NULL,
.funcArg1 = fft_stat,
.funcArg2 = NULL,
.funcArg3 = NULL,
.funcArg4 = NULL,
.funcArg5 = NULL,
.funcArg6 = NULL,
.funcArg7 = NULL,
.funcArg8 = NULL,
.funcArg9 = NULL,
.funcArg10 = NULL,
.funcGenericObj = NULL,
},
.funcs[5] = {0}, // last element set all to zero..
// PLC consts
/* CONTINIOUS MODE = 1 */
.consts[0] = {
.constName = "fft_CONT",
.constDesc = "FFT Mode: Continious",
.constValue = CONT
},
/* TRIGGERED MODE = 2 */
.consts[1] = {
.constName = "fft_TRIGG",
.constDesc = "FFT Mode :Triggered",
.constValue = TRIGG
},
/* TRIGGERED MODE = 2 */
.consts[2] = {
.constName = "fft_NO_STAT",
.constDesc = "FFT Status: Invalid state",
.constValue = NO_STAT,
},
/* TRIGGERED MODE = 2 */
.consts[3] = {
.constName = "fft_IDLE",
.constDesc = "FFT Status: Idle state (waiting for trigger)",
.constValue = IDLE
},
/* TRIGGERED MODE = 2 */
.consts[4] = {
.constName = "fft_ACQ",
.constDesc = "FFT Status: Acquiring data",
.constValue = ACQ
},
/* TRIGGERED MODE = 2 */
.consts[5] = {
.constName = "fft_CALC",
.constDesc = "FFT Status: Calculating result",
.constValue = CALC
},
.consts[6] = {0}, // last element set all to zero..
};
ecmc_plugin_register(pluginDataDef);
# ifdef __cplusplus
}
# endif // ifdef __cplusplus