/*************************************************************************\ * 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. * * ecmcDAQWrap.cpp * * Created on: Sept 21, 2020 * Author: anderssandstrom * Credits to https://github.com/sgreg/dynamic-loading * \*************************************************************************/ // Needed to get headers in ecmc right... #define ECMC_IS_PLUGIN #include #include #include #include "ecmcDAQWrap.h" #include "ecmcDAQDataArray.h" #include "ecmcDAQDefs.h" #include #include #include "envDefs.h" #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 ecmcDAQDataArray object array = NULL; try { array = new ecmcDAQDataArray(name, portName); } catch(std::exception& e) { if(array) { delete array; } printf("Exception: %s. Plugin will unload.\n",e.what()); return ECMC_PLUGIN_DAQ_ERROR_CODE; } arrays.push_back(array); arrayCounter++; return 0; } 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(); } int createDAQChannel(int type) { try { arrays.back()->addChannel(type); } catch(std::exception& e) { printf("Exception: %s. Plugin will unload.\n",e.what()); return ECMC_PLUGIN_DAQ_ERROR_CODE; } return 0; } int createDAQItem(const char* name, int type) { try { arrays.back()->addDataItemToChannel(name,type); } catch(std::exception& e) { printf("Exception: %s. Plugin will unload.\n",e.what()); return ECMC_PLUGIN_DAQ_ERROR_CODE; } return 0; } void deleteAllDAQs() { for(std::vector::iterator pDAQArray = arrays.begin(); pDAQArray != arrays.end(); ++pDAQArray) { if(*pDAQArray) { delete (*pDAQArray); } } } int linkDataToDAQs() { for(std::vector::iterator pDAQArray = arrays.begin(); pDAQArray != arrays.end(); ++pDAQArray) { if(*pDAQArray) { try { (*pDAQArray)->connectToDataSources(); } catch(std::exception& e) { printf("Exception: %s. Plugin will unload.\n",e.what()); return ECMC_PLUGIN_DAQ_ERROR_CODE; } } } 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); // } // catch(std::exception& e) { // printf("Exception: %s. DAQ index out of range.\n",e.what()); // return ECMC_PLUGIN_DAQ_ERROR_CODE; // } // return 0; //} int executeDAQs() { try { for(std::vector::iterator pDAQArray = arrays.begin(); pDAQArray != arrays.end(); ++pDAQArray) { if(*pDAQArray) { (*pDAQArray)->execute(); } } } catch(std::exception& e) { printf("Exception: %s.\n",e.what()); return ECMC_PLUGIN_DAQ_ERROR_CODE; } return 0; } /** * EPICS iocsh shell command: ecmcAddDAQArray */ void ecmcAddDAQArrayHelp() { printf("\n"); printf(" Use ecmcAddDAQArray(,)\n"); printf(" : Name of DAQ array object.\n"); printf(" : Asyn port name.\n"); printf("\n"); } int ecmcAddDAQArray(const char* name,const char* portname) { if(!name) { ecmcAddDAQArrayHelp(); return asynError; } if(!portname) { ecmcAddDAQArrayHelp(); return asynError; } if(strcmp(name,"-h") == 0 || strcmp(name,"--help") == 0 ) { ecmcAddDAQArrayHelp(); return asynSuccess; } try { return createDAQArray(name,portname); } catch(std::exception& e) { printf("Exception: %s. Create DAQ array failed.\n",e.what()); exit(EXIT_FAILURE); } return asynSuccess; } static const iocshArg initArg0_0 = { "Array name", iocshArgString }; static const iocshArg initArg1_0 = { "Asyn port name", iocshArgString }; static const iocshArg *const initArgs_0[] = { &initArg0_0, &initArg1_0}; static const iocshFuncDef initFuncDef_0 = { "ecmcAddDAQArray", 2, initArgs_0}; static void initCallFunc_0(const iocshArgBuf *args) { ecmcAddDAQArray(args[0].sval, args[1].sval); } /** * EPICS iocsh shell command: ecmcAddDAQChannel */ void ecmcAddDAQChannelHelp() { printf("\n"); printf(" Use ecmcAddDAQChannel()\n"); printf(" : Type identifier if channel (int).\n"); printf("\n"); } int ecmcAddDAQChannel(int type) { try { return createDAQChannel(type); } catch(std::exception& e) { ecmcAddDAQChannelHelp(); printf("Exception: %s. Create DAQ channel failed.\n",e.what()); exit(EXIT_FAILURE); } return asynSuccess; } static const iocshArg initArg0_1 = { "Type", iocshArgInt }; static const iocshArg *const initArgs_1[] = { &initArg0_1}; static const iocshFuncDef initFuncDef_1 = { "ecmcAddDAQChannel", 1, initArgs_1}; static void initCallFunc_1(const iocshArgBuf *args) { ecmcAddDAQChannel(args[0].ival); } /** * EPICS iocsh shell command: ecmcAddDAQItem */ void ecmcAddDAQItemHelp() { printf("\n"); printf(" Use ecmcAddDAQItem(, )\n"); printf(" : Data item name ex: 'ec0.s11.analogInput01' .\n"); printf(" : Optional format conversion of data:.\n"); printf(" 0 = raw : Take raw value (do not apply special format)\n"); printf(" 1 = time_micro_s : Time: Recalc 64bit nano seconds to 32 bit micro second counter\n"); printf(" 2 = time_micro_s_minus_period : Time: Recalc 64bit nano seconds to 32 bit micro second counter minus one ec-period.\n"); printf(" Useful for oversampling slaves where normally the nextsync time is available.\n"); printf(" The calculated time then would correspond to the first data in the array recived.\n"); printf(" 3 = time_ns_minus_period : Time: Raw value minus one period.\n"); printf("\n"); } int ecmcAddDAQItem(const char* name, int format) { if(strcmp(name,"-h") == 0 || strcmp(name,"--help") == 0 ) { ecmcAddDAQItemHelp(); return asynSuccess; } try { return createDAQItem(name,format); } catch(std::exception& e) { printf("Exception: %s. Create DAQ item failed.\n",e.what()); exit(EXIT_FAILURE); } return asynSuccess; } static const iocshArg initArg0_2 = { "Data item name/path", iocshArgString }; static const iocshArg initArg1_2 = { "Type", iocshArgInt }; static const iocshArg *const initArgs_2[] = { &initArg0_2, &initArg1_2}; static const iocshFuncDef initFuncDef_2 = { "ecmcAddDAQItem", 2, initArgs_2}; static void initCallFunc_2(const iocshArgBuf *args) { ecmcAddDAQItem(args[0].sval,args[1].ival); } /** * EPICS iocsh shell command: ecmcDAQReadNelm */ void ecmcDAQReadNelmHelp() { printf("\n"); printf(" Use ecmcDAQReadNelm(,)\n"); printf(" : Name of DAQ array object.\n"); printf(" : Variable for return value.\n"); printf("\n"); } static char nelmBuffer[100]; int ecmcDAQReadNelm(const char* name, const char* result_var) { if(!name) { ecmcAddDAQArrayHelp(); return asynError; } if(!result_var) { ecmcAddDAQArrayHelp(); return asynError; } if(strcmp(name,"-h") == 0 || strcmp(name,"--help") == 0 ) { ecmcDAQReadNelmHelp(); return asynSuccess; } memset(&nelmBuffer[0],0,100); int nelm = 0; try { nelm = getDAQDataArrayNelm(name); sprintf(nelmBuffer, "%d", nelm); epicsEnvSet(result_var, nelmBuffer); } catch(std::exception& e) { printf("Exception: %s. Find DAQ item failed.\n",e.what()); exit(EXIT_FAILURE); } return asynSuccess; } static const iocshArg initArg0_3 = { "name", iocshArgString }; static const iocshArg initArg1_3 = { "Return value variable", iocshArgString }; static const iocshArg *const initArgs_3[] = { &initArg0_3, &initArg1_3}; 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(int dummy) { 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);