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
34template class ::IceInternal::Handle<::armarx::ConditionCheck>;
35
36namespace armarx
37{
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
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
165 {
166 return fulFilled;
167 }
168
169 const Variant&
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
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
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
uint8_t index
virtual ConditionCheckPtr createInstance(const CheckConfiguration &configuration, const ChannelRegistry &channelRegistry)
armarx::ChannelRegistry ChannelRegistry
Creates a new ConditionCheck instance.
virtual bool evaluate(const StringVariantMap &dataFields)
Evaluate the condition based on the current data field values.
static ParameterTypeList createParameterTypeList(int numberTypes,...)
void evaluateCondition(const DataFieldRegistry &dataFields)
Evaluates the condition based on the given registry of data fields.
void setNumberParameters(int numberParameters)
Sets the number of paramaters required for this check.
const Variant & getParameter(int index)
Retrieve parameters of check.
bool getFulFilled()
Retrieve result of a condition evaluation initiated by evaluateCondition.
ConditionCheck()
Creates and initializes a ConditionCheck instance.
void reset()
Resets the status flags of the check such as check results.
virtual ConditionCheck * clone()
Clones the current check.
void addSupportedType(VariantTypeId dataFieldType=0, ParameterTypeList parameterTypes=ParameterTypeList())
Add a supported type for elementary condition check marks pairs of (dataFieldType,...
The DatafieldRef class is similar to the ChannelRef, but points to a specific Datafield instead of to...
The Variant class is described here: Variants.
Definition Variant.h:224
#define ARMARX_DEBUG_S
The logging level for output that is only interesting while debugging.
Definition Logging.h:205
const VariantTypeId DatafieldRef
This file offers overloads of toIce() and fromIce() functions for STL container types.
IceInternal::Handle< DataFieldIdentifierBase > DataFieldIdentifierBasePtr
IceInternal::Handle< Variant > VariantPtr
Definition Variant.h:41
IceInternal::Handle< ConditionCheck > ConditionCheckPtr
IceInternal::Handle< DatafieldRef > DatafieldRefPtr
Definition Observer.h:43
Ice::Int VariantTypeId
Definition Variant.h:43
std::map< std::string, Variant > StringVariantMap
Definition Variant.h:748