Files
ecmc_plugin_daq/src/ecmcDAQDataArray.cpp
2024-03-04 11:22:34 +01:00

205 lines
6.5 KiB
C++

/*************************************************************************\
* Copyright (c) 2024 PSI
* ecmc is distributed subject to a Software License Agreement found
* in file LICENSE that is included with this distribution.
*
* ecmcDAQDataArray.cpp
*
* Created on: March 1, 2024
* Author: anders sandstrom
* Credits to https://github.com/sgreg/dynamic-loading
*
\*************************************************************************/
// Needed to get headers in ecmc right...
#define ECMC_IS_PLUGIN
#define ECMC_PLUGIN_ASYN_PREFIX "plugin.daq"
#define ECMC_PLUGIN_ASYN_ENABLE "enable"
#define ECMC_PLUGIN_ASYN_RAWDATA "rawdata"
#include <sstream>
#include "ecmcDAQDataArray.h"
#include "ecmcPluginClient.h"
ecmcDAQDataArray::ecmcDAQDataArray(const char* name, const char* portName)
: asynPortDriver(portName,
1, /* maxAddr */
asynInt32Mask | asynFloat64Mask | asynFloat32ArrayMask |
asynFloat64ArrayMask | asynEnumMask | asynDrvUserMask |
asynOctetMask | asynInt8ArrayMask | asynInt16ArrayMask |
asynInt32ArrayMask | asynUInt32DigitalMask, /* Interface mask */
asynInt32Mask | asynFloat64Mask | asynFloat32ArrayMask |
asynFloat64ArrayMask | asynEnumMask | asynDrvUserMask |
asynOctetMask | asynInt8ArrayMask | asynInt16ArrayMask |
asynInt32ArrayMask | asynUInt32DigitalMask, /* Interrupt mask */
ASYN_CANBLOCK , /*NOT ASYN_MULTI_DEVICE*/
1, /* Autoconnect */
0, /* Default priority */
0) /* Default stack size */
{
channelCounter_ = 0;
dataElementCount_ = 0;
totalElementCount_ = 0;
firstDataElementIndex_ = 0;
asynEnableId_ = 1;
asynRawDataId_ = -1;
enablePlugin_ = -1;
dataSourcesLinked_ = 0;
name_ = name;
}
ecmcDAQDataArray::~ecmcDAQDataArray() {
}
void ecmcDAQDataArray::addChannel(int type) {
dataChannels_.push_back(new ecmcDAQDataChannel(type));
channelCounter_++;
}
void ecmcDAQDataArray::addDataItemToChannel(const char* name, int format) {
// Always add to last added channel
dataChannels_.back()->addDataItem(name, format);
}
void ecmcDAQDataArray::connectToDataSources() {
if( dataSourcesLinked_ ) {
return;
}
dataElementCount_ = 0;
for(std::vector<ecmcDAQDataChannel*>::iterator pDataCh = dataChannels_.begin(); pDataCh != dataChannels_.end(); ++pDataCh) {
if(!(*pDataCh)) {
throw std::runtime_error( "Channel empty..");
}
(*pDataCh)->connectToDataSources();
dataElementCount_ = dataElementCount_ + (*pDataCh)->getDataElementCount();
}
// Header: First element is time stamp then 4 elements per channel
totalElementCount_ = dataElementCount_ + channelCounter_ * 4 + 1;
// Now we we can finally allocate teh buffer (ecmc is still not in realtime, enterRT)
buffer_ = new double [totalElementCount_];
memset(buffer_,0,totalElementCount_*sizeof(double));
// Build header
buildArrayHeader();
// Register asyn parameters
initAsyn();
dataSourcesLinked_ = 1;
}
/* Prepare header first in array, 4 elements per channel:
* array[0] = Ec timestamp, updated each cycle, the reset of header is static
* Channel 1:
* array[1] = Channel type
* array[2] = Data start index
* array[3] = Data element count
* array[4] = spare..
* Channel 2:
* array[5] = Channel type
* array[6] = Data start index
* array[7] = Data element count
* array[8] = spare..
*....
*/
void ecmcDAQDataArray::buildArrayHeader(){
// 4 elements plus first timestamp to first data element, only first element will change in realtime
size_t dataStartOffset = channelCounter_* 4 + 1;
firstDataElementIndex_ = dataStartOffset;
if( totalElementCount_ < dataStartOffset) {
throw std::runtime_error( "Array to small, header will not fit (array size must be bigger than total data size plus 4*data_channel_count+1)..");
}
size_t index = 0;
buffer_[index] = 0; // Timestamp, will be set in each loop in execute
index++;
// Each Data channel takes 4 doubles
for(std::vector<ecmcDAQDataChannel*>::iterator pDataCh = dataChannels_.begin(); pDataCh != dataChannels_.end(); ++pDataCh) {
if(!(*pDataCh)) {
throw std::runtime_error( "Channel empty..");
}
// First element: Type
buffer_[index] = (double)(*pDataCh)->getType();
index++;
// Second element: Data start index in array
buffer_[index] = (double)dataStartOffset;
index++;
// Third element: Data element count (size)
buffer_[index] = (double)(*pDataCh)->getDataElementCount();
// Prepare data start index for next data item
dataStartOffset = dataStartOffset + (*pDataCh)->getDataElementCount();
index++;
// Forth index spare...
buffer_[index] = -1234.0;
index++;
}
}
void ecmcDAQDataArray::setEnable(int enable) {
enablePlugin_ = enable;
}
void ecmcDAQDataArray::execute() {
if(!enablePlugin_) {
return;
}
size_t index = firstDataElementIndex_ ;
for(std::vector<ecmcDAQDataChannel*>::iterator pDataCh = dataChannels_.begin(); pDataCh != dataChannels_.end(); ++pDataCh) {
//always atleast one data item in a channel. Set "first" bit in call to getData()
buffer_[index]=(*pDataCh)->getData(1);
index++;
while(!(*pDataCh)->empty()) {
buffer_[index]=(*pDataCh)->getData(0);
}
}
updateAsyn();
}
void ecmcDAQDataArray::updateAsyn() {
doCallbacksFloat64Array(buffer_, totalElementCount_, asynRawDataId_,0);
setIntegerParam(asynEnableId_, enablePlugin_);
// Update integers
callParamCallbacks();
}
void ecmcDAQDataArray::initAsyn() {
// Add enable "plugin.daq.enable"
std::string paramName =ECMC_PLUGIN_ASYN_PREFIX ".";
paramName += name_;
paramName += ".";
paramName += ECMC_PLUGIN_ASYN_ENABLE;
if( createParam(0, paramName.c_str(), asynParamInt32, &asynEnableId_) != asynSuccess ) {
throw std::runtime_error("Failed create asyn parameter enable");
}
setIntegerParam(asynEnableId_, enablePlugin_);
// Add rawdata "plugin.fft%d.rawdata"
paramName =ECMC_PLUGIN_ASYN_PREFIX ".";
paramName += name_;
paramName += ".";
paramName += ECMC_PLUGIN_ASYN_RAWDATA;
if( createParam(0, paramName.c_str(), asynParamFloat64Array, &asynRawDataId_ ) != asynSuccess ) {
throw std::runtime_error("Failed create asyn parameter rawdata");
}
doCallbacksFloat64Array(buffer_, totalElementCount_, asynRawDataId_,0);
// Update integers
callParamCallbacks();
return;
}