diff --git a/.gitignore b/.gitignore index c6127b3..ff55d68 100644 --- a/.gitignore +++ b/.gitignore @@ -50,3 +50,5 @@ modules.order Module.symvers Mkfile.old dkms.conf + +.vscode/ \ No newline at end of file diff --git a/hid/hid_app/README.md b/hid/hid_app/README.md index b6c95e9..878a86a 100644 --- a/hid/hid_app/README.md +++ b/hid/hid_app/README.md @@ -20,12 +20,14 @@ If you have not already installed Git and VS Code, you will need to do so. The f Clone the Flipper Zero firmware from GitHub. The following command will clone the firmware into a folder named official-firmware. (The below commands may wrap on your screen. You can copy and paste the entire command; there should only be two lines.) +Open a command window (in windows, press the Windows key+R, type: cmd, then press enter) ```console +md cd git clone --recursive https://github.com/flipperdevices/flipperzero-firmware.git official-firmware ``` -Replace _<your working directory>_ with the directory where you want to clone the firmware. +Replace _<your working directory>_ with the directory where you want to clone the firmware (like \flipper). ## Step 3. Run FBT to build the firmware and configure VS Code. diff --git a/plugins/minimal_viewport/README.md b/plugins/minimal_viewport/README.md new file mode 100644 index 0000000..11cfeed --- /dev/null +++ b/plugins/minimal_viewport/README.md @@ -0,0 +1,40 @@ +# BASIC DEMO +## Introduction +This is a minimal Hello World application for the Flipper Zero using the Viewport. The goal of this project is to use it as a starting point for other applications. + + +## Installation Directions +This project is intended to be overlayed on top of an existing firmware repo. +- Clone, Build & Deploy an existing flipper zero firmware repo. See this [tutorial](/firmware/updating/README.md) for updating firmware. +- Copy the "minimal_viewport" [folder](..) to the \applications\plugins\minimal_viewport folder in your firmware. +- Build & deploy the firmware. See this [tutorial](/firmware/updating/README.md) for updating firmware. +- NOTE: You can also extract the basic_demo.FAP from resources.tar file and use qFlipper to copy the file to the SD Card/apps/Misc folder. + + +## Running the updated firmware +These directions assume you are starting at the flipper desktop. If not, please press the back button until you are at the desktop. + +- Press the OK button on the flipper to pull up the main menu. +- Choose "Applications" from the menu. +- Choose "Misc" from the sub-menu. +- Choose "Minimal Viewport Demo" + +- The flipper should say "Hello World!" + +- Press the BACK button to exit. + + +## How it works +- application.fam + - specifies the name of our application. + - specifies the entry point for our application. + - specifies we use the GUI. + - specifies our icon is the minimal_viewport.png file. + - specifies our application can be found in the "Misc" category. + +- minimal_viewport.png + - The icon for our application. + +- minimal_viewport_app.c + - We #include the libraries we referece. + \ No newline at end of file diff --git a/plugins/minimal_viewport/application.fam b/plugins/minimal_viewport/application.fam new file mode 100644 index 0000000..4ee6e0e --- /dev/null +++ b/plugins/minimal_viewport/application.fam @@ -0,0 +1,10 @@ +App( + appid="Minimal_Viewport_Demo", + name="Minimal Viewport Demo", + apptype=FlipperAppType.EXTERNAL, + entry_point="minimal_viewport_demo_app", + requires=["gui"], + stack_size=2 * 1024, + fap_icon="minimal_viewport.png", + fap_category="Misc", +) diff --git a/plugins/minimal_viewport/minimal_viewport.png b/plugins/minimal_viewport/minimal_viewport.png new file mode 100644 index 0000000..522b649 Binary files /dev/null and b/plugins/minimal_viewport/minimal_viewport.png differ diff --git a/plugins/minimal_viewport/minimal_viewport_app.c b/plugins/minimal_viewport/minimal_viewport_app.c new file mode 100644 index 0000000..229d6de --- /dev/null +++ b/plugins/minimal_viewport/minimal_viewport_app.c @@ -0,0 +1,43 @@ +#include +#include +typedef struct { + int type; + InputEvent input; +} AppEvent; +static void input_callback(InputEvent* input_event, void* ctx) { + FuriMessageQueue* queue = ctx; + AppEvent event = { + .type = input_event->type, + .input = *input_event, + }; + furi_message_queue_put(queue, &event, FuriWaitForever); +} +static void render_callback(Canvas* canvas, void* ctx) { + UNUSED(ctx); + canvas_set_font(canvas, FontPrimary); + canvas_draw_str_aligned(canvas, 15, 30, AlignLeft, AlignTop, "HELLO WORLD!"); +} +//static ViewPort* view_port = view_port_alloc(); +int32_t minimal_viewport_demo_app(void* p) { + UNUSED(p); + FuriMessageQueue* queue = furi_message_queue_alloc(8, sizeof(AppEvent)); + ViewPort* view_port = view_port_alloc(); + view_port_input_callback_set(view_port, input_callback, queue); + view_port_draw_callback_set(view_port, render_callback, NULL); + Gui* gui = furi_record_open(RECORD_GUI); + gui_add_view_port(gui, view_port, GuiLayerFullscreen); + bool processing = true; + AppEvent event; + do { + if(furi_message_queue_get(queue, &event, FuriWaitForever) == FuriStatusOk) { + if(event.input.type == InputTypeShort && event.input.key == InputKeyBack) { + processing = false; + } + } + } while(processing); + view_port_enabled_set(view_port, false); + gui_remove_view_port(gui, view_port); + view_port_free(view_port); + furi_record_close(RECORD_GUI); + return 0; +} \ No newline at end of file diff --git a/subghz/plugins/rock_paper_scissors/README.md b/subghz/plugins/rock_paper_scissors/README.md index 354cbf3..086d360 100644 --- a/subghz/plugins/rock_paper_scissors/README.md +++ b/subghz/plugins/rock_paper_scissors/README.md @@ -12,8 +12,9 @@ Watch on [YouTube](https://youtu.be/eGOv6Gbar7I). - Download the latest FAP file matching your firmware version. Copy the downloaded FAP file to the SD Card/apps/Games folder (using qFlipper or by ejecting the SD Card and inserting it into your PC). - - Official Firmware [Release 0.79.1](https://github.com/jamisonderek/flipper-zero-tutorials/raw/main/subghz/plugins/rock_paper_scissors/prebuilt/v1.0/official-firmware/release-0.79.1/Rock_Paper_Scissors.fap) + - Official Firmware [Release 0.80.1](https://github.com/jamisonderek/flipper-zero-tutorials/raw/main/subghz/plugins/rock_paper_scissors/prebuilt/v1.0/official-firmware/release-0.80.1/Rock_Paper_Scissors.fap) - Official Firmware [RC 0.80.0](https://github.com/jamisonderek/flipper-zero-tutorials/raw/main/subghz/plugins/rock_paper_scissors/prebuilt/v1.0/official-firmware/rc-0.80.0/Rock_Paper_Scissors.fap) + - Official Firmware [Release 0.79.1](https://github.com/jamisonderek/flipper-zero-tutorials/raw/main/subghz/plugins/rock_paper_scissors/prebuilt/v1.0/official-firmware/release-0.79.1/Rock_Paper_Scissors.fap) - [Archived releases](./prebuilt/v1.0/official-firmware) _(games may not have latest fixes & features)_ - If you have a different firmware, see the [installation directions](#installation-directions) below. diff --git a/subghz/plugins/rock_paper_scissors/prebuilt/v1.0/official-firmware/release-0.80.1/Rock_Paper_Scissors.fap b/subghz/plugins/rock_paper_scissors/prebuilt/v1.0/official-firmware/release-0.80.1/Rock_Paper_Scissors.fap new file mode 100644 index 0000000..97195a3 Binary files /dev/null and b/subghz/plugins/rock_paper_scissors/prebuilt/v1.0/official-firmware/release-0.80.1/Rock_Paper_Scissors.fap differ diff --git a/subghz/plugins/rock_paper_scissors/rock_paper_scissors.c b/subghz/plugins/rock_paper_scissors/rock_paper_scissors.c index 34f2096..dbfca1b 100644 --- a/subghz/plugins/rock_paper_scissors/rock_paper_scissors.c +++ b/subghz/plugins/rock_paper_scissors/rock_paper_scissors.c @@ -268,12 +268,41 @@ static void rps_receive_data(GameContext* game_context, uint32_t tick) { break; } + case GameRfPurposePlayAgain: { + // IMPORTANT: The code processing the event needs to furi_string_free the senderName! + FuriString* name = furi_string_alloc(); + furi_string_set(name, sender_name); + + GameEvent event = { + .type = GameEventRemotePlayAgain, .sender_name = name, .game_number = game_number}; + furi_message_queue_put(game_context->queue, &event, FuriWaitForever); + break; + } + + case GameRfPurposeQuit: { + // IMPORTANT: The code processing the event needs to furi_string_free the senderName! + FuriString* name = furi_string_alloc(); + furi_string_set(name, sender_name); + + GameEvent event = { + .type = GameEventRemoteQuit, .sender_name = name, .game_number = game_number}; + furi_message_queue_put(game_context->queue, &event, FuriWaitForever); + break; + } + case GameRfPurposeJoin: if(index >= len) { FURI_LOG_W(TAG, "Failed to parse join message. >%s<", message); return; } else { sender_contact = (char*)message + index; + while(index < len) { + if(message[index] == '\n' || message[index] == '\r') { + message[index] = 0; + break; + } + index++; + } FURI_LOG_T(TAG, "Join had contact of >%s<", sender_contact); // IMPORTANT: The code processing the event needs to furi_string_free the senderName! @@ -297,6 +326,13 @@ static void rps_receive_data(GameContext* game_context, uint32_t tick) { return; } else { sender_contact = (char*)message + index; + while(index < len) { + if(message[index] == '\n' || message[index] == '\r') { + message[index] = 0; + break; + } + index++; + } FURI_LOG_T(TAG, "Join acknowledge for game %d.", game_number); FURI_LOG_T(TAG, "Join ack had contact of >%s<", sender_contact); @@ -1015,6 +1051,38 @@ static void rps_broadcast_not_beacon(GameContext* game_context) { rps_broadcast(game_context, data->buffer); } +static void rps_broadcast_play_again(GameContext* game_context) { + GameData* data = game_context->data; + FURI_LOG_I(TAG, "Sending play again"); + + // The message for game 42 should look like... "YourFlip: RPS:PA042\r\n" + furi_string_printf( + data->buffer, + "%s: %s:%c%c%03u\r\n", + furi_hal_version_get_name_ptr(), + RPS_GAME_NAME, + GameRfPurposePlayAgain, + MAJOR_VERSION, + data->game_number); + rps_broadcast(game_context, data->buffer); +} + +static void rps_broadcast_quit(GameContext* game_context) { + GameData* data = game_context->data; + FURI_LOG_I(TAG, "Sending quit"); + + // The message for game 42 should look like... "YourFlip: RPS:QA042\r\n" + furi_string_printf( + data->buffer, + "%s: %s:%c%c%03u\r\n", + furi_hal_version_get_name_ptr(), + RPS_GAME_NAME, + GameRfPurposeQuit, + MAJOR_VERSION, + data->game_number); + rps_broadcast(game_context, data->buffer); +} + // Send message that indicates Flipper is joining a specific game. // We broadcast - "YourFlip: " + "RPS:" + join"J" + version"A" + game"###" + "NYourNameHere" + "\r\n" // @param game_context pointer to a GameContext. @@ -2240,17 +2308,19 @@ int32_t rock_paper_scissors_app(void* p) { event.input.type == InputTypeShort) { switch(event.input.key) { case InputKeyLeft: - game_context->data->keyboard_col = 0; // YES + game_context->data->keyboard_col = 0; // YES - Play again break; case InputKeyRight: - game_context->data->keyboard_col = 1; // NO + game_context->data->keyboard_col = 1; // NO - Back to main menu break; case InputKeyOk: if(game_context->data->keyboard_col == 1) { + rps_broadcast_quit(game_context); game_context->data->local_player = StateMainMenuHost; game_context->data->remote_player = StateUnknown; game_context->data->screen_state = ScreenMainMenu; } else { + rps_broadcast_play_again(game_context); game_context->data->remote_player = StateReady; game_context->data->remote_move_tick = furi_get_tick(); game_context->data->local_player = StateReady; @@ -2335,6 +2405,18 @@ int32_t rock_paper_scissors_app(void* p) { FURI_LOG_I(TAG, "Remote not beacon detected. game number %03u", event.game_number); remote_games_remove(game_context, &event); break; + case GameEventRemotePlayAgain: + 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; + break; + case GameEventRemoteQuit: + game_context->data->local_player = StateMainMenuHost; + game_context->data->remote_player = StateUnknown; + game_context->data->screen_state = ScreenMainMenu; + break; case GameEventRemoteJoined: if(furi_mutex_acquire(game_context->mutex, FuriWaitForever) == FuriStatusOk) { if(event.game_number == game_context->data->game_number) { diff --git a/subghz/plugins/rock_paper_scissors/rock_paper_scissors.h b/subghz/plugins/rock_paper_scissors/rock_paper_scissors.h index e6b92ff..c70ee00 100644 --- a/subghz/plugins/rock_paper_scissors/rock_paper_scissors.h +++ b/subghz/plugins/rock_paper_scissors/rock_paper_scissors.h @@ -170,6 +170,8 @@ typedef enum { GameRfPurposeJoin = 'J', // Join a game. GameRfPurposeJoinAcknowledge = 'A', // Acknowledge a join request. GameRfPurposeMove = 'M', // Player move. + GameRfPurposePlayAgain = 'P', // Play another game. + GameRfPurposeQuit = 'Q', // Quit, don't play another game. } GameRfPurpose; // Messages in our event queue are one of the following types. @@ -182,6 +184,8 @@ typedef enum { GameEventRemoteJoined, GameEventRemoteJoinAcknowledged, GameEventLocalMove, + GameEventRemotePlayAgain, + GameEventRemoteQuit, GameEventRemoteMove, GameEventSendMove, GameEventPlaySong,