/*************************************************************************\ * 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 #include #include #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. */ class ecmcDAQChannelItem { public: ecmcDAQChannelItem(const char* name, ecmcDAQDataFormat format) { dataItem_ = NULL; dataItemInfo_ = NULL; name_ = name; cstrName_ = strdup(name); format_ = format; // micro s in int32 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; } ~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; } } /*struct ecmcDataItemInfo { char *name; uint8_t *data; size_t dataSize; size_t dataElementSize; size_t dataBitCount; ecmcEcDataType dataType; ecmcDataDir dataDirection; double dataUpdateRateMs; int dataPointerValid; };*/ /* Return data: * if "first" is set to true the first data point will be returned. * if "first" is set to false the the next data point will be returned. * 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(int first) { double data = 0; uint64_t time = 0; if(first) { dataIndexToReturn_ = 0; } if(dataIndexToReturn_ >= dataElementCount_) { printf("ERROR: Try to read outside data buffer for data item %s\n", name_.c_str()); 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_MEM_INVALID_DATA_TYPE; break; } dataIndexToReturn_++; return formatData(data,time); } 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; } return data; } /* Returns true if all data have been retruned with getData(). */ bool empty(){ return dataIndexToReturn_ >= dataElementCount_; } size_t getDataElementCount(){ return dataElementCount_; } 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_; }; #endif /* ECMC_DAQ_CHANNEL_ITEM_H_ */