From 16f1795e32ff12e53707ed9faae09ad40218f70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anders=20Sandstr=C3=B6m?= Date: Mon, 4 Mar 2024 21:30:23 +0100 Subject: [PATCH] WIP --- iocsh/test.script | 60 +++++++++++++++++++++------- src/ecmcDAQChannelItem.h | 11 +++++- src/ecmcDAQDataArray.cpp | 16 ++++++++ src/ecmcDAQDataArray.h | 1 + src/ecmcDAQDataChannel.cpp | 19 ++++++++- src/ecmcDAQDataChannel.h | 1 + src/ecmcDAQWrap.cpp | 80 +++++++++++++++++++++++++++++++------- src/ecmcDAQWrap.h | 13 +------ src/ecmcPluginDAQ.c | 6 +-- 9 files changed, 160 insertions(+), 47 deletions(-) diff --git a/iocsh/test.script b/iocsh/test.script index 22227ab..a3d4d9f 100644 --- a/iocsh/test.script +++ b/iocsh/test.script @@ -45,20 +45,52 @@ ${SCRIPTEXEC} ${ECMC_CONFIG_ROOT}loadYamlAxis.cmd, "FILE=./cfg/axis.yaml,LIMIT=1 # require ecmc_plugin_daq sandst_a "PLUGIN_ID=0" -ecmcAddDAQArray("test",PLUGIN.DAQ.test) -ecmcAddDAQChannel(123) -ecmcAddDAQItem(ec0.s13.ONE,0) -ecmcAddDAQItem(ax1.actpos,0) -ecmcAddDAQItem(ec0.s13.positionActual01,0) -ecmcAddDAQItem(ec0.s13.ONE,0) -ecmcAddDAQItem(ax1.setpos,0) -ecmcAddDAQChannel(12) -ecmcAddDAQItem(ec0.s13.positionActual01,0) -ecmcAddDAQItem(ec0.s13.positionActual01,0) -ecmcAddDAQItem(ec0.s13.positionActual01,0) -ecmcAddDAQItem(ec0.s13.ONE,0) -ecmcAddDAQItem(ec0.s13.ONE,0) -ecmcAddDAQItem(ax1.setpos,0) +#ecmcAddDAQArray("test",PLUGIN.DAQ.test) +#ecmcAddDAQChannel(123) +#ecmcAddDAQItem(ec0.s13.ONE,0) +#ecmcAddDAQItem(ax1.actpos,0) +#ecmcAddDAQItem(ec0.s13.positionActual01,0) +#ecmcAddDAQItem(ec0.s13.ONE,0) +#ecmcAddDAQItem(ax1.setpos,0) +#ecmcAddDAQChannel(12) +#ecmcAddDAQItem(ec0.s13.positionActual01,0) +#ecmcAddDAQItem(ec0.s13.positionActual01,0) +#ecmcAddDAQItem(ec0.s13.positionActual01,0) +#ecmcAddDAQItem(ec0.s13.ONE,0) +#ecmcAddDAQItem(ec0.s13.ONE,0) +#ecmcAddDAQItem(ax1.setpos,0) + +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqArray.cmd, "NAME=Testing1" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqChannel.cmd, "TYPE=1234" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.ONE,FORMAT=2" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.positionActual01" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.positionActual01" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqChannel.cmd, "TYPE=4321" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.ONE,FORMAT=2" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.positionActual01" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcLoadDaqArrayRecords.cmd "NAME=Testing1" + +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqArray.cmd, "NAME=Testing2" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqChannel.cmd, "TYPE=1234" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.ONE,FORMAT=2" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.positionActual01" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.positionActual01" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqChannel.cmd, "TYPE=4321" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.ONE,FORMAT=2" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ec0.s13.positionActual01" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcAddDaqDataItem.cmd, "PARAM=ax1.setpos" +${SCRIPTEXEC} ${ecmc_plugin_daq_DIR}ecmcLoadDaqArrayRecords.cmd "NAME=Testing2" ############################################################################## ## Configure diagnostics: diff --git a/src/ecmcDAQChannelItem.h b/src/ecmcDAQChannelItem.h index 12ea3e5..c189490 100644 --- a/src/ecmcDAQChannelItem.h +++ b/src/ecmcDAQChannelItem.h @@ -229,17 +229,24 @@ class ecmcDAQChannelItem { return data; } - /* Returns true if all data have been retruned with getData(). */ bool empty(){ return dataIndexToReturn_ >= dataElementCount_; } - size_t getDataElementCount(){ + 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_; diff --git a/src/ecmcDAQDataArray.cpp b/src/ecmcDAQDataArray.cpp index c2aaa4d..99deeef 100644 --- a/src/ecmcDAQDataArray.cpp +++ b/src/ecmcDAQDataArray.cpp @@ -202,6 +202,22 @@ void ecmcDAQDataArray::initAsyn() { return; } +int ecmcDAQDataArray::validate() { + if(dataElementCount_==0) { + throw std::runtime_error("Error: DAQ-Array element count 0"); + } + if(channelCounter_==0) { + throw std::runtime_error("Error: DAQ-Array channel count 0"); + } + for(std::vector::iterator pDataCh = dataChannels_.begin(); pDataCh != dataChannels_.end(); ++pDataCh) { + if(!(*pDataCh)) { + throw std::runtime_error( "Channel empty.."); + } + (*pDataCh)->validate(); + } + return 0; +} + size_t ecmcDAQDataArray::getArraySize() { return totalElementCount_; } diff --git a/src/ecmcDAQDataArray.h b/src/ecmcDAQDataArray.h index 4d8ccc5..362131a 100644 --- a/src/ecmcDAQDataArray.h +++ b/src/ecmcDAQDataArray.h @@ -31,6 +31,7 @@ class ecmcDAQDataArray : public asynPortDriver { void addDataItemToChannel(const char* name, int format); void setEnable(int enable); size_t getArraySize(); + int validate(); private: void buildArrayHeader(); diff --git a/src/ecmcDAQDataChannel.cpp b/src/ecmcDAQDataChannel.cpp index 4fdf9c6..d475551 100644 --- a/src/ecmcDAQDataChannel.cpp +++ b/src/ecmcDAQDataChannel.cpp @@ -43,7 +43,7 @@ void ecmcDAQDataChannel::connectToDataSources() { for(std::vector::iterator pDataItem = dataItems_.begin(); pDataItem != dataItems_.end(); ++pDataItem) { if(!(*pDataItem)) { - throw std::runtime_error( "Channel empty.."); + throw std::runtime_error( "Data item empty.."); } (*pDataItem)->connectToSource(); dataElementCount_ = dataElementCount_ + (*pDataItem)->getDataElementCount(); @@ -93,3 +93,20 @@ double ecmcDAQDataChannel::getData(int first){ bool ecmcDAQDataChannel::empty(){ return returnedDataCounter_>=dataElementCount_; } + +int ecmcDAQDataChannel::validate() { + if(dataElementCount_==0) { + throw std::runtime_error("Error: DAQ-Channel element count 0"); + } + if(itemCounter_==0) { + throw std::runtime_error("Error: DAQ-Channel data item count 0"); + } + for(std::vector::iterator pDataItem = dataItems_.begin(); pDataItem != dataItems_.end(); ++pDataItem) { + if(!(*pDataItem)) { + throw std::runtime_error( "Data item empty.."); + } + (*pDataItem)->validate(); + } + return 0; +} + diff --git a/src/ecmcDAQDataChannel.h b/src/ecmcDAQDataChannel.h index e60c7ea..85f53bc 100644 --- a/src/ecmcDAQDataChannel.h +++ b/src/ecmcDAQDataChannel.h @@ -28,6 +28,7 @@ class ecmcDAQDataChannel { double getData(int first); bool empty(); double getType(); + int validate(); private: std::vector dataItems_; diff --git a/src/ecmcDAQWrap.cpp b/src/ecmcDAQWrap.cpp index ba1c997..41c3019 100644 --- a/src/ecmcDAQWrap.cpp +++ b/src/ecmcDAQWrap.cpp @@ -23,13 +23,30 @@ #include #include -#define ECMC_PLUGIN_PORTNAME_PREFIX "PLUGIN.DAQ" #define ECMC_PLUGIN_DAQ_ERROR_CODE 1 static std::vector arrays; static int arrayCounter = 0; +ecmcDAQDataArray* getDAQArrayFromName(const char *name) { + // Find group by name + for(std::vector::iterator array = arrays.begin(); array != arrays.end(); ++array) { + bool found = strcmp(name, (*array)->getName().c_str()) == 0; + if(found) { + return (*array); + } + } + return NULL; +} + + int createDAQArray(const char* name, const char* portName ) { + // Check if already exists + ecmcDAQDataArray array = getDAQArrayFromName(name); + if(array){ + printf("Error: DAQ-Array %s already defined.\n",name); + return ECMC_PLUGIN_DAQ_ERROR_CODE; + } // create new ecmcFFT object ecmcDAQDataArray* array = NULL; @@ -51,21 +68,10 @@ int createDAQArray(const char* name, const char* portName ) { return 0; } -ecmcDAQDataArray* getDAQArrayFromName(const char *name) { - // Find group by name - for(std::vector::iterator array = arrays.begin(); array != arrays.end(); ++array) { - bool found = strcmp(name, (*array)->getName().c_str()) == 0; - if(found) { - return (*array); - } - } - return NULL; -} - - int getDAQDataArrayNelm(const char *name){ ecmcDAQDataArray array = getDAQArrayFromName(name); if(!array){ + printf("Error: DAQ-Array %s not found.\n",name); return -1; } return array->getArraySize(); @@ -119,6 +125,20 @@ int linkDataToDAQs() { return 0; } +int validateDAQs() { + for(std::vector::iterator pDAQArray = arrays.begin(); pDAQArray != arrays.end(); ++pDAQArray) { + if(*pDAQArray) { + try { + (*pDAQArray)->validate(); + } + catch(std::exception& e) { + printf("Exception: %s. Plugin will unload.\n",e.what()); + return ECMC_PLUGIN_DAQ_ERROR_CODE; + } + } + } + return 0; +} //int enableDAQ(int scopeIndex, int enable) { // try { // arrays.at(scopeIndex)->setEnable(enable); @@ -283,11 +303,11 @@ static void initCallFunc_2(const iocshArgBuf *args) { /** - * EPICS iocsh shell command: ecmcAddDAQItem + * EPICS iocsh shell command: ecmcDAQReadNelm */ void ecmcDAQReadNelmHelp() { printf("\n"); - printf(" Use ecmcDAQReadNELM(,)\n"); + printf(" Use ecmcDAQReadNelm(,)\n"); printf(" : Name of DAQ array object.\n"); printf(" : Variable for return value.\n"); printf("\n"); @@ -337,12 +357,42 @@ static const iocshFuncDef initFuncDef_3 = { "ecmcDAQReadNelm", 2, initArgs_3} static void initCallFunc_3(const iocshArgBuf *args) { ecmcDAQReadNelm(args[0].sval,args[1].sval); } + +/** + * EPICS iocsh shell command: ecmcDAQConnectToDataSource +*/ + +int ecmcDAQConnectToDataSource() { + + try { + linkDataToDAQs(); + } + catch(std::exception& e) { + printf("Exception: %s. Connect data sources failed.\n",e.what()); + exit(EXIT_FAILURE); + } + + return asynSuccess; +} + +static const iocshArg initArg0_4 = +{ "dummy", iocshArgInt }; + + +static const iocshArg *const initArgs_4[] = { &initArg0_4}; + +static const iocshFuncDef initFuncDef_4 = { "ecmcDAQConnectToDataSource", 1, initArgs_4}; +static void initCallFunc_4(const iocshArgBuf *args) { + ecmcDAQConnectToDataSource(args[0].ival); +} + // Register void ecmcDAQPlgRegister(void) { iocshRegister(&initFuncDef_0, initCallFunc_0); iocshRegister(&initFuncDef_1, initCallFunc_1); iocshRegister(&initFuncDef_2, initCallFunc_2); iocshRegister(&initFuncDef_3, initCallFunc_3); + iocshRegister(&initFuncDef_3, initCallFunc_4); } epicsExportRegistrar(ecmcDAQPlgRegister); diff --git a/src/ecmcDAQWrap.h b/src/ecmcDAQWrap.h index d81314f..585b1d6 100644 --- a/src/ecmcDAQWrap.h +++ b/src/ecmcDAQWrap.h @@ -19,16 +19,6 @@ extern "C" { int executeDAQs(); -/** \brief Link data to _all_ scope objects - * - * This tells the DAQ 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 linkDataToDAQs(); - /** \brief Deletes all created scope objects\n * * Should be called when destructs.\n @@ -36,7 +26,8 @@ int linkDataToDAQs(); void deleteAllDAQs(); - +// validate DAQs +int validateDAQs(); # ifdef __cplusplus } diff --git a/src/ecmcPluginDAQ.c b/src/ecmcPluginDAQ.c index dd8600d..f5c48ff 100644 --- a/src/ecmcPluginDAQ.c +++ b/src/ecmcPluginDAQ.c @@ -71,11 +71,9 @@ int daqRealtime(int ecmcError) return executeDAQs(); } -/** 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 daqEnterRT(){ - return linkDataToDAQs(); + return validateDAQs(); //linkDataToDAQs(); } /** Optional function.