msl2008.cpp

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