ConditionCheck.cpp
Go to the documentation of this file.
1 /*
2 * This file is part of ArmarX.
3 *
4 * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5 *
6 * ArmarX is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 * ArmarX is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * @package ArmarX::Core
19 * @author Kai Welke (welke _at_ kit _dot_ edu)
20 * @date 2011
21 * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22 * GNU General Public License
23 */
24 
30 
31 #include <algorithm>
32 #include <cstdarg>
33 
34 template class ::IceInternal::Handle<::armarx::ConditionCheck>;
35 
36 namespace armarx
37 {
38  ConditionCheck::ConditionCheck()
39  {
40 
41  reset();
42  }
43 
44  ConditionCheckPtr ConditionCheck::createInstance(const CheckConfiguration& configuration, const ChannelRegistry& channelRegistry)
45  {
46  // channel available?
47  DataFieldIdentifierBasePtr dataFieldIdentifier = configuration.dataFieldIdentifier;
48  ChannelRegistry::const_iterator iterChannels = channelRegistry.find(dataFieldIdentifier->channelName);
49 
50  if (iterChannels == channelRegistry.end())
51  {
52  throw InvalidConditionException("Invalid channel \"" + dataFieldIdentifier->channelName + "\" in check " + configuration.checkName);
53  }
54 
55  // datafield available?
56  const DataFieldRegistry& dataFieldRegistry = iterChannels->second.dataFields;
57  DataFieldRegistry::const_iterator iterData = dataFieldRegistry.find(dataFieldIdentifier->datafieldName);
58 
59  if (iterData == dataFieldRegistry.end())
60  {
61  throw InvalidConditionException("Invalid datafield \"" + dataFieldIdentifier->channelName + "." + dataFieldIdentifier->datafieldName + "\" in check " + configuration.checkName);
62  }
63 
64  // types supported by check?
65  VariantPtr dataField = VariantPtr::dynamicCast(iterData->second.value);
66  assureTypeSupported(configuration, dataField->getType());
67 
68  // create new instance of check
69  ConditionCheckPtr check = this->clone();
70  check->configuration = configuration;
71 
72  return check;
73  }
74 
75  void ConditionCheck::reset()
76  {
77  firstEval = true;
78  numberParameters = 0;
79  fulFilled = false;
80  }
81 
82  void ConditionCheck::evaluateCondition(const DataFieldRegistry& dataFields)
83  {
84  // find data fields that correspond to the current check
85  // DataFieldRegistry::const_iterator iter = dataFields.begin();
86 
87  StringVariantMap checkDataFields;
88 
89  // TODO: this loop should be skipped, computational to heavy, is it even possible to install a condition over several datafields? (I dont think so)
90  // while (iter != dataFields.end())
91  // {
92  // DatafieldRefPtr ref = DatafieldRefPtr::dynamicCast(iter->second.identifier);
93  // ARMARX_CHECK_EXPRESSION(ref);
94 
95  // if (ref->getDataFieldIdentifier()->beginsWith(*DataFieldIdentifierPtr::dynamicCast(configuration.dataFieldIdentifier)))
96  // {
97  // checkDataFields[iter->second.identifier->datafieldName] = *VariantPtr::dynamicCast(iter->second.value);
98  // }
99 
100  // iter++;
101  // }
102 
103  auto iter = dataFields.find(configuration.dataFieldIdentifier->datafieldName);
104  if (iter != dataFields.end())
105  {
106  checkDataFields[iter->second.identifier->datafieldName] = *VariantPtr::dynamicCast(iter->second.value);
107  }
108  if (checkDataFields.size() == 0)
109  {
110  return;
111  }
112 
113  // evaluate condition
114  bool oldFulFilled = fulFilled;
115  fulFilled = evaluate(checkDataFields);
116 
117  // if status changed, inform listener
118  if (configuration.reportAlways || oldFulFilled != fulFilled || firstEval || configuration.reportDatafieldValues)
119  {
120  if (oldFulFilled != fulFilled)
121  {
122  ARMARX_DEBUG_S << "Evaluating check: '" << configuration.checkName << "' - status changed (" << oldFulFilled << " -> " << fulFilled << ")" << std::endl;
123  }
124  else if (firstEval)
125  {
126  ARMARX_DEBUG_S << "First evaluating of check: '" << configuration.checkName << "' is " << fulFilled;
127  }
128  else
129  {
130  ARMARX_DEBUG_S << "Unchanged value of check: '" << configuration.checkName << "' is " << fulFilled;
131  }
132 
133 
134  firstEval = false;
135  if (configuration.reportDatafieldValues)
136  {
137  configuration.listener->setValueAndData(fulFilled, configuration.dataFieldIdentifier, iter->second.value);
138  }
139  else
140  {
141  configuration.listener->setValue(fulFilled);
142  }
143  }
144  }
145 
146  bool ConditionCheck::getFulFilled()
147  {
148  return fulFilled;
149  }
150 
151  const Variant& ConditionCheck::getParameter(int index)
152  {
153  if (index >= numberParameters)
154  {
155  throw LocalException("Illegal parameter requested\n");
156  }
157 
158  VariantPtr var = VariantPtr::dynamicCast(configuration.checkParameters.at(index));
159 
160  if (var->getType() == VariantType::DatafieldRef) // get datafield content
161  {
162  DatafieldRefPtr dfr = var->getClass<DatafieldRef>();
163  // ARMARX_VERBOSE_S << "Turning Datafield " << dfr->getDataFieldIdentifier()->getIdentifierStr() << "into variant";
164  var = dfr->getDataField();
165  }
166 
167  return *var;
168  }
169 
170  void ConditionCheck::assureTypeSupported(const CheckConfiguration& configuration, VariantTypeId dataFieldType)
171  {
172 
173  SupportedTypeList::iterator iter = supportedTypes.begin();
174 
175  bool bValidType = false;
176 
177  while (iter != supportedTypes.end())
178  {
179  VariantTypeId supportedType = iter->dataFieldType;
180 
181  // 0 means: all types are supported
182  if (supportedType == 0)
183  {
184  bValidType = true;
185  break;
186  }
187  else if (supportedType == dataFieldType)
188  {
189  if (configuration.checkParameters.size() != iter->parameterTypes.size())
190  {
191  throw InvalidConditionException("Wrong number of parameters for condition in check " + configuration.checkName);
192  }
193 
194  ParameterTypeList::iterator iter_param = iter->parameterTypes.begin();
195  bool bParameterValid = true;
196  int p = 0;
197 
198  while (iter_param != iter->parameterTypes.end())
199  {
200 
201 
202  VariantTypeId paramType = configuration.checkParameters.at(p)->getType();
203 
204  if (paramType == VariantType::DatafieldRef) // get datafield and check for type of the datafield
205  {
206  VariantPtr var = VariantPtr::dynamicCast(configuration.checkParameters.at(p));
207  DatafieldRefPtr dfr = var->getClass<DatafieldRef>();
208 
209  if (!dfr->validate())
210  {
211  bParameterValid = false;
212  break;
213  }
214 
215  // ARMARX_VERBOSE_S << dfr->getDataFieldIdentifier()->getIdentifierStr() << " has type: " << dfr->getDataField()->getType();
216  paramType = dfr->getDataField()->getType();
217  }
218 
219  if (*iter_param != paramType)
220  {
221  bParameterValid = false;
222  break;
223  }
224 
225  p++;
226  iter_param++;
227  }
228 
229  if (bParameterValid)
230  {
231  bValidType = true;
232  break;
233  }
234  }
235 
236  iter++;
237  }
238 
239  if (!bValidType)
240  {
241  throw InvalidConditionException("Invalid types for check " + configuration.checkName + " Type: " + Variant::typeToString(dataFieldType));
242  }
243  }
244 
245  void ConditionCheck::setNumberParameters(int numberParameters)
246  {
247  this->numberParameters = numberParameters;
248  }
249 
250  void ConditionCheck::addSupportedType(VariantTypeId dataFieldType, ParameterTypeList parameterTypes)
251  {
252  SupportedType type;
253  type.dataFieldType = dataFieldType;
254  type.parameterTypes = parameterTypes;
255 
256  supportedTypes.push_back(type);
257  }
258 
259  ParameterTypeList ConditionCheck::createParameterTypeList(int numberTypes, ...)
260  {
261  va_list ap;
262  va_start(ap, numberTypes);
263 
264  ParameterTypeList params;
265 
266  for (int p = 0 ; p < numberTypes; p++)
267  {
268  params.push_back((VariantTypeId) va_arg(ap, int));
269  }
270 
271  va_end(ap);
272 
273  return params;
274  }
275 }
armarx::Variant
The Variant class is described here: Variants.
Definition: Variant.h:224
armarx::StringVariantMap
std::map< std::string, Variant > StringVariantMap
Definition: Variant.h:748
IceInternal::Handle
Definition: forward_declarations.h:8
DatafieldRef.h
armarx::DatafieldRefPtr
IceInternal::Handle< DatafieldRef > DatafieldRefPtr
Definition: Observer.h:44
armarx::VariantPtr
IceInternal::Handle< Variant > VariantPtr
Definition: Variant.h:42
ARMARX_DEBUG_S
#define ARMARX_DEBUG_S
Definition: Logging.h:198
armarx::VariantTypeId
Ice::Int VariantTypeId
Definition: Variant.h:44
armarx::DatafieldRef
The DatafieldRef class is similar to the ChannelRef, but points to a specific Datafield instead of to...
Definition: DatafieldRef.h:51
armarx::VariantType::DatafieldRef
const VariantTypeId DatafieldRef
Definition: DatafieldRef.h:169
ExpressionException.h
armarx::ConditionCheck::ChannelRegistry
armarx::ChannelRegistry ChannelRegistry
Creates a new ConditionCheck instance.
Definition: ConditionCheck.h:83
ConditionCheck.h
Logging.h
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:28
Exception.h