294 lines
9.1 KiB
C++
294 lines
9.1 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.
|
|
*
|
|
* ecmcDAQChannelItem.h
|
|
*
|
|
* Created on: Mar 01, 2024
|
|
* Author: anders sandstrom
|
|
*
|
|
\*************************************************************************/
|
|
#ifndef ECMC_DAQ_CHANNEL_ITEM_H_
|
|
#define ECMC_DAQ_CHANNEL_ITEM_H_
|
|
|
|
#include <stdexcept>
|
|
#include <vector>
|
|
#include <string>
|
|
#include "string.h"
|
|
#include "ecmcDataItem.h"
|
|
#include "ecmcPluginClient.h"
|
|
#include "ecmcDAQDefs.h"
|
|
|
|
enum class ecmcDAQDataFormat { raw = 0,
|
|
time_micro_s = 1,
|
|
time_micro_s_minus_period = 2,
|
|
time_ns_minus_period = 3
|
|
};
|
|
|
|
/* Class to store one data item
|
|
* name : ecmc parameter name, example ec0.s1.positionActual01, ax1.enc.posact, ...
|
|
* format : Format the data in these ways:
|
|
* 0=raw : Take raw value (do not apply special format)
|
|
* 1=time_micro_s : Time: Recalc 64bit nano seconds to 32 bit micro second counter
|
|
* 2=time_micro_s_minus_period : Time: Recalc 64bit nano seconds to 32 bit micro second counter minus one ec-period.
|
|
* Useful for oversampling slaves where normally the nextsync time is available.
|
|
* The calculated time then would correspond to the first data in the array recived.
|
|
* 3=time_ns_minus_period : Time: Raw value minus one period.
|
|
* sendOneCycleOldData : Send data from previous cycle (or for arrays elements are shifted one index). To be used by Edwin to trigger on timechange for incremntal timestamped cards..
|
|
*/
|
|
|
|
|
|
class ecmcDAQChannelItem {
|
|
public:
|
|
ecmcDAQChannelItem(const char* name, ecmcDAQDataFormat format, int sendOneCycleOldData) {
|
|
dataItem_ = NULL;
|
|
dataItemInfo_ = NULL;
|
|
name_ = name;
|
|
cstrName_ = strdup(name);
|
|
format_ = format; // micro s in int32
|
|
sendOneCycleOldData_ = sendOneCycleOldData; // Will only work for scalars (if arrays the elements are shifted once)
|
|
sampleTimeCompensation_ = 0;
|
|
dataIndexToReturn_ = 0;
|
|
dataElementCount_ = 0;
|
|
bytesPerElement_ = 0;
|
|
int8Ptr_ = NULL;
|
|
uint8Ptr_ = NULL;
|
|
int16Ptr_ = NULL;
|
|
uint16Ptr_ = NULL;
|
|
int32Ptr_ = NULL;
|
|
uint32Ptr_ = NULL;
|
|
int64Ptr_ = NULL;
|
|
uint64Ptr_ = NULL;
|
|
float32Ptr_ = NULL;
|
|
float64Ptr_ = NULL;
|
|
dataType_ = ECMC_EC_NONE;
|
|
dataOld_ = 0;
|
|
printf("ecmcDAQChannelItem: Created new item %s, format %d\n",name,(int)format);
|
|
}
|
|
|
|
~ecmcDAQChannelItem() {
|
|
free(cstrName_);
|
|
}
|
|
|
|
|
|
void connectToSource() {
|
|
// Get data item
|
|
dataItem_ = (ecmcDataItem*) getEcmcDataItem(cstrName_);
|
|
if(!dataItem_) {
|
|
printf("ERROR: DataItem %s NULL.\n", name_.c_str());
|
|
throw std::runtime_error( "ERROR: DataItem NULL." );
|
|
}
|
|
|
|
dataItemInfo_ = dataItem_->getDataItemInfo();
|
|
if(!dataItemInfo_) {
|
|
printf("ERROR: DataItemInfo %s NULL.\n", name_.c_str());
|
|
throw std::runtime_error( "ERROR: DataItemInfo NULL." );
|
|
}
|
|
|
|
bytesPerElement_ = dataItemInfo_->dataElementSize;
|
|
dataElementCount_ = dataItemInfo_->dataSize / bytesPerElement_;
|
|
dataType_= dataItemInfo_->dataType;
|
|
|
|
// Execute here to be sure that startup.cmd of ecmc(cfg) has been executed.
|
|
switch(format_) {
|
|
case ecmcDAQDataFormat::time_micro_s_minus_period:
|
|
sampleTimeCompensation_ = getEcmcSampleTimeMS()*1000;
|
|
break;
|
|
case ecmcDAQDataFormat::time_ns_minus_period:
|
|
sampleTimeCompensation_ = getEcmcSampleTimeMS()*1000000;
|
|
break;
|
|
default:
|
|
sampleTimeCompensation_ = 0;
|
|
break;
|
|
}
|
|
printf("Connected to data item %s (elements %zu)\n",cstrName_,dataElementCount_);
|
|
}
|
|
|
|
void resetIndex(int reset) {
|
|
if(reset) {
|
|
dataIndexToReturn_ = 0;
|
|
}
|
|
}
|
|
|
|
/* Return data:
|
|
* looping with false will return new data for each call untill theres no more data
|
|
* before call, check if data is available with notEmpty()
|
|
*/
|
|
double getData() {
|
|
double data = 0;
|
|
uint64_t time = 0;
|
|
|
|
if(dataIndexToReturn_ >= dataElementCount_) {
|
|
printf("ecmcDAQChannelItem::ERROR: Try to read outside data buffer for data item %s (elements %zu)\n", name_.c_str(),dataElementCount_);
|
|
return -1;
|
|
}
|
|
|
|
switch (dataType_) {
|
|
case ECMC_EC_B1:
|
|
uint8Ptr_ = (uint8_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
data = (double)(*uint8Ptr_ & 0x01);
|
|
break;
|
|
|
|
case ECMC_EC_B2:
|
|
uint8Ptr_ = (uint8_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
data = (double)(*uint8Ptr_ & 0x03);
|
|
break;
|
|
|
|
case ECMC_EC_B3:
|
|
uint8Ptr_ = (uint8_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
data = (double)(*uint8Ptr_ & 0x07);
|
|
break;
|
|
|
|
case ECMC_EC_B4:
|
|
uint8Ptr_ = (uint8_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
data = (double)(*uint8Ptr_ & 0x0F);
|
|
break;
|
|
case ECMC_EC_U8:
|
|
uint8Ptr_ = (uint8_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
time = *uint8Ptr_;
|
|
data = (double)*uint8Ptr_;
|
|
break;
|
|
|
|
case ECMC_EC_S8:
|
|
int8Ptr_ = (int8_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
time = *int8Ptr_;
|
|
data = (double)*int8Ptr_;
|
|
break;
|
|
|
|
case ECMC_EC_U16:
|
|
uint16Ptr_ = (uint16_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
time = *uint16Ptr_;
|
|
data = (double)*uint16Ptr_;
|
|
break;
|
|
|
|
case ECMC_EC_S16:
|
|
int16Ptr_ = (int16_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
time = *int16Ptr_;
|
|
data = (double)*int16Ptr_;
|
|
break;
|
|
|
|
case ECMC_EC_U32:
|
|
uint32Ptr_ = (uint32_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
time = *uint32Ptr_;
|
|
data = (double)*uint32Ptr_;
|
|
break;
|
|
|
|
case ECMC_EC_S32:
|
|
int32Ptr_ = (int32_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
time = *int32Ptr_;
|
|
data = (double)*int32Ptr_;
|
|
break;
|
|
|
|
case ECMC_EC_U64:
|
|
uint64Ptr_ = (uint64_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
time = *uint64Ptr_;
|
|
data = (double)*uint64Ptr_;
|
|
break;
|
|
|
|
case ECMC_EC_S64:
|
|
int64Ptr_ = (int64_t *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
time = *uint64Ptr_;
|
|
data = (double)*int64Ptr_;
|
|
break;
|
|
|
|
case ECMC_EC_F32:
|
|
float32Ptr_ = (float *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
data = (double)*float32Ptr_;
|
|
break;
|
|
|
|
case ECMC_EC_F64:
|
|
float64Ptr_ = (double *)&dataItemInfo_->data[dataIndexToReturn_ * bytesPerElement_];
|
|
data = (double)*float64Ptr_;
|
|
break;
|
|
|
|
default:
|
|
data = 0;
|
|
return ERROR_DAQ_MEM_INVALID_DATA_TYPE;
|
|
break;
|
|
}
|
|
|
|
dataIndexToReturn_++;
|
|
|
|
double freshData = formatData(data,time);
|
|
double dataToSend = 0;
|
|
|
|
if(sendOneCycleOldData_) {
|
|
dataToSend = dataOld_;
|
|
} else {
|
|
dataToSend = freshData;
|
|
}
|
|
|
|
// Store the fresh data here
|
|
dataOld_ = freshData;
|
|
|
|
return dataToSend;
|
|
}
|
|
|
|
double formatData(double data, uint64_t time){
|
|
// Time format only works for integer values, otherwise a 0 will be returned
|
|
switch(format_) {
|
|
case ecmcDAQDataFormat::time_micro_s:
|
|
time = time / 1000; // micro seconds
|
|
data = (double)(time & 0xFFFFFFFF); //keep 32bits
|
|
break;
|
|
case ecmcDAQDataFormat::time_micro_s_minus_period:
|
|
time = time / 1000; // micro seconds
|
|
data = (double)(time & 0xFFFFFFFF); //keep 32bits
|
|
data = data - sampleTimeCompensation_;
|
|
break;
|
|
case ecmcDAQDataFormat::time_ns_minus_period:
|
|
data = (double)(time - (uint64_t)sampleTimeCompensation_);
|
|
break;
|
|
default:
|
|
;
|
|
break;
|
|
}
|
|
//printf("DATA %s = %lf\n",cstrName_, data);
|
|
return data;
|
|
}
|
|
|
|
/* Returns true if all data have been retruned with getData().
|
|
*/
|
|
bool empty(){
|
|
return dataIndexToReturn_ >= dataElementCount_;
|
|
}
|
|
|
|
size_t getDataElementCount(){
|
|
return dataElementCount_;
|
|
}
|
|
|
|
int validate() {
|
|
if(dataElementCount_==0) {
|
|
throw std::runtime_error("Error: DAQ-data item element count 0");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
ecmcDataItem* dataItem_;
|
|
ecmcDataItemInfo* dataItemInfo_;
|
|
std::string name_;
|
|
char *cstrName_;
|
|
ecmcDAQDataFormat format_;
|
|
double sampleTimeCompensation_;
|
|
size_t dataIndexToReturn_;
|
|
size_t dataElementCount_;
|
|
size_t bytesPerElement_;
|
|
ecmcEcDataType dataType_;
|
|
int8_t *int8Ptr_;
|
|
uint8_t *uint8Ptr_;
|
|
int16_t *int16Ptr_;
|
|
uint16_t *uint16Ptr_;
|
|
int32_t *int32Ptr_;
|
|
uint32_t *uint32Ptr_;
|
|
int64_t *int64Ptr_;
|
|
uint64_t *uint64Ptr_;
|
|
float *float32Ptr_;
|
|
double *float64Ptr_;
|
|
int sendOneCycleOldData_;
|
|
double dataOld_;
|
|
};
|
|
#endif /* ECMC_DAQ_CHANNEL_ITEM_H_ */
|
|
|