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
44using namespace fawkes;
45using namespace xmlpp;
46
47// REFBOX_CODES //////////////////////////
48
49static const std::string REFBOX_EVENT = "RefboxEvent";
50static const std::string REFBOX_GAMEINFO = "GameInfo";
51static const std::string REFBOX_EVENT_REFEREE = "Referee";
52static const std::string REFBOX_EVENT_TEAMSETUP = "TeamSetup";
53
54static const std::string REFBOX_CANCEL = "Cancel";
55
56static const std::string REFBOX_GAMESTART = "GameStart";
57static const std::string REFBOX_GAMESTOP = "GameStop";
58
59static const std::string REFBOX_STAGE_CHANGED = "StageChanged";
60static const std::string REFBOX_STAGETYPE_PREGAME = "preGame";
61static const std::string REFBOX_STAGETYPE_FIRSTHALF = "firstHalf";
62static const std::string REFBOX_STAGETYPE_HALFTIME = "halfTime";
63static const std::string REFBOX_STAGETYPE_SECONDHALF = "secondHalf";
64static const std::string REFBOX_STAGETYPE_SHOOTOUT = "shootOut";
65static const std::string REFBOX_STAGETYPE_ENDGAME = "endGame";
66
67static const std::string REFBOX_GOAL_AWARDED = "GoalAwarded";
68static const std::string REFBOX_GOAL_REMOVED = "GoalRemoved";
69
70static const std::string REFBOX_CARD_AWARDED = "CardAwarded";
71static const std::string REFBOX_CARD_REMOVED = "CardRemoved";
72
73static const std::string REFBOX_SUBSTITUTION = "Substitution";
74static const std::string REFBOX_PLAYER_OUT = "PlayerOut";
75static const std::string REFBOX_PLAYER_IN = "PlayerIn";
76
77static const std::string REFBOX_DROPPEDBALL = "DroppedBall";
78static const std::string REFBOX_KICKOFF = "KickOff";
79static const std::string REFBOX_FREEKICK = "FreeKick";
80static const std::string REFBOX_GOALKICK = "GoalKick";
81static const std::string REFBOX_THROWIN = "ThrowIn";
82static const std::string REFBOX_CORNER = "Corner";
83static const std::string REFBOX_PENALTY = "Penalty";
84
85static const std::string REFBOX_TEAMCOLOR_CYAN = "Cyan";
86static const std::string REFBOX_TEAMCOLOR_MAGENTA = "Magenta";
87
88static const std::string REFBOX_GOALCOLOR_YELLOW = "yellow";
89static const std::string REFBOX_GOALCOLOR_BLUE = "blue";
90
91static const std::string REFBOX_CARDCOLOR_YELLOW = "yellow";
92static 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. */
134void
135Msl2010RefBoxProcessor::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. */
172void
173Msl2010RefBoxProcessor::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
327void
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
350bool
352{
353 if (connection_died_) {
354 reconnect();
355 }
356 return !connection_died_;
357}
void refbox_process()
Process incoming refbox communication.
Definition: msl2010.cpp:328
~Msl2010RefBoxProcessor()
Destructor.
Definition: msl2010.cpp:126
Msl2010RefBoxProcessor(fawkes::Logger *logger, const char *refbox_host, unsigned short int refbox_port)
Constructor.
Definition: msl2010.cpp:106
bool check_connection()
Check if the connection is alive and reconnect.
Definition: msl2010.cpp:351
RefBoxStateHandler * _rsh
Refbox state handler, set via set_handler()
Definition: processor.h:40
virtual void set_gamestate(int game_state, fawkes::worldinfo_gamestate_team_t state_team)=0
Set current game state.
virtual void set_score(unsigned int score_cyan, unsigned int score_magenta)=0
Set score.
virtual void set_half(fawkes::worldinfo_gamestate_half_t half, bool kickoff=false)=0
Set current half of the game time.
Base class for exceptions in Fawkes.
Definition: exception.h:36
Interface for logging.
Definition: logger.h:42
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_info(const char *component, const char *format,...)=0
Log informational message.
Multicast datagram socket.
void set_loop(bool loop)
Set loopback of sent packets.
virtual void bind()
Bind socket.
virtual size_t read(void *buf, size_t count, bool read_all=true)
Read from socket.
Definition: socket.cpp:760
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
virtual void close()
Close socket.
Definition: socket.cpp:311
Fawkes library namespace.