Fawkes API  Fawkes Development Version
refbox_state_sender.cpp
00001 
00002 /***************************************************************************
00003  *  refbox_state_sender.cpp - Fawkes RefBox state sender
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_sender.h"
00024 
00025 #include <netcomm/worldinfo/transceiver.h>
00026 #include <core/macros.h>
00027 
00028 #include <cstdio>
00029 
00030 using namespace fawkes;
00031 
00032 /** @class RefBoxStateSender "refbox_state_sender.h"
00033  * RefBox repeater state sender.
00034  * Adapter to the WorldInfoTransceiver, provides easy optional debugging output
00035  * to stdout.
00036  * @author Tim Niemueller
00037  */
00038 
00039 /** Constructor.
00040  * @param addr multicast address to send information to and receive from
00041  * @param port UDP port to send information to and receive from
00042  * @param key encryption key
00043  * @param iv encryption initialisation vector
00044  * @param debug true to enable debug output
00045  */
00046 RefBoxStateSender::RefBoxStateSender(const char *addr, unsigned short port,
00047                                      const char *key, const char *iv,
00048                                      bool debug)
00049 {
00050   __debug = debug;
00051 
00052   __transceiver = new WorldInfoTransceiver(WorldInfoTransceiver::MULTICAST, addr, port, key, iv);
00053   __transceiver->set_loop( true );
00054 
00055   __game_state = GS_FROZEN;
00056   __state_team = TEAM_BOTH;
00057   __score_cyan = 0;
00058   __score_magenta = 0;
00059   __our_team = TEAM_CYAN;
00060   __our_goal_color = GOAL_BLUE;
00061   __half = HALF_FIRST;
00062   __timeout_thread = NULL;
00063 }
00064 
00065 /** Constructor.
00066  * Only to be used by derivatives. These must implement the send() method!
00067  */
00068 RefBoxStateSender::RefBoxStateSender()
00069 {
00070   __debug = false;
00071   __transceiver = NULL;
00072   __game_state = GS_FROZEN;
00073   __state_team = TEAM_BOTH;
00074   __score_cyan = 0;
00075   __score_magenta = 0;
00076   __our_team = TEAM_CYAN;
00077   __our_goal_color = GOAL_BLUE;
00078   __half = HALF_FIRST;
00079   __timeout_thread = NULL;
00080 }
00081 
00082 
00083 /** Destructor. */
00084 RefBoxStateSender::~RefBoxStateSender()
00085 {
00086   if ( __timeout_thread ) {
00087     __timeout_thread->cancel();
00088     __timeout_thread->join();
00089     delete __timeout_thread;
00090   }
00091   delete __transceiver;
00092 }
00093 
00094 
00095 /** Set current game state.
00096  * @param game_state current game state
00097  * @param state_team team referenced by the game state
00098  */
00099 void
00100 RefBoxStateSender::set_gamestate(int game_state,
00101                                  worldinfo_gamestate_team_t state_team)
00102 {
00103   if ( __debug ) {
00104     printf("Setting gamestate to '%d' for team '%s'\n",
00105            game_state, worldinfo_gamestate_team_tostring(state_team));
00106   }
00107 
00108   __game_state = game_state;
00109   __state_team = state_team;
00110 }
00111 
00112 
00113 /** Set score.
00114  * @param score_cyan current score of team cyan
00115  * @param score_magenta current score of team magenta
00116  */
00117 void
00118 RefBoxStateSender::set_score(unsigned int score_cyan, unsigned int score_magenta)
00119 {
00120   if ( __debug ) {
00121     printf("Setting score to %u:%u (cyan:magenta)\n", score_cyan, score_magenta);
00122   }
00123   __score_cyan = score_cyan;
00124   __score_magenta = score_magenta;
00125 }
00126 
00127 
00128 /** Set team and goal info.
00129  * @param our_team our team color
00130  * @param goal_color our goal color
00131  */
00132 void
00133 RefBoxStateSender::set_team_goal(worldinfo_gamestate_team_t our_team,
00134                                  worldinfo_gamestate_goalcolor_t goal_color)
00135 {
00136   if ( __debug ) {
00137     printf("Setting team color to '%s' and goal color to '%s'\n",
00138            worldinfo_gamestate_team_tostring(our_team),
00139            worldinfo_gamestate_goalcolor_tostring(goal_color));
00140   }
00141   __our_team = our_team;
00142   __our_goal_color = goal_color;
00143 }
00144 
00145 
00146 /** Set current half of the game time.
00147  * @param half current half
00148  */
00149 void
00150 RefBoxStateSender::set_half(worldinfo_gamestate_half_t half)
00151 {
00152   if ( __debug ) {
00153     printf("Setting half to '%s'\n",
00154            worldinfo_gamestate_half_tostring(half));
00155   }
00156   __half = half;
00157 }
00158 
00159 
00160 /** Add penalty.
00161  * @param player number of the player to add the penalty for
00162  * @param penalty penalty code
00163  * @param seconds_remaining estimated time when the penalty will be lifted
00164  */
00165 void
00166 RefBoxStateSender::add_penalty(unsigned int player, unsigned int penalty,
00167                                unsigned int seconds_remaining)
00168 {
00169   rss_penalty_t p;
00170   p.player            = player;
00171   p.penalty           = penalty;
00172   p.seconds_remaining = seconds_remaining;
00173   __penalties[player] = p;
00174 }
00175 
00176 
00177 /** Send worldinfo. */
00178 void
00179 RefBoxStateSender::send()
00180 {
00181   if ( __debug ) {
00182     printf("Sending worldinfo\n");
00183   }
00184 
00185   if ( __timeout_thread ) {
00186     __timeout_thread->cancel();
00187     __timeout_thread->join();
00188     delete __timeout_thread;
00189   }
00190   __timeout_thread = new RefBoxStateSender::TimeoutThread(this);
00191   __timeout_thread->start();
00192 }
00193 
00194 
00195 /** Execute send operation.
00196  * Called by internal timeout thread.
00197  */
00198 void
00199 RefBoxStateSender::execute_send()
00200 {
00201   if (unlikely(! __transceiver)) {
00202     return;
00203   } else {
00204     __transceiver->set_gamestate(__game_state, __state_team);
00205     __transceiver->set_score(__score_cyan, __score_magenta);
00206     __transceiver->set_team_goal(__our_team, __our_goal_color);
00207     __transceiver->set_half(__half);
00208     for (__pit = __penalties.begin(); __pit != __penalties.end(); ++__pit) {
00209       __transceiver->add_penalty(__pit->second.player, __pit->second.penalty,
00210                                  __pit->second.seconds_remaining);
00211     }
00212     __penalties.clear();
00213     __transceiver->send();
00214   }
00215 }
00216 
00217 /** @class RefBoxStateSender::TimeoutThread <tools/refboxrep/refbox_state_sender.h>
00218  * Timeout thread.
00219  * This thread sends out a burst of world info packages if new information has been set
00220  * for sending and will then slow down until only one packet per second is sent.
00221  * @author Tim Niemueller
00222  */
00223 
00224 /** Constructor.
00225  * @param rss parent refbox state sender
00226  */
00227 RefBoxStateSender::TimeoutThread::TimeoutThread(RefBoxStateSender *rss)
00228   : Thread("RefBoxStateSender::TimeoutThread", Thread::OPMODE_CONTINUOUS)
00229 {
00230   __timeout_usec = 0;
00231   __rss = rss;
00232 }
00233 
00234 
00235 /** Destructor. */
00236 RefBoxStateSender::TimeoutThread::~TimeoutThread()
00237 {
00238 }
00239 
00240 
00241 void
00242 RefBoxStateSender::TimeoutThread::loop()
00243 {
00244   __rss->execute_send();
00245 
00246   switch (__timeout_usec) {
00247   case      0: __timeout_usec =       1; break;
00248   case      1: __timeout_usec =       2; break;
00249   case      2: __timeout_usec =   50000; break;
00250   //case  50000: __timeout_usec =  250000; break;
00251   //case 250000: __timeout_usec =  500000; break;
00252   //case 500000: __timeout_usec = 1000000; break;
00253   }
00254 
00255   usleep(__timeout_usec);
00256 }