/* python has its own ideas about which version to support */ #undef _POSIX_C_SOURCE #undef _XOPEN_SOURCE #include #ifdef HAVE_NUMPY #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "pydevsup.h" initHookState pyInitLastState; /* extern int pyDevSupCommon_registerRecordDeviceDriver(DBBASE *pbase); */ typedef struct { const initHookState state; const char * const name; } pystate; epicsThreadPrivateId pyDevReasonID; #define INITST(hook) {initHook ## hook, #hook } static pystate statenames[] = { INITST(AtIocBuild), INITST(AtBeginning), INITST(AfterCallbackInit), INITST(AfterCaLinkInit), INITST(AfterInitDrvSup), INITST(AfterInitRecSup), INITST(AfterInitDevSup), INITST(AfterInitDatabase), INITST(AfterFinishDevSup), INITST(AfterScanInit), INITST(AfterInitialProcess), INITST(AfterCaServerInit), INITST(AfterIocBuilt), INITST(AtIocRun), INITST(AfterDatabaseRunning), INITST(AfterCaServerRunning), INITST(AfterIocRunning), INITST(AtIocPause), INITST(AfterCaServerPaused), INITST(AfterDatabasePaused), INITST(AfterIocPaused), {(initHookState)9999, "AtIocExit"}, {(initHookState)0, NULL} }; #undef INITST void py(const char* code) { PyGILState_STATE state; if(!code) return; state = PyGILState_Ensure(); if(PyRun_SimpleStringFlags(code, NULL)!=0) PyErr_Print(); PyGILState_Release(state); } void pyfile(const char* file) { FILE *fp; PyGILState_STATE state; if(!file) return; state = PyGILState_Ensure(); fp = fopen(file, "r"); if(!fp) { fprintf(stderr, "Failed to open: %s\n", file); perror("open"); } else { if(PyRun_SimpleFileExFlags(fp, file, 1, NULL)!=0) PyErr_Print(); } /* fp closed by python */ PyGILState_Release(state); } static const iocshArg argCode = {"python code", iocshArgString}; static const iocshArg argFile = {"file", iocshArgString}; static const iocshArg* const codeArgs[] = {&argCode}; static const iocshArg* const fileArgs[] = {&argFile}; static const iocshFuncDef codeDef = {"py", 1, codeArgs}; static const iocshFuncDef fileDef = {"pyfile", 1, fileArgs}; static void codeRun(const iocshArgBuf *args){py(args[0].sval);} static void fileRun(const iocshArgBuf *args){pyfile(args[0].sval);} initHookState pyInitLastState = (initHookState)-1; static void pyhook(initHookState state) { static int madenoise = 0; PyGILState_STATE gilstate; PyObject *mod, *ret; /* ignore deprecated init hooks */ if(state==initHookAfterInterruptAccept || state==initHookAtEnd) return; gilstate = PyGILState_Ensure(); pyInitLastState = state; mod = PyImport_ImportModule("devsup.hooks"); if(!mod) { if(!madenoise) fprintf(stderr, "Error: Couldn't import devsup.hooks! Python module initHooks can not be run!\n"); madenoise=1; goto fail; } ret = PyObject_CallMethod(mod, "_runhook", "l", (long)state); Py_DECREF(mod); if(PyErr_Occurred()) { PyErr_Print(); PyErr_Clear(); } Py_XDECREF(ret); fail: PyGILState_Release(gilstate); } static PyObject* py_announce(PyObject *unused, PyObject *args, PyObject *kws) { static char* names[] = {"state", NULL}; int state; if(!PyArg_ParseTupleAndKeywords(args, kws, "i", names, &state)) return NULL; Py_BEGIN_ALLOW_THREADS { initHookAnnounce((initHookState)state); } Py_END_ALLOW_THREADS Py_RETURN_NONE; } static PyObject *py_iocsh(PyObject *unused, PyObject *args, PyObject *kws) { int ret; static char* names[] = {"script", "cmd", NULL}; char *script=NULL, *cmd=NULL; if(!PyArg_ParseTupleAndKeywords(args, kws, "|ss", names, &script, &cmd)) return NULL; if(!(!script ^ !cmd)) { PyErr_SetString(PyExc_ValueError, "iocsh requires a script file name or command string"); return NULL; } Py_BEGIN_ALLOW_THREADS { if(script) ret = iocsh(script); else ret = iocshCmd(cmd); } Py_END_ALLOW_THREADS return PyInt_FromLong(ret); } static PyObject *py_dbReadDatabase(PyObject *unused, PyObject *args, PyObject *kws) { long status; static char* names[] = {"name", "fp", "path", "sub", NULL}; char *fname=NULL, *path=NULL, *sub=NULL; int fd=-1; if(!PyArg_ParseTupleAndKeywords(args, kws, "|siss", names, &fname, &fd, &path, &sub)) return NULL; if(!((!fname) ^ (fd<0))) { PyErr_SetString(PyExc_ValueError, "dbReadDatabase requires a file name or descriptor"); return NULL; } Py_BEGIN_ALLOW_THREADS { if(fname) { status = dbReadDatabase(&pdbbase, fname, path, sub); } else { FILE *ff = fdopen(fd, "r"); status = dbReadDatabaseFP(&pdbbase, ff, path, sub); // dbReadDatabaseFP() has called fclose() } } Py_END_ALLOW_THREADS if(status) { char buf[30]; errSymLookup(status, buf, sizeof(buf)); PyErr_SetString(PyExc_RuntimeError, buf); return NULL; } Py_RETURN_NONE; } static PyObject *py_iocInit(PyObject *unused, PyObject *args, PyObject *kws) { static char* names[] = {"isolate", NULL}; PyObject *pyisolate = Py_True; int isolate, ret; if(!PyArg_ParseTupleAndKeywords(args, kws, "|O", names, &pyisolate)) return NULL; isolate = PyObject_IsTrue(pyisolate); Py_BEGIN_ALLOW_THREADS { if(isolate) { #if EPICS_VERSION_INT=3.15"); #else ret = iocBuildIsolated(); #endif } else { ret = iocBuild(); } if(!ret) ret = iocRun(); } Py_END_ALLOW_THREADS if(ret) return PyErr_Format(PyExc_RuntimeError, "Error %d", ret); Py_RETURN_NONE; } static PyObject *py_pyDevSupCommon(PyObject *unused) { /* Py_BEGIN_ALLOW_THREADS { pyDevSupCommon_registerRecordDeviceDriver(pdbbase); } Py_END_ALLOW_THREADS */ Py_RETURN_NONE; } static struct PyMethodDef dbapimethod[] = { {"initHookAnnounce", (PyCFunction)py_announce, METH_VARARGS|METH_KEYWORDS, "initHookAnnounce(state)\n"}, {"iocsh", (PyCFunction)py_iocsh, METH_VARARGS|METH_KEYWORDS, "Execute IOC shell script or command"}, {"dbReadDatabase", (PyCFunction)py_dbReadDatabase, METH_VARARGS|METH_KEYWORDS, "Load EPICS database file"}, {"iocInit", (PyCFunction)py_iocInit, METH_NOARGS, "Initialize IOC"}, {"_dbd_setup", (PyCFunction)pyDBD_setup, METH_NOARGS, ""}, {"_dbd_rrd_base", (PyCFunction)py_pyDevSupCommon, METH_NOARGS, ""}, {"_dbd_cleanup", (PyCFunction)pyDBD_cleanup, METH_NOARGS, ""}, {NULL} }; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef dbapimodule = { PyModuleDef_HEAD_INIT, "devsup._dbapi", NULL, -1, &dbapimethod }; #endif #if PY_MAJOR_VERSION >= 3 PyMODINIT_FUNC PyInit__dbapi(void) #else PyMODINIT_FUNC init_dbapi(void) #endif { PyObject *mod = NULL, *hookdict, *vertup; pystate *st; pyDevReasonID = epicsThreadPrivateCreate(); iocshRegister(&codeDef, &codeRun); iocshRegister(&fileDef, &fileRun); initHookRegister(&pyhook); import_array(); #if PY_MAJOR_VERSION >= 3 mod = PyModule_Create(&dbapimodule); #else mod = Py_InitModule("devsup._dbapi", dbapimethod); #endif if(!mod) goto fail; hookdict = PyDict_New(); if(!hookdict) goto fail; PyModule_AddObject(mod, "_hooks", hookdict); for(st = statenames; st->name; st++) { PyObject *ent = PyInt_FromLong((long)st->state); if(!ent) goto fail; if(PyDict_SetItemString(hookdict, st->name, ent)) { Py_DECREF(ent); goto fail; } } PyModule_AddIntMacro(mod, NO_ALARM); PyModule_AddIntMacro(mod, MINOR_ALARM); PyModule_AddIntMacro(mod, MAJOR_ALARM); PyModule_AddIntMacro(mod, INVALID_ALARM); PyModule_AddIntMacro(mod, READ_ALARM); PyModule_AddIntMacro(mod, WRITE_ALARM); PyModule_AddIntMacro(mod, HIHI_ALARM); PyModule_AddIntMacro(mod, HIGH_ALARM); PyModule_AddIntMacro(mod, LOLO_ALARM); PyModule_AddIntMacro(mod, LOW_ALARM); PyModule_AddIntMacro(mod, STATE_ALARM); PyModule_AddIntMacro(mod, COS_ALARM); PyModule_AddIntMacro(mod, COMM_ALARM); PyModule_AddIntMacro(mod, TIMEOUT_ALARM); PyModule_AddIntMacro(mod, HW_LIMIT_ALARM); PyModule_AddIntMacro(mod, CALC_ALARM); PyModule_AddIntMacro(mod, SCAN_ALARM); PyModule_AddIntMacro(mod, LINK_ALARM); PyModule_AddIntMacro(mod, SOFT_ALARM); PyModule_AddIntMacro(mod, BAD_SUB_ALARM); PyModule_AddIntMacro(mod, UDF_ALARM); PyModule_AddIntMacro(mod, DISABLE_ALARM); PyModule_AddIntMacro(mod, SIMM_ALARM); PyModule_AddIntMacro(mod, READ_ACCESS_ALARM); PyModule_AddIntMacro(mod, WRITE_ACCESS_ALARM); /* standard macros from epicsVersion.h */ PyModule_AddStringMacro(mod, EPICS_VERSION_STRING); #ifdef EPICS_DEV_SNAPSHOT PyModule_AddStringMacro(mod, EPICS_DEV_SNAPSHOT); #endif PyModule_AddStringMacro(mod, EPICS_SITE_VERSION); PyModule_AddIntMacro(mod, EPICS_VERSION); PyModule_AddIntMacro(mod, EPICS_REVISION); PyModule_AddIntMacro(mod, EPICS_PATCH_LEVEL); PyModule_AddIntMacro(mod, EPICS_MODIFICATION); /* additional build time info */ PyModule_AddStringMacro(mod, XEPICS_ARCH); PyModule_AddStringMacro(mod, XPYDEV_BASE); PyModule_AddStringMacro(mod, XEPICS_BASE); vertup = Py_BuildValue("(iiiiss)", (int)EPICS_VERSION, (int)EPICS_REVISION, (int)EPICS_MODIFICATION, (int)EPICS_PATCH_LEVEL, EPICS_SITE_VERSION, #ifdef EPICS_DEV_SNAPSHOT EPICS_DEV_SNAPSHOT); #else ""); #endif if(vertup) PyModule_AddObject(mod, "epicsver", vertup); /* pyDevSup version */ vertup = Py_BuildValue("(ii)", 0, 2); if(vertup) PyModule_AddObject(mod, "pydevver", vertup); if(pyField_prepare(mod)) goto fail; if(pyRecord_prepare(mod)) goto fail; if(pyUTest_prepare(mod)) goto fail; MODINIT_RET(mod); fail: fprintf(stderr, "Failed to initialize builtin _dbapi module!\n"); Py_XDECREF(mod); MODINIT_RET(NULL); }