spl.cpp

00001
00002 /***************************************************************************
00003  *  spl.cpp - Fawkes SPL refbox repeater
00004  *
00005  *  Created: Tue Jul 08 13:50:06 2008
00006  *  Copyright  2008  Tim Niemueller [www.niemueller.de]
00007  *             2009  Tobias Kellner
00008  *
00009  ****************************************************************************/
00010
00011 /*  This program is free software; you can redistribute it and/or modify
00012  *  it under the terms of the GNU General Public License as published by
00013  *  the Free Software Foundation; either version 2 of the License, or
00014  *  (at your option) any later version.
00015  *
00016  *  This program is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  *  GNU Library General Public License for more details.
00020  *
00021  *  Read the full text in the LICENSE.GPL file in the doc directory.
00022  */
00023
00024 #include "spl.h"
00025 #include "state_handler.h"
00026 #include <core/exception.h>
00027 #include <netcomm/socket/datagram.h>
00028 #include <utils/logging/logger.h>
00029
00030 #include <cstring>
00031 #include <cstdio>
00032 #include <unistd.h>
00033 #include <cerrno>
00034 // it it was defined, Exception::errno() could not be called...
00035 #ifdef errno
00036 #  undef errno
00037 #endif
00038 using namespace fawkes;
00039
00040 static const uint32_t  SPL_STRUCT_VERSION = 6;
00041
00042 static const uint8_t   SPL_STATE_INITIAL  = 0;
00043 static const uint8_t   SPL_STATE_READY    = 1;
00044 static const uint8_t   SPL_STATE_SET      = 2;
00045 static const uint8_t   SPL_STATE_PLAYING  = 3;
00046 static const uint8_t   SPL_STATE_FINISHED = 4;
00047
00048 static const uint8_t   SPL_STATE2_NORMAL       = 0;
00049 static const uint8_t   SPL_STATE2_PENALTYSHOOT = 1;
00050
00051 static const uint8_t   SPL_PENALTY_NONE              =  0;
00052 static const uint8_t   SPL_PENALTY_BALL_HOLDING      =  1;
00053 static const uint8_t   SPL_PENALTY_GOALIE_PUSHING    =  2;
00054 static const uint8_t   SPL_PENALTY_PLAYER_PUSHING    =  3;
00055 static const uint8_t   SPL_PENALTY_ILLEGAL_DEFENDER  =  4;
00056 static const uint8_t   SPL_PENALTY_ILLEGAL_DEFENSE   =  5;
00057 static const uint8_t   SPL_PENALTY_OBSTRUCTION       =  6;
00058 static const uint8_t   SPL_PENALTY_REQ_FOR_PICKUP    =  7;
00059 static const uint8_t   SPL_PENALTY_LEAVING           =  8;
00060 static const uint8_t   SPL_PENALTY_DAMAGE            =  9;
00061 static const uint8_t   SPL_PENALTY_MANUAL            = 10;
00062
00063 // team numbers
00064 static const uint8_t   SPL_TEAM_BLUE                 =  0;
00065 static const uint8_t   SPL_TEAM_RED                  =  1;
00066
00067 static const char    SPL_GAMECONTROL_HEADER[GCHS]  = {'R', 'G', 'm', 'e'};
00068
00069 
00070 /** @class SplRefBoxProcessor "processor/spl.h"
00071  * SPL league refbox repeater.
00072  * This class will listen to SPL refbox commands and derive matching
00073  * game states from the communication stream and send this via the world info.
00074  * @author Tim Niemueller
00075  */
00076 
00077 /** Constructor.
00078  * @param logger Logger
00079  * @param broadcast_port Broadcast port
00080  * @param team_number our team number
00081  * @param player_number individual player number
00082  */
00083 SplRefBoxProcessor::SplRefBoxProcessor(fawkes::Logger *logger,
00084                                        unsigned short int broadcast_port,
00085                                        unsigned int team_number,
00086                                        unsigned int player_number)
00087 {
00088   __player_number = player_number;
00089   __team_number = team_number;
00090   __logger = logger;
00091   __quit = false;
00092   __s = new DatagramSocket(0.0000000001);
00093   __s->bind(broadcast_port);
00094
00095   __penalty = SPL_PENALTY_NONE;
00096 }
00097
00098 
00099 /** Destructor. */
00100 SplRefBoxProcessor::~SplRefBoxProcessor()
00101 {
00102   __s->close();
00103   delete __s;
00104 }
00105
00106 
00107 /** Process received struct. */
00108 void
00109 SplRefBoxProcessor::process_struct(spl_gamecontrol_t *msg)
00110 {
00111   fawkes::worldinfo_gamestate_team_t our_team;
00112   //fawkes::worldinfo_gamestate_goalcolor_t our_goal;
00113
00114   int team_index;
00115   if (msg->teams[0].team_number == __team_number) team_index = 0;
00116   else if (msg->teams[1].team_number == __team_number) team_index = 1;
00117   else return; //Message doesn't concern us
00118
00119   switch (msg->teams[team_index].team_color) {
00120     case SPL_TEAM_BLUE:
00121       our_team = TEAM_CYAN;
00122       break;
00123     case SPL_TEAM_RED:
00124       our_team = TEAM_MAGENTA;
00125       break;
00126     default:
00127       printf("Ignoring faulty packet\n");
00128       return;
00129   }
00130
00131   _rsh->set_score(msg->teams[team_index].score, msg->teams[(team_index == 1 ? 0 : 1)].score);
00132   _rsh->set_team_goal(our_team, (our_team == TEAM_CYAN ? GOAL_BLUE : GOAL_YELLOW)); //blue team defends blue goal
00133
00134   for (unsigned int pl_num = 0; pl_num < MAX_NUM_PLAYERS; ++pl_num)
00135   {
00136     if ((pl_num + 1) == __player_number)
00137     {
00138       if ((msg->teams[team_index].players[pl_num].penalty != __penalty) ||
00139           (msg->teams[team_index].players[pl_num].penalty != PENALTY_NONE))
00140       {
00141         __penalty = msg->teams[team_index].players[pl_num].penalty;
00142         _rsh->add_penalty(__penalty,
00143                           msg->teams[team_index].players[pl_num].secs_till_unpenalized);
00144       }
00145       break;
00146     }
00147   }
00148
00149   switch (msg->state) {
00150   case SPL_STATE_INITIAL:
00151     _rsh->set_gamestate(GS_SPL_INITIAL, TEAM_BOTH);
00152     break;
00153   case SPL_STATE_READY:
00154     _rsh->set_gamestate(GS_SPL_READY, TEAM_BOTH);
00155     break;
00156   case SPL_STATE_SET:
00157     _rsh->set_gamestate(GS_SPL_SET, TEAM_BOTH);
00158     break;
00159   case SPL_STATE_PLAYING:
00160     _rsh->set_gamestate(GS_SPL_PLAY, TEAM_BOTH);
00161     break;
00162   case SPL_STATE_FINISHED:
00163     _rsh->set_gamestate(GS_SPL_FINISHED, TEAM_BOTH);
00164     break;
00165   default:
00166     _rsh->set_gamestate(GS_SPL_FINISHED, TEAM_BOTH);
00167     break;
00168   }
00169
00170   _rsh->set_half((msg->first_half == 1) ? HALF_FIRST : HALF_SECOND,
00171                  msg->kick_off_team == team_index);
00172 }
00173
00174
00175 void
00176 SplRefBoxProcessor::refbox_process()
00177 {
00178   try {
00179     spl_gamecontrol_t ctrlmsg;
00180     size_t bytes_read = __s->recv((void *)&ctrlmsg, sizeof(ctrlmsg));
00181     if ( bytes_read == sizeof(ctrlmsg) ) {
00182       if ( (strncmp(ctrlmsg.header, SPL_GAMECONTROL_HEADER, GCHS) == 0) &&
00183            (ctrlmsg.version == SPL_STRUCT_VERSION) ) {
00184         process_struct(&ctrlmsg);
00185       }
00186     }
00187   } catch (fawkes::Exception &e) {
00188     if ( e.errno() != EAGAIN ) {
00189       __logger->log_warn("SplRefBoxProcessor", "Receiving failed, exception follows");
00190       __logger->log_warn("SplRefBoxProcessor", e);
00191     } // else just no data available this time
00192   }
00193 }
00194
00195 bool
00196 SplRefBoxProcessor::check_connection()
00197 {
00198   return true;
00199 }
00200
00201 
00202 /** Run.
00203  * Reads messages from the network, processes them and calls the refbox state sender.
00204  */
00205 void
00206 SplRefBoxProcessor::run()
00207 {
00208   spl_gamecontrol_t ctrlmsg;
00209   while ( ! __quit ) {
00210     size_t bytes_read = __s->recv((void *)&ctrlmsg, sizeof(ctrlmsg));
00211     if ( bytes_read == sizeof(ctrlmsg) ) {
00212       if ( (strncmp(ctrlmsg.header, SPL_GAMECONTROL_HEADER, GCHS) == 0) &&
00213            (ctrlmsg.version == SPL_STRUCT_VERSION) ) {
00214         process_struct(&ctrlmsg);
00215         _rsh->handle_refbox_state();
00216       } else {
00217         printf("Received illegal package\n");
00218       }
00219     }
00220   }
00221 }