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

17
.gitignore vendored Normal file
View File

@@ -0,0 +1,17 @@
*~
*-dev
modules.order
Module.symvers
Mkfile.old
core.*
#*
.#*
\#*
*.local
\#*
.cvsignore
*_old/
*PVs.list
*-loc/*.Makefile
ecmc_plugin_fft/*.Makefile
*__*

28
Makefile Normal file
View File

@@ -0,0 +1,28 @@
#
# Copyright (c) 2018 - 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 : Jeong Han Lee
# email : han.lee@esss.se
# Date : 2020Mar22-1607-33CET
# version : 1.0.0
TOP:=$(CURDIR)
include $(TOP)/configure/CONFIG
include $(TOP)/configure/RULES

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
e3-ecmc_plugin_socketcan
======
ESS Site-specific EPICS module : ecmcPlugin_socketcan

0
cmds/.keep Normal file
View File

11
configure/CONFIG Normal file
View File

@@ -0,0 +1,11 @@
#
VARS_EXCLUDES := $(.VARIABLES)
include $(TOP)/configure/RELEASE
include $(TOP)/configure/CONFIG_MODULE
E3_REQUIRE_LOCATION := $(EPICS_BASE)/$(E3_REQUIRE_NAME)/$(E3_REQUIRE_VERSION)
REQUIRE_CONFIG := $(E3_REQUIRE_LOCATION)/configure
include $(REQUIRE_CONFIG)/CONFIG

37
configure/CONFIG_MODULE Normal file
View File

@@ -0,0 +1,37 @@
#
EPICS_MODULE_NAME:=ecmc_plugin_socketcan
EPICS_MODULE_TAG:=master
#
E3_MODULE_VERSION:=master
# DEPENDENT MODULE VERSION
# For Example,
ECMC_DEP_VERSION:=6.3.0
ASYN_DEP_VERSION:=4.37.0
#DEVLIB2_DEP_VERSION:=2.9.0
#PCRE_DEP_VERSION:=8.41.0
#ADCORE_DEP_VERSION:=3.7.0
#ADSUPPORT_DEP_VERSION:=1.9.0
#LOKI_DEP_VERSION=1.0.0
#NDS_DEP_VERSION=2.3.3
#SIS8300DRV_DEP_VERSION=4.3.1
#SEQUENCER_DEP_VERSION=2.2.7
#
#
#E3_KMOD_SRC_PATH:=$(E3_MODULE_SRC_PATH)
#
# In most case, we don't need to touch the following variables.
#
E3_MODULE_NAME:=$(EPICS_MODULE_NAME)
E3_MODULE_SRC_PATH:=ecmc_plugin_fft
E3_MODULE_MAKEFILE:=$(EPICS_MODULE_NAME).Makefile
-include $(TOP)/configure/CONFIG_OPTIONS
# The definitions shown below can also be placed in an untracked CONFIG_MODULE.local
-include $(TOP)/configure/CONFIG_MODULE.local

6
configure/CONFIG_OPTIONS Normal file
View File

@@ -0,0 +1,6 @@
#
# WITH_PVA:=NO
#
# The definitions shown below can also be placed in an untracked CONFIG_OPTIONS.local
-include $(TOP)/configure/CONFIG_OPTIONS.local

11
configure/RELEASE Normal file
View File

@@ -0,0 +1,11 @@
#
EPICS_BASE:=${HOME}/epics/base-7.0.4
E3_REQUIRE_NAME:=require
E3_REQUIRE_VERSION:=3.3.0
# The definitions shown below can also be placed in an untracked RELEASE.local
-include $(TOP)/../../RELEASE.local
-include $(TOP)/../RELEASE.local
-include $(TOP)/configure/RELEASE.local

12
configure/RULES Normal file
View File

@@ -0,0 +1,12 @@
include $(REQUIRE_CONFIG)/RULES_E3
include $(REQUIRE_CONFIG)/DEFINES_FT
include $(REQUIRE_CONFIG)/RULES_PATCH
include $(REQUIRE_CONFIG)/RULES_E3_SITELIBS
include $(REQUIRE_CONFIG)/RULES_VLIBS
include $(REQUIRE_CONFIG)/RULES_VARS
include $(TOP)/configure/module/RULES_MODULE
-include $(TOP)/configure/module/RULES_DKMS_L

View File

@@ -0,0 +1,38 @@
# KMOD_NAME := mrf
# .PHONY: dkms_add
# dkms_add: conf
# $(MSI) -M name="$(E3_MODULE_NAME)" -M version="$(E3_MODULE_VERSION)" -M kmod_name="$(KMOD_NAME)" $(TOP)/dkms/dkms_with_msi.conf.in > $(TOP)/dkms/dkms_with_msi.conf
# $(QUIET) cat $(TOP)/dkms/dkms_with_msi.conf $(TOP)/dkms/dkms_without_msi.conf > $(TOP)/dkms/dkms.conf
# $(QUIET) install -m 644 $(TOP)/dkms/dkms.conf $(E3_KMOD_SRC_PATH)/
# $(SUDO) install -d /usr/src/$(E3_MODULE_NAME)-$(E3_MODULE_VERSION)
# $(SUDO) cp -r $(TOP)/$(E3_KMOD_SRC_PATH)/* /usr/src/$(E3_MODULE_NAME)-$(E3_MODULE_VERSION)/
# $(SUDO) $(DKMS) add $(DKMS_ARGS)
# setup:
# $(QUIET) $(SUDO2) 'echo KERNEL==\"uio*\", ATTR{name}==\"mrf-pci\", MODE=\"0666\" | tee /etc/udev/rules.d/99-$(KMOD_NAME).rules'
# $(QUIET) $(SUDO) /bin/udevadm control --reload-rules
# $(QUIET) $(SUDO) /bin/udevadm trigger
# $(QUIET) $(SUDO2) 'echo $(KMOD_NAME) | tee /etc/modules-load.d/$(KMOD_NAME).conf'
# $(QUIET) $(SUDO) depmod --quick
# $(QUIET) $(SUDO) modprobe -rv $(KMOD_NAME)
# $(QUIET) $(SUDO) modprobe -v $(KMOD_NAME)
# $(QUIET) echo ""
# $(QUIET) echo ""
# $(QUIET) echo "It is OK to see \"E3/RULES_DKMS:37: recipe for target 'setup' failed\""
# $(QUIET) echo "---------------------------------------------------------------------"
# $(QUIET) -ls -l /dev/uio* 2>/dev/null
# $(QUIET) echo "---------------------------------------------------------------------"
# setup_clean:
# $(QUIET) $(SUDO) modprobe -rv $(KMOD_NAME)
# $(SUDO) rm -f /etc/modules-load.d/$(KMOD_NAME).conf
# $(SUDO) rm -f /etc/udev/rules.d/99-$(KMOD_NAME).rules
# .PHONY: setup setup_clean

View File

@@ -0,0 +1,20 @@
#
.PHONY: db hdrs
db: conf
$(QUIET) $(E3_MODULE_MAKE_CMDS) db
hdrs:
# $(SUDO) install -m 755 -d $(E3_MODULES_INSTALL_LOCATION_INC)/pv
# cd $(E3_MODULES_INSTALL_LOCATION_INC) && $(SUDO) mv *.h pv/
#.PHONY: epics
#epics:
# $(QUIET)echo "EPICS_BASE:=$(EPICS_BASE)" > $(TOP)/$(E3_MODULE_SRC_PATH)/configure/RELEASE
# $(QUIET)echo "ASYN:=$(M_ASYN)" > $(TOP)/$(E3_MODULE_SRC_PATH)/configure/RELEASE
# $(QUIET)echo "SSCAN:=$(M_SSCAN)" >> $(TOP)/$(E3_MODULE_SRC_PATH)/configure/RELEASE
# $(QUIET)echo "SNCSEQ:=$(M_SNCSEQ)" >> $(TOP)/$(E3_MODULE_SRC_PATH)/configure/RELEASE
# $(QUIET)echo "CHECK_RELEASE:=YES" > $(TOP)/$(E3_MODULE_SRC_PATH)/configure/CONFIG_SITE
# $(QUIET)echo "INSTALL_LOCATION:=$(M_DEVLIB2)" >> $(TOP)/$(E3_MODULE_SRC_PATH)/configure/CONFIG_SITE
# $(SUDOBASH) "$(MAKE) -C $(E3_MODULE_SRC_PATH)"

28
docs/.MODULE_LOG Normal file
View File

@@ -0,0 +1,28 @@
>>
Script is used : e3TemplateGenerator.bash
Script Path : /home/anderssandstrom/plugin_ecmc/e3-tools/e3TemplateGenerator
Script Version : 1.0.8
Script Run Time : 2020Mar22-1607-33CET
User : anderssandstrom
e3-tools Hash : bf03d40
>>
>> git diff
>>
>> git diff --cached
>>
>> git diff HEAD
>>
>> Your sources are located in e3-ecmcPlugin_Simple.
>>
EPICS_MODULE_NAME : ecmcPlugin_Simple
E3_MODULE_SRC_PATH : ecmcPlugin_Simple
E3_TARGET_URL : https://github.com/anderssandstrom
>>
e3 module name : e3-ecmcPlugin_Simple
e3 target url full : https://github.com/anderssandstrom/e3-ecmcPlugin_Simple.git
>>
e3 module is located in siteMods

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
###

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

0
iocsh/.keep Normal file
View File

0
opi/.keep Normal file
View File

7
patch/Site/HISTORY.md Normal file
View File

@@ -0,0 +1,7 @@
# E3_MODULE_VERSION-what_ever_filename.p0.patch
Generic Description.....
* created by Jeong Han Lee, han.lee@esss.se
* related URL or reference https://github.com/icshwi
* Tuesday, February 13 13:24:57 CET 2018

22
patch/Site/README.md Normal file
View File

@@ -0,0 +1,22 @@
# Site Specific EPICS Module Patch Files
## Changes
The changes were tested in local environemnt, and commits to the forked repository and do pull request to the epics community module repository.
* Check the original HASH, and your own master
* feb8856 : The original HASH
* master : Changed
## How to create a p0 patch file between commits
* Show what the difference between commits
* Create p0 patch
```
$git diff feb8856 master --no-prefix > ../patch/Site/E3_MODULE_VERSION-what_ever_filename.p0.patch
```

0
template/.keep Normal file
View File