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
44using namespace fawkes;
45namespace 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 */
55FawkesRemotePlexilAdapter::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 */
65FawkesRemotePlexilAdapter::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 */
79bool
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
147void
148FawkesRemotePlexilAdapter::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 */
190bool
192{
193 return true;
194}
195
196/** Stop adapter.
197 * @return true if successful, false otherwise.
198 */
199bool
201{
202 return true;
203}
204
205/** Reset adapter.
206 * @return true if successful, false otherwise.
207 */
208bool
210{
211 return true;
212}
213
214/** Shut adapter down.
215 * @return true if successful, false otherwise.
216 */
217bool
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 */
233void
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 */
254void
256{
257}
258
259extern "C" {
260void
261initFawkesRemoteAdapter()
262{
263 REGISTER_ADAPTER(FawkesRemotePlexilAdapter, "FawkesRemoteAdapter");
264}
265}
Interface adapter to provide logging facilities.
virtual bool reset()
Reset adapter.
virtual bool shutdown()
Shut adapter down.
void executeCommand(PLEXIL::Command *cmd)
Perform given command.
virtual void fam_event(const char *filename, unsigned int mask)
Event has been raised.
virtual bool initialize()
Initialize adapter.
void invokeAbort(PLEXIL::Command *cmd)
Abort currently running execution.
virtual ~FawkesRemotePlexilAdapter()
Destructor.
virtual bool stop()
Stop adapter.
virtual bool start()
Start adapter.
FawkesRemotePlexilAdapter(PLEXIL::AdapterExecInterface &execInterface)
Constructor.
static void finalize()
Finalize.
Definition: clock.cpp:74
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual const char * what() const noexcept
Get primary string.
Definition: exception.cpp:639
virtual const char * what_no_backtrace() const noexcept
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:663
static const unsigned int FAM_MODIFY
File was modified.
Definition: fam.h:41
static const unsigned int FAM_DELETE
Subfile was deleted.
Definition: fam.h:51
static const unsigned int FAM_IGNORED
File was ignored.
Definition: fam.h:57
void lock() const
Lock access to the encapsulated object.
Definition: lockptr.h:257
void unlock() const
Unlock object mutex.
Definition: lockptr.h:273
void clear()
Remove all nodes and edges from navgraph.
Definition: navgraph.cpp:747
void set_notifications_enabled(bool enabled)
Enable or disable notifications.
Definition: navgraph.cpp:1498
void notify_of_change() noexcept
Notify all listeners of a change.
Definition: navgraph.cpp:1505
Fawkes library namespace.
NavGraph * load_yaml_navgraph(std::string filename, bool allow_multi_graph)
Load topological map graph stored in RCSoft format.