Commit 1ff01145 authored by Joseph Mirabel's avatar Joseph Mirabel Committed by Guilhem Saurel

Add SignalWrapper which allows to bind a Python function to a signal.

parent 582b6658
......@@ -73,6 +73,7 @@ ADD_LIBRARY(${PYTHON_MODULE}
factory-py.cc
pool-py.cc
signal-caster-py.cc
signal-wrapper.cc
)
# Remove prefix lib
......
......@@ -23,6 +23,7 @@
#include <dynamic-graph/signal-base.h>
#include "exception.hh"
#include "signal-wrapper.hh"
namespace dynamicgraph {
namespace python {
......@@ -30,6 +31,7 @@ namespace dynamicgraph {
// Declare functions defined in other source files
namespace signalBase {
extern PyObject* create(PyObject* self, PyObject* args);
extern PyObject* createSignalWrapper(PyObject* self, PyObject* args);
extern PyObject* getTime(PyObject* self, PyObject* args);
extern PyObject* setTime(PyObject* self, PyObject* args);
extern PyObject* getName(PyObject* self, PyObject* args);
......@@ -151,6 +153,8 @@ static PyMethodDef dynamicGraphMethods[] = {
// Signals
{"create_signal_base", dynamicgraph::python::signalBase::create, METH_VARARGS,
"create a SignalBase C++ object"},
{"create_signal_wrapper", dynamicgraph::python::signalBase::createSignalWrapper, METH_VARARGS,
"create a SignalWrapper C++ object"},
{"signal_base_get_time", dynamicgraph::python::signalBase::getTime,
METH_VARARGS, "Get time of a SignalBase"},
{"signal_base_set_time", dynamicgraph::python::signalBase::setTime,
......
......@@ -25,6 +25,7 @@
#include "convert-dg-to-py.hh"
#include "exception.hh"
#include "signal-wrapper.hh"
using dynamicgraph::SignalBase;
......@@ -56,6 +57,58 @@ namespace dynamicgraph {
return PyCObject_FromVoidPtr((void*)obj, destroy);
}
template <class T> void* createSignalWrapperTpl (const char* name, PyObject* o, std::string& error)
{
typedef SignalWrapper<T, int> SignalWrapper_t;
if (!SignalWrapper_t::checkCallable (o, error)) {
return NULL;
}
SignalWrapper_t* obj = new SignalWrapper_t(name, o);
return (void*) obj;
}
#define SIGNAL_WRAPPER_TYPE(IF, Enum, Type) \
IF (command::Value::typeName(command::Value::Enum) \
.compare(type) == 0) { \
obj = createSignalWrapperTpl<Type> (name, object, error); \
}
/**
\brief Create an instance of SignalWrapper
*/
PyObject* createSignalWrapper(PyObject* /*self*/, PyObject* args)
{
char *name = NULL;
char *type = NULL;
PyObject* object = NULL;
if (!PyArg_ParseTuple(args, "ssO", &name, &type, &object))
return NULL;
void* obj = NULL;
std::string error;
SIGNAL_WRAPPER_TYPE( if, BOOL ,bool)
// SIGNAL_WRAPPER_TYPE(else if, UNSIGNED ,bool)
SIGNAL_WRAPPER_TYPE(else if, INT ,int )
SIGNAL_WRAPPER_TYPE(else if, FLOAT ,float )
SIGNAL_WRAPPER_TYPE(else if, DOUBLE ,double)
// SIGNAL_WRAPPER_TYPE(else if, STRING ,bool)
SIGNAL_WRAPPER_TYPE(else if, VECTOR ,Vector)
// SIGNAL_WRAPPER_TYPE(else if, MATRIX ,bool)
// SIGNAL_WRAPPER_TYPE(else if, MATRIX4D ,bool)
else {
error = "Type not understood";
}
if (obj == NULL) {
PyErr_SetString(dgpyError, error.c_str());
return NULL;
}
// Return the pointer
return PyCObject_FromVoidPtr(obj, destroy);
}
/**
\brief Destroy an instance of InvertedPendulum
*/
......
// Copyright (c) 2018, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of dynamic-graph-python.
// dynamic-graph-python is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// dynamic-graph-python 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 Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// dynamic-graph-python. If not, see <http://www.gnu.org/licenses/>.
#include <Python.h>
#include <signal-wrapper.hh>
namespace dynamicgraph {
namespace python {
namespace signalWrapper {
void convert (PyObject* o, bool & v) { v = (o == Py_True); }
void convert (PyObject* o, int & v) { v = (int)PyInt_AS_LONG (o); }
void convert (PyObject* o, float & v) { v = (float)PyFloat_AS_DOUBLE (o); }
void convert (PyObject* o, double& v) { v = PyFloat_AS_DOUBLE (o); }
void convert (PyObject* o, Vector & v)
{
v.resize(PyTuple_Size(o));
for (int i = 0; i < v.size(); ++i)
convert(PyTuple_GetItem(o,i), v[i]);
}
}
template <class T, class Time>
bool SignalWrapper<T,Time>::checkCallable (PyObject* c, std::string& error)
{
if (PyCallable_Check(c) == 0) {
PyObject* str = PyObject_Str(c);
error = PyString_AsString(str);
error += " is not callable";
Py_DECREF(str);
return false;
}
return true;
}
template class SignalWrapper<bool , int>;
template class SignalWrapper<int , int>;
template class SignalWrapper<float , int>;
template class SignalWrapper<double, int>;
template class SignalWrapper<Vector, int>;
} // namespace dynamicgraph
} // namespace python
// Copyright (c) 2018, Joseph Mirabel
// Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
//
// This file is part of dynamic-graph-python.
// dynamic-graph-python is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// dynamic-graph-python 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 Lesser Public License for more details. You should have
// received a copy of the GNU Lesser General Public License along with
// dynamic-graph-python. If not, see <http://www.gnu.org/licenses/>.
#include <Python.h>
#include <dynamic-graph/linear-algebra.h>
#include <dynamic-graph/signal.h>
namespace dynamicgraph {
namespace python {
namespace signalWrapper {
void convert (PyObject* o, int & v);
void convert (PyObject* o, bool & v);
void convert (PyObject* o, float & v);
void convert (PyObject* o, double& v);
// void convert (PyObject* o, std::string& v);
void convert (PyObject* o, Vector & v);
// void convert (PyObject* o, Eigen::MatrixXd& v);
// void convert (PyObject* o, Eigen::Matrix4d& v);
}
template <class T, class Time>
class SignalWrapper : public Signal<T, Time>
{
public:
typedef Signal<T,Time> parent_t;
static bool checkCallable (PyObject* c, std::string& error);
SignalWrapper (std::string name, PyObject* _callable) :
parent_t (name)
, callable (_callable)
// , argsTuple (NULL)
// , argTime (NULL)
// , argValue (NULL)
{
typedef boost::function2<T&,T&,Time> function_t;
Py_INCREF(callable);
function_t f = boost::bind (&SignalWrapper::call, this, _1, _2);
this->setFunction (f);
// argsTuple = PyTuple_New(1);
// argTime = Py
}
virtual ~SignalWrapper ()
{
Py_DECREF(callable);
// Py_DECREF(args);
};
private:
T& call (T& value, Time t)
{
char format[] = "i";
PyObject* obj = PyObject_CallFunction(callable, format, t);
if (obj == NULL)
std::cerr << "Could not call callable" << std::endl;
else {
signalWrapper::convert (obj, value);
Py_DECREF(obj);
}
return value;
}
PyObject* callable;
// PyObject* argsTuple;
// PyObject* argTime;
// PyObject* argValue;
};
} // namespace dynamicgraph
} // namespace python
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment