Fawkes API  Fawkes Development Version
engine_thread.cpp
1 
2 /***************************************************************************
3  * engine_thread.cpp - Thread driving the XABSL Engine
4  *
5  * Created: Thu Aug 07 17:01:29 2008
6  * Copyright 2006-2008 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include "engine_thread.h"
24 
25 #include "skill_wrapper.h"
26 #include "xabsl_tools.h"
27 
28 #include <XabslEngine/XabslEngine.h>
29 #include <core/exceptions/software.h>
30 #include <interfaces/ObjectPositionInterface.h>
31 #include <interfaces/SkillerInterface.h>
32 #include <utils/time/time.h>
33 
34 using namespace fawkes;
35 
36 /** Global XabslEngineThread required for xet_current_time(). */
37 static XabslEngineThread *g_xe = NULL;
38 
39 /** Get current time.
40  * Uses a globally set XabslEngineThread instance to determine the current
41  * time, may be simulated time!
42  * @return continuous time in miliseconds
43  */
44 static unsigned long int
45 xet_current_time()
46 {
47  if (!g_xe) {
48  throw NullPointerException("No XabslEngineThread instance exists");
49  }
50 
51  return g_xe->current_time();
52 }
53 
54 /** @class XabslEngineThread "engine_thread.h"
55  * Xabsl Engine Thread.
56  * This thread drives the Xabsl engine.
57  * @author Tim Niemueller
58  */
59 
60 /** Constructor. */
62 : Thread("XabslEngineThread", Thread::OPMODE_WAITFORWAKEUP),
63  BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_THINK)
64 {
65 }
66 
67 void
69 {
70  if (g_xe) {
71  throw Exception("Global XabslEngineThread has already been set.");
72  }
73  g_xe = this;
74 
75  xe_ = NULL;
76  xleh_ = NULL;
77  now_ = NULL;
78  ball_rx_ = NULL;
79  ball_ry_ = NULL;
80  skiller_if_ = NULL;
81  wm_ball_if_ = NULL;
82 
83  now_ = new Time(clock);
84  xleh_ = new XabslLoggingErrorHandler(logger);
85  xe_ = new xabsl::Engine(*xleh_, &xet_current_time);
86 
87  wm_ball_if_ = blackboard->open_for_reading<ObjectPositionInterface>("WM Ball");
88  skiller_if_ = blackboard->open_for_reading<SkillerInterface>("Skiller");
89 
91  params.push_back(std::make_pair("x", "double"));
92  params.push_back(std::make_pair("y", "double"));
93  params.push_back(std::make_pair("ori", "double"));
94  XabslSkillWrapper *sw = new XabslSkillWrapper("relgoto", *xleh_, params);
95  wrappers_[sw->name()] = sw;
96  xe_->registerBasicBehavior(*sw);
97 
98  ball_ry_ = ball_rx_ = NULL;
99  for (InterfaceFieldIterator i = wm_ball_if_->fields(); i != wm_ball_if_->fields_end(); ++i) {
100  if (strcmp(i.get_name(), "relative_x") == 0) {
101  ball_rx_ = new XabslInterfaceFieldWrapper<double, float>(i.get_type(),
102  i.get_name(),
103  (float *)i.get_value());
104  xe_->registerDecimalInputSymbol("ball.relative_x",
105  ball_rx_,
106  (double (xabsl::FunctionProvider::*)())
108  } else if (strcmp(i.get_name(), "relative_y") == 0) {
109  ball_ry_ = new XabslInterfaceFieldWrapper<double, float>(i.get_type(),
110  i.get_name(),
111  (float *)i.get_value());
112  xe_->registerDecimalInputSymbol("ball.relative_y",
113  ball_ry_,
114  (double (xabsl::FunctionProvider::*)())
116  }
117  }
118 
119  XabslFileInputSource xinput(XABSLDIR "agent.xabslc");
120  xe_->createOptionGraph(xinput);
121 
122  if (xleh_->errorsOccurred) {
123  finalize();
124  throw Exception("Error while creating XABSL engine, see log for details");
125  }
126 
127  /* Test code, exporting interfaces to allow for real skill-level programming
128  * is an overly complex and error prone task.
129  * Since C++ methods for basic behaviors for sending a message cannot be
130  * created on-the-fly wrappers would need to be written or generated for each
131  * possible message type.
132 
133  navi_if_ = blackboard->open_for_reading<NavigatorInterface>("Navigator");
134 
135  std::string base_name = "navi_";
136  InterfaceFieldIterator i;
137  for (i = navi_if_->fields(); i != navi_if_->fields_end(); ++i) {
138  switch (i.get_type()) {
139  case Interface::IFT_BOOL:
140  {
141  XabslInterfaceFieldWrapper<bool> *ifw = new XabslInterfaceFieldWrapper<bool>(new InterfaceFieldPointer<bool>(i.get_type(), i.get_name(), (bool *)i.get_value()));
142  xe_->registerBooleanInputSymbol((base_name + ifw->get_name()).c_str(),
143  ifw,
144  (bool (xabsl::FunctionProvider::*)())&XabslInterfaceFieldWrapper<bool>::get_value);
145  xe_->registerBooleanOutputSymbol((base_name + ifw->get_name()).c_str(),
146  ifw,
147  (void (xabsl::FunctionProvider::*)(bool))&XabslInterfaceFieldWrapper<bool>::set_value,
148  (bool (xabsl::FunctionProvider::*)())&XabslInterfaceFieldWrapper<bool>::get_value);
149  }
150  break;
151  case Interface::IFT_INT:
152  case Interface::IFT_UINT:
153  case Interface::IFT_LONGINT:
154  case Interface::IFT_LONGUINT:
155  case Interface::IFT_FLOAT:
156  {
157  XabslInterfaceFieldWrapper<double> *ifw = new XabslInterfaceFieldWrapper<double>(new InterfaceFieldPointer<double>(i.get_type(), i.get_name(), (double *)i.get_value()));
158  xe_->registerDecimalInputSymbol((base_name + ifw->get_name()).c_str(),
159  ifw,
160  (double (xabsl::FunctionProvider::*)())&XabslInterfaceFieldWrapper<double>::get_value);
161  xe_->registerDecimalOutputSymbol((base_name + ifw->get_name()).c_str(),
162  ifw,
163  (void (xabsl::FunctionProvider::*)(double))&XabslInterfaceFieldWrapper<double>::set_value,
164  (double (xabsl::FunctionProvider::*)())&XabslInterfaceFieldWrapper<double>::get_value);
165  }
166  break;
167  case Interface::IFT_STRING:
168  // ignored, XABSL can't handle that
169  break;
170  }
171  }
172  */
173 }
174 
175 void
177 {
178  g_xe = NULL;
179 
180  for (wit_ = wrappers_.begin(); wit_ != wrappers_.end(); ++wit_) {
181  delete wit_->second;
182  }
183  wrappers_.clear();
184 
185  delete xe_;
186  delete xleh_;
187  delete now_;
188  delete ball_rx_;
189  delete ball_ry_;
190 
191  if (skiller_if_)
192  blackboard->close(skiller_if_);
193  if (wm_ball_if_)
194  blackboard->close(wm_ball_if_);
195 }
196 
197 void
199 {
200  try {
202  } catch (Exception &e) {
203  logger->log_error("XabslEngineThread",
204  "Cannot aquire exclusive skiller "
205  "control, exception follows");
206  logger->log_error("XabslEngineThread", e);
207  }
208 }
209 
210 void
212 {
213  now_->stamp();
214 
215  wm_ball_if_->read();
216  skiller_if_->read();
217 
218  xe_->execute();
219 
220  std::string skill_string = "";
221  for (wit_ = wrappers_.begin(); wit_ != wrappers_.end(); ++wit_) {
222  std::string css = wit_->second->skill_string();
223  if (css != "") {
224  skill_string += css + "; ";
225  }
226  }
227  if (skill_string != "") {
228  logger->log_debug(name(), "Skill string: %s", skill_string.c_str());
229  }
230 
231  try {
232  skiller_if_->msgq_enqueue(new SkillerInterface::ExecSkillMessage(skill_string.c_str()));
233  } catch (Exception &e) {
234  logger->log_warn("XabslEngineThread", "Executing skill failed, exception follows");
235  logger->log_warn("XabslEngineThread", e);
236  }
237 }
238 
239 /** Get current time.
240  * @return continuous time in miliseconds
241  */
242 unsigned long int
244 {
245  return now_->in_msec();
246 }
fawkes::Time::in_msec
long in_msec() const
Convert the stored time into milli-seconds.
Definition: time.cpp:228
fawkes::Interface::fields_end
InterfaceFieldIterator fields_end()
Invalid iterator.
Definition: interface.cpp:1207
XabslEngineThread::current_time
unsigned long int current_time()
Get current time.
Definition: engine_thread.cpp:243
fawkes::Interface::read
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:472
fawkes::BlockedTimingAspect
Thread aspect to use blocked timing.
Definition: blocked_timing.h:51
fawkes::Thread::name
const char * name() const
Get name of thread.
Definition: thread.h:100
fawkes::ClockAspect::clock
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:42
XabslEngineThread::finalize
virtual void finalize()
Finalize the thread.
Definition: engine_thread.cpp:176
XabslFileInputSource
File input class for Xabsl integration.
Definition: xabsl_tools.h:47
fawkes::InterfaceFieldIterator
Interface field iterator.
Definition: field_iterator.h:39
XabslSkillWrapper::name
const char * name()
Get name of the skill.
Definition: skill_wrapper.cpp:64
fawkes::SkillerInterface::AcquireControlMessage
AcquireControlMessage Fawkes BlackBoard Interface Message.
Definition: SkillerInterface.h:155
XabslSkillWrapper::ParameterList
std::list< std::pair< std::string, std::string > > ParameterList
Parameter list.
Definition: skill_wrapper.h:40
fawkes::SkillerInterface::ExecSkillMessage
ExecSkillMessage Fawkes BlackBoard Interface Message.
Definition: SkillerInterface.h:84
XabslInterfaceFieldWrapper< double, float >
fawkes::LoggingAspect::logger
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
fawkes::BlackBoard::close
virtual void close(Interface *interface)=0
Close interface.
fawkes::Logger::log_error
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
fawkes
Fawkes library namespace.
XabslLoggingErrorHandler
Logging error handler for XABSL integration.
Definition: xabsl_tools.h:35
fawkes::Logger::log_warn
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
XabslEngineThread::once
virtual void once()
Execute an action exactly once.
Definition: engine_thread.cpp:198
fawkes::SkillerInterface
SkillerInterface Fawkes BlackBoard Interface.
Definition: SkillerInterface.h:34
fawkes::Interface::fields
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
Definition: interface.cpp:1198
fawkes::Time
A class for handling time.
Definition: time.h:93
XabslEngineThread
Xabsl Engine Thread.
Definition: engine_thread.h:58
fawkes::Thread
Thread class encapsulation of pthreads.
Definition: thread.h:46
fawkes::BlackBoardAspect::blackboard
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:44
XabslEngineThread::XabslEngineThread
XabslEngineThread()
Constructor.
Definition: engine_thread.cpp:61
fawkes::BlackBoard::open_for_reading
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
fawkes::Time::stamp
Time & stamp()
Set this time to the current time.
Definition: time.cpp:704
XabslEngineThread::init
virtual void init()
Initialize the thread.
Definition: engine_thread.cpp:68
fawkes::NullPointerException
A NULL pointer was supplied where not allowed.
Definition: software.h:32
fawkes::Interface::msgq_enqueue
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:882
XabslEngineThread::loop
virtual void loop()
Code to execute in the thread.
Definition: engine_thread.cpp:211
XabslSkillWrapper
Xabsl Skill Wrapper.
Definition: skill_wrapper.h:34
fawkes::Logger::log_debug
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
fawkes::ObjectPositionInterface
ObjectPositionInterface Fawkes BlackBoard Interface.
Definition: ObjectPositionInterface.h:34
fawkes::Exception
Base class for exceptions in Fawkes.
Definition: exception.h:36