my changes for some plugins and 2048

This commit is contained in:
RogueMaster
2022-09-16 17:23:45 -04:00
parent 93d5839a51
commit 918c5a8439
25 changed files with 1260 additions and 39 deletions
+68
View File
@@ -1 +1,69 @@
## Doing a direct unleashed fork to implement FAPS and all the old stuff will be re-implemented.
To Be Added/To Verify Present:
- Games & Plugins?
- Assets: Running DolphinRestorer.fap on new install will auto-level to the end of Level 2.
- GPIO: Feature to read EEPROM of SFP Modules using I2C [(By marcusju)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/198)
- Development free space thanks to removal of unused debug tools and [thanks to ESurge](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/46/files) for removal of first start assets.
- Plugins: Menu, Icons, and Raycast exit [Thanks to Redlink](https://github.com/redlink2/flipperzero-firmware/tree/menuChanges)
- Settings: Favorite Game by holding UP on Desktop [Thanks to gotnull](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/57)
- Settings: Hold Down for Games Menu [(Thanks to ESurge)](https://github.com/ESurge/flipperzero-firmware-wPlugins)
- Settings: Rename from SD `dolphin/name.txt` [(Thanks to E_Surge)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/259)
- Settings: Scan names will have timestamp instead of random name assigned for [NFC](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/lib/toolbox/random_name.c) and [SubGHz](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/applications/subghz/scenes/subghz_scene_read_raw.c) (By RogueMaster)
- SubGHz: Auto Detect Raw in READ action (Needs To Be Enabled In Read Settings) [from perspecdev](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/152)
- SubGHz: [Add settings to subghz read functionality to allow setting RSSI threshold (raw only) (By PolymerPrints)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/184)
Implemented:
- Animations: Hold Center to change Flipper idle animation. [Thanks to Zycenios](https://github.com/flipperdevices/flipperzero-firmware/commit/111786ef40e50a40d2e510595672b569d9b97bba) With changes by RogueMaster.
- Animations: iButton and RFID P0kem0n images [Thanks to Panzer00Z](https://github.com/Panzer00Z/flipperzero-firmware/)
- Animations: Idle animations will show all animations regardless of level and butthurt [Thanks to qqMajiKpp]
- Animations: RM FW Update image [(Thanks to E_Surge)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/257)
- Animations: SubGHZ Scanning image with Pikachu [Thanks to Panzer00Z](https://github.com/Panzer00Z/flipperzero-firmware/blob/3a548ea9bb181c9348d8afb427890c411456134e/assets/icons/SubGhz/Scanning_123x52.png)
- Assets: Includes a NFC Level 50 Gan0n Amiibo
- Assets: Includes a NFC Rick Roll link
- Assets: Includes New Dolphin Animations: [Rick Roll, Matrix & Swim animations (By qqMajiKpp)], [Rukamon 2x and Agumon animations (By Syrius)], [Mew (By Arkaivos)], [Eye of the Flipper (By Kuronons)], [Shodan (By qqMajiKpp)], [Sirene & The Witch (By Haseo)], [Dino & A New Hope (By Haseo)], [Earth Arcadia (By Kuronons)], [Kuronons Black Flags Collection (21 Animations)(By Kuronons)], [D.Va (By Haseo)], [GITS (By Haseo)], [Slayers (By qqMajiKpp)], [P0liwhirl (By Panzer00Z)], [RogueMaster CFW Animation (By Kuronons)], [Nyan Cat (By Haseo)], [L (By Kuronons)], [Laughing Man (By Kuronons)], [B0ws3r (By Haseo)], [Kuronons Black Flags Collection VOL 2 (9 Animations)(By Kuronons)], [Thanks for all the fish (By qqMajiKpp)], [OCP, Skynet and Weyland (By Kuronons)], [Mario (By Haseo)], [Umbrella (By Haseo)], [Trioptimum (By qqMajiKpp)], [Tyrell & Cyberdyne (By Kuronons)], [Allen & Maha (By Haseo)], [Starfield (By qqMajiKpp)] & [DJ (By ut1s)]
- Assets: Includes sample Music Player tunes
- Assets: Includes sample SubGHz assets for Crosswalk, Handicap Doors, Sextoys, Tesla Charge Port, and Unitree Go1 Robot Dog
- Assets: Includes Sonic Screw Driver sound for the Wav Player
- BadUSB: Added ignore DUCKY_LANG cmd to retain compatibility with existing scripts [(Thanks to v1nc)](https://github.com/v1nc/flipperzero-firmware)
- BadUSB: Assets for Kiosk Evasion and Wifi Stealer
- BadUSB: sk-SK maping keybord for BadUsb [(By jaroslavmraz)](https://github.com/flipperdevices/flipperzero-firmware/pull/1619)
- BadUSB: pt-BR maping keybord for BadUsb [(By web-mancha)](https://github.com/Eng1n33r/flipperzero-firmware/pull/65)
- BadUSB: show script errors on screen [(By CromFr)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/200)
- Dolphin: Assigned profile pic for levels 1-10, 11-20 and 21-30 respectively from default lvl 1, 2 & 3
- Dolphin: Expanded max level from 3 to 30 using [Roll20](https://roll20.net/compendium/dnd5e/Monsters#h-Experience%20Points), Increased max deed XP per action type from 15 to 45 exp daily & updated animation manifest for max level 30 for all animations (By RogueMaster)
- Dolphin: Internal manifest updated to have animations always available with max level 30
- Dolphin: Level animation sequence for level 3+ to be lvl1->2 for levels 1-20 and lvl2->3 for levels 21-30.
- Dolphin: Mood Stays Happy [(Thanks to biocage)](https://github.com/biocage/flipperzero-firmware), changed to Mood Stays Less Than 6 / Mood Stays High (but not in game mode) (By RogueMaster)
- Dolphin: Passport: DB Themed [(Thanks to Kuronons)]
- Dolphin: Passport: Show EXP [(By Dabolus)](https://github.com/Dabolus/flipperzero-firmware-rpg/)
- Dolphin: Changed daily MAX to 198 on all 7 Deed Types. Random Deed Selection used for MAX +3 EXP daily gain.
- Dolphin: Plugin Achivement +3 EXP for a total of up to 700 EXP daily. Plugin Achivements are:
- - Dice First Roll for d20+ = sides on dice (i.e. Nat 20 on d20)
- - Dice First Roll for d20+ = sides on dice - 1 (+1 EXP) (i.e. 19 on d20)
- - Games Only Mode from Lock Menu
- - Getting 2048 in 2048
- - Mouse Jacker Ducky Run
- - NRFSniffer Found Address
- - Stopwatch @ Alert
- - Tetris, Snake, or Flappy Bird Score For EXP
- - Zombiez for every 20 Zombie kills
- Dolphin: SD dolphin manifest updated to weight animations differently
- Icon Decode/Encode [(Thanks to PixlEmly)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/55/files)
- IR: Universal AC, Audio, Fans & Projectors from [Unleashed/Eng1n33r](https://github.com/Eng1n33r/flipperzero-firmware)
- Plugins: 2048, Arkanoid, Snake, and Tetris show score. Thanks to [whoamins](https://github.com/flipperdevices/flipperzero-firmware/commit/7feda832ede1ba8468eff2ca055fef3ddbdc16ac) and [DevMilanIan](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/188) With position changes by RogueMaster. Also all + Tic Tac Toe updated by [Unleashed/Eng1n33r](https://github.com/Eng1n33r/flipperzero-firmware) for stability.
- Settings: Actual PIN Lock [(By RogueMaster)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/applications/desktop/desktop.c)
- Settings: Auto-Lock Options Added: 10s+15s+90s [(By RogueMaster)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c)
- Settings: Battery Meter on Desktop [Thanks to McAzzaMan](https://github.com/McAzzaMan/flipperzero-firmware/tree/BatteryPercentageView)
- Settings: Custom name with this compile: CUSTOM_FLIPPER_NAME=name ./fbt updater_package [By Unleashed/xMasterX](https://github.com/Eng1n33r/flipperzero-firmware)
- Settings: Desktop => [Games Only Mode (By RogueMaster)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/GAMES_ONLY.md) [(Thanks to Astrrra for Inverted Mode to Mimic)](https://github.com/wetox-team/flipperzero-firmware/commit/ce91582b7417c5d7a9d8416c17a102d3a5868238)
- - [UP UP DOWN DOWN LEFT RIGHT LEFT RIGHT FROM CLOCK](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/GAMES_ONLY.md)<== FULL LIST OF GAMES ONLY CONTROLS
- Settings: "DUMB Mode" is now "Lock W PIN + Off" [(By RogueMaster)]
- Settings: LCD Timeout Options Added: 10s+90s+2min+5min+10min [(By RogueMaster)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/applications/notification/notification_settings_app.c)
- SubGHz: Extended ranges enabled through flag in /ext/subghz/assets/extend_range.txt [from tkerrby](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/pull/116)
- SubGHz: Moved setting_user file to setting_user.txt! This makes it changable from IOS app. (By RogueMaster)
- SubGHz: New frequency analyzer [(By ClusterM)](https://github.com/flipperdevices/flipperzero-firmware/pull/1501) [feedback mode (by darmiel)](https://github.com/darmiel/flipper-playlist/tree/feat/stealth-frequency-analyzer)
- SubGHz: Protocols An-Motors, BFT Mitto, Came Atomo, FAAC SLH (Spa), HCS101, Keeloq, Keeloq Common, Nice Flor S, SecPlus v1+v2 and Star Line updates from [Eng1n33r](https://github.com/Eng1n33r/flipperzero-firmware)
- SubGHz: Unlock from SD flag from [(cloudbreakdaniel)](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/commit/97db0dc91ee3dff812b4dec0618e3f198de14405). Update `subghz/assets/extend_range.txt` with [this file](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/blob/420/assets/resources/subghz/assets/extend_range.txt) on SD. **UPDATE IGNORE FLAG TO TRUE TO UNLEASH YOUR FLIPPER!!**
+53 -5
View File
@@ -113,6 +113,7 @@ static const char ducky_cmd_string[] = {"STRING "};
static const char ducky_cmd_defdelay_1[] = {"DEFAULT_DELAY "};
static const char ducky_cmd_defdelay_2[] = {"DEFAULTDELAY "};
static const char ducky_cmd_repeat[] = {"REPEAT "};
static const char ducky_cmd_sysrq[] = {"SYSRQ "};
static const char ducky_cmd_altchar[] = {"ALTCHAR "};
static const char ducky_cmd_altstr_1[] = {"ALTSTRING "};
@@ -236,7 +237,8 @@ static uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool
return 0;
}
static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
static int32_t
ducky_parse_line(BadUsbScript* bad_usb, string_t line, char* error, size_t error_len) {
uint32_t line_len = string_size(line);
const char* line_tmp = string_get_cstr(line);
bool state = false;
@@ -269,6 +271,9 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
if((state) && (delay_val > 0)) {
return (int32_t)delay_val;
}
if(error != NULL) {
snprintf(error, error_len, "Invalid number %s", line_tmp);
}
return SCRIPT_STATE_ERROR;
} else if(
(strncmp(line_tmp, ducky_cmd_defdelay_1, strlen(ducky_cmd_defdelay_1)) == 0) ||
@@ -276,17 +281,26 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
// DEFAULT_DELAY
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
state = ducky_get_number(line_tmp, &bad_usb->defdelay);
if(!state && error != NULL) {
snprintf(error, error_len, "Invalid number %s", line_tmp);
}
return (state) ? (0) : SCRIPT_STATE_ERROR;
} else if(strncmp(line_tmp, ducky_cmd_string, strlen(ducky_cmd_string)) == 0) {
// STRING
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
state = ducky_string(bad_usb, line_tmp);
if(!state && error != NULL) {
snprintf(error, error_len, "Invalid string %s", line_tmp);
}
return (state) ? (0) : SCRIPT_STATE_ERROR;
} else if(strncmp(line_tmp, ducky_cmd_altchar, strlen(ducky_cmd_altchar)) == 0) {
// ALTCHAR
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
ducky_numlock_on();
state = ducky_altchar(line_tmp);
if(!state && error != NULL) {
snprintf(error, error_len, "Invalid altchar %s", line_tmp);
}
return (state) ? (0) : SCRIPT_STATE_ERROR;
} else if(
(strncmp(line_tmp, ducky_cmd_altstr_1, strlen(ducky_cmd_altstr_1)) == 0) ||
@@ -295,16 +309,35 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
ducky_numlock_on();
state = ducky_altstring(line_tmp);
if(!state && error != NULL) {
snprintf(error, error_len, "Invalid altstring %s", line_tmp);
}
return (state) ? (0) : SCRIPT_STATE_ERROR;
} else if(strncmp(line_tmp, ducky_cmd_repeat, strlen(ducky_cmd_repeat)) == 0) {
// REPEAT
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
state = ducky_get_number(line_tmp, &bad_usb->repeat_cnt);
if(!state && error != NULL) {
snprintf(error, error_len, "Invalid number %s", line_tmp);
}
return (state) ? (0) : SCRIPT_STATE_ERROR;
} else if(strncmp(line_tmp, ducky_cmd_sysrq, strlen(ducky_cmd_sysrq)) == 0) {
// SYSRQ
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
uint16_t key = ducky_get_keycode(bad_usb, line_tmp, true);
furi_hal_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
furi_hal_hid_kb_press(key);
furi_hal_hid_kb_release_all();
return (0);
} else {
// Special keys + modifiers
uint16_t key = ducky_get_keycode(bad_usb, line_tmp, false);
if(key == HID_KEYBOARD_NONE) return SCRIPT_STATE_ERROR;
if(key == HID_KEYBOARD_NONE) {
if(error != NULL) {
snprintf(error, error_len, "No keycode defined for %s", line_tmp);
}
return SCRIPT_STATE_ERROR;
}
if((key & 0xFF00) != 0) {
// It's a modifier key
line_tmp = &line_tmp[ducky_get_command_len(line_tmp) + 1];
@@ -314,6 +347,9 @@ static int32_t ducky_parse_line(BadUsbScript* bad_usb, string_t line) {
furi_hal_hid_kb_release(key);
return (0);
}
if(error != NULL) {
strncpy(error, "Unknown error", error_len);
}
return SCRIPT_STATE_ERROR;
}
@@ -392,7 +428,8 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
if(bad_usb->repeat_cnt > 0) {
bad_usb->repeat_cnt--;
delay_val = ducky_parse_line(bad_usb, bad_usb->line_prev);
delay_val = ducky_parse_line(
bad_usb, bad_usb->line_prev, bad_usb->st.error, sizeof(bad_usb->st.error));
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
return 0;
} else if(delay_val < 0) { // Script error
@@ -426,10 +463,20 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
bad_usb->st.line_cur++;
bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1);
bad_usb->buf_start = i + 1;
delay_val = ducky_parse_line(bad_usb, bad_usb->line);
delay_val = ducky_parse_line(
bad_usb, bad_usb->line, bad_usb->st.error, sizeof(bad_usb->st.error));
if(delay_val < 0) {
bad_usb->st.error_line = bad_usb->st.line_cur;
FURI_LOG_E(WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur);
if(delay_val == SCRIPT_STATE_NEXT_LINE) {
snprintf(
bad_usb->st.error, sizeof(bad_usb->st.error), "Forbidden empty line");
FURI_LOG_E(
WORKER_TAG, "Forbidden empty line at line %lu", bad_usb->st.line_cur);
} else {
FURI_LOG_E(
WORKER_TAG, "Unknown command at line %lu", bad_usb->st.line_cur);
}
return SCRIPT_STATE_ERROR;
} else {
return (delay_val + bad_usb->defdelay);
@@ -609,6 +656,7 @@ BadUsbScript* bad_usb_script_open(string_t file_path) {
bad_usb_script_set_default_keyboard_layout(bad_usb);
bad_usb->st.state = BadUsbStateInit;
bad_usb->st.error[0] = '\0';
bad_usb->thread = furi_thread_alloc();
furi_thread_set_name(bad_usb->thread, "BadUsbWorker");
@@ -26,6 +26,7 @@ typedef struct {
uint16_t line_nb;
uint32_t delay_remain;
uint16_t error_line;
char error[64];
} BadUsbState;
BadUsbScript* bad_usb_script_open(string_t file_path);
@@ -14,13 +14,15 @@ static bool bad_usb_layout_select(BadUsbApp* bad_usb) {
string_set_str(predefined_path, BAD_USB_APP_PATH_LAYOUT_FOLDER);
}
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, BAD_USB_APP_LAYOUT_EXTENSION, &I_keyboard_10px);
// Input events and views are managed by file_browser
bool res = dialog_file_browser_show(
bad_usb->dialogs, bad_usb->keyboard_layout, predefined_path, &browser_options);
bad_usb->dialogs,
bad_usb->keyboard_layout,
predefined_path,
BAD_USB_APP_LAYOUT_EXTENSION,
true,
&I_keyboard_10px,
true);
string_clear(predefined_path);
return res;
@@ -5,13 +5,15 @@
static bool bad_usb_file_select(BadUsbApp* bad_usb) {
furi_assert(bad_usb);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(
&browser_options, BAD_USB_APP_SCRIPT_EXTENSION, &I_badusb_10px);
// Input events and views are managed by file_browser
bool res = dialog_file_browser_show(
bad_usb->dialogs, bad_usb->file_path, bad_usb->file_path, &browser_options);
bad_usb->dialogs,
bad_usb->file_path,
bad_usb->file_path,
BAD_USB_APP_SCRIPT_EXTENSION,
true,
&I_badusb_10px,
true);
return res;
}
@@ -46,4 +48,4 @@ bool bad_usb_scene_file_select_on_event(void* context, SceneManagerEvent event)
void bad_usb_scene_file_select_on_exit(void* context) {
UNUSED(context);
// BadUsbApp* bad_usb = context;
}
}
@@ -26,6 +26,7 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
elements_string_fit_width(canvas, disp_str, 128 - 2);
canvas_set_font(canvas, FontSecondary);
canvas_draw_str(canvas, 2, 8, string_get_cstr(disp_str));
string_reset(disp_str);
if(strlen(model->layout) == 0) {
string_set(disp_str, "(default)");
@@ -39,8 +40,6 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
elements_string_fit_width(canvas, disp_str, 128 - 2);
canvas_draw_str(canvas, 2, 8 + canvas_current_font_height(canvas), string_get_cstr(disp_str));
string_reset(disp_str);
canvas_draw_icon(canvas, 22, 24, &I_UsbTree_48x22);
if((model->state.state == BadUsbStateIdle) || (model->state.state == BadUsbStateDone)) {
@@ -73,6 +72,7 @@ static void bad_usb_draw_callback(Canvas* canvas, void* _model) {
canvas_draw_str_aligned(
canvas, 127, 46, AlignRight, AlignBottom, string_get_cstr(disp_str));
string_reset(disp_str);
canvas_draw_str_aligned(canvas, 127, 56, AlignRight, AlignBottom, model->state.error);
} else if(model->state.state == BadUsbStateIdle) {
canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18);
canvas_set_font(canvas, FontBigNumbers);
@@ -188,6 +188,7 @@ void bad_usb_set_layout(BadUsb* bad_usb, const char* layout) {
return true;
});
}
void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
furi_assert(st);
with_view_model(
@@ -196,4 +197,4 @@ void bad_usb_set_state(BadUsb* bad_usb, BadUsbState* st) {
model->anim_frame ^= 1;
return true;
});
}
}
@@ -2,6 +2,7 @@
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#include <dolphin/dolphin.h>
#include "bird.h"
@@ -237,9 +238,9 @@ static void flappy_game_render_callback(Canvas* const canvas, void* ctx) {
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 37, 31, "Game Over");
/*if(game_state->points != 0 && game_state->points % 5 == 0) {
if(game_state->points != 0 && game_state->points % 5 == 0) {
DOLPHIN_DEED(getRandomDeed());
}*/
}
canvas_set_font(canvas, FontSecondary);
char buffer[12];
@@ -334,7 +335,7 @@ int32_t flappy_game_app(void* p) {
flappy_game_tick(game_state);
}
} else {
//FURI_LOG_D(TAG, "osMessageQueue: event timeout");
// FURI_LOG_D(TAG, "osMessageQueue: event timeout");
// event timeout
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

@@ -0,0 +1,12 @@
App(
appid="GAME_2048",
name="2048",
apptype=FlipperAppType.EXTERNAL,
entry_point="game_2048_app",
cdefines=["APP_2048_GAME"],
requires=["gui"],
stack_size=2 * 1024,
order=10,
fap_icon="2048.png",
fap_category="Games",
)
+155
View File
@@ -0,0 +1,155 @@
#include <stdbool.h>
#include <stdint.h>
#include <gui/canvas.h>
/* 7px 3 width digit font by Sefjor
* digit encoding example
*7 ¦¦¦ 111
*6 ¦ ¦ 101
*5 ¦ ¦ 101
*4 ¦ ¦ 101
*3 ¦ ¦ 101
*2 ¦ ¦ 101
*1 ¦¦¦ 111
*0 000 this string is empty, used to align
* ? ? ?
* FE 82 FE //0
*/
static uint8_t font[10][3] = {
{0xFE, 0x82, 0xFE}, // 0;
{0x00, 0xFE, 0x00}, // 1;
{0xF2, 0x92, 0x9E}, // 2;
{0x92, 0x92, 0xFE}, // 3;
{0x1E, 0x10, 0xFE}, // 4;
{0x9E, 0x92, 0xF2}, // 5;
{0xFE, 0x92, 0xF2}, // 6;
{0x02, 0x02, 0xFE}, // 7;
{0xFE, 0x92, 0xFE}, // 8;
{0x9E, 0x92, 0xFE}, // 9;
};
#define FONT_HEIGHT 8
#define FONT_WIDTH 3
static void game_2048_draw_black_point(Canvas* const canvas, uint8_t x, uint8_t y) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_dot(canvas, x, y);
}
static void game_2048_draw_white_square(Canvas* const canvas, uint8_t x, uint8_t y) {
canvas_set_color(canvas, ColorWhite);
canvas_draw_box(canvas, x, y, 15 - 1, 15 - 3);
}
static void _game_2048_draw_column(
Canvas* const canvas,
int digit,
int coord_x,
int coord_y,
uint8_t column) {
for(int x = 0; x < FONT_HEIGHT; ++x) {
bool is_filled = (font[digit][column] >> x) & 0x1;
if(is_filled) {
game_2048_draw_black_point(canvas, coord_x, coord_y + x);
}
}
}
static uint8_t
_game_2048_draw_digit(Canvas* const canvas, uint8_t digit, uint8_t coord_x, uint8_t coord_y) {
uint8_t x_shift = 0;
if(digit != 1) {
for(int column = 0; column < FONT_WIDTH; column++) {
_game_2048_draw_column(canvas, digit, coord_x + column, coord_y, column);
}
x_shift = 3;
} else {
_game_2048_draw_column(canvas, digit, coord_x, coord_y, true);
x_shift = 1;
}
return x_shift;
}
/* We drawing text field with 1px white border
* at given coords. Total size is:
* x = 9 = 1 + 7 + 1
* y = 1 + total text width + 1
*/
/*
* Returns array of digits and it's size,
* digits should be at least 4 size
* works from 1 to 9999
*/
static void _game_2048_parse_number(uint16_t number, uint8_t* digits, uint8_t* size) {
*size = 0;
uint16_t divider = 1000;
//find first digit, result is highest divider
while(number / divider == 0) {
divider /= 10;
if(divider == 0) {
break;
}
}
for(int i = 0; divider != 0; i++) {
digits[i] = number / divider;
number %= divider;
*size += 1;
divider /= 10;
}
}
uint8_t _game_2048_calculate_shift(uint16_t num) {
uint8_t shift = 0;
switch(num) {
case 1:
shift = 7;
break;
case 2:
case 4:
case 8:
shift = 6;
break;
case 16:
shift = 5;
break;
case 32:
case 64:
shift = 4;
break;
case 128:
shift = 3;
break;
case 256:
shift = 2;
break;
case 512:
shift = 3;
break;
case 1024:
shift = 2;
break;
}
return shift;
}
void game_2048_draw_number(Canvas* const canvas, uint8_t x, uint8_t y, int number) {
uint8_t digits[4];
uint8_t size;
_game_2048_parse_number(number, digits, &size);
if(number > 512) {
game_2048_draw_white_square(canvas, x, y);
}
x += _game_2048_calculate_shift(number);
y += 4;
for(int i = 0; i < size; ++i) {
x += _game_2048_draw_digit(canvas, digits[i], x, y);
x++;
}
}
+3
View File
@@ -0,0 +1,3 @@
#include <gui/canvas.h>
void game_2048_draw_number(Canvas* const canvas, uint8_t x, uint8_t y, int number);
+493
View File
@@ -0,0 +1,493 @@
#include <stdint.h>
#include <gui/gui.h>
#include <time.h>
#include <math.h>
#include <dolphin/dolphin.h>
#include "font.h"
#define DEBUG false
/*
0 empty
1 2
2 4
3 8
4 16
5 32
6 64
7 128
8 256
9 512
10 1024
11 2048
12 4096
...
*/
typedef uint8_t cell_state;
/* DirectionLeft <--
┌╌╌╌╌┐┌╌╌╌╌┐┌╌╌╌╌┐┌╌╌╌╌┐
╎ ╎╎ ╎╎ ╎╎ ╎
└╌╌╌╌┘└╌╌╌╌┘└╌╌╌╌┘└╌╌╌╌┘
┌╌╌╌╌┐┌╌╌╌╌┐┌╌╌╌╌┐┌╌╌╌╌┐
╎ ╎╎ ╎╎ ╎╎ ╎
└╌╌╌╌┘└╌╌╌╌┘└╌╌╌╌┘└╌╌╌╌┘
┌╌╌┌╌╌╌╌┐╌╌┐┌╌╌╌╌┐┌╌╌╌╌┐
╎ 2╎ 2 ╎ ╎╎ ╎╎ ╎
└╌╌└╌╌╌╌┘╌╌┘└╌╌╌╌┘└╌╌╌╌┘
┌╌╌┌╌╌╌╌┐┌╌╌┌╌╌╌╌┐┌╌╌╌╌┐
╎ 4╎ 4 ╎╎ 2╎ 2 ╎╎ ╎
└╌╌└╌╌╌╌┘└╌╌└╌╌╌╌┘└╌╌╌╌┘
*/
typedef enum {
DirectionIdle,
DirectionUp,
DirectionRight,
DirectionDown,
DirectionLeft,
} Direction;
typedef struct {
uint8_t y; // 0 <= y <= 3
uint8_t x; // 0 <= x <= 3
} Point;
typedef struct {
uint32_t gameScore;
uint32_t highScore;
} Score;
typedef struct {
/*
+----X
|
| field[x][y]
Y
*/
uint8_t field[4][4];
uint8_t next_field[4][4];
Score score; // original scoring
Direction direction;
/*
field {
animation-timing-function: linear;
animation-duration: 300ms;
}
*/
uint32_t animation_start_ticks;
Point keyframe_from[4][4];
Point keyframe_to[4][4];
bool debug;
} GameState;
#define XtoPx(x) (33 + x * 15)
#define YtoPx(x) (1 + y * 15)
static void game_2048_render_callback(Canvas* const canvas, ValueMutex* const vm) {
const GameState* game_state = acquire_mutex(vm, 25);
if(game_state == NULL) {
return;
}
// Before the function is called, the state is set with the canvas_reset(canvas)
if(game_state->direction == DirectionIdle) {
for(uint8_t y = 0; y < 4; y++) {
for(uint8_t x = 0; x < 4; x++) {
uint8_t field = game_state->field[y][x];
canvas_set_color(canvas, ColorBlack);
canvas_draw_frame(canvas, XtoPx(x), YtoPx(y), 16, 16);
if(field != 0) {
game_2048_draw_number(canvas, XtoPx(x), YtoPx(y), 1 << field);
}
}
}
// display score
char buffer[12];
snprintf(buffer, sizeof(buffer), "%lu", game_state->score.gameScore);
canvas_draw_str_aligned(canvas, 127, 8, AlignRight, AlignBottom, buffer);
if(game_state->score.highScore > 0) {
char buffer2[12];
snprintf(buffer2, sizeof(buffer2), "%lu", game_state->score.highScore);
canvas_draw_str_aligned(canvas, 127, 62, AlignRight, AlignBottom, buffer2);
}
} else { // if animation
// for animation
// (osKernelGetSysTimerCount() - game_state->animation_start_ticks) / osKernelGetSysTimerFreq();
// TODO: end animation event/callback/set AnimationIdle
}
release_mutex(vm, game_state);
}
static void
game_2048_input_callback(const InputEvent* const input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
}
// if return false then Game Over
static bool game_2048_set_new_number(GameState* const game_state) {
uint8_t empty = 0;
for(uint8_t y = 0; y < 4; y++) {
for(uint8_t x = 0; x < 4; x++) {
if(game_state->field[y][x] == 0) {
empty++;
}
}
}
if(empty == 0) {
return false;
}
if(empty == 1) {
// If it is 1 move before losing, we help the player and get rid of randomness.
for(uint8_t y = 0; y < 4; y++) {
for(uint8_t x = 0; x < 4; x++) {
if(game_state->field[y][x] == 0) {
bool haveFour =
// +----X
// |
// | field[x][y], 0 <= x, y <= 3
// Y
// up == 4 or
(y > 0 && game_state->field[y - 1][x] == 2) ||
// right == 4 or
(x < 3 && game_state->field[y][x + 1] == 2) ||
// down == 4
(y < 3 && game_state->field[y + 1][x] == 2) ||
// left == 4
(x > 0 && game_state->field[y][x - 1] == 2);
if(haveFour) {
game_state->field[y][x] = 2;
return true;
}
game_state->field[y][x] = 1;
return true;
}
}
}
}
uint8_t target = rand() % empty;
uint8_t twoOrFore = rand() % 4 < 3;
for(uint8_t y = 0; y < 4; y++) {
for(uint8_t x = 0; x < 4; x++) {
if(game_state->field[y][x] == 0) {
if(target == 0) {
if(twoOrFore) {
game_state->field[y][x] = 1; // 2^1 == 2 75%
} else {
game_state->field[y][x] = 2; // 2^2 == 4 25%
}
goto exit;
}
target--;
}
}
}
exit:
return true;
}
// static void game_2048_process_row(uint8_t before[4], uint8_t *(after[4])) {
// // move 1 row left.
// for(uint8_t i = 0; i <= 2; i++) {
// if(before[i] != 0 && before[i] == before[i + 1]) {
// before[i]++;
// before[i + 1] = 0;
// i++;
// }
// }
// for(uint8_t i = 0, j = 0; i <= 3; i++) {
// if (before[i] != 0) {
// before[j] = before[i];
// i++;
// }
// }
// }
static void game_2048_process_move(GameState* const game_state) {
memset(game_state->next_field, 0, sizeof(game_state->next_field));
// +----X
// |
// | field[x][y], 0 <= x, y <= 3
// Y
// up
if(game_state->direction == DirectionUp) {
for(uint8_t x = 0; x < 4; x++) {
uint8_t next_y = 0;
for(int8_t y = 0; y < 4; y++) {
uint8_t field = game_state->field[y][x];
if(field == 0) {
continue;
}
if(game_state->next_field[next_y][x] == 0) {
game_state->next_field[next_y][x] = field;
continue;
}
if(field == game_state->next_field[next_y][x]) {
game_state->next_field[next_y][x]++;
game_state->score.gameScore += pow(2, game_state->next_field[next_y][x]);
if(game_state->next_field[next_y][x] == 11 && !game_state->debug) {
DOLPHIN_DEED(getRandomDeed());
} // get some xp for making a 2048 tile
next_y++;
continue;
}
next_y++;
game_state->next_field[next_y][x] = field;
}
}
}
// right
if(game_state->direction == DirectionRight) {
for(uint8_t y = 0; y < 4; y++) {
uint8_t next_x = 3;
for(int8_t x = 3; x >= 0; x--) {
uint8_t field = game_state->field[y][x];
if(field == 0) {
continue;
}
if(game_state->next_field[y][next_x] == 0) {
game_state->next_field[y][next_x] = field;
continue;
}
if(field == game_state->next_field[y][next_x]) {
game_state->next_field[y][next_x]++;
game_state->score.gameScore += pow(2, game_state->next_field[y][next_x]);
if(game_state->next_field[y][next_x] == 11 && !game_state->debug) {
DOLPHIN_DEED(getRandomDeed());
} // get some xp for making a 2048 tile
next_x--;
continue;
}
next_x--;
game_state->next_field[y][next_x] = field;
}
}
}
// down
if(game_state->direction == DirectionDown) {
for(uint8_t x = 0; x < 4; x++) {
uint8_t next_y = 3;
for(int8_t y = 3; y >= 0; y--) {
uint8_t field = game_state->field[y][x];
if(field == 0) {
continue;
}
if(game_state->next_field[next_y][x] == 0) {
game_state->next_field[next_y][x] = field;
continue;
}
if(field == game_state->next_field[next_y][x]) {
game_state->next_field[next_y][x]++;
game_state->score.gameScore += pow(2, game_state->next_field[next_y][x]);
if(game_state->next_field[next_y][x] == 11 && !game_state->debug) {
DOLPHIN_DEED(getRandomDeed());
} // get some xp for making a 2048 tile
next_y--;
continue;
}
next_y--;
game_state->next_field[next_y][x] = field;
}
}
}
// 0, 0, 1, 1
// 1, 0, 0, 0
// left
if(game_state->direction == DirectionLeft) {
for(uint8_t y = 0; y < 4; y++) {
uint8_t next_x = 0;
for(uint8_t x = 0; x < 4; x++) {
uint8_t field = game_state->field[y][x];
if(field == 0) {
continue;
}
if(game_state->next_field[y][next_x] == 0) {
game_state->next_field[y][next_x] = field;
continue;
}
if(field == game_state->next_field[y][next_x]) {
game_state->next_field[y][next_x]++;
game_state->score.gameScore += pow(2, game_state->next_field[y][next_x]);
if(game_state->next_field[y][next_x] == 11 && !game_state->debug) {
DOLPHIN_DEED(getRandomDeed());
} // get some xp for making a 2048 tile
next_x++;
continue;
}
next_x++;
game_state->next_field[y][next_x] = field;
}
}
}
// <debug>
game_state->direction = DirectionIdle;
memcpy(game_state->field, game_state->next_field, sizeof(game_state->field));
// </debug>
}
static void game_2048_restart(GameState* const game_state) {
game_state->debug = DEBUG;
// check score
if(game_state->score.gameScore > game_state->score.highScore) {
game_state->score.highScore = game_state->score.gameScore;
}
// clear all cells
for(uint8_t y = 0; y < 4; y++) {
for(uint8_t x = 0; x < 4; x++) {
game_state->field[y][x] = 0;
}
}
// start next game
game_state->score.gameScore = 0;
game_2048_set_new_number(game_state);
game_2048_set_new_number(game_state);
}
int32_t game_2048_app(void* p) {
UNUSED(p);
int32_t return_code = 0;
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
GameState* game_state = malloc(sizeof(GameState));
ValueMutex state_mutex;
if(!init_mutex(&state_mutex, game_state, sizeof(GameState))) {
return_code = 255;
goto free_and_exit;
}
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(
view_port, (ViewPortDrawCallback)game_2048_render_callback, &state_mutex);
view_port_input_callback_set(
view_port, (ViewPortInputCallback)game_2048_input_callback, event_queue);
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
game_state->direction = DirectionIdle;
game_2048_restart(game_state);
if(game_state->debug) {
game_state->field[0][0] = 0;
game_state->field[0][1] = 0;
game_state->field[0][2] = 0;
game_state->field[0][3] = 0;
game_state->field[1][0] = 1;
game_state->field[1][1] = 2;
game_state->field[1][2] = 3;
game_state->field[1][3] = 4;
game_state->field[2][0] = 5;
game_state->field[2][1] = 6;
game_state->field[2][2] = 7;
game_state->field[2][3] = 8;
game_state->field[3][0] = 9;
game_state->field[3][1] = 10;
game_state->field[3][2] = 11;
game_state->field[3][3] = 12;
}
InputEvent event;
for(bool loop = true; loop;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
GameState* game_state = (GameState*)acquire_mutex_block(&state_mutex);
if(event_status == FuriStatusOk) {
if(event.type == InputTypeShort) {
switch(event.key) {
case InputKeyUp:
game_state->direction = DirectionUp;
game_2048_process_move(game_state);
game_2048_set_new_number(game_state);
break;
case InputKeyDown:
game_state->direction = DirectionDown;
game_2048_process_move(game_state);
game_2048_set_new_number(game_state);
break;
case InputKeyRight:
game_state->direction = DirectionRight;
game_2048_process_move(game_state);
game_2048_set_new_number(game_state);
break;
case InputKeyLeft:
game_state->direction = DirectionLeft;
game_2048_process_move(game_state);
game_2048_set_new_number(game_state);
break;
case InputKeyOk:
game_state->direction = DirectionIdle;
break;
case InputKeyBack:
loop = false;
break;
}
} else if(event.type == InputTypeLong) {
if(event.key == InputKeyOk) {
game_state->direction = DirectionIdle;
game_2048_restart(game_state);
}
}
}
view_port_update(view_port);
release_mutex(&state_mutex, game_state);
}
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
view_port_free(view_port);
delete_mutex(&state_mutex);
free_and_exit:
free(game_state);
furi_message_queue_free(event_queue);
return return_code;
}
@@ -0,0 +1,62 @@
# flipperzero-nrf24
An [NRF24](https://www.sparkfun.com/datasheets/Components/SMD/nRF24L01Pluss_Preliminary_Product_Specification_v1_0.pdf) driver for the [Flipper Zero](https://flipperzero.one/) device. The NRF24 is a popular line of 2.4GHz radio transceivers from Nordic Semiconductors. This library is not currently complete, but functional.
## Warning
This repo contains two Flipper Zero apps that utilize the NRF24 driver to sniff for NRF24 addresses and perform mousejack attacks. These apps are for **educational purposes** only. Please use this code responsibly and only use these apps on your own equipment.
## Acknowledgments
The NRF24 sniffing technique was discovered and shared by Travis Goodspeed in [his blog](http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html).
The mousejack vulnerabilities were discovered and reported by Marc Newlin, see [the blog](https://www.bastille.net/research/vulnerabilities/mousejack/technical-details) for technical details.
Much of the driver code was inspired by [RadioHead's Arduino library](https://www.airspayce.com/mikem/arduino/RadioHead/classRH__NRF24.html).
Much of the mousejack code was inspired by the [Jackit project](https://github.com/insecurityofthings/jackit).
## PinOut from from NoComp/Frog
<img src="https://media.discordapp.net/attachments/937479784726949900/994495234618687509/unknown.png?width=567&height=634">
# Mousejack / NRF24 pinout by UberGuidoZ
2/A7 on FZ goes to MOSI/6 on nrf24l01<br>
3/A6 on FZ goes to MISO/7 on nrf24l01<br>
4/A4 on FZ goes to CSN/4 on nrf24l01<br>
5/B3 on FZ goes to SCK/5 on nrf24l01<br>
6/B2 on FZ goes to CE/3 on nrf24l01<br>
8/GND on FZ goes to GND/1 on nrf24l01<br>
9/3V3 on FZ goes to VCC/2 on nrf24l01<br>
IRQ/8 is left disconnected on nrf24l01
![NRF_Pins](https://user-images.githubusercontent.com/57457139/178093717-39effd5c-ebe2-4253-b13c-70517d7902f9.png)
If the nRF module is acting a bit flakey, try adding a capacitor to the vcc/gnd lines! I've not tried the Plus model so it may have a bigger need for a cap. Otherwise, I haven't had any major issues. Anything from a 3.3 uF to 10 uF should do. (Watch your positive/negative placement! Negative to ground.) I learned if you wanna get fancy, include a 0.1 uF cap in parallel. The 3.3 uF to 10 uF will respond to slow freq changes while the 0.1 uF will respond to the high freq switching spikes that the larger one cannot. That said, a single 10 uF will likely suffice for the Mousejack attack. ¯\\\_(ツ)_/¯
![NRF_Capacitor](https://user-images.githubusercontent.com/57457139/178169959-d030f9a6-d2ac-46af-af8b-470ff092c8a7.jpg)
Selfmade NRF24 breakoutboard:
![NRF_soldered](https://user-images.githubusercontent.com/22019133/183419103-9c40b28b-8152-4212-98e0-9a3358f69518.jpeg)
![NRF_soldered2](https://user-images.githubusercontent.com/22019133/183419176-26c0359b-0ecb-4015-8f8b-3a75209502ba.jpeg)
## Practical hints from einstein2150
If you are not successfull with the NRF Sniff Plugin you can try to get the MAC of the device with the crazyradio pa USB dongle. Have a look here: https://github.com/SySS-Research/nrf24-playset
A sample output of the NRF-Research script could be like
```
[2022-08-05 13:28:56.366] Found nRF24 device with address 38:24:93:C0:07 on channel 75\
[2022-08-05 13:28:56.371] Checking communication\
[2022-08-05 13:28:59.088] Scan for nRF24 device\
[2022-08-05 13:28:59.097] Actively searching for address 07:C0:93:24:38\
```
Be carefull with the byte-order using in mousejacker! The correct byte order is the reverse-byteorder. In my example the reversed one is ```07:C0:93:24:38``` for my Logitech R400 presenter.
The next thing which could make trouble is the datarate. In my case the Logitech-device is only responding at 2Mbit. Commands at 1Mbit are not detected.
Now its time to write all the relevant information in the config file. In my case you are creating a file ```addresses.txt``` in the SD directory of ```/nrfsniff```. The file content corresponding to the results of the research is ```07C0932438,2``` representing the reversed byte order of the MAC and the comma-separated datarate.
Start the Mouse Jacker plugin and select the prepared ```addresses.txt```. If everything is alright you are starting with your MAC ready for attack:
![mousejacker start-screen](https://user-images.githubusercontent.com/22019133/183419533-ef5c8df1-e328-45e3-b85d-376513d69c82.jpeg)
If you have troube you can check if a datarate of 1 Mbit will help. Change ```07C0932438,2``` to ```07C0932438,1``` in this case. Another problem in the practical use is electromagnetical noise. In my case the external USB-3.1-Hub creating massive noise in the 2,4 Ghz-Frequency around a distance of 5 cm. Try using a long USB connection-cable for the receiver. In my case the response of the attack raises significant because the signals of the NRF-breakoutboard is no more covered with noise.
@@ -10,6 +10,7 @@
#include <furi_hal_resources.h>
#include <nrf24.h>
#include "mousejacker_ducky.h"
#include <dolphin/dolphin.h>
#define TAG "mousejacker"
#define LOGITECH_MAX_CHANNEL 85
@@ -174,6 +175,7 @@ static bool process_ducky_file(
mj_process_ducky_script(
nrf24_HANDLE, addr, addr_size, rate, (char*)file_buf, plugin_state);
FURI_LOG_D(TAG, "finished execution");
DOLPHIN_DEED(getRandomDeed());
loaded = true;
} else {
FURI_LOG_D(TAG, "load failed. file size: %d", file_size);
@@ -256,7 +256,7 @@ MusicPlayer* music_player_alloc() {
instance->model = malloc(sizeof(MusicPlayerModel));
memset(instance->model->duration_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE);
memset(instance->model->semitone_history, 0xff, MUSIC_PLAYER_SEMITONE_HISTORY_SIZE);
instance->model->volume = 3;
instance->model->volume = 4;
instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
+31
View File
@@ -0,0 +1,31 @@
# flipperzero-nrf24
An [NRF24](https://www.sparkfun.com/datasheets/Components/SMD/nRF24L01Pluss_Preliminary_Product_Specification_v1_0.pdf) driver for the [Flipper Zero](https://flipperzero.one/) device. The NRF24 is a popular line of 2.4GHz radio transceivers from Nordic Semiconductors. This library is not currently complete, but functional.
## Warning
This repo contains two Flipper Zero apps that utilize the NRF24 driver to sniff for NRF24 addresses and perform mousejack attacks. These apps are for **educational purposes** only. Please use this code responsibly and only use these apps on your own equipment.
## Acknowledgments
The NRF24 sniffing technique was discovered and shared by Travis Goodspeed in [his blog](http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html).
The mousejack vulnerabilities were discovered and reported by Marc Newlin, see [the blog](https://www.bastille.net/research/vulnerabilities/mousejack/technical-details) for technical details.
Much of the driver code was inspired by [RadioHead's Arduino library](https://www.airspayce.com/mikem/arduino/RadioHead/classRH__NRF24.html).
Much of the mousejack code was inspired by the [Jackit project](https://github.com/insecurityofthings/jackit).
#
## PinOut from from NoComp/Frog
<img src="https://media.discordapp.net/attachments/937479784726949900/994495234618687509/unknown.png?width=567&height=634">
# Mousejack / NRF24 pinout by UberGuidoZ
2/A7 on FZ goes to MOSI/6 on nrf24l01<br>
3/A6 on FZ goes to MISO/7 on nrf24l01<br>
4/A4 on FZ goes to CSN/4 on nrf24l01<br>
5/B3 on FZ goes to SCK/5 on nrf24l01<br>
6/B2 on FZ goes to CE/3 on nrf24l01<br>
8/GND on FZ goes to GND/1 on nrf24l01<br>
9/3V3 on FZ goes to VCC/2 on nrf24l01<br>
IRQ/8 is left disconnected on nrf24l01
![NRF_Pins](https://user-images.githubusercontent.com/57457139/178093717-39effd5c-ebe2-4253-b13c-70517d7902f9.png)
If the nRF module is acting a bit flakey, try adding a capacitor to the vcc/gnd lines! I've not tried the Plus model so it may have a bigger need for a cap. Otherwise, I haven't had any major issues. Anything from a 3.3 uF to 10 uF should do. (Watch your positive/negative placement! Negative to ground.) I learned if you wanna get fancy, include a 0.1 uF cap in parallel. The 3.3 uF to 10 uF will respond to slow freq changes while the 0.1 uF will respond to the high freq switching spikes that the larger one cannot. That said, a single 10 uF will likely suffice for the Mousejack attack. ¯\\\_(ツ)_/¯
![NRF_Capacitor](https://user-images.githubusercontent.com/57457139/178169959-d030f9a6-d2ac-46af-af8b-470ff092c8a7.jpg)
+5 -2
View File
@@ -4,7 +4,7 @@
#include <input/input.h>
#include <notification/notification_messages.h>
#include <stdlib.h>
#include <dolphin/dolphin.h>
#include <nrf24.h>
#include <toolbox/stream/file_stream.h>
@@ -291,6 +291,7 @@ static void wrap_up(Storage* storage, NotificationApp* notification) {
hexlify(addr, 5, top_address);
found_count++;
save_addr_to_file(storage, addr, 5, notification);
DOLPHIN_DEED(getRandomDeed());
if(confirmed_idx < MAX_CONFIRMED) memcpy(confirmed[confirmed_idx++], addr, 5);
break;
}
@@ -402,6 +403,9 @@ int32_t nrfsniff_app(void* p) {
}
}
}
} else {
// FURI_LOG_D(TAG, "osMessageQueue: event timeout");
// event timeout
}
if(sniffing_state) {
@@ -448,7 +452,6 @@ int32_t nrfsniff_app(void* p) {
furi_record_close(RECORD_STORAGE);
view_port_free(view_port);
furi_message_queue_free(event_queue);
free(plugin_state);
return 0;
}
+16 -4
View File
@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <notification/notification.h>
#include <notification/notification_messages.h>
#include <dolphin/dolphin.h>
typedef struct {
// +-----x
@@ -61,12 +62,17 @@ typedef struct {
InputEvent input;
} SnakeEvent;
static const NotificationSequence sequence_short_vibro_and_sound = {
static const NotificationSequence sequence_short_vibro_and_rgb = {
&message_red_255,
&message_blue_255,
&message_green_255,
&message_vibro_on,
&message_note_c5,
&message_delay_50,
&message_delay_100,
&message_sound_off,
&message_vibro_off,
&message_red_0,
&message_blue_0,
&message_green_0,
NULL,
};
@@ -113,6 +119,10 @@ static void snake_game_render_callback(Canvas* const canvas, void* ctx) {
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 37, 31, "Game Over");
if((snake_state->len - 7) % 20 == 0 && (snake_state->len - 7) != 0) {
DOLPHIN_DEED(getRandomDeed());
}
canvas_set_font(canvas, FontSecondary);
char buffer[12];
snprintf(buffer, sizeof(buffer), "Score: %u", snake_state->len - 7);
@@ -266,6 +276,7 @@ static void snake_game_process_game_step(SnakeState* const snake_state, Notifica
return;
} else if(snake_state->state == GameStateLastChance) {
snake_state->state = GameStateGameOver;
notification_message(notify, &sequence_single_vibro);
return;
}
} else {
@@ -277,17 +288,18 @@ static void snake_game_process_game_step(SnakeState* const snake_state, Notifica
crush = snake_game_collision_with_tail(snake_state, next_step);
if(crush) {
snake_state->state = GameStateGameOver;
notification_message(notify, &sequence_single_vibro);
return;
}
bool eatFruit = (next_step.x == snake_state->fruit.x) && (next_step.y == snake_state->fruit.y);
if(eatFruit) {
notification_message(notify, &sequence_short_vibro_and_sound);
//notification_message(notify, &sequence_blink_white_100);
snake_state->len++;
if(snake_state->len >= MAX_SNAKE_LEN) {
snake_state->state = GameStateGameOver;
notification_message(notify, &sequence_single_vibro);
return;
}
}
@@ -6,6 +6,7 @@
#include <string.h>
#include <furi_hal_resources.h>
#include <furi_hal_gpio.h>
#include <dolphin/dolphin.h>
#define BORDER_OFFSET 1
#define MARGIN_OFFSET 3
@@ -150,6 +151,10 @@ static void tetris_game_render_callback(Canvas* const canvas, void* ctx) {
canvas_set_font(canvas, FontPrimary);
canvas_draw_str(canvas, 4, 63, "Game Over");
if(tetris_state->numLines % 8 == 0 && tetris_state->numLines != 0) {
DOLPHIN_DEED(getRandomDeed());
}
char buffer[13];
snprintf(buffer, sizeof(buffer), "Lines: %u", tetris_state->numLines);
canvas_set_font(canvas, FontSecondary);
+5 -10
View File
@@ -17,19 +17,14 @@
#define WAVPLAYER_FOLDER "/ext/wav_player"
static bool open_wav_stream(Stream* stream) {
DialogsApp* dialogs = furi_record_open("dialogs");
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
bool result = false;
string_t path;
string_init(path);
string_set_str(path, WAVPLAYER_FOLDER);
bool ret = dialog_file_browser_show(dialogs, path, path, ".wav", true, &I_music_10px, false);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, ".wav", &I_music_10px);
browser_options.hide_ext = false;
bool ret = dialog_file_browser_show(dialogs, path, path, &browser_options);
furi_record_close("dialogs");
furi_record_close(RECORD_DIALOGS);
if(ret) {
if(!file_stream_open(stream, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
FURI_LOG_E(TAG, "Cannot open file \"%s\"", string_get_cstr(path));
@@ -119,7 +114,7 @@ static WavPlayerApp* app_alloc() {
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
app->notification = furi_record_open("notification");
app->notification = furi_record_open(RECORD_NOTIFICATION);
notification_message(app->notification, &sequence_display_backlight_enforce_on);
return app;
@@ -139,7 +134,7 @@ static void app_free(WavPlayerApp* app) {
furi_record_close(RECORD_STORAGE);
notification_message(app->notification, &sequence_display_backlight_enforce_auto);
furi_record_close("notification");
furi_record_close(RECORD_NOTIFICATION);
free(app);
}
+69
View File
@@ -0,0 +1,69 @@
#####################################
encode.py
decode.py
iconencode.py
icondecode.py
A set of python3 scripts for processing the Flipper image files.
These work as-is but I am rolling in improvements.
#####################################
PREREQUISITES
You'll need heatshrink installed - a small embedded/RTOS compression and decompression library
You can get that here https://github.com/atomicobject/heatshrink
#####################################
HOW TO USE
##
# decode.
Decode a .mb into .xbm:
decode.py input_image output_image [width] [height]
Dimensions are not stored in .bm so you need to specify
If you have the meta.txt available for the animation set the dimensions will be in here.
It may also be part of the directory name for the animation files as well.
If you do not enter anything here it will assume 128x64. THIS WILL NOT ALWAYS BE CORRECT.
##
# encode
Encode an .xbm file into .xb
encode.py input_image output_image
You will also get the image dimensions for use in meta.txt
That's it.
##
# iconencode
Compress an icon asset from an XBM to a compressed char array ready to paste
Will assume dimensions of 128x64
Header works like this, you'll have to do this manually for now!
Image Header Format Example
0x01 = Compressed
0x00 = Reserved Section
0xa4,0x01 = 0x1a4, or, 420 - the size of the compressed array, minus this header. Just count the commas ;)
Rest of the data is char array output from heatshrink of the original XBM char array.
Calculated Header: 0x01,0x00,0xa4,0x01
from furi_hal_compress.c:
typedef struct {
uint8_t is_compressed;
uint8_t reserved;
uint16_t compressed_buff_size;
} FuriHalCompressHeader;
##
# icondecode
Decompress an icon asset (as found in assets_icons.c and elsewhere)
icondecodepy input_image output_image [trim] [width] [height]
The icons in this file have a different header format. This will need to be trimmed.
A value of 8 for trim appears to be correct.
As with regular decoding, the width and height are not listed - but can be found in code/const/variable/etc names.
copy just the char array. The script does not care if the curly braces or semicolon are in place.
i.e. the following are all acceptable and equivalent.
{0x00,0x08,0x1C,0x3E,0x7F,};
{0x00,0x08,0x1C,0x3E,0x7F,}
0x00,0x08,0x1C,0x3E,0x7F
+74
View File
@@ -0,0 +1,74 @@
import logging
import argparse
import subprocess
import io
import os
import sys
def padded_hex(i, l):
given_int = i
given_len = l
hex_result = hex(given_int)[2:] # remove '0x' from beginning of str
num_hex_chars = len(hex_result)
extra_zeros = '0' * (given_len - num_hex_chars) # may not get used..
return ('0x' + hex_result if num_hex_chars == given_len else
'?' * given_len if num_hex_chars > given_len else
'0x' + extra_zeros + hex_result if num_hex_chars < given_len else
None)
parser = argparse.ArgumentParser(description='Turn cooked Flipper .bm files back into .xbm')
parser.add_argument('infile', metavar='i',
help='Input file')
parser.add_argument('outfile', metavar='o',
help='File to write to')
parser.add_argument('Width', metavar='W', type=int, nargs="?", default="128",
help='Width of the image. Find from meta.txt or directory name')
parser.add_argument('Height', metavar='H', type=int, nargs="?", default="64",
help='Height of the image. Find from meta.txt or directory name')
args = vars(parser.parse_args())
r = open(args["infile"],"rb")
w = open(args["outfile"],"w")
fileStream=r.read()
filename=os.path.splitext(os.path.basename(args["outfile"]))[0]
imageWidth=args["Width"]
imageHeight=args["Height"]
#remove headers and padding
if(fileStream[0:2] == bytes([0x01,0x00])):
unpad=fileStream[4:]
else:
if(fileStream[0:1] == bytes([0x00])):
unpad=fileStream[2:]
#lzss decompress
data_decoded_str = subprocess.check_output(
["heatshrink", "-d","-w8","-l4"], input=unpad
)
#turn it back into xbm
b=list(data_decoded_str)
c=', '.join(padded_hex(my_int,2) for my_int in b)
width_out = "#define "+ filename+ "_width "+ str(imageWidth) + "\n"
height_out = "#define "+ filename+ "_height "+ str(imageHeight) + "\n"
bytes_out = "static unsigned char "+ filename+ "_bits[] = {"+ str(c) + "};"
data=width_out+height_out+bytes_out
w.write(data)
r.close()
w.close()
+49
View File
@@ -0,0 +1,49 @@
import logging
import argparse
import subprocess
import io
import os
import sys
parser = argparse.ArgumentParser(description='Turn .xbm files into cooked .bm files for flipper FS')
parser.add_argument('infile', metavar='i',
help='Input file')
parser.add_argument('outfile', metavar='o',
help='File to write to')
args = vars(parser.parse_args())
r = open(args["infile"],"r")
w = open(args["outfile"],"wb")
output = subprocess.check_output(["cat", args["infile"]])
f = io.StringIO(output.decode().strip())
print("Image Dimensions:")
width = int(f.readline().strip().split(" ")[2])
print("W: ", width)
height = int(f.readline().strip().split(" ")[2])
print("H: ", height)
data = f.read().strip().replace("\n", "").replace(" ", "").split("=")[1][:-1]
data_str = data[1:-1].replace(",", " ").replace("0x", "")
data_bin = bytearray.fromhex(data_str)
data_encoded_str = subprocess.check_output(
["heatshrink", "-e", "-w8", "-l4"], input=data_bin
)
assert data_encoded_str
data_enc = bytearray(data_encoded_str)
data_enc = bytearray([len(data_enc) & 0xFF, len(data_enc) >> 8]) + data_enc
if len(data_enc) < len(data_bin) + 1:
data = b"\x01\x00" + data_enc
else:
data = b"\x00" + data_bin
w.write(data)
r.close()
w.close()
+65
View File
@@ -0,0 +1,65 @@
import logging
import argparse
import subprocess
import io
import os
import sys
def padded_hex(i, l):
given_int = i
given_len = l
hex_result = hex(given_int)[2:] # remove '0x' from beginning of str
num_hex_chars = len(hex_result)
extra_zeros = '0' * (given_len - num_hex_chars) # may not get used..
return ('0x' + hex_result if num_hex_chars == given_len else
'?' * given_len if num_hex_chars > given_len else
'0x' + extra_zeros + hex_result if num_hex_chars < given_len else
None)
parser = argparse.ArgumentParser(description='Turn icon char arrays back into .xbm')
parser.add_argument('infile', metavar='i',
help='Input file')
parser.add_argument('outfile', metavar='o',
help='File to write to')
parser.add_argument('Width', metavar='W', type=int, nargs="?", default="128",
help='Width of the image. Find from meta.txt or directory name')
parser.add_argument('Height', metavar='H', type=int, nargs="?", default="64",
help='Height of the image. Find from meta.txt or directory name')
parser.add_argument('Trim', metavar='T', type=int, nargs="?", default="8",
help='Number of bytes off the start/header to trim. Multiples of 2 required.')
args = vars(parser.parse_args())
r = open(args["infile"],"r")
w = open(args["outfile"],"w")
imageWidth=args["Width"]
imageHeight=args["Height"]
trimStart=args["Trim"]
output = subprocess.check_output(["cat", args["infile"]]) #yes this is terrible.
f = io.StringIO(output.decode().strip())
data = f.read().strip().replace(";","").replace("{","").replace("}","")
data_str = data.replace(",", "").replace("0x", "")
data_bin = bytearray.fromhex(data_str[trimStart:])
data_decoded_str = subprocess.check_output(
["heatshrink", "-d","-w8","-l4"], input=data_bin
)
b=list(data_decoded_str)
c=', '.join(padded_hex(my_int,2) for my_int in b)
width_out = "#define icon_width "+ str(imageWidth) + "\n"
height_out = "#define icon_height "+ str(imageHeight) + "\n"
bytes_out = "static unsigned char icon_bits[] = {"+ str(c) + "};"
data=width_out+height_out+bytes_out
w.write(data)
r.close()
w.close()
+68
View File
@@ -0,0 +1,68 @@
import logging
import argparse
import subprocess
import io
import os
import sys
def padded_hex(i, l):
given_int = i
given_len = l
hex_result = hex(given_int)[2:] # remove '0x' from beginning of str
num_hex_chars = len(hex_result)
extra_zeros = '0' * (given_len - num_hex_chars) # may not get used..
return ('0x' + hex_result if num_hex_chars == given_len else
'?' * given_len if num_hex_chars > given_len else
'0x' + extra_zeros + hex_result if num_hex_chars < given_len else
None)
parser = argparse.ArgumentParser(description='Turn icon char arrays back into .xbm')
parser.add_argument('infile', metavar='i',
help='Input file')
parser.add_argument('Width', metavar='W', type=int, nargs="?", default="128",
help='Width of the image. Find from meta.txt or directory name')
parser.add_argument('Height', metavar='H', type=int, nargs="?", default="64",
help='Height of the image. Find from meta.txt or directory name')
args = vars(parser.parse_args())
r = open(args["infile"],"r")
infile=args["infile"].split(".")[0]
imageWidth=args["Width"]
imageHeight=args["Height"]
dims=str(imageWidth)+"x"+str(imageHeight)
output = subprocess.check_output(["cat", args["infile"]]) #yes this is terrible.
f = io.StringIO(output.decode().strip())
data = f.read().strip().replace(";","").replace("{","").replace("}","")
data_str = data.replace(",", "").replace("0x", "")
data_bin = bytearray.fromhex(data_str)
data_encoded_str = subprocess.check_output(
["heatshrink", "-e","-w8","-l4"], input=data_bin
)
b=list(data_encoded_str)
c=','.join(padded_hex(my_int,2) for my_int in b)
# a bit ugly.
framename="_I_"+infile+"_"+dims
print(len(b))
#d=len(b)
# if b > 255 split 0x1234 into 0x34,0x12
#d=hex(len(b))
char_out = "const uint8_t "+framename+"_0[] = {"+ str(c) + ",};"
char_out2 = "const uint8_t "+framename+"[] = {"+framename+"_0};"
#data=bytes_out
print(char_out)
print(char_out2)
#w.write(data)
#w.close()