22 #include "globals_adapter.h"
26 #include <AdapterConfiguration.hh>
27 #include <AdapterExecInterface.hh>
28 #include <AdapterFactory.hh>
30 #include <InterfaceManager.hh>
31 #include <StateCacheEntry.hh>
45 : InterfaceAdapter(execInterface)
55 pugi::xml_node
const xml)
56 : InterfaceAdapter(execInterface, xml)
72 reinterpret_cast<fawkes::Configuration *>(m_execInterface.getProperty(
"::Fawkes::Config"));
73 logger_ = reinterpret_cast<fawkes::Logger *>(m_execInterface.getProperty(
"::Fawkes::Logger"));
75 if (!config_ || !logger_) {
76 warn(
"GlobalState:initialize: requires FawkesRemoteAdapter or must run in plexil plugin");
80 cfg_default_adapter_ =
false;
81 const pugi::xml_node config = getXml();
82 for (
const auto &c : config.children()) {
83 if (strcmp(c.name(),
"DefaultLookupAdapter") == 0) {
84 cfg_default_adapter_ =
true;
85 logger_->log_warn(
"GlobalState",
86 "Default lookup adapter, allowing on-the-fly state registration");
90 std::string cfg_prefix;
92 std::string cfg_spec = config_->
get_string(
"/plexil/spec");
93 cfg_prefix =
"/plexil/" + cfg_spec +
"/";
98 cfg_prefix +=
"global-states/";
100 struct GlobalStateValueConfig
102 GlobalStateValueConfig() : arity(0)
106 PLEXIL::ValueType value_type;
110 std::vector<std::string> args;
113 std::map<std::string, StateValue> values;
115 std::map<std::string, GlobalStateValueConfig> configured_values;
116 std::unique_ptr<Configuration::ValueIterator> cfg_item{config_->
search(cfg_prefix)};
117 while (cfg_item->next()) {
118 std::string path = cfg_item->
path();
120 std::string::size_type start_pos = cfg_prefix.size();
121 std::string::size_type slash_pos = path.find(
"/", start_pos + 1);
122 if (slash_pos != std::string::npos) {
123 std::string
id = path.substr(start_pos, slash_pos - start_pos);
125 start_pos = slash_pos + 1;
126 slash_pos = path.find(
"/", start_pos);
127 std::string what = path.substr(start_pos, slash_pos - start_pos);
129 if (what ==
"name") {
130 configured_values[id].name = cfg_item->get_string();
131 }
else if (what ==
"type") {
132 configured_values[id].value_type = PLEXIL::parseValueType(cfg_item->get_string());
133 }
else if (what ==
"arity") {
134 configured_values[id].arity = cfg_item->get_uint();
135 }
else if (what ==
"values") {
136 start_pos = slash_pos + 1;
137 slash_pos = path.find(
"/", start_pos);
138 std::string value_id = path.substr(start_pos, slash_pos - start_pos);
140 start_pos = slash_pos + 1;
141 slash_pos = path.find(
"/", start_pos);
142 std::string value_what = path.substr(start_pos, slash_pos - start_pos);
144 if (value_what ==
"args") {
145 configured_values[id].values[value_id].args = cfg_item->get_strings();
151 for (
const auto &c : configured_values) {
152 if (c.second.name.empty()) {
153 warn(
"GlobalState:initialize: no name for state at index " << c.first);
156 if (c.second.value_type == PLEXIL::UNKNOWN_TYPE) {
157 warn(
"GlobalState:initialize: missing or invalid type at index " << c.first);
160 for (
const auto &v : c.second.values) {
161 if (v.second.args.size() != c.second.arity) {
162 warn(
"GlobalState:initialize: invalid arity value for state " << c.first <<
" of "
168 if (c.second.values.empty()) {
169 PLEXIL::State s(c.second.name);
170 values_[s] = std::make_pair(c.second.value_type, PLEXIL::Value());
172 for (
const auto &vc : c.second.values) {
173 PLEXIL::State s(c.second.name, vc.second.args.size());
174 for (
size_t i = 0; i < vc.second.args.size(); ++i) {
175 s.setParameter(i, vc.second.args[i]);
179 std::string conf_path = cfg_prefix + c.first +
"/values/" + vc.first +
"/value";
180 if (config_->
exists(conf_path)) {
181 switch (c.second.value_type) {
182 case PLEXIL::STRING_TYPE: v = config_->
get_string(conf_path);
break;
183 case PLEXIL::INTEGER_TYPE: v = config_->
get_int(conf_path);
break;
184 case PLEXIL::REAL_TYPE: v = config_->
get_float(conf_path);
break;
185 case PLEXIL::BOOLEAN_TYPE: v = config_->
get_bool(conf_path);
break;
187 warn(
"GlobalState:initialize: Unsupported value type "
188 << PLEXIL::valueTypeName(c.second.value_type) <<
" for " << s.toString() <<
" at "
193 values_[s] = std::make_pair(c.second.value_type, v);
198 for (
const auto &v : values_) {
199 logger_->log_debug(
"GlobalState",
200 "Registering value %s=%s",
201 v.first.toString().c_str(),
202 v.second.second.valueToString().c_str());
203 PLEXIL::g_configuration->registerLookupInterface(v.first.name(),
this);
206 namespace p = std::placeholders;
209 std::bind(&GlobalStatePlexilAdapter::global_set_value,
this, p::_1, PLEXIL::INTEGER_TYPE)},
211 std::bind(&GlobalStatePlexilAdapter::global_set_value,
this, p::_1, PLEXIL::REAL_TYPE)},
213 std::bind(&GlobalStatePlexilAdapter::global_set_value,
this, p::_1, PLEXIL::BOOLEAN_TYPE)},
214 {
"global_set_string",
215 std::bind(&GlobalStatePlexilAdapter::global_set_value,
this, p::_1, PLEXIL::STRING_TYPE)},
217 std::bind(&GlobalStatePlexilAdapter::global_set_value,
this, p::_1, PLEXIL::UNKNOWN_TYPE)},
218 {
"global_print_all", std::bind(&GlobalStatePlexilAdapter::global_print_all,
this, p::_1)},
221 for (
const auto &c : commands_) {
222 PLEXIL::g_configuration->registerCommandInterface(c.first,
this);
226 if (cfg_default_adapter_) {
227 PLEXIL::g_configuration->defaultRegisterAdapter(
this);
274 std::string
const &name = cmd->getName();
276 auto c = commands_.find(name);
277 if (c != commands_.end()) {
280 warn(
"GlobalState:executeCommand: called for unknown"
283 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
284 m_execInterface.notifyOfExternalEvent();
294 m_execInterface.handleCommandAbortAck(cmd,
false);
295 m_execInterface.notifyOfExternalEvent();
304 PLEXIL::StateCacheEntry &cache_entry)
306 if (values_.find(state) == values_.end()) {
307 cache_entry.setUnknown();
312 cache_entry.update(values_.at(state).second);
321 subscribed_states_.insert(state);
330 subscribed_states_.erase(state);
334 GlobalStatePlexilAdapter::global_set_value(PLEXIL::Command *cmd, PLEXIL::ValueType value_type)
336 std::vector<PLEXIL::Value>
const &args = cmd->getArgValues();
337 if (value_type != PLEXIL::UNKNOWN_TYPE) {
338 if (!verify_args(args,
339 "GlobalState:global_set_value",
340 {{
"name", PLEXIL::STRING_TYPE}, {
"value", value_type}})) {
341 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
342 m_execInterface.notifyOfExternalEvent();
346 if (args.size() < 2) {
347 warn(
"GlobalState:global_set_value: Command requires at least 2 arguments, got "
349 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
350 m_execInterface.notifyOfExternalEvent();
353 for (
size_t i = 0; i < args.size() - 1; ++i) {
354 if (args[i].valueType() != PLEXIL::STRING_TYPE) {
355 warn(
"GlobalState:global_set_value: "
356 <<
" argument " << i <<
" expected to be of type "
357 <<
"String, but is of type " << PLEXIL::valueTypeName(args[i].valueType()));
358 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
359 m_execInterface.notifyOfExternalEvent();
366 args[0].getValue(name);
369 size_t num_args = args.size() - 2;
371 PLEXIL::State s(name, num_args);
372 for (
size_t i = 0; i < args.size() - 2; ++i) {
373 s.setParameter(i, args[i + 1]);
376 if (values_.find(s) == values_.end()) {
377 if (cfg_default_adapter_) {
378 if (args.back().valueType() != PLEXIL::UNKNOWN_TYPE) {
380 "Adding state %s (value type %s)",
381 s.toString().c_str(),
382 PLEXIL::valueTypeName(args.back().valueType()).c_str());
383 values_[s] = std::make_pair(args.back().valueType(), args.back());
386 warn(
"GlobalState:global_set_value: called for unknown state " << s.toString()
387 <<
" and not default adapter");
388 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
389 m_execInterface.notifyOfExternalEvent();
394 if (args.back().valueType() != values_[s].first) {
395 warn(
"GlobalState:global_set_value: state "
396 << s.toString() <<
" is of type " << PLEXIL::valueTypeName(values_[s].first)
398 <<
"with " << PLEXIL::valueTypeName(args.back().valueType()));
399 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
400 m_execInterface.notifyOfExternalEvent();
406 s.toString().c_str(),
407 args.back().valueToString().c_str());
408 values_[s].second = args.back();
410 if (subscribed_states_.find(s) != subscribed_states_.end()) {
411 m_execInterface.handleValueChange(s, args.back());
414 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
415 m_execInterface.notifyOfExternalEvent();
419 GlobalStatePlexilAdapter::global_print_all(PLEXIL::Command *cmd)
421 logger_->
log_info(
"GlobalState",
"Current globals");
422 for (
const auto &v : values_) {
425 v.first.toString().c_str(),
426 PLEXIL::valueTypeName(v.second.first).c_str(),
427 v.second.second.valueToString().c_str());
429 m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_SUCCESS);
430 m_execInterface.notifyOfExternalEvent();