Fawkes API  Fawkes Development Version
msl2010.cpp
1 
2 /***************************************************************************
3  * msl2010.cpp - Fawkes mid-size refbox 2010 protocol repeater
4  *
5  * Created: Wed Apr 09 10:38:16 2008
6  * Copyright 2008 Stefan Schiffer [stefanschiffer.de]
7  * 2010 Tim Niemueller [www.niemueller.de]
8  *
9  ****************************************************************************/
10 
11 /* This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Library General Public License for more details.
20  *
21  * Read the full text in the LICENSE.GPL file in the doc directory.
22  */
23 
24 #include "msl2010.h"
25 
26 #include <libxml++/libxml++.h>
27 #include <logging/logger.h>
28 #include <netcomm/socket/datagram_multicast.h>
29 
30 #include <cstdlib>
31 #include <cstring>
32 #include <sstream>
33 #include <string>
34 // libxml++ pulls in Glib::ustring, which has a looong tail of dependent
35 // includes, one being <sys/signal.h>, which on FreeBSD defines POLL_IN
36 // for the SIGPOLL. Since we do not use the signal in any way we simply
37 // undefine the constants, such that the Socket::POLL_IN constant does
38 // not get messed up.
39 #ifdef __FreeBSD__
40 # undef POLL_IN
41 # undef POLL_ERR
42 #endif
43 
44 using namespace fawkes;
45 using namespace xmlpp;
46 
47 // REFBOX_CODES //////////////////////////
48 
49 static const std::string REFBOX_EVENT = "RefboxEvent";
50 static const std::string REFBOX_GAMEINFO = "GameInfo";
51 static const std::string REFBOX_EVENT_REFEREE = "Referee";
52 static const std::string REFBOX_EVENT_TEAMSETUP = "TeamSetup";
53 
54 static const std::string REFBOX_CANCEL = "Cancel";
55 
56 static const std::string REFBOX_GAMESTART = "GameStart";
57 static const std::string REFBOX_GAMESTOP = "GameStop";
58 
59 static const std::string REFBOX_STAGE_CHANGED = "StageChanged";
60 static const std::string REFBOX_STAGETYPE_PREGAME = "preGame";
61 static const std::string REFBOX_STAGETYPE_FIRSTHALF = "firstHalf";
62 static const std::string REFBOX_STAGETYPE_HALFTIME = "halfTime";
63 static const std::string REFBOX_STAGETYPE_SECONDHALF = "secondHalf";
64 static const std::string REFBOX_STAGETYPE_SHOOTOUT = "shootOut";
65 static const std::string REFBOX_STAGETYPE_ENDGAME = "endGame";
66 
67 static const std::string REFBOX_GOAL_AWARDED = "GoalAwarded";
68 static const std::string REFBOX_GOAL_REMOVED = "GoalRemoved";
69 
70 static const std::string REFBOX_CARD_AWARDED = "CardAwarded";
71 static const std::string REFBOX_CARD_REMOVED = "CardRemoved";
72 
73 static const std::string REFBOX_SUBSTITUTION = "Substitution";
74 static const std::string REFBOX_PLAYER_OUT = "PlayerOut";
75 static const std::string REFBOX_PLAYER_IN = "PlayerIn";
76 
77 static const std::string REFBOX_DROPPEDBALL = "DroppedBall";
78 static const std::string REFBOX_KICKOFF = "KickOff";
79 static const std::string REFBOX_FREEKICK = "FreeKick";
80 static const std::string REFBOX_GOALKICK = "GoalKick";
81 static const std::string REFBOX_THROWIN = "ThrowIn";
82 static const std::string REFBOX_CORNER = "Corner";
83 static const std::string REFBOX_PENALTY = "Penalty";
84 
85 static const std::string REFBOX_TEAMCOLOR_CYAN = "Cyan";
86 static const std::string REFBOX_TEAMCOLOR_MAGENTA = "Magenta";
87 
88 static const std::string REFBOX_GOALCOLOR_YELLOW = "yellow";
89 static const std::string REFBOX_GOALCOLOR_BLUE = "blue";
90 
91 static const std::string REFBOX_CARDCOLOR_YELLOW = "yellow";
92 static const std::string REFBOX_CARDCOLOR_RED = "red";
93 
94 /** @class Msl2010RefBoxProcessor "processor/msl2010.h"
95  * Mid-size league refbox repeater.
96  * This class will communicate with the mid-size league refbox and derive matching
97  * game states from the communiation stream and send this via the world info.
98  * @author Stefan Schiffer
99  */
100 
101 /** Constructor.
102  * @param logger logger for output
103  * @param refbox_host refbox host
104  * @param refbox_port refbox port
105  */
107  const char * refbox_host,
108  unsigned short int refbox_port)
109 : name_("Msl2010RefBoxProc")
110 {
111  logger_ = logger;
112  quit_ = false;
113  s_ = NULL;
114  score_cyan_ = score_magenta_ = 0;
115  connection_died_ = false;
116 
117  refbox_host_ = strdup(refbox_host);
118  refbox_port_ = refbox_port;
119 
120  do {
121  reconnect();
122  } while (!s_);
123 }
124 
125 /** Destructor. */
127 {
128  free(refbox_host_);
129  s_->close();
130  delete s_;
131 }
132 
133 /** Reconnect to refbox. */
134 void
135 Msl2010RefBoxProcessor::reconnect()
136 {
137  if (s_) {
138  s_->close();
139  delete s_;
140  }
141  logger_->log_info(name_, "Trying to connect to refbox at %s:%u", refbox_host_, refbox_port_);
142  try {
143  logger_->log_info(name_, "Creating MulticastDatagramSocket");
144  s_ = new MulticastDatagramSocket(Socket::IPv4, refbox_host_, refbox_port_, 2.3);
145  //printf("set loop\n");
146  s_->set_loop(true); // (re)receive locally sent stuff
147  //printf("bind\n");
148  s_->bind();
149  //printf("bind done\n");
150 
151  // printf("check for data availability ...\n");
152  // if ( !s_->available() ) {
153  // printf("... nothing to receive\n");
154  // } else {
155  // printf("... data is available!\n");
156  // }
157 
158  connection_died_ = false;
159 
160  } catch (Exception &e) {
161  delete s_;
162  s_ = NULL;
163  //printf(".");
164  //fflush(stdout);
165  //usleep(500000);
166  }
167 
168  logger_->log_info(name_, "Init done");
169 }
170 
171 /** Process received string. */
172 void
173 Msl2010RefBoxProcessor::process_string(char *buf, size_t len)
174 {
175  logger_->log_info(name_, "Received\n *****\n %s \n *****", buf);
176 
177  std::istringstream iss(std::string(buf), std::istringstream::in);
178 
179  dom = new DomParser();
180  //dom->set_validate();
181  dom->set_substitute_entities();
182  dom->parse_stream(iss);
183  root = dom->get_document()->get_root_node();
184 
185  //printf( " root node:\n%s\n", root->get_name().data() );
186 
187  const Element *el = dynamic_cast<const Element *>(root);
188 
189  if (el) {
190  /// valid element
191  //printf("Is valid Element\n");
192  logger_->log_info(name_, "root-element name is '%s'", el->get_name().data());
193 
194  const Node::NodeList nl = el->get_children();
195 
196  if (nl.size() == 0) {
197  logger_->log_info(name_, "root has NO children!");
198  } else {
199  //printf("root has %u children!\n", nl.size());
200 
201  for (Node::NodeList::const_iterator it = nl.begin(); it != nl.end(); ++it) {
202  const Node *node = *it;
203  logger_->log_info(name_, "1st level child name is '%s'", node->get_name().data());
204 
205  //if( node->get_name().data() == REFBOX_GAMEINFO ) {
206  //
207  //}
208  //else if( node->get_name().data() == REFBOX_EVENT ) {
209  //
210  //}
211  //else {
212  // printf(" unhandled RefboxMessage-type '%s'!\n", node->get_name().data() );
213  //}
214 
215  const Node::NodeList cnl = node->get_children();
216 
217  if (cnl.size() == 0) {
218  logger_->log_info(name_, "child has NO children!");
219  } else {
220  //printf("child has %u children!\n", nl.size());
221 
222  for (Node::NodeList::const_iterator cit = cnl.begin(); cit != cnl.end(); ++cit) {
223  const Node * cnode = *cit;
224  const Element *cel = dynamic_cast<const Element *>(cnode);
225  std::string cnodename(cnode->get_name().data());
226 
227  logger_->log_info(name_, "2nd level child name is '%s'", cnode->get_name().data());
228 
229  const Attribute *cattr;
230  std::string cteamcolor;
231  //std::string cgoalcolor;
232  //std::string ccardcolor;
233  std::string cstagetype;
234 
235  if (cnodename == REFBOX_KICKOFF || cnodename == REFBOX_FREEKICK
236  || cnodename == REFBOX_GOALKICK || cnodename == REFBOX_THROWIN
237  || cnodename == REFBOX_CORNER || cnodename == REFBOX_PENALTY
238  || cnodename == REFBOX_GOAL_AWARDED || cnodename == REFBOX_GOAL_REMOVED
239  || cnodename == REFBOX_CARD_AWARDED || cnodename == REFBOX_CARD_REMOVED
240  || cnodename == REFBOX_PLAYER_OUT || cnodename == REFBOX_PLAYER_IN
241  || cnodename == REFBOX_SUBSTITUTION) {
242  cattr = cel->get_attribute("team");
243  cteamcolor = std::string(cattr->get_value().data());
244  }
245 
246  if (cnodename == REFBOX_CANCEL) {
247  // refbox canceled last command
248  logger_->log_info(name_, "RefBox cancelled last command");
249  } else if (cnodename == REFBOX_GAMESTOP) {
250  _rsh->set_gamestate(GS_FROZEN, TEAM_BOTH);
251  } else if (cnodename == REFBOX_GAMESTART) {
252  _rsh->set_gamestate(GS_PLAY, TEAM_BOTH);
253  } else if (cnodename == REFBOX_DROPPEDBALL) {
254  _rsh->set_gamestate(GS_DROP_BALL, TEAM_BOTH);
255  } else if (cnodename == REFBOX_GOAL_AWARDED) {
256  // increment according to color
257  if (cteamcolor == REFBOX_TEAMCOLOR_CYAN) {
258  _rsh->set_score(++score_cyan_, score_magenta_);
259  } else if (cteamcolor == REFBOX_TEAMCOLOR_MAGENTA) {
260  _rsh->set_score(score_cyan_, ++score_magenta_);
261  }
262  _rsh->set_gamestate(GS_FROZEN, TEAM_BOTH);
263  } else if (cnodename == REFBOX_KICKOFF) {
264  if (cteamcolor == REFBOX_TEAMCOLOR_CYAN) {
265  _rsh->set_gamestate(GS_KICK_OFF, TEAM_CYAN);
266  } else if (cteamcolor == REFBOX_TEAMCOLOR_MAGENTA) {
267  _rsh->set_gamestate(GS_KICK_OFF, TEAM_MAGENTA);
268  }
269  } else if (cnodename == REFBOX_PENALTY) {
270  if (cteamcolor == REFBOX_TEAMCOLOR_CYAN) {
271  _rsh->set_gamestate(GS_PENALTY, TEAM_CYAN);
272  } else if (cteamcolor == REFBOX_TEAMCOLOR_MAGENTA) {
273  _rsh->set_gamestate(GS_PENALTY, TEAM_MAGENTA);
274  }
275  } else if (cnodename == REFBOX_CORNER) {
276  if (cteamcolor == REFBOX_TEAMCOLOR_CYAN) {
277  _rsh->set_gamestate(GS_CORNER_KICK, TEAM_CYAN);
278  } else if (cteamcolor == REFBOX_TEAMCOLOR_MAGENTA) {
279  _rsh->set_gamestate(GS_CORNER_KICK, TEAM_MAGENTA);
280  }
281  } else if (cnodename == REFBOX_THROWIN) {
282  if (cteamcolor == REFBOX_TEAMCOLOR_CYAN) {
283  _rsh->set_gamestate(GS_THROW_IN, TEAM_CYAN);
284  } else if (cteamcolor == REFBOX_TEAMCOLOR_MAGENTA) {
285  _rsh->set_gamestate(GS_THROW_IN, TEAM_MAGENTA);
286  }
287  } else if (cnodename == REFBOX_FREEKICK) {
288  if (cteamcolor == REFBOX_TEAMCOLOR_CYAN) {
289  _rsh->set_gamestate(GS_FREE_KICK, TEAM_CYAN);
290  } else if (cteamcolor == REFBOX_TEAMCOLOR_MAGENTA) {
291  _rsh->set_gamestate(GS_FREE_KICK, TEAM_MAGENTA);
292  }
293  } else if (cnodename == REFBOX_GOALKICK) {
294  if (cteamcolor == REFBOX_TEAMCOLOR_CYAN) {
295  _rsh->set_gamestate(GS_GOAL_KICK, TEAM_CYAN);
296  } else if (cteamcolor == REFBOX_TEAMCOLOR_MAGENTA) {
297  _rsh->set_gamestate(GS_GOAL_KICK, TEAM_MAGENTA);
298  }
299  } else if (cnodename == REFBOX_STAGE_CHANGED) {
300  cattr = cel->get_attribute("newStage");
301  cstagetype = std::string(cattr->get_value().data());
302  if (cstagetype == REFBOX_STAGETYPE_PREGAME) {
303  //
304  } else if (cstagetype == REFBOX_STAGETYPE_FIRSTHALF) {
305  _rsh->set_half(HALF_FIRST);
306  } else if (cstagetype == REFBOX_STAGETYPE_HALFTIME) {
307  _rsh->set_gamestate(GS_HALF_TIME, TEAM_BOTH);
308  } else if (cstagetype == REFBOX_STAGETYPE_SECONDHALF) {
309  _rsh->set_half(HALF_SECOND);
310  } else if (cstagetype == REFBOX_STAGETYPE_SHOOTOUT) {
311  //
312  } else if (cstagetype == REFBOX_STAGETYPE_ENDGAME) {
313  //
314  }
315  }
316 
317  } // end-for "child-node children list iteration"
318  } // end-if "child-node has children"
319  } // end-for "root children list iteration"
320  } // end-if "root has children"
321  } else {
322  // throw RefBoxParserException("root is not an element");
323  logger_->log_info(name_, "root is NOT a valid element");
324  }
325 }
326 
327 void
329 {
330  short pollrv = s_->poll(0, Socket::POLL_IN);
331  do {
332  if (pollrv == Socket::POLL_ERR) {
333  logger_->log_warn(name_, "Polling socket failed");
334  } else if (pollrv & Socket::POLL_IN) {
335  char tmpbuf[1024];
336  size_t bytes_read = s_->read(tmpbuf, sizeof(tmpbuf), /* read all */ false);
337  logger_->log_debug(name_, "Read %zu bytes", bytes_read);
338  if (bytes_read == 0) {
339  // seems that the remote has died, reconnect
340  connection_died_ = true;
341  } else {
342  tmpbuf[bytes_read] = '\0';
343  process_string(tmpbuf, bytes_read);
344  }
345  }
346  pollrv = s_->poll(0, Socket::POLL_IN);
347  } while (pollrv & Socket::POLL_IN);
348 }
349 
350 bool
352 {
353  if (connection_died_) {
354  reconnect();
355  }
356  return !connection_died_;
357 }
fawkes::MulticastDatagramSocket::set_loop
void set_loop(bool loop)
Set loopback of sent packets.
Definition: datagram_multicast.cpp:183
Msl2010RefBoxProcessor::refbox_process
void refbox_process()
Process incoming refbox communication.
Definition: msl2010.cpp:328
Msl2010RefBoxProcessor::Msl2010RefBoxProcessor
Msl2010RefBoxProcessor(fawkes::Logger *logger, const char *refbox_host, unsigned short int refbox_port)
Constructor.
Definition: msl2010.cpp:106
fawkes::Logger::log_info
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
fawkes::Socket::close
virtual void close()
Close socket.
Definition: socket.cpp:311
fawkes::Socket::poll
virtual short poll(int timeout=-1, short what=POLL_IN|POLL_HUP|POLL_PRI|POLL_RDHUP)
Wait for some event on socket.
Definition: socket.cpp:685
RefBoxStateHandler::set_score
virtual void set_score(unsigned int score_cyan, unsigned int score_magenta)=0
Set score.
fawkes::MulticastDatagramSocket
Multicast datagram socket.
Definition: datagram_multicast.h:33
fawkes::Logger
Interface for logging.
Definition: logger.h:42
fawkes
Fawkes library namespace.
fawkes::Logger::log_warn
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
fawkes::MulticastDatagramSocket::bind
virtual void bind()
Bind socket.
Definition: datagram_multicast.cpp:106
RefBoxStateHandler::set_gamestate
virtual void set_gamestate(int game_state, fawkes::worldinfo_gamestate_team_t state_team)=0
Set current game state.
Msl2010RefBoxProcessor::check_connection
bool check_connection()
Check if the connection is alive and reconnect.
Definition: msl2010.cpp:351
fawkes::Socket::read
virtual size_t read(void *buf, size_t count, bool read_all=true)
Read from socket.
Definition: socket.cpp:760
fawkes::Logger::log_debug
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
RefBoxStateHandler::set_half
virtual void set_half(fawkes::worldinfo_gamestate_half_t half, bool kickoff=false)=0
Set current half of the game time.
Msl2010RefBoxProcessor::~Msl2010RefBoxProcessor
~Msl2010RefBoxProcessor()
Destructor.
Definition: msl2010.cpp:126
RefBoxProcessor::_rsh
RefBoxStateHandler * _rsh
Refbox state handler, set via set_handler()
Definition: processor.h:40
fawkes::Exception
Base class for exceptions in Fawkes.
Definition: exception.h:36