refbox_state_writer.cpp

00001 
00002 /***************************************************************************
00003  *  refbox_state_writer.cpp - Fawkes RefBox state writer
00004  *
00005  *  Created: Wed Apr 09 10:19:27 2008
00006  *  Copyright  2008  Tim Niemueller [www.niemueller.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 "refbox_state_writer.h"
00024 
00025 #include <netcomm/worldinfo/transceiver.h>
00026 #include <utils/time/time.h>
00027 #include <utils/time/clock.h>
00028 
00029 #include <set>
00030 #include <cstdio>
00031 
00032 #define log(...)    if (__debug) {\
00033                       printf("%3u %s ", __counter, get_time().c_str());\
00034                       printf(__VA_ARGS__);\
00035                       fflush(stdout);\
00036                     }
00037 
00038 using namespace std;
00039 using namespace fawkes;
00040 
00041 namespace {
00042 std::string get_time() throw()
00043 {
00044   Clock* c = Clock::instance();
00045   Time t = c->now();
00046   char* buf = new char[Time::TIMESTR_SIZE];
00047   t.str_r(buf, true);
00048   std::string str = buf;
00049   delete buf;
00050   std::string::size_type from =
00051     1+str.find_first_of(' ',
00052       1+str.find_first_of(' ',
00053         1+str.find_first_of(' ')));
00054   std::string::size_type to = str.find_last_of(' ');
00055   return str.substr(from, to - from + 1);
00056 }
00057 }
00058 
00059 /** @class RefBoxStateBBWriter "refbox_state_writer.h"
00060  * RefBox repeater state writer.
00061  * Writes to GameStateInterfaces "WM GameState" of given hosts.
00062  * @author Christoph Schwering
00063  */
00064 
00065 /** Constructor.
00066  * @param hosts hosts to connect to to send game state info via remote
00067  * blackboard
00068  * @param debug true to enable debug output
00069  */
00070 RefBoxStateBBWriter::RefBoxStateBBWriter(vector<string> hosts, bool debug)
00071 {
00072   __counter = 0;
00073   __debug = debug;
00074 
00075   __game_state = GS_FROZEN;
00076   __state_team = TEAM_BOTH;
00077   __score_cyan = 0;
00078   __score_magenta = 0;
00079   __our_team = TEAM_CYAN;
00080   __our_goal_color = GOAL_BLUE;
00081   __half = HALF_FIRST;
00082 
00083   for (vector<string>::const_iterator it = hosts.begin(); it != hosts.end();
00084       it++) {
00085     connect(*it);
00086   }
00087 }
00088 
00089 
00090 /** Destructor. */
00091 RefBoxStateBBWriter::~RefBoxStateBBWriter()
00092 {
00093   for (map<RemoteBlackBoard*, GameStateInterface*>::iterator it = __giss.begin();
00094       it != __giss.end(); it++) {
00095     RemoteBlackBoard* rbb = it->first;
00096     GameStateInterface* gis = it->second;
00097     rbb->close(gis);
00098     delete rbb;
00099   }
00100 }
00101 
00102 
00103 /* Connects to a host and opens and stores the interface at the right place. */
00104 void RefBoxStateBBWriter::connect(const string& host) 
00105 {
00106   try {
00107     RemoteBlackBoard* rbb = new RemoteBlackBoard(host.c_str(), 1910);
00108     __rbbs[rbb] = host;
00109     GameStateInterface* gis = static_cast<GameStateInterface*>(rbb->open_for_writing("GameStateInterface", "WM GameState"));
00110     __giss[rbb] = gis;
00111     log("Successfully connected to %s\n", host.c_str());
00112     set_gamestate(__game_state, __state_team);
00113     set_score(__score_cyan, __score_magenta);
00114     set_team_goal(__our_team, __our_goal_color);
00115     set_half(__half);
00116     gis->write();
00117   } catch (Exception& e) {
00118     log("Connecting to %s failed\n", host.c_str());
00119     e.print_trace();
00120     log("\n");
00121     log("\n");
00122   }
00123 }
00124 
00125 /** Set current game state.
00126  * @param game_state current game state
00127  * @param state_team team referenced by the game state
00128  */
00129 void
00130 RefBoxStateBBWriter::set_gamestate(int game_state,
00131                                    worldinfo_gamestate_team_t state_team)
00132 {
00133   log("Setting gamestate to '%d' for team '%s'\n",
00134       game_state, worldinfo_gamestate_team_tostring(state_team));
00135 
00136   __game_state = game_state;
00137   __state_team = state_team;
00138 
00139   for (map<RemoteBlackBoard*,GameStateInterface*>::iterator it = __giss.begin(); it != __giss.end(); it++) {
00140     GameStateInterface* gis = it->second;
00141     switch (game_state)
00142       {
00143       case(GS_FROZEN):
00144         gis->set_game_state( GameStateInterface::GS_FROZEN );
00145         break;
00146 
00147       case(GS_PLAY):
00148         gis->set_game_state( GameStateInterface::GS_PLAY );
00149         break;
00150 
00151       case(GS_KICK_OFF):
00152         gis->set_game_state( GameStateInterface::GS_KICK_OFF );
00153         break;
00154 
00155       case(GS_DROP_BALL):
00156         gis->set_game_state( GameStateInterface::GS_DROP_BALL );
00157         break;
00158 
00159       case(GS_PENALTY):
00160         gis->set_game_state( GameStateInterface::GS_PENALTY );
00161         break;
00162 
00163       case(GS_CORNER_KICK):
00164         gis->set_game_state( GameStateInterface::GS_CORNER_KICK );
00165         break;
00166 
00167       case(GS_THROW_IN):
00168         gis->set_game_state( GameStateInterface::GS_THROW_IN );
00169         break;
00170 
00171       case(GS_FREE_KICK):
00172         gis->set_game_state( GameStateInterface::GS_FREE_KICK );
00173         break;
00174 
00175       case(GS_GOAL_KICK):
00176         gis->set_game_state( GameStateInterface::GS_GOAL_KICK );
00177         break;
00178 
00179       case(GS_HALF_TIME):
00180         gis->set_game_state( GameStateInterface::GS_HALF_TIME );
00181         break;
00182       }
00183 
00184     switch (state_team)
00185       {
00186       case(TEAM_NONE):
00187         gis->set_state_team( GameStateInterface::TEAM_NONE );
00188         break;
00189 
00190       case(TEAM_CYAN):
00191         gis->set_state_team( GameStateInterface::TEAM_CYAN );
00192         break;
00193 
00194       case(TEAM_MAGENTA):
00195         gis->set_state_team( GameStateInterface::TEAM_MAGENTA );
00196         break;
00197 
00198       case(TEAM_BOTH):
00199         gis->set_state_team( GameStateInterface::TEAM_BOTH );
00200         break;
00201       }
00202   }
00203 }
00204 
00205 
00206 /** Set score.
00207  * @param score_cyan current score of team cyan
00208  * @param score_magenta current score of team magenta
00209  */
00210 void
00211 RefBoxStateBBWriter::set_score(unsigned int score_cyan, unsigned int score_magenta)
00212 {
00213   log("Setting score to %u:%u (cyan:magenta)\n", score_cyan, score_magenta);
00214 
00215   __score_cyan = score_cyan;
00216   __score_magenta = score_magenta;
00217 
00218   for (map<RemoteBlackBoard*,GameStateInterface*>::iterator it = __giss.begin(); it != __giss.end(); it++) {
00219     GameStateInterface* gis = it->second;
00220     gis->set_score_cyan( score_cyan );
00221     gis->set_score_magenta( score_magenta );
00222   }
00223 }
00224 
00225 
00226 /** Set team and goal info.
00227  * @param our_team our team color
00228  * @param goal_color our goal color
00229  */
00230 void
00231 RefBoxStateBBWriter::set_team_goal(worldinfo_gamestate_team_t our_team,
00232     worldinfo_gamestate_goalcolor_t goal_color)
00233 {
00234   log("Setting team color to '%s' and goal color to '%s'\n",
00235       worldinfo_gamestate_team_tostring(our_team),
00236       worldinfo_gamestate_goalcolor_tostring(goal_color));
00237 
00238   __our_team = our_team;
00239   __our_goal_color = goal_color;
00240 
00241   for (map<RemoteBlackBoard*,GameStateInterface*>::iterator it = __giss.begin(); it != __giss.end(); it++) {
00242     GameStateInterface* gis = it->second;
00243     if (our_team == TEAM_CYAN) {
00244       gis->set_our_team( GameStateInterface::TEAM_CYAN );
00245     } else {
00246       gis->set_our_team( GameStateInterface::TEAM_MAGENTA );
00247     }
00248 
00249     if (goal_color == GOAL_BLUE) {
00250       gis->set_our_goal_color( GameStateInterface::GOAL_BLUE );
00251     } else {
00252       gis->set_our_goal_color( GameStateInterface::GOAL_YELLOW );
00253     }
00254   }
00255 }
00256 
00257 
00258 /** Set current half of the game time.
00259  * @param half current half
00260  */
00261 void
00262 RefBoxStateBBWriter::set_half(worldinfo_gamestate_half_t half)
00263 {
00264   log("Setting half to '%s'\n",
00265       worldinfo_gamestate_half_tostring(half));
00266 
00267   __half = half;
00268 
00269   for (map<RemoteBlackBoard*,GameStateInterface*>::iterator it = __giss.begin(); it != __giss.end(); it++) {
00270     GameStateInterface* gis = it->second;
00271     switch (half) {
00272       case HALF_FIRST:
00273         gis->set_half(GameStateInterface::HALF_FIRST);
00274         break;
00275       case HALF_SECOND:
00276         gis->set_half(GameStateInterface::HALF_SECOND);
00277         break;
00278     }
00279   }
00280 }
00281 
00282 
00283 /** Send worldinfo. */
00284 void
00285 RefBoxStateBBWriter::send()
00286 {
00287   ++__counter;
00288   log("Sending worldinfo\n");
00289 
00290   set<RemoteBlackBoard*> erase_rbbs;
00291   set<string> reconnect_hosts;
00292 
00293   unsigned int i = 0;
00294   for (map<RemoteBlackBoard*,GameStateInterface*>::iterator it = __giss.begin(); it != __giss.end(); it++) {
00295     RemoteBlackBoard* rbb = it->first;
00296     GameStateInterface* gis = it->second;
00297     const string host = __rbbs[rbb].c_str();
00298     try {
00299       gis->set_score_cyan(gis->score_cyan() + 1); // just for checking at the recipient's side whether the data ankommt
00300       gis->write();
00301       log("%u. Successfully wrote game state on %s\n", ++i, __rbbs[rbb].c_str());
00302     } catch (Exception& e) {
00303       log("%u. Writing game state on %s failed, reason:\n", ++i, __rbbs[rbb].c_str());
00304       e.print_trace();
00305       log("I will reconnect after this loop\n");
00306       erase_rbbs.insert(rbb);
00307       reconnect_hosts.insert(host);
00308     }
00309   }
00310   for (set<RemoteBlackBoard*>::iterator it = erase_rbbs.begin(); it != erase_rbbs.end(); it++) {
00311     RemoteBlackBoard* rbb = *it;
00312     __rbbs.erase(rbb);
00313     __giss.erase(rbb);
00314   }
00315   for (set<std::string>::iterator it = reconnect_hosts.begin(); it != reconnect_hosts.end(); it++) {
00316     std::string host = *it;
00317     log("Reconnecting to %s\n", host.c_str());
00318     connect(host);
00319   }
00320 
00321   log("Sending worldinfo done\n");
00322 }