Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * msl2010.cpp - Fawkes mid-size refbox 2010 protocol repeater 00004 * 00005 * Created: Wed Apr 09 10:38:16 2008 00006 * Copyright 2008 Stefan Schiffer [stefanschiffer.de] 00007 * 2010 Tim Niemueller [www.niemueller.de] 00008 * 00009 ****************************************************************************/ 00010 00011 /* This program is free software; you can redistribute it and/or modify 00012 * it under the terms of the GNU General Public License as published by 00013 * the Free Software Foundation; either version 2 of the License, or 00014 * (at your option) any later version. 00015 * 00016 * This program is distributed in the hope that it will be useful, 00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00019 * GNU Library General Public License for more details. 00020 * 00021 * Read the full text in the LICENSE.GPL file in the doc directory. 00022 */ 00023 00024 #include "msl2010.h" 00025 #include <netcomm/socket/datagram_multicast.h> 00026 #include <logging/logger.h> 00027 00028 #include <string> 00029 #include <sstream> 00030 #include <cstdlib> 00031 #include <cstring> 00032 00033 #include <libxml++/libxml++.h> 00034 // libxml++ pulls in Glib::ustring, which has a looong tail of dependent 00035 // includes, one being <sys/signal.h>, which on FreeBSD defines POLL_IN 00036 // for the SIGPOLL. Since we do not use the signal in any way we simply 00037 // undefine the constants, such that the Socket::POLL_IN constant does 00038 // not get messed up. 00039 #ifdef __FreeBSD__ 00040 # undef POLL_IN 00041 # undef POLL_ERR 00042 #endif 00043 00044 using namespace fawkes; 00045 using namespace xmlpp; 00046 00047 00048 // REFBOX_CODES ////////////////////////// 00049 00050 static const std::string REFBOX_EVENT = "RefboxEvent"; 00051 static const std::string REFBOX_GAMEINFO = "GameInfo"; 00052 static const std::string REFBOX_EVENT_REFEREE = "Referee"; 00053 static const std::string REFBOX_EVENT_TEAMSETUP = "TeamSetup"; 00054 00055 static const std::string REFBOX_CANCEL = "Cancel"; 00056 00057 static const std::string REFBOX_GAMESTART = "GameStart"; 00058 static const std::string REFBOX_GAMESTOP = "GameStop"; 00059 00060 static const std::string REFBOX_STAGE_CHANGED = "StageChanged"; 00061 static const std::string REFBOX_STAGETYPE_PREGAME = "preGame"; 00062 static const std::string REFBOX_STAGETYPE_FIRSTHALF = "firstHalf"; 00063 static const std::string REFBOX_STAGETYPE_HALFTIME = "halfTime"; 00064 static const std::string REFBOX_STAGETYPE_SECONDHALF = "secondHalf"; 00065 static const std::string REFBOX_STAGETYPE_SHOOTOUT = "shootOut"; 00066 static const std::string REFBOX_STAGETYPE_ENDGAME = "endGame"; 00067 00068 static const std::string REFBOX_GOAL_AWARDED = "GoalAwarded"; 00069 static const std::string REFBOX_GOAL_REMOVED = "GoalRemoved"; 00070 00071 static const std::string REFBOX_CARD_AWARDED = "CardAwarded"; 00072 static const std::string REFBOX_CARD_REMOVED = "CardRemoved"; 00073 00074 static const std::string REFBOX_SUBSTITUTION = "Substitution"; 00075 static const std::string REFBOX_PLAYER_OUT = "PlayerOut"; 00076 static const std::string REFBOX_PLAYER_IN = "PlayerIn"; 00077 00078 static const std::string REFBOX_DROPPEDBALL = "DroppedBall"; 00079 static const std::string REFBOX_KICKOFF = "KickOff"; 00080 static const std::string REFBOX_FREEKICK = "FreeKick"; 00081 static const std::string REFBOX_GOALKICK = "GoalKick"; 00082 static const std::string REFBOX_THROWIN = "ThrowIn"; 00083 static const std::string REFBOX_CORNER = "Corner"; 00084 static const std::string REFBOX_PENALTY = "Penalty"; 00085 00086 static const std::string REFBOX_TEAMCOLOR_CYAN = "Cyan"; 00087 static const std::string REFBOX_TEAMCOLOR_MAGENTA = "Magenta"; 00088 00089 static const std::string REFBOX_GOALCOLOR_YELLOW = "yellow"; 00090 static const std::string REFBOX_GOALCOLOR_BLUE = "blue"; 00091 00092 static const std::string REFBOX_CARDCOLOR_YELLOW = "yellow"; 00093 static const std::string REFBOX_CARDCOLOR_RED = "red"; 00094 00095 00096 /** @class Msl2010RefBoxProcessor "processor/msl2010.h" 00097 * Mid-size league refbox repeater. 00098 * This class will communicate with the mid-size league refbox and derive matching 00099 * game states from the communiation stream and send this via the world info. 00100 * @author Stefan Schiffer 00101 */ 00102 00103 /** Constructor. 00104 * @param logger logger for output 00105 * @param refbox_host refbox host 00106 * @param refbox_port refbox port 00107 */ 00108 Msl2010RefBoxProcessor::Msl2010RefBoxProcessor(Logger *logger, 00109 const char *refbox_host, 00110 unsigned short int refbox_port) 00111 : __name("Msl2010RefBoxProc") 00112 { 00113 __logger = logger; 00114 __quit = false; 00115 __s = NULL; 00116 __score_cyan = __score_magenta = 0; 00117 __connection_died = false; 00118 00119 __refbox_host = strdup(refbox_host); 00120 __refbox_port = refbox_port; 00121 00122 do { 00123 reconnect(); 00124 } while (! __s); 00125 } 00126 00127 00128 /** Destructor. */ 00129 Msl2010RefBoxProcessor::~Msl2010RefBoxProcessor() 00130 { 00131 free(__refbox_host); 00132 __s->close(); 00133 delete __s; 00134 } 00135 00136 00137 /** Reconnect to refbox. */ 00138 void 00139 Msl2010RefBoxProcessor::reconnect() 00140 { 00141 if ( __s ) { 00142 __s->close(); 00143 delete __s; 00144 } 00145 __logger->log_info(__name, "Trying to connect to refbox at %s:%u", 00146 __refbox_host, __refbox_port); 00147 try { 00148 __logger->log_info(__name, "Creating MulticastDatagramSocket"); 00149 __s = new MulticastDatagramSocket(__refbox_host, __refbox_port, 2.3); 00150 //printf("set loop\n"); 00151 __s->set_loop(true); // (re)receive locally sent stuff 00152 //printf("bind\n"); 00153 __s->bind(); 00154 //printf("bind done\n"); 00155 00156 // printf("check for data availability ...\n"); 00157 // if ( !__s->available() ) { 00158 // printf("... nothing to receive\n"); 00159 // } else { 00160 // printf("... data is available!\n"); 00161 // } 00162 00163 __connection_died = false; 00164 00165 } catch (Exception &e) { 00166 delete __s; 00167 __s = NULL; 00168 //printf("."); 00169 //fflush(stdout); 00170 //usleep(500000); 00171 } 00172 00173 __logger->log_info(__name, "Init done"); 00174 } 00175 00176 00177 /** Process received string. */ 00178 void 00179 Msl2010RefBoxProcessor::process_string(char *buf, size_t len) 00180 { 00181 __logger->log_info(__name, "Received\n *****\n %s \n *****", buf); 00182 00183 std::istringstream iss( std::string(buf), std::istringstream::in); 00184 00185 dom = new DomParser(); 00186 //dom->set_validate(); 00187 dom->set_substitute_entities(); 00188 dom->parse_stream(iss); 00189 root = dom->get_document()->get_root_node(); 00190 00191 //printf( " root node:\n%s\n", root->get_name().data() ); 00192 00193 const Element * el = dynamic_cast<const Element *>(root); 00194 00195 if ( el ) { 00196 /// valid element 00197 //printf("Is valid Element\n"); 00198 __logger->log_info(__name, "root-element name is '%s'", el->get_name().data() ); 00199 00200 const Node::NodeList nl = el->get_children(); 00201 00202 if( nl.size() == 0 ) { 00203 __logger->log_info(__name, "root has NO children!"); 00204 } 00205 else { 00206 //printf("root has %u children!\n", nl.size()); 00207 00208 for (Node::NodeList::const_iterator it = nl.begin(); it != nl.end(); ++it) { 00209 const Node* node = *it; 00210 __logger->log_info(__name, "1st level child name is '%s'", node->get_name().data() ); 00211 00212 //if( node->get_name().data() == REFBOX_GAMEINFO ) { 00213 // 00214 //} 00215 //else if( node->get_name().data() == REFBOX_EVENT ) { 00216 // 00217 //} 00218 //else { 00219 // printf(" unhandled RefboxMessage-type '%s'!\n", node->get_name().data() ); 00220 //} 00221 00222 const Node::NodeList cnl = node->get_children(); 00223 00224 if( cnl.size() == 0 ) { 00225 __logger->log_info(__name, "child has NO children!"); 00226 } 00227 else { 00228 //printf("child has %u children!\n", nl.size()); 00229 00230 for (Node::NodeList::const_iterator cit = cnl.begin(); cit != cnl.end(); ++cit) { 00231 const Node* cnode = *cit; 00232 const Element* cel = dynamic_cast<const Element *>(cnode); 00233 std::string cnodename(cnode->get_name().data()); 00234 00235 __logger->log_info(__name, "2nd level child name is '%s'", cnode->get_name().data() ); 00236 00237 const Attribute* cattr; 00238 std::string cteamcolor; 00239 //std::string cgoalcolor; 00240 //std::string ccardcolor; 00241 std::string cstagetype; 00242 00243 if( cnodename == REFBOX_KICKOFF || cnodename == REFBOX_FREEKICK || 00244 cnodename == REFBOX_GOALKICK || cnodename == REFBOX_THROWIN || 00245 cnodename == REFBOX_CORNER || cnodename == REFBOX_PENALTY || 00246 cnodename == REFBOX_GOAL_AWARDED || cnodename == REFBOX_GOAL_REMOVED || 00247 cnodename == REFBOX_CARD_AWARDED || cnodename == REFBOX_CARD_REMOVED || 00248 cnodename == REFBOX_PLAYER_OUT || cnodename == REFBOX_PLAYER_IN || 00249 cnodename == REFBOX_SUBSTITUTION ) 00250 { 00251 cattr = cel->get_attribute("team"); 00252 cteamcolor = std::string( cattr->get_value().data() ); 00253 } 00254 00255 if( cnodename == REFBOX_CANCEL ) { 00256 // refbox canceled last command 00257 __logger->log_info(__name, "RefBox cancelled last command"); 00258 } 00259 else if( cnodename == REFBOX_GAMESTOP ) { 00260 _rsh->set_gamestate(GS_FROZEN, TEAM_BOTH); 00261 } 00262 else if( cnodename == REFBOX_GAMESTART ) { 00263 _rsh->set_gamestate(GS_PLAY, TEAM_BOTH); 00264 } 00265 else if( cnodename == REFBOX_DROPPEDBALL ) { 00266 _rsh->set_gamestate(GS_DROP_BALL, TEAM_BOTH); 00267 } 00268 else if( cnodename == REFBOX_GOAL_AWARDED ) { 00269 // increment according to color 00270 if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) { 00271 _rsh->set_score(++__score_cyan, __score_magenta); 00272 } 00273 else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) { 00274 _rsh->set_score(__score_cyan, ++__score_magenta); 00275 } 00276 _rsh->set_gamestate(GS_FROZEN, TEAM_BOTH); 00277 } 00278 else if( cnodename == REFBOX_KICKOFF ) { 00279 if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) { 00280 _rsh->set_gamestate(GS_KICK_OFF, TEAM_CYAN); 00281 } 00282 else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) { 00283 _rsh->set_gamestate(GS_KICK_OFF, TEAM_MAGENTA); 00284 } 00285 } 00286 else if( cnodename == REFBOX_PENALTY ) { 00287 if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) { 00288 _rsh->set_gamestate(GS_PENALTY, TEAM_CYAN); 00289 } 00290 else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) { 00291 _rsh->set_gamestate(GS_PENALTY, TEAM_MAGENTA); 00292 } 00293 } 00294 else if( cnodename == REFBOX_CORNER ) { 00295 if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) { 00296 _rsh->set_gamestate(GS_CORNER_KICK, TEAM_CYAN); 00297 } 00298 else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) { 00299 _rsh->set_gamestate(GS_CORNER_KICK, TEAM_MAGENTA); 00300 } 00301 } 00302 else if( cnodename == REFBOX_THROWIN ) { 00303 if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) { 00304 _rsh->set_gamestate(GS_THROW_IN, TEAM_CYAN); 00305 } 00306 else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) { 00307 _rsh->set_gamestate(GS_THROW_IN, TEAM_MAGENTA); 00308 } 00309 } 00310 else if( cnodename == REFBOX_FREEKICK ) { 00311 if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) { 00312 _rsh->set_gamestate(GS_FREE_KICK, TEAM_CYAN); 00313 } 00314 else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) { 00315 _rsh->set_gamestate(GS_FREE_KICK, TEAM_MAGENTA); 00316 } 00317 } 00318 else if( cnodename == REFBOX_GOALKICK ) { 00319 if( cteamcolor == REFBOX_TEAMCOLOR_CYAN ) { 00320 _rsh->set_gamestate(GS_GOAL_KICK, TEAM_CYAN); 00321 } 00322 else if ( cteamcolor == REFBOX_TEAMCOLOR_MAGENTA ) { 00323 _rsh->set_gamestate(GS_GOAL_KICK, TEAM_MAGENTA); 00324 } 00325 } 00326 else if( cnodename == REFBOX_STAGE_CHANGED ) { 00327 cattr = cel->get_attribute("newStage"); 00328 cstagetype = std::string( cattr->get_value().data() ); 00329 if( cstagetype == REFBOX_STAGETYPE_PREGAME ) { 00330 // 00331 } else if( cstagetype == REFBOX_STAGETYPE_FIRSTHALF ) { 00332 _rsh->set_half(HALF_FIRST); 00333 } else if( cstagetype == REFBOX_STAGETYPE_HALFTIME ) { 00334 _rsh->set_gamestate(GS_HALF_TIME, TEAM_BOTH); 00335 } else if( cstagetype == REFBOX_STAGETYPE_SECONDHALF ) { 00336 _rsh->set_half(HALF_SECOND); 00337 } else if( cstagetype == REFBOX_STAGETYPE_SHOOTOUT ) { 00338 // 00339 } else if( cstagetype == REFBOX_STAGETYPE_ENDGAME ) { 00340 // 00341 } 00342 00343 } 00344 00345 } // end-for "child-node children list iteration" 00346 } // end-if "child-node has children" 00347 } // end-for "root children list iteration" 00348 } // end-if "root has children" 00349 } 00350 else { 00351 // throw RefBoxParserException("root is not an element"); 00352 __logger->log_info(__name, "root is NOT a valid element"); 00353 } 00354 00355 } 00356 00357 void 00358 Msl2010RefBoxProcessor::refbox_process() 00359 { 00360 short pollrv = __s->poll(0, Socket::POLL_IN); 00361 do { 00362 00363 if (pollrv == Socket::POLL_ERR) { 00364 __logger->log_warn(__name, "Polling socket failed"); 00365 } else if (pollrv & Socket::POLL_IN) { 00366 char tmpbuf[1024]; 00367 size_t bytes_read = __s->read(tmpbuf, sizeof(tmpbuf), /* read all */ false); 00368 __logger->log_debug(__name, "Read %zu bytes", bytes_read); 00369 if ( bytes_read == 0 ) { 00370 // seems that the remote has died, reconnect 00371 __connection_died = true; 00372 } else { 00373 tmpbuf[bytes_read] = '\0'; 00374 process_string(tmpbuf, bytes_read); 00375 } 00376 } 00377 pollrv = __s->poll(0, Socket::POLL_IN); 00378 } while (pollrv & Socket::POLL_IN); 00379 } 00380 00381 bool 00382 Msl2010RefBoxProcessor::check_connection() 00383 { 00384 if (__connection_died) { 00385 reconnect(); 00386 } 00387 return ! __connection_died; 00388 }