Преглед изворни кода

Merge laser_tag from https://github.com/RocketGod-git/Flipper-Zero-Laser-Tag

Willy-JL пре 1 година
родитељ
комит
a83d4bca83

+ 1 - 1
laser_tag/application.fam

@@ -6,7 +6,7 @@ App(
     cdefines=["APP_LASER_TAG"],
     fap_category="Games",
     fap_author="@RocketGod-git & @jamisonderek",
-    fap_version="1.0",
+    fap_version="1.1",
     fap_description="Laser Tag game for Flipper Zero",
     fap_icon="icons/laser_tag_10px.png",
     fap_libs=["assets"],

+ 5 - 0
laser_tag/docs/CHANGELOG.md

@@ -1,3 +1,8 @@
+## v1.1
+
+- Update app icon
+
+
 ## v1.0
 
 - Initial release.

BIN
laser_tag/icons/laser_tag_10px.png


+ 16 - 0
laser_tag/infrared_controller.c

@@ -187,3 +187,19 @@ bool infrared_controller_receive(InfraredController* controller) {
 
     return hit;
 }
+
+void infrared_controller_pause(InfraredController* controller) {
+    if(controller->worker_rx_active) {
+        FURI_LOG_I(TAG, "Stopping RX worker");
+        infrared_worker_rx_stop(controller->worker);
+        controller->worker_rx_active = false;
+    }
+}
+
+void infrared_controller_resume(InfraredController* controller) {
+    if(!controller->worker_rx_active) {
+        FURI_LOG_I(TAG, "Starting RX worker");
+        infrared_worker_rx_start(controller->worker);
+        controller->worker_rx_active = true;
+    }
+}

+ 2 - 0
laser_tag/infrared_controller.h

@@ -10,6 +10,8 @@ void infrared_controller_free(InfraredController* controller);
 void infrared_controller_set_team(InfraredController* controller, LaserTagTeam team);
 void infrared_controller_send(InfraredController* controller);
 bool infrared_controller_receive(InfraredController* controller);
+void infrared_controller_pause(InfraredController* controller);
+void infrared_controller_resume(InfraredController* controller);
 
 #define IR_COMMAND_RED_TEAM  0xA1
 #define IR_COMMAND_BLUE_TEAM 0xB2

+ 79 - 0
laser_tag/laser_tag_app.c

@@ -2,6 +2,7 @@
 #include "laser_tag_view.h"
 #include "infrared_controller.h"
 #include "game_state.h"
+#include "lfrfid_reader.h"
 #include <furi.h>
 #include <gui/gui.h>
 #include <input/input.h>
@@ -20,6 +21,7 @@ struct LaserTagApp {
     GameState* game_state;
     LaserTagState state;
     bool need_redraw;
+    LFRFIDReader* reader;
 };
 
 const NotificationSequence sequence_vibro_1 = {&message_vibro_on, &message_vibro_off, NULL};
@@ -144,6 +146,55 @@ static void laser_tag_app_draw_callback(Canvas* canvas, void* context) {
     FURI_LOG_D(TAG, "Exiting draw callback");
 }
 
+static bool matching_team(LaserTagApp* app, uint8_t data) {
+    if(data == 0) {
+        return true;
+    } else if(game_state_get_team(app->game_state) == TeamRed) {
+        return data == 0xA1;
+    } else if(game_state_get_team(app->game_state) == TeamBlue) {
+        return data == 0xB2;
+    }
+    return false;
+}
+
+static void tag_callback(uint8_t* data, uint8_t length, void* context) {
+    LaserTagApp* app = (LaserTagApp*)context;
+
+    if(length != 5) {
+        FURI_LOG_W(TAG, "Tag is not for game.  Length: %d", length);
+        return;
+    }
+
+    if(data[0] != 0x13 || data[1] != 0x37) {
+        FURI_LOG_D(
+            TAG,
+            "Tag is not for game.  Data: %02x %02x %02x %02x %02x",
+            data[0],
+            data[1],
+            data[2],
+            data[3],
+            data[4]);
+        return;
+    }
+
+    if(matching_team(app, data[2])) {
+        if(data[3] == 0xFD) {
+            uint16_t max_delta_ammo = data[4];
+            uint16_t ammo = game_state_get_ammo(app->game_state);
+            uint16_t delta_ammo = INITIAL_AMMO - ammo;
+            if(delta_ammo > max_delta_ammo) {
+                delta_ammo = max_delta_ammo;
+            }
+            game_state_increase_ammo(app->game_state, delta_ammo);
+            FURI_LOG_D(TAG, "Increased ammo by: %d", delta_ammo);
+        } else {
+            FURI_LOG_W(TAG, "Tag action unknown: %02x %02x", data[3], data[4]);
+        }
+    } else {
+        FURI_LOG_I(TAG, "Tag not for team: %02x", data[2]);
+    }
+}
+
 LaserTagApp* laser_tag_app_alloc() {
     FURI_LOG_D(TAG, "Allocating Laser Tag App");
     LaserTagApp* app = malloc(sizeof(LaserTagApp));
@@ -186,6 +237,9 @@ LaserTagApp* laser_tag_app_alloc() {
     }
     FURI_LOG_I(TAG, "Timer allocated");
 
+    app->reader = lfrfid_reader_alloc();
+    lfrfid_reader_set_tag_callback(app->reader, "EM4100", tag_callback, app);
+
     furi_timer_start(app->timer, furi_kernel_get_tick_frequency());
     FURI_LOG_D(TAG, "Timer started");
 
@@ -205,6 +259,10 @@ void laser_tag_app_free(LaserTagApp* app) {
     if(app->ir_controller) {
         infrared_controller_free(app->ir_controller);
     }
+    if(app->reader) {
+        lfrfid_reader_free(app->reader);
+        app->reader = NULL;
+    }
     free(app->game_state);
     furi_record_close(RECORD_GUI);
     furi_record_close(RECORD_NOTIFICATION);
@@ -356,6 +414,27 @@ int32_t laser_tag_app(void* p) {
                             FURI_LOG_I(TAG, "OK key pressed, firing laser");
                             laser_tag_app_fire(app);
                             break;
+                        case InputKeyUp:
+                            FURI_LOG_I(TAG, "Up key pressed, scanning for ammo");
+                            notification_message(app->notifications, &sequence_short_beep);
+                            uint16_t ammo = game_state_get_ammo(app->game_state);
+                            infrared_controller_pause(app->ir_controller);
+                            lfrfid_reader_start(app->reader);
+                            for(int i = 0; i < 30; i++) {
+                                furi_delay_ms(100);
+                                if(ammo != game_state_get_ammo(app->game_state)) {
+                                    break;
+                                }
+                            }
+                            lfrfid_reader_stop(app->reader);
+                            infrared_controller_resume(app->ir_controller);
+                            if(ammo != game_state_get_ammo(app->game_state)) {
+                                notification_message(app->notifications, &sequence_success);
+                            } else {
+                                notification_message(app->notifications, &sequence_error);
+                            }
+                            app->need_redraw = true;
+                            break;
                         default:
                             break;
                         }

+ 117 - 0
laser_tag/lfrfid_reader.c

@@ -0,0 +1,117 @@
+#include "lfrfid_reader.h"
+#include <lfrfid/protocols/lfrfid_protocols.h>
+#include <toolbox/protocols/protocol_dict.h>
+#include <lib/lfrfid/lfrfid_worker.h>
+
+#define TAG "LfRfid_Reader"
+
+typedef enum {
+    LFRFIDReaderEventTagRead = (1 << 0),
+    LFRFIDReaderEventStopThread = (1 << 1),
+    LFRFIDReaderEventAll = (LFRFIDReaderEventTagRead | LFRFIDReaderEventStopThread),
+} LFRFIDReaderEventType;
+
+struct LFRFIDReader {
+    char* requested_protocol;
+    ProtocolId protocol;
+    ProtocolDict* dict;
+    LFRFIDWorker* worker;
+    FuriThread* thread;
+    LFRFIDReaderTagCallback callback;
+    void* callback_context;
+};
+
+static void lfrfid_cli_read_callback(LFRFIDWorkerReadResult result, ProtocolId proto, void* ctx) {
+    furi_assert(ctx);
+    LFRFIDReader* context = ctx;
+    if(result == LFRFIDWorkerReadDone) {
+        context->protocol = proto;
+        furi_thread_flags_set(furi_thread_get_id(context->thread), LFRFIDReaderEventTagRead);
+    }
+}
+
+LFRFIDReader* lfrfid_reader_alloc() {
+    LFRFIDReader* reader = malloc(sizeof(LFRFIDReader));
+    reader->protocol = PROTOCOL_NO;
+    reader->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
+    reader->worker = lfrfid_worker_alloc(reader->dict);
+
+    return reader;
+}
+
+void lfrfid_reader_set_tag_callback(
+    LFRFIDReader* reader,
+    char* requested_protocol,
+    LFRFIDReaderTagCallback callback,
+    void* context) {
+    furi_assert(reader);
+    furi_assert(requested_protocol);
+    reader->requested_protocol = requested_protocol;
+    reader->callback = callback;
+    reader->callback_context = context;
+}
+
+static int32_t lfrfid_reader_start_thread(void* ctx) {
+    LFRFIDReader* reader = (LFRFIDReader*)ctx;
+    furi_thread_flags_clear(LFRFIDReaderEventAll);
+    lfrfid_worker_start_thread(reader->worker);
+    lfrfid_worker_read_start(
+        reader->worker, LFRFIDWorkerReadTypeASKOnly, lfrfid_cli_read_callback, reader);
+    while(true) {
+        uint32_t flags = furi_thread_flags_wait(LFRFIDReaderEventAll, FuriFlagWaitAny, 100);
+
+        if(flags != (unsigned)FuriFlagErrorTimeout) {
+            if((flags & LFRFIDReaderEventTagRead) == LFRFIDReaderEventTagRead) {
+                furi_thread_flags_clear(LFRFIDReaderEventTagRead);
+                if(reader->protocol != PROTOCOL_NO) {
+                    const char* protocol_name =
+                        protocol_dict_get_name(reader->dict, reader->protocol);
+                    if(strcmp(protocol_name, reader->requested_protocol) == 0) {
+                        size_t size = protocol_dict_get_data_size(reader->dict, reader->protocol);
+                        uint8_t* data = malloc(size);
+                        protocol_dict_get_data(reader->dict, reader->protocol, data, size);
+                        if(reader->callback) {
+                            FURI_LOG_D(TAG, "Tag %s detected", protocol_name);
+                            reader->callback(data, size, reader->callback_context);
+                        } else {
+                            FURI_LOG_W(TAG, "No callback set for tag %s", protocol_name);
+                        }
+                        free(data);
+                    } else {
+                        FURI_LOG_W(TAG, "Unsupported tag %s, expected EM4100", protocol_name);
+                    }
+                }
+                reader->protocol = PROTOCOL_NO;
+                lfrfid_worker_read_start(
+                    reader->worker, LFRFIDWorkerReadTypeASKOnly, lfrfid_cli_read_callback, reader);
+            } else if((flags & LFRFIDReaderEventStopThread) == LFRFIDReaderEventStopThread) {
+                break;
+            }
+        }
+    }
+    lfrfid_worker_stop(reader->worker);
+    lfrfid_worker_stop_thread(reader->worker);
+    FURI_LOG_D(TAG, "LfRfidReader thread exiting");
+    return 0;
+}
+
+void lfrfid_reader_start(LFRFIDReader* reader) {
+    reader->thread =
+        furi_thread_alloc_ex("lfrfid_reader", 2048, lfrfid_reader_start_thread, reader);
+    furi_thread_start(reader->thread);
+}
+
+void lfrfid_reader_stop(LFRFIDReader* reader) {
+    if(reader->thread) {
+        furi_thread_flags_set(furi_thread_get_id(reader->thread), LFRFIDReaderEventStopThread);
+        furi_thread_join(reader->thread);
+        reader->thread = NULL;
+    }
+}
+
+void lfrfid_reader_free(LFRFIDReader* reader) {
+    lfrfid_reader_stop(reader);
+    protocol_dict_free(reader->dict);
+    lfrfid_worker_free(reader->worker);
+    free(reader);
+}

+ 57 - 0
laser_tag/lfrfid_reader.h

@@ -0,0 +1,57 @@
+#pragma once
+
+/**
+* @file lfrfid_reader.h
+* @brief EM4100 tag reader, inspired by applications/main/lfrfid/lfrfid_cli.c
+* @details This file contains the declaration of the LFRFIDReader structure and its functions. You typically allocate a new LFRFIDReader, set the tag detection callback, start the reader. The tag detection callback is called each time a tag is detected. Once you are done, you stop the reader and free it.
+* @author CodeAllNight (MrDerekJamison)
+*/
+
+#include <furi.h>
+
+typedef struct LFRFIDReader LFRFIDReader;
+
+/**
+ * @brief Callback function for tag detection.
+ * @param data Tag data.
+ * @param length Tag data length.
+ * @param context Callback context.
+ */
+typedef void (*LFRFIDReaderTagCallback)(uint8_t* data, uint8_t length, void* context);
+
+/**
+ * @brief Allocates a new LFRFIDReader.
+ * @return LFRFIDReader* Pointer to the allocated LFRFIDReader.
+ */
+LFRFIDReader* lfrfid_reader_alloc();
+
+/**
+ * @brief Sets the tag detection callback.
+ * @param reader LFRFIDReader to set the callback for.
+ * @param requested_protocol Requested protocol, e.g. "EM4100".
+ * @param callback Callback function.
+ * @param context Callback context.
+ */
+void lfrfid_reader_set_tag_callback(
+    LFRFIDReader* reader,
+    char* requested_protocol,
+    LFRFIDReaderTagCallback callback,
+    void* context);
+
+/**
+ * @brief Starts the LFRFIDReader.
+ * @param reader LFRFIDReader to start.
+ */
+void lfrfid_reader_start(LFRFIDReader* reader);
+
+/**
+ * @brief Stops the LFRFIDReader.
+ * @param reader LFRFIDReader to stop.
+ */
+void lfrfid_reader_stop(LFRFIDReader* reader);
+
+/**
+ * @brief Frees the LFRFIDReader.
+ * @param reader LFRFIDReader to free.
+ */
+void lfrfid_reader_free(LFRFIDReader* reader);