diff --git a/adaptors/java/.gitignore b/adaptors/java/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..6b468b62a9884e67ca19b673f8e14e1931d65036 --- /dev/null +++ b/adaptors/java/.gitignore @@ -0,0 +1 @@ +*.class diff --git a/adaptors/java/src/Makefile b/adaptors/java/src/Makefile index 2f5a03ef519c268bb1f9287ffcd3bd8190df5244..c9e9ea01f2a88d566d2023e099104a1d3a2889b5 100644 --- a/adaptors/java/src/Makefile +++ b/adaptors/java/src/Makefile @@ -3,8 +3,6 @@ JARNAME=Moberg TARFILE=java_se.lth.control.realtime.Moberg-$(VERSION).tar.gz JNINAME=se_lth_control_realtime_moberg_Moberg -JAVAH_PATH=$(shell javah -Xbootclasspath/p:build -version >/dev/null 2>&1 && \ - echo -Xbootclasspath/p:build || echo -bootclasspath build) JNI_INCLUDE=/usr/lib/jvm/java/include/ CC=gcc CC_JNI_FLAGS=-Wall -Werror -shared -fPIC \ @@ -44,7 +42,7 @@ JAVAC: $(JAVAFILES:%.java=build/%.class) build/%.class: src/%.java # Recompile all javafiles at once (do JIT compilation once) mkdir -p build - cd src ; javac -d ../build -target 1.5 -source 1.5 $(JAVAFILES) + cd src ; javac -d ../build $(JAVAFILES) build/$(JARNAME).jar: JAVAC jar -cf $@ \ @@ -53,7 +51,7 @@ build/$(JARNAME).jar: JAVAC build/%.h: $(shell echo $(JNINAME:%=build/%.class) | sed -e 's:_:/:g') # Too many dependencies, base the ones we need on $* (matches % above) - javah -o $@ -force $(JAVAH_PATH) $(shell echo $* | sed -e s/_/./g) + cd src ; javac -h ../$(dir $@) $(shell echo $* | sed -e 's|_|/|g').java build/lib%.so: $(JNINAME:%=build/%.h) $(JNINAME:%=src/%.c) # Too many dependencies, base the ones we need on $* (matches % above) diff --git a/adaptors/python/.gitignore b/adaptors/python2/.gitignore similarity index 100% rename from adaptors/python/.gitignore rename to adaptors/python2/.gitignore diff --git a/adaptors/python/Makefile b/adaptors/python2/Makefile similarity index 68% rename from adaptors/python/Makefile rename to adaptors/python2/Makefile index 9f966ec414f14b119092b8ec03a6e9715fb3d347..eeb6d4596350123987bb6e5fe0f537587c08584c 100644 --- a/adaptors/python/Makefile +++ b/adaptors/python2/Makefile @@ -5,14 +5,11 @@ all: BUILD INSTALL .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/python2/python-moberg.c b/adaptors/python2/python-moberg.c new file mode 100644 index 0000000000000000000000000000000000000000..3ebadf94f8aa1504397e0349e698f8a97e35f947 --- /dev/null +++ b/adaptors/python2/python-moberg.c @@ -0,0 +1,771 @@ +/* + 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("d", 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 desired_value, actual_value; + if (! PyArg_ParseTuple(args, "d", &desired_value)) { + goto err; + } + struct moberg_status status = self->channel.write(self->channel.context, + desired_value, + &actual_value); + if (!moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._AnalogOut(%d).write() failed with %d", + self->index, status.result); + goto err; + } + + return Py_BuildValue("d", actual_value); +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) +{ + PyObject *desired; + int actual; + if (! PyArg_ParseTuple(args, "O", &desired)) { + goto err; + } + struct moberg_status status = self->channel.write(self->channel.context, + PyObject_IsTrue(desired), + &actual); + if (!moberg_OK(status)) { + PyErr_Format(PyExc_OSError, "moberg._DigitalOut(%d).write() failed with %d", + self->index, status.result); + goto err; + } + return Py_BuildValue("O", actual ? Py_True: Py_False); +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 + */ + +#define INITERROR return + +PyMODINIT_FUNC initmoberg(void) +{ + 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; + } + + static PyMethodDef methods[] = { {NULL, NULL, 0, NULL} }; + m = Py_InitModule("moberg", methods); + 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); + +} diff --git a/adaptors/python/setup.py b/adaptors/python2/setup.py similarity index 100% rename from adaptors/python/setup.py rename to adaptors/python2/setup.py diff --git a/adaptors/python3/.gitignore b/adaptors/python3/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..f65eb2942dc78eb04f2d5d1e680fd693a7f484aa --- /dev/null +++ b/adaptors/python3/.gitignore @@ -0,0 +1,2 @@ +/__pycache__ +/install \ No newline at end of file diff --git a/adaptors/python3/Makefile b/adaptors/python3/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..486da900f2eb2bb5af6bd79b991ea53fc8ac77ac --- /dev/null +++ b/adaptors/python3/Makefile @@ -0,0 +1,15 @@ +MOBERG_VERSION=$(shell git describe --tags) + +all: BUILD INSTALL + +.PHONY: BUILD +BUILD: + python3 ./setup.py build + +.PHONY: INSTALL +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/python3/python-moberg.c similarity index 98% rename from adaptors/python/python-moberg.c rename to adaptors/python3/python-moberg.c index c00392e16191776529bfeffa16dacf640c4e16f0..c19373dfc1e9970ca776e96c120beecf4948be24 100644 --- a/adaptors/python/python-moberg.c +++ b/adaptors/python3/python-moberg.c @@ -735,8 +735,6 @@ static PyTypeObject MobergEncoderInType = { * Module initialization */ -#if PY_MAJOR_VERSION >= 3 - static PyModuleDef mobergmodule = { PyModuleDef_HEAD_INIT, .m_name = "moberg", @@ -748,12 +746,6 @@ static PyModuleDef mobergmodule = { PyMODINIT_FUNC PyInit_moberg(void) -#else - -#define INITERROR return - -PyMODINIT_FUNC initmoberg(void) -#endif { PyObject *m; if (PyType_Ready(&MobergType) < 0 || @@ -765,12 +757,7 @@ PyMODINIT_FUNC initmoberg(void) 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; } @@ -788,7 +775,5 @@ PyMODINIT_FUNC initmoberg(void) Py_INCREF(&MobergEncoderInType); PyModule_AddObject(m, "_EncoderIn", (PyObject *) &MobergEncoderInType); -#if PY_MAJOR_VERSION >= 3 return m; -#endif } diff --git a/adaptors/python3/setup.py b/adaptors/python3/setup.py new file mode 100755 index 0000000000000000000000000000000000000000..2e5fa2fdfa166fde009731479e2986c639f6607a --- /dev/null +++ b/adaptors/python3/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])