diff --git a/LCS/WinCCWrapper/CMakeLists.txt b/LCS/WinCCWrapper/CMakeLists.txt index 9c27cda941686b32cf500187319529c7cb17ac08..3907d6bd0e5301975dd8644a6accdf03dde0e0b4 100644 --- a/LCS/WinCCWrapper/CMakeLists.txt +++ b/LCS/WinCCWrapper/CMakeLists.txt @@ -6,6 +6,8 @@ include(LofarFindPackage) #hard-coded path where wincc api can be found on build systems set(WINCC_ROOT_DIR /opt/WinCC_OA/3.15 CACHE PATH "root dir where the WinCC_OA api can be found") lofar_find_package(WINCC) +lofar_find_package(Boost REQUIRED python) +lofar_find_package(Python) IF(WINCC_FOUND) add_subdirectory(include) diff --git a/LCS/WinCCWrapper/include/WinCCManager.h b/LCS/WinCCWrapper/include/WinCCManager.h index 0de8c0453d3e65ccafb7fff82522993ea73a1770..69e70cbb947cf731c2a3bbf24224aa4ed7c16b5c 100644 --- a/LCS/WinCCWrapper/include/WinCCManager.h +++ b/LCS/WinCCWrapper/include/WinCCManager.h @@ -30,6 +30,8 @@ #include <Manager.hxx> #include <Variable.hxx> +#include <boost/python.hpp> + namespace LOFAR { namespace WINCCWRAPPER { @@ -69,12 +71,11 @@ public: bool get_datapoint(const std::string &name, std::string &value); //! get the datapoint with the given name and return it's tm value in parameter value. returns true upon success. bool get_datapoint(const std::string &name, struct tm &value); - //! get the datapoint with the given name and return it's DynVar value in parameter value. returns true upon success. - bool get_datapoint(const std::string &name, int value[]); - + //! get the datapoint with the given name and return it's boost::python::list value in parameter value. returns true upon success. + bool get_datapoint(const std::string &name, boost::python::list &value); + //! get the datapoint with the given name and return it's std::vector<int> value in parameter value. returns true upon success. bool get_datapoint(const std::string &name, std::vector<int> &value); - //! mark the datapoint with given name valid. returns true upon success. bool set_datapoint_valid(const std::string &name) { return set_datapoint_validity(name, true, nullptr); } //! mark the datapoint with given name invalid. returns true upon success. diff --git a/LCS/WinCCWrapper/include/WinCCWrapper.h b/LCS/WinCCWrapper/include/WinCCWrapper.h index 76a5cc33e9562994fe71b2d6654555691f77fdf3..26fa060d6064ee4fcff3f620e44b86a90c52327a 100644 --- a/LCS/WinCCWrapper/include/WinCCWrapper.h +++ b/LCS/WinCCWrapper/include/WinCCWrapper.h @@ -28,6 +28,8 @@ #include "WinCCResources.h" #include "WinCCManager.h" +#include <boost/python.hpp> + namespace LOFAR { namespace WINCCWRAPPER { @@ -50,8 +52,13 @@ public: //! set the datapoint with given name to the given int value, mark it valid/invalid, returns true upon success. bool set_datapoint(const std::string &name, int value, bool valid=true); + //! set the datapoint with given name to the given boost::python::list value, mark it valid/invalid, returns true upon success. + bool set_datapoint(const std::string &name, boost::python::list &value, bool valid=true); + //! set the datapoint with given name to the given boost::python::tuple value, mark it valid/invalid, returns true upon success. + bool set_datapoint(const std::string &name, boost::python::tuple &value, bool valid=true); //! set the datapoint with given name to the given std::vector<int> value, mark it valid/invalid, returns true upon success. bool set_datapoint(const std::string &name, std::vector<int> &value, bool valid=true); + //! set the datapoint with given name to the given long value, mark it valid/invalid, returns true upon success. bool set_datapoint(const std::string &name, long value, bool valid=true); //! set the datapoint with given name to the given float value, mark it valid/invalid, returns true upon success. @@ -80,8 +87,11 @@ public: std::string get_datapoint_string(const std::string &name); //! get the datapoint with the given name and return it as a time_t value if possible, otherwise an exception is raised. time_t get_datapoint_time(const std::string &name); + //! get the datapoint with the given name and return it as a boost::python::list value if possible, otherwise an exception is raised. + boost::python::list get_datapoint_list(const std::string &name); //! get the datapoint with the given name and return it as a std::vector<int> value if possible, otherwise an exception is raised. - std::vector<int> get_datapoint_int_vector(const std::string &name); + //! this method is used in the WinCCGet test + std::vector<int> get_datapoint_vector(const std::string &name); private: // get_datapoint diff --git a/LCS/WinCCWrapper/src/WinCCManager.cc b/LCS/WinCCWrapper/src/WinCCManager.cc index a8e492018d08ecef298c0d3ddf0d6896734605e1..6aa6c34b42ef58025ee2c2e37199c6820783e7f0 100644 --- a/LCS/WinCCWrapper/src/WinCCManager.cc +++ b/LCS/WinCCWrapper/src/WinCCManager.cc @@ -36,6 +36,7 @@ #include <DynPtrArray.hxx> #include <cassert> #include <vector> +#include <boost/python.hpp> namespace LOFAR { namespace WINCCWRAPPER { @@ -228,6 +229,27 @@ bool WinCCManager::get_datapoint_variable(const std::string &name, Variable *&va template <typename Tval> Variable::ConvertResult convert(Variable *var, Tval &value, Variable *&converted_var); +template <> +Variable::ConvertResult convert(Variable *var, boost::python::list& value, Variable *&converted_var) +{ + Variable::ConvertResult cr = var->convert(VariableType::DYNINTEGER_VAR, converted_var); + + if(Variable::ConvertResult::OK == cr) + { + DynVar *dv = (DynVar*)converted_var; + + for(unsigned int i = 0; i < dv->getNumberOfItems(); i++) { + Variable *elem = dv->getAt(i); + if(elem->inherits(VariableType::INTEGER_VAR)) { + value.append(((IntegerVar*)elem)->getValue()); + } + else + return Variable::ConvertResult::CONV_NOT_DEFINED; + } + } + return cr; +} + template <> Variable::ConvertResult convert(Variable *var, std::vector<int> &value, Variable *&converted_var) { @@ -369,6 +391,11 @@ bool WinCCManager::get_datapoint(const std::string &name, struct tm &value) return _get_datapoint(name, value); } +bool WinCCManager::get_datapoint(const std::string &name, boost::python::list &value) +{ + return _get_datapoint(name, value); +} + bool WinCCManager::get_datapoint(const std::string &name, std::vector<int> &value) { return _get_datapoint(name, value); diff --git a/LCS/WinCCWrapper/src/WinCCWrapper.cc b/LCS/WinCCWrapper/src/WinCCWrapper.cc index 4d1bd50b8445d99fd968e771056a4bb181ef0563..ab6191dc8d62d0f793b0c91541d59e3e2ecd4986 100644 --- a/LCS/WinCCWrapper/src/WinCCWrapper.cc +++ b/LCS/WinCCWrapper/src/WinCCWrapper.cc @@ -23,7 +23,7 @@ #include <LongVar.hxx> #include <TimeVar.hxx> #include <DynVar.hxx> - +#include <vector> #include <Variable.hxx> #include <condition_variable> @@ -34,6 +34,8 @@ #include "WinCCWrapper.h" #include "ConnectWaitForAnswer.h" +#include <boost/python.hpp> + namespace LOFAR { namespace WINCCWRAPPER { @@ -76,6 +78,24 @@ bool WinCCWrapper::set_datapoint(const std::string &name, int value, bool valid) return manager->set_datapoint(name + DP_SUFFIX, variable, valid); } +bool WinCCWrapper::set_datapoint(const std::string &name, boost::python::list &value, bool valid) +{ + DynVar variable(VariableType::INTEGER_VAR); + + for(int i = 0; i < boost::python::len(value); i++) { + int boost_elem = boost::python::extract<int>(value[i]); + IntegerVar elem{boost_elem}; + variable.append(elem);} + return manager->set_datapoint(name + DP_SUFFIX, variable, valid); +} + +bool WinCCWrapper::set_datapoint(const std::string &name, boost::python::tuple &value, bool valid) +{ + // do a simple type conversion to a boost::python::list to access the 'append' method + boost::python::list temp_list = boost::python::list(value); + return set_datapoint(name, temp_list, valid); +} + bool WinCCWrapper::set_datapoint(const std::string &name, std::vector<int> &value, bool valid) { DynVar variable(VariableType::INTEGER_VAR); @@ -137,7 +157,15 @@ int WinCCWrapper::get_datapoint_int(const std::string &name) throw std::runtime_error("Could not get datapoint"); } -std::vector<int> WinCCWrapper::get_datapoint_int_vector(const std::string &name) +boost::python::list WinCCWrapper::get_datapoint_list(const std::string &name) +{ + boost::python::list value; + if(get_datapoint(name, value)) + return value; + throw std::runtime_error("Could not get datapoint"); +} + +std::vector<int> WinCCWrapper::get_datapoint_vector(const std::string &name) { std::vector<int> value; if(get_datapoint(name, value)) diff --git a/LCS/WinCCWrapper/src/WinCCWrapper_boost_python.cc b/LCS/WinCCWrapper/src/WinCCWrapper_boost_python.cc index 9e4818ab3fd65a4018be312212ccee031fe08a27..4eee1f9936c9b91cbc785b0385f971bee0d07182 100644 --- a/LCS/WinCCWrapper/src/WinCCWrapper_boost_python.cc +++ b/LCS/WinCCWrapper/src/WinCCWrapper_boost_python.cc @@ -7,7 +7,7 @@ //# The LOFAR Software Suite 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. +//# option) any later versions //# //# The LOFAR Software Suite is distributed in the hope that it will be //# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -19,6 +19,8 @@ #include <boost/python.hpp> #include "WinCCWrapper.h" +#include <vector> +#include <boost/python/suite/indexing/vector_indexing_suite.hpp> BOOST_PYTHON_MODULE(pywincc) { @@ -26,7 +28,10 @@ BOOST_PYTHON_MODULE(pywincc) using namespace LOFAR::WINCCWRAPPER; bool (WinCCWrapper::*set_datapoint_int)(const std::string&, int, bool) = &WinCCWrapper::set_datapoint; - bool (WinCCWrapper::*set_datapoint_int_vector)(const std::string&, std::vector<int>&, bool) = &WinCCWrapper::set_datapoint; + bool (WinCCWrapper::*set_datapoint_list)(const std::string&, boost::python::list&, bool) = &WinCCWrapper::set_datapoint; + bool (WinCCWrapper::*set_datapoint_tuple)(const std::string&, boost::python::tuple&, bool) = &WinCCWrapper::set_datapoint; + // the set_datapoint_vector method is used in the WinCCGet and WinCCSet tests + bool (WinCCWrapper::*set_datapoint_vector)(const std::string&, std::vector<int>&, bool) = &WinCCWrapper::set_datapoint; bool (WinCCWrapper::*set_datapoint_long)(const std::string&, long, bool) = &WinCCWrapper::set_datapoint; bool (WinCCWrapper::*set_datapoint_float)(const std::string&, float, bool) = &WinCCWrapper::set_datapoint; bool (WinCCWrapper::*set_datapoint_bool)(const std::string&, bool, bool) = &WinCCWrapper::set_datapoint; @@ -35,9 +40,17 @@ BOOST_PYTHON_MODULE(pywincc) bool (WinCCWrapper::*set_datapoint_valid)(const std::string&) = &WinCCWrapper::set_datapoint_valid; bool (WinCCWrapper::*set_datapoint_invalid)(const std::string&) = &WinCCWrapper::set_datapoint_invalid; + // define the conversion between std::vector<int> and boost::python::list + class_<std::vector<int>>("VectorIterable") + .def(vector_indexing_suite<std::vector<int>>()) + ; + class_<WinCCWrapper>("WinCCWrapper", init<const std::string&>()) .def("set_datapoint_int", set_datapoint_int) - .def("set_datapoint_int_vector", set_datapoint_int_vector) + .def("set_datapoint_list", set_datapoint_list) + // define the "set_datapoint_list" method once more to accept a tuple instead of a list + .def("set_datapoint_list", set_datapoint_tuple) + .def("set_datapoint_vector", set_datapoint_vector) .def("set_datapoint_long", set_datapoint_long) .def("set_datapoint_float", set_datapoint_float) .def("set_datapoint_bool", set_datapoint_bool) @@ -47,7 +60,8 @@ BOOST_PYTHON_MODULE(pywincc) .def("set_datapoint_valid", set_datapoint_valid) .def("set_datapoint_invalid", set_datapoint_invalid) .def("get_datapoint_int", &WinCCWrapper::get_datapoint_int) - .def("get_datapoint_int_vector", &WinCCWrapper::get_datapoint_int_vector) + .def("get_datapoint_list", &WinCCWrapper::get_datapoint_list) + .def("get_datapoint_vector", &WinCCWrapper::get_datapoint_vector) .def("get_datapoint_long", &WinCCWrapper::get_datapoint_long) .def("get_datapoint_float", &WinCCWrapper::get_datapoint_float) .def("get_datapoint_bool", &WinCCWrapper::get_datapoint_bool) diff --git a/LCS/WinCCWrapper/test/CMakeLists.txt b/LCS/WinCCWrapper/test/CMakeLists.txt index c0e25c5a523711a37a3deb95c9ddd43d87d35077..e078c144ddbf0c50648ff3ab211926d8962030c5 100644 --- a/LCS/WinCCWrapper/test/CMakeLists.txt +++ b/LCS/WinCCWrapper/test/CMakeLists.txt @@ -4,5 +4,19 @@ IF(BUILD_TESTING) lofar_add_bin_program(WinCCSet WinCCSet.cc) lofar_add_bin_program(WinCCGet WinCCGet.cc) +# Start of added material + +# Try to find Boost-Python. +# If found, build the bindings, otherwise give a warning. +FIND_PATH(BOOST_PYTHON_FOUND "boost/python.hpp") + +# create python modules and boost python bindings + +include(LofarFindPackage) +lofar_find_package(Python 2.6 REQUIRED) +lofar_find_package(Boost REQUIRED COMPONENTS python) + +# End of added material + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include) ENDIF(BUILD_TESTING) diff --git a/LCS/WinCCWrapper/test/WinCCGet.cc b/LCS/WinCCWrapper/test/WinCCGet.cc index 8756888fb00cc8d99d189dc1c5e24ec4bd38099b..ecd0c9328eefb560eca139472d0449a463840f51 100644 --- a/LCS/WinCCWrapper/test/WinCCGet.cc +++ b/LCS/WinCCWrapper/test/WinCCGet.cc @@ -2,6 +2,9 @@ #include <string> #include <WinCCWrapper.h> #include <vector> +#include <boost/python.hpp> +#include <iostream> +#include <boost/format.hpp> using namespace LOFAR::WINCCWRAPPER; using namespace std; @@ -41,16 +44,17 @@ int main(int argc, char * argv[]) value = wrapper.get_datapoint_string(dpname); cout << dpname << ": " << value << endl; } - else if (string(argv[2]) == "vector") { - vector<int> value; - value = wrapper.get_datapoint_int_vector(dpname); - - cout << dpname << ": "; + else if (string(argv[2]) == "list") { + // We use the argument 'list' for consistency with the python interface, + // even though we must pass a vector + std::vector<int> value; + value = wrapper.get_datapoint_vector(dpname); + cout << dpname << ": ["; for (auto iter = value.cbegin(); iter != value.cend(); iter++) { - cout << *iter << " "; + cout << *iter << ", "; } - cout << endl; + cout << "\b\b]" << endl; // remove the last ', ' from the end. } else { cout << "Unknown datatype: " << string(argv[2]) << "\n" << endl; diff --git a/LCS/WinCCWrapper/test/WinCCSet.cc b/LCS/WinCCWrapper/test/WinCCSet.cc index 028805bfd3549b1e4561878173207e428434dd95..75c7e0e740482eb31930867ec3b21357fd991081 100644 --- a/LCS/WinCCWrapper/test/WinCCSet.cc +++ b/LCS/WinCCWrapper/test/WinCCSet.cc @@ -2,6 +2,7 @@ #include <string> #include <WinCCWrapper.h> #include <vector> +#include <boost/python.hpp> using namespace LOFAR::WINCCWRAPPER; using namespace std; @@ -10,7 +11,7 @@ void get_help(){ cout << "Usage:" << endl; cout << "WinCCSet \"datapoint_name\" datapoint_type new_value" << endl; cout << "Accepted datapoint types:" << endl; - cout << " int, float, string, vector (for int vectors)" << endl; + cout << " int, float, string, list (for int list)" << endl; } int main(int argc, char * argv[]) @@ -22,7 +23,6 @@ int main(int argc, char * argv[]) get_help(); return 0; } - WinCCWrapper wrapper{""}; string dpname{argv[1]}; @@ -38,8 +38,10 @@ int main(int argc, char * argv[]) string value{argv[3]}; wrapper.set_datapoint(dpname, value); } - else if (string(argv[2]) == "vector") { - + else if (string(argv[2]) == "list") { + // we cannot append to lists made outside of a boost python module declaration, + // so we pass a vector instead. + // We use the argument "list" for consistency with the python interface vector<int> value(argc-3); for (int i = 3; i < argc; i++) { @@ -54,3 +56,4 @@ int main(int argc, char * argv[]) } return 0; } +