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 }
Xabsl Engine Thread.
Definition: engine_thread.h:58
virtual void once()
Execute an action exactly once.
virtual void init()
Initialize the thread.
virtual void loop()
Code to execute in the thread.
virtual void finalize()
Finalize the thread.
XabslEngineThread()
Constructor.
unsigned long int current_time()
Get current time.
File input class for Xabsl integration.
Definition: xabsl_tools.h:47
Logging error handler for XABSL integration.
Definition: xabsl_tools.h:35
Xabsl Skill Wrapper.
Definition: skill_wrapper.h:34
std::list< std::pair< std::string, std::string > > ParameterList
Parameter list.
Definition: skill_wrapper.h:40
const char * name()
Get name of the skill.
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:44
virtual Interface * open_for_reading(const char *interface_type, const char *identifier, const char *owner=NULL)=0
Open interface for reading.
virtual void close(Interface *interface)=0
Close interface.
Thread aspect to use blocked timing.
Clock * clock
By means of this member access to the clock is given.
Definition: clock.h:42
Base class for exceptions in Fawkes.
Definition: exception.h:36
Interface field iterator.
InterfaceFieldIterator fields_end()
Invalid iterator.
Definition: interface.cpp:1207
InterfaceFieldIterator fields()
Get iterator over all fields of this interface instance.
Definition: interface.cpp:1198
void read()
Read from BlackBoard into local copy.
Definition: interface.cpp:472
unsigned int msgq_enqueue(Message *message)
Enqueue message at end of queue.
Definition: interface.cpp:882
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
virtual void log_error(const char *component, const char *format,...)=0
Log error message.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
A NULL pointer was supplied where not allowed.
Definition: software.h:32
ObjectPositionInterface Fawkes BlackBoard Interface.
AcquireControlMessage Fawkes BlackBoard Interface Message.
ExecSkillMessage Fawkes BlackBoard Interface Message.
SkillerInterface Fawkes BlackBoard Interface.
Thread class encapsulation of pthreads.
Definition: thread.h:46
const char * name() const
Get name of thread.
Definition: thread.h:100
A class for handling time.
Definition: time.h:93
Time & stamp()
Set this time to the current time.
Definition: time.cpp:704
long in_msec() const
Convert the stored time into milli-seconds.
Definition: time.cpp:228
Fawkes library namespace.