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