diff --git a/src/ioc/Makefile b/src/ioc/Makefile index 5e165b5..7972bea 100644 --- a/src/ioc/Makefile +++ b/src/ioc/Makefile @@ -7,6 +7,7 @@ pvAccessIOC_LIBS += pvAccess pvData pvAccessIOC_LIBS += $(EPICS_BASE_IOC_LIBS) INC += pv/syncChannelFind.h +INC += pv/iocshelper.h DBD += PVAServerRegister.dbd DBD += PVAClientRegister.dbd diff --git a/src/ioc/pv/iocshelper.h b/src/ioc/pv/iocshelper.h new file mode 100644 index 0000000..d4b3f55 --- /dev/null +++ b/src/ioc/pv/iocshelper.h @@ -0,0 +1,156 @@ +#ifndef IOCSHELPER_H +#define IOCSHELPER_H +/** Helper for exposing functions and variables in the IOC shell + * + * Limitations: + * - supports functions with up to 4 arguments + * - argument and variable types must be: int, double, char*, or const char* + * + @code + #include + void fn0() {} + void fn2(int a, const char *b) {} + int var; + void myRegistrar() { + epics::iocshRegister<&fn0>("fn0"); + epics::iocshRegister("fn0", "a description", "b description"); + epics::iocshVariable("var"); + } + extern "C" { + epicsExportRegistrar(myRegistrar); + } + @endcode + */ + +#include + +#include + +namespace epics { +namespace detail { + +template +struct getarg {}; +template<> struct getarg { + static int op(const iocshArgBuf& a) { return a.ival; } + enum { argtype = iocshArgInt }; +}; +template<> struct getarg { + static double op(const iocshArgBuf& a) { return a.dval; } + enum { argtype = iocshArgDouble }; +}; +template<> struct getarg { + static char* op(const iocshArgBuf& a) { return a.sval; } + enum { argtype = iocshArgString }; +}; +template<> struct getarg { + static const char* op(const iocshArgBuf& a) { return a.sval; } + enum { argtype = iocshArgString }; +}; + + +template +struct iocshFuncInfo{ + iocshFuncDef def; + std::string name; + iocshArg *argarr[N]; + iocshArg args[N]; + std::string argnames[N]; + iocshFuncInfo(const std::string& n) :name(n) { + def.name = name.c_str(); + def.nargs = N; + def.arg = (iocshArg**)&argarr; + for(size_t i=0; i + void set(const char *name) { + argnames[n] = name; + args[n].name = argnames[n].c_str(); + args[n].type = (iocshArgType)detail::getarg::argtype; + } +}; + +template +static void call0(const iocshArgBuf *args) +{ + fn(); +} + +template +static void call1(const iocshArgBuf *args) +{ + fn(getarg::op(args[0])); +} + +template +static void call2(const iocshArgBuf *args) +{ + fn(getarg::op(args[0]), + getarg::op(args[1])); +} + +template +static void call3(const iocshArgBuf *args) +{ + fn(getarg::op(args[0]), + getarg::op(args[1]), + getarg::op(args[2])); +} + +} // namespace detail + + +template +void iocshRegister(const char *name) +{ + static detail::iocshFuncInfo<0> info(name); + iocshRegister(&info.def, &detail::call0); +} + +template +void iocshRegister(const char *name, const char *arg1name) +{ + static detail::iocshFuncInfo<1> info(name); + info.set<0,A>(arg1name); + iocshRegister(&info.def, &detail::call1); +} + +template +void iocshRegister(const char *name, + const char *arg1name, + const char *arg2name) +{ + static detail::iocshFuncInfo<2> info(name); + info.set<0,A>(arg1name); + info.set<1,B>(arg2name); + iocshRegister(&info.def, &detail::call2); +} + +template +void iocshRegister(const char *name, + const char *arg1name, + const char *arg2name, + const char *arg3name) +{ + static detail::iocshFuncInfo<3> info(name); + info.set<0,A>(arg1name); + info.set<1,B>(arg2name); + info.set<2,C>(arg3name); + iocshRegister(&info.def, &detail::call3); +} + +template +void iocshVariable(const char *name) +{ + static iocshVarDef def[2]; + def[0].name = name; + def[0].pval = (void*)addr; + def[0].type = (iocshArgType)detail::getarg::argtype; + def[1].name = NULL; + iocshRegisterVariable(def); +} + +} // namespace epics + +#endif // IOCSHELPER_H