Fawkes API Fawkes Development Version
config_adapter.cpp
1
2/***************************************************************************
3 * config_adapter.cpp - PLEXIL adapter for protobuf_comm
4 *
5 * Created: Thu Aug 16 11:06:55 2018
6 * Copyright 2006-2018 Tim Niemueller [www.niemueller.de]
7 ****************************************************************************/
8
9/* This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * Read the full text in the LICENSE.GPL file in the doc directory.
20 */
21
22#include "config_adapter.h"
23
24#include "utils.h"
25
26#include <AdapterConfiguration.hh>
27#include <AdapterExecInterface.hh>
28#include <AdapterFactory.hh>
29#include <Command.hh>
30#include <InterfaceManager.hh>
31#include <StateCacheEntry.hh>
32#include <limits>
33
34using namespace fawkes;
35
36/** @class ConfigurationPlexilAdapter "config_adapter.h"
37 * Plexil adapter to provide access to the Fawkes configuration.
38 * @author Tim Niemueller
39 */
40
41/** Constructor.
42 * @param execInterface Reference to the parent AdapterExecInterface object.
43 */
44ConfigurationPlexilAdapter::ConfigurationPlexilAdapter(PLEXIL::AdapterExecInterface &execInterface)
45: InterfaceAdapter(execInterface)
46{
47}
48
49/** Constructor from configuration XML.
50 * @param execInterface Reference to the parent AdapterExecInterface object.
51 * @param xml A const reference to the XML element describing this adapter
52 * @note The instance maintains a shared pointer to the XML.
53 */
54ConfigurationPlexilAdapter::ConfigurationPlexilAdapter(PLEXIL::AdapterExecInterface &execInterface,
55 pugi::xml_node const xml)
56: InterfaceAdapter(execInterface, xml)
57{
58}
59
60/** Destructor. */
62{
63}
64
65/** Initialize adapter.
66 * @return true if initialization was successful, false otherwise.
67 */
68bool
70{
71 logger_ = reinterpret_cast<fawkes::Logger *>(m_execInterface.getProperty("::Fawkes::Logger"));
72 config_ =
73 reinterpret_cast<fawkes::Configuration *>(m_execInterface.getProperty("::Fawkes::Config"));
74
75 namespace p = std::placeholders;
76 commands_ = {
77 {"config_get_int_or_default",
78 std::bind(&ConfigurationPlexilAdapter::config_get_value_or_default,
79 this,
80 p::_1,
81 PLEXIL::INTEGER_TYPE)},
82 {"config_get_real_or_default",
83 std::bind(
84 &ConfigurationPlexilAdapter::config_get_value_or_default, this, p::_1, PLEXIL::REAL_TYPE)},
85 {"config_get_bool_or_default",
86 std::bind(&ConfigurationPlexilAdapter::config_get_value_or_default,
87 this,
88 p::_1,
89 PLEXIL::BOOLEAN_TYPE)},
90 {"config_get_string_or_default",
91 std::bind(
92 &ConfigurationPlexilAdapter::config_get_value_or_default, this, p::_1, PLEXIL::STRING_TYPE)},
93 {"config_get_int",
94 std::bind(&ConfigurationPlexilAdapter::config_get_value, this, p::_1, PLEXIL::INTEGER_TYPE)},
95 {"config_get_real",
96 std::bind(&ConfigurationPlexilAdapter::config_get_value, this, p::_1, PLEXIL::REAL_TYPE)},
97 {"config_get_bool",
98 std::bind(&ConfigurationPlexilAdapter::config_get_value, this, p::_1, PLEXIL::BOOLEAN_TYPE)},
99 {"config_get_string",
100 std::bind(&ConfigurationPlexilAdapter::config_get_value, this, p::_1, PLEXIL::STRING_TYPE)},
101 {"config_exists", std::bind(&ConfigurationPlexilAdapter::config_exists, this, p::_1)},
102 };
103
104 for (const auto &c : commands_) {
105 PLEXIL::g_configuration->registerCommandInterface(c.first, this);
106 }
107
108 return true;
109}
110
111/** Start adapter.
112 * @return true if starting was successful, false otherwise.
113 */
114bool
116{
117 return true;
118}
119
120/** Stop adapter.
121 * @return true if successful, false otherwise.
122 */
123bool
125{
126 return true;
127}
128
129/** Reset adapter.
130 * @return true if successful, false otherwise.
131 */
132bool
134{
135 return true;
136}
137
138/** Shut adapter down.
139 * @return true if successful, false otherwise.
140 */
141bool
143{
144 return true;
145}
146
147/** Perform given command.
148 * @param cmd command to execute
149 */
150void
152{
153 std::string const &name = cmd->getName();
154
155 auto c = commands_.find(name);
156 if (c != commands_.end()) {
157 c->second(cmd);
158 } else {
159 warn("ConfigCommAdapter:executeCommand: called for unknown"
160 " command "
161 << name);
162 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
163 m_execInterface.notifyOfExternalEvent();
164 }
165}
166
167/** Abort currently running execution.
168 * @param cmd command to abort
169 */
170void
172{
173 m_execInterface.handleCommandAbortAck(cmd, false);
174 m_execInterface.notifyOfExternalEvent();
175}
176
177void
178ConfigurationPlexilAdapter::config_get_value_or_default(PLEXIL::Command * cmd,
179 PLEXIL::ValueType value_type)
180{
181 std::vector<PLEXIL::Value> const &args = cmd->getArgValues();
182 if (!verify_args(args,
183 "ConfigCommAdapter:config_get_value_or_default",
184 {{"path", PLEXIL::STRING_TYPE}, {"default", value_type}})) {
185 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
186 m_execInterface.notifyOfExternalEvent();
187 return;
188 }
189
190 std::string path;
191 args[0].getValue(path);
192
193 try {
194 switch (value_type) {
195 case PLEXIL::STRING_TYPE: {
196 std::string default_value;
197 args[1].getValue(default_value);
198 std::string v = config_->get_string_or_default(path.c_str(), default_value);
199 m_execInterface.handleCommandReturn(cmd, PLEXIL::Value(v));
200 } break;
201
202 case PLEXIL::REAL_TYPE: {
203 double default_value;
204 args[1].getValue(default_value);
205
206 double v = default_value;
207 // do not use "or_default" here since it can only represent float
208 try {
209 v = config_->get_float(path.c_str());
210 } catch (Exception &e) {
211 } // ignored, use default
212 m_execInterface.handleCommandReturn(cmd, PLEXIL::Value(v));
213 } break;
214
215 case PLEXIL::BOOLEAN_TYPE: {
216 bool default_value;
217 args[1].getValue(default_value);
218 bool v = config_->get_bool_or_default(path.c_str(), default_value);
219 m_execInterface.handleCommandReturn(cmd, PLEXIL::Value(v));
220 } break;
221
222 case PLEXIL::INTEGER_TYPE: {
223 int default_value;
224 args[1].getValue(default_value);
225 if (config_->is_uint(path.c_str())) {
226 unsigned int uv = config_->get_uint(path.c_str());
227 if (uv > std::numeric_limits<int>::max()) {
228 warn("ConfigCommAdapter:config_get_value_or_default:"
229 << " Unsigned integer too large to store in int (" << uv << ")");
230 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
231 m_execInterface.notifyOfExternalEvent();
232 return;
233 }
234 }
235 int v = config_->get_int_or_default(path.c_str(), default_value);
236 m_execInterface.handleCommandReturn(cmd, PLEXIL::Value(v));
237 } break;
238
239 default:
240 // this would only occur when misconfiguring in initialize()
241 warn("ConfigCommAdapter:config_get_value_or_default:"
242 << " Unsupported Plexil type " << PLEXIL::valueTypeName(value_type));
243 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
244 m_execInterface.notifyOfExternalEvent();
245 return;
246 }
247
248 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
249 m_execInterface.notifyOfExternalEvent();
250
251 } catch (Exception &e) {
252 warn("ConfigCommAdapter:config_get_value_or_default:"
253 << " Failed to get value " << path << " as " << PLEXIL::valueTypeName(value_type) << ": "
254 << e.what_no_backtrace());
255 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
256 m_execInterface.notifyOfExternalEvent();
257 return;
258 }
259}
260
261void
262ConfigurationPlexilAdapter::config_get_value(PLEXIL::Command *cmd, PLEXIL::ValueType value_type)
263{
264 std::vector<PLEXIL::Value> const &args = cmd->getArgValues();
265 if (!verify_args(args, "ConfigCommAdapter:config_get_value", {{"path", PLEXIL::STRING_TYPE}})) {
266 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
267 m_execInterface.notifyOfExternalEvent();
268 return;
269 }
270
271 std::string path;
272 args[0].getValue(path);
273
274 try {
275 switch (value_type) {
276 case PLEXIL::STRING_TYPE: {
277 std::string v = config_->get_string(path.c_str());
278 m_execInterface.handleCommandReturn(cmd, PLEXIL::Value(v));
279 } break;
280
281 case PLEXIL::REAL_TYPE: {
282 float v = config_->get_float(path.c_str());
283 m_execInterface.handleCommandReturn(cmd, PLEXIL::Value((double)v));
284 } break;
285
286 case PLEXIL::BOOLEAN_TYPE: {
287 bool v = config_->get_bool(path.c_str());
288 m_execInterface.handleCommandReturn(cmd, PLEXIL::Value(v));
289 } break;
290
291 case PLEXIL::INTEGER_TYPE: {
292 if (config_->is_uint(path.c_str())) {
293 unsigned int uv = config_->get_uint(path.c_str());
294 if (uv > std::numeric_limits<int>::max()) {
295 warn("ConfigCommAdapter:config_get_value:"
296 << " Unsigned integer too large to store in int (" << uv << ")");
297 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
298 m_execInterface.notifyOfExternalEvent();
299 return;
300 }
301 }
302 int v = config_->get_int(path.c_str());
303 m_execInterface.handleCommandReturn(cmd, PLEXIL::Value(v));
304 } break;
305
306 default:
307 // this would only occur when misconfiguring in initialize()
308 warn("ConfigCommAdapter:config_get_value:"
309 << " Unsupported Plexil type " << PLEXIL::valueTypeName(value_type));
310 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
311 m_execInterface.notifyOfExternalEvent();
312 return;
313 }
314
315 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
316 m_execInterface.notifyOfExternalEvent();
317
318 } catch (Exception &e) {
319 warn("ConfigCommAdapter:config_get_value:"
320 << " Failed to get value " << path << " as " << PLEXIL::valueTypeName(value_type) << ": "
321 << e.what_no_backtrace());
322 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
323 m_execInterface.notifyOfExternalEvent();
324 return;
325 }
326}
327
328void
329ConfigurationPlexilAdapter::config_exists(PLEXIL::Command *cmd)
330{
331 std::vector<PLEXIL::Value> const &args = cmd->getArgValues();
332 if (!verify_args(args, "ConfigCommAdapter:config_exists", {{"path", PLEXIL::STRING_TYPE}})) {
333 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
334 m_execInterface.notifyOfExternalEvent();
335 return;
336 }
337
338 std::string path;
339 args[0].getValue(path);
340
341 try {
342 m_execInterface.handleCommandReturn(cmd, PLEXIL::Value(config_->exists(path.c_str())));
343 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
344 m_execInterface.notifyOfExternalEvent();
345 } catch (Exception &e) {
346 warn("ConfigCommAdapter:config_exists:"
347 << " Failed to check " << path << ": " << e.what_no_backtrace());
348 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
349 m_execInterface.notifyOfExternalEvent();
350 return;
351 }
352}
353
354extern "C" {
355void
356initFawkesConfigurationAdapter()
357{
358 REGISTER_ADAPTER(ConfigurationPlexilAdapter, "FawkesConfigurationAdapter");
359}
360}
Interface adapter to provide logging facilities.
virtual bool initialize()
Initialize adapter.
ConfigurationPlexilAdapter(PLEXIL::AdapterExecInterface &execInterface)
Constructor.
virtual bool start()
Start adapter.
virtual bool stop()
Stop adapter.
void invokeAbort(PLEXIL::Command *cmd)
Abort currently running execution.
void executeCommand(PLEXIL::Command *cmd)
Perform given command.
virtual bool reset()
Reset adapter.
virtual ~ConfigurationPlexilAdapter()
Destructor.
virtual bool shutdown()
Shut adapter down.
Interface for configuration handling.
Definition: config.h:68
virtual unsigned int get_uint(const char *path)=0
Get value from configuration which is of type unsigned int.
virtual bool is_uint(const char *path)=0
Check if a value is of type unsigned int.
virtual bool get_bool(const char *path)=0
Get value from configuration which is of type bool.
virtual std::string get_string_or_default(const char *path, const std::string &default_val)
Get value from configuration which is of type string, or the given default if the path does not exist...
Definition: config.cpp:736
virtual float get_float(const char *path)=0
Get value from configuration which is of type float.
virtual int get_int_or_default(const char *path, const int &default_val)
Get value from configuration which is of type int, or the given default if the path does not exist.
Definition: config.cpp:716
virtual bool get_bool_or_default(const char *path, const bool &default_val)
Get value from configuration which is of type bool, or the given default if the path does not exist.
Definition: config.cpp:726
virtual bool exists(const char *path)=0
Check if a given value exists.
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
virtual int get_int(const char *path)=0
Get value from configuration which is of type int.
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual const char * what_no_backtrace() const noexcept
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:663
Interface for logging.
Definition: logger.h:42
Fawkes library namespace.