diff --git a/src/liboncilla/BackendFactory.cpp b/src/liboncilla/BackendFactory.cpp deleted file mode 100644 index bda3e32..0000000 --- a/src/liboncilla/BackendFactory.cpp +++ /dev/null @@ -1,100 +0,0 @@ -/** - * \file BackendFactory.cpp - * - * \date Jun 21, 2012 - * \author Alexandre Tuleu - */ - -#include "BackendFactory.h" -#include -#include - -namespace rci { -namespace oncilla { - - BackendFactory & BackendFactory::Instance(){ - static BackendFactory * s_rci_oncilla_backend_factory = new BackendFactory(); - return *s_rci_oncilla_backend_factory; - } - - - void BackendFactory::RegisterBackend(Priority p, EntryPtr e){ - EntryByPriority::const_iterator fi = d_entries.find(p); - if(fi != d_entries.end()){ - return; - } - d_entries.insert(std::make_pair(p,e)); - } - - BackendFactory::EntryPtr BackendFactory::HighestPriorityBackend(){ - LoadExternalBackend(); - EntryByPriority::const_reverse_iterator fi = d_entries.rbegin(); - if (fi == d_entries.rend()){ - return 0; - } - return fi->second; - } - - void BackendFactory::LoadExternalBackend(){ - for(SetOfBackendName::const_iterator n = d_unloaded.begin(); - n != d_unloaded.end(); - ++n){ -#ifndef NDEBUG - std::cerr << "Looking for module '" << *n << "' : " << std::flush; -#endif - char * error; - void * module_handle = dlopen(n->c_str(),RTLD_NOW); - if((error = dlerror()) != NULL ){ -#ifndef NDEBUG - std::cerr << std::endl << " got an error : '" << error << "'" << std::endl; -#else - std::cerr << "Got an error while trying to open module '" << *n - << "' : " << error << std::endl; -#endif - continue; - } -#ifndef NDEBUG - std::cerr << " found." << std::endl; -#endif - liboncilla_backend_entry_fct entry = (liboncilla_backend_entry_fct) dlsym(module_handle,"liboncilla_webots_backend_entry"); - - if((error = dlerror()) != NULL){ - throw std::runtime_error("Could not find 'liboncilla_webots_backend_entry' symbol in '" + (*n) + "'."); - } - (*entry)(); - d_loaded.insert(std::make_pair(*n,module_handle)); - } - d_unloaded.clear(); - } - - void BackendFactory::AddAdditionalBackend(const std::string& name){ - ListOfLoadedBackend::const_iterator fi = d_loaded.find(name); - if( fi != d_loaded.end()){ - return; - } - d_unloaded.insert(name); - } - - BackendFactory::BackendFactory(){ - d_unloaded.insert("liboncilla-webots.so"); - d_unloaded.insert("liboncilla-hw.so"); - } - - BackendFactory::~BackendFactory(){ - for(ListOfLoadedBackend::iterator b = d_loaded.begin(); - b != d_loaded.end(); - ++b) { - char * error; - dlclose(b->second); - - if( (error = dlerror()) != NULL){ - std::cerr << "Could not unload module '" << b->first << "' : " - << std::endl - << " error : '" << error << "'." << std::endl; - } - } - } - - -} /* namespace oncilla */ -} /* namespace rci */ diff --git a/src/liboncilla/BackendFactory.h b/src/liboncilla/BackendFactory.h deleted file mode 100644 index 6800905..0000000 --- a/src/liboncilla/BackendFactory.h +++ /dev/null @@ -1,83 +0,0 @@ -/** - * \file BackendFactory.h - * - * \date Jun 21, 2012 - * \author Alexandre Tuleu - */ - -#ifndef LIBONCILLA_BACKENDFACTORY_H_ -#define LIBONCILLA_BACKENDFACTORY_H_ - -#include -#include -#include -#include -#include - -extern "C" { - typedef void (*liboncilla_backend_entry_fct)(); -} - -namespace rci{ -namespace oncilla{ - - - class OncillaSynchronizer; - - class BackendFactory { - public : - /** - * define the priority of the backend - */ - enum Priority{ - HARDWARE = 0, - SIMULATION = 1, - USER_DEFINED_PRIORITY = 2 - }; - /** - * Pointer to a function that will be the entry of the Backend. - */ - typedef OncillaSynchronizer * (*EntryPtr)(); - - static BackendFactory & Instance(); - - - - void AddAdditionalBackend(const std::string & name); - /** - * Register a new backend. - * \param p the Priority of the backend - * \param entry the EntryPtr of the backend - * \warning : if a backend with the same priority is already here, the call - * will be silently discarded. - */ - void RegisterBackend(Priority p, EntryPtr entry); - /** - * \return the EntryPtr of the highest priority backend or 0 if none was - * registered with RegisterBackend(). - */ - EntryPtr HighestPriorityBackend(); - - - - private: - typedef std::map EntryByPriority; - typedef std::set SetOfBackendName; - typedef std::map ListOfLoadedBackend; - - void LoadExternalBackend(); - - BackendFactory(); - virtual ~BackendFactory(); - - EntryByPriority d_entries; - - SetOfBackendName d_unloaded; - ListOfLoadedBackend d_loaded; - - }; - -} -} - -#endif // LIBONCILLA_BACKENDFACTORY_H_ diff --git a/src/liboncilla/BackendLoader.cpp b/src/liboncilla/BackendLoader.cpp new file mode 100644 index 0000000..afdbe62 --- /dev/null +++ b/src/liboncilla/BackendLoader.cpp @@ -0,0 +1,50 @@ +/** + * \file BackendLoader.cpp + * + * \date Jun 21, 2012 + * \author Alexandre Tuleu + */ + +#include "BackendLoader.h" +#include +namespace rci { +namespace oncilla { + +BackendLoader::BackendLoader(){ + //adds the different variants. first try to open simulation backend, if not + //found, will try to open HW backend ... + //if not found will fire a std::runtime_error + //library predix and suffix are determined from platform bx biorob-cpp/PluginLoader + d_loader.AppendVariant("oncilla-webots"); + d_loader.AppendVariant("oncilla-hw"); + typedef PluginLoader PL; + // backend should be compiled using the cross-platform MODULE target of CMake + // and to avoid unexpected jitter, we resolve all symbols at opening. + d_loader.SetHint((PL::LoadingHint) (PL::IsCMakeModuleObject | PL::ResolveAllSymbols)); +} + + +BackendLoader::~BackendLoader(){} + +const OncillaBackend::Ptr & BackendLoader::SuitableBackend(){ + + if(d_loadedBackend){ + return d_loadedBackend; + } + + try{ + //try to loads backend from constructor order + d_loadedBackend = d_loader.LoadPlugin(); + } catch (const std::runtime_error & e) { + //PluginLoader fire a std::runtime error with all the + //dlopen / dlsym error messages, we propagate this error with a nice + //specific wrapper arround std::runtime_error (could be useful + // for higher level to recover from that error) + throw LoadingError(e.what()); + } + + return d_loadedBackend; +} + +} /* namespace oncilla */ +} /* namespace rci */ diff --git a/src/liboncilla/BackendLoader.h b/src/liboncilla/BackendLoader.h new file mode 100644 index 0000000..ceeea77 --- /dev/null +++ b/src/liboncilla/BackendLoader.h @@ -0,0 +1,32 @@ +/** + * \file BackendLoader.h + * + * \date Jun 21, 2012 + * \author Alexandre Tuleu + */ + +#ifndef LIBONCILLA_BACKENDLOADER_H_ +#define LIBONCILLA_BACKENDLOADER_H_ + +#include "OncillaBackend.h" + +namespace rci{ +namespace oncilla{ + + class OncillaSynchronizer; + + class BackendLoader { + public : + BackendLoader(); + virtual ~BackendLoader(); + const OncillaBackend::Ptr & SuitableBackend(); + + private: + PluginLoader d_loader; + OncillaBackend::Ptr d_loadedBackend; + }; + +} +} + +#endif // LIBONCILLA_BACKENDFACTORY_H_ diff --git a/src/liboncilla/CMakeLists.txt b/src/liboncilla/CMakeLists.txt index e25ab5b..a063339 100644 --- a/src/liboncilla/CMakeLists.txt +++ b/src/liboncilla/CMakeLists.txt @@ -1,35 +1,47 @@ set(ONCILLAHEADERS OncillaTrunk.h OncillaL0.h OncillaL1L2.h OncillaL3.h OncillaL4.h Oncilla.h OncillaSynchronizer.h - BackendFactory.h + BackendLoader.h + OncillaBackend.h common.h) +set(ONCILLA_EXCEPTIONS_HEADERS + exceptions/LoadingError.h) + set(ONCILLASOURCES OncillaTrunk.cpp OncillaL0.cpp OncillaL1L2.cpp OncillaL3.cpp OncillaL4.cpp Oncilla.cpp OncillaSynchronizer.cpp - BackendFactory.cpp) + OncillaBackend.cpp + exceptions/LoadingError.cpp + BackendLoader.cpp) -add_library(oncilla SHARED ${ONCILLASOURCES} ${ONCILLAHEADERS}) +add_library(oncilla SHARED ${ONCILLASOURCES} ${ONCILLAHEADERS} ${ONCILLA_EXCEPTIONS_HEADERS}) target_link_libraries(oncilla ${RCI_LIBRARIES} ${BIOROB_CPP_LIBRARIES}) set_target_properties(oncilla PROPERTIES VERSION ${VERSION_STRING} SOVERSION ${VERSION_ABI}) install(TARGETS oncilla DESTINATION lib) +set(DEST_INCLUDE_DIR include/liboncilla-${VERSION_API}/liboncilla) + install(FILES ${ONCILLAHEADERS} - DESTINATION include/liboncilla-${VERSION_API}/liboncilla ) + DESTINATION ${DEST_INCLUDE_DIR} ) + + +install(FILES ${ONCILLA_EXCEPTIONS_HEADERS} + DESTINATION ${DEST_INCLUDE_DIRS}/exceptions) \ No newline at end of file diff --git a/src/liboncilla/Oncilla.cpp b/src/liboncilla/Oncilla.cpp index 09c2b33..0cfb468 100644 --- a/src/liboncilla/Oncilla.cpp +++ b/src/liboncilla/Oncilla.cpp @@ -1,129 +1,129 @@ /* * Oncilla.cpp * * Created on: 15 dec. 2011 * Author: Alexandre Tuleu, Arne Nordmann */ #include "Oncilla.h" -#include "BackendFactory.h" +#include "BackendLoader.h" namespace rci { namespace oncilla { OncillaSynchronizerPtr Oncilla::s_synchronizer; Oncilla::LegNames Oncilla::s_legNames; const std::string & Oncilla::nameOfLeg(Leg l){ if(s_legNames.empty()){ s_legNames.push_back("Left Fore"); s_legNames.push_back("Right Fore"); s_legNames.push_back("Left Hind"); s_legNames.push_back("Right Hind"); s_legNames.push_back("Undefined"); } if(l >= NUM_LEGS){ return s_legNames.back(); } return s_legNames[l]; } Oncilla::Oncilla(){ if(!s_synchronizer){ - BackendFactory::EntryPtr e = BackendFactory::Instance().HighestPriorityBackend(); - if( e == 0){ - throw std::runtime_error("No backend for liboncilla were found. Are you" - " sure you are linking your program with a backend like " - "'liboncilla-webots' or 'liboncilla-hw' ?."); + if(!d_backend){ + BackendLoader bl; + //we have to keep alive the pointer or dlclose() will be called once + //We free him. Or we could add BackendLoader as a member of Oncilla + // I prefer only to have the Object creator interface. + d_backend = bl.SuitableBackend(); } - OncillaSynchronizerPtr p((*e)()); - s_synchronizer = p; + s_synchronizer = d_backend->CreateSynchronizer(); init(); } } Oncilla::~Oncilla() { } #define CREATE_NODES(LegName)do{\ d_L0s.push_back(OncillaL0Ptr(new OncillaL0(LegName " Oncilla L0" )));\ d_L1s.push_back(OncillaL1Ptr(new OncillaL1L2(*s_synchronizer,\ LegName " Oncilla L1")));\ d_L2s.push_back(OncillaL2Ptr(new OncillaL1L2(*s_synchronizer,\ LegName " Oncilla L2")));\ d_L3s.push_back(OncillaL3Ptr(new OncillaL3(LegName " Oncilla L3")));\ d_L4s.push_back(OncillaL4Ptr(new OncillaL4(LegName " Oncilla L4")));\ }while(0) #define REGISTER_NODES(Type)do{\ for(std::vector < Oncilla ## Type ## Ptr >::const_iterator n = d_ ## Type ## s.begin();\ n != d_ ## Type ## s.end();\ ++n){\ Leg l = static_cast(n - d_ ## Type ## s.begin());\ s_synchronizer->register ## Type ## Node(l,*n);\ }\ }while(0) void Oncilla::init() { d_L0s.reserve(4); d_L1s.reserve(4); d_L2s.reserve(4); d_L3s.reserve(4); d_L4s.reserve(4); CREATE_NODES("Left Fore"); CREATE_NODES("Right Fore"); CREATE_NODES("Left Hind"); CREATE_NODES("Right Hind"); d_trunk = OncillaTrunkPtr(new OncillaTrunk("Oncilla Trunk")); REGISTER_NODES(L0); REGISTER_NODES(L1); REGISTER_NODES(L2); REGISTER_NODES(L3); REGISTER_NODES(L4); s_synchronizer->registerTrunkNode(d_trunk); } OncillaL0Ptr Oncilla::getL0(Leg l) const { return this->d_L0s[l]; } OncillaL1Ptr Oncilla::getL1(Leg l) const { return this->d_L1s[l]; } OncillaL2Ptr Oncilla::getL2(Leg l) const { return this->d_L2s[l]; } OncillaL3Ptr Oncilla::getL3(Leg l) const { return this->d_L3s[l]; } OncillaL4Ptr Oncilla::getL4(Leg l) const { return this->d_L4s[l]; } OncillaTrunkPtr Oncilla::getTrunk() const { return this->d_trunk; } OncillaSynchronizerPtr Oncilla::getSynchronizer() const { if(!s_synchronizer){ throw std::logic_error("Internal error : synchronizer seems unitialized" ", but it should never happen. Please report this bug."); } return this->s_synchronizer; } } } diff --git a/src/liboncilla/Oncilla.h b/src/liboncilla/Oncilla.h index 40d74a8..3818590 100644 --- a/src/liboncilla/Oncilla.h +++ b/src/liboncilla/Oncilla.h @@ -1,64 +1,66 @@ /* * Oncilla.h * * Created on: 15 dec. 2011 * Author: Alexandre Tuleu, Arne Nordmann */ #pragma once #include #include #include #include "common.h" #include "OncillaSynchronizer.h" - +#include "OncillaBackend.h" namespace rci { namespace oncilla { +class BackendLoader; class Oncilla; typedef boost::shared_ptr OncillaPtr; class OncillaSynchronizer; typedef boost::shared_ptr OncillaSynchronizerPtr; class Oncilla { public: static const std::string & nameOfLeg(Leg l); Oncilla(); virtual ~Oncilla(); OncillaL0Ptr getL0(Leg l) const; OncillaL1Ptr getL1(Leg l) const; OncillaL2Ptr getL2(Leg l) const; OncillaL3Ptr getL3(Leg l) const; OncillaL4Ptr getL4(Leg l) const; OncillaTrunkPtr getTrunk() const; OncillaSynchronizerPtr getSynchronizer() const; private: typedef std::vector LegNames; static LegNames s_legNames; void init(); static OncillaSynchronizerPtr s_synchronizer; std::vector d_L0s; std::vector d_L1s; std::vector d_L2s; std::vector d_L3s; std::vector d_L4s; OncillaTrunkPtr d_trunk; + OncillaBackend::Ptr d_backend; }; } } diff --git a/src/liboncilla/OncillaBackend.cpp b/src/liboncilla/OncillaBackend.cpp new file mode 100644 index 0000000..c51f42f --- /dev/null +++ b/src/liboncilla/OncillaBackend.cpp @@ -0,0 +1,12 @@ +/* + * OncillaBackend.cpp + * + * Created on: Jan 18, 2013 + * Author: tuleu + */ + +#include "OncillaBackend.h" + +OncillaBackend::~OncillaBackend(){ +} + diff --git a/src/liboncilla/OncillaBackend.h b/src/liboncilla/OncillaBackend.h new file mode 100644 index 0000000..77b15c1 --- /dev/null +++ b/src/liboncilla/OncillaBackend.h @@ -0,0 +1,34 @@ +/* + * Backend.h + * + * Created on: Jan 18, 2013 + * Author: tuleu + */ + +#ifndef LIBONCILLA_ONCILLABACKEND_H_ +#define LIBONCILLA_ONCILLABACKEND_H_ + + +#include +#include +#include + +namespace rci{ +namespace oncilla{ + + class OncillaSynchronizer; +} +} + +class OncillaBackend { + BIOROB_CPP_DECLARE_PLUGIN(OncillaBackend); + DISABLE_ASSIGNEMENT(OncillaBackend); + DISABLE_COPY(OncillaBackend); +public : + typedef std::tr1::shared_ptr Ptr; + + virtual ~OncillaBackend(); + virtual boost::shared_ptr CreateSynchronizer() = 0; +}; + +#endif /* LIBONCILLA_ONCILLABACKEND_H_ */ diff --git a/src/liboncilla/exceptions/LoadingError.cpp b/src/liboncilla/exceptions/LoadingError.cpp new file mode 100644 index 0000000..30da17d --- /dev/null +++ b/src/liboncilla/exceptions/LoadingError.cpp @@ -0,0 +1,21 @@ +/* + * LoadingError.cpp + * + * Created on: Jan 18, 2013 + * Author: tuleu + */ + +#include "LoadingError.h" + +namespace rci { +namespace oncilla { + +LoadingError::LoadingError(const std::string & reason) + : std::runtime_error("Could not load a suitable oncilla backend, reason :\n" + reason){ +} + +LoadingError::~LoadingError(){ +} + +} /* namespace oncilla */ +} /* namespace rci */ diff --git a/src/liboncilla/exceptions/LoadingError.h b/src/liboncilla/exceptions/LoadingError.h new file mode 100644 index 0000000..5671590 --- /dev/null +++ b/src/liboncilla/exceptions/LoadingError.h @@ -0,0 +1,24 @@ +/* + * LoadingError.h + * + * Created on: Jan 18, 2013 + * Author: tuleu + */ + +#ifndef LOADINGERROR_H_ +#define LOADINGERROR_H_ + +#include + +namespace rci { +namespace oncilla { + +class LoadingError : public std::runtime_error{ +public: + LoadingError(const std::string & reason); + virtual ~LoadingError() throw(); +}; + +} /* namespace oncilla */ +} /* namespace rci */ +#endif /* LOADINGERROR_H_ */