Skip to content
Snippets Groups Projects
Commit 7ea69f02 authored by ziemke's avatar ziemke
Browse files

Task #1703: Added DynVar methods to WinCCWrapper package

parent 0d685c7c
No related branches found
No related tags found
No related merge requests found
# See lofar/trunk/sw_documentation_template.md for example
# WinCCWrapper Overview {#winccwrapper_overview} \ No newline at end of file
## General
### Description/Summary
The WinCCWrapper library is a simple C++ wrapper around the difficult to use WinCC_OA API. Of course one could always still choose use the WinCC_OA API which provides more features than this simple wrapper. This WinCCWrapper is aimed at providing a simple API to set and get datapoints into a wincc database. All calls are blocking/synchronous (where the underlying WinCC_OA API is asynchronous).
This WinCCWrapper library has the following features:
- set/get datapoints for the most common datatypes (int, long, float, bool, string, time_t)
- mark datapoints as valid/invalid.
- "connect" to changes in datapoints: whenever a 'connected' datapoint is changed (by whoever from whereever) then a supplied callback function is called.
Boost-python bindings are provided as well, exposing the same API in python.
### Authors/Owners
- Auke Klazema <mailto:klazema@astron.nl>
- Jorrit Schaap <mailto:schaap@astron.nl>
### Overview
This package builds a c++ library, and python bindings. For further details, see Description above.
- - -
## DEVELOPMENT
### Analyses
This library originated from the Responsive Telescope project which needed a means to use the station monitoring information available in the wincc database. It was later extended in the APERTIF project to provide a means to set/get the validness of datapoints.
The folling feaures were required, and implemented:
- set/get datapoints for the most common datatypes (int, long, float, bool, string, time_t)
- mark datapoints as valid/invalid.
- "connect" to changes in datapoints: whenever a 'connected' datapoint is changed (by whoever from whereever) then a supplied callback function is called.
Because the WinCC_OA API is hard to use, we decided to implement this simple wrapper.
Because the WinCC_OA API is in C++, this wrapper needed to be written in C++ as well.
Because we needed to have the same API available in python as well, we decided to create boost-python bindings.
### Design
No fancy design needed. This is just a library with a few classes wrapping the complicated WinCC_OA API into a simple API.
### Source Code
- [WinCCWrapper in SVN](https://svn.astron.nl/LOFAR/branches/SW-26_WinCC/LCS/WinCCWrapper)
- [WinCCWrapper Code Documentation](@ref winccwrapper_overview)
### Testing
#### Unit Testing
We decided not to provide unit tests, because that would require to write a quite large mocked version of the WinCC_OA API, which would be bigger and more complex than the wrapper classes themselves.
#### Integration Testing
When BUILD_TESTING is ON, then little test programs are built: WinCCSet and WinCCGet. They can be run from the cmdline (on a host where WinCC is running) and be used to test whether you can successfully set and/or get a datapoint. This is a manual test.
#### Build & Deploy
This library needs a c++11 compiler.
Dependencies on other libraries are automatically found by cmake, and otherwise reported which are missing.
##### Build locally
svn co https://svn.astron.nl/LOFAR/<some_branch_or_trunk> <my_source_dir>
cd <my_source_dir>
mkdir -p build/gnu_cxx11debug
cd build/gnu_cxx11debug
cmake -DBUILD_PACKAGES=WinCCWrapper -DUSE_LOG4CPLUS=OFF -DCMAKE_INSTALL_PREFIX=/opt/lofar/ ../..
cd ../..
make
make install
##### Build using Jenkins
There are no special Jenkins jobs for this package specifically. Such a job is also not needed. CMake will automatically take care of building this package whenever a package which is build by Jenkins is dependent on WinCCWrapper.
##### Deploy
There is no special Jenkins job to deploy this package specifically. Such a job is also not needed. The library from this package is deployed automatically thanks to cmake/jenkins whenever another package is deployed which depends on this package.
- - -
## OPERATIONS
### Configuration
- There are no configuration files.
### Log Files
- This library does not produce log files. A program using this library could produce logfiles, and these log files will contain the log lines issued by this library.
### Runtime
- This library just loads whenever a using program is started.
### Interfaces (API)
- It's a library. See the source code documentation for the api.
### Files/Databases
- It depends on a running WINCC_OA instance (which run on the mcu's)
- No other files and/or databases are needed.
### Dependencies
- WINCC_OA 3.15 (API, and runtime, which are installed on mcu's and the buildhostcentos7)
### Security
- No login credentials are needed.
- - -
## ADDITIONAL INFORMATION
### User Documentation
N.A.
### Operations Documentation
N.A.
...@@ -69,6 +69,8 @@ public: ...@@ -69,6 +69,8 @@ public:
bool get_datapoint(const std::string &name, std::string &value); 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. //! 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); 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, DynVar &value);
//! mark the datapoint with given name valid. returns true upon success. //! 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); } bool set_datapoint_valid(const std::string &name) { return set_datapoint_validity(name, true, nullptr); }
......
...@@ -60,6 +60,8 @@ public: ...@@ -60,6 +60,8 @@ public:
bool set_datapoint(const std::string &name, std::string value, bool valid=true); bool set_datapoint(const std::string &name, std::string value, bool valid=true);
//! set the datapoint with given name to the given time_t value, mark it valid/invalid, returns true upon success. //! set the datapoint with given name to the given time_t value, mark it valid/invalid, returns true upon success.
bool set_datapoint_time(const std::string &name, time_t value, bool valid=true); bool set_datapoint_time(const std::string &name, time_t value, bool valid=true);
//! set the datapoint with given name to the given DynVar value, mark it valid/invalid, returns true upon success.
bool set_datapoint(const std::string &name, DynVar value, bool valid=true);
//! mark the datapoint with given name valid. //! mark the datapoint with given name valid.
bool set_datapoint_valid(const std::string &name); bool set_datapoint_valid(const std::string &name);
...@@ -78,6 +80,8 @@ public: ...@@ -78,6 +80,8 @@ public:
std::string get_datapoint_string(const std::string &name); 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. //! 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); time_t get_datapoint_time(const std::string &name);
//! get the datapoint with the given name and return it as a DynVar value if possible, otherwise an exception is raised.
DynVar get_datapoint_DynVar(const std::string &name);
private: private:
// get_datapoint // get_datapoint
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#include <LongVar.hxx> #include <LongVar.hxx>
#include <TextVar.hxx> #include <TextVar.hxx>
#include <cassert> #include <cassert>
#include <DynVar.hxx>
namespace LOFAR { namespace LOFAR {
namespace WINCCWRAPPER { namespace WINCCWRAPPER {
...@@ -285,6 +286,19 @@ Variable::ConvertResult convert(Variable *var, struct tm &value, Variable *&conv ...@@ -285,6 +286,19 @@ Variable::ConvertResult convert(Variable *var, struct tm &value, Variable *&conv
return cr; return cr;
} }
template <>
Variable::ConvertResult convert(Variable *var, int[] &value, Variable *&converted_var)
{
Variable::ConvertResult cr = var->convert(VariableType::DYN_VAR, converted_var);
if(Variable::ConvertResult::OK == cr) {
for (int i = 0; i < value.getNumberOfItems(); i++) {
value[i] = ((DynVar*)converted_var)->getNext();
}
}
return cr;
}
//internal generic method to get the typed (Tval) value of a datapoint //internal generic method to get the typed (Tval) value of a datapoint
//used by the public strictly typed methods //used by the public strictly typed methods
template <typename Tval> template <typename Tval>
...@@ -342,6 +356,11 @@ bool WinCCManager::get_datapoint(const std::string &name, struct tm &value) ...@@ -342,6 +356,11 @@ bool WinCCManager::get_datapoint(const std::string &name, struct tm &value)
return _get_datapoint(name, value); return _get_datapoint(name, value);
} }
bool WinCCManager::get_datapoint(const std::string &name, DynVar &value)
{
return _get_datapoint(name, value);
}
bool WinCCManager::set_datapoint_validity(const std::string &name, bool validity, const Variable *value) bool WinCCManager::set_datapoint_validity(const std::string &name, bool validity, const Variable *value)
{ {
DpIdentifier dpId; DpIdentifier dpId;
...@@ -387,7 +406,7 @@ bool WinCCManager::set_datapoint_validity(const std::string &name, bool validity ...@@ -387,7 +406,7 @@ bool WinCCManager::set_datapoint_validity(const std::string &name, bool validity
//delete it, since it was a cloned variable created in get_datapoint_variable //delete it, since it was a cloned variable created in get_datapoint_variable
delete last_known_value; delete last_known_value;
} }
return true; return true;
} }
...@@ -425,7 +444,7 @@ void WinCCManager::handle_hotlink(const std::string &name, const std::string &va ...@@ -425,7 +444,7 @@ void WinCCManager::handle_hotlink(const std::string &name, const std::string &va
if(callback) if(callback)
{ {
callback(name, value); callback(name, value);
} }
} }
void WinCCManager::signalHandler(int sig) void WinCCManager::signalHandler(int sig)
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <FloatVar.hxx> #include <FloatVar.hxx>
#include <LongVar.hxx> #include <LongVar.hxx>
#include <TimeVar.hxx> #include <TimeVar.hxx>
#include <DynVar.hxx>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
...@@ -68,7 +69,7 @@ void WinCCWrapper::set_connect_datapoints_callback(std::function<void(std::strin ...@@ -68,7 +69,7 @@ void WinCCWrapper::set_connect_datapoints_callback(std::function<void(std::strin
// set_datapoint // set_datapoint
bool WinCCWrapper::set_datapoint(const std::string &name, int value, bool valid) bool WinCCWrapper::set_datapoint(const std::string &name, int value, bool valid)
{ {
IntegerVar variable{value}; IntegerVar variable{value};
return manager->set_datapoint(name + DP_SUFFIX, variable, valid); return manager->set_datapoint(name + DP_SUFFIX, variable, valid);
} }
...@@ -109,6 +110,13 @@ bool WinCCWrapper::set_datapoint_time(const std::string &name, time_t value, boo ...@@ -109,6 +110,13 @@ bool WinCCWrapper::set_datapoint_time(const std::string &name, time_t value, boo
return manager->set_datapoint(name + DP_SUFFIX, variable, valid); return manager->set_datapoint(name + DP_SUFFIX, variable, valid);
} }
bool WinCCWrapper::set_datapoint(const std::string &name, DynVar value, bool valid)
{
DynVar variable{value};
return manager->set_datapoint(name + DP_SUFFIX, variable, valid);
}
// get_datapoint // get_datapoint
template <typename T> template <typename T>
bool WinCCWrapper::get_datapoint(const std::string &name, T &value) bool WinCCWrapper::get_datapoint(const std::string &name, T &value)
...@@ -164,6 +172,14 @@ time_t WinCCWrapper::get_datapoint_time(const std::string &name) ...@@ -164,6 +172,14 @@ time_t WinCCWrapper::get_datapoint_time(const std::string &name)
throw std::runtime_error("Could not get datapoint"); throw std::runtime_error("Could not get datapoint");
} }
DynVar WinCCWrapper::get_datapoint_DynVar(const std::string &name)
{
DynVar value;
if(get_datapoint(name, value))
return value;
throw std::runtime_error("Could not get datapoint");
}
bool WinCCWrapper::set_datapoint_valid(const std::string &name) bool WinCCWrapper::set_datapoint_valid(const std::string &name)
{ {
return manager->set_datapoint_valid(name + DP_SUFFIX); return manager->set_datapoint_valid(name + DP_SUFFIX);
......
...@@ -33,6 +33,7 @@ BOOST_PYTHON_MODULE(pywincc) ...@@ -33,6 +33,7 @@ BOOST_PYTHON_MODULE(pywincc)
bool (WinCCWrapper::*set_datapoint_time)(const std::string&, time_t, bool) = &WinCCWrapper::set_datapoint_time; bool (WinCCWrapper::*set_datapoint_time)(const std::string&, time_t, bool) = &WinCCWrapper::set_datapoint_time;
bool (WinCCWrapper::*set_datapoint_valid)(const std::string&) = &WinCCWrapper::set_datapoint_valid; bool (WinCCWrapper::*set_datapoint_valid)(const std::string&) = &WinCCWrapper::set_datapoint_valid;
bool (WinCCWrapper::*set_datapoint_invalid)(const std::string&) = &WinCCWrapper::set_datapoint_invalid; bool (WinCCWrapper::*set_datapoint_invalid)(const std::string&) = &WinCCWrapper::set_datapoint_invalid;
bool (WinCCWrapper::*set_datapoint_DynVar)(const std::string&, DynVar, bool) = &WinCCWrapper::set_datapoint;
class_<WinCCWrapper>("WinCCWrapper", init<const std::string&>()) class_<WinCCWrapper>("WinCCWrapper", init<const std::string&>())
.def("set_datapoint_int", set_datapoint_int) .def("set_datapoint_int", set_datapoint_int)
...@@ -44,6 +45,7 @@ BOOST_PYTHON_MODULE(pywincc) ...@@ -44,6 +45,7 @@ BOOST_PYTHON_MODULE(pywincc)
.def("set_datapoint", set_datapoint_float) // 'common'/'generic' set_datapoint python method just calls set_datapoint_float .def("set_datapoint", set_datapoint_float) // 'common'/'generic' set_datapoint python method just calls set_datapoint_float
.def("set_datapoint_valid", set_datapoint_valid) .def("set_datapoint_valid", set_datapoint_valid)
.def("set_datapoint_invalid", set_datapoint_invalid) .def("set_datapoint_invalid", set_datapoint_invalid)
.def("set_datapoint_DynVar", set_datapoint_DynVar)
.def("get_datapoint_int", &WinCCWrapper::get_datapoint_int) .def("get_datapoint_int", &WinCCWrapper::get_datapoint_int)
.def("get_datapoint_long", &WinCCWrapper::get_datapoint_long) .def("get_datapoint_long", &WinCCWrapper::get_datapoint_long)
.def("get_datapoint_float", &WinCCWrapper::get_datapoint_float) .def("get_datapoint_float", &WinCCWrapper::get_datapoint_float)
...@@ -51,6 +53,7 @@ BOOST_PYTHON_MODULE(pywincc) ...@@ -51,6 +53,7 @@ BOOST_PYTHON_MODULE(pywincc)
.def("get_datapoint_string", &WinCCWrapper::get_datapoint_string) .def("get_datapoint_string", &WinCCWrapper::get_datapoint_string)
.def("get_datapoint_time", &WinCCWrapper::get_datapoint_time) .def("get_datapoint_time", &WinCCWrapper::get_datapoint_time)
.def("get_datapoint", &WinCCWrapper::get_datapoint_float) // 'common'/'generic' get_datapoint python method just calls get_datapoint_float .def("get_datapoint", &WinCCWrapper::get_datapoint_float) // 'common'/'generic' get_datapoint python method just calls get_datapoint_float
.def("get_datapoint_DynVar", &WinCCWrapper:get_datapoint_DynVar)
; ;
} }
...@@ -13,6 +13,6 @@ int main(int, char * argv[]) ...@@ -13,6 +13,6 @@ int main(int, char * argv[])
value = wrapper.get_datapoint_int(dpname); value = wrapper.get_datapoint_int(dpname);
std::cout << dpname << ": " << value << std::endl; std::cout << dpname << ": " << value << std::endl;
return 0; return 0;
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment