From e1d90b024504eb11916a117354b10166b172431d Mon Sep 17 00:00:00 2001 From: RocketGod <57732082+RocketGod-git@users.noreply.github.com> Date: Thu, 22 Aug 2024 12:31:03 -0700 Subject: [PATCH] Fixed some stuff. Added tons of logging for cli log, but ir still crashes. --- .gitignore | 1 + docs/README.md | 4 +- game_state.c | 36 +++++++--- game_state.h | 6 +- infrared_controller.c | 146 +++++++++++++++++++++++++++++++------- infrared_controller.h | 33 +-------- laser_tag_app.c | 160 +++++++++++++++++++++++++++++++++++------- laser_tag_app.h | 11 +-- laser_tag_icons.c | 147 +++++++++++++++++++++++++------------- laser_tag_icons.h | 9 +-- laser_tag_view.c | 50 ++++++++++--- laser_tag_view.h | 9 +-- 12 files changed, 439 insertions(+), 173 deletions(-) diff --git a/.gitignore b/.gitignore index 81a8981f739..dd6a4750db6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ dist/* .vscode .clang-format +.clangd .editorconfig .env .ufbt diff --git a/docs/README.md b/docs/README.md index 2fb6d451b8d..fd239c8f37e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,3 +1,3 @@ -# Flipper Zero - Laser Tag +# Flipper Zero - Development Toolkit -Not working, yet. +Short description. diff --git a/game_state.c b/game_state.c index c492f94ce39..40eabecfd37 100644 --- a/game_state.c +++ b/game_state.c @@ -1,5 +1,7 @@ + #include "game_state.h" #include +#include struct GameState { LaserTagTeam team; @@ -12,36 +14,39 @@ struct GameState { GameState* game_state_alloc() { GameState* state = malloc(sizeof(GameState)); + if(!state) { + return NULL; + } state->team = TeamRed; - state->health = 100; + state->health = INITIAL_HEALTH; state->score = 0; - state->ammo = 100; + state->ammo = INITIAL_AMMO; state->game_time = 0; state->game_over = false; return state; } -void game_state_free(GameState* state) { - free(state); -} - void game_state_reset(GameState* state) { - state->health = 100; + furi_assert(state); + state->health = INITIAL_HEALTH; state->score = 0; - state->ammo = 100; + state->ammo = INITIAL_AMMO; state->game_time = 0; state->game_over = false; } void game_state_set_team(GameState* state, LaserTagTeam team) { + furi_assert(state); state->team = team; } LaserTagTeam game_state_get_team(GameState* state) { + furi_assert(state); return state->team; } void game_state_decrease_health(GameState* state, uint8_t amount) { + furi_assert(state); if(state->health > amount) { state->health -= amount; } else { @@ -51,22 +56,27 @@ void game_state_decrease_health(GameState* state, uint8_t amount) { } void game_state_increase_health(GameState* state, uint8_t amount) { - state->health = (state->health + amount > 100) ? 100 : state->health + amount; + furi_assert(state); + state->health = (state->health + amount > MAX_HEALTH) ? MAX_HEALTH : state->health + amount; } uint8_t game_state_get_health(GameState* state) { + furi_assert(state); return state->health; } void game_state_increase_score(GameState* state, uint16_t points) { + furi_assert(state); state->score += points; } uint16_t game_state_get_score(GameState* state) { + furi_assert(state); return state->score; } void game_state_decrease_ammo(GameState* state, uint16_t amount) { + furi_assert(state); if(state->ammo > amount) { state->ammo -= amount; } else { @@ -75,25 +85,31 @@ void game_state_decrease_ammo(GameState* state, uint16_t amount) { } void game_state_increase_ammo(GameState* state, uint16_t amount) { + furi_assert(state); state->ammo += amount; } uint16_t game_state_get_ammo(GameState* state) { + furi_assert(state); return state->ammo; } void game_state_update_time(GameState* state, uint32_t delta_time) { + furi_assert(state); state->game_time += delta_time; } uint32_t game_state_get_time(GameState* state) { + furi_assert(state); return state->game_time; } bool game_state_is_game_over(GameState* state) { + furi_assert(state); return state->game_over; } void game_state_set_game_over(GameState* state, bool game_over) { + furi_assert(state); state->game_over = game_over; -} \ No newline at end of file +} diff --git a/game_state.h b/game_state.h index c1c5f52e319..006cbdbd732 100644 --- a/game_state.h +++ b/game_state.h @@ -1,3 +1,4 @@ + #pragma once #include @@ -16,7 +17,6 @@ typedef enum { typedef struct GameState GameState; GameState* game_state_alloc(); -void game_state_free(GameState* state); void game_state_reset(GameState* state); void game_state_set_team(GameState* state, LaserTagTeam team); @@ -40,5 +40,5 @@ bool game_state_is_game_over(GameState* state); void game_state_set_game_over(GameState* state, bool game_over); #define INITIAL_HEALTH 100 -#define INITIAL_AMMO 100 -#define MAX_HEALTH 100 \ No newline at end of file +#define INITIAL_AMMO 100 +#define MAX_HEALTH 100 diff --git a/infrared_controller.c b/infrared_controller.c index 6c32dd38119..b5c3f278f6d 100644 --- a/infrared_controller.c +++ b/infrared_controller.c @@ -5,10 +5,7 @@ #include #include -#define TAG "LaserTagInfrared" - -#define IR_COMMAND_RED_TEAM 0xA1 -#define IR_COMMAND_BLUE_TEAM 0xB2 +#define TAG "InfraredController" struct InfraredController { LaserTagTeam team; @@ -16,97 +13,196 @@ struct InfraredController { FuriThread* rx_thread; volatile bool rx_running; volatile bool hit_received; + FuriMutex* mutex; }; static void infrared_rx_callback(void* context, InfraredWorkerSignal* received_signal) { + FURI_LOG_D(TAG, "RX callback triggered"); + furi_assert(context); + furi_assert(received_signal); + InfraredController* controller = (InfraredController*)context; - + furi_mutex_acquire(controller->mutex, FuriWaitForever); + + FURI_LOG_D(TAG, "Context and received signal validated"); + const InfraredMessage* message = infrared_worker_get_decoded_signal(received_signal); - if (message != NULL) { + if(message != NULL) { uint32_t received_command = message->address; + FURI_LOG_D(TAG, "Received command: 0x%lx", (unsigned long)received_command); + if((controller->team == TeamRed && received_command == IR_COMMAND_BLUE_TEAM) || (controller->team == TeamBlue && received_command == IR_COMMAND_RED_TEAM)) { controller->hit_received = true; + FURI_LOG_D( + TAG, "Hit detected for team: %s", controller->team == TeamRed ? "Red" : "Blue"); } + } else { + FURI_LOG_E(TAG, "Received NULL message"); } + + furi_mutex_release(controller->mutex); } static int32_t infrared_rx_thread(void* context) { + FURI_LOG_D(TAG, "RX thread started"); + furi_assert(context); + InfraredController* controller = (InfraredController*)context; - + while(controller->rx_running) { - infrared_worker_rx_start(controller->worker); - furi_thread_flags_wait(0, FuriFlagWaitAny, 10); + furi_mutex_acquire(controller->mutex, FuriWaitForever); + FURI_LOG_D(TAG, "Starting infrared_worker_rx_start"); + + // Check for worker validity before starting + if(controller->worker) { + infrared_worker_rx_start(controller->worker); + FURI_LOG_D(TAG, "infrared_worker_rx_start succeeded"); + } else { + FURI_LOG_E(TAG, "InfraredWorker is NULL"); + furi_mutex_release(controller->mutex); + continue; + } + + furi_mutex_release(controller->mutex); + + FURI_LOG_D(TAG, "Waiting for thread flags"); + FuriStatus status = furi_thread_flags_wait(0, FuriFlagWaitAny, 10); + + if(status == FuriStatusErrorTimeout) { + FURI_LOG_D(TAG, "RX loop timeout, continuing"); + } else { + FURI_LOG_D(TAG, "RX loop received flag: %d", status); + } } + FURI_LOG_D(TAG, "RX thread stopping"); return 0; } InfraredController* infrared_controller_alloc() { + FURI_LOG_D(TAG, "Allocating InfraredController"); + InfraredController* controller = malloc(sizeof(InfraredController)); + if(!controller) { + FURI_LOG_E(TAG, "Failed to allocate InfraredController struct"); + return NULL; + } + FURI_LOG_D(TAG, "InfraredController struct allocated"); + controller->team = TeamRed; + FURI_LOG_D(TAG, "Team initialized to Red"); + + FURI_LOG_D(TAG, "Allocating InfraredWorker"); controller->worker = infrared_worker_alloc(); + if(!controller->worker) { + FURI_LOG_E(TAG, "Failed to allocate InfraredWorker"); + free(controller); + return NULL; + } + FURI_LOG_D(TAG, "InfraredWorker allocated"); + controller->rx_running = true; controller->hit_received = false; - infrared_worker_rx_set_received_signal_callback(controller->worker, infrared_rx_callback, controller); + FURI_LOG_D(TAG, "Creating mutex"); + controller->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + if(!controller->mutex) { + FURI_LOG_E(TAG, "Failed to create mutex"); + infrared_worker_free(controller->worker); + free(controller); + return NULL; + } + FURI_LOG_D(TAG, "Setting up RX callback"); + infrared_worker_rx_set_received_signal_callback( + controller->worker, infrared_rx_callback, controller); + + FURI_LOG_D(TAG, "Allocating RX thread"); controller->rx_thread = furi_thread_alloc(); + if(!controller->rx_thread) { + FURI_LOG_E(TAG, "Failed to allocate RX thread"); + furi_mutex_free(controller->mutex); + infrared_worker_free(controller->worker); + free(controller); + return NULL; + } + furi_thread_set_name(controller->rx_thread, "IR_Rx_Thread"); furi_thread_set_stack_size(controller->rx_thread, 1024); furi_thread_set_context(controller->rx_thread, controller); furi_thread_set_callback(controller->rx_thread, infrared_rx_thread); + + FURI_LOG_D(TAG, "Starting RX thread"); furi_thread_start(controller->rx_thread); + FURI_LOG_D(TAG, "Starting InfraredWorker RX"); infrared_worker_rx_start(controller->worker); + FURI_LOG_D(TAG, "InfraredController allocated successfully"); return controller; } void infrared_controller_free(InfraredController* controller) { + FURI_LOG_D(TAG, "Freeing InfraredController"); furi_assert(controller); controller->rx_running = false; + FURI_LOG_D(TAG, "Stopping RX thread"); furi_thread_join(controller->rx_thread); furi_thread_free(controller->rx_thread); + FURI_LOG_D(TAG, "Stopping InfraredWorker RX"); + furi_mutex_acquire(controller->mutex, FuriWaitForever); infrared_worker_rx_stop(controller->worker); infrared_worker_free(controller->worker); + furi_mutex_release(controller->mutex); + + furi_mutex_free(controller->mutex); free(controller); + FURI_LOG_D(TAG, "InfraredController freed"); } void infrared_controller_set_team(InfraredController* controller, LaserTagTeam team) { furi_assert(controller); + furi_mutex_acquire(controller->mutex, FuriWaitForever); controller->team = team; + furi_mutex_release(controller->mutex); + FURI_LOG_D(TAG, "Team set to %s", (team == TeamRed) ? "Red" : "Blue"); } void infrared_controller_send(InfraredController* controller) { + FURI_LOG_D(TAG, "Sending IR signal"); furi_assert(controller); + + furi_mutex_acquire(controller->mutex, FuriWaitForever); + uint32_t command = (controller->team == TeamRed) ? IR_COMMAND_RED_TEAM : IR_COMMAND_BLUE_TEAM; InfraredMessage message = { - .protocol = InfraredProtocolNEC, - .address = 0x00, - .command = command, - .repeat = false - }; - + .protocol = InfraredProtocolNEC, .address = 0x00, .command = command, .repeat = false}; + infrared_worker_set_decoded_signal(controller->worker, &message); - + + FURI_LOG_D(TAG, "Starting IR transmission"); infrared_worker_tx_set_get_signal_callback( - controller->worker, - infrared_worker_tx_get_signal_steady_callback, - NULL); - + controller->worker, infrared_worker_tx_get_signal_steady_callback, NULL); + infrared_worker_tx_start(controller->worker); - - furi_delay_ms(250); // Delay to ensure the signal is sent - + + furi_delay_ms(250); + infrared_worker_tx_stop(controller->worker); + FURI_LOG_D(TAG, "IR signal sent"); + + furi_mutex_release(controller->mutex); } bool infrared_controller_receive(InfraredController* controller) { furi_assert(controller); + furi_mutex_acquire(controller->mutex, FuriWaitForever); bool hit = controller->hit_received; controller->hit_received = false; + furi_mutex_release(controller->mutex); + FURI_LOG_D(TAG, "Checking for hit: %s", hit ? "Hit received" : "No hit"); return hit; -} \ No newline at end of file +} diff --git a/infrared_controller.h b/infrared_controller.h index 391e26ee12a..18f3bfa67c7 100644 --- a/infrared_controller.h +++ b/infrared_controller.h @@ -1,42 +1,15 @@ #pragma once #include -#include "game_state.h" // For LaserTagTeam enum +#include "game_state.h" typedef struct InfraredController InfraredController; -/** - * Allocate and initialize an InfraredController. - * @return Pointer to the newly allocated InfraredController. - */ InfraredController* infrared_controller_alloc(); - -/** - * Free an InfraredController and its resources. - * @param controller Pointer to the InfraredController to free. - */ void infrared_controller_free(InfraredController* controller); - -/** - * Set the team for the InfraredController. - * @param controller Pointer to the InfraredController. - * @param team The team to set (TeamRed or TeamBlue). - */ void infrared_controller_set_team(InfraredController* controller, LaserTagTeam team); - -/** - * Send an infrared signal corresponding to the controller's team. - * @param controller Pointer to the InfraredController. - */ void infrared_controller_send(InfraredController* controller); - -/** - * Check if a hit has been received from the opposite team. - * @param controller Pointer to the InfraredController. - * @return true if a hit was received, false otherwise. - */ bool infrared_controller_receive(InfraredController* controller); -// IR command definitions -#define IR_COMMAND_RED_TEAM 0xA1 -#define IR_COMMAND_BLUE_TEAM 0xB2 \ No newline at end of file +#define IR_COMMAND_RED_TEAM 0xA1 +#define IR_COMMAND_BLUE_TEAM 0xB2 diff --git a/laser_tag_app.c b/laser_tag_app.c index 099f1a55093..9996bcaface 100644 --- a/laser_tag_app.c +++ b/laser_tag_app.c @@ -4,12 +4,10 @@ #include "game_state.h" #include #include -#include #include #include -#include -#define TAG "LaserTag" +#define TAG "LaserTagApp" struct LaserTagApp { Gui* gui; @@ -21,64 +19,105 @@ struct LaserTagApp { InfraredController* ir_controller; GameState* game_state; LaserTagState state; + bool need_redraw; }; -const NotificationSequence sequence_vibro_1 = { - &message_vibro_on, - &message_vibro_off, - NULL -}; +const NotificationSequence sequence_vibro_1 = {&message_vibro_on, &message_vibro_off, NULL}; static void laser_tag_app_timer_callback(void* context) { furi_assert(context); LaserTagApp* app = context; - game_state_update_time(app->game_state, 1); - laser_tag_view_update(app->view, app->game_state); + FURI_LOG_D(TAG, "Timer callback triggered"); + if(app->game_state) { + game_state_update_time(app->game_state, 1); + FURI_LOG_D(TAG, "Updated game time by 1"); + if(app->view) { + FURI_LOG_D(TAG, "Updating view with the latest game state"); + laser_tag_view_update(app->view, app->game_state); + app->need_redraw = true; + } + } } static void laser_tag_app_input_callback(InputEvent* input_event, void* context) { furi_assert(context); LaserTagApp* app = context; - furi_message_queue_put(app->event_queue, input_event, FuriWaitForever); + FURI_LOG_D( + TAG, "Input callback triggered: type=%d, key=%d", input_event->type, input_event->key); + furi_message_queue_put(app->event_queue, input_event, 0); + FURI_LOG_D(TAG, "Input event queued successfully"); } static void laser_tag_app_draw_callback(Canvas* canvas, void* context) { furi_assert(context); LaserTagApp* app = context; + FURI_LOG_D(TAG, "Entering draw callback"); + if(app->state == LaserTagStateTeamSelect) { + FURI_LOG_D(TAG, "Drawing team selection screen"); canvas_clear(canvas); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 32, 32, "Select Team:"); canvas_set_font(canvas, FontSecondary); canvas_draw_str(canvas, 32, 48, "LEFT: Red RIGHT: Blue"); - } else { + } else if(app->view) { + FURI_LOG_D(TAG, "Drawing game view"); laser_tag_view_draw(laser_tag_view_get_view(app->view), canvas); } + FURI_LOG_D(TAG, "Exiting draw callback"); } LaserTagApp* laser_tag_app_alloc() { + FURI_LOG_D(TAG, "Allocating Laser Tag App"); LaserTagApp* app = malloc(sizeof(LaserTagApp)); + if(!app) { + FURI_LOG_E(TAG, "Failed to allocate LaserTagApp"); + return NULL; + } + FURI_LOG_D(TAG, "LaserTagApp struct allocated"); + + memset(app, 0, sizeof(LaserTagApp)); app->gui = furi_record_open(RECORD_GUI); app->view_port = view_port_alloc(); app->view = laser_tag_view_alloc(); - app->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); app->notifications = furi_record_open(RECORD_NOTIFICATION); - app->ir_controller = infrared_controller_alloc(); app->game_state = game_state_alloc(); + app->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); + + if(!app->gui || !app->view_port || !app->view || !app->notifications || !app->game_state || + !app->event_queue) { + FURI_LOG_E(TAG, "Failed to allocate resources"); + laser_tag_app_free(app); + return NULL; + } + app->state = LaserTagStateTeamSelect; + app->need_redraw = true; + FURI_LOG_D(TAG, "Initial state set"); view_port_draw_callback_set(app->view_port, laser_tag_app_draw_callback, app); view_port_input_callback_set(app->view_port, laser_tag_app_input_callback, app); gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); + FURI_LOG_D(TAG, "ViewPort callbacks set and added to GUI"); app->timer = furi_timer_alloc(laser_tag_app_timer_callback, FuriTimerTypePeriodic, app); + if(!app->timer) { + FURI_LOG_E(TAG, "Failed to allocate timer"); + laser_tag_app_free(app); + return NULL; + } + FURI_LOG_D(TAG, "Timer allocated"); + furi_timer_start(app->timer, furi_kernel_get_tick_frequency()); + FURI_LOG_D(TAG, "Timer started"); + FURI_LOG_D(TAG, "Laser Tag App allocated successfully"); return app; } void laser_tag_app_free(LaserTagApp* app) { + FURI_LOG_D(TAG, "Freeing Laser Tag App"); furi_assert(app); furi_timer_free(app->timer); @@ -87,53 +126,107 @@ void laser_tag_app_free(LaserTagApp* app) { view_port_free(app->view_port); laser_tag_view_free(app->view); furi_message_queue_free(app->event_queue); - infrared_controller_free(app->ir_controller); - game_state_free(app->game_state); - + if(app->ir_controller) { + infrared_controller_free(app->ir_controller); + } + free(app->game_state); furi_record_close(RECORD_GUI); furi_record_close(RECORD_NOTIFICATION); free(app); + FURI_LOG_D(TAG, "Laser Tag App freed"); } void laser_tag_app_fire(LaserTagApp* app) { + furi_assert(app); + FURI_LOG_D(TAG, "Firing laser"); + + if(!app->ir_controller) { + FURI_LOG_E(TAG, "IR controller is NULL in laser_tag_app_fire"); + return; + } + + FURI_LOG_D(TAG, "Sending infrared signal"); infrared_controller_send(app->ir_controller); + FURI_LOG_D(TAG, "Decreasing ammo by 1"); game_state_decrease_ammo(app->game_state, 1); + FURI_LOG_D(TAG, "Notifying with blink blue"); notification_message(app->notifications, &sequence_blink_blue_100); + app->need_redraw = true; } void laser_tag_app_handle_hit(LaserTagApp* app) { + furi_assert(app); + FURI_LOG_D(TAG, "Handling hit"); + + FURI_LOG_D(TAG, "Decreasing health by 10"); game_state_decrease_health(app->game_state, 10); + FURI_LOG_D(TAG, "Notifying with vibration"); notification_message(app->notifications, &sequence_vibro_1); + app->need_redraw = true; } -void laser_tag_app_enter_game_state(LaserTagApp* app) { +static bool laser_tag_app_enter_game_state(LaserTagApp* app) { + furi_assert(app); + FURI_LOG_D(TAG, "Entering game state"); + app->state = LaserTagStateGame; + FURI_LOG_D(TAG, "Resetting game state"); game_state_reset(app->game_state); + FURI_LOG_D(TAG, "Updating view with new game state"); laser_tag_view_update(app->view, app->game_state); + + FURI_LOG_D(TAG, "Allocating IR controller"); + app->ir_controller = infrared_controller_alloc(); + if(!app->ir_controller) { + FURI_LOG_E(TAG, "Failed to allocate IR controller"); + return false; + } + FURI_LOG_D(TAG, "IR controller allocated"); + + FURI_LOG_D(TAG, "Setting IR controller team"); + infrared_controller_set_team(app->ir_controller, game_state_get_team(app->game_state)); + app->need_redraw = true; + return true; } int32_t laser_tag_app(void* p) { UNUSED(p); + FURI_LOG_I(TAG, "Laser Tag app starting"); + LaserTagApp* app = laser_tag_app_alloc(); + if(!app) { + FURI_LOG_E(TAG, "Failed to allocate application"); + return -1; + } + FURI_LOG_D(TAG, "LaserTagApp allocated successfully"); + FURI_LOG_D(TAG, "Entering main loop"); InputEvent event; bool running = true; while(running) { + FURI_LOG_D(TAG, "Start of main loop iteration"); + FuriStatus status = furi_message_queue_get(app->event_queue, &event, 100); if(status == FuriStatusOk) { - if(event.type == InputTypePress) { + FURI_LOG_D(TAG, "Received input event: type=%d, key=%d", event.type, event.key); + if(event.type == InputTypePress || event.type == InputTypeRepeat) { + FURI_LOG_D(TAG, "Processing input event"); if(app->state == LaserTagStateTeamSelect) { switch(event.key) { case InputKeyLeft: - infrared_controller_set_team(app->ir_controller, TeamRed); + FURI_LOG_D(TAG, "Selected Red Team"); game_state_set_team(app->game_state, TeamRed); - laser_tag_app_enter_game_state(app); + if(!laser_tag_app_enter_game_state(app)) { + running = false; + } break; case InputKeyRight: - infrared_controller_set_team(app->ir_controller, TeamBlue); + FURI_LOG_D(TAG, "Selected Blue Team"); game_state_set_team(app->game_state, TeamBlue); - laser_tag_app_enter_game_state(app); + if(!laser_tag_app_enter_game_state(app)) { + running = false; + } break; default: break; @@ -141,9 +234,11 @@ int32_t laser_tag_app(void* p) { } else { switch(event.key) { case InputKeyBack: + FURI_LOG_D(TAG, "Exiting game"); running = false; break; case InputKeyOk: + FURI_LOG_D(TAG, "Firing laser"); laser_tag_app_fire(app); break; default: @@ -151,24 +246,37 @@ int32_t laser_tag_app(void* p) { } } } + } else if(status == FuriStatusErrorTimeout) { + FURI_LOG_D(TAG, "No input event, continuing"); + } else { + FURI_LOG_E(TAG, "Failed to get input event, status: %d", status); } - if(app->state == LaserTagStateGame) { + if(app->state == LaserTagStateGame && app->ir_controller) { + FURI_LOG_D(TAG, "Game is active"); if(infrared_controller_receive(app->ir_controller)) { + FURI_LOG_D(TAG, "Hit received"); laser_tag_app_handle_hit(app); } if(game_state_is_game_over(app->game_state)) { + FURI_LOG_D(TAG, "Game over"); notification_message(app->notifications, &sequence_error); running = false; } + } - laser_tag_view_update(app->view, app->game_state); + if(app->need_redraw) { + FURI_LOG_D(TAG, "Updating view port"); + view_port_update(app->view_port); + app->need_redraw = false; } - view_port_update(app->view_port); + FURI_LOG_D(TAG, "End of main loop iteration"); + furi_delay_ms(10); } + FURI_LOG_I(TAG, "Laser Tag app exiting"); laser_tag_app_free(app); return 0; } diff --git a/laser_tag_app.h b/laser_tag_app.h index c932c4ae499..b7891213078 100644 --- a/laser_tag_app.h +++ b/laser_tag_app.h @@ -1,3 +1,4 @@ + #pragma once #include @@ -11,21 +12,15 @@ #include #include -#define FRAME_WIDTH 128 +#define FRAME_WIDTH 128 #define FRAME_HEIGHT 64 typedef struct LaserTagApp LaserTagApp; LaserTagApp* laser_tag_app_alloc(); - void laser_tag_app_free(LaserTagApp* app); - int32_t laser_tag_app(void* p); - void laser_tag_app_set_view_port(LaserTagApp* app, View* view); - void laser_tag_app_switch_to_next_scene(LaserTagApp* app); - void laser_tag_app_fire(LaserTagApp* app); - -void laser_tag_app_handle_hit(LaserTagApp* app); \ No newline at end of file +void laser_tag_app_handle_hit(LaserTagApp* app); diff --git a/laser_tag_icons.c b/laser_tag_icons.c index c6912c71730..2b92995a142 100644 --- a/laser_tag_icons.c +++ b/laser_tag_icons.c @@ -1,70 +1,119 @@ + #include "laser_tag_icons.h" #include const uint8_t laser_gun_icon_data[] = { - 0b00000000, 0b00000000, - 0b00000001, 0b10000000, - 0b00000011, 0b11000000, - 0b00000111, 0b11100000, - 0b00001111, 0b11110000, - 0b00011111, 0b11111000, - 0b11111111, 0b11111110, - 0b11111111, 0b11111111, + 0b00000000, + 0b00000000, + 0b00000001, + 0b10000000, + 0b00000011, + 0b11000000, + 0b00000111, + 0b11100000, + 0b00001111, + 0b11110000, + 0b00011111, + 0b11111000, + 0b11111111, + 0b11111110, + 0b11111111, + 0b11111111, }; const uint8_t health_icon_data[] = { - 0b00001100, 0b00110000, - 0b00011110, 0b01111000, - 0b00111111, 0b11111100, - 0b01111111, 0b11111110, - 0b01111111, 0b11111110, - 0b00111111, 0b11111100, - 0b00011111, 0b11111000, - 0b00000111, 0b11100000, + 0b00001100, + 0b00110000, + 0b00011110, + 0b01111000, + 0b00111111, + 0b11111100, + 0b01111111, + 0b11111110, + 0b01111111, + 0b11111110, + 0b00111111, + 0b11111100, + 0b00011111, + 0b11111000, + 0b00000111, + 0b11100000, }; const uint8_t ammo_icon_data[] = { - 0b00011000, 0b00011000, - 0b00111100, 0b00111100, - 0b01111110, 0b01111110, - 0b11111111, 0b11111111, - 0b11111111, 0b11111111, - 0b01111110, 0b01111110, - 0b00111100, 0b00111100, - 0b00011000, 0b00011000, + 0b00011000, + 0b00011000, + 0b00111100, + 0b00111100, + 0b01111110, + 0b01111110, + 0b11111111, + 0b11111111, + 0b11111111, + 0b11111111, + 0b01111110, + 0b01111110, + 0b00111100, + 0b00111100, + 0b00011000, + 0b00011000, }; const uint8_t team_red_icon_data[] = { - 0b00011000, 0b00011000, - 0b00111100, 0b00111100, - 0b01111110, 0b01111110, - 0b11111111, 0b11111111, - 0b11111111, 0b11111111, - 0b01111110, 0b01111110, - 0b00111100, 0b00111100, - 0b00011000, 0b00011000, + 0b00011000, + 0b00011000, + 0b00111100, + 0b00111100, + 0b01111110, + 0b01111110, + 0b11111111, + 0b11111111, + 0b11111111, + 0b11111111, + 0b01111110, + 0b01111110, + 0b00111100, + 0b00111100, + 0b00011000, + 0b00011000, }; const uint8_t team_blue_icon_data[] = { - 0b11100111, 0b11100111, - 0b11000011, 0b11000011, - 0b10000001, 0b10000001, - 0b00000000, 0b00000000, - 0b00000000, 0b00000000, - 0b10000001, 0b10000001, - 0b11000011, 0b11000011, - 0b11100111, 0b11100111, + 0b11100111, + 0b11100111, + 0b11000011, + 0b11000011, + 0b10000001, + 0b10000001, + 0b00000000, + 0b00000000, + 0b00000000, + 0b00000000, + 0b10000001, + 0b10000001, + 0b11000011, + 0b11000011, + 0b11100111, + 0b11100111, }; const uint8_t game_over_icon_data[] = { - 0b11111111, 0b11111111, - 0b10000000, 0b00000001, - 0b10111101, 0b10111101, - 0b10100001, 0b10100001, - 0b10100001, 0b10100001, - 0b10111101, 0b10111101, - 0b10000000, 0b00000001, - 0b11111111, 0b11111111, + 0b11111111, + 0b11111111, + 0b10000000, + 0b00000001, + 0b10111101, + 0b10111101, + 0b10100001, + 0b10100001, + 0b10100001, + 0b10100001, + 0b10111101, + 0b10111101, + 0b10000000, + 0b00000001, + 0b11111111, + 0b11111111, }; const uint8_t* const laser_gun_icon_frames[] = {laser_gun_icon_data}; @@ -120,4 +169,4 @@ const Icon I_game_over_icon = { .frame_count = 1, .frame_rate = 0, .frames = game_over_icon_frames, -}; \ No newline at end of file +}; diff --git a/laser_tag_icons.h b/laser_tag_icons.h index d1026367399..32326667b35 100644 --- a/laser_tag_icons.h +++ b/laser_tag_icons.h @@ -1,3 +1,4 @@ + #pragma once #include @@ -10,8 +11,8 @@ extern const Icon I_team_blue_icon; extern const Icon I_game_over_icon; #define LASER_GUN_ICON (&I_laser_gun_icon) -#define HEALTH_ICON (&I_health_icon) -#define AMMO_ICON (&I_ammo_icon) -#define TEAM_RED_ICON (&I_team_red_icon) +#define HEALTH_ICON (&I_health_icon) +#define AMMO_ICON (&I_ammo_icon) +#define TEAM_RED_ICON (&I_team_red_icon) #define TEAM_BLUE_ICON (&I_team_blue_icon) -#define GAME_OVER_ICON (&I_game_over_icon) \ No newline at end of file +#define GAME_OVER_ICON (&I_game_over_icon) diff --git a/laser_tag_view.c b/laser_tag_view.c index 7c1ec65e53e..2fd5fe655a5 100644 --- a/laser_tag_view.c +++ b/laser_tag_view.c @@ -1,3 +1,4 @@ + #include "laser_tag_view.h" #include "laser_tag_icons.h" #include @@ -18,25 +19,40 @@ typedef struct { static void laser_tag_view_draw_callback(Canvas* canvas, void* model) { LaserTagViewModel* m = model; + furi_assert(m); + furi_assert(canvas); canvas_clear(canvas); canvas_set_color(canvas, ColorBlack); canvas_draw_icon(canvas, 0, 0, m->team == TeamRed ? TEAM_RED_ICON : TEAM_BLUE_ICON); canvas_draw_icon(canvas, 0, 10, HEALTH_ICON); - canvas_draw_str_aligned(canvas, 20, 14, AlignLeft, AlignBottom, furi_string_get_cstr(furi_string_alloc_printf("%d", m->health))); + FuriString* str = furi_string_alloc_printf("%d", m->health); + canvas_draw_str_aligned(canvas, 20, 14, AlignLeft, AlignBottom, furi_string_get_cstr(str)); + canvas_draw_icon(canvas, 0, 20, AMMO_ICON); - canvas_draw_str_aligned(canvas, 20, 24, AlignLeft, AlignBottom, furi_string_get_cstr(furi_string_alloc_printf("%d", m->ammo))); + furi_string_reset(str); + furi_string_printf(str, "%d", m->ammo); + canvas_draw_str_aligned(canvas, 20, 24, AlignLeft, AlignBottom, furi_string_get_cstr(str)); + canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignBottom, "Score:"); - canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignBottom, furi_string_get_cstr(furi_string_alloc_printf("%d", m->score))); + furi_string_reset(str); + furi_string_printf(str, "%d", m->score); + canvas_draw_str_aligned(canvas, 64, 20, AlignCenter, AlignBottom, furi_string_get_cstr(str)); + uint32_t minutes = m->game_time / 60; uint32_t seconds = m->game_time % 60; - canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignBottom, furi_string_get_cstr(furi_string_alloc_printf("%02ld:%02ld", minutes, seconds))); + furi_string_reset(str); + furi_string_printf(str, "%02ld:%02ld", minutes, seconds); + canvas_draw_str_aligned(canvas, 64, 40, AlignCenter, AlignBottom, furi_string_get_cstr(str)); + canvas_draw_icon(canvas, 112, 0, LASER_GUN_ICON); if(m->game_over) { canvas_draw_icon(canvas, 56, 28, GAME_OVER_ICON); } + + furi_string_free(str); } static bool laser_tag_view_input_callback(InputEvent* event, void* context) { @@ -47,26 +63,40 @@ static bool laser_tag_view_input_callback(InputEvent* event, void* context) { LaserTagView* laser_tag_view_alloc() { LaserTagView* laser_tag_view = malloc(sizeof(LaserTagView)); + if(!laser_tag_view) { + return NULL; + } + laser_tag_view->view = view_alloc(); + if(!laser_tag_view->view) { + free(laser_tag_view); + return NULL; + } + view_set_context(laser_tag_view->view, laser_tag_view); view_allocate_model(laser_tag_view->view, ViewModelTypeLocking, sizeof(LaserTagViewModel)); view_set_draw_callback(laser_tag_view->view, laser_tag_view_draw_callback); view_set_input_callback(laser_tag_view->view, laser_tag_view_input_callback); + return laser_tag_view; } +void laser_tag_view_free(LaserTagView* laser_tag_view) { + if(!laser_tag_view) return; + if(laser_tag_view->view) { + view_free(laser_tag_view->view); + } + free(laser_tag_view); +} + void laser_tag_view_draw(View* view, Canvas* canvas) { + furi_assert(view); + furi_assert(canvas); LaserTagViewModel* model = view_get_model(view); laser_tag_view_draw_callback(canvas, model); view_commit_model(view, false); } -void laser_tag_view_free(LaserTagView* laser_tag_view) { - furi_assert(laser_tag_view); - view_free(laser_tag_view->view); - free(laser_tag_view); -} - View* laser_tag_view_get_view(LaserTagView* laser_tag_view) { furi_assert(laser_tag_view); return laser_tag_view->view; diff --git a/laser_tag_view.h b/laser_tag_view.h index f7079f49ad3..c99e3d2a066 100644 --- a/laser_tag_view.h +++ b/laser_tag_view.h @@ -1,3 +1,4 @@ + #pragma once #include @@ -6,11 +7,7 @@ typedef struct LaserTagView LaserTagView; LaserTagView* laser_tag_view_alloc(); - -void laser_tag_view_draw(View* view, Canvas* canvas); - void laser_tag_view_free(LaserTagView* laser_tag_view); - +void laser_tag_view_draw(View* view, Canvas* canvas); View* laser_tag_view_get_view(LaserTagView* laser_tag_view); - -void laser_tag_view_update(LaserTagView* laser_tag_view, GameState* game_state); \ No newline at end of file +void laser_tag_view_update(LaserTagView* laser_tag_view, GameState* game_state);