Fawkes API  Fawkes Development Version
msl2010.cpp
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 <utils/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 }