Cleanup
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -1,153 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* 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_ */
|
||||
@@ -1,54 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* 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_ */
|
||||
@@ -1,133 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* 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;
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
/*************************************************************************\
|
||||
* 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_ */
|
||||
@@ -299,3 +299,65 @@ ecmc_plugin_register(pluginDataDef);
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif // ifdef __cplusplus
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/raw.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
int s;
|
||||
int nbytes;
|
||||
struct sockaddr_can addr;
|
||||
struct can_frame frame;
|
||||
struct ifreq ifr;
|
||||
|
||||
const char *ifname = "vcan0";
|
||||
|
||||
if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) == -1) {
|
||||
perror("Error while opening socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(ifr.ifr_name, ifname);
|
||||
ioctl(s, SIOCGIFINDEX, &ifr);
|
||||
|
||||
addr.can_family = AF_CAN;
|
||||
addr.can_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
printf("%s at index %d\n", ifname, ifr.ifr_ifindex);
|
||||
|
||||
if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
||||
perror("Error in socket bind");
|
||||
return -2;
|
||||
}
|
||||
|
||||
frame.can_id = 0x123;
|
||||
frame.can_dlc = 2;
|
||||
frame.data[0] = 0x11;
|
||||
frame.data[1] = 0x22;
|
||||
|
||||
nbytes = write(s, &frame, sizeof(struct can_frame));
|
||||
|
||||
printf("Wrote %d bytes\n", nbytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user