Host ACKs the join request.

This commit is contained in:
Derek Jamison 2023-03-06 12:40:58 -05:00
parent 74f931e1f6
commit c683a15a5f
3 changed files with 74 additions and 22 deletions

View File

@ -17,22 +17,22 @@ Completed work:
- Show games found & let user pick the game to join. - Show games found & let user pick the game to join.
- Config - Allow changing game number. - Config - Allow changing game number.
- Config - Allow changing frequency. - Config - Allow changing frequency.
- Receiving a Join game does an ACK (to cause game on joiner to start).
Remaining work (for subghz version): Remaining work (for subghz version):
- Receiving a Join game should do an ACK (to cause game on joiner to start). - Log game results & contact info onto SD card.
- Log joined game into SD card. - Config - Allow changing hard-coded CONTACT_INFO message.
- Log game results into SD card.
- Allow viewing past games/scores. - Allow viewing past games/scores.
- Config - Allow changing message on join. - A join ACK removes it from the list of available games.
- Refactor the code, so it has less duplication. - Refactor the code, so it has less duplication.
- Write tutorial. - Write tutorial.
- Add game ending animations. - Add game ending animations.
Future ideas: Future ideas:
- Uses Princeton signals for second player.
- Create stand-alone hardware badges that can play the game too. - Create stand-alone hardware badges that can play the game too.
- Uses Princeton signals for second player.
- Instead of subghz, use IR. - Instead of subghz, use IR.
- Instead of subghz, use GPIO. - Instead of subghz, use GPIO.

View File

@ -231,6 +231,21 @@ static void rps_receive_data(GameContext* game_context, uint32_t tick) {
} }
break; break;
case GameRfPurposeJoinAcknowledge:
if(sscanf(
(const char*)message + game_name_len + 2,
"%03u :%8s",
&game_number,
sender_name) == 2) {
FURI_LOG_T(TAG, "Join acknowledge for game %d.", game_number);
GameEvent event = {
.type = GameEventRemoteJoinAcknowledged, .game_number = game_number};
furi_message_queue_put(game_context->queue, &event, FuriWaitForever);
} else {
FURI_LOG_W(TAG, "Failed to parse join acknowledge message. >%s<", message);
}
break;
default: default:
if(version <= MAJOR_VERSION) { if(version <= MAJOR_VERSION) {
// The version is same or less than ours, so we should know about the message purpose. // The version is same or less than ours, so we should know about the message purpose.
@ -705,12 +720,12 @@ static void rps_broadcast_beacon(GameContext* game_context) {
rps_broadcast(game_context, data->buffer); rps_broadcast(game_context, data->buffer);
} }
// Temporary - the KeyLeft button handler invokes this method. // Send message that indicates Flipper is joining a specific game.
// We broadcast - "RPS:" + join"J" + version"A" + game"###" + "NYourNameHere" + " :" + "YourFlip" + "\r\n" // We broadcast - "RPS:" + join"J" + version"A" + game"###" + "NYourNameHere" + " :" + "YourFlip" + "\r\n"
// @param game_context pointer to a GameContext. // @param game_context pointer to a GameContext.
// @param gameNumber the game to join (from previous beacon). static void rps_broadcast_join(GameContext* game_context) {
static void rps_broadcast_join(GameContext* game_context, unsigned int gameNumber) {
GameData* data = game_context->data; GameData* data = game_context->data;
unsigned int gameNumber = data->game_number;
FURI_LOG_I(TAG, "Joining game %d.", gameNumber); FURI_LOG_I(TAG, "Joining game %d.", gameNumber);
// The message for game 42 should look like... "RPS:JA042NYourNameHere :YourFlip\r\n" // The message for game 42 should look like... "RPS:JA042NYourNameHere :YourFlip\r\n"
@ -726,6 +741,26 @@ static void rps_broadcast_join(GameContext* game_context, unsigned int gameNumbe
rps_broadcast(game_context, data->buffer); rps_broadcast(game_context, data->buffer);
} }
// Send message that acknowledges Flipper joining a specific game.
// We broadcast - "RPS:" + joinAck"A" + version"A" + game"###" + " :" + "YourFlip" + "\r\n"
// @param game_context pointer to a GameContext.
static void rps_broadcast_join_acknowledge(GameContext* game_context) {
GameData* data = game_context->data;
unsigned int gameNumber = data->game_number;
FURI_LOG_I(TAG, "Acknowledge joining game %d.", gameNumber);
// The message for game 42 should look like... "RPS:AA042 :YourFlip\r\n"
furi_string_printf(
data->buffer,
"%s%c%c%03u :%s\r\n",
RPS_GAME_NAME,
GameRfPurposeJoinAcknowledge,
MAJOR_VERSION,
data->game_number,
furi_hal_version_get_name_ptr());
rps_broadcast(game_context, data->buffer);
}
// Calculates the elapsed duration (in ticks) since a previous tick. // Calculates the elapsed duration (in ticks) since a previous tick.
// @param tick previous tick obtained from furi_get_tick(). // @param tick previous tick obtained from furi_get_tick().
static uint32_t duration(uint32_t tick) { static uint32_t duration(uint32_t tick) {
@ -1274,7 +1309,6 @@ int32_t rock_paper_scissors_app(void* p) {
} else if( } else if(
game_context->data->screen_state == ScreenJoinGame && game_context->data->screen_state == ScreenJoinGame &&
event.input.type == InputTypeShort) { event.input.type == InputTypeShort) {
unsigned int joinGameNumber;
GameInfo* game; GameInfo* game;
GameEvent newEvent = { GameEvent newEvent = {
.type = GameEventLocalMove, .tick = furi_get_tick(), .move = MoveUnknown}; .type = GameEventLocalMove, .tick = furi_get_tick(), .move = MoveUnknown};
@ -1298,20 +1332,11 @@ int32_t rock_paper_scissors_app(void* p) {
if(update_frequency(game_context) && game) { if(update_frequency(game_context) && game) {
// We send "Join" when OK button clicked. // We send "Join" when OK button clicked.
joinGameNumber = game->game_number; game_context->data->game_number = game->game_number;
if(furi_mutex_acquire(game_context->mutex, FuriWaitForever) == if(furi_mutex_acquire(game_context->mutex, FuriWaitForever) ==
FuriStatusOk) { FuriStatusOk) {
game_context->data->local_player = StateHostingLookingForPlayer; game_context->data->local_player = StateHostingLookingForPlayer;
rps_broadcast_join(game_context, joinGameNumber); rps_broadcast_join(game_context);
// TODO: This is a hack to get the game started. It would
// be better to wait for the remote player to accept our join.
game_context->data->remote_player = StateReady;
game_context->data->remote_move_tick = furi_get_tick();
game_context->data->local_player = StateReady;
game_context->data->local_move_tick = furi_get_tick();
game_context->data->screen_state = ScreenPlayingGame;
furi_mutex_release(game_context->mutex); furi_mutex_release(game_context->mutex);
} else { } else {
FURI_LOG_E(TAG, "Failed to aquire mutex."); FURI_LOG_E(TAG, "Failed to aquire mutex.");
@ -1493,6 +1518,7 @@ int32_t rock_paper_scissors_app(void* p) {
if(furi_mutex_acquire(game_context->mutex, FuriWaitForever) == FuriStatusOk) { if(furi_mutex_acquire(game_context->mutex, FuriWaitForever) == FuriStatusOk) {
if(event.game_number == game_context->data->game_number) { if(event.game_number == game_context->data->game_number) {
rps_state_machine_remote_joined(game_context); rps_state_machine_remote_joined(game_context);
rps_broadcast_join_acknowledge(game_context);
} else { } else {
FURI_LOG_T( FURI_LOG_T(
TAG, TAG,
@ -1504,6 +1530,26 @@ int32_t rock_paper_scissors_app(void* p) {
FURI_LOG_E(TAG, "Failed to aquire mutex."); FURI_LOG_E(TAG, "Failed to aquire mutex.");
} }
break; break;
case GameEventRemoteJoinAcknowledged:
if(furi_mutex_acquire(game_context->mutex, FuriWaitForever) == FuriStatusOk) {
if(event.game_number == game_context->data->game_number) {
FURI_LOG_I(TAG, "Remote join acknowledged.");
game_context->data->remote_player = StateReady;
game_context->data->remote_move_tick = furi_get_tick();
game_context->data->local_player = StateReady;
game_context->data->local_move_tick = furi_get_tick();
game_context->data->screen_state = ScreenPlayingGame;
} else {
FURI_LOG_T(
TAG,
"Remote join acknowledge another Flipper on game %03u.",
event.game_number);
}
furi_mutex_release(game_context->mutex);
} else {
FURI_LOG_E(TAG, "Failed to aquire mutex.");
}
break;
case GameEventLocalMove: case GameEventLocalMove:
if(furi_mutex_acquire(game_context->mutex, FuriWaitForever) == FuriStatusOk) { if(furi_mutex_acquire(game_context->mutex, FuriWaitForever) == FuriStatusOk) {
rps_state_machine_local_moved(game_context, event.move); rps_state_machine_local_moved(game_context, event.move);

View File

@ -154,6 +154,7 @@ typedef enum {
typedef enum { typedef enum {
GameRfPurposeBeacon = 'B', // Beacon. GameRfPurposeBeacon = 'B', // Beacon.
GameRfPurposeJoin = 'J', // Join a game. GameRfPurposeJoin = 'J', // Join a game.
GameRfPurposeJoinAcknowledge = 'A', // Acknowledge a join request.
GameRfPurposeMove = 'M', // Player move. GameRfPurposeMove = 'M', // Player move.
} GameRfPurpose; } GameRfPurpose;
@ -164,6 +165,7 @@ typedef enum {
GameEventDataDetected, GameEventDataDetected,
GameEventRemoteBeacon, GameEventRemoteBeacon,
GameEventRemoteJoined, GameEventRemoteJoined,
GameEventRemoteJoinAcknowledged,
GameEventLocalMove, GameEventLocalMove,
GameEventRemoteMove, GameEventRemoteMove,
GameEventSendMove, GameEventSendMove,
@ -324,8 +326,12 @@ static void rps_broadcast_beacon(GameContext* game_context);
// Temporary - the KeyLeft button handler invokes this method. // Temporary - the KeyLeft button handler invokes this method.
// We broadcast - "RPS:" + join"J" + version"A" + game"###" + "NYourNameHere" + " :" + "YourFlip" + "\r\n" // We broadcast - "RPS:" + join"J" + version"A" + game"###" + "NYourNameHere" + " :" + "YourFlip" + "\r\n"
// @param game_context pointer to a GameContext. // @param game_context pointer to a GameContext.
// @param gameNumber the game to join (from previous beacon). static void rps_broadcast_join(GameContext* game_context);
static void rps_broadcast_join(GameContext* game_context, unsigned int gameNumber);
// Send message that acknowledges Flipper joining a specific game.
// We broadcast - "RPS:" + joinAck"A" + version"A" + game"###" + " :" + "YourFlip" + "\r\n"
// @param game_context pointer to a GameContext.
static void rps_broadcast_join_acknowledge(GameContext* game_context);
// Calculates the elapsed duration (in ticks) since a previous tick. // Calculates the elapsed duration (in ticks) since a previous tick.
// @param tick previous tick obtained from furi_get_tick(). // @param tick previous tick obtained from furi_get_tick().