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

Task #2926: Merge 'any'-type conversion (by Mancini) and WinCCWrapper type check (Ziemke/Apertif)

parents 278e6746 5f4bcf34
No related branches found
No related tags found
No related merge requests found
Showing
with 634 additions and 23 deletions
......@@ -1730,6 +1730,7 @@ LCS/WinCCWrapper/include/CMakeLists.txt -text
LCS/WinCCWrapper/include/WinCCManager.h -text
LCS/WinCCWrapper/include/WinCCResources.h -text
LCS/WinCCWrapper/include/WinCCWrapper.h -text
LCS/WinCCWrapper/include/exceptions.h -text
LCS/WinCCWrapper/src/CMakeLists.txt -text
LCS/WinCCWrapper/src/ConnectWaitForAnswer.cc -text
LCS/WinCCWrapper/src/ConnectWaitForAnswer.h -text
......@@ -1738,8 +1739,10 @@ LCS/WinCCWrapper/src/WinCCResources.cc -text
LCS/WinCCWrapper/src/WinCCWrapper.cc -text
LCS/WinCCWrapper/src/WinCCWrapper_boost_python.cc -text
LCS/WinCCWrapper/src/__init__.py -text
LCS/WinCCWrapper/src/exceptions.h -text
LCS/WinCCWrapper/test/CMakeLists.txt -text
LCS/WinCCWrapper/test/WinCCGet.cc -text
LCS/WinCCWrapper/test/WinCCQuery.cc -text
LCS/WinCCWrapper/test/WinCCSet.cc -text
LCS/WinCCWrapper/test/mock.py -text
LCS/doc/package.dox -text
......
......@@ -4,7 +4,7 @@ lofar_package(WinCCWrapper 1.0 )
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")
#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)
IF(WINCC_FOUND)
......
# Create symbolic link to include directory.
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_BINARY_DIR}/include/${PACKAGE_NAME})
......@@ -8,4 +8,5 @@ install(FILES
WinCCManager.h
WinCCResources.h
WinCCWrapper.h
exceptions.h
DESTINATION include/${PACKAGE_NAME})
......@@ -31,6 +31,7 @@
#include <Variable.hxx>
#include <boost/python.hpp>
#include <boost/any.hpp>
namespace LOFAR {
namespace WINCCWRAPPER {
......@@ -41,7 +42,6 @@ class WinCCManager : public Manager
public:
//! default constructor
WinCCManager();
//! run the manager, connect to the running wincc instance.
void run();
//! exit the manager, disconnect from the running wincc instance.
......@@ -49,8 +49,15 @@ public:
//! subscribe for changes on this list of datapoints. Whenever any of these datapoints changes value, the callback function from set_connect_datapoints_callback is called with the changed datapoint name and value.
void connect_datapoints(const std::vector<std::string> &data_points);
//! subscribe for changes on this list of datapoints. Whenever any of these datapoints change all the values from these datapoints gets returned in one call.
void connect_datapoints_multiple(const std::vector<std::string> &data_points);
//! unsubscribe for changes on this list of datapoints.
void disconnect_datapoints(const std::vector<std::string> &data_points);
//! provide your callback function which is called whenever any of the connected datapoints is changed.
void set_connect_datapoints_callback(std::function<void(std::string name, std::string value)> callback_functor) {callback = callback_functor;};
//! provide your callback function which is called whenever any of the connected datapoints is changed.
void set_connect_datapoints_callback(std::function<void(std::string name, std::string value)> callback) {callback = callback;};
void set_connect_datapoints_callback(std::function<void(std::map<std::string, std::string>)> callback_functor) {callback_multi = callback_functor;};
//! set the datapoint with given name to the given value, returns true upon success.
/*! set the datapoint with given name to the given value
......@@ -75,7 +82,10 @@ public:
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);
//! get the datapoint with a any type
bool get_datapoint_any(const std::string &datapoint_name, boost::any &value);
//! set the datapoint with a any type
bool set_datapoint_any(const std::string &datapoint_name, const boost::any &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.
......@@ -83,24 +93,32 @@ public:
//! set the datapoint with given name valid/invalid. returns true upon success.
bool set_datapoint_validity(const std::string &name, bool validity, const Variable *value=nullptr);
bool get_query(const std::string &query, std::vector<std::vector<std::string>> & result);
//! handle signals to exit nicely
virtual void signalHandler(int sig);
void wait_for_event(long sec, long microSec);
private:
void init();
friend class ConnectWaitForAnswer;
void handle_hotlink(const std::string &name, const std::string &value);
void handle_hotlink(const std::map<std::string, std::string> &);
void handle_get(const std::string &name, Variable *&value);
bool request_datapoint(const std::string &name);
bool request_query_result(const std::string &query, PVSSulong & identifier);
template <typename Tval>
bool _get_datapoint(const std::string &name, Tval &value);
template <typename Tval>
bool _get_datapoint(const std::string &name, Tval *value);
bool get_datapoint_variable(const std::string &name, Variable *&value);
bool has_received_variable(const std::string &name);
......@@ -109,6 +127,7 @@ private:
volatile static bool doExit;
std::function<void(std::string name, std::string value)> callback;
std::function<void(std::map<std::string, std::string>)> callback_multi;
std::mutex mtx;
std::condition_variable cv;
std::map<std::string, Variable *> values;
......
......@@ -27,9 +27,12 @@ namespace LOFAR {
class WinCCResources
{
public:
WinCCResources(const std::string &projec_name);
WinCCResources(const std::string &project_name);
WinCCResources(const std::string &program_name, const std::string &project_name, const int num);
private:
void init(const std::string &projec_name);
void init(const std::string &project_name);
void init(const std::string &program_name, const std::string &project_name, const int num);
};
} // namespace WINCCWRAPPER
......
......@@ -21,6 +21,7 @@
#define WINCCSERVICES_WINCC_WRAPPER_H
#include <string>
#include <boost/variant.hpp>
#include <vector>
#include <ctime>
#include <functional>
......@@ -29,6 +30,7 @@
#include "WinCCManager.h"
#include <boost/python.hpp>
#include <boost/any.hpp>
namespace LOFAR {
namespace WINCCWRAPPER {
......@@ -40,6 +42,9 @@ class WinCCWrapper
public:
//! default constructor
WinCCWrapper(const std::string &project_name);
//! default constructor
WinCCWrapper(const std::string &program_name, const std::string &project_name, const int num);
//! disconnect from the running wincc instance.
void exit();
//! connect to the running wincc instance.
......@@ -47,14 +52,21 @@ public:
//! subscribe for changes on this list of datapoints. Whenever any of these datapoints changes value, the callback function from set_connect_datapoints_callback is called with the changed datapoint name and value.
void connect_datapoints(const std::vector<std::string> &data_points);
//! subscribe for changes on this list of datapoints. Whenever any of these datapoints changes value, the callback function from set_connect_datapoints_callback is called with all the specified values.
void connect_datapoints_multi(const std::vector<std::string> &data_points);
//! unsubscribe for changes on the given list of datapoints.
void disconnect_datapoints(const std::vector<std::string> &data_points);
//! provide your callback function which is called whenever any of the connected datapoints is changed.
void set_connect_datapoints_callback(std::function<void(std::string name, std::string value)> callback);
//! provide your callback function which is called whenever any of the connected datapoints is changed. It returns all the specified datapoints even if only one changes.
void set_connect_datapoints_callback(std::function<void(std::map<std::string, std::string>)> callback);
//! 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.
//! 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);
......@@ -70,11 +82,14 @@ public:
//! 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_any(const std::string &name, boost::any value);
//! mark the datapoint with given name valid.
bool set_datapoint_valid(const std::string &name);
//! mark the datapoint with given name invalid.
bool set_datapoint_invalid(const std::string &name);
//! provide the boost::any for the given datapoint name
boost::any get_datapoint_any (const std::string &name);
//! get the datapoint with the given name and return it as an int value if possible, otherwise an exception is raised.
int get_datapoint_int(const std::string &name);
//! get the datapoint with the given name and return it as a long value if possible, otherwise an exception is raised.
......@@ -88,11 +103,17 @@ public:
//! 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);
boost::python::list get_datapoint_list(const std::string &name);
//! get the datapoint last set time
time_t get_datapoint_set_time(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.
//! this method is used in the WinCCGet test
std::vector<int> get_datapoint_vector(const std::string &name);
//! get the datapoint with the given name and return it as a std::vector<std::string> value.
std::vector<std::string> get_datapoint_vector_string(const std::string &name);
std::string get_formatted_datapoint(const std::string &name);
void wait_for_event(long sec, long microSec);
private:
// get_datapoint
template <typename T>
......
#ifndef WINCC_EXCEPTIONS
#define WINCC_EXCEPTIONS
namespace LOFAR{
namespace WINCCWRAPPER{
class DatapointNameNotFound : public std::exception
{
private:
std::string message;
public:
DatapointNameNotFound(const std::string & datapointName):
message{"Datapoint " + datapointName + " not found"}{}
const char * what () const throw ()
{
return message.c_str();
}
};
}
}
#endif
......@@ -25,13 +25,22 @@ namespace LOFAR {
using namespace std;
ConnectWaitForAnswer::ConnectWaitForAnswer(const bool handle_multi): HotLinkWaitForAnswer{}, multi{handle_multi}{
}
ConnectWaitForAnswer::ConnectWaitForAnswer(): HotLinkWaitForAnswer{}{
}
void ConnectWaitForAnswer::hotLinkCallBack(DpMsgAnswer &answer)
{
const std::string answer_id{std::to_string(answer.getAnswerId())};
for (AnswerGroup *grpPtr = answer.getFirstGroup(); grpPtr; grpPtr = answer.getNextGroup())
{
if (grpPtr->getError())
{
cout << "Error!" << endl;
cout <<grpPtr->getError()->toString()<< endl;
}
else
{
......@@ -42,6 +51,8 @@ void ConnectWaitForAnswer::hotLinkCallBack(DpMsgAnswer &answer)
if(varPtr)
{
string name = get_datapoint_name(item);
if(name.compare("") == 0) name += answer_id;
Variable *value = varPtr->clone(); //WinCCManager should delete cloned pointer
((WinCCManager *) Manager::getManPtr())->handle_get(name, value);
......@@ -52,6 +63,14 @@ void ConnectWaitForAnswer::hotLinkCallBack(DpMsgAnswer &answer)
}
void ConnectWaitForAnswer::hotLinkCallBack(DpHLGroup &group)
{
if(multi){
handle_multi(group);
}else{
handle_one_by_one(group);
}
}
void ConnectWaitForAnswer::handle_one_by_one(DpHLGroup &group)
{
for (DpVCItem *item = group.getFirstItem(); item; item = group.getNextItem())
{
......@@ -59,6 +78,25 @@ void ConnectWaitForAnswer::hotLinkCallBack(DpHLGroup &group)
}
}
void ConnectWaitForAnswer::handle_multi(DpHLGroup &group)
{
std::map<std::string, std::string> values;
for (DpVCItem *item = group.getFirstItem(); item; item = group.getNextItem())
{
Variable *varPtr = item->getValuePtr();
if (varPtr){
const string name = get_datapoint_name(item);
const string value = varPtr->formatValue().c_str();
values[name] = value;
}
}
((WinCCManager *) Manager::getManPtr())->handle_hotlink(values);
}
void ConnectWaitForAnswer::handle_group_item(const DpVCItem* const item)
{
Variable *varPtr = item->getValuePtr();
......@@ -66,6 +104,7 @@ void ConnectWaitForAnswer::handle_group_item(const DpVCItem* const item)
if (varPtr)
{
string name = get_datapoint_name(item);
string value = varPtr->formatValue().c_str();
((WinCCManager *) Manager::getManPtr())->handle_hotlink(name, value);
......
......@@ -32,12 +32,18 @@ namespace LOFAR {
class ConnectWaitForAnswer : public HotLinkWaitForAnswer
{
public:
ConnectWaitForAnswer();
ConnectWaitForAnswer(const bool handle_multi);
using HotLinkWaitForAnswer::hotLinkCallBack;
virtual void hotLinkCallBack(DpMsgAnswer &answer);
virtual void hotLinkCallBack(DpHLGroup &group);
private:
bool multi;
void handle_one_by_one(DpHLGroup &group);
void handle_multi(DpHLGroup &group);
void handle_group_item(const DpVCItem* const item);
std::string get_datapoint_name(const DpVCItem* const item);
};
} // namespace WINCCWRAPPER
......
......@@ -34,10 +34,18 @@
#include <TextVar.hxx>
#include <DynVar.hxx>
#include <DynPtrArray.hxx>
#include <Resources.hxx>
#include <cassert>
#include <vector>
#include <boost/python.hpp>
#include <Manager.hxx>
#include <DpElement.hxx>
#include <DpIdentification.hxx>
#include <DpIdentificationResultType.hxx>
#include <boost/any.hpp>
#include <exceptions.h>
namespace LOFAR {
namespace WINCCWRAPPER {
......@@ -100,12 +108,77 @@ void WinCCManager::connect_datapoints(const std::vector<std::string> &dataPoints
}
}
void WinCCManager::connect_datapoints_multiple(const std::vector<std::string> &dataPoints)
{
DpIdentList dpList;
for(vector<string>::const_iterator it = dataPoints.begin(); it != dataPoints.end(); it++)
{
DpIdentifier dpIdConnect;
if (Manager::getId(it->c_str(), dpIdConnect) == PVSS_FALSE)
{
// This name was unknown
ErrHdl::error(ErrClass::PRIO_SEVERE,
ErrClass::ERR_PARAM,
ErrClass::UNEXPECTEDSTATE,
"PublishManager",
"connect_datapoints",
CharString("Datapoint ") + CharString(it->c_str()) +
CharString(" missing"));
}
else
{
dpList.append(dpIdConnect);
}
}
// We give the dpConnect a nice naked pointer because it will delete it when the manager stops.
HotLinkWaitForAnswer* wait = new ConnectWaitForAnswer(true);
Manager::dpConnect(dpList, wait);
}
void WinCCManager::disconnect_datapoints(const std::vector<std::string> &dataPoints)
{
for(vector<string>::const_iterator it = dataPoints.begin(); it != dataPoints.end(); it++)
{
DpIdentifier dpIdConnect;
if (Manager::getId(it->c_str(), dpIdConnect) == PVSS_FALSE)
{
// This name was unknown
ErrHdl::error(ErrClass::PRIO_SEVERE,
ErrClass::ERR_PARAM,
ErrClass::UNEXPECTEDSTATE,
"PublishManager",
"connect_datapoints",
CharString("Datapoint ") + CharString(it->c_str()) +
CharString(" missing"));
}
else
{
// We give the dpConnect a nice naked pointer because it will delete it when the manager stops.
HotLinkWaitForAnswer* wait = new ConnectWaitForAnswer();
Manager::dpDisconnect(dpIdConnect, wait);
}
}
}
bool WinCCManager::set_datapoint(const std::string &name, const Variable &value, bool valid)
{
//reuse the set_datapoint_validity, and explicitly set the value to the given value
return set_datapoint_validity(name, valid, &value);
}
// request the query (async). is called by _get_query which makes it blocking (synchronous) by waiting for the answer.
bool WinCCManager::request_query_result(const std::string &query, PVSSulong & identifier)
{
HotLinkWaitForAnswer* wait = new ConnectWaitForAnswer();
return (PVSS_TRUE == Manager::dpQuery(query.c_str(), identifier, wait));
}
// request the datapoint (async). is called by _get_datapoint which makes it blocking (synchronous) by waiting for the answer.
bool WinCCManager::request_datapoint(const std::string &name)
{
......@@ -333,6 +406,72 @@ Variable::ConvertResult convert(Variable *var, struct tm &value, Variable *&conv
return cr;
}
boost::any convert_any(Variable * variable, boost::any & value){
Variable * converted_variable{nullptr};
switch(variable->isA()){
case VariableType::INTEGER_VAR:{
int casted_variable;
convert(variable, casted_variable, converted_variable);
value = casted_variable;
break;
}
case VariableType::FLOAT_VAR: {
float casted_variable;
convert(variable, casted_variable, converted_variable);
value = casted_variable;
break;
}
case VariableType::TEXT_VAR: {
std::string casted_variable;
convert(variable, casted_variable, converted_variable);
value = casted_variable;
break;
}
case VariableType::LONG_VAR:{
// Find the wincc guy who though this out
long casted_variable;
convert(variable, casted_variable, converted_variable);
value = casted_variable;
break;
}
case VariableType::BIT_VAR: {
bool casted_variable;
convert(variable, casted_variable, converted_variable);
value = casted_variable;
break;
}
case VariableType::TIME_VAR: {
time_t casted_variable;
convert(variable, casted_variable, converted_variable);
value = casted_variable;
break;
}
case VariableType::ANYTYPE_VAR: {
const AnyTypeVar * converted_var{static_cast<AnyTypeVar*>(variable)};
convert_any(converted_var->getVar(), value);
break;
}
case VariableType::DPIDENTIFIER_VAR: {
value = std::string{variable->formatValue().c_str()};
break;
}
default:
CharString value_str = variable->formatValue();
std::cerr<<value_str;
std::cerr<<"Datapoint type still not supported: "<<std::hex<<variable->isA()<<std::endl;
value = std::string{value_str.c_str()};
}
if(converted_variable != nullptr) delete converted_variable;
return true;
}
//internal generic method to get the typed (Tval) value of a datapoint
//used by the public strictly typed methods
template <typename Tval>
......@@ -355,6 +494,42 @@ bool WinCCManager::_get_datapoint(const std::string &name, Tval &value)
return false;
}
bool convert_to_vector2(Variable * variable, std::vector<std::vector<std::string>> & result){
if(variable->isA(VariableType::DYN_VAR)){
const DynVar * rows{static_cast<DynVar *>(variable)};
for(DynPtrArrayIndex i=0; i < rows->getNumberOfItems(); i++){
const DynVar * row{static_cast<DynVar *>(rows->getAt(i))};
std::vector<std::string> * current_row{new std::vector<std::string>{}};
Variable * column{static_cast<DynVar *>(row->getNext())};
while(column){
current_row->push_back(column->formatValue().c_str());
column = static_cast<DynVar *>(row->getNext());
}
result.push_back(*current_row);
row = static_cast<DynVar *>(rows->getNext());
}
return true;
}
return false;
}
//internal generic method to query a set of WinCC data points. Since the type is not previously know
bool WinCCManager::get_query(const std::string &query, std::vector<std::vector<std::string>> & result){
Variable * variable_value = nullptr;
PVSSulong identifier;
if(request_query_result(query, identifier))
{
std::string identifier_str{std::to_string(identifier)};
if(wait_for_received_variable(identifier_str, 1000)) {
if(get_received_variable(identifier_str, variable_value)) {
convert_to_vector2(variable_value, result);
return true;
}
}
}
return false;
}
//below, a few strictly type methods for get_datapoint are defined
//they just call the templated _get_datapoint, so why not just use the one and only templated method?
......@@ -401,10 +576,11 @@ bool WinCCManager::get_datapoint(const std::string &name, std::vector<int> &valu
return _get_datapoint(name, value);
}
bool WinCCManager::set_datapoint_validity(const std::string &name, bool validity, const Variable *value)
{
DpIdentifier dpId;
if (Manager::getId(name.c_str(), dpId) == PVSS_FALSE)
{
// This name was unknown.
......@@ -434,8 +610,48 @@ bool WinCCManager::set_datapoint_validity(const std::string &name, bool validity
infoBits.set(DriverBits::DRV_VALID_INVALID);
}
DrvManager *drvman = DrvManager::getSelfPtr();
drvman ->sendVCMsg(dpId, value!=NULL ? *value : *last_known_value, now, infoBits);
// get VariableType from DpIdentifier
// assign values
VariableType dpId_VariableType;
DpElementType dpId_ElementType;
DpIdentification temp_dpId; // make a temp dpId to use the 'getElementType' method
DpIdentificationResult dir = temp_dpId.getElementType(dpId, dpId_ElementType);
// check that the dpIdResult is OK
if(DpIdentificationResult::DpIdentOK == dir) {
dpId_VariableType = DpElement::getVariableType(dpId_ElementType);
}
else {
return false;
}
// check that the VariableType of the datapoint identifier matches the VariableType of the value given.
// if not, convert value to the appropriate datapoint type
if (value->isA() != dpId_VariableType){
VariablePtr converted_var = NULL;
Variable::ConvertResult cr = value->convert(dpId_VariableType, converted_var);
// if conversion succeeds, send the converted var
if(Variable::ConvertResult::OK == cr) {
DrvManager *drvman = DrvManager::getSelfPtr();
drvman ->sendVCMsg(dpId, converted_var!=NULL ? *converted_var : *last_known_value, now, infoBits);
delete converted_var; //delete it, since it was a newly created variable in var->convert
}
// Either 'out_of_bounds' error or 'conv_not_defined' error in converting
else {
delete converted_var; //delete it, since it was a newly created variable in var->convert
return false;
}
}
// no need for conversion
else {
DrvManager *drvman = DrvManager::getSelfPtr();
drvman ->sendVCMsg(dpId, value!=NULL ? *value : *last_known_value, now, infoBits);
}
//process, wait max 10 ms
long sec=0, usec=10000;
......@@ -472,6 +688,10 @@ void WinCCManager::run()
}
}
void WinCCManager::wait_for_event(long sec, long microSec){
dispatch(sec, microSec);
}
void WinCCManager::exit()
{
Manager::exit(0);
......@@ -485,6 +705,14 @@ void WinCCManager::handle_hotlink(const std::string &name, const std::string &va
}
}
void WinCCManager::handle_hotlink(const std::map<std::string, std::string> & values)
{
if(callback_multi)
{
callback_multi(values);
}
}
void WinCCManager::signalHandler(int sig)
{
if ((sig == SIGINT) || (sig == SIGTERM))
......@@ -497,6 +725,81 @@ void WinCCManager::signalHandler(int sig)
}
}
bool WinCCManager::set_datapoint_any(const std::string &datapoint_name, const boost::any &value){
Variable * variable{nullptr};
if(get_datapoint_variable(datapoint_name, variable)){
switch(variable->isA()){
case VariableType::INTEGER_VAR: {
IntegerVar converted_value{boost::any_cast<int>(value)};
set_datapoint(datapoint_name, converted_value);
break;
}
case VariableType::FLOAT_VAR: {
FloatVar converted_value{boost::any_cast<float>(value)};
set_datapoint(datapoint_name, converted_value);
break;
}
case VariableType::TEXT_VAR: {
TextVar converted_value{CharString(boost::any_cast<std::string>(value).c_str())};
set_datapoint(datapoint_name, converted_value);
break;
}
case VariableType::LONG_VAR:{
LongVar converted_value{boost::any_cast<long>(value)};
set_datapoint(datapoint_name, converted_value);
break;
}
case VariableType::BIT_VAR: {
BitVar converted_value{boost::any_cast<bool>(value)};
set_datapoint(datapoint_name, converted_value);
break;
}
case VariableType::TIME_VAR: {
TimeVar converted_value(0,0);
converted_value.setSeconds(boost::any_cast<time_t>(value));
set_datapoint(datapoint_name, converted_value);
break;
}
default:
std::cerr<<"Datapoint type still not supported: "<<std::hex<<variable->isA()<<std::endl;
return false;
}
}else{
return false;
}
return true;
}
bool WinCCManager::get_datapoint_any(const std::string &datapoint_name, boost::any & value){
// Yeah I know... WinCC API is getting a &* to allocate the memory space...
Variable * variable{nullptr};
bool returnValue{true};
if(!get_datapoint_variable(datapoint_name, variable)){
// This name was unknown.
ErrHdl::error(ErrClass::PRIO_SEVERE,
ErrClass::ERR_PARAM,
ErrClass::UNEXPECTEDSTATE,
Resources::getProgName(),
"get_datapoint",
CharString("Datapoint ") + CharString(datapoint_name.c_str()) +
CharString(" missing"));
throw DatapointNameNotFound{datapoint_name};
}
convert_any(variable, value);
if(variable != nullptr) delete variable;
return returnValue;
}
} // namespace WINCCWRAPPER
} // namespace LOFAR
......@@ -31,11 +31,62 @@ WinCCResources::WinCCResources(const std::string &project_name)
init(project_name);
}
void WinCCResources::init(const std::string & /*project_name*/)
WinCCResources::WinCCResources(const::std::string &program_name, const std::string &project_name, const int num)
{
// TODO set specific project instead of current project.
char* ownArgv[] = {(char *)"WinCCWrapper", (char *)"-currentproj", (char *)"-log", (char *)"+stderr"};
int ownArgc = sizeof ownArgv / sizeof ownArgv[0];
init(program_name, project_name, num);
}
void WinCCResources::init(const::std::string &program_name, const std::string & project_name, const int num)
{
std::vector<std::string> args{program_name};
if(project_name.compare("-currentproj") == 0){
args.push_back("-currentproj");
}else{
args.push_back("-proj");
args.push_back(project_name);
}
args.push_back("-log");
args.push_back("+stderr");
args.push_back("-num");
args.push_back(std::to_string(num));
int ownArgc = args.size();
char * ownArgv[ownArgc];
for(int i=0; i<ownArgc; i++){
ownArgv[i] = const_cast<char *>(args.at(i).c_str());
}
Resources::init(ownArgc, ownArgv);
}
void WinCCResources::init(const std::string & project_name)
{
std::vector<std::string> args{"WinCCWrapper"};
if(project_name.compare("-currentproj") == 0){
args.push_back("-currentproj");
}else{
args.push_back("-proj");
args.push_back(project_name);
}
args.push_back("-log");
args.push_back("+stderr");
int ownArgc = args.size();
char * ownArgv[ownArgc];
for(int i=0; i<ownArgc; i++){
ownArgv[i] = const_cast<char *>(args.at(i).c_str());
}
Resources::init(ownArgc, ownArgv);
}
......
......@@ -43,6 +43,9 @@ using namespace std;
//! Each datapoint has a human readable name in the wincc database, but the actual value is stored in a sub-item. Append that to each set/get datapoint name.
static const string DP_SUFFIX = ":_original.._value";
//! This property refers to the last set time
static const string DP_SUFFIX_STIME = ":_original.._stime";
WinCCWrapper::WinCCWrapper(const std::string &project_name) :
resources(project_name)
......@@ -50,6 +53,12 @@ WinCCWrapper::WinCCWrapper(const std::string &project_name) :
manager = new WinCCManager();
}
WinCCWrapper::WinCCWrapper(const std::string &program_name, const std::string &project_name, const int num) :
resources(program_name, project_name, num)
{
manager = new WinCCManager();
}
void WinCCWrapper::run()
{
manager->run();
......@@ -65,11 +74,31 @@ void WinCCWrapper::connect_datapoints(const std::vector<std::string> &data_point
manager->connect_datapoints(data_points);
}
void WinCCWrapper::connect_datapoints_multi(const std::vector<std::string> &data_points)
{
manager->connect_datapoints_multiple(data_points);
}
void WinCCWrapper::disconnect_datapoints(const std::vector<std::string> &data_points)
{
manager->connect_datapoints(data_points);
}
void WinCCWrapper::wait_for_event(long sec, long microSec){
manager->wait_for_event(sec, microSec);
}
void WinCCWrapper::set_connect_datapoints_callback(std::function<void(std::string name, std::string value)> callback)
{
manager->set_connect_datapoints_callback(callback);
}
void WinCCWrapper::set_connect_datapoints_callback(std::function<void(std::map<std::string, std::string>)> callback)
{
manager->set_connect_datapoints_callback(callback);
}
// set_datapoint
bool WinCCWrapper::set_datapoint(const std::string &name, int value, bool valid)
{
......@@ -99,7 +128,7 @@ bool WinCCWrapper::set_datapoint(const std::string &name, boost::python::tuple &
bool WinCCWrapper::set_datapoint(const std::string &name, std::vector<int> &value, bool valid)
{
DynVar variable(VariableType::INTEGER_VAR);
for(auto iter = value.cbegin(); iter != value.cend(); iter++) {
IntegerVar elem{*iter};
variable.append(elem);}
......@@ -142,6 +171,12 @@ bool WinCCWrapper::set_datapoint_time(const std::string &name, time_t value, boo
return manager->set_datapoint(name + DP_SUFFIX, variable, valid);
}
boost::any WinCCWrapper::get_datapoint_any (const std::string &name){
boost::any datapoint_value;
manager->get_datapoint_any(name + DP_SUFFIX, datapoint_value);
return datapoint_value;
}
// get_datapoint
template <typename T>
bool WinCCWrapper::get_datapoint(const std::string &name, T &value)
......@@ -213,6 +248,21 @@ time_t WinCCWrapper::get_datapoint_time(const std::string &name)
throw std::runtime_error("Could not get datapoint");
}
std::string WinCCWrapper::get_formatted_datapoint(const std::string &name){
std::string value;
if(manager->get_datapoint(name, value)){
return value;
}
throw std::runtime_error("Could not get datapoint");
}
time_t WinCCWrapper::get_datapoint_set_time(const std::string &name){
struct tm value;
if(manager->get_datapoint(name + DP_SUFFIX_STIME, value))
return mktime(&value);
throw std::runtime_error("Could not get datapoint");
}
bool WinCCWrapper::set_datapoint_valid(const std::string &name)
{
return manager->set_datapoint_valid(name + DP_SUFFIX);
......@@ -223,5 +273,8 @@ bool WinCCWrapper::set_datapoint_invalid(const std::string &name)
return manager->set_datapoint_invalid(name + DP_SUFFIX);
}
bool WinCCWrapper::set_datapoint_any(const std::string &name, boost::any value){
return manager->set_datapoint_any(name + DP_SUFFIX, value);
}
} // namespace WINCCWRAPPER
} // namespace LOFAR
class DatapointNameNotFound : public std::exception
{
private:
std::string message;
public:
DatapointNameNotFound(const std::string & datapointName):
message{"Datapoint " + datapointName + " not found"}{}
const char * what () const throw ()
{
return message.c_str();
}
}
......@@ -8,6 +8,15 @@ IF(BUILD_TESTING)
lofar_add_bin_program(WinCCSet WinCCSet.cc)
lofar_add_bin_program(WinCCGet WinCCGet.cc)
lofar_add_bin_program(WinCCQuery WinCCQuery.cc)
find_package(Boost COMPONENTS program_options system REQUIRED)
target_link_libraries(WinCCQuery
wincc_wrapper
${Boost_LIBRARIES}
)
ENDIF(WINCC_FOUND)
ENDIF(BUILD_TESTING)
......
......@@ -3,28 +3,28 @@
#include <WinCCWrapper.h>
#include <vector>
#include <iostream>
#include <Resources.hxx>
using namespace LOFAR::WINCCWRAPPER;
using namespace std;
void get_help(){
cout << "Usage:" << endl;
cout << "WinCCGet \"datapoint_name\" datapoint_type" << endl;
cout << "WinCCGet \"datapoint_name\" datapoint_type project_name" << endl;
cout << "Accepted datapoint types:" << endl;
cout << " int, float, string, list (for int lists)" << endl;
}
int main(int argc, char * argv[])
{
bool asking_for_help = ((argc == 2) && (string(argv[1]) == "--help" || string(argv[1]) == "--h"));
bool invalid_args = (argc != 3);
bool asking_for_help = ((argc < 4) && (string(argv[1]) == "--help" || string(argv[1]) == "--h"));
bool invalid_args = (argc != 4);
if (asking_for_help || invalid_args){
get_help();
return 0;
}
WinCCWrapper wrapper{""};
WinCCWrapper wrapper{std::string(argv[3])};
string dpname{argv[1]};
if (string(argv[2]) == "int") {
......
#include <cstdlib>
#include <string>
#include <WinCCManager.h>
#include <WinCCResources.h>
#include <vector>
#include <iostream>
#include <Resources.hxx>
#include <boost/program_options.hpp>
#include <boost/any.hpp>
using namespace LOFAR::WINCCWRAPPER;
using namespace std;
namespace po = boost::program_options;
void set_options(po::options_description & description){
description.add_options()
("help", "produce help message")
("sql", po::value<std::string>(), "SQL_query")
("project", po::value<std::string>(), "WinCC project");
}
int main(int argc, char * argv[])
{
// Declare the supported options.
po::options_description desc("Query the WinCCDatabase");
set_options(desc);
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("help")) {
cout << desc << "\n";
return 1;
}
if (vm.count("sql") == 1 && vm.count("project") == 1) {
const string sql{vm["sql"].as<string>()};
WinCCResources resource{"WinCCQuery", vm["project"].as<string>(), 0};
WinCCManager manager;
cout << "The SQL is: [" << sql << "].\n";
std::vector<std::vector<std::string>> queryResult;
manager.get_query(sql, queryResult);
std::cout<< "RESULTS ----"<<"\n\n";
std::cout<< "datapoint" << "\t";
for(auto & row : queryResult){
for(std::string & column : row){
std::cout<<column<<"\t";
}
std::cout<<"\n";
}
} else {
cout << desc;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment