From ff73bde3f51ce207f8fdad658494e3600a15c500 Mon Sep 17 00:00:00 2001 From: Derek Jamison Date: Sun, 9 Apr 2023 09:19:36 -0400 Subject: [PATCH 1/5] Updated .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) 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 From a5ca0c19760721c81cff38b43d64b1ab49911f3a Mon Sep 17 00:00:00 2001 From: Derek Jamison Date: Sun, 9 Apr 2023 09:22:17 -0400 Subject: [PATCH 2/5] Viewport code example. --- plugins/minimal_viewport/README.md | 40 ++++++++++++++++ plugins/minimal_viewport/application.fam | 10 ++++ plugins/minimal_viewport/minimal_viewport.png | Bin 0 -> 1817 bytes .../minimal_viewport/minimal_viewport_app.c | 43 ++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 plugins/minimal_viewport/README.md create mode 100644 plugins/minimal_viewport/application.fam create mode 100644 plugins/minimal_viewport/minimal_viewport.png create mode 100644 plugins/minimal_viewport/minimal_viewport_app.c 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 0000000000000000000000000000000000000000..522b64971b2a44e7d665d4beaa1d5285b30ddb74 GIT binary patch literal 1817 zcma)7eM}Q)7(XO1`I_0rlo+;L4vji&?|M*>3$=r`LN^X8-|P#I-dlRo_HK7qT0TOI zu&EmgWHS>ao5;`&4a=A;a|(V;C8EMImL+40825+EVw?n~b75icwdJFZeKcwBeV^y| z{NCU5yw5$|Yst-uiCi6tAV`ck+n5KR$~tm+DE$5Mj=mW|LTWjK!D2QTP>aahI0rzG z^`i$`M-z?PVu$or`^7zERMgw=&183G(2jT88rzfiZ3{otmU{NvYuZ`k9GW9vVi ztUOQ-Uwz2t*TDki0z5ebYXMNu$=hW^?HEZHq#@ibYOt08KyItFLyRlmwm%a!6GtVA> z(nIQ#RD*O;VmNbovWvJ97g9H!wDG$vJaqcXe*LY1iOKwp<`d5qb?q6!I5PIn4)tZpE9g znef7s_g}TY((umITPr7ajk)co#>#8%yetm)ywH8~;qui-zOIXKPgRW$-;TeL$rcX& zvg~uu;rzR)>bj7Fs*0Jfl7^Lg3Af}Fm}X~Z;j-|;SUr412-&3)fDjN77W17 zW!H!xzb3c9T2pCFV=?{an8Bxw;gTq?4)YOHaIKhe4D~_eN*z{0TTlZp z0#vKkstF8+qiDLw+NeC^mOwb%=`g!23lxrfJRY?tNzIEDxF#(v4JSyPBvlZhlB!)Y z<5jt&1V2fD#t0;<$O$sXyHJIeDd*j?4ucAO(twv+Aa_ZD0>Dz>iU-%I2}P_AD%g3M zm+ZVSFD3{-?+yx*Iom(*E1n=Itl84cUPgEnNYnogbvox|OR}j7CLE|=kmNaHsi0Z_ zcpi{=w`c{XD&Ue6FjOf3W#ApWm=C)E=rB#dX5qZRQDWqrz$L-5LI<(fQ~HQ!zA%0= znr9(b5{53=;j9RZ3LPfpWo4pflOaWumXe|()$mZIQk2=rRDc}ds*vse0~f5t92;a* z5^=bd8!vQmFm*COQL^CBVW}iOM_u}NJG={uhMmeXGGk<9D3~N*pJ_-HNfZ!TDw(7- z+C(CaB4Fx1Fwb(f>i>fJx*LU`bQnX^R5mBcyjVSN4)kn3czuy6V03WGK`@B1Dyiu( zLF8Gt6|g=5&@S;d*~5q+qXOQa4$H9FIGBDlYEk+Y)u=UuI%N*)u>;5uoRcP*A~wzC zgfA(;*Go$X@Z0~N06%sq0YODwEFc|M-rU7iNynEepdYvBjrS$tx59A(cQ9^lHYvOL z`378YsEKfTE!)Y&!pZlH*_crfS8RPgtf{GqSQ* +#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 From ffdd29255005f79223557479a0d37ef87c4c524c Mon Sep 17 00:00:00 2001 From: Derek Jamison Date: Sun, 9 Apr 2023 09:24:27 -0400 Subject: [PATCH 3/5] RPS play again signal from remote user. --- .../rock_paper_scissors/rock_paper_scissors.c | 86 ++++++++++++++++++- .../rock_paper_scissors/rock_paper_scissors.h | 4 + 2 files changed, 88 insertions(+), 2 deletions(-) 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, From a49aeb3536c3a506d9cb2a7ddd4ac2a16fb40636 Mon Sep 17 00:00:00 2001 From: Derek Jamison Date: Sun, 9 Apr 2023 11:42:52 -0400 Subject: [PATCH 4/5] Add prebuilt for Release 0.80.1 --- subghz/plugins/rock_paper_scissors/README.md | 3 ++- .../release-0.80.1/Rock_Paper_Scissors.fap | Bin 0 -> 37856 bytes 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 subghz/plugins/rock_paper_scissors/prebuilt/v1.0/official-firmware/release-0.80.1/Rock_Paper_Scissors.fap 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 0000000000000000000000000000000000000000..97195a3125d5bedb1fa98344908ac964a395e011 GIT binary patch literal 37856 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ⅇ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 Date: Sun, 9 Apr 2023 17:29:38 -0400 Subject: [PATCH 5/5] Updated readme --- hid/hid_app/README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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.