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 #include <netcomm/socket/datagram_multicast.h>
26 #include <logging/logger.h>
27 
28 #include <string>
29 #include <sstream>
30 #include <cstdlib>
31 #include <cstring>
32 
33 #include <libxml++/libxml++.h>
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 
48 // REFBOX_CODES //////////////////////////
49 
50 static const std::string REFBOX_EVENT = "RefboxEvent";
51 static const std::string REFBOX_GAMEINFO = "GameInfo";
52 static const std::string REFBOX_EVENT_REFEREE = "Referee";
53 static const std::string REFBOX_EVENT_TEAMSETUP = "TeamSetup";
54 
55 static const std::string REFBOX_CANCEL = "Cancel";
56 
57 static const std::string REFBOX_GAMESTART = "GameStart";
58 static const std::string REFBOX_GAMESTOP = "GameStop";
59 
60 static const std::string REFBOX_STAGE_CHANGED = "StageChanged";
61 static const std::string REFBOX_STAGETYPE_PREGAME = "preGame";
62 static const std::string REFBOX_STAGETYPE_FIRSTHALF = "firstHalf";
63 static const std::string REFBOX_STAGETYPE_HALFTIME = "halfTime";
64 static const std::string REFBOX_STAGETYPE_SECONDHALF = "secondHalf";
65 static const std::string REFBOX_STAGETYPE_SHOOTOUT = "shootOut";
66 static const std::string REFBOX_STAGETYPE_ENDGAME = "endGame";
67 
68 static const std::string REFBOX_GOAL_AWARDED = "GoalAwarded";
69 static const std::string REFBOX_GOAL_REMOVED = "GoalRemoved";
70 
71 static const std::string REFBOX_CARD_AWARDED = "CardAwarded";
72 static const std::string REFBOX_CARD_REMOVED = "CardRemoved";
73 
74 static const std::string REFBOX_SUBSTITUTION = "Substitution";
75 static const std::string REFBOX_PLAYER_OUT = "PlayerOut";
76 static const std::string REFBOX_PLAYER_IN = "PlayerIn";
77 
78 static const std::string REFBOX_DROPPEDBALL = "DroppedBall";
79 static const std::string REFBOX_KICKOFF = "KickOff";
80 static const std::string REFBOX_FREEKICK = "FreeKick";
81 static const std::string REFBOX_GOALKICK = "GoalKick";
82 static const std::string REFBOX_THROWIN = "ThrowIn";
83 static const std::string REFBOX_CORNER = "Corner";
84 static const std::string REFBOX_PENALTY = "Penalty";
85 
86 static const std::string REFBOX_TEAMCOLOR_CYAN = "Cyan";
87 static const std::string REFBOX_TEAMCOLOR_MAGENTA = "Magenta";
88 
89 static const std::string REFBOX_GOALCOLOR_YELLOW = "yellow";
90 static const std::string REFBOX_GOALCOLOR_BLUE = "blue";
91 
92 static const std::string REFBOX_CARDCOLOR_YELLOW = "yellow";
93 static const std::string REFBOX_CARDCOLOR_RED = "red";
94 
95 
96 /** @class Msl2010RefBoxProcessor "processor/msl2010.h"
97  * Mid-size league refbox repeater.
98  * This class will communicate with the mid-size league refbox and derive matching
99  * game states from the communiation stream and send this via the world info.
100  * @author Stefan Schiffer
101  */
102 
103 /** Constructor.
104  * @param logger logger for output
105  * @param refbox_host refbox host
106  * @param refbox_port refbox port
107  */
109  const char *refbox_host,
110  unsigned short int refbox_port)
111  : __name("Msl2010RefBoxProc")
112 {
113  __logger = logger;
114  __quit = false;
115  __s = NULL;
116  __score_cyan = __score_magenta = 0;
117  __connection_died = false;
118 
119  __refbox_host = strdup(refbox_host);
120  __refbox_port = refbox_port;
121 
122  do {
123  reconnect();
124  } while (! __s);
125 }
126 
127 
128 /** Destructor. */
130 {
131  free(__refbox_host);
132  __s->close();
133  delete __s;
134 }
135 
136 
137 /** Reconnect to refbox. */
138 void
139 Msl2010RefBoxProcessor::reconnect()
140 {
141  if ( __s ) {
142  __s->close();
143  delete __s;
144  }
145  __logger->log_info(__name, "Trying to connect to refbox at %s:%u",
146  __refbox_host, __refbox_port);
147  try {
148  __logger->log_info(__name, "Creating MulticastDatagramSocket");
149  __s = new MulticastDatagramSocket(Socket::IPv4, __refbox_host, __refbox_port, 2.3);
150  //printf("set loop\n");
151  __s->set_loop(true); // (re)receive locally sent stuff
152  //printf("bind\n");
153  __s->bind();
154  //printf("bind done\n");
155 
156  // printf("check for data availability ...\n");
157  // if ( !__s->available() ) {
158  // printf("... nothing to receive\n");
159  // } else {
160  // printf("... data is available!\n");
161  // }
162 
163  __connection_died = false;
164 
165  } catch (Exception &e) {
166  delete __s;
167  __s = NULL;
168  //printf(".");
169  //fflush(stdout);
170  //usleep(500000);
171  }
172 
173  __logger->log_info(__name, "Init done");
174 }
175 
176 
177 /** Process received string. */
178 void
179 Msl2010RefBoxProcessor::process_string(char *buf, size_t len)
180 {
181  __logger->log_info(__name, "Received\n *****\n %s \n *****", buf);
182 
183  std::istringstream iss( std::string(buf), std::istringstream::in);
184 
185  dom = new DomParser();
186  //dom->set_validate();
187  dom->set_substitute_entities();
188  dom->parse_stream(iss);
189  root = dom->get_document()->get_root_node();
190 
191  //printf( " root node:\n%s\n", root->get_name().data() );
192 
193  const Element * el = dynamic_cast<const Element *>(root);
194 
195  if ( el ) {
196  /// valid element
197  //printf("Is valid Element\n");
198  __logger->log_info(__name, "root-element name is '%s'", el->get_name().data() );
199 
200  const Node::NodeList nl = el->get_children();
201 
202  if( nl.size() == 0 ) {
203  __logger->log_info(__name, "root has NO children!");
204  }
205  else {
206  //printf("root has %u children!\n", nl.size());
207 
208  for (Node::NodeList::const_iterator it = nl.begin(); it != nl.end(); ++it) {
209  const Node* node = *it;
210  __logger->log_info(__name, "1st level child name is '%s'", node->get_name().data() );
211 
212  //if( node->get_name().data() == REFBOX_GAMEINFO ) {
213  //
214  //}
215  //else if( node->get_name().data() == REFBOX_EVENT ) {
216  //
217  //}
218  //else {
219  // printf(" unhandled RefboxMessage-type '%s'!\n", node->get_name().data() );
220  //}
221 
222  const Node::NodeList cnl = node->get_children();
223 
224  if( cnl.size() == 0 ) {
225  __logger->log_info(__name, "child has NO children!");
226  }
227  else {
228  //printf("child has %u children!\n", nl.size());
229 
230  for (Node::NodeList::const_iterator cit = cnl.begin(); cit != cnl.end(); ++cit) {
231  const Node* cnode = *cit;
232  const Element* cel = dynamic_cast<const Element *>(cnode);
233  std::string cnodename(cnode->get_name().data());
234 
235  __logger->log_info(__name, "2nd level child name is '%s'", cnode->get_name().data() );
236 
237  const Attribute* cattr;
238  std::string cteamcolor;
239  //std::string cgoalcolor;
240  //std::string ccardcolor;
241  std::string cstagetype;
242 
243  if( cnodename == REFBOX_KICKOFF || cnodename == REFBOX_FREEKICK ||
244  cnodename == REFBOX_GOALKICK || cnodename == REFBOX_THROWIN ||
245  cnodename == REFBOX_CORNER || cnodename == REFBOX_PENALTY ||
246  cnodename == REFBOX_GOAL_AWARDED || cnodename == REFBOX_GOAL_REMOVED ||
247  cnodename == REFBOX_CARD_AWARDED || cnodename == REFBOX_CARD_REMOVED ||
248  cnodename == REFBOX_PLAYER_OUT || cnodename == REFBOX_PLAYER_IN ||
249  cnodename == REFBOX_SUBSTITUTION )
250  {
251  cattr = cel->get_attribute("team");
252  cteamcolor = std::string( cattr->get_value().data() );
253  }
254 
255  if( cnodename == REFBOX_CANCEL ) {
256  // refbox canceled last command
257  __logger->log_info(__name, "RefBox cancelled last command");
258  }
259  else if( cnodename == REFBOX_GAMESTOP ) {
261  }
262  else if( cnodename == REFBOX_GAMESTART ) {
264  }
265  else if( cnodename == REFBOX_DROPPEDBALL ) {
267  }
268  else if( cnodename == REFBOX_GOAL_AWARDED ) {
269  // increment according to color
270  if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) {
271  _rsh->set_score(++__score_cyan, __score_magenta);
272  }
273  else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) {
274  _rsh->set_score(__score_cyan, ++__score_magenta);
275  }
277  }
278  else if( cnodename == REFBOX_KICKOFF ) {
279  if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) {
281  }
282  else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) {
284  }
285  }
286  else if( cnodename == REFBOX_PENALTY ) {
287  if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) {
289  }
290  else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) {
292  }
293  }
294  else if( cnodename == REFBOX_CORNER ) {
295  if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) {
297  }
298  else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) {
300  }
301  }
302  else if( cnodename == REFBOX_THROWIN ) {
303  if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) {
305  }
306  else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) {
308  }
309  }
310  else if( cnodename == REFBOX_FREEKICK ) {
311  if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) {
313  }
314  else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) {
316  }
317  }
318  else if( cnodename == REFBOX_GOALKICK ) {
319  if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) {
321  }
322  else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) {
324  }
325  }
326  else if( cnodename == REFBOX_STAGE_CHANGED ) {
327  cattr = cel->get_attribute("newStage");
328  cstagetype = std::string( cattr->get_value().data() );
329  if( cstagetype == REFBOX_STAGETYPE_PREGAME ) {
330  //
331  } else if( cstagetype == REFBOX_STAGETYPE_FIRSTHALF ) {
333  } else if( cstagetype == REFBOX_STAGETYPE_HALFTIME ) {
335  } else if( cstagetype == REFBOX_STAGETYPE_SECONDHALF ) {
337  } else if( cstagetype == REFBOX_STAGETYPE_SHOOTOUT ) {
338  //
339  } else if( cstagetype == REFBOX_STAGETYPE_ENDGAME ) {
340  //
341  }
342 
343  }
344 
345  } // end-for "child-node children list iteration"
346  } // end-if "child-node has children"
347  } // end-for "root children list iteration"
348  } // end-if "root has children"
349  }
350  else {
351  // throw RefBoxParserException("root is not an element");
352  __logger->log_info(__name, "root is NOT a valid element");
353  }
354 
355 }
356 
357 void
359 {
360  short pollrv = __s->poll(0, Socket::POLL_IN);
361  do {
362 
363  if (pollrv == Socket::POLL_ERR) {
364  __logger->log_warn(__name, "Polling socket failed");
365  } else if (pollrv & Socket::POLL_IN) {
366  char tmpbuf[1024];
367  size_t bytes_read = __s->read(tmpbuf, sizeof(tmpbuf), /* read all */ false);
368  __logger->log_debug(__name, "Read %zu bytes", bytes_read);
369  if ( bytes_read == 0 ) {
370  // seems that the remote has died, reconnect
371  __connection_died = true;
372  } else {
373  tmpbuf[bytes_read] = '\0';
374  process_string(tmpbuf, bytes_read);
375  }
376  }
377  pollrv = __s->poll(0, Socket::POLL_IN);
378  } while (pollrv & Socket::POLL_IN);
379 }
380 
381 bool
383 {
384  if (__connection_died) {
385  reconnect();
386  }
387  return ! __connection_died;
388 }
Kick off.
Definition: enums.h:33
virtual void close()
Close socket.
Definition: socket.cpp:274
Goal kick.
Definition: enums.h:39
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
Referee drops ball, both teams can wrestle for the ball.
Definition: enums.h:34
Throw in.
Definition: enums.h:37
Fawkes library namespace.
virtual void set_gamestate(int game_state, fawkes::worldinfo_gamestate_team_t state_team)=0
Set current game state.
void set_loop(bool loop)
Set loopback of sent packets.
RefBoxStateHandler * _rsh
Refbox state handler, set via set_handler()
Definition: processor.h:40
virtual void bind()
Bind socket.
Magenta team.
Definition: enums.h:57
Play, normal play.
Definition: enums.h:32
virtual void set_half(fawkes::worldinfo_gamestate_half_t half, bool kickoff=false)=0
Set current half of the game time.
First half.
Definition: enums.h:71
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual void set_score(unsigned int score_cyan, unsigned int score_magenta)=0
Set score.
Both teams.
Definition: enums.h:58
Multicast datagram socket.
Frozen, nothing moves.
Definition: enums.h:31
Definition: parser.h:34
virtual size_t read(void *buf, size_t count, bool read_all=true)
Read from socket.
Definition: socket.cpp:729
void refbox_process()
Process incoming refbox communication.
Definition: msl2010.cpp:358
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
Second half.
Definition: enums.h:72
~Msl2010RefBoxProcessor()
Destructor.
Definition: msl2010.cpp:129
Penalty kick.
Definition: enums.h:35
Half time.
Definition: enums.h:40
Cyan team.
Definition: enums.h:56
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
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:652
Free kick.
Definition: enums.h:38
bool check_connection()
Check if the connection is alive and reconnect.
Definition: msl2010.cpp:382
Corner kick.
Definition: enums.h:36
Msl2010RefBoxProcessor(fawkes::Logger *logger, const char *refbox_host, unsigned short int refbox_port)
Constructor.
Definition: msl2010.cpp:108
Interface for logging.
Definition: logger.h:34