/*************************************************************************\ * Copyright (c) 2023 Paul Scherrer Institute * ecmc is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. * * ecmcSafetyPlgWrap.cpp * * Created on: jan 29, 2024 * 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 #include #include "ecmcSafetyPlgWrap.h" #include "ecmcSS1SafetyGroup.h" #define ECMC_PLUGIN_MAX_PORTNAME_CHARS 64 #define ECMC_PLUGIN_PORTNAME_PREFIX "PLUGIN.SAFETY" static std::vector safetyGroups; static int safetyGroupsCounter = 0; static char portNameBuffer[ECMC_PLUGIN_MAX_PORTNAME_CHARS]; static const char *configString = NULL; int setCfgString(const char* cfgString) { configString = cfgString; return 0; } int createSafetyGroup(const char *name, const char *ec_rampdown_cmd, const char *ec_standstill_status, int time_delay_ms) { // create new ecmcSS1SafetyGroup object ecmcSS1SafetyGroup* safetyGroup = NULL; // create asynport name for new object () memset(portNameBuffer, 0, ECMC_PLUGIN_MAX_PORTNAME_CHARS); snprintf (portNameBuffer, ECMC_PLUGIN_MAX_PORTNAME_CHARS, ECMC_PLUGIN_PORTNAME_PREFIX "_%d", safetyGroupsCounter); try { safetyGroup = new ecmcSS1SafetyGroup(name, ec_rampdown_cmd, ec_standstill_status, time_delay_ms, configString, portNameBuffer); } catch(std::exception& e) { if(safetyGroup) { delete safetyGroup; } return ECMC_PLUGIN_SAFETY_ERROR_CODE; } safetyGroups.push_back(safetyGroup); safetyGroupsCounter++; return 0; } int addAxisToSafetyGroup(const char *groupName, int axisId, double veloLimit, int standStillTimeMs) { // Find group by name for(std::vector::iterator psafetyGroup = safetyGroups.begin(); psafetyGroup != safetyGroups.end(); ++psafetyGroup) { bool found = strcmp(groupName, (*psafetyGroup)->getName().c_str()) == 0; if(found) { (*psafetyGroup)->addAxis(axisId,veloLimit,standStillTimeMs); return asynSuccess; } } return asynError; } void deleteAllSafetyGroups() { return; // The delete process results in seg fault.. need to investigate.. for(std::vector::iterator psafetyGroup = safetyGroups.begin(); psafetyGroup != safetyGroups.end(); ++psafetyGroup) { if(*psafetyGroup) { delete (*psafetyGroup); } } } int validate() { for(std::vector::iterator psafetyGroup = safetyGroups.begin(); psafetyGroup != safetyGroups.end(); ++psafetyGroup) { if(*psafetyGroup) { try { (*psafetyGroup)->validate(); } catch(std::exception& e) { printf("Exception: %s. Plugin will unload.\n",e.what()); return ECMC_PLUGIN_SAFETY_ERROR_CODE; } } } return 0; } int executeSafetyGroups() { for(std::vector::iterator psafetyGroup = safetyGroups.begin(); psafetyGroup != safetyGroups.end(); ++psafetyGroup) { if(*psafetyGroup) { try { (*psafetyGroup)->execute(); } catch(std::exception& e) { printf("Exception: %s. Plugin will unload.\n",e.what()); return ECMC_PLUGIN_SAFETY_ERROR_CODE; } } } return 0; } /** * EPICS iocsh shell command: ecmcAddSS1SafetyGroup */ void ecmcAddSS1SafetyGroupPrintHelp() { printf("\n"); printf(" Use ecmcAddSS1SafetyGroup(, , ,)\n"); printf(" : Name of group.\n"); printf(" : Ethercat entry input for rampdown cmd.\n"); printf(" : Ethercat entry output for group standstill status.\n"); printf(" : Time delay of STO [ms].\n"); printf("\n"); } int ecmcAddSS1SafetyGroup(const char* name, const char* ec_rampdown_cmd,const char* ec_standstill_status,int time_delay_ms) { if(!name) { ecmcAddSS1SafetyGroupPrintHelp(); return asynError; } if(strcmp(name,"-h") == 0 || strcmp(name,"--help") == 0 ) { ecmcAddSS1SafetyGroupPrintHelp(); return asynSuccess; } if(!ec_rampdown_cmd) { printf("Error: ec_rampdown_cmd ethercat entry not defined.\n"); ecmcAddSS1SafetyGroupPrintHelp(); return asynError; } if(!ec_standstill_status) { printf("Error: ec_standstill_status ethercat entry not defined.\n"); ecmcAddSS1SafetyGroupPrintHelp(); return asynError; } if(time_delay_ms <= 0) { printf("Error: time_delay invalid.\n"); exit (1); } try { createSafetyGroup(name,ec_rampdown_cmd,ec_standstill_status, time_delay_ms); } catch(std::exception& e) { printf("Exception: %s. Add safety group failed.\n",e.what()); exit (1); } return asynSuccess; } static const iocshArg initArg0_1 = { "Name", iocshArgString }; static const iocshArg initArg1_1 = { "ec entry input ramp down cmd", iocshArgString }; static const iocshArg initArg2_1 = { "ec entry output axes standstill status", iocshArgString }; static const iocshArg initArg3_1 = { "STO delay [ms]", iocshArgInt }; static const iocshArg *const initArgs_1[] = { &initArg0_1, &initArg1_1, &initArg2_1, &initArg3_1}; static const iocshFuncDef initFuncDef_1 = { "ecmcAddSS1SafetyGroup", 4, initArgs_1 }; static void initCallFunc_1(const iocshArgBuf *args) { ecmcAddSS1SafetyGroup(args[0].sval, args[1].sval, args[2].sval, args[3].ival); } /** * EPICS iocsh shell command: ecmcAddAxisToSafetyGroup */ void ecmcAddAxisToSafetyGroupPrintHelp() { printf("\n"); printf(" Use ecmcAddAxisToSafetyGroup(, )\n"); printf(" : Name of safety group.\n"); printf(" : Axis index to add.\n"); printf(" : Axis standstill velo limit [unit of axis].\n"); printf("