├── mousejacker ├── shared ├── mouse_10px.png ├── application.fam └── mousejacker_ducky.h ├── nrfsniff ├── shared ├── nrfsniff_10px.png └── application.fam ├── dice ├── dice.png └── application.fam ├── game2048 ├── font.c ├── 2048.png ├── font.h └── application.fam ├── calculator ├── calc.png ├── calcIcon.png ├── application.fam └── tinyexpr.h ├── montyhall ├── Monty.png └── application.fam ├── paint ├── paintIcon.png ├── application.fam └── paint.c ├── tama_p1 ├── tamaIcon.png ├── icons │ ├── icon_0.png │ ├── icon_1.png │ ├── icon_2.png │ ├── icon_3.png │ ├── icon_4.png │ ├── icon_5.png │ ├── icon_6.png │ └── icon_7.png ├── application.fam ├── tama.h ├── README.md ├── hal_types.h ├── tamalib │ ├── hal_types.h.template │ ├── hw.h │ ├── tamalib.h │ ├── hal.h │ ├── README.md │ ├── tamalib.c │ ├── hw.c │ └── cpu.h ├── compiled │ └── assets_icons.h └── hal.c ├── flipfrid ├── rfid_10px.png ├── application.fam ├── LICENSE.md ├── scene │ ├── flipfrid_scene_entrypoint.h │ ├── flipfrid_scene_run_attack.h │ ├── flipfrid_scene_load_file.h │ ├── flipfrid_scene_select_field.h │ ├── flipfrid_scene_load_custom_uids.h │ ├── flipfrid_scene_load_custom_uids.c │ ├── flipfrid_scene_select_field.c │ ├── flipfrid_scene_load_file.c │ └── flipfrid_scene_entrypoint.c ├── README.md └── flipfrid.h ├── game_of_life ├── golIcon.png ├── application.fam └── game_of_life.c ├── tanksgame ├── tanksIcon.png ├── application.fam └── constants.h ├── videopoker ├── pokerIcon.png └── application.fam ├── wav_player ├── wav_10px.png ├── application.fam ├── wav_player_hal.h ├── wav_parser.h ├── wav_player_view.h ├── wav_player_hal.c ├── wav_parser.c └── wav_player_view.c ├── zombiez ├── zombie_10px.png ├── application.fam └── zombiez.h ├── arkanoid ├── arkanoid_10px.png └── application.fam ├── mandelbrot ├── Mandelbrot.png ├── application.fam └── mandelbrot.c ├── sentry_safe ├── safe_10px.png ├── application.fam └── sentry_safe.c ├── dolphinbackup ├── bckupIcon.png ├── scenes │ ├── storage_DolphinBackup_scene_config.h │ ├── storage_DolphinBackup_scene.h │ ├── storage_DolphinBackup_scene_progress.c │ ├── storage_DolphinBackup_scene.c │ └── storage_DolphinBackup_scene_confirm.c ├── application.fam ├── storage_DolphinBackup.h └── storage_DolphinBackup.c ├── flappy_bird ├── flappy_10px.png ├── application.fam └── bird.h ├── mouse_jiggler ├── mouse_10px.png ├── application.fam └── mouse_jiggler.c ├── tetris_game ├── tetris_10px.png └── application.fam ├── dolphinrestorer ├── restoreIcon.png ├── scenes │ ├── drestorer_scene_config.h │ ├── drestorer_scene.h │ ├── drestorer_scene_progress.c │ ├── drestorer_scene.c │ └── drestorer_scene_confirm.c ├── application.fam ├── drestorer.h └── drestorer.c ├── barcode_generator ├── barcode_10px.png └── application.fam ├── multi_converter ├── converter_10px.png ├── application.fam ├── multi_converter_definitions.h ├── multi_converter_mode_display.h ├── multi_converter_mode_select.h ├── multi_converter_units.h ├── multi_converter.c ├── multi_converter_mode_select.c └── multi_converter_units.c ├── shared └── shim │ ├── string.h │ └── string.c ├── tictactoe_game ├── tictactoe_10px.png └── application.fam ├── spectrum_analyzer ├── spectrum_10px.png ├── application.fam ├── spectrum_analyzer_worker.h ├── spectrum_analyzer.h └── spectrum_analyzer_worker.c ├── .gitmodules └── Readme.md /mousejacker/shared: -------------------------------------------------------------------------------- 1 | ../shared -------------------------------------------------------------------------------- /nrfsniff/shared: -------------------------------------------------------------------------------- 1 | ../shared -------------------------------------------------------------------------------- /dice/dice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/dice/dice.png -------------------------------------------------------------------------------- /game2048/font.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/game2048/font.c -------------------------------------------------------------------------------- /calculator/calc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/calculator/calc.png -------------------------------------------------------------------------------- /game2048/2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/game2048/2048.png -------------------------------------------------------------------------------- /montyhall/Monty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/montyhall/Monty.png -------------------------------------------------------------------------------- /paint/paintIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/paint/paintIcon.png -------------------------------------------------------------------------------- /tama_p1/tamaIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tama_p1/tamaIcon.png -------------------------------------------------------------------------------- /calculator/calcIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/calculator/calcIcon.png -------------------------------------------------------------------------------- /flipfrid/rfid_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/flipfrid/rfid_10px.png -------------------------------------------------------------------------------- /game_of_life/golIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/game_of_life/golIcon.png -------------------------------------------------------------------------------- /tama_p1/icons/icon_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tama_p1/icons/icon_0.png -------------------------------------------------------------------------------- /tama_p1/icons/icon_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tama_p1/icons/icon_1.png -------------------------------------------------------------------------------- /tama_p1/icons/icon_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tama_p1/icons/icon_2.png -------------------------------------------------------------------------------- /tama_p1/icons/icon_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tama_p1/icons/icon_3.png -------------------------------------------------------------------------------- /tama_p1/icons/icon_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tama_p1/icons/icon_4.png -------------------------------------------------------------------------------- /tama_p1/icons/icon_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tama_p1/icons/icon_5.png -------------------------------------------------------------------------------- /tama_p1/icons/icon_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tama_p1/icons/icon_6.png -------------------------------------------------------------------------------- /tama_p1/icons/icon_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tama_p1/icons/icon_7.png -------------------------------------------------------------------------------- /tanksgame/tanksIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tanksgame/tanksIcon.png -------------------------------------------------------------------------------- /videopoker/pokerIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/videopoker/pokerIcon.png -------------------------------------------------------------------------------- /wav_player/wav_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/wav_player/wav_10px.png -------------------------------------------------------------------------------- /zombiez/zombie_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/zombiez/zombie_10px.png -------------------------------------------------------------------------------- /arkanoid/arkanoid_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/arkanoid/arkanoid_10px.png -------------------------------------------------------------------------------- /mandelbrot/Mandelbrot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/mandelbrot/Mandelbrot.png -------------------------------------------------------------------------------- /mousejacker/mouse_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/mousejacker/mouse_10px.png -------------------------------------------------------------------------------- /nrfsniff/nrfsniff_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/nrfsniff/nrfsniff_10px.png -------------------------------------------------------------------------------- /sentry_safe/safe_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/sentry_safe/safe_10px.png -------------------------------------------------------------------------------- /dolphinbackup/bckupIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/dolphinbackup/bckupIcon.png -------------------------------------------------------------------------------- /flappy_bird/flappy_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/flappy_bird/flappy_10px.png -------------------------------------------------------------------------------- /mouse_jiggler/mouse_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/mouse_jiggler/mouse_10px.png -------------------------------------------------------------------------------- /tetris_game/tetris_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tetris_game/tetris_10px.png -------------------------------------------------------------------------------- /dolphinrestorer/restoreIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/dolphinrestorer/restoreIcon.png -------------------------------------------------------------------------------- /barcode_generator/barcode_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/barcode_generator/barcode_10px.png -------------------------------------------------------------------------------- /game2048/font.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void game_2048_draw_number(Canvas* const canvas, uint8_t x, uint8_t y, int number); -------------------------------------------------------------------------------- /multi_converter/converter_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/multi_converter/converter_10px.png -------------------------------------------------------------------------------- /shared/shim/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | char* mystrtok(char* s, char* delm); 4 | char* mystrcat(char *dest, const char *src); 5 | -------------------------------------------------------------------------------- /tictactoe_game/tictactoe_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/tictactoe_game/tictactoe_10px.png -------------------------------------------------------------------------------- /dolphinrestorer/scenes/drestorer_scene_config.h: -------------------------------------------------------------------------------- 1 | ADD_SCENE(drestorer, confirm, Confirm) 2 | ADD_SCENE(drestorer, progress, Progress) 3 | -------------------------------------------------------------------------------- /spectrum_analyzer/spectrum_10px.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vmeurisse/flipperzero-plugins/HEAD/spectrum_analyzer/spectrum_10px.png -------------------------------------------------------------------------------- /dolphinbackup/scenes/storage_DolphinBackup_scene_config.h: -------------------------------------------------------------------------------- 1 | ADD_SCENE(storage_DolphinBackup, confirm, Confirm) 2 | ADD_SCENE(storage_DolphinBackup, progress, Progress) 3 | -------------------------------------------------------------------------------- /dice/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="GAME_Dice", 3 | name="Dice", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="dice_app", 6 | cdefines=["APP_DICE"], 7 | requires=["gui"], 8 | stack_size=2 * 1024, 9 | order=70, 10 | fap_icon="dice.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /paint/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="APPS_Paint", 3 | name="Paint", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="paint_app", 6 | cdefines=["APP_PAINT"], 7 | requires=["gui"], 8 | stack_size=2 * 1024, 9 | order=175, 10 | fap_icon="paintIcon.png", 11 | fap_category="Misc", 12 | ) -------------------------------------------------------------------------------- /wav_player/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="wav_player", 3 | name="WAV Player", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="wav_player_app", 6 | cdefines=["APP_WAV_PLAYER"], 7 | stack_size=4 * 1024, 8 | order=46, 9 | fap_icon="wav_10px.png", 10 | fap_category="Music", 11 | ) 12 | -------------------------------------------------------------------------------- /game2048/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="GAME_2048", 3 | name="2048", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="game_2048_app", 6 | cdefines=["APP_2048_GAME"], 7 | requires=["gui"], 8 | stack_size=2 * 1024, 9 | order=10, 10 | fap_icon="2048.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /calculator/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="Calculator", 3 | name="Calculator", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="calculator_app", 6 | cdefines=["APP_CALCULATOR"], 7 | requires=["gui"], 8 | stack_size=1 * 1024, 9 | order=45, 10 | fap_icon="calcIcon.png", 11 | fap_category="Misc", 12 | ) 13 | -------------------------------------------------------------------------------- /nrfsniff/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="nrf_sniff", 3 | name="[NRF24] Sniffer", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="nrfsniff_app", 6 | cdefines=["APP_NRFSNIFF"], 7 | requires=["gui"], 8 | stack_size=2 * 1024, 9 | order=70, 10 | fap_icon="nrfsniff_10px.png", 11 | fap_category="GPIO", 12 | ) 13 | -------------------------------------------------------------------------------- /tama_p1/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="GAME_TAMA_P1", 3 | name="TAMA P1", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="tama_p1_app", 6 | cdefines=["APP_TAMA_P1"], 7 | requires=["gui", "storage"], 8 | stack_size=1 * 1024, 9 | order=215, 10 | fap_icon="tamaIcon.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /tanksgame/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="GAME_Tanks", 3 | name="Tanks", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="tanks_game_app", 6 | cdefines=["APP_TANKS_GAME"], 7 | requires=["gui", "subghz"], 8 | stack_size=4 * 1024, 9 | order=230, 10 | fap_icon="tanksIcon.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /tetris_game/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="tetris_game", 3 | name="Tetris", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="tetris_game_app", 6 | cdefines=["APP_TETRIS_GAME"], 7 | requires=["gui"], 8 | stack_size=2 * 1024, 9 | order=20, 10 | fap_icon="tetris_10px.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /zombiez/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="game_zombiez", 3 | name="Zombiez", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="zombiez_game_app", 6 | cdefines=["APP_ZOMBIEZ_GAME"], 7 | requires=["gui"], 8 | stack_size=2 * 1024, 9 | order=280, 10 | fap_icon="zombie_10px.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /arkanoid/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="arkanoid_game", 3 | name="Arkanoid", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="arkanoid_game_app", 6 | cdefines=["APP_ARKANOID_GAME"], 7 | requires=["gui"], 8 | stack_size=1 * 1024, 9 | order=30, 10 | fap_icon="arkanoid_10px.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /montyhall/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="GAME_MontyHall", 3 | name="Monty Hall", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="montyhall_game_app", 6 | cdefines=["APP_MONTYHALL_GAME"], 7 | requires=["gui"], 8 | stack_size=1 * 1024, 9 | order=185, 10 | fap_icon="Monty.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /sentry_safe/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="sentry_safe", 3 | name="[GPIO] Sentry Safe", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="sentry_safe_app", 6 | cdefines=["APP_SENTRY_SAFE"], 7 | requires=["gui"], 8 | stack_size=1 * 1024, 9 | order=80, 10 | fap_icon="safe_10px.png", 11 | fap_category="GPIO", 12 | ) 13 | -------------------------------------------------------------------------------- /flappy_bird/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="game_flappybird", 3 | name="Flappy Bird", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="flappy_game_app", 6 | cdefines=["APP_FLAPPY_GAME"], 7 | requires=["gui"], 8 | stack_size=4 * 1024, 9 | order=100, 10 | fap_icon="flappy_10px.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /game_of_life/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="GAME_GameOfLife", 3 | name="Game of Life", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="game_of_life_app", 6 | cdefines=["APP_GAMEOFLIFE_GAME"], 7 | requires=["gui"], 8 | stack_size=2 * 1024, 9 | order=110, 10 | fap_icon="golIcon.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /videopoker/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="GAME_VideoPoker", 3 | name="Video Poker", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="video_poker_app", 6 | cdefines=["APP_VIDEOPOKER_GAME"], 7 | requires=["gui"], 8 | stack_size=2 * 1024, 9 | order=270, 10 | fap_icon="pokerIcon.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /mandelbrot/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="GAME_MandelbrotSet", 3 | name="Mandelbrot Set", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="mandelbrot_app", 6 | cdefines=["APP_MANDELBROT_GAME"], 7 | requires=["gui"], 8 | stack_size=1 * 1024, 9 | order=130, 10 | fap_icon="Mandelbrot.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /mouse_jiggler/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="APPS_MouseJiggler", 3 | name="Mouse Jiggler", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="mouse_jiggler_app", 6 | cdefines=["APP_MOUSE_JIGGLER"], 7 | requires=["gui"], 8 | stack_size=1 * 1024, 9 | order=150, 10 | fap_icon="mouse_10px.png", 11 | fap_category="Misc", 12 | ) 13 | -------------------------------------------------------------------------------- /dolphinrestorer/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="APPS_DolphinRestorer", 3 | name="Dolphin Restorer", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="drestorer_app", 6 | cdefines=["APP_DRESTORER"], 7 | requires=["gui","storage"], 8 | stack_size= 2 * 1024, 9 | order=90, 10 | fap_icon="restoreIcon.png", 11 | fap_category="Tools", 12 | ) -------------------------------------------------------------------------------- /tictactoe_game/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="tictactoe_game", 3 | name="Tic Tac Toe", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="tictactoe_game_app", 6 | cdefines=["APP_TICTACTOE_GAME"], 7 | requires=["gui"], 8 | stack_size=1 * 1024, 9 | order=40, 10 | fap_icon="tictactoe_10px.png", 11 | fap_category="Games", 12 | ) 13 | -------------------------------------------------------------------------------- /dolphinbackup/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="APPS_DolphinBackup", 3 | name="Dolphin Backup", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="storage_DolphinBackup_app", 6 | cdefines=["APP_DBACKUP"], 7 | requires=["gui", "storage"], 8 | stack_size=2 * 1024, 9 | order=85, 10 | fap_icon="bckupIcon.png", 11 | fap_category="Tools", 12 | ) -------------------------------------------------------------------------------- /multi_converter/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="multi_converter", 3 | name="Multi Converter", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="multi_converter_app", 6 | cdefines=["APP_DEC_HEX_CONVERTER"], 7 | requires=["gui"], 8 | stack_size=1 * 1024, 9 | order=19, 10 | fap_icon="converter_10px.png", 11 | fap_category="Misc", 12 | ) 13 | -------------------------------------------------------------------------------- /spectrum_analyzer/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="spectrum_analyzer", 3 | name="Spectrum Analyzer", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="spectrum_analyzer_app", 6 | cdefines=["APP_SPECTRUM_ANALYZER"], 7 | requires=["gui"], 8 | stack_size=2 * 1024, 9 | order=12, 10 | fap_icon="spectrum_10px.png", 11 | fap_category="Tools", 12 | ) 13 | -------------------------------------------------------------------------------- /flipfrid/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="flipfrid", 3 | name="RFID Fuzzer", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="flipfrid_start", 6 | cdefines=["APP_FLIP_FRID"], 7 | requires=["gui", "storage", "dialogs", "input", "notification"], 8 | stack_size=1 * 1024, 9 | order=15, 10 | fap_icon="rfid_10px.png", 11 | fap_category="Tools", 12 | ) 13 | -------------------------------------------------------------------------------- /mousejacker/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="mouse_jacker", 3 | name="[NRF24] Mouse Jacker", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="mousejacker_app", 6 | cdefines=["APP_MOUSEJACKER"], 7 | requires=[ 8 | "gui", 9 | "dialogs", 10 | ], 11 | stack_size=2 * 1024, 12 | order=60, 13 | fap_icon="mouse_10px.png", 14 | fap_category="GPIO", 15 | ) 16 | -------------------------------------------------------------------------------- /barcode_generator/application.fam: -------------------------------------------------------------------------------- 1 | App( 2 | appid="barcode_generator", 3 | name="UPC-A Generator", 4 | apptype=FlipperAppType.EXTERNAL, 5 | entry_point="barcode_UPCA_generator_app", 6 | cdefines=["APP_BARCODE_GEN"], 7 | requires=[ 8 | "gui", 9 | "dialogs", 10 | ], 11 | stack_size=1 * 1024, 12 | order=50, 13 | fap_icon="barcode_10px.png", 14 | fap_category="Misc", 15 | ) -------------------------------------------------------------------------------- /flipfrid/LICENSE.md: -------------------------------------------------------------------------------- 1 | /* 2 | * ---------------------------------------------------------------------------- 3 | * "THE BEER-WARE LICENSE" (Revision 42): 4 | * @G4N4P4T1 wrote this file. As long as you retain this notice you 5 | * can do whatever you want with this stuff. If we meet some day, and you think 6 | * this stuff is worth it, you can buy me a beer in return. 7 | * ---------------------------------------------------------------------------- 8 | */ -------------------------------------------------------------------------------- /flipfrid/scene/flipfrid_scene_entrypoint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../flipfrid.h" 3 | 4 | void flipfrid_scene_entrypoint_on_enter(FlipFridState* context); 5 | void flipfrid_scene_entrypoint_on_exit(FlipFridState* context); 6 | void flipfrid_scene_entrypoint_on_tick(FlipFridState* context); 7 | void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context); 8 | void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context); -------------------------------------------------------------------------------- /flipfrid/scene/flipfrid_scene_run_attack.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../flipfrid.h" 3 | 4 | void flipfrid_scene_run_attack_on_enter(FlipFridState* context); 5 | void flipfrid_scene_run_attack_on_exit(FlipFridState* context); 6 | void flipfrid_scene_run_attack_on_tick(FlipFridState* context); 7 | void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context); 8 | void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context); 9 | -------------------------------------------------------------------------------- /wav_player/wav_player_hal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | void wav_player_speaker_init(); 10 | 11 | void wav_player_speaker_start(); 12 | 13 | void wav_player_speaker_stop(); 14 | 15 | void wav_player_dma_init(uint32_t address, size_t size); 16 | 17 | void wav_player_dma_start(); 18 | 19 | void wav_player_dma_stop(); 20 | 21 | #ifdef __cplusplus 22 | } 23 | #endif -------------------------------------------------------------------------------- /flipfrid/scene/flipfrid_scene_load_file.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../flipfrid.h" 3 | 4 | void flipfrid_scene_load_file_on_enter(FlipFridState* context); 5 | void flipfrid_scene_load_file_on_exit(FlipFridState* context); 6 | void flipfrid_scene_load_file_on_tick(FlipFridState* context); 7 | void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context); 8 | void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context); 9 | bool flipfrid_load_protocol_from_file(FlipFridState* context); -------------------------------------------------------------------------------- /flipfrid/scene/flipfrid_scene_select_field.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../flipfrid.h" 3 | 4 | void flipfrid_scene_select_field_on_enter(FlipFridState* context); 5 | void flipfrid_scene_select_field_on_exit(FlipFridState* context); 6 | void flipfrid_scene_select_field_on_tick(FlipFridState* context); 7 | void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context); 8 | void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context); 9 | void center_displayed_key(FlipFridState* context, uint8_t index); -------------------------------------------------------------------------------- /flipfrid/scene/flipfrid_scene_load_custom_uids.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../flipfrid.h" 3 | 4 | void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context); 5 | void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context); 6 | void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context); 7 | void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context); 8 | void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context); 9 | bool flipfrid_load_custom_uids_from_file(FlipFridState* context); -------------------------------------------------------------------------------- /tanksgame/constants.h: -------------------------------------------------------------------------------- 1 | #ifndef FLIPPERZERO_FIRMWARE_CONSTANTS_H 2 | #define FLIPPERZERO_FIRMWARE_CONSTANTS_H 3 | 4 | const uint8_t SCREEN_WIDTH_TANKS = 128; 5 | const uint8_t SCREEN_HEIGHT_TANKS = 64; 6 | 7 | const uint8_t FIELD_WIDTH = 16; 8 | const uint8_t FIELD_HEIGHT = 11; 9 | 10 | const uint16_t TURN_LENGTH = 300; 11 | const uint16_t LONG_PRESS_LENGTH = 10; 12 | 13 | const uint8_t SHOT_COOLDOWN = 5; 14 | const uint8_t RESPAWN_COOLDOWN = 8; 15 | const uint8_t PLAYER_RESPAWN_COOLDOWN = 1; 16 | 17 | const uint8_t CELL_LENGTH_PIXELS = 6; 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "bpm-tapper"] 2 | path = bpm-tapper 3 | url = https://github.com/panki27/bpm-tapper.git 4 | [submodule "metronome"] 5 | path = metronome 6 | url = https://github.com/panki27/Metronome.git 7 | [submodule "dtmf_dolphin"] 8 | path = dtmf_dolphin 9 | url = https://github.com/kowalski7cc/dtmf_dolphin.git 10 | [submodule "caesar-cipher"] 11 | path = caesar-cipher 12 | url = https://github.com/panki27/caesar-cipher 13 | [submodule "FlipperZeroUSBKeyboard"] 14 | path = usb-keyboard 15 | url = https://github.com/huuck/FlipperZeroUSBKeyboard.git 16 | -------------------------------------------------------------------------------- /tama_p1/tama.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "tamalib/tamalib.h" 5 | 6 | #define TAG "TamaP1" 7 | #define TAMA_ROM_PATH EXT_PATH("tama_p1/rom.bin") 8 | #define TAMA_SCREEN_SCALE_FACTOR 2 9 | #define TAMA_LCD_ICON_SIZE 14 10 | #define TAMA_LCD_ICON_MARGIN 1 11 | 12 | typedef struct { 13 | FuriThread* thread; 14 | hal_t hal; 15 | uint8_t* rom; 16 | // 32x16 screen, perfectly represented through uint32_t 17 | uint32_t framebuffer[16]; 18 | uint8_t icons; 19 | bool halted; 20 | bool fast_forward_done; 21 | bool buzzer_on; 22 | float frequency; 23 | } TamaApp; 24 | 25 | typedef enum { 26 | EventTypeInput, 27 | EventTypeTick, 28 | } EventType; 29 | 30 | typedef struct { 31 | EventType type; 32 | InputEvent input; 33 | } TamaEvent; 34 | 35 | extern TamaApp* g_ctx; 36 | extern FuriMutex* g_state_mutex; 37 | 38 | void tama_p1_hal_init(hal_t* hal); 39 | -------------------------------------------------------------------------------- /shared/shim/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | char* mystrtok(char* s, char* delm) { 8 | static int currIndex = 0; 9 | if(!s || !delm || s[currIndex] == '\0') return NULL; 10 | char* W = (char*)malloc(sizeof(char) * 100); 11 | int i = currIndex, k = 0, j = 0; 12 | 13 | while(s[i] != '\0') { 14 | j = 0; 15 | while(delm[j] != '\0') { 16 | if(s[i] != delm[j]) 17 | W[k] = s[i]; 18 | else 19 | goto It; 20 | j++; 21 | } 22 | 23 | i++; 24 | k++; 25 | } 26 | It: 27 | W[i] = 0; 28 | currIndex = i + 1; 29 | //Iterator = ++ptr; 30 | return W; 31 | } 32 | 33 | char* mystrcat(char *dest, const char *src) 34 | { 35 | char *rdest = dest; 36 | 37 | while (*dest) 38 | dest++; 39 | while ((*dest++ = *src++)); 40 | 41 | return rdest; 42 | } 43 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # Flipper plugins 2 | 3 | Application collection for the [official flipper zero firmware](https://github.com/flipperdevices/flipperzero-firmware). 4 | 5 | Note that I'am not the author of these apps. I just ported them to the official firmware and compiled them. 6 | 7 | ## Installation instructions 8 | 9 | **You need to have an official firmware ≥ 0.67.2.** 10 | 11 | Go to the [releases](https://github.com/vmeurisse/flipperzero-plugins/releases), download apps.zip and extract it in your SD card. 12 | 13 | ## Build instructions 14 | 15 | - Clone the [official flipper zero firmware](https://github.com/flipperdevices/flipperzero-firmware) 16 | - Add the content of this repo to the `applications_user` folder 17 | - Follow [official instructions](https://github.com/flipperdevices/flipperzero-firmware/blob/dev/documentation/AppsOnSDCard.md) 18 | 19 | ### Calculator 20 | 21 | To build the calculator app, you need to comment the line `"-Werror",` in file `site_scons/cc.scons`. 22 | -------------------------------------------------------------------------------- /tama_p1/README.md: -------------------------------------------------------------------------------- 1 | Tama P1 Emulator for Flipper Zero 2 | ======================================= 3 | 4 | This is a tama P1 Emulator app for Flipper Zero, based on [TamaLIB](https://github.com/jcrona/tamalib/). 5 | 6 | How to play 7 | ----------- 8 | Create a `tama_p1` folder in your microSD card, and put the ROM as `rom.bin`. 9 | Left button is A, OK is B, and right button is C. Hold the back button to exit. 10 | There is currently no saving, so your progress will be reset when you exit the 11 | app. 12 | 13 | Building 14 | -------- 15 | Run the following to compile icons: 16 | ``` 17 | scripts/assets.py icons applications/tama_p1/icons applications/tama_p1/compiled 18 | ``` 19 | 20 | Note: you may also need to add `-Wno-unused-parameter` to `CCFLAGS` in 21 | `site_cons/cc.scons` to suppress unused parameter errors in TamaLIB. 22 | 23 | Implemented 24 | ----------- 25 | - Basic emulation 26 | - Input 27 | - Sound 28 | 29 | To-do 30 | ----- 31 | - Saving/loading 32 | - Multiple slots? 33 | - In-game reset 34 | - Test mode? 35 | - Volume adjustment 36 | -------------------------------------------------------------------------------- /mousejacker/mousejacker_ducky.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "shared/lib/drivers/nrf24.h" 9 | #include 10 | #include 11 | #include 12 | #include "shared/shim/string.h" 13 | 14 | #ifdef __cplusplus 15 | extern "C" { 16 | #endif 17 | 18 | typedef struct { 19 | char* name; 20 | uint8_t hid; 21 | uint8_t mod; 22 | } MJDuckyKey; 23 | 24 | typedef struct { 25 | bool ducky_err; 26 | bool addr_err; 27 | bool is_thread_running; 28 | bool is_ducky_running; 29 | bool close_thread_please; 30 | Storage* storage; 31 | FuriThread* mjthread; 32 | Stream* file_stream; 33 | } PluginState; 34 | 35 | void mj_process_ducky_script( 36 | FuriHalSpiBusHandle* handle, 37 | uint8_t* addr, 38 | uint8_t addr_size, 39 | uint8_t rate, 40 | char* script, 41 | PluginState* plugin_state); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | -------------------------------------------------------------------------------- /dolphinrestorer/scenes/drestorer_scene.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // Generate scene id and total number 6 | #define ADD_SCENE(prefix, name, id) StorageMoveToSd##id, 7 | typedef enum { 8 | #include "drestorer_scene_config.h" 9 | StorageMoveToSdSceneNum, 10 | } StorageMoveToSdScene; 11 | #undef ADD_SCENE 12 | 13 | extern const SceneManagerHandlers drestorer_scene_handlers; 14 | 15 | // Generate scene on_enter handlers declaration 16 | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); 17 | #include "drestorer_scene_config.h" 18 | #undef ADD_SCENE 19 | 20 | // Generate scene on_event handlers declaration 21 | #define ADD_SCENE(prefix, name, id) \ 22 | bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); 23 | #include "drestorer_scene_config.h" 24 | #undef ADD_SCENE 25 | 26 | // Generate scene on_exit handlers declaration 27 | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); 28 | #include "drestorer_scene_config.h" 29 | #undef ADD_SCENE 30 | -------------------------------------------------------------------------------- /dolphinrestorer/scenes/drestorer_scene_progress.c: -------------------------------------------------------------------------------- 1 | #include "../drestorer.h" 2 | 3 | void drestorer_scene_progress_on_enter(void* context) { 4 | StorageMoveToSd* app = context; 5 | 6 | widget_add_string_element( 7 | app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "Moving..."); 8 | 9 | view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget); 10 | 11 | drestorer_perform(); 12 | view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); 13 | } 14 | 15 | bool drestorer_scene_progress_on_event(void* context, SceneManagerEvent event) { 16 | StorageMoveToSd* app = context; 17 | bool consumed = false; 18 | 19 | if(event.type == SceneManagerEventTypeCustom) { 20 | view_dispatcher_stop(app->view_dispatcher); 21 | } else if(event.type == SceneManagerEventTypeBack) { 22 | consumed = true; 23 | } 24 | 25 | return consumed; 26 | } 27 | 28 | void drestorer_scene_progress_on_exit(void* context) { 29 | StorageMoveToSd* app = context; 30 | widget_reset(app->widget); 31 | } 32 | -------------------------------------------------------------------------------- /spectrum_analyzer/spectrum_analyzer_worker.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | typedef void (*SpectrumAnalyzerWorkerCallback)( 6 | void* chan_table, 7 | float max_rssi, 8 | uint8_t max_rssi_dec, 9 | uint8_t max_rssi_channel, 10 | void* context); 11 | 12 | typedef struct SpectrumAnalyzerWorker SpectrumAnalyzerWorker; 13 | 14 | SpectrumAnalyzerWorker* spectrum_analyzer_worker_alloc(); 15 | 16 | void spectrum_analyzer_worker_free(SpectrumAnalyzerWorker* instance); 17 | 18 | void spectrum_analyzer_worker_set_callback( 19 | SpectrumAnalyzerWorker* instance, 20 | SpectrumAnalyzerWorkerCallback callback, 21 | void* context); 22 | 23 | void spectrum_analyzer_worker_set_filter(SpectrumAnalyzerWorker* instance); 24 | 25 | void spectrum_analyzer_worker_set_frequencies( 26 | SpectrumAnalyzerWorker* instance, 27 | uint32_t channel0_frequency, 28 | uint32_t spacing, 29 | uint8_t width); 30 | 31 | void spectrum_analyzer_worker_start(SpectrumAnalyzerWorker* instance); 32 | 33 | void spectrum_analyzer_worker_stop(SpectrumAnalyzerWorker* instance); 34 | -------------------------------------------------------------------------------- /flipfrid/README.md: -------------------------------------------------------------------------------- 1 | # Flipfrid 2 | 3 | Basic EM4100 and HIDProx Fuzzer. 4 | 5 | ## Why 6 | 7 | Flipfrid is a simple Rfid fuzzer using EM4100 protocol (125khz). 8 | Objective is to provide a simple to use fuzzer to test readers by emulating various cards. 9 | 10 | - EM4100 cards use a 1 byte customer id and 4 bytes card id. 11 | - HIDProx cards use a 2 byte customer id and 3 byte card id. 12 | 13 | ## How 14 | 15 | 1) Select the Protocol with the left and right arrows 16 | 2) Select the Mode with the up and down arrows 17 | 18 | ### Info 19 | 20 | There are 2 Protocols: 21 | - EM4100 22 | - HIDProx 23 | 24 | There are 4 modes: 25 | - Default Values: Try factory/default keys and emulate one after the other. 26 | - BF customer id: An iteration from 0X00 to 0XFF on the first byte. 27 | - Load Dump file: Load an existing dump (.rfid) generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF; 28 | - Uids list: Iterate over an input text file (one uid per line) and emulate one after the other. 29 | 30 | 31 | 32 | 33 | TODO : 34 | - blank screen on back press 35 | - Add second byte test to `BF customer id` 36 | -------------------------------------------------------------------------------- /dolphinbackup/scenes/storage_DolphinBackup_scene.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // Generate scene id and total number 6 | #define ADD_SCENE(prefix, name, id) StorageDolphinBackup##id, 7 | typedef enum { 8 | #include "storage_DolphinBackup_scene_config.h" 9 | StorageDolphinBackupSceneNum, 10 | } StorageDolphinBackupScene; 11 | #undef ADD_SCENE 12 | 13 | extern const SceneManagerHandlers storage_DolphinBackup_scene_handlers; 14 | 15 | // Generate scene on_enter handlers declaration 16 | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); 17 | #include "storage_DolphinBackup_scene_config.h" 18 | #undef ADD_SCENE 19 | 20 | // Generate scene on_event handlers declaration 21 | #define ADD_SCENE(prefix, name, id) \ 22 | bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); 23 | #include "storage_DolphinBackup_scene_config.h" 24 | #undef ADD_SCENE 25 | 26 | // Generate scene on_exit handlers declaration 27 | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); 28 | #include "storage_DolphinBackup_scene_config.h" 29 | #undef ADD_SCENE 30 | -------------------------------------------------------------------------------- /dolphinrestorer/drestorer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gui/modules/widget_elements/widget_element_i.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "scenes/drestorer_scene.h" 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | typedef enum { 23 | MoveToSdCustomEventExit, 24 | MoveToSdCustomEventConfirm, 25 | } MoveToSdCustomEvent; 26 | 27 | typedef struct { 28 | // records 29 | Gui* gui; 30 | Widget* widget; 31 | NotificationApp* notifications; 32 | 33 | // view managment 34 | SceneManager* scene_manager; 35 | ViewDispatcher* view_dispatcher; 36 | 37 | FuriPubSubSubscription* sub; 38 | 39 | } StorageMoveToSd; 40 | 41 | typedef enum { 42 | StorageMoveToSdViewWidget, 43 | } StorageMoveToSdView; 44 | 45 | bool drestorer_perform(void); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /wav_player/wav_parser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | typedef enum { 9 | FormatTagPCM = 0x0001, 10 | FormatTagIEEE_FLOAT = 0x0003, 11 | } FormatTag; 12 | 13 | typedef struct { 14 | uint8_t riff[4]; 15 | uint32_t size; 16 | uint8_t wave[4]; 17 | } WavHeaderChunk; 18 | 19 | typedef struct { 20 | uint8_t fmt[4]; 21 | uint32_t size; 22 | uint16_t tag; 23 | uint16_t channels; 24 | uint32_t sample_rate; 25 | uint32_t byte_per_sec; 26 | uint16_t block_align; 27 | uint16_t bits_per_sample; 28 | } WavFormatChunk; 29 | 30 | typedef struct { 31 | uint8_t data[4]; 32 | uint32_t size; 33 | } WavDataChunk; 34 | 35 | typedef struct WavParser WavParser; 36 | 37 | WavParser* wav_parser_alloc(); 38 | 39 | void wav_parser_free(WavParser* parser); 40 | 41 | bool wav_parser_parse(WavParser* parser, Stream* stream); 42 | 43 | size_t wav_parser_get_data_start(WavParser* parser); 44 | 45 | size_t wav_parser_get_data_end(WavParser* parser); 46 | 47 | size_t wav_parser_get_data_len(WavParser* parser); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif -------------------------------------------------------------------------------- /dolphinbackup/scenes/storage_DolphinBackup_scene_progress.c: -------------------------------------------------------------------------------- 1 | #include "../storage_DolphinBackup.h" 2 | 3 | void storage_DolphinBackup_scene_progress_on_enter(void* context) { 4 | StorageDolphinBackup* app = context; 5 | 6 | widget_add_string_element( 7 | app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "Moving..."); 8 | 9 | view_dispatcher_switch_to_view(app->view_dispatcher, StorageDolphinBackupViewWidget); 10 | 11 | storage_DolphinBackup_perform(); 12 | view_dispatcher_send_custom_event(app->view_dispatcher, DolphinBackupCustomEventExit); 13 | } 14 | 15 | bool storage_DolphinBackup_scene_progress_on_event(void* context, SceneManagerEvent event) { 16 | StorageDolphinBackup* app = context; 17 | bool consumed = false; 18 | 19 | if(event.type == SceneManagerEventTypeCustom) { 20 | view_dispatcher_stop(app->view_dispatcher); 21 | } else if(event.type == SceneManagerEventTypeBack) { 22 | consumed = true; 23 | } 24 | 25 | return consumed; 26 | } 27 | 28 | void storage_DolphinBackup_scene_progress_on_exit(void* context) { 29 | StorageDolphinBackup* app = context; 30 | widget_reset(app->widget); 31 | } 32 | -------------------------------------------------------------------------------- /dolphinrestorer/scenes/drestorer_scene.c: -------------------------------------------------------------------------------- 1 | #include "drestorer_scene.h" 2 | 3 | // Generate scene on_enter handlers array 4 | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, 5 | void (*const drestorer_on_enter_handlers[])(void*) = { 6 | #include "drestorer_scene_config.h" 7 | }; 8 | #undef ADD_SCENE 9 | 10 | // Generate scene on_event handlers array 11 | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, 12 | bool (*const drestorer_on_event_handlers[])(void* context, SceneManagerEvent event) = { 13 | #include "drestorer_scene_config.h" 14 | }; 15 | #undef ADD_SCENE 16 | 17 | // Generate scene on_exit handlers array 18 | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, 19 | void (*const drestorer_on_exit_handlers[])(void* context) = { 20 | #include "drestorer_scene_config.h" 21 | }; 22 | #undef ADD_SCENE 23 | 24 | // Initialize scene handlers configuration structure 25 | const SceneManagerHandlers drestorer_scene_handlers = { 26 | .on_enter_handlers = drestorer_on_enter_handlers, 27 | .on_event_handlers = drestorer_on_event_handlers, 28 | .on_exit_handlers = drestorer_on_exit_handlers, 29 | .scene_num = StorageMoveToSdSceneNum, 30 | }; 31 | -------------------------------------------------------------------------------- /dolphinbackup/storage_DolphinBackup.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "gui/modules/widget_elements/widget_element_i.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include "scenes/storage_DolphinBackup_scene.h" 17 | 18 | #ifdef __cplusplus 19 | extern "C" { 20 | #endif 21 | 22 | typedef enum { 23 | DolphinBackupCustomEventExit, 24 | DolphinBackupCustomEventConfirm, 25 | } DolphinBackupCustomEvent; 26 | 27 | typedef struct { 28 | // records 29 | Gui* gui; 30 | Widget* widget; 31 | NotificationApp* notifications; 32 | 33 | // view managment 34 | SceneManager* scene_manager; 35 | ViewDispatcher* view_dispatcher; 36 | 37 | FuriPubSubSubscription* sub; 38 | 39 | } StorageDolphinBackup; 40 | 41 | typedef enum { 42 | StorageDolphinBackupViewWidget, 43 | } StorageDolphinBackupView; 44 | 45 | bool storage_DolphinBackup_perform(void); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | -------------------------------------------------------------------------------- /dolphinbackup/scenes/storage_DolphinBackup_scene.c: -------------------------------------------------------------------------------- 1 | #include "storage_DolphinBackup_scene.h" 2 | 3 | // Generate scene on_enter handlers array 4 | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, 5 | void (*const storage_DolphinBackup_on_enter_handlers[])(void*) = { 6 | #include "storage_DolphinBackup_scene_config.h" 7 | }; 8 | #undef ADD_SCENE 9 | 10 | // Generate scene on_event handlers array 11 | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, 12 | bool (*const storage_DolphinBackup_on_event_handlers[])(void* context, SceneManagerEvent event) = { 13 | #include "storage_DolphinBackup_scene_config.h" 14 | }; 15 | #undef ADD_SCENE 16 | 17 | // Generate scene on_exit handlers array 18 | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, 19 | void (*const storage_DolphinBackup_on_exit_handlers[])(void* context) = { 20 | #include "storage_DolphinBackup_scene_config.h" 21 | }; 22 | #undef ADD_SCENE 23 | 24 | // Initialize scene handlers configuration structure 25 | const SceneManagerHandlers storage_DolphinBackup_scene_handlers = { 26 | .on_enter_handlers = storage_DolphinBackup_on_enter_handlers, 27 | .on_event_handlers = storage_DolphinBackup_on_event_handlers, 28 | .on_exit_handlers = storage_DolphinBackup_on_exit_handlers, 29 | .scene_num = StorageDolphinBackupSceneNum, 30 | }; 31 | -------------------------------------------------------------------------------- /wav_player/wav_player_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | typedef struct WavPlayerView WavPlayerView; 9 | 10 | typedef enum { 11 | WavPlayerCtrlVolUp, 12 | WavPlayerCtrlVolDn, 13 | WavPlayerCtrlMoveL, 14 | WavPlayerCtrlMoveR, 15 | WavPlayerCtrlOk, 16 | WavPlayerCtrlBack, 17 | } WavPlayerCtrl; 18 | 19 | typedef void (*WavPlayerCtrlCallback)(WavPlayerCtrl ctrl, void* context); 20 | 21 | WavPlayerView* wav_player_view_alloc(); 22 | 23 | void wav_player_view_free(WavPlayerView* wav_view); 24 | 25 | View* wav_player_view_get_view(WavPlayerView* wav_view); 26 | 27 | void wav_player_view_set_volume(WavPlayerView* wav_view, float volume); 28 | 29 | void wav_player_view_set_start(WavPlayerView* wav_view, size_t start); 30 | 31 | void wav_player_view_set_end(WavPlayerView* wav_view, size_t end); 32 | 33 | void wav_player_view_set_current(WavPlayerView* wav_view, size_t current); 34 | 35 | void wav_player_view_set_play(WavPlayerView* wav_view, bool play); 36 | 37 | void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count); 38 | 39 | void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback); 40 | 41 | void wav_player_view_set_context(WavPlayerView* wav_view, void* context); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif -------------------------------------------------------------------------------- /tama_p1/hal_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic tama P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _HAL_TYPES_H_ 21 | #define _HAL_TYPES_H_ 22 | 23 | #include 24 | 25 | typedef bool bool_t; 26 | typedef uint8_t u4_t; 27 | typedef uint8_t u5_t; 28 | typedef uint8_t u8_t; 29 | typedef uint16_t u12_t; 30 | typedef uint16_t u13_t; 31 | typedef uint32_t u32_t; 32 | typedef uint32_t 33 | timestamp_t; // WARNING: Must be an unsigned type to properly handle wrapping (u32 wraps in around 1h11m when expressed in us) 34 | 35 | #endif /* _HAL_TYPES_H_ */ 36 | -------------------------------------------------------------------------------- /tama_p1/tamalib/hal_types.h.template: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _HAL_TYPES_H_ 21 | #define _HAL_TYPES_H_ 22 | 23 | typedef unsigned char bool_t; 24 | typedef unsigned char u4_t; 25 | typedef unsigned char u5_t; 26 | typedef unsigned char u8_t; 27 | typedef unsigned short u12_t; 28 | typedef unsigned short u13_t; 29 | typedef unsigned int u32_t; 30 | typedef unsigned int timestamp_t; // WARNING: Must be an unsigned type to properly handle wrapping (u32 wraps in around 1h11m when expressed in us) 31 | 32 | #endif /* _HAL_TYPES_H_ */ 33 | -------------------------------------------------------------------------------- /zombiez/zombiez.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint8_t zombie_array[2][8][5] = { 4 | { 5 | {0, 0, 1, 1, 1}, 6 | {0, 0, 1, 1, 1}, 7 | {1, 1, 1, 1, 1}, 8 | {0, 0, 1, 1, 1}, 9 | {0, 0, 1, 1, 1}, 10 | {0, 0, 1, 1, 1}, 11 | {0, 0, 1, 0, 0}, 12 | {0, 0, 1, 0, 0}, 13 | }, 14 | { 15 | {0, 0, 1, 1, 1}, 16 | {0, 0, 1, 1, 1}, 17 | {1, 1, 1, 1, 1}, 18 | {0, 0, 1, 1, 1}, 19 | {0, 0, 1, 1, 1}, 20 | {0, 0, 1, 1, 1}, 21 | {0, 0, 0, 0, 1}, 22 | {0, 0, 0, 0, 1}, 23 | }, 24 | }; 25 | 26 | uint8_t heart_array[5][5][5] = { 27 | { 28 | {0, 1, 0, 1, 0}, 29 | {1, 1, 1, 1, 1}, 30 | {1, 1, 1, 1, 1}, 31 | {0, 1, 1, 1, 0}, 32 | {0, 0, 1, 0, 0}, 33 | }, 34 | { 35 | {0, 0, 0, 0, 0}, 36 | {1, 1, 1, 1, 1}, 37 | {1, 1, 1, 1, 1}, 38 | {0, 1, 1, 1, 0}, 39 | {0, 0, 1, 0, 0}, 40 | }, 41 | { 42 | {0, 0, 0, 0, 0}, 43 | {0, 0, 0, 0, 0}, 44 | {1, 1, 1, 1, 1}, 45 | {0, 1, 1, 1, 0}, 46 | {0, 0, 1, 0, 0}, 47 | }, 48 | { 49 | {0, 0, 0, 0, 0}, 50 | {0, 0, 0, 0, 0}, 51 | {0, 0, 0, 0, 0}, 52 | {0, 1, 1, 1, 0}, 53 | {0, 0, 1, 0, 0}, 54 | }, 55 | { 56 | {1, 0, 0, 0, 1}, 57 | {0, 1, 0, 1, 0}, 58 | {0, 0, 1, 0, 0}, 59 | {0, 1, 0, 1, 0}, 60 | {1, 0, 0, 0, 1}, 61 | }, 62 | }; -------------------------------------------------------------------------------- /tama_p1/tamalib/hw.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _HW_H_ 21 | #define _HW_H_ 22 | 23 | #include "hal.h" 24 | 25 | #define LCD_WIDTH 32 26 | #define LCD_HEIGHT 16 27 | 28 | #define ICON_NUM 8 29 | 30 | typedef enum { 31 | BTN_STATE_RELEASED = 0, 32 | BTN_STATE_PRESSED, 33 | } btn_state_t; 34 | 35 | typedef enum { 36 | BTN_LEFT = 0, 37 | BTN_MIDDLE, 38 | BTN_RIGHT, 39 | } button_t; 40 | 41 | bool_t hw_init(void); 42 | void hw_release(void); 43 | 44 | void hw_set_lcd_pin(u8_t seg, u8_t com, u8_t val); 45 | void hw_set_button(button_t btn, btn_state_t state); 46 | 47 | void hw_set_buzzer_freq(u4_t freq); 48 | void hw_enable_buzzer(bool_t en); 49 | 50 | #endif /* _HW_H_ */ 51 | -------------------------------------------------------------------------------- /spectrum_analyzer/spectrum_analyzer.h: -------------------------------------------------------------------------------- 1 | #define NUM_CHANNELS 132 2 | #define NUM_CHUNKS 6 3 | #define CHUNK_SIZE (NUM_CHANNELS / NUM_CHUNKS) 4 | 5 | // Screen coordinates 6 | #define FREQ_BOTTOM_Y 50 7 | #define FREQ_START_X 14 8 | // How many channels displayed on the scale (On screen still 218) 9 | #define FREQ_LENGTH_X 102 10 | // dBm threshold to show peak value 11 | #define PEAK_THRESHOLD -85 12 | 13 | /* 14 | * ultrawide mode: 80 MHz on screen, 784 kHz per channel 15 | * wide mode (default): 20 MHz on screen, 196 kHz per channel 16 | * narrow mode: 4 MHz on screen, 39 kHz per channel 17 | * ultranarrow mode: 2 MHz on screen, 19 kHz per channel 18 | */ 19 | #define WIDE 0 20 | #define NARROW 1 21 | #define ULTRAWIDE 2 22 | #define ULTRANARROW 3 23 | 24 | /* channel spacing in Hz */ 25 | #define WIDE_SPACING 196078 26 | #define NARROW_SPACING 39215 27 | #define ULTRAWIDE_SPACING 784313 28 | #define ULTRANARROW_SPACING 19607 29 | 30 | /* vertical scrolling */ 31 | #define VERTICAL_SHORT_STEP 16 32 | #define MAX_VSCROLL 120 33 | #define MIN_VSCROLL 0 34 | #define DEFAULT_VSCROLL 48 35 | 36 | /* frequencies in MHz */ 37 | #define DEFAULT_FREQ 440 38 | #define WIDE_STEP 5 39 | #define NARROW_STEP 1 40 | #define ULTRAWIDE_STEP 20 41 | #define ULTRANARROW_STEP 1 42 | #define WIDE_MARGIN 13 43 | #define NARROW_MARGIN 3 44 | #define ULTRAWIDE_MARGIN 42 45 | #define ULTRANARROW_MARGIN 1 46 | 47 | /* frequency bands supported by device */ 48 | #define BAND_300 0 49 | #define BAND_400 1 50 | #define BAND_900 2 51 | 52 | /* band limits in MHz */ 53 | #define MIN_300 281 54 | #define CEN_300 315 55 | #define MAX_300 361 56 | #define MIN_400 378 57 | #define CEN_400 435 58 | #define MAX_400 481 59 | #define MIN_900 749 60 | #define CEN_900 855 61 | #define MAX_900 962 62 | 63 | /* band transition points in MHz */ 64 | #define EDGE_400 369 65 | #define EDGE_900 615 66 | 67 | /* VCO transition points in Hz */ 68 | #define MID_300 318000000 69 | #define MID_400 424000000 70 | #define MID_900 848000000 71 | 72 | #define UPPER(a, b, c) ((((a) - (b) + ((c) / 2)) / (c)) * (c)) 73 | #define LOWER(a, b, c) ((((a) + (b)) / (c)) * (c)) -------------------------------------------------------------------------------- /flipfrid/flipfrid.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | #define TAG "FlipFrid" 23 | 24 | typedef enum { 25 | FlipFridAttackDefaultValues, 26 | FlipFridAttackBfCustomerId, 27 | FlipFridAttackLoadFile, 28 | FlipFridAttackLoadFileCustomUids, 29 | } FlipFridAttacks; 30 | 31 | typedef enum { 32 | EM4100, 33 | HIDProx, 34 | } FlipFridProtos; 35 | 36 | typedef enum { 37 | NoneScene, 38 | SceneEntryPoint, 39 | SceneSelectFile, 40 | SceneSelectField, 41 | SceneAttack, 42 | SceneLoadCustomUids, 43 | } FlipFridScene; 44 | 45 | typedef enum { 46 | EventTypeTick, 47 | EventTypeKey, 48 | } EventType; 49 | 50 | typedef struct { 51 | EventType evt_type; 52 | InputKey key; 53 | InputType input_type; 54 | } FlipFridEvent; 55 | 56 | // STRUCTS 57 | typedef struct { 58 | bool is_running; 59 | bool is_attacking; 60 | FlipFridScene current_scene; 61 | FlipFridScene previous_scene; 62 | NotificationApp* notify; 63 | u_int8_t menu_index; 64 | u_int8_t menu_proto_index; 65 | 66 | string_t data_str; 67 | uint8_t data[6]; 68 | uint8_t payload[6]; 69 | uint8_t attack_step; 70 | FlipFridAttacks attack; 71 | FlipFridProtos proto; 72 | string_t attack_name; 73 | string_t proto_name; 74 | 75 | DialogsApp* dialogs; 76 | string_t notification_msg; 77 | uint8_t key_index; 78 | LFRFIDWorker* worker; 79 | ProtocolDict* dict; 80 | ProtocolId protocol; 81 | 82 | // Used for custom dictionnary 83 | Stream* uids_stream; 84 | } FlipFridState; -------------------------------------------------------------------------------- /flappy_bird/bird.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | uint8_t bird_array[3][15][11] = { 4 | { 5 | {0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0}, 6 | {0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0}, 7 | {0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0}, 8 | {0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0}, 9 | {0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0}, 10 | {0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1}, 11 | {1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1}, 12 | {1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1}, 13 | {1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1}, 14 | {1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0}, 15 | {1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0}, 16 | {0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0}, 17 | {0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0}, 18 | {0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0}, 19 | {0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, 20 | }, 21 | { 22 | {0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0}, 23 | {0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0}, 24 | {0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0}, 25 | {0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0}, 26 | {0, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0}, 27 | {0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1}, 28 | {1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1}, 29 | {1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1}, 30 | {1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1}, 31 | {1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0}, 32 | {1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0}, 33 | {0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0}, 34 | {0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0}, 35 | {0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0}, 36 | {0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, 37 | }, 38 | { 39 | {0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0}, 40 | {0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0}, 41 | {0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0}, 42 | {0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 0}, 43 | {0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0}, 44 | {0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1}, 45 | {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}, 46 | {1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1}, 47 | {1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1}, 48 | {1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0}, 49 | {1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0}, 50 | {0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0}, 51 | {0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0}, 52 | {0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0}, 53 | {0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0}, 54 | }}; 55 | -------------------------------------------------------------------------------- /tama_p1/tamalib/tamalib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _TAMALIB_H_ 21 | #define _TAMALIB_H_ 22 | 23 | #include "cpu.h" 24 | #include "hw.h" 25 | #include "hal.h" 26 | 27 | #define tamalib_set_button(btn, state) hw_set_button(btn, state) 28 | 29 | #define tamalib_set_speed(speed) cpu_set_speed(speed) 30 | 31 | #define tamalib_get_state() cpu_get_state() 32 | #define tamalib_refresh_hw() cpu_refresh_hw() 33 | 34 | #define tamalib_reset() cpu_reset() 35 | 36 | #define tamalib_add_bp(list, addr) cpu_add_bp(list, addr) 37 | #define tamalib_free_bp(list) cpu_free_bp(list) 38 | 39 | typedef enum { 40 | EXEC_MODE_PAUSE, 41 | EXEC_MODE_RUN, 42 | EXEC_MODE_STEP, 43 | EXEC_MODE_NEXT, 44 | EXEC_MODE_TO_CALL, 45 | EXEC_MODE_TO_RET, 46 | } exec_mode_t; 47 | 48 | void tamalib_release(void); 49 | bool_t tamalib_init(const u12_t* program, breakpoint_t* breakpoints, u32_t freq); 50 | 51 | void tamalib_set_framerate(u8_t framerate); 52 | u8_t tamalib_get_framerate(void); 53 | 54 | void tamalib_register_hal(hal_t* hal); 55 | 56 | void tamalib_set_exec_mode(exec_mode_t mode); 57 | 58 | /* NOTE: Only one of these two functions must be used in the main application 59 | * (tamalib_step() should be used only if tamalib_mainloop() does not fit the 60 | * main application execution flow). 61 | */ 62 | void tamalib_step(void); 63 | void tamalib_mainloop(void); 64 | 65 | #endif /* _TAMALIB_H_ */ 66 | -------------------------------------------------------------------------------- /dolphinrestorer/scenes/drestorer_scene_confirm.c: -------------------------------------------------------------------------------- 1 | #include "../drestorer.h" 2 | #include "gui/canvas.h" 3 | #include "gui/modules/widget_elements/widget_element_i.h" 4 | #include "storage/storage.h" 5 | 6 | static void 7 | drestorer_scene_confirm_widget_callback(GuiButtonType result, InputType type, void* context) { 8 | StorageMoveToSd* app = context; 9 | furi_assert(app); 10 | if(type == InputTypeShort) { 11 | if(result == GuiButtonTypeRight) { 12 | view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventConfirm); 13 | } else if(result == GuiButtonTypeLeft) { 14 | view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); 15 | } 16 | } 17 | } 18 | 19 | void drestorer_scene_confirm_on_enter(void* context) { 20 | StorageMoveToSd* app = context; 21 | 22 | widget_add_button_element( 23 | app->widget, GuiButtonTypeLeft, "Cancel", drestorer_scene_confirm_widget_callback, app); 24 | widget_add_button_element( 25 | app->widget, GuiButtonTypeRight, "Confirm", drestorer_scene_confirm_widget_callback, app); 26 | 27 | widget_add_string_element( 28 | app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "Backup Found"); 29 | widget_add_string_multiline_element( 30 | app->widget, 31 | 64, 32 | 32, 33 | AlignCenter, 34 | AlignCenter, 35 | FontSecondary, 36 | "Copy backup from\nSD card to internal storage?"); 37 | 38 | view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget); 39 | } 40 | 41 | bool drestorer_scene_confirm_on_event(void* context, SceneManagerEvent event) { 42 | StorageMoveToSd* app = context; 43 | bool consumed = false; 44 | 45 | if(event.type == SceneManagerEventTypeCustom) { 46 | if(event.event == MoveToSdCustomEventConfirm) { 47 | scene_manager_next_scene(app->scene_manager, StorageMoveToSdProgress); 48 | consumed = true; 49 | } else if(event.event == MoveToSdCustomEventExit) { 50 | view_dispatcher_stop(app->view_dispatcher); 51 | } 52 | } 53 | 54 | return consumed; 55 | } 56 | 57 | void drestorer_scene_confirm_on_exit(void* context) { 58 | StorageMoveToSd* app = context; 59 | widget_reset(app->widget); 60 | } 61 | -------------------------------------------------------------------------------- /wav_player/wav_player_hal.c: -------------------------------------------------------------------------------- 1 | #include "wav_player_hal.h" 2 | #include 3 | #include 4 | 5 | #define FURI_HAL_SPEAKER_TIMER TIM16 6 | #define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1 7 | #define DMA_INSTANCE DMA1, LL_DMA_CHANNEL_1 8 | 9 | void wav_player_speaker_init() { 10 | LL_TIM_InitTypeDef TIM_InitStruct = {0}; 11 | TIM_InitStruct.Prescaler = 4; 12 | TIM_InitStruct.Autoreload = 255; 13 | LL_TIM_Init(FURI_HAL_SPEAKER_TIMER, &TIM_InitStruct); 14 | 15 | LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0}; 16 | TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1; 17 | TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE; 18 | TIM_OC_InitStruct.CompareValue = 127; 19 | LL_TIM_OC_Init(FURI_HAL_SPEAKER_TIMER, FURI_HAL_SPEAKER_CHANNEL, &TIM_OC_InitStruct); 20 | } 21 | 22 | void wav_player_speaker_start() { 23 | LL_TIM_EnableAllOutputs(FURI_HAL_SPEAKER_TIMER); 24 | LL_TIM_EnableCounter(FURI_HAL_SPEAKER_TIMER); 25 | } 26 | 27 | void wav_player_speaker_stop() { 28 | LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER); 29 | LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER); 30 | } 31 | 32 | void wav_player_dma_init(uint32_t address, size_t size) { 33 | uint32_t dma_dst = (uint32_t) & (FURI_HAL_SPEAKER_TIMER->CCR1); 34 | 35 | LL_DMA_ConfigAddresses(DMA_INSTANCE, address, dma_dst, LL_DMA_DIRECTION_MEMORY_TO_PERIPH); 36 | LL_DMA_SetDataLength(DMA_INSTANCE, size); 37 | 38 | LL_DMA_SetPeriphRequest(DMA_INSTANCE, LL_DMAMUX_REQ_TIM16_UP); 39 | LL_DMA_SetDataTransferDirection(DMA_INSTANCE, LL_DMA_DIRECTION_MEMORY_TO_PERIPH); 40 | LL_DMA_SetChannelPriorityLevel(DMA_INSTANCE, LL_DMA_PRIORITY_VERYHIGH); 41 | LL_DMA_SetMode(DMA_INSTANCE, LL_DMA_MODE_CIRCULAR); 42 | LL_DMA_SetPeriphIncMode(DMA_INSTANCE, LL_DMA_PERIPH_NOINCREMENT); 43 | LL_DMA_SetMemoryIncMode(DMA_INSTANCE, LL_DMA_MEMORY_INCREMENT); 44 | LL_DMA_SetPeriphSize(DMA_INSTANCE, LL_DMA_PDATAALIGN_HALFWORD); 45 | LL_DMA_SetMemorySize(DMA_INSTANCE, LL_DMA_MDATAALIGN_HALFWORD); 46 | 47 | LL_DMA_EnableIT_TC(DMA_INSTANCE); 48 | LL_DMA_EnableIT_HT(DMA_INSTANCE); 49 | } 50 | 51 | void wav_player_dma_start() { 52 | LL_DMA_EnableChannel(DMA_INSTANCE); 53 | LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_SPEAKER_TIMER); 54 | } 55 | 56 | void wav_player_dma_stop() { 57 | LL_DMA_DisableChannel(DMA_INSTANCE); 58 | } -------------------------------------------------------------------------------- /multi_converter/multi_converter_definitions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define MULTI_CONVERTER_NUMBER_DIGITS 9 4 | 5 | typedef enum { 6 | EventTypeKey, 7 | } EventType; 8 | 9 | typedef struct { 10 | InputEvent input; 11 | EventType type; 12 | } MultiConverterEvent; 13 | 14 | typedef enum { 15 | ModeDisplay, 16 | ModeSelector, 17 | } MultiConverterMode; 18 | 19 | typedef enum { 20 | None, 21 | Reset, 22 | Convert, 23 | } MultiConverterModeTrigger; 24 | 25 | // new units goes here, used as index to the main multi_converter_available_units array (multi_converter_units.h) 26 | typedef enum { 27 | UnitTypeDec, 28 | UnitTypeHex, 29 | UnitTypeBin, 30 | 31 | UnitTypeCelsius, 32 | UnitTypeFahernheit, 33 | UnitTypeKelvin, 34 | 35 | UnitTypeKilometers, 36 | UnitTypeMeters, 37 | UnitTypeCentimeters, 38 | UnitTypeMiles, 39 | UnitTypeFeet, 40 | UnitTypeInches, 41 | 42 | UnitTypeDegree, 43 | UnitTypeRadian, 44 | } MultiConverterUnitType; 45 | 46 | typedef struct { 47 | MultiConverterUnitType selected_unit_type_orig; 48 | MultiConverterUnitType selected_unit_type_dest; 49 | uint8_t select_orig; 50 | } MultiConverterModeSelect; 51 | 52 | typedef struct { 53 | uint8_t cursor; // cursor position when typing 54 | int8_t key; // hover key 55 | uint8_t comma; // comma already added? (only one comma allowed) 56 | uint8_t negative; // is negative? 57 | } MultiConverterModeDisplay; 58 | 59 | typedef struct MultiConverterUnit MultiConverterUnit; 60 | typedef struct MultiConverterState MultiConverterState; 61 | 62 | struct MultiConverterUnit { 63 | uint8_t allow_comma; 64 | uint8_t allow_negative; 65 | uint8_t max_number_keys; 66 | char mini_name[4]; 67 | char name[12]; 68 | void (*convert_function)(MultiConverterState* const); 69 | uint8_t (*allowed_function)(MultiConverterUnitType); 70 | }; 71 | 72 | struct MultiConverterState { 73 | char buffer_orig[MULTI_CONVERTER_NUMBER_DIGITS + 1]; 74 | char buffer_dest[MULTI_CONVERTER_NUMBER_DIGITS + 1]; 75 | MultiConverterUnitType unit_type_orig; 76 | MultiConverterUnitType unit_type_dest; 77 | MultiConverterMode mode; 78 | MultiConverterModeDisplay display; 79 | MultiConverterModeSelect select; 80 | uint8_t keyboard_lock; // used to create a small lock when switching from SELECT to DISPLAY modes 81 | // (debouncing, basically; otherwise it switch modes twice 'cause it's too fast!) 82 | }; 83 | -------------------------------------------------------------------------------- /wav_player/wav_parser.c: -------------------------------------------------------------------------------- 1 | #include "wav_parser.h" 2 | 3 | #define TAG "WavParser" 4 | 5 | const char* format_text(FormatTag tag) { 6 | switch(tag) { 7 | case FormatTagPCM: 8 | return "PCM"; 9 | case FormatTagIEEE_FLOAT: 10 | return "IEEE FLOAT"; 11 | default: 12 | return "Unknown"; 13 | } 14 | }; 15 | 16 | struct WavParser { 17 | WavHeaderChunk header; 18 | WavFormatChunk format; 19 | WavDataChunk data; 20 | size_t wav_data_start; 21 | size_t wav_data_end; 22 | }; 23 | 24 | WavParser* wav_parser_alloc() { 25 | return malloc(sizeof(WavParser)); 26 | } 27 | 28 | void wav_parser_free(WavParser* parser) { 29 | free(parser); 30 | } 31 | 32 | bool wav_parser_parse(WavParser* parser, Stream* stream) { 33 | stream_read(stream, (uint8_t*)&parser->header, sizeof(WavHeaderChunk)); 34 | stream_read(stream, (uint8_t*)&parser->format, sizeof(WavFormatChunk)); 35 | stream_read(stream, (uint8_t*)&parser->data, sizeof(WavDataChunk)); 36 | 37 | if(memcmp(parser->header.riff, "RIFF", 4) != 0 || 38 | memcmp(parser->header.wave, "WAVE", 4) != 0) { 39 | FURI_LOG_E(TAG, "WAV: wrong header"); 40 | return false; 41 | } 42 | 43 | if(memcmp(parser->format.fmt, "fmt ", 4) != 0) { 44 | FURI_LOG_E(TAG, "WAV: wrong format"); 45 | return false; 46 | } 47 | 48 | if(parser->format.tag != FormatTagPCM || memcmp(parser->data.data, "data", 4) != 0) { 49 | FURI_LOG_E( 50 | TAG, 51 | "WAV: non-PCM format %u, next '%lu'", 52 | parser->format.tag, 53 | (uint32_t)parser->data.data); 54 | return false; 55 | } 56 | 57 | FURI_LOG_I( 58 | TAG, 59 | "Format tag: %s, ch: %u, smplrate: %lu, bps: %lu, bits: %u", 60 | format_text(parser->format.tag), 61 | parser->format.channels, 62 | parser->format.sample_rate, 63 | parser->format.byte_per_sec, 64 | parser->format.bits_per_sample); 65 | 66 | parser->wav_data_start = stream_tell(stream); 67 | parser->wav_data_end = parser->wav_data_start + parser->data.size; 68 | 69 | FURI_LOG_I(TAG, "data: %u - %u", parser->wav_data_start, parser->wav_data_end); 70 | 71 | return true; 72 | } 73 | 74 | size_t wav_parser_get_data_start(WavParser* parser) { 75 | return parser->wav_data_start; 76 | } 77 | 78 | size_t wav_parser_get_data_end(WavParser* parser) { 79 | return parser->wav_data_end; 80 | } 81 | 82 | size_t wav_parser_get_data_len(WavParser* parser) { 83 | return parser->wav_data_end - parser->wav_data_start; 84 | } 85 | -------------------------------------------------------------------------------- /dolphinbackup/scenes/storage_DolphinBackup_scene_confirm.c: -------------------------------------------------------------------------------- 1 | #include "../storage_DolphinBackup.h" 2 | #include "gui/canvas.h" 3 | #include "gui/modules/widget_elements/widget_element_i.h" 4 | #include "storage/storage.h" 5 | 6 | static void storage_DolphinBackup_scene_confirm_widget_callback( 7 | GuiButtonType result, 8 | InputType type, 9 | void* context) { 10 | StorageDolphinBackup* app = context; 11 | furi_assert(app); 12 | if(type == InputTypeShort) { 13 | if(result == GuiButtonTypeRight) { 14 | view_dispatcher_send_custom_event( 15 | app->view_dispatcher, DolphinBackupCustomEventConfirm); 16 | } else if(result == GuiButtonTypeLeft) { 17 | view_dispatcher_send_custom_event(app->view_dispatcher, DolphinBackupCustomEventExit); 18 | } 19 | } 20 | } 21 | 22 | void storage_DolphinBackup_scene_confirm_on_enter(void* context) { 23 | StorageDolphinBackup* app = context; 24 | 25 | widget_add_button_element( 26 | app->widget, 27 | GuiButtonTypeLeft, 28 | "Cancel", 29 | storage_DolphinBackup_scene_confirm_widget_callback, 30 | app); 31 | widget_add_button_element( 32 | app->widget, 33 | GuiButtonTypeRight, 34 | "Confirm", 35 | storage_DolphinBackup_scene_confirm_widget_callback, 36 | app); 37 | 38 | widget_add_string_element( 39 | app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "SD Card Present"); 40 | widget_add_string_multiline_element( 41 | app->widget, 42 | 64, 43 | 32, 44 | AlignCenter, 45 | AlignCenter, 46 | FontSecondary, 47 | "Copy data from\ninternal storage to SD card?"); 48 | 49 | view_dispatcher_switch_to_view(app->view_dispatcher, StorageDolphinBackupViewWidget); 50 | } 51 | 52 | bool storage_DolphinBackup_scene_confirm_on_event(void* context, SceneManagerEvent event) { 53 | StorageDolphinBackup* app = context; 54 | bool consumed = false; 55 | 56 | if(event.type == SceneManagerEventTypeCustom) { 57 | if(event.event == DolphinBackupCustomEventConfirm) { 58 | scene_manager_next_scene(app->scene_manager, StorageDolphinBackupProgress); 59 | consumed = true; 60 | } else if(event.event == DolphinBackupCustomEventExit) { 61 | view_dispatcher_stop(app->view_dispatcher); 62 | } 63 | } 64 | 65 | return consumed; 66 | } 67 | 68 | void storage_DolphinBackup_scene_confirm_on_exit(void* context) { 69 | StorageDolphinBackup* app = context; 70 | widget_reset(app->widget); 71 | } 72 | -------------------------------------------------------------------------------- /multi_converter/multi_converter_mode_display.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "multi_converter_definitions.h" 7 | #include "multi_converter_units.h" 8 | 9 | // 10 | // performs a unit conversion from origin to source buffers, if there's any error, overflow or 11 | // non-compatible format (which shouldn't happen, but just in case) abort conversion and outputs 12 | // some "?" strings on the buffer or something similar 13 | // 14 | void multi_converter_mode_display_convert(MultiConverterState* const multi_converter_state); 15 | 16 | // 17 | // draw the main DISPLAY view with the current multi_converter_state values 18 | // 19 | void multi_converter_mode_display_draw( 20 | Canvas* const canvas, 21 | const MultiConverterState* multi_converter_state); 22 | 23 | // 24 | // keyboard navigation on DISPLAY mode (NAVIGATION only, no BACK nor OK - InputKey guaranteed to be left/right/up/down) 25 | // 26 | void multi_converter_mode_display_navigation( 27 | InputKey key, 28 | MultiConverterState* const multi_converter_state); 29 | 30 | // 31 | // reset the DISPLAY mode with the current units, cleaning the buffers and different flags; 32 | // call this when exiting the SELECT mode / changing the units 33 | // 34 | void multi_converter_mode_display_reset(MultiConverterState* const multi_converter_state); 35 | 36 | // 37 | // toggle the negative flag on current selected buffer ONLY if the unit allows negative numbers 38 | // (adding negative number may crop the last char on the buffer; it cannot be recovered) 39 | // 40 | void multi_converter_mode_display_toggle_negative(MultiConverterState* const multi_converter_state); 41 | 42 | // 43 | // add a comma/dot/decimal separator/whatever on current selected buffer ONLY if the unit allows it 44 | // (only ONE comma allowed, not in the beginning nor end) 45 | // 46 | void multi_converter_mode_display_add_comma(MultiConverterState* const multi_converter_state); 47 | 48 | // 49 | // add a regular number to the buffer if it's <= the max_number_keys from the unit (not necessary 50 | // since the draw and navigation functions won't allow a trigger for an invalid number, but still 51 | // to keep the "checks" policy on each "add key" function...) 52 | // 53 | void multi_converter_mode_display_add_number(MultiConverterState* const multi_converter_state); 54 | 55 | // 56 | // handle the OK action when selecting a specific key on the keyboard (add a number, a symbol, change mode...) 57 | // returns a ModeTrigger enum value: may or may not let to a mode change on the main loop (WON'T change the mode here) 58 | // 59 | MultiConverterModeTrigger multi_converter_mode_display_ok( 60 | uint8_t long_press, 61 | MultiConverterState* const multi_converter_state); -------------------------------------------------------------------------------- /calculator/tinyexpr.h: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: Zlib 2 | /* 3 | * TINYEXPR - Tiny recursive descent parser and evaluation engine in C 4 | * 5 | * Copyright (c) 2015-2020 Lewis Van Winkle 6 | * 7 | * http://CodePlea.com 8 | * 9 | * This software is provided 'as-is', without any express or implied 10 | * warranty. In no event will the authors be held liable for any damages 11 | * arising from the use of this software. 12 | * 13 | * Permission is granted to anyone to use this software for any purpose, 14 | * including commercial applications, and to alter it and redistribute it 15 | * freely, subject to the following restrictions: 16 | * 17 | * 1. The origin of this software must not be misrepresented; you must not 18 | * claim that you wrote the original software. If you use this software 19 | * in a product, an acknowledgement in the product documentation would be 20 | * appreciated but is not required. 21 | * 2. Altered source versions must be plainly marked as such, and must not be 22 | * misrepresented as being the original software. 23 | * 3. This notice may not be removed or altered from any source distribution. 24 | */ 25 | 26 | #ifndef TINYEXPR_H 27 | #define TINYEXPR_H 28 | 29 | #ifdef __cplusplus 30 | extern "C" { 31 | #endif 32 | 33 | typedef struct te_expr { 34 | int type; 35 | union { 36 | double value; 37 | const double* bound; 38 | const void* function; 39 | }; 40 | void* parameters[1]; 41 | } te_expr; 42 | 43 | enum { 44 | TE_VARIABLE = 0, 45 | 46 | TE_FUNCTION0 = 8, 47 | TE_FUNCTION1, 48 | TE_FUNCTION2, 49 | TE_FUNCTION3, 50 | TE_FUNCTION4, 51 | TE_FUNCTION5, 52 | TE_FUNCTION6, 53 | TE_FUNCTION7, 54 | 55 | TE_CLOSURE0 = 16, 56 | TE_CLOSURE1, 57 | TE_CLOSURE2, 58 | TE_CLOSURE3, 59 | TE_CLOSURE4, 60 | TE_CLOSURE5, 61 | TE_CLOSURE6, 62 | TE_CLOSURE7, 63 | 64 | TE_FLAG_PURE = 32 65 | }; 66 | 67 | typedef struct te_variable { 68 | const char* name; 69 | const void* address; 70 | int type; 71 | void* context; 72 | } te_variable; 73 | 74 | /* Parses the input expression, evaluates it, and frees it. */ 75 | /* Returns NaN on error. */ 76 | double te_interp(const char* expression, int* error); 77 | 78 | /* Parses the input expression and binds variables. */ 79 | /* Returns NULL on error. */ 80 | te_expr* 81 | te_compile(const char* expression, const te_variable* variables, int var_count, int* error); 82 | 83 | /* Evaluates the expression. */ 84 | double te_eval(const te_expr* n); 85 | 86 | /* Prints debugging information on the syntax tree. */ 87 | void te_print(const te_expr* n); 88 | 89 | /* Frees the expression. */ 90 | /* This is safe to call on NULL pointers. */ 91 | void te_free(te_expr* n); 92 | 93 | #ifdef __cplusplus 94 | } 95 | #endif 96 | 97 | #endif /*TINYEXPR_H*/ 98 | -------------------------------------------------------------------------------- /flipfrid/scene/flipfrid_scene_load_custom_uids.c: -------------------------------------------------------------------------------- 1 | #include "flipfrid_scene_load_custom_uids.h" 2 | #include "flipfrid_scene_run_attack.h" 3 | #include "flipfrid_scene_entrypoint.h" 4 | 5 | #define LFRFID_UIDS_EXTENSION ".txt" 6 | #define RFIDFUZZER_APP_PATH_FOLDER "/ext/rfidfuzzer" 7 | 8 | bool flipfrid_load_uids(FlipFridState* context, const char* file_path) { 9 | bool result = false; 10 | Storage* storage = furi_record_open(RECORD_STORAGE); 11 | context->uids_stream = buffered_file_stream_alloc(storage); 12 | result = 13 | buffered_file_stream_open(context->uids_stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING); 14 | // Close if loading fails 15 | if(!result) { 16 | buffered_file_stream_close(context->uids_stream); 17 | return false; 18 | } 19 | return result; 20 | } 21 | 22 | bool flipfrid_load_custom_uids_from_file(FlipFridState* context) { 23 | // Input events and views are managed by file_select 24 | string_t uid_path; 25 | string_init(uid_path); 26 | string_set_str(uid_path, RFIDFUZZER_APP_PATH_FOLDER); 27 | 28 | DialogsFileBrowserOptions browser_options; 29 | dialog_file_browser_set_basic_options(&browser_options, LFRFID_UIDS_EXTENSION, &I_125_10px); 30 | browser_options.hide_ext = false; 31 | 32 | bool res = dialog_file_browser_show(context->dialogs, uid_path, uid_path, &browser_options); 33 | 34 | if(res) { 35 | res = flipfrid_load_uids(context, string_get_cstr(uid_path)); 36 | } 37 | 38 | string_clear(uid_path); 39 | 40 | return res; 41 | } 42 | 43 | void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context) { 44 | if(flipfrid_load_custom_uids_from_file(context)) { 45 | // Force context loading 46 | flipfrid_scene_run_attack_on_enter(context); 47 | context->current_scene = SceneAttack; 48 | } else { 49 | flipfrid_scene_entrypoint_on_enter(context); 50 | context->current_scene = SceneEntryPoint; 51 | } 52 | } 53 | 54 | void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context) { 55 | UNUSED(context); 56 | } 57 | 58 | void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context) { 59 | UNUSED(context); 60 | } 61 | 62 | void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context) { 63 | if(event.evt_type == EventTypeKey) { 64 | if(event.input_type == InputTypeShort) { 65 | switch(event.key) { 66 | case InputKeyDown: 67 | case InputKeyUp: 68 | case InputKeyLeft: 69 | case InputKeyRight: 70 | case InputKeyOk: 71 | case InputKeyBack: 72 | context->current_scene = SceneEntryPoint; 73 | break; 74 | } 75 | } 76 | } 77 | } 78 | 79 | void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context) { 80 | UNUSED(context); 81 | UNUSED(canvas); 82 | } 83 | -------------------------------------------------------------------------------- /multi_converter/multi_converter_mode_select.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "multi_converter_definitions.h" 8 | #include "multi_converter_units.h" 9 | 10 | // 11 | // aux draw function for units offsets and draw stuff 12 | // 13 | void multi_converter_mode_select_draw_destination_offset( 14 | uint8_t x, 15 | uint8_t y, 16 | int8_t d, 17 | Canvas* const canvas, 18 | const MultiConverterState* multi_converter_state); 19 | 20 | void multi_converter_mode_select_draw_selected_unit( 21 | uint8_t x, 22 | uint8_t y, 23 | MultiConverterUnitType unit_type, 24 | Canvas* const canvas); 25 | 26 | // 27 | // draw the main SELECT view with the current multi_converter_state values 28 | // 29 | void multi_converter_mode_select_draw( 30 | Canvas* const canvas, 31 | const MultiConverterState* multi_converter_state); 32 | 33 | // 34 | // reset the SELECT mode view, showing as "pre-selected" the current working units 35 | // 36 | void multi_converter_mode_select_reset(MultiConverterState* const multi_converter_state); 37 | 38 | // 39 | // exit from SELECT mode and go back to display view, if save_changes == 1 use the current SELECT view info 40 | // to modify the current selected units and reset the views properly (usually if the ORIGIN unit has been 41 | // changed, reset everything; otherwise just trigger the convert function with a new DESTINATION) 42 | // 43 | // currently this function DON'T CHECK invalid unit relations (the navigation and display functions will 44 | // prevent weird behaviours, so for now we're trusting the selected_unit_orig/dest_type values) 45 | // 46 | // returns an enum code MultiConverterDisplayTrigger based on doing nothing (cancel), triggering the display 47 | // convert method or reseting the whole display mode (when fully changing the units) 48 | // 49 | // notice the MODE CHANGE itself is not done here but in the main loop (outside the call) via the ModeTrigger enum element 50 | // 51 | MultiConverterModeTrigger multi_converter_mode_select_exit( 52 | uint8_t save_changes, 53 | MultiConverterState* const multi_converter_state); 54 | 55 | // 56 | // switch between selecting the ORIGIN or the DESTINATION unit on DISPLAY mode (since there're only 57 | // two options, both left/right arrow keys acts as toggles, no "direction" required) 58 | // 59 | void multi_converter_mode_select_switch(MultiConverterState* const multi_converter_state); 60 | 61 | // 62 | // change the selected unit on SELECTED mode, using the select_orig flag to check if we're switching the 63 | // ORIGIN or the DESTINATION unit; the DIRECTION (up or down to travel the array) is set as a param 64 | // 65 | // when switching the ORIGIN one, reset the DESTINATION to the first valid unit (if the current one is not 66 | // valid anymore); when switching the DESTINATION one, an allowed_function() check is performed in order to 67 | // properly set a valid destination unit. 68 | // 69 | // (notice the draw step also perform which units are valid to display, so no worries about that here) 70 | // 71 | void multi_converter_mode_select_change_unit( 72 | int8_t direction, 73 | MultiConverterState* const multi_converter_state); 74 | -------------------------------------------------------------------------------- /tama_p1/tamalib/hal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _HAL_H_ 21 | #define _HAL_H_ 22 | 23 | #include "../hal_types.h" 24 | 25 | #ifndef NULL 26 | #define NULL 0 27 | #endif 28 | 29 | typedef enum { 30 | LOG_ERROR = 0x1, 31 | LOG_INFO = (0x1 << 1), 32 | LOG_MEMORY = (0x1 << 2), 33 | LOG_CPU = (0x1 << 3), 34 | } log_level_t; 35 | 36 | /* The Hardware Abstraction Layer 37 | * NOTE: This structure acts as an abstraction layer between TamaLIB and the OS/SDK. 38 | * All pointers MUST be implemented, but some implementations can be left empty. 39 | */ 40 | typedef struct { 41 | /* Memory allocation functions 42 | * NOTE: Needed only if breakpoints support is required. 43 | */ 44 | void* (*malloc)(u32_t size); 45 | void (*free)(void* ptr); 46 | 47 | /* What to do if the CPU has halted 48 | */ 49 | void (*halt)(void); 50 | 51 | /* Log related function 52 | * NOTE: Needed only if log messages are required. 53 | */ 54 | bool_t (*is_log_enabled)(log_level_t level); 55 | void (*log)(log_level_t level, char* buff, ...); 56 | 57 | /* Clock related functions 58 | * NOTE: Timestamps granularity is configured with tamalib_init(), an accuracy 59 | * of ~30 us (1/32768) is required for a cycle accurate emulation. 60 | */ 61 | void (*sleep_until)(timestamp_t ts); 62 | timestamp_t (*get_timestamp)(void); 63 | 64 | /* Screen related functions 65 | * NOTE: In case of direct hardware access to pixels, the set_XXXX() functions 66 | * (called for each pixel/icon update) can directly drive them, otherwise they 67 | * should just store the data in a buffer and let update_screen() do the actual 68 | * rendering (at 30 fps). 69 | */ 70 | void (*update_screen)(void); 71 | void (*set_lcd_matrix)(u8_t x, u8_t y, bool_t val); 72 | void (*set_lcd_icon)(u8_t icon, bool_t val); 73 | 74 | /* Sound related functions 75 | * NOTE: set_frequency() changes the output frequency of the sound, while 76 | * play_frequency() decides whether the sound should be heard or not. 77 | */ 78 | void (*set_frequency)(u32_t freq); 79 | void (*play_frequency)(bool_t en); 80 | 81 | /* Event handler from the main app (if any) 82 | * NOTE: This function usually handles button related events, states loading/saving ... 83 | */ 84 | int (*handler)(void); 85 | } hal_t; 86 | 87 | extern hal_t* g_hal; 88 | 89 | #endif /* _HAL_H_ */ 90 | -------------------------------------------------------------------------------- /tama_p1/compiled/assets_icons.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | const uint8_t _I_icon_0_0[] = { 4 | 0x01, 0x00, 0x1a, 0x00, 0x00, 0x0d, 0xaa, 0x1d, 0x7e, 0x00, 0x9c, 0x3e, 0xf9, 0x0f, 0x9e, 5 | 0x43, 0xe3, 0x00, 0x12, 0x9c, 0x43, 0xa7, 0x10, 0xc9, 0xe4, 0x30, 0x0a, 0x31, 0x08, 0x60, 6 | }; 7 | const uint8_t* const _I_icon_0[] = {_I_icon_0_0}; 8 | 9 | const uint8_t _I_icon_1_0[] = { 10 | 0x00, 0x00, 0x00, 0x40, 0x04, 0x04, 0x04, 0xf0, 0x11, 0xf9, 0x1b, 0xf8, 0x07, 0x8c, 0x06, 11 | 0xed, 0x36, 0xac, 0x26, 0xe8, 0x02, 0x52, 0x0b, 0x02, 0x18, 0xe0, 0x01, 0xe0, 0x01, 12 | }; 13 | const uint8_t* const _I_icon_1[] = {_I_icon_1_0}; 14 | 15 | const uint8_t _I_icon_2_0[] = { 16 | 0x00, 0x00, 0x00, 0x0e, 0x00, 0x13, 0x00, 0x21, 0x3c, 0x21, 0x3e, 0x23, 0x3f, 0x9f, 0x1f, 17 | 0xc0, 0x0f, 0xe0, 0x07, 0xf0, 0x01, 0x7c, 0x00, 0x1f, 0x00, 0x06, 0x00, 0x06, 0x00, 18 | }; 19 | const uint8_t* const _I_icon_2[] = {_I_icon_2_0}; 20 | 21 | const uint8_t _I_icon_3_0[] = { 22 | 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x1c, 0x40, 0x3a, 0xc0, 0x36, 0xf0, 0x37, 0x18, 0x2d, 23 | 0x0c, 0x2b, 0x0e, 0x02, 0x1f, 0x06, 0x3e, 0x07, 0xfe, 0x00, 0x7f, 0x00, 0x18, 0x00, 24 | }; 25 | const uint8_t* const _I_icon_3[] = {_I_icon_3_0}; 26 | 27 | const uint8_t _I_icon_4_0[] = { 28 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0xc7, 0x3c, 0x82, 0x2f, 0xf2, 0x26, 0xc7, 0x2c, 29 | 0x69, 0x28, 0x2f, 0x2c, 0xe7, 0x27, 0x02, 0x20, 0x02, 0x30, 0x06, 0x1c, 0xfc, 0x0f, 30 | }; 31 | const uint8_t* const _I_icon_4[] = {_I_icon_4_0}; 32 | 33 | const uint8_t _I_icon_5_0[] = { 34 | 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0xfe, 0x0f, 0x03, 0x38, 0xc9, 0x22, 0x9a, 0x32, 35 | 0xa2, 0x28, 0x24, 0x2c, 0x21, 0x20, 0x61, 0x30, 0x21, 0x10, 0xf3, 0x11, 0x1e, 0x0f, 36 | }; 37 | const uint8_t* const _I_icon_5[] = {_I_icon_5_0}; 38 | 39 | const uint8_t _I_icon_6_0[] = { 40 | 0x01, 0x00, 0x17, 0x00, 0x00, 0x44, 0x62, 0xfd, 0x38, 0xbf, 0xcf, 0xb7, 0xf3, 0xf8, 41 | 0xfc, 0x6e, 0x3f, 0x1a, 0xff, 0xc0, 0x3f, 0xf0, 0x1f, 0xf4, 0x02, 0x71, 0x00, 42 | }; 43 | const uint8_t* const _I_icon_6[] = {_I_icon_6_0}; 44 | 45 | const uint8_t _I_icon_7_0[] = { 46 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x41, 0x0e, 0xc4, 0x1f, 0x94, 0x20, 47 | 0x00, 0x21, 0x22, 0x1f, 0x1d, 0x0a, 0x63, 0x20, 0xde, 0x20, 0x80, 0x1f, 0x00, 0x0e, 48 | }; 49 | const uint8_t* const _I_icon_7[] = {_I_icon_7_0}; 50 | 51 | const Icon I_icon_0 = 52 | {.width = 14, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_icon_0}; 53 | const Icon I_icon_1 = 54 | {.width = 14, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_icon_1}; 55 | const Icon I_icon_2 = 56 | {.width = 14, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_icon_2}; 57 | const Icon I_icon_3 = 58 | {.width = 14, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_icon_3}; 59 | const Icon I_icon_4 = 60 | {.width = 14, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_icon_4}; 61 | const Icon I_icon_5 = 62 | {.width = 14, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_icon_5}; 63 | const Icon I_icon_6 = 64 | {.width = 14, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_icon_6}; 65 | const Icon I_icon_7 = 66 | {.width = 14, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_icon_7}; -------------------------------------------------------------------------------- /tama_p1/tamalib/README.md: -------------------------------------------------------------------------------- 1 | # TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 2 | 3 | 4 | ## Synopsis 5 | 6 | TamaLib is a hardware agnostic Tamagotchi P1 emulation library built from scratch. It is self-contained and aims at running on any platform powerful enough, from microcontrollers (MCUs) to desktop computers, thus spreading virtual life across the digital world. 7 | 8 | So far, it has been successfully implemented on different platforms: 9 | - Desktop computers (check out [TamaTool](https://github.com/jcrona/tamatool/) for more information) 10 | - STM32F072 MCU based board (check out [MCUGotchi](https://github.com/jcrona/mcugotchi/) for more information). 11 | - OpenTama which is an STM32L072 MCU based board (check out [OpenTama](https://github.com/Sparkr-tech/opentama) and [MCUGotchi](https://github.com/jcrona/mcugotchi/) for more information). 12 | - Arduino UNO (check out [ArduinoGotchi](https://github.com/GaryZ88/ArduinoGotchi/) for more information). 13 | 14 | ## Importing TamaLIB 15 | 16 | TamaLIB cannot be used as is. In order to create life on a specific target, you need to import all TamaLIB related __.c__ and __.h__ files in your project (for instance in a __lib__ subfolder), to create a __hal_types.h__ file using the template provided and to implement the __hal_t__ structure, that will act as an abstraction layer between TamaLIB and your OS or SDK (detailed information can be found in __hal.h__). This abstraction layer basically connects TamaLIB to your target's buttons, clock, audio and screen, while also defining the C types that TamaLIB should use to represent 4-bit, 5-bit, 8-bit, 12-bit, 13-bit and 32-bit variables. Once done, you will be able to call the TamaLIB API from your project. 17 | 18 | 19 | ## Using the TamaLIB API 20 | 21 | Basically: 22 | ``` 23 | /* ... */ 24 | 25 | /* Register the HAL */ 26 | tamalib_register_hal(&my_hal); 27 | 28 | /* ... */ 29 | 30 | /* Initialize TamaLIB */ 31 | tamalib_init(my_program, my_breakpoints, 1000000); // my_breakpoints can be NULL, 1000000 means that timestamps will be expressed in us 32 | 33 | /* ... */ 34 | 35 | /* Enter TamaLIB's loop */ 36 | tamalib_mainloop(); 37 | 38 | /* ... */ 39 | 40 | /* Release TamaLIB */ 41 | tamalib_release(); 42 | 43 | /* ... */ 44 | ``` 45 | Your main project should then forward any button input to TamaLIB using the `tamalib_set_button()` function. 46 | 47 | As an alternative to `tamalib_mainloop()`, you can call `tamalib_step()` directly if your execution flow requires something more complex than a simple mainloop. In that case, TamaLIB will neither call the HAL `handler()` function, nor the HAL `update_screen()` function by itslef. 48 | 49 | 50 | ## License 51 | 52 | TamaLIB is distributed under the GPLv2 license. See the LICENSE file for more information. 53 | 54 | 55 | ## Hardware information 56 | 57 | The Tamagotchi P1 is based on an 58 | [E0C6S46 Epson MCU](https://download.epson-europe.com/pub/electronics-de/asmic/4bit/62family/technicalmanual/tm_6s46.pdf), 59 | and runs at 32,768 kHz. Its LCD is 32x16 B/W pixels, with 8 icons. 60 | To my knowledge, the ROM available online has been extracted from a high-res picture of a die. The ROM mask was clear enough to be optically read. The pictures can be seen [there](https://siliconpr0n.org/map/bandai/tamagotchi-v1/) (thx asterick for the link !). 61 | I would love to see the same work done on a P2 and add support for it in TamaLIB/TamaTool ! 62 | 63 | __ 64 | Copyright (C) 2021 Jean-Christophe Rona 65 | -------------------------------------------------------------------------------- /tama_p1/tamalib/tamalib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #include "tamalib.h" 21 | #include "hw.h" 22 | #include "cpu.h" 23 | #include "hal.h" 24 | 25 | #define DEFAULT_FRAMERATE 30 // fps 26 | 27 | static exec_mode_t exec_mode = EXEC_MODE_RUN; 28 | 29 | static u32_t step_depth = 0; 30 | 31 | static timestamp_t screen_ts = 0; 32 | 33 | static u32_t ts_freq; 34 | 35 | static u8_t g_framerate = DEFAULT_FRAMERATE; 36 | 37 | hal_t* g_hal; 38 | 39 | bool_t tamalib_init(const u12_t* program, breakpoint_t* breakpoints, u32_t freq) { 40 | bool_t res = 0; 41 | 42 | res |= cpu_init(program, breakpoints, freq); 43 | res |= hw_init(); 44 | 45 | ts_freq = freq; 46 | 47 | return res; 48 | } 49 | 50 | void tamalib_release(void) { 51 | hw_release(); 52 | cpu_release(); 53 | } 54 | 55 | void tamalib_set_framerate(u8_t framerate) { 56 | g_framerate = framerate; 57 | } 58 | 59 | u8_t tamalib_get_framerate(void) { 60 | return g_framerate; 61 | } 62 | 63 | void tamalib_register_hal(hal_t* hal) { 64 | g_hal = hal; 65 | } 66 | 67 | void tamalib_set_exec_mode(exec_mode_t mode) { 68 | exec_mode = mode; 69 | step_depth = cpu_get_depth(); 70 | cpu_sync_ref_timestamp(); 71 | } 72 | 73 | void tamalib_step(void) { 74 | if(exec_mode == EXEC_MODE_PAUSE) { 75 | return; 76 | } 77 | 78 | if(cpu_step()) { 79 | exec_mode = EXEC_MODE_PAUSE; 80 | step_depth = cpu_get_depth(); 81 | } else { 82 | switch(exec_mode) { 83 | case EXEC_MODE_PAUSE: 84 | case EXEC_MODE_RUN: 85 | break; 86 | 87 | case EXEC_MODE_STEP: 88 | exec_mode = EXEC_MODE_PAUSE; 89 | break; 90 | 91 | case EXEC_MODE_NEXT: 92 | if(cpu_get_depth() <= step_depth) { 93 | exec_mode = EXEC_MODE_PAUSE; 94 | step_depth = cpu_get_depth(); 95 | } 96 | break; 97 | 98 | case EXEC_MODE_TO_CALL: 99 | if(cpu_get_depth() > step_depth) { 100 | exec_mode = EXEC_MODE_PAUSE; 101 | step_depth = cpu_get_depth(); 102 | } 103 | break; 104 | 105 | case EXEC_MODE_TO_RET: 106 | if(cpu_get_depth() < step_depth) { 107 | exec_mode = EXEC_MODE_PAUSE; 108 | step_depth = cpu_get_depth(); 109 | } 110 | break; 111 | } 112 | } 113 | } 114 | 115 | void tamalib_mainloop(void) { 116 | timestamp_t ts; 117 | 118 | while(!g_hal->handler()) { 119 | tamalib_step(); 120 | 121 | /* Update the screen @ g_framerate fps */ 122 | ts = g_hal->get_timestamp(); 123 | if(ts - screen_ts >= ts_freq / g_framerate) { 124 | screen_ts = ts; 125 | g_hal->update_screen(); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /tama_p1/tamalib/hw.c: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #include "hw.h" 21 | #include "cpu.h" 22 | #include "hal.h" 23 | 24 | /* SEG -> LCD mapping */ 25 | static u8_t seg_pos[40] = {0, 1, 2, 3, 4, 5, 6, 7, 32, 8, 9, 10, 11, 12, 26 | 13, 14, 15, 33, 34, 35, 31, 30, 29, 28, 27, 26, 25, 24, 27 | 36, 23, 22, 21, 20, 19, 18, 17, 16, 37, 38, 39}; 28 | 29 | bool_t hw_init(void) { 30 | /* Buttons are active LOW */ 31 | cpu_set_input_pin(PIN_K00, PIN_STATE_HIGH); 32 | cpu_set_input_pin(PIN_K01, PIN_STATE_HIGH); 33 | cpu_set_input_pin(PIN_K02, PIN_STATE_HIGH); 34 | 35 | return 0; 36 | } 37 | 38 | void hw_release(void) { 39 | } 40 | 41 | void hw_set_lcd_pin(u8_t seg, u8_t com, u8_t val) { 42 | if(seg_pos[seg] < LCD_WIDTH) { 43 | g_hal->set_lcd_matrix(seg_pos[seg], com, val); 44 | } else { 45 | /* 46 | * IC n -> seg-com|... 47 | * IC 0 -> 8-0 |18-3 |19-2 48 | * IC 1 -> 8-1 |17-0 |19-3 49 | * IC 2 -> 8-2 |17-1 |37-12|38-13|39-14 50 | * IC 3 -> 8-3 |17-2 |18-1 |19-0 51 | * IC 4 -> 28-12|37-13|38-14|39-15 52 | * IC 5 -> 28-13|37-14|38-15 53 | * IC 6 -> 28-14|37-15|39-12 54 | * IC 7 -> 28-15|38-12|39-13 55 | */ 56 | if(seg == 8 && com < 4) { 57 | g_hal->set_lcd_icon(com, val); 58 | } else if(seg == 28 && com >= 12) { 59 | g_hal->set_lcd_icon(com - 8, val); 60 | } 61 | } 62 | } 63 | 64 | void hw_set_button(button_t btn, btn_state_t state) { 65 | pin_state_t pin_state = (state == BTN_STATE_PRESSED) ? PIN_STATE_LOW : PIN_STATE_HIGH; 66 | 67 | switch(btn) { 68 | case BTN_LEFT: 69 | cpu_set_input_pin(PIN_K02, pin_state); 70 | break; 71 | 72 | case BTN_MIDDLE: 73 | cpu_set_input_pin(PIN_K01, pin_state); 74 | break; 75 | 76 | case BTN_RIGHT: 77 | cpu_set_input_pin(PIN_K00, pin_state); 78 | break; 79 | } 80 | } 81 | 82 | void hw_set_buzzer_freq(u4_t freq) { 83 | u32_t snd_freq = 0; 84 | 85 | switch(freq) { 86 | case 0: 87 | /* 4096.0 Hz */ 88 | snd_freq = 40960; 89 | break; 90 | 91 | case 1: 92 | /* 3276.8 Hz */ 93 | snd_freq = 32768; 94 | break; 95 | 96 | case 2: 97 | /* 2730.7 Hz */ 98 | snd_freq = 27307; 99 | break; 100 | 101 | case 3: 102 | /* 2340.6 Hz */ 103 | snd_freq = 23406; 104 | break; 105 | 106 | case 4: 107 | /* 2048.0 Hz */ 108 | snd_freq = 20480; 109 | break; 110 | 111 | case 5: 112 | /* 1638.4 Hz */ 113 | snd_freq = 16384; 114 | break; 115 | 116 | case 6: 117 | /* 1365.3 Hz */ 118 | snd_freq = 13653; 119 | break; 120 | 121 | case 7: 122 | /* 1170.3 Hz */ 123 | snd_freq = 11703; 124 | break; 125 | } 126 | 127 | if(snd_freq != 0) { 128 | g_hal->set_frequency(snd_freq); 129 | } 130 | } 131 | 132 | void hw_enable_buzzer(bool_t en) { 133 | g_hal->play_frequency(en); 134 | } 135 | -------------------------------------------------------------------------------- /tama_p1/hal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "tama.h" 7 | 8 | #define TAG_HAL "TamaLIB" 9 | 10 | static void* tama_p1_hal_malloc(u32_t size) { 11 | return malloc(size); 12 | } 13 | 14 | static void tama_p1_hal_free(void* ptr) { 15 | free(ptr); 16 | } 17 | 18 | static void tama_p1_hal_halt(void) { 19 | g_ctx->halted = true; 20 | } 21 | 22 | static bool_t tama_p1_hal_is_log_enabled(log_level_t level) { 23 | switch(level) { 24 | case LOG_ERROR: 25 | return true; 26 | case LOG_INFO: 27 | return true; 28 | case LOG_MEMORY: 29 | return false; 30 | case LOG_CPU: 31 | return false; 32 | default: 33 | return false; 34 | } 35 | } 36 | 37 | static void tama_p1_hal_log(log_level_t level, char* buff, ...) { 38 | if(!tama_p1_hal_is_log_enabled(level)) return; 39 | 40 | string_t string; 41 | va_list args; 42 | va_start(args, buff); 43 | string_init_vprintf(string, buff, args); 44 | va_end(args); 45 | 46 | switch(level) { 47 | case LOG_ERROR: 48 | FURI_LOG_E(TAG_HAL, "%s", string_get_cstr(string)); 49 | break; 50 | case LOG_INFO: 51 | FURI_LOG_I(TAG_HAL, "%s", string_get_cstr(string)); 52 | break; 53 | case LOG_MEMORY: 54 | case LOG_CPU: 55 | default: 56 | FURI_LOG_D(TAG_HAL, "%s", string_get_cstr(string)); 57 | break; 58 | } 59 | 60 | string_clear(string); 61 | } 62 | 63 | static void tama_p1_hal_sleep_until(timestamp_t ts) { 64 | while(true) { 65 | uint32_t count = LL_TIM_GetCounter(TIM2); 66 | uint32_t delay = ts - count; 67 | // FURI_LOG_D(TAG, "delay: %x", delay); 68 | // Stolen from furi_delay_until_tick 69 | if(delay != 0 && 0 == (delay >> (8 * sizeof(uint32_t) - 1))) { 70 | // Not the best place to release mutex, but this is the only place we know whether 71 | // we're ahead or behind, otherwise around the step call we'll always have to 72 | // delay a tick and run more and more behind. 73 | furi_mutex_release(g_state_mutex); 74 | furi_delay_tick(1); 75 | while(furi_mutex_acquire(g_state_mutex, FuriWaitForever) != FuriStatusOk) 76 | furi_delay_tick(1); 77 | } else { 78 | break; 79 | } 80 | } 81 | } 82 | 83 | static timestamp_t tama_p1_hal_get_timestamp(void) { 84 | return LL_TIM_GetCounter(TIM2); 85 | } 86 | 87 | static void tama_p1_hal_update_screen(void) { 88 | // Do nothing, covered by main loop 89 | } 90 | 91 | static void tama_p1_hal_set_lcd_matrix(u8_t x, u8_t y, bool_t val) { 92 | if(val) 93 | g_ctx->framebuffer[y] |= 1 << x; 94 | else 95 | g_ctx->framebuffer[y] &= ~(1 << x); 96 | } 97 | 98 | static void tama_p1_hal_set_lcd_icon(u8_t icon, bool_t val) { 99 | if(val) 100 | g_ctx->icons |= 1 << icon; 101 | else 102 | g_ctx->icons &= ~(1 << icon); 103 | } 104 | 105 | static void tama_p1_hal_play_frequency(bool_t en) { 106 | if(en) 107 | furi_hal_speaker_start(g_ctx->frequency, 0.5f); 108 | else 109 | furi_hal_speaker_stop(); 110 | 111 | g_ctx->buzzer_on = en; 112 | } 113 | 114 | static void tama_p1_hal_set_frequency(u32_t freq) { 115 | g_ctx->frequency = freq / 10.0F; 116 | if(g_ctx->buzzer_on) tama_p1_hal_play_frequency(true); 117 | } 118 | 119 | static int tama_p1_hal_handler(void) { 120 | // Do nothing 121 | return 0; 122 | } 123 | 124 | void tama_p1_hal_init(hal_t* hal) { 125 | hal->malloc = tama_p1_hal_malloc; 126 | hal->free = tama_p1_hal_free; 127 | hal->halt = tama_p1_hal_halt; 128 | hal->is_log_enabled = tama_p1_hal_is_log_enabled; 129 | hal->log = tama_p1_hal_log; 130 | hal->sleep_until = tama_p1_hal_sleep_until; 131 | hal->get_timestamp = tama_p1_hal_get_timestamp; 132 | hal->update_screen = tama_p1_hal_update_screen; 133 | hal->set_lcd_matrix = tama_p1_hal_set_lcd_matrix; 134 | hal->set_lcd_icon = tama_p1_hal_set_lcd_icon; 135 | hal->set_frequency = tama_p1_hal_set_frequency; 136 | hal->play_frequency = tama_p1_hal_play_frequency; 137 | hal->handler = tama_p1_hal_handler; 138 | } 139 | -------------------------------------------------------------------------------- /flipfrid/scene/flipfrid_scene_select_field.c: -------------------------------------------------------------------------------- 1 | #include "flipfrid_scene_select_field.h" 2 | 3 | void flipfrid_center_displayed_key(FlipFridState* context, uint8_t index) { 4 | const char* key_cstr = string_get_cstr(context->data_str); 5 | uint8_t str_index = (index * 3); 6 | 7 | char display_menu[17] = { 8 | 'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'}; 9 | 10 | if(index > 1) { 11 | display_menu[0] = key_cstr[str_index - 6]; 12 | display_menu[1] = key_cstr[str_index - 5]; 13 | } else { 14 | display_menu[0] = ' '; 15 | display_menu[1] = ' '; 16 | } 17 | 18 | if(index > 0) { 19 | display_menu[3] = key_cstr[str_index - 3]; 20 | display_menu[4] = key_cstr[str_index - 2]; 21 | } else { 22 | display_menu[3] = ' '; 23 | display_menu[4] = ' '; 24 | } 25 | 26 | display_menu[7] = key_cstr[str_index]; 27 | display_menu[8] = key_cstr[str_index + 1]; 28 | 29 | if((str_index + 4) <= (uint8_t)strlen(key_cstr)) { 30 | display_menu[11] = key_cstr[str_index + 3]; 31 | display_menu[12] = key_cstr[str_index + 4]; 32 | } else { 33 | display_menu[11] = ' '; 34 | display_menu[12] = ' '; 35 | } 36 | 37 | if((str_index + 8) <= (uint8_t)strlen(key_cstr)) { 38 | display_menu[14] = key_cstr[str_index + 6]; 39 | display_menu[15] = key_cstr[str_index + 7]; 40 | } else { 41 | display_menu[14] = ' '; 42 | display_menu[15] = ' '; 43 | } 44 | 45 | string_reset(context->notification_msg); 46 | string_set_str(context->notification_msg, display_menu); 47 | } 48 | 49 | void flipfrid_scene_select_field_on_enter(FlipFridState* context) { 50 | string_clear(context->notification_msg); 51 | } 52 | 53 | void flipfrid_scene_select_field_on_exit(FlipFridState* context) { 54 | UNUSED(context); 55 | } 56 | 57 | void flipfrid_scene_select_field_on_tick(FlipFridState* context) { 58 | UNUSED(context); 59 | } 60 | 61 | void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context) { 62 | if(event.evt_type == EventTypeKey) { 63 | if(event.input_type == InputTypeShort) { 64 | const char* key_cstr = string_get_cstr(context->data_str); 65 | 66 | // don't look, it's ugly but I'm a python dev so... 67 | uint8_t nb_bytes = 0; 68 | for(uint8_t i = 0; i < strlen(key_cstr); i++) { 69 | if(' ' == key_cstr[i]) { 70 | nb_bytes++; 71 | } 72 | } 73 | 74 | switch(event.key) { 75 | case InputKeyDown: 76 | case InputKeyUp: 77 | break; 78 | case InputKeyLeft: 79 | if(context->key_index > 0) { 80 | context->key_index = context->key_index - 1; 81 | } 82 | break; 83 | case InputKeyRight: 84 | if(context->key_index < nb_bytes) { 85 | context->key_index = context->key_index + 1; 86 | } 87 | break; 88 | case InputKeyOk: 89 | string_reset(context->notification_msg); 90 | context->current_scene = SceneAttack; 91 | break; 92 | case InputKeyBack: 93 | string_reset(context->notification_msg); 94 | context->current_scene = SceneSelectFile; 95 | break; 96 | } 97 | FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes); 98 | } 99 | } 100 | } 101 | 102 | void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context) { 103 | canvas_clear(canvas); 104 | canvas_set_color(canvas, ColorBlack); 105 | 106 | // Frame 107 | //canvas_draw_frame(canvas, 0, 0, 128, 64); 108 | 109 | // Title 110 | canvas_set_font(canvas, FontPrimary); 111 | canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "Use < > to select byte."); 112 | 113 | char msg_index[18]; 114 | snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index); 115 | canvas_draw_str_aligned(canvas, 64, 26, AlignCenter, AlignTop, msg_index); 116 | 117 | flipfrid_center_displayed_key(context, context->key_index); 118 | canvas_set_font(canvas, FontSecondary); 119 | canvas_draw_str_aligned( 120 | canvas, 64, 40, AlignCenter, AlignTop, string_get_cstr(context->notification_msg)); 121 | } 122 | -------------------------------------------------------------------------------- /game_of_life/game_of_life.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #define SCREEN_WIDTH 128 8 | #define SCREEN_HEIGHT 64 9 | #define TOTAL_PIXELS SCREEN_WIDTH* SCREEN_HEIGHT 10 | 11 | typedef enum { 12 | EventTypeTick, 13 | EventTypeKey, 14 | } EventType; 15 | 16 | typedef struct { 17 | EventType type; 18 | InputEvent input; 19 | } AppEvent; 20 | 21 | typedef struct { 22 | bool revive; 23 | int evo; 24 | } State; 25 | 26 | unsigned char new[TOTAL_PIXELS] = {}; 27 | unsigned char old[TOTAL_PIXELS] = {}; 28 | unsigned char* fields[] = {new, old}; 29 | 30 | int current = 0; 31 | int next = 1; 32 | 33 | unsigned char get_cell(int x, int y) { 34 | if(x <= 0 || x >= SCREEN_WIDTH) return 0; 35 | if(y <= 0 || y >= SCREEN_HEIGHT) return 0; 36 | 37 | int pix = (y * SCREEN_WIDTH) + x; 38 | return fields[current][pix]; 39 | } 40 | 41 | int count_neightbors(int x, int y) { 42 | return get_cell(x + 1, y - 1) + get_cell(x - 1, y - 1) + get_cell(x - 1, y + 1) + 43 | get_cell(x + 1, y + 1) + get_cell(x + 1, y) + get_cell(x - 1, y) + get_cell(x, y - 1) + 44 | get_cell(x, y + 1); 45 | } 46 | 47 | static void update_field(State* state) { 48 | if(state->revive) { 49 | for(int i = 0; i < TOTAL_PIXELS; ++i) { 50 | if((random() % 100) == 1) { 51 | fields[current][i] = 1; 52 | } 53 | state->revive = false; 54 | } 55 | } 56 | 57 | for(int i = 0; i < TOTAL_PIXELS; ++i) { 58 | int x = i % SCREEN_WIDTH; 59 | int y = (int)(i / SCREEN_WIDTH); 60 | 61 | int v = get_cell(x, y); 62 | int n = count_neightbors(x, y); 63 | 64 | if(v && n == 3) { 65 | ++state->evo; 66 | } else if(v && (n < 2 || n > 3)) { 67 | ++state->evo; 68 | v = 0; 69 | } else if(!v && n == 3) { 70 | ++state->evo; 71 | v = 1; 72 | } 73 | 74 | fields[next][i] = v; 75 | } 76 | 77 | next ^= current; 78 | current ^= next; 79 | next ^= current; 80 | 81 | if(state->evo < TOTAL_PIXELS) { 82 | state->revive = true; 83 | state->evo = 0; 84 | } 85 | } 86 | 87 | static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { 88 | furi_assert(event_queue); 89 | 90 | AppEvent event = {.type = EventTypeKey, .input = *input_event}; 91 | furi_message_queue_put(event_queue, &event, 0); 92 | } 93 | 94 | static void render_callback(Canvas* canvas, void* ctx) { 95 | State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25); 96 | canvas_clear(canvas); 97 | 98 | for(int i = 0; i < TOTAL_PIXELS; ++i) { 99 | int x = i % SCREEN_WIDTH; 100 | int y = (int)(i / SCREEN_WIDTH); 101 | if(fields[current][i] == 1) canvas_draw_dot(canvas, x, y); 102 | } 103 | release_mutex((ValueMutex*)ctx, state); 104 | } 105 | 106 | int32_t game_of_life_app(void* p) { 107 | UNUSED(p); 108 | srand(DWT->CYCCNT); 109 | 110 | FuriMessageQueue* event_queue = furi_message_queue_alloc(1, sizeof(AppEvent)); 111 | furi_check(event_queue); 112 | 113 | State* _state = malloc(sizeof(State)); 114 | 115 | ValueMutex state_mutex; 116 | if(!init_mutex(&state_mutex, _state, sizeof(State))) { 117 | printf("cannot create mutex\r\n"); 118 | furi_message_queue_free(event_queue); 119 | free(_state); 120 | return 255; 121 | } 122 | 123 | ViewPort* view_port = view_port_alloc(); 124 | view_port_draw_callback_set(view_port, render_callback, &state_mutex); 125 | view_port_input_callback_set(view_port, input_callback, event_queue); 126 | 127 | Gui* gui = furi_record_open(RECORD_GUI); 128 | gui_add_view_port(gui, view_port, GuiLayerFullscreen); 129 | 130 | AppEvent event; 131 | for(bool processing = true; processing;) { 132 | State* state = (State*)acquire_mutex_block(&state_mutex); 133 | FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25); 134 | 135 | if(event_status == FuriStatusOk && event.type == EventTypeKey && 136 | event.input.type == InputTypePress) { 137 | if(event.input.key == InputKeyBack) { 138 | // furiac_exit(NULL); 139 | processing = false; 140 | release_mutex(&state_mutex, state); 141 | break; 142 | } 143 | } 144 | 145 | update_field(state); 146 | 147 | view_port_update(view_port); 148 | release_mutex(&state_mutex, state); 149 | } 150 | 151 | view_port_enabled_set(view_port, false); 152 | gui_remove_view_port(gui, view_port); 153 | furi_record_close(RECORD_GUI); 154 | view_port_free(view_port); 155 | furi_message_queue_free(event_queue); 156 | delete_mutex(&state_mutex); 157 | free(_state); 158 | 159 | return 0; 160 | } -------------------------------------------------------------------------------- /mouse_jiggler/mouse_jiggler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MOUSE_MOVE_SHORT 5 7 | #define MOUSE_MOVE_LONG 20 8 | 9 | typedef enum { 10 | EventTypeInput, 11 | EventTypeKey, 12 | } EventType; 13 | 14 | typedef struct { 15 | EventType type; 16 | InputEvent input; 17 | } UsbMouseEvent; 18 | 19 | typedef struct { 20 | bool running; 21 | } MouseJigglerState; 22 | 23 | static void mouse_jiggler_render_callback(Canvas* canvas, void* ctx) { 24 | const MouseJigglerState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25); 25 | if(plugin_state == NULL) { 26 | return; 27 | } 28 | 29 | canvas_set_font(canvas, FontPrimary); 30 | canvas_draw_str(canvas, 2, 12, "USB Mouse Jiggler"); 31 | if(!plugin_state->running) { 32 | canvas_set_font(canvas, FontSecondary); 33 | canvas_draw_str(canvas, 2, 27, " -> STOPPED"); 34 | canvas_draw_str(canvas, 2, 51, "Press [ok] to start"); 35 | canvas_draw_str(canvas, 2, 63, "Press [back] to exit"); 36 | } else { 37 | canvas_set_font(canvas, FontSecondary); 38 | canvas_draw_str(canvas, 2, 27, " -> RUNNING"); 39 | canvas_draw_str(canvas, 2, 51, "Press [back] to stop"); 40 | } 41 | 42 | release_mutex((ValueMutex*)ctx, plugin_state); 43 | } 44 | 45 | static void mouse_jiggler_input_callback(InputEvent* input_event, void* ctx) { 46 | FuriMessageQueue* event_queue = ctx; 47 | furi_assert(event_queue); 48 | 49 | UsbMouseEvent event = {.type = EventTypeKey, .input = *input_event}; 50 | furi_message_queue_put(event_queue, &event, FuriWaitForever); 51 | } 52 | 53 | static void mouse_jiggler_state_init(MouseJigglerState* const plugin_state) { 54 | plugin_state->running = false; 55 | } 56 | 57 | int32_t mouse_jiggler_app(void* p) { 58 | UNUSED(p); 59 | 60 | FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(UsbMouseEvent)); 61 | 62 | MouseJigglerState* plugin_state = malloc(sizeof(MouseJigglerState)); 63 | if(plugin_state == NULL) { 64 | FURI_LOG_E("MouseJiggler", "MouseJigglerState: malloc error\r\n"); 65 | return 255; 66 | } 67 | mouse_jiggler_state_init(plugin_state); 68 | 69 | ValueMutex state_mutex; 70 | if(!init_mutex(&state_mutex, plugin_state, sizeof(MouseJigglerState))) { 71 | FURI_LOG_E("MouseJiggler", "cannot create mutex\r\n"); 72 | furi_message_queue_free(event_queue); 73 | free(plugin_state); 74 | return 255; 75 | } 76 | 77 | ViewPort* view_port = view_port_alloc(); 78 | view_port_draw_callback_set(view_port, mouse_jiggler_render_callback, &state_mutex); 79 | view_port_input_callback_set(view_port, mouse_jiggler_input_callback, event_queue); 80 | 81 | FuriHalUsbInterface* usb_mode_prev = furi_hal_usb_get_config(); 82 | furi_hal_usb_set_config(&usb_hid, NULL); 83 | 84 | // Open GUI and register view_port 85 | Gui* gui = furi_record_open(RECORD_GUI); 86 | gui_add_view_port(gui, view_port, GuiLayerFullscreen); 87 | 88 | UsbMouseEvent event; 89 | //bool status = 0; 90 | 91 | for(bool processing = true; processing;) { 92 | FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); 93 | 94 | MouseJigglerState* plugin_state = (MouseJigglerState*)acquire_mutex_block(&state_mutex); 95 | 96 | if(event_status == FuriStatusOk) { 97 | if(event.type == EventTypeKey) { 98 | if(event.input.type == InputTypePress) { 99 | switch(event.input.key) { 100 | case InputKeyOk: 101 | if(!plugin_state->running) { 102 | plugin_state->running = true; 103 | } 104 | break; 105 | case InputKeyBack: 106 | if(!plugin_state->running) { 107 | processing = false; 108 | } else { 109 | plugin_state->running = false; 110 | } 111 | break; 112 | default: 113 | break; 114 | } 115 | } 116 | } 117 | } 118 | 119 | if(plugin_state->running) { 120 | furi_hal_hid_mouse_move(MOUSE_MOVE_SHORT, 0); 121 | furi_delay_ms(500); 122 | furi_hal_hid_mouse_move(-MOUSE_MOVE_SHORT, 0); 123 | furi_delay_ms(500); 124 | } 125 | 126 | view_port_update(view_port); 127 | release_mutex(&state_mutex, plugin_state); 128 | } 129 | 130 | furi_hal_usb_set_config(usb_mode_prev, NULL); 131 | 132 | // remove & free all stuff created by app 133 | view_port_enabled_set(view_port, false); 134 | gui_remove_view_port(gui, view_port); 135 | furi_record_close(RECORD_GUI); 136 | view_port_free(view_port); 137 | furi_message_queue_free(event_queue); 138 | delete_mutex(&state_mutex); 139 | 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /paint/paint.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include // Header-file for boolean data-type. 8 | 9 | typedef struct selected_position { 10 | int x; 11 | int y; 12 | } selected_position; 13 | 14 | typedef struct { 15 | selected_position selected; 16 | bool board[32][16]; 17 | bool isDrawing; 18 | } PaintData; 19 | 20 | void paint_draw_callback(Canvas* canvas, void* ctx) { 21 | const PaintData* paint_state = acquire_mutex((ValueMutex*)ctx, 25); 22 | UNUSED(ctx); 23 | canvas_clear(canvas); 24 | canvas_set_color(canvas, ColorBlack); 25 | //draw the canvas(32x16) on screen(144x64) using 4x4 tiles 26 | for(int y = 0; y < 16; y++) { 27 | for(int x = 0; x < 32; x++) { 28 | if(paint_state->board[x][y]) { 29 | canvas_draw_box(canvas, x * 4, y * 4, 4, 4); 30 | } 31 | } 32 | } 33 | 34 | //draw cursor as a 4x4 black box with a 2x2 white box inside 35 | canvas_set_color(canvas, ColorBlack); 36 | canvas_draw_box(canvas, paint_state->selected.x * 4, paint_state->selected.y * 4, 4, 4); 37 | canvas_set_color(canvas, ColorWhite); 38 | canvas_draw_box( 39 | canvas, paint_state->selected.x * 4 + 1, paint_state->selected.y * 4 + 1, 2, 2); 40 | 41 | //release the mutex 42 | release_mutex((ValueMutex*)ctx, paint_state); 43 | } 44 | 45 | void paint_input_callback(InputEvent* input_event, void* ctx) { 46 | furi_assert(ctx); 47 | FuriMessageQueue* event_queue = ctx; 48 | furi_message_queue_put(event_queue, input_event, FuriWaitForever); 49 | } 50 | 51 | int32_t paint_app(void* p) { 52 | UNUSED(p); 53 | FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); 54 | 55 | PaintData* paint_state = malloc(sizeof(PaintData)); 56 | ValueMutex paint_state_mutex; 57 | if(!init_mutex(&paint_state_mutex, paint_state, sizeof(PaintData))) { 58 | FURI_LOG_E("paint", "cannot create mutex\r\n"); 59 | free(paint_state); 60 | return -1; 61 | } 62 | 63 | // Configure view port 64 | ViewPort* view_port = view_port_alloc(); 65 | view_port_draw_callback_set(view_port, paint_draw_callback, &paint_state_mutex); 66 | view_port_input_callback_set(view_port, paint_input_callback, event_queue); 67 | 68 | // Register view port in GUI 69 | Gui* gui = furi_record_open(RECORD_GUI); 70 | gui_add_view_port(gui, view_port, GuiLayerFullscreen); 71 | 72 | //NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); 73 | 74 | InputEvent event; 75 | 76 | while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { 77 | //break out of the loop if the back key is pressed 78 | if(event.type == InputTypeShort && event.key == InputKeyBack) { 79 | break; 80 | } 81 | 82 | //check the key pressed and change x and y accordingly 83 | if(event.type == InputTypeShort) { 84 | switch(event.key) { 85 | case InputKeyUp: 86 | paint_state->selected.y -= 1; 87 | break; 88 | case InputKeyDown: 89 | paint_state->selected.y += 1; 90 | break; 91 | case InputKeyLeft: 92 | paint_state->selected.x -= 1; 93 | break; 94 | case InputKeyRight: 95 | paint_state->selected.x += 1; 96 | break; 97 | case InputKeyOk: 98 | paint_state->board[paint_state->selected.x][paint_state->selected.y] = 99 | !paint_state->board[paint_state->selected.x][paint_state->selected.y]; 100 | break; 101 | 102 | default: 103 | break; 104 | } 105 | 106 | //check if cursor position is out of bounds and reset it to the closest position 107 | if(paint_state->selected.x < 0) { 108 | paint_state->selected.x = 0; 109 | } 110 | if(paint_state->selected.x > 31) { 111 | paint_state->selected.x = 31; 112 | } 113 | if(paint_state->selected.y < 0) { 114 | paint_state->selected.y = 0; 115 | } 116 | if(paint_state->selected.y > 15) { 117 | paint_state->selected.y = 15; 118 | } 119 | if(paint_state->isDrawing == true) { 120 | paint_state->board[paint_state->selected.x][paint_state->selected.y] = true; 121 | } 122 | view_port_update(view_port); 123 | } 124 | if(event.key == InputKeyBack && event.type == InputTypeLong) { 125 | paint_state->board[1][1] = true; 126 | for(int y = 0; y < 16; y++) { 127 | for(int x = 0; x < 32; x++) { 128 | paint_state->board[x][y] = false; 129 | } 130 | } 131 | view_port_update(view_port); 132 | } 133 | if(event.key == InputKeyOk && event.type == InputTypeLong) { 134 | paint_state->isDrawing = !paint_state->isDrawing; 135 | paint_state->board[paint_state->selected.x][paint_state->selected.y] = true; 136 | view_port_update(view_port); 137 | } 138 | } 139 | 140 | gui_remove_view_port(gui, view_port); 141 | view_port_free(view_port); 142 | furi_message_queue_free(event_queue); 143 | free(paint_state); 144 | furi_record_close(RECORD_NOTIFICATION); 145 | furi_record_close(RECORD_GUI); 146 | 147 | return 0; 148 | } 149 | -------------------------------------------------------------------------------- /sentry_safe/sentry_safe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | typedef struct { 9 | uint8_t status; 10 | } SentryState; 11 | 12 | typedef enum { 13 | EventTypeTick, 14 | EventTypeKey, 15 | } EventType; 16 | 17 | typedef struct { 18 | EventType type; 19 | InputEvent input; 20 | } Event; 21 | 22 | const char* status_texts[3] = {"[Press OK to open safe]", "Sending...", "Done !"}; 23 | 24 | static void sentry_safe_render_callback(Canvas* const canvas, void* ctx) { 25 | const SentryState* sentry_state = acquire_mutex((ValueMutex*)ctx, 25); 26 | if(sentry_state == NULL) { 27 | return; 28 | } 29 | 30 | // Before the function is called, the state is set with the canvas_reset(canvas) 31 | 32 | // Frame 33 | canvas_draw_frame(canvas, 0, 0, 128, 64); 34 | 35 | // Message 36 | canvas_set_font(canvas, FontPrimary); 37 | 38 | canvas_draw_frame(canvas, 22, 4, 84, 24); 39 | canvas_draw_str_aligned(canvas, 64, 15, AlignCenter, AlignBottom, "BLACK <-> GND"); 40 | canvas_draw_str_aligned(canvas, 64, 25, AlignCenter, AlignBottom, "GREEN <-> C1 "); 41 | canvas_draw_str_aligned( 42 | canvas, 64, 50, AlignCenter, AlignBottom, status_texts[sentry_state->status]); 43 | 44 | release_mutex((ValueMutex*)ctx, sentry_state); 45 | } 46 | 47 | static void sentry_safe_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { 48 | furi_assert(event_queue); 49 | 50 | Event event = {.type = EventTypeKey, .input = *input_event}; 51 | furi_message_queue_put(event_queue, &event, FuriWaitForever); 52 | } 53 | 54 | void send_request(int command, int a, int b, int c, int d, int e) { 55 | int checksum = (command + a + b + c + d + e); 56 | 57 | furi_hal_gpio_init_simple(&gpio_ext_pc1, GpioModeOutputPushPull); 58 | furi_hal_gpio_write(&gpio_ext_pc1, false); 59 | furi_delay_ms(3.4); 60 | furi_hal_gpio_write(&gpio_ext_pc1, true); 61 | 62 | furi_hal_uart_init(FuriHalUartIdLPUART1, 4800); 63 | //furi_hal_uart_set_br(FuriHalUartIdLPUART1, 4800); 64 | //furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, usb_uart_on_irq_cb, usb_uart); 65 | 66 | uint8_t data[8] = {0x0, command, a, b, c, d, e, checksum}; 67 | furi_hal_uart_tx(FuriHalUartIdLPUART1, data, 8); 68 | 69 | furi_delay_ms(100); 70 | 71 | furi_hal_uart_set_irq_cb(FuriHalUartIdLPUART1, NULL, NULL); 72 | furi_hal_uart_deinit(FuriHalUartIdLPUART1); 73 | } 74 | 75 | void reset_code(int a, int b, int c, int d, int e) { 76 | send_request(0x75, a, b, c, d, e); 77 | } 78 | 79 | void try_code(int a, int b, int c, int d, int e) { 80 | send_request(0x71, a, b, c, d, e); 81 | } 82 | 83 | int32_t sentry_safe_app(void* p) { 84 | UNUSED(p); 85 | 86 | FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(Event)); 87 | 88 | SentryState* sentry_state = malloc(sizeof(SentryState)); 89 | 90 | sentry_state->status = 0; 91 | 92 | ValueMutex state_mutex; 93 | if(!init_mutex(&state_mutex, sentry_state, sizeof(SentryState))) { 94 | FURI_LOG_E("SentrySafe", "cannot create mutex\r\n"); 95 | furi_message_queue_free(event_queue); 96 | free(sentry_state); 97 | return 255; 98 | } 99 | 100 | ViewPort* view_port = view_port_alloc(); 101 | view_port_draw_callback_set(view_port, sentry_safe_render_callback, &state_mutex); 102 | view_port_input_callback_set(view_port, sentry_safe_input_callback, event_queue); 103 | 104 | // Open GUI and register view_port 105 | Gui* gui = furi_record_open(RECORD_GUI); 106 | gui_add_view_port(gui, view_port, GuiLayerFullscreen); 107 | 108 | Event event; 109 | for(bool processing = true; processing;) { 110 | FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); 111 | 112 | SentryState* sentry_state = (SentryState*)acquire_mutex_block(&state_mutex); 113 | 114 | if(event_status == FuriStatusOk) { 115 | // press events 116 | if(event.type == EventTypeKey) { 117 | if(event.input.type == InputTypePress) { 118 | switch(event.input.key) { 119 | case InputKeyUp: 120 | break; 121 | case InputKeyDown: 122 | break; 123 | case InputKeyRight: 124 | break; 125 | case InputKeyLeft: 126 | break; 127 | case InputKeyOk: 128 | 129 | if(sentry_state->status == 2) { 130 | sentry_state->status = 0; 131 | 132 | } else if(sentry_state->status == 0) { 133 | sentry_state->status = 1; 134 | 135 | reset_code(1, 2, 3, 4, 5); 136 | furi_delay_ms(500); 137 | try_code(1, 2, 3, 4, 5); 138 | 139 | sentry_state->status = 2; 140 | } 141 | 142 | break; 143 | case InputKeyBack: 144 | processing = false; 145 | break; 146 | } 147 | } 148 | } 149 | } else { 150 | // event timeout 151 | } 152 | 153 | view_port_update(view_port); 154 | release_mutex(&state_mutex, sentry_state); 155 | } 156 | 157 | view_port_enabled_set(view_port, false); 158 | gui_remove_view_port(gui, view_port); 159 | furi_record_close(RECORD_GUI); 160 | view_port_free(view_port); 161 | furi_message_queue_free(event_queue); 162 | delete_mutex(&state_mutex); 163 | free(sentry_state); 164 | 165 | return 0; 166 | } -------------------------------------------------------------------------------- /multi_converter/multi_converter_units.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "multi_converter_definitions.h" 7 | 8 | #define MULTI_CONVERTER_AVAILABLE_UNITS 14 9 | 10 | #define multi_converter_get_unit(unit_type) multi_converter_available_units[unit_type] 11 | #define multi_converter_get_unit_type_offset(unit_type, offset) \ 12 | (((unit_type + offset) % MULTI_CONVERTER_AVAILABLE_UNITS + MULTI_CONVERTER_AVAILABLE_UNITS) % \ 13 | MULTI_CONVERTER_AVAILABLE_UNITS) 14 | // the modulo operation will fail with extremely large values on the units array 15 | 16 | // DEC / HEX / BIN 17 | void multi_converter_unit_dec_hex_bin_convert(MultiConverterState* const multi_converter_state); 18 | uint8_t multi_converter_unit_dec_hex_bin_allowed(MultiConverterUnitType); 19 | 20 | // CEL / FAR / KEL 21 | void multi_converter_unit_temperature_convert(MultiConverterState* const multi_converter_state); 22 | uint8_t multi_converter_unit_temperature_allowed(MultiConverterUnitType); 23 | 24 | // KM / M / CM / MILES / FEET / INCHES 25 | void multi_converter_unit_distance_convert(MultiConverterState* const multi_converter_state); 26 | uint8_t multi_converter_unit_distance_allowed(MultiConverterUnitType); 27 | 28 | // DEG / RAD 29 | void multi_converter_unit_angle_convert(MultiConverterState* const multi_converter_state); 30 | uint8_t multi_converter_unit_angle_allowed(MultiConverterUnitType unit_type); 31 | 32 | // 33 | // each unit is made of comma? + negative? + keyboard_length + mini_name + name + convert function + allowed function 34 | // (setting functions as NULL will cause convert / select options to be ignored) 35 | // 36 | static const MultiConverterUnit multi_converter_unit_dec = { 37 | 0, 38 | 0, 39 | 10, 40 | "DEC\0", 41 | "Decimal\0", 42 | multi_converter_unit_dec_hex_bin_convert, 43 | multi_converter_unit_dec_hex_bin_allowed}; 44 | static const MultiConverterUnit multi_converter_unit_hex = { 45 | 0, 46 | 0, 47 | 16, 48 | "HEX\0", 49 | "Hexadecimal\0", 50 | multi_converter_unit_dec_hex_bin_convert, 51 | multi_converter_unit_dec_hex_bin_allowed}; 52 | static const MultiConverterUnit multi_converter_unit_bin = { 53 | 0, 54 | 0, 55 | 2, 56 | "BIN\0", 57 | "Binary\0", 58 | multi_converter_unit_dec_hex_bin_convert, 59 | multi_converter_unit_dec_hex_bin_allowed}; 60 | 61 | static const MultiConverterUnit multi_converter_unit_cel = { 62 | 1, 63 | 1, 64 | 10, 65 | "CEL\0", 66 | "Celsius\0", 67 | multi_converter_unit_temperature_convert, 68 | multi_converter_unit_temperature_allowed}; 69 | static const MultiConverterUnit multi_converter_unit_far = { 70 | 1, 71 | 1, 72 | 10, 73 | "FAR\0", 74 | "Fahernheit\0", 75 | multi_converter_unit_temperature_convert, 76 | multi_converter_unit_temperature_allowed}; 77 | static const MultiConverterUnit multi_converter_unit_kel = { 78 | 1, 79 | 1, 80 | 10, 81 | "KEL\0", 82 | "Kelvin\0", 83 | multi_converter_unit_temperature_convert, 84 | multi_converter_unit_temperature_allowed}; 85 | 86 | static const MultiConverterUnit multi_converter_unit_km = { 87 | 1, 88 | 0, 89 | 10, 90 | "KM\0", 91 | "Kilometers\0", 92 | multi_converter_unit_distance_convert, 93 | multi_converter_unit_distance_allowed}; 94 | static const MultiConverterUnit multi_converter_unit_m = { 95 | 1, 96 | 0, 97 | 10, 98 | "M\0", 99 | "Meters\0", 100 | multi_converter_unit_distance_convert, 101 | multi_converter_unit_distance_allowed}; 102 | static const MultiConverterUnit multi_converter_unit_cm = { 103 | 1, 104 | 0, 105 | 10, 106 | "CM\0", 107 | "Centimeters\0", 108 | multi_converter_unit_distance_convert, 109 | multi_converter_unit_distance_allowed}; 110 | static const MultiConverterUnit multi_converter_unit_mi = { 111 | 1, 112 | 0, 113 | 10, 114 | "MI\0", 115 | "Miles\0", 116 | multi_converter_unit_distance_convert, 117 | multi_converter_unit_distance_allowed}; 118 | static const MultiConverterUnit multi_converter_unit_ft = { 119 | 1, 120 | 0, 121 | 10, 122 | "FT\0", 123 | "Feet\0", 124 | multi_converter_unit_distance_convert, 125 | multi_converter_unit_distance_allowed}; 126 | static const MultiConverterUnit multi_converter_unit_in = { 127 | 1, 128 | 0, 129 | 10, 130 | " \"\0", 131 | "Inches\0", 132 | multi_converter_unit_distance_convert, 133 | multi_converter_unit_distance_allowed}; 134 | 135 | static const MultiConverterUnit multi_converter_unit_deg = { 136 | 1, 137 | 0, 138 | 10, 139 | "DEG\0", 140 | "Degree\0", 141 | multi_converter_unit_angle_convert, 142 | multi_converter_unit_angle_allowed}; 143 | static const MultiConverterUnit multi_converter_unit_rad = { 144 | 1, 145 | 0, 146 | 10, 147 | "RAD\0", 148 | "Radian\0", 149 | multi_converter_unit_angle_convert, 150 | multi_converter_unit_angle_allowed}; 151 | 152 | // index order set by the MultiConverterUnitType enum element (multi_converter_definitions.h) 153 | static const MultiConverterUnit multi_converter_available_units[MULTI_CONVERTER_AVAILABLE_UNITS] = { 154 | [UnitTypeDec] = multi_converter_unit_dec, 155 | [UnitTypeHex] = multi_converter_unit_hex, 156 | [UnitTypeBin] = multi_converter_unit_bin, 157 | 158 | [UnitTypeCelsius] = multi_converter_unit_cel, 159 | [UnitTypeFahernheit] = multi_converter_unit_far, 160 | [UnitTypeKelvin] = multi_converter_unit_kel, 161 | 162 | [UnitTypeKilometers] = multi_converter_unit_km, 163 | [UnitTypeMeters] = multi_converter_unit_m, 164 | [UnitTypeCentimeters] = multi_converter_unit_cm, 165 | [UnitTypeMiles] = multi_converter_unit_mi, 166 | [UnitTypeFeet] = multi_converter_unit_ft, 167 | [UnitTypeInches] = multi_converter_unit_in, 168 | 169 | [UnitTypeDegree] = multi_converter_unit_deg, 170 | [UnitTypeRadian] = multi_converter_unit_rad, 171 | }; -------------------------------------------------------------------------------- /dolphinrestorer/drestorer.c: -------------------------------------------------------------------------------- 1 | #include "drestorer.h" 2 | #include 3 | #include 4 | #include "loader/loader.h" 5 | #include "m-string.h" 6 | #include 7 | 8 | #define TAG "MoveToInt" 9 | 10 | #define MOVE_SRC "/ext/dolphin_restorer" 11 | #define MOVE_DST "/int" 12 | 13 | static const char* app_dirs[] = { 14 | ".bt.settings", 15 | ".desktop.settings", 16 | ".dolphin.state", 17 | ".notification.settings", 18 | ".bt.keys", 19 | ".power.settings", 20 | }; 21 | 22 | bool drestorer_perform(void) { 23 | Storage* storage = furi_record_open(RECORD_STORAGE); 24 | string_t path_src; 25 | string_t path_dst; 26 | string_init(path_src); 27 | string_init(path_dst); 28 | 29 | for(uint32_t i = 0; i < COUNT_OF(app_dirs); i++) { 30 | string_printf(path_src, "%s/%s", MOVE_SRC, app_dirs[i]); 31 | string_printf(path_dst, "%s/%s", MOVE_DST, app_dirs[i]); 32 | storage_simply_remove_recursive(storage, string_get_cstr(path_dst)); 33 | storage_common_copy(storage, string_get_cstr(path_src), string_get_cstr(path_dst)); 34 | } 35 | 36 | string_clear(path_src); 37 | string_clear(path_dst); 38 | 39 | furi_record_close(RECORD_STORAGE); 40 | 41 | return false; 42 | } 43 | 44 | static bool drestorer_check(void) { 45 | Storage* storage = furi_record_open(RECORD_STORAGE); 46 | 47 | FileInfo file_info; 48 | bool state = false; 49 | string_t path; 50 | string_init(path); 51 | 52 | for(uint32_t i = 0; i < COUNT_OF(app_dirs); i++) { 53 | string_printf(path, "%s/%s", MOVE_SRC, app_dirs[i]); 54 | if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) { 55 | // if((file_info.flags & FSF_DIRECTORY) != 0) { 56 | state = true; 57 | break; 58 | // } 59 | } 60 | } 61 | 62 | string_clear(path); 63 | 64 | furi_record_close(RECORD_STORAGE); 65 | 66 | return state; 67 | } 68 | 69 | static bool drestorer_custom_event_callback(void* context, uint32_t event) { 70 | furi_assert(context); 71 | StorageMoveToSd* app = context; 72 | return scene_manager_handle_custom_event(app->scene_manager, event); 73 | } 74 | 75 | static bool drestorer_back_event_callback(void* context) { 76 | furi_assert(context); 77 | StorageMoveToSd* app = context; 78 | return scene_manager_handle_back_event(app->scene_manager); 79 | } 80 | 81 | static void drestorer_unmount_callback(const void* message, void* context) { 82 | StorageMoveToSd* app = context; 83 | furi_assert(app); 84 | const StorageEvent* storage_event = message; 85 | 86 | if((storage_event->type == StorageEventTypeCardUnmount) || 87 | (storage_event->type == StorageEventTypeCardMountError)) { 88 | view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); 89 | } 90 | } 91 | 92 | static StorageMoveToSd* drestorer_alloc() { 93 | StorageMoveToSd* app = malloc(sizeof(StorageMoveToSd)); 94 | 95 | app->gui = furi_record_open(RECORD_GUI); 96 | app->notifications = furi_record_open(RECORD_NOTIFICATION); 97 | 98 | app->view_dispatcher = view_dispatcher_alloc(); 99 | app->scene_manager = scene_manager_alloc(&drestorer_scene_handlers, app); 100 | 101 | view_dispatcher_enable_queue(app->view_dispatcher); 102 | view_dispatcher_set_event_callback_context(app->view_dispatcher, app); 103 | 104 | view_dispatcher_set_custom_event_callback( 105 | app->view_dispatcher, drestorer_custom_event_callback); 106 | view_dispatcher_set_navigation_event_callback( 107 | app->view_dispatcher, drestorer_back_event_callback); 108 | 109 | view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); 110 | 111 | app->widget = widget_alloc(); 112 | view_dispatcher_add_view( 113 | app->view_dispatcher, StorageMoveToSdViewWidget, widget_get_view(app->widget)); 114 | 115 | scene_manager_next_scene(app->scene_manager, StorageMoveToSdConfirm); 116 | 117 | Storage* storage = furi_record_open(RECORD_STORAGE); 118 | app->sub = furi_pubsub_subscribe(storage_get_pubsub(storage), drestorer_unmount_callback, app); 119 | furi_record_close(RECORD_STORAGE); 120 | 121 | return app; 122 | } 123 | 124 | static void drestorer_free(StorageMoveToSd* app) { 125 | Storage* storage = furi_record_open(RECORD_STORAGE); 126 | furi_pubsub_unsubscribe(storage_get_pubsub(storage), app->sub); 127 | furi_record_close(RECORD_STORAGE); 128 | furi_record_close(RECORD_NOTIFICATION); 129 | 130 | view_dispatcher_remove_view(app->view_dispatcher, StorageMoveToSdViewWidget); 131 | widget_free(app->widget); 132 | view_dispatcher_free(app->view_dispatcher); 133 | scene_manager_free(app->scene_manager); 134 | 135 | furi_record_close(RECORD_GUI); 136 | 137 | free(app); 138 | } 139 | 140 | int32_t drestorer_app(void* p) { 141 | UNUSED(p); 142 | 143 | if(drestorer_check()) { 144 | StorageMoveToSd* app = drestorer_alloc(); 145 | notification_message(app->notifications, &sequence_display_backlight_on); 146 | view_dispatcher_run(app->view_dispatcher); 147 | drestorer_free(app); 148 | } else { 149 | FURI_LOG_I(TAG, "Nothing to move"); 150 | } 151 | 152 | return 0; 153 | } 154 | 155 | static void drestorer_mount_callback(const void* message, void* context) { 156 | UNUSED(context); 157 | 158 | const StorageEvent* storage_event = message; 159 | 160 | if(storage_event->type == StorageEventTypeCardMount) { 161 | Loader* loader = furi_record_open("loader"); 162 | loader_start(loader, "StorageMoveToSd", NULL); 163 | furi_record_close("loader"); 164 | } 165 | } 166 | 167 | int32_t drestorer_start(void* p) { 168 | UNUSED(p); 169 | Storage* storage = furi_record_open(RECORD_STORAGE); 170 | 171 | furi_pubsub_subscribe(storage_get_pubsub(storage), drestorer_mount_callback, NULL); 172 | 173 | furi_record_close(RECORD_STORAGE); 174 | return 0; 175 | } 176 | -------------------------------------------------------------------------------- /mandelbrot/mandelbrot.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef enum { 8 | EventTypeTick, 9 | EventTypeKey, 10 | } EventType; 11 | 12 | typedef struct { 13 | EventType type; 14 | InputEvent input; 15 | } PluginEvent; 16 | 17 | typedef struct { 18 | float xZoom; 19 | float yZoom; 20 | float xOffset; 21 | float yOffset; 22 | float zoom; 23 | } PluginState; 24 | 25 | bool mandelbrot_pixel(int x, int y, float xZoom, float yZoom, float xOffset, float yOffset) { 26 | float ratio = 128.0 / 64.0; 27 | //x0 := scaled x coordinate of pixel (scaled to lie in the Mandelbrot X scale (-2.00, 0.47)) 28 | float x0 = (((x / 128.0) * ratio * xZoom)) - xOffset; 29 | //y0 := scaled y coordinate of pixel (scaled to lie in the Mandelbrot Y scale (-1.12, 1.12)) 30 | float y0 = ((y / 64.0) * yZoom) - yOffset; 31 | float x1 = 0.0; 32 | float y1 = 0.0; 33 | float x2 = 0.0; 34 | float y2 = 0.0; 35 | 36 | int iteration = 0; 37 | int max_iteration = 50; 38 | 39 | while(x2 + y2 <= 4.0 && iteration < max_iteration) { 40 | y1 = 2.0 * x1 * y1 + y0; 41 | x1 = x2 - y2 + x0; 42 | x2 = x1 * x1; 43 | y2 = y1 * y1; 44 | iteration++; 45 | } 46 | 47 | if(iteration > 49) { 48 | return true; 49 | } 50 | 51 | return false; 52 | } 53 | 54 | static void render_callback(Canvas* const canvas, void* ctx) { 55 | const PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25); 56 | if(plugin_state == NULL) { 57 | return; 58 | } 59 | // border around the edge of the screen 60 | canvas_draw_frame(canvas, 0, 0, 128, 64); 61 | 62 | for(int y = 0; y < 64; y++) { 63 | for(int x = 0; x < 128; x++) { 64 | // did you know if you just pass the indivdiual bits of plugin_state instead of plugin_state 65 | // you dont get any compiler warnings :) 66 | if(mandelbrot_pixel( 67 | x, 68 | y, 69 | plugin_state->xZoom, 70 | plugin_state->yZoom, 71 | plugin_state->xOffset, 72 | plugin_state->yOffset)) { 73 | canvas_draw_dot(canvas, x, y); 74 | } 75 | } 76 | } 77 | 78 | release_mutex((ValueMutex*)ctx, plugin_state); 79 | } 80 | 81 | static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { 82 | furi_assert(event_queue); 83 | 84 | PluginEvent event = {.type = EventTypeKey, .input = *input_event}; 85 | furi_message_queue_put(event_queue, &event, FuriWaitForever); 86 | } 87 | 88 | static void mandelbrot_state_init(PluginState* const plugin_state) { 89 | plugin_state->xOffset = 3.0; 90 | plugin_state->yOffset = 1.12; 91 | plugin_state->xZoom = 2.47; 92 | plugin_state->yZoom = 2.24; 93 | plugin_state->zoom = 1; // this controls the camera when 94 | } 95 | 96 | int32_t mandelbrot_app(void* p) { 97 | UNUSED(p); 98 | 99 | FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); 100 | 101 | PluginState* plugin_state = malloc(sizeof(PluginState)); 102 | mandelbrot_state_init(plugin_state); 103 | ValueMutex state_mutex; 104 | if(!init_mutex(&state_mutex, plugin_state, sizeof(PluginState))) { 105 | FURI_LOG_E("mandelbrot", "cannot create mutex\r\n"); 106 | furi_message_queue_free(event_queue); 107 | free(plugin_state); 108 | return 255; 109 | } 110 | 111 | // Set system callbacks 112 | ViewPort* view_port = view_port_alloc(); 113 | view_port_draw_callback_set(view_port, render_callback, &state_mutex); 114 | view_port_input_callback_set(view_port, input_callback, event_queue); 115 | 116 | // Open GUI and register view_port 117 | Gui* gui = furi_record_open(RECORD_GUI); 118 | gui_add_view_port(gui, view_port, GuiLayerFullscreen); 119 | 120 | PluginEvent event; 121 | for(bool processing = true; processing;) { 122 | FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); 123 | PluginState* plugin_state = (PluginState*)acquire_mutex_block(&state_mutex); 124 | 125 | if(event_status == FuriStatusOk) { 126 | // press events 127 | if(event.type == EventTypeKey) { 128 | if(event.input.type == InputTypePress) { 129 | switch(event.input.key) { 130 | case InputKeyUp: 131 | plugin_state->yOffset += 0.1 / plugin_state->zoom; 132 | break; 133 | case InputKeyDown: 134 | plugin_state->yOffset += -0.1 / plugin_state->zoom; 135 | break; 136 | case InputKeyRight: 137 | plugin_state->xOffset += -0.1 / plugin_state->zoom; 138 | break; 139 | case InputKeyLeft: 140 | plugin_state->xOffset += 0.1 / plugin_state->zoom; 141 | break; 142 | case InputKeyOk: 143 | plugin_state->xZoom -= (2.47 / 10) / plugin_state->zoom; 144 | plugin_state->yZoom -= (2.24 / 10) / plugin_state->zoom; 145 | // used to make camera control finer the more zoomed you are 146 | // this needs to be some sort of curve 147 | plugin_state->zoom += 0.15; 148 | break; 149 | case InputKeyBack: 150 | processing = false; 151 | break; 152 | } 153 | } 154 | } 155 | } else { 156 | FURI_LOG_D("mandelbrot", "osMessageQueue: event timeout"); 157 | // event timeout 158 | } 159 | view_port_update(view_port); 160 | release_mutex(&state_mutex, plugin_state); 161 | } 162 | 163 | view_port_enabled_set(view_port, false); 164 | gui_remove_view_port(gui, view_port); 165 | furi_record_close(RECORD_GUI); 166 | view_port_free(view_port); 167 | furi_message_queue_free(event_queue); 168 | 169 | return 0; 170 | } -------------------------------------------------------------------------------- /flipfrid/scene/flipfrid_scene_load_file.c: -------------------------------------------------------------------------------- 1 | #include "flipfrid_scene_load_file.h" 2 | #include "flipfrid_scene_entrypoint.h" 3 | 4 | #define LFRFID_APP_EXTENSION ".rfid" 5 | #define LFRFID_APP_PATH_FOLDER "/ext/lfrfid" 6 | 7 | bool flipfrid_load(FlipFridState* context, const char* file_path) { 8 | bool result = false; 9 | Storage* storage = furi_record_open(RECORD_STORAGE); 10 | FlipperFormat* fff_data_file = flipper_format_file_alloc(storage); 11 | string_t temp_str; 12 | string_init(temp_str); 13 | do { 14 | if(!flipper_format_file_open_existing(fff_data_file, file_path)) { 15 | FURI_LOG_E(TAG, "Error open file %s", file_path); 16 | string_reset(context->notification_msg); 17 | string_set_str(context->notification_msg, "Error open file"); 18 | break; 19 | } 20 | 21 | // FileType 22 | if(!flipper_format_read_string(fff_data_file, "Filetype", temp_str)) { 23 | FURI_LOG_E(TAG, "Missing or incorrect Filetype"); 24 | string_reset(context->notification_msg); 25 | string_set_str(context->notification_msg, "Missing or incorrect Filetypes"); 26 | break; 27 | } else { 28 | FURI_LOG_I(TAG, "Filetype: %s", string_get_cstr(temp_str)); 29 | } 30 | 31 | // Key type 32 | if(!flipper_format_read_string(fff_data_file, "Key type", temp_str)) { 33 | FURI_LOG_E(TAG, "Missing or incorrect Key type"); 34 | string_reset(context->notification_msg); 35 | string_set_str(context->notification_msg, "Missing or incorrect Key type"); 36 | break; 37 | } else { 38 | FURI_LOG_I(TAG, "Key type: %s", string_get_cstr(temp_str)); 39 | 40 | if(context->proto == EM4100) { 41 | if(strcmp(string_get_cstr(temp_str), "EM4100") != 0) { 42 | FURI_LOG_E(TAG, "Unsupported Key type"); 43 | string_reset(context->notification_msg); 44 | string_set_str(context->notification_msg, "Unsupported Key type"); 45 | break; 46 | } 47 | } else { 48 | if(strcmp(string_get_cstr(temp_str), "HIDProx") != 0) { 49 | FURI_LOG_E(TAG, "Unsupported Key type"); 50 | string_reset(context->notification_msg); 51 | string_set_str(context->notification_msg, "Unsupported Key type"); 52 | break; 53 | } 54 | } 55 | } 56 | 57 | // Data 58 | if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) { 59 | FURI_LOG_E(TAG, "Missing or incorrect Data"); 60 | string_reset(context->notification_msg); 61 | string_set_str(context->notification_msg, "Missing or incorrect Key"); 62 | break; 63 | } else { 64 | FURI_LOG_I(TAG, "Key: %s", string_get_cstr(context->data_str)); 65 | 66 | if(context->proto == EM4100) { 67 | if(string_size(context->data_str) != 14) { 68 | FURI_LOG_E(TAG, "Incorrect Key length"); 69 | string_reset(context->notification_msg); 70 | string_set_str(context->notification_msg, "Incorrect Key length"); 71 | break; 72 | } 73 | } else { 74 | if(string_size(context->data_str) != 17) { 75 | FURI_LOG_E(TAG, "Incorrect Key length"); 76 | string_reset(context->notification_msg); 77 | string_set_str(context->notification_msg, "Incorrect Key length"); 78 | break; 79 | } 80 | } 81 | 82 | // String to uint8_t 83 | for(uint8_t i = 0; i < 6; i++) { 84 | char temp_str2[3]; 85 | temp_str2[0] = string_get_cstr(context->data_str)[i * 3]; 86 | temp_str2[1] = string_get_cstr(context->data_str)[i * 3 + 1]; 87 | temp_str2[2] = '\0'; 88 | context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16); 89 | } 90 | } 91 | 92 | result = true; 93 | } while(0); 94 | string_clear(temp_str); 95 | flipper_format_free(fff_data_file); 96 | if(result) { 97 | FURI_LOG_I(TAG, "Loaded successfully"); 98 | string_reset(context->notification_msg); 99 | string_set_str(context->notification_msg, "Source loaded."); 100 | } 101 | return result; 102 | } 103 | 104 | void flipfrid_scene_load_file_on_enter(FlipFridState* context) { 105 | if(flipfrid_load_protocol_from_file(context)) { 106 | context->current_scene = SceneSelectField; 107 | } else { 108 | flipfrid_scene_entrypoint_on_enter(context); 109 | context->current_scene = SceneEntryPoint; 110 | } 111 | } 112 | 113 | void flipfrid_scene_load_file_on_exit(FlipFridState* context) { 114 | UNUSED(context); 115 | } 116 | 117 | void flipfrid_scene_load_file_on_tick(FlipFridState* context) { 118 | UNUSED(context); 119 | } 120 | 121 | void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context) { 122 | if(event.evt_type == EventTypeKey) { 123 | if(event.input_type == InputTypeShort) { 124 | switch(event.key) { 125 | case InputKeyDown: 126 | case InputKeyUp: 127 | case InputKeyLeft: 128 | case InputKeyRight: 129 | case InputKeyOk: 130 | case InputKeyBack: 131 | context->current_scene = SceneEntryPoint; 132 | break; 133 | } 134 | } 135 | } 136 | } 137 | 138 | void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context) { 139 | UNUSED(context); 140 | UNUSED(canvas); 141 | } 142 | 143 | bool flipfrid_load_protocol_from_file(FlipFridState* context) { 144 | string_t user_file_path; 145 | string_init(user_file_path); 146 | string_set_str(user_file_path, LFRFID_APP_PATH_FOLDER); 147 | 148 | DialogsFileBrowserOptions browser_options; 149 | dialog_file_browser_set_basic_options(&browser_options, LFRFID_APP_EXTENSION, &I_125_10px); 150 | 151 | // Input events and views are managed by file_select 152 | bool res = dialog_file_browser_show( 153 | context->dialogs, user_file_path, user_file_path, &browser_options); 154 | 155 | if(res) { 156 | res = flipfrid_load(context, string_get_cstr(user_file_path)); 157 | } 158 | 159 | string_clear(user_file_path); 160 | 161 | return res; 162 | } -------------------------------------------------------------------------------- /flipfrid/scene/flipfrid_scene_entrypoint.c: -------------------------------------------------------------------------------- 1 | #include "flipfrid_scene_entrypoint.h" 2 | 3 | string_t menu_items[4]; 4 | string_t menu_proto_items[2]; 5 | 6 | void flipfrid_scene_entrypoint_menu_callback( 7 | FlipFridState* context, 8 | uint32_t index, 9 | uint32_t proto_index) { 10 | switch(index) { 11 | case FlipFridAttackDefaultValues: 12 | context->attack = FlipFridAttackDefaultValues; 13 | context->current_scene = SceneAttack; 14 | string_set_str(context->attack_name, "Default Values"); 15 | break; 16 | case FlipFridAttackBfCustomerId: 17 | context->attack = FlipFridAttackBfCustomerId; 18 | context->current_scene = SceneAttack; 19 | string_set_str(context->attack_name, "Bad Customer ID"); 20 | break; 21 | case FlipFridAttackLoadFile: 22 | context->attack = FlipFridAttackLoadFile; 23 | context->current_scene = SceneSelectFile; 24 | string_set_str(context->attack_name, "Load File"); 25 | break; 26 | case FlipFridAttackLoadFileCustomUids: 27 | context->attack = FlipFridAttackLoadFileCustomUids; 28 | context->current_scene = SceneLoadCustomUids; 29 | string_set_str(context->attack_name, "Load Custom UIDs"); 30 | break; 31 | default: 32 | break; 33 | } 34 | 35 | switch(proto_index) { 36 | case EM4100: 37 | context->proto = EM4100; 38 | string_set_str(context->proto_name, "EM4100"); 39 | break; 40 | case HIDProx: 41 | context->proto = HIDProx; 42 | string_set_str(context->proto_name, "HIDProx"); 43 | break; 44 | default: 45 | break; 46 | } 47 | } 48 | 49 | void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) { 50 | // Clear the previous payload 51 | context->payload[0] = 0x00; 52 | context->payload[1] = 0x00; 53 | context->payload[2] = 0x00; 54 | context->payload[3] = 0x00; 55 | context->payload[4] = 0x00; 56 | context->payload[5] = 0x00; 57 | 58 | context->menu_index = 0; 59 | for(uint32_t i = 0; i < 4; i++) { 60 | string_init(menu_items[i]); 61 | } 62 | 63 | string_set(menu_items[0], "Default Values"); 64 | string_set(menu_items[1], "BF Customer ID"); 65 | string_set(menu_items[2], "Load File"); 66 | string_set(menu_items[3], "Load uids from file"); 67 | 68 | context->menu_proto_index = 0; 69 | for(uint32_t i = 0; i < 2; i++) { 70 | string_init(menu_proto_items[i]); 71 | } 72 | 73 | string_set(menu_proto_items[0], "EM4100"); 74 | string_set(menu_proto_items[1], "HIDProx"); 75 | } 76 | 77 | void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) { 78 | UNUSED(context); 79 | for(uint32_t i = 0; i < 4; i++) { 80 | string_clear(menu_items[i]); 81 | } 82 | 83 | for(uint32_t i = 0; i < 2; i++) { 84 | string_clear(menu_proto_items[i]); 85 | } 86 | } 87 | 88 | void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) { 89 | UNUSED(context); 90 | } 91 | 92 | void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context) { 93 | if(event.evt_type == EventTypeKey) { 94 | if(event.input_type == InputTypeShort) { 95 | switch(event.key) { 96 | case InputKeyDown: 97 | if(context->menu_index < FlipFridAttackLoadFileCustomUids) { 98 | context->menu_index++; 99 | } 100 | break; 101 | case InputKeyUp: 102 | if(context->menu_index > FlipFridAttackDefaultValues) { 103 | context->menu_index--; 104 | } 105 | break; 106 | case InputKeyLeft: 107 | if(context->menu_proto_index > EM4100) { 108 | context->menu_proto_index--; 109 | } 110 | break; 111 | case InputKeyRight: 112 | if(context->menu_proto_index < HIDProx) { 113 | context->menu_proto_index++; 114 | } 115 | break; 116 | case InputKeyOk: 117 | flipfrid_scene_entrypoint_menu_callback( 118 | context, context->menu_index, context->menu_proto_index); 119 | break; 120 | case InputKeyBack: 121 | context->is_running = false; 122 | break; 123 | } 124 | } 125 | } 126 | } 127 | 128 | void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) { 129 | canvas_clear(canvas); 130 | canvas_set_color(canvas, ColorBlack); 131 | 132 | if(context->menu_index > FlipFridAttackDefaultValues) { 133 | canvas_set_font(canvas, FontSecondary); 134 | canvas_draw_str_aligned( 135 | canvas, 136 | 64, 137 | 24, 138 | AlignCenter, 139 | AlignTop, 140 | string_get_cstr(menu_items[context->menu_index - 1])); 141 | } 142 | 143 | canvas_set_font(canvas, FontPrimary); 144 | canvas_draw_str_aligned( 145 | canvas, 64, 36, AlignCenter, AlignTop, string_get_cstr(menu_items[context->menu_index])); 146 | 147 | if(context->menu_index < FlipFridAttackLoadFileCustomUids) { 148 | canvas_set_font(canvas, FontSecondary); 149 | canvas_draw_str_aligned( 150 | canvas, 151 | 64, 152 | 48, 153 | AlignCenter, 154 | AlignTop, 155 | string_get_cstr(menu_items[context->menu_index + 1])); 156 | } 157 | 158 | if(context->menu_proto_index > EM4100) { 159 | canvas_set_font(canvas, FontSecondary); 160 | canvas_draw_str_aligned( 161 | canvas, 162 | 64, 163 | -12, 164 | AlignCenter, 165 | AlignTop, 166 | string_get_cstr(menu_proto_items[context->menu_proto_index - 1])); 167 | } 168 | 169 | canvas_set_font(canvas, FontPrimary); 170 | canvas_draw_str_aligned(canvas, 34, 4, AlignCenter, AlignTop, "<"); 171 | 172 | canvas_set_font(canvas, FontPrimary); 173 | canvas_draw_str_aligned( 174 | canvas, 175 | 64, 176 | 4, 177 | AlignCenter, 178 | AlignTop, 179 | string_get_cstr(menu_proto_items[context->menu_proto_index])); 180 | 181 | canvas_set_font(canvas, FontPrimary); 182 | canvas_draw_str_aligned(canvas, 94, 4, AlignCenter, AlignTop, ">"); 183 | 184 | if(context->menu_proto_index < HIDProx) { 185 | canvas_set_font(canvas, FontSecondary); 186 | canvas_draw_str_aligned( 187 | canvas, 188 | 64, 189 | -12, 190 | AlignCenter, 191 | AlignTop, 192 | string_get_cstr(menu_proto_items[context->menu_proto_index + 1])); 193 | } 194 | } -------------------------------------------------------------------------------- /spectrum_analyzer/spectrum_analyzer_worker.c: -------------------------------------------------------------------------------- 1 | #include "spectrum_analyzer.h" 2 | #include "spectrum_analyzer_worker.h" 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | struct SpectrumAnalyzerWorker { 10 | FuriThread* thread; 11 | bool should_work; 12 | 13 | SpectrumAnalyzerWorkerCallback callback; 14 | void* callback_context; 15 | 16 | uint32_t channel0_frequency; 17 | uint32_t spacing; 18 | uint8_t width; 19 | float max_rssi; 20 | uint8_t max_rssi_dec; 21 | uint8_t max_rssi_channel; 22 | 23 | uint8_t channel_ss[NUM_CHANNELS]; 24 | }; 25 | 26 | /* set the channel bandwidth */ 27 | void spectrum_analyzer_worker_set_filter(SpectrumAnalyzerWorker* instance) { 28 | uint8_t filter_config[2][2] = { 29 | {CC1101_MDMCFG4, 0}, 30 | {0, 0}, 31 | }; 32 | 33 | // FURI_LOG_D("SpectrumWorker", "spectrum_analyzer_worker_set_filter: width = %u", instance->width); 34 | 35 | /* channel spacing should fit within 80% of channel filter bandwidth */ 36 | switch(instance->width) { 37 | case NARROW: 38 | filter_config[0][1] = 0xFC; /* 39.2 kHz / .8 = 49 kHz --> 58 kHz */ 39 | break; 40 | case ULTRAWIDE: 41 | filter_config[0][1] = 0x0C; /* 784 kHz / .8 = 980 kHz --> 812 kHz */ 42 | break; 43 | default: 44 | filter_config[0][1] = 0x6C; /* 196 kHz / .8 = 245 kHz --> 270 kHz */ 45 | break; 46 | } 47 | furi_hal_subghz_load_registers((uint8_t*)filter_config); 48 | } 49 | 50 | static int32_t spectrum_analyzer_worker_thread(void* context) { 51 | furi_assert(context); 52 | SpectrumAnalyzerWorker* instance = context; 53 | 54 | FURI_LOG_D("SpectrumWorker", "spectrum_analyzer_worker_thread: Start"); 55 | 56 | // Start CC1101 57 | furi_hal_subghz_reset(); 58 | furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); 59 | furi_hal_subghz_set_frequency(433920000); 60 | furi_hal_subghz_flush_rx(); 61 | furi_hal_subghz_rx(); 62 | 63 | static const uint8_t radio_config[][2] = { 64 | {CC1101_FSCTRL1, 0x12}, 65 | {CC1101_FSCTRL0, 0x00}, 66 | 67 | {CC1101_AGCCTRL2, 0xC0}, 68 | 69 | {CC1101_MDMCFG4, 0x6C}, 70 | {CC1101_TEST2, 0x88}, 71 | {CC1101_TEST1, 0x31}, 72 | {CC1101_TEST0, 0x09}, 73 | /* End */ 74 | {0, 0}, 75 | }; 76 | 77 | while(instance->should_work) { 78 | furi_delay_ms(50); 79 | 80 | // FURI_LOG_T("SpectrumWorker", "spectrum_analyzer_worker_thread: Worker Loop"); 81 | furi_hal_subghz_idle(); 82 | furi_hal_subghz_load_registers((uint8_t*)radio_config); 83 | 84 | // TODO: Check filter! 85 | // spectrum_analyzer_worker_set_filter(instance); 86 | 87 | instance->max_rssi_dec = 0; 88 | 89 | // Visit each channel non-consecutively 90 | for(uint8_t ch_offset = 0, chunk = 0; ch_offset < CHUNK_SIZE; 91 | ++chunk >= NUM_CHUNKS && ++ch_offset && (chunk = 0)) { 92 | uint8_t ch = chunk * CHUNK_SIZE + ch_offset; 93 | furi_hal_subghz_set_frequency(instance->channel0_frequency + (ch * instance->spacing)); 94 | 95 | furi_hal_subghz_rx(); 96 | furi_delay_ms(3); 97 | 98 | // dec dBm 99 | //max_ss = 127 -> -10.5 100 | //max_ss = 0 -> -74.0 101 | //max_ss = 255 -> -74.5 102 | //max_ss = 128 -> -138.0 103 | instance->channel_ss[ch] = (furi_hal_subghz_get_rssi() + 138) * 2; 104 | 105 | if(instance->channel_ss[ch] > instance->max_rssi_dec) { 106 | instance->max_rssi_dec = instance->channel_ss[ch]; 107 | instance->max_rssi = (instance->channel_ss[ch] / 2) - 138; 108 | instance->max_rssi_channel = ch; 109 | } 110 | 111 | furi_hal_subghz_idle(); 112 | } 113 | 114 | // FURI_LOG_T("SpectrumWorker", "channel_ss[0]: %u", instance->channel_ss[0]); 115 | 116 | // Report results back to main thread 117 | if(instance->callback) { 118 | instance->callback( 119 | (void*)&(instance->channel_ss), 120 | instance->max_rssi, 121 | instance->max_rssi_dec, 122 | instance->max_rssi_channel, 123 | instance->callback_context); 124 | } 125 | } 126 | 127 | return 0; 128 | } 129 | 130 | SpectrumAnalyzerWorker* spectrum_analyzer_worker_alloc() { 131 | FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_alloc: Start"); 132 | 133 | SpectrumAnalyzerWorker* instance = malloc(sizeof(SpectrumAnalyzerWorker)); 134 | 135 | instance->thread = furi_thread_alloc(); 136 | furi_thread_set_name(instance->thread, "SpectrumWorker"); 137 | furi_thread_set_stack_size(instance->thread, 2048); 138 | furi_thread_set_context(instance->thread, instance); 139 | furi_thread_set_callback(instance->thread, spectrum_analyzer_worker_thread); 140 | 141 | FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_alloc: End"); 142 | 143 | return instance; 144 | } 145 | 146 | void spectrum_analyzer_worker_free(SpectrumAnalyzerWorker* instance) { 147 | FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_free"); 148 | furi_assert(instance); 149 | furi_thread_free(instance->thread); 150 | free(instance); 151 | } 152 | 153 | void spectrum_analyzer_worker_set_callback( 154 | SpectrumAnalyzerWorker* instance, 155 | SpectrumAnalyzerWorkerCallback callback, 156 | void* context) { 157 | furi_assert(instance); 158 | instance->callback = callback; 159 | instance->callback_context = context; 160 | } 161 | 162 | void spectrum_analyzer_worker_set_frequencies( 163 | SpectrumAnalyzerWorker* instance, 164 | uint32_t channel0_frequency, 165 | uint32_t spacing, 166 | uint8_t width) { 167 | furi_assert(instance); 168 | 169 | FURI_LOG_D( 170 | "SpectrumWorker", 171 | "spectrum_analyzer_worker_set_frequencies - channel0_frequency= %u - spacing = %u - width = %u", 172 | channel0_frequency, 173 | spacing, 174 | width); 175 | 176 | instance->channel0_frequency = channel0_frequency; 177 | instance->spacing = spacing; 178 | instance->width = width; 179 | } 180 | 181 | void spectrum_analyzer_worker_start(SpectrumAnalyzerWorker* instance) { 182 | FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_start"); 183 | 184 | furi_assert(instance); 185 | furi_assert(instance->should_work == false); 186 | 187 | instance->should_work = true; 188 | furi_thread_start(instance->thread); 189 | } 190 | 191 | void spectrum_analyzer_worker_stop(SpectrumAnalyzerWorker* instance) { 192 | FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_stop"); 193 | furi_assert(instance); 194 | furi_assert(instance->should_work == true); 195 | 196 | instance->should_work = false; 197 | furi_thread_join(instance->thread); 198 | } -------------------------------------------------------------------------------- /dolphinbackup/storage_DolphinBackup.c: -------------------------------------------------------------------------------- 1 | #include "storage_DolphinBackup.h" 2 | #include 3 | #include 4 | #include "loader/loader.h" 5 | #include "m-string.h" 6 | #include 7 | 8 | #define TAG "DolphinBackup" 9 | 10 | #define MOVE_SRC "/int" 11 | #define MOVE_DST "/ext" 12 | 13 | static const char* app_dirsDolphinBackup[] = { 14 | "subghz", 15 | "lfrfid", 16 | "nfc", 17 | "infrared", 18 | "ibutton", 19 | "badusb", 20 | ".bt.settings", 21 | ".desktop.settings", 22 | ".dolphin.state", 23 | ".notification.settings", 24 | ".bt.keys", 25 | ".power.settings", 26 | }; 27 | 28 | bool storage_DolphinBackup_perform(void) { 29 | Storage* storage = furi_record_open(RECORD_STORAGE); 30 | string_t path_src; 31 | string_t path_dst; 32 | string_t new_path; 33 | string_init(path_src); 34 | string_init(path_dst); 35 | string_init(new_path); 36 | 37 | string_printf(new_path, "%s/dolphin_restorer", MOVE_DST); 38 | storage_common_mkdir(storage, string_get_cstr(new_path)); 39 | string_clear(new_path); 40 | for(uint32_t i = 0; i < COUNT_OF(app_dirsDolphinBackup); i++) { 41 | if(i > 5) { 42 | string_printf(path_src, "%s/%s", MOVE_SRC, app_dirsDolphinBackup[i]); 43 | string_printf(path_dst, "%s/dolphin_restorer/%s", MOVE_DST, app_dirsDolphinBackup[i]); 44 | storage_simply_remove_recursive(storage, string_get_cstr(path_dst)); 45 | storage_common_copy(storage, string_get_cstr(path_src), string_get_cstr(path_dst)); 46 | } else { 47 | string_printf(path_src, "%s/%s", MOVE_SRC, app_dirsDolphinBackup[i]); 48 | string_printf(path_dst, "%s/%s", MOVE_DST, app_dirsDolphinBackup[i]); 49 | storage_common_merge(storage, string_get_cstr(path_src), string_get_cstr(path_dst)); 50 | storage_simply_remove_recursive(storage, string_get_cstr(path_src)); 51 | } 52 | } 53 | 54 | string_clear(path_src); 55 | string_clear(path_dst); 56 | 57 | furi_record_close(RECORD_STORAGE); 58 | 59 | return false; 60 | } 61 | 62 | static bool storage_DolphinBackup_check(void) { 63 | Storage* storage = furi_record_open(RECORD_STORAGE); 64 | 65 | FileInfo file_info; 66 | bool state = false; 67 | string_t path; 68 | string_init(path); 69 | 70 | for(uint32_t i = 0; i < COUNT_OF(app_dirsDolphinBackup); i++) { 71 | string_printf(path, "%s/%s", MOVE_SRC, app_dirsDolphinBackup[i]); 72 | if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) { 73 | // if((file_info.flags & FSF_DIRECTORY) != 0) { 74 | state = true; 75 | break; 76 | // } 77 | } 78 | } 79 | 80 | string_clear(path); 81 | 82 | furi_record_close(RECORD_STORAGE); 83 | 84 | return state; 85 | } 86 | 87 | static bool storage_DolphinBackup_custom_event_callback(void* context, uint32_t event) { 88 | furi_assert(context); 89 | StorageDolphinBackup* app = context; 90 | return scene_manager_handle_custom_event(app->scene_manager, event); 91 | } 92 | 93 | static bool storage_DolphinBackup_back_event_callback(void* context) { 94 | furi_assert(context); 95 | StorageDolphinBackup* app = context; 96 | return scene_manager_handle_back_event(app->scene_manager); 97 | } 98 | 99 | static void storage_DolphinBackup_unmount_callback(const void* message, void* context) { 100 | StorageDolphinBackup* app = context; 101 | furi_assert(app); 102 | const StorageEvent* storage_event = message; 103 | 104 | if((storage_event->type == StorageEventTypeCardUnmount) || 105 | (storage_event->type == StorageEventTypeCardMountError)) { 106 | view_dispatcher_send_custom_event(app->view_dispatcher, DolphinBackupCustomEventExit); 107 | } 108 | } 109 | 110 | static StorageDolphinBackup* storage_DolphinBackup_alloc() { 111 | StorageDolphinBackup* app = malloc(sizeof(StorageDolphinBackup)); 112 | 113 | app->gui = furi_record_open(RECORD_GUI); 114 | app->notifications = furi_record_open(RECORD_NOTIFICATION); 115 | 116 | app->view_dispatcher = view_dispatcher_alloc(); 117 | app->scene_manager = scene_manager_alloc(&storage_DolphinBackup_scene_handlers, app); 118 | 119 | view_dispatcher_enable_queue(app->view_dispatcher); 120 | view_dispatcher_set_event_callback_context(app->view_dispatcher, app); 121 | 122 | view_dispatcher_set_custom_event_callback( 123 | app->view_dispatcher, storage_DolphinBackup_custom_event_callback); 124 | view_dispatcher_set_navigation_event_callback( 125 | app->view_dispatcher, storage_DolphinBackup_back_event_callback); 126 | 127 | view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); 128 | 129 | app->widget = widget_alloc(); 130 | view_dispatcher_add_view( 131 | app->view_dispatcher, StorageDolphinBackupViewWidget, widget_get_view(app->widget)); 132 | 133 | scene_manager_next_scene(app->scene_manager, StorageDolphinBackupConfirm); 134 | 135 | Storage* storage = furi_record_open(RECORD_STORAGE); 136 | app->sub = furi_pubsub_subscribe( 137 | storage_get_pubsub(storage), storage_DolphinBackup_unmount_callback, app); 138 | furi_record_close(RECORD_STORAGE); 139 | 140 | return app; 141 | } 142 | 143 | static void storage_DolphinBackup_free(StorageDolphinBackup* app) { 144 | Storage* storage = furi_record_open(RECORD_STORAGE); 145 | furi_pubsub_unsubscribe(storage_get_pubsub(storage), app->sub); 146 | furi_record_close(RECORD_STORAGE); 147 | furi_record_close(RECORD_NOTIFICATION); 148 | 149 | view_dispatcher_remove_view(app->view_dispatcher, StorageDolphinBackupViewWidget); 150 | widget_free(app->widget); 151 | view_dispatcher_free(app->view_dispatcher); 152 | scene_manager_free(app->scene_manager); 153 | 154 | furi_record_close(RECORD_GUI); 155 | 156 | free(app); 157 | } 158 | 159 | int32_t storage_DolphinBackup_app(void* p) { 160 | UNUSED(p); 161 | 162 | if(storage_DolphinBackup_check()) { 163 | StorageDolphinBackup* app = storage_DolphinBackup_alloc(); 164 | notification_message(app->notifications, &sequence_display_backlight_on); 165 | view_dispatcher_run(app->view_dispatcher); 166 | storage_DolphinBackup_free(app); 167 | } else { 168 | FURI_LOG_I(TAG, "Nothing to move"); 169 | } 170 | 171 | return 0; 172 | } 173 | 174 | static void storage_DolphinBackup_mount_callback(const void* message, void* context) { 175 | UNUSED(context); 176 | 177 | const StorageEvent* storage_event = message; 178 | 179 | if(storage_event->type == StorageEventTypeCardMount) { 180 | Loader* loader = furi_record_open("loader"); 181 | loader_start(loader, "StorageDolphinBackup", NULL); 182 | furi_record_close("loader"); 183 | } 184 | } 185 | 186 | int32_t storage_DolphinBackup_start(void* p) { 187 | UNUSED(p); 188 | Storage* storage = furi_record_open(RECORD_STORAGE); 189 | 190 | furi_pubsub_subscribe(storage_get_pubsub(storage), storage_DolphinBackup_mount_callback, NULL); 191 | 192 | furi_record_close(RECORD_STORAGE); 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /multi_converter/multi_converter.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "multi_converter_definitions.h" 7 | #include "multi_converter_mode_display.h" 8 | #include "multi_converter_mode_select.h" 9 | 10 | static void multi_converter_render_callback(Canvas* const canvas, void* ctx) { 11 | const MultiConverterState* multi_converter_state = acquire_mutex((ValueMutex*)ctx, 25); 12 | if(multi_converter_state == NULL) { 13 | return; 14 | } 15 | 16 | if(multi_converter_state->mode == ModeDisplay) { 17 | multi_converter_mode_display_draw(canvas, multi_converter_state); 18 | } else { 19 | multi_converter_mode_select_draw(canvas, multi_converter_state); 20 | } 21 | 22 | release_mutex((ValueMutex*)ctx, multi_converter_state); 23 | } 24 | 25 | static void 26 | multi_converter_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { 27 | furi_assert(event_queue); 28 | 29 | MultiConverterEvent event = {.type = EventTypeKey, .input = *input_event}; 30 | furi_message_queue_put(event_queue, &event, FuriWaitForever); 31 | } 32 | 33 | static void multi_converter_init(MultiConverterState* const multi_converter_state) { 34 | // initial default values 35 | 36 | multi_converter_state->buffer_orig[MULTI_CONVERTER_NUMBER_DIGITS] = '\0'; 37 | multi_converter_state->buffer_dest[MULTI_CONVERTER_NUMBER_DIGITS] = '\0'; // null terminators 38 | 39 | multi_converter_state->unit_type_orig = UnitTypeDec; 40 | multi_converter_state->unit_type_dest = UnitTypeHex; 41 | 42 | multi_converter_state->keyboard_lock = 0; 43 | 44 | // init the display view 45 | multi_converter_mode_display_reset(multi_converter_state); 46 | 47 | // init the select view 48 | multi_converter_mode_select_reset(multi_converter_state); 49 | 50 | // set ModeDisplay as the current mode 51 | multi_converter_state->mode = ModeDisplay; 52 | } 53 | 54 | // main entry point 55 | int32_t multi_converter_app(void* p) { 56 | UNUSED(p); 57 | 58 | // get event queue 59 | FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(MultiConverterEvent)); 60 | 61 | // allocate state 62 | MultiConverterState* multi_converter_state = malloc(sizeof(MultiConverterState)); 63 | 64 | // set mutex for plugin state (different threads can access it) 65 | ValueMutex state_mutex; 66 | if(!init_mutex(&state_mutex, multi_converter_state, sizeof(multi_converter_state))) { 67 | FURI_LOG_E("MultiConverter", "cannot create mutex\r\n"); 68 | furi_message_queue_free(event_queue); 69 | free(multi_converter_state); 70 | return 255; 71 | } 72 | 73 | // register callbacks for drawing and input processing 74 | ViewPort* view_port = view_port_alloc(); 75 | view_port_draw_callback_set(view_port, multi_converter_render_callback, &state_mutex); 76 | view_port_input_callback_set(view_port, multi_converter_input_callback, event_queue); 77 | 78 | // open GUI and register view_port 79 | Gui* gui = furi_record_open("gui"); 80 | gui_add_view_port(gui, view_port, GuiLayerFullscreen); 81 | 82 | multi_converter_init(multi_converter_state); 83 | 84 | // main loop 85 | MultiConverterEvent event; 86 | for(bool processing = true; processing;) { 87 | FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); 88 | MultiConverterState* multi_converter_state = 89 | (MultiConverterState*)acquire_mutex_block(&state_mutex); 90 | 91 | if(event_status == FuriStatusOk) { 92 | // press events 93 | if(event.type == EventTypeKey && !multi_converter_state->keyboard_lock) { 94 | if(multi_converter_state->mode == ModeDisplay) { 95 | if(event.input.key == InputKeyBack) { 96 | if(event.input.type == InputTypePress) processing = false; 97 | } else if(event.input.key == InputKeyOk) { // the "ok" press can be short or long 98 | MultiConverterModeTrigger t = None; 99 | 100 | if(event.input.type == InputTypeLong) 101 | t = multi_converter_mode_display_ok(1, multi_converter_state); 102 | else if(event.input.type == InputTypeShort) 103 | t = multi_converter_mode_display_ok(0, multi_converter_state); 104 | 105 | if(t == Reset) { 106 | multi_converter_mode_select_reset(multi_converter_state); 107 | multi_converter_state->mode = ModeSelector; 108 | } 109 | } else { 110 | if(event.input.type == InputTypePress) 111 | multi_converter_mode_display_navigation( 112 | event.input.key, multi_converter_state); 113 | } 114 | 115 | } else { // ModeSelect 116 | if(event.input.type == InputTypePress) { 117 | switch(event.input.key) { 118 | default: 119 | break; 120 | case InputKeyBack: 121 | case InputKeyOk: { 122 | MultiConverterModeTrigger t = multi_converter_mode_select_exit( 123 | event.input.key == InputKeyOk ? 1 : 0, multi_converter_state); 124 | 125 | if(t == Reset) { 126 | multi_converter_mode_display_reset(multi_converter_state); 127 | } else if(t == Convert) { 128 | multi_converter_mode_display_convert(multi_converter_state); 129 | } 130 | 131 | multi_converter_state->keyboard_lock = 1; 132 | multi_converter_state->mode = ModeDisplay; 133 | break; 134 | } 135 | case InputKeyLeft: 136 | case InputKeyRight: 137 | multi_converter_mode_select_switch(multi_converter_state); 138 | break; 139 | case InputKeyUp: 140 | multi_converter_mode_select_change_unit(-1, multi_converter_state); 141 | break; 142 | case InputKeyDown: 143 | multi_converter_mode_select_change_unit(1, multi_converter_state); 144 | break; 145 | } 146 | } 147 | } 148 | } else if(multi_converter_state->keyboard_lock) { 149 | multi_converter_state->keyboard_lock = 0; 150 | } 151 | } else { 152 | // event timeout 153 | } 154 | 155 | view_port_update(view_port); 156 | release_mutex(&state_mutex, multi_converter_state); 157 | } 158 | 159 | view_port_enabled_set(view_port, false); 160 | gui_remove_view_port(gui, view_port); 161 | furi_record_close("gui"); 162 | view_port_free(view_port); 163 | furi_message_queue_free(event_queue); 164 | delete_mutex(&state_mutex); 165 | free(multi_converter_state); 166 | 167 | return 0; 168 | } -------------------------------------------------------------------------------- /wav_player/wav_player_view.c: -------------------------------------------------------------------------------- 1 | #include "wav_player_view.h" 2 | 3 | #define DATA_COUNT 116 4 | 5 | struct WavPlayerView { 6 | View* view; 7 | WavPlayerCtrlCallback callback; 8 | void* context; 9 | }; 10 | 11 | typedef struct { 12 | bool play; 13 | float volume; 14 | size_t start; 15 | size_t end; 16 | size_t current; 17 | uint8_t data[DATA_COUNT]; 18 | } WavPlayerViewModel; 19 | 20 | float map(float x, float in_min, float in_max, float out_min, float out_max) { 21 | return (x - in_min) * (out_max - out_min + 1) / (in_max - in_min + 1) + out_min; 22 | } 23 | 24 | static void wav_player_view_draw_callback(Canvas* canvas, void* _model) { 25 | WavPlayerViewModel* model = _model; 26 | 27 | canvas_clear(canvas); 28 | canvas_set_color(canvas, ColorBlack); 29 | uint8_t x_pos = 0; 30 | uint8_t y_pos = 0; 31 | 32 | // volume 33 | x_pos = 124; 34 | y_pos = 0; 35 | const float volume = (64 / 10.0f) * model->volume; 36 | canvas_draw_frame(canvas, x_pos, y_pos, 4, 64); 37 | canvas_draw_box(canvas, x_pos, y_pos + (64 - volume), 4, volume); 38 | 39 | // play / pause 40 | x_pos = 58; 41 | y_pos = 55; 42 | if(!model->play) { 43 | canvas_draw_line(canvas, x_pos, y_pos, x_pos + 8, y_pos + 4); 44 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 8, y_pos + 4); 45 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos); 46 | } else { 47 | canvas_draw_box(canvas, x_pos, y_pos, 3, 9); 48 | canvas_draw_box(canvas, x_pos + 4, y_pos, 3, 9); 49 | } 50 | 51 | x_pos = 78; 52 | y_pos = 55; 53 | canvas_draw_line(canvas, x_pos, y_pos, x_pos + 4, y_pos + 4); 54 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 4, y_pos + 4); 55 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos); 56 | 57 | x_pos = 82; 58 | y_pos = 55; 59 | canvas_draw_line(canvas, x_pos, y_pos, x_pos + 4, y_pos + 4); 60 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos + 4, y_pos + 4); 61 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos); 62 | 63 | x_pos = 40; 64 | y_pos = 55; 65 | canvas_draw_line(canvas, x_pos, y_pos, x_pos - 4, y_pos + 4); 66 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos - 4, y_pos + 4); 67 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos); 68 | 69 | x_pos = 44; 70 | y_pos = 55; 71 | canvas_draw_line(canvas, x_pos, y_pos, x_pos - 4, y_pos + 4); 72 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos - 4, y_pos + 4); 73 | canvas_draw_line(canvas, x_pos, y_pos + 8, x_pos, y_pos); 74 | 75 | // len 76 | x_pos = 4; 77 | y_pos = 47; 78 | const uint8_t play_len = 116; 79 | uint8_t play_pos = map(model->current, model->start, model->end, 0, play_len - 4); 80 | 81 | canvas_draw_frame(canvas, x_pos, y_pos, play_len, 4); 82 | canvas_draw_box(canvas, x_pos + play_pos, y_pos - 2, 4, 8); 83 | canvas_draw_box(canvas, x_pos, y_pos, play_pos, 4); 84 | 85 | // osc 86 | x_pos = 4; 87 | y_pos = 0; 88 | for(size_t i = 1; i < DATA_COUNT; i++) { 89 | canvas_draw_line(canvas, x_pos + i - 1, model->data[i - 1], x_pos + i, model->data[i]); 90 | } 91 | } 92 | 93 | static bool wav_player_view_input_callback(InputEvent* event, void* context) { 94 | WavPlayerView* wav_player_view = context; 95 | bool consumed = false; 96 | 97 | if(wav_player_view->callback) { 98 | if(event->type == InputTypeShort || event->type == InputTypeRepeat) { 99 | if(event->key == InputKeyUp) { 100 | wav_player_view->callback(WavPlayerCtrlVolUp, wav_player_view->context); 101 | consumed = true; 102 | } else if(event->key == InputKeyDown) { 103 | wav_player_view->callback(WavPlayerCtrlVolDn, wav_player_view->context); 104 | consumed = true; 105 | } else if(event->key == InputKeyLeft) { 106 | wav_player_view->callback(WavPlayerCtrlMoveL, wav_player_view->context); 107 | consumed = true; 108 | } else if(event->key == InputKeyRight) { 109 | wav_player_view->callback(WavPlayerCtrlMoveR, wav_player_view->context); 110 | consumed = true; 111 | } else if(event->key == InputKeyOk) { 112 | wav_player_view->callback(WavPlayerCtrlOk, wav_player_view->context); 113 | consumed = true; 114 | } else if(event->key == InputKeyBack) { 115 | wav_player_view->callback(WavPlayerCtrlBack, wav_player_view->context); 116 | consumed = true; 117 | } 118 | } 119 | } 120 | 121 | return consumed; 122 | } 123 | 124 | WavPlayerView* wav_player_view_alloc() { 125 | WavPlayerView* wav_view = malloc(sizeof(WavPlayerView)); 126 | wav_view->view = view_alloc(); 127 | view_set_context(wav_view->view, wav_view); 128 | view_allocate_model(wav_view->view, ViewModelTypeLocking, sizeof(WavPlayerViewModel)); 129 | view_set_draw_callback(wav_view->view, wav_player_view_draw_callback); 130 | view_set_input_callback(wav_view->view, wav_player_view_input_callback); 131 | 132 | return wav_view; 133 | } 134 | 135 | void wav_player_view_free(WavPlayerView* wav_view) { 136 | furi_assert(wav_view); 137 | view_free(wav_view->view); 138 | free(wav_view); 139 | } 140 | 141 | View* wav_player_view_get_view(WavPlayerView* wav_view) { 142 | furi_assert(wav_view); 143 | return wav_view->view; 144 | } 145 | 146 | void wav_player_view_set_volume(WavPlayerView* wav_view, float volume) { 147 | furi_assert(wav_view); 148 | with_view_model( 149 | wav_view->view, (WavPlayerViewModel * model) { 150 | model->volume = volume; 151 | return true; 152 | }); 153 | } 154 | 155 | void wav_player_view_set_start(WavPlayerView* wav_view, size_t start) { 156 | furi_assert(wav_view); 157 | with_view_model( 158 | wav_view->view, (WavPlayerViewModel * model) { 159 | model->start = start; 160 | return true; 161 | }); 162 | } 163 | 164 | void wav_player_view_set_end(WavPlayerView* wav_view, size_t end) { 165 | furi_assert(wav_view); 166 | with_view_model( 167 | wav_view->view, (WavPlayerViewModel * model) { 168 | model->end = end; 169 | return true; 170 | }); 171 | } 172 | 173 | void wav_player_view_set_current(WavPlayerView* wav_view, size_t current) { 174 | furi_assert(wav_view); 175 | with_view_model( 176 | wav_view->view, (WavPlayerViewModel * model) { 177 | model->current = current; 178 | return true; 179 | }); 180 | } 181 | 182 | void wav_player_view_set_play(WavPlayerView* wav_view, bool play) { 183 | furi_assert(wav_view); 184 | with_view_model( 185 | wav_view->view, (WavPlayerViewModel * model) { 186 | model->play = play; 187 | return true; 188 | }); 189 | } 190 | 191 | void wav_player_view_set_data(WavPlayerView* wav_view, uint16_t* data, size_t data_count) { 192 | furi_assert(wav_view); 193 | with_view_model( 194 | wav_view->view, (WavPlayerViewModel * model) { 195 | size_t inc = (data_count / DATA_COUNT) - 1; 196 | 197 | for(size_t i = 0; i < DATA_COUNT; i++) { 198 | model->data[i] = *data / 6; 199 | if(model->data[i] > 42) model->data[i] = 42; 200 | data += inc; 201 | } 202 | return true; 203 | }); 204 | } 205 | 206 | void wav_player_view_set_ctrl_callback(WavPlayerView* wav_view, WavPlayerCtrlCallback callback) { 207 | furi_assert(wav_view); 208 | wav_view->callback = callback; 209 | } 210 | 211 | void wav_player_view_set_context(WavPlayerView* wav_view, void* context) { 212 | furi_assert(wav_view); 213 | wav_view->context = context; 214 | } -------------------------------------------------------------------------------- /multi_converter/multi_converter_mode_select.c: -------------------------------------------------------------------------------- 1 | #include "multi_converter_mode_select.h" 2 | 3 | #define MULTI_CONVERTER_LIST_ENTRIES_COUNT 3 4 | 5 | #define MULTI_CONVERTER_INFO_STRING_FROM "FROM:" 6 | #define MULTI_CONVERTER_INFO_STRING_TO "TO:" 7 | #define MULTI_CONVERTER_INFO_STRING_OK "OK: Change" 8 | #define MULTI_CONVERTER_INFO_STRING_BACK "BACK: Cancel" 9 | 10 | void multi_converter_mode_select_draw_destination_offset( 11 | uint8_t x, 12 | uint8_t y, 13 | int8_t d, 14 | Canvas* const canvas, 15 | const MultiConverterState* multi_converter_state) { 16 | int i = 1; 17 | while( 18 | i < 19 | MULTI_CONVERTER_AVAILABLE_UNITS) { // in case there's no match, to avoid an endless loop (in theory shouldn't happen, but...) 20 | int ut = multi_converter_get_unit_type_offset( 21 | (multi_converter_state->select).selected_unit_type_dest, i * d); 22 | if(multi_converter_available_units[(multi_converter_state->select).selected_unit_type_orig] 23 | .allowed_function(ut) && 24 | (multi_converter_state->select).selected_unit_type_orig != ut) { 25 | canvas_draw_str(canvas, x, y, multi_converter_available_units[ut].name); 26 | break; 27 | } 28 | i++; 29 | } 30 | } 31 | 32 | void multi_converter_mode_select_draw_selected_unit( 33 | uint8_t x, 34 | uint8_t y, 35 | MultiConverterUnitType unit_type, 36 | Canvas* const canvas) { 37 | canvas_draw_box( 38 | canvas, 39 | x - 2, 40 | y - 10, 41 | canvas_string_width(canvas, multi_converter_available_units[unit_type].name) + 4, 42 | 13); 43 | canvas_set_color(canvas, ColorWhite); 44 | canvas_draw_str(canvas, x, y, multi_converter_available_units[unit_type].name); 45 | canvas_set_color(canvas, ColorBlack); 46 | } 47 | 48 | void multi_converter_mode_select_draw( 49 | Canvas* const canvas, 50 | const MultiConverterState* multi_converter_state) { 51 | int y = 10; 52 | int x = 10; 53 | 54 | canvas_set_color(canvas, ColorBlack); 55 | 56 | // FROM 57 | canvas_set_font(canvas, FontPrimary); 58 | canvas_draw_str(canvas, x, y, MULTI_CONVERTER_INFO_STRING_FROM); 59 | 60 | canvas_set_font(canvas, FontSecondary); 61 | 62 | // offset -1 63 | y += 12; 64 | 65 | canvas_draw_str( 66 | canvas, 67 | x, 68 | y, 69 | multi_converter_available_units[multi_converter_get_unit_type_offset( 70 | (multi_converter_state->select).selected_unit_type_orig, 71 | -1)] 72 | .name); 73 | 74 | // current selected element 75 | y += 12; 76 | 77 | multi_converter_mode_select_draw_selected_unit( 78 | x, y, (multi_converter_state->select).selected_unit_type_orig, canvas); 79 | 80 | if((multi_converter_state->select).select_orig) canvas_draw_str(canvas, x - 6, y, ">"); 81 | 82 | // offset +1 83 | y += 12; 84 | 85 | canvas_draw_str( 86 | canvas, 87 | x, 88 | y, 89 | multi_converter_available_units[multi_converter_get_unit_type_offset( 90 | (multi_converter_state->select).selected_unit_type_orig, 91 | 1)] 92 | .name); 93 | 94 | // TO 95 | y = 10; 96 | x = 70; 97 | 98 | canvas_set_font(canvas, FontPrimary); 99 | canvas_draw_str(canvas, x, y, MULTI_CONVERTER_INFO_STRING_TO); 100 | 101 | canvas_set_font(canvas, FontSecondary); 102 | 103 | // offset -1: go back from current selected destination and find the first one valid (even if it's itself) 104 | y += 12; 105 | 106 | multi_converter_mode_select_draw_destination_offset(x, y, -1, canvas, multi_converter_state); 107 | 108 | // current selected element 109 | y += 12; 110 | 111 | multi_converter_mode_select_draw_selected_unit( 112 | x, y, (multi_converter_state->select).selected_unit_type_dest, canvas); 113 | 114 | if(!(multi_converter_state->select).select_orig) canvas_draw_str(canvas, x - 6, y, ">"); 115 | 116 | // offset +1: same but on the opposite direction 117 | y += 12; 118 | 119 | multi_converter_mode_select_draw_destination_offset(x, y, 1, canvas, multi_converter_state); 120 | 121 | // OK / CANCEL 122 | 123 | canvas_set_color(canvas, ColorBlack); 124 | canvas_draw_box( 125 | canvas, 0, 64 - 12, canvas_string_width(canvas, MULTI_CONVERTER_INFO_STRING_OK) + 4, 12); 126 | canvas_draw_box( 127 | canvas, 128 | 128 - 4 - canvas_string_width(canvas, MULTI_CONVERTER_INFO_STRING_BACK), 129 | 64 - 12, 130 | canvas_string_width(canvas, "BACK: Cancel") + 4, 131 | 12); 132 | 133 | canvas_set_color(canvas, ColorWhite); 134 | canvas_draw_str(canvas, 2, 64 - 3, MULTI_CONVERTER_INFO_STRING_OK); 135 | canvas_draw_str( 136 | canvas, 137 | 128 - 2 - canvas_string_width(canvas, MULTI_CONVERTER_INFO_STRING_BACK), 138 | 64 - 3, 139 | MULTI_CONVERTER_INFO_STRING_BACK); 140 | } 141 | 142 | void multi_converter_mode_select_reset(MultiConverterState* const multi_converter_state) { 143 | // initial pre-selected values are equal to the current selected values 144 | (multi_converter_state->select).selected_unit_type_orig = 145 | multi_converter_state->unit_type_orig; 146 | (multi_converter_state->select).selected_unit_type_dest = 147 | multi_converter_state->unit_type_dest; 148 | 149 | (multi_converter_state->select).select_orig = 1; 150 | } 151 | 152 | MultiConverterModeTrigger multi_converter_mode_select_exit( 153 | uint8_t save_changes, 154 | MultiConverterState* const multi_converter_state) { 155 | if(save_changes) { 156 | multi_converter_state->unit_type_dest = 157 | (multi_converter_state->select).selected_unit_type_dest; 158 | 159 | if(multi_converter_state->unit_type_orig == 160 | (multi_converter_state->select).selected_unit_type_orig) { 161 | // if the ORIGIN unit didn't changed, just trigger the convert 162 | 163 | return Convert; 164 | } else { 165 | multi_converter_state->unit_type_orig = 166 | (multi_converter_state->select).selected_unit_type_orig; 167 | multi_converter_state->unit_type_dest = 168 | (multi_converter_state->select).selected_unit_type_dest; 169 | 170 | return Reset; 171 | } 172 | } 173 | 174 | return None; 175 | } 176 | 177 | void multi_converter_mode_select_switch(MultiConverterState* const multi_converter_state) { 178 | (multi_converter_state->select).select_orig ^= 1; 179 | } 180 | 181 | void multi_converter_mode_select_change_unit( 182 | int8_t direction, 183 | MultiConverterState* const multi_converter_state) { 184 | MultiConverterUnitType d; 185 | if((multi_converter_state->select).select_orig) { 186 | (multi_converter_state->select).selected_unit_type_orig = 187 | multi_converter_get_unit_type_offset( 188 | (multi_converter_state->select).selected_unit_type_orig, direction); 189 | d = (multi_converter_state->select).selected_unit_type_dest; 190 | } else { 191 | d = ((multi_converter_state->select).selected_unit_type_dest + direction) % 192 | MULTI_CONVERTER_AVAILABLE_UNITS; 193 | } 194 | 195 | // check each unit with the ORIGIN allowed_function() to make sure we're selecting a valid DESTINATION 196 | // (when changing the ORIGIN unit the DIRECTION in which we'll switch the DESTINATION will be the SAME); 197 | // also notice that ORIGIN must be DIFFERENT than DESTINATION 198 | int i = 0; 199 | while(i < MULTI_CONVERTER_AVAILABLE_UNITS) { 200 | if(multi_converter_available_units[(multi_converter_state->select).selected_unit_type_orig] 201 | .allowed_function(d) && 202 | (multi_converter_state->select).selected_unit_type_orig != d) { 203 | (multi_converter_state->select).selected_unit_type_dest = d; 204 | break; 205 | } 206 | 207 | d = multi_converter_get_unit_type_offset(d, direction); 208 | i++; 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /tama_p1/tamalib/cpu.h: -------------------------------------------------------------------------------- 1 | /* 2 | * TamaLIB - A hardware agnostic Tamagotchi P1 emulation library 3 | * 4 | * Copyright (C) 2021 Jean-Christophe Rona 5 | * 6 | * This program is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU General Public License 8 | * as published by the Free Software Foundation; either version 2 9 | * of the License, or (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | */ 20 | #ifndef _CPU_H_ 21 | #define _CPU_H_ 22 | 23 | #include "hal.h" 24 | 25 | #define MEMORY_SIZE 4096 // 4096 x 4 bits (640 x 4 bits of RAM) 26 | 27 | #define MEM_RAM_ADDR 0x000 28 | #define MEM_RAM_SIZE 0x280 29 | #define MEM_DISPLAY1_ADDR 0xE00 30 | #define MEM_DISPLAY1_SIZE 0x050 31 | #define MEM_DISPLAY2_ADDR 0xE80 32 | #define MEM_DISPLAY2_SIZE 0x050 33 | #define MEM_IO_ADDR 0xF00 34 | #define MEM_IO_SIZE 0x080 35 | 36 | /* Define this if you want to reduce the footprint of the memory buffer from 4096 u4_t (most likely bytes) 37 | * to 464 u8_t (bytes for sure), while increasing slightly the number of operations needed to read/write from/to it. 38 | */ 39 | #define LOW_FOOTPRINT 40 | 41 | #ifdef LOW_FOOTPRINT 42 | /* Invalid memory areas are not buffered to reduce the footprint of the library in memory */ 43 | #define MEM_BUFFER_SIZE (MEM_RAM_SIZE + MEM_DISPLAY1_SIZE + MEM_DISPLAY2_SIZE + MEM_IO_SIZE) / 2 44 | 45 | /* Maps the CPU memory to the memory buffer */ 46 | #define RAM_TO_MEMORY(n) ((n - MEM_RAM_ADDR) / 2) 47 | #define DISP1_TO_MEMORY(n) ((n - MEM_DISPLAY1_ADDR + MEM_RAM_SIZE) / 2) 48 | #define DISP2_TO_MEMORY(n) ((n - MEM_DISPLAY2_ADDR + MEM_RAM_SIZE + MEM_DISPLAY1_SIZE) / 2) 49 | #define IO_TO_MEMORY(n) \ 50 | ((n - MEM_IO_ADDR + MEM_RAM_SIZE + MEM_DISPLAY1_SIZE + MEM_DISPLAY2_SIZE) / 2) 51 | 52 | #define SET_RAM_MEMORY(buffer, n, v) \ 53 | { \ 54 | buffer[RAM_TO_MEMORY(n)] = (buffer[RAM_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | \ 55 | ((v)&0xF) << (((n) % 2) << 2); \ 56 | } 57 | #define SET_DISP1_MEMORY(buffer, n, v) \ 58 | { \ 59 | buffer[DISP1_TO_MEMORY(n)] = (buffer[DISP1_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | \ 60 | ((v)&0xF) << (((n) % 2) << 2); \ 61 | } 62 | #define SET_DISP2_MEMORY(buffer, n, v) \ 63 | { \ 64 | buffer[DISP2_TO_MEMORY(n)] = (buffer[DISP2_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | \ 65 | ((v)&0xF) << (((n) % 2) << 2); \ 66 | } 67 | #define SET_IO_MEMORY(buffer, n, v) \ 68 | { \ 69 | buffer[IO_TO_MEMORY(n)] = (buffer[IO_TO_MEMORY(n)] & ~(0xF << (((n) % 2) << 2))) | \ 70 | ((v)&0xF) << (((n) % 2) << 2); \ 71 | } 72 | #define SET_MEMORY(buffer, n, v) \ 73 | { \ 74 | if((n) < (MEM_RAM_ADDR + MEM_RAM_SIZE)) { \ 75 | SET_RAM_MEMORY(buffer, n, v); \ 76 | } else if((n) < MEM_DISPLAY1_ADDR) { \ 77 | /* INVALID_MEMORY */ \ 78 | } else if((n) < (MEM_DISPLAY1_ADDR + MEM_DISPLAY1_SIZE)) { \ 79 | SET_DISP1_MEMORY(buffer, n, v); \ 80 | } else if((n) < MEM_DISPLAY2_ADDR) { \ 81 | /* INVALID_MEMORY */ \ 82 | } else if((n) < (MEM_DISPLAY2_ADDR + MEM_DISPLAY2_SIZE)) { \ 83 | SET_DISP2_MEMORY(buffer, n, v); \ 84 | } else if((n) < MEM_IO_ADDR) { \ 85 | /* INVALID_MEMORY */ \ 86 | } else if((n) < (MEM_IO_ADDR + MEM_IO_SIZE)) { \ 87 | SET_IO_MEMORY(buffer, n, v); \ 88 | } else { \ 89 | /* INVALID_MEMORY */ \ 90 | } \ 91 | } 92 | 93 | #define GET_RAM_MEMORY(buffer, n) ((buffer[RAM_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF) 94 | #define GET_DISP1_MEMORY(buffer, n) ((buffer[DISP1_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF) 95 | #define GET_DISP2_MEMORY(buffer, n) ((buffer[DISP2_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF) 96 | #define GET_IO_MEMORY(buffer, n) ((buffer[IO_TO_MEMORY(n)] >> (((n) % 2) << 2)) & 0xF) 97 | #define GET_MEMORY(buffer, n) \ 98 | ((buffer \ 99 | [((n) < (MEM_RAM_ADDR + MEM_RAM_SIZE)) ? RAM_TO_MEMORY(n) : \ 100 | ((n) < MEM_DISPLAY1_ADDR) ? 0 : \ 101 | ((n) < (MEM_DISPLAY1_ADDR + MEM_DISPLAY1_SIZE)) ? DISP1_TO_MEMORY(n) : \ 102 | ((n) < MEM_DISPLAY2_ADDR) ? 0 : \ 103 | ((n) < (MEM_DISPLAY2_ADDR + MEM_DISPLAY2_SIZE)) ? DISP2_TO_MEMORY(n) : \ 104 | ((n) < MEM_IO_ADDR) ? 0 : \ 105 | ((n) < (MEM_IO_ADDR + MEM_IO_SIZE)) ? IO_TO_MEMORY(n) : \ 106 | 0] >> \ 107 | (((n) % 2) << 2)) & \ 108 | 0xF) 109 | 110 | #define MEM_BUFFER_TYPE u8_t 111 | #else 112 | #define MEM_BUFFER_SIZE MEMORY_SIZE 113 | 114 | #define SET_MEMORY(buffer, n, v) \ 115 | { buffer[n] = v; } 116 | #define SET_RAM_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v) 117 | #define SET_DISP1_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v) 118 | #define SET_DISP2_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v) 119 | #define SET_IO_MEMORY(buffer, n, v) SET_MEMORY(buffer, n, v) 120 | 121 | #define GET_MEMORY(buffer, n) (buffer[n]) 122 | #define GET_RAM_MEMORY(buffer, n) GET_MEMORY(buffer, n) 123 | #define GET_DISP1_MEMORY(buffer, n) GET_MEMORY(buffer, n) 124 | #define GET_DISP2_MEMORY(buffer, n) GET_MEMORY(buffer, n) 125 | #define GET_IO_MEMORY(buffer, n) GET_MEMORY(buffer, n) 126 | 127 | #define MEM_BUFFER_TYPE u4_t 128 | #endif 129 | 130 | typedef struct breakpoint { 131 | u13_t addr; 132 | struct breakpoint* next; 133 | } breakpoint_t; 134 | 135 | /* Pins (TODO: add other pins) */ 136 | typedef enum { 137 | PIN_K00 = 0x0, 138 | PIN_K01 = 0x1, 139 | PIN_K02 = 0x2, 140 | PIN_K03 = 0x3, 141 | PIN_K10 = 0X4, 142 | PIN_K11 = 0X5, 143 | PIN_K12 = 0X6, 144 | PIN_K13 = 0X7, 145 | } pin_t; 146 | 147 | typedef enum { 148 | PIN_STATE_LOW = 0, 149 | PIN_STATE_HIGH = 1, 150 | } pin_state_t; 151 | 152 | typedef enum { 153 | INT_PROG_TIMER_SLOT = 0, 154 | INT_SERIAL_SLOT = 1, 155 | INT_K10_K13_SLOT = 2, 156 | INT_K00_K03_SLOT = 3, 157 | INT_STOPWATCH_SLOT = 4, 158 | INT_CLOCK_TIMER_SLOT = 5, 159 | INT_SLOT_NUM, 160 | } int_slot_t; 161 | 162 | typedef struct { 163 | u4_t factor_flag_reg; 164 | u4_t mask_reg; 165 | bool_t triggered; /* 1 if triggered, 0 otherwise */ 166 | u8_t vector; 167 | } interrupt_t; 168 | 169 | typedef struct { 170 | u13_t* pc; 171 | u12_t* x; 172 | u12_t* y; 173 | u4_t* a; 174 | u4_t* b; 175 | u5_t* np; 176 | u8_t* sp; 177 | u4_t* flags; 178 | 179 | u32_t* tick_counter; 180 | u32_t* clk_timer_timestamp; 181 | u32_t* prog_timer_timestamp; 182 | bool_t* prog_timer_enabled; 183 | u8_t* prog_timer_data; 184 | u8_t* prog_timer_rld; 185 | 186 | u32_t* call_depth; 187 | 188 | interrupt_t* interrupts; 189 | 190 | MEM_BUFFER_TYPE* memory; 191 | } state_t; 192 | 193 | void cpu_add_bp(breakpoint_t** list, u13_t addr); 194 | void cpu_free_bp(breakpoint_t** list); 195 | 196 | void cpu_set_speed(u8_t speed); 197 | 198 | state_t* cpu_get_state(void); 199 | 200 | u32_t cpu_get_depth(void); 201 | 202 | void cpu_set_input_pin(pin_t pin, pin_state_t state); 203 | 204 | void cpu_sync_ref_timestamp(void); 205 | 206 | void cpu_refresh_hw(void); 207 | 208 | void cpu_reset(void); 209 | 210 | bool_t cpu_init(const u12_t* program, breakpoint_t* breakpoints, u32_t freq); 211 | void cpu_release(void); 212 | 213 | int cpu_step(void); 214 | 215 | #endif /* _CPU_H_ */ 216 | -------------------------------------------------------------------------------- /multi_converter/multi_converter_units.c: -------------------------------------------------------------------------------- 1 | #include "multi_converter_units.h" 2 | 3 | #define MULTI_CONVERTER_CHAR_OVERFLOW '#' 4 | #define MULTI_CONVERTER_MAX_SUPORTED_INT 999999999 5 | 6 | #define multi_converter_unit_set_overflow(b) \ 7 | for(int _i = 0; _i < MULTI_CONVERTER_NUMBER_DIGITS; _i++) \ 8 | b[_i] = MULTI_CONVERTER_CHAR_OVERFLOW; 9 | 10 | // 11 | // DEC / HEX / BIN conversion 12 | // 13 | void multi_converter_unit_dec_hex_bin_convert(MultiConverterState* const multi_converter_state) { 14 | char dest[MULTI_CONVERTER_NUMBER_DIGITS]; 15 | 16 | int i = 0; 17 | uint8_t overflow = 0; 18 | 19 | int a = 0; 20 | int r = 0; 21 | uint8_t f = 1; 22 | 23 | switch(multi_converter_state->unit_type_orig) { 24 | default: 25 | break; 26 | case UnitTypeDec: { 27 | a = atoi(multi_converter_state->buffer_orig); 28 | f = (multi_converter_state->unit_type_dest == UnitTypeHex ? 16 : 2); 29 | 30 | break; 31 | } 32 | case UnitTypeHex: 33 | a = strtol(multi_converter_state->buffer_orig, NULL, 16); 34 | f = (multi_converter_state->unit_type_dest == UnitTypeDec ? 10 : 2); 35 | 36 | break; 37 | case UnitTypeBin: 38 | a = strtol(multi_converter_state->buffer_orig, NULL, 2); 39 | f = (multi_converter_state->unit_type_dest == UnitTypeDec ? 10 : 16); 40 | 41 | break; 42 | } 43 | 44 | while(a > 0) { 45 | r = a % f; 46 | dest[i] = r + (r < 10 ? '0' : ('A' - 10)); 47 | a /= f; 48 | if(i++ >= MULTI_CONVERTER_NUMBER_DIGITS) { 49 | overflow = 1; 50 | break; 51 | } 52 | } 53 | 54 | if(overflow) { 55 | multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); 56 | } else { 57 | // copy DEST (reversed) to destination and append empty chars at the end 58 | for(int j = 0; j < MULTI_CONVERTER_NUMBER_DIGITS; j++) { 59 | if(i >= 1) 60 | multi_converter_state->buffer_dest[j] = dest[--i]; 61 | else 62 | multi_converter_state->buffer_dest[j] = ' '; 63 | } 64 | } 65 | } 66 | 67 | uint8_t multi_converter_unit_dec_hex_bin_allowed(MultiConverterUnitType unit_type) { 68 | return (unit_type == UnitTypeDec || unit_type == UnitTypeHex || unit_type == UnitTypeBin); 69 | } 70 | 71 | // 72 | // CEL / FAR / KEL 73 | // 74 | void multi_converter_unit_temperature_convert(MultiConverterState* const multi_converter_state) { 75 | double a = strtof(multi_converter_state->buffer_orig, NULL); 76 | uint8_t overflow = 0; 77 | 78 | switch(multi_converter_state->unit_type_orig) { 79 | default: 80 | break; 81 | case UnitTypeCelsius: 82 | if(multi_converter_state->unit_type_dest == UnitTypeFahernheit) { 83 | // celsius to fahrenheit 84 | a = (a * ((double)1.8)) + 32; 85 | } else { // UnitTypeKelvin 86 | a += ((double)273.15); 87 | } 88 | 89 | break; 90 | case UnitTypeFahernheit: 91 | // fahrenheit to celsius, always 92 | a = (a - 32) / ((double)1.8); 93 | if(multi_converter_state->unit_type_dest == UnitTypeKelvin) { 94 | // if kelvin, add 95 | a += ((double)273.15); 96 | } 97 | 98 | break; 99 | case UnitTypeKelvin: 100 | // kelvin to celsius, always 101 | a -= ((double)273.15); 102 | if(multi_converter_state->unit_type_dest == UnitTypeFahernheit) { 103 | // if fahernheit, convert 104 | a = (a * ((double)1.8)) + 32; 105 | } 106 | 107 | break; 108 | } 109 | 110 | if(overflow) { 111 | multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); 112 | } else { 113 | int ret = snprintf( 114 | multi_converter_state->buffer_dest, MULTI_CONVERTER_NUMBER_DIGITS + 1, "%.3lf", a); 115 | 116 | if(ret < 0) multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); 117 | } 118 | } 119 | 120 | uint8_t multi_converter_unit_temperature_allowed(MultiConverterUnitType unit_type) { 121 | return ( 122 | unit_type == UnitTypeCelsius || unit_type == UnitTypeFahernheit || 123 | unit_type == UnitTypeKelvin); 124 | } 125 | 126 | // 127 | // KM / M / CM / MILES / FEET / INCHES 128 | // 129 | 130 | void multi_converter_unit_distance_convert(MultiConverterState* const multi_converter_state) { 131 | double a = strtof(multi_converter_state->buffer_orig, NULL); 132 | uint8_t overflow = 0; 133 | 134 | switch(multi_converter_state->unit_type_orig) { 135 | default: 136 | break; 137 | case UnitTypeKilometers: 138 | if(multi_converter_state->unit_type_dest == UnitTypeMeters) 139 | a *= ((double)1000); 140 | else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters) 141 | a *= ((double)100000); 142 | else if(multi_converter_state->unit_type_dest == UnitTypeMiles) 143 | a *= ((double)0.6213711); 144 | else if(multi_converter_state->unit_type_dest == UnitTypeFeet) 145 | a *= ((double)3280.839895013); 146 | else if(multi_converter_state->unit_type_dest == UnitTypeInches) 147 | a *= ((double)39370.078740157); 148 | break; 149 | case UnitTypeMeters: 150 | if(multi_converter_state->unit_type_dest == UnitTypeKilometers) 151 | a /= ((double)1000); 152 | else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters) 153 | a *= ((double)100); 154 | else if(multi_converter_state->unit_type_dest == UnitTypeMiles) 155 | a *= ((double)0.0006213711); 156 | else if(multi_converter_state->unit_type_dest == UnitTypeFeet) 157 | a *= ((double)3.280839895013); 158 | else if(multi_converter_state->unit_type_dest == UnitTypeInches) 159 | a *= ((double)39.370078740157); 160 | break; 161 | case UnitTypeCentimeters: 162 | if(multi_converter_state->unit_type_dest == UnitTypeKilometers) 163 | a /= ((double)100000); 164 | else if(multi_converter_state->unit_type_dest == UnitTypeMeters) 165 | a /= ((double)100); 166 | else if(multi_converter_state->unit_type_dest == UnitTypeMiles) 167 | a *= ((double)0.000006213711); 168 | else if(multi_converter_state->unit_type_dest == UnitTypeFeet) 169 | a *= ((double)0.03280839895013); 170 | else if(multi_converter_state->unit_type_dest == UnitTypeInches) 171 | a *= ((double)0.39370078740157); 172 | break; 173 | 174 | case UnitTypeMiles: 175 | if(multi_converter_state->unit_type_dest == UnitTypeKilometers) 176 | a *= ((double)1.609344); 177 | else if(multi_converter_state->unit_type_dest == UnitTypeMeters) 178 | a *= ((double)1609.344); 179 | else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters) 180 | a *= ((double)160934.4); 181 | else if(multi_converter_state->unit_type_dest == UnitTypeFeet) 182 | a *= ((double)5280); 183 | else if(multi_converter_state->unit_type_dest == UnitTypeInches) 184 | a *= ((double)63360); 185 | break; 186 | case UnitTypeFeet: 187 | if(multi_converter_state->unit_type_dest == UnitTypeKilometers) 188 | a *= ((double)0.0003048); 189 | else if(multi_converter_state->unit_type_dest == UnitTypeMeters) 190 | a *= ((double)0.3048); 191 | else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters) 192 | a *= ((double)30.48); 193 | else if(multi_converter_state->unit_type_dest == UnitTypeMiles) 194 | a *= ((double)0.000189393939394); 195 | else if(multi_converter_state->unit_type_dest == UnitTypeInches) 196 | a *= ((double)12); 197 | break; 198 | case UnitTypeInches: 199 | if(multi_converter_state->unit_type_dest == UnitTypeKilometers) 200 | a *= ((double)0.0000254); 201 | else if(multi_converter_state->unit_type_dest == UnitTypeMeters) 202 | a *= ((double)0.0254); 203 | else if(multi_converter_state->unit_type_dest == UnitTypeCentimeters) 204 | a *= ((double)2.54); 205 | else if(multi_converter_state->unit_type_dest == UnitTypeMiles) 206 | a *= ((double)0.0000157828282828); 207 | else if(multi_converter_state->unit_type_dest == UnitTypeFeet) 208 | a *= ((double)0.0833333333333); 209 | break; 210 | } 211 | 212 | if(overflow) { 213 | multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); 214 | } else { 215 | int ret = snprintf( 216 | multi_converter_state->buffer_dest, MULTI_CONVERTER_NUMBER_DIGITS + 1, "%lf", a); 217 | 218 | if(ret < 0) multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); 219 | } 220 | } 221 | 222 | uint8_t multi_converter_unit_distance_allowed(MultiConverterUnitType unit_type) { 223 | return ( 224 | unit_type == UnitTypeKilometers || unit_type == UnitTypeMeters || 225 | unit_type == UnitTypeCentimeters || unit_type == UnitTypeMiles || 226 | unit_type == UnitTypeFeet || unit_type == UnitTypeInches); 227 | } 228 | 229 | // 230 | // DEG / RAD 231 | // 232 | 233 | void multi_converter_unit_angle_convert(MultiConverterState* const multi_converter_state) { 234 | double a = strtof(multi_converter_state->buffer_orig, NULL); 235 | uint8_t overflow = 0; 236 | 237 | switch(multi_converter_state->unit_type_orig) { 238 | default: 239 | break; 240 | case UnitTypeDegree: 241 | if(multi_converter_state->unit_type_dest == UnitTypeRadian) a *= ((double)0.0174532925199); 242 | break; 243 | 244 | case UnitTypeRadian: 245 | if(multi_converter_state->unit_type_dest == UnitTypeDegree) a *= ((double)57.2957795131); 246 | break; 247 | } 248 | 249 | if(overflow) { 250 | multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); 251 | } else { 252 | int ret = snprintf( 253 | multi_converter_state->buffer_dest, MULTI_CONVERTER_NUMBER_DIGITS + 1, "%lf", a); 254 | 255 | if(ret < 0) multi_converter_unit_set_overflow(multi_converter_state->buffer_dest); 256 | } 257 | } 258 | 259 | uint8_t multi_converter_unit_angle_allowed(MultiConverterUnitType unit_type) { 260 | return (unit_type == UnitTypeDegree || unit_type == UnitTypeRadian); 261 | } --------------------------------------------------------------------------------