Fawkes API Fawkes Development Version
|
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 }