This commit is contained in:
Michael Davidsaver
2013-03-24 20:28:48 -04:00
parent e7b7bee395
commit c87e90ba26
5 changed files with 514 additions and 12 deletions

View File

@ -37,6 +37,8 @@ devsup_SRCS_DEFAULT += devsupMain.cpp
devsup_SRCS_vxWorks += -nil- devsup_SRCS_vxWorks += -nil-
devsup_SRCS += setup.c devsup_SRCS += setup.c
devsup_SRCS += dbrec.c
devsup_SRCS += dbfield.c
# Add support from base/src/vxWorks if needed # Add support from base/src/vxWorks if needed
#devsup_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary #devsup_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary

192
devsupApp/src/dbfield.c Normal file
View File

@ -0,0 +1,192 @@
/* python has its own ideas about which version to support */
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#include <Python.h>
#include <epicsVersion.h>
#include <dbCommon.h>
#include <dbAccess.h>
#include <dbStaticLib.h>
typedef struct {
PyObject_HEAD
DBADDR addr;
} pyField;
static int pyField_Init(pyField *self, PyObject *args, PyObject *kws)
{
const char *pvname;
if(PyArg_ParseTuple(args, "s", &pvname))
return -1;
if(dbNameToAddr(pvname, &self->addr)) {
PyErr_SetString(PyExc_ValueError, "Record field not found");
return -1;
}
if(self->addr.field_type >= DBF_ENUM) {
PyErr_SetString(PyExc_ValueError, "Access to this field type is not supported");
return -1;
}
return 0;
}
static PyObject* pyField_name(pyField *self)
{
return Py_BuildValue("ss",
self->addr.precord->name,
self->addr.pfldDes->name);
}
static PyObject* pyField_fldinfo(pyField *self)
{
short dbf=self->addr.field_type;
short fsize=self->addr.field_size;
unsigned long nelm=self->addr.no_elements;
return Py_BuildValue("hhk", dbf, fsize, nelm);
}
union dbfvalue {
char dv_sval[MAX_STRING_SIZE];
epicsUInt32 dv_uval;
epicsInt32 dv_ival;
double dv_fval;
};
static PyObject* pyField_getval(pyField *self)
{
union dbfvalue buf;
long nReq = 1;
short reqtype;
switch(self->addr.field_type)
{
case DBF_CHAR:
case DBF_UCHAR:
case DBF_SHORT:
case DBF_USHORT:
case DBF_ENUM:
case DBF_LONG:
reqtype = DBF_LONG;
break;
case DBF_ULONG:
reqtype = DBF_ULONG;
break;
case DBF_FLOAT:
case DBF_DOUBLE:
reqtype = DBF_DOUBLE;
break;
case DBF_STRING:
reqtype = DBF_STRING;
break;
default:
PyErr_SetString(PyExc_ValueError, "Access to this field type is not supported");
return NULL;
}
if(dbGet(&self->addr, reqtype, buf.dv_sval, NULL, &nReq, NULL)) {
PyErr_SetString(PyExc_ValueError, "Error getting field value");
return NULL;
}
switch(reqtype) {
case DBF_LONG:
return PyInt_FromLong(buf.dv_ival);
case DBF_ULONG:
return PyInt_FromLong(buf.dv_uval);
case DBF_DOUBLE:
return PyInt_FromLong(buf.dv_fval);
case DBF_STRING:
return PyString_FromString(buf.dv_sval);
default:
Py_RETURN_NONE;
}
}
static PyObject* pyField_putval(pyField *self, PyObject* args)
{
PyObject *val;
union dbfvalue buf;
short puttype;
if(!PyArg_ParseTuple(args, "O", &val))
return NULL;
if(PyFloat_Check(val)) {
double v = PyFloat_AsDouble(val);
buf.dv_fval = v;
puttype = DBF_DOUBLE;
} else if(PyInt_Check(val)) {
long v = PyInt_AsLong(val);
if(v>0x7fffffffL) {
buf.dv_uval = v;
puttype = DBF_ULONG;
} else {
buf.dv_ival = v;
puttype = DBF_LONG;
}
} else if(PyString_Check(val)) {
const char *v = PyString_AsString(val);
strncpy(buf.dv_sval, v, MAX_STRING_SIZE);
buf.dv_sval[MAX_STRING_SIZE-1] = '\0';
puttype = DBF_STRING;
} else {
PyErr_SetString(PyExc_TypeError, "Unable to convert put type");
return NULL;
}
if(dbPut(&self->addr, puttype, buf.dv_sval, 1)){
PyErr_SetString(PyExc_ValueError, "Error putting field value");
return NULL;
}
Py_RETURN_NONE;
}
static PyMethodDef pyField_methods[] = {
{"name", (PyCFunction)pyField_name, METH_NOARGS,
"Return Names (\"record\",\"field\")"},
{"fieldinfo", (PyCFunction)pyField_fldinfo, METH_NOARGS,
"Field type info\nReturn (type, size, #elements"},
{"getval", (PyCFunction)pyField_getval, METH_VARARGS,
"Returns scalar version of field value"},
{"putval", (PyCFunction)pyField_putval, METH_VARARGS,
"Sets field value from a scalar"},
{NULL, NULL, 0, NULL}
};
static PyTypeObject pyField_type = {
PyObject_HEAD_INIT(NULL)
0,
"_dbapi.Field",
sizeof(pyField),
};
int pyField_prepare(void)
{
pyField_type.tp_flags = Py_TPFLAGS_DEFAULT;
pyField_type.tp_methods = pyField_methods;
pyField_type.tp_init = (initproc)pyField_Init;
pyField_type.tp_new = PyType_GenericNew;
if(PyType_Ready(&pyField_type)<0)
return -1;
return 0;
}
void pyField_setup(PyObject *module)
{
PyObject *typeobj=(PyObject*)&pyField_type;
Py_INCREF(typeobj);
PyModule_AddObject(module, "Field", (PyObject*)&pyField_type);
}

161
devsupApp/src/dbrec.c Normal file
View File

@ -0,0 +1,161 @@
/* python has its own ideas about which version to support */
#undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE
#include <Python.h>
#include <epicsVersion.h>
#include <dbCommon.h>
#include <dbAccess.h>
#include <dbStaticLib.h>
#include <dbScan.h>
typedef struct {
PyObject_HEAD
DBENTRY entry;
} pyRecord;
static int pyRecord_Init(pyRecord *self, PyObject *args, PyObject *kws)
{
const char *recname;
if(!PyArg_ParseTuple(args, "s", &recname))
return -1;
dbInitEntry(pdbbase, &self->entry);
if(dbFindRecord(&self->entry, recname)){
PyErr_SetString(PyExc_ValueError, "Record not found");
return -1;
}
return 0;
}
static PyObject* pyRecord_name(pyRecord *self)
{
dbCommon *prec=self->entry.precnode->precord;
return PyString_FromString(prec->name);
}
static PyObject* pyRecord_info(pyRecord *self, PyObject *args)
{
const char *name;
PyObject *def = Py_None;
DBENTRY entry;
if(!PyArg_ParseTuple(args, "s|O", &name, &def))
return NULL;
dbCopyEntryContents(&self->entry, &entry);
if(dbFindInfo(&entry, name)) {
if(def) {
Py_INCREF(def);
return def;
} else {
PyErr_SetNone(PyExc_KeyError);
return NULL;
}
}
return PyString_FromString(dbGetInfoString(&entry));
}
static PyObject* pyRecord_infos(pyRecord *self)
{
PyObject *dict;
DBENTRY entry;
long status;
dict = PyDict_New();
if(!dict)
return NULL;
dbCopyEntryContents(&self->entry, &entry);
for(status = dbFirstInfo(&entry); status==0; status = dbNextInfo(&entry))
{
PyObject *val = PyString_FromString(dbGetInfoString(&entry));
if(!val)
goto fail;
if(PyDict_SetItemString(dict, dbGetInfoName(&entry), val)<0) {
Py_DECREF(val);
goto fail;
}
}
return dict;
fail:
Py_DECREF(dict);
return NULL;
}
static PyObject* pyRecord_scan(pyRecord *self, PyObject *args, PyObject *kws)
{
dbCommon *prec = self->entry.precnode->precord;
static char* names[] = {"sync", NULL};
PyObject *sync = Py_False;
if(!PyArg_ParseTupleAndKeywords(args, kws, "|O", names, &sync))
return NULL;
if(!PyObject_IsTrue(sync)) {
scanOnce(prec);
} else {
Py_BEGIN_ALLOW_THREADS {
dbScanLock(prec);
dbProcess(prec);
dbScanUnlock(prec);
} Py_END_ALLOW_THREADS
}
Py_RETURN_NONE;
}
static PyMethodDef pyRecord_methods[] = {
{"name", (PyCFunction)pyRecord_name, METH_NOARGS,
"Return record name string"},
{"info", (PyCFunction)pyRecord_info, METH_VARARGS,
"Lookup info name\ninfo(name, def=None)"},
{"infos", (PyCFunction)pyRecord_infos, METH_NOARGS,
"Return a dictionary of all infos for this record."},
{"scan", (PyCFunction)pyRecord_scan, METH_VARARGS|METH_KEYWORDS,
"scan(sync=False)\nScan this record. If sync is False then"
"a scan request is queued. If sync is True then the record"
"is scannined immidately on the current thread."
},
{NULL, NULL, 0, NULL}
};
static PyTypeObject pyRecord_type = {
PyObject_HEAD_INIT(NULL)
0,
"_dbapi.Record",
sizeof(pyRecord),
};
int pyRecord_prepare(void)
{
pyRecord_type.tp_flags = Py_TPFLAGS_DEFAULT;
pyRecord_type.tp_methods = pyRecord_methods;
pyRecord_type.tp_init = (initproc)pyRecord_Init;
pyRecord_type.tp_new = PyType_GenericNew;
if(PyType_Ready(&pyRecord_type)<0)
return -1;
return 0;
}
void pyRecord_setup(PyObject *module)
{
PyObject *typeobj=(PyObject*)&pyRecord_type;
Py_INCREF(typeobj);
PyModule_AddObject(module, "Field", (PyObject*)&pyRecord_type);
}

View File

@ -1,3 +1,6 @@
/* Global interpreter setup
*/
/* python has its own ideas about which version to support */ /* python has its own ideas about which version to support */
#undef _POSIX_C_SOURCE #undef _POSIX_C_SOURCE
#undef _XOPEN_SOURCE #undef _XOPEN_SOURCE
@ -6,49 +9,98 @@
#include <stdio.h> #include <stdio.h>
#include <epicsVersion.h>
#include <dbCommon.h>
#include <dbAccess.h>
#include <dbStaticLib.h>
#include <dbScan.h>
#include <initHooks.h>
#include <epicsThread.h> #include <epicsThread.h>
#include <epicsExit.h> #include <epicsExit.h>
#include <initHooks.h>
static PyThreadState *main_state; static PyObject *hooktable;
typedef struct {
const initHookState state;
const char * const name;
} pystate;
#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)0, NULL}
};
#undef INITST
static void cleanupPy(void *junk) static void cleanupPy(void *junk)
{ {
PyEval_RestoreThread(main_state); PyThreadState *state = PyGILState_GetThisThreadState();
PyEval_RestoreThread(state);
/* release extra reference for hooktable */
Py_DECREF(hooktable);
hooktable = NULL;
Py_Finalize(); Py_Finalize();
} }
/* Initialize the interpreter environment /* Initialize the interpreter environment
*/ */
static epicsThreadOnceId setupPyOnceId = EPICS_THREAD_ONCE_INIT;
static void setupPyOnce(void *junk) static void setupPyOnce(void *junk)
{ {
Py_Initialize(); PyThreadState *state;
Py_Initialize();
PyEval_InitThreads(); PyEval_InitThreads();
state = PyEval_SaveThread();
epicsAtExit(&cleanupPy, NULL); epicsAtExit(&cleanupPy, NULL);
main_state = PyEval_SaveThread();
} }
static epicsThreadOnceId setupPyOnceId = EPICS_THREAD_ONCE_INIT;
void evalPy(const char* code) void evalPy(const char* code)
{ {
PyEval_RestoreThread(main_state); PyGILState_STATE state;
state = PyGILState_Ensure();
if(PyRun_SimpleStringFlags(code, NULL)!=0) if(PyRun_SimpleStringFlags(code, NULL)!=0)
PyErr_Print(); PyErr_Print();
main_state = PyEval_SaveThread(); PyGILState_Release(state);
} }
void evalFilePy(const char* file) void evalFilePy(const char* file)
{ {
FILE *fp; FILE *fp;
PyGILState_STATE state;
PyEval_RestoreThread(main_state); state = PyGILState_Ensure();
fp = fopen(file, "r"); fp = fopen(file, "r");
if(!fp) { if(!fp) {
@ -60,7 +112,97 @@ void evalFilePy(const char* file)
} }
/* fp closed by python */ /* fp closed by python */
main_state = PyEval_SaveThread(); PyGILState_Release(state);
}
static void pyhook(initHookState state)
{
PyGILState_STATE gilstate;
gilstate = PyGILState_Ensure();
if(hooktable && PyDict_Check(hooktable)) {
PyObject *next;
PyObject *key = PyInt_FromLong((long)state);
PyObject *list = PyDict_GetItem(hooktable, key);
Py_DECREF(key);
list = PyObject_GetIter(list);
if(!list) {
fprintf(stderr, "hook sequence not iterable!");
} else {
while((next=PyIter_Next(list))!=NULL) {
PyObject *obj;
if(!PyCallable_Check(next))
continue;
obj = PyObject_CallFunction(next, "O", key);
Py_DECREF(next);
if(obj)
Py_DECREF(obj);
else {
PyErr_Print();
PyErr_Clear();
}
}
if(!PyErr_Occurred()) {
PyErr_Print();
PyErr_Clear();
}
Py_DECREF(list);
}
}
PyGILState_Release(gilstate);
}
static const char sitestr[] = EPICS_SITE_VERSION;
static PyObject *modversion(PyObject *self)
{
int ver=EPICS_VERSION, rev=EPICS_REVISION, mod=EPICS_MODIFICATION, patch=EPICS_PATCH_LEVEL;
return Py_BuildValue("iiiis", ver, rev, mod, patch, sitestr);
}
static PyMethodDef devsup_methods[] = {
{"verinfo", (PyCFunction)modversion, METH_NOARGS,
"EPICS Version information\nreturn (MAJOR, MINOR, MOD, PATH, \"site\""},
{NULL, NULL, 0, NULL}
};
int pyField_prepare(void);
void pyField_setup(PyObject *module);
int pyRecord_prepare(void);
void pyRecord_setup(PyObject *module);
/* initialize "magic" builtin module */
static void init_dbapi(void)
{
PyObject *mod;
pystate *st;
hooktable = PyDict_New();
if(!hooktable)
return;
if(pyField_prepare())
return;
if(pyRecord_prepare())
return;
mod = Py_InitModule("_dbapi", devsup_methods);
for(st = statenames; st->name; st++) {
PyModule_AddIntConstant(mod, st->name, (long)st->state);
}
Py_INCREF(hooktable); /* an extra ref */
PyModule_AddObject(mod, "_hooktable", hooktable);
pyField_setup(mod);
pyRecord_setup(mod);
} }
#include <iocsh.h> #include <iocsh.h>
@ -82,6 +224,8 @@ static void pySetupReg(void)
epicsThreadOnce(&setupPyOnceId, &setupPyOnce, NULL); epicsThreadOnce(&setupPyOnceId, &setupPyOnce, NULL);
iocshRegister(&codeDef, &codeRun); iocshRegister(&codeDef, &codeRun);
iocshRegister(&fileDef, &fileRun); iocshRegister(&fileDef, &fileRun);
initHookRegister(&pyhook);
init_dbapi();
} }
#include <epicsExport.h> #include <epicsExport.h>

View File

@ -1,3 +1,6 @@
#!./bin/linux-x86-debug/devsup #!./bin/linux-x86-debug/devsup
dbLoadDatabase("dbd/devsup.dbd") dbLoadDatabase("dbd/devsup.dbd")
devsup_registerRecordDeviceDriver(pdbbase) devsup_registerRecordDeviceDriver(pdbbase)
evalPy "print 1"
evalPy "print 2"