diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bd0008b1b2639ccf6354dae8ff497a54ff986eac..8ddf198c5a15dcc81dd97a25458daf242a16acfa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,16 +54,17 @@ INSTALL(TARGETS ${LIBRARY_NAME} SET(PYTHON_MODULE wrap) ADD_LIBRARY(${PYTHON_MODULE} - MODULE - exception-python.cc - convert-dg-to-py.cc - dynamic-graph-py.cc - signal-base-py.cc - entity-py.cc - factory-py.cc - pool-py.cc - signal-caster-py.cc - signal-wrapper.cc + MODULE + convert-dg-to-py.cc + debug-py.cc + dynamic-graph-py.cc + entity-py.cc + exception-python.cc + factory-py.cc + pool-py.cc + signal-base-py.cc + signal-caster-py.cc + signal-wrapper.cc ) # Remove prefix lib @@ -117,5 +118,3 @@ ELSE(WIN32) SET(TRACERREALTIME_PLUGIN ${DYNAMIC_GRAPH_PLUGINDIR}/tracer-real-time${CMAKE_SHARED_LIBRARY_SUFFIX}) ENDIF(WIN32) DYNAMIC_GRAPH_PYTHON_MODULE("tracer_real_time" ${TRACERREALTIME_PLUGIN} tracer_real_time-wrap) - - diff --git a/src/debug-py.cc b/src/debug-py.cc new file mode 100644 index 0000000000000000000000000000000000000000..d12b1b356f8cad9683bd793964d4ff1dc0bd874e --- /dev/null +++ b/src/debug-py.cc @@ -0,0 +1,95 @@ +// Copyright 2019, Olivier Stasse, LAAS-CNRS. +// +// See LICENSE + +#include <iostream> + +#define ENABLE_RT_LOG +#include <dynamic-graph/real-time-logger.h> + +#include <map> +#include <Python.h> +#include <dynamic-graph/pool.h> +#include <dynamic-graph/entity.h> +#include <vector> +#include "exception.hh" + +#include <boost/shared_ptr.hpp> + +typedef boost::shared_ptr<std::ofstream> ofstreamShrPtr; + +namespace dynamicgraph { + namespace python { + + extern PyObject* dgpyError; + namespace debug { + + std::map<std::string, ofstreamShrPtr > mapOfFiles_; + + PyObject* addLoggerFileOutputStream (PyObject* /*self*/, PyObject* args) + { + char* filename; + if (!PyArg_ParseTuple(args, "s", &filename)) + return NULL; + std::string sfilename(filename); + try { + std::ofstream *aofs = new std::ofstream; + ofstreamShrPtr ofs_shrptr = boost::shared_ptr<std::ofstream>(aofs); + aofs->open(filename, + std::ofstream::out); + dynamicgraph::RealTimeLogger::instance(); + dgADD_OSTREAM_TO_RTLOG(*aofs); + dgRTLOG() << "Added " << filename << " as an output stream \n"; + mapOfFiles_[sfilename]= ofs_shrptr; + } CATCH_ALL_EXCEPTIONS(); + return Py_BuildValue (""); + } + + PyObject* closeLoggerFileOutputStream (PyObject* /*self*/, PyObject* /*args */) + { + try { + for (std::map<std::string,ofstreamShrPtr>::iterator + it=mapOfFiles_.begin(); + it!=mapOfFiles_.end(); ++it) + { + it->second->close(); + } + } CATCH_ALL_EXCEPTIONS(); + return Py_BuildValue (""); + } + + PyObject* addLoggerCoutOutputStream (PyObject* /*self*/, PyObject* /*args*/) + { + try { + dgADD_OSTREAM_TO_RTLOG(std::cout); + } CATCH_ALL_EXCEPTIONS(); + return Py_BuildValue (""); + } + + PyObject* realTimeLoggerDestroy (PyObject* /*self*/, PyObject* /*args*/) + { + try { + RealTimeLogger::destroy(); + } CATCH_ALL_EXCEPTIONS(); + return Py_BuildValue (""); + } + + PyObject* realTimeLoggerSpinOnce (PyObject* /*self*/, PyObject* /*args*/) + { + try { + RealTimeLogger::instance().spinOnce(); + } CATCH_ALL_EXCEPTIONS(); + return Py_BuildValue (""); + } + + PyObject* realTimeLoggerInstance (PyObject* /*self*/, PyObject* /*args*/) + { + try { + RealTimeLogger::instance(); + } CATCH_ALL_EXCEPTIONS(); + return Py_BuildValue (""); + } + + } // python + } // namespace debug +} // dynamicgraph diff --git a/src/dynamic-graph-py.cc b/src/dynamic-graph-py.cc index bed9a046fae96390801aba005cc307e6c1ea3ccc..8021647b87f50c05b9c8fb2dd35fdd1f7e9c90d0 100644 --- a/src/dynamic-graph-py.cc +++ b/src/dynamic-graph-py.cc @@ -60,6 +60,10 @@ namespace dynamicgraph { extern PyObject* getDocString(PyObject* self, PyObject* args); extern PyObject* setLoggerVerbosityLevel(PyObject*self, PyObject *args); extern PyObject* getLoggerVerbosityLevel(PyObject *self, PyObject *args); + extern PyObject* setTimeSample(PyObject*self, PyObject *args); + extern PyObject* getTimeSample(PyObject *self, PyObject *args); + extern PyObject* setStreamPrintPeriod(PyObject*self, PyObject *args); + extern PyObject* getStreamPrintPeriod(PyObject *self, PyObject *args); } namespace factory { @@ -72,6 +76,15 @@ namespace dynamicgraph { extern PyObject* writeGraph (PyObject* self, PyObject* args); extern PyObject* getEntityList(PyObject* self, PyObject* args); } + namespace debug { + extern PyObject* addLoggerFileOutputStream(PyObject* self, PyObject* args); + extern PyObject* addLoggerCoutOutputStream(PyObject* self, PyObject* args); + extern PyObject* closeLoggerFileOutputStream(PyObject* self, PyObject* args); + extern PyObject* realTimeLoggerSpinOnce(PyObject* self, PyObject* args); + extern PyObject* realTimeLoggerDestroy(PyObject* self, PyObject* args); + extern PyObject* realTimeLoggerInstance(PyObject* self, PyObject* args); + + } PyObject* dgpyError; @@ -237,6 +250,46 @@ static PyMethodDef dynamicGraphMethods[] = { dynamicgraph::python::entity::getLoggerVerbosityLevel, METH_VARARGS, "get the verbosity level of the entity"}, + {"addLoggerFileOutputStream", + dynamicgraph::python::debug::addLoggerFileOutputStream, + METH_VARARGS, + "add a output file stream to the logger by filename"}, + {"addLoggerCoutOutputStream", + dynamicgraph::python::debug::addLoggerCoutOutputStream, + METH_VARARGS, + "add std::cout as output stream to the logger"}, + {"closeLoggerFileOutputStream", + dynamicgraph::python::debug::closeLoggerFileOutputStream, + METH_VARARGS, + "close all the loggers file output streams."}, + {"entity_set_time_sample", + dynamicgraph::python::entity::setTimeSample, + METH_VARARGS, + "set the time sample for printing debugging information"}, + {"entity_get_time_sample", + dynamicgraph::python::entity::getTimeSample, + METH_VARARGS, + "get the time sample for printing debugging information"}, + {"entity_set_stream_print_period", + dynamicgraph::python::entity::setStreamPrintPeriod, + METH_VARARGS, + "set the period at which debugging information are printed"}, + {"entity_get_stream_print_period", + dynamicgraph::python::entity::getStreamPrintPeriod, + METH_VARARGS, + "get the period at which debugging information are printed"}, + {"real_time_logger_destroy", + dynamicgraph::python::debug::realTimeLoggerDestroy, + METH_VARARGS, + "Destroy the real time logger."}, + {"real_time_logger_spin_once", + dynamicgraph::python::debug::realTimeLoggerSpinOnce, + METH_VARARGS, + "Destroy the real time logger."}, + {"real_time_logger_instance", + dynamicgraph::python::debug::realTimeLoggerInstance, + METH_VARARGS, + "Starts the real time logger."}, {NULL, NULL, 0, NULL} /* Sentinel */ }; diff --git a/src/dynamic_graph/entity.py b/src/dynamic_graph/entity.py index e28e18d3a8d2d3e5d3b6193680a1a99a0c6aa6af..d95964bed7b9b9fa971d79069fb8c210070bd226 100644 --- a/src/dynamic_graph/entity.py +++ b/src/dynamic_graph/entity.py @@ -63,13 +63,13 @@ def updateEntityClasses(dictionary): from enum import Enum class VerbosityLevel(Enum): - """ + """ Enum class for setVerbosityLevel """ VERBOSITY_ALL =0 VERBOSITY_INFO_WARNING_ERROR = 1 VERBOSITY_WARNING_ERROR = 2 - VERBOSITY_ERROR = 3 + VERBOSITY_ERROR = 3 VERBOSITY_NONE = 4 class Entity (object) : @@ -84,7 +84,7 @@ class Entity (object) : entities = dict () - + def __init__(self, className, instanceName): """ Constructor: if not called by a child class, create and store a pointer @@ -257,13 +257,13 @@ class Entity (object) : self.boundNewCommand( cmd ) def setLoggerVerbosityLevel(self,verbosity): - """ + """ Specify for the entity the verbosity level """ return wrap.entity_set_logger_verbosity(self.obj, verbosity) def getLoggerVerbosityLevel(self): - """ + """ Returns the entity's verbosity level """ r=wrap.entity_get_logger_verbosity(self.obj) @@ -276,3 +276,27 @@ class Entity (object) : elif r==3: return VerbosityLevel.VERBOSITY_ERROR return VerbosityLevel.VERBOSITY_NONE + + def setTimeSample(self,timeSample): + """ + Specify for the entity the time at which call is counted. + """ + return wrap.entity_set_time_sample(self.obj, timeSample) + + def getTimeSample(self): + """ + Returns for the entity the time at which call is counted. + """ + return wrap.entity_get_time_sample(self.obj) + + def setStreamPrintPeriod(self,streamPrintPeriod): + """ + Specify for the entity the period at which debugging information is printed + """ + return wrap.entity_set_stream_print_period(self.obj, streamPrintPeriod) + + def getStreamPrintPeriod(self): + """ + Returns for the entity the period at which debugging information is printed + """ + return wrap.entity_get_stream_print_period(self.obj) diff --git a/src/entity-py.cc b/src/entity-py.cc index 63fb344d6deda7d198888a99a0b4181083ca3b46..325e3e7ac2ea4dbdb3ea138851be4203d06aa0cb 100644 --- a/src/entity-py.cc +++ b/src/entity-py.cc @@ -437,7 +437,7 @@ namespace dynamicgraph { // Retrieve object verbosity level PyObject* valueOfVerbosityLevel = PyObject_GetAttrString(objectVerbosityLevel, "value"); - long verbosityLevel = PyLong_AsLong(valueOfVerbosityLevel);//*((int*) lpointer); + long verbosityLevel = PyLong_AsLong(valueOfVerbosityLevel); try { switch(verbosityLevel) @@ -457,11 +457,11 @@ namespace dynamicgraph { PyErr_SetString(dgpyError, exc.what()); return NULL; } catch (const char* s) { - PyErr_SetString(dgpyError, s); - return NULL; + PyErr_SetString(dgpyError, s); + return NULL; } catch (...) { - PyErr_SetString(dgpyError, "Unknown exception"); - return NULL; + PyErr_SetString(dgpyError, "Unknown exception"); + return NULL; } return Py_BuildValue(""); @@ -495,6 +495,136 @@ namespace dynamicgraph { return Py_BuildValue("i",ares); } + /** + \brief Get stream print period + */ + PyObject* getStreamPrintPeriod(PyObject* /*self*/, PyObject* args) + { + PyObject* object = NULL; + if (!PyArg_ParseTuple(args, "O", &object)) + return NULL; + + // Retrieve the entity instance + if (!PyCObject_Check(object)) { + PyErr_SetString(PyExc_TypeError, + "first argument is not an object"); + return NULL; + } + + void *pointer = PyCObject_AsVoidPtr(object); + Entity* entity = (Entity*)pointer; + + double r ; + try { + r = entity->getStreamPrintPeriod(); + } CATCH_ALL_EXCEPTIONS(); + + return Py_BuildValue("d",r); + } + + /** + \brief Set print period + */ + PyObject* setStreamPrintPeriod(PyObject* /*self*/, PyObject* args ) + { + + PyObject* object = NULL; + double streamPrintPeriod=0; + if (!PyArg_ParseTuple(args, "Od", &object,&streamPrintPeriod)) + return NULL; + + // Retrieve the entity instance + if (!PyCObject_Check(object)) { + PyErr_SetString(PyExc_TypeError, + "First argument should be an object"); + return NULL; + } + + void *pointer = PyCObject_AsVoidPtr(object); + Entity* entity = (Entity*)pointer; + + try { + entity->setStreamPrintPeriod(streamPrintPeriod); + + } catch (const std::exception& exc) { + PyErr_SetString(dgpyError, exc.what()); + return NULL; + } catch (const char* s) { + PyErr_SetString(dgpyError, s); + return NULL; + } catch (...) { + PyErr_SetString(dgpyError, "Unknown exception"); + return NULL; + } + + return Py_BuildValue(""); + } + + /** + \brief Get stream print period + */ + PyObject* getTimeSample(PyObject* /*self*/, PyObject* args) + { + PyObject* object = NULL; + if (!PyArg_ParseTuple(args, "O", &object)) + return NULL; + + // Retrieve the entity instance + if (!PyCObject_Check(object)) { + PyErr_SetString(PyExc_TypeError, + "first argument is not an object"); + return NULL; + } + + void *pointer = PyCObject_AsVoidPtr(object); + Entity* entity = (Entity*)pointer; + + double r ; + try { + r = entity->getTimeSample(); + } CATCH_ALL_EXCEPTIONS(); + + return Py_BuildValue("d",r); + } + + /** + \brief Set time sample + */ + PyObject* setTimeSample(PyObject* /*self*/, PyObject* args ) + { + + PyObject* object = NULL; + double timeSample; + if (!PyArg_ParseTuple(args, "Od", &object,&timeSample)) + return NULL; + + // Retrieve the entity instance + if (!PyCObject_Check(object)) { + PyErr_SetString(PyExc_TypeError, + "First argument should be an object"); + return NULL; + } + + void *pointer = PyCObject_AsVoidPtr(object); + Entity* entity = (Entity*)pointer; + + try { + entity->setTimeSample(timeSample); + + } catch (const std::exception& exc) { + PyErr_SetString(dgpyError, exc.what()); + return NULL; + } catch (const char* s) { + PyErr_SetString(dgpyError, s); + return NULL; + } catch (...) { + PyErr_SetString(dgpyError, "Unknown exception"); + return NULL; + } + + return Py_BuildValue(""); + } + } } diff --git a/src/pool-py.cc b/src/pool-py.cc index c9085c2442745dba144805b428229c0b724addba..2caa96cc42a566b097d1fdb6ce2814bdfc8eb0c6 100644 --- a/src/pool-py.cc +++ b/src/pool-py.cc @@ -24,6 +24,7 @@ namespace dynamicgraph { extern PyObject* dgpyError; namespace pool { + PyObject* writeGraph (PyObject* /*self*/, PyObject* args) { char* filename; @@ -52,16 +53,16 @@ namespace dynamicgraph { Py_ssize_t classNumber = listOfEntities.size(); // Build a tuple object PyObject* classTuple = PyTuple_New(classNumber); - + Py_ssize_t iEntity = 0; - for (PoolStorage::Entities::const_iterator entity_it = + for (PoolStorage::Entities::const_iterator entity_it = listOfEntities.begin(); entity_it != listOfEntities.end(); ++entity_it) { const std::string & aname = entity_it->second->getName(); - - PyObject* className = + + PyObject* className = Py_BuildValue("s", aname.c_str()); PyTuple_SetItem(classTuple, iEntity, className); iEntity++; @@ -71,6 +72,7 @@ namespace dynamicgraph { return NULL; } + } // python - } // dynamicgraph -} // namespace pool + } // namespace pool +} // dynamicgraph diff --git a/unitTesting/custom_entity.cpp b/unitTesting/custom_entity.cpp index 5f5aa33a1ca5781d8ce8191fbb0d5057c483f9af..12e9fd7e4d48d0abb32e36de8531eaa5185494ca 100644 --- a/unitTesting/custom_entity.cpp +++ b/unitTesting/custom_entity.cpp @@ -36,6 +36,7 @@ namespace dynamicgraph "CustomEntity("+name+")::input(double)::out_double") { + addSignal(); } void addSignal() @@ -53,6 +54,18 @@ namespace dynamicgraph { const double &aDouble = m_sigdSIN(inTime); res = aDouble; + std::ostringstream oss; + oss << "start update " << res; + sendMsg(oss.str().c_str(),MSG_TYPE_ERROR); + sendMsg("This is a message of level MSG_TYPE_DEBUG",MSG_TYPE_DEBUG); + sendMsg("This is a message of level MSG_TYPE_INFO",MSG_TYPE_INFO); + sendMsg("This is a message of level MSG_TYPE_WARNING",MSG_TYPE_WARNING); + sendMsg("This is a message of level MSG_TYPE_ERROR",MSG_TYPE_ERROR); + sendMsg("This is a message of level MSG_TYPE_DEBUG_STREAM",MSG_TYPE_DEBUG_STREAM); + sendMsg("This is a message of level MSG_TYPE_INFO_STREAM",MSG_TYPE_INFO_STREAM); + sendMsg("This is a message of level MSG_TYPE_WARNING_STREAM",MSG_TYPE_WARNING_STREAM); + sendMsg("This is a message of level MSG_TYPE_ERROR_STREAM",MSG_TYPE_ERROR_STREAM); + sendMsg("end update",MSG_TYPE_ERROR); return res; } diff --git a/unitTesting/test_custom_entity.py b/unitTesting/test_custom_entity.py index 92903c0231674fed34f97b79d4cc1850f15f47bf..b9c264c25c89fbf04c2df2fe18682e5e219642f9 100644 --- a/unitTesting/test_custom_entity.py +++ b/unitTesting/test_custom_entity.py @@ -1,7 +1,9 @@ # Olivier Stasse # 2019 CNRS -# +# import sys, os +import time + # Put local python module at first priority sys.path.insert(0,os.getcwd()+'/../src') sys.path.insert(0,os.getcwd()) @@ -9,18 +11,63 @@ sys.path.insert(0,os.getcwd()) print(os.getcwd()) from dynamic_graph_tests.custom_entity import * from dynamic_graph.entity import VerbosityLevel +from dynamic_graph import addLoggerFileOutputStream, addLoggerCoutOutputStream, closeLoggerFileOutputStream +from dynamic_graph import real_time_logger_instance, real_time_logger_spin_once, real_time_logger_destroy + +# Starts the real time logger instance +real_time_logger_instance() aCustomEntity = CustomEntity("a_custom_entity") -print(dir(aCustomEntity)) + +addLoggerFileOutputStream("/tmp/output.dat") aCustomEntity.signals() + +aCustomEntity.setTimeSample(0.001) +print(aCustomEntity.getTimeSample()) +aCustomEntity.setStreamPrintPeriod(0.002) +print(aCustomEntity.getStreamPrintPeriod()) + aCustomEntity.setLoggerVerbosityLevel(VerbosityLevel.VERBOSITY_INFO_WARNING_ERROR) print(aCustomEntity.getLoggerVerbosityLevel()) +for i in range(0,5): + aCustomEntity.in_double.value=i + aCustomEntity.out_double.recompute(i) + real_time_logger_spin_once() + print(i) + aCustomEntity.setLoggerVerbosityLevel(VerbosityLevel.VERBOSITY_WARNING_ERROR) print(aCustomEntity.getLoggerVerbosityLevel()) +for i in range(5,10): + aCustomEntity.in_double.value=i + aCustomEntity.out_double.recompute(i) + real_time_logger_spin_once() + aCustomEntity.setLoggerVerbosityLevel(VerbosityLevel.VERBOSITY_ERROR) print(aCustomEntity.getLoggerVerbosityLevel()) +for i in range(10,15): + aCustomEntity.in_double.value=i + aCustomEntity.out_double.recompute(i) + real_time_logger_spin_once() + +addLoggerCoutOutputStream() + aCustomEntity.setLoggerVerbosityLevel(VerbosityLevel.VERBOSITY_NONE) print(aCustomEntity.getLoggerVerbosityLevel()) +for i in range(15,20): + aCustomEntity.in_double.value=i + aCustomEntity.out_double.recompute(i) + real_time_logger_spin_once() + aCustomEntity.setLoggerVerbosityLevel(VerbosityLevel.VERBOSITY_ALL) print(aCustomEntity.getLoggerVerbosityLevel()) +for i in range(20,25): + aCustomEntity.in_double.value=i + aCustomEntity.out_double.recompute(i) + real_time_logger_spin_once() + + +# End the real time logger +real_time_logger_destroy() +# Close all the output stream +closeLoggerFileOutputStream()