From c82e5a221eb964409efb04cad03220d38b28e946 Mon Sep 17 00:00:00 2001 From: Anders Blomdell <anders.blomdell@control.lth.se> Date: Tue, 26 Mar 2019 16:38:05 +0100 Subject: [PATCH] Add python adapter --- adaptors/python/.gitignore | 2 + adaptors/python/Makefile | 18 + adaptors/python/python-moberg.c | 792 ++++++++++++++++++++++++++++++++ adaptors/python/setup.py | 28 ++ 4 files changed, 840 insertions(+) create mode 100644 adaptors/python/.gitignore create mode 100644 adaptors/python/Makefile create mode 100644 adaptors/python/python-moberg.c create mode 100755 adaptors/python/setup.py diff --git a/adaptors/python/.gitignore b/adaptors/python/.gitignore new file mode 100644 index 0000000..f65eb29 --- /dev/null +++ b/adaptors/python/.gitignore @@ -0,0 +1,2 @@ +/__pycache__ +/install \ No newline at end of file diff --git a/adaptors/python/Makefile b/adaptors/python/Makefile new file mode 100644 index 0000000..1085417 --- /dev/null +++ b/adaptors/python/Makefile @@ -0,0 +1,18 @@ +MOBERG_VERSION=$(shell git describe --tags) + +all: BUILD + +.PHONY: BUILD +BUILD: + python2 ./setup.py build + python3 ./setup.py build + +.PHONY: INSTALL +INSTALL: + MOBERG_VERSION=$(MOBERG_VERSION) python2 \ + ./setup.py install -O1 --prefix=/usr/ --root=./install + MOBERG_VERSION=$(MOBERG_VERSION) python3 \ + ./setup.py install -O1 --prefix=/usr/ --root=./install + +clean: + rm -rf build install diff --git a/adaptors/python/python-moberg.c b/adaptors/python/python-moberg.c new file mode 100644 index 0000000..33dced2 --- /dev/null +++ b/adaptors/python/python-moberg.c @@ -0,0 +1,792 @@ +/* + python-moberg.c -- python interface to moberg I/O system + + Copyright (C) 2019 Anders Blomdell <anders.blomdell@gmail.com> + + This file is part of Moberg. + + Moberg is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include <Python.h> +#include <structmember.h> +#include <moberg.h> + +#ifndef Py_UNUSED /* This is already defined for Python 3.4 onwards */ +#ifdef __GNUC__ +#define Py_UNUSED(name) _unused_ ## name __attribute__((unused)) +#else +#define Py_UNUSED(name) _unused_ ## name +#endif +#endif + +static PyTypeObject MobergType; +static PyTypeObject MobergAnalogInType; +static PyTypeObject MobergAnalogOutType; +static PyTypeObject MobergDigitalInType; +static PyTypeObject MobergDigitalOutType; +static PyTypeObject MobergEncoderInType; + +/* + * moberg.Moberg class + */ + +typedef struct { + PyObject_HEAD + struct moberg *moberg; +} MobergObject; + +static void +Moberg_dealloc(MobergObject *self) +{ + if (self->moberg) { + moberg_free(self->moberg); + } + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +Moberg_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = { NULL }; + if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { + return NULL; + } + MobergObject *self = (MobergObject *) type->tp_alloc(type, 0); + return (PyObject *) self; +} + +static int +Moberg_init(MobergObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = { NULL }; + if (! PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) { + return -1; + } + self->moberg = moberg_new(); + if (! self->moberg) { + PyErr_SetString(PyExc_OSError, "moberg.Moberg.__init__() failed"); + return -1; + } + return 0; +} + +static PyObject * +Moberg_analog_in(MobergObject *self, PyObject *args) +{ + int index; + if (! PyArg_ParseTuple(args, "i", &index)) { + PyErr_SetString(PyExc_AttributeError, "index"); + return NULL; + } + PyObject *ain_args = Py_BuildValue("Oi", self, index); + PyObject *ain = MobergAnalogInType.tp_new(&MobergAnalogInType, + ain_args, NULL); + /* NB: _AnalogIn.__init__ should never be called */ + Py_DECREF(ain_args); + return ain; +} + +static PyObject * +Moberg_analog_out(MobergObject *self, PyObject *args) +{ + int index; + if (! PyArg_ParseTuple(args, "i", &index)) { + PyErr_SetString(PyExc_AttributeError, "index"); + return NULL; + } + PyObject *aout_args = Py_BuildValue("Oi", self, index); + PyObject *aout = MobergAnalogOutType.tp_new(&MobergAnalogOutType, + aout_args, NULL); + /* NB: _AnalogOut.__init__ should never be called */ + Py_DECREF(aout_args); + return aout; +} + +static PyObject * +Moberg_digital_in(MobergObject *self, PyObject *args) +{ + int index; + if (! PyArg_ParseTuple(args, "i", &index)) { + PyErr_SetString(PyExc_AttributeError, "index"); + return NULL; + } + PyObject *din_args = Py_BuildValue("Oi", self, index); + PyObject *din = MobergDigitalInType.tp_new(&MobergDigitalInType, + din_args, NULL); + /* NB: _DigitalIn.__init__ should never be called */ + Py_DECREF(din_args); + return din; +} + +static PyObject * +Moberg_digital_out(MobergObject *self, PyObject *args) +{ + int index; + if (! PyArg_ParseTuple(args, "i", &index)) { + PyErr_SetString(PyExc_AttributeError, "index"); + return NULL; + } + PyObject *dout_args = Py_BuildValue("Oi", self, index); + PyObject *dout = MobergDigitalOutType.tp_new(&MobergDigitalOutType, + dout_args, NULL); + /* NB: _DigitalOut.__init__ should never be called */ + Py_DECREF(dout_args); + return dout; +} + +static PyObject * +Moberg_encoder_in(MobergObject *self, PyObject *args) +{ + int index; + if (! PyArg_ParseTuple(args, "i", &index)) { + PyErr_SetString(PyExc_AttributeError, "index"); + return NULL; + } + PyObject *ein_args = Py_BuildValue("Oi", self, index); + PyObject *ein = MobergEncoderInType.tp_new(&MobergEncoderInType, + ein_args, NULL); + /* NB: _EncoderIn.__init__ should never be called */ + Py_DECREF(ein_args); + return ein; +} + +static PyMethodDef Moberg_methods[] = { + {"analog_in", (PyCFunction) Moberg_analog_in, METH_VARARGS, + "Return AnalogIn object for channel" + }, + {"analog_out", (PyCFunction) Moberg_analog_out, METH_VARARGS, + "Return AnalogOut object for channel" + }, + {"digital_in", (PyCFunction) Moberg_digital_in, METH_VARARGS, + "Return DigitalIn object for channel" + }, + {"digital_out", (PyCFunction) Moberg_digital_out, METH_VARARGS, + "Return DigitalOut object for channel" + }, + {"encoder_in", (PyCFunction) Moberg_encoder_in, METH_VARARGS, + "Return EncoderIn object for channel" + }, + + {NULL} /* Sentinel */ +}; + +static PyTypeObject MobergType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "moberg.Moberg", + .tp_doc = "Moberg objects", + .tp_basicsize = sizeof(MobergObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = Moberg_new, + .tp_init = (initproc) Moberg_init, + .tp_dealloc = (destructor) Moberg_dealloc, + .tp_methods = Moberg_methods, +}; + +/* + * moberg._AnalogIn class (should never be directly instatiated) + */ + +typedef struct { + PyObject_HEAD + PyObject *moberg_object; + int index; + struct moberg_analog_in channel; +} MobergAnalogInObject; + +static void +MobergAnalogIn_dealloc(MobergAnalogInObject *self) +{ + if (self->moberg_object) { + struct moberg *moberg = ((MobergObject*)self->moberg_object)->moberg; + struct moberg_status status = + moberg_analog_in_close(moberg, self->index, self->channel); + if (! moberg_OK(status)) { + fprintf(stderr, "Failed to close moberg._AnalogIn(%d) [errno=%d]\n", + self->index, status.result); + } + Py_DECREF(self->moberg_object); + } + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +MobergAnalogIn_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *moberg_object; + int index; + struct moberg_analog_in channel = {0}; + + static char *kwlist[] = { "moberg", "index", NULL }; + if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, + &moberg_object, &index)) { + goto err; + } + if (Py_TYPE(moberg_object) != &MobergType) { + PyErr_SetString(PyExc_AttributeError, "moberg argument is not Moberg"); + goto err; + } + struct moberg *moberg = ((MobergObject*)moberg_object)->moberg; + struct moberg_status status = moberg_analog_in_open(moberg, index, &channel); + if (! moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._AnalogIn(%d) failed with %d", + index, status.result); + goto err; + } + MobergAnalogInObject *self; + self = (MobergAnalogInObject *) type->tp_alloc(type, 0); + if (self == NULL) { goto close; } + Py_INCREF(moberg_object); + self->moberg_object = moberg_object; + self->index = index; + self->channel = channel; + return (PyObject *) self; +close: + status = moberg_analog_in_close(moberg, index, channel); +err: + return NULL; +} + +static int +MobergAnalogIn_init(MobergAnalogInObject *self, PyObject *args, PyObject *kwds) +{ + PyErr_SetString(PyExc_AttributeError, "Not intended to be called"); + return -1; +} + +static PyObject * +MobergAnalogIn_read(MobergAnalogInObject *self, PyObject *Py_UNUSED(ignored)) +{ + double value; + struct moberg_status status = self->channel.read(self->channel.context, + &value); + if (!moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._AnalogIn(%d).read() failed with %d", + self->index, status.result); + } + return Py_BuildValue("f", value); +} + +static PyMethodDef MobergAnalogIn_methods[] = { + {"read", (PyCFunction) MobergAnalogIn_read, METH_NOARGS, + "Sample and return the AnalogIn value" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject MobergAnalogInType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "moberg.AnalogIn", + .tp_doc = "AnalogIn objects", + .tp_basicsize = sizeof(MobergAnalogInObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = MobergAnalogIn_new, + .tp_init = (initproc) MobergAnalogIn_init, + .tp_dealloc = (destructor) MobergAnalogIn_dealloc, + .tp_methods = MobergAnalogIn_methods, +}; + +/* + * moberg._AnalogOut class (should never be directly instatiated) + */ + +typedef struct { + PyObject_HEAD + PyObject *moberg_object; + int index; + struct moberg_analog_out channel; +} MobergAnalogOutObject; + +static void +MobergAnalogOut_dealloc(MobergAnalogOutObject *self) +{ + if (self->moberg_object) { + struct moberg *moberg = ((MobergObject*)self->moberg_object)->moberg; + struct moberg_status status = + moberg_analog_out_close(moberg, self->index, self->channel); + if (! moberg_OK(status)) { + fprintf(stderr, "Failed to close moberg._AnalogOut(%d) [errno=%d]\n", + self->index, status.result); + } + Py_DECREF(self->moberg_object); + } + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +MobergAnalogOut_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *moberg_object; + int index; + struct moberg_analog_out channel = {0}; + + static char *kwlist[] = { "moberg", "index", NULL }; + if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, + &moberg_object, &index)) { + goto err; + } + if (Py_TYPE(moberg_object) != &MobergType) { + PyErr_SetString(PyExc_AttributeError, "moberg argument is not Moberg"); + goto err; + } + struct moberg *moberg = ((MobergObject*)moberg_object)->moberg; + struct moberg_status status = moberg_analog_out_open(moberg, index, &channel); + if (! moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._AnalogOut(%d) failed with %d", + index, status.result); + goto err; + } + MobergAnalogOutObject *self; + self = (MobergAnalogOutObject *) type->tp_alloc(type, 0); + if (self == NULL) { goto close; } + Py_INCREF(moberg_object); + self->moberg_object = moberg_object; + self->index = index; + self->channel = channel; + return (PyObject *) self; +close: + status = moberg_analog_out_close(moberg, index, channel); +err: + return NULL; +} + +static int +MobergAnalogOut_init(MobergAnalogOutObject *self, PyObject *args, PyObject *kwds) +{ + PyErr_SetString(PyExc_AttributeError, "Not intended to be called"); + return -1; +} + +static PyObject * +MobergAnalogOut_write(MobergAnalogOutObject *self, PyObject *args) +{ + double value = 1.23; + if (! PyArg_ParseTuple(args, "d", &value)) { + goto err; + } + struct moberg_status status = self->channel.write(self->channel.context, + value); + if (!moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._AnalogOut(%d).write() failed with %d", + self->index, status.result); + goto err; + } + Py_INCREF(Py_None); + return Py_None; +err: + return NULL; +} + +static PyMethodDef MobergAnalogOut_methods[] = { + {"write", (PyCFunction) MobergAnalogOut_write, METH_VARARGS, + "Set AnalogOut value" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject MobergAnalogOutType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "moberg.AnalogOut", + .tp_doc = "AnalogOut objects", + .tp_basicsize = sizeof(MobergAnalogOutObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = MobergAnalogOut_new, + .tp_init = (initproc) MobergAnalogOut_init, + .tp_dealloc = (destructor) MobergAnalogOut_dealloc, + .tp_methods = MobergAnalogOut_methods, +}; + +/* + * moberg._DigitalIn class (should never be directly instatiated) + */ + +typedef struct { + PyObject_HEAD + PyObject *moberg_object; + int index; + struct moberg_digital_in channel; +} MobergDigitalInObject; + +static void +MobergDigitalIn_dealloc(MobergDigitalInObject *self) +{ + if (self->moberg_object) { + struct moberg *moberg = ((MobergObject*)self->moberg_object)->moberg; + struct moberg_status status = + moberg_digital_in_close(moberg, self->index, self->channel); + if (! moberg_OK(status)) { + fprintf(stderr, "Failed to close moberg._DigitalIn(%d) [errno=%d]\n", + self->index, status.result); + } + Py_DECREF(self->moberg_object); + } + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +MobergDigitalIn_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *moberg_object; + int index; + struct moberg_digital_in channel = {0}; + + static char *kwlist[] = { "moberg", "index", NULL }; + if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, + &moberg_object, &index)) { + goto err; + } + if (Py_TYPE(moberg_object) != &MobergType) { + PyErr_SetString(PyExc_AttributeError, "moberg argument is not Moberg"); + goto err; + } + struct moberg *moberg = ((MobergObject*)moberg_object)->moberg; + struct moberg_status status = moberg_digital_in_open(moberg, index, &channel); + if (! moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._DigitalIn(%d) failed with %d", + index, status.result); + goto err; + } + MobergDigitalInObject *self; + self = (MobergDigitalInObject *) type->tp_alloc(type, 0); + if (self == NULL) { goto close; } + Py_INCREF(moberg_object); + self->moberg_object = moberg_object; + self->index = index; + self->channel = channel; + return (PyObject *) self; +close: + status = moberg_digital_in_close(moberg, index, channel); +err: + return NULL; +} + +static int +MobergDigitalIn_init(MobergDigitalInObject *self, PyObject *args, PyObject *kwds) +{ + PyErr_SetString(PyExc_AttributeError, "Not intended to be called"); + return -1; +} + +static PyObject * +MobergDigitalIn_read(MobergDigitalInObject *self, PyObject *Py_UNUSED(ignored)) +{ + int value; + struct moberg_status status = self->channel.read(self->channel.context, + &value); + if (!moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._DigitalIn(%d).read() failed with %d", + self->index, status.result); + } + return Py_BuildValue("O", value ? Py_True: Py_False); +} + +static PyMethodDef MobergDigitalIn_methods[] = { + {"read", (PyCFunction) MobergDigitalIn_read, METH_NOARGS, + "Sample and return the DigitalIn value" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject MobergDigitalInType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "moberg.DigitalIn", + .tp_doc = "DigitalIn objects", + .tp_basicsize = sizeof(MobergDigitalInObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = MobergDigitalIn_new, + .tp_init = (initproc) MobergDigitalIn_init, + .tp_dealloc = (destructor) MobergDigitalIn_dealloc, + .tp_methods = MobergDigitalIn_methods, +}; + +/* + * moberg._DigitalOut class (should never be directly instatiated) + */ + +typedef struct { + PyObject_HEAD + PyObject *moberg_object; + int index; + struct moberg_digital_out channel; +} MobergDigitalOutObject; + +static void +MobergDigitalOut_dealloc(MobergDigitalOutObject *self) +{ + if (self->moberg_object) { + struct moberg *moberg = ((MobergObject*)self->moberg_object)->moberg; + struct moberg_status status = + moberg_digital_out_close(moberg, self->index, self->channel); + if (! moberg_OK(status)) { + fprintf(stderr, "Failed to close moberg._DigitalOut(%d) [errno=%d]\n", + self->index, status.result); + } + Py_DECREF(self->moberg_object); + } + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +MobergDigitalOut_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *moberg_object; + int index; + struct moberg_digital_out channel = {0}; + + static char *kwlist[] = { "moberg", "index", NULL }; + if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, + &moberg_object, &index)) { + goto err; + } + if (Py_TYPE(moberg_object) != &MobergType) { + PyErr_SetString(PyExc_AttributeError, "moberg argument is not Moberg"); + goto err; + } + struct moberg *moberg = ((MobergObject*)moberg_object)->moberg; + struct moberg_status status = moberg_digital_out_open(moberg, index, &channel); + if (! moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._DigitalOut(%d) failed with %d", + index, status.result); + goto err; + } + MobergDigitalOutObject *self; + self = (MobergDigitalOutObject *) type->tp_alloc(type, 0); + if (self == NULL) { goto close; } + Py_INCREF(moberg_object); + self->moberg_object = moberg_object; + self->index = index; + self->channel = channel; + return (PyObject *) self; +close: + status = moberg_digital_out_close(moberg, index, channel); +err: + return NULL; +} + +static int +MobergDigitalOut_init(MobergDigitalOutObject *self, PyObject *args, PyObject *kwds) +{ + PyErr_SetString(PyExc_AttributeError, "Not intended to be called"); + return -1; +} + +static PyObject * +MobergDigitalOut_write(MobergDigitalOutObject *self, PyObject *args) +{ + double value = 1.23; + if (! PyArg_ParseTuple(args, "d", &value)) { + goto err; + } + struct moberg_status status = self->channel.write(self->channel.context, + value); + if (!moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._DigitalOut(%d).write() failed with %d", + self->index, status.result); + goto err; + } + Py_INCREF(Py_None); + return Py_None; +err: + return NULL; +} + +static PyMethodDef MobergDigitalOut_methods[] = { + {"write", (PyCFunction) MobergDigitalOut_write, METH_VARARGS, + "Set DigitalOut value" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject MobergDigitalOutType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "moberg.DigitalOut", + .tp_doc = "DigitalOut objects", + .tp_basicsize = sizeof(MobergDigitalOutObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = MobergDigitalOut_new, + .tp_init = (initproc) MobergDigitalOut_init, + .tp_dealloc = (destructor) MobergDigitalOut_dealloc, + .tp_methods = MobergDigitalOut_methods, +}; + +/* + * moberg._EncoderIn class (should never be directly instatiated) + */ + +typedef struct { + PyObject_HEAD + PyObject *moberg_object; + int index; + struct moberg_encoder_in channel; +} MobergEncoderInObject; + +static void +MobergEncoderIn_dealloc(MobergEncoderInObject *self) +{ + if (self->moberg_object) { + struct moberg *moberg = ((MobergObject*)self->moberg_object)->moberg; + struct moberg_status status = + moberg_encoder_in_close(moberg, self->index, self->channel); + if (! moberg_OK(status)) { + fprintf(stderr, "Failed to close moberg._EncoderIn(%d) [errno=%d]\n", + self->index, status.result); + } + Py_DECREF(self->moberg_object); + } + Py_TYPE(self)->tp_free((PyObject *) self); +} + +static PyObject * +MobergEncoderIn_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *moberg_object; + int index; + struct moberg_encoder_in channel = {0}; + + static char *kwlist[] = { "moberg", "index", NULL }; + if (! PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, + &moberg_object, &index)) { + goto err; + } + if (Py_TYPE(moberg_object) != &MobergType) { + PyErr_SetString(PyExc_AttributeError, "moberg argument is not Moberg"); + goto err; + } + struct moberg *moberg = ((MobergObject*)moberg_object)->moberg; + struct moberg_status status = moberg_encoder_in_open(moberg, index, &channel); + if (! moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._EncoderIn(%d) failed with %d", + index, status.result); + goto err; + } + MobergEncoderInObject *self; + self = (MobergEncoderInObject *) type->tp_alloc(type, 0); + if (self == NULL) { goto close; } + Py_INCREF(moberg_object); + self->moberg_object = moberg_object; + self->index = index; + self->channel = channel; + return (PyObject *) self; +close: + status = moberg_encoder_in_close(moberg, index, channel); +err: + return NULL; +} + +static int +MobergEncoderIn_init(MobergEncoderInObject *self, PyObject *args, PyObject *kwds) +{ + PyErr_SetString(PyExc_AttributeError, "Not intended to be called"); + return -1; +} + +static PyObject * +MobergEncoderIn_read(MobergEncoderInObject *self, PyObject *Py_UNUSED(ignored)) +{ + long value; + struct moberg_status status = self->channel.read(self->channel.context, + &value); + if (!moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._EncoderIn(%d).read() failed with %d", + self->index, status.result); + } + return Py_BuildValue("l", value); +} + +static PyMethodDef MobergEncoderIn_methods[] = { + {"read", (PyCFunction) MobergEncoderIn_read, METH_NOARGS, + "Sample and return the EncoderIn value" + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject MobergEncoderInType = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "moberg.EncoderIn", + .tp_doc = "EncoderIn objects", + .tp_basicsize = sizeof(MobergEncoderInObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_new = MobergEncoderIn_new, + .tp_init = (initproc) MobergEncoderIn_init, + .tp_dealloc = (destructor) MobergEncoderIn_dealloc, + .tp_methods = MobergEncoderIn_methods, +}; + +/* + * Module initialization + */ + +#if PY_MAJOR_VERSION >= 3 + +static PyModuleDef mobergmodule = { + PyModuleDef_HEAD_INIT, + .m_name = "moberg", + .m_doc = "Moberg I/O interface module.", + .m_size = -1, +}; + +#define INITERROR return NULL + +PyMODINIT_FUNC +PyInit_moberg(void) +#else + +#define INITERROR return + +PyMODINIT_FUNC initmoberg(void) +#endif +{ + PyObject *m; + if (PyType_Ready(&MobergType) < 0 || + PyType_Ready(&MobergAnalogInType) < 0 || + PyType_Ready(&MobergAnalogOutType) < 0 || + PyType_Ready(&MobergDigitalInType) < 0 || + PyType_Ready(&MobergDigitalOutType) < 0 || + PyType_Ready(&MobergEncoderInType) < 0) { + INITERROR; + } + +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&mobergmodule); +#else + static PyMethodDef methods[] = { {NULL, NULL, 0, NULL} }; + m = Py_InitModule("moberg", methods); +#endif + if (m == NULL) { + INITERROR; + } + + Py_INCREF(&MobergType); + PyModule_AddObject(m, "Moberg", (PyObject *) &MobergType); + Py_INCREF(&MobergAnalogInType); + PyModule_AddObject(m, "_AnalogIn", (PyObject *) &MobergAnalogInType); + Py_INCREF(&MobergAnalogOutType); + PyModule_AddObject(m, "_AnalogOut", (PyObject *) &MobergAnalogOutType); + Py_INCREF(&MobergDigitalInType); + PyModule_AddObject(m, "_DigitalIn", (PyObject *) &MobergDigitalInType); + Py_INCREF(&MobergDigitalOutType); + PyModule_AddObject(m, "_DigitalOut", (PyObject *) &MobergDigitalOutType); + Py_INCREF(&MobergEncoderInType); + PyModule_AddObject(m, "_EncoderIn", (PyObject *) &MobergEncoderInType); + +#if PY_MAJOR_VERSION >= 3 + return m; +#endif +} diff --git a/adaptors/python/setup.py b/adaptors/python/setup.py new file mode 100755 index 0000000..2e5fa2f --- /dev/null +++ b/adaptors/python/setup.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +from distutils.core import setup, Extension + +module = Extension('moberg', + sources = ['python-moberg.c'], + include_dirs=['../..'], + libraries=['moberg']) +longdesc = '''This extension provides bindings to the Moberg I/O library +''' + +try: + import os + VERSION=os.environ['MOBERG_VERSION'] +except KeyError: + VERSION='_UNKNOWN_' + pass + +setup( + name = 'python-moberg', + version = VERSION, + description = 'Python bindings to the Moberg I/O library', + long_description = longdesc, + author = 'Anders Blomdell', + author_email = 'anders.blomdell@control.lth.se', + url = 'http://gitlab.control.lth.se/anders_blomdell/moberg.git', + license = 'GPLv2', + platforms = 'Linux', + ext_modules = [module]) -- GitLab