401 lines
10 KiB
C++
401 lines
10 KiB
C++
/*************************************************************************\
|
|
* 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 <vector>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include "ecmcDAQWrap.h"
|
|
#include "ecmcDAQDataArray.h"
|
|
#include "ecmcDAQDefs.h"
|
|
#include <epicsExport.h>
|
|
#include <iocsh.h>
|
|
#include "envDefs.h"
|
|
|
|
#define ECMC_PLUGIN_DAQ_ERROR_CODE 1
|
|
|
|
static std::vector<ecmcDAQDataArray*> arrays;
|
|
static int arrayCounter = 0;
|
|
|
|
ecmcDAQDataArray* getDAQArrayFromName(const char *name) {
|
|
// Find group by name
|
|
for(std::vector<ecmcDAQDataArray*>::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<ecmcDAQDataArray*>::iterator pDAQArray = arrays.begin(); pDAQArray != arrays.end(); ++pDAQArray) {
|
|
if(*pDAQArray) {
|
|
delete (*pDAQArray);
|
|
}
|
|
}
|
|
}
|
|
|
|
int linkDataToDAQs() {
|
|
for(std::vector<ecmcDAQDataArray*>::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<ecmcDAQDataArray*>::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<ecmcDAQDataArray*>::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(<name>,<asyn_port_name>)\n");
|
|
printf(" <name> : Name of DAQ array object.\n");
|
|
printf(" <asyn_port_name> : 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(<type>)\n");
|
|
printf(" <type> : 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(<dataitem_name>, <format>)\n");
|
|
printf(" <dataitem_name> : Data item name ex: 'ec0.s11.analogInput01' .\n");
|
|
printf(" <format> : 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(<name>,<result_var_name>)\n");
|
|
printf(" <name> : Name of DAQ array object.\n");
|
|
printf(" <result_var_name> : 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);
|