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 #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 }