Fawkes API  Fawkes Development Version
remote_adapter.cpp
1 
2 /***************************************************************************
3  * remote_adapter.cpp - Access Fawkes remotely from PLEXIL
4  *
5  * Created: Mon Aug 20 14:41:13 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 "remote_adapter.h"
23 
24 #include "utils.h"
25 
26 #include <blackboard/remote.h>
27 #include <config/netconf.h>
28 #include <core/threading/mutex_locker.h>
29 #include <logging/console.h>
30 #include <navgraph/navgraph.h>
31 #include <navgraph/yaml_navgraph.h>
32 #include <netcomm/fawkes/client.h>
33 #include <utils/system/fam.h>
34 #include <utils/time/clock.h>
35 
36 #include <AdapterConfiguration.hh>
37 #include <AdapterExecInterface.hh>
38 #include <AdapterFactory.hh>
39 #include <Command.hh>
40 #include <Error.hh>
41 #include <InterfaceManager.hh>
42 #include <boost/filesystem.hpp>
43 
44 using namespace fawkes;
45 namespace fs = boost::filesystem;
46 
47 /** @class FawkesRemotePlexilAdapter "remote_adapter.h"
48  * Plexil adapter to provide access to the FawkesRemote.
49  * @author Tim Niemueller
50  */
51 
52 /** Constructor.
53  * @param execInterface Reference to the parent AdapterExecInterface object.
54  */
55 FawkesRemotePlexilAdapter::FawkesRemotePlexilAdapter(PLEXIL::AdapterExecInterface &execInterface)
56 : InterfaceAdapter(execInterface)
57 {
58 }
59 
60 /** Constructor from configuration XML.
61  * @param execInterface Reference to the parent AdapterExecInterface object.
62  * @param xml A const reference to the XML element describing this adapter
63  * @note The instance maintains a shared pointer to the XML.
64  */
65 FawkesRemotePlexilAdapter::FawkesRemotePlexilAdapter(PLEXIL::AdapterExecInterface &execInterface,
66  pugi::xml_node const xml)
67 : InterfaceAdapter(execInterface, xml)
68 {
69 }
70 
71 /** Destructor. */
73 {
74 }
75 
76 /** Initialize adapter.
77  * @return true if initialization was successful, false otherwise.
78  */
79 bool
81 {
82  std::string cfg_host;
83  int cfg_port;
84  bool cfg_navgraph_allow_multi;
85 
86  clock_ = Clock::instance();
87  logger_ = std::make_unique<fawkes::ConsoleLogger>();
88 
89  cfg_host = get_xml_config_value(getXml(), "host");
90  cfg_port = std::stoi(get_xml_config_value(getXml(), "port"));
91 
92  cfg_navgraph_filename_ = get_xml_config_value(getXml(), "navgraph_filename");
93  cfg_navgraph_allow_multi = get_xml_config_value(getXml(), "navgraph_allow_multi") == "true";
94 
95  client_ = std::make_unique<fawkes::FawkesNetworkClient>(cfg_host.c_str(), cfg_port);
96 
97  try {
98  logger_->log_info("FawkesRemote", "Connecting to Fawkes at %s:%i", cfg_host.c_str(), cfg_port);
99  client_->connect();
100  } catch (Exception &e) {
101  warn("FawkesRemoteAdapter:initialize: failed to connect to Fawkes: " << e.what_no_backtrace());
102  return false;
103  }
104 
105  logger_->log_info("FawkesRemote", "Mirroring configuration");
106  config_ = std::make_unique<fawkes::NetworkConfiguration>(client_.get());
107  config_->set_mirror_mode(true);
108 
109  logger_->log_info("FawkesRemote", "Accessing blackboard");
110  blackboard_ = std::make_unique<fawkes::RemoteBlackBoard>(client_.get());
111 
112  if (cfg_navgraph_filename_[0] != '/') {
113  cfg_navgraph_filename_ = std::string(CONFDIR) + "/" + cfg_navgraph_filename_;
114  }
115  fs::path p(cfg_navgraph_filename_);
116  p = fs::absolute(p);
117  cfg_navgraph_filename_ = p.string();
118  logger_->log_info("FawkesRemote", "Loading navgraph file %s", cfg_navgraph_filename_.c_str());
119  navgraph_ = load_yaml_navgraph(cfg_navgraph_filename_, cfg_navgraph_allow_multi);
120 
121  fs::create_directories(p.parent_path());
122  navgraph_fam_ = std::make_unique<fawkes::FileAlterationMonitor>();
123  navgraph_fam_->add_filter((std::string("^") + p.filename().string() + "$").c_str());
124  navgraph_fam_->watch_dir(p.parent_path().string().c_str());
125  navgraph_fam_->add_listener(this);
126 
127  navgraph_fam_thread_ = std::thread([this]() {
128  while (true) {
129  std::unique_lock<std::mutex> lock(this->navgraph_fam_mutex_);
130  if (!this->navgraph_fam_)
131  break;
132  lock.unlock();
133  using namespace std::chrono_literals;
134  std::this_thread::sleep_for(1s);
135  }
136  });
137 
138  m_execInterface.setProperty("::Fawkes::Config", config_.get());
139  m_execInterface.setProperty("::Fawkes::Clock", clock_);
140  m_execInterface.setProperty("::Fawkes::Logger", logger_.get());
141  m_execInterface.setProperty("::Fawkes::BlackBoard", blackboard_.get());
142  m_execInterface.setProperty("::Fawkes::NavGraph", &navgraph_);
143 
144  return true;
145 }
146 
147 void
148 FawkesRemotePlexilAdapter::fam_event(const char *filename, unsigned int mask)
149 {
150  // The file will be ignored from now onwards, re-register
151  // if (mask & FAM_IGNORED) {
152  // boost::filesystem::path p(cfg_navgraph_file_);
153  // fam_->watch_dir(p.parent_path().string().c_str());
154  // }
155 
156  if (mask & FAM_DELETE) {
157  warn("FawkesRemoteAdapter:fam_event: navgraph file deleted, clearing");
158  navgraph_->clear();
159  return;
160  }
161 
162  if (mask & (FAM_MODIFY | FAM_IGNORED)) {
163  warn("FawkesRemoteAdapter:fam_event: NavGraph changed on disk, reloading");
164 
165  try {
168  /* recursive mutex */ true);
169 
170  // disable notifications to not trigger them while navgraph is locked
171  navgraph_->set_notifications_enabled(false);
172  navgraph_.lock();
173  **navgraph_ = **new_graph;
174  navgraph_.unlock();
175  navgraph_->set_notifications_enabled(true);
176  navgraph_->notify_of_change();
177  } catch (fawkes::Exception &e) {
178  warn("FawkesRemoteAdapter:fam_event: loading new graph failed: " << e.what_no_backtrace());
179  return;
180  } catch (std::runtime_error &e) {
181  warn("FawkesRemoteAdapter:fam_event: loading new graph failed: " << e.what());
182  return;
183  }
184  }
185 }
186 
187 /** Start adapter.
188  * @return true if starting was successful, false otherwise.
189  */
190 bool
192 {
193  return true;
194 }
195 
196 /** Stop adapter.
197  * @return true if successful, false otherwise.
198  */
199 bool
201 {
202  return true;
203 }
204 
205 /** Reset adapter.
206  * @return true if successful, false otherwise.
207  */
208 bool
210 {
211  return true;
212 }
213 
214 /** Shut adapter down.
215  * @return true if successful, false otherwise.
216  */
217 bool
219 {
220  clock_->finalize();
221  client_->disconnect();
222 
223  std::unique_lock<std::mutex> lock(navgraph_fam_mutex_);
224  navgraph_fam_.reset();
225  navgraph_fam_thread_.join();
226 
227  return true;
228 }
229 
230 /** Perform given command.
231  * @param cmd command to execute
232  */
233 void
235 {
236  /*
237  std::string const &name = cmd->getName();
238 
239  auto c = commands_.find(name);
240  if (c != commands_.end()) {
241  c->second(cmd);
242  } else {
243  warn("FawkesRemoteAdapter:executeCommand: called for unknown"
244  " command " << name);
245  m_execInterface.handleCommandAck(cmd, PLEXIL::COMMAND_FAILED);
246  m_execInterface.notifyOfExternalEvent();
247  }
248  */
249 }
250 
251 /** Abort currently running execution.
252  * @param cmd command to abort
253  */
254 void
256 {
257 }
258 
259 extern "C" {
260 void
261 initFawkesRemoteAdapter()
262 {
263  REGISTER_ADAPTER(FawkesRemotePlexilAdapter, "FawkesRemoteAdapter");
264 }
265 }
void executeCommand(PLEXIL::Command *cmd)
Perform given command.
Fawkes library namespace.
virtual ~FawkesRemotePlexilAdapter()
Destructor.
void unlock() const
Unlock object mutex.
Definition: lockptr.h:273
virtual bool shutdown()
Shut adapter down.
Interface adapter to provide logging facilities.
virtual bool initialize()
Initialize adapter.
void invokeAbort(PLEXIL::Command *cmd)
Abort currently running execution.
virtual bool start()
Start adapter.
virtual bool reset()
Reset adapter.
void set_notifications_enabled(bool enabled)
Enable or disable notifications.
Definition: navgraph.cpp:1498
static const unsigned int FAM_IGNORED
File was ignored.
Definition: fam.h:57
Base class for exceptions in Fawkes.
Definition: exception.h:35
NavGraph * load_yaml_navgraph(std::string filename, bool allow_multi_graph)
Load topological map graph stored in RCSoft format.
void clear()
Remove all nodes and edges from navgraph.
Definition: navgraph.cpp:747
void notify_of_change()
Notify all listeners of a change.
Definition: navgraph.cpp:1505
virtual const char * what_no_backtrace() const
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:663
static void finalize()
Finalize.
Definition: clock.cpp:74
virtual bool stop()
Stop adapter.
static const unsigned int FAM_DELETE
Subfile was deleted.
Definition: fam.h:51
static const unsigned int FAM_MODIFY
File was modified.
Definition: fam.h:41
virtual void fam_event(const char *filename, unsigned int mask)
Event has been raised.
FawkesRemotePlexilAdapter(PLEXIL::AdapterExecInterface &execInterface)
Constructor.
void lock() const
Lock access to the encapsulated object.
Definition: lockptr.h:257