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 
25 #include <algorithm>
26 #include <cstdarg>
27 
33 
34 template class ::IceInternal::Handle<::armarx::ConditionCheck>;
35 
36 namespace armarx
37 {
38  ConditionCheck::ConditionCheck()
39  {
40 
41  reset();
42  }
43 
45  ConditionCheck::createInstance(const CheckConfiguration& configuration,
46  const ChannelRegistry& channelRegistry)
47  {
48  // channel available?
49  DataFieldIdentifierBasePtr dataFieldIdentifier = configuration.dataFieldIdentifier;
50  ChannelRegistry::const_iterator iterChannels =
51  channelRegistry.find(dataFieldIdentifier->channelName);
52 
53  if (iterChannels == channelRegistry.end())
54  {
55  throw InvalidConditionException("Invalid channel \"" +
56  dataFieldIdentifier->channelName + "\" in check " +
57  configuration.checkName);
58  }
59 
60  // datafield available?
61  const DataFieldRegistry& dataFieldRegistry = iterChannels->second.dataFields;
62  DataFieldRegistry::const_iterator iterData =
63  dataFieldRegistry.find(dataFieldIdentifier->datafieldName);
64 
65  if (iterData == dataFieldRegistry.end())
66  {
67  throw InvalidConditionException(
68  "Invalid datafield \"" + dataFieldIdentifier->channelName + "." +
69  dataFieldIdentifier->datafieldName + "\" in check " + configuration.checkName);
70  }
71 
72  // types supported by check?
73  VariantPtr dataField = VariantPtr::dynamicCast(iterData->second.value);
74  assureTypeSupported(configuration, dataField->getType());
75 
76  // create new instance of check
77  ConditionCheckPtr check = this->clone();
78  check->configuration = configuration;
79 
80  return check;
81  }
82 
83  void
84  ConditionCheck::reset()
85  {
86  firstEval = true;
87  numberParameters = 0;
88  fulFilled = false;
89  }
90 
91  void
92  ConditionCheck::evaluateCondition(const DataFieldRegistry& dataFields)
93  {
94  // find data fields that correspond to the current check
95  // DataFieldRegistry::const_iterator iter = dataFields.begin();
96 
97  StringVariantMap checkDataFields;
98 
99  // TODO: this loop should be skipped, computational to heavy, is it even possible to install a condition over several datafields? (I dont think so)
100  // while (iter != dataFields.end())
101  // {
102  // DatafieldRefPtr ref = DatafieldRefPtr::dynamicCast(iter->second.identifier);
103  // ARMARX_CHECK_EXPRESSION(ref);
104 
105  // if (ref->getDataFieldIdentifier()->beginsWith(*DataFieldIdentifierPtr::dynamicCast(configuration.dataFieldIdentifier)))
106  // {
107  // checkDataFields[iter->second.identifier->datafieldName] = *VariantPtr::dynamicCast(iter->second.value);
108  // }
109 
110  // iter++;
111  // }
112 
113  auto iter = dataFields.find(configuration.dataFieldIdentifier->datafieldName);
114  if (iter != dataFields.end())
115  {
116  checkDataFields[iter->second.identifier->datafieldName] =
117  *VariantPtr::dynamicCast(iter->second.value);
118  }
119  if (checkDataFields.size() == 0)
120  {
121  return;
122  }
123 
124  // evaluate condition
125  bool oldFulFilled = fulFilled;
126  fulFilled = evaluate(checkDataFields);
127 
128  // if status changed, inform listener
129  if (configuration.reportAlways || oldFulFilled != fulFilled || firstEval ||
130  configuration.reportDatafieldValues)
131  {
132  if (oldFulFilled != fulFilled)
133  {
134  ARMARX_DEBUG_S << "Evaluating check: '" << configuration.checkName
135  << "' - status changed (" << oldFulFilled << " -> " << fulFilled
136  << ")" << std::endl;
137  }
138  else if (firstEval)
139  {
140  ARMARX_DEBUG_S << "First evaluating of check: '" << configuration.checkName
141  << "' is " << fulFilled;
142  }
143  else
144  {
145  ARMARX_DEBUG_S << "Unchanged value of check: '" << configuration.checkName
146  << "' is " << fulFilled;
147  }
148 
149 
150  firstEval = false;
151  if (configuration.reportDatafieldValues)
152  {
153  configuration.listener->setValueAndData(
154  fulFilled, configuration.dataFieldIdentifier, iter->second.value);
155  }
156  else
157  {
158  configuration.listener->setValue(fulFilled);
159  }
160  }
161  }
162 
163  bool
164  ConditionCheck::getFulFilled()
165  {
166  return fulFilled;
167  }
168 
169  const Variant&
170  ConditionCheck::getParameter(int index)
171  {
172  if (index >= numberParameters)
173  {
174  throw LocalException("Illegal parameter requested\n");
175  }
176 
177  VariantPtr var = VariantPtr::dynamicCast(configuration.checkParameters.at(index));
178 
179  if (var->getType() == VariantType::DatafieldRef) // get datafield content
180  {
181  DatafieldRefPtr dfr = var->getClass<DatafieldRef>();
182  // ARMARX_VERBOSE_S << "Turning Datafield " << dfr->getDataFieldIdentifier()->getIdentifierStr() << "into variant";
183  var = dfr->getDataField();
184  }
185 
186  return *var;
187  }
188 
189  void
190  ConditionCheck::assureTypeSupported(const CheckConfiguration& configuration,
191  VariantTypeId dataFieldType)
192  {
193 
194  SupportedTypeList::iterator iter = supportedTypes.begin();
195 
196  bool bValidType = false;
197 
198  while (iter != supportedTypes.end())
199  {
200  VariantTypeId supportedType = iter->dataFieldType;
201 
202  // 0 means: all types are supported
203  if (supportedType == 0)
204  {
205  bValidType = true;
206  break;
207  }
208  else if (supportedType == dataFieldType)
209  {
210  if (configuration.checkParameters.size() != iter->parameterTypes.size())
211  {
212  throw InvalidConditionException(
213  "Wrong number of parameters for condition in check " +
214  configuration.checkName);
215  }
216 
217  ParameterTypeList::iterator iter_param = iter->parameterTypes.begin();
218  bool bParameterValid = true;
219  int p = 0;
220 
221  while (iter_param != iter->parameterTypes.end())
222  {
223 
224 
225  VariantTypeId paramType = configuration.checkParameters.at(p)->getType();
226 
227  if (paramType ==
228  VariantType::
229  DatafieldRef) // get datafield and check for type of the datafield
230  {
231  VariantPtr var =
232  VariantPtr::dynamicCast(configuration.checkParameters.at(p));
233  DatafieldRefPtr dfr = var->getClass<DatafieldRef>();
234 
235  if (!dfr->validate())
236  {
237  bParameterValid = false;
238  break;
239  }
240 
241  // ARMARX_VERBOSE_S << dfr->getDataFieldIdentifier()->getIdentifierStr() << " has type: " << dfr->getDataField()->getType();
242  paramType = dfr->getDataField()->getType();
243  }
244 
245  if (*iter_param != paramType)
246  {
247  bParameterValid = false;
248  break;
249  }
250 
251  p++;
252  iter_param++;
253  }
254 
255  if (bParameterValid)
256  {
257  bValidType = true;
258  break;
259  }
260  }
261 
262  iter++;
263  }
264 
265  if (!bValidType)
266  {
267  throw InvalidConditionException("Invalid types for check " + configuration.checkName +
268  " Type: " + Variant::typeToString(dataFieldType));
269  }
270  }
271 
272  void
273  ConditionCheck::setNumberParameters(int numberParameters)
274  {
275  this->numberParameters = numberParameters;
276  }
277 
278  void
279  ConditionCheck::addSupportedType(VariantTypeId dataFieldType, ParameterTypeList parameterTypes)
280  {
281  SupportedType type;
282  type.dataFieldType = dataFieldType;
283  type.parameterTypes = parameterTypes;
284 
285  supportedTypes.push_back(type);
286  }
287 
288  ParameterTypeList
289  ConditionCheck::createParameterTypeList(int numberTypes, ...)
290  {
291  va_list ap;
292  va_start(ap, numberTypes);
293 
294  ParameterTypeList params;
295 
296  for (int p = 0; p < numberTypes; p++)
297  {
298  params.push_back((VariantTypeId)va_arg(ap, int));
299  }
300 
301  va_end(ap);
302 
303  return params;
304  }
305 } // namespace armarx
armarx::Variant
The Variant class is described here: Variants.
Definition: Variant.h:223
armarx::StringVariantMap
std::map< std::string, Variant > StringVariantMap
Definition: Variant.h:748
index
uint8_t index
Definition: EtherCATFrame.h:59
IceInternal::Handle
Definition: forward_declarations.h:8
DatafieldRef.h
armarx::DatafieldRefPtr
IceInternal::Handle< DatafieldRef > DatafieldRefPtr
Definition: Observer.h:43
armarx::VariantPtr
IceInternal::Handle< Variant > VariantPtr
Definition: Variant.h:41
ARMARX_DEBUG_S
#define ARMARX_DEBUG_S
Definition: Logging.h:205
armarx::VariantTypeId
Ice::Int VariantTypeId
Definition: Variant.h:43
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:197
ExpressionException.h
armarx::ConditionCheck::ChannelRegistry
armarx::ChannelRegistry ChannelRegistry
Creates a new ConditionCheck instance.
Definition: ConditionCheck.h:82
ConditionCheck.h
Logging.h
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
Exception.h