Fawkes API Fawkes Development Version
spl.cpp
1
2/***************************************************************************
3 * spl.cpp - Fawkes SPL refbox repeater
4 *
5 * Created: Tue Jul 08 13:50:06 2008
6 * Copyright 2008 Tim Niemueller [www.niemueller.de]
7 * 2009 Tobias Kellner
8 *
9 ****************************************************************************/
10
11/* This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Library General Public License for more details.
20 *
21 * Read the full text in the LICENSE.GPL file in the doc directory.
22 */
23
24#include "spl.h"
25
26#include "state_handler.h"
27
28#include <core/exception.h>
29#include <logging/logger.h>
30#include <netcomm/socket/datagram.h>
31
32#ifdef USE_SPL_GC6
33# include <interfaces/SoccerPenaltyInterface.h>
34#endif
35
36#include <cerrno>
37#include <cstdio>
38#include <cstring>
39#include <unistd.h>
40// it it was defined, Exception::errno() could not be called...
41#ifdef errno
42# undef errno
43#endif
44using namespace fawkes;
45
46#ifdef USE_SPL_GC6
47static const uint32_t SPL_STRUCT_VERSION = 6;
48#else
49static const uint32_t SPL_STRUCT_VERSION = 7;
50#endif
51
52static const uint8_t SPL_STATE_INITIAL = 0;
53static const uint8_t SPL_STATE_READY = 1;
54static const uint8_t SPL_STATE_SET = 2;
55static const uint8_t SPL_STATE_PLAYING = 3;
56static const uint8_t SPL_STATE_FINISHED = 4;
57
58/*
59static const uint8_t SPL_STATE2_NORMAL = 0;
60static const uint8_t SPL_STATE2_PENALTYSHOOT = 1;
61*/
62
63static const uint8_t SPL_PENALTY_NONE = 0;
64#ifdef USE_SPL_GC6
65static const uint8_t SPL_PENALTY_BALL_HOLDING = 1;
66static const uint8_t SPL_PENALTY_GOALIE_PUSHING = 2;
67static const uint8_t SPL_PENALTY_PLAYER_PUSHING = 3;
68static const uint8_t SPL_PENALTY_ILLEGAL_DEFENDER = 4;
69static const uint8_t SPL_PENALTY_ILLEGAL_DEFENSE = 5;
70static const uint8_t SPL_PENALTY_OBSTRUCTION = 6;
71static const uint8_t SPL_PENALTY_REQ_FOR_PICKUP = 7;
72static const uint8_t SPL_PENALTY_LEAVING = 8;
73static const uint8_t SPL_PENALTY_DAMAGE = 9;
74static const uint8_t SPL_PENALTY_MANUAL = 10;
75#else
76/*
77static const uint8_t SPL_PENALTY_BALL_HOLDING = 1;
78static const uint8_t SPL_PENALTY_PLAYER_PUSHING = 2;
79static const uint8_t SPL_PENALTY_OBSTRUCTION = 3;
80static const uint8_t SPL_PENALTY_INACTIVE_PLAYER = 4;
81static const uint8_t SPL_PENALTY_ILLEGAL_DEFENDER = 5;
82static const uint8_t SPL_PENALTY_LEAVING_THE_FIELD = 6;
83static const uint8_t SPL_PENALTY_PLAYING_WITH_HANDS = 7;
84static const uint8_t SPL_PENALTY_REQ_FOR_PICKUP = 8;
85static const uint8_t SPL_PENALTY_MANUAL = 15;
86*/
87#endif
88
89// team numbers
90static const uint8_t SPL_TEAM_BLUE = 0;
91static const uint8_t SPL_TEAM_RED = 1;
92
93/*
94static const uint8_t SPL_GOAL_BLUE = 0;
95static const uint8_t SPL_GOAL_YELLOW = 1;
96*/
97
98static const char SPL_GAMECONTROL_HEADER[SPL_HEADER_SIZE] = {'R', 'G', 'm', 'e'};
99
100/** @class SplRefBoxProcessor "processor/spl.h"
101 * SPL league refbox repeater.
102 * This class will listen to SPL refbox commands and derive matching
103 * game states from the communication stream and send this via the world info.
104 * @author Tim Niemueller
105 */
106
107/** Constructor.
108 * @param logger Logger
109 * @param broadcast_port Broadcast port
110 * @param team_number our team number
111 * @param player_number individual player number
112 */
114 unsigned short int broadcast_port,
115 unsigned int team_number,
116 unsigned int player_number)
117{
118 player_number_ = player_number;
119 team_number_ = team_number;
120 logger_ = logger;
121 quit_ = false;
122 s_.reset(new DatagramSocket(Socket::IPv4, 0.0000000001));
123 s_->bind(broadcast_port);
124
125 penalty_ = SPL_PENALTY_NONE;
126}
127
128/** Destructor. */
130{
131 s_->close();
132 s_.reset();
133}
134
135/** Process received struct. */
136void
137SplRefBoxProcessor::process_struct(spl_gamecontrol_t *msg)
138{
140 //fawkes::worldinfo_gamestate_goalcolor_t our_goal;
141
142 int team_index;
143 if (msg->teams[0].team_number == team_number_)
144 team_index = 0;
145 else if (msg->teams[1].team_number == team_number_)
146 team_index = 1;
147 else
148 return; //Message doesn't concern us
149
150 switch (msg->teams[team_index].team_color) {
151 case SPL_TEAM_BLUE: our_team = TEAM_CYAN; break;
152 case SPL_TEAM_RED: our_team = TEAM_MAGENTA; break;
153 default: printf("Ignoring faulty packet\n"); return;
154 }
155
156 _rsh->set_score(msg->teams[team_index].score, msg->teams[(team_index == 1 ? 0 : 1)].score);
157 _rsh->set_team_goal(our_team,
158 (our_team == TEAM_CYAN ? GOAL_BLUE
159 : GOAL_YELLOW)); //blue team defends blue goal
160
161 for (unsigned int pl_num = 0; pl_num < SPL_MAX_NUM_PLAYERS; ++pl_num) {
162 if ((pl_num + 1) == player_number_) {
163 if ((msg->teams[team_index].players[pl_num].penalty != penalty_)
164 || (msg->teams[team_index].players[pl_num].penalty != PENALTY_NONE)) {
165 penalty_ = msg->teams[team_index].players[pl_num].penalty;
166
167#ifdef USE_SPL_GC6
168 // convert GC6 codes to new GC7 codes, "closest match"
169 switch (penalty_) {
170 case SPL_PENALTY_BALL_HOLDING:
171 penalty_ = SoccerPenaltyInterface::SPL_PENALTY_BALL_HOLDING;
172 break;
173 case SPL_PENALTY_GOALIE_PUSHING:
174 case SPL_PENALTY_PLAYER_PUSHING:
175 penalty_ = SoccerPenaltyInterface::SPL_PENALTY_PLAYER_PUSHING;
176 break;
177 case SPL_PENALTY_ILLEGAL_DEFENDER:
178 case SPL_PENALTY_ILLEGAL_DEFENSE:
179 penalty_ = SoccerPenaltyInterface::SPL_PENALTY_ILLEGAL_DEFENDER;
180 break;
181 case SPL_PENALTY_OBSTRUCTION:
182 penalty_ = SoccerPenaltyInterface::SPL_PENALTY_OBSTRUCTION;
183 break;
184 case SPL_PENALTY_REQ_FOR_PICKUP:
185 penalty_ = SoccerPenaltyInterface::SPL_PENALTY_REQ_FOR_PICKUP;
186 break;
187 case SPL_PENALTY_LEAVING:
188 penalty_ = SoccerPenaltyInterface::SPL_PENALTY_LEAVING_THE_FIELD;
189 break;
190 case SPL_PENALTY_DAMAGE:
191 case SPL_PENALTY_MANUAL: penalty_ = SoccerPenaltyInterface::SPL_PENALTY_MANUAL; break;
192 default: penalty_ = SoccerPenaltyInterface::SPL_PENALTY_NONE; break;
193 }
194#endif
195
196 _rsh->add_penalty(penalty_, msg->teams[team_index].players[pl_num].secs_till_unpenalized);
197 }
198 break;
199 }
200 }
201
202 switch (msg->state) {
203 case SPL_STATE_INITIAL: _rsh->set_gamestate(GS_SPL_INITIAL, TEAM_BOTH); break;
204 case SPL_STATE_READY: _rsh->set_gamestate(GS_SPL_READY, TEAM_BOTH); break;
205 case SPL_STATE_SET: _rsh->set_gamestate(GS_SPL_SET, TEAM_BOTH); break;
206 case SPL_STATE_PLAYING: _rsh->set_gamestate(GS_SPL_PLAY, TEAM_BOTH); break;
207 case SPL_STATE_FINISHED: _rsh->set_gamestate(GS_SPL_FINISHED, TEAM_BOTH); break;
208 default: _rsh->set_gamestate(GS_SPL_FINISHED, TEAM_BOTH); break;
209 }
210
211 _rsh->set_half((msg->first_half == 1) ? HALF_FIRST : HALF_SECOND,
212 msg->kick_off_team == team_index);
213}
214
215void
217{
218 try {
219 spl_gamecontrol_t ctrlmsg;
220 size_t bytes_read = s_->recv((void *)&ctrlmsg, sizeof(ctrlmsg));
221 if (bytes_read == sizeof(ctrlmsg)) {
222 if ((strncmp(ctrlmsg.header, SPL_GAMECONTROL_HEADER, SPL_HEADER_SIZE) == 0)
223 && (ctrlmsg.version == SPL_STRUCT_VERSION)) {
224 process_struct(&ctrlmsg);
225 }
226 }
227 } catch (fawkes::Exception &e) {
228 if (e.get_errno() != EAGAIN) {
229 logger_->log_warn("SplRefBoxProcessor", "Receiving failed, exception follows");
230 logger_->log_warn("SplRefBoxProcessor", e);
231 } // else just no data available this time
232 }
233}
234
235bool
237{
238 return true;
239}
240
241/** Run.
242 * Reads messages from the network, processes them and calls the refbox state sender.
243 */
244void
246{
247 spl_gamecontrol_t ctrlmsg;
248 while (!quit_) {
249 size_t bytes_read = s_->recv((void *)&ctrlmsg, sizeof(ctrlmsg));
250 if (bytes_read == sizeof(ctrlmsg)) {
251 if ((strncmp(ctrlmsg.header, SPL_GAMECONTROL_HEADER, SPL_HEADER_SIZE) == 0)
252 && (ctrlmsg.version == SPL_STRUCT_VERSION)) {
253 process_struct(&ctrlmsg);
255 } else {
256 printf("Received illegal package\n");
257 }
258 }
259 }
260}
RefBoxStateHandler * _rsh
Refbox state handler, set via set_handler()
Definition: processor.h:40
virtual void set_gamestate(int game_state, fawkes::worldinfo_gamestate_team_t state_team)=0
Set current game state.
virtual void add_penalty(unsigned int penalty, unsigned int seconds_remaining)=0
Add penalty.
virtual void handle_refbox_state()=0
Process the information set up to now.
virtual void set_team_goal(fawkes::worldinfo_gamestate_team_t our_team, fawkes::worldinfo_gamestate_goalcolor_t goal_color)=0
Set team and goal info.
virtual void set_score(unsigned int score_cyan, unsigned int score_magenta)=0
Set score.
virtual void set_half(fawkes::worldinfo_gamestate_half_t half, bool kickoff=false)=0
Set current half of the game time.
~SplRefBoxProcessor()
Destructor.
Definition: spl.cpp:129
bool check_connection()
Check if the connection is alive and reconnect.
Definition: spl.cpp:236
void refbox_process()
Process incoming refbox communication.
Definition: spl.cpp:216
void run()
Run.
Definition: spl.cpp:245
SplRefBoxProcessor(fawkes::Logger *logger, unsigned short int broadcast_port, unsigned int team_number, unsigned int player_number)
Constructor.
Definition: spl.cpp:113
Datagram socket.
Definition: datagram.h:32
Base class for exceptions in Fawkes.
Definition: exception.h:36
int get_errno() noexcept
Get errno.
Definition: exception.cpp:622
Interface for logging.
Definition: logger.h:42
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
Fawkes library namespace.
worldinfo_gamestate_team_t
Team.
Definition: enums.h:53
@ TEAM_MAGENTA
Magenta team.
Definition: enums.h:56
@ TEAM_CYAN
Cyan team.
Definition: enums.h:55
SPL RefBox protocol game control struct.
Definition: spl.h:67
uint8_t first_half
1 = game in first half, 0 otherwise
Definition: spl.h:72
uint32_t version
version of the data structure
Definition: spl.h:69
spl_teaminfo_t teams[2]
Info about the teams.
Definition: spl.h:80
char header[SPL_HEADER_SIZE]
header to identify the structure
Definition: spl.h:68
uint8_t state
state of the game (STATE_READY, STATE_PLAYING, etc.)
Definition: spl.h:71
uint8_t kick_off_team
the next team to kick off
Definition: spl.h:73
uint16_t secs_till_unpenalized
estimate of time till unpenalised
Definition: spl.h:48
uint16_t penalty
penalty state of the player
Definition: spl.h:47
uint8_t team_color
colour of the team
Definition: spl.h:55
uint8_t score
team's score
Definition: spl.h:60
spl_robotinfo_t players[SPL_MAX_NUM_PLAYERS]
the team's players
Definition: spl.h:62
uint8_t team_number
unique team number
Definition: spl.h:54