From d74fa7bf528b52f8a89b0410a91a3ecc8c04c948 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Thu, 16 Nov 2023 05:14:05 +0000 Subject: [PATCH] 17 more apps done, 14 to go --- .../external/arkanoid/application.fam | 13 - .../external/arkanoid/arkanoid_10px.png | Bin 1622 -> 0 bytes .../external/arkanoid/arkanoid_game.c | 479 ------ .../external/calculator/application.fam | 15 - applications/external/calculator/calcIcon.png | Bin 2002 -> 0 bytes applications/external/calculator/calculator.c | 458 ----- applications/external/calculator/tinyexpr.c | 786 --------- applications/external/calculator/tinyexpr.h | 97 -- applications/external/doom/application.fam | 17 - applications/external/doom/assets.c | 331 ---- applications/external/doom/assets.h | 108 -- applications/external/doom/assets/door2.png | Bin 31942 -> 0 bytes .../external/doom/assets/door_inv.png | Bin 1068 -> 0 bytes .../external/doom/assets/fire_inv.png | Bin 583 -> 0 bytes .../external/doom/assets/fireball_inv.png | Bin 418 -> 0 bytes .../doom/assets/fireball_mask_inv.png | Bin 388 -> 0 bytes .../external/doom/assets/gradient_inv.png | Bin 1037 -> 0 bytes applications/external/doom/assets/gun_inv.png | Bin 1050 -> 0 bytes .../external/doom/assets/gun_mask_inv.png | Bin 847 -> 0 bytes applications/external/doom/assets/imp_inv.png | Bin 903 -> 0 bytes .../external/doom/assets/imp_mask_inv.png | Bin 958 -> 0 bytes .../external/doom/assets/item_inv.png | Bin 417 -> 0 bytes .../external/doom/assets/item_mask_inv.png | Bin 383 -> 0 bytes .../external/doom/assets/logo_inv.png | Bin 5085 -> 0 bytes applications/external/doom/constants.h | 91 - applications/external/doom/display.h | 281 ---- applications/external/doom/doom.c | 1104 ------------ applications/external/doom/doom_10px.png | Bin 1772 -> 0 bytes .../external/doom/doom_music_player_worker.c | 504 ------ .../external/doom/doom_music_player_worker.h | 44 - applications/external/doom/entities.c | 42 - applications/external/doom/entities.h | 56 - applications/external/doom/level.h | 188 --- applications/external/doom/sound.h | 34 - applications/external/doom/types.c | 33 - applications/external/doom/types.h | 36 - .../external/flappy_bird/application.fam | 14 - .../external/flappy_bird/assets/bird_01.png | Bin 113 -> 0 bytes .../external/flappy_bird/assets/bird_02.png | Bin 116 -> 0 bytes .../external/flappy_bird/assets/bird_03.png | Bin 116 -> 0 bytes .../external/flappy_bird/flappy_10px.png | Bin 1787 -> 0 bytes .../external/flappy_bird/flappy_bird.c | 379 ----- .../external/game_of_life/application.fam | 15 - .../external/game_of_life/game_of_life.c | 164 -- .../external/game_of_life/golIcon.png | Bin 1921 -> 0 bytes applications/external/hc_sr04/application.fam | 15 - .../external/hc_sr04/dist_sensor10px.png | Bin 141 -> 0 bytes applications/external/hc_sr04/hc_sr04.c | 275 --- .../heap_defence_game/application.fam | 14 - .../assets_images/Background_128x64.png | Bin 872 -> 0 bytes .../assets_images/Box1_10x10.png | Bin 489 -> 0 bytes .../assets_images/Box2_10x10.png | Bin 448 -> 0 bytes .../assets_images/Box3_10x10.png | Bin 459 -> 0 bytes .../assets_images/Box4_10x10.png | Bin 463 -> 0 bytes .../assets_images/Box5_10x10.png | Bin 475 -> 0 bytes .../assets_images/Box6p_10x10.png | Bin 471 -> 0 bytes .../assets_images/Box7p_10x10.png | Bin 470 -> 0 bytes .../assets_images/Box8p_10x10.png | Bin 465 -> 0 bytes .../assets_images/Game_over_128x64.png | Bin 683 -> 0 bytes .../HD_game_over_128x64/frame_01.png | Bin 683 -> 0 bytes .../HD_game_over_128x64/frame_02.png | Bin 680 -> 0 bytes .../HD_game_over_128x64/frame_03.png | Bin 671 -> 0 bytes .../HD_game_over_128x64/frame_04.png | Bin 667 -> 0 bytes .../HD_game_over_128x64/frame_05.png | Bin 670 -> 0 bytes .../HD_game_over_128x64/frame_06.png | Bin 669 -> 0 bytes .../HD_game_over_128x64/frame_07.png | Bin 677 -> 0 bytes .../HD_game_over_128x64/frame_rate | 1 - .../HD_person_block_left_10x20/frame_01.png | Bin 8918 -> 0 bytes .../HD_person_block_left_10x20/frame_02.png | Bin 9144 -> 0 bytes .../HD_person_block_left_10x20/frame_rate | 1 - .../HD_person_block_right_10x20/frame_01.png | Bin 475 -> 0 bytes .../HD_person_block_right_10x20/frame_02.png | Bin 503 -> 0 bytes .../HD_person_block_right_10x20/frame_rate | 1 - .../HD_person_left_10x20/frame_01.png | Bin 214 -> 0 bytes .../HD_person_left_10x20/frame_02.png | Bin 216 -> 0 bytes .../HD_person_left_10x20/frame_03.png | Bin 221 -> 0 bytes .../HD_person_left_10x20/frame_04.png | Bin 216 -> 0 bytes .../HD_person_left_10x20/frame_rate | 1 - .../HD_person_right_10x20/frame_01.png | Bin 217 -> 0 bytes .../HD_person_right_10x20/frame_02.png | Bin 218 -> 0 bytes .../HD_person_right_10x20/frame_03.png | Bin 216 -> 0 bytes .../HD_person_right_10x20/frame_04.png | Bin 218 -> 0 bytes .../HD_person_right_10x20/frame_rate | 1 - .../HD_start_128x64/frame_01.png | Bin 3820 -> 0 bytes .../HD_start_128x64/frame_02.png | Bin 3881 -> 0 bytes .../HD_start_128x64/frame_03.png | Bin 3810 -> 0 bytes .../HD_start_128x64/frame_04.png | Bin 3881 -> 0 bytes .../assets_images/HD_start_128x64/frame_rate | 1 - .../assets_images/Person4_1_10x20.png | Bin 8918 -> 0 bytes .../assets_images/Person4_2_10x20.png | Bin 9144 -> 0 bytes .../assets_images/Person5_1_10x20.png | Bin 475 -> 0 bytes .../assets_images/Person5_2_10x20.png | Bin 503 -> 0 bytes .../assets_images/Start_128x64.png | Bin 3881 -> 0 bytes .../external/heap_defence_game/box.png | Bin 131 -> 0 bytes .../external/heap_defence_game/heap_defence.c | 598 ------- .../external/heap_defence_game/hede_assets.c | 28 - .../external/heap_defence_game/hede_assets.h | 11 - .../external/ir_scope/application.fam | 13 - applications/external/ir_scope/ir_scope.c | 184 -- applications/external/ir_scope/ir_scope.png | Bin 169 -> 0 bytes .../external/mandelbrot/Mandelbrot.png | Bin 1918 -> 0 bytes .../external/mandelbrot/application.fam | 15 - applications/external/mandelbrot/mandelbrot.c | 171 -- applications/external/paint/application.fam | 15 - applications/external/paint/paint.c | 153 -- applications/external/paint/paintIcon.png | Bin 1911 -> 0 bytes .../spectrum_analyzer/application.fam | 13 - .../helpers/radio_device_loader.c | 64 - .../helpers/radio_device_loader.h | 15 - .../spectrum_analyzer/spectrum_10px.png | Bin 135 -> 0 bytes .../spectrum_analyzer/spectrum_analyzer.c | 611 ------- .../spectrum_analyzer/spectrum_analyzer.h | 84 - .../spectrum_analyzer_worker.c | 345 ---- .../spectrum_analyzer_worker.h | 35 - .../external/tanksgame/application.fam | 12 - applications/external/tanksgame/constants.h | 19 - .../tanksgame/helpers/radio_device_loader.c | 64 - .../tanksgame/helpers/radio_device_loader.h | 15 - .../tanksgame/images/HappyFlipper_128x64.png | Bin 633 -> 0 bytes .../images/TanksSplashScreen_128x64.png | Bin 649 -> 0 bytes .../external/tanksgame/images/enemy_down.png | Bin 157 -> 0 bytes .../external/tanksgame/images/enemy_left.png | Bin 159 -> 0 bytes .../external/tanksgame/images/enemy_right.png | Bin 159 -> 0 bytes .../external/tanksgame/images/enemy_up.png | Bin 160 -> 0 bytes .../tanksgame/images/projectile_down.png | Bin 104 -> 0 bytes .../tanksgame/images/projectile_left.png | Bin 106 -> 0 bytes .../tanksgame/images/projectile_right.png | Bin 108 -> 0 bytes .../tanksgame/images/projectile_up.png | Bin 102 -> 0 bytes .../external/tanksgame/images/tank_base.png | Bin 3047 -> 0 bytes .../external/tanksgame/images/tank_down.png | Bin 3040 -> 0 bytes .../tanksgame/images/tank_explosion.png | Bin 3050 -> 0 bytes .../tanksgame/images/tank_hedgehog.png | Bin 3049 -> 0 bytes .../external/tanksgame/images/tank_left.png | Bin 159 -> 0 bytes .../external/tanksgame/images/tank_right.png | Bin 155 -> 0 bytes .../external/tanksgame/images/tank_stone.png | Bin 3046 -> 0 bytes .../external/tanksgame/images/tank_up.png | Bin 157 -> 0 bytes .../external/tanksgame/images/tank_wall.png | Bin 3039 -> 0 bytes applications/external/tanksgame/tanksIcon.png | Bin 1913 -> 0 bytes applications/external/tanksgame/tanks_game.c | 1476 ----------------- .../external/tetris_game/application.fam | 13 - .../external/tetris_game/tetris_10px.png | Bin 1625 -> 0 bytes .../external/tetris_game/tetris_game.c | 478 ------ .../external/tictactoe_game/application.fam | 13 - .../tictactoe_game/tictactoe_10px.png | Bin 1605 -> 0 bytes .../external/tictactoe_game/tictactoe_game.c | 387 ----- applications/external/unitemp/LICENSE.md | 674 -------- applications/external/unitemp/Sensors.c | 653 -------- applications/external/unitemp/Sensors.h | 339 ---- applications/external/unitemp/application.fam | 17 - .../external/unitemp/assets/co2_11x14.png | Bin 176 -> 0 bytes .../unitemp/assets/flipper_happy_2_60x38.png | Bin 564 -> 0 bytes .../unitemp/assets/flipper_happy_60x38.png | Bin 563 -> 0 bytes .../unitemp/assets/flipper_sad_60x38.png | Bin 560 -> 0 bytes .../unitemp/assets/heat_index_11x14.png | Bin 1239 -> 0 bytes .../external/unitemp/assets/hum_9x15.png | Bin 198 -> 0 bytes .../external/unitemp/assets/in_hg_15x15.png | Bin 219 -> 0 bytes .../external/unitemp/assets/mm_hg_15x15.png | Bin 207 -> 0 bytes .../external/unitemp/assets/pressure_7x13.png | Bin 169 -> 0 bytes .../external/unitemp/assets/repo_qr_50x50.png | Bin 700 -> 0 bytes .../external/unitemp/assets/sherlok_53x45.png | Bin 695 -> 0 bytes .../external/unitemp/assets/temp_C_11x14.png | Bin 214 -> 0 bytes .../external/unitemp/assets/temp_F_11x14.png | Bin 210 -> 0 bytes applications/external/unitemp/icon.png | Bin 1826 -> 0 bytes .../external/unitemp/interfaces/I2CSensor.c | 131 -- .../external/unitemp/interfaces/I2CSensor.h | 128 -- .../unitemp/interfaces/OneWireSensor.c | 367 ---- .../unitemp/interfaces/OneWireSensor.h | 226 --- .../external/unitemp/interfaces/SPISensor.c | 89 - .../external/unitemp/interfaces/SPISensor.h | 66 - .../unitemp/interfaces/SingleWireSensor.c | 279 ---- .../unitemp/interfaces/SingleWireSensor.h | 92 - .../external/unitemp/interfaces/endianness.h | 60 - .../external/unitemp/sensors/AM2320.c | 106 -- .../external/unitemp/sensors/AM2320.h | 62 - .../external/unitemp/sensors/BME680.c | 431 ----- .../external/unitemp/sensors/BME680.h | 111 -- .../external/unitemp/sensors/BMP180.c | 171 -- .../external/unitemp/sensors/BMP180.h | 62 - .../external/unitemp/sensors/BMx280.c | 345 ---- .../external/unitemp/sensors/BMx280.h | 102 -- applications/external/unitemp/sensors/DHT20.c | 154 -- applications/external/unitemp/sensors/DHT20.h | 63 - .../external/unitemp/sensors/HDC1080.c | 94 -- .../external/unitemp/sensors/HDC1080.h | 62 - .../external/unitemp/sensors/HTU21x.c | 107 -- .../external/unitemp/sensors/HTU21x.h | 62 - applications/external/unitemp/sensors/LM75.c | 87 - applications/external/unitemp/sensors/LM75.h | 62 - .../external/unitemp/sensors/MAX31855.c | 93 -- .../external/unitemp/sensors/MAX31855.h | 65 - .../external/unitemp/sensors/MAX6675.c | 81 - .../external/unitemp/sensors/MAX6675.h | 65 - applications/external/unitemp/sensors/SCD30.c | 381 ----- applications/external/unitemp/sensors/SCD30.h | 59 - applications/external/unitemp/sensors/SCD40.c | 285 ---- applications/external/unitemp/sensors/SCD40.h | 59 - applications/external/unitemp/sensors/SHT30.c | 90 - applications/external/unitemp/sensors/SHT30.h | 70 - .../external/unitemp/sensors/Sensors.xlsx | Bin 12642 -> 0 bytes applications/external/unitemp/unitemp.c | 343 ---- applications/external/unitemp/unitemp.h | 170 -- .../external/unitemp/views/General_view.c | 688 -------- .../external/unitemp/views/MainMenu_view.c | 99 -- .../external/unitemp/views/Popup_view.c | 49 - .../unitemp/views/SensorActions_view.c | 125 -- .../external/unitemp/views/SensorEdit_view.c | 383 ----- .../unitemp/views/SensorNameEdit_view.c | 47 - .../external/unitemp/views/SensorsList_view.c | 163 -- .../external/unitemp/views/Settings_view.c | 167 -- .../external/unitemp/views/UnitempViews.h | 94 -- .../external/unitemp/views/Widgets_view.c | 206 --- .../external/videopoker/application.fam | 15 - applications/external/videopoker/poker.c | 819 --------- .../external/videopoker/pokerIcon.png | Bin 1899 -> 0 bytes applications/external/zombiez/application.fam | 13 - applications/external/zombiez/zombie_10px.png | Bin 8741 -> 0 bytes applications/external/zombiez/zombiez.c | 402 ----- applications/external/zombiez/zombiez.h | 62 - 218 files changed, 20726 deletions(-) delete mode 100644 applications/external/arkanoid/application.fam delete mode 100644 applications/external/arkanoid/arkanoid_10px.png delete mode 100644 applications/external/arkanoid/arkanoid_game.c delete mode 100644 applications/external/calculator/application.fam delete mode 100644 applications/external/calculator/calcIcon.png delete mode 100644 applications/external/calculator/calculator.c delete mode 100644 applications/external/calculator/tinyexpr.c delete mode 100644 applications/external/calculator/tinyexpr.h delete mode 100644 applications/external/doom/application.fam delete mode 100644 applications/external/doom/assets.c delete mode 100644 applications/external/doom/assets.h delete mode 100644 applications/external/doom/assets/door2.png delete mode 100644 applications/external/doom/assets/door_inv.png delete mode 100644 applications/external/doom/assets/fire_inv.png delete mode 100644 applications/external/doom/assets/fireball_inv.png delete mode 100644 applications/external/doom/assets/fireball_mask_inv.png delete mode 100644 applications/external/doom/assets/gradient_inv.png delete mode 100644 applications/external/doom/assets/gun_inv.png delete mode 100644 applications/external/doom/assets/gun_mask_inv.png delete mode 100644 applications/external/doom/assets/imp_inv.png delete mode 100644 applications/external/doom/assets/imp_mask_inv.png delete mode 100644 applications/external/doom/assets/item_inv.png delete mode 100644 applications/external/doom/assets/item_mask_inv.png delete mode 100644 applications/external/doom/assets/logo_inv.png delete mode 100644 applications/external/doom/constants.h delete mode 100644 applications/external/doom/display.h delete mode 100644 applications/external/doom/doom.c delete mode 100644 applications/external/doom/doom_10px.png delete mode 100644 applications/external/doom/doom_music_player_worker.c delete mode 100644 applications/external/doom/doom_music_player_worker.h delete mode 100644 applications/external/doom/entities.c delete mode 100644 applications/external/doom/entities.h delete mode 100644 applications/external/doom/level.h delete mode 100644 applications/external/doom/sound.h delete mode 100644 applications/external/doom/types.c delete mode 100644 applications/external/doom/types.h delete mode 100644 applications/external/flappy_bird/application.fam delete mode 100644 applications/external/flappy_bird/assets/bird_01.png delete mode 100644 applications/external/flappy_bird/assets/bird_02.png delete mode 100644 applications/external/flappy_bird/assets/bird_03.png delete mode 100644 applications/external/flappy_bird/flappy_10px.png delete mode 100644 applications/external/flappy_bird/flappy_bird.c delete mode 100644 applications/external/game_of_life/application.fam delete mode 100644 applications/external/game_of_life/game_of_life.c delete mode 100644 applications/external/game_of_life/golIcon.png delete mode 100644 applications/external/hc_sr04/application.fam delete mode 100644 applications/external/hc_sr04/dist_sensor10px.png delete mode 100644 applications/external/hc_sr04/hc_sr04.c delete mode 100644 applications/external/heap_defence_game/application.fam delete mode 100644 applications/external/heap_defence_game/assets_images/Background_128x64.png delete mode 100644 applications/external/heap_defence_game/assets_images/Box1_10x10.png delete mode 100644 applications/external/heap_defence_game/assets_images/Box2_10x10.png delete mode 100644 applications/external/heap_defence_game/assets_images/Box3_10x10.png delete mode 100644 applications/external/heap_defence_game/assets_images/Box4_10x10.png delete mode 100644 applications/external/heap_defence_game/assets_images/Box5_10x10.png delete mode 100644 applications/external/heap_defence_game/assets_images/Box6p_10x10.png delete mode 100644 applications/external/heap_defence_game/assets_images/Box7p_10x10.png delete mode 100644 applications/external/heap_defence_game/assets_images/Box8p_10x10.png delete mode 100644 applications/external/heap_defence_game/assets_images/Game_over_128x64.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_01.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_02.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_03.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_04.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_05.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_06.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_07.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_rate delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_01.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_02.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_rate delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_01.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_02.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_01.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_02.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_03.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_04.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_rate delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_01.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_02.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_03.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_04.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate delete mode 100644 applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_01.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_02.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_03.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_04.png delete mode 100644 applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_rate delete mode 100644 applications/external/heap_defence_game/assets_images/Person4_1_10x20.png delete mode 100644 applications/external/heap_defence_game/assets_images/Person4_2_10x20.png delete mode 100644 applications/external/heap_defence_game/assets_images/Person5_1_10x20.png delete mode 100644 applications/external/heap_defence_game/assets_images/Person5_2_10x20.png delete mode 100644 applications/external/heap_defence_game/assets_images/Start_128x64.png delete mode 100644 applications/external/heap_defence_game/box.png delete mode 100644 applications/external/heap_defence_game/heap_defence.c delete mode 100644 applications/external/heap_defence_game/hede_assets.c delete mode 100644 applications/external/heap_defence_game/hede_assets.h delete mode 100644 applications/external/ir_scope/application.fam delete mode 100644 applications/external/ir_scope/ir_scope.c delete mode 100644 applications/external/ir_scope/ir_scope.png delete mode 100644 applications/external/mandelbrot/Mandelbrot.png delete mode 100644 applications/external/mandelbrot/application.fam delete mode 100644 applications/external/mandelbrot/mandelbrot.c delete mode 100644 applications/external/paint/application.fam delete mode 100644 applications/external/paint/paint.c delete mode 100644 applications/external/paint/paintIcon.png delete mode 100644 applications/external/spectrum_analyzer/application.fam delete mode 100644 applications/external/spectrum_analyzer/helpers/radio_device_loader.c delete mode 100644 applications/external/spectrum_analyzer/helpers/radio_device_loader.h delete mode 100644 applications/external/spectrum_analyzer/spectrum_10px.png delete mode 100644 applications/external/spectrum_analyzer/spectrum_analyzer.c delete mode 100644 applications/external/spectrum_analyzer/spectrum_analyzer.h delete mode 100644 applications/external/spectrum_analyzer/spectrum_analyzer_worker.c delete mode 100644 applications/external/spectrum_analyzer/spectrum_analyzer_worker.h delete mode 100644 applications/external/tanksgame/application.fam delete mode 100644 applications/external/tanksgame/constants.h delete mode 100644 applications/external/tanksgame/helpers/radio_device_loader.c delete mode 100644 applications/external/tanksgame/helpers/radio_device_loader.h delete mode 100644 applications/external/tanksgame/images/HappyFlipper_128x64.png delete mode 100644 applications/external/tanksgame/images/TanksSplashScreen_128x64.png delete mode 100644 applications/external/tanksgame/images/enemy_down.png delete mode 100644 applications/external/tanksgame/images/enemy_left.png delete mode 100644 applications/external/tanksgame/images/enemy_right.png delete mode 100644 applications/external/tanksgame/images/enemy_up.png delete mode 100644 applications/external/tanksgame/images/projectile_down.png delete mode 100644 applications/external/tanksgame/images/projectile_left.png delete mode 100644 applications/external/tanksgame/images/projectile_right.png delete mode 100644 applications/external/tanksgame/images/projectile_up.png delete mode 100644 applications/external/tanksgame/images/tank_base.png delete mode 100644 applications/external/tanksgame/images/tank_down.png delete mode 100644 applications/external/tanksgame/images/tank_explosion.png delete mode 100644 applications/external/tanksgame/images/tank_hedgehog.png delete mode 100644 applications/external/tanksgame/images/tank_left.png delete mode 100644 applications/external/tanksgame/images/tank_right.png delete mode 100644 applications/external/tanksgame/images/tank_stone.png delete mode 100644 applications/external/tanksgame/images/tank_up.png delete mode 100644 applications/external/tanksgame/images/tank_wall.png delete mode 100644 applications/external/tanksgame/tanksIcon.png delete mode 100644 applications/external/tanksgame/tanks_game.c delete mode 100644 applications/external/tetris_game/application.fam delete mode 100644 applications/external/tetris_game/tetris_10px.png delete mode 100644 applications/external/tetris_game/tetris_game.c delete mode 100644 applications/external/tictactoe_game/application.fam delete mode 100644 applications/external/tictactoe_game/tictactoe_10px.png delete mode 100644 applications/external/tictactoe_game/tictactoe_game.c delete mode 100644 applications/external/unitemp/LICENSE.md delete mode 100644 applications/external/unitemp/Sensors.c delete mode 100644 applications/external/unitemp/Sensors.h delete mode 100644 applications/external/unitemp/application.fam delete mode 100644 applications/external/unitemp/assets/co2_11x14.png delete mode 100644 applications/external/unitemp/assets/flipper_happy_2_60x38.png delete mode 100644 applications/external/unitemp/assets/flipper_happy_60x38.png delete mode 100644 applications/external/unitemp/assets/flipper_sad_60x38.png delete mode 100644 applications/external/unitemp/assets/heat_index_11x14.png delete mode 100644 applications/external/unitemp/assets/hum_9x15.png delete mode 100644 applications/external/unitemp/assets/in_hg_15x15.png delete mode 100644 applications/external/unitemp/assets/mm_hg_15x15.png delete mode 100644 applications/external/unitemp/assets/pressure_7x13.png delete mode 100644 applications/external/unitemp/assets/repo_qr_50x50.png delete mode 100644 applications/external/unitemp/assets/sherlok_53x45.png delete mode 100644 applications/external/unitemp/assets/temp_C_11x14.png delete mode 100644 applications/external/unitemp/assets/temp_F_11x14.png delete mode 100644 applications/external/unitemp/icon.png delete mode 100644 applications/external/unitemp/interfaces/I2CSensor.c delete mode 100644 applications/external/unitemp/interfaces/I2CSensor.h delete mode 100644 applications/external/unitemp/interfaces/OneWireSensor.c delete mode 100644 applications/external/unitemp/interfaces/OneWireSensor.h delete mode 100644 applications/external/unitemp/interfaces/SPISensor.c delete mode 100644 applications/external/unitemp/interfaces/SPISensor.h delete mode 100644 applications/external/unitemp/interfaces/SingleWireSensor.c delete mode 100644 applications/external/unitemp/interfaces/SingleWireSensor.h delete mode 100644 applications/external/unitemp/interfaces/endianness.h delete mode 100644 applications/external/unitemp/sensors/AM2320.c delete mode 100644 applications/external/unitemp/sensors/AM2320.h delete mode 100644 applications/external/unitemp/sensors/BME680.c delete mode 100644 applications/external/unitemp/sensors/BME680.h delete mode 100644 applications/external/unitemp/sensors/BMP180.c delete mode 100644 applications/external/unitemp/sensors/BMP180.h delete mode 100644 applications/external/unitemp/sensors/BMx280.c delete mode 100644 applications/external/unitemp/sensors/BMx280.h delete mode 100644 applications/external/unitemp/sensors/DHT20.c delete mode 100644 applications/external/unitemp/sensors/DHT20.h delete mode 100644 applications/external/unitemp/sensors/HDC1080.c delete mode 100644 applications/external/unitemp/sensors/HDC1080.h delete mode 100644 applications/external/unitemp/sensors/HTU21x.c delete mode 100644 applications/external/unitemp/sensors/HTU21x.h delete mode 100644 applications/external/unitemp/sensors/LM75.c delete mode 100644 applications/external/unitemp/sensors/LM75.h delete mode 100644 applications/external/unitemp/sensors/MAX31855.c delete mode 100644 applications/external/unitemp/sensors/MAX31855.h delete mode 100644 applications/external/unitemp/sensors/MAX6675.c delete mode 100644 applications/external/unitemp/sensors/MAX6675.h delete mode 100644 applications/external/unitemp/sensors/SCD30.c delete mode 100644 applications/external/unitemp/sensors/SCD30.h delete mode 100644 applications/external/unitemp/sensors/SCD40.c delete mode 100644 applications/external/unitemp/sensors/SCD40.h delete mode 100644 applications/external/unitemp/sensors/SHT30.c delete mode 100644 applications/external/unitemp/sensors/SHT30.h delete mode 100644 applications/external/unitemp/sensors/Sensors.xlsx delete mode 100644 applications/external/unitemp/unitemp.c delete mode 100644 applications/external/unitemp/unitemp.h delete mode 100644 applications/external/unitemp/views/General_view.c delete mode 100644 applications/external/unitemp/views/MainMenu_view.c delete mode 100644 applications/external/unitemp/views/Popup_view.c delete mode 100644 applications/external/unitemp/views/SensorActions_view.c delete mode 100644 applications/external/unitemp/views/SensorEdit_view.c delete mode 100644 applications/external/unitemp/views/SensorNameEdit_view.c delete mode 100644 applications/external/unitemp/views/SensorsList_view.c delete mode 100644 applications/external/unitemp/views/Settings_view.c delete mode 100644 applications/external/unitemp/views/UnitempViews.h delete mode 100644 applications/external/unitemp/views/Widgets_view.c delete mode 100644 applications/external/videopoker/application.fam delete mode 100644 applications/external/videopoker/poker.c delete mode 100644 applications/external/videopoker/pokerIcon.png delete mode 100644 applications/external/zombiez/application.fam delete mode 100644 applications/external/zombiez/zombie_10px.png delete mode 100644 applications/external/zombiez/zombiez.c delete mode 100644 applications/external/zombiez/zombiez.h diff --git a/applications/external/arkanoid/application.fam b/applications/external/arkanoid/application.fam deleted file mode 100644 index 19e851514..000000000 --- a/applications/external/arkanoid/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="arkanoid", - name="Arkanoid", - apptype=FlipperAppType.EXTERNAL, - entry_point="arkanoid_game_app", - requires=["gui"], - stack_size=1 * 1024, - fap_icon="arkanoid_10px.png", - fap_category="Games", - fap_author="@xMasterX & @gotnull", - fap_version="1.0", - fap_description="Arkanoid Game", -) diff --git a/applications/external/arkanoid/arkanoid_10px.png b/applications/external/arkanoid/arkanoid_10px.png deleted file mode 100644 index 344d2db737b25c786418f9432c86a207ee3db4e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1622 zcmcIlO>f*p7}=0deKf;k~nbzIG` zO|#v;tx`gXP8{7Jm{O0}p4C$81A(_Z8hQtvyR|QP^3k{~Gf&s2)2TLXX)+(_hU>aI zp*p1)5V$x=OE$x4abv~M5e3iVtc+!rSK6{ zjbh?r!|c#LK8RS!&IguJJUlrMGzh$IT9hp1qTBHih|=OX@+fWF z)MgB~Ovl1vXxcawG{i02X&a0?f`ojb3+y|RA64nA?3ZmDNe&!MhCIg{M#OeFZVz3K z4acN7q)vpH(c+ZYhG6zGN?`jikKxNQvX%6BPTKsWCS^HRox8i;CC-BpmZno_i -#include -#include -#include -#include -#include -#include -#include - -#define TAG "Arkanoid" - -#define FLIPPER_LCD_WIDTH 128 -#define FLIPPER_LCD_HEIGHT 64 -#define MAX_SPEED 3 - -typedef enum { EventTypeTick, EventTypeKey } EventType; - -typedef struct { - //Brick Bounds used in collision detection - int leftBrick; - int rightBrick; - int topBrick; - int bottomBrick; - bool isHit[4][13]; //Array of if bricks are hit or not -} BrickState; - -typedef struct { - int dx; //Initial movement of ball - int dy; //Initial movement of ball - int xb; //Balls starting possition - int yb; //Balls starting possition - bool released; //If the ball has been released by the player - //Ball Bounds used in collision detection - int leftBall; - int rightBall; - int topBall; - int bottomBall; -} BallState; - -typedef struct { - FuriMutex* mutex; - BallState ball_state; - BrickState brick_state; - NotificationApp* notify; - unsigned int COLUMNS; //Columns of bricks - unsigned int ROWS; //Rows of bricks - bool initialDraw; //If the inital draw has happened - int xPaddle; //X position of paddle - char text[16]; //General string buffer - bool bounced; //Used to fix double bounce glitch - int lives; //Amount of lives - int level; //Current level - unsigned int score; //Score for the game - unsigned int brickCount; //Amount of bricks hit - int tick; //Tick counter - bool gameStarted; // Did the game start? - int speed; // Ball speed -} ArkanoidState; - -typedef struct { - EventType type; - InputEvent input; -} GameEvent; - -static const NotificationSequence sequence_short_sound = { - &message_note_c5, - &message_delay_50, - &message_sound_off, - NULL, -}; - -// generate number in range [min,max) -int rand_range(int min, int max) { - return min + rand() % (max - min); -} - -void move_ball(Canvas* canvas, ArkanoidState* st) { - st->tick++; - - int current_speed = abs(st->speed - 1 - MAX_SPEED); - if(st->tick % current_speed != 0 && st->tick % (current_speed + 1) != 0) { - return; - } - - if(st->ball_state.released) { - //Move ball - if(abs(st->ball_state.dx) == 2) { - st->ball_state.xb += st->ball_state.dx / 2; - // 2x speed is really 1.5 speed - if((st->tick / current_speed) % 2 == 0) st->ball_state.xb += st->ball_state.dx / 2; - } else { - st->ball_state.xb += st->ball_state.dx; - } - st->ball_state.yb = st->ball_state.yb + st->ball_state.dy; - - //Set bounds - st->ball_state.leftBall = st->ball_state.xb; - st->ball_state.rightBall = st->ball_state.xb + 2; - st->ball_state.topBall = st->ball_state.yb; - st->ball_state.bottomBall = st->ball_state.yb + 2; - - //Bounce off top edge - if(st->ball_state.yb <= 0) { - st->ball_state.yb = 2; - st->ball_state.dy = -st->ball_state.dy; - } - - //Lose a life if bottom edge hit - if(st->ball_state.yb >= FLIPPER_LCD_HEIGHT) { - canvas_draw_frame(canvas, st->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1); - st->xPaddle = 54; - st->ball_state.yb = 60; - st->ball_state.released = false; - st->lives--; - st->gameStarted = false; - - if(rand_range(0, 2) == 0) { - st->ball_state.dx = 1; - } else { - st->ball_state.dx = -1; - } - } - - //Bounce off left side - if(st->ball_state.xb <= 0) { - st->ball_state.xb = 2; - st->ball_state.dx = -st->ball_state.dx; - } - - //Bounce off right side - if(st->ball_state.xb >= FLIPPER_LCD_WIDTH - 2) { - st->ball_state.xb = FLIPPER_LCD_WIDTH - 4; - st->ball_state.dx = -st->ball_state.dx; - // arduboy.tunes.tone(523, 250); - } - - //Bounce off paddle - if(st->ball_state.xb + 1 >= st->xPaddle && st->ball_state.xb <= st->xPaddle + 12 && - st->ball_state.yb + 2 >= FLIPPER_LCD_HEIGHT - 1 && - st->ball_state.yb <= FLIPPER_LCD_HEIGHT) { - st->ball_state.dy = -st->ball_state.dy; - st->ball_state.dx = - ((st->ball_state.xb - (st->xPaddle + 6)) / 3); //Applies spin on the ball - // prevent straight bounce, but not prevent roguuemaster from stealing - if(st->ball_state.dx == 0) { - st->ball_state.dx = (rand_range(0, 2) == 1) ? 1 : -1; - } - } - - //Bounce off Bricks - for(unsigned int row = 0; row < st->ROWS; row++) { - for(unsigned int column = 0; column < st->COLUMNS; column++) { - if(!st->brick_state.isHit[row][column]) { - //Sets Brick bounds - st->brick_state.leftBrick = 10 * column; - st->brick_state.rightBrick = 10 * column + 10; - st->brick_state.topBrick = 6 * row + 1; - st->brick_state.bottomBrick = 6 * row + 7; - - //If A collison has occured - if(st->ball_state.topBall <= st->brick_state.bottomBrick && - st->ball_state.bottomBall >= st->brick_state.topBrick && - st->ball_state.leftBall <= st->brick_state.rightBrick && - st->ball_state.rightBall >= st->brick_state.leftBrick) { - st->score += st->level; - // Blink led when we hit some brick - notification_message(st->notify, &sequence_short_sound); - //notification_message(st->notify, &sequence_blink_white_100); - - st->brickCount++; - st->brick_state.isHit[row][column] = true; - canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4); - - //Vertical collision - if(st->ball_state.bottomBall > st->brick_state.bottomBrick || - st->ball_state.topBall < st->brick_state.topBrick) { - //Only bounce once each ball move - if(!st->bounced) { - st->ball_state.dy = -st->ball_state.dy; - st->ball_state.yb += st->ball_state.dy; - st->bounced = true; - } - } - - //Hoizontal collision - if(st->ball_state.leftBall < st->brick_state.leftBrick || - st->ball_state.rightBall > st->brick_state.rightBrick) { - //Only bounce once brick each ball move - if(!st->bounced) { - st->ball_state.dx = -st->ball_state.dx; - st->ball_state.xb += st->ball_state.dx; - st->bounced = true; - } - } - } - } - } - } - - //Reset Bounce - st->bounced = false; - } else { - //Ball follows paddle - st->ball_state.xb = st->xPaddle + 5; - } -} - -void draw_lives(Canvas* canvas, ArkanoidState* arkanoid_state) { - if(arkanoid_state->lives == 3) { - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8); - - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12); - - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 15); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 15); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 16); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 16); - } else if(arkanoid_state->lives == 2) { - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8); - - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12); - } else { - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7); - canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8); - canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8); - } -} - -void draw_score(Canvas* canvas, ArkanoidState* arkanoid_state) { - snprintf(arkanoid_state->text, sizeof(arkanoid_state->text), "%u", arkanoid_state->score); - canvas_draw_str_aligned( - canvas, - FLIPPER_LCD_WIDTH - 2, - FLIPPER_LCD_HEIGHT - 6, - AlignRight, - AlignBottom, - arkanoid_state->text); -} - -void draw_ball(Canvas* canvas, ArkanoidState* ast) { - canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb); - canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb); - canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb + 1); - canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb + 1); - - move_ball(canvas, ast); -} - -void draw_paddle(Canvas* canvas, ArkanoidState* arkanoid_state) { - canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1); -} - -void reset_level(Canvas* canvas, ArkanoidState* arkanoid_state) { - //Undraw paddle - canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1); - - //Undraw ball - canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb); - canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb); - canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb + 1); - canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb + 1); - - //Alter various variables to reset the game - arkanoid_state->xPaddle = 54; - arkanoid_state->ball_state.yb = 60; - arkanoid_state->brickCount = 0; - arkanoid_state->ball_state.released = false; - arkanoid_state->gameStarted = false; - - // Reset all brick hit states - for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) { - for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) { - arkanoid_state->brick_state.isHit[row][column] = false; - } - } -} - -static void arkanoid_state_init(ArkanoidState* arkanoid_state) { - // Init notification - arkanoid_state->notify = furi_record_open(RECORD_NOTIFICATION); - - // Set the initial game state - arkanoid_state->COLUMNS = 13; - arkanoid_state->ROWS = 4; - arkanoid_state->ball_state.dx = -1; - arkanoid_state->ball_state.dy = -1; - arkanoid_state->speed = 2; - arkanoid_state->bounced = false; - arkanoid_state->lives = 3; - arkanoid_state->level = 1; - arkanoid_state->score = 0; - arkanoid_state->COLUMNS = 13; - arkanoid_state->COLUMNS = 13; - - // Reset initial state - arkanoid_state->initialDraw = false; - arkanoid_state->gameStarted = false; -} - -static void arkanoid_draw_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - ArkanoidState* arkanoid_state = ctx; - furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever); - - //Initial level draw - if(!arkanoid_state->initialDraw) { - arkanoid_state->initialDraw = true; - - // Set default font for text - canvas_set_font(canvas, FontSecondary); - - //Draws the new level - reset_level(canvas, arkanoid_state); - } - - //Draws new bricks and resets their values - for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) { - for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) { - if(!arkanoid_state->brick_state.isHit[row][column]) { - canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4); - } - } - } - - if(arkanoid_state->lives > 0) { - draw_paddle(canvas, arkanoid_state); - draw_ball(canvas, arkanoid_state); - draw_score(canvas, arkanoid_state); - draw_lives(canvas, arkanoid_state); - - if(arkanoid_state->brickCount == arkanoid_state->ROWS * arkanoid_state->COLUMNS) { - arkanoid_state->level++; - reset_level(canvas, arkanoid_state); - } - } else { - reset_level(canvas, arkanoid_state); - arkanoid_state->initialDraw = false; - arkanoid_state->lives = 3; - arkanoid_state->score = 0; - } - - furi_mutex_release(arkanoid_state->mutex); -} - -static void arkanoid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void arkanoid_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -int32_t arkanoid_game_app(void* p) { - UNUSED(p); - int32_t return_code = 0; - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); - - ArkanoidState* arkanoid_state = malloc(sizeof(ArkanoidState)); - arkanoid_state_init(arkanoid_state); - - arkanoid_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!arkanoid_state->mutex) { - FURI_LOG_E(TAG, "Cannot create mutex\r\n"); - return_code = 255; - goto free_and_exit; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, arkanoid_draw_callback, arkanoid_state); - view_port_input_callback_set(view_port, arkanoid_input_callback, event_queue); - - FuriTimer* timer = - furi_timer_alloc(arkanoid_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 22); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - GameEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // Key events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress || event.input.type == InputTypeLong || - event.input.type == InputTypeRepeat) { - switch(event.input.key) { - case InputKeyBack: - processing = false; - break; - case InputKeyRight: - if(arkanoid_state->xPaddle < FLIPPER_LCD_WIDTH - 12) { - arkanoid_state->xPaddle += 8; - } - break; - case InputKeyLeft: - if(arkanoid_state->xPaddle > 0) { - arkanoid_state->xPaddle -= 8; - } - break; - case InputKeyUp: - if(arkanoid_state->speed < MAX_SPEED) { - arkanoid_state->speed++; - } - break; - case InputKeyDown: - if(arkanoid_state->speed > 1) { - arkanoid_state->speed--; - } - break; - case InputKeyOk: - if(arkanoid_state->gameStarted == false) { - //Release ball if FIRE pressed - arkanoid_state->ball_state.released = true; - - //Apply random direction to ball on release - if(rand_range(0, 2) == 0) { - arkanoid_state->ball_state.dx = 1; - } else { - arkanoid_state->ball_state.dx = -1; - } - - //Makes sure the ball heads upwards - arkanoid_state->ball_state.dy = -1; - //start the game flag - arkanoid_state->gameStarted = true; - } - break; - default: - break; - } - } - } - } - - view_port_update(view_port); - furi_mutex_release(arkanoid_state->mutex); - } - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); - view_port_free(view_port); - furi_mutex_free(arkanoid_state->mutex); - -free_and_exit: - free(arkanoid_state); - furi_message_queue_free(event_queue); - - return return_code; -} diff --git a/applications/external/calculator/application.fam b/applications/external/calculator/application.fam deleted file mode 100644 index cfd183ec3..000000000 --- a/applications/external/calculator/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="calculator", - name="Calculator", - apptype=FlipperAppType.EXTERNAL, - entry_point="calculator_app", - cdefines=["APP_CALCULATOR"], - requires=["gui"], - stack_size=1 * 1024, - fap_icon="calcIcon.png", - fap_category="Tools", - fap_author="@n-o-T-I-n-s-a-n-e", - fap_weburl="https://github.com/n-o-T-I-n-s-a-n-e", - fap_version="1.0", - fap_description="Calculator, that can calculate simple expressions", -) diff --git a/applications/external/calculator/calcIcon.png b/applications/external/calculator/calcIcon.png deleted file mode 100644 index 05cda6ce675061565bcc15d251f85a8d599b76af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2002 zcmcIlPiP}m7@x8#YnQYKFU1NwOfM_?=3g>@O}3;>-4=Fg=>}R4tG=1{CK;NUH_l9( zwBVuMytwxkJlK{}g~b+6{-J{CUPL|UT|q1AVg(Ns6zZEyl8sQiy%JD# zf5S(qT%5aEojN@|Jvlj{($Ue;;o;%v=;-nB@xj5t@bK`?&d%Q6UM`p0*x1MFMw0>KEnPDFL%BwCWi`GrkAwCZg zu`%EBLuyUqj<-VSEa8N;am@=#-0_Ep9P6PHx1d;}6;9&1H@z0&TWhmbXKl$b5I253 zH&|?$6v4*{WLthCh|N}sYXh6~Jyi=F+crs-N?bXO$SzuQ>?DaWtMM{$L{VflgO_Yo zftv9wD~qx$h^ipvfuxxQ)szZs=flx>EL)6_YtC1m@5G~0iK{0`XbM8J+2osfoK1c%$Ok0UA>5@WtlTUoWQ`r zGnEoYlj1!OnW9}#= z(d(wEO0q54vJG@q#X!+0ny$DCkY&ThiUesewTt#bIzz_4`}sII6RswN=`$sGG2?j&iD$Rdb#H_x%iF9dYM-jJ0u7IC^U;J(x&|fAN#~Cd*HL?CH1=X8WU$RTrl9BW zA~TDLn>1mB%QZTLhx1OjKp`<)IlqjH@#Ft2Bg1y;FsNaA($Wp=FRUn}XHx&vio)3g zEAW@BH=WrvCBiZ7`~?e^eN_uit*_i8udvyZG8YHq)$ diff --git a/applications/external/calculator/calculator.c b/applications/external/calculator/calculator.c deleted file mode 100644 index cc12cb7d1..000000000 --- a/applications/external/calculator/calculator.c +++ /dev/null @@ -1,458 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include // Header-file for boolean data-type. -#include // Header-file for string functions. -#include "tinyexpr.h" // Header-file for the TinyExpr library. - -#include -#include - -const short MAX_TEXT_LENGTH = 20; - -typedef struct { - short x; - short y; -} selectedPosition; - -typedef struct { - FuriMutex* mutex; - selectedPosition position; - //string with the inputted calculator text - char text[20]; - short textLength; - char log[20]; -} Calculator; - -char getKeyAtPosition(short x, short y) { - if(x == 0 && y == 0) { - return 'C'; - } - if(x == 1 && y == 0) { - return '<'; - } - if(x == 2 && y == 0) { - return '%'; - } - if(x == 3 && y == 0) { - return '/'; - } - if(x == 0 && y == 1) { - return '1'; - } - if(x == 1 && y == 1) { - return '2'; - } - if(x == 2 && y == 1) { - return '3'; - } - if(x == 3 && y == 1) { - return '*'; - } - if(x == 0 && y == 2) { - return '4'; - } - if(x == 1 && y == 2) { - return '5'; - } - if(x == 2 && y == 2) { - return '6'; - } - if(x == 3 && y == 2) { - return '-'; - } - if(x == 0 && y == 3) { - return '7'; - } - if(x == 1 && y == 3) { - return '8'; - } - if(x == 2 && y == 3) { - return '9'; - } - if(x == 3 && y == 3) { - return '+'; - } - if(x == 0 && y == 4) { - return '('; - } - if(x == 1 && y == 4) { - return '0'; - } - if(x == 2 && y == 4) { - return '.'; - } - if(x == 3 && y == 4) { - return '='; - } - return ' '; -} - -short calculateStringWidth(const char* str, short lenght) { - /* widths: - 1 = 2 - 2, 3, 4, 5, 6, 7, 8, 9, 0, X, -, +, . = = 5 - %, / = 7 - S = 5 - (, ) = 3 - - */ - short width = 0; - for(short i = 0; i < lenght; i++) { - switch(str[i]) { - case '1': - width += 2; - break; - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '0': - case '*': - case '-': - case '+': - case '.': - width += 5; - break; - case '%': - case '/': - width += 7; - break; - case 'S': - width += 5; - break; - case '(': - case ')': - width += 3; - break; - default: - break; - } - width += 1; - } - - return width; -} - -void generate_calculator_layout(Canvas* canvas) { - //draw dotted lines - for(int i = 0; i <= 64; i++) { - if(i % 2 == 0) { - canvas_draw_dot(canvas, i, 14); - canvas_draw_dot(canvas, i, 33); - } - if(i % 2 == 1) { - canvas_draw_dot(canvas, i, 15); - canvas_draw_dot(canvas, i, 34); - } - } - - //draw horizontal lines - canvas_draw_box(canvas, 0, 41, 64, 2); - canvas_draw_box(canvas, 0, 57, 64, 2); - canvas_draw_box(canvas, 0, 73, 64, 2); - canvas_draw_box(canvas, 0, 89, 64, 2); - canvas_draw_box(canvas, 0, 105, 64, 2); - canvas_draw_box(canvas, 0, 121, 64, 2); - - //draw vertical lines - canvas_draw_box(canvas, 0, 43, 1, 80); - canvas_draw_box(canvas, 15, 43, 2, 80); - canvas_draw_box(canvas, 31, 43, 2, 80); - canvas_draw_box(canvas, 47, 43, 2, 80); - canvas_draw_box(canvas, 63, 43, 1, 80); - - //draw buttons - //row 1 (C, ;, %, ÷) - canvas_draw_str(canvas, 5, 54, "C"); - canvas_draw_str(canvas, 19, 54, " <-"); - canvas_draw_str(canvas, 35, 54, " %"); - canvas_draw_str(canvas, 51, 54, " /"); - - //row 2 (1, 2, 3, X) - canvas_draw_str(canvas, 5, 70, " 1"); - canvas_draw_str(canvas, 19, 70, " 2"); - canvas_draw_str(canvas, 35, 70, " 3"); - canvas_draw_str(canvas, 51, 70, " X"); - - //row 3 (4, 5, 6, -) - canvas_draw_str(canvas, 5, 86, " 4"); - canvas_draw_str(canvas, 19, 86, " 5"); - canvas_draw_str(canvas, 35, 86, " 6"); - canvas_draw_str(canvas, 51, 86, " -"); - - //row 4 (7, 8, 9, +) - canvas_draw_str(canvas, 5, 102, " 7"); - canvas_draw_str(canvas, 19, 102, " 8"); - canvas_draw_str(canvas, 35, 102, " 9"); - canvas_draw_str(canvas, 51, 102, " +"); - - //row 5 (+/-, 0, ., =) - canvas_draw_str(canvas, 3, 118, "( )"); - canvas_draw_str(canvas, 19, 118, " 0"); - canvas_draw_str(canvas, 35, 118, " ."); - canvas_draw_str(canvas, 51, 118, " ="); -} - -void calculator_draw_callback(Canvas* canvas, void* ctx) { - furi_assert(ctx); - const Calculator* calculator_state = ctx; - furi_mutex_acquire(calculator_state->mutex, FuriWaitForever); - - canvas_clear(canvas); - - //show selected button - short startX = 1; - short startY = 43; - - canvas_set_color(canvas, ColorBlack); - canvas_draw_box( - canvas, - startX + (calculator_state->position.x) * 16, - (startY) + (calculator_state->position.y) * 16, - 16, - 16); - canvas_set_color(canvas, ColorWhite); - canvas_draw_box( - canvas, - startX + (calculator_state->position.x) * 16 + 2, - (startY) + (calculator_state->position.y) * 16 + 2, - 10, - 10); - - canvas_set_color(canvas, ColorBlack); - generate_calculator_layout(canvas); - - //draw text - short stringWidth = calculateStringWidth(calculator_state->text, calculator_state->textLength); - short startingPosition = 5; - if(stringWidth > 60) { - startingPosition += 60 - (stringWidth + 5); - } - canvas_set_color(canvas, ColorBlack); - canvas_draw_str(canvas, startingPosition, 28, calculator_state->text); - //canvas_draw_str(canvas, 10, 10, calculator_state->log); - - //draw cursor - canvas_draw_box(canvas, stringWidth + 5, 29, 5, 1); - - furi_mutex_release(calculator_state->mutex); -} - -void calculator_input_callback(InputEvent* input_event, void* ctx) { - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - furi_message_queue_put(event_queue, input_event, FuriWaitForever); -} - -void calculate(Calculator* calculator_state) { - double result; - result = te_interp(calculator_state->text, 0); - - calculator_state->textLength = 0; - calculator_state->text[0] = '\0'; - // sprintf(calculator_state->text, "%f", result); - - //invert sign if negative - if(result < 0) { - calculator_state->text[calculator_state->textLength++] = '-'; - result = -result; - } - - //get numbers before and after decimal - int beforeDecimal = result; - int afterDecimal = (result - beforeDecimal) * 100; - - char beforeDecimalString[10]; - char afterDecimalString[10]; - int i = 0; - //parse to a string - while(beforeDecimal > 0) { - beforeDecimalString[i++] = beforeDecimal % 10 + '0'; - beforeDecimal /= 10; - } - // invert string - for(int j = 0; j < i / 2; j++) { - char temp = beforeDecimalString[j]; - beforeDecimalString[j] = beforeDecimalString[i - j - 1]; - beforeDecimalString[i - j - 1] = temp; - } - //add it to the answer - for(int j = 0; j < i; j++) { - calculator_state->text[calculator_state->textLength++] = beforeDecimalString[j]; - } - - i = 0; - if(afterDecimal > 0) { - while(afterDecimal > 0) { - afterDecimalString[i++] = afterDecimal % 10 + '0'; - afterDecimal /= 10; - } - // invert string - for(int j = 0; j < i / 2; j++) { - char temp = afterDecimalString[j]; - afterDecimalString[j] = afterDecimalString[i - j - 1]; - afterDecimalString[i - j - 1] = temp; - } - - //add decimal point - calculator_state->text[calculator_state->textLength++] = '.'; - - //add numbers after decimal - for(int j = 0; j < i; j++) { - calculator_state->text[calculator_state->textLength++] = afterDecimalString[j]; - } - } - calculator_state->text[calculator_state->textLength] = '\0'; -} - -int32_t calculator_app(void* p) { - UNUSED(p); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - - Calculator* calculator_state = malloc(sizeof(Calculator)); - calculator_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!calculator_state->mutex) { - //FURI_LOG_E("calculator", "cannot create mutex\r\n"); - free(calculator_state); - return -1; - } - - // Configure view port - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, calculator_draw_callback, calculator_state); - view_port_input_callback_set(view_port, calculator_input_callback, event_queue); - view_port_set_orientation(view_port, ViewPortOrientationVertical); - - // Register view port in GUI - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - //NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - - InputEvent event; - - while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { - //break out of the loop if the back key is pressed - if(event.type == InputTypeShort && event.key == InputKeyBack) { - break; - } - - if(event.type == InputTypeShort) { - switch(event.key) { - case InputKeyUp: - if(calculator_state->position.y > 0) { - calculator_state->position.y--; - } - break; - case InputKeyDown: - if(calculator_state->position.y < 4) { - calculator_state->position.y++; - } - break; - case InputKeyLeft: - if(calculator_state->position.x > 0) { - calculator_state->position.x--; - } - break; - case InputKeyRight: - if(calculator_state->position.x < 3) { - calculator_state->position.x++; - } - break; - case InputKeyOk: { - //add the selected button to the text - //char* text = calculator_state->text; - // short* textLength = &calculator_state->textLength; - - char key = - getKeyAtPosition(calculator_state->position.x, calculator_state->position.y); - - switch(key) { - case 'C': - while(calculator_state->textLength > 0) { - calculator_state->text[calculator_state->textLength--] = '\0'; - } - calculator_state->text[0] = '\0'; - calculator_state->log[2] = key; - break; - case '<': - calculator_state->log[2] = key; - if(calculator_state->textLength > 0) { - calculator_state->text[--calculator_state->textLength] = '\0'; - } else { - calculator_state->text[0] = '\0'; - } - break; - case '=': - calculator_state->log[2] = key; - calculate(calculator_state); - break; - case '%': - case '/': - case '*': - case '-': - case '+': - case '.': - case '(': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '0': - if(calculator_state->textLength < MAX_TEXT_LENGTH) { - calculator_state->text[calculator_state->textLength++] = key; - calculator_state->text[calculator_state->textLength] = '\0'; - } - //calculator_state->log[1] = calculator_state->text[*textLength]; - break; - default: - break; - } - } - default: - break; - } - - view_port_update(view_port); - } - - if(event.type == InputTypeLong) { - switch(event.key) { - case InputKeyOk: - if(calculator_state->position.x == 0 && calculator_state->position.y == 4) { - if(calculator_state->textLength < MAX_TEXT_LENGTH) { - calculator_state->text[calculator_state->textLength++] = ')'; - calculator_state->text[calculator_state->textLength] = '\0'; - } - view_port_update(view_port); - } - break; - default: - break; - } - } - } - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_mutex_free(calculator_state->mutex); - furi_message_queue_free(event_queue); - - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_GUI); - free(calculator_state); - - return 0; -} diff --git a/applications/external/calculator/tinyexpr.c b/applications/external/calculator/tinyexpr.c deleted file mode 100644 index cfd4cb8ab..000000000 --- a/applications/external/calculator/tinyexpr.c +++ /dev/null @@ -1,786 +0,0 @@ -// SPDX-License-Identifier: Zlib -/* - * TINYEXPR - Tiny recursive descent parser and evaluation engine in C - * - * Copyright (c) 2015-2020 Lewis Van Winkle - * - * http://CodePlea.com - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgement in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -/* COMPILE TIME OPTIONS */ - -/* Exponentiation associativity: -For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing. -For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/ -/* #define TE_POW_FROM_RIGHT */ - -/* Logarithms -For log = base 10 log do nothing -For log = natural log uncomment the next line. */ -/* #define TE_NAT_LOG */ - -#include "tinyexpr.h" -#include -#include -#include -#include -#include -#include - -#ifndef NAN -#define NAN (0.0 / 0.0) -#endif - -#ifndef INFINITY -#define INFINITY (1.0 / 0.0) -#endif - -typedef double (*te_fun2)(double, double); - -enum { - TOK_NULL = TE_CLOSURE7 + 1, - TOK_ERROR, - TOK_END, - TOK_SEP, - TOK_OPEN, - TOK_CLOSE, - TOK_NUMBER, - TOK_VARIABLE, - TOK_INFIX -}; - -enum { TE_CONSTANT = 1 }; - -typedef struct state { - const char* start; - const char* next; - int type; - union { - double value; - const double* bound; - const void* function; - }; - void* context; - - const te_variable* lookup; - int lookup_len; -} state; - -#define TYPE_MASK(TYPE) ((TYPE)&0x0000001F) - -#define IS_PURE(TYPE) (((TYPE)&TE_FLAG_PURE) != 0) -#define IS_FUNCTION(TYPE) (((TYPE)&TE_FUNCTION0) != 0) -#define IS_CLOSURE(TYPE) (((TYPE)&TE_CLOSURE0) != 0) -#define ARITY(TYPE) (((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE)&0x00000007) : 0) -#define NEW_EXPR(type, ...) new_expr((type), (const te_expr*[]){__VA_ARGS__}) - -static te_expr* new_expr(const int type, const te_expr* parameters[]) { - const int arity = ARITY(type); - const int psize = sizeof(void*) * arity; - const int size = - (sizeof(te_expr) - sizeof(void*)) + psize + (IS_CLOSURE(type) ? sizeof(void*) : 0); - te_expr* ret = malloc(size); - memset(ret, 0, size); - if(arity && parameters) { - memcpy(ret->parameters, parameters, psize); - } - ret->type = type; - ret->bound = 0; - return ret; -} - -void te_free_parameters(te_expr* n) { - if(!n) return; - switch(TYPE_MASK(n->type)) { - case TE_FUNCTION7: - case TE_CLOSURE7: - te_free(n->parameters[6]); /* Falls through. */ - case TE_FUNCTION6: - case TE_CLOSURE6: - te_free(n->parameters[5]); /* Falls through. */ - case TE_FUNCTION5: - case TE_CLOSURE5: - te_free(n->parameters[4]); /* Falls through. */ - case TE_FUNCTION4: - case TE_CLOSURE4: - te_free(n->parameters[3]); /* Falls through. */ - case TE_FUNCTION3: - case TE_CLOSURE3: - te_free(n->parameters[2]); /* Falls through. */ - case TE_FUNCTION2: - case TE_CLOSURE2: - te_free(n->parameters[1]); /* Falls through. */ - case TE_FUNCTION1: - case TE_CLOSURE1: - te_free(n->parameters[0]); - } -} - -void te_free(te_expr* n) { - if(!n) return; - te_free_parameters(n); - free(n); -} - -static double pi(void) { - return 3.14159265358979323846; -} -static double e(void) { - return 2.71828182845904523536; -} -static double fac(double a) { /* simplest version of fac */ - if(a < (double)0.0) return NAN; - if(a > UINT_MAX) return INFINITY; - unsigned int ua = (unsigned int)(a); - unsigned long int result = 1, i; - for(i = 1; i <= ua; i++) { - if(i > ULONG_MAX / result) return INFINITY; - result *= i; - } - return (double)result; -} -static double ncr(double n, double r) { - if(n < (double)0.0 || r < (double)0.0 || n < r) return NAN; - if(n > UINT_MAX || r > UINT_MAX) return INFINITY; - unsigned long int un = (unsigned int)(n), ur = (unsigned int)(r), i; - unsigned long int result = 1; - if(ur > un / 2) ur = un - ur; - for(i = 1; i <= ur; i++) { - if(result > ULONG_MAX / (un - ur + i)) return INFINITY; - result *= un - ur + i; - result /= i; - } - return result; -} -static double npr(double n, double r) { - return ncr(n, r) * fac(r); -} - -#ifdef _MSC_VER -#pragma function(ceil) -#pragma function(floor) -#endif - -static const te_variable functions[] = { - /* must be in alphabetical order */ - {"abs", fabs, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"acos", acos, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"asin", asin, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"atan", atan, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"atan2", atan2, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"ceil", ceil, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"cos", cos, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"cosh", cosh, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"e", e, TE_FUNCTION0 | TE_FLAG_PURE, 0}, - {"exp", exp, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"fac", fac, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"floor", floor, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"ln", log, TE_FUNCTION1 | TE_FLAG_PURE, 0}, -#ifdef TE_NAT_LOG - {"log", log, TE_FUNCTION1 | TE_FLAG_PURE, 0}, -#else - {"log", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0}, -#endif - {"log10", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"ncr", ncr, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"npr", npr, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"pi", pi, TE_FUNCTION0 | TE_FLAG_PURE, 0}, - {"pow", pow, TE_FUNCTION2 | TE_FLAG_PURE, 0}, - {"sin", sin, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"sinh", sinh, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"sqrt", sqrt, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"tan", tan, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {"tanh", tanh, TE_FUNCTION1 | TE_FLAG_PURE, 0}, - {0, 0, 0, 0}}; - -static const te_variable* find_builtin(const char* name, int len) { - int imin = 0; - int imax = sizeof(functions) / sizeof(te_variable) - 2; - - /*Binary search.*/ - while(imax >= imin) { - const int i = (imin + ((imax - imin) / 2)); - int c = strncmp(name, functions[i].name, len); - if(!c) c = '\0' - functions[i].name[len]; - if(c == 0) { - return functions + i; - } else if(c > 0) { - imin = i + 1; - } else { - imax = i - 1; - } - } - - return 0; -} - -static const te_variable* find_lookup(const state* s, const char* name, int len) { - int iters; - const te_variable* var; - if(!s->lookup) return 0; - - for(var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) { - if(strncmp(name, var->name, len) == 0 && var->name[len] == '\0') { - return var; - } - } - return 0; -} - -static double add(double a, double b) { - return a + b; -} -static double sub(double a, double b) { - return a - b; -} -static double mul(double a, double b) { - return a * b; -} -static double divide(double a, double b) { - return a / b; -} -static double negate(double a) { - return -a; -} -static double comma(double a, double b) { - (void)a; - return b; -} - -void next_token(state* s) { - s->type = TOK_NULL; - - do { - if(!*s->next) { - s->type = TOK_END; - return; - } - - /* Try reading a number. */ - if((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') { - s->value = strtof(s->next, (char**)&s->next); - s->type = TOK_NUMBER; - } else { - /* Look for a variable or builtin function call. */ - if(isalpha((int)s->next[0])) { - const char* start; - start = s->next; - while(isalpha((int)s->next[0]) || isdigit((int)s->next[0]) || (s->next[0] == '_')) - s->next++; - - const te_variable* var = find_lookup(s, start, s->next - start); - if(!var) var = find_builtin(start, s->next - start); - - if(!var) { - s->type = TOK_ERROR; - } else { - switch(TYPE_MASK(var->type)) { - case TE_VARIABLE: - s->type = TOK_VARIABLE; - s->bound = var->address; - break; - - case TE_CLOSURE0: - case TE_CLOSURE1: - case TE_CLOSURE2: - case TE_CLOSURE3: /* Falls through. */ - case TE_CLOSURE4: - case TE_CLOSURE5: - case TE_CLOSURE6: - case TE_CLOSURE7: /* Falls through. */ - s->context = var->context; /* Falls through. */ - - case TE_FUNCTION0: - case TE_FUNCTION1: - case TE_FUNCTION2: - case TE_FUNCTION3: /* Falls through. */ - case TE_FUNCTION4: - case TE_FUNCTION5: - case TE_FUNCTION6: - case TE_FUNCTION7: /* Falls through. */ - s->type = var->type; - s->function = var->address; - break; - } - } - - } else { - /* Look for an operator or special character. */ - switch(s->next++[0]) { - case '+': - s->type = TOK_INFIX; - s->function = add; - break; - case '-': - s->type = TOK_INFIX; - s->function = sub; - break; - case '*': - s->type = TOK_INFIX; - s->function = mul; - break; - case '/': - s->type = TOK_INFIX; - s->function = divide; - break; - case '^': - s->type = TOK_INFIX; - s->function = pow; - break; - case '%': - s->type = TOK_INFIX; - s->function = fmod; - break; - case '(': - s->type = TOK_OPEN; - break; - case ')': - s->type = TOK_CLOSE; - break; - case ',': - s->type = TOK_SEP; - break; - case ' ': - case '\t': - case '\n': - case '\r': - break; - default: - s->type = TOK_ERROR; - break; - } - } - } - } while(s->type == TOK_NULL); -} - -static te_expr* list(state* s); -static te_expr* expr(state* s); -static te_expr* power(state* s); - -static te_expr* base(state* s) { - /* = | | {"(" ")"} | | "(" {"," } ")" | "(" ")" */ - te_expr* ret; - int arity; - - switch(TYPE_MASK(s->type)) { - case TOK_NUMBER: - ret = new_expr(TE_CONSTANT, 0); - ret->value = s->value; - next_token(s); - break; - - case TOK_VARIABLE: - ret = new_expr(TE_VARIABLE, 0); - ret->bound = s->bound; - next_token(s); - break; - - case TE_FUNCTION0: - case TE_CLOSURE0: - ret = new_expr(s->type, 0); - ret->function = s->function; - if(IS_CLOSURE(s->type)) ret->parameters[0] = s->context; - next_token(s); - if(s->type == TOK_OPEN) { - next_token(s); - if(s->type != TOK_CLOSE) { - s->type = TOK_ERROR; - } else { - next_token(s); - } - } - break; - - case TE_FUNCTION1: - case TE_CLOSURE1: - ret = new_expr(s->type, 0); - ret->function = s->function; - if(IS_CLOSURE(s->type)) ret->parameters[1] = s->context; - next_token(s); - ret->parameters[0] = power(s); - break; - - case TE_FUNCTION2: - case TE_FUNCTION3: - case TE_FUNCTION4: - case TE_FUNCTION5: - case TE_FUNCTION6: - case TE_FUNCTION7: - case TE_CLOSURE2: - case TE_CLOSURE3: - case TE_CLOSURE4: - case TE_CLOSURE5: - case TE_CLOSURE6: - case TE_CLOSURE7: - arity = ARITY(s->type); - - ret = new_expr(s->type, 0); - ret->function = s->function; - if(IS_CLOSURE(s->type)) ret->parameters[arity] = s->context; - next_token(s); - - if(s->type != TOK_OPEN) { - s->type = TOK_ERROR; - } else { - int i; - for(i = 0; i < arity; i++) { - next_token(s); - ret->parameters[i] = expr(s); - if(s->type != TOK_SEP) { - break; - } - } - if(s->type != TOK_CLOSE || i != arity - 1) { - s->type = TOK_ERROR; - } else { - next_token(s); - } - } - - break; - - case TOK_OPEN: - next_token(s); - ret = list(s); - if(s->type != TOK_CLOSE) { - s->type = TOK_ERROR; - } else { - next_token(s); - } - break; - - default: - ret = new_expr(0, 0); - s->type = TOK_ERROR; - ret->value = NAN; - break; - } - - return ret; -} - -static te_expr* power(state* s) { - /* = {("-" | "+")} */ - int sign = 1; - while(s->type == TOK_INFIX && (s->function == add || s->function == sub)) { - if(s->function == sub) sign = -sign; - next_token(s); - } - - te_expr* ret; - - if(sign == 1) { - ret = base(s); - } else { - ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, base(s)); - ret->function = negate; - } - - return ret; -} - -#ifdef TE_POW_FROM_RIGHT -static te_expr* factor(state* s) { - /* = {"^" } */ - te_expr* ret = power(s); - - int neg = 0; - - if(ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) { - te_expr* se = ret->parameters[0]; - free(ret); - ret = se; - neg = 1; - } - - te_expr* insertion = 0; - - while(s->type == TOK_INFIX && (s->function == pow)) { - te_fun2 t = s->function; - next_token(s); - - if(insertion) { - /* Make exponentiation go right-to-left. */ - te_expr* insert = - NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], power(s)); - insert->function = t; - insertion->parameters[1] = insert; - insertion = insert; - } else { - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s)); - ret->function = t; - insertion = ret; - } - } - - if(neg) { - ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret); - ret->function = negate; - } - - return ret; -} -#else -static te_expr* factor(state* s) { - /* = {"^" } */ - te_expr* ret = power(s); - - while(s->type == TOK_INFIX && (s->function == pow)) { - te_fun2 t = s->function; - next_token(s); - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, power(s)); - ret->function = t; - } - - return ret; -} -#endif - -static te_expr* term(state* s) { - /* = {("*" | "/" | "%") } */ - te_expr* ret = factor(s); - - while(s->type == TOK_INFIX && - (s->function == mul || s->function == divide || s->function == fmod)) { - te_fun2 t = s->function; - next_token(s); - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, factor(s)); - ret->function = t; - } - - return ret; -} - -static te_expr* expr(state* s) { - /* = {("+" | "-") } */ - te_expr* ret = term(s); - - while(s->type == TOK_INFIX && (s->function == add || s->function == sub)) { - te_fun2 t = s->function; - next_token(s); - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, term(s)); - ret->function = t; - } - - return ret; -} - -static te_expr* list(state* s) { - /* = {"," } */ - te_expr* ret = expr(s); - - while(s->type == TOK_SEP) { - next_token(s); - ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, expr(s)); - ret->function = comma; - } - - return ret; -} - -#define TE_FUN(...) ((double (*)(__VA_ARGS__))n->function) -#define M(e) te_eval(n->parameters[e]) - -double te_eval(const te_expr* n) { - if(!n) return NAN; - - switch(TYPE_MASK(n->type)) { - case TE_CONSTANT: - return n->value; - case TE_VARIABLE: - return *n->bound; - - case TE_FUNCTION0: - case TE_FUNCTION1: - case TE_FUNCTION2: - case TE_FUNCTION3: - case TE_FUNCTION4: - case TE_FUNCTION5: - case TE_FUNCTION6: - case TE_FUNCTION7: - switch(ARITY(n->type)) { - case 0: - return TE_FUN(void)(); - case 1: - return TE_FUN(double)(M(0)); - case 2: - return TE_FUN(double, double)(M(0), M(1)); - case 3: - return TE_FUN(double, double, double)(M(0), M(1), M(2)); - case 4: - return TE_FUN(double, double, double, double)(M(0), M(1), M(2), M(3)); - case 5: - return TE_FUN(double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4)); - case 6: - return TE_FUN(double, double, double, double, double, double)( - M(0), M(1), M(2), M(3), M(4), M(5)); - case 7: - return TE_FUN(double, double, double, double, double, double, double)( - M(0), M(1), M(2), M(3), M(4), M(5), M(6)); - default: - return NAN; - } - - case TE_CLOSURE0: - case TE_CLOSURE1: - case TE_CLOSURE2: - case TE_CLOSURE3: - case TE_CLOSURE4: - case TE_CLOSURE5: - case TE_CLOSURE6: - case TE_CLOSURE7: - switch(ARITY(n->type)) { - case 0: - return TE_FUN(void*)(n->parameters[0]); - case 1: - return TE_FUN(void*, double)(n->parameters[1], M(0)); - case 2: - return TE_FUN(void*, double, double)(n->parameters[2], M(0), M(1)); - case 3: - return TE_FUN(void*, double, double, double)(n->parameters[3], M(0), M(1), M(2)); - case 4: - return TE_FUN(void*, double, double, double, double)( - n->parameters[4], M(0), M(1), M(2), M(3)); - case 5: - return TE_FUN(void*, double, double, double, double, double)( - n->parameters[5], M(0), M(1), M(2), M(3), M(4)); - case 6: - return TE_FUN(void*, double, double, double, double, double, double)( - n->parameters[6], M(0), M(1), M(2), M(3), M(4), M(5)); - case 7: - return TE_FUN(void*, double, double, double, double, double, double, double)( - n->parameters[7], M(0), M(1), M(2), M(3), M(4), M(5), M(6)); - default: - return NAN; - } - - default: - return NAN; - } -} - -#undef TE_FUN -#undef M - -static void optimize(te_expr* n) { - /* Evaluates as much as possible. */ - if(n->type == TE_CONSTANT) return; - if(n->type == TE_VARIABLE) return; - - /* Only optimize out functions flagged as pure. */ - if(IS_PURE(n->type)) { - const int arity = ARITY(n->type); - int known = 1; - int i; - for(i = 0; i < arity; ++i) { - optimize(n->parameters[i]); - if(((te_expr*)(n->parameters[i]))->type != TE_CONSTANT) { - known = 0; - } - } - if(known) { - const double value = te_eval(n); - te_free_parameters(n); - n->type = TE_CONSTANT; - n->value = value; - } - } -} - -te_expr* - te_compile(const char* expression, const te_variable* variables, int var_count, int* error) { - state s; - s.start = s.next = expression; - s.lookup = variables; - s.lookup_len = var_count; - - next_token(&s); - te_expr* root = list(&s); - - if(s.type != TOK_END) { - te_free(root); - if(error) { - *error = (s.next - s.start); - if(*error == 0) *error = 1; - } - return 0; - } else { - optimize(root); - if(error) *error = 0; - return root; - } -} - -double te_interp(const char* expression, int* error) { - te_expr* n = te_compile(expression, 0, 0, error); - double ret; - if(n) { - ret = te_eval(n); - te_free(n); - } else { - ret = NAN; - } - return ret; -} - -static void pn(const te_expr* n, int depth) { - int i, arity; - printf("%*s", depth, ""); - - switch(TYPE_MASK(n->type)) { - case TE_CONSTANT: - printf("%f\n", n->value); - break; - case TE_VARIABLE: - printf("bound %p\n", n->bound); - break; - - case TE_FUNCTION0: - case TE_FUNCTION1: - case TE_FUNCTION2: - case TE_FUNCTION3: - case TE_FUNCTION4: - case TE_FUNCTION5: - case TE_FUNCTION6: - case TE_FUNCTION7: - case TE_CLOSURE0: - case TE_CLOSURE1: - case TE_CLOSURE2: - case TE_CLOSURE3: - case TE_CLOSURE4: - case TE_CLOSURE5: - case TE_CLOSURE6: - case TE_CLOSURE7: - arity = ARITY(n->type); - printf("f%d", arity); - for(i = 0; i < arity; i++) { - printf(" %p", n->parameters[i]); - } - printf("\n"); - for(i = 0; i < arity; i++) { - pn(n->parameters[i], depth + 1); - } - break; - } -} - -void te_print(const te_expr* n) { - pn(n, 0); -} diff --git a/applications/external/calculator/tinyexpr.h b/applications/external/calculator/tinyexpr.h deleted file mode 100644 index 3833965a1..000000000 --- a/applications/external/calculator/tinyexpr.h +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: Zlib -/* - * TINYEXPR - Tiny recursive descent parser and evaluation engine in C - * - * Copyright (c) 2015-2020 Lewis Van Winkle - * - * http://CodePlea.com - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgement in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - */ - -#ifndef TINYEXPR_H -#define TINYEXPR_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct te_expr { - int type; - union { - double value; - const double* bound; - const void* function; - }; - void* parameters[1]; -} te_expr; - -enum { - TE_VARIABLE = 0, - - TE_FUNCTION0 = 8, - TE_FUNCTION1, - TE_FUNCTION2, - TE_FUNCTION3, - TE_FUNCTION4, - TE_FUNCTION5, - TE_FUNCTION6, - TE_FUNCTION7, - - TE_CLOSURE0 = 16, - TE_CLOSURE1, - TE_CLOSURE2, - TE_CLOSURE3, - TE_CLOSURE4, - TE_CLOSURE5, - TE_CLOSURE6, - TE_CLOSURE7, - - TE_FLAG_PURE = 32 -}; - -typedef struct te_variable { - const char* name; - const void* address; - int type; - void* context; -} te_variable; - -/* Parses the input expression, evaluates it, and frees it. */ -/* Returns NaN on error. */ -double te_interp(const char* expression, int* error); - -/* Parses the input expression and binds variables. */ -/* Returns NULL on error. */ -te_expr* - te_compile(const char* expression, const te_variable* variables, int var_count, int* error); - -/* Evaluates the expression. */ -double te_eval(const te_expr* n); - -/* Prints debugging information on the syntax tree. */ -void te_print(const te_expr* n); - -/* Frees the expression. */ -/* This is safe to call on NULL pointers. */ -void te_free(te_expr* n); - -#ifdef __cplusplus -} -#endif - -#endif /*TINYEXPR_H*/ diff --git a/applications/external/doom/application.fam b/applications/external/doom/application.fam deleted file mode 100644 index 995286d74..000000000 --- a/applications/external/doom/application.fam +++ /dev/null @@ -1,17 +0,0 @@ -App( - appid="doom", - name="DOOM", - apptype=FlipperAppType.EXTERNAL, - entry_point="doom_app", - requires=[ - "gui", - "music_player", - ], - stack_size=4 * 1024, - fap_icon="doom_10px.png", - fap_category="Games", - fap_icon_assets="assets", - fap_author="@xMasterX & @Svarich & @hedger (original code by @p4nic4ttack)", - fap_version="1.0", - fap_description="Will it run Doom?", -) diff --git a/applications/external/doom/assets.c b/applications/external/doom/assets.c deleted file mode 100644 index 864588581..000000000 --- a/applications/external/doom/assets.c +++ /dev/null @@ -1,331 +0,0 @@ -#include "assets.h" - -const uint8_t space[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t zero[] = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60}; -const uint8_t one[] = {0x00, 0x20, 0x20, 0x20, 0x20, 0x70}; -const uint8_t two[] = {0x00, 0x60, 0x90, 0x20, 0x40, 0xf0}; -const uint8_t three[] = {0x00, 0x60, 0x90, 0x20, 0x90, 0x60}; -const uint8_t four[] = {0x00, 0x90, 0x90, 0xf0, 0x10, 0x10}; -const uint8_t five[] = {0x00, 0xf0, 0x80, 0xe0, 0x10, 0xe0}; -const uint8_t six[] = {0x00, 0x60, 0x80, 0xe0, 0x90, 0x60}; -const uint8_t seven[] = {0x00, 0xf0, 0x10, 0x10, 0x10, 0x10}; -const uint8_t eight[] = {0x00, 0x60, 0x90, 0x60, 0x90, 0x60}; -const uint8_t nine[] = {0x00, 0x60, 0x90, 0x70, 0x10, 0x60}; -const uint8_t A[] = {0x00, 0x60, 0x90, 0xf0, 0x90, 0x90}; -const uint8_t B[] = {0x00, 0xe0, 0x90, 0xe0, 0x90, 0xe0}; -const uint8_t C[] = {0x00, 0x60, 0x90, 0x80, 0x90, 0x60}; -const uint8_t D[] = {0x00, 0xe0, 0x90, 0x90, 0x90, 0xe0}; -const uint8_t E[] = {0x00, 0xf0, 0x80, 0xe0, 0x80, 0xf0}; -const uint8_t F[] = {0x00, 0xf0, 0x80, 0xe0, 0x80, 0x80}; -const uint8_t G[] = {0x00, 0x60, 0x80, 0x80, 0x90, 0x60}; -const uint8_t H[] = {0x00, 0x90, 0x90, 0xf0, 0x90, 0x90}; -const uint8_t I[] = {0x00, 0x20, 0x20, 0x20, 0x20, 0x20}; -const uint8_t J[] = {0x00, 0x10, 0x10, 0x10, 0x90, 0x60}; -const uint8_t K[] = {0x00, 0x90, 0xa0, 0xc0, 0xa0, 0x90}; -const uint8_t L[] = {0x00, 0x80, 0x80, 0x80, 0x80, 0xf0}; -const uint8_t M[] = {0x00, 0x90, 0xf0, 0x90, 0x90, 0x90}; -const uint8_t N[] = {0x00, 0x90, 0xd0, 0xb0, 0x90, 0x90}; -const uint8_t O[] = {0x00, 0x60, 0x90, 0x90, 0x90, 0x60}; -const uint8_t P[] = {0x00, 0xe0, 0x90, 0xe0, 0x80, 0x80}; -const uint8_t Q[] = {0x00, 0x60, 0x90, 0x90, 0xb0, 0x70}; -const uint8_t R[] = {0x00, 0xe0, 0x90, 0xe0, 0x90, 0x90}; -const uint8_t S[] = {0x00, 0x60, 0x80, 0x60, 0x10, 0xe0}; -const uint8_t T[] = {0x00, 0xe0, 0x40, 0x40, 0x40, 0x40}; -const uint8_t U[] = {0x00, 0x90, 0x90, 0x90, 0x90, 0x60}; -const uint8_t V[] = {0x00, 0x90, 0x90, 0x90, 0x60, 0x60}; -const uint8_t W[] = {0x00, 0x90, 0x90, 0x90, 0xf0, 0x90}; -const uint8_t X[] = {0x00, 0x90, 0x90, 0x60, 0x90, 0x90}; -const uint8_t Y[] = {0x00, 0x90, 0x90, 0x60, 0x60, 0x60}; -const uint8_t Z[] = {0x00, 0xf0, 0x10, 0x60, 0x80, 0xf0}; -const uint8_t dot[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x40}; -const uint8_t comma[] = {0x00, 0x00, 0x00, 0x00, 0x20, 0x40}; -const uint8_t dash[] = {0x00, 0x00, 0x00, 0x60, 0x00, 0x00}; -const uint8_t underscore[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0xf0}; -const uint8_t bracket_open[] = {0x00, 0x20, 0x40, 0x40, 0x40, 0x20}; -const uint8_t bracket_close[] = {0x00, 0x40, 0x20, 0x20, 0x20, 0x40}; -const uint8_t cross_left[] = {0x10, 0x10, 0x70, 0x70, 0x10, 0x10}; -const uint8_t cross_right[] = {0x80, 0x80, 0xe0, 0xe0, 0x80, 0x80}; -const uint8_t pacman_left[] = {0x00, 0x30, 0x50, 0x70, 0x70, 0x00}; -const uint8_t pacman_right[] = {0x00, 0xc0, 0x60, 0xe0, 0xe0, 0xe0}; -const uint8_t box[] = {0x00, 0xf0, 0xf0, 0xf0, 0xf0, 0x00}; -const uint8_t* char_arr[48] = { - space, - zero, - one, - two, - three, - four, - five, - six, - seven, - eight, - nine, - A, - B, - C, - D, - E, - F, - G, - H, - I, - J, - K, - L, - M, - N, - O, - P, - Q, - R, - S, - T, - U, - V, - W, - X, - Y, - Z, - dot, - comma, - dash, - underscore, - bracket_open, - bracket_close, - cross_left, - cross_right, - pacman_left, - pacman_right, - box}; -const uint8_t gradient[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, 0x22, 0x22, - 0x00, 0x00, 0x8a, 0x8a, 0x00, 0x00, 0x22, 0x22, 0x00, 0x00, 0xaa, 0xaa, - 0x10, 0x10, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0x01, 0x01, 0xaa, 0xaa, - 0x44, 0x44, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x44, 0x44, 0xaa, 0xaa, - 0x15, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xbb, 0xbb, - 0x55, 0x55, 0xaa, 0xea, 0x55, 0x55, 0xbb, 0xbb, 0x55, 0x55, 0xff, 0xff, - 0x55, 0x55, 0xfb, 0xfb, 0x55, 0x55, 0xff, 0xff, 0x55, 0x55, 0xbb, 0xbf, - 0x57, 0x57, 0xff, 0xff, 0xdd, 0xdd, 0xff, 0xff, 0x77, 0x75, 0xff, 0xff, - 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -//const uint8_t gun[] = {0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0x27, 0xff, 0xff, 0xfe, 0x3b, 0xff, 0xff, 0xfd, 0xfb, 0xff, 0xff, 0xfd, 0xfd, 0xff, 0xff, 0xfd, 0x15, 0xff, 0xff, 0xfb, 0x2e, 0xff, 0xff, 0xf6, 0x77, 0x7f, 0xff, 0xe6, 0xff, 0xff, 0xff, 0xf2, 0x3d, 0x7f, 0xff, 0xd6, 0x7e, 0x3f, 0xff, 0xf4, 0x5d, 0xdf, 0xff, 0xce, 0xbf, 0xbf, 0xff, 0xdc, 0xff, 0x3f, 0xff, 0xec, 0xff, 0xbf, 0xff, 0x8d, 0xfd, 0xff, 0xff, 0xb6, 0xff, 0xbf, 0xfe, 0x1f, 0x57, 0xdf, 0xf8, 0x0e, 0xff, 0xcf, 0xf4, 0x46, 0x1f, 0x17, 0xf8, 0xa3, 0xfc, 0x03, 0xf8, 0x10, 0x00, 0x11, 0xf8, 0x8a, 0x80, 0x2d, 0xe4, 0x44, 0x00, 0x4d, 0xee, 0xa8, 0x82, 0x9b, 0xcd, 0x50, 0x00, 0x17, 0xec, 0xa0, 0x8a, 0x2f, 0xcc, 0x00, 0x04, 0x67, 0xe8, 0x28, 0x1a, 0xff, 0xe4, 0x70, 0x4d, 0xcf, 0xfc, 0x82, 0xa7, 0xef, 0x90, 0x40, 0x13, 0xdf}; -// const uint8_t gun_mask[] = {0xff, 0xff, 0x8f, 0xff, 0xff, 0xfe, 0x03, 0xff, 0xff, 0xfc, 0x01, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x0f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x3f, 0xff, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, 0x0f, 0xf0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x80, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f}; -const uint8_t gun[] = {0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, 0x01, 0xc4, 0x00, - 0x00, 0x02, 0x04, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x02, 0xea, 0x00, - 0x00, 0x04, 0xd1, 0x00, 0x00, 0x09, 0x88, 0x80, 0x00, 0x19, 0x00, 0x00, - 0x00, 0x0d, 0xc2, 0x80, 0x00, 0x29, 0x81, 0xc0, 0x00, 0x0b, 0xa2, 0x20, - 0x00, 0x31, 0x40, 0x40, 0x00, 0x23, 0x00, 0xc0, 0x00, 0x13, 0x00, 0x40, - 0x00, 0x72, 0x02, 0x00, 0x00, 0x49, 0x00, 0x40, 0x01, 0xe0, 0xa8, 0x20, - 0x07, 0xf1, 0x00, 0x30, 0x0b, 0xb9, 0xe0, 0xe8, 0x07, 0x5c, 0x03, 0xfc, - 0x07, 0xef, 0xff, 0xee, 0x07, 0x75, 0x7f, 0xd2, 0x1b, 0xbb, 0xff, 0xb2, - 0x11, 0x57, 0x7d, 0x64, 0x32, 0xaf, 0xff, 0xe8, 0x13, 0x5f, 0x75, 0xd0, - 0x33, 0xff, 0xfb, 0x98, 0x17, 0xd7, 0xe5, 0x00, 0x1b, 0x8f, 0xb2, 0x30, - 0x03, 0x7d, 0x58, 0x10, 0x6f, 0xbf, 0xec, 0x20}; -const uint8_t gun_mask[] = {0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0xfc, 0x00, 0x00, 0x03, 0xfe, 0x00, - 0x00, 0x07, 0xfe, 0x00, 0x00, 0x07, 0xff, 0x00, 0x00, 0x07, 0xff, 0x00, - 0x00, 0x0f, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0x80, - 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xf0, - 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xe0, 0x00, 0x7f, 0xff, 0xe0, - 0x00, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xf0, - 0x0f, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xfe, - 0x1f, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, - 0x3f, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8, - 0x7f, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xf8, - 0x7f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xf0}; - -const uint8_t - imp_inv[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, - 0x02, 0x80, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x01, 0x0f, 0xb3, 0x00, 0x00, 0xd0, 0x4e, 0x00, 0x00, 0x79, 0x8c, - 0x00, 0x00, 0x1c, 0x19, 0x00, 0x01, 0x8a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x40, 0x02, 0x08, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x8e, - 0x30, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x20, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02, 0x40, 0x00, 0x00, 0x03, 0xe0, - 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0xa1, 0x80, 0x01, 0x80, 0x13, 0x00, - 0x00, 0xf3, 0x8a, 0x00, 0x00, 0x09, 0x94, 0x00, 0x00, 0x88, 0x38, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x23, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x80, - 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x04, 0x30, 0x00, 0x00, 0x02, 0x20, 0x00, - 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x02, 0x20, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, - 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, - 0x00, 0x1f, 0x00, 0x00, 0x02, 0x2a, 0x80, 0x00, 0x01, 0x05, 0x00, 0x00, 0x01, - 0xae, 0x20, 0x00, 0x01, 0x24, 0x40, 0x00, 0x02, 0xac, 0x80, 0x00, 0x02, 0x86, - 0x00, 0x00, 0x03, 0x20, 0x20, 0x00, 0x04, 0x30, 0x40, 0x00, 0x0c, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x08, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x1a, 0x00, 0x00, 0x00, - 0x1c, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x98, - 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0a, 0x00, - 0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x80, 0x00, 0x01, 0xd6, 0x80, 0x00, - 0x02, 0xbf, 0x80, 0x00, 0x06, 0x61, 0xa0, 0x00, 0x0c, 0xe8, 0x80, 0x00, 0x0c, - 0x10, 0x00, 0x00, 0x1a, 0x22, 0x00, 0x00, 0x12, 0x40, 0x00, 0x00, 0x06, 0x0c, - 0x00, 0x00, 0x04, 0x0d, 0x00, 0x00, 0x3a, 0x03, 0x00, 0x00, 0x10, 0x02, 0x00, - 0x00, 0x60, 0x0a, 0x00, 0x00, 0x50, 0x04, 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, - 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x01, - 0x18, 0x00, 0x00, 0x01, 0x41, 0x40, 0x02, 0x33, 0xb6, 0x80, 0x01, 0x9c, 0x04, - 0x00, 0x08, 0xfa, 0x02, 0x08, 0x05, 0x00, 0x01, 0x0c, 0x27, 0x83, 0xa2, 0x2a, - 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00}; //{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x07, 0x40, 0x00, 0x00, 0x02, 0x80, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0f, 0xb3, 0x00, 0x00, 0xd0, 0x4e, 0x00, 0x00, 0x79, 0x8c, 0x00, 0x00, 0x1c, 0x19, 0x00, 0x01, 0x8a, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x02, 0x08, 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0x01, 0x8e, 0x30, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t imp_mask_inv[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, - 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x01, 0x07, 0xf1, 0x80, - 0x00, 0xdf, 0xfe, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x01, 0xff, 0xff, 0x80, - 0x00, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x80, 0x03, 0xcf, 0xf1, 0xc0, 0x01, 0xc7, 0xf1, 0xc0, - 0x01, 0x87, 0xf1, 0xc0, 0x03, 0x0f, 0xf9, 0x80, 0x03, 0x0f, 0xfb, 0x80, 0x01, 0x8f, 0xff, 0x80, - 0x03, 0x9f, 0x79, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x0f, 0x78, 0x00, - 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x30, 0x00, - 0x00, 0x03, 0x78, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xe0, 0x00, - 0x00, 0x07, 0xc0, 0x00, 0x01, 0x07, 0xe1, 0x00, 0x00, 0x8f, 0xfa, 0x00, 0x00, 0xff, 0xfe, 0x00, - 0x00, 0x3f, 0xfe, 0x00, 0x01, 0x7f, 0xff, 0x80, 0x00, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0x80, - 0x03, 0xcf, 0xfb, 0xc0, 0x03, 0x87, 0xf1, 0xc0, 0x03, 0xcf, 0xf3, 0xc0, 0x01, 0xcf, 0xf1, 0x80, - 0x00, 0xcf, 0xf1, 0x00, 0x00, 0x0f, 0xfb, 0x80, 0x00, 0x1e, 0x78, 0x00, 0x00, 0x0e, 0x78, 0x00, - 0x00, 0x1e, 0x78, 0x00, 0x00, 0x0f, 0x70, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x07, 0x70, 0x00, - 0x00, 0x07, 0x70, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x03, 0x30, 0x00, 0x00, 0x03, 0x20, 0x00, - 0x00, 0x07, 0x30, 0x00, 0x00, 0x05, 0x70, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1f, 0x00, - 0x00, 0x00, 0x1f, 0x00, 0x00, 0x03, 0x3f, 0x80, 0x00, 0x01, 0x3f, 0x00, 0x00, 0x01, 0xff, 0x30, - 0x00, 0x03, 0xff, 0xc0, 0x00, 0x03, 0xff, 0xc0, 0x00, 0x03, 0xff, 0x80, 0x00, 0x07, 0xff, 0xe0, - 0x00, 0x07, 0xff, 0xc0, 0x00, 0x05, 0xff, 0xe0, 0x00, 0x00, 0xfc, 0xe0, 0x00, 0x01, 0xfc, 0xe0, - 0x00, 0x01, 0xfc, 0x70, 0x00, 0x03, 0xfc, 0x38, 0x00, 0x03, 0xfe, 0x70, 0x00, 0x07, 0xfc, 0x00, - 0x00, 0x07, 0x9e, 0x00, 0x00, 0x0f, 0xbc, 0x00, 0x00, 0x0f, 0x3e, 0x00, 0x00, 0x07, 0x9c, 0x00, - 0x00, 0x03, 0x9c, 0x00, 0x00, 0x03, 0xb8, 0x00, 0x00, 0x03, 0x98, 0x00, 0x00, 0x01, 0x98, 0x00, - 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x1f, 0x00, - 0x00, 0x00, 0x1f, 0x40, 0x00, 0x00, 0x3e, 0x80, 0x00, 0x01, 0xff, 0x80, 0x00, 0x03, 0xff, 0x80, - 0x00, 0x07, 0xff, 0xe0, 0x00, 0x0e, 0xff, 0xc0, 0x00, 0x0c, 0xff, 0x80, 0x00, 0x1f, 0xfe, 0x00, - 0x00, 0x13, 0xfc, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x1f, 0xff, 0x00, 0x00, 0x3f, 0x9f, 0x00, - 0x00, 0x3e, 0x0f, 0x00, 0x00, 0x7c, 0x0f, 0x00, 0x00, 0x78, 0x0f, 0x00, 0x00, 0x78, 0x07, 0x80, - 0x00, 0x78, 0x07, 0x40, 0x00, 0x38, 0x07, 0x80, 0x00, 0x30, 0x07, 0x00, 0x00, 0x30, 0x01, 0x00, - 0x01, 0xf0, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1c, 0x00, - 0x00, 0x01, 0x3e, 0x00, 0x00, 0x03, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xe0, 0x01, 0x3f, 0xff, 0xc0, - 0x01, 0xff, 0xff, 0xc0, 0x19, 0xff, 0xff, 0xe8, 0x7f, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xfe, - 0x1f, 0xc2, 0x07, 0xe0, 0x1f, 0x00, 0x01, 0xe0, 0x0e, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, -}; //{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x03, 0xc0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x07, 0xe0, 0x00, 0x00, 0x03, 0xe0, 0x00, 0x01, 0x07, 0xf1, 0x80, 0x00, 0xdf, 0xfe, 0x00, 0x00, 0x3f, 0xfe, 0x00, 0x00, 0x7f, 0xff, 0x00, 0x01, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0x80, 0x03, 0xcf, 0xf1, 0xc0, 0x01, 0xc7, 0xf1, 0xc0, 0x01, 0x87, 0xf1, 0xc0, 0x03, 0x0f, 0xf9, 0x80, 0x03, 0x0f, 0xfb, 0x80, 0x01, 0x8f, 0xff, 0x80, 0x03, 0x9f, 0x79, 0x00, 0x00, 0x1f, 0x7c, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x0f, 0x78, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x03, 0x78, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}; -const uint8_t fireball[] = {0x00, 0x00, 0x01, 0x40, 0x0a, 0xb0, 0x0e, 0xd0, 0x00, 0x68, 0x53, - 0xb4, 0x0f, 0x48, 0x27, 0x78, 0x17, 0xa8, 0x27, 0xf0, 0x21, 0xd6, - 0x02, 0xf8, 0x20, 0x48, 0x06, 0x20, 0x01, 0x00, 0x00, 0x00}; -const uint8_t fireball_mask[] = {0x1f, 0x40, 0x0f, 0xf0, 0x3f, 0xf8, 0x1f, 0xfc, 0x7f, 0xfd, 0x7f, - 0xfc, 0x7f, 0xfd, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0xff, 0xfe, 0x3f, 0xfe, 0x17, 0xf8, 0x07, 0xf4, 0x01, 0xe0}; -const uint8_t item[] = {0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0x77, 0xee, 0x3f, - 0xfc, 0x5f, 0xfa, 0x2f, 0xf6, 0x53, 0xcc, 0x3e, 0x7e, 0x5e, 0x7c, - 0x38, 0x1e, 0x58, 0x1c, 0x3e, 0x7e, 0x5e, 0x7e, 0x2e, 0xfc, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, - 0x17, 0xfc, 0x22, 0x6c, 0x36, 0x44, 0x3f, 0xfc, 0x1f, 0xfc, 0x2b, - 0xfc, 0x05, 0x54, 0x02, 0xa8, 0x00, 0x00, 0x00, 0x00}; -const uint8_t item_mask[] = {0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, - 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, - 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x3f, 0xfc, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xfc, - 0x1f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc, 0x3f, - 0xfc, 0x07, 0xfc, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x00}; - -//const uint8_t door[] = {0xff, 0xff, 0xff, 0xff,0xb2, 0xbd, 0xcd, 0x5b,0x9a, 0xf4, 0x6d, 0x71,0xff, 0xff, 0xff, 0xff,0x00, 0x00, 0x00, 0x00,0xbf, 0xff, 0xff, 0xfd,0x3f, 0x00, 0xfe, 0xfc,0x3e, 0x00, 0xc6, 0xfc,0xbc, 0xaa, 0xfe, 0xbd,0x39, 0x54, 0xc6, 0xbc,0x32, 0x8e, 0xfe, 0xac,0xb5, 0xfe, 0xc6, 0xad,0x3f, 0xe0, 0xfe, 0xac,0x31, 0xe0, 0xc6, 0xac,0xb3, 0xf4, 0xfe, 0xad,0x3f, 0xe8, 0xc6, 0xac,0x3c, 0xf4, 0xd6, 0xac,0xb8, 0xff, 0xfe, 0xad,0x34, 0xc7, 0xfe, 0xfc,0x38, 0xd6, 0x0e, 0x0c,0xb0, 0xd6, 0x4e, 0x0d,0x3f, 0xd6, 0xaf, 0x5c,0x30, 0x47, 0xff, 0xac,0xb7, 0x57, 0xff, 0xfd,0x3f, 0xc6, 0x0e, 0x0c,0x35, 0x56, 0x40, 0x4c,0xb5, 0x46, 0xaa, 0xad,0x35, 0x56, 0x55, 0x4c,0xff, 0xff, 0xff, 0xff,0xb0, 0x1f, 0xf8, 0x0d,0xd9, 0x30, 0x0c, 0x9b,0xff, 0xe0, 0x07, 0xff}; -const uint8_t door[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0xe1, 0x8c, 0x00, 0x04, - 0x00, 0x7c, 0x03, 0x18, 0x60, 0x08, 0x00, 0x3e, 0x0f, 0xf7, 0xdf, 0x00, 0x1f, 0x00, 0xfe, 0x0f, - 0xbe, 0xf8, 0x3e, 0x00, 0x3f, 0x1f, 0xff, 0xdf, 0x00, 0x1f, 0x81, 0xff, 0x0f, 0xff, 0xf8, 0x7e, - 0x00, 0x3f, 0x8f, 0xff, 0xdf, 0x00, 0xff, 0xf9, 0xff, 0x1f, 0xff, 0xf8, 0xff, 0x80, 0x3f, 0xc7, - 0xff, 0xcc, 0x07, 0xff, 0xfc, 0xff, 0x1f, 0xff, 0xe3, 0xff, 0x80, 0x3f, 0xc7, 0xff, 0xc0, 0x07, - 0xff, 0xfc, 0x7f, 0x0f, 0xfe, 0x03, 0xff, 0xc0, 0x3f, 0xc3, 0xf7, 0xc0, 0x07, 0xdf, 0xf8, 0x3e, - 0x0f, 0xbe, 0x01, 0xff, 0x80, 0x1f, 0x80, 0xe3, 0x80, 0x07, 0x8f, 0xf8, 0x1e, 0x07, 0x1c, 0x01, - 0xff, 0x80, 0x3f, 0xc1, 0xff, 0xc0, 0x0f, 0xff, 0xfc, 0x3f, 0x0f, 0xbe, 0x03, 0xff, 0xc0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0x80, 0x00, - 0x7f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xe0, 0x00, 0x1f, 0xf0, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, - 0xc0, 0x00, 0x00, 0xe0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x01, - 0xe0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x01, 0xf0, 0x00, 0x0f, - 0xf0, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0x81, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, - 0x07, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x0f, 0xff, 0xff, - 0xff, 0xe1, 0xff, 0xe1, 0xf0, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0xff, - 0xc1, 0xf3, 0x00, 0x0f, 0xf0, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0xff, 0x81, 0xff, 0xc0, - 0x0f, 0xf0, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0x01, 0xff, 0xc0, 0x0f, 0xf0, 0xff, - 0x00, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xe0, 0x0f, 0xf0, 0xff, 0x01, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xe0, 0x0f, 0xf0, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xe1, - 0xff, 0xe1, 0xff, 0xe0, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xc1, 0xff, - 0xf0, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x8f, 0xe0, 0xff, 0x81, 0xff, 0xff, 0x0f, 0xf0, - 0xff, 0x1f, 0xff, 0xff, 0xfe, 0x07, 0xe0, 0x7f, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, - 0xff, 0xfc, 0x07, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0x8f, 0xfc, 0x03, - 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0x07, 0xfc, 0x07, 0xe0, 0xff, 0xc1, - 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xfe, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, - 0xf0, 0xff, 0x0f, 0x9c, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, - 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xfc, 0x00, 0x7f, - 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, - 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xfc, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, - 0x8f, 0xf0, 0xff, 0x1f, 0xfe, 0x00, 0x7f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, - 0x1f, 0xfc, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xfc, 0x00, - 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xf0, 0x00, 0x1f, 0xff, 0xe0, - 0x7f, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xf0, 0x00, 0x1f, 0xff, 0xe0, 0xff, 0x81, 0xff, - 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xe0, 0x00, 0x3f, 0xff, 0xe0, 0xff, 0xc1, 0xff, 0xff, 0x8f, 0xf0, - 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x1f, - 0x80, 0x3f, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x3f, 0xc0, 0x1f, 0xff, - 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0x7f, 0xc0, 0x0f, 0xff, 0xe1, 0xff, 0xe1, - 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x00, 0xff, 0xc0, 0x07, 0xff, 0xe1, 0xff, 0xe1, 0xff, 0xff, 0x8f, - 0xf0, 0xff, 0x01, 0xff, 0xc0, 0x03, 0x8f, 0xc0, 0xc1, 0x81, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x03, - 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0xff, 0xc0, 0xff, - 0x80, 0x00, 0x00, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc1, 0xff, 0x80, 0x00, 0x00, - 0x01, 0xf3, 0x8e, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xff, 0x9c, - 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc0, 0xff, 0xfc, 0x01, 0xff, 0xfe, 0x0f, 0xf0, 0xff, - 0x0f, 0xff, 0xc3, 0xff, 0xc1, 0xff, 0xfe, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xc3, - 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, - 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, - 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x8f, 0xf0, - 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x0f, 0xff, - 0xc3, 0xff, 0xc3, 0xff, 0xff, 0x00, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x0f, 0xff, 0xc3, 0xff, 0xc3, - 0xff, 0xff, 0x00, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xe3, 0xff, 0xc3, 0xff, 0xff, 0x00, - 0x3f, 0xfe, 0x0f, 0xf0, 0xff, 0x07, 0xff, 0xf3, 0xff, 0xc1, 0xef, 0xfe, 0x00, 0x3f, 0xfe, 0x0f, - 0xf0, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x82, 0x00, 0x00, 0x1f, 0xff, 0x0f, 0xf0, 0xff, 0x1f, - 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, - 0xc0, 0x00, 0x00, 0x00, 0x07, 0xff, 0x0f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, - 0x00, 0x03, 0x8e, 0x0f, 0xf0, 0xff, 0x1f, 0xc1, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x03, 0x88, - 0x0f, 0xf0, 0xff, 0x0f, 0x80, 0xff, 0xff, 0xc1, 0xff, 0xfc, 0x00, 0xff, 0xfe, 0x0f, 0xf0, 0xff, - 0x06, 0x00, 0x73, 0xff, 0xc3, 0xff, 0xfe, 0x01, 0xff, 0xff, 0x0f, 0xf0, 0xff, 0x00, 0x00, 0x03, - 0xff, 0xc3, 0xff, 0xff, 0x83, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x07, 0x0c, 0x73, 0xff, 0xc3, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x0f, 0xfe, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, - 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, - 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, - 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x8f, 0xf0, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8f, - 0xf0, 0xfe, 0x1f, 0xff, 0xff, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x87, 0xf0, 0xfe, 0x1f, - 0xfe, 0xfb, 0xff, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xf0, 0xfc, 0x0f, 0x9e, 0x73, 0xff, - 0x81, 0xf9, 0xf7, 0xe7, 0x9c, 0xff, 0x03, 0xf0, 0xfc, 0x07, 0xfe, 0xfb, 0xc0, 0x00, 0xf0, 0x00, - 0x6f, 0xbe, 0xfe, 0x03, 0xf0, 0x3c, 0x07, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xfe, - 0x03, 0xc0, 0x1c, 0x0f, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x03, 0x80, 0x1e, - 0x0f, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x07, 0x80, 0x3f, 0x0f, 0xff, 0xff, - 0xe0, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0x0f, 0xc0, 0x1f, 0x8f, 0xff, 0xff, 0xe7, 0xff, 0xff, - 0xfe, 0x7f, 0xff, 0xff, 0x1f, 0x80, 0x1f, 0xc7, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0x3f, 0x80, 0x07, 0xc3, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xfc, 0x3e, 0x00, - 0x07, 0xc1, 0xfe, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xcf, 0xf7, 0xf8, 0x3e, 0x00, 0x01, 0x00, 0xfc, - 0x7e, 0x7f, 0xff, 0xff, 0xff, 0xe7, 0xe3, 0xf0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, - 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, - 0x00, 0x00, 0x00, 0x00}; \ No newline at end of file diff --git a/applications/external/doom/assets.h b/applications/external/doom/assets.h deleted file mode 100644 index 546d7607d..000000000 --- a/applications/external/doom/assets.h +++ /dev/null @@ -1,108 +0,0 @@ -#pragma once -#include - -#ifndef _sprites_h -#define _sprites_h - -#define bmp_font_width 24 // in bytes -#define bmp_font_height 6 -#define bmp_font_width_pxs 192 -#define bmp_font_height_pxs 48 -#define CHAR_MAP " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.,-_(){}[]#" -#define CHAR_WIDTH 4 -#define CHAR_HEIGHT 6 - -#define BMP_GUN_WIDTH 32 -#define BMP_GUN_HEIGHT 32 - -#define BMP_FIRE_WIDTH 24 -#define BMP_FIRE_HEIGHT 20 - -#define BMP_IMP_WIDTH 32 -#define BMP_IMP_HEIGHT 32 -#define BMP_IMP_COUNT 5 - -#define BMP_FIREBALL_WIDTH 16 -#define BMP_FIREBALL_HEIGHT 16 - -#define BMP_DOOR_WIDTH 100 -#define BMP_DOOR_HEIGHT 100 - -#define BMP_ITEMS_WIDTH 16 -#define BMP_ITEMS_HEIGHT 16 -#define BMP_ITEMS_COUNT 2 - -#define BMP_LOGO_WIDTH 128 -#define BMP_LOGO_HEIGHT 64 - -#define GRADIENT_WIDTH 2 -#define GRADIENT_HEIGHT 8 -#define GRADIENT_COUNT 8 -#define GRADIENT_WHITE 7 -#define GRADIENT_BLACK 0 - -// Fonts -extern const uint8_t zero[]; -extern const uint8_t one[]; -extern const uint8_t two[]; -extern const uint8_t three[]; -extern const uint8_t four[]; -extern const uint8_t five[]; -extern const uint8_t six[]; -extern const uint8_t seven[]; -extern const uint8_t eight[]; -extern const uint8_t nine[]; -extern const uint8_t A[]; -extern const uint8_t B[]; -extern const uint8_t C[]; -extern const uint8_t D[]; -extern const uint8_t E[]; -extern const uint8_t F[]; -extern const uint8_t G[]; -extern const uint8_t H[]; -extern const uint8_t I[]; -extern const uint8_t J[]; -extern const uint8_t K[]; -extern const uint8_t L[]; -extern const uint8_t M[]; -extern const uint8_t N[]; -extern const uint8_t O[]; -extern const uint8_t P[]; -extern const uint8_t Q[]; -extern const uint8_t R[]; -extern const uint8_t S[]; -extern const uint8_t T[]; -extern const uint8_t U[]; -extern const uint8_t V[]; -extern const uint8_t W[]; -extern const uint8_t X[]; -extern const uint8_t Y[]; -extern const uint8_t Z[]; -extern const uint8_t dot[]; -extern const uint8_t comma[]; -extern const uint8_t dash[]; -extern const uint8_t underscore[]; -extern const uint8_t bracket_open[]; -extern const uint8_t bracket_close[]; -extern const uint8_t cross_left[]; -extern const uint8_t cross_right[]; -extern const uint8_t pacman_left[]; -extern const uint8_t pacman_right[]; -extern const uint8_t box[]; -extern const uint8_t* char_arr[48]; -extern const uint8_t gradient[]; -//extern const uint8_t gun[] -//extern const uint8_t gun_mask[] -extern const uint8_t gun[]; -extern const uint8_t gun_mask[]; - -extern const uint8_t imp_inv[]; -extern const uint8_t imp_mask_inv[]; -extern const uint8_t fireball[]; -extern const uint8_t fireball_mask[]; -extern const uint8_t item[]; -extern const uint8_t item_mask[]; - -extern const uint8_t door[]; - -#endif diff --git a/applications/external/doom/assets/door2.png b/applications/external/doom/assets/door2.png deleted file mode 100644 index b4b4f03995d0a9da6374bbd471e2a068db3f9865..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31942 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 VrOV0%#})tp002ovPDHLkV1nA-0CWHV diff --git a/applications/external/doom/assets/fireball_inv.png b/applications/external/doom/assets/fireball_inv.png deleted file mode 100644 index b046288f8c413683b93d1bc87b189ead18d3ca61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 418 zcmV;T0bTxyP)Px$TuDShR5(vvQwx$qAq;|e|05fAAZp)ir&H^X06{7rfCKPx$K1oDDR5(vzv)oMR{m9$RNiQOO*jUe+8Igc>{b3fOcn$K4ciEAxcMX140 zU9ncU-o_?x1F`~{rar@ZO6$11r*P1%9=-xZRcZO7lEgVQf2B0@$^Dhs2v)(n#@*ib zUs2|K*VKBotG4%7_E=J;8j;VvHkE-BGS6r{f}its!oN1R6P3|UFTZi*h=mcg#k=-+ zwTW#Y*)p?XX+0|XF+}Si(W>5Ks`D0xq7!zeAJ!U3llxt0bwPx&$4Nv%R9HuaSKG3LAPl4U|DUX!Nz+R}caATsD3GQ}%i6*<))>Qv@h2`k;Ic8+ z>L05Q_?8REylp-vV#4AYaX*&DgvA9g2Pmw!_mN&UF=7~#iO#>s1!`cM+Kccmo(bny z2>Ya9Ap_&iJzqok;6Y&twMyd_!oH2LSwvcLT0Gc#7T7yDW7?EN#U}~gN$gdUERY@= z$#9r_q147&&#Jk|b!65#pYhBzgZ%05lj?UGmEwv_G?BOQYup~>*oa$a4?BaNP|KJ$ z$HPyV|3D@PJ_TKgQQ|baNRTHYuUa_}VCS`-lJ1;DN-myZ&stFTzgLCsDr~gj#x*X) zs7NMae#%}p=UC4}(=8hYB#_WsNUed*oG*;+-vxFr?1-3>-Cw`S!8FebvyeG;Vs6>% zs6L0tTv+Z-#Nsc3fJ*Zim2E|Y@kFc$y3A05@BypTt`U8r4tzzj>WTvrM-YhQy^r7h zz0|~rM@*cHbP?TCfv~+of;jAaKWoe@V^2gjZXgRz(j(%9XC-l|aatJiW&8{akwCyNlTMZ5J~x#aqMz}6QS7^IyhMlM1Y+YiLvWqSlpEu z9Bjp+E!@T9@qU1^oQtyTesF-DD=g;%utTAzN4m9v$SdR=Rz2mNlSNG8g&-__{^3UD z1jIh;rW?V&zbpeO0;agaQo^Z3SU_C(RR@kq?cS&dpGD+z66=NQBE+=S0~Y*IZu6Hw zbkm*HZlhj6*#)Bs4?p|pg0`OdB<9C>f7Mj1%Da5kbXJ5uh*fgYeL>vEGK)Z`1Ns%zNqr=L?7J41$AemSHl_d2HF*nB>2XM4y?jewx(B$t-4V zC)Hdan?_p}v0gO=@4aH>NVwLsz?fp&5**HsaX!_vlc>_Yz)*IztAa@GYilLPxksXpvnOWd0LwB(Tq(QJp-O!U$}%2|=iF7s0UA-^4V zl*Zr1Q+r_I%1byu6DpOcDR;((hvY{^MPLxNQ6Z0;=fK=sOc~00000NkvXX Hu0mjfATIzz diff --git a/applications/external/doom/assets/gun_inv.png b/applications/external/doom/assets/gun_inv.png deleted file mode 100644 index e2ec052952905c92e9d11e523da71d6fa0dc96d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1050 zcmV+#1m*jQP)Px&)Ja4^R9HuSS6P;XFbGWa{zvX)UQrZF)bXcnH4&%XG zxSurjND72jtxpw*2SGZmbd0UUC}|;~l;8}*Jp}dCOa@~RBvX%aH|Y@&Zc0FbwG`l( z*)?n_1w$pvgROet^QeIC9!xxu$4js4vaI)FRzWr;6axC9Z_%%8#vnk%D5We(B2`*N z%pf0#X@x5=iS>-oRkHS&7s$Grchp?x=E{Gp%k==(FIEBM!T|z8Xr~;NKYc<3Rd&1- z&-~{D#lq5=joq6LXjNkX$qkXy&B)$|=gWU9I766gFHqsbiZWX0+Su&bTLnP4mD2kv zqY*LGKux42*ZKtqj(7}HK(JaR5Rx(e6pwt~oUbaSHZZRMeIR$JJ^?GO-GuH(LWKlR ziP@60GMt8Or7!M=PdW+hzya!2uRW_Tk)hbxQB3 zm2E7eaZ_q_lB6rn;fORJzNkTv7LXw%e!2#{OL1L_bNpNtQb$EKC0VP#0=)r?xCkQQv$4@l@X)8Ua2&=s{-J)o-M zG$VCUJ;QEz$OyWvn^MPz^=cRi%yU#T$cjz(8WK>b$$0lrL6KOLz?lnH#~5bhrW4jf zP_?y!9KE6T4Ilzc% zw+e#gtN&p<<~^peXH{}yPAlicwABlUi{?D4bXvn{8G8n28=iM*<*r%5Wpjjcstz)m zl%fLNvq_>}?)-1TI{OpJ7D#Mmuj`9Ndvs8Sb3E{57n zDyD?;U62*tlm^lE z@p5*;biy8hoX(_YjRR%o2u7lEFcGjgLoc{1(fpfH&S=tZb3tLwdWm{30${fF3)eHO#PWcmEuEzIV4s=NAlL)anbfTQ00>Px&2}wjjR9HuiR|}FQDG1cs`yY8_g5)D0`nqDGr&}#Zk_4x5Ow=Tfn!N7Suh>>$U#`jI+9|ndvfF?>BIE??1hV!v70pQHc z)_<*r`F)~ZcOBd|8R4Y`4;FTi0g*D$BPg(0t6yIo&8lGmP)_Tz3X26FQgCH~*uWSc z=bHbiohOpQ1f0h_xHB4a5ivkLa8CvR{CX}aKmsZV(~XJno`p?)w!cY^9RRDoH95!l zn}dWFilez`(Tq(d9T0_on)|-$3oS-e>`LK9FcC^7m*LSU^lYF%MY#LoQGi-1sXa0S zwHdzqfU?2)zXY^{`2#(>>2fMm)N2v7`U-4t)4`cb1ti}E$nF<9psEJ)G(4y6ec~}F z?SeV2ZLJ{sLthZ7K-lw|29ZYmW8_-zJ=ib(!uBNvnSx0yORIvghlv*xk5-{t=(-V{ z>SWlHYKt?LqH+XxXhfm)OUWs~tLq&szShj>&&f|`3%{0Skx7JiSl`Krao3`v*Lebsus z5rphbzg|ZE(3MORHVu>WaLw}ERuW9OhP4sFOG*A3p+U>Mf3@3s8FezfyskIi z2q|;-r|yL>ClnvI;yM3ozH8chws)`%ppve0<Px&K}keGR9HuiS66n#FbEX({f``xH*_R+6MrOYTLqXROw5}X(^`wyBEsKA`A6@U zUirH`tpgS>UZmsgd3$Z^=u2F*h?)H^Ht}(Fp_n`T7&n<7`ZH`vn${J7udhWYRVfwl z0@0(3Fz?9dTcEXuHn9ev;YHwA2K7BJqGzFa57F9tTSk4-3||kCgad(cNBRIhn1Ic7 z4oeUk%uiXFTCzGuG4~f9Tm*0?d_&luNanm3(Q6PK71Z#Yk{6Agh_rdL@peo&1fh&s zjL|BSMNm!W@F%Tw85Nud2(psX2FN_fY*GRVF%|{h2ne7)<-UM(R^3Tacz|>R zN6YwNs=}c&F(#B0)j?3UPWXzAZ$5AUA98z*RE}h9_9!giu>tsikRnZcHak%gnh`n{ zX>`e1b^e%L8Q|~57r>QAD|0!iprpzm4WQXi5GfbLa1{|G2ll_F0+(>*i{zeWr^Z|E zgOPZa5GZ-vBELFX9a?NPWQ6<#a`%JJYabO5@P;71E4nJ)*#KgSD#YgoSFvqqGn9Q^ zX|)}kgBxE7mS%V}475{KC zb__AJL9=6;&o~Lgat#ligk!b?)Y)#9Jo&yY_|Pk=v0B(_R`RZb40@o<*cUazmPwU} z-f)f0jRtTY$Ek#7EEc;z3*Wc6#rxULf|jp4qLQwq39~v|va@UP#Pq*B^f{dp3h~Y@ES;bq^$<3!ap3nNdRM9#J^X(qF*6TLn?vH*a+=!$3a-`cp zuza)PkqW6|w`v1TOMfFx0E{|W~vbOm5#O%T)P{z26lwlR0p+a$xNmy6#;7$N4aw2h9g&x&2MO{H6~<7Do>g dFGoSH`3t~`RjZcOFsT3l002ovPDHLkV1mi>ol5`! diff --git a/applications/external/doom/assets/imp_mask_inv.png b/applications/external/doom/assets/imp_mask_inv.png deleted file mode 100644 index 70e99127021de388624f3dd9b187cf77ba77a4a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 958 zcmV;v13~Px&cu7P-R9HuSSKF53FbK2L|NrEgIpQjCI(gWgx-JM1f^3l^vi6$Kbt1T-|E#s= zw>aPSwSN_V>i_M7U-Prw{gVZ@*3i|RH{*eE;8Cx#fscIvoCv-u=z8-l%ATYBJZs^n z8nP@klaG7TY<275N|vlGI{B7j#TL`iK;_n0Ohzdhj$vMm&j7m|mpFt^-qz2mq`ljv>nrqz|V&93t^n)nb(a z+FKUr)m;v<8vxuI^3^$~&Lh?8I;cU(3L4FbBMWSj`f31}j$6M}y))qxNF!xcM&!8V z7s;O_ObkIX?s+OT^t6dz<@ zYO;YCUErv66p#R+)q>Gu61H;WJr|p>;pf$DMOyv?Pj996g?P^#cv@FqHSZ)r*CQsL?Mo#nk9GyG58R8j8*r9HzRvjJJ(O^^UR3o>%Z;4i z01;_)ML{Y+POCOqjR!xJ&>|=U0F{6!5G*2bZn(VfUA`Onm}WW5XeUjH2x#nI<^ zDsW;qlP$_)bHIr9-{U*seP#4S&6=SDh|u^_?T9m@(wmjgnx=$7vVpgCMu>~8VJ|d7@tjmrY)BFcv*N^%jeAI z9(S$Jl!rv444)jA*QOscC?(g{cE#!Y$O})RM%=p=6K_T~>9BzKmP6~sEBUCby$$ot zrSXaSHhV+?gcK;@xJ9FDZrnVJ(}};D4IQ3UAWT7pn3nRj`qyeU=Ko7P%#D|&v?neu zw;$1aL69zX#?rMK?QF4c|GE!&(V9wK^EsKV^&e9FtL>_2zgmKa(e(LKz9w1frKYzX gF`dV0wzJ*-13?RLuaP50!vFvP07*qoM6N<$g7sC)xc~qF diff --git a/applications/external/doom/assets/item_inv.png b/applications/external/doom/assets/item_inv.png deleted file mode 100644 index 1d32dbcd8e523fdde813aa45d9f0c408716c3a55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 417 zcmV;S0bc%zP)Px$TS-JgR5(vvlR=ilFbG4zzWn?i9i9J84VPV1IB-K`K_yat)(O-QlmOga zJcUeW-+4eq^5!_L3I>co#H6D@-Fq@Gn5U|$pc$D=iWXwP#RgXbmN z!Ol3RV=c+~qxeIAHU&iYiIqDJY#W456*H4TJdPM$`C1G1+>=xN(V)8`bA>J?7zJLT zwCR$dSMW1lFoQ4y55-(At3JAWMw35?8yG-sfrL{nA=Q6mV9y*JI@WsJc>0K$oQMH7 zs~g7w=ADoIMiY-^qDp-jqy%@=lKjIo1Au(bcOqG3xw1N zLS}{AKCpdZ#b&&bYh`@{<9jwE5urerI%u&>ZD_JupU=lOe&F^G&Qc%EoG8hD00000 LNkvXXu0mjfdm*rZ diff --git a/applications/external/doom/assets/item_mask_inv.png b/applications/external/doom/assets/item_mask_inv.png deleted file mode 100644 index a0bde9c76401a4cf074f8a59a18b41eafddfeaed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 383 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 -#include -#include "constants.h" -#include "doom_icons.h" -#include -#include "assets.h" - -#define CHECK_BIT(var, pos) ((var) & (1 << (pos))) - -static const uint8_t bit_mask[8] = {128, 64, 32, 16, 8, 4, 2, 1}; - -#define pgm_read_byte(addr) (*(const unsigned char*)(addr)) -#define read_bit(b, n) b& pgm_read_byte(bit_mask + n) ? 1 : 0 -//#define read_bit(byte, index) (((unsigned)(byte) >> (index)) & 1) - -void drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canvas* const canvas); -void drawPixel(int8_t x, int8_t y, bool color, bool raycasterViewport, Canvas* const canvas); -void drawSprite( - int8_t x, - int8_t y, - const uint8_t* bitmap, - const uint8_t* bitmap_mask, - int16_t w, - int16_t h, - uint8_t sprite, - double distance, - Canvas* const canvas); -void drawBitmap( - int16_t x, - int16_t y, - const Icon* i, - int16_t w, - int16_t h, - uint16_t color, - Canvas* const canvas); -void drawTextSpace(int8_t x, int8_t y, char* txt, uint8_t space, Canvas* const canvas); -void drawChar(int8_t x, int8_t y, char ch, Canvas* const canvas); -void clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas); -void drawGun( - int16_t x, - int16_t y, - const uint8_t* bitmap, - int16_t w, - int16_t h, - uint16_t color, - Canvas* const canvas); -void drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas); -void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas); -void fadeScreen(uint8_t intensity, bool color, Canvas* const canvas); -bool getGradientPixel(uint8_t x, uint8_t y, uint8_t i); -double getActualFps(); -void fps(); -uint8_t reverse_bits(uint8_t num); - -// FPS control -double delta = 1; -uint32_t lastFrameTime = 0; -uint8_t zbuffer[128]; /// 128 = screen width & REMOVE WHEN DISPLAY.H IMPLEMENTED - -void drawGun( - int16_t x, - int16_t y, - const uint8_t* bitmap, - int16_t w, - int16_t h, - uint16_t color, - Canvas* const canvas) { - int16_t byteWidth = (w + 7) / 8; - uint8_t byte = 0; - for(int16_t j = 0; j < h; j++, y++) { - for(int16_t i = 0; i < w; i++) { - if(i & 7) - byte <<= 1; - else - byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); - if(byte & 0x80) drawPixel(x + i, y, color, false, canvas); - } - } -} - -void drawVLine(uint8_t x, int8_t start_y, int8_t end_y, uint8_t intensity, Canvas* const canvas) { - UNUSED(intensity); - uint8_t dots = end_y - start_y; - for(int i = 0; i < dots; i++) { - canvas_draw_dot(canvas, x, start_y + i); - } -} - -void drawBitmap( - int16_t x, - int16_t y, - const Icon* i, - int16_t w, - int16_t h, - uint16_t color, - Canvas* const canvas) { - UNUSED(w); - UNUSED(h); - if(!color) { - canvas_invert_color(canvas); - } - canvas_draw_icon(canvas, x, y, i); - if(!color) { - canvas_invert_color(canvas); - } -} - -void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas) { - char buf[4]; - snprintf(buf, 4, "%d", num); - drawTextSpace(x, y, buf, 1, canvas); -} - -void drawTextSpace(int8_t x, int8_t y, char* txt, uint8_t space, Canvas* const canvas) { - uint8_t pos = x; - uint8_t i = 0; - char ch; - while((ch = txt[i]) != '\0') { - drawChar(pos, y, ch, canvas); - i++; - pos += CHAR_WIDTH + space; - - // shortcut on end of screen - if(pos > SCREEN_WIDTH) return; - } -} - -// Custom drawBitmap method with scale support, mask, zindex and pattern filling -void drawSprite( - int8_t x, - int8_t y, - const uint8_t* bitmap, - const uint8_t* bitmap_mask, - int16_t w, - int16_t h, - uint8_t sprite, - double distance, - Canvas* const canvas) { - uint8_t tw = (double)w / distance; - uint8_t th = (double)h / distance; - uint8_t byte_width = w / 8; - uint8_t pixel_size = fmax(1, (double)1.0 / (double)distance); - uint16_t sprite_offset = byte_width * h * sprite; - - bool pixel; - bool maskPixel; - - // Don't draw the whole sprite if the anchor is hidden by z buffer - // Not checked per pixel for performance reasons - if(zbuffer[(int)(fmin(fmax(x, 0), ZBUFFER_SIZE - 1) / Z_RES_DIVIDER)] < - distance * DISTANCE_MULTIPLIER) { - return; - } - - for(uint8_t ty = 0; ty < th; ty += pixel_size) { - // Don't draw out of screen - if(y + ty < 0 || y + ty >= RENDER_HEIGHT) { - continue; - } - - uint8_t sy = ty * distance; // The y from the sprite - - for(uint8_t tx = 0; tx < tw; tx += pixel_size) { - uint8_t sx = tx * distance; // The x from the sprite - uint16_t byte_offset = sprite_offset + sy * byte_width + sx / 8; - - // Don't draw out of screen - if(x + tx < 0 || x + tx >= SCREEN_WIDTH) { - continue; - } - - maskPixel = read_bit(pgm_read_byte(bitmap_mask + byte_offset), sx % 8); - - if(maskPixel) { - pixel = read_bit(pgm_read_byte(bitmap + byte_offset), sx % 8); - for(uint8_t ox = 0; ox < pixel_size; ox++) { - for(uint8_t oy = 0; oy < pixel_size; oy++) { - if(bitmap == imp_inv) - drawPixel(x + tx + ox, y + ty + oy, 1, true, canvas); - else - drawPixel(x + tx + ox, y + ty + oy, pixel, true, canvas); - } - } - } - } - } -} - -void drawPixel(int8_t x, int8_t y, bool color, bool raycasterViewport, Canvas* const canvas) { - if(x < 0 || x >= SCREEN_WIDTH || y < 0 || - y >= (raycasterViewport ? RENDER_HEIGHT : SCREEN_HEIGHT)) { - return; - } - if(color) - canvas_draw_dot(canvas, x, y); - else { - canvas_invert_color(canvas); - canvas_draw_dot(canvas, x, y); - canvas_invert_color(canvas); - } -} - -void drawChar(int8_t x, int8_t y, char ch, Canvas* const canvas) { - uint8_t lsb; - uint8_t c = 0; - while(CHAR_MAP[c] != ch && CHAR_MAP[c] != '\0') c++; - for(uint8_t i = 0; i < 6; i++) { - //lsb = (char_arr[c][i] >> 4); - lsb = reverse_bits(char_arr[c][i]); - for(uint8_t n = 0; n < 4; n++) { - if(CHECK_BIT(lsb, n)) { - drawPixel(x + n, y + i, true, false, canvas); - } - } - } -} - -void clearRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas) { - canvas_invert_color(canvas); - - for(int i = 0; i < w; i++) { - for(int j = 0; j < h; j++) { - canvas_draw_dot(canvas, x + i, y + j); - } - } - - canvas_invert_color(canvas); -} - -void drawRect(uint8_t x, uint8_t y, uint8_t w, uint8_t h, Canvas* const canvas) { - for(int i = 0; i < w; i++) { - for(int j = 0; j < h; j++) { - canvas_draw_dot(canvas, x + i, y + j); - } - } -} - -bool getGradientPixel(uint8_t x, uint8_t y, uint8_t i) { - if(i == 0) return 0; - if(i >= GRADIENT_COUNT - 1) return 1; - - uint8_t index = - fmax(0, fmin(GRADIENT_COUNT - 1, i)) * GRADIENT_WIDTH * GRADIENT_HEIGHT // gradient index - + y * GRADIENT_WIDTH % (GRADIENT_WIDTH * GRADIENT_HEIGHT) // y byte offset - + x / GRADIENT_HEIGHT % GRADIENT_WIDTH; // x byte offset - //uint8_t *gradient_data = NULL; - //furi_hal_compress_icon_decode(icon_get_data(&I_gradient_inv), &gradient_data); - // return the bit based on x - return read_bit(pgm_read_byte(gradient + index), x % 8); -} - -void fadeScreen(uint8_t intensity, bool color, Canvas* const canvas) { - for(uint8_t x = 0; x < SCREEN_WIDTH; x++) { - for(uint8_t y = 0; y < SCREEN_HEIGHT; y++) { - if(getGradientPixel(x, y, intensity)) drawPixel(x, y, color, false, canvas); - } - } -} - -// Adds a delay to limit play to specified fps -// Calculates also delta to keep movement consistent in lower framerates -void fps() { - while(furi_get_tick() - lastFrameTime < FRAME_TIME) - ; - delta = (double)(furi_get_tick() - lastFrameTime) / (double)FRAME_TIME; - lastFrameTime = furi_get_tick(); -} - -double getActualFps() { - return 1000 / ((double)FRAME_TIME * (double)delta); -} - -uint8_t reverse_bits(uint8_t num) { - unsigned int NO_OF_BITS = sizeof(num) * 8; - uint8_t reverse_num = 0; - uint8_t i; - for(i = 0; i < NO_OF_BITS; i++) { - if((num & (1 << i))) reverse_num |= 1 << ((NO_OF_BITS - 1) - i); - } - return reverse_num; -} \ No newline at end of file diff --git a/applications/external/doom/doom.c b/applications/external/doom/doom.c deleted file mode 100644 index c2d9a6bf0..000000000 --- a/applications/external/doom/doom.c +++ /dev/null @@ -1,1104 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "sound.h" -#include "display.h" -#include "assets.h" -#include "constants.h" -#include "entities.h" -#include "types.h" -#include "level.h" -#include -#include -#include - -#define SOUND - -// Useful macros -#define swap(a, b) \ - do { \ - typeof(a) temp = a; \ - a = b; \ - b = temp; \ - } while(0) -#define sign(a, b) (double)(a > b ? 1 : (b > a ? -1 : 0)) -#define pgm_read_byte(addr) (*(const unsigned char*)(addr)) - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} PluginEvent; - -typedef struct { - FuriMutex* mutex; - Player player; - Entity entity[MAX_ENTITIES]; - StaticEntity static_entity[MAX_STATIC_ENTITIES]; - uint8_t num_entities; - uint8_t num_static_entities; - - uint8_t scene; - uint8_t gun_pos; - double jogging; - double view_height; - bool init; - - bool up; - bool down; - bool left; - bool right; - bool fired; - bool gun_fired; - - double rot_speed; - double old_dir_x; - double old_plane_x; - NotificationApp* notify; -#ifdef SOUND - MusicPlayer* music_instance; - bool intro_sound; -#endif -} PluginState; - -static const NotificationSequence sequence_short_sound = { - &message_note_c5, - &message_delay_50, - &message_sound_off, - NULL, -}; -static const NotificationSequence sequence_long_sound = { - &message_note_c3, - &message_delay_100, - &message_sound_off, - NULL, -}; - -Coords translateIntoView(Coords* pos, PluginState* const plugin_state); -void updateHud(Canvas* const canvas, PluginState* const plugin_state); -// general - -bool invert_screen = false; -uint8_t flash_screen = 0; - -// game -// player and entities - -uint8_t getBlockAt(const uint8_t level[], uint8_t x, uint8_t y) { - if(x >= LEVEL_WIDTH || y >= LEVEL_HEIGHT) { - return E_FLOOR; - } - - // y is read in inverse order - return pgm_read_byte(level + (((LEVEL_HEIGHT - 1 - y) * LEVEL_WIDTH + x) / 2)) >> - (!(x % 2) * 4) // displace part of wanted bits - & 0b1111; // mask wanted bits -} - -// Finds the player in the map -void initializeLevel(const uint8_t level[], PluginState* const plugin_state) { - for(uint8_t y = LEVEL_HEIGHT - 1; y > 0; y--) { - for(uint8_t x = 0; x < LEVEL_WIDTH; x++) { - uint8_t block = getBlockAt(level, x, y); - - if(block == E_PLAYER) { - plugin_state->player = create_player(x, y); - return; - } - - // todo create other static entities - } - } -} - -bool isSpawned(UID uid, PluginState* const plugin_state) { - for(uint8_t i = 0; i < plugin_state->num_entities; i++) { - if(plugin_state->entity[i].uid == uid) return true; - } - - return false; -} - -bool isStatic(UID uid, PluginState* const plugin_state) { - for(uint8_t i = 0; i < plugin_state->num_static_entities; i++) { - if(plugin_state->static_entity[i].uid == uid) return true; - } - - return false; -} - -void spawnEntity(uint8_t type, uint8_t x, uint8_t y, PluginState* const plugin_state) { - // Limit the number of spawned entities - if(plugin_state->num_entities >= MAX_ENTITIES) { - return; - } - - // todo: read static entity status - - switch(type) { - case E_ENEMY: - plugin_state->entity[plugin_state->num_entities] = create_enemy(x, y); - plugin_state->num_entities++; - break; - - case E_KEY: - plugin_state->entity[plugin_state->num_entities] = create_key(x, y); - plugin_state->num_entities++; - break; - - case E_MEDIKIT: - plugin_state->entity[plugin_state->num_entities] = create_medikit(x, y); - plugin_state->num_entities++; - break; - } -} - -void spawnFireball(double x, double y, PluginState* const plugin_state) { - // Limit the number of spawned entities - if(plugin_state->num_entities >= MAX_ENTITIES) { - return; - } - - UID uid = create_uid(E_FIREBALL, x, y); - // Remove if already exists, don't throw anything. Not the best, but shouldn't happen too often - if(isSpawned(uid, plugin_state)) return; - - // Calculate direction. 32 angles - int16_t dir = - FIREBALL_ANGLES + atan2(y - plugin_state->player.pos.y, x - plugin_state->player.pos.x) / - (double)PI * FIREBALL_ANGLES; - if(dir < 0) dir += FIREBALL_ANGLES * 2; - plugin_state->entity[plugin_state->num_entities] = create_fireball(x, y, dir); - plugin_state->num_entities++; -} - -void removeEntity(UID uid, PluginState* const plugin_state) { - uint8_t i = 0; - bool found = false; - - while(i < plugin_state->num_entities) { - if(!found && plugin_state->entity[i].uid == uid) { - // todo: doze it - found = true; - plugin_state->num_entities--; - } - - // displace entities - if(found) { - plugin_state->entity[i] = plugin_state->entity[i + 1]; - } - - i++; - } -} - -void removeStaticEntity(UID uid, PluginState* const plugin_state) { - uint8_t i = 0; - bool found = false; - - while(i < plugin_state->num_static_entities) { - if(!found && plugin_state->static_entity[i].uid == uid) { - found = true; - plugin_state->num_static_entities--; - } - - // displace entities - if(found) { - plugin_state->static_entity[i] = plugin_state->static_entity[i + 1]; - } - - i++; - } -} - -UID detectCollision( - const uint8_t level[], - Coords* pos, - double relative_x, - double relative_y, - bool only_walls, - PluginState* const plugin_state) { - // Wall collision - uint8_t round_x = (int)(pos->x + relative_x); - uint8_t round_y = (int)(pos->y + relative_y); - uint8_t block = getBlockAt(level, round_x, round_y); - - if(block == E_WALL) { - // playSound(hit_wall_snd, HIT_WALL_SND_LEN); - return create_uid(block, round_x, round_y); - } - - if(only_walls) { - return UID_null; - } - - // Entity collision - for(uint8_t i = 0; i < plugin_state->num_entities; i++) { - // Don't collide with itself - if(&(plugin_state->entity[i].pos) == pos) { - continue; - } - - uint8_t type = uid_get_type(plugin_state->entity[i].uid); - - // Only ALIVE enemy collision - if(type != E_ENEMY || plugin_state->entity[i].state == S_DEAD || - plugin_state->entity[i].state == S_HIDDEN) { - continue; - } - - Coords new_coords = { - plugin_state->entity[i].pos.x - relative_x, - plugin_state->entity[i].pos.y - relative_y}; - uint8_t distance = coords_distance(pos, &new_coords); - - // Check distance and if it's getting closer - if(distance < ENEMY_COLLIDER_DIST && distance < plugin_state->entity[i].distance) { - return plugin_state->entity[i].uid; - } - } - - return UID_null; -} - -// Shoot -void fire(PluginState* const plugin_state) { - //playSound(shoot_snd, SHOOT_SND_LEN); - - for(uint8_t i = 0; i < plugin_state->num_entities; i++) { - // Shoot only ALIVE enemies - if(uid_get_type(plugin_state->entity[i].uid) != E_ENEMY || - plugin_state->entity[i].state == S_DEAD || plugin_state->entity[i].state == S_HIDDEN) { - continue; - } - - Coords transform = translateIntoView(&(plugin_state->entity[i].pos), plugin_state); - if(fabs(transform.x) < 20 && transform.y > 0) { - uint8_t damage = (double)fmin( - GUN_MAX_DAMAGE, - GUN_MAX_DAMAGE / (fabs(transform.x) * plugin_state->entity[i].distance) / 5); - if(damage > 0) { - plugin_state->entity[i].health = fmax(0, plugin_state->entity[i].health - damage); - plugin_state->entity[i].state = S_HIT; - plugin_state->entity[i].timer = 4; - } - } - } -} - -UID updatePosition( - const uint8_t level[], - Coords* pos, - double relative_x, - double relative_y, - bool only_walls, - PluginState* const plugin_state) { - UID collide_x = detectCollision(level, pos, relative_x, 0, only_walls, plugin_state); - UID collide_y = detectCollision(level, pos, 0, relative_y, only_walls, plugin_state); - - if(!collide_x) pos->x += relative_x; - if(!collide_y) pos->y += relative_y; - - return collide_x || collide_y || UID_null; -} - -void updateEntities(const uint8_t level[], Canvas* const canvas, PluginState* const plugin_state) { - uint8_t i = 0; - while(i < plugin_state->num_entities) { - // update distance - plugin_state->entity[i].distance = - coords_distance(&(plugin_state->player.pos), &(plugin_state->entity[i].pos)); - - // Run the timer. Works with actual frames. - // Todo: use delta here. But needs double type and more memory - if(plugin_state->entity[i].timer > 0) plugin_state->entity[i].timer--; - - // too far away. put it in doze mode - if(plugin_state->entity[i].distance > MAX_ENTITY_DISTANCE) { - removeEntity(plugin_state->entity[i].uid, plugin_state); - // don't increase 'i', since current one has been removed - continue; - } - - // bypass render if hidden - if(plugin_state->entity[i].state == S_HIDDEN) { - i++; - continue; - } - - uint8_t type = uid_get_type(plugin_state->entity[i].uid); - - switch(type) { - case E_ENEMY: { - // Enemy "IA" - if(plugin_state->entity[i].health == 0) { - if(plugin_state->entity[i].state != S_DEAD) { - plugin_state->entity[i].state = S_DEAD; - plugin_state->entity[i].timer = 6; - } - } else if(plugin_state->entity[i].state == S_HIT) { - if(plugin_state->entity[i].timer == 0) { - // Back to alert state - plugin_state->entity[i].state = S_ALERT; - plugin_state->entity[i].timer = 40; // delay next fireball thrown - } - } else if(plugin_state->entity[i].state == S_FIRING) { - if(plugin_state->entity[i].timer == 0) { - // Back to alert state - plugin_state->entity[i].state = S_ALERT; - plugin_state->entity[i].timer = 40; // delay next fireball throwm - } - } else { - // ALERT STATE - if(plugin_state->entity[i].distance > ENEMY_MELEE_DIST && - plugin_state->entity[i].distance < MAX_ENEMY_VIEW) { - if(plugin_state->entity[i].state != S_ALERT) { - plugin_state->entity[i].state = S_ALERT; - plugin_state->entity[i].timer = 20; // used to throw fireballs - } else { - if(plugin_state->entity[i].timer == 0) { - // Throw a fireball - spawnFireball( - plugin_state->entity[i].pos.x, - plugin_state->entity[i].pos.y, - plugin_state); - plugin_state->entity[i].state = S_FIRING; - plugin_state->entity[i].timer = 6; - } else { - // move towards to the player. - updatePosition( - level, - &(plugin_state->entity[i].pos), - sign(plugin_state->player.pos.x, plugin_state->entity[i].pos.x) * - (double)ENEMY_SPEED * 1, // NOT SURE (delta) - sign(plugin_state->player.pos.y, plugin_state->entity[i].pos.y) * - (double)ENEMY_SPEED * 1, // NOT SURE (delta) - true, - plugin_state); - } - } - } else if(plugin_state->entity[i].distance <= ENEMY_MELEE_DIST) { - if(plugin_state->entity[i].state != S_MELEE) { - // Preparing the melee attack - plugin_state->entity[i].state = S_MELEE; - plugin_state->entity[i].timer = 10; - } else if(plugin_state->entity[i].timer == 0) { - // Melee attack - plugin_state->player.health = - fmax(0, plugin_state->player.health - ENEMY_MELEE_DAMAGE); - plugin_state->entity[i].timer = 14; - flash_screen = 1; - updateHud(canvas, plugin_state); - } - } else { - // stand - plugin_state->entity[i].state = S_STAND; - } - } - break; - } - - case E_FIREBALL: { - if(plugin_state->entity[i].distance < FIREBALL_COLLIDER_DIST) { - // Hit the player and disappear - plugin_state->player.health = - fmax(0, plugin_state->player.health - ENEMY_FIREBALL_DAMAGE); - flash_screen = 1; - updateHud(canvas, plugin_state); - removeEntity(plugin_state->entity[i].uid, plugin_state); - continue; // continue in the loop - } else { - // Move. Only collide with walls. - // Note: using health to store the angle of the movement - UID collided = updatePosition( - level, - &(plugin_state->entity[i].pos), - cos((double)plugin_state->entity[i].health / FIREBALL_ANGLES * (double)PI) * - (double)FIREBALL_SPEED, - sin((double)plugin_state->entity[i].health / FIREBALL_ANGLES * (double)PI) * - (double)FIREBALL_SPEED, - true, - plugin_state); - - if(collided) { - removeEntity(plugin_state->entity[i].uid, plugin_state); - continue; // continue in the entity check loop - } - } - break; - } - - case E_MEDIKIT: { - if(plugin_state->entity[i].distance < ITEM_COLLIDER_DIST) { - // pickup - notification_message(plugin_state->notify, &sequence_long_sound); - //playSound(medkit_snd, MEDKIT_SND_LEN); - plugin_state->entity[i].state = S_HIDDEN; - plugin_state->player.health = fmin(100, plugin_state->player.health + 50); - updateHud(canvas, plugin_state); - flash_screen = 1; - } - break; - } - - case E_KEY: { - if(plugin_state->entity[i].distance < ITEM_COLLIDER_DIST) { - // pickup - notification_message(plugin_state->notify, &sequence_long_sound); - //playSound(get_key_snd, GET_KEY_SND_LEN); - plugin_state->entity[i].state = S_HIDDEN; - plugin_state->player.keys++; - updateHud(canvas, plugin_state); - flash_screen = 1; - } - break; - } - } - - i++; - } -} - -// The map raycaster. Based on https://lodev.org/cgtutor/raycasting.html -void renderMap( - const uint8_t level[], - double view_height, - Canvas* const canvas, - PluginState* const plugin_state) { - UID last_uid = 0; // NOT SURE ? - - for(uint8_t x = 0; x < SCREEN_WIDTH; x += RES_DIVIDER) { - double camera_x = 2 * (double)x / SCREEN_WIDTH - 1; - double ray_x = plugin_state->player.dir.x + plugin_state->player.plane.x * camera_x; - double ray_y = plugin_state->player.dir.y + plugin_state->player.plane.y * camera_x; - uint8_t map_x = (uint8_t)plugin_state->player.pos.x; - uint8_t map_y = (uint8_t)plugin_state->player.pos.y; - Coords map_coords = {plugin_state->player.pos.x, plugin_state->player.pos.y}; - double delta_x = fabs(1 / ray_x); - double delta_y = fabs(1 / ray_y); - - int8_t step_x; - int8_t step_y; - double side_x; - double side_y; - - if(ray_x < 0) { - step_x = -1; - side_x = (plugin_state->player.pos.x - map_x) * delta_x; - } else { - step_x = 1; - side_x = (map_x + (double)1.0 - plugin_state->player.pos.x) * delta_x; - } - - if(ray_y < 0) { - step_y = -1; - side_y = (plugin_state->player.pos.y - map_y) * delta_y; - } else { - step_y = 1; - side_y = (map_y + (double)1.0 - plugin_state->player.pos.y) * delta_y; - } - - // Wall detection - uint8_t depth = 0; - bool hit = 0; - bool side; - while(!hit && depth < MAX_RENDER_DEPTH) { - if(side_x < side_y) { - side_x += delta_x; - map_x += step_x; - side = 0; - } else { - side_y += delta_y; - map_y += step_y; - side = 1; - } - - uint8_t block = getBlockAt(level, map_x, map_y); - - if(block == E_WALL) { - hit = 1; - } else { - // Spawning entities here, as soon they are visible for the - // player. Not the best place, but would be a very performance - // cost scan for them in another loop - if(block == E_ENEMY || (block & 0b00001000) /* all collectable items */) { - // Check that it's close to the player - if(coords_distance(&(plugin_state->player.pos), &map_coords) < - MAX_ENTITY_DISTANCE) { - UID uid = create_uid(block, map_x, map_y); - if(last_uid != uid && !isSpawned(uid, plugin_state)) { - spawnEntity(block, map_x, map_y, plugin_state); - last_uid = uid; - } - } - } - } - - depth++; - } - - if(hit) { - double distance; - - if(side == 0) { - distance = - fmax(1, (map_x - plugin_state->player.pos.x + (1 - step_x) / 2) / ray_x); - } else { - distance = - fmax(1, (map_y - plugin_state->player.pos.y + (1 - step_y) / 2) / ray_y); - } - - // store zbuffer value for the column - zbuffer[x / Z_RES_DIVIDER] = fmin(distance * DISTANCE_MULTIPLIER, 255); - - // rendered line height - uint8_t line_height = RENDER_HEIGHT / distance; - - drawVLine( - x, - view_height / distance - line_height / 2 + RENDER_HEIGHT / 2, - view_height / distance + line_height / 2 + RENDER_HEIGHT / 2, - GRADIENT_COUNT - (int)distance / MAX_RENDER_DEPTH * GRADIENT_COUNT - side * 2, - canvas); - } - } -} - -// Sort entities from far to close -uint8_t sortEntities(PluginState* const plugin_state) { - uint8_t gap = plugin_state->num_entities; - bool swapped = false; - while(gap > 1 || swapped) { - //shrink factor 1.3 - gap = (gap * 10) / 13; - if(gap == 9 || gap == 10) gap = 11; - if(gap < 1) gap = 1; - swapped = false; - for(uint8_t i = 0; i < plugin_state->num_entities - gap; i++) { - uint8_t j = i + gap; - if(plugin_state->entity[i].distance < plugin_state->entity[j].distance) { - swap(plugin_state->entity[i], plugin_state->entity[j]); - swapped = true; - } - } - } - return swapped; -} - -Coords translateIntoView(Coords* pos, PluginState* const plugin_state) { - //translate sprite position to relative to camera - double sprite_x = pos->x - plugin_state->player.pos.x; - double sprite_y = pos->y - plugin_state->player.pos.y; - - //required for correct matrix multiplication - double inv_det = - ((double)1.0 / - ((double)plugin_state->player.plane.x * (double)plugin_state->player.dir.y - - (double)plugin_state->player.dir.x * (double)plugin_state->player.plane.y)); - double transform_x = - inv_det * (plugin_state->player.dir.y * sprite_x - plugin_state->player.dir.x * sprite_y); - double transform_y = inv_det * (-plugin_state->player.plane.y * sprite_x + - plugin_state->player.plane.x * sprite_y); // Z in screen - Coords res = {transform_x, transform_y}; - return res; -} - -void renderEntities(double view_height, Canvas* const canvas, PluginState* const plugin_state) { - sortEntities(plugin_state); - - for(uint8_t i = 0; i < plugin_state->num_entities; i++) { - if(plugin_state->entity[i].state == S_HIDDEN) continue; - - Coords transform = translateIntoView(&(plugin_state->entity[i].pos), plugin_state); - - // don´t render if behind the player or too far away - if(transform.y <= (double)0.1 || transform.y > MAX_SPRITE_DEPTH) { - continue; - } - - int16_t sprite_screen_x = HALF_WIDTH * ((double)1.0 + transform.x / transform.y); - int8_t sprite_screen_y = RENDER_HEIGHT / 2 + view_height / transform.y; - uint8_t type = uid_get_type(plugin_state->entity[i].uid); - - // don´t try to render if outside of screen - // doing this pre-shortcut due int16 -> int8 conversion makes out-of-screen - // values fit into the screen space - if(sprite_screen_x < -HALF_WIDTH || sprite_screen_x > SCREEN_WIDTH + HALF_WIDTH) { - continue; - } - - switch(type) { - case E_ENEMY: { - uint8_t sprite; - if(plugin_state->entity[i].state == S_ALERT) { - // walking - sprite = ((int)furi_get_tick() / 500) % 2; - } else if(plugin_state->entity[i].state == S_FIRING) { - // fireball - sprite = 2; - } else if(plugin_state->entity[i].state == S_HIT) { - // hit - sprite = 3; - } else if(plugin_state->entity[i].state == S_MELEE) { - // melee atack - sprite = plugin_state->entity[i].timer > 10 ? 2 : 1; - } else if(plugin_state->entity[i].state == S_DEAD) { - // dying - sprite = plugin_state->entity[i].timer > 0 ? 3 : 4; - } else { - // stand - sprite = 0; - } - - drawSprite( - sprite_screen_x - BMP_IMP_WIDTH * (double).5 / transform.y, - sprite_screen_y - 8 / transform.y, - imp_inv, - imp_mask_inv, - BMP_IMP_WIDTH, - BMP_IMP_HEIGHT, - sprite, - transform.y, - canvas); - break; - } - - case E_FIREBALL: { - drawSprite( - sprite_screen_x - BMP_FIREBALL_WIDTH / 2 / transform.y, - sprite_screen_y - BMP_FIREBALL_HEIGHT / 2 / transform.y, - fireball, - fireball_mask, - BMP_FIREBALL_WIDTH, - BMP_FIREBALL_HEIGHT, - 0, - transform.y, - canvas); - break; - } - - case E_MEDIKIT: { - drawSprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, - item, - item_mask, - BMP_ITEMS_WIDTH, - BMP_ITEMS_HEIGHT, - 0, - transform.y, - canvas); - break; - } - - case E_KEY: { - drawSprite( - sprite_screen_x - BMP_ITEMS_WIDTH / 2 / transform.y, - sprite_screen_y + 5 / transform.y, - item, - item_mask, - BMP_ITEMS_WIDTH, - BMP_ITEMS_HEIGHT, - 1, - transform.y, - canvas); - break; - } - } - } -} - -void renderGun(uint8_t gun_pos, double amount_jogging, Canvas* const canvas) { - // jogging - char x = 48 + sin((double)furi_get_tick() * (double)JOGGING_SPEED) * 10 * amount_jogging; - char y = RENDER_HEIGHT - gun_pos + - fabs(cos((double)furi_get_tick() * (double)JOGGING_SPEED)) * 8 * amount_jogging; - - if(gun_pos > GUN_SHOT_POS - 2) { - // Gun fire - drawBitmap(x + 6, y - 11, &I_fire_inv, BMP_FIRE_WIDTH, BMP_FIRE_HEIGHT, 1, canvas); - } - - // Don't draw over the hud! - uint8_t clip_height = fmax(0, fmin(y + BMP_GUN_HEIGHT, RENDER_HEIGHT) - y); - - // Draw the gun (black mask + actual sprite). - drawBitmap(x, y, &I_gun_mask_inv, BMP_GUN_WIDTH, clip_height, 0, canvas); - drawBitmap(x, y, &I_gun_inv, BMP_GUN_WIDTH, clip_height, 1, canvas); - //drawGun(x,y,gun_mask, BMP_GUN_WIDTH, clip_height, 0, canvas); - //drawGun(x,y,gun, BMP_GUN_WIDTH, clip_height, 1, canvas); -} - -// Only needed first time -void renderHud(Canvas* const canvas, PluginState* plugin_state) { - drawTextSpace(2, 58, "{}", 0, canvas); // Health symbol - drawTextSpace(40, 58, "[]", 0, canvas); // Keys symbol - updateHud(canvas, plugin_state); -} - -// Render values for the HUD -void updateHud(Canvas* const canvas, PluginState* plugin_state) { - clearRect(12, 58, 15, 6, canvas); - clearRect(50, 58, 15, 6, canvas); - drawText(12, 58, plugin_state->player.health, canvas); - drawText(50, 58, plugin_state->player.keys, canvas); -} - -// Debug stats -void renderStats(Canvas* const canvas, PluginState* plugin_state) { - clearRect(58, 58, 70, 6, canvas); - drawText(114, 58, (int)getActualFps(), canvas); - drawText(82, 58, plugin_state->num_entities, canvas); - // drawText(94, 58, freeMemory()); -} - -// Intro screen -void loopIntro(Canvas* const canvas) { - canvas_draw_icon(canvas, 0, 0, &I_logo_inv); - //drawTextSpace(SCREEN_WIDTH / 2 - 25, SCREEN_HEIGHT * .8, "PRESS FIRE", 1, canvas); -} - -static void render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - PluginState* plugin_state = ctx; - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - canvas_set_font(canvas, FontPrimary); - - switch(plugin_state->scene) { - case INTRO: { - loopIntro(canvas); - break; - } - case GAME_PLAY: { - updateEntities(sto_level_1, canvas, plugin_state); - - renderGun(plugin_state->gun_pos, plugin_state->jogging, canvas); - renderMap(sto_level_1, plugin_state->view_height, canvas, plugin_state); - - renderEntities(plugin_state->view_height, canvas, plugin_state); - - renderHud(canvas, plugin_state); - updateHud(canvas, plugin_state); - renderStats(canvas, plugin_state); - break; - } - } - furi_mutex_release(plugin_state->mutex); -} - -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - PluginEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, 0); -} - -static void doom_state_init(PluginState* const plugin_state) { - plugin_state->notify = furi_record_open(RECORD_NOTIFICATION); - plugin_state->num_entities = 0; - plugin_state->num_static_entities = 0; - - plugin_state->scene = INTRO; - plugin_state->gun_pos = 0; - plugin_state->view_height = 0; - plugin_state->init = true; - - plugin_state->up = false; - plugin_state->down = false; - plugin_state->left = false; - plugin_state->right = false; - plugin_state->fired = false; - plugin_state->gun_fired = false; -#ifdef SOUND - - plugin_state->music_instance = malloc(sizeof(MusicPlayer)); - plugin_state->music_instance->model = malloc(sizeof(MusicPlayerModel)); - memset( - plugin_state->music_instance->model->duration_history, - 0xff, - MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); - memset( - plugin_state->music_instance->model->semitone_history, - 0xff, - MUSIC_PLAYER_SEMITONE_HISTORY_SIZE); - plugin_state->music_instance->model->volume = 2; - - plugin_state->music_instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - //plugin_state->music_instance->view_port = view_port_alloc(); - - plugin_state->music_instance->worker = music_player_worker_alloc(); - //music_player_worker_set_volume(plugin_state->music_instance->worker, 0.75); - music_player_worker_set_volume( - plugin_state->music_instance->worker, - MUSIC_PLAYER_VOLUMES[plugin_state->music_instance->model->volume]); - plugin_state->intro_sound = true; - //init_sound(plugin_state->music_instance); -#endif -} - -static void doom_game_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - PluginEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -static void doom_game_tick(PluginState* const plugin_state) { - if(plugin_state->scene == GAME_PLAY) { - //fps(); - //player is alive - if(plugin_state->player.health > 0) { - if(plugin_state->up) { - plugin_state->player.velocity += - ((double)MOV_SPEED - plugin_state->player.velocity) * (double).4; - plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV; - //plugin_state->up = false; - } else if(plugin_state->down) { - plugin_state->player.velocity += - (-(double)MOV_SPEED - plugin_state->player.velocity) * (double).4; - plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV; - //plugin_state->down = false; - } else { - plugin_state->player.velocity *= (double).5; - plugin_state->jogging = fabs(plugin_state->player.velocity) * MOV_SPEED_INV; - } - - if(plugin_state->right) { - plugin_state->rot_speed = (double)ROT_SPEED * delta; - plugin_state->old_dir_x = plugin_state->player.dir.x; - plugin_state->player.dir.x = - plugin_state->player.dir.x * cos(-(plugin_state->rot_speed)) - - plugin_state->player.dir.y * sin(-(plugin_state->rot_speed)); - plugin_state->player.dir.y = - plugin_state->old_dir_x * sin(-(plugin_state->rot_speed)) + - plugin_state->player.dir.y * cos(-(plugin_state->rot_speed)); - plugin_state->old_plane_x = plugin_state->player.plane.x; - plugin_state->player.plane.x = - plugin_state->player.plane.x * cos(-(plugin_state->rot_speed)) - - plugin_state->player.plane.y * sin(-(plugin_state->rot_speed)); - plugin_state->player.plane.y = - plugin_state->old_plane_x * sin(-(plugin_state->rot_speed)) + - plugin_state->player.plane.y * cos(-(plugin_state->rot_speed)); - - //plugin_state->right = false; - } else if(plugin_state->left) { - plugin_state->rot_speed = (double)ROT_SPEED * delta; - plugin_state->old_dir_x = plugin_state->player.dir.x; - plugin_state->player.dir.x = - plugin_state->player.dir.x * cos(plugin_state->rot_speed) - - plugin_state->player.dir.y * sin(plugin_state->rot_speed); - plugin_state->player.dir.y = - plugin_state->old_dir_x * sin(plugin_state->rot_speed) + - plugin_state->player.dir.y * cos(plugin_state->rot_speed); - plugin_state->old_plane_x = plugin_state->player.plane.x; - plugin_state->player.plane.x = - plugin_state->player.plane.x * cos(plugin_state->rot_speed) - - plugin_state->player.plane.y * sin(plugin_state->rot_speed); - plugin_state->player.plane.y = - plugin_state->old_plane_x * sin(plugin_state->rot_speed) + - plugin_state->player.plane.y * cos(plugin_state->rot_speed); - //plugin_state->left = false; - } - plugin_state->view_height = - fabs(sin((double)furi_get_tick() * (double)JOGGING_SPEED)) * 6 * - plugin_state->jogging; - - if(plugin_state->gun_pos > GUN_TARGET_POS) { - // Right after fire - plugin_state->gun_pos -= 1; - } else if(plugin_state->gun_pos < GUN_TARGET_POS) { - plugin_state->gun_pos += 2; - } else if(!plugin_state->gun_fired && plugin_state->fired) { - //furi_hal_speaker_start(20480 / 10, 0.45f); - /*#ifdef SOUND - music_player_worker_start(plugin_state->music_instance->worker); -#endif*/ - plugin_state->gun_pos = GUN_SHOT_POS; - plugin_state->gun_fired = true; - plugin_state->fired = false; - fire(plugin_state); - - } else if(plugin_state->gun_fired && !plugin_state->fired) { - //furi_hal_speaker_stop(); - plugin_state->gun_fired = false; - - notification_message(plugin_state->notify, &sequence_short_sound); - - /*#ifdef SOUND - music_player_worker_stop(plugin_state->music_instance->worker); -#endif*/ - } - } else { - // Player is dead - if(plugin_state->view_height > -10) plugin_state->view_height--; - if(plugin_state->gun_pos > 1) plugin_state->gun_pos -= 2; - } - - if(fabs(plugin_state->player.velocity) > (double)0.003) { - updatePosition( - sto_level_1, - &(plugin_state->player.pos), - plugin_state->player.dir.x * plugin_state->player.velocity * delta, - plugin_state->player.dir.y * plugin_state->player.velocity * delta, - false, - plugin_state); - } else { - plugin_state->player.velocity = 0; - } - } -} - -int32_t doom_app() { - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); - PluginState* plugin_state = malloc(sizeof(PluginState)); - doom_state_init(plugin_state); - plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!plugin_state->mutex) { - FURI_LOG_E("Doom_game", "cannot create mutex\r\n"); - furi_record_close(RECORD_NOTIFICATION); - furi_message_queue_free(event_queue); - free(plugin_state); - return 255; - } - FuriTimer* timer = - furi_timer_alloc(doom_game_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 12); - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, plugin_state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - ////////////////////////////////// - plugin_state->init = false; - - PluginEvent event; -#ifdef SOUND - music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dsintro); - music_player_worker_start(plugin_state->music_instance->worker); -#endif - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); -#ifdef SOUND - furi_check( - furi_mutex_acquire(plugin_state->music_instance->model_mutex, FuriWaitForever) == - FuriStatusOk); -#endif - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.key == InputKeyBack) { - processing = false; -#ifdef SOUND - if(plugin_state->intro_sound) { - furi_mutex_release(plugin_state->music_instance->model_mutex); - music_player_worker_stop(plugin_state->music_instance->worker); - } -#endif - } - - if(event.input.type == InputTypePress) { - if(plugin_state->scene == INTRO && event.input.key == InputKeyOk) { - plugin_state->scene = GAME_PLAY; - initializeLevel(sto_level_1, plugin_state); -#ifdef SOUND - furi_mutex_release(plugin_state->music_instance->model_mutex); - music_player_worker_stop(plugin_state->music_instance->worker); - plugin_state->intro_sound = false; -#endif - goto skipintro; - } - - //While playing game - if(plugin_state->scene == GAME_PLAY) { - // If the player is alive - if(plugin_state->player.health > 0) { - //Player speed - if(event.input.key == InputKeyUp) { - plugin_state->up = true; - } else if(event.input.key == InputKeyDown) { - plugin_state->down = true; - } - // Player rotation - if(event.input.key == InputKeyRight) { - plugin_state->right = true; - } else if(event.input.key == InputKeyLeft) { - plugin_state->left = true; - } - if(event.input.key == InputKeyOk) { - /*#ifdef SOUND - music_player_worker_load_rtttl_from_string(plugin_state->music_instance->worker, dspistol); -#endif*/ - if(plugin_state->fired) { - plugin_state->fired = false; - } else { - plugin_state->fired = true; - } - } - } else { - // Player is dead - if(event.input.key == InputKeyOk) plugin_state->scene = INTRO; - } - } - } - if(event.input.type == InputTypeRelease) { - if(plugin_state->player.health > 0) { - //Player speed - if(event.input.key == InputKeyUp) { - plugin_state->up = false; - } else if(event.input.key == InputKeyDown) { - plugin_state->down = false; - } - // Player rotation - if(event.input.key == InputKeyRight) { - plugin_state->right = false; - } else if(event.input.key == InputKeyLeft) { - plugin_state->left = false; - } - } - } - } - - skipintro: - if(event.type == EventTypeTick) { - doom_game_tick(plugin_state); - } - } -#ifdef SOUND - furi_mutex_release(plugin_state->music_instance->model_mutex); -#endif - view_port_update(view_port); - furi_mutex_release(plugin_state->mutex); - } -#ifdef SOUND - music_player_worker_free(plugin_state->music_instance->worker); - furi_mutex_free(plugin_state->music_instance->model_mutex); - free(plugin_state->music_instance->model); - free(plugin_state->music_instance); -#endif - furi_record_close(RECORD_NOTIFICATION); - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_mutex_free(plugin_state->mutex); - furi_message_queue_free(event_queue); - free(plugin_state); - return 0; -} diff --git a/applications/external/doom/doom_10px.png b/applications/external/doom/doom_10px.png deleted file mode 100644 index 17fe22c8763a9e3b86fcd6116a4a51d3a1b820a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1772 zcmcIl&2QX99CaJ1Dv`n?><-!3Z4ycFTxWJA703jj71#v(sGrRV-pf=>fO1mC=-@Nzc{eGVLbbs&d zYwItrYnpa#cV}=QuWG!0^|JiEynpzMygXO#+^sdu?5Xdi`TdP!O}lb88y+@?@w*Wf zxk;EvxH->DiPp3m8}pLTBi`r$m^z?{^ z%-Fc8->)H1`+}4lcFJWP}IGSVZduzWo46zLRX9=5!0q`NUO^=kvTKk$JtZTyO_@Fj~;FGdcC#R|CEEX2WQ`Zy!OqNSDbkK&ih}WOVj&5eDvV# ngXbU8vG&vNKmRy>X-#|ikLy>z`b>X8okzRddxI};efY`WEeb3q diff --git a/applications/external/doom/doom_music_player_worker.c b/applications/external/doom/doom_music_player_worker.c deleted file mode 100644 index e81549625..000000000 --- a/applications/external/doom/doom_music_player_worker.c +++ /dev/null @@ -1,504 +0,0 @@ -#include "doom_music_player_worker.h" - -#include -#include - -#include -#include - -#include - -#define TAG "MusicPlayerWorker" - -#define MUSIC_PLAYER_FILETYPE "Flipper Music Format" -#define MUSIC_PLAYER_VERSION 0 - -#define SEMITONE_PAUSE 0xFF - -#define NOTE_C4 261.63f -#define NOTE_C4_SEMITONE (4.0f * 12.0f) -#define TWO_POW_TWELTH_ROOT 1.059463094359f - -typedef struct { - uint8_t semitone; - uint8_t duration; - uint8_t dots; -} NoteBlock; - -ARRAY_DEF(NoteBlockArray, NoteBlock, M_POD_OPLIST); - -struct MusicPlayerWorker { - FuriThread* thread; - bool should_work; - - MusicPlayerWorkerCallback callback; - void* callback_context; - - float volume; - uint32_t bpm; - uint32_t duration; - uint32_t octave; - NoteBlockArray_t notes; -}; - -static int32_t music_player_worker_thread_callback(void* context) { - furi_assert(context); - MusicPlayerWorker* instance = context; - - NoteBlockArray_it_t it; - NoteBlockArray_it(it, instance->notes); - if(furi_hal_speaker_acquire(1000)) { - while(instance->should_work) { - if(NoteBlockArray_end_p(it)) { - NoteBlockArray_it(it, instance->notes); - furi_delay_ms(10); - } else { - NoteBlock* note_block = NoteBlockArray_ref(it); - - float note_from_a4 = (float)note_block->semitone - NOTE_C4_SEMITONE; - float frequency = NOTE_C4 * powf(TWO_POW_TWELTH_ROOT, note_from_a4); - float duration = 60.0 * furi_kernel_get_tick_frequency() * 4 / instance->bpm / - note_block->duration; - uint32_t dots = note_block->dots; - while(dots > 0) { - duration += duration / 2; - dots--; - } - uint32_t next_tick = furi_get_tick() + duration; - float volume = instance->volume; - - if(instance->callback) { - instance->callback( - note_block->semitone, - note_block->dots, - note_block->duration, - 0.0, - instance->callback_context); - } - - furi_hal_speaker_stop(); - furi_hal_speaker_start(frequency, volume); - while(instance->should_work && furi_get_tick() < next_tick) { - volume *= 0.9945679; - furi_hal_speaker_set_volume(volume); - furi_delay_ms(2); - } - NoteBlockArray_next(it); - } - } - - furi_hal_speaker_stop(); - furi_hal_speaker_release(); - } else { - FURI_LOG_E(TAG, "Speaker system is busy with another process."); - } - - return 0; -} - -MusicPlayerWorker* music_player_worker_alloc() { - MusicPlayerWorker* instance = malloc(sizeof(MusicPlayerWorker)); - - NoteBlockArray_init(instance->notes); - - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "MusicPlayerWorker"); - furi_thread_set_stack_size(instance->thread, 1024); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, music_player_worker_thread_callback); - - instance->volume = 1.0f; - - return instance; -} - -void music_player_worker_free(MusicPlayerWorker* instance) { - furi_assert(instance); - furi_thread_free(instance->thread); - NoteBlockArray_clear(instance->notes); - free(instance); -} - -static bool is_digit(const char c) { - return isdigit(c) != 0; -} - -static bool is_letter(const char c) { - return islower(c) != 0 || isupper(c) != 0; -} - -static bool is_space(const char c) { - return c == ' ' || c == '\t'; -} - -static size_t extract_number(const char* string, uint32_t* number) { - size_t ret = 0; - while(is_digit(*string)) { - *number *= 10; - *number += (*string - '0'); - string++; - ret++; - } - return ret; -} - -static size_t extract_dots(const char* string, uint32_t* number) { - size_t ret = 0; - while(*string == '.') { - *number += 1; - string++; - ret++; - } - return ret; -} - -static size_t extract_char(const char* string, char* symbol) { - if(is_letter(*string)) { - *symbol = *string; - return 1; - } else { - return 0; - } -} - -static size_t extract_sharp(const char* string, char* symbol) { - if(*string == '#' || *string == '_') { - *symbol = '#'; - return 1; - } else { - return 0; - } -} - -static size_t skip_till(const char* string, const char symbol) { - size_t ret = 0; - while(*string != '\0' && *string != symbol) { - string++; - ret++; - } - if(*string != symbol) { - ret = 0; - } - return ret; -} - -static bool music_player_worker_add_note( - MusicPlayerWorker* instance, - uint8_t semitone, - uint8_t duration, - uint8_t dots) { - NoteBlock note_block; - - note_block.semitone = semitone; - note_block.duration = duration; - note_block.dots = dots; - - NoteBlockArray_push_back(instance->notes, note_block); - - return true; -} - -static int8_t note_to_semitone(const char note) { - switch(note) { - case 'C': - return 0; - // C# - case 'D': - return 2; - // D# - case 'E': - return 4; - case 'F': - return 5; - // F# - case 'G': - return 7; - // G# - case 'A': - return 9; - // A# - case 'B': - return 11; - default: - return 0; - } -} - -static bool music_player_worker_parse_notes(MusicPlayerWorker* instance, const char* string) { - const char* cursor = string; - bool result = true; - - while(*cursor != '\0') { - if(!is_space(*cursor)) { - uint32_t duration = 0; - char note_char = '\0'; - char sharp_char = '\0'; - uint32_t octave = 0; - uint32_t dots = 0; - - // Parsing - cursor += extract_number(cursor, &duration); - cursor += extract_char(cursor, ¬e_char); - cursor += extract_sharp(cursor, &sharp_char); - cursor += extract_number(cursor, &octave); - cursor += extract_dots(cursor, &dots); - - // Post processing - note_char = toupper(note_char); - if(!duration) { - duration = instance->duration; - } - if(!octave) { - octave = instance->octave; - } - - // Validation - bool is_valid = true; - is_valid &= (duration >= 1 && duration <= 128); - is_valid &= ((note_char >= 'A' && note_char <= 'G') || note_char == 'P'); - is_valid &= (sharp_char == '#' || sharp_char == '\0'); - is_valid &= (octave <= 16); - is_valid &= (dots <= 16); - if(!is_valid) { - FURI_LOG_E( - TAG, - "Invalid note: %lu%c%c%lu.%lu", - duration, - note_char == '\0' ? '_' : note_char, - sharp_char == '\0' ? '_' : sharp_char, - octave, - dots); - result = false; - break; - } - - // Note to semitones - uint8_t semitone = 0; - if(note_char == 'P') { - semitone = SEMITONE_PAUSE; - } else { - semitone += octave * 12; - semitone += note_to_semitone(note_char); - semitone += sharp_char == '#' ? 1 : 0; - } - - if(music_player_worker_add_note(instance, semitone, duration, dots)) { - FURI_LOG_D( - TAG, - "Added note: %c%c%lu.%lu = %u %lu", - note_char == '\0' ? '_' : note_char, - sharp_char == '\0' ? '_' : sharp_char, - octave, - dots, - semitone, - duration); - } else { - FURI_LOG_E( - TAG, - "Invalid note: %c%c%lu.%lu = %u %lu", - note_char == '\0' ? '_' : note_char, - sharp_char == '\0' ? '_' : sharp_char, - octave, - dots, - semitone, - duration); - } - cursor += skip_till(cursor, ','); - } - - if(*cursor != '\0') cursor++; - } - - return result; -} - -bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path) { - furi_assert(instance); - furi_assert(file_path); - - bool ret = false; - if(strcasestr(file_path, ".fmf")) { - ret = music_player_worker_load_fmf_from_file(instance, file_path); - } else { - ret = music_player_worker_load_rtttl_from_file(instance, file_path); - } - return ret; -} - -bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path) { - furi_assert(instance); - furi_assert(file_path); - - bool result = false; - FuriString* temp_str; - temp_str = furi_string_alloc(); - - Storage* storage = furi_record_open(RECORD_STORAGE); - FlipperFormat* file = flipper_format_file_alloc(storage); - - do { - if(!flipper_format_file_open_existing(file, file_path)) break; - - uint32_t version = 0; - if(!flipper_format_read_header(file, temp_str, &version)) break; - if(furi_string_cmp_str(temp_str, MUSIC_PLAYER_FILETYPE) || - (version != MUSIC_PLAYER_VERSION)) { - FURI_LOG_E(TAG, "Incorrect file format or version"); - break; - } - - if(!flipper_format_read_uint32(file, "BPM", &instance->bpm, 1)) { - FURI_LOG_E(TAG, "BPM is missing"); - break; - } - if(!flipper_format_read_uint32(file, "Duration", &instance->duration, 1)) { - FURI_LOG_E(TAG, "Duration is missing"); - break; - } - if(!flipper_format_read_uint32(file, "Octave", &instance->octave, 1)) { - FURI_LOG_E(TAG, "Octave is missing"); - break; - } - - if(!flipper_format_read_string(file, "Notes", temp_str)) { - FURI_LOG_E(TAG, "Notes is missing"); - break; - } - - if(!music_player_worker_parse_notes(instance, furi_string_get_cstr(temp_str))) { - break; - } - - result = true; - } while(false); - - furi_record_close(RECORD_STORAGE); - flipper_format_free(file); - furi_string_free(temp_str); - - return result; -} - -bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path) { - furi_assert(instance); - furi_assert(file_path); - - bool result = false; - FuriString* content; - content = furi_string_alloc(); - Storage* storage = furi_record_open(RECORD_STORAGE); - File* file = storage_file_alloc(storage); - - do { - if(!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) { - FURI_LOG_E(TAG, "Unable to open file"); - break; - }; - - uint16_t ret = 0; - do { - uint8_t buffer[65] = {0}; - ret = storage_file_read(file, buffer, sizeof(buffer) - 1); - for(size_t i = 0; i < ret; i++) { - furi_string_push_back(content, buffer[i]); - } - } while(ret > 0); - - furi_string_trim(content); - if(!furi_string_size(content)) { - FURI_LOG_E(TAG, "Empty file"); - break; - } - - if(!music_player_worker_load_rtttl_from_string(instance, furi_string_get_cstr(content))) { - FURI_LOG_E(TAG, "Invalid file content"); - break; - } - - result = true; - } while(0); - - storage_file_free(file); - furi_record_close(RECORD_STORAGE); - furi_string_free(content); - - return result; -} - -bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string) { - furi_assert(instance); - - const char* cursor = string; - - // Skip name - cursor += skip_till(cursor, ':'); - if(*cursor != ':') { - return false; - } - - // Duration - cursor += skip_till(cursor, '='); - if(*cursor != '=') { - return false; - } - cursor++; - cursor += extract_number(cursor, &instance->duration); - - // Octave - cursor += skip_till(cursor, '='); - if(*cursor != '=') { - return false; - } - cursor++; - cursor += extract_number(cursor, &instance->octave); - - // BPM - cursor += skip_till(cursor, '='); - if(*cursor != '=') { - return false; - } - cursor++; - cursor += extract_number(cursor, &instance->bpm); - - // Notes - cursor += skip_till(cursor, ':'); - if(*cursor != ':') { - return false; - } - cursor++; - if(!music_player_worker_parse_notes(instance, cursor)) { - return false; - } - - return true; -} - -void music_player_worker_set_callback( - MusicPlayerWorker* instance, - MusicPlayerWorkerCallback callback, - void* context) { - furi_assert(instance); - instance->callback = callback; - instance->callback_context = context; -} - -void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume) { - furi_assert(instance); - instance->volume = volume; -} - -void music_player_worker_start(MusicPlayerWorker* instance) { - furi_assert(instance); - furi_assert(instance->should_work == false); - - instance->should_work = true; - furi_thread_start(instance->thread); -} - -void music_player_worker_stop(MusicPlayerWorker* instance) { - furi_assert(instance); - furi_assert(instance->should_work == true); - - instance->should_work = false; - furi_thread_join(instance->thread); -} diff --git a/applications/external/doom/doom_music_player_worker.h b/applications/external/doom/doom_music_player_worker.h deleted file mode 100644 index 9958a9273..000000000 --- a/applications/external/doom/doom_music_player_worker.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef void (*MusicPlayerWorkerCallback)( - uint8_t semitone, - uint8_t dots, - uint8_t duration, - float position, - void* context); - -typedef struct MusicPlayerWorker MusicPlayerWorker; - -MusicPlayerWorker* music_player_worker_alloc(); - -void music_player_worker_free(MusicPlayerWorker* instance); - -bool music_player_worker_load(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_fmf_from_file(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_rtttl_from_file(MusicPlayerWorker* instance, const char* file_path); - -bool music_player_worker_load_rtttl_from_string(MusicPlayerWorker* instance, const char* string); - -void music_player_worker_set_callback( - MusicPlayerWorker* instance, - MusicPlayerWorkerCallback callback, - void* context); - -void music_player_worker_set_volume(MusicPlayerWorker* instance, float volume); - -void music_player_worker_start(MusicPlayerWorker* instance); - -void music_player_worker_stop(MusicPlayerWorker* instance); - -#ifdef __cplusplus -} -#endif diff --git a/applications/external/doom/entities.c b/applications/external/doom/entities.c deleted file mode 100644 index 86c7f6ae1..000000000 --- a/applications/external/doom/entities.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "entities.h" - -//extern "C" -/*Player create_player(double x, double y){ - return {create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100, 0}; -}*/ - -Player create_player(double x, double y) { - Player p; - p.pos = create_coords((double)x + (double)0.5, (double)y + (double)0.5); - p.dir = create_coords(1, 0); - p.plane = create_coords(0, -0.66); - p.velocity = 0; - p.health = 100; - p.keys = 0; - return p; //{create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100, 0}; -} - -//extern "C" -Entity - create_entity(uint8_t type, uint8_t x, uint8_t y, uint8_t initialState, uint8_t initialHealth) { - UID uid = create_uid(type, x, y); - Coords pos = create_coords((double)x + (double).5, (double)y + (double).5); - Entity new_entity; // = { uid, pos, initialState, initialHealth, 0, 0 }; - new_entity.uid = uid; - new_entity.pos = pos; - new_entity.state = initialState; - new_entity.health = initialHealth; - new_entity.distance = 0; - new_entity.timer = 0; - return new_entity; -} - -//extern "C" -StaticEntity crate_static_entity(UID uid, uint8_t x, uint8_t y, bool active) { - StaticEntity ent; - ent.uid = uid; - ent.x = x; - ent.y = y; - ent.active = active; - return ent; -} \ No newline at end of file diff --git a/applications/external/doom/entities.h b/applications/external/doom/entities.h deleted file mode 100644 index ef5eb1a78..000000000 --- a/applications/external/doom/entities.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _entities_h -#define _entities_h -#include -#include -#include "types.h" - -// Shortcuts -//#define create_player(x, y) {create_coords((double) x + (double)0.5, (double) y + (double)0.5), create_coords(1, 0), create_coords(0, -0.66), 0, 100} - -#define create_enemy(x, y) create_entity(E_ENEMY, x, y, S_STAND, 50) -#define create_medikit(x, y) create_entity(E_MEDIKIT, x, y, S_STAND, 0) -#define create_key(x, y) create_entity(E_KEY, x, y, S_STAND, 0) -#define create_fireball(x, y, dir) create_entity(E_FIREBALL, x, y, S_STAND, dir) -#define create_door(x, y) create_entity(E_DOOR, x, y, S_STAND, 0) - -// entity statuses -#define S_STAND 0 -#define S_ALERT 1 -#define S_FIRING 2 -#define S_MELEE 3 -#define S_HIT 4 -#define S_DEAD 5 -#define S_HIDDEN 6 -#define S_OPEN 7 -#define S_CLOSE 8 - -typedef struct Player { - Coords pos; - Coords dir; - Coords plane; - double velocity; - uint8_t health; - uint8_t keys; -} Player; - -typedef struct Entity { - UID uid; - Coords pos; - uint8_t state; - uint8_t health; // angle for fireballs - uint8_t distance; - uint8_t timer; -} Entity; - -typedef struct StaticEntity { - UID uid; - uint8_t x; - uint8_t y; - bool active; -} StaticEntity; - -Entity - create_entity(uint8_t type, uint8_t x, uint8_t y, uint8_t initialState, uint8_t initialHealth); -StaticEntity create_static_entity(UID uid, uint8_t x, uint8_t y, bool active); -Player create_player(double x, double y); -#endif diff --git a/applications/external/doom/level.h b/applications/external/doom/level.h deleted file mode 100644 index 4d92a1cc6..000000000 --- a/applications/external/doom/level.h +++ /dev/null @@ -1,188 +0,0 @@ -#ifndef _level_h -#define _level_h - -#include "constants.h" - -/* - Based on E1M1 from Wolfenstein 3D - - ################################################################ - #############################...........######################## - ######....###################........E..######################## - ######....########..........#...........#...#################### - ######.....#######..........L.....E.......M.#################### - ######.....#######..........#...........#...#################### - ##################...########...........######################## - ######.........###...########...........######################## - ######.........###...#############D############################# - ######.........#......E##########...############################ - ######....E....D...E...##########...############################ - ######.........#.......##########...############################ - ######....E....##################...############################ - #...##.........##################...############################ - #.K.######D######################...############################ - #...#####...###############...#E.....K########################## - ##D######...###############..####...############################ - #...#####...###############..####...############################ - #...#...#...###############..####...############################ - #...D...#...#####################...############################ - #...#...#...#####################...############################ - #...######D#######################L############################# - #.E.##.........#################.....#################........## - #...##.........############...............############........## - #...##...E.....############...............############........## - #....#.........############...E.......E....#.........#........## - #....L....K....############................D....E....D....E...## - #....#.........############................#.........#........## - #...##.....E...############...............####....####........## - #...##.........############...............#####..#####.....M..## - #...##.........#################.....##########..#####........## - #...######L#######################D############..############### - #...#####...#####################...###########..############### - #E.E#####...#####################...###########..############### - #...#...#...#####################.E.###########..############### - #...D.M.#...#####################...###########..############### - #...#...#...#####################...###########..###.#.#.#.##### - #...#####...#####################...###########...#.........#### - #...#####...#####################...###########...D....E..K.#### - #................##......########...###########...#.........#### - #....E........E...L...E...X######...################.#.#.#.##### - #................##......########...############################ - #################################...############################ - #############..#..#..#############L############################# - ###########....#..#.########....#...#....####################### - #############.....##########.P..D...D....####################### - ############################....#...#....####################### - ##############..#################...############################ - ##############..############....#...#....####################### - ############################....D...D....####################### - ############################....#...#....####################### - #################################...############################ - ############################.............####################### - ############################..........EK.####################### - ############################.............####################### - ################################################################ -*/ - -/* - Same map above built from some regexp replacements using the legend above. - Using this way lets me use only 4 bit to store each block -*/ -const uint8_t sto_level_1[LEVEL_SIZE] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x02, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, - 0x00, 0x20, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x2F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x02, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x20, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x90, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF2, - 0x00, 0x00, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x4F, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x20, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x02, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x20, - 0x00, 0x00, 0x00, 0x20, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0x05, 0x00, 0x00, 0x90, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0x04, 0x00, 0x00, 0x20, 0x00, 0xFF, - 0xF0, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x02, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x08, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x4F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF2, 0x02, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0x40, 0x80, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x40, 0x00, 0x02, 0x00, 0x90, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, - 0xF0, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x50, 0x00, 0x20, 0x00, 0x7F, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0x0F, 0x0F, 0x0F, 0xFF, 0xFF, - 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xF0, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x0F, 0x00, 0xF0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x0F, 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, - 0x40, 0x00, 0x40, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x40, 0x00, 0x40, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0xF0, 0x00, 0xF0, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xF0, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x29, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, -}; - -#endif diff --git a/applications/external/doom/sound.h b/applications/external/doom/sound.h deleted file mode 100644 index 514381334..000000000 --- a/applications/external/doom/sound.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef sound_h -#define sound_h -#include -#include -#include -#include "doom_music_player_worker.h" - -//static const char dspistol[] = "AnyConv:d=,o=,b=120:408,40p,40p,40p,40p,405,40p,40p,40p,405,30p.,30p.,30p.,13p"; -static const char dsintro[] = - "Doom:d=32,o=4,b=56:f,f,f5,f,f,d#5,f,f,c#5,f,f,b,f,f,c5,c#5,f,f,f5,f,f,d#5,f,f,c#5,f,f,8b.,f,f,f5,f,f,d#5,f,f,c#5,f,f,b,f,f,c5,c#5,f,f,f5,f,f,d#5,f,f,c#5,f,f,8b.,a#,a#,a#5,a#,a#,g#5,a#,a#,f#5,a#,a#,e5,a#,a#,f5,f#5,a#,a#,a#5,a#,a#,g#5,a#,a#,f#5,a#,a#,8e5"; -//static const char dsgetpow[] = "dsgetpow:d=,o=,b=120:407,40p,30.6,407,40p,406,40p,407,40p,40p,407,30p.,407"; -//static const char dsnoway[] = "dsnoway:d=,o=,b=120:407,30.4"; - -#define MUSIC_PLAYER_SEMITONE_HISTORY_SIZE 4 -static const float MUSIC_PLAYER_VOLUMES[] = {0, .25, .5, .75, 1}; - -typedef struct { - uint8_t semitone_history[MUSIC_PLAYER_SEMITONE_HISTORY_SIZE]; - uint8_t duration_history[MUSIC_PLAYER_SEMITONE_HISTORY_SIZE]; - - uint8_t volume; - uint8_t semitone; - uint8_t dots; - uint8_t duration; - float position; -} MusicPlayerModel; - -typedef struct { - MusicPlayerModel* model; - MusicPlayerWorker* worker; - FuriMutex** model_mutex; -} MusicPlayer; - -#endif \ No newline at end of file diff --git a/applications/external/doom/types.c b/applications/external/doom/types.c deleted file mode 100644 index 6b55d56a7..000000000 --- a/applications/external/doom/types.c +++ /dev/null @@ -1,33 +0,0 @@ -#include "types.h" - -/*template -inline T sq(T value) { - return value * value; -}*/ - -double sq(double val) { - return val * val; -} - -//extern "C" -Coords create_coords(double x, double y) { - Coords cord; - cord.x = x; - cord.y = y; - return cord; -} - -//extern "C" -uint8_t coords_distance(Coords* a, Coords* b) { - return sqrt(sq(a->x - b->x) + sq(a->y - b->y)) * 20; -} - -//extern "C" -UID create_uid(uint8_t type, uint8_t x, uint8_t y) { - return ((y << 6) | x) << 4 | type; -} - -//extern "C" -uint8_t uid_get_type(UID uid) { - return uid & 0x0F; -} diff --git a/applications/external/doom/types.h b/applications/external/doom/types.h deleted file mode 100644 index b8579f645..000000000 --- a/applications/external/doom/types.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _types_h -#define _types_h - -#include -#include -//#include "constants.h" - -#define UID_null 0 - -// Entity types (legend applies to level.h) -#define E_FLOOR 0x0 // . (also null) -#define E_WALL 0xF // # -#define E_PLAYER 0x1 // P -#define E_ENEMY 0x2 // E -#define E_DOOR 0x4 // D -#define E_LOCKEDDOOR 0x5 // L -#define E_EXIT 0x7 // X -// collectable entities >= 0x8 -#define E_MEDIKIT 0x8 // M -#define E_KEY 0x9 // K -#define E_FIREBALL 0xA // not in map - -typedef uint16_t UID; -typedef uint8_t EType; - -typedef struct Coords { - double x; - double y; -} Coords; - -UID create_uid(EType type, uint8_t x, uint8_t y); -EType uid_get_type(UID uid); -Coords create_coords(double x, double y); -uint8_t coords_distance(Coords* a, Coords* b); - -#endif diff --git a/applications/external/flappy_bird/application.fam b/applications/external/flappy_bird/application.fam deleted file mode 100644 index 625c5f66c..000000000 --- a/applications/external/flappy_bird/application.fam +++ /dev/null @@ -1,14 +0,0 @@ -App( - appid="flappy_bird", - name="Flappy Bird", - apptype=FlipperAppType.EXTERNAL, - entry_point="flappy_game_app", - requires=["gui"], - stack_size=4 * 1024, - fap_icon="flappy_10px.png", - fap_category="Games", - fap_icon_assets="assets", - fap_author="@DroomOne & @xMasterX", - fap_version="1.0", - fap_description="Flappy Bird Game", -) diff --git a/applications/external/flappy_bird/assets/bird_01.png b/applications/external/flappy_bird/assets/bird_01.png deleted file mode 100644 index 0cd1870536fa29d7db22e8f916d3a2f1b7320057..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngj$P6TBb-Ky}DYgKg5ZC|z{{xw!hc4FvDK$?Q z#}JO|$q97_4j4B&PH1)vU}@3Hl8BlmG3&KN%q$6=EQuS^3~4Lb?u&#LX#jOFc)I$z JtaD0e0s#Iu9~l4u diff --git a/applications/external/flappy_bird/assets/bird_02.png b/applications/external/flappy_bird/assets/bird_02.png deleted file mode 100644 index 3c37cdb8b8b47f302e22225f07023a9feb7dcead..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngj$P6TBb-Ky}DYgKg5ZC|z{{xw!hc4FvDNRoo z#}JO|$q97_4j4B&PH1)vXjvH4vT$kJ!j+u|xAq-e)Y-VWt#L0SLv}se^@9R+D}kCA NJYD@<);T3K0RRxqCCdN+ diff --git a/applications/external/flappy_bird/assets/bird_03.png b/applications/external/flappy_bird/assets/bird_03.png deleted file mode 100644 index a111ce163c6a06870a345bb9fc65976ae3ec3586..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^{6Ngj$P6TBb-Ky}DYgKg5ZC|z{{xw!hc4FvDNRoo z#}JO|$q97_4j4B&PH0{j)Uq(NW#P)UgG)OPZt8Pf*y*^at#L0SL!mF*_oJ3CRsuCK Nc)I$ztaD0e0st5aCKdny diff --git a/applications/external/flappy_bird/flappy_10px.png b/applications/external/flappy_bird/flappy_10px.png deleted file mode 100644 index d624d3571225bc955e857d924b75144c66178722..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1787 zcmcIlPly{;93EFF?&5k8L_7_%hg#~JdGjX8{GsWxO|~Y`S(j~aw;;4{-g`-g&CDBT zW;fY|UV7`L2SHTuBBBQm9z+n7RlMj$M7@dN(SuN`$AVCQlgy-5+U;H%lFZBGd*APS z-|w6EZf*xdOOE{jR$N~S3KO7VGW^3m$PqMW)C z_IC0e|B}aKq*E>fp--X&(28<4t@g#T82oB#!#qzs!x)dp z`qm4M**b}0U{P@fTWs*sA-wVrJUHdWd}H*Q(Z8>E!ke-L@|GsTP_)J%-!@H zN03^>G?8t)E((I0iJS(mqkx;(;TUtmf{N|6G=xWojviz!RB>Q*9A@LdvQeK92MJzt zkVA!q>;`eE#qA()>Y94LZcC12>PrspTAIq4*OzHTAwOY62f|3=L6K%)hgEdK3|ebFZ4+W4O)BG7Mll^>5Q?WJxrymx_`X%lQsScN-u3?LmCeR?3{*HEXF9dm|0Vd|M%;DzpKowL7IzhW~B`m=wNQh z`6^5l65|p^Aw7UU2szJB)m&n}%={Gzk) z*U`tPyKlAXN1u1UzWsyu<@>iUZr|m - -#include "flappy_bird_icons.h" -#include -#include -#include -#include -#include - -#define TAG "Flappy" -#define DEBUG false - -#define FLAPPY_BIRD_HEIGHT 15 -#define FLAPPY_BIRD_WIDTH 10 - -#define FLAPPY_PILAR_MAX 6 -#define FLAPPY_PILAR_DIST 35 - -#define FLAPPY_GAB_HEIGHT 25 -#define FLAPPY_GAB_WIDTH 10 - -#define FLAPPY_GRAVITY_JUMP -1.1 -#define FLAPPY_GRAVITY_TICK 0.15 - -#define FLIPPER_LCD_WIDTH 128 -#define FLIPPER_LCD_HEIGHT 64 - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef enum { BirdState0 = 0, BirdState1, BirdState2, BirdStateMAX } BirdState; - -const Icon* bird_states[BirdStateMAX] = { - &I_bird_01, - &I_bird_02, - &I_bird_03, -}; - -typedef struct { - int x; - int y; -} POINT; - -typedef struct { - float gravity; - POINT point; -} BIRD; - -typedef struct { - POINT point; - int height; - int visible; - bool passed; -} PILAR; - -typedef enum { - GameStateLife, - GameStateGameOver, -} State; - -typedef struct { - BIRD bird; - int points; - int pilars_count; - PILAR pilars[FLAPPY_PILAR_MAX]; - bool debug; - State state; - FuriMutex* mutex; -} GameState; - -typedef struct { - EventType type; - InputEvent input; -} GameEvent; - -typedef enum { - DirectionUp, - DirectionRight, - DirectionDown, - DirectionLeft, -} Direction; - -static void flappy_game_random_pilar(GameState* const game_state) { - PILAR pilar; - - pilar.passed = false; - pilar.visible = 1; - pilar.height = random() % (FLIPPER_LCD_HEIGHT - FLAPPY_GAB_HEIGHT) + 1; - pilar.point.y = 0; - pilar.point.x = FLIPPER_LCD_WIDTH + FLAPPY_GAB_WIDTH + 1; - - game_state->pilars_count++; - game_state->pilars[game_state->pilars_count % FLAPPY_PILAR_MAX] = pilar; -} - -static void flappy_game_state_init(GameState* const game_state) { - BIRD bird; - bird.gravity = 0.0f; - bird.point.x = 15; - bird.point.y = 32; - - game_state->debug = DEBUG; - game_state->bird = bird; - game_state->pilars_count = 0; - game_state->points = 0; - game_state->state = GameStateLife; - memset(game_state->pilars, 0, sizeof(game_state->pilars)); - - flappy_game_random_pilar(game_state); -} - -static void flappy_game_state_free(GameState* const game_state) { - free(game_state); -} - -static void flappy_game_tick(GameState* const game_state) { - if(game_state->state == GameStateLife) { - if(!game_state->debug) { - game_state->bird.gravity += FLAPPY_GRAVITY_TICK; - game_state->bird.point.y += game_state->bird.gravity; - } - - // Checking the location of the last respawned pilar. - PILAR* pilar = &game_state->pilars[game_state->pilars_count % FLAPPY_PILAR_MAX]; - if(pilar->point.x == (FLIPPER_LCD_WIDTH - FLAPPY_PILAR_DIST)) - flappy_game_random_pilar(game_state); - - // Updating the position/status of the pilars (visiblity, posotion, game points) - // | | | | | - // | | | | | - // |__| | |__| - // _____X | X_____ - // | | | | | // [Pos + Width of pilar] >= [Bird Pos] - // |_____| | |_____| - // X <----> | X <-> - // Bird Pos + Lenght of the bird] >= [Pilar] - for(int i = 0; i < FLAPPY_PILAR_MAX; i++) { - PILAR* pilar = &game_state->pilars[i]; - if(pilar != NULL && pilar->visible && game_state->state == GameStateLife) { - pilar->point.x--; - if(game_state->bird.point.x >= pilar->point.x + FLAPPY_GAB_WIDTH && - pilar->passed == false) { - pilar->passed = true; - game_state->points++; - } - if(pilar->point.x < -FLAPPY_GAB_WIDTH) pilar->visible = 0; - - if(game_state->bird.point.y <= 0 - FLAPPY_BIRD_WIDTH) { - game_state->bird.point.y = 64; - } - - if(game_state->bird.point.y > 64 - FLAPPY_BIRD_WIDTH) { - game_state->bird.point.y = FLIPPER_LCD_HEIGHT - FLAPPY_BIRD_WIDTH; - } - - // Bird inbetween pipes - if((game_state->bird.point.x + FLAPPY_BIRD_HEIGHT >= pilar->point.x) && - (game_state->bird.point.x <= pilar->point.x + FLAPPY_GAB_WIDTH)) { - // Bird below Bottom Pipe - if(game_state->bird.point.y + FLAPPY_BIRD_WIDTH - 2 >= - pilar->height + FLAPPY_GAB_HEIGHT) { - game_state->state = GameStateGameOver; - break; - } - - // Bird above Upper Pipe - if(game_state->bird.point.y < pilar->height) { - game_state->state = GameStateGameOver; - break; - } - } - } - } - } -} - -static void flappy_game_flap(GameState* const game_state) { - game_state->bird.gravity = FLAPPY_GRAVITY_JUMP; -} - -static void flappy_game_render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const GameState* game_state = ctx; - furi_mutex_acquire(game_state->mutex, FuriWaitForever); - - canvas_draw_frame(canvas, 0, 0, 128, 64); - - if(game_state->state == GameStateLife) { - // Pilars - for(int i = 0; i < FLAPPY_PILAR_MAX; i++) { - const PILAR* pilar = &game_state->pilars[i]; - if(pilar != NULL && pilar->visible == 1) { - canvas_draw_frame( - canvas, pilar->point.x, pilar->point.y, FLAPPY_GAB_WIDTH, pilar->height); - - canvas_draw_frame( - canvas, pilar->point.x + 1, pilar->point.y, FLAPPY_GAB_WIDTH, pilar->height); - - canvas_draw_frame( - canvas, - pilar->point.x + 2, - pilar->point.y, - FLAPPY_GAB_WIDTH - 1, - pilar->height); - - canvas_draw_frame( - canvas, - pilar->point.x, - pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT, - FLAPPY_GAB_WIDTH, - FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT); - - canvas_draw_frame( - canvas, - pilar->point.x + 1, - pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT, - FLAPPY_GAB_WIDTH - 1, - FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT); - - canvas_draw_frame( - canvas, - pilar->point.x + 2, - pilar->point.y + pilar->height + FLAPPY_GAB_HEIGHT, - FLAPPY_GAB_WIDTH - 1, - FLIPPER_LCD_HEIGHT - pilar->height - FLAPPY_GAB_HEIGHT); - } - } - - // Switch animation - BirdState bird_state = BirdState1; - if(game_state->bird.gravity < -0.5) - bird_state = BirdState0; - else if(game_state->bird.gravity > 0.5) - bird_state = BirdState2; - - canvas_draw_icon( - canvas, game_state->bird.point.x, game_state->bird.point.y, bird_states[bird_state]); - - canvas_set_font(canvas, FontSecondary); - char buffer[12]; - snprintf(buffer, sizeof(buffer), "Score: %u", game_state->points); - canvas_draw_str_aligned(canvas, 100, 12, AlignCenter, AlignBottom, buffer); - - if(game_state->debug) { - char coordinates[20]; - snprintf(coordinates, sizeof(coordinates), "Y: %u", game_state->bird.point.y); - canvas_draw_str_aligned(canvas, 1, 12, AlignCenter, AlignBottom, coordinates); - } - } - - if(game_state->state == GameStateGameOver) { - // Screen is 128x64 px - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 34, 20, 62, 24); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 34, 20, 62, 24); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 37, 31, "Game Over"); - - canvas_set_font(canvas, FontSecondary); - char buffer[12]; - snprintf(buffer, sizeof(buffer), "Score: %u", game_state->points); - canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); - } - - furi_mutex_release(game_state->mutex); -} - -static void flappy_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void flappy_game_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -int32_t flappy_game_app(void* p) { - UNUSED(p); - int32_t return_code = 0; - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); - - GameState* game_state = malloc(sizeof(GameState)); - flappy_game_state_init(game_state); - - game_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!game_state->mutex) { - FURI_LOG_E(TAG, "cannot create mutex\r\n"); - return_code = 255; - goto free_and_exit; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, flappy_game_render_callback, game_state); - view_port_input_callback_set(view_port, flappy_game_input_callback, event_queue); - - FuriTimer* timer = - furi_timer_alloc(flappy_game_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 25); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - GameEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(game_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - if(game_state->state == GameStateLife) { - flappy_game_flap(game_state); - } - - break; - case InputKeyDown: - break; - case InputKeyRight: - break; - case InputKeyLeft: - break; - case InputKeyOk: - if(game_state->state == GameStateGameOver) { - flappy_game_state_init(game_state); - } - - if(game_state->state == GameStateLife) { - flappy_game_flap(game_state); - } - - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } else if(event.type == EventTypeTick) { - flappy_game_tick(game_state); - } - } - - view_port_update(view_port); - furi_mutex_release(game_state->mutex); - } - - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_mutex_free(game_state->mutex); - -free_and_exit: - flappy_game_state_free(game_state); - furi_message_queue_free(event_queue); - - return return_code; -} diff --git a/applications/external/game_of_life/application.fam b/applications/external/game_of_life/application.fam deleted file mode 100644 index a4de9ff40..000000000 --- a/applications/external/game_of_life/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="gameoflife", - name="Game of Life", - apptype=FlipperAppType.EXTERNAL, - entry_point="game_of_life_app", - cdefines=["APP_GAMEOFLIFE_GAME"], - requires=["gui"], - stack_size=2 * 1024, - fap_icon="golIcon.png", - fap_category="Games", - fap_author="@tgxn (original by @itsyourbedtime)", - fap_weburl="https://github.com/tgxn/flipperzero-firmware/blob/dev/applications/game_of_life/game_of_life.c", - fap_version="1.0", - fap_description="Life, is a cellular automaton devised by the British mathematician John Horton Conway in 1970.", -) diff --git a/applications/external/game_of_life/game_of_life.c b/applications/external/game_of_life/game_of_life.c deleted file mode 100644 index 8629062b8..000000000 --- a/applications/external/game_of_life/game_of_life.c +++ /dev/null @@ -1,164 +0,0 @@ -#include -#include - -#include -#include - -#define SCREEN_WIDTH 128 -#define SCREEN_HEIGHT 64 -#define TOTAL_PIXELS SCREEN_WIDTH* SCREEN_HEIGHT - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} AppEvent; - -typedef struct { - bool revive; - int evo; - FuriMutex* mutex; -} State; - -unsigned char new[TOTAL_PIXELS] = {}; -unsigned char old[TOTAL_PIXELS] = {}; -unsigned char* fields[] = {new, old}; - -int current = 0; -int next = 1; - -unsigned char get_cell(int x, int y) { - if(x <= 0 || x >= SCREEN_WIDTH) return 0; - if(y <= 0 || y >= SCREEN_HEIGHT) return 0; - - int pix = (y * SCREEN_WIDTH) + x; - return fields[current][pix]; -} - -int count_neightbors(int x, int y) { - return get_cell(x + 1, y - 1) + get_cell(x - 1, y - 1) + get_cell(x - 1, y + 1) + - get_cell(x + 1, y + 1) + get_cell(x + 1, y) + get_cell(x - 1, y) + get_cell(x, y - 1) + - get_cell(x, y + 1); -} - -static void update_field(State* state) { - if(state->revive) { - for(int i = 0; i < TOTAL_PIXELS; ++i) { - if((random() % 100) == 1) { - fields[current][i] = 1; - } - state->revive = false; - } - } - - for(int i = 0; i < TOTAL_PIXELS; ++i) { - int x = i % SCREEN_WIDTH; - int y = (int)(i / SCREEN_WIDTH); - - int v = get_cell(x, y); - int n = count_neightbors(x, y); - - if(v && n == 3) { - ++state->evo; - } else if(v && (n < 2 || n > 3)) { - ++state->evo; - v = 0; - } else if(!v && n == 3) { - ++state->evo; - v = 1; - } - - fields[next][i] = v; - } - - next ^= current; - current ^= next; - next ^= current; - - if(state->evo < TOTAL_PIXELS) { - state->revive = true; - state->evo = 0; - } -} - -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - AppEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, 0); -} - -static void render_callback(Canvas* canvas, void* ctx) { - //furi_assert(ctx); - State* state = ctx; - furi_mutex_acquire(state->mutex, FuriWaitForever); - - canvas_clear(canvas); - - for(int i = 0; i < TOTAL_PIXELS; ++i) { - int x = i % SCREEN_WIDTH; - int y = (int)(i / SCREEN_WIDTH); - if(fields[current][i] == 1) canvas_draw_dot(canvas, x, y); - } - furi_mutex_release(state->mutex); -} - -int32_t game_of_life_app(void* p) { - UNUSED(p); - srand(DWT->CYCCNT); - - FuriMessageQueue* event_queue = furi_message_queue_alloc(1, sizeof(AppEvent)); - furi_check(event_queue); - - State* _state = malloc(sizeof(State)); - - _state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!_state->mutex) { - printf("cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(_state); - return 255; - } - - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, _state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - AppEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25); - furi_mutex_acquire(_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk && event.type == EventTypeKey && - event.input.type == InputTypePress) { - if(event.input.key == InputKeyBack) { - // furiac_exit(NULL); - processing = false; - furi_mutex_release(_state->mutex); - break; - } - } - - update_field(_state); - - view_port_update(view_port); - furi_mutex_release(_state->mutex); - } - - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(_state->mutex); - free(_state); - - return 0; -} \ No newline at end of file diff --git a/applications/external/game_of_life/golIcon.png b/applications/external/game_of_life/golIcon.png deleted file mode 100644 index df14f812c2d4bd216dfb21ffc46b47813ce58cf0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1921 zcmcIlO>g5w7F}B;J zJs{W{r|*oVjpALgEh~mDh2S4N~dmLZoCq^33yoJ@3pX2m24# z*WOrD6lJ~LY97Lv&)04&!|ykLZa#%!DLs6+r9As-;}2N8(rtJRMfvLKtAEoKSg#)J zb#^W)Y=%HRN^e$n>xmZ;M{ox=6&Mi~SC}IAIRgHXp37)kZEb3`9oN z(V!ot?x?PfiCviI+q$NXA=yb?YvdNyWA8xSmWfd95gy`7P zjWRN9w_>?QMV)*!u&1iEga__nb9Z77R&}kHWwER4!{M+rESF@`)eXmSbWC(Y5Fk)` z9%XcdqV!%tGNEaTlqF%Dg)&leTI$QwtgeB}MJ$7O#vP@TghA@`5sh`Dg!9;@K+n4# zIvC8*X|{6)RwhngNt|}hW1%04RGubG?3{@xyEio!_hcs1p8OBrW`F<7L(XOfAQgB4{R)j+Fgr#SW$xRZ=dQ>RU%)#N{x(pL;YpAeuB2buF(R z!VWUbj$ygjbj##zTy`-opdJW<(~K?#mOKp37lC@7+m6zVMohGubq$;SDHE2!#JIC4x}Mzm}MwqbIcRoK`sINy})G|xnSzR)k13^-=lbS;DUhEIG{wJd>5 z8`!F5U?M^sUzi33W7d@I-6Vt_qWyW++$#=@f>dqG5ENmzcFUT|nH$JtKtVs@fOdr*N8PEULDXObf@y^*RPcP(QkwZ-ctV^7;#|O}4`;61!Lk1?{jWfb<$&6tGkV*^nlp(S;(sTzC2c zfu!{8`Y;yL$Nw2d!OeO!>I%4Np#$dwtLgcjG+(uveszIsFXS?nTmzaRS3x?Lsj&*S zXm@UFrh*4keNtNH4q+78R<(>AQn67rz&>I;Ae`6+vjeN}tRK!16m$>+Czyn#RZZ27tR^Glnz5nDN_OLgi diff --git a/applications/external/hc_sr04/application.fam b/applications/external/hc_sr04/application.fam deleted file mode 100644 index cbe135194..000000000 --- a/applications/external/hc_sr04/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="hc_sr04", - name="[HC-SR] Dist. Sensor", - apptype=FlipperAppType.EXTERNAL, - entry_point="hc_sr04_app", - requires=[ - "gui", - ], - stack_size=2 * 1024, - fap_icon="dist_sensor10px.png", - fap_category="GPIO", - fap_author="@xMasterX (first implementation by @Sanqui)", - fap_version="1.0", - fap_description="HC-SR(04) Distance sensor reader", -) diff --git a/applications/external/hc_sr04/dist_sensor10px.png b/applications/external/hc_sr04/dist_sensor10px.png deleted file mode 100644 index af9aa7358ea19072cccd0e462070dab2695cab9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 141 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4F%}28J29*~C-V}>arbm_43U`H zJHeCdfB_G)yW;=qVA* oJ^0$FdYZ?lpqVlAH`e}OzR_*?{aKRrL!glip00i_>zopr0MDB=8UO$Q diff --git a/applications/external/hc_sr04/hc_sr04.c b/applications/external/hc_sr04/hc_sr04.c deleted file mode 100644 index 66ffdad30..000000000 --- a/applications/external/hc_sr04/hc_sr04.c +++ /dev/null @@ -1,275 +0,0 @@ -// insired by -// https://github.com/esphome/esphome/blob/ac0d921413c3884752193fe568fa82853f0f99e9/esphome/components/ultrasonic/ultrasonic_sensor.cpp -// Ported and modified by @xMasterX - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} PluginEvent; - -typedef struct { - FuriMutex* mutex; - NotificationApp* notification; - bool have_5v; - bool measurement_made; - uint32_t echo; // us - float distance; // meters -} PluginState; - -const NotificationSequence sequence_done = { - &message_display_backlight_on, - &message_green_255, - &message_note_c5, - &message_delay_50, - &message_sound_off, - NULL, -}; - -static void render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const PluginState* plugin_state = ctx; - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - // border around the edge of the screen - // canvas_draw_frame(canvas, 0, 0, 128, 64); - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned( - canvas, 64, 2, AlignCenter, AlignTop, "HC-SR04 Ultrasonic\nDistance Sensor"); - - canvas_set_font(canvas, FontSecondary); - - if(!plugin_state->have_5v) { - elements_multiline_text_aligned( - canvas, - 4, - 28, - AlignLeft, - AlignTop, - "5V on GPIO must be\nenabled, or USB must\nbe connected."); - } else { - if(!plugin_state->measurement_made) { - elements_multiline_text_aligned( - canvas, 64, 28, AlignCenter, AlignTop, "Press OK button to measure"); - elements_multiline_text_aligned( - canvas, 64, 40, AlignCenter, AlignTop, "13/TX -> Trig\n14/RX -> Echo"); - } else { - elements_multiline_text_aligned(canvas, 4, 28, AlignLeft, AlignTop, "Readout:"); - - FuriString* str_buf; - str_buf = furi_string_alloc(); - furi_string_printf(str_buf, "Echo: %ld us", plugin_state->echo); - - canvas_draw_str_aligned( - canvas, 8, 38, AlignLeft, AlignTop, furi_string_get_cstr(str_buf)); - furi_string_printf(str_buf, "Distance: %02f m", (double)plugin_state->distance); - canvas_draw_str_aligned( - canvas, 8, 48, AlignLeft, AlignTop, furi_string_get_cstr(str_buf)); - - furi_string_free(str_buf); - } - } - - furi_mutex_release(plugin_state->mutex); -} - -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - PluginEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void hc_sr04_state_init(PluginState* const plugin_state) { - plugin_state->echo = -1; - plugin_state->distance = -1; - plugin_state->measurement_made = false; - - furi_hal_power_suppress_charge_enter(); - - plugin_state->have_5v = false; - if(furi_hal_power_is_otg_enabled() || furi_hal_power_is_charging()) { - plugin_state->have_5v = true; - } else { - furi_hal_power_enable_otg(); - plugin_state->have_5v = true; - } -} - -float hc_sr04_us_to_m(uint32_t us) { - //speed of sound for 20°C, 50% relative humidity - //331.3 + 20 * 0.606 + 50 * 0.0124 = 0.034404 - const float speed_sound_m_per_s = 344.04f; - const float time_s = us / 1e6f; - const float total_dist = time_s * speed_sound_m_per_s; - return total_dist / 2.0f; -} - -static void hc_sr04_measure(PluginState* const plugin_state) { - //plugin_state->echo = 1; - //return; - - if(!plugin_state->have_5v) { - if(furi_hal_power_is_otg_enabled() || furi_hal_power_is_charging()) { - plugin_state->have_5v = true; - } else { - return; - } - } - - //furi_hal_light_set(LightRed, 0xFF); - notification_message(plugin_state->notification, &sequence_blink_start_yellow); - - const uint32_t timeout_ms = 2000; - // Pin 13 / TX -> Trig - furi_hal_gpio_write(&gpio_usart_tx, false); - furi_hal_gpio_init(&gpio_usart_tx, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); - - // Pin 14 / RX -> Echo - furi_hal_gpio_write(&gpio_usart_rx, false); - furi_hal_gpio_init(&gpio_usart_rx, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh); - - //FURI_CRITICAL_ENTER(); - // 10 ms pulse on TX - furi_hal_gpio_write(&gpio_usart_tx, true); - furi_delay_ms(10); - furi_hal_gpio_write(&gpio_usart_tx, false); - - const uint32_t start = furi_get_tick(); - - while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx)) - ; - while(furi_get_tick() - start < timeout_ms && !furi_hal_gpio_read(&gpio_usart_rx)) - ; - - const uint32_t pulse_start = DWT->CYCCNT; - - while(furi_get_tick() - start < timeout_ms && furi_hal_gpio_read(&gpio_usart_rx)) - ; - const uint32_t pulse_end = DWT->CYCCNT; - - //FURI_CRITICAL_EXIT(); - - plugin_state->echo = - (pulse_end - pulse_start) / furi_hal_cortex_instructions_per_microsecond(); - plugin_state->distance = hc_sr04_us_to_m(plugin_state->echo); - plugin_state->measurement_made = true; - - //furi_hal_light_set(LightRed, 0x00); - notification_message(plugin_state->notification, &sequence_blink_stop); - notification_message(plugin_state->notification, &sequence_done); -} - -int32_t hc_sr04_app() { - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); - - PluginState* plugin_state = malloc(sizeof(PluginState)); - - hc_sr04_state_init(plugin_state); - - furi_hal_console_disable(); - - plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!plugin_state->mutex) { - FURI_LOG_E("hc_sr04", "cannot create mutex\r\n"); - if(furi_hal_power_is_otg_enabled()) { - furi_hal_power_disable_otg(); - } - furi_hal_console_enable(); - furi_hal_power_suppress_charge_exit(); - furi_message_queue_free(event_queue); - free(plugin_state); - return 255; - } - - plugin_state->notification = furi_record_open(RECORD_NOTIFICATION); - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, plugin_state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - PluginEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - case InputKeyDown: - case InputKeyRight: - case InputKeyLeft: - break; - case InputKeyOk: - hc_sr04_measure(plugin_state); - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } - } - - view_port_update(view_port); - furi_mutex_release(plugin_state->mutex); - } - - if(furi_hal_power_is_otg_enabled()) { - furi_hal_power_disable_otg(); - } - furi_hal_power_suppress_charge_exit(); - - // Return TX / RX back to usart mode - furi_hal_gpio_init_ex( - &gpio_usart_tx, - GpioModeAltFunctionPushPull, - GpioPullUp, - GpioSpeedVeryHigh, - GpioAltFn7USART1); - furi_hal_gpio_init_ex( - &gpio_usart_rx, - GpioModeAltFunctionPushPull, - GpioPullUp, - GpioSpeedVeryHigh, - GpioAltFn7USART1); - furi_hal_console_enable(); - - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(plugin_state->mutex); - free(plugin_state); - - return 0; -} diff --git a/applications/external/heap_defence_game/application.fam b/applications/external/heap_defence_game/application.fam deleted file mode 100644 index d19b48ebb..000000000 --- a/applications/external/heap_defence_game/application.fam +++ /dev/null @@ -1,14 +0,0 @@ -App( - appid="heap_defence", - name="Heap Defence", - apptype=FlipperAppType.EXTERNAL, - entry_point="heap_defence_app", - requires=["gui"], - stack_size=1 * 1024, - fap_category="Games", - fap_icon="box.png", - fap_icon_assets="assets_images", - fap_author="@xMasterX (original implementation by @wquinoa & @Vedmein)", - fap_version="1.0", - fap_description="Heap Defence game from hackathon (aka Stack Attack)", -) diff --git a/applications/external/heap_defence_game/assets_images/Background_128x64.png b/applications/external/heap_defence_game/assets_images/Background_128x64.png deleted file mode 100644 index a7eb1326f588aa9a14a0a60df174def162787c23..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 872 zcmV-u1DE`XP)EX>4Tx02q~xP_aq_K@fclNlbA?3b7E86c!c+Y)l^v972RkR7kAc>|PPPJ&(H! z#y`l%r?)K_9$QM&|OTIS)XHyKYJ+XtTrP)7r& zXlhery(k*M8$TaVg6|#i^6U0S!^VXnu9;6J%S%9Akau6pOt>XKe7+xDlP}0y)}`#J zCHa|kR``m%?~=Ls^OS9ZIDNR2KJx@2Zg7hTZA>x83<*kfh$%aLba6!-RCNrEoK?tI z;|&E2F+uF{Kd$^Ex=yK@Q7w)yaGVl9$UQe>-@|HB9j!B+>+J>D^LRIRclT({E6qRu z@C%j_NRp7vwoCv3010qNS#tmYE+YT{E+YYWr9XB6000McNlirueSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{00GEJL_t(|+U=XaN&`U< zhrd~_FcPa23PuZSAHetU8GIlg!N*BqWg&tf7=j{p#so1q7Q1J1`KMPpGaHsmE@^(d zzxgt=!-=Y(_??1!mY=8VQ90Ki4shat&HG$g5txT={nqdTXb~z)cYYtqlF_s12X4w@ z)URzW5LL_3E-QC*>34}0^Vsr)a=Rpa?g>G%11x1k>vTwi33FfyO7fQqXqh=YlE+L) zfi8-oH3X%_AIEY)~qXUf90Hno0if@L0iz-x?zv;kAkG6ko}(6szCiQ^;yfT25DW+g1OtKr!GK^uFd!HZ3KmjC&8CE z|26Jai1__XNzqkIW=3s(n|c3D#w+1TF@d{TVxpcsTwyNhFL#@LK1YB%^YV0^eXAlw5}~Fbd?Dy<>{RhdLsNW zFDs9s;5S3@>@A8P`6LNV2+Ue30w2z`-iiFWY-$cef^g8#^(z2^78K)=d{n- z|Np=}O~_-?gtOaxfC0pmwc6x=<11Hv2m#DR*eJzX3_ zIIidRIr1?ma2&Qe^nZU3yGg^YKmjC&8CE z|26Jai1__XNzqkIW=3s(n|c3D#w+1TF@d{TVxpcsTwyNhFL#@LK1YB%^YV0^eXAlw5}~Fbd?Dy<>{RhdLsNW zFDs9s;5S3@>@A8P`6LNV2+Ue30w2z`-iiFWY-$cef^g8#^(z2^78K)=d{n- z|Np=}O~_-?gtOaxfC0o=;1OBOz@VoL!i*J5?aP3I>?NMQuIx{FSUHS^3O7|G0fi(> zTq8=H^K)}k^GX<;i&7IyQd1PlGfOfQ+&z5*!W;R-fr=D7T^vI=t|zDbIN!h+Az|Pm oDJjtzcJfFAtAPFqkC~Gh98B4TIWJ#q1*&E6boFyt=akR{00)etUjP6A diff --git a/applications/external/heap_defence_game/assets_images/Box3_10x10.png b/applications/external/heap_defence_game/assets_images/Box3_10x10.png deleted file mode 100644 index e20e75b005587aacd3c7bd58f760c00f6842e37b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 459 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V3y@T|W;bJCVC2hmb`J1#c2+1T%1_J8No8P= znA#h#(TmwppqAUyr_hyaqrgNFF)_9rA9)@brxx!Jk2QDR#0l=P?cdFP%>KmjC&8CE z|26Jai1__XNzqkIW=3s(n|c3D#w+1TF@d{TVxpcsTwyNhFL#@LK1YB%^YV0^eXAlw5}~Fbd?Dy<>{RhdLsNW zFDs9s;5S3@>@A8P`6LNV2+Ue30w2z`-iiFWY-$cef^g8#^(z2^78K)=d{n- z|Np=}O~_-?gtOaxfC0o=;1OBOz@VoL!i*J5?aP3I>?NMQuIx{FSUFV0S)w_rfkKic zt`Q~9`MJ5Nc_j?aMX8A;sVNHOnI#zt?w-B@;f;LaKtbp~6v&WwK!K2m47XAJdGIiftH{rm;!{G1LSDwJ~_Q`njxgN@xNAz<;Hu diff --git a/applications/external/heap_defence_game/assets_images/Box4_10x10.png b/applications/external/heap_defence_game/assets_images/Box4_10x10.png deleted file mode 100644 index 98d1341043e6e81dc9883715af6252e9df253526..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 463 zcmV;=0WkiFP)EX>4Tx02q~xP_aq_K@fclNlbA?3b7E86c!c+Y)l^v972RkR7kAc>|PPPJ&(H! z#y`l%r?)K_9$QM&|OTIS)XHyKYJ+XtTrP)7r& zXlhery(k*M8$TaVg6|#i^6U0S!^VXnu9;6J%S%9Akau6pOt>XKe7+xDlP}0y)}`#J zCHa|kR``m%?~=Ls^OS9ZIDNR2KJx@2Zg7hTZA>x83<*kfh$%aLba6!-RCNrEoK?tI z;|&E2F+uF{Kd$^Ex=yK@Q7w)yaGVl9$UQe>-@|HB9j!B+>+J>D^LRIRclT({E6qRu z@C%j_NRp7vwoCv3010qNS#tmYE+YT{E+YYWr9XB6000McNlirueSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{001vZL_t&t*JEV(&wv3~ z7%)T`8CVcZ6qPXWA1=+rz<||EOaoZZHRIHdRge*z;{kqg1s&yuOw|AY002ovPDHLk FV1loBtrY+O diff --git a/applications/external/heap_defence_game/assets_images/Box5_10x10.png b/applications/external/heap_defence_game/assets_images/Box5_10x10.png deleted file mode 100644 index f8dbf339f8de7adb3e855f456f5fe89049ebd2bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 475 zcmV<10VMv3P)EX>4Tx02q~xP_aq_K@fclNlbA?3b7E86c!c+Y)l^v972RkR7kAc>|PPPJ&(H! z#y`l%r?)K_9$QM&|OTIS)XHyKYJ+XtTrP)7r& zXlhery(k*M8$TaVg6|#i^6U0S!^VXnu9;6J%S%9Akau6pOt>XKe7+xDlP}0y)}`#J zCHa|kR``m%?~=Ls^OS9ZIDNR2KJx@2Zg7hTZA>x83<*kfh$%aLba6!-RCNrEoK?tI z;|&E2F+uF{Kd$^Ex=yK@Q7w)yaGVl9$UQe>-@|HB9j!B+>+J>D^LRIRclT({E6qRu z@C%j_NRp7vwoCv3010qNS#tmYE+YT{E+YYWr9XB6000McNlirueSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{0028lL_t&t*KLkL4geqs z!#czNzl?`zB;Zca!7`By1&zwkgOwyQ^lCeSb&*QMdY788;+W4TxtG$f{058B4HkzG RlO6y7002ovPDHLkV1mZYv&#Sg diff --git a/applications/external/heap_defence_game/assets_images/Box6p_10x10.png b/applications/external/heap_defence_game/assets_images/Box6p_10x10.png deleted file mode 100644 index da50f8c860d1541f433f7532e8e968fd72b865ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 471 zcmV;|0Vw{7P)EX>4Tx02q~xP_aq_K@fclNlbA?3b7E86c!c+Y)l^v972RkR7kAc>|PPPJ&(H! z#y`l%r?)K_9$QM&|OTIS)XHyKYJ+XtTrP)7r& zXlhery(k*M8$TaVg6|#i^6U0S!^VXnu9;6J%S%9Akau6pOt>XKe7+xDlP}0y)}`#J zCHa|kR``m%?~=Ls^OS9ZIDNR2KJx@2Zg7hTZA>x83<*kfh$%aLba6!-RCNrEoK?tI z;|&E2F+uF{Kd$^Ex=yK@Q7w)yaGVl9$UQe>-@|HB9j!B+>+J>D^LRIRclT({E6qRu z@C%j_NRp7vwoCv3010qNS#tmYE+YT{E+YYWr9XB6000McNlirueSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{001{hL_t&t*LBW84geqs z1Hmov|6i^LF-k;^6Iu}FnE@0R5MXqX7amq-0zRF4*A?rrHr}GT=O_G$3Kbhd0cijL N002ovPDHLkV1i_9ti1pL diff --git a/applications/external/heap_defence_game/assets_images/Box7p_10x10.png b/applications/external/heap_defence_game/assets_images/Box7p_10x10.png deleted file mode 100644 index efcd2ac0cf54c748487e5b9b1da5b9dc2a381140..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 470 zcmV;{0V)28P)EX>4Tx02q~xP_aq_K@fclNlbA?3b7E86c!c+Y)l^v972RkR7kAc>|PPPJ&(H! z#y`l%r?)K_9$QM&|OTIS)XHyKYJ+XtTrP)7r& zXlhery(k*M8$TaVg6|#i^6U0S!^VXnu9;6J%S%9Akau6pOt>XKe7+xDlP}0y)}`#J zCHa|kR``m%?~=Ls^OS9ZIDNR2KJx@2Zg7hTZA>x83<*kfh$%aLba6!-RCNrEoK?tI z;|&E2F+uF{Kd$^Ex=yK@Q7w)yaGVl9$UQe>-@|HB9j!B+>+J>D^LRIRclT({E6qRu z@C%j_NRp7vwoCv3010qNS#tmYE+YT{E+YYWr9XB6000McNlirueSad^gZEa<4bO1wgWnpw>WFU8GbZ8()Nlj2!fese{001^gL_t&t*Nu)r3IHGs z!&2G*zg!Pfa1Oy-27!hN(+Hq=0RxN<<&>Sb+ySln|2*KmjC&8CE z|26Jai1__XNzqkIW=3s(n|c3D#w+1TF@d{TVxpcsTwyNhFL#@LK1YB%^YV0^eXAlw5}~Fbd?Dy<>{RhdLsNW zFDs9s;5S3@>@A8P`6LNV2+Ue30w2z`-iiFWY-$cef^g8#^(z2^78K)=d{n- z|Np=}O~_-?gtOaxfC0o=;1OBOz@VoL!i*J5?aP3I>?NMQuIx{FSa}tN_ zTq8=H^K)}k^GX<;i&7IyQd1PlGfOfQ+&z5*!W;R-fr<=0T^vI=t|zDbIN!h+Az|Pm zDH)+4!t|$oMT?=}B_AH1h_f!{49?cfd2b_FB{y2iF-Warlh)Y%uO6tG!PC{xWt~$( F69C=dr`Z4i diff --git a/applications/external/heap_defence_game/assets_images/Game_over_128x64.png b/applications/external/heap_defence_game/assets_images/Game_over_128x64.png deleted file mode 100644 index d4837e635037355a8a9aa7f42d46d83aa22c2bd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 683 zcmV;c0#yBpP)Px#22e~?MF0Q*|NsA`*`M7200KivL_t(I%Z1d>Ytv91 z0Pt_}y0$`1BNkRLTYHdQ4HG1Xbjh}Z7ykfHBJAiTG8q;6BO^?2_FveaFg#VL@a^J7 z*gSZy8r@YSbz|)zYy7^~Mw>G5L4JLB@0;(-`@R7Dzh(a2%Hmw0qdJAVGf-6yQW+Wo zEF`cA#!~F&>3W8mq3@0fSS;(*!^g_l*$qMZ$-c613SDO>0QQCribDZ+y3Vr@n8F6N zbAmqHH|vi9ic73(niRAT>*kmsx5SPN4hXs#)d8~L9T^$`Ll&BmK_GjFMnOQZ61|{_ zFt2Jv3~FBWHcuDjI}X;OQqdAC1APVSQ~Iq+H0pH z`arn|tq(lYn?JG#mo)v{d$e!{`yAL5BrHyW%>b@}AS(&@f{M*yC4oLFPgC#_R|RYY zIRV}~e8N|~A0_b8f2;G?4h0~4?ZjD~Cw3;lC72Xc4n7CwvW_#+$}}YKgJtRR0c?kQ ztWm+hcMh*C+zzS}jaT5%50|A*?D|+e5fGzOl8P~S9C*>SQ7-{o2NwYa>>!jtc7Yba z6=2)bs>KA7W-r!!3K;&a_Zc_~0FMCl`RDvG9VytaKzSZ+?VqDM54XXNQZZ?7HQaeH zGtf-+P%{fXZXh&mOr;9Vhllgeu@`lMRFu6|VQqesgSG*CiytJf%h&xI{s20@?;I7O R2;Tqz002ovPDHLkV1kAlDAWJ| diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_01.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_01.png deleted file mode 100644 index d4837e635037355a8a9aa7f42d46d83aa22c2bd9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 683 zcmV;c0#yBpP)Px#22e~?MF0Q*|NsA`*`M7200KivL_t(I%Z1d>Ytv91 z0Pt_}y0$`1BNkRLTYHdQ4HG1Xbjh}Z7ykfHBJAiTG8q;6BO^?2_FveaFg#VL@a^J7 z*gSZy8r@YSbz|)zYy7^~Mw>G5L4JLB@0;(-`@R7Dzh(a2%Hmw0qdJAVGf-6yQW+Wo zEF`cA#!~F&>3W8mq3@0fSS;(*!^g_l*$qMZ$-c613SDO>0QQCribDZ+y3Vr@n8F6N zbAmqHH|vi9ic73(niRAT>*kmsx5SPN4hXs#)d8~L9T^$`Ll&BmK_GjFMnOQZ61|{_ zFt2Jv3~FBWHcuDjI}X;OQqdAC1APVSQ~Iq+H0pH z`arn|tq(lYn?JG#mo)v{d$e!{`yAL5BrHyW%>b@}AS(&@f{M*yC4oLFPgC#_R|RYY zIRV}~e8N|~A0_b8f2;G?4h0~4?ZjD~Cw3;lC72Xc4n7CwvW_#+$}}YKgJtRR0c?kQ ztWm+hcMh*C+zzS}jaT5%50|A*?D|+e5fGzOl8P~S9C*>SQ7-{o2NwYa>>!jtc7Yba z6=2)bs>KA7W-r!!3K;&a_Zc_~0FMCl`RDvG9VytaKzSZ+?VqDM54XXNQZZ?7HQaeH zGtf-+P%{fXZXh&mOr;9Vhllgeu@`lMRFu6|VQqesgSG*CiytJf%h&xI{s20@?;I7O R2;Tqz002ovPDHLkV1kAlDAWJ| diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_02.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_02.png deleted file mode 100644 index a88122d905478d73b7471fbe634a56541ae69be6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 680 zcmV;Z0$2TsP)Px#22e~?MF0Q*|NsA`*`M7200KZsL_t(I%Z1d>Ytv91 z0Pt_}y0$`1D;72|TYHdQ4HG1XWX-mN7ykfHGT6~eWHKuBM@E?5?7y%-VR))g;oHTF zuzB!YHM*-v>&BWx*7$ud?QFup2l??neBZCU?+d{HOXlCJEbaxmsxjQ3LaD?-T7rgv z8WLCpffPA;dY+-GYr6pfi)4)=Jgfxv?hvG3>>C@#(6x7bU~k!=I1+HLYd;?XQ`o>f zC+NdNqy7}2xWKxGL7nzt%?Jo`3+zbefS?&+9Uu$tk*)$TWJ4p=31s(BF9`6L!ANs8cmF#$w6Tot;P(#UzDiH zM!Q#YW>6(y4V9(|_~Li-^B6(S9iz#YkM##vC*y$N3z`8RrPA)560qDKGzT1%_Uh@F zK2R>i+DAUq+ds1hm$dxc2dv=~_BpT^BrL|jrT{m9pOplBMaAN<9D~dHsB90l4+Xj(~=@iJJJHzbIWk z0(YoIDkTj3;PASJu3w#~JOfAGa8c?+j*Hb30TJ3|sThF(o^);0%D~pZK|ldJ2xX8R zpbc;YSXP|1*Dx!X&iU>63d8GspMsr^f0C-_kJGSUNy44|^W>;^!3q;VXRG1NgOPz| zBBGQ@MchJYT8VBMG#?+%*CRLV_=#TjT7}j5Lk{XX?4=i&*W{c24SxZEpz=K2Yw2D9 O0000Px#22e~?MF0Q*|NsA`*`M7200K8jL_t(I%Z<~|Ytv91 z0Pt_}x~4)+D;72|TYHdQ4HG1XWXaZp7ykfHBJAiTG8q;6BcrG{`!DQI7@jIr_;&Fk zY#uyUjqWPay0PYvHGbb~t4$c_gZ%pNecycF%Qpc39+|(lvN-4Is7&GZ42ne#(hAfC z*ht_Igi`F~=z5Bpq3?zSES7bO@Ua}ayF-wEurF*lg|5330DH{_g^_?;UH8cln92s$ z89^WJnze@jg(cQCO-kB_4KpNAme`@e0YNvT8bB7>hlU2gkPXeqAduS!MqWU$8a<#>@dEhl1Fi|! z3=|I4_FH_!zj{BK!*l^G$rtZW$EG` zREK)3QNzGD4lix229=4%J8I0=7XF0t(ncD1q$p zTTg)F{ORN={NG@h1~(n@AoZL(O2d9R2{-o7l4);(6D5HDt-7}eW(FFGh+-xcaSfs2 zB+@cy+&@@+j@wZuNMzY-=GPa0a?mzmFTKE=E?>1ZzX3B-?)=JaWGVmv002ovPDHLk FV1j-lGLQfO diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_04.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_04.png deleted file mode 100644 index d0c63d48427b1c296024d1f25cdc974f0254d124..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 667 zcmV;M0%ZM(P)Px#22e~?MF0Q*|NsA`*`M7200J{fL_t(I%Z<}dYZFlr z0PxwJG>H(Ch=CT|HaSSIE)`@CyUn&9y!Zh;iO{2$l}d?_KN}Y9&3uJ^gyJbegh}H? zXgzq2y4tHqVoQ_5HtW2XM6*jlAMC#$^JeGmn+5pyNc_E3u;4GjPZ2WDU}sNR8*k>IZe&v_x} zm5ib*faai^Ss6iAaL!XuZJVk{s*rUlVY`!=L&&g(+jXI=v=)=x%0 zLqO&CqSEW%lP@m-_EYbuOfzT-z$qw{n}Rn3xB~p7BH=S-Z2_xu=u-Ac1U}H3giSvs z!Fx-O#jbaQDWLbF_eK}59ZDeFcfzDD3OkkHGE6dg0X+feV#}FmD?G*T`OC`1J-~q; zYTPjJO~9)%?^kJ}i4Gk02Fpq-bdgHO5<+qcN-hKmqUjo>7XUZ7LLdn{1O-rCaqCL3 z?LVD7h5s8!ad6@x4`a{iqc}8+QMl1Oi>AE^b`Synx2oga?mzmFTTLEu3q(Negi)u?)-boG&BGJ002ovPDHLkV1gE} B9=-qo diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_05.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_05.png deleted file mode 100644 index 1c2756fdb0c5f423c3fd316d23d99987ae97adc3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 670 zcmV;P0%84$P)Px#22e~?MF0Q*|NsA`*`M7200K5iL_t(I%Z<}dYZE~f z0Pwf_(rkp7L=3dxw#h+yb*UhG*lo7Gc<}>x5}`*gE0q!T0hdi7ibI+pKRUSxrJg2X=Sn$IP2IJ2L?PE{VTYRld{w6en=L#ti-UGx!x}MYOV~685Exci21tV6G<5(Z>|3G9p!$bqT0*cIKI4U; zUo;Dz0E)q|GO`ER;W-aMwPmRys6zIogza`ZhKOMew`*336Jw|f$lzA362sT?91q#5 zw@Y3OMFyrIpVf~;0#!RATP&Z-cP@{IBY2^GB6}oeDb(9148Hb@?4E#3ef?w@ zFoaZkFEYLUJ^Ati;6QsvC7Qy%0GxnA*$MblfGZ$KDh!C9DdPxOjiE!C$8+$3)+B5O zngstXJrcX#31fKPePf7e2NDPm+$d>?#7-r64C8c8Kvw{I*l@@C3J(do!Lo9353p}U zIv*JLCg4?x_p3P8#R(jA`^!or@{o$h5+ZW*N;U!s;?UK}$OCS0hCmW_2=btMqUuR- zoIfXd0{>T#7QtQY@?fEzI$DJN!aUsAKbsGG6P$1k_-<92vtT8lYRp0|0Tpi+t`St7 zxv&V;`-ijb$PXLA+&p`=^!n^22YnOv78jT@)T@5YZ`~B`TvLP+-2eap07*qoM6N<$ Eg1ZkP=>Px# diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_06.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_06.png deleted file mode 100644 index 313fd69617999bd8b1f4f5d03495456e279836a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 669 zcmV;O0%HA%P)Px#22e~?MF0Q*|NsA`*`M7200K2hL_t(I%Z<~|YtwKP z0PvT*uB}kpiiHi#)*NJ4!vyIeU9(-h_y>3rVMi~K$*9mDsbzYz|HA%+;i*D}*VT)# zdGK5{x~oX)#+pOc_`csZ+LVC?l6>>w`{TWQ-xuKDSK@C|mCp>{`V?-@AfFeYtUygd zg%~UbUkRNwzfVak8M{6MhN{6m22}LzT@REW_yxTwbnP7%@HGx|BMG;<_7e{Kkj0ATzc*cof zTQ3zI0Th8@W@Qg52j@Hl)vl?ENfjzzO4#mYA_y7QaJykvI538~fGln`Y7u-r&-0M2 zX0PHzpfg}i<1m4q{;Yo-6TCBSAd&TBz&faqL1fYW*d!nuI5O?4%D;M_wJtNe( zVBnj8mlfVGeWHm991Xl>r4u?x`muzN?1GXDL4qi{CK(054UP~%j`AINr2OT#S>s}+XK7YtT+l0Nv1k;9k)vx&tmzV7P_D00000NkvXXu0mjf DP@5g1 diff --git a/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_07.png b/applications/external/heap_defence_game/assets_images/HD_game_over_128x64/frame_07.png deleted file mode 100644 index cf854656c803ff05907e7e45a48903e6c76b7728..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 677 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 Lfku_u)sX)I(Bd4y diff --git a/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_02.png b/applications/external/heap_defence_game/assets_images/HD_person_block_left_10x20/frame_02.png deleted file mode 100644 index afc4a932f119db0aaa914af16f1677053693e95c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9144 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 R&h!8P002ovPDHLkV1kVh$LIh6 diff --git a/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_02.png b/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_02.png deleted file mode 100644 index afee3ec83688184aeffefb7a154218a787aaa1fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 503 zcmVEX>4Tx04R~2kg-a`P!xv0v|2^#q&SF32G@d%nOv$u5ENppV0B896pKj=NlNhz zd=q_`4uaqt_yP*f{x>=}n8gc+|Ko7Z|KEF|WhY@;F6=^@RfX&KhnK@Ed+CiXi*(qg z9fW1x_q-Dt&*v+a(U+d_YM%S^bfUNnrE^sl=0ye8zSx;nxnULSw*&uB{2;cYG>gPf z;+-gs44Yj)O{U?Gr@2ix&MwYPU$uqHF{gOgjF>VZp`s_v)H%XoPwG+-a8F4nO^DT- zX{O>vRLaTaKr|5PHVt{3b)Kh`kvt~yG6{F2@-%sv|NUP3IIB0Ujd>mvLEUPrTH`Ui zKf>w|)}CSIx*==%_uCp~oO003u6L_t&-({+$h4!|G?LthE^zjF5>D$dPBFs3cE zvbj#c&!^C;013jJHK2>SYpU+3$s&zj^r;3ebnF3o@98E1;<6<2#0*xd?KxlJt+VXL t-g4WBFS_h|Q1mcd=;ZL?ndccEzyp5ICNHzsM{ocD002ovPDHLkV1hw}-bMfb diff --git a/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate b/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate deleted file mode 100644 index 0cfbf0888..000000000 --- a/applications/external/heap_defence_game/assets_images/HD_person_block_right_10x20/frame_rate +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_01.png b/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_01.png deleted file mode 100644 index e8bb70be6a7bcf06c7330a06f4e9421c94ee2fae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^Ahw7A6Ohc7dF}+HSkfJR9T^xl_H+M9WCij$3p^r= z85p>QL70(Y)*K0-V1=iPV~EA+rIQW$4j6DSXKVlezsY(Fv*4ko7Qq4@btcbA^A<-~ zvNAZF31QPdU6eg_xxV{z8^OO}ksCT|Z$3_0zH(M;p}f88z5k~wOEbbnDvnhyt}R>g zra`is{rS!ID?;wuZT`&fT(5QHfz9#*`?P9Tm+S4XW537EUa^9=QhbU9&QL70(Y)*K0-V3ntfV~EA+r6G<&2OL!W$T}E4Xu4N3T13zww zzxQo*l<>r9TlOw}AC~*|V~JPBw?y0L(^bl=|MAYLDg7nQL70(Y)*K0-V7;e{V~EA+r6G=d4F)_?z5o9k$=zXej*5J8Lv*1wpNgj*BLhR! z$9e42FYh{Ex%XLeXqo#~H;ad^^ZKpz^`Gus`8mky{F_71|1Xt!8_antxRZ%BYX2@- zwM=KD&+do(G6gH$RA<@!T(?4X@73mtXZ1m|-~N%j@%Nw;UHx3vIVCg!0KpPa!2kdN diff --git a/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_04.png b/applications/external/heap_defence_game/assets_images/HD_person_left_10x20/frame_04.png deleted file mode 100644 index d7dd740f79e26f37fad93ea1ad618a21de16aa1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^Ahw7A6Ohc7dF}+HSkfJR9T^xl_H+M9WCij$3p^r= z85p>QL70(Y)*K0-V3ntfV~EA+r6G<&2OL!W$T}E4Xu4N3T13zww zzxQo*l<>r9TlOw}AC~*|V~JPBw?y0L(^bl=|MAYLDg7nQL70(Y)*K0-V6~@;C(nYL!x$>bNk~yNSO~!PxloFOfi7 z28IRZdcvY-g8$AFo}sl``CM-Gln47Jw$Cb-Rd2l>oVn`2$)8KlOqp@O?e08_M`fy^ z|5MM^TE1BwrGN6z{EMYm3f?PiD-O&0_Ipc4MEuUnw)|@=m+xkLsk}%krhAer&>0M# Lu6{1-oD!M<QL70(Y)*K0-V2!7XV~EA+rNN#;2NXDrdH(-5vc19V=XKzopr04K0Zga7~l diff --git a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_03.png b/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_03.png deleted file mode 100644 index 5c2911fbc919ca04b96d43ddd37582e05e06b6c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^Ahw7A6Ohc7dF}+HSkfJR9T^xl_H+M9WCij$3p^r= z85p>QL70(Y)*K0-V3ntfV~EA+rNNGT2NZZF9s6HDQ?~5op%)QPmMv_^W%Zoo&A{NW zKk!*us@K)uUZ-{y`-hx%NY>8T`1$>%slQife6jWXpMP%V=f?`SHrKzLFlSEEZb`L= zi+z7dT;1cjf4Yj}O6PuAQ=RFZijlF!Q*Omp5Rq+e9LK~miR&K7Z@2U9A6u3+$V L^>bP0l+XkKIO$KF diff --git a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_04.png b/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_04.png deleted file mode 100644 index 9a03083a02a30bcc903b743025177c2d0f2f2c1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 218 zcmeAS@N?(olHy`uVBq!ia0vp^Ahw7A6Ohc7dF}+HSkfJR9T^xl_H+M9WCij$3p^r= z85p>QL70(Y)*K0-V2!7XV~EA+rNN#;2NXDrdH(-5vc19V=XKzopr04K0Zga7~l diff --git a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate b/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate deleted file mode 100644 index 0cfbf0888..000000000 --- a/applications/external/heap_defence_game/assets_images/HD_person_right_10x20/frame_rate +++ /dev/null @@ -1 +0,0 @@ -2 diff --git a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_01.png b/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_01.png deleted file mode 100644 index 7fd2f86273c53e71f9467ae7afa11dee8220cb42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3820 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 Y0dK(J#mu?FfdBvi07*qoM6N<$f}FN}wEzGB diff --git a/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_04.png b/applications/external/heap_defence_game/assets_images/HD_start_128x64/frame_04.png deleted file mode 100644 index 32fc98b74154a3485d6f5f011c3b532450b70945..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3881 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 Lfku_u)sX)I(Bd4y diff --git a/applications/external/heap_defence_game/assets_images/Person4_2_10x20.png b/applications/external/heap_defence_game/assets_images/Person4_2_10x20.png deleted file mode 100644 index afc4a932f119db0aaa914af16f1677053693e95c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9144 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 R&h!8P002ovPDHLkV1kVh$LIh6 diff --git a/applications/external/heap_defence_game/assets_images/Person5_2_10x20.png b/applications/external/heap_defence_game/assets_images/Person5_2_10x20.png deleted file mode 100644 index afee3ec83688184aeffefb7a154218a787aaa1fe..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 503 zcmVEX>4Tx04R~2kg-a`P!xv0v|2^#q&SF32G@d%nOv$u5ENppV0B896pKj=NlNhz zd=q_`4uaqt_yP*f{x>=}n8gc+|Ko7Z|KEF|WhY@;F6=^@RfX&KhnK@Ed+CiXi*(qg z9fW1x_q-Dt&*v+a(U+d_YM%S^bfUNnrE^sl=0ye8zSx;nxnULSw*&uB{2;cYG>gPf z;+-gs44Yj)O{U?Gr@2ix&MwYPU$uqHF{gOgjF>VZp`s_v)H%XoPwG+-a8F4nO^DT- zX{O>vRLaTaKr|5PHVt{3b)Kh`kvt~yG6{F2@-%sv|NUP3IIB0Ujd>mvLEUPrTH`Ui zKf>w|)}CSIx*==%_uCp~oO003u6L_t&-({+$h4!|G?LthE^zjF5>D$dPBFs3cE zvbj#c&!^C;013jJHK2>SYpU+3$s&zj^r;3ebnF3o@98E1;<6<2#0*xd?KxlJt+VXL t-g4WBFS_h|Q1mcd=;ZL?ndccEzyp5ICNHzsM{ocD002ovPDHLkV1hw}-bMfb diff --git a/applications/external/heap_defence_game/assets_images/Start_128x64.png b/applications/external/heap_defence_game/assets_images/Start_128x64.png deleted file mode 100644 index 32fc98b74154a3485d6f5f011c3b532450b70945..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3881 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 diff --git a/applications/external/heap_defence_game/heap_defence.c b/applications/external/heap_defence_game/heap_defence.c deleted file mode 100644 index 111c22dce..000000000 --- a/applications/external/heap_defence_game/heap_defence.c +++ /dev/null @@ -1,598 +0,0 @@ -// -// Created by moh on 30.11.2021. -// -// Ported to latest firmware by @xMasterX - 18 Oct 2022 -// - -#include - -#include "hede_assets.h" -#include "heap_defence_icons.h" - -#include -#include -#include -#include -#include -#include - -#define Y_FIELD_SIZE 6 -#define Y_LAST (Y_FIELD_SIZE - 1) -#define X_FIELD_SIZE 12 -#define X_LAST (X_FIELD_SIZE - 1) - -#define DRAW_X_OFFSET 4 - -#define TAG "HeDe" - -#define BOX_HEIGHT 10 -#define BOX_WIDTH 10 -#define TIMER_UPDATE_FREQ 8 -#define BOX_GENERATION_RATE 15 - -static IconAnimation* BOX_DESTROYED; -static const Icon* boxes[] = { - (Icon*)&A_HD_BoxDestroyed_10x10, - &I_Box1_10x10, - &I_Box2_10x10, - &I_Box3_10x10, - &I_Box4_10x10, - &I_Box5_10x10}; - -static uint8_t BOX_TEXTURE_COUNT = sizeof(boxes) / sizeof(Icon*); - -typedef enum { - AnimationGameOver = 0, - AnimationPause, - AnimationLeft, - AnimationRight, -} Animations; - -static IconAnimation* animations[4]; - -typedef u_int8_t byte; - -typedef enum { - GameStatusVibro = 1 << 0, - GameStatusInProgress = 1 << 1, -} GameStatuses; - -typedef struct { - uint8_t x; - uint8_t y; -} Position; - -typedef enum { PlayerRising = 1, PlayerFalling = -1, PlayerNothing = 0 } PlayerStates; - -typedef struct { - Position p; - int8_t x_direction; - int8_t j_tick; - int8_t h_tick; - int8_t states; - bool right_frame; -} Person; - -typedef struct { - uint8_t offset : 4; - uint8_t box_id : 3; - uint8_t exists : 1; -} Box; - -static const uint8_t ROW_BYTE_SIZE = sizeof(Box) * X_FIELD_SIZE; - -typedef struct { - Box** field; - Person* person; - Animations animation; - GameStatuses game_status; - FuriMutex* mutex; -} GameState; - -typedef Box** Field; - -typedef enum { EventGameTick, EventKeyPress } EventType; - -typedef struct { - EventType type; - InputEvent input; -} GameEvent; - -/** - * #Construct / Destroy - */ - -static void game_reset_field_and_player(GameState* game) { - ///Reset field - bzero(game->field[0], X_FIELD_SIZE * Y_FIELD_SIZE * sizeof(Box)); - - ///Reset person - bzero(game->person, sizeof(Person)); - game->person->p.x = X_FIELD_SIZE / 2; - game->person->p.y = Y_LAST; -} - -static GameState* allocGameState() { - GameState* game = malloc(sizeof(GameState)); - - game->person = malloc(sizeof(Person)); - - game->field = malloc(Y_FIELD_SIZE * sizeof(Box*)); - game->field[0] = malloc(X_FIELD_SIZE * Y_FIELD_SIZE * sizeof(Box)); - for(int y = 1; y < Y_FIELD_SIZE; ++y) { - game->field[y] = game->field[0] + (y * X_FIELD_SIZE); - } - game_reset_field_and_player(game); - - game->game_status = GameStatusInProgress; - return game; -} - -static void game_destroy(GameState* game) { - furi_assert(game); - free(game->field[0]); - free(game->field); - free(game); -} - -static void assets_load() { - /// Init animations - animations[AnimationPause] = icon_animation_alloc(&A_HD_start_128x64); - animations[AnimationGameOver] = icon_animation_alloc(&A_HD_game_over_128x64); - animations[AnimationLeft] = icon_animation_alloc(&A_HD_person_left_10x20); - animations[AnimationRight] = icon_animation_alloc(&A_HD_person_right_10x20); - - BOX_DESTROYED = icon_animation_alloc(&A_HD_BoxDestroyed_10x10); - - icon_animation_start(animations[AnimationLeft]); - icon_animation_start(animations[AnimationRight]); -} - -static void assets_clear() { - for(int i = 0; i < 4; ++i) { - icon_animation_stop(animations[i]); - icon_animation_free(animations[i]); - } - icon_animation_free(BOX_DESTROYED); -} - -/** - * Box utils - */ - -static inline bool is_empty(Box* box) { - return !box->exists; -} - -static inline bool has_dropped(Box* box) { - return box->offset == 0; -} - -static Box* get_upper_box(Field field, Position current) { - return (&field[current.y - 1][current.x]); -} - -static Box* get_lower_box(Field field, Position current) { - return (&field[current.y + 1][current.x]); -} - -static Box* get_next_box(Field field, Position current, int x_direction) { - return (&field[current.y][current.x + x_direction]); -} - -static inline void decrement_y_offset_to_zero(Box* n) { - if(n->offset) --n->offset; -} - -static inline void heap_swap(Box* first, Box* second) { - Box temp = *first; - - *first = *second; - *second = temp; -} - -/** - * #Box logic - */ - -static void generate_box(GameState const* game) { - furi_assert(game); - - static byte tick_count = BOX_GENERATION_RATE; - if(tick_count++ != BOX_GENERATION_RATE) { - return; - } - tick_count = 0; - - int x_offset = rand() % X_FIELD_SIZE; - while(game->field[1][x_offset].exists) { - x_offset = rand() % X_FIELD_SIZE; - } - - game->field[1][x_offset].exists = true; - game->field[1][x_offset].offset = BOX_HEIGHT; - game->field[1][x_offset].box_id = (rand() % (BOX_TEXTURE_COUNT - 1)) + 1; -} - -static void drop_box(GameState* game) { - furi_assert(game); - - for(int y = Y_LAST; y > 0; y--) { - for(int x = 0; x < X_FIELD_SIZE; x++) { - Box* current_box = game->field[y] + x; - Box* upper_box = game->field[y - 1] + x; - - if(y == Y_LAST) { - decrement_y_offset_to_zero(current_box); - } - - decrement_y_offset_to_zero(upper_box); - - if(is_empty(current_box) && !is_empty(upper_box) && has_dropped(upper_box)) { - upper_box->offset = BOX_HEIGHT; - heap_swap(current_box, upper_box); - } - } - } -} - -static bool clear_rows(Box** field) { - for(int x = 0; x < X_FIELD_SIZE; ++x) { - if(is_empty(field[Y_LAST] + x) || !has_dropped(field[Y_LAST] + x)) { - return false; - } - } - - memset(field[Y_LAST], 128, ROW_BYTE_SIZE); - return true; -} - -/** - * Input Handling - */ - -static inline bool on_ground(Person* person, Field field) { - return person->p.y == Y_LAST || field[person->p.y + 1][person->p.x].exists; -} - -static void handle_key_presses(Person* person, InputEvent* input, GameState* game) { - switch(input->key) { - case InputKeyUp: - if(person->states == PlayerNothing && on_ground(person, game->field)) { - person->states = PlayerRising; - person->j_tick = 0; - } - break; - case InputKeyLeft: - person->right_frame = false; - if(person->h_tick == 0) { - person->h_tick = 1; - person->x_direction = -1; - } - break; - case InputKeyRight: - person->right_frame = true; - if(person->h_tick == 0) { - person->h_tick = 1; - person->x_direction = 1; - } - break; - case InputKeyOk: - game->game_status &= ~GameStatusInProgress; - game->animation = AnimationPause; - icon_animation_start(animations[AnimationPause]); - default: - break; - } -} - -/** - * #Person logic - */ - -static inline bool ground_box_check(Field field, Position new_position) { - Box* lower_box = get_lower_box(field, new_position); - - bool ground_box_dropped = - (new_position.y == Y_LAST || //Eсли мы и так в самом низу - is_empty(lower_box) || // Ecли снизу пустота - has_dropped(lower_box)); //Eсли бокс снизу допадал - return ground_box_dropped; -} - -static inline bool is_movable(Field field, Position box_pos, int x_direction) { - //TODO::Moжет и не двух, предположение - bool out_of_bounds = box_pos.x == 0 || box_pos.x == X_LAST; - if(out_of_bounds) return false; - bool box_on_top = box_pos.y < 1 || get_upper_box(field, box_pos)->exists; - if(box_on_top) return false; - bool has_next_box = get_next_box(field, box_pos, x_direction)->exists; - if(has_next_box) return false; - - return true; -} - -static bool horizontal_move(Person* person, Field field) { - Position new_position = person->p; - - if(!person->x_direction) return false; - - new_position.x += person->x_direction; - - bool on_edge_column = new_position.x > X_LAST; - if(on_edge_column) return false; - - if(is_empty(&field[new_position.y][new_position.x])) { - bool ground_box_dropped = ground_box_check(field, new_position); - if(ground_box_dropped) { - person->p = new_position; - return true; - } - } else if(is_movable(field, new_position, person->x_direction)) { - *get_next_box(field, new_position, person->x_direction) = - field[new_position.y][new_position.x]; - - field[new_position.y][new_position.x] = (Box){0}; - person->p = new_position; - return true; - } - return false; -} - -void hd_person_set_state(Person* person, PlayerStates state) { - person->states = state; - person->j_tick = 0; -} - -static void person_move(Person* person, Field field) { - /// Left-right logic - FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); - - if(person->states == PlayerNothing) { - if(!on_ground(person, field)) { - hd_person_set_state(person, PlayerFalling); - } - } else if(person->states == PlayerRising) { - if(person->j_tick++ == 0) { - person->p.y--; - } else if(person->j_tick == 6) { - hd_person_set_state(person, PlayerNothing); - } - - /// Destroy upper box - get_upper_box(field, person->p)->box_id = 0; - field[person->p.y][person->p.x].box_id = 0; - - } else if(person->states == PlayerFalling) { - if(person->j_tick++ == 0) { - if(on_ground(person, field)) { // TODO: Test the bugfix - hd_person_set_state(person, PlayerNothing); - } else { - person->p.y++; - } - } else if(person->j_tick == 5) { - if(on_ground(person, field)) { - hd_person_set_state(person, PlayerNothing); - } else { - hd_person_set_state(person, PlayerFalling); - } - } - } - - switch(person->h_tick) { - case 0: - break; - case 1: - person->h_tick++; - FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); - bool moved = horizontal_move(person, field); - if(!moved) { - person->h_tick = 0; - person->x_direction = 0; - } - break; - case 5: - FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); - person->h_tick = 0; - person->x_direction = 0; - break; - default: - FURI_LOG_W(TAG, "[JUMP]func:[%s] line: %d", __FUNCTION__, __LINE__); - person->h_tick++; - } -} - -static inline bool is_person_dead(Person* person, Box** field) { - return get_upper_box(field, person->p)->box_id != 0; -} - -/** - * #Callback - */ - -static void draw_box(Canvas* canvas, Box* box, int x, int y) { - if(is_empty(box)) { - return; - } - byte y_screen = y * BOX_HEIGHT - box->offset; - byte x_screen = x * BOX_WIDTH + DRAW_X_OFFSET; - - if(box->box_id == 0) { - canvas_set_bitmap_mode(canvas, true); - icon_animation_start(BOX_DESTROYED); - canvas_draw_icon_animation(canvas, x_screen, y_screen, BOX_DESTROYED); - if(icon_animation_is_last_frame(BOX_DESTROYED)) { - *box = (Box){0}; - icon_animation_stop(BOX_DESTROYED); - } - canvas_set_bitmap_mode(canvas, false); - } else { - canvas_draw_icon(canvas, x_screen, y_screen, boxes[box->box_id]); - } -} - -static void heap_defense_render_callback(Canvas* const canvas, void* mutex) { - furi_assert(mutex); - const GameState* game = mutex; - furi_mutex_acquire(game->mutex, FuriWaitForever); - - ///Draw GameOver or Pause - if(!(game->game_status & GameStatusInProgress)) { - FURI_LOG_W(TAG, "[DAED_DRAW]func: [%s] line: %d ", __FUNCTION__, __LINE__); - - canvas_draw_icon_animation(canvas, 0, 0, animations[game->animation]); - furi_mutex_release(game->mutex); - return; - } - - ///Draw field - canvas_draw_icon(canvas, 0, 0, &I_Background_128x64); - - ///Draw Person - const Person* person = game->person; - IconAnimation* player_animation = person->right_frame ? animations[AnimationRight] : - animations[AnimationLeft]; - - uint8_t x_screen = person->p.x * BOX_WIDTH + DRAW_X_OFFSET; - if(person->h_tick && person->h_tick != 1) { - if(person->right_frame) { - x_screen += (person->h_tick) * 2 - BOX_WIDTH; - } else { - x_screen -= (person->h_tick) * 2 - BOX_WIDTH; - } - } - - uint8_t y_screen = (person->p.y - 1) * BOX_HEIGHT; - if(person->j_tick) { - if(person->states == PlayerRising) { - y_screen += BOX_HEIGHT - (person->j_tick) * 2; - } else if(person->states == PlayerFalling) { - y_screen -= BOX_HEIGHT - (person->j_tick) * 2; - } - } - - canvas_draw_icon_animation(canvas, x_screen, y_screen, player_animation); - - ///Draw Boxes - canvas_set_color(canvas, ColorBlack); - for(int y = 1; y < Y_FIELD_SIZE; ++y) { - for(int x = 0; x < X_FIELD_SIZE; ++x) { - draw_box(canvas, &(game->field[y][x]), x, y); - } - } - - furi_mutex_release(game->mutex); -} - -static void heap_defense_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - if(input_event->type != InputTypePress && input_event->type != InputTypeLong) return; - - furi_assert(event_queue); - GameEvent event = {.type = EventKeyPress, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void heap_defense_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event; - event.type = EventGameTick; - event.input = (InputEvent){0}; - furi_message_queue_put(event_queue, &event, 0); -} - -int32_t heap_defence_app(void* p) { - UNUSED(p); - - //FURI_LOG_W(TAG, "Heap defence start %d", __LINE__); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); - GameState* game = allocGameState(); - - game->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!game->mutex) { - game_destroy(game); - return 1; - } - - assets_load(); - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, heap_defense_render_callback, game); - view_port_input_callback_set(view_port, heap_defense_input_callback, event_queue); - - FuriTimer* timer = - furi_timer_alloc(heap_defense_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / TIMER_UPDATE_FREQ); - - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - - memset(game->field[Y_LAST], 128, ROW_BYTE_SIZE); - game->person->p.y -= 2; - game->game_status = 0; - game->animation = AnimationPause; - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - GameEvent event = {0}; - while(event.input.key != InputKeyBack) { - if(furi_message_queue_get(event_queue, &event, 100) != FuriStatusOk) { - continue; - } - - furi_mutex_acquire(game->mutex, FuriWaitForever); - - //unset vibration - if(game->game_status & GameStatusVibro) { - notification_message(notification, &sequence_reset_vibro); - game->game_status &= ~GameStatusVibro; - icon_animation_stop(BOX_DESTROYED); - memset(game->field[Y_LAST], 0, ROW_BYTE_SIZE); - } - - if(!(game->game_status & GameStatusInProgress)) { - if(event.type == EventKeyPress && event.input.key == InputKeyOk) { - game->game_status |= GameStatusInProgress; - icon_animation_stop(animations[game->animation]); - } - - } else if(event.type == EventKeyPress) { - handle_key_presses(game->person, &(event.input), game); - } else { // EventGameTick - - drop_box(game); - generate_box(game); - if(clear_rows(game->field)) { - notification_message(notification, &sequence_set_vibro_on); - icon_animation_start(BOX_DESTROYED); - game->game_status |= GameStatusVibro; - } - person_move(game->person, game->field); - - if(is_person_dead(game->person, game->field)) { - game->game_status &= ~GameStatusInProgress; - game->animation = AnimationGameOver; - icon_animation_start(animations[AnimationGameOver]); - game_reset_field_and_player(game); - notification_message(notification, &sequence_error); - } - } - furi_mutex_release(game->mutex); - view_port_update(view_port); - } - - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_record_close(RECORD_GUI); - furi_record_close(RECORD_NOTIFICATION); - furi_message_queue_free(event_queue); - assets_clear(); - furi_mutex_free(game->mutex); - game_destroy(game); - - return 0; -} diff --git a/applications/external/heap_defence_game/hede_assets.c b/applications/external/heap_defence_game/hede_assets.c deleted file mode 100644 index f45c0583d..000000000 --- a/applications/external/heap_defence_game/hede_assets.c +++ /dev/null @@ -1,28 +0,0 @@ -// -// Created by user on 15.12.2021. -// -#include "hede_assets.h" -#include - -const uint8_t _A_HD_BoxDestroyed_10x10_0[] = { - 0x01, 0x00, 0x10, 0x00, 0x00, 0x1d, 0xa2, 0x01, 0xc8, 0x80, - 0x6d, 0x20, 0x15, 0x08, 0x06, 0x72, 0x01, 0x48, 0x07, 0xa0, -}; -const uint8_t _A_HD_BoxDestroyed_10x10_1[] = { - 0x00, 0x00, 0x00, 0x28, 0x01, 0x4A, 0x00, 0xA8, 0x01, 0x84, 0x00, - 0x22, 0x00, 0x88, 0x00, 0x58, 0x01, 0x22, 0x00, 0x00, 0x00, -}; -const uint8_t _A_HD_BoxDestroyed_10x10_2[] = { - 0x00, 0x00, 0x00, 0x08, 0x01, 0x42, 0x00, 0x09, 0x01, 0x00, 0x02, - 0x02, 0x00, 0x01, 0x02, 0x00, 0x01, 0x21, 0x00, 0x42, 0x02, -}; -const uint8_t* _A_HD_BoxDestroyed_10x10[] = { - _A_HD_BoxDestroyed_10x10_0, - _A_HD_BoxDestroyed_10x10_1, - _A_HD_BoxDestroyed_10x10_2}; -const Icon A_HD_BoxDestroyed_10x10 = { - .width = 10, - .height = 10, - .frame_count = 3, - .frame_rate = 4, - .frames = _A_HD_BoxDestroyed_10x10}; \ No newline at end of file diff --git a/applications/external/heap_defence_game/hede_assets.h b/applications/external/heap_defence_game/hede_assets.h deleted file mode 100644 index 3bcabc59f..000000000 --- a/applications/external/heap_defence_game/hede_assets.h +++ /dev/null @@ -1,11 +0,0 @@ -// -// Created by user on 15.12.2021. -// - -#ifndef HEDE_ASSETS_H -#define HEDE_ASSETS_H -#include - -extern const Icon A_HD_BoxDestroyed_10x10; - -#endif diff --git a/applications/external/ir_scope/application.fam b/applications/external/ir_scope/application.fam deleted file mode 100644 index ceaa629f7..000000000 --- a/applications/external/ir_scope/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="ir_scope", - name="IR Scope", - apptype=FlipperAppType.EXTERNAL, - entry_point="ir_scope_app", - requires=["gui"], - stack_size=2 * 1024, - fap_icon="ir_scope.png", - fap_category="Infrared", - fap_author="@kallanreed", - fap_version="1.2", - fap_description="App allows to see incoming IR signals.", -) diff --git a/applications/external/ir_scope/ir_scope.c b/applications/external/ir_scope/ir_scope.c deleted file mode 100644 index d56d1c78c..000000000 --- a/applications/external/ir_scope/ir_scope.c +++ /dev/null @@ -1,184 +0,0 @@ -// Author: github.com/kallanreed -#include -#include -#include -#include -#include -#include - -#define TAG "IR Scope" -#define COLS 128 -#define ROWS 8 - -typedef struct { - bool autoscale; - uint16_t us_per_sample; - size_t timings_cnt; - uint32_t* timings; - uint32_t timings_sum; - FuriMutex* mutex; -} IRScopeState; - -static void state_set_autoscale(IRScopeState* state) { - if(state->autoscale) state->us_per_sample = state->timings_sum / (ROWS * COLS); -} - -static void canvas_draw_str_outline(Canvas* canvas, int x, int y, const char* str) { - canvas_set_color(canvas, ColorWhite); - for(int y1 = -1; y1 <= 1; ++y1) - for(int x1 = -1; x1 <= 1; ++x1) canvas_draw_str(canvas, x + x1, y + y1, str); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_str(canvas, x, y, str); -} - -static void render_callback(Canvas* canvas, void* ctx) { - const IRScopeState* state = (IRScopeState*)ctx; - - furi_mutex_acquire(state->mutex, FuriWaitForever); - - canvas_clear(canvas); - canvas_draw_frame(canvas, 0, 0, 128, 64); - - // Draw the signal chart. - bool on = false; - bool done = false; - size_t ix = 0; - int timing_cols = -1; // Count of columns used to draw the current timing - for(size_t row = 0; row < ROWS && !done; ++row) { - for(size_t col = 0; col < COLS && !done; ++col) { - done = ix >= state->timings_cnt; - - if(!done && timing_cols < 0) { - timing_cols = state->timings[ix] / state->us_per_sample; - on = !on; - } - - if(timing_cols == 0) ++ix; - - int y = row * 8 + 7; - canvas_draw_line(canvas, col, y, col, y - (on ? 5 : 0)); - --timing_cols; - } - } - - canvas_set_font(canvas, FontSecondary); - if(state->autoscale) - canvas_draw_str_outline(canvas, 100, 64, "Auto"); - else { - char buf[20]; - snprintf(buf, sizeof(buf), "%uus", state->us_per_sample); - canvas_draw_str_outline(canvas, 100, 64, buf); - } - - furi_mutex_release(state->mutex); -} - -static void input_callback(InputEvent* input_event, void* ctx) { - FuriMessageQueue* event_queue = ctx; - furi_message_queue_put(event_queue, input_event, FuriWaitForever); -} - -static void ir_received_callback(void* ctx, InfraredWorkerSignal* signal) { - furi_check(signal); - IRScopeState* state = (IRScopeState*)ctx; - - furi_mutex_acquire(state->mutex, FuriWaitForever); - - const uint32_t* timings; - infrared_worker_get_raw_signal(signal, &timings, &state->timings_cnt); - - if(state->timings) { - free(state->timings); - state->timings_sum = 0; - } - - state->timings = malloc(state->timings_cnt * sizeof(uint32_t)); - - // Copy and sum. - for(size_t i = 0; i < state->timings_cnt; ++i) { - state->timings[i] = timings[i]; - state->timings_sum += timings[i]; - } - - state_set_autoscale(state); - - furi_mutex_release(state->mutex); -} - -int32_t ir_scope_app(void* p) { - UNUSED(p); - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - furi_check(event_queue); - - if(furi_hal_infrared_is_busy()) { - FURI_LOG_E(TAG, "Infrared is busy."); - return -1; - } - - IRScopeState state = { - .autoscale = false, .us_per_sample = 200, .timings = NULL, .timings_cnt = 0, .mutex = NULL}; - state.mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!state.mutex) { - FURI_LOG_E(TAG, "Cannot create mutex."); - return -1; - } - - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, &state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - Gui* gui = furi_record_open("gui"); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - InfraredWorker* worker = infrared_worker_alloc(); - infrared_worker_rx_enable_signal_decoding(worker, false); - infrared_worker_rx_enable_blink_on_receiving(worker, true); - infrared_worker_rx_set_received_signal_callback(worker, ir_received_callback, &state); - infrared_worker_rx_start(worker); - - InputEvent event; - bool processing = true; - while(processing) { - if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) { - if(event.type == InputTypeRelease) { - furi_mutex_acquire(state.mutex, FuriWaitForever); - - if(event.key == InputKeyBack) { - processing = false; - } else if(event.key == InputKeyUp) { - state.us_per_sample = MIN(1000, state.us_per_sample + 25); - state.autoscale = false; - } else if(event.key == InputKeyDown) { - state.us_per_sample = MAX(25, state.us_per_sample - 25); - state.autoscale = false; - } else if(event.key == InputKeyOk) { - state.autoscale = !state.autoscale; - if(state.autoscale) - state_set_autoscale(&state); - else - state.us_per_sample = 200; - } - - furi_mutex_release(state.mutex); - } - } - view_port_update(view_port); - } - - // Clean up. - infrared_worker_rx_stop(worker); - infrared_worker_free(worker); - - if(state.timings) free(state.timings); - - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close("gui"); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(state.mutex); - - return 0; -} diff --git a/applications/external/ir_scope/ir_scope.png b/applications/external/ir_scope/ir_scope.png deleted file mode 100644 index c0d7eaba0e2c1b18ed85bb9ec348ecbfb63a6575..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V6Od#Ihk44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0h7I;J!Gcbs$f-s|Jkje+3pq;0SV~9p@X|E$6g969lAODvNCJJxz;NQg8 z`;6IJfzu^AD}H}xN$}#DrmMn?wY|KxYc03`d0F11Iahh@4*6-C`yFp}^IHK;V(@hJ Kb6Mw<&;$VC0WZS< diff --git a/applications/external/mandelbrot/Mandelbrot.png b/applications/external/mandelbrot/Mandelbrot.png deleted file mode 100644 index 485f70e5c3425761f3fe2a489f785f4fff5e0d84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1918 zcmcIlJ&zkj7~YT&C5H~Bpg;-5vXKyo%zk=5W#{mnkJ#e&I9-hH=x%mq)?S@=XW895 z`>vp%ql!dB0WA$k5wuVsK?4+_pr%1INJ#tvq|3XzwqvBr#SND1`S3H(`}MptAMb46 zTV1)iA_&52uiM#$v7E15y9~eI{=N19hD-VGy>;Q?qgVcd#g#$ZZwtaV4_^2eKM(7x zJ6rwDv$HdpzW2j#AHr}w?Y^H2f-IHaOJDx+`zL_PmCs0Yl6R zEKcH4l6#YuR1teHFSiv*tRTf9Cw+QCdVi5ldPe@S~z7fy;F)aXRNt@@c{#b;<;%iYBXNY%`$m zUkr`oIXW*kkHN~+>2rzm{z=M|U6%8sjIhmPmK3*V#?m1#cs}G$@ooP1e>|jQZZJK{ zMpcd|QP_yZz?}nDtNcs7jf~-fXMN5`vx@D^EQ-1zo8s$xQ9}7Rf1~thdVqCs!CF#T zJ*2uwGy9t5sitS>Z>ol;sx{OHK~P-a<-nXq;mI;k-}ib+Uf_hVUZ*92Q*snhPYoKT z-f%E-%%FiBw?UC>ss_S_7TTIgZPFl>UvR#|$x)e!@_emd$_a4Hv*}ry9%z9cAjh&8 zGHqaU%+N%-?gq@%Fc`CDZ0}|f^bj5`vX)*^U}U;uTN=Yi)hru@tf3+|a6)8-s^eO= zMm4HS;uE_Ye8e-KQ^>9%iIjLD&teSviDEopN}3F2k_J(O5eTLmE^1iL!(xmx)*e6+o~=7& zi9m9Ed~q1d>Er(lqvj?SO#y -#include -#include -#include -#include - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} PluginEvent; - -typedef struct { - FuriMutex* mutex; - float xZoom; - float yZoom; - float xOffset; - float yOffset; - float zoom; -} PluginState; - -bool mandelbrot_pixel(int x, int y, float xZoom, float yZoom, float xOffset, float yOffset) { - float ratio = 128.0 / 64.0; - //x0 := scaled x coordinate of pixel (scaled to lie in the Mandelbrot X scale (-2.00, 0.47)) - float x0 = (((x / 128.0) * ratio * xZoom)) - xOffset; - //y0 := scaled y coordinate of pixel (scaled to lie in the Mandelbrot Y scale (-1.12, 1.12)) - float y0 = ((y / 64.0) * yZoom) - yOffset; - float x1 = 0.0; - float y1 = 0.0; - float x2 = 0.0; - float y2 = 0.0; - - int iteration = 0; - int max_iteration = 50; - - while(x2 + y2 <= 4.0 && iteration < max_iteration) { - y1 = 2.0 * x1 * y1 + y0; - x1 = x2 - y2 + x0; - x2 = x1 * x1; - y2 = y1 * y1; - iteration++; - } - - if(iteration > 49) { - return true; - } - - return false; -} - -static void render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const PluginState* plugin_state = ctx; - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - // border around the edge of the screen - canvas_draw_frame(canvas, 0, 0, 128, 64); - - for(int y = 0; y < 64; y++) { - for(int x = 0; x < 128; x++) { - // did you know if you just pass the indivdiual bits of plugin_state instead of plugin_state - // you dont get any compiler warnings :) - if(mandelbrot_pixel( - x, - y, - plugin_state->xZoom, - plugin_state->yZoom, - plugin_state->xOffset, - plugin_state->yOffset)) { - canvas_draw_dot(canvas, x, y); - } - } - } - - furi_mutex_release(plugin_state->mutex); -} - -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - PluginEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void mandelbrot_state_init(PluginState* const plugin_state) { - plugin_state->xOffset = 3.0; - plugin_state->yOffset = 1.12; - plugin_state->xZoom = 2.47; - plugin_state->yZoom = 2.24; - plugin_state->zoom = 1; // this controls the camera when -} - -int32_t mandelbrot_app(void* p) { - UNUSED(p); - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); - - PluginState* plugin_state = malloc(sizeof(PluginState)); - mandelbrot_state_init(plugin_state); - plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!plugin_state->mutex) { - FURI_LOG_E("mandelbrot", "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(plugin_state); - return 255; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, plugin_state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - PluginEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - plugin_state->yOffset += 0.1 / plugin_state->zoom; - break; - case InputKeyDown: - plugin_state->yOffset += -0.1 / plugin_state->zoom; - break; - case InputKeyRight: - plugin_state->xOffset += -0.1 / plugin_state->zoom; - break; - case InputKeyLeft: - plugin_state->xOffset += 0.1 / plugin_state->zoom; - break; - case InputKeyOk: - plugin_state->xZoom -= (2.47 / 10) / plugin_state->zoom; - plugin_state->yZoom -= (2.24 / 10) / plugin_state->zoom; - // used to make camera control finer the more zoomed you are - // this needs to be some sort of curve - plugin_state->zoom += 0.15; - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } - } - view_port_update(view_port); - furi_mutex_release(plugin_state->mutex); - } - - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(plugin_state->mutex); - free(plugin_state); - - return 0; -} \ No newline at end of file diff --git a/applications/external/paint/application.fam b/applications/external/paint/application.fam deleted file mode 100644 index e5dec6040..000000000 --- a/applications/external/paint/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="paint", - name="Paint", - apptype=FlipperAppType.EXTERNAL, - entry_point="paint_app", - cdefines=["APP_PAINT"], - requires=["gui"], - stack_size=2 * 1024, - fap_icon="paintIcon.png", - fap_category="Media", - fap_author="@n-o-T-I-n-s-a-n-e", - fap_weburl="https://github.com/n-o-T-I-n-s-a-n-e", - fap_version="1.0", - fap_description="A basic Paint app, Click Ok to draw dot, hold Ok to enable drawing continuously, hold Back to clear the screen", -) diff --git a/applications/external/paint/paint.c b/applications/external/paint/paint.c deleted file mode 100644 index 0d4124b02..000000000 --- a/applications/external/paint/paint.c +++ /dev/null @@ -1,153 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include // Header-file for boolean data-type. - -typedef struct selected_position { - int x; - int y; -} selected_position; - -typedef struct { - FuriMutex* mutex; - selected_position selected; - bool board[32][16]; - bool isDrawing; -} PaintData; - -void paint_draw_callback(Canvas* canvas, void* ctx) { - furi_assert(ctx); - const PaintData* paint_state = ctx; - furi_mutex_acquire(paint_state->mutex, FuriWaitForever); - - canvas_clear(canvas); - canvas_set_color(canvas, ColorBlack); - //draw the canvas(32x16) on screen(144x64) using 4x4 tiles - for(int y = 0; y < 16; y++) { - for(int x = 0; x < 32; x++) { - if(paint_state->board[x][y]) { - canvas_draw_box(canvas, x * 4, y * 4, 4, 4); - } - } - } - - //draw cursor as a 4x4 black box with a 2x2 white box inside - canvas_set_color(canvas, ColorBlack); - canvas_draw_box(canvas, paint_state->selected.x * 4, paint_state->selected.y * 4, 4, 4); - canvas_set_color(canvas, ColorWhite); - canvas_draw_box( - canvas, paint_state->selected.x * 4 + 1, paint_state->selected.y * 4 + 1, 2, 2); - - //release the mutex - furi_mutex_release(paint_state->mutex); -} - -void paint_input_callback(InputEvent* input_event, void* ctx) { - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - furi_message_queue_put(event_queue, input_event, FuriWaitForever); -} - -int32_t paint_app(void* p) { - UNUSED(p); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - - PaintData* paint_state = malloc(sizeof(PaintData)); - - paint_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!paint_state->mutex) { - FURI_LOG_E("paint", "cannot create mutex\r\n"); - free(paint_state); - return -1; - } - - // Configure view port - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, paint_draw_callback, paint_state); - view_port_input_callback_set(view_port, paint_input_callback, event_queue); - - // Register view port in GUI - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - //NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - - InputEvent event; - - while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { - //break out of the loop if the back key is pressed - if(event.type == InputTypeShort && event.key == InputKeyBack) { - break; - } - - //check the key pressed and change x and y accordingly - if(event.type == InputTypeShort) { - switch(event.key) { - case InputKeyUp: - paint_state->selected.y -= 1; - break; - case InputKeyDown: - paint_state->selected.y += 1; - break; - case InputKeyLeft: - paint_state->selected.x -= 1; - break; - case InputKeyRight: - paint_state->selected.x += 1; - break; - case InputKeyOk: - paint_state->board[paint_state->selected.x][paint_state->selected.y] = - !paint_state->board[paint_state->selected.x][paint_state->selected.y]; - break; - - default: - break; - } - - //check if cursor position is out of bounds and reset it to the closest position - if(paint_state->selected.x < 0) { - paint_state->selected.x = 0; - } - if(paint_state->selected.x > 31) { - paint_state->selected.x = 31; - } - if(paint_state->selected.y < 0) { - paint_state->selected.y = 0; - } - if(paint_state->selected.y > 15) { - paint_state->selected.y = 15; - } - if(paint_state->isDrawing == true) { - paint_state->board[paint_state->selected.x][paint_state->selected.y] = true; - } - view_port_update(view_port); - } - if(event.key == InputKeyBack && event.type == InputTypeLong) { - paint_state->board[1][1] = true; - for(int y = 0; y < 16; y++) { - for(int x = 0; x < 32; x++) { - paint_state->board[x][y] = false; - } - } - view_port_update(view_port); - } - if(event.key == InputKeyOk && event.type == InputTypeLong) { - paint_state->isDrawing = !paint_state->isDrawing; - paint_state->board[paint_state->selected.x][paint_state->selected.y] = true; - view_port_update(view_port); - } - } - - gui_remove_view_port(gui, view_port); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(paint_state->mutex); - furi_record_close(RECORD_NOTIFICATION); - furi_record_close(RECORD_GUI); - free(paint_state); - - return 0; -} diff --git a/applications/external/paint/paintIcon.png b/applications/external/paint/paintIcon.png deleted file mode 100644 index cc0a8b7d8077a58e373a30f38a1ece7caffc8150..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1911 zcmcIlO>g5w81`ye1V!Zl5-RKpEbnFcnAjf2pGvk$o3e>im(UGrxiOv@Cst#RvE3%^ z0iorDRB3+*(h9C{00DfEJbdYIas$@S_jda` z7Z(>W{piQvK7--KwDWN;Nj16rUiPXVYt%n14*gw^invCY2zYH0r+}8E#^xj? z^oSR7zz0#%RGxhIy&^}fsT`QT=BL|y7uZgP2MjSUh&+i$ zN$yRW%9PlHdAY4B@)S}WHI-IrQ9ks0^0vshY}YWNnx@INThjx}B)0pWj5Ul^%~Ev( z>9$w5JiRW@J_^{ANi%pRPgTd`acykWL^e=$*L775s~96dp!_r` z$OI+%?TTbZ)8;wNqO^!aBA2uz5XVJR0hg;-;&j2CeLBIRlTN_vCVF6Y z7wEj$IRPs(r!OVW`==>a_jxXkGs<^Pcv9S+8%u|x5cyF2hi{9&|K%a03xnx#Hk#&$ zQI(H)4BRLJZV zy4lw)PcuCOzpELZrd3cM1i?r_Rs#zbg{P}Pec$UQc|j7&yX~d|PSv7_d0J36aor)v zF@rjC+&V+9sTqhEdT8q=vuT}9{etstL66H!l;N~m94dG^ZI`NdrcHC7f4a0a zYk^TDPxa^#TDCz`p=JF!Q)b)IC5c@vgo<`NEr(lqvEDRk_wOQ#-UO&qmP_QMI*9-cXtxq2O1AHwv!2kdN diff --git a/applications/external/spectrum_analyzer/application.fam b/applications/external/spectrum_analyzer/application.fam deleted file mode 100644 index 13f5d49f9..000000000 --- a/applications/external/spectrum_analyzer/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="spectrum_analyzer", - name="Spectrum Analyzer", - apptype=FlipperAppType.EXTERNAL, - entry_point="spectrum_analyzer_app", - requires=["gui"], - stack_size=2 * 1024, - fap_icon="spectrum_10px.png", - fap_category="Sub-GHz", - fap_author="@xMasterX & @theY4Kman & @ALEEF02 (original by @jolcese)", - fap_version="1.1", - fap_description="Displays a spectrogram chart to visually represent RF signals around you.", -) diff --git a/applications/external/spectrum_analyzer/helpers/radio_device_loader.c b/applications/external/spectrum_analyzer/helpers/radio_device_loader.c deleted file mode 100644 index d2cffde58..000000000 --- a/applications/external/spectrum_analyzer/helpers/radio_device_loader.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "radio_device_loader.h" - -#include -#include - -static void radio_device_loader_power_on() { - uint8_t attempts = 0; - while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { - furi_hal_power_enable_otg(); - //CC1101 power-up time - furi_delay_ms(10); - } -} - -static void radio_device_loader_power_off() { - if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg(); -} - -bool radio_device_loader_is_connect_external(const char* name) { - bool is_connect = false; - bool is_otg_enabled = furi_hal_power_is_otg_enabled(); - - if(!is_otg_enabled) { - radio_device_loader_power_on(); - } - - const SubGhzDevice* device = subghz_devices_get_by_name(name); - if(device) { - is_connect = subghz_devices_is_connect(device); - } - - if(!is_otg_enabled) { - radio_device_loader_power_off(); - } - return is_connect; -} - -const SubGhzDevice* radio_device_loader_set( - const SubGhzDevice* current_radio_device, - SubGhzRadioDeviceType radio_device_type) { - const SubGhzDevice* radio_device; - - if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 && - radio_device_loader_is_connect_external(SUBGHZ_DEVICE_CC1101_EXT_NAME)) { - radio_device_loader_power_on(); - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME); - subghz_devices_begin(radio_device); - } else if(current_radio_device == NULL) { - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); - } else { - radio_device_loader_end(current_radio_device); - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); - } - - return radio_device; -} - -void radio_device_loader_end(const SubGhzDevice* radio_device) { - furi_assert(radio_device); - radio_device_loader_power_off(); - if(radio_device != subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME)) { - subghz_devices_end(radio_device); - } -} \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/helpers/radio_device_loader.h b/applications/external/spectrum_analyzer/helpers/radio_device_loader.h deleted file mode 100644 index bee4e2c36..000000000 --- a/applications/external/spectrum_analyzer/helpers/radio_device_loader.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -/** SubGhzRadioDeviceType */ -typedef enum { - SubGhzRadioDeviceTypeInternal, - SubGhzRadioDeviceTypeExternalCC1101, -} SubGhzRadioDeviceType; - -const SubGhzDevice* radio_device_loader_set( - const SubGhzDevice* current_radio_device, - SubGhzRadioDeviceType radio_device_type); - -void radio_device_loader_end(const SubGhzDevice* radio_device); \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/spectrum_10px.png b/applications/external/spectrum_analyzer/spectrum_10px.png deleted file mode 100644 index 743c2460b3ebde5152334c7c3e8e7a5d082b651b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4F%}28J29*~C-V}>arAU?4ABUl zJHe5Q!GPoNoB#56FFq`r5O`{j)M`N$&IK_Obp(@iS1hOxxLkbL*pR7zitn6fx3`?% iv3hNhdGYHn54r0fTK>MN-zEw)jKR~@&t;ucLK6TuM=vx0 diff --git a/applications/external/spectrum_analyzer/spectrum_analyzer.c b/applications/external/spectrum_analyzer/spectrum_analyzer.c deleted file mode 100644 index 345dd008b..000000000 --- a/applications/external/spectrum_analyzer/spectrum_analyzer.c +++ /dev/null @@ -1,611 +0,0 @@ -#include -#include - -#include -#include -#include -#include "spectrum_analyzer.h" - -#include -#include "spectrum_analyzer_worker.h" - -typedef struct { - uint32_t center_freq; - uint8_t width; - uint8_t modulation; - uint8_t band; - uint8_t vscroll; - - uint32_t channel0_frequency; - uint32_t spacing; - - bool mode_change; - bool modulation_change; - - float max_rssi; - uint8_t max_rssi_dec; - uint8_t max_rssi_channel; - uint8_t channel_ss[NUM_CHANNELS]; -} SpectrumAnalyzerModel; - -typedef struct { - SpectrumAnalyzerModel* model; - FuriMutex* model_mutex; - - FuriMessageQueue* event_queue; - - ViewPort* view_port; - Gui* gui; - - SpectrumAnalyzerWorker* worker; -} SpectrumAnalyzer; - -void spectrum_analyzer_draw_scale(Canvas* canvas, const SpectrumAnalyzerModel* model) { - // Draw line - canvas_draw_line( - canvas, FREQ_START_X, FREQ_BOTTOM_Y, FREQ_START_X + FREQ_LENGTH_X, FREQ_BOTTOM_Y); - // Draw minor scale - for(int i = FREQ_START_X; i < FREQ_START_X + FREQ_LENGTH_X; i += 5) { - canvas_draw_line(canvas, i, FREQ_BOTTOM_Y, i, FREQ_BOTTOM_Y + 2); - } - // Draw major scale - for(int i = FREQ_START_X; i < FREQ_START_X + FREQ_LENGTH_X; i += 25) { - canvas_draw_line(canvas, i, FREQ_BOTTOM_Y, i, FREQ_BOTTOM_Y + 4); - } - - // Draw scale tags - uint32_t tag_left = 0; - uint32_t tag_center = 0; - uint32_t tag_right = 0; - char temp_str[18]; - - tag_center = model->center_freq; - - switch(model->width) { - case NARROW: - tag_left = model->center_freq - 2000; - tag_right = model->center_freq + 2000; - break; - case ULTRANARROW: - tag_left = model->center_freq - 1000; - tag_right = model->center_freq + 1000; - break; - case PRECISE: - tag_left = model->center_freq - 200; - tag_right = model->center_freq + 200; - break; - case ULTRAWIDE: - tag_left = model->center_freq - 40000; - tag_right = model->center_freq + 40000; - break; - default: - tag_left = model->center_freq - 10000; - tag_right = model->center_freq + 10000; - } - - canvas_set_font(canvas, FontSecondary); - switch(model->width) { - case PRECISE: - case ULTRANARROW: - snprintf(temp_str, 18, "%.1f", ((double)tag_left) / 1000); - canvas_draw_str_aligned(canvas, FREQ_START_X, 63, AlignCenter, AlignBottom, temp_str); - snprintf(temp_str, 18, "%.1f", ((double)tag_center) / 1000); - canvas_draw_str_aligned(canvas, 128 / 2, 63, AlignCenter, AlignBottom, temp_str); - snprintf(temp_str, 18, "%.1f", ((double)tag_right) / 1000); - canvas_draw_str_aligned( - canvas, FREQ_START_X + FREQ_LENGTH_X - 1, 63, AlignCenter, AlignBottom, temp_str); - break; - default: - snprintf(temp_str, 18, "%lu", tag_left / 1000); - canvas_draw_str_aligned(canvas, FREQ_START_X, 63, AlignCenter, AlignBottom, temp_str); - snprintf(temp_str, 18, "%lu", tag_center / 1000); - canvas_draw_str_aligned(canvas, 128 / 2, 63, AlignCenter, AlignBottom, temp_str); - snprintf(temp_str, 18, "%lu", tag_right / 1000); - canvas_draw_str_aligned( - canvas, FREQ_START_X + FREQ_LENGTH_X - 1, 63, AlignCenter, AlignBottom, temp_str); - } -} - -static void spectrum_analyzer_render_callback(Canvas* const canvas, void* ctx) { - SpectrumAnalyzer* spectrum_analyzer = ctx; - //furi_check(furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk); - - SpectrumAnalyzerModel* model = spectrum_analyzer->model; - - spectrum_analyzer_draw_scale(canvas, model); - - for(uint8_t column = 0; column < 128; column++) { - uint8_t ss = model->channel_ss[column + 2]; - // Compress height to max of 64 values (255>>2) - uint8_t s = MAX((ss - model->vscroll) >> 2, 0); - uint8_t y = FREQ_BOTTOM_Y - s; // bar height - - // Draw each bar - canvas_draw_line(canvas, column, FREQ_BOTTOM_Y, column, y); - } - - if(model->mode_change) { - char temp_mode_str[12]; - switch(model->width) { - case NARROW: - strncpy(temp_mode_str, "NARROW", 12); - break; - case ULTRANARROW: - strncpy(temp_mode_str, "ULTRANARROW", 12); - break; - case PRECISE: - strncpy(temp_mode_str, "PRECISE", 12); - break; - case ULTRAWIDE: - strncpy(temp_mode_str, "ULTRAWIDE", 12); - break; - default: - strncpy(temp_mode_str, "WIDE", 12); - break; - } - - // Current mode label - char tmp_str[21]; - snprintf(tmp_str, 21, "Mode: %s", temp_mode_str); - canvas_draw_str_aligned(canvas, 127, 4, AlignRight, AlignTop, tmp_str); - } - - if(model->modulation_change) { - char temp_mod_str[12]; - switch(model->modulation) { - case NARROW_MODULATION: - strncpy(temp_mod_str, "NARROW", 12); - break; - default: - strncpy(temp_mod_str, "DEFAULT", 12); - break; - } - - // Current modulation label - char tmp_str[27]; - snprintf(tmp_str, 27, "Modulation: %s", temp_mod_str); - canvas_draw_str_aligned(canvas, 127, 4, AlignRight, AlignTop, tmp_str); - } - - // Draw cross and label - if(model->max_rssi > PEAK_THRESHOLD) { - // Compress height to max of 64 values (255>>2) - uint8_t max_y = MAX((model->max_rssi_dec - model->vscroll) >> 2, 0); - max_y = (FREQ_BOTTOM_Y - max_y); - - // Cross - int16_t x1, x2, y1, y2; - x1 = model->max_rssi_channel - 2 - 2; - if(x1 < 0) x1 = 0; - y1 = max_y - 2; - if(y1 < 0) y1 = 0; - x2 = model->max_rssi_channel - 2 + 2; - if(x2 > 127) x2 = 127; - y2 = max_y + 2; - if(y2 > 63) y2 = 63; // SHOULD NOT HAPPEN CHECK! - canvas_draw_line(canvas, x1, y1, x2, y2); - - x1 = model->max_rssi_channel - 2 + 2; - if(x1 > 127) x1 = 127; - y1 = max_y - 2; - if(y1 < 0) y1 = 0; - x2 = model->max_rssi_channel - 2 - 2; - if(x2 < 0) x2 = 0; - y2 = max_y + 2; - if(y2 > 63) y2 = 63; // SHOULD NOT HAPPEN CHECK! - canvas_draw_line(canvas, (uint8_t)x1, (uint8_t)y1, (uint8_t)x2, (uint8_t)y2); - - // Label - char temp_str[36]; - snprintf( - temp_str, - 36, - "Peak: %3.2f Mhz %3.1f dbm", - ((double)(model->channel0_frequency + (model->max_rssi_channel * model->spacing)) / - 1000000), - (double)model->max_rssi); - canvas_draw_str_aligned(canvas, 127, 0, AlignRight, AlignTop, temp_str); - } - - //furi_mutex_release(spectrum_analyzer->model_mutex); - - // FURI_LOG_D("Spectrum", "model->vscroll %u", model->vscroll); -} - -static void spectrum_analyzer_input_callback(InputEvent* input_event, void* ctx) { - SpectrumAnalyzer* spectrum_analyzer = ctx; - // Handle short and long presses - if(input_event->type == InputTypeShort || input_event->type == InputTypeLong) { - furi_message_queue_put(spectrum_analyzer->event_queue, input_event, FuriWaitForever); - } -} - -static void spectrum_analyzer_worker_callback( - void* channel_ss, - float max_rssi, - uint8_t max_rssi_dec, - uint8_t max_rssi_channel, - void* context) { - SpectrumAnalyzer* spectrum_analyzer = context; - furi_check( - furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk); - - SpectrumAnalyzerModel* model = (SpectrumAnalyzerModel*)spectrum_analyzer->model; - memcpy(model->channel_ss, (uint8_t*)channel_ss, sizeof(uint8_t) * NUM_CHANNELS); - model->max_rssi = max_rssi; - model->max_rssi_dec = max_rssi_dec; - model->max_rssi_channel = max_rssi_channel; - - furi_mutex_release(spectrum_analyzer->model_mutex); - view_port_update(spectrum_analyzer->view_port); -} - -void spectrum_analyzer_calculate_frequencies(SpectrumAnalyzerModel* model) { - // REDO ALL THIS. CALCULATE ONLY WITH SPACING! - - uint8_t new_band; - uint32_t min_hz; - uint32_t max_hz; - uint32_t margin; - uint32_t step; - uint32_t upper_limit; - uint32_t lower_limit; - uint32_t next_up; - uint32_t next_down; - uint8_t next_band_up; - uint8_t next_band_down; - - switch(model->width) { - case NARROW: - margin = NARROW_MARGIN; - step = NARROW_STEP; - model->spacing = NARROW_SPACING; - break; - case ULTRANARROW: - margin = ULTRANARROW_MARGIN; - step = ULTRANARROW_STEP; - model->spacing = ULTRANARROW_SPACING; - break; - case PRECISE: - margin = PRECISE_MARGIN; - step = PRECISE_STEP; - model->spacing = PRECISE_SPACING; - break; - case ULTRAWIDE: - margin = ULTRAWIDE_MARGIN; - step = ULTRAWIDE_STEP; - model->spacing = ULTRAWIDE_SPACING; - /* nearest 20 MHz step */ - model->center_freq = ((model->center_freq + 10000) / 20000) * 20000; - break; - default: - margin = WIDE_MARGIN; - step = WIDE_STEP; - model->spacing = WIDE_SPACING; - /* nearest 5 MHz step */ - model->center_freq = ((model->center_freq + 2000) / 5000) * 5000; - break; - } - - /* handle cases near edges of bands */ - if(model->center_freq > EDGE_900) { - new_band = BAND_900; - upper_limit = UPPER(MAX_900, margin, step); - lower_limit = LOWER(MIN_900, margin, step); - next_up = LOWER(MIN_300, margin, step); - next_down = UPPER(MAX_400, margin, step); - next_band_up = BAND_300; - next_band_down = BAND_400; - } else if(model->center_freq > EDGE_400) { - new_band = BAND_400; - upper_limit = UPPER(MAX_400, margin, step); - lower_limit = LOWER(MIN_400, margin, step); - next_up = LOWER(MIN_900, margin, step); - next_down = UPPER(MAX_300, margin, step); - next_band_up = BAND_900; - next_band_down = BAND_300; - } else { - new_band = BAND_300; - upper_limit = UPPER(MAX_300, margin, step); - lower_limit = LOWER(MIN_300, margin, step); - next_up = LOWER(MIN_400, margin, step); - next_down = UPPER(MAX_900, margin, step); - next_band_up = BAND_400; - next_band_down = BAND_900; - } - - if(model->center_freq > upper_limit) { - model->center_freq = upper_limit; - if(new_band == model->band) { - new_band = next_band_up; - model->center_freq = next_up; - } - } else if(model->center_freq < lower_limit) { - model->center_freq = lower_limit; - if(new_band == model->band) { - new_band = next_band_down; - model->center_freq = next_down; - } - } - - model->band = new_band; - /* doing everything in Hz from here on */ - switch(model->band) { - case BAND_400: - min_hz = MIN_400 * 1000; - max_hz = MAX_400 * 1000; - break; - case BAND_300: - min_hz = MIN_300 * 1000; - max_hz = MAX_300 * 1000; - break; - default: - min_hz = MIN_900 * 1000; - max_hz = MAX_900 * 1000; - break; - } - - model->channel0_frequency = - model->center_freq * 1000 - (model->spacing * ((NUM_CHANNELS / 2) + 1)); - - // /* calibrate upper channels */ - // hz = model->center_freq * 1000000; - // max_chan = NUM_CHANNELS / 2; - // while (hz <= max_hz && max_chan < NUM_CHANNELS) { - // instance->chan_table[max_chan].frequency = hz; - // FURI_LOG_T("Spectrum", "calibrate_freq ch[%u]: %lu", max_chan, hz); - // hz += model->spacing; - // max_chan++; - // } - - // /* calibrate lower channels */ - // hz = instance->freq * 1000000 - model->spacing; - // min_chan = NUM_CHANNELS / 2; - // while (hz >= min_hz && min_chan > 0) { - // min_chan--; - // instance->chan_table[min_chan].frequency = hz; - // FURI_LOG_T("Spectrum", "calibrate_freq ch[%u]: %lu", min_chan, hz); - // hz -= model->spacing; - // } - - model->max_rssi = -200.0; - model->max_rssi_dec = 0; - - FURI_LOG_D("Spectrum", "setup_frequencies - max_hz: %lu - min_hz: %lu", max_hz, min_hz); - FURI_LOG_D("Spectrum", "center_freq: %lu", model->center_freq); - FURI_LOG_D( - "Spectrum", - "ch[0]: %lu - ch[%u]: %lu", - model->channel0_frequency, - NUM_CHANNELS - 1, - model->channel0_frequency + ((NUM_CHANNELS - 1) * model->spacing)); -} - -SpectrumAnalyzer* spectrum_analyzer_alloc() { - SpectrumAnalyzer* instance = malloc(sizeof(SpectrumAnalyzer)); - instance->model = malloc(sizeof(SpectrumAnalyzerModel)); - - SpectrumAnalyzerModel* model = instance->model; - - for(uint8_t ch = 0; ch < NUM_CHANNELS - 1; ch++) { - model->channel_ss[ch] = 0; - } - model->max_rssi_dec = 0; - model->max_rssi_channel = 0; - model->max_rssi = PEAK_THRESHOLD - 1; // Should initializar to < PEAK_THRESHOLD - - model->center_freq = DEFAULT_FREQ; - model->width = WIDE; - model->modulation = DEFAULT_MODULATION; - model->band = BAND_400; - - model->vscroll = DEFAULT_VSCROLL; - - instance->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - instance->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - - instance->worker = spectrum_analyzer_worker_alloc(); - - spectrum_analyzer_worker_set_callback( - instance->worker, spectrum_analyzer_worker_callback, instance); - - // Set system callbacks - instance->view_port = view_port_alloc(); - view_port_draw_callback_set(instance->view_port, spectrum_analyzer_render_callback, instance); - view_port_input_callback_set(instance->view_port, spectrum_analyzer_input_callback, instance); - - // Open GUI and register view_port - instance->gui = furi_record_open(RECORD_GUI); - gui_add_view_port(instance->gui, instance->view_port, GuiLayerFullscreen); - - return instance; -} - -void spectrum_analyzer_free(SpectrumAnalyzer* instance) { - // view_port_enabled_set(view_port, false); - gui_remove_view_port(instance->gui, instance->view_port); - furi_record_close(RECORD_GUI); - view_port_free(instance->view_port); - - spectrum_analyzer_worker_free(instance->worker); - - furi_message_queue_free(instance->event_queue); - - furi_mutex_free(instance->model_mutex); - - free(instance->model); - free(instance); -} - -int32_t spectrum_analyzer_app(void* p) { - UNUSED(p); - - SpectrumAnalyzer* spectrum_analyzer = spectrum_analyzer_alloc(); - InputEvent input; - - furi_hal_power_suppress_charge_enter(); - - FURI_LOG_D("Spectrum", "Main Loop - Starting worker"); - furi_delay_ms(50); - - spectrum_analyzer_worker_start(spectrum_analyzer->worker); - spectrum_analyzer_calculate_frequencies(spectrum_analyzer->model); - spectrum_analyzer_worker_set_frequencies( - spectrum_analyzer->worker, - spectrum_analyzer->model->channel0_frequency, - spectrum_analyzer->model->spacing, - spectrum_analyzer->model->width); - - FURI_LOG_D("Spectrum", "Main Loop - Wait on queue"); - furi_delay_ms(50); - - while(furi_message_queue_get(spectrum_analyzer->event_queue, &input, FuriWaitForever) == - FuriStatusOk) { - furi_check( - furi_mutex_acquire(spectrum_analyzer->model_mutex, FuriWaitForever) == FuriStatusOk); - - FURI_LOG_D("Spectrum", "Main Loop - Input: %u", input.key); - - SpectrumAnalyzerModel* model = spectrum_analyzer->model; - - uint8_t vstep = VERTICAL_SHORT_STEP; - uint32_t hstep; - - bool exit_loop = false; - - switch(model->width) { - case NARROW: - hstep = NARROW_STEP; - break; - case ULTRANARROW: - hstep = ULTRANARROW_STEP; - break; - case ULTRAWIDE: - hstep = ULTRAWIDE_STEP; - break; - case PRECISE: - hstep = PRECISE_STEP; - break; - default: - hstep = WIDE_STEP; - break; - } - - switch(input.type) { - case InputTypeShort: - switch(input.key) { - case InputKeyUp: - model->vscroll = MAX(model->vscroll - vstep, MIN_VSCROLL); - FURI_LOG_D("Spectrum", "Vscroll: %u", model->vscroll); - break; - case InputKeyDown: - model->vscroll = MIN(model->vscroll + vstep, MAX_VSCROLL); - FURI_LOG_D("Spectrum", "Vscroll: %u", model->vscroll); - break; - case InputKeyRight: - model->center_freq += hstep; - FURI_LOG_D("Spectrum", "center_freq: %lu", model->center_freq); - spectrum_analyzer_calculate_frequencies(model); - spectrum_analyzer_worker_set_frequencies( - spectrum_analyzer->worker, - model->channel0_frequency, - model->spacing, - model->width); - break; - case InputKeyLeft: - model->center_freq -= hstep; - spectrum_analyzer_calculate_frequencies(model); - spectrum_analyzer_worker_set_frequencies( - spectrum_analyzer->worker, - model->channel0_frequency, - model->spacing, - model->width); - FURI_LOG_D("Spectrum", "center_freq: %lu", model->center_freq); - break; - case InputKeyOk: { - switch(model->width) { - case WIDE: - model->width = NARROW; - break; - case NARROW: - model->width = ULTRANARROW; - break; - case ULTRANARROW: - model->width = PRECISE; - break; - case PRECISE: - model->width = ULTRAWIDE; - break; - case ULTRAWIDE: - model->width = WIDE; - break; - default: - model->width = WIDE; - break; - } - } - model->mode_change = true; - view_port_update(spectrum_analyzer->view_port); - - furi_delay_ms(1000); - - model->mode_change = false; - spectrum_analyzer_calculate_frequencies(model); - spectrum_analyzer_worker_set_frequencies( - spectrum_analyzer->worker, - model->channel0_frequency, - model->spacing, - model->width); - FURI_LOG_D("Spectrum", "Width: %u", model->width); - break; - case InputKeyBack: - exit_loop = true; - break; - default: - break; - } - break; - case InputTypeLong: - switch(input.key) { - case InputKeyOk: - FURI_LOG_D("Spectrum", "InputTypeLong"); - switch(model->modulation) { - case NARROW_MODULATION: - model->modulation = DEFAULT_MODULATION; - break; - case DEFAULT_MODULATION: - default: - model->modulation = NARROW_MODULATION; - break; - } - - model->modulation_change = true; - view_port_update(spectrum_analyzer->view_port); - - furi_delay_ms(1000); - - model->modulation_change = false; - spectrum_analyzer_worker_set_modulation( - spectrum_analyzer->worker, spectrum_analyzer->model->modulation); - break; - default: - break; - } - break; - default: - break; - } - - furi_mutex_release(spectrum_analyzer->model_mutex); - view_port_update(spectrum_analyzer->view_port); - if(exit_loop == true) break; - } - - spectrum_analyzer_worker_stop(spectrum_analyzer->worker); - - furi_hal_power_suppress_charge_exit(); - - spectrum_analyzer_free(spectrum_analyzer); - - return 0; -} \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/spectrum_analyzer.h b/applications/external/spectrum_analyzer/spectrum_analyzer.h deleted file mode 100644 index bdd4c841c..000000000 --- a/applications/external/spectrum_analyzer/spectrum_analyzer.h +++ /dev/null @@ -1,84 +0,0 @@ -#define NUM_CHANNELS 132 -#define NUM_CHUNKS 6 -#define CHUNK_SIZE (NUM_CHANNELS / NUM_CHUNKS) - -// Screen coordinates -#define FREQ_BOTTOM_Y 50 -#define FREQ_START_X 14 -// How many channels displayed on the scale (On screen still 218) -#define FREQ_LENGTH_X 102 -// dBm threshold to show peak value -#define PEAK_THRESHOLD -85 - -/* - * ultrawide mode: 80 MHz on screen, 784 kHz per channel - * wide mode (default): 20 MHz on screen, 196 kHz per channel - * narrow mode: 4 MHz on screen, 39 kHz per channel - * ultranarrow mode: 2 MHz on screen, 19 kHz per channel - * precise mode: 400 KHz on screen, 3.92 kHz per channel - */ -#define WIDE 0 -#define NARROW 1 -#define ULTRAWIDE 2 -#define ULTRANARROW 3 -#define PRECISE 4 - -/* channel spacing in Hz */ -#define WIDE_SPACING 196078 -#define NARROW_SPACING 39215 -#define ULTRAWIDE_SPACING 784313 -#define ULTRANARROW_SPACING 19607 -#define PRECISE_SPACING 3921 - -/* vertical scrolling */ -#define VERTICAL_SHORT_STEP 16 -#define MAX_VSCROLL 120 -#define MIN_VSCROLL 0 -#define DEFAULT_VSCROLL 48 - -/* frequencies in KHz */ -#define DEFAULT_FREQ 440000 -#define WIDE_STEP 5000 -#define NARROW_STEP 1000 -#define ULTRAWIDE_STEP 20000 -#define ULTRANARROW_STEP 500 -#define PRECISE_STEP 100 - -/* margin in KHz */ -#define WIDE_MARGIN 13000 -#define NARROW_MARGIN 3000 -#define ULTRAWIDE_MARGIN 42000 -#define ULTRANARROW_MARGIN 1000 -#define PRECISE_MARGIN 200 - -/* frequency bands supported by device */ -#define BAND_300 0 -#define BAND_400 1 -#define BAND_900 2 - -/* band limits in KHz */ -#define MIN_300 281000 -#define CEN_300 315000 -#define MAX_300 361000 -#define MIN_400 378000 -#define CEN_400 435000 -#define MAX_400 481000 -#define MIN_900 749000 -#define CEN_900 855000 -#define MAX_900 962000 - -/* band transition points in KHz */ -#define EDGE_400 369000 -#define EDGE_900 615000 - -/* VCO transition points in Hz */ -#define MID_300 318000000 -#define MID_400 424000000 -#define MID_900 848000000 - -#define UPPER(a, b, c) ((((a) - (b) + ((c) / 2)) / (c)) * (c)) -#define LOWER(a, b, c) ((((a) + (b)) / (c)) * (c)) - -/* Modulation references */ -#define DEFAULT_MODULATION 0 -#define NARROW_MODULATION 1 \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/spectrum_analyzer_worker.c b/applications/external/spectrum_analyzer/spectrum_analyzer_worker.c deleted file mode 100644 index 4076e8a04..000000000 --- a/applications/external/spectrum_analyzer/spectrum_analyzer_worker.c +++ /dev/null @@ -1,345 +0,0 @@ -#include "spectrum_analyzer.h" -#include "spectrum_analyzer_worker.h" - -#include -#include - -#include "helpers/radio_device_loader.h" - -#include - -struct SpectrumAnalyzerWorker { - FuriThread* thread; - bool should_work; - - SpectrumAnalyzerWorkerCallback callback; - void* callback_context; - - const SubGhzDevice* radio_device; - - uint32_t channel0_frequency; - uint32_t spacing; - uint8_t width; - uint8_t modulation; - float max_rssi; - uint8_t max_rssi_dec; - uint8_t max_rssi_channel; - - uint8_t channel_ss[NUM_CHANNELS]; -}; - -/* set the channel bandwidth */ -void spectrum_analyzer_worker_set_filter(SpectrumAnalyzerWorker* instance) { - uint8_t filter_config[2][2] = { - {CC1101_MDMCFG4, 0}, - {0, 0}, - }; - - // FURI_LOG_D("SpectrumWorker", "spectrum_analyzer_worker_set_filter: width = %u", instance->width); - - /* channel spacing should fit within 80% of channel filter bandwidth */ - switch(instance->width) { - case NARROW: - filter_config[0][1] = 0xFC; /* 39.2 kHz / .8 = 49 kHz --> 58 kHz */ - break; - case ULTRAWIDE: - filter_config[0][1] = 0x0C; /* 784 kHz / .8 = 980 kHz --> 812 kHz */ - break; - default: - filter_config[0][1] = 0x6C; /* 196 kHz / .8 = 245 kHz --> 270 kHz */ - break; - } - - UNUSED(filter_config); - // furi_hal_subghz_load_registers((uint8_t*)filter_config); -} - -static int32_t spectrum_analyzer_worker_thread(void* context) { - furi_assert(context); - SpectrumAnalyzerWorker* instance = context; - - FURI_LOG_D("SpectrumWorker", "spectrum_analyzer_worker_thread: Start"); - - // Start CC1101 - subghz_devices_reset(instance->radio_device); - subghz_devices_load_preset(instance->radio_device, FuriHalSubGhzPresetOok650Async, NULL); - subghz_devices_set_frequency(instance->radio_device, 433920000); - subghz_devices_flush_rx(instance->radio_device); - subghz_devices_set_rx(instance->radio_device); - - // Default modulation - const uint8_t default_modulation[] = { - - /* Frequency Synthesizer Control */ - CC1101_FSCTRL0, - 0x00, - CC1101_FSCTRL1, - 0x12, // IF = (26*10^6) / (2^10) * 0x12 = 304687.5 Hz - - // Modem Configuration - // CC1101_MDMCFG0, - // 0x00, // Channel spacing is 25kHz - // CC1101_MDMCFG1, - // 0x00, // Channel spacing is 25kHz - // CC1101_MDMCFG2, - // 0x30, // Format ASK/OOK, No preamble/sync - // CC1101_MDMCFG3, - // 0x32, // Data rate is 121.399 kBaud - CC1101_MDMCFG4, - 0x6C, // Rx BW filter is 270.83 kHz - - /* Frequency Offset Compensation Configuration */ - // CC1101_FOCCFG, - // 0x18, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - // CC1101_AGCCTRL0, - // 0x91, // 10 - Medium hysteresis, medium asymmetric dead zone, medium gain ; 01 - 16 samples agc; 00 - Normal AGC, 01 - 8dB boundary - // CC1101_AGCCTRL1, - // 0x0, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - CC1101_AGCCTRL2, - 0xC0, // 03 - The 3 highest DVGA gain settings can not be used; 000 - MAX LNA+LNA2; 000 - MAIN_TARGET 24 dB - - /* Frontend configuration */ - // CC1101_FREND0, - // 0x11, // Adjusts current TX LO buffer + high is PATABLE[1] - // CC1101_FREND1, - // 0xB6, // - - CC1101_TEST2, - 0x88, - CC1101_TEST1, - 0x31, - CC1101_TEST0, - 0x09, - - /* End */ - 0, - 0, - - // ook_async_patable - 0x00, - 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - - // Narrow modulation - const uint8_t narrow_modulation[] = { - - /* Frequency Synthesizer Control */ - CC1101_FSCTRL0, - 0x00, - CC1101_FSCTRL1, - 0x00, // IF = (26*10^6) / (2^10) * 0x00 = 0 Hz - - // Modem Configuration - // CC1101_MDMCFG0, - // 0x00, // Channel spacing is 25kHz - // CC1101_MDMCFG1, - // 0x00, // Channel spacing is 25kHz - // CC1101_MDMCFG2, - // 0x30, // Format ASK/OOK, No preamble/sync - // CC1101_MDMCFG3, - // 0x32, // Data rate is 121.399 kBaud - CC1101_MDMCFG4, - 0xFC, // Rx BW filter is 58.04 kHz - - /* Frequency Offset Compensation Configuration */ - // CC1101_FOCCFG, - // 0x18, // no frequency offset compensation, POST_K same as PRE_K, PRE_K is 4K, GATE is off - - /* Automatic Gain Control */ - CC1101_AGCCTRL0, - 0x30, // 00 - NO hysteresis, symmetric dead zone, high gain ; 11 - 32 samples agc; 00 - Normal AGC, 00 - 8dB boundary - CC1101_AGCCTRL1, - 0x0, // 0; 0 - LNA 2 gain is decreased to minimum before decreasing LNA gain; 00 - Relative carrier sense threshold disabled; 0000 - RSSI to MAIN_TARGET - CC1101_AGCCTRL2, - 0x84, // 02 - The 2 highest DVGA gain settings can not be used; 000 - MAX LNA+LNA2; 100 - MAIN_TARGET 36 dB - - /* Frontend configuration */ - // CC1101_FREND0, - // 0x11, // Adjusts current TX LO buffer + high is PATABLE[1] - // CC1101_FREND1, - // 0xB6, // - - CC1101_TEST2, - 0x88, - CC1101_TEST1, - 0x31, - CC1101_TEST0, - 0x09, - - /* End */ - 0, - 0, - - // ook_async_patable - 0x00, - 0xC0, // 12dBm 0xC0, 10dBm 0xC5, 7dBm 0xCD, 5dBm 0x86, 0dBm 0x50, -6dBm 0x37, -10dBm 0x26, -15dBm 0x1D, -20dBm 0x17, -30dBm 0x03 - 0x00, - 0x00, - 0x00, - 0x00, - 0x00, - 0x00}; - - const uint8_t* modulations[] = {default_modulation, narrow_modulation}; - - while(instance->should_work) { - furi_delay_ms(50); - - // FURI_LOG_T("SpectrumWorker", "spectrum_analyzer_worker_thread: Worker Loop"); - subghz_devices_idle(instance->radio_device); - subghz_devices_load_preset( - instance->radio_device, - FuriHalSubGhzPresetCustom, - (uint8_t*)modulations[instance->modulation]); - //subghz_devices_load_preset( - // instance->radio_device, FuriHalSubGhzPresetCustom, (uint8_t*)default_modulation); - //furi_hal_subghz_load_custom_preset(modulations[instance->modulation]); - - // TODO: Check filter! - // spectrum_analyzer_worker_set_filter(instance); - - instance->max_rssi_dec = 0; - - // Visit each channel non-consecutively - for(uint8_t ch_offset = 0, chunk = 0; ch_offset < CHUNK_SIZE; - ++chunk >= NUM_CHUNKS && ++ch_offset && (chunk = 0)) { - uint8_t ch = chunk * CHUNK_SIZE + ch_offset; - - if(subghz_devices_is_frequency_valid( - instance->radio_device, - instance->channel0_frequency + (ch * instance->spacing))) - subghz_devices_set_frequency( - instance->radio_device, - instance->channel0_frequency + (ch * instance->spacing)); - - subghz_devices_set_rx(instance->radio_device); - furi_delay_ms(3); - - // dec dBm - //max_ss = 127 -> -10.5 - //max_ss = 0 -> -74.0 - //max_ss = 255 -> -74.5 - //max_ss = 128 -> -138.0 - instance->channel_ss[ch] = (subghz_devices_get_rssi(instance->radio_device) + 138) * 2; - - if(instance->channel_ss[ch] > instance->max_rssi_dec) { - instance->max_rssi_dec = instance->channel_ss[ch]; - instance->max_rssi = (instance->channel_ss[ch] / 2) - 138; - instance->max_rssi_channel = ch; - } - - subghz_devices_idle(instance->radio_device); - } - - // FURI_LOG_T("SpectrumWorker", "channel_ss[0]: %u", instance->channel_ss[0]); - - // Report results back to main thread - if(instance->callback) { - instance->callback( - (void*)&(instance->channel_ss), - instance->max_rssi, - instance->max_rssi_dec, - instance->max_rssi_channel, - instance->callback_context); - } - } - - return 0; -} - -SpectrumAnalyzerWorker* spectrum_analyzer_worker_alloc() { - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_alloc: Start"); - - SpectrumAnalyzerWorker* instance = malloc(sizeof(SpectrumAnalyzerWorker)); - - instance->thread = furi_thread_alloc(); - furi_thread_set_name(instance->thread, "SpectrumWorker"); - furi_thread_set_stack_size(instance->thread, 2048); - furi_thread_set_context(instance->thread, instance); - furi_thread_set_callback(instance->thread, spectrum_analyzer_worker_thread); - - subghz_devices_init(); - - instance->radio_device = - radio_device_loader_set(instance->radio_device, SubGhzRadioDeviceTypeExternalCC1101); - - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_alloc: End"); - - return instance; -} - -void spectrum_analyzer_worker_free(SpectrumAnalyzerWorker* instance) { - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_free"); - furi_assert(instance); - furi_thread_free(instance->thread); - - subghz_devices_sleep(instance->radio_device); - radio_device_loader_end(instance->radio_device); - - subghz_devices_deinit(); - - free(instance); -} - -void spectrum_analyzer_worker_set_callback( - SpectrumAnalyzerWorker* instance, - SpectrumAnalyzerWorkerCallback callback, - void* context) { - furi_assert(instance); - instance->callback = callback; - instance->callback_context = context; -} - -void spectrum_analyzer_worker_set_frequencies( - SpectrumAnalyzerWorker* instance, - uint32_t channel0_frequency, - uint32_t spacing, - uint8_t width) { - furi_assert(instance); - - FURI_LOG_D( - "SpectrumWorker", - "spectrum_analyzer_worker_set_frequencies - channel0_frequency= %lu - spacing = %lu - width = %u", - channel0_frequency, - spacing, - width); - - instance->channel0_frequency = channel0_frequency; - instance->spacing = spacing; - instance->width = width; -} - -void spectrum_analyzer_worker_set_modulation(SpectrumAnalyzerWorker* instance, uint8_t modulation) { - furi_assert(instance); - - FURI_LOG_D( - "SpectrumWorker", "spectrum_analyzer_worker_set_modulation - modulation = %u", modulation); - - instance->modulation = modulation; -} - -void spectrum_analyzer_worker_start(SpectrumAnalyzerWorker* instance) { - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_start"); - - furi_assert(instance); - furi_assert(instance->should_work == false); - - instance->should_work = true; - furi_thread_start(instance->thread); -} - -void spectrum_analyzer_worker_stop(SpectrumAnalyzerWorker* instance) { - FURI_LOG_D("Spectrum", "spectrum_analyzer_worker_stop"); - furi_assert(instance); - furi_assert(instance->should_work == true); - - instance->should_work = false; - furi_thread_join(instance->thread); -} \ No newline at end of file diff --git a/applications/external/spectrum_analyzer/spectrum_analyzer_worker.h b/applications/external/spectrum_analyzer/spectrum_analyzer_worker.h deleted file mode 100644 index 796f532e6..000000000 --- a/applications/external/spectrum_analyzer/spectrum_analyzer_worker.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include - -typedef void (*SpectrumAnalyzerWorkerCallback)( - void* chan_table, - float max_rssi, - uint8_t max_rssi_dec, - uint8_t max_rssi_channel, - void* context); - -typedef struct SpectrumAnalyzerWorker SpectrumAnalyzerWorker; - -SpectrumAnalyzerWorker* spectrum_analyzer_worker_alloc(); - -void spectrum_analyzer_worker_free(SpectrumAnalyzerWorker* instance); - -void spectrum_analyzer_worker_set_callback( - SpectrumAnalyzerWorker* instance, - SpectrumAnalyzerWorkerCallback callback, - void* context); - -void spectrum_analyzer_worker_set_filter(SpectrumAnalyzerWorker* instance); - -void spectrum_analyzer_worker_set_frequencies( - SpectrumAnalyzerWorker* instance, - uint32_t channel0_frequency, - uint32_t spacing, - uint8_t width); - -void spectrum_analyzer_worker_set_modulation(SpectrumAnalyzerWorker* instance, uint8_t modulation); - -void spectrum_analyzer_worker_start(SpectrumAnalyzerWorker* instance); - -void spectrum_analyzer_worker_stop(SpectrumAnalyzerWorker* instance); diff --git a/applications/external/tanksgame/application.fam b/applications/external/tanksgame/application.fam deleted file mode 100644 index bf6bd1b4a..000000000 --- a/applications/external/tanksgame/application.fam +++ /dev/null @@ -1,12 +0,0 @@ -App( - appid="tanks", - name="Tanks", - apptype=FlipperAppType.EXTERNAL, - entry_point="tanks_game_app", - cdefines=["APP_TANKS_GAME"], - requires=["gui", "subghz"], - stack_size=4 * 1024, - fap_icon="tanksIcon.png", - fap_category="Games", - fap_icon_assets="images", -) diff --git a/applications/external/tanksgame/constants.h b/applications/external/tanksgame/constants.h deleted file mode 100644 index d65dd32ea..000000000 --- a/applications/external/tanksgame/constants.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef FLIPPERZERO_FIRMWARE_CONSTANTS_H -#define FLIPPERZERO_FIRMWARE_CONSTANTS_H - -const uint8_t SCREEN_WIDTH_TANKS = 128; -const uint8_t SCREEN_HEIGHT_TANKS = 64; - -const uint8_t FIELD_WIDTH = 16; -const uint8_t FIELD_HEIGHT = 11; - -const uint16_t TURN_LENGTH = 300; -const uint16_t LONG_PRESS_LENGTH = 10; - -const uint8_t SHOT_COOLDOWN = 5; -const uint8_t RESPAWN_COOLDOWN = 8; -const uint8_t PLAYER_RESPAWN_COOLDOWN = 1; - -const uint8_t CELL_LENGTH_PIXELS = 6; - -#endif diff --git a/applications/external/tanksgame/helpers/radio_device_loader.c b/applications/external/tanksgame/helpers/radio_device_loader.c deleted file mode 100644 index d2cffde58..000000000 --- a/applications/external/tanksgame/helpers/radio_device_loader.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "radio_device_loader.h" - -#include -#include - -static void radio_device_loader_power_on() { - uint8_t attempts = 0; - while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) { - furi_hal_power_enable_otg(); - //CC1101 power-up time - furi_delay_ms(10); - } -} - -static void radio_device_loader_power_off() { - if(furi_hal_power_is_otg_enabled()) furi_hal_power_disable_otg(); -} - -bool radio_device_loader_is_connect_external(const char* name) { - bool is_connect = false; - bool is_otg_enabled = furi_hal_power_is_otg_enabled(); - - if(!is_otg_enabled) { - radio_device_loader_power_on(); - } - - const SubGhzDevice* device = subghz_devices_get_by_name(name); - if(device) { - is_connect = subghz_devices_is_connect(device); - } - - if(!is_otg_enabled) { - radio_device_loader_power_off(); - } - return is_connect; -} - -const SubGhzDevice* radio_device_loader_set( - const SubGhzDevice* current_radio_device, - SubGhzRadioDeviceType radio_device_type) { - const SubGhzDevice* radio_device; - - if(radio_device_type == SubGhzRadioDeviceTypeExternalCC1101 && - radio_device_loader_is_connect_external(SUBGHZ_DEVICE_CC1101_EXT_NAME)) { - radio_device_loader_power_on(); - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_EXT_NAME); - subghz_devices_begin(radio_device); - } else if(current_radio_device == NULL) { - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); - } else { - radio_device_loader_end(current_radio_device); - radio_device = subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME); - } - - return radio_device; -} - -void radio_device_loader_end(const SubGhzDevice* radio_device) { - furi_assert(radio_device); - radio_device_loader_power_off(); - if(radio_device != subghz_devices_get_by_name(SUBGHZ_DEVICE_CC1101_INT_NAME)) { - subghz_devices_end(radio_device); - } -} \ No newline at end of file diff --git a/applications/external/tanksgame/helpers/radio_device_loader.h b/applications/external/tanksgame/helpers/radio_device_loader.h deleted file mode 100644 index bee4e2c36..000000000 --- a/applications/external/tanksgame/helpers/radio_device_loader.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -/** SubGhzRadioDeviceType */ -typedef enum { - SubGhzRadioDeviceTypeInternal, - SubGhzRadioDeviceTypeExternalCC1101, -} SubGhzRadioDeviceType; - -const SubGhzDevice* radio_device_loader_set( - const SubGhzDevice* current_radio_device, - SubGhzRadioDeviceType radio_device_type); - -void radio_device_loader_end(const SubGhzDevice* radio_device); \ No newline at end of file diff --git a/applications/external/tanksgame/images/HappyFlipper_128x64.png b/applications/external/tanksgame/images/HappyFlipper_128x64.png deleted file mode 100644 index d95412f3fc948ab35488bfb2863d5e99c1549b5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 633 zcmeAS@N?(olHy`uVBq!ia0vp^4M6O`2qYMOt#!Htq*&4&eH|GXHuiJ>Nn{1`6_P!I zd>I(3)PQPRfU1B(4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v&Zs#nFUg#aNWqT?B^gg;;v2;nhMNKJLf3T*3IsVgV7dR_e+i&DK>CL@b;;?HY7${s#- z^dG;E#QH-VU$wqW2z=4(?9Q_9+nE^x9`X#O9tr=re1e%iv1a@cxUihJjh`vffYB`D z!U2}t={q+)5&UtD#qRq}KMtlziQ z;92-;WxFTKS-nj4a(Sg%#a_AzPXy z-$k)A9y!psp>mFix#BU^lr>xVG-b}bndkmd_{k!c87VtUrWPbDi*0<)#qn^~<)a1* z`V2oO1iLm=@|AtxcRH#v!i-&Cft%}vsDM6y#hZqoySijVKL1UfoZgwTug8jgg7&6d z&x1C97}srF_~*_f^-5s;sFt`!l%ynNn{1`6_P!I zd>I(3)PQPRfU1B(4KElNN(~qoUL`OvSj}Ky5HFasE6@fg!Ib3f?!v&Zs#nc$C93Y zeX@v*%x>qE6Z^g7T+aJ{S)JhwPn5hKZX%YYRdd3GW14FgMqKS)=4`_G<P}pY7HK!7(1s9z{6!B^^Dy_QLOoG6AL8?^-lpamao#FwmRvp9Qt&?;-4$LS3#+Pb|YeY#(Vo9o1a#1RfVlXl= zGSW3P)HN^(F*39=HnK9c&^9ozGBB7oWAh&r4Y~O#nQ4`{HM~E{?Euuk;OXk;vd$@? F2>|m+_4)t+ diff --git a/applications/external/tanksgame/images/enemy_down.png b/applications/external/tanksgame/images/enemy_down.png deleted file mode 100644 index 84d64ed44d7a46e8438d789c73258f7f48b6f9f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XJ3i-X*q7}lMWc?smOq&xaLGB9lH z=l+w(3gmMZctjR6Fz_7#VaBQ2e9}NcBTpB{5Q*^Ql!SyI{45S!j1rQPk_UtY^t2M1 wE-BFVdQ&MBb@0P}AtS^xk5 diff --git a/applications/external/tanksgame/images/enemy_left.png b/applications/external/tanksgame/images/enemy_left.png deleted file mode 100644 index e118d03a88a35f189f7e9d64be46dc975a331ab7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XJ3i-X*q7}lMWc?smOq&xaLGB9lH z=l+w(3gmMZctjR6Fz_7#VaBQ2e9}Nc6Hgb%5Q*^IUPmql1CGNz|Nn2^%<7n8$#HZ_ z5U;@WD=+6CUNC3V@{O$KbxYP5exD{?F4Muzpe)S2)$X1wP(OpGtDnm{r-UW|6qPM^ diff --git a/applications/external/tanksgame/images/enemy_right.png b/applications/external/tanksgame/images/enemy_right.png deleted file mode 100644 index 8c5f0603b7b1a85df0e552a9688476f9e2e22d62..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XJ3i-X*q7}lMWc?smOq&xaLGB9lH z=l+w(3gmMZctjR6Fz_7#VaBQ2e9}Nc6Hgb%5Q*^8UPdkk0}iIG|Nq}i4cKy!Pvn#e zQ@|@Hp+nnVTArF5H$lhugHhx9p4r!)?<`V&n88y~tIWJ%b?kTQ*z$8GBNPe82zopr0N&Lc Az5oCK diff --git a/applications/external/tanksgame/images/projectile_left.png b/applications/external/tanksgame/images/projectile_left.png deleted file mode 100644 index c8c54786d99cb80a5c434adefcd22148164f24af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XI?JzX3_IAoLm@U!qlFmU_yOq?iq zEQMiZD$~actd2FVdQ&MBb@ E0RPGx3;+NC diff --git a/applications/external/tanksgame/images/projectile_up.png b/applications/external/tanksgame/images/projectile_up.png deleted file mode 100644 index 5324466572c019530b09851a69d82dc8d9ccfa96..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102 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 diff --git a/applications/external/tanksgame/images/tank_down.png b/applications/external/tanksgame/images/tank_down.png deleted file mode 100644 index d4e2c8786011e5d8e0c2227b748afd672521cbde..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3040 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 q=-vv0=3zL-1Gr)wzcK} diff --git a/applications/external/tanksgame/images/tank_hedgehog.png b/applications/external/tanksgame/images/tank_hedgehog.png deleted file mode 100644 index fdd804be97d5abda446013eb1c58999ca516a62e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3049 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 diff --git a/applications/external/tanksgame/images/tank_wall.png b/applications/external/tanksgame/images/tank_wall.png deleted file mode 100644 index 88d537cdb70009c0f3a4e82df66b5729d4938f65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3039 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "tanks_icons.h" -#include -#include "helpers/radio_device_loader.h" - -#include "constants.h" - -typedef struct { - // +-----x - // | - // | - // y - uint8_t x; - uint8_t y; -} Point; - -typedef enum { - CellEmpty = 1, - CellWall, - CellExplosion, - CellTankUp, - CellTankRight, - CellTankDown, - CellTankLeft, - CellEnemyUp, - CellEnemyRight, - CellEnemyDown, - CellEnemyLeft, - CellProjectileUp, - CellProjectileRight, - CellProjectileDown, - CellProjectileLeft, -} GameCellState; - -typedef enum { - MenuStateSingleMode, - MenuStateCooperativeServerMode, - MenuStateCooperativeClientMode, -} MenuState; - -typedef enum { - GameStateMenu, - GameStateSingle, - GameStateCooperativeServer, - GameStateCooperativeClient, - GameStateGameOver, -} GameState; - -typedef enum { - DirectionUp, - DirectionRight, - DirectionDown, - DirectionLeft, -} Direction; - -typedef enum { - ModeSingle, - ModeCooperative, -} Mode; - -typedef struct { - Point coordinates; - Direction direction; - bool explosion; - bool is_p1; - bool is_p2; -} ProjectileState; - -typedef struct { - Point coordinates; - uint16_t score; - uint8_t lives; - Direction direction; - bool moving; - bool shooting; - bool live; - uint8_t cooldown; - uint8_t respawn_cooldown; -} PlayerState; - -typedef struct { - // char map[FIELD_WIDTH][FIELD_HEIGHT]; - char thisMap[16][11]; - Point team_one_respawn_points[3]; - Point team_two_respawn_points[3]; - Mode mode; - bool server; - GameState state; - MenuState menu_state; - ProjectileState* projectiles[100]; - PlayerState* bots[6]; - uint8_t enemies_left; - uint8_t enemies_live; - uint8_t enemies_respawn_cooldown; - uint8_t received; - uint8_t sent; - PlayerState* p1; - PlayerState* p2; - FuriMutex* mutex; -} TanksState; - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} TanksEvent; - -typedef enum { - GoesUp, - GoesRight, - GoesDown, - GoesLeft, - Shoots, -} ClientAction; - -//char map[FIELD_HEIGHT][FIELD_WIDTH + 1] = { -char thisMap[11][16 + 1] = { - "* - * -", - " - - = ", - " - - 2", - "1 = - -- ", - "-- = - -- ", - "a-1 = - = 2", - "-- = - -- ", - "1 = - -- ", - " - - 2", - " - - = ", - "* - * -", -}; - -static void tanks_game_write_cell(unsigned char* data, int8_t x, int8_t y, GameCellState cell) { - uint8_t index = y * 16 + x; - data[index] = cell; - // if (x % 2) { - // data[index] = (data[index] & 0b00001111) + (cell << 4); - // } else { - // data[index] = (data[index] & 0b0000) + cell; - // } -} - -// Enum with < 16 items => 4 bits in cell, 2 cells in byte -unsigned char* tanks_game_serialize(const TanksState* const tanks_state) { - static unsigned char result[11 * 16 + 1]; - - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - result[(y * FIELD_WIDTH + x)] = 0; - - GameCellState cell = CellEmpty; - - if(tanks_state->thisMap[x][y] == '-') { - cell = CellWall; - - tanks_game_write_cell(result, x, y, cell); - } - } - } - - for(uint8_t i = 0; i < 6; i++) { - if(tanks_state->bots[i] != NULL) { - GameCellState cell = CellEmpty; - - switch(tanks_state->bots[i]->direction) { - case DirectionUp: - cell = CellEnemyUp; - break; - case DirectionDown: - cell = CellEnemyDown; - break; - case DirectionRight: - cell = CellEnemyRight; - break; - case DirectionLeft: - cell = CellEnemyLeft; - break; - default: - break; - } - - tanks_game_write_cell( - result, - tanks_state->bots[i]->coordinates.x, - tanks_state->bots[i]->coordinates.y, - cell); - } - } - - for(int8_t x = 0; x < 100; x++) { - if(tanks_state->projectiles[x] != NULL) { - GameCellState cell = CellEmpty; - - switch(tanks_state->projectiles[x]->direction) { - case DirectionUp: - cell = CellProjectileUp; - break; - case DirectionDown: - cell = CellProjectileDown; - break; - case DirectionRight: - cell = CellProjectileRight; - break; - case DirectionLeft: - cell = CellProjectileLeft; - break; - default: - break; - } - - tanks_game_write_cell( - result, - tanks_state->projectiles[x]->coordinates.x, - tanks_state->projectiles[x]->coordinates.y, - cell); - } - } - - if(tanks_state->p1 != NULL && tanks_state->p1->live) { - GameCellState cell = CellEmpty; - - switch(tanks_state->p1->direction) { - case DirectionUp: - cell = CellTankUp; - break; - case DirectionDown: - cell = CellTankDown; - break; - case DirectionRight: - cell = CellTankRight; - break; - case DirectionLeft: - cell = CellTankLeft; - break; - default: - break; - } - - tanks_game_write_cell( - result, tanks_state->p1->coordinates.x, tanks_state->p1->coordinates.y, cell); - } - - if(tanks_state->p2 != NULL && tanks_state->p2->live) { - GameCellState cell = CellEmpty; - - switch(tanks_state->p2->direction) { - case DirectionUp: - cell = CellTankUp; - break; - case DirectionDown: - cell = CellTankDown; - break; - case DirectionRight: - cell = CellTankRight; - break; - case DirectionLeft: - cell = CellTankLeft; - break; - default: - break; - } - - tanks_game_write_cell( - result, tanks_state->p2->coordinates.x, tanks_state->p2->coordinates.y, cell); - } - - return result; -} - -static void - tanks_game_render_cell(GameCellState cell, uint8_t x, uint8_t y, Canvas* const canvas) { - const Icon* icon; - - if(cell == CellEmpty) { - return; - } - - switch(cell) { - case CellWall: - icon = &I_tank_wall; - break; - case CellExplosion: - icon = &I_tank_explosion; - break; - case CellTankUp: - icon = &I_tank_up; - break; - case CellTankRight: - icon = &I_tank_right; - break; - case CellTankDown: - icon = &I_tank_down; - break; - case CellTankLeft: - icon = &I_tank_left; - break; - case CellEnemyUp: - icon = &I_enemy_up; - break; - case CellEnemyRight: - icon = &I_enemy_right; - break; - case CellEnemyDown: - icon = &I_enemy_down; - break; - case CellEnemyLeft: - icon = &I_enemy_left; - break; - case CellProjectileUp: - icon = &I_projectile_up; - break; - case CellProjectileRight: - icon = &I_projectile_right; - break; - case CellProjectileDown: - icon = &I_projectile_down; - break; - case CellProjectileLeft: - icon = &I_projectile_left; - break; - default: - return; - break; - } - - canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, icon); -} - -static void tanks_game_render_constant_cells(Canvas* const canvas) { - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - char cell = thisMap[y][x]; - - if(cell == '=') { - canvas_draw_icon( - canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_stone); - continue; - } - - if(cell == '*') { - canvas_draw_icon( - canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_hedgehog); - continue; - } - - if(cell == 'a') { - canvas_draw_icon( - canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_base); - continue; - } - } - } -} - -void tanks_game_deserialize_and_write_to_state(unsigned char* data, TanksState* const tanks_state) { - for(uint8_t i = 0; i < 11 * 16; i++) { - uint8_t x = i % 16; - uint8_t y = i / 16; - tanks_state->thisMap[x][y] = data[i]; - } -} - -void tanks_game_deserialize_and_render(unsigned char* data, Canvas* const canvas) { - //for (uint8_t i = 0; i < 11 * 16 / 2; i++) { - for(uint8_t i = 0; i < 11 * 16; i++) { - char cell = data[i]; - uint8_t x = i % 16; // One line (16 cells) = 8 bytes - uint8_t y = i / 16; - - // GameCellState first = cell >> 4; - // GameCellState second = cell & 0b00001111; - - tanks_game_render_cell(cell, x, y, canvas); - // tanks_game_render_cell(second, x + 1, y, canvas); - } - - tanks_game_render_constant_cells(canvas); -} - -static void tanks_game_render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const TanksState* tanks_state = ctx; - furi_mutex_acquire(tanks_state->mutex, FuriWaitForever); - - // Before the function is called, the state is set with the canvas_reset(canvas) - if(tanks_state->state == GameStateMenu) { - canvas_draw_icon(canvas, 0, 0, &I_TanksSplashScreen_128x64); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 124, 10, AlignRight, AlignBottom, "Single"); - canvas_draw_str_aligned(canvas, 124, 25, AlignRight, AlignBottom, "Co-op S"); - canvas_draw_str_aligned(canvas, 124, 40, AlignRight, AlignBottom, "Co-op C"); - - switch(tanks_state->menu_state) { - case MenuStateSingleMode: - canvas_draw_icon(canvas, 74, 3, &I_tank_right); - break; - case MenuStateCooperativeServerMode: - canvas_draw_icon(canvas, 74, 18, &I_tank_right); - break; - case MenuStateCooperativeClientMode: - canvas_draw_icon(canvas, 74, 33, &I_tank_right); - break; - } - - canvas_draw_frame(canvas, 0, 0, 128, 64); - - furi_mutex_release(tanks_state->mutex); - return; - } - - // Field right border - canvas_draw_box(canvas, FIELD_WIDTH * CELL_LENGTH_PIXELS, 0, 2, SCREEN_HEIGHT_TANKS); - - // Cooperative client - if(tanks_state->mode == ModeCooperative && !tanks_state->server) { - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - tanks_game_render_cell(tanks_state->thisMap[x][y], x, y, canvas); - } - } - - tanks_game_render_constant_cells(canvas); - - furi_mutex_release(tanks_state->mutex); - return; - } - - // Player - // Point coordinates = tanks_state->p1->coordinates; - // const Icon *icon; - // switch (tanks_state->p1->direction) { - // case DirectionUp: - // icon = &I_tank_up; - // break; - // case DirectionDown: - // icon = &I_tank_down; - // break; - // case DirectionRight: - // icon = &I_tank_right; - // break; - // case DirectionLeft: - // icon = &I_tank_left; - // break; - // default: - // icon = &I_tank_explosion; - // } - - // if (tanks_state->p1->live) { - // canvas_draw_icon(canvas, coordinates.x * CELL_LENGTH_PIXELS, coordinates.y * CELL_LENGTH_PIXELS - 1, icon); - // } - // - // for(int8_t x = 0; x < FIELD_WIDTH; x++) { - // for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - // switch (tanks_state->thisMap[x][y]) { - // case '-': - // canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_wall); - // break; - // - // case '=': - // canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_stone); - // break; - // - // case '*': - // canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_hedgehog); - // break; - // - // case 'a': - // canvas_draw_icon(canvas, x * CELL_LENGTH_PIXELS, y * CELL_LENGTH_PIXELS - 1, &I_tank_base); - // break; - // } - // } - // } - - // for ( - // uint8_t i = 0; - // i < 6; - // i++ - // ) { - // if (tanks_state->bots[i] != NULL) { - // const Icon *icon; - // - // switch(tanks_state->bots[i]->direction) { - // case DirectionUp: - // icon = &I_enemy_up; - // break; - // case DirectionDown: - // icon = &I_enemy_down; - // break; - // case DirectionRight: - // icon = &I_enemy_right; - // break; - // case DirectionLeft: - // icon = &I_enemy_left; - // break; - // default: - // icon = &I_tank_explosion; - // } - // - // canvas_draw_icon( - // canvas, - // tanks_state->bots[i]->coordinates.x * CELL_LENGTH_PIXELS, - // tanks_state->bots[i]->coordinates.y * CELL_LENGTH_PIXELS - 1, - // icon); - // } - // } - - // for(int8_t x = 0; x < 100; x++) { - // if (tanks_state->projectiles[x] != NULL) { - // ProjectileState *projectile = tanks_state->projectiles[x]; - // - // if (projectile->explosion) { - // canvas_draw_icon( - // canvas, - // projectile->coordinates.x * CELL_LENGTH_PIXELS, - // projectile->coordinates.y * CELL_LENGTH_PIXELS - 1, - // &I_tank_explosion); - // continue; - // } - // - // const Icon *icon; - // - // switch(projectile->direction) { - // case DirectionUp: - // icon = &I_projectile_up; - // break; - // case DirectionDown: - // icon = &I_projectile_down; - // break; - // case DirectionRight: - // icon = &I_projectile_right; - // break; - // case DirectionLeft: - // icon = &I_projectile_left; - // break; - // default: - // icon = &I_tank_explosion; - // } - // - // canvas_draw_icon( - // canvas, - // projectile->coordinates.x * CELL_LENGTH_PIXELS, - // projectile->coordinates.y * CELL_LENGTH_PIXELS - 1, - // icon); - // } - // } - - // Info - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - char buffer1[13]; - snprintf(buffer1, sizeof(buffer1), "live: %u", tanks_state->enemies_live); - canvas_draw_str_aligned(canvas, 127, 8, AlignRight, AlignBottom, buffer1); - - snprintf(buffer1, sizeof(buffer1), "left: %u", tanks_state->enemies_left); - canvas_draw_str_aligned(canvas, 127, 18, AlignRight, AlignBottom, buffer1); - - snprintf(buffer1, sizeof(buffer1), "p1 l: %u", tanks_state->p1->lives); - canvas_draw_str_aligned(canvas, 127, 28, AlignRight, AlignBottom, buffer1); - - snprintf(buffer1, sizeof(buffer1), "p1 s: %u", tanks_state->p1->score); - canvas_draw_str_aligned(canvas, 127, 38, AlignRight, AlignBottom, buffer1); - - if(tanks_state->state == GameStateCooperativeServer && tanks_state->p2) { - snprintf(buffer1, sizeof(buffer1), "rec: %u", tanks_state->received); - canvas_draw_str_aligned(canvas, 127, 48, AlignRight, AlignBottom, buffer1); - - snprintf(buffer1, sizeof(buffer1), "snt: %u", tanks_state->sent); - canvas_draw_str_aligned(canvas, 127, 58, AlignRight, AlignBottom, buffer1); - // snprintf(buffer1, sizeof(buffer1), "p2 l: %u", tanks_state->p2->lives); - // canvas_draw_str_aligned(canvas, 127, 48, AlignRight, AlignBottom, buffer1); - // - // snprintf(buffer1, sizeof(buffer1), "p2 s: %u", tanks_state->p2->score); - // canvas_draw_str_aligned(canvas, 127, 58, AlignRight, AlignBottom, buffer1); - } - - if(tanks_state->state == GameStateCooperativeClient) { - snprintf(buffer1, sizeof(buffer1), "rec: %u", tanks_state->received); - canvas_draw_str_aligned(canvas, 127, 48, AlignRight, AlignBottom, buffer1); - } - - // Game Over banner - if(tanks_state->state == GameStateGameOver) { - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 34, 20, 62, 24); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 34, 20, 62, 24); - canvas_set_font(canvas, FontPrimary); - - if(tanks_state->enemies_left == 0 && tanks_state->enemies_live == 0) { - canvas_draw_str(canvas, 37, 31, "You win!"); - } else { - canvas_draw_str(canvas, 37, 31, "Game Over"); - } - - canvas_set_font(canvas, FontSecondary); - char buffer[13]; - snprintf(buffer, sizeof(buffer), "Score: %u", tanks_state->p1->score); - canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, buffer); - } - - // TEST start - unsigned char* data = tanks_game_serialize(tanks_state); - tanks_game_deserialize_and_render(data, canvas); - // TEST enf - - furi_mutex_release(tanks_state->mutex); -} - -static void tanks_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - TanksEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void tanks_game_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - TanksEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -static bool tanks_get_cell_is_free(TanksState* const tanks_state, Point point) { - // Tiles - if(tanks_state->thisMap[point.x][point.y] != ' ') { - return false; - } - - // Projectiles - for(int8_t x = 0; x < 100; x++) { - if(tanks_state->projectiles[x] != NULL) { - if(tanks_state->projectiles[x]->coordinates.x == point.x && - tanks_state->projectiles[x]->coordinates.y == point.y) { - return false; - } - } - } - - // Player 1 - if(tanks_state->p1 != NULL) { - if(tanks_state->p1->coordinates.x == point.x && - tanks_state->p1->coordinates.y == point.y) { - return false; - } - } - - // Player 2 - if(tanks_state->p2 != NULL) { - if(tanks_state->p2->coordinates.x == point.x && - tanks_state->p2->coordinates.y == point.y) { - return false; - } - } - - // Bots - for(int8_t x = 0; x < 6; x++) { - if(tanks_state->bots[x] != NULL) { - if(tanks_state->bots[x]->coordinates.x == point.x && - tanks_state->bots[x]->coordinates.y == point.y) { - return false; - } - } - } - - return true; -} - -static uint8_t tanks_get_random_free_respawn_point_index( - TanksState* const tanks_state, - Point respawn_points[3]) { - uint8_t first = rand() % 3; - int8_t add = rand() % 2 ? +1 : -1; - int8_t second = first + add; - uint8_t third; - - if(second == 4) { - second = 0; - } else if(second == -1) { - second = 3; - } - - for(uint8_t i = 0; i < 3; i++) { - if(i != first && i != second) { - third = i; - } - } - - if(tanks_get_cell_is_free(tanks_state, respawn_points[first])) { - return first; - } - - if(tanks_get_cell_is_free(tanks_state, respawn_points[second])) { - return second; - } - - if(tanks_get_cell_is_free(tanks_state, respawn_points[third])) { - return third; - } - - return -1; -} - -static void tanks_game_init_game(TanksState* const tanks_state, GameState type) { - srand(DWT->CYCCNT); - - tanks_state->state = type; - - for(int8_t x = 0; x < 100; x++) { - if(tanks_state->projectiles[x] != NULL) { - free(tanks_state->projectiles[x]); - tanks_state->projectiles[x] = NULL; - } - } - - int8_t team_one_respawn_points_counter = 0; - int8_t team_two_respawn_points_counter = 0; - - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - tanks_state->thisMap[x][y] = ' '; - - if(thisMap[y][x] == '1') { - Point respawn = {x, y}; - tanks_state->team_one_respawn_points[team_one_respawn_points_counter++] = respawn; - } - - if(thisMap[y][x] == '2') { - Point respawn = {x, y}; - tanks_state->team_two_respawn_points[team_two_respawn_points_counter++] = respawn; - } - - if(thisMap[y][x] == '-') { - tanks_state->thisMap[x][y] = '-'; - } - - if(thisMap[y][x] == '=') { - tanks_state->thisMap[x][y] = '='; - } - - if(thisMap[y][x] == '*') { - tanks_state->thisMap[x][y] = '*'; - } - - if(thisMap[y][x] == 'a') { - tanks_state->thisMap[x][y] = 'a'; - } - } - } - - uint8_t index1 = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_one_respawn_points); - Point c = { - tanks_state->team_one_respawn_points[index1].x, - tanks_state->team_one_respawn_points[index1].y}; - - PlayerState p1 = { - c, - 0, - 4, - DirectionRight, - 0, - 0, - 1, - SHOT_COOLDOWN, - PLAYER_RESPAWN_COOLDOWN, - }; - - PlayerState* p1_state = malloc(sizeof(PlayerState)); - *p1_state = p1; - - tanks_state->p1 = p1_state; - - if(type == GameStateCooperativeServer) { - int8_t index2 = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_one_respawn_points); - Point c = { - tanks_state->team_one_respawn_points[index2].x, - tanks_state->team_one_respawn_points[index2].y}; - - PlayerState p2 = { - c, - 0, - 4, - DirectionRight, - 0, - 0, - 1, - SHOT_COOLDOWN, - PLAYER_RESPAWN_COOLDOWN, - }; - - PlayerState* p2_state = malloc(sizeof(PlayerState)); - *p2_state = p2; - - tanks_state->p2 = p2_state; - } - - tanks_state->enemies_left = 5; - tanks_state->enemies_live = 0; - tanks_state->enemies_respawn_cooldown = RESPAWN_COOLDOWN; - tanks_state->received = 0; - tanks_state->sent = 0; - - if(type == GameStateCooperativeClient) { - for(int8_t x = 0; x < FIELD_WIDTH; x++) { - for(int8_t y = 0; y < FIELD_HEIGHT; y++) { - tanks_state->thisMap[x][y] = CellEmpty; - } - } - } -} - -static bool - tanks_game_collision(Point const next_step, bool shoot, TanksState const* const tanks_state) { - if((int8_t)next_step.x < 0 || (int8_t)next_step.y < 0) { - return true; - } - - if(next_step.x >= FIELD_WIDTH || next_step.y >= FIELD_HEIGHT) { - return true; - } - - char tile = tanks_state->thisMap[next_step.x][next_step.y]; - - if(tile == '*' && !shoot) { - return true; - } - - if(tile == '-' || tile == '=' || tile == 'a') { - return true; - } - - for(uint8_t i = 0; i < 6; i++) { - if(tanks_state->bots[i] != NULL) { - if(tanks_state->bots[i]->coordinates.x == next_step.x && - tanks_state->bots[i]->coordinates.y == next_step.y) { - return true; - } - } - } - - if(tanks_state->p1 != NULL && tanks_state->p1->live && - tanks_state->p1->coordinates.x == next_step.x && - tanks_state->p1->coordinates.y == next_step.y) { - return true; - } - - if(tanks_state->p2 != NULL && tanks_state->p2->live && - tanks_state->p2->coordinates.x == next_step.x && - tanks_state->p2->coordinates.y == next_step.y) { - return true; - } - - return false; -} - -static Point tanks_game_get_next_step(Point coordinates, Direction direction) { - Point next_step = {coordinates.x, coordinates.y}; - - switch(direction) { - // +-----x - // | - // | - // y - case DirectionUp: - next_step.y--; - break; - case DirectionRight: - next_step.x++; - break; - case DirectionDown: - next_step.y++; - break; - case DirectionLeft: - next_step.x--; - break; - default: - break; - } - return next_step; -} - -static uint8_t tanks_game_get_free_projectile_index(TanksState* const tanks_state) { - uint8_t freeProjectileIndex; - for(freeProjectileIndex = 0; freeProjectileIndex < 100; freeProjectileIndex++) { - if(tanks_state->projectiles[freeProjectileIndex] == NULL) { - return freeProjectileIndex; - } - } - - return 0; -} - -static void tanks_game_shoot( - TanksState* const tanks_state, - PlayerState* tank_state, - bool is_p1, - bool is_p2) { - tank_state->cooldown = SHOT_COOLDOWN; - - uint8_t freeProjectileIndex = tanks_game_get_free_projectile_index(tanks_state); - - ProjectileState* projectile_state = malloc(sizeof(ProjectileState)); - Point next_step = tanks_game_get_next_step(tank_state->coordinates, tank_state->direction); - - projectile_state->direction = tank_state->direction; - projectile_state->coordinates = next_step; - projectile_state->is_p1 = is_p1; - projectile_state->is_p2 = is_p2; - - bool crush = tanks_game_collision(projectile_state->coordinates, true, tanks_state); - projectile_state->explosion = crush; - - tanks_state->projectiles[freeProjectileIndex] = projectile_state; -} - -static void tanks_game_process_game_step(TanksState* const tanks_state) { - if(tanks_state->state == GameStateMenu) { - return; - } - - if(tanks_state->enemies_left == 0 && tanks_state->enemies_live == 0) { - tanks_state->state = GameStateGameOver; - } - - if(!tanks_state->p1->live && tanks_state->p1->lives == 0) { - tanks_state->state = GameStateGameOver; - } - - if(tanks_state->state == GameStateGameOver) { - return; - } - - if(tanks_state->p1 != NULL) { - if(!tanks_state->p1->live && tanks_state->p1->respawn_cooldown > 0) { - tanks_state->p1->respawn_cooldown--; - } - } - - // Player 1 spawn - if(tanks_state->p1 && !tanks_state->p1->live && tanks_state->p1->lives > 0) { - int8_t index = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_one_respawn_points); - - if(index != -1) { - Point point = tanks_state->team_one_respawn_points[index]; - Point c = {point.x, point.y}; - tanks_state->p1->coordinates = c; - tanks_state->p1->live = true; - tanks_state->p1->direction = DirectionRight; - tanks_state->p1->cooldown = SHOT_COOLDOWN; - tanks_state->p1->respawn_cooldown = SHOT_COOLDOWN; - } - } - - // Player 2 spawn - if(tanks_state->state == GameStateCooperativeServer && tanks_state->p2 && - !tanks_state->p2->live && tanks_state->p2->lives > 0) { - int8_t index = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_one_respawn_points); - - if(index != -1) { - Point point = tanks_state->team_one_respawn_points[index]; - Point c = {point.x, point.y}; - tanks_state->p2->coordinates = c; - tanks_state->p2->live = true; - tanks_state->p2->direction = DirectionRight; - tanks_state->p2->cooldown = SHOT_COOLDOWN; - tanks_state->p2->respawn_cooldown = SHOT_COOLDOWN; - } - } - - // Bot turn - for(uint8_t i = 0; i < 6; i++) { - if(tanks_state->bots[i] != NULL) { - PlayerState* bot = tanks_state->bots[i]; - if(bot->cooldown) { - bot->cooldown--; - } - - // Rotate - if(rand() % 3 == 0) { - bot->direction = (rand() % 4); - } - - // Move - if(rand() % 2 == 0) { - Point next_step = tanks_game_get_next_step(bot->coordinates, bot->direction); - bool crush = tanks_game_collision(next_step, false, tanks_state); - - if(!crush) { - bot->coordinates = next_step; - } - } - - // Shoot - if(bot->cooldown == 0 && rand() % 3 != 0) { - tanks_game_shoot(tanks_state, bot, false, false); - } - } - } - - // Bot spawn - if(tanks_state->enemies_respawn_cooldown) { - tanks_state->enemies_respawn_cooldown--; - } - - if(tanks_state->enemies_left > 0 && tanks_state->enemies_live <= 4 && - tanks_state->enemies_respawn_cooldown == 0) { - int8_t index = tanks_get_random_free_respawn_point_index( - tanks_state, tanks_state->team_two_respawn_points); - - if(index != -1) { - tanks_state->enemies_left--; - tanks_state->enemies_live++; - tanks_state->enemies_respawn_cooldown = RESPAWN_COOLDOWN; - Point point = tanks_state->team_two_respawn_points[index]; - - Point c = {point.x, point.y}; - - PlayerState bot = { - c, - 0, - 0, - DirectionLeft, - 0, - 0, - 1, - SHOT_COOLDOWN, - PLAYER_RESPAWN_COOLDOWN, - }; - - uint8_t freeEnemyIndex; - for(freeEnemyIndex = 0; freeEnemyIndex < 6; freeEnemyIndex++) { - if(tanks_state->bots[freeEnemyIndex] == NULL) { - break; - } - } - - PlayerState* bot_state = malloc(sizeof(PlayerState)); - *bot_state = bot; - - tanks_state->bots[freeEnemyIndex] = bot_state; - } - } - - if(tanks_state->p1 != NULL && tanks_state->p1->live && tanks_state->p1->moving) { - Point next_step = - tanks_game_get_next_step(tanks_state->p1->coordinates, tanks_state->p1->direction); - bool crush = tanks_game_collision(next_step, false, tanks_state); - - if(!crush) { - tanks_state->p1->coordinates = next_step; - } - } - - // Player 2 spawn - if(tanks_state->state == GameStateCooperativeServer && tanks_state->p2 && - tanks_state->p2->live && tanks_state->p2->moving) { - Point next_step = - tanks_game_get_next_step(tanks_state->p2->coordinates, tanks_state->p2->direction); - bool crush = tanks_game_collision(next_step, false, tanks_state); - - if(!crush) { - tanks_state->p2->coordinates = next_step; - } - } - - for(int8_t x = 0; x < 100; x++) { - if(tanks_state->projectiles[x] != NULL) { - ProjectileState* projectile = tanks_state->projectiles[x]; - Point c = projectile->coordinates; - - if(projectile->explosion) { - // Break a wall - if(tanks_state->thisMap[c.x][c.y] == '-') { - tanks_state->thisMap[c.x][c.y] = ' '; - } - - // Kill a bot - for(uint8_t i = 0; i < 6; i++) { - if(tanks_state->bots[i] != NULL) { - if(tanks_state->bots[i]->coordinates.x == c.x && - tanks_state->bots[i]->coordinates.y == c.y) { - if(projectile->is_p1) { - tanks_state->p1->score++; - } - - if(projectile->is_p2) { - tanks_state->p2->score++; - } - - // No friendly fire - if(projectile->is_p1 || projectile->is_p2) { - tanks_state->enemies_live--; - free(tanks_state->bots[i]); - tanks_state->bots[i] = NULL; - } - } - } - } - - // Destroy the flag - if(tanks_state->thisMap[c.x][c.y] == 'a') { - tanks_state->state = GameStateGameOver; - return; - } - - // Kill a player 1 - if(tanks_state->p1 != NULL) { - if(tanks_state->p1->live && tanks_state->p1->coordinates.x == c.x && - tanks_state->p1->coordinates.y == c.y) { - tanks_state->p1->live = false; - tanks_state->p1->lives--; - tanks_state->p1->respawn_cooldown = PLAYER_RESPAWN_COOLDOWN; - } - } - - // Kill a player 2 - if(tanks_state->p2 != NULL) { - if(tanks_state->p2->live && tanks_state->p2->coordinates.x == c.x && - tanks_state->p2->coordinates.y == c.y) { - tanks_state->p2->live = false; - tanks_state->p2->lives--; - tanks_state->p2->respawn_cooldown = PLAYER_RESPAWN_COOLDOWN; - } - } - - // Delete projectile - free(tanks_state->projectiles[x]); - tanks_state->projectiles[x] = NULL; - continue; - } - - Point next_step = - tanks_game_get_next_step(projectile->coordinates, projectile->direction); - bool crush = tanks_game_collision(next_step, true, tanks_state); - projectile->coordinates = next_step; - - if(crush) { - projectile->explosion = true; - } - } - } - - if(tanks_state->p1->cooldown > 0) { - tanks_state->p1->cooldown--; - } - - if(tanks_state->p2 != NULL && tanks_state->p2->cooldown > 0) { - tanks_state->p2->cooldown--; - } - - if(tanks_state->p1 != NULL && tanks_state->p1->live && tanks_state->p1->shooting && - tanks_state->p1->cooldown == 0) { - tanks_game_shoot(tanks_state, tanks_state->p1, true, false); - } - - tanks_state->p1->moving = false; - tanks_state->p1->shooting = false; - - if(tanks_state->p2 != NULL) { - tanks_state->p2->moving = false; - tanks_state->p2->shooting = false; - } -} - -int32_t tanks_game_app(void* p) { - UNUSED(p); - srand(DWT->CYCCNT); - - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TanksEvent)); - - TanksState* tanks_state = malloc(sizeof(TanksState)); - - tanks_state->state = GameStateMenu; - tanks_state->menu_state = MenuStateSingleMode; - - tanks_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!tanks_state->mutex) { - FURI_LOG_E("Tanks", "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(tanks_state); - return 255; - } - - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, tanks_game_render_callback, tanks_state); - view_port_input_callback_set(view_port, tanks_game_input_callback, event_queue); - - FuriTimer* timer = - furi_timer_alloc(tanks_game_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 4); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - TanksEvent event; - - // Initialize network thing. - uint32_t frequency = 433920000; - size_t message_max_len = 180; - uint8_t incomingMessage[180] = {0}; - SubGhzTxRxWorker* subghz_txrx = subghz_tx_rx_worker_alloc(); - - subghz_devices_init(); - const SubGhzDevice* subghz_device = - radio_device_loader_set(NULL, SubGhzRadioDeviceTypeExternalCC1101); - - subghz_devices_reset(subghz_device); - subghz_devices_load_preset(subghz_device, FuriHalSubGhzPresetOok650Async, NULL); - - subghz_tx_rx_worker_start(subghz_txrx, subghz_device, frequency); - furi_hal_power_suppress_charge_enter(); - - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - - furi_mutex_acquire(tanks_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // press events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - if(tanks_state->state == GameStateMenu) { - if(tanks_state->menu_state == MenuStateCooperativeServerMode) { - tanks_state->menu_state = MenuStateSingleMode; - } else if(tanks_state->menu_state == MenuStateCooperativeClientMode) { - tanks_state->menu_state = MenuStateCooperativeServerMode; - } - } else if(tanks_state->state == GameStateCooperativeClient) { - FuriString* goesUp = furi_string_alloc(); - char arr[2]; - arr[0] = GoesUp; - arr[1] = 0; - furi_string_set(goesUp, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(goesUp), - strlen(furi_string_get_cstr(goesUp))); - furi_string_free(goesUp); - } else { - tanks_state->p1->moving = true; - tanks_state->p1->direction = DirectionUp; - } - break; - case InputKeyDown: - if(tanks_state->state == GameStateMenu) { - if(tanks_state->menu_state == MenuStateSingleMode) { - tanks_state->menu_state = MenuStateCooperativeServerMode; - } else if(tanks_state->menu_state == MenuStateCooperativeServerMode) { - tanks_state->menu_state = MenuStateCooperativeClientMode; - } - } else if(tanks_state->state == GameStateCooperativeClient) { - FuriString* goesDown = furi_string_alloc(); - char arr[2]; - arr[0] = GoesDown; - arr[1] = 0; - furi_string_set(goesDown, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(goesDown), - strlen(furi_string_get_cstr(goesDown))); - furi_string_free(goesDown); - } else { - tanks_state->p1->moving = true; - tanks_state->p1->direction = DirectionDown; - } - break; - case InputKeyRight: - if(!(tanks_state->state == GameStateMenu)) { - if(tanks_state->state == GameStateCooperativeClient) { - FuriString* goesRight = furi_string_alloc(); - char arr[2]; - arr[0] = GoesRight; - arr[1] = 0; - furi_string_set(goesRight, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(goesRight), - strlen(furi_string_get_cstr(goesRight))); - furi_string_free(goesRight); - } else { - tanks_state->p1->moving = true; - tanks_state->p1->direction = DirectionRight; - } - } - break; - case InputKeyLeft: - if(!(tanks_state->state == GameStateMenu)) { - if(tanks_state->state == GameStateCooperativeClient) { - FuriString* goesLeft = furi_string_alloc(); - char arr[2]; - arr[0] = GoesLeft; - arr[1] = 0; - furi_string_set(goesLeft, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(goesLeft), - strlen(furi_string_get_cstr(goesLeft))); - furi_string_free(goesLeft); - } else { - tanks_state->p1->moving = true; - tanks_state->p1->direction = DirectionLeft; - } - } - break; - case InputKeyOk: - if(tanks_state->state == GameStateMenu) { - if(tanks_state->menu_state == MenuStateSingleMode) { - tanks_state->server = true; - tanks_game_init_game(tanks_state, GameStateSingle); - break; - } else if(tanks_state->menu_state == MenuStateCooperativeServerMode) { - tanks_state->server = true; - tanks_game_init_game(tanks_state, GameStateCooperativeServer); - break; - } else if(tanks_state->menu_state == MenuStateCooperativeClientMode) { - tanks_state->server = false; - tanks_game_init_game(tanks_state, GameStateCooperativeClient); - break; - } - } else if(tanks_state->state == GameStateGameOver) { - tanks_game_init_game(tanks_state, tanks_state->state); - } else if(tanks_state->state == GameStateCooperativeClient) { - FuriString* shoots = furi_string_alloc(); - char arr[2]; - arr[0] = Shoots; - arr[1] = 0; - furi_string_set(shoots, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(shoots), - strlen(furi_string_get_cstr(shoots))); - furi_string_free(shoots); - } else { - tanks_state->p1->shooting = true; - } - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } else if(event.type == EventTypeTick) { - if(tanks_state->state == GameStateCooperativeServer) { - if(subghz_tx_rx_worker_available(subghz_txrx)) { - memset(incomingMessage, 0x00, message_max_len); - subghz_tx_rx_worker_read(subghz_txrx, incomingMessage, message_max_len); - - if(incomingMessage != NULL) { - tanks_state->received++; - - switch(incomingMessage[0]) { - case GoesUp: - tanks_state->p2->moving = true; - tanks_state->p2->direction = DirectionUp; - break; - case GoesRight: - tanks_state->p2->moving = true; - tanks_state->p2->direction = DirectionRight; - break; - case GoesDown: - tanks_state->p2->moving = true; - tanks_state->p2->direction = DirectionDown; - break; - case GoesLeft: - tanks_state->p2->moving = true; - tanks_state->p2->direction = DirectionLeft; - break; - case Shoots: - tanks_state->p2->shooting = true; - break; - default: - break; - } - } - } - - tanks_game_process_game_step(tanks_state); - - FuriString* serializedData = furi_string_alloc(); - unsigned char* data = tanks_game_serialize(tanks_state); - char arr[11 * 16 + 1]; - - for(uint8_t i = 0; i < 11 * 16; i++) { - arr[i] = data[i]; - } - - arr[11 * 16] = 0; - - furi_string_set(serializedData, (char*)&arr); - - subghz_tx_rx_worker_write( - subghz_txrx, - (uint8_t*)furi_string_get_cstr(serializedData), - strlen(furi_string_get_cstr(serializedData))); - furi_string_free(serializedData); - tanks_state->sent++; - } else if(tanks_state->state == GameStateSingle) { - tanks_game_process_game_step(tanks_state); - } else if(tanks_state->state == GameStateCooperativeClient) { - if(subghz_tx_rx_worker_available(subghz_txrx)) { - memset(incomingMessage, 0x00, message_max_len); - subghz_tx_rx_worker_read(subghz_txrx, incomingMessage, message_max_len); - - tanks_state->received++; - - tanks_game_deserialize_and_write_to_state( - (unsigned char*)incomingMessage, tanks_state); - } - } - } - } else { - // event timeout - } - - view_port_update(view_port); - furi_mutex_release(tanks_state->mutex); - furi_delay_ms(1); - } - - furi_delay_ms(10); - furi_hal_power_suppress_charge_exit(); - - if(subghz_tx_rx_worker_is_running(subghz_txrx)) { - subghz_tx_rx_worker_stop(subghz_txrx); - subghz_tx_rx_worker_free(subghz_txrx); - } - - subghz_devices_deinit(); - - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(tanks_state->mutex); - - if(tanks_state->p1 != NULL) { - free(tanks_state->p1); - } - - if(tanks_state->p2 != NULL) { - free(tanks_state->p2); - } - - free(tanks_state); - - return 0; -} diff --git a/applications/external/tetris_game/application.fam b/applications/external/tetris_game/application.fam deleted file mode 100644 index 0766daf1e..000000000 --- a/applications/external/tetris_game/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="tetris", - name="Tetris", - apptype=FlipperAppType.EXTERNAL, - entry_point="tetris_game_app", - requires=["gui"], - stack_size=2 * 1024, - fap_icon="tetris_10px.png", - fap_category="Games", - fap_author="@xMasterX & @jeffplang", - fap_version="1.0", - fap_description="Tetris Game", -) diff --git a/applications/external/tetris_game/tetris_10px.png b/applications/external/tetris_game/tetris_10px.png deleted file mode 100644 index e4886d8357b8a9bdb82fcd03e47c53e73a06755c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1625 zcmcIkO>f*p7715)NnxR?96!A%G%@F zlk6s!R-8b}wU??lI3j)kJs{BwS8hoB11^Xkz{kw4*R4<+a>0`AvHi^RKJSO0ulhS5 zUs`!*#W0LZz3uLGpBS?;h_A=ZM#wFSW(BKIS>t^u2|2vi;AlFU$EU0pJCc}2^#kg3RlW+X##AS0-hE>g&fhBmM2GO2=DGg4T#iFHa# zU>u(g&9Vkv$<0F*rPljO;%abIaBG)W;-I8_^N{EA>M|Ik&EDdmoXj(2)Z!DKDOjb1 z*-fZoETpK$;x&0RpPOuoaHHfzigF;tWZ9_xk_9-9iNUpdY0kv7`cNyXH}EczJc6og z4#EMly@BI~c005?*RdO7ynx1P4j7T-Y+%9CyGOG<1T+tuO=y& z4_!#8p7jV)-DJ*S{W^U`_0FbqK|39DMS4o}7qChsa!N|RK2nwb&*8FOC%z(wr%OLu zGZT`K@o$hxZ-T&erGOqhk diff --git a/applications/external/tetris_game/tetris_game.c b/applications/external/tetris_game/tetris_game.c deleted file mode 100644 index 95770e045..000000000 --- a/applications/external/tetris_game/tetris_game.c +++ /dev/null @@ -1,478 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define BORDER_OFFSET 1 -#define MARGIN_OFFSET 3 -#define BLOCK_HEIGHT 6 -#define BLOCK_WIDTH 6 - -#define FIELD_WIDTH 11 -#define FIELD_HEIGHT 24 - -#define MAX_FALL_SPEED 500 -#define MIN_FALL_SPEED 100 - -typedef struct Point { - // Also used for offset data, which is sometimes negative - int8_t x, y; -} Point; - -// Rotation logic taken from -// https://www.youtube.com/watch?v=yIpk5TJ_uaI -typedef enum { OffsetTypeCommon, OffsetTypeI, OffsetTypeO } OffsetType; - -// Since we only support rotating clockwise, these are actual translation values, -// not values to be subtracted to get translation values - -static const Point rotOffsetTranslation[3][4][5] = { - {{{0, 0}, {-1, 0}, {-1, -1}, {0, 2}, {-1, 2}}, - {{0, 0}, {1, 0}, {1, 1}, {0, -2}, {1, -2}}, - {{0, 0}, {1, 0}, {1, -1}, {0, 2}, {1, 2}}, - {{0, 0}, {-1, 0}, {-1, 1}, {0, -2}, {-1, -2}}}, - {{{1, 0}, {-1, 0}, {2, 0}, {-1, 1}, {2, -2}}, - {{0, 1}, {-1, 1}, {2, 1}, {-1, -1}, {2, 2}}, - {{-1, 0}, {1, 0}, {-2, 0}, {1, -1}, {-2, 2}}, - {{0, -1}, {1, -1}, {-2, -1}, {1, 1}, {-2, -2}}}, - {{{0, -1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{0, 1}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, - {{-1, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}}}; - -typedef struct { - Point p[4]; - uint8_t rotIdx; - OffsetType offsetType; -} Piece; - -// Shapes @ spawn locations, rotation point first -static Piece shapes[] = { - {.p = {{5, 1}, {4, 0}, {5, 0}, {6, 1}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // Z - {.p = {{5, 1}, {4, 1}, {5, 0}, {6, 0}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // S - {.p = {{5, 1}, {4, 1}, {6, 1}, {6, 0}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // L - {.p = {{5, 1}, {4, 0}, {4, 1}, {6, 1}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // J - {.p = {{5, 1}, {4, 1}, {5, 0}, {6, 1}}, .rotIdx = 0, .offsetType = OffsetTypeCommon}, // T - {.p = {{5, 1}, {4, 1}, {6, 1}, {7, 1}}, .rotIdx = 0, .offsetType = OffsetTypeI}, // I - {.p = {{5, 1}, {5, 0}, {6, 0}, {6, 1}}, .rotIdx = 0, .offsetType = OffsetTypeO} // O -}; - -typedef enum { GameStatePlaying, GameStateGameOver } GameState; - -typedef struct { - bool playField[FIELD_HEIGHT][FIELD_WIDTH]; - Piece currPiece; - uint16_t numLines; - uint16_t fallSpeed; - GameState gameState; - FuriTimer* timer; - FuriMutex* mutex; -} TetrisState; - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} TetrisEvent; - -static void tetris_game_draw_border(Canvas* const canvas) { - canvas_draw_line(canvas, 0, 0, 0, 127); - canvas_draw_line(canvas, 0, 127, 63, 127); - canvas_draw_line(canvas, 63, 127, 63, 0); - - canvas_draw_line(canvas, 2, 0, 2, 125); - canvas_draw_line(canvas, 2, 125, 61, 125); - canvas_draw_line(canvas, 61, 125, 61, 0); -} - -static void tetris_game_draw_playfield(Canvas* const canvas, const TetrisState* tetris_state) { - // Playfield: 11 x 24 - - for(int y = 0; y < FIELD_HEIGHT; y++) { - for(int x = 0; x < FIELD_WIDTH; x++) { - if(tetris_state->playField[y][x]) { - uint16_t xOffset = x * 5; - uint16_t yOffset = y * 5; - - canvas_draw_rframe( - canvas, - BORDER_OFFSET + MARGIN_OFFSET + xOffset, - BORDER_OFFSET + MARGIN_OFFSET + yOffset - 1, - BLOCK_WIDTH, - BLOCK_HEIGHT, - 1); - canvas_draw_dot( - canvas, - BORDER_OFFSET + MARGIN_OFFSET + xOffset + 2, - BORDER_OFFSET + MARGIN_OFFSET + yOffset + 1); - canvas_draw_dot( - canvas, - BORDER_OFFSET + MARGIN_OFFSET + xOffset + 3, - BORDER_OFFSET + MARGIN_OFFSET + yOffset + 1); - canvas_draw_dot( - canvas, - BORDER_OFFSET + MARGIN_OFFSET + xOffset + 2, - BORDER_OFFSET + MARGIN_OFFSET + yOffset + 2); - } - } - } -} - -static void tetris_game_render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const TetrisState* tetris_state = ctx; - furi_mutex_acquire(tetris_state->mutex, FuriWaitForever); - - tetris_game_draw_border(canvas); - tetris_game_draw_playfield(canvas, tetris_state); - - // Show score on the game field - if(tetris_state->gameState == GameStatePlaying) { - char buffer2[6]; - snprintf(buffer2, sizeof(buffer2), "%u", tetris_state->numLines); - canvas_draw_str_aligned(canvas, 58, 10, AlignRight, AlignBottom, buffer2); - } - - if(tetris_state->gameState == GameStateGameOver) { - // 128 x 64 - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 1, 52, 62, 24); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 1, 52, 62, 24); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 4, 63, "Game Over"); - - char buffer[13]; - snprintf(buffer, sizeof(buffer), "Lines: %u", tetris_state->numLines); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str_aligned(canvas, 32, 73, AlignCenter, AlignBottom, buffer); - } - furi_mutex_release(tetris_state->mutex); -} - -static void tetris_game_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - TetrisEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void tetris_game_init_state(TetrisState* tetris_state) { - tetris_state->gameState = GameStatePlaying; - tetris_state->numLines = 0; - tetris_state->fallSpeed = MAX_FALL_SPEED; - memset(tetris_state->playField, 0, sizeof(tetris_state->playField)); - - memcpy(&tetris_state->currPiece, &shapes[rand() % 7], sizeof(tetris_state->currPiece)); - - furi_timer_start(tetris_state->timer, tetris_state->fallSpeed); -} - -static void tetris_game_remove_curr_piece(TetrisState* tetris_state) { - for(int i = 0; i < 4; i++) { - uint8_t x = tetris_state->currPiece.p[i].x; - uint8_t y = tetris_state->currPiece.p[i].y; - - tetris_state->playField[y][x] = false; - } -} - -static void tetris_game_render_curr_piece(TetrisState* tetris_state) { - for(int i = 0; i < 4; i++) { - uint8_t x = tetris_state->currPiece.p[i].x; - uint8_t y = tetris_state->currPiece.p[i].y; - - tetris_state->playField[y][x] = true; - } -} - -static void tetris_game_rotate_shape(Point currShape[], Point newShape[]) { - // Copy shape data - for(int i = 0; i < 4; i++) { - newShape[i] = currShape[i]; - } - - for(int i = 1; i < 4; i++) { - int8_t relX = currShape[i].x - currShape[0].x; - int8_t relY = currShape[i].y - currShape[0].y; - - // Matrix rotation thing - int8_t newRelX = (relX * 0) + (relY * -1); - int8_t newRelY = (relX * 1) + (relY * 0); - - newShape[i].x = currShape[0].x + newRelX; - newShape[i].y = currShape[0].y + newRelY; - } -} - -static void tetris_game_apply_kick(Point points[], Point kick) { - for(int i = 0; i < 4; i++) { - points[i].x += kick.x; - points[i].y += kick.y; - } -} - -static bool tetris_game_is_valid_pos(TetrisState* tetris_state, Point* shape) { - for(int i = 0; i < 4; i++) { - if(shape[i].x < 0 || shape[i].x > (FIELD_WIDTH - 1) || - tetris_state->playField[shape[i].y][shape[i].x] == true) { - return false; - } - } - return true; -} - -static void tetris_game_try_rotation(TetrisState* tetris_state, Piece* newPiece) { - uint8_t currRotIdx = tetris_state->currPiece.rotIdx; - - Point* rotatedShape = malloc(sizeof(Point) * 4); - Point* kickedShape = malloc(sizeof(Point) * 4); - - memcpy(rotatedShape, &tetris_state->currPiece.p, sizeof(tetris_state->currPiece.p)); - - tetris_game_rotate_shape(tetris_state->currPiece.p, rotatedShape); - - for(int i = 0; i < 5; i++) { - memcpy(kickedShape, rotatedShape, (sizeof(Point) * 4)); - tetris_game_apply_kick( - kickedShape, rotOffsetTranslation[newPiece->offsetType][currRotIdx][i]); - - if(tetris_game_is_valid_pos(tetris_state, kickedShape)) { - memcpy(&newPiece->p, kickedShape, sizeof(newPiece->p)); - newPiece->rotIdx = (newPiece->rotIdx + 1) % 4; - break; - } - } - free(rotatedShape); - free(kickedShape); -} - -static bool tetris_game_row_is_line(bool row[]) { - for(int i = 0; i < FIELD_WIDTH; i++) { - if(row[i] == false) return false; - } - return true; -} - -static void - tetris_game_check_for_lines(TetrisState* tetris_state, uint8_t* lines, uint8_t* numLines) { - for(int i = 0; i < FIELD_HEIGHT; i++) { - if(tetris_game_row_is_line(tetris_state->playField[i])) { - *(lines++) = i; - *numLines += 1; - } - } -} - -static bool tetris_game_piece_at_bottom(TetrisState* tetris_state, Piece* newPiece) { - for(int i = 0; i < 4; i++) { - Point* pos = (Point*)&newPiece->p; - if(pos[i].y >= FIELD_HEIGHT || tetris_state->playField[pos[i].y][pos[i].x] == true) { - return true; - } - } - return false; -} - -static void tetris_game_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - TetrisEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void - tetris_game_process_step(TetrisState* tetris_state, Piece* newPiece, bool wasDownMove) { - if(tetris_state->gameState == GameStateGameOver) return; - - tetris_game_remove_curr_piece(tetris_state); - - if(wasDownMove) { - if(tetris_game_piece_at_bottom(tetris_state, newPiece)) { - furi_timer_stop(tetris_state->timer); - - tetris_game_render_curr_piece(tetris_state); - uint8_t numLines = 0; - uint8_t lines[] = {0, 0, 0, 0}; - uint16_t nextFallSpeed; - - tetris_game_check_for_lines(tetris_state, lines, &numLines); - if(numLines > 0) { - for(int i = 0; i < numLines; i++) { - // zero out row - for(int j = 0; j < FIELD_WIDTH; j++) { - tetris_state->playField[lines[i]][j] = false; - } - // move all above rows down - for(int k = lines[i]; k >= 0; k--) { - for(int m = 0; m < FIELD_WIDTH; m++) { - tetris_state->playField[k][m] = - (k == 0) ? false : tetris_state->playField[k - 1][m]; - } - } - } - - uint16_t oldNumLines = tetris_state->numLines; - tetris_state->numLines += numLines; - if((oldNumLines / 10) % 10 != (tetris_state->numLines / 10) % 10) { - nextFallSpeed = - tetris_state->fallSpeed - (100 / (tetris_state->numLines / 10)); - if(nextFallSpeed >= MIN_FALL_SPEED) { - tetris_state->fallSpeed = nextFallSpeed; - } - } - } - - // Check for game over - Piece* spawnedPiece = &shapes[rand() % 7]; - if(!tetris_game_is_valid_pos(tetris_state, spawnedPiece->p)) { - tetris_state->gameState = GameStateGameOver; - } else { - memcpy(&tetris_state->currPiece, spawnedPiece, sizeof(tetris_state->currPiece)); - furi_timer_start(tetris_state->timer, tetris_state->fallSpeed); - } - } - } - - if(tetris_game_is_valid_pos(tetris_state, newPiece->p)) { - memcpy(&tetris_state->currPiece, newPiece, sizeof(tetris_state->currPiece)); - } - - tetris_game_render_curr_piece(tetris_state); -} - -int32_t tetris_game_app() { - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(TetrisEvent)); - - TetrisState* tetris_state = malloc(sizeof(TetrisState)); - - tetris_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!tetris_state->mutex) { - FURI_LOG_E("TetrisGame", "cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(tetris_state); - return 255; - } - - // Not doing this eventually causes issues with TimerSvc due to not sleeping/yielding enough in this task - furi_timer_set_thread_priority(FuriTimerThreadPriorityElevated); - - ViewPort* view_port = view_port_alloc(); - view_port_set_orientation(view_port, ViewPortOrientationVertical); - view_port_draw_callback_set(view_port, tetris_game_render_callback, tetris_state); - view_port_input_callback_set(view_port, tetris_game_input_callback, event_queue); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - tetris_state->timer = - furi_timer_alloc(tetris_game_update_timer_callback, FuriTimerTypePeriodic, event_queue); - tetris_game_init_state(tetris_state); - - TetrisEvent event; - - Piece* newPiece = malloc(sizeof(Piece)); - uint8_t downRepeatCounter = 0; - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - for(bool processing = true; processing;) { - // This 10U implicitly sets the game loop speed. downRepeatCounter relies on this value - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 10U); - - furi_mutex_acquire(tetris_state->mutex, FuriWaitForever); - - memcpy(newPiece, &tetris_state->currPiece, sizeof(tetris_state->currPiece)); - bool wasDownMove = false; - - if(!furi_hal_gpio_read(&gpio_button_right)) { - if(downRepeatCounter > 3) { - for(int i = 0; i < 4; i++) { - newPiece->p[i].y += 1; - } - downRepeatCounter = 0; - wasDownMove = true; - } else { - downRepeatCounter++; - } - } - - if(event_status == FuriStatusOk) { - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress || event.input.type == InputTypeLong || - event.input.type == InputTypeRepeat) { - switch(event.input.key) { - case InputKeyUp: - break; - case InputKeyDown: - break; - case InputKeyRight: - for(int i = 0; i < 4; i++) { - newPiece->p[i].x += 1; - } - break; - case InputKeyLeft: - for(int i = 0; i < 4; i++) { - newPiece->p[i].x -= 1; - } - break; - case InputKeyOk: - if(tetris_state->gameState == GameStatePlaying) { - tetris_game_remove_curr_piece(tetris_state); - tetris_game_try_rotation(tetris_state, newPiece); - tetris_game_render_curr_piece(tetris_state); - } else { - tetris_game_init_state(tetris_state); - } - break; - case InputKeyBack: - processing = false; - break; - default: - break; - } - } - } else if(event.type == EventTypeTick) { - // TODO: This is inverted. it returns true when the button is not pressed. - // see macro in input.c and do that - if(furi_hal_gpio_read(&gpio_button_right)) { - for(int i = 0; i < 4; i++) { - newPiece->p[i].y += 1; - } - wasDownMove = true; - } - } - } - - tetris_game_process_step(tetris_state, newPiece, wasDownMove); - - view_port_update(view_port); - furi_mutex_release(tetris_state->mutex); - } - - furi_timer_free(tetris_state->timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(tetris_state->mutex); - furi_timer_set_thread_priority(FuriTimerThreadPriorityNormal); - free(newPiece); - free(tetris_state); - - return 0; -} diff --git a/applications/external/tictactoe_game/application.fam b/applications/external/tictactoe_game/application.fam deleted file mode 100644 index 48d904d0e..000000000 --- a/applications/external/tictactoe_game/application.fam +++ /dev/null @@ -1,13 +0,0 @@ -App( - appid="tictactoe", - name="Tic Tac Toe", - apptype=FlipperAppType.EXTERNAL, - entry_point="tictactoe_game_app", - requires=["gui"], - stack_size=1 * 1024, - fap_icon="tictactoe_10px.png", - fap_category="Games", - fap_author="@xMasterX & @gotnull", - fap_version="1.0", - fap_description="Tic Tac Toe game, for 2 players, play on one device", -) diff --git a/applications/external/tictactoe_game/tictactoe_10px.png b/applications/external/tictactoe_game/tictactoe_10px.png deleted file mode 100644 index 41ca1d97344062a9951dc39176de4a94ca051345..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1605 zcmcIk&u`pB6m}X_f}n~+FBQF5vmhui_ITF2Yg;u@nhj(n9HMlkrkohhjCZZ9J;t77 zH#woImmU$~f;b~_;U7Q(AuincFSzs%0I59hdQFAekPDXVd1HU`z3=_-dvbX2(T%M) zwhY6#G1?yP>Yep8UQyn5ux(XpHTH3s7(gX>!7p$-yi_{^lfl+ih zG|O6arT5OjOQZLN#MSt`koJ+R)M?4(-kHpGXYEYz_H1!l&X$o1Zp)d>09Ju8r*&0K zl~&bMy(EtIa~n+&?3R*gRgRUKtqXOyW-%$Xi22TgG#6@K-KiBd2jq}x86v0}#l**s zJEq-$cmeIcN5CK}Xas#Am}XZ4E0HGWSAj-RFv=^15P>KwO-0a?%%M)dhq>c8 znDtzOW7(tFb7QaPyPhj(f2j-34;4SH(^sEgwXIMbINA&aUFv(p;{%*{aSwMLcYtGG z3M`3qJfFo$Ecu%4lQM-rhs~a6tyKwNWZi+65Z}R`U=B{C%dpP|3=b$xoFpE2%mr0~ z2Z<^(27QudY$EL!qxOU-4|1&r6d z9wJ^BSqjv=PG69{tLa?P&ZiPcFDd>CR;fhKSt)lWkm>(yF8gKTD|U9d^s5#Af0W*& zl}}kdkuW%IR0m_%BW6_;```6ietT{lt>G}^YO@`#uxZD$%z?Uu;rs4SPjAEE?u>>z z<6B?zzn(qY-rU^mbUKeWHVW(J=38HUiGIEF)py_jZhZRs?dyO3^5)z1pdalW41c)y H*`vP!1_SN0 diff --git a/applications/external/tictactoe_game/tictactoe_game.c b/applications/external/tictactoe_game/tictactoe_game.c deleted file mode 100644 index 6ad076a4a..000000000 --- a/applications/external/tictactoe_game/tictactoe_game.c +++ /dev/null @@ -1,387 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#define TAG "TicTacToe" - -typedef enum { EventTypeTick, EventTypeKey } EventType; - -typedef struct { - FuriMutex* mutex; - FuriTimer* timer; - uint8_t selBoxX; - uint8_t selBoxY; - - uint8_t selX; - uint8_t selY; - - uint16_t scoreX; - uint16_t scoreO; - - char player; - - char field[3][3]; - bool fieldx[3][3]; - - uint8_t coords[3]; - - bool button_state; - -} TicTacToeState; - -typedef struct { - EventType type; - InputEvent input; -} GameEvent; - -void drawCross(Canvas* const canvas, uint8_t x, uint8_t y) { - canvas_draw_line(canvas, x, y, x + 9, y + 9); // top left - bottom right slash - canvas_draw_line(canvas, x + 9, y, x, y + 9); // down left - top right slash -} - -void drawCircle(Canvas* const canvas, uint8_t x, uint8_t y) { - canvas_draw_circle(canvas, x + 4, y + 5, 5); -} - -void player_switch(TicTacToeState* ts) { - if(ts->player == 'O') { - ts->player = 'X'; - } else if(ts->player == 'X') { - ts->player = 'O'; - } -} - -void tictactoe_draw(Canvas* canvas, TicTacToeState* ts) { - // Draws the game field - canvas_draw_frame(canvas, 0, 0, 64, 64); // frame - canvas_draw_line(canvas, 0, 21, 63, 21); // horizontal line - canvas_draw_line(canvas, 0, 42, 63, 42); // horizontal line - canvas_draw_line(canvas, 21, 0, 21, 63); // vertical line - canvas_draw_line(canvas, 42, 0, 42, 63); // vertical line - - // Draws the game field elements (X or O) - for(uint8_t i = 0; i <= 2; i++) { - for(uint8_t j = 0; j <= 2; j++) { - if(ts->field[i][j] == 'O') { - drawCircle(canvas, ts->coords[i], ts->coords[j]); - } else if(ts->field[i][j] == 'X') { - drawCross(canvas, ts->coords[i], ts->coords[j]); - } - } - } - - // Draws the selection box - if(ts->selX == 1) { - ts->selBoxX = 1; - } else if(ts->selX == 2) { - ts->selBoxX = 22; - } else if(ts->selX == 3) { - ts->selBoxX = 43; - } - - if(ts->selY == 1) { - ts->selBoxY = 1; - } else if(ts->selY == 2) { - ts->selBoxY = 22; - } else if(ts->selY == 3) { - ts->selBoxY = 43; - } - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, ts->selBoxX, ts->selBoxY, 20, 20); - canvas_draw_frame(canvas, ts->selBoxX + 1, ts->selBoxY + 1, 18, 18); - - // Draws the sidebar - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 81, 10, "SCORE"); - canvas_draw_str(canvas, 75, 24, "X:"); - - char scoreXBuffer[10]; - snprintf(scoreXBuffer, sizeof(scoreXBuffer), "%d", ts->scoreX); - canvas_draw_str(canvas, 88, 24, scoreXBuffer); - canvas_draw_str(canvas, 75, 35, "O:"); - - char scoreOBuffer[10]; - snprintf(scoreOBuffer, sizeof(scoreOBuffer), "%d", ts->scoreO); - canvas_draw_str(canvas, 88, 35, scoreOBuffer); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str(canvas, 75, 46, "Player:"); - - if(ts->player == 'X') { - drawCross(canvas, 93, 50); - } else if(ts->player == 'O') { - drawCircle(canvas, 93, 50); - } -} - -void clear_game_field(TicTacToeState* ts) { - // Clears the game field arrays - for(uint8_t i = 0; i <= 2; i++) { - for(uint8_t j = 0; j <= 2; j++) { - ts->field[i][j] = ' '; - ts->fieldx[i][j] = false; - } - } - - ts->selX = 2; // Centers the selection box on X axis - ts->selY = 2; // Centers the selection box on Y axis -} - -void reset_game_data(TicTacToeState* ts) { - ts->scoreO = 0; - ts->scoreX = 0; - ts->player = 'X'; -} - -void draw_win(Canvas* canvas, char player, TicTacToeState* ts) { - // Handles the score table - if(player == 'X') { - ts->scoreX++; - } else if(player == 'O') { - ts->scoreO++; - } - - // Switches the players - player_switch(ts); - - // Draws the board with players switched - tictactoe_draw(canvas, ts); - - // Clear the game field - clear_game_field(ts); - - // Draw the new board - tictactoe_draw(canvas, ts); -} - -static void tictactoe_state_init(TicTacToeState* tictactoe_state) { - // Set the initial game state - tictactoe_state->selX = 2; - tictactoe_state->selY = 2; - tictactoe_state->player = 'X'; - tictactoe_state->coords[0] = 6; - tictactoe_state->coords[1] = 27; - tictactoe_state->coords[2] = 48; - tictactoe_state->button_state = false; - - clear_game_field(tictactoe_state); - - reset_game_data(tictactoe_state); -} - -static void tictactoe_draw_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - TicTacToeState* ticst = ctx; - furi_mutex_acquire(ticst->mutex, FuriWaitForever); - - if(ticst->selX > 3) { - ticst->selX = 3; - } else if(ticst->selX < 1) { - ticst->selX = 1; - } - - if(ticst->selY > 3) { - ticst->selY = 3; - } else if(ticst->selY < 1) { - ticst->selY = 1; - } - - // Assigns the game field elements their value (X or O) when the OK button is pressed - if(ticst->button_state) { - ticst->button_state = false; - for(uint8_t i = 0; i <= 2; i++) { - for(uint8_t j = 0; j <= 2; j++) { - if((ticst->selX == i + 1) && (ticst->selY == j + 1) && - (ticst->fieldx[i][j] == false)) { - if(ticst->player == 'X') { - ticst->field[i][j] = 'X'; - ticst->fieldx[i][j] = true; - player_switch(ticst); - } else if(ticst->player == 'O') { - ticst->field[i][j] = 'O'; - ticst->fieldx[i][j] = true; - player_switch(ticst); - } - } - } - } - } - - // Checks the game field for winning combinations - if((ticst->field[0][0] == 'X') && (ticst->field[1][0] == 'X') && (ticst->field[2][0] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][1] == 'X') && (ticst->field[1][1] == 'X') && - (ticst->field[2][1] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][2] == 'X') && (ticst->field[1][2] == 'X') && - (ticst->field[2][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][0] == 'X') && (ticst->field[0][1] == 'X') && - (ticst->field[0][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[1][0] == 'X') && (ticst->field[1][1] == 'X') && - (ticst->field[1][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[2][0] == 'X') && (ticst->field[2][1] == 'X') && - (ticst->field[2][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][0] == 'X') && (ticst->field[1][1] == 'X') && - (ticst->field[2][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[2][0] == 'X') && (ticst->field[1][1] == 'X') && - (ticst->field[0][2] == 'X')) { - draw_win(canvas, 'X', ticst); - } else if( - (ticst->field[0][0] == 'O') && (ticst->field[1][0] == 'O') && - (ticst->field[2][0] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[0][1] == 'O') && (ticst->field[1][1] == 'O') && - (ticst->field[2][1] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[0][2] == 'O') && (ticst->field[1][2] == 'O') && - (ticst->field[2][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[0][0] == 'O') && (ticst->field[0][1] == 'O') && - (ticst->field[0][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[1][0] == 'O') && (ticst->field[1][1] == 'O') && - (ticst->field[1][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[2][0] == 'O') && (ticst->field[2][1] == 'O') && - (ticst->field[2][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[0][0] == 'O') && (ticst->field[1][1] == 'O') && - (ticst->field[2][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->field[2][0] == 'O') && (ticst->field[1][1] == 'O') && - (ticst->field[0][2] == 'O')) { - draw_win(canvas, 'O', ticst); - } else if( - (ticst->fieldx[0][0] == true) && (ticst->fieldx[0][1] == true) && - (ticst->fieldx[0][2] == true) && (ticst->fieldx[1][0] == true) && - (ticst->fieldx[1][1] == true) && (ticst->fieldx[1][2] == true) && - (ticst->fieldx[2][0] == true) && (ticst->fieldx[2][1] == true) && - (ticst->fieldx[2][2] == true)) { - draw_win(canvas, 'T', ticst); - } - - tictactoe_draw(canvas, ticst); - - furi_mutex_release(ticst->mutex); -} - -static void tictactoe_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void tictactoe_update_timer_callback(FuriMessageQueue* event_queue) { - furi_assert(event_queue); - - GameEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -int32_t tictactoe_game_app(void* p) { - UNUSED(p); - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent)); - - TicTacToeState* tictactoe_state = malloc(sizeof(TicTacToeState)); - - tictactoe_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - - if(!tictactoe_state->mutex) { - FURI_LOG_E(TAG, "Cannot create mutex\r\n"); - furi_message_queue_free(event_queue); - free(tictactoe_state); - return 255; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, tictactoe_draw_callback, tictactoe_state); - view_port_input_callback_set(view_port, tictactoe_input_callback, event_queue); - - tictactoe_state->timer = - furi_timer_alloc(tictactoe_update_timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(tictactoe_state->timer, furi_kernel_get_tick_frequency() / 22); - - tictactoe_state_init(tictactoe_state); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - GameEvent event; - for(bool processing = true; processing;) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(tictactoe_state->mutex, FuriWaitForever); - - if(event_status == FuriStatusOk) { - // Key events - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyBack: - processing = false; - break; - case InputKeyRight: - tictactoe_state->selX++; - break; - case InputKeyLeft: - tictactoe_state->selX--; - break; - case InputKeyUp: - tictactoe_state->selY--; - break; - case InputKeyDown: - tictactoe_state->selY++; - break; - case InputKeyOk: - tictactoe_state->button_state = true; - break; - default: - break; - } - } - } - } - - view_port_update(view_port); - furi_mutex_release(tictactoe_state->mutex); - } - - furi_timer_free(tictactoe_state->timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_message_queue_free(event_queue); - furi_mutex_free(tictactoe_state->mutex); - free(tictactoe_state); - - return 0; -} \ No newline at end of file diff --git a/applications/external/unitemp/LICENSE.md b/applications/external/unitemp/LICENSE.md deleted file mode 100644 index f288702d2..000000000 --- a/applications/external/unitemp/LICENSE.md +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. diff --git a/applications/external/unitemp/Sensors.c b/applications/external/unitemp/Sensors.c deleted file mode 100644 index 33dd3fa88..000000000 --- a/applications/external/unitemp/Sensors.c +++ /dev/null @@ -1,653 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "Sensors.h" -#include - -//Порты ввода/вывода, которые не были обозначены в общем списке -const GpioPin SWC_10 = {.pin = LL_GPIO_PIN_14, .port = GPIOA}; -const GpioPin SIO_12 = {.pin = LL_GPIO_PIN_13, .port = GPIOA}; -const GpioPin TX_13 = {.pin = LL_GPIO_PIN_6, .port = GPIOB}; -const GpioPin RX_14 = {.pin = LL_GPIO_PIN_7, .port = GPIOB}; - -//Количество доступных портов ввода/вывода -#define GPIO_ITEMS (sizeof(GPIOList) / sizeof(GPIO)) -//Количество интерфейсов -#define INTERFACES_TYPES_COUNT (int)(sizeof(interfaces) / sizeof(const Interface*)) -//Количество типов датчиков -#define SENSOR_TYPES_COUNT (int)(sizeof(sensorTypes) / sizeof(const SensorType*)) - -//Перечень достуных портов ввода/вывода -static const GPIO GPIOList[] = { - {2, "2 (A7)", &gpio_ext_pa7}, - {3, "3 (A6)", &gpio_ext_pa6}, - {4, "4 (A4)", &gpio_ext_pa4}, - {5, "5 (B3)", &gpio_ext_pb3}, - {6, "6 (B2)", &gpio_ext_pb2}, - {7, "7 (C3)", &gpio_ext_pc3}, - {10, " 10(SWC) ", &SWC_10}, - {12, "12 (SIO)", &SIO_12}, - {13, "13 (TX)", &TX_13}, - {14, "14 (RX)", &RX_14}, - {15, "15 (C1)", &gpio_ext_pc1}, - {16, "16 (C0)", &gpio_ext_pc0}, - {17, "17 (1W)", &gpio_ibutton}}; - -//Список интерфейсов, которые прикреплены к GPIO (определяется индексом) -//NULL - порт свободен, указатель на интерфейс - порт занят этим интерфейсом -static const Interface* gpio_interfaces_list[GPIO_ITEMS] = {0}; - -const Interface SINGLE_WIRE = { - .name = "Single wire", - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .updater = unitemp_singlewire_update}; -const Interface I2C = { - .name = "I2C", - .allocator = unitemp_I2C_sensor_alloc, - .mem_releaser = unitemp_I2C_sensor_free, - .updater = unitemp_I2C_sensor_update}; -const Interface ONE_WIRE = { - .name = "One wire", - .allocator = unitemp_onewire_sensor_alloc, - .mem_releaser = unitemp_onewire_sensor_free, - .updater = unitemp_onewire_sensor_update}; -const Interface SPI = { - .name = "SPI", - .allocator = unitemp_spi_sensor_alloc, - .mem_releaser = unitemp_spi_sensor_free, - .updater = unitemp_spi_sensor_update}; - -//Перечень интерфейсов подключения -//static const Interface* interfaces[] = {&SINGLE_WIRE, &I2C, &ONE_WIRE, &SPI}; -//Перечень датчиков -static const SensorType* sensorTypes[] = {&DHT11, &DHT12_SW, &DHT20, &DHT21, &DHT22, - &Dallas, &AM2320_SW, &AM2320_I2C, &HTU21x, &AHT10, - &SHT30, &GXHT30, &LM75, &HDC1080, &BMP180, - &BMP280, &BME280, &BME680, &MAX31855, &MAX6675, - &SCD30, &SCD40}; - -const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) { - if(index > SENSOR_TYPES_COUNT) return NULL; - return sensorTypes[index]; -} - -const SensorType* unitemp_sensors_getTypeFromStr(char* str) { - UNUSED(str); - if(str == NULL) return NULL; - for(uint8_t i = 0; i < unitemp_sensors_getTypesCount(); i++) { - if(!strcmp(str, sensorTypes[i]->typename)) { - return sensorTypes[i]; - } - } - return NULL; -} - -uint8_t unitemp_sensors_getTypesCount(void) { - return SENSOR_TYPES_COUNT; -} -const SensorType** unitemp_sensors_getTypes(void) { - return sensorTypes; -} - -int unitemp_getIntFromType(const SensorType* type) { - for(int i = 0; i < SENSOR_TYPES_COUNT; i++) { - if(!strcmp(type->typename, sensorTypes[i]->typename)) { - return i; - } - } - return 255; -} -const GPIO* unitemp_gpio_getFromInt(uint8_t name) { - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - if(GPIOList[i].num == name) { - return &GPIOList[i]; - } - } - return NULL; -} - -const GPIO* unitemp_gpio_getFromIndex(uint8_t index) { - return &GPIOList[index]; -} - -uint8_t unitemp_gpio_toInt(const GPIO* gpio) { - if(gpio == NULL) return 255; - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - if(GPIOList[i].pin->pin == gpio->pin->pin && GPIOList[i].pin->port == gpio->pin->port) { - return GPIOList[i].num; - } - } - return 255; -} - -uint8_t unitemp_gpio_to_index(const GpioPin* gpio) { - if(gpio == NULL) return 255; - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - if(GPIOList[i].pin->pin == gpio->pin && GPIOList[i].pin->port == gpio->port) { - return i; - } - } - return 255; -} - -uint8_t unitemp_gpio_getAviablePortsCount(const Interface* interface, const GPIO* extraport) { - uint8_t aviable_ports_count = 0; - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - //Проверка для one wire - if(interface == &ONE_WIRE) { - if(((gpio_interfaces_list[i] == NULL || gpio_interfaces_list[i] == &ONE_WIRE)) || - (unitemp_gpio_getFromIndex(i) == extraport)) { - aviable_ports_count++; - } - } - - //Проверка для single wire - if(interface == &SINGLE_WIRE || interface == &SPI) { - if(gpio_interfaces_list[i] == NULL || (unitemp_gpio_getFromIndex(i) == extraport)) { - aviable_ports_count++; - } - } - - if(interface == &I2C) { - //У I2C два фиксированых порта - return 0; - } - } - return aviable_ports_count; -} - -void unitemp_gpio_lock(const GPIO* gpio, const Interface* interface) { - uint8_t i = unitemp_gpio_to_index(gpio->pin); - if(i == 255) return; - gpio_interfaces_list[i] = interface; -} - -void unitemp_gpio_unlock(const GPIO* gpio) { - uint8_t i = unitemp_gpio_to_index(gpio->pin); - if(i == 255) return; - gpio_interfaces_list[i] = NULL; -} - -const GPIO* - unitemp_gpio_getAviablePort(const Interface* interface, uint8_t index, const GPIO* extraport) { - //Проверка для I2C - if(interface == &I2C) { - if((gpio_interfaces_list[10] == NULL || gpio_interfaces_list[10] == &I2C) && - (gpio_interfaces_list[11] == NULL || gpio_interfaces_list[11] == &I2C)) { - //Возврат истины - return unitemp_gpio_getFromIndex(0); - } else { - //Возврат лжи - return NULL; - } - } - if(interface == &SPI) { - if(!((gpio_interfaces_list[0] == NULL || gpio_interfaces_list[0] == &SPI) && - (gpio_interfaces_list[1] == NULL || gpio_interfaces_list[1] == &SPI) && - (gpio_interfaces_list[3] == NULL || gpio_interfaces_list[3] == &SPI))) { - return NULL; - } - } - - uint8_t aviable_index = 0; - for(uint8_t i = 0; i < GPIO_ITEMS; i++) { - //Проверка для one wire - if(interface == &ONE_WIRE) { - if(((gpio_interfaces_list[i] == NULL || gpio_interfaces_list[i] == &ONE_WIRE)) || - (unitemp_gpio_getFromIndex(i) == extraport)) { - if(aviable_index == index) { - return unitemp_gpio_getFromIndex(i); - } else { - aviable_index++; - } - } - } - //Проверка для single wire - if(interface == &SINGLE_WIRE || interface == &SPI) { - if(gpio_interfaces_list[i] == NULL || unitemp_gpio_getFromIndex(i) == extraport) { - if(aviable_index == index) { - return unitemp_gpio_getFromIndex(i); - } else { - aviable_index++; - } - } - } - } - - return NULL; -} - -void unitemp_sensor_delete(Sensor* sensor) { - for(uint8_t i = 0; i < app->sensors_count; i++) { - if(app->sensors[i] == sensor) { - app->sensors[i]->status = UT_SENSORSTATUS_INACTIVE; - unitemp_sensors_save(); - unitemp_sensors_reload(); - return; - } - } -} - -Sensor* unitemp_sensor_getActive(uint8_t index) { - uint8_t aviable_index = 0; - for(uint8_t i = 0; i < app->sensors_count; i++) { - if(app->sensors[i]->status != UT_SENSORSTATUS_INACTIVE) { - if(aviable_index == index) { - return app->sensors[i]; - } else { - aviable_index++; - } - } - } - return NULL; -} - -uint8_t unitemp_sensors_getCount(void) { - if(app->sensors == NULL) return 0; - return app->sensors_count; -} - -uint8_t unitemp_sensors_getActiveCount(void) { - if(app->sensors == NULL) return 0; - uint8_t counter = 0; - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - if(app->sensors[i]->status != UT_SENSORSTATUS_INACTIVE) counter++; - } - return counter; -} - -void unitemp_sensors_add(Sensor* sensor) { - app->sensors = - (Sensor**)realloc(app->sensors, (unitemp_sensors_getCount() + 1) * sizeof(Sensor*)); - app->sensors[unitemp_sensors_getCount()] = sensor; - app->sensors_count++; -} - -bool unitemp_sensors_load(void) { - UNITEMP_DEBUG("Loading sensors..."); - - //Выделение памяти на поток - app->file_stream = file_stream_alloc(app->storage); - - //Переменная пути к файлу - FuriString* filepath = furi_string_alloc(); - //Составление пути к файлу - furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SENSORS); - - //Открытие потока к файлу с датчиками - if(!file_stream_open( - app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) { - if(file_stream_get_error(app->file_stream) == FSE_NOT_EXIST) { - FURI_LOG_W(APP_NAME, "Missing sensors file"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } else { - FURI_LOG_E( - APP_NAME, - "An error occurred while loading the sensors file: %d", - file_stream_get_error(app->file_stream)); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - } - - //Вычисление размера файла - uint16_t file_size = stream_size(app->file_stream); - //Если файл пустой, то: - if(file_size == (uint8_t)0) { - FURI_LOG_W(APP_NAME, "Sensors file is empty"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - //Выделение памяти под загрузку файла - uint8_t* file_buf = malloc(file_size); - //Опустошение буфера файла - memset(file_buf, 0, file_size); - //Загрузка файла - if(stream_read(app->file_stream, file_buf, file_size) != file_size) { - //Выход при ошибке чтения - FURI_LOG_E(APP_NAME, "Error reading sensors file"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - free(file_buf); - return false; - } - - //Указатель на начало строки - FuriString* file = furi_string_alloc_set_str((char*)file_buf); - //Сколько байт до конца строки - size_t line_end = 0; - - while(line_end != ((size_t)-1) && line_end != (size_t)(file_size - 1)) { - //Имя датчика - char name[11] = {0}; - //Тип датчика - char type[11] = {0}; - //Смещение по температуре - int temp_offset = 0; - //Смещение по строке для отделения аргументов - int offset = 0; - //Чтение из строки - sscanf(((char*)(file_buf + line_end)), "%s %s %d %n", name, type, &temp_offset, &offset); - //Ограничение длины имени - name[10] = '\0'; - - //Замена ? на пробел - for(uint8_t i = 0; i < 10; i++) { - if(name[i] == '?') name[i] = ' '; - } - - char* args = ((char*)(file_buf + line_end + offset)); - const SensorType* stype = unitemp_sensors_getTypeFromStr(type); - - //Проверка типа датчика - if(stype != NULL && sizeof(name) > 0 && sizeof(name) <= 11) { - Sensor* sensor = - unitemp_sensor_alloc(name, unitemp_sensors_getTypeFromStr(type), args); - if(sensor != NULL) { - sensor->temp_offset = temp_offset; - unitemp_sensors_add(sensor); - } else { - FURI_LOG_E(APP_NAME, "Failed sensor (%s:%s) mem allocation", name, type); - } - } else { - FURI_LOG_E(APP_NAME, "Unsupported sensor name (%s) or sensor type (%s)", name, type); - } - //Вычисление конца строки - line_end = furi_string_search_char(file, '\n', line_end + 1); - } - - free(file_buf); - file_stream_close(app->file_stream); - stream_free(app->file_stream); - - FURI_LOG_I(APP_NAME, "Sensors have been successfully loaded"); - return true; -} - -bool unitemp_sensors_save(void) { - UNITEMP_DEBUG("Saving sensors..."); - - //Выделение памяти для потока - app->file_stream = file_stream_alloc(app->storage); - - //Переменная пути к файлу - FuriString* filepath = furi_string_alloc(); - //Составление пути к файлу - furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SENSORS); - //Создание папки плагина - storage_common_mkdir(app->storage, APP_PATH_FOLDER); - //Открытие потока - if(!file_stream_open( - app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) { - FURI_LOG_E( - APP_NAME, - "An error occurred while saving the sensors file: %d", - file_stream_get_error(app->file_stream)); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - - //Сохранение датчиков - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - Sensor* sensor = unitemp_sensor_getActive(i); - //Замена пробела на ? - for(uint8_t i = 0; i < 10; i++) { - if(sensor->name[i] == ' ') sensor->name[i] = '?'; - } - - stream_write_format( - app->file_stream, - "%s %s %d ", - sensor->name, - sensor->type->typename, - sensor->temp_offset); - - if(sensor->type->interface == &SINGLE_WIRE) { - stream_write_format( - app->file_stream, "%d\n", unitemp_singlewire_sensorGetGPIO(sensor)->num); - } - if(sensor->type->interface == &SPI) { - uint8_t gpio_num = ((SPISensor*)sensor->instance)->CS_pin->num; - stream_write_format(app->file_stream, "%d\n", gpio_num); - } - - if(sensor->type->interface == &I2C) { - stream_write_format( - app->file_stream, "%X\n", ((I2CSensor*)sensor->instance)->currentI2CAdr); - } - if(sensor->type->interface == &ONE_WIRE) { - stream_write_format( - app->file_stream, - "%d %02X%02X%02X%02X%02X%02X%02X%02X\n", - ((OneWireSensor*)sensor->instance)->bus->gpio->num, - ((OneWireSensor*)sensor->instance)->deviceID[0], - ((OneWireSensor*)sensor->instance)->deviceID[1], - ((OneWireSensor*)sensor->instance)->deviceID[2], - ((OneWireSensor*)sensor->instance)->deviceID[3], - ((OneWireSensor*)sensor->instance)->deviceID[4], - ((OneWireSensor*)sensor->instance)->deviceID[5], - ((OneWireSensor*)sensor->instance)->deviceID[6], - ((OneWireSensor*)sensor->instance)->deviceID[7]); - } - } - - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - - FURI_LOG_I(APP_NAME, "Sensors have been successfully saved"); - return true; -} -void unitemp_sensors_reload(void) { - unitemp_sensors_deInit(); - unitemp_sensors_free(); - - unitemp_sensors_load(); - unitemp_sensors_init(); -} - -bool unitemp_sensor_isContains(Sensor* sensor) { - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - if(app->sensors[i] == sensor) return true; - } - return false; -} - -Sensor* unitemp_sensor_alloc(char* name, const SensorType* type, char* args) { - if(name == NULL || type == NULL) return NULL; - bool status = false; - //Выделение памяти под датчик - Sensor* sensor = malloc(sizeof(Sensor)); - if(sensor == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s allocation error", name); - return false; - } - - //Выделение памяти под имя - sensor->name = malloc(11); - if(sensor->name == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s name allocation error", name); - return false; - } - //Запись имени датчка - strcpy(sensor->name, name); - //Тип датчика - sensor->type = type; - //Статус датчика по умолчанию - ошибка - sensor->status = UT_SENSORSTATUS_ERROR; - //Время последнего опроса - sensor->lastPollingTime = - furi_get_tick() - 10000; //чтобы первый опрос произошёл как можно раньше - - sensor->temp = -128.0f; - sensor->hum = -128.0f; - sensor->pressure = -128.0f; - sensor->temp_offset = 0; - //Выделение памяти под инстанс датчика в зависимости от его интерфейса - status = sensor->type->interface->allocator(sensor, args); - - //Выход если датчик успешно развёрнут - if(status) { - UNITEMP_DEBUG("Sensor %s allocated", name); - return sensor; - } - //Выход с очисткой если память для датчика не была выделена - free(sensor->name); - free(sensor); - FURI_LOG_E(APP_NAME, "Sensor %s(%s) allocation error", name, type->typename); - return NULL; -} - -void unitemp_sensor_free(Sensor* sensor) { - if(sensor == NULL) { - FURI_LOG_E(APP_NAME, "Null pointer sensor releasing"); - return; - } - if(sensor->type == NULL) { - FURI_LOG_E(APP_NAME, "Sensor type is null"); - return; - } - if(sensor->type->mem_releaser == NULL) { - FURI_LOG_E(APP_NAME, "Sensor releaser is null"); - return; - } - bool status = false; - //Высвобождение памяти под инстанс - status = sensor->type->interface->mem_releaser(sensor); - - if(status) { - UNITEMP_DEBUG("Sensor %s memory successfully released", sensor->name); - } else { - FURI_LOG_E(APP_NAME, "Sensor %s memory is not released", sensor->name); - } - free(sensor->name); -} - -void unitemp_sensors_free(void) { - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - unitemp_sensor_free(app->sensors[i]); - } - app->sensors_count = 0; -} - -bool unitemp_sensors_init(void) { - bool result = true; - - //Перебор датчиков из списка - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - //Включение 5V если на порту 1 FZ его нет - //Может пропасть при отключении USB - if(furi_hal_power_is_otg_enabled() != true) { - furi_hal_power_enable_otg(); - UNITEMP_DEBUG("OTG enabled"); - } - if(!(*app->sensors[i]->type->initializer)(app->sensors[i])) { - FURI_LOG_E( - APP_NAME, - "An error occurred during sensor initialization %s", - app->sensors[i]->name); - result = false; - } - FURI_LOG_I(APP_NAME, "Sensor %s successfully initialized", app->sensors[i]->name); - } - app->sensors_ready = true; - return result; -} - -bool unitemp_sensors_deInit(void) { - bool result = true; - //Выключение 5 В если до этого оно не было включено - if(app->settings.lastOTGState != true) { - furi_hal_power_disable_otg(); - UNITEMP_DEBUG("OTG disabled"); - } - - //Перебор датчиков из списка - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - if(!(*app->sensors[i]->type->deinitializer)(app->sensors[i])) { - FURI_LOG_E( - APP_NAME, - "An error occurred during sensor deinitialization %s", - app->sensors[i]->name); - result = false; - } - } - return result; -} - -UnitempStatus unitemp_sensor_updateData(Sensor* sensor) { - if(sensor == NULL) return UT_SENSORSTATUS_ERROR; - - //Проверка на допустимость опроса датчика - if(furi_get_tick() - sensor->lastPollingTime < sensor->type->pollingInterval) { - //Возврат ошибки если последний опрос датчика был неудачным - if(sensor->status == UT_SENSORSTATUS_TIMEOUT) { - return UT_SENSORSTATUS_TIMEOUT; - } - return UT_SENSORSTATUS_EARLYPOOL; - } - - sensor->lastPollingTime = furi_get_tick(); - - if(!furi_hal_power_is_otg_enabled()) { - furi_hal_power_enable_otg(); - } - - sensor->status = sensor->type->interface->updater(sensor); - - if(sensor->status != UT_SENSORSTATUS_OK && sensor->status != UT_SENSORSTATUS_POLLING) { - UNITEMP_DEBUG("Sensor %s update status %d", sensor->name, sensor->status); - } - - if(sensor->status == UT_SENSORSTATUS_OK) { - if(app->settings.heat_index && - ((sensor->type->datatype & (UT_TEMPERATURE | UT_HUMIDITY)) == - (UT_TEMPERATURE | UT_HUMIDITY))) { - unitemp_calculate_heat_index(sensor); - } - if(app->settings.temp_unit == UT_TEMP_FAHRENHEIT) { - uintemp_celsiumToFarengate(sensor); - } - - sensor->temp += sensor->temp_offset / 10.f; - if(app->settings.pressure_unit == UT_PRESSURE_MM_HG) { - unitemp_pascalToMmHg(sensor); - } else if(app->settings.pressure_unit == UT_PRESSURE_IN_HG) { - unitemp_pascalToInHg(sensor); - } else if(app->settings.pressure_unit == UT_PRESSURE_KPA) { - unitemp_pascalToKPa(sensor); - } - } - return sensor->status; -} - -void unitemp_sensors_updateValues(void) { - for(uint8_t i = 0; i < unitemp_sensors_getCount(); i++) { - unitemp_sensor_updateData(unitemp_sensor_getActive(i)); - } -} diff --git a/applications/external/unitemp/Sensors.h b/applications/external/unitemp/Sensors.h deleted file mode 100644 index 339a4deff..000000000 --- a/applications/external/unitemp/Sensors.h +++ /dev/null @@ -1,339 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SENSORS -#define UNITEMP_SENSORS -#include -#include - -//Маски бит для определения типов возвращаемых значений -#define UT_TEMPERATURE 0b00000001 -#define UT_HUMIDITY 0b00000010 -#define UT_PRESSURE 0b00000100 -#define UT_CO2 0b00001000 - -//Статусы опроса датчика -typedef enum { - UT_DATA_TYPE_TEMP = UT_TEMPERATURE, - UT_DATA_TYPE_TEMP_HUM = UT_TEMPERATURE | UT_HUMIDITY, - UT_DATA_TYPE_TEMP_PRESS = UT_TEMPERATURE | UT_PRESSURE, - UT_DATA_TYPE_TEMP_HUM_PRESS = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE, - UT_DATA_TYPE_TEMP_HUM_CO2 = UT_TEMPERATURE | UT_HUMIDITY | UT_CO2, -} SensorDataType; - -//Типы возвращаемых данных -typedef enum { - UT_SENSORSTATUS_OK, //Всё хорошо, опрос успешен - UT_SENSORSTATUS_TIMEOUT, //Датчик не отозвался - UT_SENSORSTATUS_EARLYPOOL, //Опрос раньше положенной задержки - UT_SENSORSTATUS_BADCRC, //Неверная контрольная сумма - UT_SENSORSTATUS_ERROR, //Прочие ошибки - UT_SENSORSTATUS_POLLING, //В датчике происходит преобразование - UT_SENSORSTATUS_INACTIVE, //Датчик на редактировании или удалён - -} UnitempStatus; - -//Порт ввода/вывода Flipper Zero -typedef struct GPIO { - const uint8_t num; - const char* name; - const GpioPin* pin; -} GPIO; - -typedef struct Sensor Sensor; - -/** - * @brief Указатель функции выделения памяти и подготовки экземпляра датчика - */ -typedef bool(SensorAllocator)(Sensor* sensor, char* args); -/** - * @brief Указатель на функцию высвобождении памяти датчика - */ -typedef bool(SensorFree)(Sensor* sensor); -/** - * @brief Указатель функции инициализации датчика - */ -typedef bool(SensorInitializer)(Sensor* sensor); -/** - * @brief Указатель функции деинициализации датчика - */ -typedef bool(SensorDeinitializer)(Sensor* sensor); -/** - * @brief Указатель функции обновления значения датчика - */ -typedef UnitempStatus(SensorUpdater)(Sensor* sensor); - -//Типы подключения датчиков -typedef struct Interface { - //Имя интерфейса - const char* name; - //Функция выделения памяти интерфейса - SensorAllocator* allocator; - //Функция высвыбождения памяти интерфейса - SensorFree* mem_releaser; - //Функция обновления значения датчика по интерфейсу - SensorUpdater* updater; -} Interface; - -//Типы датчиков -typedef struct { - //Модель датчика - const char* typename; - //Полное имя с аналогами - const char* altname; - //Тип возвращаемых данных - SensorDataType datatype; - //Интерфейс подключения - const Interface* interface; - //Интервал опроса датчика - uint16_t pollingInterval; - //Функция выделения памяти для датчика - SensorAllocator* allocator; - //Функция высвыбождения памяти для датчика - SensorFree* mem_releaser; - //Функция инициализации датчика - SensorInitializer* initializer; - //Функция деинициализация датчика - SensorDeinitializer* deinitializer; - //Функция обновления значения датчка - SensorUpdater* updater; -} SensorType; - -//Датчик -typedef struct Sensor { - //Имя датчика - char* name; - //Температура - float temp; - float heat_index; - //Относительная влажность - float hum; - //Атмосферное давление - float pressure; - // Концентрация CO2 - float co2; - //Тип датчика - const SensorType* type; - //Статус последнего опроса датчика - UnitempStatus status; - //Время последнего опроса датчика - uint32_t lastPollingTime; - //Смещение по температуре (x10) - int8_t temp_offset; - //Экземпляр датчика - void* instance; -} Sensor; - -extern const Interface SINGLE_WIRE; //Собственный однопроводной протокол датчиков DHTXX и AM23XX -extern const Interface ONE_WIRE; //Однопроводной протокол Dallas -extern const Interface I2C; //I2C_2 (PC0, PC1) -extern const Interface SPI; //SPI_1 (MOSI - 2, MISO - 3, CS - 4, SCK - 5) - -/* ============================= Датчик(и) ============================= */ -/** - * @brief Выделение памяти под датчик - * - * @param name Имя датчика - * @param type Тип датчика - * @param args Указатель на строку с парамерами датчика - * @return Указатель на датчик в случае успешного выделения памяти, NULL при ошибке - */ -Sensor* unitemp_sensor_alloc(char* name, const SensorType* type, char* args); - -/** - * @brief Высвыбождение памяти конкретного датчка - * @param sensor Указатель на датчик - */ -void unitemp_sensor_free(Sensor* sensor); - -/** - * @brief Обновление данных указанного датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_sensor_updateData(Sensor* sensor); - -/** - * @brief Проверка наличия датчика в памяти - * - * @param sensor Указатель на датчик - * @return Истина если этот датчик уже загружен, ложь если это новый датчик - */ -bool unitemp_sensor_isContains(Sensor* sensor); - -/** - * @brief Получить датчик из списка по индексу - * - * @param index Индекс датчика (0 - unitemp_sensors_getCount()) - * @return Указатель на датчик при успехе, NULL при неудаче - */ -Sensor* unitemp_sensor_getActive(uint8_t index); - -/** - * @brief Загрузка датчиков с SD-карты - * @return Истина если загрузка прошла успешно - */ -bool unitemp_sensors_load(); - -/** - * @brief Функция перезагрузки датчиков с SD-карты -*/ -void unitemp_sensors_reload(void); - -/** - * @brief Сохранение датчиков на SD-карту - * @return Истина если сохранение прошло успешно - */ -bool unitemp_sensors_save(void); - -/** - * @brief Удаление датчика - * - * @param sensor Указатель на датчик - */ -void unitemp_sensor_delete(Sensor* sensor); - -/** - * @brief Инициализация загруженных датчиков - * @return Истина если всё прошло успешно - */ -bool unitemp_sensors_init(void); - -/** - * @brief Деинициализация загруженных датчиков - * @return Истина если всё прошло успешно - */ -bool unitemp_sensors_deInit(void); - -/** - * @brief Высвыбождение памяти всех датчиков - */ -void unitemp_sensors_free(void); - -/** - * @brief Обновить данные всех датчиков - */ -void unitemp_sensors_updateValues(void); - -/** - * @brief Получить количество загруженных датчиков - * @return Количество датчиков - */ -uint8_t unitemp_sensors_getCount(void); - -/** - * @brief Добавить датчик в общий список - * @param sensor Указатель на датчик - */ -void unitemp_sensors_add(Sensor* sensor); - -/** -* @brief Получить списк доступных типов датчиков -* @return Указатель на список датчиков -*/ -const SensorType** unitemp_sensors_getTypes(void); - -/** -* @brief Получить количество доступных типов датчиков -* @return Количество доступных типов датчиков -*/ -uint8_t unitemp_sensors_getTypesCount(void); - -/** - * @brief Получить тип сенсора по его индексу - * @param index Индекс типа датчика (от 0 до SENSOR_TYPES_COUNT) - * @return const SensorType* - */ -const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index); - -/** - * @brief Преобразовать строчное название датчка в указатель - * - * @param str Имя датчика в виде строки - * @return Указатель на тип датчика при успехе, иначе NULL - */ -const SensorType* unitemp_sensors_getTypeFromStr(char* str); - -/** - * @brief Получить количество активных датчиков - * - * @return Количество активных датчиков - */ -uint8_t unitemp_sensors_getActiveCount(void); - -/* ============================= GPIO ============================= */ -/** - * @brief Конвертация номера порта на корпусе FZ в GPIO - * @param name Номер порта на корпусе FZ - * @return Указатель на GPIO при успехе, NULL при ошибке - */ -const GPIO* unitemp_gpio_getFromInt(uint8_t name); -/** - * @brief Конвертация GPIO в номер на корпусе FZ - * @param gpio Указатель на порт - * @return Номер порта на корпусе FZ - */ -uint8_t unitemp_gpio_toInt(const GPIO* gpio); - -/** - * @brief Блокировка GPIO указанным интерфейсом - * @param gpio Указатель на порт - * @param interface Указатель на интерфейс, которым порт будет занят - */ -void unitemp_gpio_lock(const GPIO* gpio, const Interface* interface); - -/** - * @brief Разблокировка порта - * @param gpio Указатель на порт - */ -void unitemp_gpio_unlock(const GPIO* gpio); -/** - * @brief Получить количество доступных портов для указанного интерфейса - * @param interface Указатель на интерфейс - * @return Количество доступных портов - */ -uint8_t unitemp_gpio_getAviablePortsCount(const Interface* interface, const GPIO* extraport); -/** - * @brief Получить указатель на доступный для интерфейса порт по индексу - * @param interface Указатель на интерфейс - * @param index Номер порта (от 0 до unitemp_gpio_getAviablePortsCount()) - * @param extraport Указатель на дополнительный порт, который будет принудительно считаться доступным. Можно указать NULL если не требуется - * @return Указатель на доступный порт - */ -const GPIO* - unitemp_gpio_getAviablePort(const Interface* interface, uint8_t index, const GPIO* extraport); - -/* Датчики */ -//DHTxx и их производные -#include "./interfaces/SingleWireSensor.h" -//DS18x2x -#include "./interfaces/OneWireSensor.h" -#include "./sensors/LM75.h" -//BMP280, BME280, BME680 -#include "./sensors/BMx280.h" -#include "./sensors/BME680.h" -#include "./sensors/AM2320.h" -#include "./sensors/DHT20.h" -#include "./sensors/SHT30.h" -#include "./sensors/BMP180.h" -#include "./sensors/HTU21x.h" -#include "./sensors/HDC1080.h" -#include "./sensors/MAX31855.h" -#include "./sensors/MAX6675.h" -#include "./sensors/SCD30.h" -#include "./sensors/SCD40.h" -#endif diff --git a/applications/external/unitemp/application.fam b/applications/external/unitemp/application.fam deleted file mode 100644 index b3f9dec35..000000000 --- a/applications/external/unitemp/application.fam +++ /dev/null @@ -1,17 +0,0 @@ -App( - appid="unitemp", - name="[GPIO] Unitemp", - apptype=FlipperAppType.EXTERNAL, - entry_point="unitemp_app", - requires=[ - "gui", - ], - stack_size=2 * 1024, - fap_description="Universal temperature sensors reader", - fap_version="1.4", - fap_author="@quen0n & (fixes by @xMasterX)", - fap_weburl="https://github.com/quen0n/unitemp-flipperzero", - fap_category="GPIO", - fap_icon="icon.png", - fap_icon_assets="assets", -) diff --git a/applications/external/unitemp/assets/co2_11x14.png b/applications/external/unitemp/assets/co2_11x14.png deleted file mode 100644 index 2a2b5e068d6153d1f30dfc93acd3b0279ee8d551..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 176 zcmeAS@N?(olHy`uVBq!ia0vp@Ak4uAB#T}@sR2?f#ZI0f96(URk}M!fC3NGbie=qQ>#|?bzTh2Q%vH}y3IC$ZRvemx8YG!hReRKhg7T% zs+8bg=d#Wzp$PyIY(cC5 diff --git a/applications/external/unitemp/assets/flipper_happy_2_60x38.png b/applications/external/unitemp/assets/flipper_happy_2_60x38.png deleted file mode 100644 index c4322c237da0a6995009e08bda5774b83515283e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 564 zcmV-40?Yl0P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf0m(^3K~!i%?UwIp4fD3v?U6hc{w7a_p9=5K?JB(bhsPdOz?Qi@rFoBtm9Sw72!@A1PMVW#EfI~O zTbe?)i1`N8NaGeo!?~-@#L+fNG#^_{&UE&c#-hyh<+1d;75;Uz0Qz;M%?isPJ*^X5 z39mr1c!^SNh9c3 zCX~5|6-V@bR$d*WiNpZJE#A_RMHXC(1AV}AIR@l-2}={kWImwx$T7dABLY0QR_CEO zD|gMFT!RDs8b-rwH@2`0c;afz?nUy_s)2^k>OKyd<6JGgcrvF2V=Ts>mZbz1HESa1 zypermjMoP^pKocLToG!s^l@C8Dv|toShd&?u@&xbY0>+6S{Y}pH~$`biGCe;OI}(q ztFL5Bm~ZKpO}k%9G~J4E_!vD6AH@f@1=DYvUH1>7Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf0mw;2K~!i%?U##| zf-nq3VgLW1cNt{Zm?mk;LlC&t;aoiI{ZnV4nG~ z)GbXRYs7p4YNTgE)1`gYz}G7Q7i|(k1BP zyq0qk8H;LS4Gn5I@70iS|JzgAN}556k|y*Vk?SKYO_f_rryinDSv z)&g_kXx&Rj!^`os7=K!}76wc9WYBpt zb>tfF9N>DsrEzgasLj&Hd1Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf0mVr~K~!i%?U#$P zf-nq3!T+979?8?;GkH4vba;QB4xhF{0z5Z7C^7`Lq@|bnI)EK%nWOv#WiNN zgte4vt|j$>``K_x)a>5kfR`6*Dbf1Oi81>gt~EkYQXDC*YakXEbfp*POE4BJ3^QpB zOm5{VtxFiI#dDr!Jh*>xN^42i!aSCU(t3)f33GC9G#{8x={?K>=CSgX);*{bSJa?n zG`yv_2gH=FtH=(mT407<;05IU7Sr6v8WxPvcx^4NVF}TMM(S!Ym}3r-=H5`8=HmK|C!E8oeM yP*3TWO`Bg!G~J4E_!vD6FU1G81=IgFyY3B5#<5PdI{%~q0000=@peSF#SkG9`3@FF6fC;XTdjT_?%?FfY&|GmkA4qW)ctjQhU48_F8K-LV zNi#4o=VXRNltlRYSS9D@>LsS+C#C9DzC zHb_`sNdc^+B->Ug!Z$#{Ilm}X!A#FU&p^qJOF==wrYI%ND#*nRsvXF)RmvzSDX`Ml zFE20GD>v55FG|-pw6wI;H!#vSGSUUA&@HaaD@m--%_~-h7y>iLCAB!YD6^m>Ge1uO zWNuzUS^4%5mXDB zFuJZtggiD2k)_eK`WI!U0uv+Ht-yc=I}lk6s@_H)lpc}NCnWKMMS-c`jtdwpu$*Ma zRnxte2bj6CJzX3_B&L=IT;yX=Nn{1`ISV`@iy0XBj({-ZRBb+KpkTD8i(`mJ@YIRXd<=>l%-!Gjf6l61s+3n! z*TJHudMmskA+11nNnCwoTU%>rrE#WM{%&(u@s+vUatHGwv!d_0-KgKKw}~h1Lx=7T p`77mrA588va5J6zX^Y(i#yg*NWhVXHI~!;XgQu&X%Q~loCIATmKg<9C diff --git a/applications/external/unitemp/assets/in_hg_15x15.png b/applications/external/unitemp/assets/in_hg_15x15.png deleted file mode 100644 index a2778248220fda613a9437a07245b84c7dbfcfa9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^{2vE3q zyT1b2o{o3V^!e$Z-(h{G@Kt)*qb3#S7Z+A74|ViiaiyawD#QEF^)nw!OrKV55DnU- zcIMKQz1IC@OTxZJ8~>lUU}09u`x~MveQs>?_jPGc2v0V)d_H4tf1jJw+#6qa1MOz; MboFyt=akR{0DT=%E&u=k diff --git a/applications/external/unitemp/assets/mm_hg_15x15.png b/applications/external/unitemp/assets/mm_hg_15x15.png deleted file mode 100644 index 66b5dc6eab5f8231184eef708e409cf18ad1c97b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^{2H#7 diff --git a/applications/external/unitemp/assets/pressure_7x13.png b/applications/external/unitemp/assets/pressure_7x13.png deleted file mode 100644 index 43aaa7bbcaa1510b55086b12a4ede0fe85ac3ad1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^>>xG=8<0#rS+W&KF%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl}2EbxddW?X?_wfUrhf_9!Rjv*Ss$$$7+cmfWbIB}xkNNPgUrHF$K z9!)VFybVWYI{3MVGkg|`OMckcutr);;K)v~Wm0a<403aMcoiv~ z_k$W==8o#aM{mCHtfuA;eV$wZZR zIRO()V)h(9DJ`PXt5TQ_6nywdR^@c!jyJqrJ2#uJ`}X3`2AQ_g_ZG~su6~@gw*KSu z7amf(XRNPoPO?1EnOmaL8++#ZUdN4x?Hgh*SnW{C+_FjboM*E57QS^JQfqT8^X)dD z-J2UQ%Vv^{lzr0d>e~xUDpf2Ma#eblOf-qPu^>TwOW*OS@*Yy2%9%ShI3Co?ko|g! z@jZ9-?){sj@44Knh`(|B@6@|jjOC;GlrvRCD?^@KEcki$+>q#cD%3s@xZqJ zY42>N?|bbZoZkZsF`#1=Ue2@s+{P`fSKZvCvPAUvS-oRdizeLFFVdQ&MBb@0K(Z;Y5)KL diff --git a/applications/external/unitemp/assets/sherlok_53x45.png b/applications/external/unitemp/assets/sherlok_53x45.png deleted file mode 100644 index 1f258737e351cc742771d8ddaa160184670cbad4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 695 zcmV;o0!aOdP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!~g&e!~vBn4jTXf0!&FnK~!i%-Ia}w z;xG(^;okq9cNw&U=DfCJI{}XSq=+{0&rDsF>(`CTVXoKf&sEG5+CDgDN{yf-?!D67 zxA7<0Hbrrn0g@R7n^GS9`T1=FAr!eQhBa7om(iqXCL@a3$*t0!)NaEHsE5&lg3z zQ>y0JI2y3Ix?io`niPuaIst1zEQRaR{VL^2={1S=I%xfjOot^jrO8<#8wa9TMPqpl zY_2`iei6rBKQ>!6R64PQ#xlyE^sEqLB38LosggJ)MV8h=h;J8v3kfy{-<^X zS|C=}gtn=jX0Kv2snulc`DBvFnZ5xnQ*3l%Qad$}n;CBXPenpBu7k}}DPAqBC!#&6 z2sWxN=2X!fUPqKnp$G*~6c@0KR$}eB*5TTr^!kygnHLw7y~A^@$9UVr+s|qP*VIas z62(^cRV=VMJjcFXXN*4SiZ+|znb0+1+f;;S7WdIp#=dvPy)4&q#1xuMpQ;s$Yh515 z$@(3glx<{1+575)U>+X;SCs$jL!p7@XbE$f=QXuw)gFlVV!i#pOxb{_Py~e%FSioo zk!i7KkJryj!o3xd!F>GMT13yH7)xfz~eqoR!ycNJY&;39eq#x zp8{xP*97Ew4+waMpK9tPo-yA4+P|$^e0{X<#u}hm)%Y=!A{5VG8d9?#XR5+Sn~J9O dA5Q9W`3ATiP9a&X@v#5^002ovPDHLkV1h6FKidER diff --git a/applications/external/unitemp/assets/temp_C_11x14.png b/applications/external/unitemp/assets/temp_C_11x14.png deleted file mode 100644 index 19cf423b4b18ec8724843dd2ee48bd7290662a38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 214 zcmeAS@N?(olHy`uVBq!ia0vp^+(697!3HFMCO(@Aq!^2X+?^QKos)S9a~60+76UaL0b$0e+I-SL!E8?##}JL+)`^^a2NXD14*vhYv$QjLW#G&u zayxp|zAjIeEx(?UEM0x=f=R)G{Oc~dhnk$yrk*iaCTz8TmhsY=uPgmB!#FNp?V0-Z z>YTN+(j(UJ&RCiK#`pethMt)Q>kkU=PY>C0w{-WcnK!w==ex`7DxRAJw3fls)z4*} HQ$iB}?4eE& diff --git a/applications/external/unitemp/assets/temp_F_11x14.png b/applications/external/unitemp/assets/temp_F_11x14.png deleted file mode 100644 index 5ed469337e7b98392d9b65e0e156a41b5b4a68c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^+(697!3HFMCO(@Aq!^2X+?^QKos)S9a~60+76UaL0b$0e+I-SL!E{d-#}JL+wS9qn2NXD*yT9+>y!ePzieLRV zA@!`v!@HP|pV^Tp^LR~^i-rA_2`Wo^Yj>{MFf+St^I9jt>;KaVP18?aToV~8e|A>r zSDwkY6gI#6`E}Vpu2VBOi+Srd_7pCDTep2Ta|65b0w)mzHW_cAl?CG$boEJ%AX`jCW1e9%DP% zO$0(h0;#H?r=Aev)C)+FP`ROs3%zh4HzW@H0bD?cLoY~WylZa@YSUb>wDyem&HLWG z@AEg;R#z^aoPKdy5QLNM<<=U1mgDKE`Q`h{A$$MC^q~zJj`Ml5f)H+7^fU92p8suDZ-ny z5Chtcl7{rhci&55L>kf+(^vg;k@lkH-Hfj9u5|G3CU%K5e^IwkvCaWg^=>FG3YUMYR-72b%2} zmZuqFbxAy2MnZ3`^;#8-&l*y%C{j;R27`e-&}Ei&70q>BMTH84fFnS@lN4wOlKgbd z(4slcqO^!uB9@FOU|U5);!?+Zh|>vel2<-)$CM#T6-`#lJ=H+pKNuRv6LelIZSyFV z-bWJWot=~_YcywD8Kz6yG$~Hk!O|WpSl(lg(Kh+}UkVAH1WdQG{>UDJ722mU=gv7+ z8|h2E#f+kYWgW))b*5J9h$7TwQ#^AeN(dX|XG=xZ0@^|aZAfL-fa(Ix>}a}Yn4aOB zQ*}>O$55Xa0zm~j9GH7f3@tfeYas)CMXAyWr9#106cfq+B95KsiMV;Y8yZC4T>#9d^4midfu zcXdf5*b7+}BVIpIjJi}wlWtkfoSpAtIm&tJcB=1VoxWF%`jI#)IuGHp)*BKolT3+J zy^bE`-l24kX$L*ZNe@W=7?!iJ7@&+cyWHs~7MJok@j2Rlg7iZr{(qES*@}B8=~CV~ z6{*~eQnr|JQk4JZ>p{NjnrZTCF0+|eHY}j-#E^@1F(ITA7h(i#%h7=g4I4P28URc} zNT97@JG91e`%$f6Or#tfaisO3_E<0GJ+~ZAx;>vv&I_9Gt!Df*xc=_U=lmpDYqy%6 zGwUDUxIQbKnt95;e}CV3^UoJ#bo<-4hI<=#e?9y2m(N@~@!ZkRX4HHB)L&{ab?+wp z>g_q&x%0~Jr{-QIWbT94-@gUE{&4=2=Wl(X-#+@|<@3kZe^K|#gQ~r>(%M^i=c9iB DwLd-Z diff --git a/applications/external/unitemp/interfaces/I2CSensor.c b/applications/external/unitemp/interfaces/I2CSensor.c deleted file mode 100644 index e5901c282..000000000 --- a/applications/external/unitemp/interfaces/I2CSensor.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "I2CSensor.h" - -static uint8_t sensors_count = 0; - -void unitemp_i2c_acquire(FuriHalI2cBusHandle* handle) { - furi_hal_i2c_acquire(handle); - LL_GPIO_SetPinPull(gpio_ext_pc1.port, gpio_ext_pc1.pin, LL_GPIO_PULL_UP); - LL_GPIO_SetPinPull(gpio_ext_pc0.port, gpio_ext_pc0.pin, LL_GPIO_PULL_UP); -} - -bool unitemp_i2c_isDeviceReady(I2CSensor* i2c_sensor) { - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = furi_hal_i2c_is_device_ready(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -uint8_t unitemp_i2c_readReg(I2CSensor* i2c_sensor, uint8_t reg) { - //Блокировка шины - unitemp_i2c_acquire(i2c_sensor->i2c); - uint8_t buff[1] = {0}; - furi_hal_i2c_read_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, reg, buff, 1, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return buff[0]; -} - -bool unitemp_i2c_readArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data) { - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = furi_hal_i2c_rx(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, data, len, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_i2c_readRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data) { - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = - furi_hal_i2c_read_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, startReg, data, len, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_i2c_writeReg(I2CSensor* i2c_sensor, uint8_t reg, uint8_t value) { - //Блокировка шины - unitemp_i2c_acquire(i2c_sensor->i2c); - uint8_t buff[1] = {value}; - bool status = - furi_hal_i2c_write_mem(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, reg, buff, 1, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_i2c_writeArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data) { - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = furi_hal_i2c_tx(i2c_sensor->i2c, i2c_sensor->currentI2CAdr, data, len, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_i2c_writeRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data) { - //Блокировка шины - unitemp_i2c_acquire(i2c_sensor->i2c); - bool status = furi_hal_i2c_write_mem( - i2c_sensor->i2c, i2c_sensor->currentI2CAdr, startReg, data, len, 10); - furi_hal_i2c_release(i2c_sensor->i2c); - return status; -} - -bool unitemp_I2C_sensor_alloc(Sensor* sensor, char* args) { - bool status = false; - I2CSensor* instance = malloc(sizeof(I2CSensor)); - if(instance == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name); - return false; - } - instance->i2c = &furi_hal_i2c_handle_external; - sensor->instance = instance; - - //Указание функций инициализации, деинициализации и обновления данных, а так же адреса на шине I2C - status = sensor->type->allocator(sensor, args); - int i2c_addr; - sscanf(args, "%X", &i2c_addr); - - //Установка адреса шины I2C - if(i2c_addr >= instance->minI2CAdr && i2c_addr <= instance->maxI2CAdr) { - instance->currentI2CAdr = i2c_addr; - } else { - instance->currentI2CAdr = instance->minI2CAdr; - } - - //Блокировка портов GPIO - sensors_count++; - unitemp_gpio_lock(unitemp_gpio_getFromInt(15), &I2C); - unitemp_gpio_lock(unitemp_gpio_getFromInt(16), &I2C); - - return status; -} - -bool unitemp_I2C_sensor_free(Sensor* sensor) { - bool status = sensor->type->mem_releaser(sensor); - free(sensor->instance); - if(--sensors_count == 0) { - unitemp_gpio_unlock(unitemp_gpio_getFromInt(15)); - unitemp_gpio_unlock(unitemp_gpio_getFromInt(16)); - } - - return status; -} - -UnitempStatus unitemp_I2C_sensor_update(Sensor* sensor) { - if(sensor->status != UT_SENSORSTATUS_OK) { - sensor->type->initializer(sensor); - } - return sensor->type->updater(sensor); -} \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/I2CSensor.h b/applications/external/unitemp/interfaces/I2CSensor.h deleted file mode 100644 index 4d468aae1..000000000 --- a/applications/external/unitemp/interfaces/I2CSensor.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_I2C -#define UNITEMP_I2C - -#include "../unitemp.h" - -#include - -//Структура I2C датчика -typedef struct I2CSensor { - //Указатель на интерфейс I2C - FuriHalI2cBusHandle* i2c; - //Минимальный адрес устройства на шине I2C - uint8_t minI2CAdr; - //Максимальный адрес устройства на шине I2C - uint8_t maxI2CAdr; - //Текущий адрес устройства на шине I2C - uint8_t currentI2CAdr; - //Указатель на собственный экземпляр датчика - void* sensorInstance; -} I2CSensor; - -/** - * @brief Заблокировать шину I2C - * - * @param handle Указатель на шину - */ -void unitemp_i2c_acquire(FuriHalI2cBusHandle* handle); - -/** - * @brief Проверить наличие датчика на шине - * - * @param i2c_sensor Указатель на датчик - * @return Истина если устройство отозвалось - */ -bool unitemp_i2c_isDeviceReady(I2CSensor* i2c_sensor); - -/** - * @brief Выделение памяти для датчика на шине I2C - * @param sensor Указатель на датчик - * @param st Тип датчика - * @return Истина если всё ок - */ -bool unitemp_I2C_sensor_alloc(Sensor* sensor, char* args); - -/** - * @brief Высвобождение памяти инстанса датчика - * @param sensor Указатель на датчик - */ -bool unitemp_I2C_sensor_free(Sensor* sensor); - -/** - * @brief Обновить значение с датчка - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_I2C_sensor_update(Sensor* sensor); -/** - * @brief Прочитать значение регистра reg - * @param i2c_sensor Указатель на инстанс датчика - * @param reg Номер регистра - * @return Значение регистра - */ -uint8_t unitemp_i2c_readReg(I2CSensor* i2c_sensor, uint8_t reg); - -/** - * @brief Прочитать масссив значений из памяти - * @param i2c_sensor Указатель на инстанс датчика - * @param startReg Адрес регистра с которого начнётся чтение - * @param len Количество байт для считывания из регистра - * @param data Указатель на массив куда будут считаны данные - * @return Истина если устройство вернуло данные - */ -bool unitemp_i2c_readRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data); - -/** - * @brief Записать значение в регистр - * @param i2c_sensor Указатель на инстанс датчика - * @param reg Номер регистра - * @param value Значение для записи - * @return Истина если значение записано - */ -bool unitemp_i2c_writeReg(I2CSensor* i2c_sensor, uint8_t reg, uint8_t value); - -/** - * @brief Записать масссив значений в память - * @param i2c_sensor Указатель на инстанс датчика - * @param startReg Адрес регистра с которого начнётся запись - * @param len Количество байт для считывания из регистра - * @param data Указатель на массив откуда будут записаны данные - * @return Истина если устройство вернуло данные - */ -bool unitemp_i2c_writeRegArray(I2CSensor* i2c_sensor, uint8_t startReg, uint8_t len, uint8_t* data); - -/** - * @brief Прочитать массив данных по шине I2C - * @param i2c_sensor Указатель на инстанс датчика - * @param startReg Адрес регистра с которого начнётся чтение - * @param data Указатель на массив куда будут считаны данные - * @return Истина если устройство вернуло данные - */ -bool unitemp_i2c_readArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data); - -/** - * @brief Записать масссив данных по шине I2C - * @param i2c_sensor Указатель на инстанс датчика - * @param len Количество байт для считывания из регистра - * @param data Указатель на массив откуда будут записаны данные - * @return Истина если устройство вернуло данные - */ -bool unitemp_i2c_writeArray(I2CSensor* i2c_sensor, uint8_t len, uint8_t* data); -#endif \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/OneWireSensor.c b/applications/external/unitemp/interfaces/OneWireSensor.c deleted file mode 100644 index 377eb0d08..000000000 --- a/applications/external/unitemp/interfaces/OneWireSensor.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -//Использован код Дмитрия Погребняка: https://aterlux.ru/article/1wire - -#include "OneWireSensor.h" -#include -#include - -const SensorType Dallas = { - .typename = "Dallas", - .altname = "Dallas (DS18x2x)", - .interface = &ONE_WIRE, - .datatype = UT_DATA_TYPE_TEMP, - .pollingInterval = 1000, - .allocator = unitemp_onewire_sensor_alloc, - .mem_releaser = unitemp_onewire_sensor_free, - .initializer = unitemp_onewire_sensor_init, - .deinitializer = unitemp_onewire_sensor_deinit, - .updater = unitemp_onewire_sensor_update}; - -// Переменные для хранения промежуточного результата сканирования шины -// найденный восьмибайтовый адрес -static uint8_t onewire_enum[8] = {0}; - -OneWireBus* uintemp_onewire_bus_alloc(const GPIO* gpio) { - if(gpio == NULL) { - return NULL; - } - - //Проверка на наличие шины на этом порте - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - if(unitemp_sensor_getActive(i)->type->interface == &ONE_WIRE && - ((OneWireSensor*)unitemp_sensor_getActive(i)->instance)->bus->gpio->num == gpio->num) { - //Если шина на этом порту уже есть, то возврат указателя на шину - return ((OneWireSensor*)unitemp_sensor_getActive(i)->instance)->bus; - } - } - - OneWireBus* bus = malloc(sizeof(OneWireBus)); - - bus->device_count = 0; - bus->gpio = gpio; - bus->powerMode = PWR_PASSIVE; - - UNITEMP_DEBUG("one wire bus (port %d) allocated", gpio->num); - - return bus; -} - -bool unitemp_onewire_bus_init(OneWireBus* bus) { - if(bus == NULL) return false; - bus->device_count++; - //Выход если шина уже была инициализирована - if(bus->device_count > 1) return true; - - bus->host = onewire_host_alloc(bus->gpio->pin); - - unitemp_gpio_lock(bus->gpio, &ONE_WIRE); - //Высокий уровень по умолчанию - furi_hal_gpio_write(bus->gpio->pin, true); - //Режим работы - OpenDrain, подтяжка включается на всякий случай - furi_hal_gpio_init( - bus->gpio->pin, //Порт FZ - GpioModeOutputOpenDrain, //Режим работы - открытый сток - GpioPullUp, //Принудительная подтяжка линии данных к питанию - GpioSpeedVeryHigh); //Скорость работы - максимальная - - return true; -} - -bool unitemp_onewire_bus_deinit(OneWireBus* bus) { - UNITEMP_DEBUG("devices on wire %d: %d", bus->gpio->num, bus->device_count); - bus->device_count--; - if(bus->device_count <= 0) { - bus->device_count = 0; - unitemp_gpio_unlock(bus->gpio); - //Режим работы - аналог, подтяжка выключена - furi_hal_gpio_init( - bus->gpio->pin, //Порт FZ - GpioModeAnalog, //Режим работы - аналог - GpioPullNo, //Подтяжка выключена - GpioSpeedLow); //Скорость работы - минимальная - //Низкий уровень по умолчанию - furi_hal_gpio_write(bus->gpio->pin, false); - return true; - } else { - return false; - } -} -inline bool unitemp_onewire_bus_start(OneWireBus* bus) { - return onewire_host_reset(bus->host); -} - -inline void unitemp_onewire_bus_send_bit(OneWireBus* bus, bool state) { - onewire_host_write_bit(bus->host, state); -} - -inline void unitemp_onewire_bus_send_byte(OneWireBus* bus, uint8_t data) { - onewire_host_write(bus->host, data); -} - -void unitemp_onewire_bus_send_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len) { - for(uint8_t i = 0; i < len; i++) { - onewire_host_write(bus->host, data[i]); - } -} - -inline bool unitemp_onewire_bus_read_bit(OneWireBus* bus) { - return onewire_host_read_bit(bus->host); -} - -inline uint8_t unitemp_onewire_bus_read_byte(OneWireBus* bus) { - return onewire_host_read(bus->host); -} - -void unitemp_onewire_bus_read_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len) { - onewire_host_read_bytes(bus->host, data, len); -} - -static uint8_t onewire_CRC_update(uint8_t crc, uint8_t b) { - for(uint8_t p = 8; p; p--) { - crc = ((crc ^ b) & 1) ? (crc >> 1) ^ 0b10001100 : (crc >> 1); - b >>= 1; - } - return crc; -} - -bool unitemp_onewire_CRC_check(uint8_t* data, uint8_t len) { - uint8_t crc = 0; - for(uint8_t i = 0; i < len; i++) { - crc = onewire_CRC_update(crc, data[i]); - } - return !crc; -} - -char* unitemp_onewire_sensor_getModel(Sensor* sensor) { - OneWireSensor* ow_sensor = sensor->instance; - switch(ow_sensor->deviceID[0]) { - case FC_DS18B20: - return "DS18B20"; - case FC_DS18S20: - return "DS18S20"; - case FC_DS1822: - return "DS1822"; - default: - return "unknown"; - } -} - -bool unitemp_onewire_sensor_readID(OneWireSensor* instance) { - if(!unitemp_onewire_bus_start(instance->bus)) return false; - unitemp_onewire_bus_send_byte(instance->bus, 0x33); // Чтение ПЗУ - unitemp_onewire_bus_read_byteArray(instance->bus, instance->deviceID, 8); - if(!unitemp_onewire_CRC_check(instance->deviceID, 8)) { - memset(instance->deviceID, 0, 8); - return false; - } - instance->familyCode = instance->deviceID[0]; - return true; -} - -void unitemp_onewire_bus_enum_init(OneWireBus* bus) { - onewire_host_reset_search(bus->host); -} - -uint8_t* unitemp_onewire_bus_enum_next(OneWireBus* bus) { - if(onewire_host_search(bus->host, onewire_enum, OneWireHostSearchModeNormal)) { - return onewire_enum; - } else { - return NULL; - } -} - -void unitemp_onewire_bus_select_sensor(OneWireSensor* instance) { - unitemp_onewire_bus_send_byte(instance->bus, 0x55); - unitemp_onewire_bus_send_byteArray(instance->bus, instance->deviceID, 8); -} - -bool unitemp_onewire_sensor_alloc(Sensor* sensor, char* args) { - OneWireSensor* instance = malloc(sizeof(OneWireSensor)); - if(instance == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name); - return false; - } - sensor->instance = instance; - //Очистка адреса - memset(instance->deviceID, 0, 8); - - int gpio, addr_0, addr_1, addr_2, addr_3, addr_4, addr_5, addr_6, addr_7; - sscanf( - args, - "%d %2X%2X%2X%2X%2X%2X%2X%2X", - &gpio, - &addr_0, - &addr_1, - &addr_2, - &addr_3, - &addr_4, - &addr_5, - &addr_6, - &addr_7); - instance->deviceID[0] = addr_0; - instance->deviceID[1] = addr_1; - instance->deviceID[2] = addr_2; - instance->deviceID[3] = addr_3; - instance->deviceID[4] = addr_4; - instance->deviceID[5] = addr_5; - instance->deviceID[6] = addr_6; - instance->deviceID[7] = addr_7; - - instance->familyCode = instance->deviceID[0]; - - instance->bus = uintemp_onewire_bus_alloc(unitemp_gpio_getFromInt(gpio)); - - if(instance != NULL) { - return true; - } - FURI_LOG_E(APP_NAME, "Sensor %s bus allocation error", sensor->name); - free(instance); - return false; -} - -bool unitemp_onewire_sensor_free(Sensor* sensor) { - if(((OneWireSensor*)sensor->instance)->bus != NULL) { - if(((OneWireSensor*)sensor->instance)->bus->device_count == 0) { - free(((OneWireSensor*)sensor->instance)->bus); - } - } - - free(sensor->instance); - - return true; -} - -bool unitemp_onewire_sensor_init(Sensor* sensor) { - OneWireSensor* instance = sensor->instance; - if(instance == NULL || instance->bus == NULL) { - FURI_LOG_E(APP_NAME, "Sensor pointer is null!"); - return false; - } - - unitemp_onewire_bus_init(instance->bus); - - if(instance->familyCode == FC_DS18B20 || instance->familyCode == FC_DS1822) { - //Установка разрядности в 10 бит - if(!unitemp_onewire_bus_start(instance->bus)) return false; - unitemp_onewire_bus_select_sensor(instance); - unitemp_onewire_bus_send_byte(instance->bus, 0x4E); // Запись в память - uint8_t buff[3]; - //Значения тревоги - buff[0] = 0x4B; //Значение нижнего предела температуры - buff[1] = 0x46; //Значение верхнего предела температуры - //Конфигурация - buff[2] = 0b01111111; //12 бит разрядность преобразования - unitemp_onewire_bus_send_byteArray(instance->bus, buff, 3); - - //Сохранение значений в EEPROM для автоматического восстановления после сбоев питания - if(!unitemp_onewire_bus_start(instance->bus)) return false; - unitemp_onewire_bus_select_sensor(instance); - unitemp_onewire_bus_send_byte(instance->bus, 0x48); // Запись в EEPROM - } - - return true; -} - -bool unitemp_onewire_sensor_deinit(Sensor* sensor) { - OneWireSensor* instance = sensor->instance; - if(instance == NULL || instance->bus == NULL) return false; - unitemp_onewire_bus_deinit(instance->bus); - - return true; -} - -UnitempStatus unitemp_onewire_sensor_update(Sensor* sensor) { - //Снятие особого статуса с датчика при пассивном режиме питания - if(sensor->status == UT_SENSORSTATUS_EARLYPOOL) { - return UT_SENSORSTATUS_POLLING; - } - - OneWireSensor* instance = sensor->instance; - uint8_t buff[9] = {0}; - if(sensor->status != UT_SENSORSTATUS_POLLING) { - //Если датчик в прошлый раз не отозвался, проверка его наличия на шине - if(sensor->status == UT_SENSORSTATUS_TIMEOUT || sensor->status == UT_SENSORSTATUS_BADCRC) { - if(!unitemp_onewire_bus_start(instance->bus)) return UT_SENSORSTATUS_TIMEOUT; - unitemp_onewire_bus_select_sensor(instance); - unitemp_onewire_bus_send_byte(instance->bus, 0xBE); // Read Scratch-pad - unitemp_onewire_bus_read_byteArray(instance->bus, buff, 9); - if(!unitemp_onewire_CRC_check(buff, 9)) { - UNITEMP_DEBUG("Sensor %s is not found", sensor->name); - return UT_SENSORSTATUS_TIMEOUT; - } - } - - if(!unitemp_onewire_bus_start(instance->bus)) return UT_SENSORSTATUS_TIMEOUT; - //Запуск преобразования на всех датчиках в режиме пассивного питания - if(instance->bus->powerMode == PWR_PASSIVE) { - unitemp_onewire_bus_send_byte(instance->bus, 0xCC); // skip addr - //Установка на всех датчиках этой шины особого статуса, чтобы не запускать преобразование ещё раз - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - if(unitemp_sensor_getActive(i)->type->interface == &ONE_WIRE && - ((OneWireSensor*)unitemp_sensor_getActive(i)->instance)->bus == instance->bus) { - unitemp_sensor_getActive(i)->status = UT_SENSORSTATUS_EARLYPOOL; - } - } - - } else { - unitemp_onewire_bus_select_sensor(instance); - } - - unitemp_onewire_bus_send_byte(instance->bus, 0x44); // convert t - if(instance->bus->powerMode == PWR_PASSIVE) { - furi_hal_gpio_write(instance->bus->gpio->pin, true); - furi_hal_gpio_init( - instance->bus->gpio->pin, GpioModeOutputPushPull, GpioPullUp, GpioSpeedVeryHigh); - } - return UT_SENSORSTATUS_POLLING; - } else { - if(instance->bus->powerMode == PWR_PASSIVE) { - furi_hal_gpio_write(instance->bus->gpio->pin, true); - furi_hal_gpio_init( - instance->bus->gpio->pin, GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh); - } - if(!unitemp_onewire_bus_start(instance->bus)) return UT_SENSORSTATUS_TIMEOUT; - unitemp_onewire_bus_select_sensor(instance); - unitemp_onewire_bus_send_byte(instance->bus, 0xBE); // Read Scratch-pad - unitemp_onewire_bus_read_byteArray(instance->bus, buff, 9); - if(!unitemp_onewire_CRC_check(buff, 9)) { - UNITEMP_DEBUG("Failed CRC check: %s", sensor->name); - return UT_SENSORSTATUS_BADCRC; - } - int16_t raw = buff[0] | ((int16_t)buff[1] << 8); - if(instance->familyCode == FC_DS18S20) { - //Песевдо-12-бит. Отключено из-за неестественности и нестабильности показаний по сравнению с DS18B20 - //sensor->temp = ((float)raw / 2.0f) - 0.25f + (16.0f - buff[6]) / 16.0f; - //Честные 9 бит - sensor->temp = ((float)raw / 2.0f); - } else { - sensor->temp = (float)raw / 16.0f; - } - } - - return UT_SENSORSTATUS_OK; -} - -bool unitemp_onewire_id_compare(uint8_t* id1, uint8_t* id2) { - if(id1 == NULL || id2 == NULL) return false; - for(uint8_t i = 0; i < 8; i++) { - if(id1[i] != id2[i]) return false; - } - return true; -} \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/OneWireSensor.h b/applications/external/unitemp/interfaces/OneWireSensor.h deleted file mode 100644 index cb031d161..000000000 --- a/applications/external/unitemp/interfaces/OneWireSensor.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_OneWire -#define UNITEMP_OneWire - -#include "../unitemp.h" -#include - -//Коды семейства устройств -typedef enum DallasFamilyCode { - FC_DS18S20 = 0x10, - FC_DS1822 = 0x22, - FC_DS18B20 = 0x28, -} DallasFamilyCode; - -//Режим питания датчка -typedef enum PowerMode { - PWR_PASSIVE, //Питание от линии данных - PWR_ACTIVE //Питание от источника питания -} PowerMode; - -//Инстанс шины one wire -typedef struct { - //Порт подключения датчика - const GPIO* gpio; - //Количество устройств на шине - //Обновляется при ручном добавлении датчика на эту шину - int8_t device_count; - //Режим питания датчиков на шине - PowerMode powerMode; - - OneWireHost* host; -} OneWireBus; - -//Инстанс датчика one wire -typedef struct OneWireSensor { - //Указатель на шину OneWire - OneWireBus* bus; - //Текущий адрес устройства на шине OneWire - uint8_t deviceID[8]; - //Код семейства устройств - DallasFamilyCode familyCode; -} OneWireSensor; - -/** - * @brief Выделение памяти для датчика на шине OneWire - * @param sensor Указатель на датчик - * @param args Указатель на массив аргументов с параметрами датчика - * @return Истина если всё ок - */ -bool unitemp_onewire_sensor_alloc(Sensor* sensor, char* args); - -/** - * @brief Высвобождение памяти инстанса датчика - * @param sensor Указатель на датчик - */ -bool unitemp_onewire_sensor_free(Sensor* sensor); - -/** - * @brief Инициализации датчика на шине one wire - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_onewire_sensor_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_onewire_sensor_deinit(Sensor* sensor); - -/** - * @brief Обновить значение с датчка - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_onewire_sensor_update(Sensor* sensor); - -/** - * @brief Выделение памяти для шины one wire и её инициализация - * @param gpio Порт на котором необходимо создать шину - * @return При успехе возвращает указатель на шину one wire - */ -OneWireBus* uintemp_onewire_bus_alloc(const GPIO* gpio); - -/** - * @brief Инициализация шины one wire - * - * @param bus Указатель на шину - * @return Истина если инициализация успешна - */ -bool unitemp_onewire_bus_init(OneWireBus* bus); - -/** - * @brief Деинициализация шины one wire - * - * @param bus Указатель на шину - * @return Истина если шина была деинициализирована, ложь если на шине остались устройства - */ -bool unitemp_onewire_bus_deinit(OneWireBus* bus); - -/** - * @brief Запуск общения с датчиками на шине one wire - * @param bus Указатель на шину - * @return Истина если хотя бы одно устройство отозвалось - */ -bool unitemp_onewire_bus_start(OneWireBus* bus); - -/** - * @brief Отправить 1 бит данных на шину one wire - * @param bus Указатель на шину - * @param state Логический уровень - */ -void unitemp_onewire_bus_send_bit(OneWireBus* bus, bool state); - -/** - * @brief Запись байта на шину one wire - * - * @param bus Указатель на шину one wire - * @param data Записываемый байт - */ -void unitemp_onewire_bus_send_byte(OneWireBus* bus, uint8_t data); - -/** - * @brief Запись массива байт на шину one wire - * - * @param bus Указатель на шину one wire - * @param data Указатель на массив, откуда будут записаны данные - * @param len Количество байт - */ -void unitemp_onewire_bus_send_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len); - -/** - * @brief Чтение бита на шине one wire - * - * @param bus Указатель на шину one wire - * @return Логический уровень бита - */ -bool unitemp_onewire_bus_read_bit(OneWireBus* bus); - -/** - * @brief Чтение байта с шины One Wire - * - * @param bus Указатель на шину one wire - * @return Байт информации - **/ -uint8_t unitemp_onewire_bus_read_byte(OneWireBus* bus); - -/** - * @brief Чтение массива байт с шины One Wire - * - * @param bus Указатель на шину one wire - * @param data Указатель на массив, куда будут записаны данные - * @param len Количество байт - */ -void unitemp_onewire_bus_read_byteArray(OneWireBus* bus, uint8_t* data, uint8_t len); - -/** - * @brief Проверить контрольную сумму массива данных - * - * @param data Указатель на массив данных - * @param len Длина массива (включая байт CRC) - * @return Истина если контрольная сумма корректная - */ -bool unitemp_onewire_CRC_check(uint8_t* data, uint8_t len); - -/** - * @brief Получить имя модели датчика на шине One Wire - * - * @param sensor Указатель на датчик - * @return Указатель на строку с названием - */ -char* unitemp_onewire_sensor_getModel(Sensor* sensor); - -/** - * @brief Чтение индификатора единственного датчика. ID запишется в инстанс датчика - * - * @param instance Указатель на инстанс датчика - * @return Истина, если код успешно прочитан, ложь если устройство отсутствует или устройств на шине больше одного - */ -bool unitemp_oneWire_sensor_readID(OneWireSensor* instance); - -/** - * @brief Команда выбора определённого датчка по его ID - * @param instance Указатель на датчик one wire - */ -void unitemp_onewire_bus_select_sensor(OneWireSensor* instance); - -/** - * @brief Инициализация процесса поиска адресов на шине one wire - */ -void unitemp_onewire_bus_enum_init(OneWireBus* bus); - -/** - * @brief Перечисляет устройства на шине one wire и получает очередной адрес - * @param bus Указатель на шину one wire - * @return Возвращает указатель на буфер, содержащий восьмибайтовое значение адреса, либо NULL, если поиск завешён - */ -uint8_t* unitemp_onewire_bus_enum_next(OneWireBus* bus); - -/** - * @brief Сравнить ID датчиков - * - * @param id1 Указатель на адрес первого датчика - * @param id2 Указатель на адрес второго датчика - * @return Истина если ID индентичны - */ -bool unitemp_onewire_id_compare(uint8_t* id1, uint8_t* id2); - -extern const SensorType Dallas; -#endif \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/SPISensor.c b/applications/external/unitemp/interfaces/SPISensor.c deleted file mode 100644 index b53aed28d..000000000 --- a/applications/external/unitemp/interfaces/SPISensor.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include -#include -#include "SPISensor.h" - -static uint8_t sensors_count = 0; - -bool unitemp_spi_sensor_alloc(Sensor* sensor, char* args) { - if(args == NULL) return false; - - //Создание инстанса датчика SPI - SPISensor* instance = malloc(sizeof(SPISensor)); - if(instance == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name); - return false; - } - sensor->instance = instance; - - //Определение GPIO chip select - int gpio = 255; - sscanf(args, "%d", &gpio); - instance->CS_pin = unitemp_gpio_getFromInt(gpio); - if(instance->CS_pin == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s GPIO setting error", sensor->name); - free(instance); - return false; - } - - instance->spi = malloc(sizeof(FuriHalSpiBusHandle)); - memcpy(instance->spi, &furi_hal_spi_bus_handle_external, sizeof(FuriHalSpiBusHandle)); - - instance->spi->cs = instance->CS_pin->pin; - - bool status = sensor->type->allocator(sensor, args); - - //Блокировка портов GPIO - sensors_count++; - unitemp_gpio_lock(unitemp_gpio_getFromInt(2), &SPI); - unitemp_gpio_lock(unitemp_gpio_getFromInt(3), &SPI); - unitemp_gpio_lock(unitemp_gpio_getFromInt(5), &SPI); - unitemp_gpio_lock(instance->CS_pin, &SPI); - return status; -} - -bool unitemp_spi_sensor_free(Sensor* sensor) { - bool status = sensor->type->mem_releaser(sensor); - unitemp_gpio_unlock(((SPISensor*)sensor->instance)->CS_pin); - free(((SPISensor*)(sensor->instance))->spi); - free(sensor->instance); - - if(--sensors_count == 0) { - unitemp_gpio_unlock(unitemp_gpio_getFromInt(2)); - unitemp_gpio_unlock(unitemp_gpio_getFromInt(3)); - unitemp_gpio_unlock(unitemp_gpio_getFromInt(5)); - } - - return status; -} - -bool unitemp_spi_sensor_init(Sensor* sensor) { - return sensor->type->initializer(sensor); -} - -bool unitemp_spi_sensor_deinit(Sensor* sensor) { - UNUSED(sensor); - - return true; -} - -UnitempStatus unitemp_spi_sensor_update(Sensor* sensor) { - return sensor->type->updater(sensor); -} \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/SPISensor.h b/applications/external/unitemp/interfaces/SPISensor.h deleted file mode 100644 index 40f284b04..000000000 --- a/applications/external/unitemp/interfaces/SPISensor.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SPI -#define UNITEMP_SPI - -#include "../unitemp.h" -#include - -//Структура SPI датчика -typedef struct SPISensor { - //Указатель на интерфейс SPI - FuriHalSpiBusHandle* spi; - //Порт подключения CS - const GPIO* CS_pin; -} SPISensor; - -/** - * @brief Выделение памяти для датчика с интерфейсом SPI - * @param sensor Указатель на датчик - * @param args Указатель на массив аргументов с параметрами датчика - * @return Истина если всё ок - */ -bool unitemp_spi_sensor_alloc(Sensor* sensor, char* args); - -/** - * @brief Высвобождение памяти инстанса датчика - * @param sensor Указатель на датчик - */ -bool unitemp_spi_sensor_free(Sensor* sensor); - -/** - * @brief Инициализации датчика с интерфейсом one wire - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_spi_sensor_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_spi_sensor_deinit(Sensor* sensor); - -/** - * @brief Обновить значение с датчка - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_spi_sensor_update(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/SingleWireSensor.c b/applications/external/unitemp/interfaces/SingleWireSensor.c deleted file mode 100644 index d6d1b092b..000000000 --- a/applications/external/unitemp/interfaces/SingleWireSensor.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "SingleWireSensor.h" - -//Максимальное количество попугаев ожидания датчика -#define POLLING_TIMEOUT_TICKS 500 - -/* Типы датчиков и их параметры */ -const SensorType DHT11 = { - .typename = "DHT11", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 2000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; -const SensorType DHT12_SW = { - .typename = "DHT12", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 2000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; -const SensorType DHT21 = { - .typename = "DHT21", - .altname = "DHT21/AM2301", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 1000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; -const SensorType DHT22 = { - .typename = "DHT22", - .altname = "DHT22/AM2302", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 2000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; -const SensorType AM2320_SW = { - .typename = "AM2320", - .altname = "AM2320 (single wire)", - .interface = &SINGLE_WIRE, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 2000, - .allocator = unitemp_singlewire_alloc, - .mem_releaser = unitemp_singlewire_free, - .initializer = unitemp_singlewire_init, - .deinitializer = unitemp_singlewire_deinit, - .updater = unitemp_singlewire_update}; - -bool unitemp_singlewire_alloc(Sensor* sensor, char* args) { - if(args == NULL) return false; - SingleWireSensor* instance = malloc(sizeof(SingleWireSensor)); - if(instance == NULL) { - FURI_LOG_E(APP_NAME, "Sensor %s instance allocation error", sensor->name); - return false; - } - sensor->instance = instance; - - int gpio = 255; - sscanf(args, "%d", &gpio); - - if(unitemp_singlewire_sensorSetGPIO(sensor, unitemp_gpio_getFromInt(gpio))) { - return true; - } - FURI_LOG_E(APP_NAME, "Sensor %s GPIO setting error", sensor->name); - free(instance); - return false; -} -bool unitemp_singlewire_free(Sensor* sensor) { - free(sensor->instance); - - return true; -} - -bool unitemp_singlewire_init(Sensor* sensor) { - SingleWireSensor* instance = ((Sensor*)sensor)->instance; - if(instance == NULL || instance->gpio == NULL) { - FURI_LOG_E(APP_NAME, "Sensor pointer is null!"); - return false; - } - unitemp_gpio_lock(instance->gpio, &SINGLE_WIRE); - //Высокий уровень по умолчанию - furi_hal_gpio_write(instance->gpio->pin, true); - //Режим работы - OpenDrain, подтяжка включается на всякий случай - furi_hal_gpio_init( - instance->gpio->pin, //Порт FZ - GpioModeOutputOpenDrain, //Режим работы - открытый сток - GpioPullUp, //Принудительная подтяжка линии данных к питанию - GpioSpeedVeryHigh); //Скорость работы - максимальная - return true; -} - -bool unitemp_singlewire_deinit(Sensor* sensor) { - SingleWireSensor* instance = ((Sensor*)sensor)->instance; - if(instance == NULL || instance->gpio == NULL) return false; - unitemp_gpio_unlock(instance->gpio); - //Низкий уровень по умолчанию - furi_hal_gpio_write(instance->gpio->pin, false); - //Режим работы - аналог, подтяжка выключена - furi_hal_gpio_init( - instance->gpio->pin, //Порт FZ - GpioModeAnalog, //Режим работы - аналог - GpioPullNo, //Подтяжка выключена - GpioSpeedLow); //Скорость работы - минимальная - return true; -} - -bool unitemp_singlewire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio) { - if(sensor == NULL || gpio == NULL) return false; - SingleWireSensor* instance = sensor->instance; - instance->gpio = gpio; - return true; -} -const GPIO* unitemp_singlewire_sensorGetGPIO(Sensor* sensor) { - if(sensor == NULL) return NULL; - SingleWireSensor* instance = sensor->instance; - return instance->gpio; -} - -UnitempStatus unitemp_singlewire_update(Sensor* sensor) { - SingleWireSensor* instance = sensor->instance; - - //Массив для приёма данных - uint8_t data[5] = {0}; - - /* Запрос */ - //Опускание линии - furi_hal_gpio_write(instance->gpio->pin, false); - //Ожидание более 18 мс - furi_delay_ms(19); - //Выключение прерываний, чтобы ничто не мешало обработке данных - __disable_irq(); - //Подъём линии - furi_hal_gpio_write(instance->gpio->pin, true); - - /* Ответ датчика */ - //Переменная-счётчик - uint16_t timeout = 0; - - //Ожидание подъёма линии - while(!furi_hal_gpio_read(instance->gpio->pin)) { - timeout++; - if(timeout > POLLING_TIMEOUT_TICKS) { - //Включение прерываний - __enable_irq(); - //Возврат признака отсутствующего датчика - return UT_SENSORSTATUS_TIMEOUT; - } - } - timeout = 0; - - //Ожидание спада линии - while(furi_hal_gpio_read(instance->gpio->pin)) { - timeout++; - if(timeout > POLLING_TIMEOUT_TICKS) { - //Включение прерываний - __enable_irq(); - //Возврат признака отсутствующего датчика - return UT_SENSORSTATUS_TIMEOUT; - } - } - - //Ожидание подъёма линии - while(!furi_hal_gpio_read(instance->gpio->pin)) { - timeout++; - if(timeout > POLLING_TIMEOUT_TICKS) { - //Включение прерываний - __enable_irq(); - //Возврат признака отсутствующего датчика - return UT_SENSORSTATUS_TIMEOUT; - } - } - timeout = 0; - - //Ожидание спада линии - while(furi_hal_gpio_read(instance->gpio->pin)) { - timeout++; - if(timeout > POLLING_TIMEOUT_TICKS) { - //Включение прерываний - __enable_irq(); - //Возврат признака отсутствующего датчика - return UT_SENSORSTATUS_TIMEOUT; - } - } - - /* Чтение данных с датчика*/ - //Приём 5 байт - for(uint8_t a = 0; a < 5; a++) { - for(uint8_t b = 7; b != 255; b--) { - uint16_t hT = 0, lT = 0; - //Пока линия в низком уровне, инкремент переменной lT - while(!furi_hal_gpio_read(instance->gpio->pin) && lT != 65535) lT++; - //Пока линия в высоком уровне, инкремент переменной hT - while(furi_hal_gpio_read(instance->gpio->pin) && hT != 65535) hT++; - //Если hT больше lT, то пришла единица - if(hT > lT) data[a] |= (1 << b); - } - } - //Включение прерываний - __enable_irq(); - - //Проверка контрольной суммы - if((uint8_t)(data[0] + data[1] + data[2] + data[3]) != data[4]) { - //Если контрольная сумма не совпала, возврат ошибки - return UT_SENSORSTATUS_BADCRC; - } - - /* Преобразование данных в явный вид */ - //DHT11 и DHT12 - if(sensor->type == &DHT11 || sensor->type == &DHT12_SW) { - sensor->hum = (float)data[0]; - sensor->temp = (float)data[2]; - - //Проверка на отрицательность температуры - if(data[3] != 0) { - //Проверка знака - if(!(data[3] & (1 << 7))) { - //Добавление положительной дробной части - sensor->temp += data[3] * 0.1f; - } else { - //А тут делаем отрицательное значение - data[3] &= ~(1 << 7); - sensor->temp += data[3] * 0.1f; - sensor->temp *= -1; - } - } - } - - //DHT21, DHT22, AM2320 - if(sensor->type == &DHT21 || sensor->type == &DHT22 || sensor->type == &AM2320_SW) { - sensor->hum = (float)(((uint16_t)data[0] << 8) | data[1]) / 10; - - uint16_t raw = (((uint16_t)data[2] << 8) | data[3]); - //Проверка на отрицательность температуры - if(READ_BIT(raw, 1 << 15)) { - //Проверка на способ кодирования данных - if(READ_BIT(raw, 0x6000)) { - //Не оригинал - sensor->temp = (float)((int16_t)raw) / 10; - } else { - //Оригинальный датчик - CLEAR_BIT(raw, 1 << 15); - sensor->temp = (float)(raw) / -10; - } - } else { - sensor->temp = (float)(raw) / 10; - } - } - //Возврат признака успешного опроса - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/interfaces/SingleWireSensor.h b/applications/external/unitemp/interfaces/SingleWireSensor.h deleted file mode 100644 index c762ff0aa..000000000 --- a/applications/external/unitemp/interfaces/SingleWireSensor.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SINGLE_WIRE -#define UNITEMP_SINGLE_WIRE - -#include "../unitemp.h" -#include "../Sensors.h" - -//Интерфейс Single Wire -typedef struct { - //Порт подключения датчика - const GPIO* gpio; -} SingleWireSensor; - -/* Датчики */ -extern const SensorType DHT11; -extern const SensorType DHT12_SW; -extern const SensorType DHT21; -extern const SensorType DHT22; -extern const SensorType AM2320_SW; - -/** - * @brief Инициализация датчика - * - * @param sensor Указатель на инициализируемый датчик - * @return Истина если всё прошло успешно - */ -bool unitemp_singlewire_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на инициализируемый датчик - * @return Истина если всё прошло успешно - */ -bool unitemp_singlewire_deinit(Sensor* sensor); - -/** - * @brief Получение данных с датчика по однопроводному интерфейсу DHTxx и AM2xxx - * - * @param sensor Указатель на датчик - * @return Статус опроса - */ -UnitempStatus unitemp_singlewire_update(Sensor* sensor); - -/** - * @brief Установить порт датчика - * - * @param sensor Указатель на датчик - * @param gpio Устанавливаемый порт - * @return Истина если всё ок - */ -bool unitemp_singlewire_sensorSetGPIO(Sensor* sensor, const GPIO* gpio); - -/** - * @brief Получить порт датчика - * - * @param sensor Указатель на датчик - * @return Указатель на GPIO - */ -const GPIO* unitemp_singlewire_sensorGetGPIO(Sensor* sensor); - -/** - * @brief Выделение памяти под датчик на линии One Wire - * - * @param sensor Указатель на датчик - * @param args Указатель на массив с аргументами параметров датчка - */ -bool unitemp_singlewire_alloc(Sensor* sensor, char* args); - -/** - * @brief Высвобождение памяти инстанса датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_singlewire_free(Sensor* sensor); -#endif \ No newline at end of file diff --git a/applications/external/unitemp/interfaces/endianness.h b/applications/external/unitemp/interfaces/endianness.h deleted file mode 100644 index c4a3f4b87..000000000 --- a/applications/external/unitemp/interfaces/endianness.h +++ /dev/null @@ -1,60 +0,0 @@ -// -// Created by Avilov Vasily on 10.06.2023. -// - -#ifndef FLIPPERZERO_FIRMWARE_ENDIANNESS_H -#define FLIPPERZERO_FIRMWARE_ENDIANNESS_H - -inline static void store16(uint8_t* b, uint16_t i) { - memcpy(b, &i, 2); -} - -inline static void store32(uint8_t* b, uint32_t i) { - memcpy(b, &i, 4); -} - -inline static uint16_t load16(uint8_t* b) { - uint16_t x; - memcpy(&x, b, 2); - return x; -} - -inline static uint32_t load32(uint8_t* b) { - uint32_t x; - memcpy(&x, b, 4); - return x; -} - -#if BYTE_ORDER == BIG_ENDIAN -#define htobe16(x) (x) -#define htobe32(x) (x) -#define htole16(x) __builtin_bswap16(x) -#define htole32(x) __builtin_bswap32(x) -#define be16toh(x) (x) -#define be32toh(x) (x) -#define le16toh(x) __builtin_bswap16(x) -#define le32toh(x) __builtin_bswap32(x) -#elif BYTE_ORDER == LITTLE_ENDIAN -#define htobe16(x) __builtin_bswap16(x) -#define htobe32(x) __builtin_bswap32(x) -#define htole16(x) (x) -#define htole32(x) (x) -#define be16toh(x) __builtin_bswap16(x) -#define be32toh(x) __builtin_bswap32(x) -#define le16toh(x) (x) -#define le32toh(x) (x) -#else -#error "What kind of system is this?" -#endif - -#define load16_le(b) (le16toh(load16(b))) -#define load32_le(b) (le32toh(load32(b))) -#define store16_le(b, i) (store16(b, htole16(i))) -#define store32_le(b, i) (store32(b, htole32(i))) - -#define load16_be(b) (be16toh(load16(b))) -#define load32_be(b) (be32toh(load32(b))) -#define store16_be(b, i) (store16(b, htobe16(i))) -#define store32_be(b, i) (store32(b, htobe32(i))) - -#endif //FLIPPERZERO_FIRMWARE_ENDIANNESS_H diff --git a/applications/external/unitemp/sensors/AM2320.c b/applications/external/unitemp/sensors/AM2320.c deleted file mode 100644 index 29b255e1d..000000000 --- a/applications/external/unitemp/sensors/AM2320.c +++ /dev/null @@ -1,106 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "AM2320.h" -#include "../interfaces/I2CSensor.h" - -const SensorType AM2320_I2C = { - .typename = "AM2320_I2C", - .altname = "AM2320 (I2C)", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 2000, - .allocator = unitemp_AM2320_I2C_alloc, - .mem_releaser = unitemp_AM2320_I2C_free, - .initializer = unitemp_AM2320_init, - .deinitializer = unitemp_AM2320_I2C_deinit, - .updater = unitemp_AM2320_I2C_update}; - -static uint16_t AM2320_calc_CRC(uint8_t* ptr, uint8_t len) { - uint16_t crc = 0xFFFF; - uint8_t i; - while(len--) { - crc ^= *ptr++; - for(i = 0; i < 8; i++) { - if(crc & 0x01) { - crc >>= 1; - crc ^= 0xA001; - } else { - crc >>= 1; - } - } - } - return crc; -} - -bool unitemp_AM2320_I2C_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x5C << 1; - i2c_sensor->maxI2CAdr = 0x5C << 1; - return true; -} - -bool unitemp_AM2320_I2C_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_AM2320_init(Sensor* sensor) { - //Нечего инициализировать - UNUSED(sensor); - return true; -} - -bool unitemp_AM2320_I2C_deinit(Sensor* sensor) { - //Нечего деинициализировать - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_AM2320_I2C_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t data[8] = {0x03, 0x00, 0x04}; - - //Wake up - unitemp_i2c_isDeviceReady(i2c_sensor); - furi_delay_ms(1); - - //Запрос - if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(2); - //Ответ - if(!unitemp_i2c_readArray(i2c_sensor, 8, data)) return UT_SENSORSTATUS_TIMEOUT; - - if(AM2320_calc_CRC(data, 6) != ((data[7] << 8) | data[6])) { - return UT_SENSORSTATUS_BADCRC; - } - - sensor->hum = (float)(((uint16_t)data[2] << 8) | data[3]) / 10; - //Проверка на отрицательность температуры - if(!(data[4] & (1 << 7))) { - sensor->temp = (float)(((uint16_t)data[4] << 8) | data[5]) / 10; - } else { - data[4] &= ~(1 << 7); - sensor->temp = (float)(((uint16_t)data[4] << 8) | data[5]) / -10; - } - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/AM2320.h b/applications/external/unitemp/sensors/AM2320.h deleted file mode 100644 index fa5f502d4..000000000 --- a/applications/external/unitemp/sensors/AM2320.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_AM2320 -#define UNITEMP_AM2320 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType AM2320_I2C; -/** - * @brief Выделение памяти и установка начальных значений датчика AM2320 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_AM2320_I2C_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика AM2320 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_AM2320_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_AM2320_I2C_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_AM2320_I2C_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_AM2320_I2C_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BME680.c b/applications/external/unitemp/sensors/BME680.c deleted file mode 100644 index 397e702cb..000000000 --- a/applications/external/unitemp/sensors/BME680.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by g0gg0 (https://github.com/g3gg0) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "BME680.h" - -const SensorType BME680 = { - .typename = "BME680", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE, - .pollingInterval = 500, - .allocator = unitemp_BME680_alloc, - .mem_releaser = unitemp_BME680_free, - .initializer = unitemp_BME680_init, - .deinitializer = unitemp_BME680_deinit, - .updater = unitemp_BME680_update}; - -//Интервал обновления калибровочных значений -#define BOSCH_CAL_UPDATE_INTERVAL 60000 - -#define BME680_ID 0x61 - -#define BME680_I2C_ADDR_MIN (0x76 << 1) -#define BME680_I2C_ADDR_MAX (0x77 << 1) - -#define BME680_REG_STATUS 0x1D -#define BME680_REG_CTRL_MEAS 0x74 -#define BME680_REG_CONFIG 0x75 -#define BME680_REG_CTRL_HUM 0x72 -//Преддескретизация температуры -#define BME680_TEMP_OVERSAMPLING_SKIP 0b00000000 -#define BME680_TEMP_OVERSAMPLING_1 0b00100000 -#define BME680_TEMP_OVERSAMPLING_2 0b01000000 -#define BME680_TEMP_OVERSAMPLING_4 0b01100000 -#define BME680_TEMP_OVERSAMPLING_8 0b10000000 -#define BME680_TEMP_OVERSAMPLING_16 0b10100000 -//Преддескретизация давления -#define BME680_PRESS_OVERSAMPLING_SKIP 0b00000000 -#define BME680_PRESS_OVERSAMPLING_1 0b00000100 -#define BME680_PRESS_OVERSAMPLING_2 0b00001000 -#define BME680_PRESS_OVERSAMPLING_4 0b00001100 -#define BME680_PRESS_OVERSAMPLING_8 0b00010000 -#define BME680_PRESS_OVERSAMPLING_16 0b00010100 -//Преддескретизация влажности -#define BME680_HUM_OVERSAMPLING_SKIP 0b00000000 -#define BME680_HUM_OVERSAMPLING_1 0b00000001 -#define BME680_HUM_OVERSAMPLING_2 0b00000010 -#define BME680_HUM_OVERSAMPLING_4 0b00000011 -#define BME680_HUM_OVERSAMPLING_8 0b00000100 -#define BME680_HUM_OVERSAMPLING_16 0b00000101 -//Режимы работы датчика -#define BME680_MODE_SLEEP 0b00000000 //Наелся и спит -#define BME680_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон -//Коэффициент фильтрации значений -#define BME680_FILTER_COEFF_1 0b00000000 -#define BME680_FILTER_COEFF_2 0b00000100 -#define BME680_FILTER_COEFF_4 0b00001000 -#define BME680_FILTER_COEFF_8 0b00001100 -#define BME680_FILTER_COEFF_16 0b00010000 -//Разрешить работу по SPI -#define BME680_SPI_3W_ENABLE 0b00000001 -#define BME680_SPI_3W_DISABLE 0b00000000 - -/* https://github.com/boschsensortec/BME680_driver/blob/master/bme680.c or - https://github.com/boschsensortec/BME68x-Sensor-API */ -static float BME680_compensate_temperature(I2CSensor* i2c_sensor, int32_t temp_adc) { - BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; - float var1 = 0; - float var2 = 0; - float calc_temp = 0; - - /* calculate var1 data */ - var1 = - ((((float)temp_adc / 16384.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 1024.0f)) * - ((float)bme680_instance->temp_cal.dig_T2)); - - /* calculate var2 data */ - var2 = - (((((float)temp_adc / 131072.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 8192.0f)) * - (((float)temp_adc / 131072.0f) - ((float)bme680_instance->temp_cal.dig_T1 / 8192.0f))) * - ((float)bme680_instance->temp_cal.dig_T3 * 16.0f)); - - /* t_fine value*/ - bme680_instance->t_fine = (var1 + var2); - - /* compensated temperature data*/ - calc_temp = ((bme680_instance->t_fine) / 5120.0f); - - return calc_temp; -} - -static float BME680_compensate_pressure(I2CSensor* i2c_sensor, int32_t pres_adc) { - BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; - - float var1; - float var2; - float var3; - float calc_pres; - - var1 = (((float)bme680_instance->t_fine / 2.0f) - 64000.0f); - var2 = var1 * var1 * (((float)bme680_instance->press_cal.dig_P6) / (131072.0f)); - var2 = var2 + (var1 * ((float)bme680_instance->press_cal.dig_P5) * 2.0f); - var2 = (var2 / 4.0f) + (((float)bme680_instance->press_cal.dig_P4) * 65536.0f); - var1 = - (((((float)bme680_instance->press_cal.dig_P3 * var1 * var1) / 16384.0f) + - ((float)bme680_instance->press_cal.dig_P2 * var1)) / - 524288.0f); - var1 = ((1.0f + (var1 / 32768.0f)) * ((float)bme680_instance->press_cal.dig_P1)); - calc_pres = (1048576.0f - ((float)pres_adc)); - - /* Avoid exception caused by division by zero */ - if((int)var1 != 0) { - calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1); - var1 = - (((float)bme680_instance->press_cal.dig_P9) * calc_pres * calc_pres) / 2147483648.0f; - var2 = calc_pres * (((float)bme680_instance->press_cal.dig_P8) / 32768.0f); - var3 = - ((calc_pres / 256.0f) * (calc_pres / 256.0f) * (calc_pres / 256.0f) * - (bme680_instance->press_cal.dig_P10 / 131072.0f)); - calc_pres = - (calc_pres + - (var1 + var2 + var3 + ((float)bme680_instance->press_cal.dig_P7 * 128.0f)) / 16.0f); - } else { - calc_pres = 0; - } - - return calc_pres; -} - -static float BME680_compensate_humidity(I2CSensor* i2c_sensor, int32_t hum_adc) { - BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; - float calc_hum; - float var1; - float var2; - float var3; - float var4; - float temp_comp; - - /* compensated temperature data*/ - temp_comp = ((bme680_instance->t_fine) / 5120.0f); - var1 = - (float)((float)hum_adc) - (((float)bme680_instance->hum_cal.dig_H1 * 16.0f) + - (((float)bme680_instance->hum_cal.dig_H3 / 2.0f) * temp_comp)); - var2 = var1 * - ((float)(((float)bme680_instance->hum_cal.dig_H2 / 262144.0f) * - (1.0f + (((float)bme680_instance->hum_cal.dig_H4 / 16384.0f) * temp_comp) + - (((float)bme680_instance->hum_cal.dig_H5 / 1048576.0f) * temp_comp * temp_comp)))); - var3 = (float)bme680_instance->hum_cal.dig_H6 / 16384.0f; - var4 = (float)bme680_instance->hum_cal.dig_H7 / 2097152.0f; - calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2); - if(calc_hum > 100.0f) { - calc_hum = 100.0f; - } else if(calc_hum < 0.0f) { - calc_hum = 0.0f; - } - - return calc_hum; -} - -/* https://github.com/boschsensortec/BME680_driver/blob/master/bme680_defs.h */ -#define BME680_COEFF_SIZE UINT8_C(41) -#define BME680_COEFF_ADDR1_LEN UINT8_C(25) -#define BME680_COEFF_ADDR2_LEN UINT8_C(16) -#define BME680_COEFF_ADDR1 UINT8_C(0x89) -#define BME680_COEFF_ADDR2 UINT8_C(0xe1) -#define BME680_CONCAT_BYTES(msb, lsb) (((uint16_t)msb << 8) | (uint16_t)lsb) -#define BME680_T2_LSB_REG (1) -#define BME680_T2_MSB_REG (2) -#define BME680_T3_REG (3) -#define BME680_P1_LSB_REG (5) -#define BME680_P1_MSB_REG (6) -#define BME680_P2_LSB_REG (7) -#define BME680_P2_MSB_REG (8) -#define BME680_P3_REG (9) -#define BME680_P4_LSB_REG (11) -#define BME680_P4_MSB_REG (12) -#define BME680_P5_LSB_REG (13) -#define BME680_P5_MSB_REG (14) -#define BME680_P7_REG (15) -#define BME680_P6_REG (16) -#define BME680_P8_LSB_REG (19) -#define BME680_P8_MSB_REG (20) -#define BME680_P9_LSB_REG (21) -#define BME680_P9_MSB_REG (22) -#define BME680_P10_REG (23) -#define BME680_H2_MSB_REG (25) -#define BME680_H2_LSB_REG (26) -#define BME680_H1_LSB_REG (26) -#define BME680_H1_MSB_REG (27) -#define BME680_H3_REG (28) -#define BME680_H4_REG (29) -#define BME680_H5_REG (30) -#define BME680_H6_REG (31) -#define BME680_H7_REG (32) -#define BME680_T1_LSB_REG (33) -#define BME680_T1_MSB_REG (34) -#define BME680_GH2_LSB_REG (35) -#define BME680_GH2_MSB_REG (36) -#define BME680_GH1_REG (37) -#define BME680_GH3_REG (38) -#define BME680_HUM_REG_SHIFT_VAL UINT8_C(4) -#define BME680_BIT_H1_DATA_MSK UINT8_C(0x0F) - -static bool BME680_readCalValues(I2CSensor* i2c_sensor) { - BME680_instance* bme680_instance = (BME680_instance*)i2c_sensor->sensorInstance; - uint8_t coeff_array[BME680_COEFF_SIZE] = {0}; - - if(!unitemp_i2c_readRegArray( - i2c_sensor, BME680_COEFF_ADDR1, BME680_COEFF_ADDR1_LEN, &coeff_array[0])) - return false; - if(!unitemp_i2c_readRegArray( - i2c_sensor, - BME680_COEFF_ADDR2, - BME680_COEFF_ADDR2_LEN, - &coeff_array[BME680_COEFF_ADDR1_LEN])) - return false; - - /* Temperature related coefficients */ - bme680_instance->temp_cal.dig_T1 = (uint16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_T1_MSB_REG], coeff_array[BME680_T1_LSB_REG])); - bme680_instance->temp_cal.dig_T2 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_T2_MSB_REG], coeff_array[BME680_T2_LSB_REG])); - bme680_instance->temp_cal.dig_T3 = (int8_t)(coeff_array[BME680_T3_REG]); - - /* Pressure related coefficients */ - bme680_instance->press_cal.dig_P1 = (uint16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P1_MSB_REG], coeff_array[BME680_P1_LSB_REG])); - bme680_instance->press_cal.dig_P2 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P2_MSB_REG], coeff_array[BME680_P2_LSB_REG])); - bme680_instance->press_cal.dig_P3 = (int8_t)coeff_array[BME680_P3_REG]; - bme680_instance->press_cal.dig_P4 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P4_MSB_REG], coeff_array[BME680_P4_LSB_REG])); - bme680_instance->press_cal.dig_P5 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P5_MSB_REG], coeff_array[BME680_P5_LSB_REG])); - bme680_instance->press_cal.dig_P6 = (int8_t)(coeff_array[BME680_P6_REG]); - bme680_instance->press_cal.dig_P7 = (int8_t)(coeff_array[BME680_P7_REG]); - bme680_instance->press_cal.dig_P8 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P8_MSB_REG], coeff_array[BME680_P8_LSB_REG])); - bme680_instance->press_cal.dig_P9 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_P9_MSB_REG], coeff_array[BME680_P9_LSB_REG])); - bme680_instance->press_cal.dig_P10 = (uint8_t)(coeff_array[BME680_P10_REG]); - - /* Humidity related coefficients */ - bme680_instance->hum_cal.dig_H1 = - (uint16_t)(((uint16_t)coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK)); - bme680_instance->hum_cal.dig_H2 = - (uint16_t)(((uint16_t)coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) | ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL)); - bme680_instance->hum_cal.dig_H3 = (int8_t)coeff_array[BME680_H3_REG]; - bme680_instance->hum_cal.dig_H4 = (int8_t)coeff_array[BME680_H4_REG]; - bme680_instance->hum_cal.dig_H5 = (int8_t)coeff_array[BME680_H5_REG]; - bme680_instance->hum_cal.dig_H6 = (uint8_t)coeff_array[BME680_H6_REG]; - bme680_instance->hum_cal.dig_H7 = (int8_t)coeff_array[BME680_H7_REG]; - - /* Gas heater related coefficients */ - bme680_instance->gas_cal.dig_GH1 = (int8_t)coeff_array[BME680_GH1_REG]; - bme680_instance->gas_cal.dig_GH2 = (int16_t)(BME680_CONCAT_BYTES( - coeff_array[BME680_GH2_MSB_REG], coeff_array[BME680_GH2_LSB_REG])); - bme680_instance->gas_cal.dig_GH3 = (int8_t)coeff_array[BME680_GH3_REG]; - -#ifdef UNITEMP_DEBUG - FURI_LOG_D( - APP_NAME, - "Sensor BME680 T1-T3: %d, %d, %d", - bme680_instance->temp_cal.dig_T1, - bme680_instance->temp_cal.dig_T2, - bme680_instance->temp_cal.dig_T3); - - FURI_LOG_D( - APP_NAME, - "Sensor BME680: P1-P10: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", - bme680_instance->press_cal.dig_P1, - bme680_instance->press_cal.dig_P2, - bme680_instance->press_cal.dig_P3, - bme680_instance->press_cal.dig_P4, - bme680_instance->press_cal.dig_P5, - bme680_instance->press_cal.dig_P6, - bme680_instance->press_cal.dig_P7, - bme680_instance->press_cal.dig_P8, - bme680_instance->press_cal.dig_P9, - bme680_instance->press_cal.dig_P10); - - FURI_LOG_D( - APP_NAME, - "Sensor BME680: H1-H7: %d, %d, %d, %d, %d, %d, %d", - bme680_instance->hum_cal.dig_H1, - bme680_instance->hum_cal.dig_H2, - bme680_instance->hum_cal.dig_H3, - bme680_instance->hum_cal.dig_H4, - bme680_instance->hum_cal.dig_H5, - bme680_instance->hum_cal.dig_H6, - bme680_instance->hum_cal.dig_H7); - - FURI_LOG_D( - APP_NAME, - "Sensor BME680 GH1-GH3: %d, %d, %d", - bme680_instance->gas_cal.dig_GH1, - bme680_instance->gas_cal.dig_GH2, - bme680_instance->gas_cal.dig_GH3); - -#endif - - bme680_instance->last_cal_update_time = furi_get_tick(); - return true; -} -static bool BME680_isMeasuring(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return (bool)(unitemp_i2c_readReg(i2c_sensor, BME680_REG_STATUS) & 0x20); -} - -bool unitemp_BME680_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BME680_instance* bme680_instance = malloc(sizeof(BME680_instance)); - if(bme680_instance == NULL) { - FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name); - return false; - } - - if(sensor->type == &BME680) bme680_instance->chip_id = BME680_ID; - - i2c_sensor->sensorInstance = bme680_instance; - - i2c_sensor->minI2CAdr = BME680_I2C_ADDR_MIN; - i2c_sensor->maxI2CAdr = BME680_I2C_ADDR_MAX; - return true; -} - -bool unitemp_BME680_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перезагрузка - unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6); - //Чтение ID датчика - uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); - if(id != BME680_ID) { - FURI_LOG_E( - APP_NAME, - "Sensor %s returned wrong ID 0x%02X, expected 0x%02X", - sensor->name, - id, - BME680_ID); - return false; - } - - unitemp_i2c_writeReg( - i2c_sensor, - BME680_REG_CTRL_HUM, - (unitemp_i2c_readReg(i2c_sensor, BME680_REG_CTRL_HUM) & ~7) | BME680_HUM_OVERSAMPLING_1); - unitemp_i2c_writeReg( - i2c_sensor, - BME680_REG_CTRL_MEAS, - BME680_TEMP_OVERSAMPLING_2 | BME680_PRESS_OVERSAMPLING_4 | BME680_MODE_FORCED); - //Настройка периода опроса и фильтрации значений - unitemp_i2c_writeReg( - i2c_sensor, BME680_REG_CONFIG, BME680_FILTER_COEFF_16 | BME680_SPI_3W_DISABLE); - //Чтение калибровочных значений - if(!BME680_readCalValues(i2c_sensor)) { - FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name); - return false; - } - return true; -} - -bool unitemp_BME680_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перевод в сон - unitemp_i2c_writeReg(i2c_sensor, BME680_REG_CTRL_MEAS, BME680_MODE_SLEEP); - return true; -} - -UnitempStatus unitemp_BME680_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BME680_instance* instance = i2c_sensor->sensorInstance; - - uint32_t t = furi_get_tick(); - - uint8_t buff[3]; - //Проверка инициализированности датчика - unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff); - if(buff[0] == 0) { - FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - - unitemp_i2c_writeReg( - i2c_sensor, - BME680_REG_CTRL_MEAS, - unitemp_i2c_readReg(i2c_sensor, BME680_REG_CTRL_MEAS) | 1); - - while(BME680_isMeasuring(sensor)) { - if(furi_get_tick() - t > 100) { - return UT_SENSORSTATUS_TIMEOUT; - } - } - - if(furi_get_tick() - instance->last_cal_update_time > BOSCH_CAL_UPDATE_INTERVAL) { - BME680_readCalValues(i2c_sensor); - } - - if(!unitemp_i2c_readRegArray(i2c_sensor, 0x1F, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0x22, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0x25, 2, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_H = ((uint16_t)buff[0] << 8) | buff[1]; - - sensor->temp = BME680_compensate_temperature(i2c_sensor, adc_T); - sensor->pressure = BME680_compensate_pressure(i2c_sensor, adc_P); - sensor->hum = BME680_compensate_humidity(i2c_sensor, adc_H); - - return UT_SENSORSTATUS_OK; -} - -bool unitemp_BME680_free(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - free(i2c_sensor->sensorInstance); - return true; -} \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BME680.h b/applications/external/unitemp/sensors/BME680.h deleted file mode 100644 index dabdaca8e..000000000 --- a/applications/external/unitemp/sensors/BME680.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by g0gg0 (https://github.com/g3gg0) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_BME680 -#define UNITEMP_BME680 - -#include "../unitemp.h" -#include "../Sensors.h" -#include "../interfaces/I2CSensor.h" - -typedef struct { - uint16_t dig_T1; - int16_t dig_T2; - int16_t dig_T3; -} BME680_temp_cal; - -typedef struct { - uint16_t dig_GH1; - int16_t dig_GH2; - int16_t dig_GH3; -} BME680_gas_cal; - -typedef struct { - uint16_t dig_P1; - int16_t dig_P2; - int16_t dig_P3; - int16_t dig_P4; - int16_t dig_P5; - int16_t dig_P6; - int16_t dig_P7; - int16_t dig_P8; - int16_t dig_P9; - int16_t dig_P10; -} BME680_press_cal; - -typedef struct { - uint16_t dig_H1; - uint16_t dig_H2; - int8_t dig_H3; - int8_t dig_H4; - int8_t dig_H5; - uint8_t dig_H6; - int8_t dig_H7; -} BME680_hum_cal; - -typedef struct { - //Калибровочные значения температуры - BME680_temp_cal temp_cal; - //Калибровочные значения давления - BME680_press_cal press_cal; - //Калибровочные значения влажности воздуха - BME680_hum_cal hum_cal; - BME680_gas_cal gas_cal; - //Время последнего обновления калибровочных значений - uint32_t last_cal_update_time; - //Индификатор датчика - uint8_t chip_id; - //Корректировочное значение температуры - int32_t t_fine; -} BME680_instance; - -extern const SensorType BME680; -/** - * @brief Выделение памяти и установка начальных значений датчика BMP680 - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_BME680_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика BMP680 - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_BME680_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_BME680_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_BME680_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * @param sensor Указатель на датчик - */ -bool unitemp_BME680_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BMP180.c b/applications/external/unitemp/sensors/BMP180.c deleted file mode 100644 index 72cff069e..000000000 --- a/applications/external/unitemp/sensors/BMP180.c +++ /dev/null @@ -1,171 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "BMP180.h" -#include "../interfaces/I2CSensor.h" - -typedef struct { - int16_t AC1; - int16_t AC2; - int16_t AC3; - uint16_t AC4; - uint16_t AC5; - uint16_t AC6; - int16_t B1; - int16_t B2; - int16_t MB; - int16_t MC; - int16_t MD; -} BMP180_cal; - -typedef struct { - //Калибровочные значения - BMP180_cal bmp180_cal; -} BMP180_instance; - -const SensorType BMP180 = { - .typename = "BMP180", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_PRESSURE, - .pollingInterval = 1000, - .allocator = unitemp_BMP180_I2C_alloc, - .mem_releaser = unitemp_BMP180_I2C_free, - .initializer = unitemp_BMP180_init, - .deinitializer = unitemp_BMP180_I2C_deinit, - .updater = unitemp_BMP180_I2C_update}; - -bool unitemp_BMP180_I2C_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x77 << 1; - i2c_sensor->maxI2CAdr = 0x77 << 1; - - BMP180_instance* bmx180_instance = malloc(sizeof(BMP180_instance)); - i2c_sensor->sensorInstance = bmx180_instance; - return true; -} - -bool unitemp_BMP180_I2C_free(Sensor* sensor) { - UNUSED(sensor); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - free(i2c_sensor->sensorInstance); - return true; -} - -bool unitemp_BMP180_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Перезагрузка - if(!unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6)) return false; - furi_delay_ms(100); - - //Проверка ID - uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); - if(id != 0x55) { - FURI_LOG_E( - APP_NAME, "Sensor %s returned wrong ID 0x%02X, expected 0x55", sensor->name, id); - return false; - } - - BMP180_instance* bmp180_instance = i2c_sensor->sensorInstance; - - uint8_t buff[22] = {0}; - - //Чтение калибровочных значений - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xAA, 22, buff)) return false; - bmp180_instance->bmp180_cal.AC1 = (buff[0] << 8) | buff[1]; - bmp180_instance->bmp180_cal.AC2 = (buff[2] << 8) | buff[3]; - bmp180_instance->bmp180_cal.AC3 = (buff[4] << 8) | buff[5]; - bmp180_instance->bmp180_cal.AC4 = (buff[6] << 8) | buff[7]; - bmp180_instance->bmp180_cal.AC5 = (buff[8] << 8) | buff[9]; - bmp180_instance->bmp180_cal.AC6 = (buff[10] << 8) | buff[11]; - bmp180_instance->bmp180_cal.B1 = (buff[12] << 8) | buff[13]; - bmp180_instance->bmp180_cal.B2 = (buff[14] << 8) | buff[15]; - bmp180_instance->bmp180_cal.MB = (buff[16] << 8) | buff[17]; - bmp180_instance->bmp180_cal.MC = (buff[18] << 8) | buff[19]; - bmp180_instance->bmp180_cal.MD = (buff[20] << 8) | buff[21]; - - UNITEMP_DEBUG( - "Sensor BMP180 (0x%02X) calibration values: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d", - i2c_sensor->currentI2CAdr, - bmp180_instance->bmp180_cal.AC1, - bmp180_instance->bmp180_cal.AC2, - bmp180_instance->bmp180_cal.AC3, - bmp180_instance->bmp180_cal.AC4, - bmp180_instance->bmp180_cal.AC5, - bmp180_instance->bmp180_cal.AC6, - bmp180_instance->bmp180_cal.B1, - bmp180_instance->bmp180_cal.B2, - bmp180_instance->bmp180_cal.MB, - bmp180_instance->bmp180_cal.MC, - bmp180_instance->bmp180_cal.MD); - return true; -} - -bool unitemp_BMP180_I2C_deinit(Sensor* sensor) { - //Нечего деинициализировать - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_BMP180_I2C_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BMP180_instance* bmp180_instance = i2c_sensor->sensorInstance; - - //Чтение температуры - if(!unitemp_i2c_writeReg(i2c_sensor, 0xF4, 0x2E)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(5); - uint8_t buff[3] = {0}; - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF6, 2, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t UT = ((uint16_t)buff[0] << 8) + buff[1]; - int32_t X1 = (UT - bmp180_instance->bmp180_cal.AC6) * bmp180_instance->bmp180_cal.AC5 >> 15; - int32_t X2 = (bmp180_instance->bmp180_cal.MC << 11) / (X1 + bmp180_instance->bmp180_cal.MD); - int32_t B5 = X1 + X2; - sensor->temp = ((B5 + 8) / 16) * 0.1f; - - //Чтение давления - if(!unitemp_i2c_writeReg(i2c_sensor, 0xF4, 0x34 + (0b11 << 6))) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(26); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF6, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - uint32_t UP = ((buff[0] << 16) + (buff[1] << 8) + buff[2]) >> (8 - 0b11); - - int32_t B6, X3, B3, P; - uint32_t B4, B7; - B6 = B5 - 4000; - X1 = (bmp180_instance->bmp180_cal.B2 * ((B6 * B6) >> 12)) >> 11; - X2 = (bmp180_instance->bmp180_cal.AC2 * B6) >> 11; - X3 = X1 + X2; - B3 = (((bmp180_instance->bmp180_cal.AC1 * 4 + X3) << 0b11) + 2) >> 2; - X1 = (bmp180_instance->bmp180_cal.AC3 * B6) >> 13; - X2 = (bmp180_instance->bmp180_cal.B1 * ((B6 * B6) >> 12)) >> 16; - X3 = ((X1 + X2) + 2) >> 2; - B4 = (bmp180_instance->bmp180_cal.AC4 * (unsigned long)(X3 + 32768)) >> 15; - B7 = ((unsigned long)UP - B3) * (50000 >> 0b11); - if(B7 < 0x80000000) - P = (B7 * 2) / B4; - else - P = (B7 / B4) * 2; - X1 = (P >> 8) * (P >> 8); - X1 = (X1 * 3038) >> 16; - X2 = (-7357 * (P)) >> 16; - P = P + ((X1 + X2 + 3791) >> 4); - sensor->pressure = P; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/BMP180.h b/applications/external/unitemp/sensors/BMP180.h deleted file mode 100644 index ce2569092..000000000 --- a/applications/external/unitemp/sensors/BMP180.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_BMP180 -#define UNITEMP_BMP180 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType BMP180; -/** - * @brief Выделение памяти и установка начальных значений датчика BMP180 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_BMP180_I2C_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика BMP180 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_BMP180_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_BMP180_I2C_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_BMP180_I2C_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_BMP180_I2C_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BMx280.c b/applications/external/unitemp/sensors/BMx280.c deleted file mode 100644 index db445d330..000000000 --- a/applications/external/unitemp/sensors/BMx280.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "BMx280.h" - -const SensorType BMP280 = { - .typename = "BMP280", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_PRESSURE, - .pollingInterval = 500, - .allocator = unitemp_BMx280_alloc, - .mem_releaser = unitemp_BMx280_free, - .initializer = unitemp_BMx280_init, - .deinitializer = unitemp_BMx280_deinit, - .updater = unitemp_BMx280_update}; -const SensorType BME280 = { - .typename = "BME280", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE, - - .pollingInterval = 500, - .allocator = unitemp_BMx280_alloc, - .mem_releaser = unitemp_BMx280_free, - .initializer = unitemp_BMx280_init, - .deinitializer = unitemp_BMx280_deinit, - .updater = unitemp_BMx280_update}; - -//Интервал обновления калибровочных значений -#define BOSCH_CAL_UPDATE_INTERVAL 60000 - -#define TEMP_CAL_START_ADDR 0x88 -#define PRESS_CAL_START_ADDR 0x8E -#define HUM_CAL_H1_ADDR 0xA1 -#define HUM_CAL_H2_ADDR 0xE1 - -#define BMP280_ID 0x58 -#define BME280_ID 0x60 - -#define BMx280_I2C_ADDR_MIN (0x76 << 1) -#define BMx280_I2C_ADDR_MAX (0x77 << 1) - -#define BMx280_REG_STATUS 0xF3 -#define BMx280_REG_CTRL_MEAS 0xF4 -#define BMx280_REG_CONFIG 0xF5 -#define BME280_REG_CTRL_HUM 0xF2 -//Преддескретизация температуры -#define BMx280_TEMP_OVERSAMPLING_SKIP 0b00000000 -#define BMx280_TEMP_OVERSAMPLING_1 0b00100000 -#define BMx280_TEMP_OVERSAMPLING_2 0b01000000 -#define BMx280_TEMP_OVERSAMPLING_4 0b01100000 -#define BMx280_TEMP_OVERSAMPLING_8 0b10000000 -#define BMx280_TEMP_OVERSAMPLING_16 0b10100000 -//Преддескретизация давления -#define BMx280_PRESS_OVERSAMPLING_SKIP 0b00000000 -#define BMx280_PRESS_OVERSAMPLING_1 0b00000100 -#define BMx280_PRESS_OVERSAMPLING_2 0b00001000 -#define BMx280_PRESS_OVERSAMPLING_4 0b00001100 -#define BMx280_PRESS_OVERSAMPLING_8 0b00010000 -#define BMx280_PRESS_OVERSAMPLING_16 0b00010100 -//Преддескретизация влажности -#define BME280_HUM_OVERSAMPLING_SKIP 0b00000000 -#define BME280_HUM_OVERSAMPLING_1 0b00000001 -#define BME280_HUM_OVERSAMPLING_2 0b00000010 -#define BME280_HUM_OVERSAMPLING_4 0b00000011 -#define BME280_HUM_OVERSAMPLING_8 0b00000100 -#define BME280_HUM_OVERSAMPLING_16 0b00000101u -//Режимы работы датчика -#define BMx280_MODE_SLEEP 0b00000000 //Наелся и спит -#define BMx280_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон -#define BMx280_MODE_NORMAL 0b00000011 //Регулярно обновляет значения -//Период обновления в нормальном режиме -#define BMx280_STANDBY_TIME_0_5 0b00000000 -#define BMx280_STANDBY_TIME_62_5 0b00100000 -#define BMx280_STANDBY_TIME_125 0b01000000 -#define BMx280_STANDBY_TIME_250 0b01100000 -#define BMx280_STANDBY_TIME_500 0b10000000 -#define BMx280_STANDBY_TIME_1000 0b10100000 -#define BMx280_STANDBY_TIME_2000 0b11000000 -#define BMx280_STANDBY_TIME_4000 0b11100000 -//Коэффициент фильтрации значений -#define BMx280_FILTER_COEFF_1 0b00000000 -#define BMx280_FILTER_COEFF_2 0b00000100 -#define BMx280_FILTER_COEFF_4 0b00001000 -#define BMx280_FILTER_COEFF_8 0b00001100 -#define BMx280_FILTER_COEFF_16 0b00010000 -//Разрешить работу по SPI -#define BMx280_SPI_3W_ENABLE 0b00000001 -#define BMx280_SPI_3W_DISABLE 0b00000000 - -static float BMx280_compensate_temperature(I2CSensor* i2c_sensor, int32_t adc_T) { - BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; - int32_t var1, var2; - var1 = ((((adc_T >> 3) - ((int32_t)bmx280_instance->temp_cal.dig_T1 << 1))) * - ((int32_t)bmx280_instance->temp_cal.dig_T2)) >> - 11; - var2 = (((((adc_T >> 4) - ((int32_t)bmx280_instance->temp_cal.dig_T1)) * - ((adc_T >> 4) - ((int32_t)bmx280_instance->temp_cal.dig_T1))) >> - 12) * - ((int32_t)bmx280_instance->temp_cal.dig_T3)) >> - 14; - bmx280_instance->t_fine = var1 + var2; - return ((bmx280_instance->t_fine * 5 + 128) >> 8) / 100.0f; -} - -static float BMx280_compensate_pressure(I2CSensor* i2c_sensor, int32_t adc_P) { - BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; - - int32_t var1, var2; - uint32_t p; - var1 = (((int32_t)bmx280_instance->t_fine) >> 1) - (int32_t)64000; - var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t)bmx280_instance->press_cal.dig_P6); - var2 = var2 + ((var1 * ((int32_t)bmx280_instance->press_cal.dig_P5)) << 1); - var2 = (var2 >> 2) + (((int32_t)bmx280_instance->press_cal.dig_P4) << 16); - var1 = (((bmx280_instance->press_cal.dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + - ((((int32_t)bmx280_instance->press_cal.dig_P2) * var1) >> 1)) >> - 18; - var1 = ((((32768 + var1)) * ((int32_t)bmx280_instance->press_cal.dig_P1)) >> 15); - if(var1 == 0) { - return 0; // avoid exception caused by division by zero - } - p = (((uint32_t)(((int32_t)1048576) - adc_P) - (var2 >> 12))) * 3125; - if(p < 0x80000000) { - p = (p << 1) / ((uint32_t)var1); - } else { - p = (p / (uint32_t)var1) * 2; - } - var1 = (((int32_t)bmx280_instance->press_cal.dig_P9) * - ((int32_t)(((p >> 3) * (p >> 3)) >> 13))) >> - 12; - var2 = (((int32_t)(p >> 2)) * ((int32_t)bmx280_instance->press_cal.dig_P8)) >> 13; - p = (uint32_t)((int32_t)p + ((var1 + var2 + bmx280_instance->press_cal.dig_P7) >> 4)); - return p; -} - -static float BMx280_compensate_humidity(I2CSensor* i2c_sensor, int32_t adc_H) { - BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; - int32_t v_x1_u32r; - v_x1_u32r = (bmx280_instance->t_fine - ((int32_t)76800)); - - v_x1_u32r = - (((((adc_H << 14) - (((int32_t)bmx280_instance->hum_cal.dig_H4) << 20) - - (((int32_t)bmx280_instance->hum_cal.dig_H5) * v_x1_u32r)) + - ((int32_t)16384)) >> - 15) * - (((((((v_x1_u32r * ((int32_t)bmx280_instance->hum_cal.dig_H6)) >> 10) * - (((v_x1_u32r * ((int32_t)bmx280_instance->hum_cal.dig_H3)) >> 11) + - ((int32_t)32768))) >> - 10) + - ((int32_t)2097152)) * - ((int32_t)bmx280_instance->hum_cal.dig_H2) + - 8192) >> - 14)); - - v_x1_u32r = - (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * - ((int32_t)bmx280_instance->hum_cal.dig_H1)) >> - 4)); - - v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r); - v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r); - return ((uint32_t)(v_x1_u32r >> 12)) / 1024.0f; -} - -static bool bmx280_readCalValues(I2CSensor* i2c_sensor) { - BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; - if(!unitemp_i2c_readRegArray( - i2c_sensor, TEMP_CAL_START_ADDR, 6, (uint8_t*)&bmx280_instance->temp_cal)) - return false; - - UNITEMP_DEBUG( - "Sensor BMx280 (0x%02X) T1-T3: %d, %d, %d", - i2c_sensor->currentI2CAdr, - bmx280_instance->temp_cal.dig_T1, - bmx280_instance->temp_cal.dig_T2, - bmx280_instance->temp_cal.dig_T3); - - if(!unitemp_i2c_readRegArray( - i2c_sensor, PRESS_CAL_START_ADDR, 18, (uint8_t*)&bmx280_instance->press_cal)) - return false; - - UNITEMP_DEBUG( - "Sensor BMx280 (0x%02X): P1-P9: %d, %d, %d, %d, %d, %d, %d, %d, %d", - i2c_sensor->currentI2CAdr, - bmx280_instance->press_cal.dig_P1, - bmx280_instance->press_cal.dig_P2, - bmx280_instance->press_cal.dig_P3, - bmx280_instance->press_cal.dig_P4, - bmx280_instance->press_cal.dig_P5, - bmx280_instance->press_cal.dig_P6, - bmx280_instance->press_cal.dig_P7, - bmx280_instance->press_cal.dig_P8, - bmx280_instance->press_cal.dig_P9); - - if(bmx280_instance->chip_id == BME280_ID) { - uint8_t buff[7] = {0}; - if(!unitemp_i2c_readRegArray(i2c_sensor, HUM_CAL_H1_ADDR, 1, buff)) return false; - bmx280_instance->hum_cal.dig_H1 = buff[0]; - - if(!unitemp_i2c_readRegArray(i2c_sensor, HUM_CAL_H2_ADDR, 7, buff)) return false; - bmx280_instance->hum_cal.dig_H2 = (uint16_t)(buff[0] | ((uint16_t)buff[1] << 8)); - bmx280_instance->hum_cal.dig_H3 = buff[2]; - bmx280_instance->hum_cal.dig_H4 = ((int16_t)buff[3] << 4) | (buff[4] & 0x0F); - bmx280_instance->hum_cal.dig_H5 = (buff[4] & 0x0F) | ((int16_t)buff[5] << 4); - bmx280_instance->hum_cal.dig_H6 = buff[6]; - - UNITEMP_DEBUG( - "Sensor BMx280 (0x%02X): H1-H6: %d, %d, %d, %d, %d, %d", - i2c_sensor->currentI2CAdr, - bmx280_instance->hum_cal.dig_H1, - bmx280_instance->hum_cal.dig_H2, - bmx280_instance->hum_cal.dig_H3, - bmx280_instance->hum_cal.dig_H4, - bmx280_instance->hum_cal.dig_H5, - bmx280_instance->hum_cal.dig_H6); - } - - bmx280_instance->last_cal_update_time = furi_get_tick(); - return true; -} -static bool bmp280_isMeasuring(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return (bool)((unitemp_i2c_readReg(i2c_sensor, BMx280_REG_STATUS) & 0x08) >> 3); -} - -bool unitemp_BMx280_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BMx280_instance* bmx280_instance = malloc(sizeof(BMx280_instance)); - if(bmx280_instance == NULL) { - FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name); - return false; - } - - if(sensor->type == &BMP280) bmx280_instance->chip_id = BMP280_ID; - if(sensor->type == &BME280) bmx280_instance->chip_id = BME280_ID; - - i2c_sensor->sensorInstance = bmx280_instance; - - i2c_sensor->minI2CAdr = BMx280_I2C_ADDR_MIN; - i2c_sensor->maxI2CAdr = BMx280_I2C_ADDR_MAX; - return true; -} - -bool unitemp_BMx280_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перезагрузка - unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6); - //Чтение ID датчика - uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); - if(id != BMP280_ID && id != BME280_ID) { - FURI_LOG_E( - APP_NAME, - "Sensor %s returned wrong ID 0x%02X, expected 0x%02X or 0x%02X", - sensor->name, - id, - BMP280_ID, - BME280_ID); - return false; - } - - //Настройка режимов работы - if(id == BME280_ID) { - unitemp_i2c_writeReg(i2c_sensor, BME280_REG_CTRL_HUM, BME280_HUM_OVERSAMPLING_1); - unitemp_i2c_writeReg( - i2c_sensor, BME280_REG_CTRL_HUM, unitemp_i2c_readReg(i2c_sensor, BME280_REG_CTRL_HUM)); - } - unitemp_i2c_writeReg( - i2c_sensor, - BMx280_REG_CTRL_MEAS, - BMx280_TEMP_OVERSAMPLING_2 | BMx280_PRESS_OVERSAMPLING_4 | BMx280_MODE_NORMAL); - //Настройка периода опроса и фильтрации значений - unitemp_i2c_writeReg( - i2c_sensor, - BMx280_REG_CONFIG, - BMx280_STANDBY_TIME_500 | BMx280_FILTER_COEFF_16 | BMx280_SPI_3W_DISABLE); - //Чтение калибровочных значений - if(!bmx280_readCalValues(i2c_sensor)) { - FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name); - return false; - } - return true; -} - -bool unitemp_BMx280_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перевод в сон - unitemp_i2c_writeReg(i2c_sensor, BMx280_REG_CTRL_MEAS, BMx280_MODE_SLEEP); - return true; -} - -UnitempStatus unitemp_BMx280_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BMx280_instance* instance = i2c_sensor->sensorInstance; - - uint32_t t = furi_get_tick(); - - uint8_t buff[3]; - //Проверка инициализированности датчика - unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff); - if(buff[0] == 0) { - FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - - while(bmp280_isMeasuring(sensor)) { - if(furi_get_tick() - t > 100) { - return UT_SENSORSTATUS_TIMEOUT; - } - } - - if(furi_get_tick() - instance->last_cal_update_time > BOSCH_CAL_UPDATE_INTERVAL) { - bmx280_readCalValues(i2c_sensor); - } - - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFA, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF7, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFD, 2, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_H = ((uint16_t)buff[0] << 8) | buff[1]; - sensor->temp = BMx280_compensate_temperature(i2c_sensor, adc_T); - sensor->pressure = BMx280_compensate_pressure(i2c_sensor, adc_P); - sensor->hum = BMx280_compensate_humidity(i2c_sensor, adc_H); - return UT_SENSORSTATUS_OK; -} - -bool unitemp_BMx280_free(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - free(i2c_sensor->sensorInstance); - return true; -} \ No newline at end of file diff --git a/applications/external/unitemp/sensors/BMx280.h b/applications/external/unitemp/sensors/BMx280.h deleted file mode 100644 index 32027f285..000000000 --- a/applications/external/unitemp/sensors/BMx280.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_BMx280 -#define UNITEMP_BMx280 - -#include "../unitemp.h" -#include "../Sensors.h" -#include "../interfaces/I2CSensor.h" - -typedef struct { - uint16_t dig_T1; - int16_t dig_T2; - int16_t dig_T3; -} BMx280_temp_cal; - -typedef struct { - uint16_t dig_P1; - int16_t dig_P2; - int16_t dig_P3; - int16_t dig_P4; - int16_t dig_P5; - int16_t dig_P6; - int16_t dig_P7; - int16_t dig_P8; - int16_t dig_P9; -} BMx280_press_cal; - -typedef struct { - uint8_t dig_H1; - int16_t dig_H2; - uint8_t dig_H3; - int16_t dig_H4; - int16_t dig_H5; - int8_t dig_H6; -} BMx280_hum_cal; - -typedef struct { - //Калибровочные значения температуры - BMx280_temp_cal temp_cal; - //Калибровочные значения давления - BMx280_press_cal press_cal; - //Калибровочные значения влажности воздуха - BMx280_hum_cal hum_cal; - //Время последнего обновления калибровочных значений - uint32_t last_cal_update_time; - //Индификатор датчика - uint8_t chip_id; - //Корректировочное значение температуры - int32_t t_fine; -} BMx280_instance; - -extern const SensorType BMP280; -extern const SensorType BME280; -/** - * @brief Выделение памяти и установка начальных значений датчика BMP280 - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_BMx280_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика BMP280 - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_BMx280_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_BMx280_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_BMx280_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * @param sensor Указатель на датчик - */ -bool unitemp_BMx280_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/DHT20.c b/applications/external/unitemp/sensors/DHT20.c deleted file mode 100644 index ce11fe3d6..000000000 --- a/applications/external/unitemp/sensors/DHT20.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "DHT20.h" -#include "../interfaces/I2CSensor.h" - -const SensorType DHT20 = { - .typename = "DHT20", - .altname = "DHT20/AM2108/AHT20", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 1000, - .allocator = unitemp_DHT20_I2C_alloc, - .mem_releaser = unitemp_DHT20_I2C_free, - .initializer = unitemp_DHT20_init, - .deinitializer = unitemp_DHT20_I2C_deinit, - .updater = unitemp_DHT20_I2C_update}; -const SensorType AHT10 = { - .typename = "AHT10", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 1000, - .allocator = unitemp_DHT20_I2C_alloc, - .mem_releaser = unitemp_DHT20_I2C_free, - .initializer = unitemp_DHT20_init, - .deinitializer = unitemp_DHT20_I2C_deinit, - .updater = unitemp_DHT20_I2C_update}; - -static uint8_t DHT20_get_status(I2CSensor* i2c_sensor) { - uint8_t status[1] = {0}; - unitemp_i2c_readArray(i2c_sensor, 1, status); - return status[0]; -} - -static uint8_t DHT20_calc_CRC8(uint8_t* message, uint8_t Num) { - uint8_t i; - uint8_t byte; - uint8_t crc = 0xFF; - for(byte = 0; byte < Num; byte++) { - crc ^= (message[byte]); - for(i = 8; i > 0; --i) { - if(crc & 0x80) - crc = (crc << 1) ^ 0x31; - else - crc = (crc << 1); - } - } - return crc; -} - -static void DHT20_reset_reg(I2CSensor* i2c_sensor, uint8_t addr) { - uint8_t data[3] = {addr, 0x00, 0x00}; - - unitemp_i2c_writeArray(i2c_sensor, 3, data); - - furi_delay_ms(5); - - unitemp_i2c_readArray(i2c_sensor, 3, data); - - furi_delay_ms(10); - - data[0] = 0xB0 | addr; - unitemp_i2c_writeArray(i2c_sensor, 3, data); -} - -bool unitemp_DHT20_I2C_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x38 << 1; - i2c_sensor->maxI2CAdr = (sensor->type == &DHT20) ? (0x38 << 1) : (0x39 << 1); - return true; -} - -bool unitemp_DHT20_I2C_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_DHT20_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t data[3] = {0xA8, 0x00, 0x00}; - if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return false; - furi_delay_ms(10); - data[0] = (sensor->type == &DHT20) ? 0xBE : 0xE1; - data[1] = 0x08; - if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return false; - furi_delay_ms(10); - - return true; -} - -bool unitemp_DHT20_I2C_deinit(Sensor* sensor) { - //Нечего деинициализировать - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_DHT20_I2C_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - if(DHT20_get_status(i2c_sensor) != 0x18) { - DHT20_reset_reg(i2c_sensor, 0x1B); - DHT20_reset_reg(i2c_sensor, 0x1C); - DHT20_reset_reg(i2c_sensor, 0x1E); - } - furi_delay_ms(10); - - uint8_t data[7] = {0xAC, 0x33, 0x00}; - if(!unitemp_i2c_writeArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(80); - uint32_t t = furi_get_tick(); - while(DHT20_get_status(i2c_sensor) == 0x80) { - if(furi_get_tick() - t > 10) return UT_SENSORSTATUS_TIMEOUT; - } - - if(!unitemp_i2c_readArray(i2c_sensor, 7, data)) return UT_SENSORSTATUS_TIMEOUT; - - if(DHT20_calc_CRC8(data, 6) != data[6]) { - return UT_SENSORSTATUS_BADCRC; - } - uint32_t RetuData = 0; - RetuData = (RetuData | data[1]) << 8; - RetuData = (RetuData | data[2]) << 8; - RetuData = (RetuData | data[3]); - RetuData = RetuData >> 4; - sensor->hum = RetuData * 100 * 10 / 1024.0f / 1024.0f / 10.0f; - - RetuData = 0; - RetuData = (RetuData | data[3]) << 8; - RetuData = (RetuData | data[4]) << 8; - RetuData = (RetuData | data[5]); - RetuData = RetuData & 0xfffff; - sensor->temp = (RetuData * 200 * 10.0f / 1024.0f / 1024.0f - 500) / 10.0f; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/DHT20.h b/applications/external/unitemp/sensors/DHT20.h deleted file mode 100644 index 417b0ed1d..000000000 --- a/applications/external/unitemp/sensors/DHT20.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_DHT20 -#define UNITEMP_DHT20 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType DHT20; -extern const SensorType AHT10; -/** - * @brief Выделение памяти и установка начальных значений датчика DHT20 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_DHT20_I2C_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика DHT20 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_DHT20_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_DHT20_I2C_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_DHT20_I2C_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_DHT20_I2C_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/HDC1080.c b/applications/external/unitemp/sensors/HDC1080.c deleted file mode 100644 index 5f2c59b24..000000000 --- a/applications/external/unitemp/sensors/HDC1080.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "HDC1080.h" -#include "../interfaces/I2CSensor.h" - -const SensorType HDC1080 = { - .typename = "HDC1080", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 250, - .allocator = unitemp_HDC1080_alloc, - .mem_releaser = unitemp_HDC1080_free, - .initializer = unitemp_HDC1080_init, - .deinitializer = unitemp_HDC1080_deinit, - .updater = unitemp_HDC1080_update}; - -bool unitemp_HDC1080_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x40 << 1; - i2c_sensor->maxI2CAdr = 0x40 << 1; - return true; -} - -bool unitemp_HDC1080_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_HDC1080_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t data[2]; - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFF, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - uint16_t device_id = ((uint16_t)data[0] << 8) | data[1]; - if(device_id != 0x1050) { - FURI_LOG_E( - APP_NAME, - "Sensor %s returned wrong ID 0x%02X, expected 0x1050", - sensor->name, - device_id); - return false; - } - data[0] = 0b0001000; - data[1] = 0; - //Установка режима работы и разрядности измерений - if(!unitemp_i2c_writeRegArray(i2c_sensor, 0x02, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - - return true; -} - -bool unitemp_HDC1080_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - UNUSED(i2c_sensor); - return true; -} - -UnitempStatus unitemp_HDC1080_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t data[2] = {0}; - //Запуск измерения - if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(10); - if(!unitemp_i2c_readArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - - sensor->temp = ((float)(((uint16_t)data[0] << 8) | data[1]) / 65536) * 165 - 40; - - data[0] = 1; - if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; - furi_delay_ms(10); - if(!unitemp_i2c_readArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - sensor->hum = ((float)(((uint16_t)data[0] << 8) | data[1]) / 65536) * 100; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/HDC1080.h b/applications/external/unitemp/sensors/HDC1080.h deleted file mode 100644 index 59ba0673c..000000000 --- a/applications/external/unitemp/sensors/HDC1080.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_HDC1080 -#define UNITEMP_HDC1080 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType HDC1080; -/** - * @brief Выделение памяти и установка начальных значений датчика HDC1080 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_HDC1080_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика HDC1080 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_HDC1080_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_HDC1080_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_HDC1080_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_HDC1080_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/HTU21x.c b/applications/external/unitemp/sensors/HTU21x.c deleted file mode 100644 index 2e7222bc4..000000000 --- a/applications/external/unitemp/sensors/HTU21x.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "HTU21x.h" -#include "../interfaces/I2CSensor.h" - -const SensorType HTU21x = { - .typename = "HTU21x", - .altname = "HTU21x/SI70xx/SHT2x", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP_HUM, - .pollingInterval = 250, - .allocator = unitemp_HTU21x_alloc, - .mem_releaser = unitemp_HTU21x_free, - .initializer = unitemp_HTU21x_init, - .deinitializer = unitemp_HTU21x_deinit, - .updater = unitemp_HTU21x_update}; - -static uint8_t checkCRC(uint16_t data) { - for(uint8_t i = 0; i < 16; i++) { - if(data & 0x8000) - data = (data << 1) ^ 0x13100; - else - data <<= 1; - } - return (data >> 8); -} - -bool unitemp_HTU21x_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x40 << 1; - i2c_sensor->maxI2CAdr = 0x41 << 1; - return true; -} - -bool unitemp_HTU21x_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_HTU21x_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - UNUSED(i2c_sensor); - return true; -} - -bool unitemp_HTU21x_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - UNUSED(i2c_sensor); - return true; -} - -UnitempStatus unitemp_HTU21x_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Датчик может быть всего один, так что норм - static bool temp_hum = false; - - uint8_t data[3]; - - if(sensor->status == UT_SENSORSTATUS_POLLING) { - if(!unitemp_i2c_readArray(i2c_sensor, 3, data)) return UT_SENSORSTATUS_TIMEOUT; - - uint16_t raw = ((uint16_t)data[0] << 8) | data[1]; - if(checkCRC(raw) != data[2]) return UT_SENSORSTATUS_BADCRC; - - if(temp_hum) { - sensor->temp = (0.002681f * raw - 46.85f); - } else { - sensor->hum = ((0.001907 * (raw ^ 0x02)) - 6); - } - temp_hum = !temp_hum; - if(temp_hum) return UT_SENSORSTATUS_EARLYPOOL; - return UT_SENSORSTATUS_OK; - } - - if(temp_hum) { - //Запрос температуры - data[0] = 0xF3; - if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; - } else { - //Запрос влажности - data[0] = 0xF5; - if(!unitemp_i2c_writeArray(i2c_sensor, 1, data)) return UT_SENSORSTATUS_TIMEOUT; - } - - return UT_SENSORSTATUS_POLLING; -} diff --git a/applications/external/unitemp/sensors/HTU21x.h b/applications/external/unitemp/sensors/HTU21x.h deleted file mode 100644 index ffe062a24..000000000 --- a/applications/external/unitemp/sensors/HTU21x.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_HTU21x -#define UNITEMP_HTU21x - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType HTU21x; -/** - * @brief Выделение памяти и установка начальных значений датчика HTU21x - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_HTU21x_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика HTU21x - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_HTU21x_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_HTU21x_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_HTU21x_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_HTU21x_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/LM75.c b/applications/external/unitemp/sensors/LM75.c deleted file mode 100644 index a9c8df84e..000000000 --- a/applications/external/unitemp/sensors/LM75.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "LM75.h" -#include "../interfaces/I2CSensor.h" - -#define LM75_REG_TEMP 0x00 -#define LM75_REG_CONFIG 0x01 -#define LM75_REG_THYST 0x02 -#define LM75_REG_TOS 0x03 - -#define LM75_CONFIG_SHUTDOWN 0b00000001 -#define LM75_CONFIG_INTERRUPT 0b00000010 -#define LM75_CONFIG_OSPOLARITY_HIGH 0b00000100 -#define LM75_CONFIG_FAULTQUEUE_1 0b00000000 -#define LM75_CONFIG_FAULTQUEUE_2 0b00001000 -#define LM75_CONFIG_FAULTQUEUE_4 0b00010000 -#define LM75_CONFIG_FAULTQUEUE_6 0b00011000 - -const SensorType LM75 = { - .typename = "LM75", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP, - .pollingInterval = 500, - .allocator = unitemp_LM75_alloc, - .mem_releaser = unitemp_LM75_free, - .initializer = unitemp_LM75_init, - .deinitializer = unitemp_LM75_deinit, - .updater = unitemp_LM75_update}; - -bool unitemp_LM75_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0b1001000 << 1; - i2c_sensor->maxI2CAdr = 0b1001111 << 1; - return true; -} - -bool unitemp_LM75_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_LM75_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Выход если не удалось записать значение в датчик - if(!unitemp_i2c_writeReg(i2c_sensor, LM75_REG_CONFIG, LM75_CONFIG_FAULTQUEUE_1)) return false; - - return true; -} - -bool unitemp_LM75_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_writeReg( - i2c_sensor, LM75_REG_CONFIG, LM75_CONFIG_FAULTQUEUE_1 | LM75_CONFIG_SHUTDOWN)) - return false; - return true; -} - -UnitempStatus unitemp_LM75_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - uint8_t buff[2]; - if(!unitemp_i2c_readRegArray(i2c_sensor, LM75_REG_TEMP, 2, buff)) - return UT_SENSORSTATUS_TIMEOUT; - int16_t raw = (((uint16_t)buff[0] << 8) | buff[1]); - sensor->temp = raw / 32 * 0.125; - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/LM75.h b/applications/external/unitemp/sensors/LM75.h deleted file mode 100644 index d5397b178..000000000 --- a/applications/external/unitemp/sensors/LM75.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_LM75 -#define UNITEMP_LM75 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType LM75; -/** - * @brief Выделение памяти и установка начальных значений датчика LM75 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_LM75_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика LM75 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_LM75_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_LM75_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_LM75_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_LM75_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/MAX31855.c b/applications/external/unitemp/sensors/MAX31855.c deleted file mode 100644 index 2411eb09e..000000000 --- a/applications/external/unitemp/sensors/MAX31855.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "MAX31855.h" - -const SensorType MAX31855 = { - .typename = "MAX31855", - .altname = "MAX31855 (Thermocouple)", - .interface = &SPI, - .datatype = UT_TEMPERATURE, - .pollingInterval = 500, - .allocator = unitemp_MAX31855_alloc, - .mem_releaser = unitemp_MAX31855_free, - .initializer = unitemp_MAX31855_init, - .deinitializer = unitemp_MAX31855_deinit, - .updater = unitemp_MAX31855_update}; - -bool unitemp_MAX31855_alloc(Sensor* sensor, char* args) { - UNUSED(sensor); - UNUSED(args); - return true; -} - -bool unitemp_MAX31855_free(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -bool unitemp_MAX31855_init(Sensor* sensor) { - SPISensor* instance = sensor->instance; - furi_hal_spi_bus_handle_init(instance->spi); - UNUSED(instance); - return true; -} - -bool unitemp_MAX31855_deinit(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_MAX31855_update(Sensor* sensor) { - SPISensor* instance = sensor->instance; - - furi_hal_spi_acquire(instance->spi); - furi_hal_gpio_write(instance->CS_pin->pin, false); - - uint8_t buff[4] = {0}; - - furi_hal_spi_bus_rx(instance->spi, buff, 4, 0xFF); - furi_hal_spi_release(instance->spi); - - uint32_t raw = (buff[0] << 24) | (buff[1] << 16) | (buff[2] << 8) | buff[3]; - - if(raw == 0xFFFFFFFF || raw == 0) return UT_SENSORSTATUS_TIMEOUT; - - //Определение состояния термопары - uint8_t state = raw & 0b111; - //Обрыв - if(state == 0x01) { - UNITEMP_DEBUG("%s has thermocouple open circuit", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - //Короткое замыкание к земле - if(state == 0x02) { - UNITEMP_DEBUG("%s has thermocouple short to GND", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - //Короткое замыкание к питанию - if(state == 0x04) { - UNITEMP_DEBUG("%s has thermocouple short to VCC", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - - raw = (raw >> 16) & 0xFFFC; - - sensor->temp = (int16_t)(raw) / 16.0f; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/MAX31855.h b/applications/external/unitemp/sensors/MAX31855.h deleted file mode 100644 index d63c39885..000000000 --- a/applications/external/unitemp/sensors/MAX31855.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_MAX31855 -#define UNITEMP_MAX31855 - -#include "../unitemp.h" -#include "../Sensors.h" -#include "../interfaces/SPISensor.h" - -extern const SensorType MAX31855; - -/** - * @brief Выделение памяти и установка начальных значений датчика MAX31855 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_MAX31855_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика MAX31855 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_MAX31855_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_MAX31855_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_MAX31855_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_MAX31855_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/MAX6675.c b/applications/external/unitemp/sensors/MAX6675.c deleted file mode 100644 index e97a96eb5..000000000 --- a/applications/external/unitemp/sensors/MAX6675.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "MAX6675.h" - -const SensorType MAX6675 = { - .typename = "MAX6675", - .altname = "MAX6675 (Thermocouple)", - .interface = &SPI, - .datatype = UT_TEMPERATURE, - .pollingInterval = 500, - .allocator = unitemp_MAX6675_alloc, - .mem_releaser = unitemp_MAX6675_free, - .initializer = unitemp_MAX6675_init, - .deinitializer = unitemp_MAX6675_deinit, - .updater = unitemp_MAX6675_update}; - -bool unitemp_MAX6675_alloc(Sensor* sensor, char* args) { - UNUSED(sensor); - UNUSED(args); - return true; -} - -bool unitemp_MAX6675_free(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -bool unitemp_MAX6675_init(Sensor* sensor) { - SPISensor* instance = sensor->instance; - furi_hal_spi_bus_handle_init(instance->spi); - UNUSED(instance); - return true; -} - -bool unitemp_MAX6675_deinit(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_MAX6675_update(Sensor* sensor) { - SPISensor* instance = sensor->instance; - - furi_hal_spi_acquire(instance->spi); - furi_hal_gpio_write(instance->CS_pin->pin, false); - - uint8_t buff[2] = {0}; - - furi_hal_spi_bus_rx(instance->spi, buff, 2, 0xFF); - furi_hal_spi_release(instance->spi); - - uint32_t raw = (buff[0] << 8) | buff[1]; - - if(raw == 0xFFFFFFFF || raw == 0) return UT_SENSORSTATUS_TIMEOUT; - - //Определение состояния термопары - uint8_t state = raw & 0b100; - //Обрыв - if(state == 0b100) { - UNITEMP_DEBUG("%s has thermocouple open circuit", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - - sensor->temp = (int16_t)(raw) / 32.0f; - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/MAX6675.h b/applications/external/unitemp/sensors/MAX6675.h deleted file mode 100644 index cce346590..000000000 --- a/applications/external/unitemp/sensors/MAX6675.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_MAX6675 -#define UNITEMP_MAX6675 - -#include "../unitemp.h" -#include "../Sensors.h" -#include "../interfaces/SPISensor.h" - -extern const SensorType MAX6675; - -/** - * @brief Выделение памяти и установка начальных значений датчика MAX6675 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_MAX6675_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика MAX6675 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_MAX6675_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_MAX6675_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_MAX6675_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_MAX6675_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/SCD30.c b/applications/external/unitemp/sensors/SCD30.c deleted file mode 100644 index d7c358055..000000000 --- a/applications/external/unitemp/sensors/SCD30.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by divinebird (https://github.com/divinebird) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -// Some information may be seen on https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library - -#include "SCD30.h" -#include "../interfaces/I2CSensor.h" -#include "../interfaces/endianness.h" -//#include <3rdparty/everest/include/everest/kremlin/c_endianness.h> - -typedef union { - uint16_t array16[2]; - uint8_t array8[4]; - float value; -} ByteToFl; - -const SensorType SCD30 = { - .typename = "SCD30", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP_HUM_CO2, - .pollingInterval = 2000, - .allocator = unitemp_SCD30_alloc, - .mem_releaser = unitemp_SCD30_free, - .initializer = unitemp_SCD30_init, - .deinitializer = unitemp_SCD30_deinit, - .updater = unitemp_SCD30_update}; - -#define SCD30_ID 0x61 - -#define COMMAND_CONTINUOUS_MEASUREMENT 0x0010 -#define COMMAND_SET_MEASUREMENT_INTERVAL 0x4600 -#define COMMAND_GET_DATA_READY 0x0202 -#define COMMAND_READ_MEASUREMENT 0x0300 -#define COMMAND_AUTOMATIC_SELF_CALIBRATION 0x5306 -#define COMMAND_SET_FORCED_RECALIBRATION_FACTOR 0x5204 -#define COMMAND_SET_TEMPERATURE_OFFSET 0x5403 -#define COMMAND_SET_ALTITUDE_COMPENSATION 0x5102 -#define COMMAND_RESET 0xD304 // Soft reset -#define COMMAND_STOP_MEAS 0x0104 -#define COMMAND_READ_FW_VER 0xD100 - -static bool dataAvailable(Sensor* sensor) __attribute__((unused)); -static bool readMeasurement(Sensor* sensor) __attribute__((unused)); -static void reset(Sensor* sensor) __attribute__((unused)); - -static bool setAutoSelfCalibration(Sensor* sensor, bool enable) __attribute__((unused)); -static bool getAutoSelfCalibration(Sensor* sensor) __attribute__((unused)); - -static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) __attribute__((unused)); - -static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration) - __attribute__((unused)); -static uint16_t getAltitudeCompensation(Sensor* sensor) __attribute__((unused)); -static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) __attribute__((unused)); -static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) __attribute__((unused)); - -static float getTemperatureOffset(Sensor* sensor) __attribute__((unused)); -static bool setTemperatureOffset(Sensor* sensor, float tempOffset) __attribute__((unused)); - -static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset) - __attribute__((unused)); -static bool beginMeasuring(Sensor* sensor) __attribute__((unused)); -static bool stopMeasurement(Sensor* sensor) __attribute__((unused)); - -static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) __attribute__((unused)); -static uint16_t getMeasurementInterval(Sensor* sensor) __attribute__((unused)); - -bool unitemp_SCD30_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - i2c_sensor->minI2CAdr = SCD30_ID << 1; - i2c_sensor->maxI2CAdr = SCD30_ID << 1; - return true; -} - -bool unitemp_SCD30_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_SCD30_init(Sensor* sensor) { - if(beginMeasuring(sensor) == true) { // Start continuous measurements - setMeasurementInterval(sensor, SCD30.pollingInterval / 1000); - setAutoSelfCalibration(sensor, true); - setAmbientPressure(sensor, 0); - } else - return false; - - return true; -} - -bool unitemp_SCD30_deinit(Sensor* sensor) { - return stopMeasurement(sensor); -} - -UnitempStatus unitemp_SCD30_update(Sensor* sensor) { - readMeasurement(sensor); - return UT_SENSORSTATUS_OK; -} - -static uint8_t computeCRC8(uint8_t* message, uint8_t len) { - uint8_t crc = 0xFF; // Init with 0xFF - for(uint8_t x = 0; x < len; x++) { - crc ^= message[x]; // XOR-in the next input byte - for(uint8_t i = 0; i < 8; i++) { - if((crc & 0x80) != 0) - crc = (uint8_t)((crc << 1) ^ 0x31); - else - crc <<= 1; - } - } - return crc; // No output reflection -} - -// Sends a command along with arguments and CRC -static bool sendCommandWithCRC(Sensor* sensor, uint16_t command, uint16_t arguments) { - static const uint8_t cmdSize = 5; - - uint8_t bytes[cmdSize]; - uint8_t* pointer = bytes; - store16_be(pointer, command); - pointer += 2; - uint8_t* argPos = pointer; - store16_be(pointer, arguments); - pointer += 2; - *pointer = computeCRC8(argPos, pointer - argPos); - - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes); -} - -// Sends just a command, no arguments, no CRC -static bool sendCommand(Sensor* sensor, uint16_t command) { - static const uint8_t cmdSize = 2; - - uint8_t bytes[cmdSize]; - store16_be(bytes, command); - - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes); -} - -static uint16_t readRegister(Sensor* sensor, uint16_t registerAddress) { - static const uint8_t regSize = 2; - - if(!sendCommand(sensor, registerAddress)) return 0; // Sensor did not ACK - - furi_delay_ms(3); - - uint8_t bytes[regSize]; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, regSize, bytes)) return 0; - - return load16_be(bytes); -} - -static bool loadWord(uint8_t* buff, uint16_t* val) { - uint16_t tmp = load16_be(buff); - uint8_t expectedCRC = computeCRC8(buff, 2); - if(buff[2] != expectedCRC) return false; - *val = tmp; - return true; -} - -static bool getSettingValue(Sensor* sensor, uint16_t registerAddress, uint16_t* val) { - static const uint8_t respSize = 3; - - if(!sendCommand(sensor, registerAddress)) return false; // Sensor did not ACK - - furi_delay_ms(3); - - uint8_t bytes[respSize]; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) return false; - - return loadWord(bytes, val); -} - -static bool loadFloat(uint8_t* buff, float* val) { - // ByteToFl tmp; - size_t cntr = 0; - uint8_t floatBuff[4]; - for(size_t i = 0; i < 2; i++) { - floatBuff[cntr++] = buff[0]; - floatBuff[cntr++] = buff[1]; - uint8_t expectedCRC = computeCRC8(buff, 2); - if(buff[2] != expectedCRC) return false; - buff += 3; - } - uint32_t tmpVal = load32_be(floatBuff); - memcpy(val, &tmpVal, sizeof(float)); - return true; -} - -// Get 18 bytes from SCD30 -// Updates global variables with floats -// Returns true if success -static bool readMeasurement(Sensor* sensor) { - // Verify we have data from the sensor - if(!dataAvailable(sensor)) { - return false; - } - - if(!sendCommand(sensor, COMMAND_READ_MEASUREMENT)) { - FURI_LOG_E(APP_NAME, "Sensor did not ACK"); - return false; // Sensor did not ACK - } - - float tempCO2 = 0; - float tempHumidity = 0; - float tempTemperature = 0; - - furi_delay_ms(3); - - static const uint8_t respSize = 18; - uint8_t buff[respSize]; - uint8_t* bytes = buff; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) { - FURI_LOG_E(APP_NAME, "Error while read measures"); - return false; - } - - bool error = false; - if(loadFloat(bytes, &tempCO2)) { - sensor->co2 = tempCO2; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing CO2"); - error = true; - } - - bytes += 6; - if(loadFloat(bytes, &tempTemperature)) { - sensor->temp = tempTemperature; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing temp"); - error = true; - } - - bytes += 6; - if(loadFloat(bytes, &tempHumidity)) { - sensor->hum = tempHumidity; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing humidity"); - error = true; - } - - return !error; -} - -static void reset(Sensor* sensor) { - sendCommand(sensor, COMMAND_RESET); -} - -static bool setAutoSelfCalibration(Sensor* sensor, bool enable) { - return sendCommandWithCRC( - sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION, enable); // Activate continuous ASC -} - -// Get the current ASC setting -static bool getAutoSelfCalibration(Sensor* sensor) { - return 1 == readRegister(sensor, COMMAND_AUTOMATIC_SELF_CALIBRATION); -} - -static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) { - return getSettingValue(sensor, COMMAND_READ_FW_VER, val); -} - -// Set the forced recalibration factor. See 1.3.7. -// The reference CO2 concentration has to be within the range 400 ppm ≤ cref(CO2) ≤ 2000 ppm. -static bool setForcedRecalibrationFactor(Sensor* sensor, uint16_t concentration) { - if(concentration < 400 || concentration > 2000) { - return false; // Error check. - } - return sendCommandWithCRC(sensor, COMMAND_SET_FORCED_RECALIBRATION_FACTOR, concentration); -} - -// Get the temperature offset. See 1.3.8. -static float getTemperatureOffset(Sensor* sensor) { - union { - int16_t signed16; - uint16_t unsigned16; - } signedUnsigned; // Avoid any ambiguity casting int16_t to uint16_t - signedUnsigned.unsigned16 = readRegister(sensor, COMMAND_SET_TEMPERATURE_OFFSET); - - return ((float)signedUnsigned.signed16) / 100.0; -} - -static bool setTemperatureOffset(Sensor* sensor, float tempOffset) { - // Temp offset is only positive. See: https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/issues/27#issuecomment-971986826 - //"The SCD30 offset temperature is obtained by subtracting the reference temperature from the SCD30 output temperature" - // https://www.sensirion.com/fileadmin/user_upload/customers/sensirion/Dokumente/9.5_CO2/Sensirion_CO2_Sensors_SCD30_Low_Power_Mode.pdf - - if(tempOffset < 0.0) return false; - - uint16_t value = tempOffset * 100; - - return sendCommandWithCRC(sensor, COMMAND_SET_TEMPERATURE_OFFSET, value); -} - -// Get the altitude compenstation. See 1.3.9. -static uint16_t getAltitudeCompensation(Sensor* sensor) { - return readRegister(sensor, COMMAND_SET_ALTITUDE_COMPENSATION); -} - -// Set the altitude compenstation. See 1.3.9. -static bool setAltitudeCompensation(Sensor* sensor, uint16_t altitude) { - return sendCommandWithCRC(sensor, COMMAND_SET_ALTITUDE_COMPENSATION, altitude); -} - -// Set the pressure compenstation. This is passed during measurement startup. -// mbar can be 700 to 1200 -static bool setAmbientPressure(Sensor* sensor, uint16_t pressure_mbar) { - if(pressure_mbar != 0 || pressure_mbar < 700 || pressure_mbar > 1200) { - return false; - } - return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressure_mbar); -} - -// Begins continuous measurements -// Continuous measurement status is saved in non-volatile memory. When the sensor -// is powered down while continuous measurement mode is active SCD30 will measure -// continuously after repowering without sending the measurement command. -// Returns true if successful -static bool beginMeasuringWithSettings(Sensor* sensor, uint16_t pressureOffset) { - return sendCommandWithCRC(sensor, COMMAND_CONTINUOUS_MEASUREMENT, pressureOffset); -} - -// Overload - no pressureOffset -static bool beginMeasuring(Sensor* sensor) { - return beginMeasuringWithSettings(sensor, 0); -} - -// Stop continuous measurement -static bool stopMeasurement(Sensor* sensor) { - return sendCommand(sensor, COMMAND_STOP_MEAS); -} - -// Sets interval between measurements -// 2 seconds to 1800 seconds (30 minutes) -static bool setMeasurementInterval(Sensor* sensor, uint16_t interval) { - if(interval < 2 || interval > 1800) return false; - if(!sendCommandWithCRC(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, interval)) return false; - uint16_t verInterval = readRegister(sensor, COMMAND_SET_MEASUREMENT_INTERVAL); - if(verInterval != interval) { - FURI_LOG_E(APP_NAME, "Measure interval wrong! Val: %02x", verInterval); - return false; - } - return true; -} - -// Gets interval between measurements -// 2 seconds to 1800 seconds (30 minutes) -static uint16_t getMeasurementInterval(Sensor* sensor) { - uint16_t interval = 0; - getSettingValue(sensor, COMMAND_SET_MEASUREMENT_INTERVAL, &interval); - return interval; -} - -// Returns true when data is available -static bool dataAvailable(Sensor* sensor) { - return 1 == readRegister(sensor, COMMAND_GET_DATA_READY); -} \ No newline at end of file diff --git a/applications/external/unitemp/sensors/SCD30.h b/applications/external/unitemp/sensors/SCD30.h deleted file mode 100644 index 1ebfbb411..000000000 --- a/applications/external/unitemp/sensors/SCD30.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by divinebird (https://github.com/divinebird) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SCD30 -#define UNITEMP_SCD30 - -#include "../unitemp.h" -#include "../Sensors.h" - -extern const SensorType SCD30; -/** - * @brief Выделение памяти и установка начальных значений датчика SCD30 - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_SCD30_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика SCD30 - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_SCD30_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_SCD30_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_SCD30_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * @param sensor Указатель на датчик - */ -bool unitemp_SCD30_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/SCD40.c b/applications/external/unitemp/sensors/SCD40.c deleted file mode 100644 index 75c5a3f56..000000000 --- a/applications/external/unitemp/sensors/SCD40.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by divinebird (https://github.com/divinebird) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -// Some information may be seen on https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library - -#include "SCD40.h" -#include "../interfaces/I2CSensor.h" -#include "../interfaces/endianness.h" -//#include <3rdparty/everest/include/everest/kremlin/c_endianness.h> - -const SensorType SCD40 = { - .typename = "SCD40", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP_HUM_CO2, - .pollingInterval = 5000, - .allocator = unitemp_SCD40_alloc, - .mem_releaser = unitemp_SCD40_free, - .initializer = unitemp_SCD40_init, - .deinitializer = unitemp_SCD40_deinit, - .updater = unitemp_SCD40_update}; - -#define SCD40_ID 0x62 - -#define COMMAND_START_PERIODIC_MEASUREMENT 0X21B1 -#define COMMAND_READ_MEASUREMENT 0XEC05 -#define COMMAND_STOP_PERIODIC_MEASUREMENT 0X3F86 - -#define COMMAND_PERSIST_SETTINGS 0X3615 -#define COMMAND_GET_SERIAL_NUMBER 0X3682 -#define COMMAND_PERFORM_SELF_TEST 0X3639 -#define COMMAND_PERFORM_FACTORY_RESET 0X3632 -#define COMMAND_REINIT 0X3646 - -#define COMMAND_SET_TEMPERATURE_OFFSET 0X241D -#define COMMAND_GET_TEMPERATURE_OFFSET 0X2318 -#define COMMAND_SET_SENSOR_ALTITUDE 0X2427 -#define COMMAND_GET_SENSOR_ALTITUDE 0X2322 -#define COMMAND_SET_AMBIENT_PRESSURE 0XE000 -#define COMMAND_PERFORM_FORCED_RECALIBRATION 0X362F -#define COMMAND_SET_AUTOMATIC_SELF_CALIBRATION_ENABLED 0X2416 -#define COMMAND_GET_AUTOMATIC_SELF_CALIBRATION_ENABLED 0X2313 - -static bool readMeasurement(Sensor* sensor) __attribute__((unused)); -static void reset(Sensor* sensor) __attribute__((unused)); - -static bool setAutoSelfCalibration(Sensor* sensor, bool enable) __attribute__((unused)); -static bool getAutoSelfCalibration(Sensor* sensor) __attribute__((unused)); - -static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) __attribute__((unused)); - -static float getTemperatureOffset(Sensor* sensor) __attribute__((unused)); -static bool setTemperatureOffset(Sensor* sensor, float tempOffset) __attribute__((unused)); - -static bool beginMeasuring(Sensor* sensor) __attribute__((unused)); -static bool stopMeasurement(Sensor* sensor) __attribute__((unused)); - -bool unitemp_SCD40_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - i2c_sensor->minI2CAdr = SCD40_ID << 1; - i2c_sensor->maxI2CAdr = SCD40_ID << 1; - return true; -} - -bool unitemp_SCD40_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_SCD40_init(Sensor* sensor) { - return beginMeasuring(sensor); -} - -bool unitemp_SCD40_deinit(Sensor* sensor) { - return stopMeasurement(sensor); -} - -UnitempStatus unitemp_SCD40_update(Sensor* sensor) { - readMeasurement(sensor); - return UT_SENSORSTATUS_OK; -} - -#define CRC8_POLYNOMIAL 0x31 -#define CRC8_INIT 0xFF - -static uint8_t computeCRC8(uint8_t* message, uint8_t len) { - uint8_t crc = CRC8_INIT; // Init with 0xFF - for(uint8_t x = 0; x < len; x++) { - crc ^= message[x]; // XOR-in the next input byte - for(uint8_t i = 0; i < 8; i++) { - if((crc & 0x80) != 0) - crc = (uint8_t)((crc << 1) ^ CRC8_POLYNOMIAL); - else - crc <<= 1; - } - } - return crc; // No output reflection -} - -// Sends a command along with arguments and CRC -static bool sendCommandWithCRC(Sensor* sensor, uint16_t command, uint16_t arguments) { - static const uint8_t cmdSize = 5; - - uint8_t bytes[cmdSize]; - uint8_t* pointer = bytes; - store16_be(pointer, command); - pointer += 2; - uint8_t* argPos = pointer; - store16_be(pointer, arguments); - pointer += 2; - *pointer = computeCRC8(argPos, pointer - argPos); - - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes); -} - -// Sends just a command, no arguments, no CRC -static bool sendCommand(Sensor* sensor, uint16_t command) { - static const uint8_t cmdSize = 2; - - uint8_t bytes[cmdSize]; - store16_be(bytes, command); - - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return unitemp_i2c_writeArray(i2c_sensor, cmdSize, bytes); -} - -static uint16_t readRegister(Sensor* sensor, uint16_t registerAddress) { - static const uint8_t regSize = 2; - - if(!sendCommand(sensor, registerAddress)) return 0; // Sensor did not ACK - - furi_delay_ms(3); - - uint8_t bytes[regSize]; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, regSize, bytes)) return 0; - - return load16_be(bytes); -} - -static bool loadWord(uint8_t* buff, uint16_t* val) { - uint16_t tmp = load16_be(buff); - uint8_t expectedCRC = computeCRC8(buff, 2); - if(buff[2] != expectedCRC) return false; - *val = tmp; - return true; -} - -static bool getSettingValue(Sensor* sensor, uint16_t registerAddress, uint16_t* val) { - static const uint8_t respSize = 3; - - if(!sendCommand(sensor, registerAddress)) return false; // Sensor did not ACK - - furi_delay_ms(3); - - uint8_t bytes[respSize]; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) return false; - - return loadWord(bytes, val); -} - -// Get 18 bytes from SCD40 -// Updates global variables with floats -// Returns true if success -static bool readMeasurement(Sensor* sensor) { - if(!sendCommand(sensor, COMMAND_READ_MEASUREMENT)) { - FURI_LOG_E(APP_NAME, "Sensor did not ACK"); - return false; // Sensor did not ACK - } - - furi_delay_ms(3); - - static const uint8_t respSize = 9; - uint8_t buff[respSize]; - uint8_t* bytes = buff; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) { - FURI_LOG_E(APP_NAME, "Error while read measures"); - return false; - } - - uint16_t tmpValue; - - bool error = false; - if(loadWord(bytes, &tmpValue)) { - sensor->co2 = tmpValue; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing CO2"); - error = true; - } - - bytes += 3; - if(loadWord(bytes, &tmpValue)) { - sensor->temp = (float)tmpValue * 175.0f / 65535.0f - 45.0f; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing temp"); - error = true; - } - - bytes += 3; - if(loadWord(bytes, &tmpValue)) { - sensor->hum = (float)tmpValue * 100.0f / 65535.0f; - } else { - FURI_LOG_E(APP_NAME, "Error while parsing humidity"); - error = true; - } - - return !error; -} - -static void reset(Sensor* sensor) { - sendCommand(sensor, COMMAND_REINIT); -} - -static bool setAutoSelfCalibration(Sensor* sensor, bool enable) { - return sendCommandWithCRC( - sensor, COMMAND_SET_AUTOMATIC_SELF_CALIBRATION_ENABLED, enable); // Activate continuous ASC -} - -// Get the current ASC setting -static bool getAutoSelfCalibration(Sensor* sensor) { - return 1 == readRegister(sensor, COMMAND_GET_AUTOMATIC_SELF_CALIBRATION_ENABLED); -} - -// Unfinished -static bool getFirmwareVersion(Sensor* sensor, uint16_t* val) { - if(!sendCommand(sensor, COMMAND_READ_MEASUREMENT)) { - FURI_LOG_E(APP_NAME, "Sensor did not ACK"); - return false; // Sensor did not ACK - } - - static const uint8_t respSize = 9; - uint8_t buff[respSize]; - uint8_t* bytes = buff; - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - if(!unitemp_i2c_readArray(i2c_sensor, respSize, bytes)) { - FURI_LOG_E(APP_NAME, "Error while read measures"); - return false; - } - - *val = 0; - - return true; -} - -static bool beginMeasuring(Sensor* sensor) { - return sendCommand(sensor, COMMAND_START_PERIODIC_MEASUREMENT); -} - -// Stop continuous measurement -static bool stopMeasurement(Sensor* sensor) { - return sendCommand(sensor, COMMAND_READ_MEASUREMENT); -} - -static float getTemperatureOffset(Sensor* sensor) { - uint16_t curOffset; - if(!getSettingValue(sensor, COMMAND_GET_TEMPERATURE_OFFSET, &curOffset)) return 0.0; - return (float)curOffset * 175.0f / 65536.0f; -} - -static bool setTemperatureOffset(Sensor* sensor, float tempOffset) { - uint16_t newOffset = tempOffset * 65536.0 / 175.0 + 0.5f; - return sendCommandWithCRC( - sensor, COMMAND_SET_TEMPERATURE_OFFSET, newOffset); // Activate continuous ASC -} diff --git a/applications/external/unitemp/sensors/SCD40.h b/applications/external/unitemp/sensors/SCD40.h deleted file mode 100644 index 5cf7a4324..000000000 --- a/applications/external/unitemp/sensors/SCD40.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - Contributed by divinebird (https://github.com/divinebird) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SCD40 -#define UNITEMP_SCD40 - -#include "../unitemp.h" -#include "../Sensors.h" - -extern const SensorType SCD40; -/** - * @brief Выделение памяти и установка начальных значений датчика SCD40 - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_SCD40_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика SCD40 - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_SCD40_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * @param sensor Указатель на датчик - */ -bool unitemp_SCD40_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * @param sensor Указатель на датчик - * @return Статус опроса датчика - */ -UnitempStatus unitemp_SCD40_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * @param sensor Указатель на датчик - */ -bool unitemp_SCD40_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/SHT30.c b/applications/external/unitemp/sensors/SHT30.c deleted file mode 100644 index dd43e80af..000000000 --- a/applications/external/unitemp/sensors/SHT30.c +++ /dev/null @@ -1,90 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "SHT30.h" -#include "../interfaces/I2CSensor.h" - -const SensorType SHT30 = { - .typename = "SHT30", - .altname = "SHT30/31/35", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 1000, - .allocator = unitemp_SHT30_I2C_alloc, - .mem_releaser = unitemp_SHT30_I2C_free, - .initializer = unitemp_SHT30_init, - .deinitializer = unitemp_SHT30_I2C_deinit, - .updater = unitemp_SHT30_I2C_update}; -const SensorType GXHT30 = { - .typename = "GXHT30", - .altname = "GXHT30/31/35", - .interface = &I2C, - .datatype = UT_TEMPERATURE | UT_HUMIDITY, - .pollingInterval = 1000, - .allocator = unitemp_SHT30_I2C_alloc, - .mem_releaser = unitemp_SHT30_I2C_free, - .initializer = unitemp_GXHT30_init, - .deinitializer = unitemp_SHT30_I2C_deinit, - .updater = unitemp_SHT30_I2C_update}; - -bool unitemp_SHT30_I2C_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - - //Адреса на шине I2C (7 бит) - i2c_sensor->minI2CAdr = 0x44 << 1; - i2c_sensor->maxI2CAdr = 0x45 << 1; - return true; -} - -bool unitemp_SHT30_I2C_free(Sensor* sensor) { - //Нечего высвобождать, так как ничего не было выделено - UNUSED(sensor); - return true; -} - -bool unitemp_SHT30_init(Sensor* sensor) { - UNUSED(sensor); - return true; -} - -bool unitemp_GXHT30_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Включение режима автоматического преобразования 2 раза в сек - uint8_t data[2] = {0x22, 0x36}; - if(!unitemp_i2c_writeArray(i2c_sensor, 2, data)) return false; - return true; -} - -bool unitemp_SHT30_I2C_deinit(Sensor* sensor) { - //Нечего деинициализировать - UNUSED(sensor); - return true; -} - -UnitempStatus unitemp_SHT30_I2C_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Получение данных - uint8_t data[6] = {0xE0, 0x00}; - if(!unitemp_i2c_writeArray(i2c_sensor, 2, data)) return UT_SENSORSTATUS_TIMEOUT; - if(!unitemp_i2c_readArray(i2c_sensor, 6, data)) return UT_SENSORSTATUS_TIMEOUT; - - sensor->temp = -45 + 175 * (((uint16_t)(data[0] << 8) | data[1]) / 65535.0f); - sensor->hum = 100 * (((uint16_t)(data[3] << 8) | data[4]) / 65535.0f); - - return UT_SENSORSTATUS_OK; -} diff --git a/applications/external/unitemp/sensors/SHT30.h b/applications/external/unitemp/sensors/SHT30.h deleted file mode 100644 index 4b5b74411..000000000 --- a/applications/external/unitemp/sensors/SHT30.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SHT30 -#define UNITEMP_SHT30 - -#include "../unitemp.h" -#include "../Sensors.h" -extern const SensorType SHT30; -extern const SensorType GXHT30; -/** - * @brief Выделение памяти и установка начальных значений датчика SHT30 - * - * @param sensor Указатель на создаваемый датчик - * @return Истина при успехе - */ -bool unitemp_SHT30_I2C_alloc(Sensor* sensor, char* args); - -/** - * @brief Инициализации датчика SHT30 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_SHT30_init(Sensor* sensor); -/** - * @brief Инициализации датчика GXHT30 - * - * @param sensor Указатель на датчик - * @return Истина если инициализация упспешная - */ -bool unitemp_GXHT30_init(Sensor* sensor); - -/** - * @brief Деинициализация датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_SHT30_I2C_deinit(Sensor* sensor); - -/** - * @brief Обновление значений из датчика - * - * @param sensor Указатель на датчик - * @return Статус обновления - */ -UnitempStatus unitemp_SHT30_I2C_update(Sensor* sensor); - -/** - * @brief Высвободить память датчика - * - * @param sensor Указатель на датчик - */ -bool unitemp_SHT30_I2C_free(Sensor* sensor); - -#endif \ No newline at end of file diff --git a/applications/external/unitemp/sensors/Sensors.xlsx b/applications/external/unitemp/sensors/Sensors.xlsx deleted file mode 100644 index c314098a88c2bbc3d75fcc900815cfbdf5bb4772..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12642 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 diff --git a/applications/external/unitemp/unitemp.c b/applications/external/unitemp/unitemp.c deleted file mode 100644 index 9f56d8eef..000000000 --- a/applications/external/unitemp/unitemp.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "unitemp.h" -#include "interfaces/SingleWireSensor.h" -#include "Sensors.h" -#include "./views/UnitempViews.h" - -#include - -/* Переменные */ -//Данные приложения -Unitemp* app; - -void uintemp_celsiumToFarengate(Sensor* sensor) { - sensor->temp = sensor->temp * (9.0 / 5.0) + 32; - sensor->heat_index = sensor->heat_index * (9.0 / 5.0) + 32; -} - -static float heat_index_consts[9] = { - -42.379f, - 2.04901523f, - 10.14333127f, - -0.22475541f, - -0.00683783f, - -0.05481717f, - 0.00122874f, - 0.00085282f, - -0.00000199f}; -void unitemp_calculate_heat_index(Sensor* sensor) { - // temp should be in Celsius, heat index will be in Celsius - float temp = sensor->temp * (9.0 / 5.0) + 32.0f; - float hum = sensor->hum; - sensor->heat_index = - (heat_index_consts[0] + heat_index_consts[1] * temp + heat_index_consts[2] * hum + - heat_index_consts[3] * temp * hum + heat_index_consts[4] * temp * temp + - heat_index_consts[5] * hum * hum + heat_index_consts[6] * temp * temp * hum + - heat_index_consts[7] * temp * hum * hum + heat_index_consts[8] * temp * temp * hum * hum - - 32.0f) * - (5.0 / 9.0); -} -void unitemp_pascalToMmHg(Sensor* sensor) { - sensor->pressure = sensor->pressure * 0.007500638; -} -void unitemp_pascalToKPa(Sensor* sensor) { - sensor->pressure = sensor->pressure / 1000.0f; -} -void unitemp_pascalToHPa(Sensor* sensor) { - sensor->pressure = sensor->pressure / 100.0f; -} -void unitemp_pascalToInHg(Sensor* sensor) { - sensor->pressure = sensor->pressure * 0.0002953007; -} - -bool unitemp_saveSettings(void) { - //Выделение памяти для потока - app->file_stream = file_stream_alloc(app->storage); - - //Переменная пути к файлу - FuriString* filepath = furi_string_alloc(); - //Составление пути к файлу - furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SETTINGS); - //Создание папки плагина - storage_common_mkdir(app->storage, APP_PATH_FOLDER); - //Открытие потока - if(!file_stream_open( - app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_CREATE_ALWAYS)) { - FURI_LOG_E( - APP_NAME, - "An error occurred while saving the settings file: %d", - file_stream_get_error(app->file_stream)); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - - //Сохранение настроек - stream_write_format( - app->file_stream, "INFINITY_BACKLIGHT %d\n", app->settings.infinityBacklight); - stream_write_format(app->file_stream, "TEMP_UNIT %d\n", app->settings.temp_unit); - stream_write_format(app->file_stream, "PRESSURE_UNIT %d\n", app->settings.pressure_unit); - stream_write_format(app->file_stream, "HEAT_INDEX %d\n", app->settings.heat_index); - - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - - FURI_LOG_I(APP_NAME, "Settings have been successfully saved"); - return true; -} - -bool unitemp_loadSettings(void) { - UNITEMP_DEBUG("Loading settings..."); - - //Выделение памяти на поток - app->file_stream = file_stream_alloc(app->storage); - - //Переменная пути к файлу - FuriString* filepath = furi_string_alloc(); - //Составление пути к файлу - furi_string_printf(filepath, "%s/%s", APP_PATH_FOLDER, APP_FILENAME_SETTINGS); - - //Открытие потока к файлу настроек - if(!file_stream_open( - app->file_stream, furi_string_get_cstr(filepath), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) { - //Сохранение настроек по умолчанию в случае отсутствия файла - if(file_stream_get_error(app->file_stream) == FSE_NOT_EXIST) { - FURI_LOG_W(APP_NAME, "Missing settings file. Setting defaults and saving..."); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - //Сохранение стандартного конфига - unitemp_saveSettings(); - return false; - } else { - FURI_LOG_E( - APP_NAME, - "An error occurred while loading the settings file: %d. Standard values have been applied", - file_stream_get_error(app->file_stream)); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - return false; - } - } - - //Вычисление размера файла - uint8_t file_size = stream_size(app->file_stream); - //Если файл пустой, то: - if(file_size == (uint8_t)0) { - FURI_LOG_W(APP_NAME, "Settings file is empty"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - //Сохранение стандартного конфига - unitemp_saveSettings(); - return false; - } - //Выделение памяти под загрузку файла - uint8_t* file_buf = malloc(file_size); - //Опустошение буфера файла - memset(file_buf, 0, file_size); - //Загрузка файла - if(stream_read(app->file_stream, file_buf, file_size) != file_size) { - //Выход при ошибке чтения - FURI_LOG_E(APP_NAME, "Error reading settings file"); - //Закрытие потока и освобождение памяти - file_stream_close(app->file_stream); - stream_free(app->file_stream); - free(file_buf); - return false; - } - //Построчное чтение файла - //Указатель на начало строки - FuriString* file = furi_string_alloc_set_str((char*)file_buf); - //Сколько байт до конца строки - size_t line_end = 0; - - while(line_end != ((size_t)-1) && line_end != (size_t)(file_size - 1)) { - char buff[20] = {0}; - sscanf(((char*)(file_buf + line_end)), "%s", buff); - - if(!strcmp(buff, "INFINITY_BACKLIGHT")) { - //Чтение значения параметра - int p = 0; - sscanf(((char*)(file_buf + line_end)), "INFINITY_BACKLIGHT %d", &p); - app->settings.infinityBacklight = p; - } else if(!strcmp(buff, "TEMP_UNIT")) { - //Чтение значения параметра - int p = 0; - sscanf(((char*)(file_buf + line_end)), "\nTEMP_UNIT %d", &p); - app->settings.temp_unit = p; - } else if(!strcmp(buff, "PRESSURE_UNIT")) { - //Чтение значения параметра - int p = 0; - sscanf(((char*)(file_buf + line_end)), "\nPRESSURE_UNIT %d", &p); - app->settings.pressure_unit = p; - } else if(!strcmp(buff, "HEAT_INDEX")) { - //Чтение значения параметра - int p = 0; - sscanf(((char*)(file_buf + line_end)), "\nHEAT_INDEX %d", &p); - app->settings.heat_index = p; - } else { - FURI_LOG_W(APP_NAME, "Unknown settings parameter: %s", buff); - } - - //Вычисление конца строки - line_end = furi_string_search_char(file, '\n', line_end + 1); - } - free(file_buf); - file_stream_close(app->file_stream); - stream_free(app->file_stream); - - FURI_LOG_I(APP_NAME, "Settings have been successfully loaded"); - return true; -} - -/** - * @brief Выделение места под переменные плагина - * - * @return true Если всё прошло успешно - * @return false Если в процессе загрузки произошла ошибка - */ -static bool unitemp_alloc(void) { - //Выделение памяти под данные приложения - app = malloc(sizeof(Unitemp)); - //Разрешение работы приложения - app->processing = true; - - //Открытие хранилища (?) - app->storage = furi_record_open(RECORD_STORAGE); - storage_common_migrate(app->storage, EXT_PATH("unitemp"), APP_PATH_FOLDER); - - //Уведомления - app->notifications = furi_record_open(RECORD_NOTIFICATION); - - //Установка значений по умолчанию - app->settings.infinityBacklight = true; //Подсветка горит всегда - app->settings.temp_unit = UT_TEMP_CELSIUS; //Единица измерения температуры - градусы Цельсия - app->settings.pressure_unit = UT_PRESSURE_MM_HG; //Единица измерения давления - мм рт. ст. - app->settings.heat_index = false; - - app->gui = furi_record_open(RECORD_GUI); - //Диспетчер окон - app->view_dispatcher = view_dispatcher_alloc(); - - app->sensors = NULL; - - app->buff = malloc(BUFF_SIZE); - - unitemp_General_alloc(); - - unitemp_MainMenu_alloc(); - unitemp_Settings_alloc(); - unitemp_SensorsList_alloc(); - unitemp_SensorEdit_alloc(); - unitemp_SensorNameEdit_alloc(); - unitemp_SensorActions_alloc(); - unitemp_widgets_alloc(); - - //Всплывающее окно - app->popup = popup_alloc(); - view_dispatcher_add_view(app->view_dispatcher, UnitempViewPopup, popup_get_view(app->popup)); - - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - return true; -} - -/** - * @brief Освыбождение памяти после работы приложения - */ -static void unitemp_free(void) { - popup_free(app->popup); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, UnitempViewPopup); - unitemp_widgets_free(); - - unitemp_SensorActions_free(); - unitemp_SensorNameEdit_free(); - unitemp_SensorEdit_free(); - unitemp_SensorsList_free(); - unitemp_Settings_free(); - unitemp_MainMenu_free(); - unitemp_General_free(); - - free(app->buff); - - view_dispatcher_free(app->view_dispatcher); - furi_record_close(RECORD_GUI); - //Очистка датчиков - //Высвыбождение данных датчиков - unitemp_sensors_free(); - free(app->sensors); - - //Закрытие уведомлений - furi_record_close(RECORD_NOTIFICATION); - //Закрытие хранилища - furi_record_close(RECORD_STORAGE); - //Удаление в самую последнюю очередь - free(app); -} - -/** - * @brief Точка входа в приложение - * - * @return Код ошибки - */ -int32_t unitemp_app() { - //Выделение памяти под переменные - //Выход если произошла ошибка - if(unitemp_alloc() == false) { - //Освобождение памяти - unitemp_free(); - //Выход - return 0; - } - - //Загрузка настроек из SD-карты - unitemp_loadSettings(); - //Применение настроек - if(app->settings.infinityBacklight == true) { - //Постоянное свечение подсветки - notification_message(app->notifications, &sequence_display_backlight_enforce_on); - } - app->settings.lastOTGState = furi_hal_power_is_otg_enabled(); - //Загрузка датчиков из SD-карты - unitemp_sensors_load(); - //Инициализация датчиков - unitemp_sensors_init(); - - unitemp_General_switch(); - - while(app->processing) { - if(app->sensors_ready) unitemp_sensors_updateValues(); - furi_delay_ms(100); - } - - //Деинициализация датчиков - unitemp_sensors_deInit(); - //Автоматическое управление подсветкой - if(app->settings.infinityBacklight == true) - notification_message(app->notifications, &sequence_display_backlight_enforce_auto); - //Освобождение памяти - unitemp_free(); - //Выход - return 0; -} diff --git a/applications/external/unitemp/unitemp.h b/applications/external/unitemp/unitemp.h deleted file mode 100644 index 320163126..000000000 --- a/applications/external/unitemp/unitemp.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP -#define UNITEMP - -/* Подключение стандартных библиотек */ - -/* Подключение API Flipper Zero */ -//Файловый поток -#include -//Экран -#include -#include -#include -#include -//Уведомления -#include -#include - -/* Внутренние библиотеки */ -//Интерфейсы подключения датчиков -#include "Sensors.h" - -/* Объявление макроподстановок */ -//Имя приложения -#define APP_NAME "Unitemp" -//Версия приложения -#define UNITEMP_APP_VER "1.4" -//Путь хранения файлов плагина -#define APP_PATH_FOLDER EXT_PATH("apps_data/unitemp") -//Имя файла с настройками -#define APP_FILENAME_SETTINGS "settings.cfg" -//Имя файла с датчиками -#define APP_FILENAME_SENSORS "sensors.cfg" - -//Размер буффера текста -#define BUFF_SIZE 32 - -#define UNITEMP_D - -#ifdef FURI_DEBUG -#define UNITEMP_DEBUG(msg, ...) FURI_LOG_D(APP_NAME, msg, ##__VA_ARGS__) -#else -#define UNITEMP_DEBUG(msg, ...) -#endif - -/* Объявление перечислений */ -//Единицы измерения температуры -typedef enum { UT_TEMP_CELSIUS, UT_TEMP_FAHRENHEIT, UT_TEMP_COUNT } tempMeasureUnit; -//Единицы измерения давления -typedef enum { - UT_PRESSURE_MM_HG, - UT_PRESSURE_IN_HG, - UT_PRESSURE_KPA, - UT_PRESSURE_HPA, - - UT_PRESSURE_COUNT -} pressureMeasureUnit; -/* Объявление структур */ -//Настройки плагина -typedef struct { - //Бесконечная работа подсветки - bool infinityBacklight; - //Единица измерения температуры - tempMeasureUnit temp_unit; - //Единица измерения давления - pressureMeasureUnit pressure_unit; - // Do calculate and show heat index - bool heat_index; - //Последнее состояние OTG - bool lastOTGState; -} UnitempSettings; - -//Основная структура плагина -typedef struct { - //Система - bool processing; //Флаг работы приложения. При ложном значении приложение закрывается - bool sensors_ready; //Флаг готовности датчиков к опросу - //Основные настройки - UnitempSettings settings; - //Массив указателей на датчики - Sensor** sensors; - //Количество загруженных датчиков - uint8_t sensors_count; - //SD-карта - Storage* storage; //Хранилище - Stream* file_stream; //Файловый поток - - //Экран - Gui* gui; - ViewDispatcher* view_dispatcher; - NotificationApp* notifications; - Widget* widget; - Popup* popup; - //Буффер для различного текста - char* buff; -} Unitemp; - -/* Объявление прототипов функций */ - -/** - * @brief Calculates the heat index in Celsius from the temperature and humidity and stores it in the sensor heat_index field - * - * @param sensor The sensor struct, with temperature in Celcius and humidity in percent - */ -void unitemp_calculate_heat_index(Sensor* sensor); - -/** - * @brief Перевод значения температуры датчика из Цельсия в Фаренгейты - * - * @param sensor Указатель на датчик - */ -void uintemp_celsiumToFarengate(Sensor* sensor); - -/** - * @brief Конвертация давления из паскалей в мм рт.ст. - * - * @param sensor Указатель на датчик - */ -void unitemp_pascalToMmHg(Sensor* sensor); - -/** - * @brief Конвертация давления из паскалей в килопаскали - * - * @param sensor Указатель на датчик - */ -void unitemp_pascalToKPa(Sensor* sensor); -/** - * @brief Конвертация давления из паскалей в дюйм рт.ст. - * - * @param sensor Указатель на датчик - */ -void unitemp_pascalToHPa(Sensor* sensor); -/** - * - * Mod BySepa - linktr.ee/BySepa - * - */ -void unitemp_pascalToInHg(Sensor* sensor); - -/** - * @brief Сохранение настроек на SD-карту - * - * @return Истина если сохранение успешное - */ -bool unitemp_saveSettings(void); -/** - * @brief Загрузка настроек с SD-карты - * - * @return Истина если загрузка успешная - */ -bool unitemp_loadSettings(void); - -extern Unitemp* app; -#endif diff --git a/applications/external/unitemp/views/General_view.c b/applications/external/unitemp/views/General_view.c deleted file mode 100644 index d0d269126..000000000 --- a/applications/external/unitemp/views/General_view.c +++ /dev/null @@ -1,688 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include "unitemp_icons.h" -#include - -// extern const Icon I_ButtonRight_4x7; -// extern const Icon I_ButtonLeft_4x7; -// extern const Icon I_Ok_btn_9x9; - -static View* view; - -typedef enum general_views { - G_NO_SENSORS_VIEW, //Нет датчиков - G_LIST_VIEW, //Вид в ввиде списка - G_CAROUSEL_VIEW, //Карусель -} general_view; - -typedef enum carousel_info { - CAROUSEL_VALUES, //Отображение значений датчиков - CAROUSEL_INFO, //Отображение информации о датчике -} carousel_info; - -static general_view current_view; - -carousel_info carousel_info_selector = CAROUSEL_VALUES; -uint8_t generalview_sensor_index = 0; - -static void _draw_temperature(Canvas* canvas, Sensor* sensor, uint8_t x, uint8_t y, Color color) { - //Рисование рамки - canvas_draw_rframe(canvas, x, y, 54, 20, 3); - - if(color == ColorBlack) { - canvas_draw_rbox(canvas, x, y, 54, 19, 3); - canvas_invert_color(canvas); - } else { - canvas_draw_rframe(canvas, x, y, 54, 19, 3); - } - - int8_t temp_dec = abs((int16_t)(sensor->temp * 10) % 10); - - //Рисование иконки - canvas_draw_icon( - canvas, - x + 3, - y + 3, - (app->settings.temp_unit == UT_TEMP_CELSIUS ? &I_temp_C_11x14 : &I_temp_F_11x14)); - - if((int16_t)sensor->temp == -128 || sensor->status == UT_SENSORSTATUS_TIMEOUT) { - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned(canvas, x + 27, y + 10, AlignCenter, AlignCenter, "--"); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, x + 50, y + 10 + 3, AlignRight, AlignCenter, ". -"); - if(color == ColorBlack) canvas_invert_color(canvas); - return; - } - - //Целая часть температуры - //Костыль для отображения знака числа меньше 0 - uint8_t offset = 0; - if(sensor->temp < 0 && sensor->temp > -1) { - app->buff[0] = '-'; - offset = 1; - } - snprintf((char*)(app->buff + offset), BUFF_SIZE, "%d", (int16_t)sensor->temp); - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned( - canvas, - x + 27 + ((sensor->temp <= -10 || sensor->temp > 99) ? 5 : 0), - y + 10, - AlignCenter, - AlignCenter, - app->buff); - //Печать дробной части температуры в диапазоне от -9 до 99 (когда два знака в числе) - if(sensor->temp > -10 && sensor->temp <= 99) { - uint8_t int_len = canvas_string_width(canvas, app->buff); - snprintf(app->buff, BUFF_SIZE, ".%d", temp_dec); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, x + 27 + int_len / 2 + 2, y + 10 + 7, app->buff); - } - if(color == ColorBlack) canvas_invert_color(canvas); -} - -static void _draw_humidity(Canvas* canvas, Sensor* sensor, const uint8_t pos[2]) { - //Рисование рамки - canvas_draw_rframe(canvas, pos[0], pos[1], 54, 20, 3); - canvas_draw_rframe(canvas, pos[0], pos[1], 54, 19, 3); - - //Рисование иконки - canvas_draw_icon(canvas, pos[0] + 3, pos[1] + 2, &I_hum_9x15); - - //Целая часть влажности - snprintf(app->buff, BUFF_SIZE, "%d", (uint8_t)sensor->hum); - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned(canvas, pos[0] + 27, pos[1] + 10, AlignCenter, AlignCenter, app->buff); - uint8_t int_len = canvas_string_width(canvas, app->buff); - //Единица измерения - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, pos[0] + 27 + int_len / 2 + 4, pos[1] + 10 + 7, "%"); -} - -static void _draw_heat_index(Canvas* canvas, Sensor* sensor, const uint8_t pos[2]) { - canvas_draw_rframe(canvas, pos[0], pos[1], 54, 20, 3); - canvas_draw_rframe(canvas, pos[0], pos[1], 54, 19, 3); - - canvas_draw_icon(canvas, pos[0] + 3, pos[1] + 3, &I_heat_index_11x14); - - int16_t heat_index_int = sensor->heat_index; - int8_t heat_index_dec = abs((int16_t)(sensor->heat_index * 10) % 10); - - snprintf(app->buff, BUFF_SIZE, "%d", heat_index_int); - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned( - canvas, - pos[0] + 27 + ((sensor->heat_index <= -10 || sensor->heat_index > 99) ? 5 : 0), - pos[1] + 10, - AlignCenter, - AlignCenter, - app->buff); - - if(heat_index_int <= 99) { - uint8_t int_len = canvas_string_width(canvas, app->buff); - snprintf(app->buff, BUFF_SIZE, ".%d", heat_index_dec); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, pos[0] + 27 + int_len / 2 + 2, pos[1] + 10 + 7, app->buff); - } -} - -static void _draw_pressure(Canvas* canvas, Sensor* sensor) { - const uint8_t x = 29, y = 39; - //Рисование рамки - if(app->settings.pressure_unit == UT_PRESSURE_HPA) { - canvas_draw_rframe(canvas, x, y, 84, 20, 3); - canvas_draw_rframe(canvas, x, y, 84, 19, 3); - } else { - canvas_draw_rframe(canvas, x, y, 69, 20, 3); - canvas_draw_rframe(canvas, x, y, 69, 19, 3); - } - - //Рисование иконки - canvas_draw_icon(canvas, x + 3, y + 4, &I_pressure_7x13); - - int16_t press_int = sensor->pressure; - // Change Temp for Pressure - int8_t press_dec = (int16_t)(sensor->pressure * 10) % 10; - - //Целая часть давления - snprintf(app->buff, BUFF_SIZE, "%d", press_int); - canvas_set_font(canvas, FontBigNumbers); - canvas_draw_str_aligned( - canvas, x + 27 + ((press_int > 99) ? 5 : 0), y + 10, AlignCenter, AlignCenter, app->buff); - //Печать дробной части давления в диапазоне от 0 до 99 (когда два знака в числе) - if(press_int <= 99) { - uint8_t int_len = canvas_string_width(canvas, app->buff); - snprintf(app->buff, BUFF_SIZE, ".%d", press_dec); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, x + 27 + int_len / 2 + 2, y + 10 + 7, app->buff); - } else if(app->settings.pressure_unit == UT_PRESSURE_HPA) { - uint8_t int_len = canvas_string_width(canvas, app->buff); - snprintf(app->buff, BUFF_SIZE, ".%d", press_dec); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, x + 32 + int_len / 2 + 2, y + 10 + 7, app->buff); - } - canvas_set_font(canvas, FontSecondary); - //Единица измерения - - if(app->settings.pressure_unit == UT_PRESSURE_MM_HG) { - canvas_draw_icon(canvas, x + 50, y + 2, &I_mm_hg_15x15); - } else if(app->settings.pressure_unit == UT_PRESSURE_IN_HG) { - canvas_draw_icon(canvas, x + 50, y + 2, &I_in_hg_15x15); - } else if(app->settings.pressure_unit == UT_PRESSURE_KPA) { - canvas_draw_str(canvas, x + 52, y + 13, "kPa"); - } else if(app->settings.pressure_unit == UT_PRESSURE_HPA) { - canvas_draw_str(canvas, x + 67, y + 13, "hPa"); - } -} - -static void _draw_co2(Canvas* canvas, Sensor* sensor, Color color) { - const uint8_t x = 29, y = 39; - //Рисование рамки - canvas_draw_rframe(canvas, x, y, 75, 20, 3); - if(color == ColorBlack) { - canvas_draw_rbox(canvas, x, y, 75, 19, 3); - canvas_invert_color(canvas); - } else { - canvas_draw_rframe(canvas, x, y, 75, 19, 3); - } - - //Рисование иконки - canvas_draw_icon(canvas, x + 3, y + 3, &I_co2_11x14); - - int16_t concentration_int = sensor->co2; - // int8_t concentration_dec = (int16_t)(sensor->co2 * 10) % 10; - - //Целая часть - if(concentration_int > 9999) { - snprintf(app->buff, BUFF_SIZE, "MAX "); - canvas_set_font(canvas, FontPrimary); - } else { - snprintf(app->buff, BUFF_SIZE, "%d", concentration_int); - canvas_set_font(canvas, FontBigNumbers); - } - - canvas_draw_str_aligned(canvas, x + 70, y + 10, AlignRight, AlignCenter, app->buff); -} - -static void _draw_singleSensor(Canvas* canvas, Sensor* sensor, const uint8_t pos[2], Color color) { - canvas_set_font(canvas, FontPrimary); - - const uint8_t max_width = 56; - - char sensor_name[12] = {0}; - memcpy(sensor_name, sensor->name, 10); - - if(canvas_string_width(canvas, sensor_name) > max_width) { - uint8_t i = 10; - while((canvas_string_width(canvas, sensor_name) > max_width - 6) && (i != 0)) { - sensor_name[i--] = '\0'; - } - sensor_name[++i] = '.'; - sensor_name[++i] = '.'; - } - - canvas_draw_str_aligned( - canvas, pos[0] + 27, pos[1] + 3, AlignCenter, AlignCenter, sensor_name); - _draw_temperature(canvas, sensor, pos[0], pos[1] + 8, color); -} - -static void _draw_view_noSensors(Canvas* canvas) { - canvas_draw_icon(canvas, 7, 17, &I_sherlok_53x45); - //Рисование рамки - canvas_draw_rframe(canvas, 0, 0, 128, 63, 7); - canvas_draw_rframe(canvas, 0, 0, 128, 64, 7); - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned(canvas, 63, 10, AlignCenter, AlignCenter, "No sensors found"); - canvas_set_font(canvas, FontSecondary); - const uint8_t x = 65, y = 32; - canvas_draw_rframe(canvas, x - 4, y - 11, 54, 33, 3); - canvas_draw_rframe(canvas, x - 4, y - 11, 54, 34, 3); - canvas_draw_str(canvas, x, y, "To add the"); - canvas_draw_str(canvas, x, y + 9, "new sensor"); - canvas_draw_str(canvas, x, y + 18, "press OK"); - - canvas_draw_icon(canvas, x + 37, y + 10, &I_Ok_btn_9x9); -} - -static void _draw_view_sensorsList(Canvas* canvas) { - //Текущая страница - uint8_t page = generalview_sensor_index / 4; - //Количество датчиков, которые будут отображаться на странице - uint8_t page_sensors_count; - if((unitemp_sensors_getActiveCount() - page * 4) / 4) { - page_sensors_count = 4; - } else { - page_sensors_count = (unitemp_sensors_getActiveCount() - page * 4) % 4; - } - - //Количество страниц - uint8_t pages = - unitemp_sensors_getActiveCount() / 4 + (unitemp_sensors_getActiveCount() % 4 ? 1 : 0); - - //Стрелка влево - if(page > 0) { - canvas_draw_icon(canvas, 2, 32, &I_ButtonLeft_4x7); - } - //Стрелка вправо - if(pages > 0 && page < pages - 1) { - canvas_draw_icon(canvas, 122, 32, &I_ButtonRight_4x7); - } - - const uint8_t value_positions[][4][2] = { - {{36, 18}}, //1 датчик - {{7, 18}, {67, 18}}, //2 датчика - {{7, 3}, {67, 3}, {37, 33}}, //3 датчика - {{7, 3}, {67, 3}, {7, 33}, {67, 33}}}; //4 датчика - //Рисование рамки - canvas_draw_rframe(canvas, 0, 0, 128, 63, 7); - canvas_draw_rframe(canvas, 0, 0, 128, 64, 7); - for(uint8_t i = 0; i < page_sensors_count; i++) { - _draw_singleSensor( - canvas, - unitemp_sensor_getActive(page * 4 + i), - value_positions[page_sensors_count - 1][i], - ColorWhite); - } -} - -static void _draw_carousel_values(Canvas* canvas) { - UnitempStatus sensor_status = unitemp_sensor_getActive(generalview_sensor_index)->status; - if(sensor_status == UT_SENSORSTATUS_ERROR || sensor_status == UT_SENSORSTATUS_TIMEOUT) { - const Icon* frames[] = { - &I_flipper_happy_60x38, &I_flipper_happy_2_60x38, &I_flipper_sad_60x38}; - canvas_draw_icon(canvas, 34, 23, frames[furi_get_tick() % 2250 / 750]); - - canvas_set_font(canvas, FontSecondary); - //TODO: Оптимизировать эту срань - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) { - snprintf( - app->buff, - BUFF_SIZE, - "Waiting for module on pin %d", - ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->gpio->num); - } - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) { - snprintf( - app->buff, - BUFF_SIZE, - "Waiting for module on pin %d", - ((OneWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->bus->gpio->num); - } - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) { - snprintf(app->buff, BUFF_SIZE, "Waiting for module on I2C pins"); - } - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) { - snprintf(app->buff, BUFF_SIZE, "Waiting for module on SPI pins"); - } - canvas_draw_str_aligned(canvas, 64, 19, AlignCenter, AlignCenter, app->buff); - return; - } - - static const uint8_t temp_positions[3][2] = {{37, 23}, {37, 16}, {9, 16}}; - static const uint8_t hum_positions[2][2] = {{37, 38}, {65, 16}}; - //Селектор значений для отображения - switch(unitemp_sensor_getActive(generalview_sensor_index)->type->datatype) { - case UT_DATA_TYPE_TEMP: - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[0][0], - temp_positions[0][1], - ColorWhite); - break; - case UT_DATA_TYPE_TEMP_HUM: - if(!app->settings.heat_index) { - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[1][0], - temp_positions[1][1], - ColorWhite); - } else { - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[2][0], - temp_positions[2][1], - ColorWhite); - _draw_heat_index( - canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]); - } - _draw_humidity( - canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[0]); - break; - case UT_DATA_TYPE_TEMP_PRESS: - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[1][0], - temp_positions[1][1], - ColorWhite); - _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index)); - break; - case UT_DATA_TYPE_TEMP_HUM_PRESS: - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[2][0], - temp_positions[2][1], - ColorWhite); - _draw_humidity( - canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]); - _draw_pressure(canvas, unitemp_sensor_getActive(generalview_sensor_index)); - break; - case UT_DATA_TYPE_TEMP_HUM_CO2: - _draw_temperature( - canvas, - unitemp_sensor_getActive(generalview_sensor_index), - temp_positions[2][0], - temp_positions[2][1], - ColorWhite); - _draw_humidity( - canvas, unitemp_sensor_getActive(generalview_sensor_index), hum_positions[1]); - _draw_co2(canvas, unitemp_sensor_getActive(generalview_sensor_index), ColorWhite); - break; - } -} - -//TODO: Оптимизировать вывод информации -static void _draw_carousel_info(Canvas* canvas) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 23, "Type:"); - - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &ONE_WIRE) { - OneWireSensor* s = unitemp_sensor_getActive(generalview_sensor_index)->instance; - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 35, "GPIO:"); - canvas_draw_str(canvas, 10, 47, "ID:"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str( - canvas, - 41, - 23, - unitemp_onewire_sensor_getModel(unitemp_sensor_getActive(generalview_sensor_index))); - canvas_draw_str(canvas, 41, 35, s->bus->gpio->name); - snprintf( - app->buff, - BUFF_SIZE, - "%02X%02X%02X%02X%02X%02X%02X%02X", - s->deviceID[0], - s->deviceID[1], - s->deviceID[2], - s->deviceID[3], - s->deviceID[4], - s->deviceID[5], - s->deviceID[6], - s->deviceID[7]); - canvas_draw_str(canvas, 24, 47, app->buff); - } - - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SINGLE_WIRE) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 35, "GPIO:"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str( - canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename); - canvas_draw_str( - canvas, - 41, - 35, - ((SingleWireSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->gpio->name); - } - - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &SPI) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 35, "MISO pin:"); - canvas_draw_str(canvas, 10, 46, "CS pin:"); - canvas_draw_str(canvas, 10, 58, "SCK pin:"); - - canvas_set_font(canvas, FontSecondary); - canvas_draw_str( - canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename); - canvas_draw_str(canvas, 60, 35, unitemp_gpio_getFromInt(3)->name); - canvas_draw_str( - canvas, - 47, - 46, - ((SPISensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->CS_pin->name); - canvas_draw_str(canvas, 54, 58, unitemp_gpio_getFromInt(5)->name); - } - - if(unitemp_sensor_getActive(generalview_sensor_index)->type->interface == &I2C) { - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 10, 35, "I2C addr:"); - canvas_draw_str(canvas, 10, 46, "SDA pin:"); - canvas_draw_str(canvas, 10, 58, "SCL pin:"); - canvas_set_font(canvas, FontSecondary); - canvas_draw_str( - canvas, 41, 23, unitemp_sensor_getActive(generalview_sensor_index)->type->typename); - snprintf( - app->buff, - BUFF_SIZE, - "0x%02X", - ((I2CSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) - ->currentI2CAdr >> - 1); - canvas_draw_str(canvas, 57, 35, app->buff); - canvas_draw_str(canvas, 54, 46, "15 (C1)"); - canvas_draw_str(canvas, 54, 58, "16 (C0)"); - } -} -static void _draw_view_sensorsCarousel(Canvas* canvas) { - //Рисование рамки - canvas_draw_rframe(canvas, 0, 0, 128, 63, 7); - canvas_draw_rframe(canvas, 0, 0, 128, 64, 7); - - //Печать имени - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, - 64, - 7, - AlignCenter, - AlignCenter, - unitemp_sensor_getActive(generalview_sensor_index)->name); - //Подчёркивание - uint8_t line_len = - canvas_string_width(canvas, unitemp_sensor_getActive(generalview_sensor_index)->name) + 2; - canvas_draw_line(canvas, 64 - line_len / 2, 12, 64 + line_len / 2, 12); - - //Стрелка вправо - if(unitemp_sensors_getTypesCount() > 0 && - generalview_sensor_index < unitemp_sensors_getActiveCount() - 1) { - canvas_draw_icon(canvas, 122, 29, &I_ButtonRight_4x7); - } - //Стрелка влево - if(generalview_sensor_index > 0) { - canvas_draw_icon(canvas, 2, 29, &I_ButtonLeft_4x7); - } - - switch(carousel_info_selector) { - case CAROUSEL_VALUES: - _draw_carousel_values(canvas); - break; - case CAROUSEL_INFO: - _draw_carousel_info(canvas); - break; - } -} - -static void _draw_callback(Canvas* canvas, void* _model) { - UNUSED(_model); - - app->sensors_ready = true; - - uint8_t sensors_count = unitemp_sensors_getActiveCount(); - - if(generalview_sensor_index + 1 > sensors_count) generalview_sensor_index = 0; - - if(sensors_count == 0) { - current_view = G_NO_SENSORS_VIEW; - _draw_view_noSensors(canvas); - } else { - if(sensors_count == 1) current_view = G_CAROUSEL_VIEW; - if(current_view == G_NO_SENSORS_VIEW) current_view = G_CAROUSEL_VIEW; - if(current_view == G_LIST_VIEW) _draw_view_sensorsList(canvas); - if(current_view == G_CAROUSEL_VIEW) _draw_view_sensorsCarousel(canvas); - } -} - -static bool _input_callback(InputEvent* event, void* context) { - UNUSED(context); - - //Обработка короткого нажатия "ок" - if(event->key == InputKeyOk && event->type == InputTypeShort) { - //Меню добавления датчика при их отсутствии - if(current_view == G_NO_SENSORS_VIEW) { - app->sensors_ready = false; - unitemp_SensorsList_switch(); - } else if(current_view == G_LIST_VIEW) { - //Переход в главное меню при выключенном селекторе - app->sensors_ready = false; - unitemp_MainMenu_switch(); - } else if(current_view == G_CAROUSEL_VIEW) { - app->sensors_ready = false; - unitemp_SensorActions_switch(unitemp_sensor_getActive(generalview_sensor_index)); - } - } - - //Обработка короткого нажатия "вниз" - if(event->key == InputKeyDown && event->type == InputTypeShort) { - //Переход из значений в информацию в карусели - if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES) { - carousel_info_selector = CAROUSEL_INFO; - return true; - } - //Переход в карусель из списка - if(current_view == G_LIST_VIEW) { - current_view = G_CAROUSEL_VIEW; - return true; - } - } - - //Обработка короткого нажатия "вверх" - if(event->key == InputKeyUp && event->type == InputTypeShort) { - //Переход из информации в значения в карусели - if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_INFO) { - carousel_info_selector = CAROUSEL_VALUES; - return true; - } - //Переход в список из карусели - if(current_view == G_CAROUSEL_VIEW && carousel_info_selector == CAROUSEL_VALUES && - unitemp_sensors_getActiveCount() > 1) { - current_view = G_LIST_VIEW; - return true; - } - } - - //Обработка короткого нажатия "вправо" - if(event->key == InputKeyRight && event->type == InputTypeShort) { - //Пролистывание карусели вперёд - if(current_view == G_CAROUSEL_VIEW) { - if(++generalview_sensor_index >= unitemp_sensors_getActiveCount()) { - generalview_sensor_index = 0; - if(carousel_info_selector == CAROUSEL_VALUES) current_view = G_LIST_VIEW; - } - - return true; - } - //Пролистывание списка вперёд - if(current_view == G_LIST_VIEW) { - generalview_sensor_index += 4; - if(generalview_sensor_index >= unitemp_sensors_getActiveCount()) { - generalview_sensor_index = 0; - current_view = G_CAROUSEL_VIEW; - } - return true; - } - } - - //Обработка короткого нажатия "влево" - if(event->key == InputKeyLeft && event->type == InputTypeShort) { - //Пролистывание карусели назад - if(current_view == G_CAROUSEL_VIEW) { - if(--generalview_sensor_index >= unitemp_sensors_getActiveCount()) { - generalview_sensor_index = unitemp_sensors_getActiveCount() - 1; - if(carousel_info_selector == CAROUSEL_VALUES) current_view = G_LIST_VIEW; - } - - return true; - } - //Пролистывание списка назад - if(current_view == G_LIST_VIEW) { - generalview_sensor_index -= 4; - if(generalview_sensor_index >= unitemp_sensors_getActiveCount()) { - generalview_sensor_index = unitemp_sensors_getActiveCount() - 1; - current_view = G_CAROUSEL_VIEW; - } - - return true; - } - } - - //Обработка короткого нажатия "назад" - if(event->key == InputKeyBack && event->type == InputTypeShort) { - //Выход из приложения при карусели или отсутствии датчиков - if(current_view == G_NO_SENSORS_VIEW || - ((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector == CAROUSEL_VALUES))) { - app->processing = false; - return true; - } - //Переключение селектора вида карусели - if((current_view == G_CAROUSEL_VIEW) && (carousel_info_selector != CAROUSEL_VALUES)) { - carousel_info_selector = CAROUSEL_VALUES; - return true; - } - //Переход в карусель из списка - if(current_view == G_LIST_VIEW) { - current_view = G_CAROUSEL_VIEW; - return true; - } - } - //Обработка длинного нажатия "Ок" - if(event->key == InputKeyOk && event->type == InputTypeLong) { - app->settings.temp_unit = !app->settings.temp_unit; - } - - return true; -} - -void unitemp_General_alloc(void) { - view = view_alloc(); - view_set_context(view, app); - view_set_draw_callback(view, _draw_callback); - view_set_input_callback(view, _input_callback); - - view_dispatcher_add_view(app->view_dispatcher, UnitempViewGeneral, view); -} - -void unitemp_General_switch(void) { - app->sensors_ready = true; - view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewGeneral); -} - -void unitemp_General_free(void) { - view_dispatcher_remove_view(app->view_dispatcher, UnitempViewGeneral); - view_free(view); -} diff --git a/applications/external/unitemp/views/MainMenu_view.c b/applications/external/unitemp/views/MainMenu_view.c deleted file mode 100644 index bfd0cb0cf..000000000 --- a/applications/external/unitemp/views/MainMenu_view.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; - -#define VIEW_ID UnitempViewMainMenu - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - //Возврат в общий вид - return UnitempViewGeneral; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - if(index == 0) { //Add new sensor - unitemp_SensorsList_switch(); - } - if(index == 1) { //Settings - unitemp_Settings_switch(); - } - if(index == 2) { - unitemp_widget_help_switch(); - } - if(index == 3) { - unitemp_widget_about_switch(); - } -} - -/** - * @brief Создание списка действий с указанным датчиком - */ -void unitemp_MainMenu_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - variable_item_list_add(variable_item_list, "Add new sensor", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Settings", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Help", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "About", 1, NULL, NULL); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); -} - -void unitemp_MainMenu_switch(void) { - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - //Переключение в вид - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_MainMenu_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/Popup_view.c b/applications/external/unitemp/views/Popup_view.c deleted file mode 100644 index efa7e7ffa..000000000 --- a/applications/external/unitemp/views/Popup_view.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include -#include - -uint32_t _prev_view_id; - -#define VIEW_ID UnitempViewPopup - -static void _popup_callback(void* context) { - UNUSED(context); - view_dispatcher_switch_to_view(app->view_dispatcher, _prev_view_id); -} - -void unitemp_popup(const Icon* icon, char* header, char* message, uint32_t prev_view_id) { - _prev_view_id = prev_view_id; - popup_reset(app->popup); - popup_set_icon(app->popup, 0, 64 - icon_get_height(icon), icon); - popup_set_header(app->popup, header, 64, 6, AlignCenter, AlignCenter); - popup_set_text( - app->popup, - message, - (128 - icon_get_width(icon)) / 2 + icon_get_width(icon), - 32, - AlignCenter, - AlignCenter); - - popup_set_timeout(app->popup, 5000); - popup_set_callback(app->popup, _popup_callback); - popup_enable_timeout(app->popup); - - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/SensorActions_view.c b/applications/external/unitemp/views/SensorActions_view.c deleted file mode 100644 index 1d1a83076..000000000 --- a/applications/external/unitemp/views/SensorActions_view.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include -#include - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; -//Текущий датчик -static Sensor* current_sensor; - -typedef enum carousel_info { - CAROUSEL_VALUES, //Отображение значений датчиков - CAROUSEL_INFO, //Отображение информации о датчике -} carousel_info; -extern carousel_info carousel_info_selector; - -#define VIEW_ID UnitempViewSensorActions - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - - //Возврат предыдущий вид - return UnitempViewGeneral; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - switch(index) { - case 0: - carousel_info_selector = CAROUSEL_INFO; - unitemp_General_switch(); - return; - case 1: - unitemp_SensorEdit_switch(current_sensor); - break; - case 2: - unitemp_widget_delete_switch(current_sensor); - break; - case 3: - unitemp_SensorsList_switch(); - break; - case 4: - unitemp_Settings_switch(); - break; - case 5: - unitemp_widget_help_switch(); - break; - case 6: - unitemp_widget_about_switch(); - break; - } -} - -/** - * @brief Создание меню действий с датчиком - */ -void unitemp_SensorActions_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - variable_item_list_add(variable_item_list, "Info", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Edit", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Delete", 1, NULL, NULL); - - variable_item_list_add(variable_item_list, "Add new sensor", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Settings", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "Help", 1, NULL, NULL); - variable_item_list_add(variable_item_list, "About", 1, NULL, NULL); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); -} - -void unitemp_SensorActions_switch(Sensor* sensor) { - current_sensor = sensor; - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_SensorActions_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/SensorEdit_view.c b/applications/external/unitemp/views/SensorEdit_view.c deleted file mode 100644 index c1ac4c028..000000000 --- a/applications/external/unitemp/views/SensorEdit_view.c +++ /dev/null @@ -1,383 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include - -#include "../interfaces/SingleWireSensor.h" -#include "../interfaces/OneWireSensor.h" -#include "../interfaces/I2CSensor.h" - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; -//Текущий редактируемый датчик -static Sensor* editable_sensor; -//Изначальный GPIO датчика -static const GPIO* initial_gpio = NULL; - -//Элемент списка - имя датчика -static VariableItem* sensor_name_item; -//Элемент списка - адрес датчика one wire -static VariableItem* onewire_addr_item; -//Элемент списка - адрес датчика one wire -static VariableItem* onewire_type_item; -//Элемент списка - смещение температуры -VariableItem* temp_offset_item; - -#define OFFSET_BUFF_SIZE 5 -//Буффер для текста смещения -static char* offset_buff; - -extern uint8_t generalview_sensor_index; - -#define VIEW_ID UnitempViewSensorEdit - -bool _onewire_id_exist(uint8_t* id) { - if(id == NULL) return false; - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - if(unitemp_sensor_getActive(i)->type == &Dallas) { - if(unitemp_onewire_id_compare( - id, ((OneWireSensor*)(unitemp_sensor_getActive(i)->instance))->deviceID)) { - return true; - } - } - } - return false; -} - -static void _onewire_scan(void) { - OneWireSensor* ow_sensor = editable_sensor->instance; - - UNITEMP_DEBUG( - "devices on wire %d: %d", ow_sensor->bus->gpio->num, ow_sensor->bus->device_count); - - //Сканирование шины one wire - unitemp_onewire_bus_init(ow_sensor->bus); - uint8_t* id = NULL; - do { - id = unitemp_onewire_bus_enum_next(ow_sensor->bus); - } while(_onewire_id_exist(id)); - - if(id == NULL) { - unitemp_onewire_bus_enum_init(ow_sensor->bus); - id = unitemp_onewire_bus_enum_next(ow_sensor->bus); - if(_onewire_id_exist(id)) { - do { - id = unitemp_onewire_bus_enum_next(ow_sensor->bus); - } while(_onewire_id_exist(id) && id != NULL); - } - if(id == NULL) { - memset(ow_sensor->deviceID, 0, 8); - ow_sensor->familyCode = 0; - unitemp_onewire_bus_deinit(ow_sensor->bus); - variable_item_set_current_value_text(onewire_addr_item, "empty"); - variable_item_set_current_value_text( - onewire_type_item, unitemp_onewire_sensor_getModel(editable_sensor)); - return; - } - } - - unitemp_onewire_bus_deinit(ow_sensor->bus); - - memcpy(ow_sensor->deviceID, id, 8); - ow_sensor->familyCode = id[0]; - - UNITEMP_DEBUG( - "Found sensor's ID: %02X%02X%02X%02X%02X%02X%02X%02X", - id[0], - id[1], - id[2], - id[3], - id[4], - id[5], - id[6], - id[7]); - - if(ow_sensor->familyCode != 0) { - char id_buff[10]; - snprintf( - id_buff, - 10, - "%02X%02X%02X", - ow_sensor->deviceID[1], - ow_sensor->deviceID[2], - ow_sensor->deviceID[3]); - //А больше не лезет( - variable_item_set_current_value_text(onewire_addr_item, id_buff); - } else { - variable_item_set_current_value_text(onewire_addr_item, "empty"); - } - variable_item_set_current_value_text( - onewire_type_item, unitemp_onewire_sensor_getModel(editable_sensor)); -} - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - editable_sensor->status = UT_SENSORSTATUS_TIMEOUT; - if(!unitemp_sensor_isContains(editable_sensor)) unitemp_sensor_free(editable_sensor); - unitemp_sensors_reload(); - //Возврат предыдущий вид - return UnitempViewGeneral; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - //Смена имени - if(index == 0) { - unitemp_SensorNameEdit_switch(editable_sensor); - } - //Сохранение - if((index == 4 && editable_sensor->type->interface != &ONE_WIRE) || - (index == 5 && editable_sensor->type->interface == &ONE_WIRE)) { - //Выход если датчик one wire не имеет ID - if(editable_sensor->type->interface == &ONE_WIRE && - ((OneWireSensor*)(editable_sensor->instance))->familyCode == 0) { - return; - } - if(initial_gpio != NULL) { - unitemp_gpio_unlock(initial_gpio); - initial_gpio = NULL; - } - editable_sensor->status = UT_SENSORSTATUS_TIMEOUT; - if(!unitemp_sensor_isContains(editable_sensor)) unitemp_sensors_add(editable_sensor); - unitemp_sensors_save(); - unitemp_sensors_reload(); - - generalview_sensor_index = unitemp_sensors_getActiveCount() - 1; - unitemp_General_switch(); - } - - //Адрес устройства на шине one wire - if(index == 4 && editable_sensor->type->interface == &ONE_WIRE) { - _onewire_scan(); - } -} - -/** - * @brief Функция обработки изменения значения GPIO - * - * @param item Указатель на элемент списка - */ -static void _gpio_change_callback(VariableItem* item) { - uint8_t index = variable_item_get_current_value_index(item); - if(editable_sensor->type->interface == &SINGLE_WIRE) { - SingleWireSensor* instance = editable_sensor->instance; - instance->gpio = - unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, initial_gpio); - variable_item_set_current_value_text(item, instance->gpio->name); - } - if(editable_sensor->type->interface == &SPI) { - SPISensor* instance = editable_sensor->instance; - instance->CS_pin = - unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, initial_gpio); - variable_item_set_current_value_text(item, instance->CS_pin->name); - } - if(editable_sensor->type->interface == &ONE_WIRE) { - OneWireSensor* instance = editable_sensor->instance; - instance->bus->gpio = - unitemp_gpio_getAviablePort(editable_sensor->type->interface, index, NULL); - variable_item_set_current_value_text(item, instance->bus->gpio->name); - } -} -/** - * @brief Функция обработки изменения значения GPIO - * - * @param item Указатель на элемент списка - */ -static void _i2caddr_change_callback(VariableItem* item) { - uint8_t index = variable_item_get_current_value_index(item); - ((I2CSensor*)editable_sensor->instance)->currentI2CAdr = - ((I2CSensor*)editable_sensor->instance)->minI2CAdr + index * 2; - char buff[5]; - snprintf(buff, 5, "0x%2X", ((I2CSensor*)editable_sensor->instance)->currentI2CAdr >> 1); - variable_item_set_current_value_text(item, buff); -} -/** - * @brief Функция обработки изменения значения имени датчика - * - * @param item Указатель на элемент списка - */ -static void _name_change_callback(VariableItem* item) { - variable_item_set_current_value_index(item, 0); - unitemp_SensorNameEdit_switch(editable_sensor); -} -/** - * @brief Функция обработки изменения значения адреса датчика one wire - * - * @param item Указатель на элемент списка - */ -static void _onwire_addr_change_callback(VariableItem* item) { - variable_item_set_current_value_index(item, 0); - _onewire_scan(); -} - -/** - * @brief Функция обработки изменения значения смещения температуры - * - * @param item Указатель на элемент списка - */ -static void _offset_change_callback(VariableItem* item) { - editable_sensor->temp_offset = variable_item_get_current_value_index(item) - 20; - snprintf( - offset_buff, OFFSET_BUFF_SIZE, "%+1.1f", (double)(editable_sensor->temp_offset / 10.0)); - variable_item_set_current_value_text(item, offset_buff); -} - -/** - * @brief Создание меню редактирования датчка - */ -void unitemp_SensorEdit_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); - - offset_buff = malloc(OFFSET_BUFF_SIZE); -} - -void unitemp_SensorEdit_switch(Sensor* sensor) { - editable_sensor = sensor; - - editable_sensor->status = UT_SENSORSTATUS_INACTIVE; - - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - - //Имя датчика - sensor_name_item = variable_item_list_add( - variable_item_list, "Name", strlen(sensor->name) > 7 ? 1 : 2, _name_change_callback, NULL); - variable_item_set_current_value_index(sensor_name_item, 0); - variable_item_set_current_value_text(sensor_name_item, sensor->name); - - //Тип датчика (не редактируется) - onewire_type_item = variable_item_list_add(variable_item_list, "Type", 1, NULL, NULL); - variable_item_set_current_value_index(onewire_type_item, 0); - variable_item_set_current_value_text( - onewire_type_item, - (sensor->type->interface == &ONE_WIRE ? unitemp_onewire_sensor_getModel(editable_sensor) : - sensor->type->typename)); - //Смещение температуры - temp_offset_item = variable_item_list_add( - variable_item_list, "Temp. offset", 41, _offset_change_callback, NULL); - variable_item_set_current_value_index(temp_offset_item, sensor->temp_offset + 20); - snprintf( - offset_buff, OFFSET_BUFF_SIZE, "%+1.1f", (double)(editable_sensor->temp_offset / 10.0)); - variable_item_set_current_value_text(temp_offset_item, offset_buff); - - //Порт подключения датчка (для one wire, SPI и single wire) - if(sensor->type->interface == &ONE_WIRE || sensor->type->interface == &SINGLE_WIRE || - sensor->type->interface == &SPI) { - if(sensor->type->interface == &ONE_WIRE) { - initial_gpio = ((OneWireSensor*)editable_sensor->instance)->bus->gpio; - } else if(sensor->type->interface == &SINGLE_WIRE) { - initial_gpio = ((SingleWireSensor*)editable_sensor->instance)->gpio; - } else if(sensor->type->interface == &SPI) { - initial_gpio = ((SPISensor*)editable_sensor->instance)->CS_pin; - } - - uint8_t aviable_gpio_count = - unitemp_gpio_getAviablePortsCount(sensor->type->interface, initial_gpio); - VariableItem* item = variable_item_list_add( - variable_item_list, "GPIO", aviable_gpio_count, _gpio_change_callback, app); - - uint8_t gpio_index = 0; - if(unitemp_sensor_isContains(editable_sensor)) { - for(uint8_t i = 0; i < aviable_gpio_count; i++) { - if(unitemp_gpio_getAviablePort(sensor->type->interface, i, initial_gpio) == - initial_gpio) { - gpio_index = i; - break; - } - } - } - variable_item_set_current_value_index(item, gpio_index); - variable_item_set_current_value_text( - item, - unitemp_gpio_getAviablePort(sensor->type->interface, gpio_index, initial_gpio)->name); - } - //Адрес устройства на шине I2C (для датчиков I2C) - if(sensor->type->interface == &I2C) { - VariableItem* item = variable_item_list_add( - variable_item_list, - "I2C address", - (((I2CSensor*)sensor->instance)->maxI2CAdr >> 1) - - (((I2CSensor*)sensor->instance)->minI2CAdr >> 1) + 1, - _i2caddr_change_callback, - app); - snprintf(app->buff, 5, "0x%2X", ((I2CSensor*)sensor->instance)->currentI2CAdr >> 1); - variable_item_set_current_value_index( - item, - (((I2CSensor*)sensor->instance)->currentI2CAdr >> 1) - - (((I2CSensor*)sensor->instance)->minI2CAdr >> 1)); - variable_item_set_current_value_text(item, app->buff); - } - - //Адрес устройства на шине one wire (для датчиков one wire) - if(sensor->type->interface == &ONE_WIRE) { - onewire_addr_item = variable_item_list_add( - variable_item_list, "Address", 2, _onwire_addr_change_callback, NULL); - OneWireSensor* ow_sensor = sensor->instance; - if(ow_sensor->familyCode == 0) { - variable_item_set_current_value_text(onewire_addr_item, "Scan"); - } else { - snprintf( - app->buff, - 10, - "%02X%02X%02X", - ow_sensor->deviceID[1], - ow_sensor->deviceID[2], - ow_sensor->deviceID[3]); - variable_item_set_current_value_text(onewire_addr_item, app->buff); - } - } - variable_item_list_add(variable_item_list, "Save", 1, NULL, NULL); - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_SensorEdit_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); - free(offset_buff); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/SensorNameEdit_view.c b/applications/external/unitemp/views/SensorNameEdit_view.c deleted file mode 100644 index 19df76edf..000000000 --- a/applications/external/unitemp/views/SensorNameEdit_view.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include - -//Окно ввода текста -static TextInput* text_input; -//Текущий редактируемый датчик -static Sensor* editable_sensor; - -#define VIEW_ID UnitempViewSensorNameEdit - -static void _sensor_name_changed_callback(void* context) { - UNUSED(context); - unitemp_SensorEdit_switch(editable_sensor); -} - -void unitemp_SensorNameEdit_alloc(void) { - text_input = text_input_alloc(); - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, text_input_get_view(text_input)); - text_input_set_header_text(text_input, "Sensor name"); -} -void unitemp_SensorNameEdit_switch(Sensor* sensor) { - editable_sensor = sensor; - text_input_set_result_callback( - text_input, _sensor_name_changed_callback, app, sensor->name, 11, true); - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} -void unitemp_SensorNameEdit_free(void) { - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); - text_input_free(text_input); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/SensorsList_view.c b/applications/external/unitemp/views/SensorsList_view.c deleted file mode 100644 index 716ec260b..000000000 --- a/applications/external/unitemp/views/SensorsList_view.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include -#include - -extern const Icon I_Cry_dolph_55x52; - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; - -#define VIEW_ID UnitempViewSensorsList - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - - //Возврат предыдущий вид - return UnitempViewGeneral; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - if(index == unitemp_sensors_getTypesCount()) { - unitemp_widget_help_switch(); - return; - } - - const SensorType* type = unitemp_sensors_getTypes()[index]; - uint8_t sensor_type_count = 0; - - //Подсчёт имеющихся датчиков данного типа - for(uint8_t i = 0; i < unitemp_sensors_getActiveCount(); i++) { - if(unitemp_sensor_getActive(i)->type == type) { - sensor_type_count++; - } - } - - //Имя датчка - char sensor_name[11]; - //Добавление счётчика к имени если такой датчик имеется - if(sensor_type_count == 0) - snprintf(sensor_name, 11, "%s", type->typename); - else - snprintf(sensor_name, 11, "%s_%d", type->typename, sensor_type_count); - - char args[22] = {0}; - - //Проверка доступности датчика - if(unitemp_gpio_getAviablePort(type->interface, 0, NULL) == NULL) { - if(type->interface == &SINGLE_WIRE || type->interface == &ONE_WIRE) { - unitemp_popup( - &I_Cry_dolph_55x52, "Sensor is unavailable", "All GPIOs\nare busy", VIEW_ID); - } - if(type->interface == &I2C) { - unitemp_popup( - &I_Cry_dolph_55x52, "Sensor is unavailable", "GPIOs 15 or 16\nare busy", VIEW_ID); - } - return; - } - - //Выбор первого доступного порта для датчика single wire и SPI - if(type->interface == &SINGLE_WIRE || type->interface == &SPI) { - snprintf( - args, - 4, - "%d", - unitemp_gpio_toInt(unitemp_gpio_getAviablePort(type->interface, 0, NULL))); - } - //Выбор первого доступного порта для датчика one wire и запись нулевого ID - if(type->interface == &ONE_WIRE) { - snprintf( - args, - 21, - "%d %02X%02X%02X%02X%02X%02X%02X%02X", - unitemp_gpio_toInt(unitemp_gpio_getAviablePort(type->interface, 0, NULL)), - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0); - } - //Для I2C адрес выберется автоматически - - unitemp_SensorEdit_switch(unitemp_sensor_alloc(sensor_name, type, args)); -} - -/** - * @brief Создание меню редактирования настроек - */ -void unitemp_SensorsList_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - //Добавление в список доступных датчиков - for(uint8_t i = 0; i < unitemp_sensors_getTypesCount(); i++) { - if(unitemp_sensors_getTypes()[i]->altname == NULL) { - variable_item_list_add( - variable_item_list, unitemp_sensors_getTypes()[i]->typename, 1, NULL, app); - } else { - variable_item_list_add( - variable_item_list, unitemp_sensors_getTypes()[i]->altname, 1, NULL, app); - } - } - variable_item_list_add(variable_item_list, "I don't know what to choose", 1, NULL, app); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); -} - -void unitemp_SensorsList_switch(void) { - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_SensorsList_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); -} \ No newline at end of file diff --git a/applications/external/unitemp/views/Settings_view.c b/applications/external/unitemp/views/Settings_view.c deleted file mode 100644 index 3d1eca906..000000000 --- a/applications/external/unitemp/views/Settings_view.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include - -//Текущий вид -static View* view; -//Список -static VariableItemList* variable_item_list; - -static const char states[2][9] = {"Auto", "Infinity"}; -static const char temp_units[UT_TEMP_COUNT][3] = {"*C", "*F"}; -static const char pressure_units[UT_PRESSURE_COUNT][6] = {"mm Hg", "in Hg", "kPa", "hPA"}; -static const char heat_index_bool[2][4] = {"OFF", "ON"}; - -//Элемент списка - бесконечная подсветка -VariableItem* infinity_backlight_item; -//Единица измерения температуры -VariableItem* temperature_unit_item; -//Единица измерения давления -VariableItem* pressure_unit_item; - -VariableItem* heat_index_item; -#define VIEW_ID UnitempViewSettings - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _exit_callback(void* context) { - UNUSED(context); - //Костыль с зависающей подсветкой - if((bool)variable_item_get_current_value_index(infinity_backlight_item) != - app->settings.infinityBacklight) { - if((bool)variable_item_get_current_value_index(infinity_backlight_item)) { - notification_message(app->notifications, &sequence_display_backlight_enforce_on); - } else { - notification_message(app->notifications, &sequence_display_backlight_enforce_auto); - } - } - - app->settings.infinityBacklight = - (bool)variable_item_get_current_value_index(infinity_backlight_item); - app->settings.temp_unit = variable_item_get_current_value_index(temperature_unit_item); - app->settings.pressure_unit = variable_item_get_current_value_index(pressure_unit_item); - app->settings.heat_index = variable_item_get_current_value_index(heat_index_item); - unitemp_saveSettings(); - unitemp_loadSettings(); - - //Возврат предыдущий вид - return UnitempViewMainMenu; -} -/** - * @brief Функция обработки нажатия средней кнопки - * - * @param context Указатель на данные приложения - * @param index На каком элементе списка была нажата кнопка - */ -static void _enter_callback(void* context, uint32_t index) { - UNUSED(context); - UNUSED(index); -} - -static void _setting_change_callback(VariableItem* item) { - if(item == infinity_backlight_item) { - variable_item_set_current_value_text( - infinity_backlight_item, - states[variable_item_get_current_value_index(infinity_backlight_item)]); - } - if(item == temperature_unit_item) { - variable_item_set_current_value_text( - temperature_unit_item, - temp_units[variable_item_get_current_value_index(temperature_unit_item)]); - } - if(item == pressure_unit_item) { - variable_item_set_current_value_text( - pressure_unit_item, - pressure_units[variable_item_get_current_value_index(pressure_unit_item)]); - } - if(item == heat_index_item) { - variable_item_set_current_value_text( - heat_index_item, - heat_index_bool[variable_item_get_current_value_index(heat_index_item)]); - } -} - -/** - * @brief Создание меню редактирования настроек - */ -void unitemp_Settings_alloc(void) { - variable_item_list = variable_item_list_alloc(); - //Сброс всех элементов меню - variable_item_list_reset(variable_item_list); - - infinity_backlight_item = variable_item_list_add( - variable_item_list, "Backlight time", UT_TEMP_COUNT, _setting_change_callback, app); - temperature_unit_item = - variable_item_list_add(variable_item_list, "Temp. unit", 2, _setting_change_callback, app); - pressure_unit_item = variable_item_list_add( - variable_item_list, "Press. unit", UT_PRESSURE_COUNT, _setting_change_callback, app); - heat_index_item = variable_item_list_add( - variable_item_list, "Calc. heat index", 2, _setting_change_callback, app); - - //Добавление колбека на нажатие средней кнопки - variable_item_list_set_enter_callback(variable_item_list, _enter_callback, app); - - //Создание вида из списка - view = variable_item_list_get_view(variable_item_list); - //Добавление колбека на нажатие кнопки "Назад" - view_set_previous_callback(view, _exit_callback); - //Добавление вида в диспетчер - view_dispatcher_add_view(app->view_dispatcher, VIEW_ID, view); -} - -void unitemp_Settings_switch(void) { - //Обнуление последнего выбранного пункта - variable_item_list_set_selected_item(variable_item_list, 0); - - variable_item_set_current_value_index( - infinity_backlight_item, (uint8_t)app->settings.infinityBacklight); - variable_item_set_current_value_text( - infinity_backlight_item, - states[variable_item_get_current_value_index(infinity_backlight_item)]); - - variable_item_set_current_value_index(temperature_unit_item, (uint8_t)app->settings.temp_unit); - variable_item_set_current_value_text( - temperature_unit_item, - temp_units[variable_item_get_current_value_index(temperature_unit_item)]); - - variable_item_set_current_value_index( - pressure_unit_item, (uint8_t)app->settings.pressure_unit); - variable_item_set_current_value_text( - pressure_unit_item, - pressure_units[variable_item_get_current_value_index(pressure_unit_item)]); - - variable_item_set_current_value_index(heat_index_item, (uint8_t)app->settings.heat_index); - variable_item_set_current_value_text( - heat_index_item, heat_index_bool[variable_item_get_current_value_index(heat_index_item)]); - - view_dispatcher_switch_to_view(app->view_dispatcher, VIEW_ID); -} - -void unitemp_Settings_free(void) { - //Очистка списка элементов - variable_item_list_free(variable_item_list); - //Очистка вида - view_free(view); - //Удаление вида после обработки - view_dispatcher_remove_view(app->view_dispatcher, VIEW_ID); -} diff --git a/applications/external/unitemp/views/UnitempViews.h b/applications/external/unitemp/views/UnitempViews.h deleted file mode 100644 index b78cf2b28..000000000 --- a/applications/external/unitemp/views/UnitempViews.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#ifndef UNITEMP_SCENES -#define UNITEMP_SCENES - -#include "../unitemp.h" - -//Виды менюшек -typedef enum UnitempViews { - UnitempViewGeneral, - UnitempViewMainMenu, - UnitempViewSettings, - UnitempViewSensorsList, - UnitempViewSensorEdit, - UnitempViewSensorNameEdit, - UnitempViewSensorActions, - UnitempViewWidget, - UnitempViewPopup, - - UnitempViewsCount -} UnitempViews; - -/** - * @brief Вывести всплывающее окно - * - * @param icon Указатель на иконку - * @param header Заголовок - * @param message Сообщение - * @param prev_view_id ID вида куда в который нужно вернуться - */ -void unitemp_popup(const Icon* icon, char* header, char* message, uint32_t prev_view_id); - -/* Общий вид на датчики */ -void unitemp_General_alloc(void); -void unitemp_General_switch(void); -void unitemp_General_free(void); - -/* Главное меню */ -void unitemp_MainMenu_alloc(void); -void unitemp_MainMenu_switch(void); -void unitemp_MainMenu_free(void); - -/* Настройки */ -void unitemp_Settings_alloc(void); -void unitemp_Settings_switch(void); -void unitemp_Settings_free(void); - -/* Список датчиков */ -void unitemp_SensorsList_alloc(void); -void unitemp_SensorsList_switch(void); -void unitemp_SensorsList_free(void); - -/* Редактор датчка */ -void unitemp_SensorEdit_alloc(void); -//sensor - указатель на редактируемый датчик -void unitemp_SensorEdit_switch(Sensor* sensor); -void unitemp_SensorEdit_free(void); - -/* Редактор имени датчика */ -void unitemp_SensorNameEdit_alloc(void); -void unitemp_SensorNameEdit_switch(Sensor* sensor); -void unitemp_SensorNameEdit_free(void); - -/* Список действий с датчиком */ -void unitemp_SensorActions_alloc(void); -void unitemp_SensorActions_switch(Sensor* sensor); -void unitemp_SensorActions_free(void); - -/* Виджеты */ -void unitemp_widgets_alloc(void); -void unitemp_widgets_free(void); - -/* Подтверждение удаления */ -void unitemp_widget_delete_switch(Sensor* sensor); -/* Помощь */ -void unitemp_widget_help_switch(void); -/* О приложении */ -void unitemp_widget_about_switch(void); -#endif \ No newline at end of file diff --git a/applications/external/unitemp/views/Widgets_view.c b/applications/external/unitemp/views/Widgets_view.c deleted file mode 100644 index 3055930cf..000000000 --- a/applications/external/unitemp/views/Widgets_view.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022-2023 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "UnitempViews.h" -#include "unitemp_icons.h" -#include - -// extern const Icon I_DolphinCommon_56x48; - -void unitemp_widgets_alloc(void) { - app->widget = widget_alloc(); - view_dispatcher_add_view( - app->view_dispatcher, UnitempViewWidget, widget_get_view(app->widget)); -} - -void unitemp_widgets_free(void) { - view_dispatcher_remove_view(app->view_dispatcher, UnitempViewWidget); - widget_free(app->widget); -} - -/* ================== Подтверждение удаления ================== */ -Sensor* current_sensor; -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _delete_exit_callback(void* context) { - UNUSED(context); - //Возвращаем ID вида, в который нужно вернуться - return UnitempViewSensorActions; -} -/** - * @brief Обработчик нажатий на кнопку в виджете - * - * @param result Какая из кнопок была нажата - * @param type Тип нажатия - * @param context Указатель на данные плагина - */ -static void _delete_click_callback(GuiButtonType result, InputType type, void* context) { - UNUSED(context); - //Коротко нажата левая кнопка (Cancel) - if(result == GuiButtonTypeLeft && type == InputTypeShort) { - unitemp_SensorActions_switch(current_sensor); - } - //Коротко нажата правая кнопка (Delete) - if(result == GuiButtonTypeRight && type == InputTypeShort) { - //Удаление датчика - unitemp_sensor_delete(current_sensor); - //Выход из меню - unitemp_General_switch(); - } -} -/** - * @brief Переключение в виджет удаления датчика - */ -void unitemp_widget_delete_switch(Sensor* sensor) { - current_sensor = sensor; - //Очистка виджета - widget_reset(app->widget); - //Добавление кнопок - widget_add_button_element( - app->widget, GuiButtonTypeLeft, "Cancel", _delete_click_callback, app); - widget_add_button_element( - app->widget, GuiButtonTypeRight, "Delete", _delete_click_callback, app); - - snprintf(app->buff, BUFF_SIZE, "\e#Delete %s?\e#", current_sensor->name); - widget_add_text_box_element( - app->widget, 0, 0, 128, 23, AlignCenter, AlignCenter, app->buff, false); - - if(current_sensor->type->interface == &ONE_WIRE) { - OneWireSensor* s = current_sensor->instance; - - snprintf( - app->buff, - BUFF_SIZE, - "\e#Type:\e# %s", - unitemp_onewire_sensor_getModel(current_sensor)); - widget_add_text_box_element( - app->widget, 0, 16, 128, 23, AlignLeft, AlignTop, app->buff, false); - snprintf(app->buff, BUFF_SIZE, "\e#GPIO:\e# %s", s->bus->gpio->name); - widget_add_text_box_element( - app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false); - - snprintf( - app->buff, - BUFF_SIZE, - "\e#ID:\e# %02X%02X%02X%02X%02X%02X%02X%02X", - s->deviceID[0], - s->deviceID[1], - s->deviceID[2], - s->deviceID[3], - s->deviceID[4], - s->deviceID[5], - s->deviceID[6], - s->deviceID[7]); - widget_add_text_box_element( - app->widget, 0, 40, 128, 23, AlignLeft, AlignTop, app->buff, false); - } - - if(current_sensor->type->interface == &SINGLE_WIRE) { - snprintf(app->buff, BUFF_SIZE, "\e#Type:\e# %s", current_sensor->type->typename); - widget_add_text_box_element( - app->widget, 0, 16, 128, 23, AlignLeft, AlignTop, app->buff, false); - snprintf( - app->buff, - BUFF_SIZE, - "\e#GPIO:\e# %s", - ((SingleWireSensor*)current_sensor->instance)->gpio->name); - widget_add_text_box_element( - app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false); - } - - if(current_sensor->type->interface == &I2C) { - snprintf(app->buff, BUFF_SIZE, "\e#Type:\e# %s", current_sensor->type->typename); - widget_add_text_box_element( - app->widget, 0, 16, 128, 23, AlignLeft, AlignTop, app->buff, false); - snprintf( - app->buff, - BUFF_SIZE, - "\e#I2C addr:\e# 0x%02X", - ((I2CSensor*)current_sensor->instance)->currentI2CAdr >> 1); - widget_add_text_box_element( - app->widget, 0, 28, 128, 23, AlignLeft, AlignTop, app->buff, false); - } - - view_set_previous_callback(widget_get_view(app->widget), _delete_exit_callback); - view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewWidget); -} - -/* ========================== Помощь ========================== */ - -/** - * @brief Функция обработки нажатия кнопки "Назад" - * - * @param context Указатель на данные приложения - * @return ID вида в который нужно переключиться - */ -static uint32_t _help_exit_callback(void* context) { - UNUSED(context); - //Возвращаем ID вида, в который нужно вернуться - return UnitempViewGeneral; -} - -/** - * @brief Переключение в виджет помощи - */ -void unitemp_widget_help_switch(void) { - //Очистка виджета - widget_reset(app->widget); - - widget_add_icon_element(app->widget, 3, 7, &I_repo_qr_50x50); - widget_add_icon_element(app->widget, 71, 15, &I_DolphinCommon_56x48); - - widget_add_string_multiline_element( - app->widget, 55, 5, AlignLeft, AlignTop, FontSecondary, "You can find help\nthere"); - - widget_add_frame_element(app->widget, 0, 0, 128, 63, 7); - widget_add_frame_element(app->widget, 0, 0, 128, 64, 7); - - view_set_previous_callback(widget_get_view(app->widget), _help_exit_callback); - view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewWidget); -} - -/* ========================== О приложении ========================== */ - -/** - * @brief Переключение в виджет о приложении - */ -void unitemp_widget_about_switch(void) { - //Очистка виджета - widget_reset(app->widget); - - widget_add_frame_element(app->widget, 0, 0, 128, 63, 7); - widget_add_frame_element(app->widget, 0, 0, 128, 64, 7); - - snprintf(app->buff, BUFF_SIZE, "#Unitemp %s#", UNITEMP_APP_VER); - widget_add_text_box_element( - app->widget, 0, 4, 128, 12, AlignCenter, AlignCenter, app->buff, false); - - widget_add_text_scroll_element( - app->widget, - 4, - 16, - 121, - 44, - "Universal plugin for viewing the values of temperature\nsensors\n\e#Author: Quenon\ngithub.com/quen0n\n\e#Designer: Svaarich\ngithub.com/Svaarich\n\e#Issues & suggestions\ntiny.one/unitemp"); - - view_set_previous_callback(widget_get_view(app->widget), _help_exit_callback); - view_dispatcher_switch_to_view(app->view_dispatcher, UnitempViewWidget); -} diff --git a/applications/external/videopoker/application.fam b/applications/external/videopoker/application.fam deleted file mode 100644 index 4997132f2..000000000 --- a/applications/external/videopoker/application.fam +++ /dev/null @@ -1,15 +0,0 @@ -App( - appid="videopoker", - name="Video Poker", - apptype=FlipperAppType.EXTERNAL, - entry_point="video_poker_app", - cdefines=["APP_VIDEOPOKER_GAME"], - requires=["gui"], - stack_size=2 * 1024, - fap_icon="pokerIcon.png", - fap_category="Games", - fap_author="@PixlEmly", - fap_weburl="https://github.com/PixlEmly", - fap_version="1.0", - fap_description="Video poker is a casino game based on five-card draw poker", -) diff --git a/applications/external/videopoker/poker.c b/applications/external/videopoker/poker.c deleted file mode 100644 index 20881529c..000000000 --- a/applications/external/videopoker/poker.c +++ /dev/null @@ -1,819 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -/* Core game logic from -https://github.com/Yaoir/VideoPoker-C -*/ - -/* KNOWN BUGS -This has been converted from a standalone PC console app to flipper -All of the original input/output handing code has been ripped out -Original code also used TONS of defines and everything was a global. -As is, it does what I wanted and doesn't seem to have major issues, so that's pretty good. -Game logic is handled during input and this is a bit of a mess of nested ifs. -Sometimes duplicate cards will show up. there is a function to test this. I should use it better. - -*/ - -#define TAG "Video Poker" - -static void Shake(void) { - NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION); - notification_message(notification, &sequence_single_vibro); - furi_record_close(RECORD_NOTIFICATION); -} - -typedef struct { - int index; /* cards value, minus 1 */ - char* sym; /* text appearance */ - int suit; /* card's suit (see just below) */ - int gone; /* true if it's been dealt */ - int held; /* for hand */ -} PokerPlayer_card; - -typedef struct { - FuriMutex** model_mutex; - FuriMessageQueue* event_queue; - ViewPort* view_port; - Gui* gui; - PokerPlayer_card hand[5]; - PokerPlayer_card shand[5]; - PokerPlayer_card deck[52]; - int GameType; /* What rules are we using */ - int held[5]; - int score; - int highscore; - int pot; - int GameState; - int selected; - int bet; - int minbet; -} PokerPlayer; - -/* GameState -0=Splash/help, OK button (later on up/down for rules or settings) -1=cards down, betting enabled, left/right to change bet, OK to confirm -2=first hand, holding enabled, left/right to pick card, OK to hold/unhold card, down to confirm -3=second hand, only confirm to claim rewards -4=game over/won -5=WIP saving gamestate -*/ - -/* -#define AllAmerican 0 -#define TensOrBetter 1 -#define BonusPoker 2 -#define DoubleBonus 3 -#define DoubleBonusBonus 4 -#define JacksOrBetter 5 -#define JacksOrBetter95 6 -#define JacksOrBetter86 7 -#define JacksOrBetter85 8 -#define JacksOrBetter75 9 -#define JacksOrBetter65 10 -#define NUMGAMES 11 -*/ -/* - The game in play. Default is Jacks or Better, - which is coded into initialization of static data -*/ -const char* gamenames[11] = { - "All American", - "Tens or Better", - "Bonus Poker", - "Double Bonus", - "Double Bonus Bonus", - "Jacks or Better", - "9/5 Jacks or Better", - "8/6 Jacks or Better", - "8/5 Jacks or Better", - "7/5 Jacks or Better", - "6/5 Jacks or Better"}; - -PokerPlayer_card deck[52] = { - /* index, card name, suit, gone */ - /* Clubs:0 Diamonds:1 Hearts: 2 Spades: 3 */ - {1, "2", 0, 0, 0}, {2, "3", 0, 0, 0}, {3, "4", 0, 0, 0}, {4, "5", 0, 0, 0}, - {5, "6", 0, 0, 0}, {6, "7", 0, 0, 0}, {7, "8", 0, 0, 0}, {8, "9", 0, 0, 0}, - {9, "10", 0, 0, 0}, {10, "J", 0, 0, 0}, {11, "Q", 0, 0, 0}, {12, "K", 0, 0, 0}, - {13, "A", 0, 0, 0}, - - {1, "2", 1, 0, 0}, {2, "3", 1, 0, 0}, {3, "4", 1, 0, 0}, {4, "5", 1, 0, 0}, - {5, "6", 1, 0, 0}, {6, "7", 1, 0, 0}, {7, "8", 1, 0, 0}, {8, "9", 1, 0, 0}, - {9, "10", 1, 0, 0}, {10, "J", 1, 0, 0}, {11, "Q", 1, 0, 0}, {12, "K", 1, 0, 0}, - {13, "A", 1, 0, 0}, - - {1, "2", 2, 0, 0}, {2, "3", 2, 0, 0}, {3, "4", 2, 0, 0}, {4, "5", 2, 0, 0}, - {5, "6", 2, 0, 0}, {6, "7", 2, 0, 0}, {7, "8", 2, 0, 0}, {8, "9", 2, 0, 0}, - {9, "10", 2, 0, 0}, {10, "J", 2, 0, 0}, {11, "Q", 2, 0, 0}, {12, "K", 2, 0, 0}, - {13, "A", 2, 0, 0}, - - {1, "2", 3, 0, 0}, {2, "3", 3, 0, 0}, {3, "4", 3, 0, 0}, {4, "5", 3, 0, 0}, - {5, "6", 3, 0, 0}, {6, "7", 3, 0, 0}, {7, "8", 3, 0, 0}, {8, "9", 3, 0, 0}, - {9, "10", 3, 0, 0}, {10, "J", 3, 0, 0}, {11, "Q", 3, 0, 0}, {12, "K", 3, 0, 0}, - {13, "A", 3, 0, 0}, -}; - -/* -Image Format -0x01 = Compressed -0x00 = Reserved Section -0xa4,0x01 = 0x1a4, or, 420 - the size of the compressed array, minus this header. -Rest of the data is char array output from heatshrink of the original XBM char array. -Calculated Header: 0x01,0x00,0xa4,0x01 -from furi_hal_compress.c: -typedef struct { - uint8_t is_compressed; - uint8_t reserved; - uint16_t compressed_buff_size; -} FuriHalCompressHeader; -*/ - -const uint8_t _I_Splash_128x64_0[] = { - 0x01, 0x00, 0x8a, 0x02, 0x00, 0x78, 0x02, 0x60, 0xe0, 0x54, 0xc0, 0x03, 0x9f, 0xc0, 0x0f, 0x5a, - 0x04, 0x04, 0x1e, 0xdf, 0x08, 0x78, 0x0c, 0x60, 0xc0, 0x21, 0x90, 0x40, 0xa3, 0x00, 0xf5, 0xfe, - 0x61, 0xc1, 0xe9, 0x1e, 0x8e, 0x59, 0xf0, 0x02, 0x24, 0x9f, 0x70, 0xc0, 0x63, 0x03, 0x01, 0x0c, - 0x0b, 0xc1, 0x80, 0xbc, 0x83, 0xd3, 0x3f, 0x63, 0x98, 0x03, 0xcf, 0x88, 0x02, 0x1c, 0x31, 0x5d, - 0x38, 0xf6, 0x19, 0xc0, 0xa0, 0xfc, 0x93, 0x13, 0x12, 0xf0, 0x38, 0x76, 0x08, 0xc7, 0x00, 0x1e, - 0x5e, 0x8b, 0xcc, 0x32, 0x86, 0x0f, 0x4f, 0x0c, 0x80, 0x06, 0x20, 0x72, 0xe4, 0x5e, 0x33, 0xd4, - 0x73, 0xf2, 0x5d, 0xe2, 0x10, 0xef, 0xe6, 0x02, 0x0f, 0x07, 0x84, 0x4c, 0x33, 0xd2, 0x70, 0x79, - 0xd8, 0x2e, 0x11, 0x88, 0x3d, 0xff, 0xc1, 0xc7, 0x83, 0xc4, 0x20, 0x10, 0xc9, 0x18, 0x3d, 0x27, - 0x18, 0x8c, 0x3c, 0xde, 0xe1, 0xe6, 0x87, 0x7e, 0x0c, 0x62, 0x12, 0x10, 0x01, 0xce, 0x31, 0x9c, - 0x39, 0x9c, 0x62, 0x67, 0x0f, 0x83, 0x7f, 0x27, 0xe0, 0xf5, 0x8c, 0x71, 0xbc, 0x31, 0x8c, 0xc4, - 0xe2, 0x1e, 0x62, 0x1e, 0x02, 0xe0, 0x80, 0x05, 0x1c, 0xe1, 0xdc, 0x23, 0x97, 0xc8, 0xe4, 0x5c, - 0x12, 0x50, 0x40, 0x7a, 0x43, 0x38, 0x77, 0x88, 0xf4, 0x36, 0x3d, 0x1f, 0x04, 0x94, 0x20, 0x1e, - 0x98, 0xce, 0x0d, 0xbe, 0x37, 0x0d, 0xcd, 0xbd, 0x0c, 0x7e, 0xbe, 0xce, 0x07, 0x1f, 0xf3, 0xfc, - 0xf8, 0xb2, 0x8d, 0x30, 0x20, 0x53, 0xbe, 0x60, 0x06, 0x03, 0x78, 0xf0, 0x06, 0x4c, 0x1e, 0x34, - 0x10, 0x29, 0x5e, 0x05, 0x0f, 0x00, 0xa0, 0x40, 0x24, 0x20, 0x52, 0x76, 0x88, 0x01, 0xc1, 0xe3, - 0x11, 0x05, 0xc3, 0xe9, 0x20, 0x10, 0x97, 0x01, 0xcf, 0xc1, 0xf2, 0x81, 0x3f, 0xe7, 0xfc, 0x66, - 0xf4, 0x02, 0xf1, 0xc0, 0x3f, 0xdf, 0xf0, 0x30, 0xc6, 0x1e, 0xe5, 0xff, 0x81, 0xf0, 0x3f, 0xe5, - 0xb2, 0x80, 0x7f, 0xc1, 0xe5, 0x1c, 0x03, 0x0f, 0xe3, 0xff, 0x1f, 0xf8, 0x02, 0x48, 0x00, 0x31, - 0xfe, 0x0b, 0xa4, 0x61, 0xcc, 0x62, 0xfc, 0x4f, 0xe3, 0x0f, 0x31, 0x41, 0x0e, 0x02, 0x07, 0x01, - 0x07, 0x8a, 0xb4, 0xa3, 0x84, 0x71, 0x8f, 0xff, 0x20, 0x77, 0x00, 0x78, 0x95, 0x46, 0x06, 0x13, - 0x10, 0x78, 0xef, 0x3f, 0x5f, 0xfc, 0xff, 0xea, 0x07, 0xf0, 0x37, 0x90, 0x3c, 0x78, 0x00, 0xf2, - 0xae, 0x7f, 0x77, 0xf7, 0xaf, 0xec, 0x0f, 0x88, 0x41, 0x1b, 0x06, 0x02, 0x03, 0xc0, 0x02, 0x8c, - 0x08, 0x5c, 0x37, 0xff, 0xa9, 0x3c, 0x7b, 0xcc, 0x52, 0xe0, 0x70, 0x7c, 0x31, 0x89, 0xe4, 0xff, - 0xfb, 0xff, 0xdf, 0x8c, 0x46, 0x03, 0x1f, 0x34, 0x17, 0x83, 0xe1, 0x71, 0x8f, 0x6f, 0xe7, 0xe0, - 0xc1, 0x8f, 0xfd, 0x20, 0x18, 0x65, 0x59, 0x47, 0xaf, 0x9b, 0x8b, 0x9e, 0x6f, 0xe7, 0x1f, 0x16, - 0x0c, 0x3e, 0x3d, 0x00, 0xe4, 0x43, 0xd1, 0xe5, 0x3f, 0xe6, 0x6e, 0xfb, 0x39, 0x88, 0x67, 0xea, - 0xff, 0xc5, 0x22, 0x8f, 0xc0, 0xf0, 0x41, 0x71, 0xe7, 0x76, 0xf9, 0x98, 0x48, 0x64, 0x17, 0x59, - 0x38, 0x05, 0x8f, 0xc0, 0xd0, 0x5f, 0xe8, 0x0f, 0x1a, 0xdb, 0xe6, 0xb1, 0xd1, 0xa0, 0x50, 0x85, - 0x59, 0x7e, 0x16, 0x05, 0x06, 0x80, 0x71, 0xbf, 0xf7, 0x19, 0x85, 0x99, 0x74, 0x6d, 0x31, 0x02, - 0x10, 0x88, 0x7c, 0xdd, 0xdb, 0x84, 0x62, 0x7c, 0x0f, 0x38, 0xe5, 0xf0, 0x1e, 0x97, 0xce, 0x67, - 0xbc, 0xb6, 0x40, 0xa3, 0x98, 0x00, 0xc5, 0x76, 0x53, 0x8c, 0x67, 0x1e, 0x07, 0x0e, 0x63, 0x0a, - 0xe4, 0x9c, 0x62, 0x0f, 0x11, 0x41, 0x95, 0x88, 0x1e, 0x41, 0xd1, 0x8c, 0x49, 0x80, 0xe6, 0x00, - 0x50, 0xb8, 0xa3, 0x07, 0xf1, 0x7f, 0x06, 0xb8, 0x00, 0x61, 0xce, 0xb2, 0x9c, 0x53, 0x01, 0xf3, - 0xf0, 0x55, 0x97, 0xd0, 0x3f, 0x40, 0x03, 0xfd, 0x33, 0xc8, 0x01, 0x71, 0x92, 0x78, 0x80, 0x2f, - 0x80, 0x6f, 0x20, 0x03, 0xff, 0x23, 0xe7, 0x02, 0x02, 0x18, 0x01, 0xa3, 0x91, 0x00, 0x18, 0xc3, - 0x20, 0x91, 0xc0, 0x7c, 0x7f, 0x83, 0x42, 0xaa, 0x1f, 0xe0, 0xbe, 0x60, 0x46, 0xa2, 0x81, 0xe2, - 0x24, 0x21, 0xf9, 0x54, 0x14, 0x18, 0x9e, 0x3f, 0xe4, 0x29, 0x00, 0x12, 0x0e, 0xb0, 0x28, 0x50, - 0x3c, 0x60, 0x50, 0x85, 0xf4, 0x7f, 0xb8, 0x3f, 0xf3, 0xf8, 0x83, 0xe0, 0x00, 0x38, 0x6e, 0x0c, - 0xc3, 0xf2, 0x2f, 0x94, 0x09, 0x07, 0xc7, 0xf7, 0x3f, 0xfe, 0x0d, 0xc4, 0x00, 0xfc, 0x4c, 0x05, - 0x86, 0x15, 0x23, 0x92, 0x03, 0xe7, 0xf9, 0x80, 0x0f, 0x97, 0x52, 0x0c, 0x2f, 0xb1, 0xf8, 0xe3, - 0x01, 0xf3, 0x82, 0x27, 0x8d, 0xe6, 0x41, 0x1c, 0x17, 0xcf, 0xfc, 0x3e, 0x64, 0xf8, -}; -const uint8_t* _I_Splash_128x64[] = {_I_Splash_128x64_0}; -const Icon I_Splash_128x64 = - {.width = 128, .height = 64, .frame_count = 1, .frame_rate = 0, .frames = _I_Splash_128x64}; - -/* -const uint8_t _I_BadEnd_128x64_0[] = { - 0x01, 0x00, 0xDF, 0x01, 0x00, 0x2c, 0x12, 0x01, 0x02, 0x80, 0x40, 0x70, 0x10, 0x0a, 0x04, 0x02, - 0x41, 0x3e, 0xcf, 0x63, 0xfb, 0xfe, 0xc8, 0x18, 0x3e, 0x6f, 0xdb, 0xfc, 0xf8, 0x3c, 0x60, 0xe0, - 0xf9, 0xb3, 0x6c, 0xf3, 0x3c, 0x1b, 0x6c, 0x18, 0x5f, 0x40, 0xf1, 0xe7, 0xdb, 0xc1, 0xf4, 0x2f, - 0x10, 0x78, 0xdb, 0xbc, 0xdf, 0xf0, 0x04, 0x59, 0x81, 0xe3, 0xc1, 0xb6, 0x41, 0x83, 0xd1, 0x00, - 0xbf, 0x6c, 0xc9, 0xe6, 0x0f, 0x91, 0xf8, 0x9b, 0xcc, 0x1f, 0x20, 0x06, 0x07, 0xf8, 0x3e, 0x0b, - 0x32, 0x00, 0x50, 0x88, 0xc4, 0x20, 0x10, 0x85, 0xfd, 0x03, 0xfc, 0x1f, 0xe0, 0xff, 0x07, 0xf9, - 0x7f, 0xc3, 0xdc, 0x89, 0x10, 0x7d, 0x00, 0x04, 0x1f, 0xe0, 0xfd, 0xfc, 0x40, 0xc1, 0xfb, 0x07, - 0x8e, 0x2f, 0xf3, 0x9f, 0x00, 0xb0, 0x7f, 0x97, 0xf6, 0x0a, 0x11, 0x10, 0xa3, 0xec, 0x10, 0x21, - 0x32, 0x07, 0xd0, 0x18, 0x40, 0xa2, 0x0f, 0xb0, 0x20, 0x81, 0xc4, 0x1f, 0xeb, 0xfa, 0xbf, 0x84, - 0x86, 0x01, 0xc8, 0x5f, 0xd0, 0x0c, 0x81, 0xe2, 0x05, 0x10, 0x7e, 0xdc, 0xc1, 0xf5, 0x01, 0xe0, - 0x41, 0xf2, 0x17, 0xf0, 0x7d, 0xaf, 0x0a, 0x7e, 0x0f, 0xbf, 0x84, 0x7f, 0x21, 0x1f, 0x2b, 0x8e, - 0x3c, 0xbe, 0xd3, 0xf0, 0x78, 0xc4, 0xfa, 0x0b, 0xf2, 0x00, 0x08, 0x81, 0xa1, 0xf3, 0x08, 0x9f, - 0xc0, 0x1e, 0x57, 0x00, 0x7b, 0x60, 0x60, 0x3e, 0x08, 0x4f, 0x80, 0x1e, 0x59, 0x05, 0xc1, 0x03, - 0xce, 0xc3, 0x00, 0x2f, 0x88, 0x3c, 0xe2, 0x10, 0x20, 0x78, 0xbd, 0xc6, 0xff, 0x7c, 0x8c, 0x0e, - 0x48, 0x1e, 0x90, 0x48, 0x47, 0xe2, 0x06, 0x1b, 0x1e, 0x3c, 0x1c, 0x1e, 0x80, 0x01, 0x93, 0xad, - 0x06, 0x1e, 0x0a, 0x28, 0x04, 0x18, 0x1e, 0x81, 0xe1, 0x90, 0x20, 0x46, 0x49, 0xa9, 0x91, 0x3e, - 0x46, 0xf8, 0x0f, 0xac, 0x48, 0x3c, 0xb0, 0x82, 0x52, 0x07, 0xa1, 0x08, 0x43, 0xe5, 0x72, 0x93, - 0x41, 0x7e, 0x01, 0x01, 0x07, 0xc7, 0x8a, 0x97, 0xa9, 0x39, 0x88, 0xa0, 0x7f, 0x00, 0xf2, 0x08, - 0x0c, 0x03, 0x25, 0x54, 0x88, 0xe9, 0x66, 0x11, 0xc2, 0x99, 0x9e, 0x07, 0xff, 0x13, 0x90, 0x7f, - 0xb2, 0x60, 0xf2, 0xaa, 0x79, 0x1b, 0xe5, 0x01, 0xfe, 0x1f, 0xca, 0x41, 0x08, 0xb0, 0xd4, 0xe2, - 0x33, 0x9c, 0x9f, 0x13, 0xff, 0x07, 0xc0, 0x0c, 0x04, 0x1e, 0x54, 0x08, 0x40, 0x64, 0x80, 0x03, - 0x84, 0xff, 0xc0, 0x68, 0x10, 0x0f, 0x80, 0x3d, 0x13, 0xc2, 0x00, 0x28, 0x25, 0xfa, 0x00, 0x0f, - 0x76, 0x60, 0x83, 0xcc, 0x04, 0x20, 0xc1, 0x07, 0xaf, 0xc8, 0x52, 0x52, 0x00, 0x7a, 0x2f, 0xcc, - 0x16, 0x31, 0x30, 0x49, 0x48, 0x17, 0xe5, 0x20, 0xc0, 0x23, 0xce, 0x81, 0x80, 0x88, 0xe6, 0x24, - 0x7c, 0x69, 0xc0, 0xd0, 0xa2, 0x1c, 0x00, 0x79, 0x85, 0x07, 0xe3, 0xa4, 0xb0, 0x4a, 0x64, 0xa0, - 0xf3, 0x57, 0x9d, 0x82, 0x01, 0x80, 0x84, 0x54, 0xb2, 0x19, 0x48, 0x91, 0x90, 0xa2, 0x1f, 0x00, - 0x79, 0x0f, 0x87, 0x80, 0x0f, 0x44, 0x21, 0x03, 0xd0, 0x3e, 0x26, 0x01, 0xa6, 0x44, 0x2c, 0x79, - 0xc0, 0x79, 0xb3, 0xc4, 0xbe, 0x5e, 0x01, 0x08, 0x80, 0x09, 0x56, 0x20, 0x01, 0x98, 0x03, 0xc4, - 0xfe, 0x51, 0x0b, 0xf8, 0x3c, 0xf8, 0x00, 0x32, 0x9c, 0x7f, 0x01, 0xe8, 0x1f, 0x40, 0x21, 0xd7, - 0x81, 0xfb, 0x80, 0xcf, 0x8f, 0x44, 0x1e, 0x7c, 0x88, 0x38, 0x28, 0x70, 0xe4, 0x92, 0xff, 0xc7, - 0xef, 0x1f, 0x80, -}; -const uint8_t* _I_BadEnd_128x64[] = {_I_BadEnd_128x64_0}; -const Icon I_BadEnd_128x64 = - {.width = 128, .height = 64, .frame_count = 1, .frame_rate = 0, .frames = _I_BadEnd_128x64}; -*/ /* space savings until external apps are possible */ -const uint8_t _I_Hand_12x10_0[] = { - 0x01, 0x00, 0x11, 0x00, 0x8c, 0x40, 0x25, 0x00, 0x16, 0xb4, 0x40, - 0x35, 0x10, 0x1d, 0x5c, 0x1b, 0x5b, 0x0a, 0x84, 0xc2, 0x80, -}; -const uint8_t* _I_Hand_12x10[] = {_I_Hand_12x10_0}; -const Icon I_Hand_12x10 = - {.width = 12, .height = 10, .frame_count = 1, .frame_rate = 0, .frames = _I_Hand_12x10}; - -const uint8_t _I_CardBack_22x35_0[] = { - 0x01, 0x00, 0x23, 0x00, 0xfe, 0x7f, 0xe1, 0xf0, 0x28, 0x04, 0x43, 0xe3, 0xff, - 0x91, 0xea, 0x75, 0x52, 0x6a, 0xad, 0x56, 0x5b, 0xad, 0xd5, 0x4a, 0x80, 0xbe, - 0x05, 0xf0, 0x2f, 0x81, 0x7c, 0x0b, 0x45, 0x32, 0x2c, 0x91, 0x7c, 0x8c, 0xa4, -}; -const uint8_t* _I_CardBack_22x35[] = {_I_CardBack_22x35_0}; -const Icon I_CardBack_22x35 = - {.width = 22, .height = 35, .frame_count = 1, .frame_rate = 0, .frames = _I_CardBack_22x35}; - -//uncompressed but lol -const uint8_t _I_club_7x8_0[] = {0x00, 0x08, 0x1c, 0x1c, 0x6b, 0x7f, 0x36, 0x08, 0x1c}; -const uint8_t* _I_club_7x8[] = {_I_club_7x8_0}; -const Icon I_club_7x8 = - {.width = 7, .height = 8, .frame_count = 1, .frame_rate = 0, .frames = _I_club_7x8}; - -//uncompressed but lol -const uint8_t _I_diamond_7x8_0[] = {0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x3e, 0x1c, 0x08}; -const uint8_t* _I_diamond_7x8[] = {_I_diamond_7x8_0}; -const Icon I_diamond_7x8 = - {.width = 7, .height = 8, .frame_count = 1, .frame_rate = 0, .frames = _I_diamond_7x8}; - -//uncompressed -const uint8_t _I_hearts_7x8_0[] = {0x00, 0x00, 0x36, 0x7f, 0x7f, 0x7f, 0x3e, 0x1c, 0x08}; -const uint8_t* _I_hearts_7x8[] = {_I_hearts_7x8_0}; -const Icon I_hearts_7x8 = - {.width = 7, .height = 8, .frame_count = 1, .frame_rate = 0, .frames = _I_hearts_7x8}; - -//uncompressed -const uint8_t _I_spade_7x8_0[] = {0x00, 0x08, 0x1c, 0x3e, 0x7f, 0x7f, 0x36, 0x08, 0x1c}; -const uint8_t* _I_spade_7x8[] = {_I_spade_7x8_0}; -const Icon I_spade_7x8 = - {.width = 7, .height = 8, .frame_count = 1, .frame_rate = 0, .frames = _I_spade_7x8}; - -// They only included Numeric Profont22 glyphs and I don't want to fuck up the font embeds right now sooo.. - -const uint8_t _I_King_7x8_0[] = { - 0x01, 0x00, 0x1a, 0x00, 0xc1, 0xc0, 0xf8, 0x70, 0x1f, 0x1c, 0x02, 0xe7, 0x00, 0x9d, 0xc0, - 0x23, 0xf0, 0x08, 0x78, 0x0c, 0x80, 0xe2, 0x0b, 0x10, 0x78, 0x84, 0xc4, 0x2e, 0x20, 0x01, -}; -const uint8_t* _I_King_7x8[] = {_I_King_7x8_0}; -const Icon I_King_7x8 = - {.width = 10, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_King_7x8}; - -const uint8_t _I_Queen_7x8_0[] = { - 0x01, 0x00, 0x13, 0x00, 0xfe, 0x40, 0x3f, 0xd0, 0x1c, 0x3c, 0x0c, 0x01, - 0x76, 0x38, 0x1f, 0x8e, 0x07, 0xc7, 0x81, 0x85, 0x47, 0xf9, 0x01, -}; -const uint8_t* _I_Queen_7x8[] = {_I_Queen_7x8_0}; -const Icon I_Queen_7x8 = - {.width = 10, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_Queen_7x8}; - -const uint8_t _I_Jack_7x8_0[] = { - 0x01, - 0x00, - 0x0D, - 0x00, - 0x80, - 0x40, - 0xc0, - 0x3a, - 0x00, - 0x5c, - 0x3c, - 0x0f, - 0xfd, - 0x01, - 0xfe, - 0x40, - 0x00, -}; -const uint8_t* _I_Jack_7x8[] = {_I_Jack_7x8_0}; -const Icon I_Jack_7x8 = - {.width = 10, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_Jack_7x8}; - -const uint8_t _I_Ace_7x8_0[] = { - 0x01, 0x00, 0x13, 0x00, 0x98, 0x40, 0x2f, 0x00, 0x12, 0xe6, 0x00, 0x4b, - 0x0d, 0x01, 0x00, 0x8c, 0x0e, 0x07, 0xff, 0x00, 0x90, 0x01, 0xc0, -}; -const uint8_t* _I_Ace_7x8[] = {_I_Ace_7x8_0}; -const Icon I_Ace_7x8 = - {.width = 10, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_Ace_7x8}; - -const uint8_t _I_Ten_7x8_0[] = { - 0x01, 0x00, 0x29, 0x00, 0x86, 0x7f, 0x00, 0x43, 0xfe, 0x80, 0xc3, 0xf0, 0xf0, 0x38, 0x7e, - 0x0e, 0x07, 0x0c, 0xe1, 0x80, 0x87, 0xc6, 0x02, 0x1b, 0x98, 0x08, 0x67, 0x60, 0x21, 0x8f, - 0x80, 0x86, 0x1e, 0x02, 0x18, 0x38, 0x08, 0x43, 0x43, 0x7f, 0x10, 0x0d, 0xfc, 0x4c, 0x20, -}; -const uint8_t* _I_Ten_7x8[] = {_I_Ten_7x8_0}; -const Icon I_Ten_7x8 = - {.width = 18, .height = 14, .frame_count = 1, .frame_rate = 0, .frames = _I_Ten_7x8}; - -const Icon card_suit[4] = {I_diamond_7x8, I_club_7x8, I_hearts_7x8, I_spade_7x8}; - -const Icon card_face[5] = {I_Ten_7x8, I_Jack_7x8, I_Queen_7x8, I_King_7x8, I_Ace_7x8}; - -/* Sanity check: check that there are no duplicate cards in hand */ - -static void playcard(PokerPlayer* app) { - int i, c, crd; - - int hold[5]; - hold[5] = 2; - // int digit; - c = 1; - c++; - c = hold[5]; /* FIX for unused-but-set-variable */ - /* initialize deck */ - for(i = 0; i < 52; i++) deck[i].gone = 0; - - /* initialize hold[] */ - for(i = 0; i < 5; i++) hold[i] = 1; - - /* app->score -= bet; */ - if(app->score > app->highscore) { - app->highscore = app->score; - } /* record high water mark */ - - for(i = 0; i < 5; i++) { - /* find a card not already dealt */ - do crd = random() % 52; - while(deck[crd].gone); - hold[i] = 1; - deck[crd].gone = 1; - if(!app->held[i]) { - app->hand[i] = deck[crd]; - } - } -} - -static int check_for_dupes(PokerPlayer* app) { - int i, j; - - for(i = 0; i < 5; i++) { - for(j = i + 1; j < 5; j++) { - if(app->hand[i].index == app->hand[j].index && app->hand[i].suit == app->hand[j].suit) - return 0; - } - } - - return 1; -} - -/* Functions that recognize winning hands */ - -/* - Flush: - returns 1 if the sorted hand is a flush -*/ - -static int flush(PokerPlayer* app) { - if(app->shand[0].suit == app->shand[1].suit && app->shand[1].suit == app->shand[2].suit && - app->shand[2].suit == app->shand[3].suit && app->shand[3].suit == app->shand[4].suit) - return 1; - - return 0; -} - -/* - Straight: - returns 1 if the sorted hand is a straight -*/ - -static int straight(PokerPlayer* app) { - if(app->shand[1].index == app->shand[0].index + 1 && - app->shand[2].index == app->shand[1].index + 1 && - app->shand[3].index == app->shand[2].index + 1 && - app->shand[4].index == app->shand[3].index + 1) - return 1; - - /* Ace low straight: Ace, 2, 3, 4, 5 */ - - if(app->shand[4].index == 13 && app->shand[0].index == 1 && app->shand[1].index == 2 && - app->shand[2].index == 3 && app->shand[3].index == 4) - return 1; - - return 0; -} - -/* - Four of a kind: - the middle 3 all match, and the first or last matches those -*/ - -static int four(PokerPlayer* app) { - if((app->shand[1].index == app->shand[2].index && - app->shand[2].index == app->shand[3].index) && - (app->shand[0].index == app->shand[2].index || app->shand[4].index == app->shand[2].index)) - return 1; - - return 0; -} - -/* - Full house: - 3 of a kind and a pair -*/ - -static int full(PokerPlayer* app) { - if(app->shand[0].index == app->shand[1].index && - (app->shand[2].index == app->shand[3].index && app->shand[3].index == app->shand[4].index)) - return 1; - - if(app->shand[3].index == app->shand[4].index && - (app->shand[0].index == app->shand[1].index && app->shand[1].index == app->shand[2].index)) - return 1; - - return 0; -} - -/* - Three of a kind: - it can appear 3 ways -*/ - -static int three(PokerPlayer* app) { - if(app->shand[0].index == app->shand[1].index && app->shand[1].index == app->shand[2].index) - return 1; - - if(app->shand[1].index == app->shand[2].index && app->shand[2].index == app->shand[3].index) - return 1; - - if(app->shand[2].index == app->shand[3].index && app->shand[3].index == app->shand[4].index) - return 1; - - return 0; -} - -/* - Two pair: - it can appear in 3 ways -*/ - -static int twopair(PokerPlayer* app) { - if(((app->shand[0].index == app->shand[1].index) && - (app->shand[2].index == app->shand[3].index)) || - ((app->shand[0].index == app->shand[1].index) && - (app->shand[3].index == app->shand[4].index)) || - ((app->shand[1].index == app->shand[2].index) && - (app->shand[3].index == app->shand[4].index))) - return 1; - - return 0; -} - -/* - Two of a kind (pair), jacks or better - or if the game is Tens or Better, 10s or better. -*/ - -static int two(PokerPlayer* app) { - int min = 10; - - if(app->GameType == 1) min = 9; - - if(app->shand[0].index == app->shand[1].index && app->shand[1].index >= min) return 1; - if(app->shand[1].index == app->shand[2].index && app->shand[2].index >= min) return 1; - if(app->shand[2].index == app->shand[3].index && app->shand[3].index >= min) return 1; - if(app->shand[3].index == app->shand[4].index && app->shand[4].index >= min) return 1; - - return 0; -} - -static int paytable[10] = { - 800, /* royal flush: 800 */ - 50, /* straight flush: 50 */ - 25, /* 4 of a kind: 25 */ - 9, /* full house: 9 */ - 6, /* flush: 6 */ - 4, /* straight: 4 */ - 3, /* 3 of a kind: 3 */ - 2, /* two pair: 2 */ - 1, /* jacks or better: 1 */ - 0 /* nothing */ -}; - -static const char* poker_handname[10] = { - "Royal Flush", - "Straight Flush", - "Four of a Kind", - "Full House", - "Flush", - "Straight", - "Three of a Kind", - "Two Pair", - "Pair", - "Nothing", -}; - -static int recognize(PokerPlayer* app) { - int i, j, f = 0; - int min = 100; - PokerPlayer_card tmp[5]; - int st = 0, fl = 0; - - /* Sort hand into sorted hand (app->shand) */ - - /* make copy of hand */ - for(i = 0; i < 5; i++) tmp[i] = app->hand[i]; - - for(i = 0; i < 5; i++) { - /* put lowest card in hand into next place in app->shand */ - - for(j = 0; j < 5; j++) - if(tmp[j].index <= min) { - min = tmp[j].index; - f = j; - } - - app->shand[i] = tmp[f]; - tmp[f].index = 100; /* larger than any card */ - min = 100; - } - - /* royal and straight flushes, strait, and flush */ - - fl = flush(app); - st = straight(app); - - if(st && fl && app->shand[0].index == 9) return 0; - if(st && fl) return 1; - if(four(app)) return 2; - if(full(app)) return 3; - if(fl) return 4; - if(st) return 5; - if(three(app)) return 6; - if(twopair(app)) return 7; - if(two(app)) return 8; - - /* Nothing */ - - return 9; -} - -void poker_draw_callback(Canvas* canvas, void* ctx) { - PokerPlayer* poker_player = ctx; - furi_check(furi_mutex_acquire(poker_player->model_mutex, FuriWaitForever) == FuriStatusOk); - canvas_clear(canvas); - char buffer[30]; - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - - /* Magic Begins */ - - /* Status Info */ - if(poker_player->GameState != 0 && poker_player->GameState != 4) { - snprintf(buffer, sizeof(buffer), "%d", poker_player->score); - canvas_draw_str_aligned(canvas, 127, 0, AlignRight, AlignTop, buffer); - } - - /* Start of game. Cards are face down, bet can be changed */ - if(poker_player->GameState == 1) { - snprintf(buffer, sizeof(buffer), "Bet:%d", poker_player->bet); - canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, buffer); - snprintf(buffer, sizeof(buffer), "<*> Place Bet"); - canvas_draw_str_aligned(canvas, 0, 9, AlignLeft, AlignTop, buffer); - - for(int i = 0; i < 5; ++i) { - canvas_draw_icon(canvas, 5 + (i * 24), 18, &I_CardBack_22x35); /* 5, 29, 53, 77, 101 */ - } - } - /* Cards are turned face up. Bet is deducted and put in th pot. Show the selector hand */ - else if(poker_player->GameState == 2 || poker_player->GameState == 3) { - snprintf(buffer, sizeof(buffer), "Pot:%d", poker_player->bet); - canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, buffer); - snprintf(buffer, sizeof(buffer), "<*> Select Hold"); - canvas_draw_str_aligned(canvas, 0, 9, AlignLeft, AlignTop, buffer); - - /* Normal or inverse to indicate selection - cards*/ - for(int i = 0; i < 5; ++i) { - poker_player->held[i] ? canvas_draw_rbox(canvas, 5 + (i * 24), 18, 22, 35, 3) : - canvas_draw_rframe(canvas, 5 + (i * 24), 18, 22, 35, 3); - } - - /* Normal or inverse to indicate selection - card suit and value */ - - for(int i = 0; i < 5; ++i) { - poker_player->held[i] ? canvas_set_color(canvas, ColorWhite) : - canvas_set_color(canvas, ColorBlack); - - canvas_draw_icon(canvas, 18 + (i * 24), 43, &card_suit[poker_player->hand[i].suit]); - } - - /* Card Value. Profont_22 does not include letters (AJQK), and "10" is too big. These are bitmaps. */ - canvas_set_font(canvas, FontBigNumbers); - - for(int i = 0; i < 5; ++i) { - poker_player->held[i] ? canvas_set_color(canvas, ColorWhite) : - canvas_set_color(canvas, ColorBlack); - if(poker_player->hand[i].index >= 1 && poker_player->hand[i].index <= 8) { - snprintf(buffer, sizeof(buffer), "%s", poker_player->hand[i].sym); - canvas_draw_str_aligned(canvas, 8 + (i * 24), 21, AlignLeft, AlignTop, buffer); - } else { - if(poker_player->hand[i].index >= 9 && poker_player->hand[i].index <= 13) { - canvas_draw_icon( - canvas, 7 + (i * 24), 21, &card_face[poker_player->hand[i].index - 9]); - } - } - } - - /* Draw the Select hand */ - if(poker_player->GameState == 2) { - canvas_set_color(canvas, ColorBlack); - - canvas_draw_icon(canvas, 11 + (poker_player->selected * 24), 54, &I_Hand_12x10); - } - } // GameState 2 or 3 - - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - if(poker_player->GameState == 3) { - snprintf( - buffer, - sizeof(buffer), - "%s:%ix", - poker_handname[recognize(poker_player)], - paytable[recognize(poker_player)]); - canvas_draw_str_aligned(canvas, 63, 61, AlignCenter, AlignBottom, buffer); - } - if(poker_player->GameState == 0) { - canvas_draw_icon(canvas, 0, 0, &I_Splash_128x64); /* Initial launch */ - } - if(poker_player->GameState == 4) { - /* canvas_draw_icon(canvas, 0, 0, &I_BadEnd_128x64); Just Lost The Game - disabled for now :( */ - canvas_set_color(canvas, ColorBlack); - canvas_set_font(canvas, FontSecondary); - snprintf(buffer, sizeof(buffer), "%s", "You have run out of money!"); - canvas_draw_str_aligned(canvas, 63, 22, AlignCenter, AlignCenter, buffer); - snprintf(buffer, sizeof(buffer), "%s", "At one point, you had"); - canvas_draw_str_aligned(canvas, 63, 32, AlignCenter, AlignCenter, buffer); - snprintf(buffer, sizeof(buffer), "%d dollars", poker_player->highscore); - canvas_draw_str_aligned(canvas, 63, 42, AlignCenter, AlignCenter, buffer); - } - - furi_mutex_release(poker_player->model_mutex); -} - -void poker_input_callback(InputEvent* input, void* ctx) { - PokerPlayer* poker_player = ctx; - furi_message_queue_put(poker_player->event_queue, input, FuriWaitForever); -} - -PokerPlayer* poker_player_alloc() { - PokerPlayer* poker_player = malloc(sizeof(PokerPlayer)); - - poker_player->score = 1000; - poker_player->model_mutex = furi_mutex_alloc(FuriMutexTypeNormal); - poker_player->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); - poker_player->view_port = view_port_alloc(); - poker_player->selected = 0; - poker_player->GameState = 0; - poker_player->bet = 10; - poker_player->minbet = 10; - poker_player->highscore = 1000; - - playcard( - poker_player); /* Get things rolling before the player gets into the game. This will preload the hand. */ - view_port_draw_callback_set(poker_player->view_port, poker_draw_callback, poker_player); - - view_port_input_callback_set(poker_player->view_port, poker_input_callback, poker_player); - - poker_player->gui = furi_record_open(RECORD_GUI); - gui_add_view_port(poker_player->gui, poker_player->view_port, GuiLayerFullscreen); - - return poker_player; -} - -void poker_player_free(PokerPlayer* poker_player) { - view_port_enabled_set(poker_player->view_port, false); - gui_remove_view_port(poker_player->gui, poker_player->view_port); - furi_record_close(RECORD_GUI); - view_port_free(poker_player->view_port); - furi_message_queue_free(poker_player->event_queue); - furi_mutex_free(poker_player->model_mutex); - - free(poker_player); -} - -int32_t video_poker_app(void* p) { - UNUSED(p); - PokerPlayer* poker_player = poker_player_alloc(); - - InputEvent event; - for(bool processing = true; processing;) { - FuriStatus status = furi_message_queue_get(poker_player->event_queue, &event, 100); - furi_check(furi_mutex_acquire(poker_player->model_mutex, FuriWaitForever) == FuriStatusOk); - if(status == FuriStatusOk) { - if(event.type == InputTypePress) { - switch(event.key) { - case InputKeyUp: - Shake(); - break; - case InputKeyDown: - if(poker_player->GameState == 2) { - playcard(poker_player); - if(check_for_dupes(poker_player) == 0) { - playcard(poker_player); - } - - poker_player->GameState = 3; - } - break; - case InputKeyLeft: - if(poker_player->GameState == 1) { - if(poker_player->bet >= poker_player->minbet + 10) { - poker_player->bet -= 10; - } - } else if(poker_player->selected > 0 && poker_player->GameState == 2) { - poker_player->selected--; - } // Move hand left/right - else if(poker_player->selected == 0 && poker_player->GameState == 2) { - poker_player->selected = 4; //wraparound - } - break; - case InputKeyRight: - if(poker_player->GameState == 1) { - if(poker_player->bet < poker_player->score + 10) { - poker_player->bet += 10; - } - } - if(poker_player->selected < 4 && poker_player->GameState == 2) { - poker_player->selected++; - } // Move hand left/right - else if(poker_player->selected == 4 && poker_player->GameState == 2) { - poker_player->selected = 0; //wraparound - } - break; - case InputKeyOk: - /* close splash screen */ - if(poker_player->GameState == 0) { - poker_player->GameState = 1; - } else if(poker_player->GameState == 1) { - /* Pledge bet. Bet is subtracted here. Original code subtracts it during playcard - but playcard is called multiple times which would otherwise subtract bet - multiple times */ - poker_player->score -= poker_player->bet; - poker_player->GameState = 2; - } else if(poker_player->GameState == 2) { - /* Select or un-select card to be held */ - poker_player->held[poker_player->selected] = - !poker_player - ->held[poker_player->selected]; //cursed and bad pls replace - } else if(poker_player->GameState == 3) { - /* accept your fate */ - if(recognize(poker_player) != 9) { - poker_player->score += - poker_player->bet * paytable[recognize(poker_player)]; - } - poker_player->GameState = 1; - if(poker_player->bet > poker_player->score) { - poker_player->bet = poker_player->score; - } - poker_player->held[0] = 0; - poker_player->held[1] = 0; - poker_player->held[2] = 0; - poker_player->held[3] = 0; - poker_player->held[4] = 0; - if(poker_player->score <= 0) { - /* lost the game */ - poker_player->GameState = 4; - } - playcard(poker_player); // shuffle shuffle - } else if(poker_player->GameState == 4) { - /* escape the summary, return to splash */ - Shake(); - poker_player->selected = 0; - poker_player->GameState = 0; - poker_player->bet = 10; - poker_player->minbet = 10; - poker_player->highscore = 1000; - poker_player->score = 1000; - poker_player->GameState = 0; - } - break; - case InputKeyBack: - /* if game is not over, we should store the game state. */ - processing = false; - break; - default: - break; - } - } - } - furi_mutex_release(poker_player->model_mutex); - view_port_update(poker_player->view_port); - } - - poker_player_free(poker_player); - return 0; -} diff --git a/applications/external/videopoker/pokerIcon.png b/applications/external/videopoker/pokerIcon.png deleted file mode 100644 index db5507d0c1b9e939498cdc2deafe9131cb764965..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1899 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 diff --git a/applications/external/zombiez/zombiez.c b/applications/external/zombiez/zombiez.c deleted file mode 100644 index a9bf74f7a..000000000 --- a/applications/external/zombiez/zombiez.c +++ /dev/null @@ -1,402 +0,0 @@ -#include -#include -#include -#include -#include - -//ORIGINAL REPO: https://github.com/Dooskington/flipperzero-zombiez -//AUTHORS: https://github.com/Dooskington | https://github.com/DevMilanIan - -#include "zombiez.h" - -#define ZOMBIES_MAX 3 -#define ZOMBIES_WIDTH 5 -#define ZOMBIES_HEIGHT 8 -#define PROJECTILES_MAX 10 - -#define MIN_Y 5 -#define MAX_Y 58 -#define WALL_X 16 -#define PLAYER_START_X 8 -#define PLAYER_START_Y (MAX_Y - MIN_Y) / 2 - -typedef enum { - EventTypeTick, - EventTypeKey, -} EventType; - -typedef struct { - EventType type; - InputEvent input; -} PluginEvent; - -typedef enum { GameStatePlaying, GameStateGameOver } GameState; - -typedef struct { - int x; - int y; -} Point; - -typedef struct { - Point position; - int hp; -} Player; - -typedef struct { - Point position; - int hp; -} Zombie; - -typedef struct { - Point position; -} Projectile; - -typedef struct { - FuriMutex* mutex; - GameState game_state; - Player player; - - size_t zombies_count; - Zombie* zombies[ZOMBIES_MAX]; - - size_t projectiles_count; - Projectile* projectiles[PROJECTILES_MAX]; - - uint16_t score; - bool input_shoot; -} PluginState; - -static void render_callback(Canvas* const canvas, void* ctx) { - furi_assert(ctx); - const PluginState* plugin_state = ctx; - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - - canvas_draw_frame(canvas, 0, 0, 128, 64); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str_aligned( - canvas, - plugin_state->player.position.x, - plugin_state->player.position.y, - AlignCenter, - AlignCenter, - "@"); - - canvas_draw_line(canvas, WALL_X, 0, WALL_X, 64); - canvas_draw_line(canvas, WALL_X + 2, 4, WALL_X + 2, 59); - - for(int i = 0; i < PROJECTILES_MAX; ++i) { - Projectile* p = plugin_state->projectiles[i]; - if(p != NULL) { - canvas_draw_disc(canvas, p->position.x, p->position.y, 3); - } - } - - for(int i = 0; i < ZOMBIES_MAX; ++i) { - Zombie* z = plugin_state->zombies[i]; - if(z != NULL) { - for(int h = 0; h < ZOMBIES_HEIGHT; h++) { - for(int w = 0; w < ZOMBIES_WIDTH; w++) { - // Switch animation - int zIdx = 0; - if(z->position.x % 2 == 0) { - zIdx = 1; - } - - // Draw zombie pixels - if(zombie_array[zIdx][h][w] == 1) { - int x = z->position.x + w; - int y = z->position.y + h; - - canvas_draw_dot(canvas, x, y); - } - } - } - } - } - - int heart; - if((plugin_state->player.hp - 10) > 5) { // 16, 17, 18, 19, 20 - heart = 0; - } else if((plugin_state->player.hp - 5) > 5) { // 11, 12, 13, 14, 15 - heart = 1; - } else if((plugin_state->player.hp - 3) > 2) { // 6, 7, 8, 9, 10 - heart = 2; - } else if(plugin_state->player.hp > 0) { // 1, 2, 3, 4, 5 - heart = 3; - } else { // 0 - heart = 4; - } - // visual representation of health - for(int h = 0; h < 5; h++) { - for(int w = 0; w < 5; w++) { - if(heart_array[heart][h][w] == 1) { - int x = 124 - w; - int y = 56 + h; - - canvas_draw_dot(canvas, x, y); - } - } - } - - // buffer hp + score - char hpBuffer[8]; - char scoreBuffer[14]; - - if(plugin_state->game_state == GameStatePlaying) { - // display ammo / reload - if(plugin_state->projectiles_count >= PROJECTILES_MAX) { - canvas_draw_str_aligned(canvas, 24, 10, AlignLeft, AlignCenter, "RELOAD"); - } else { - for(uint8_t i = 0; i < (PROJECTILES_MAX - plugin_state->projectiles_count); i++) { - canvas_draw_box(canvas, 24 + (4 * i), 6, 2, 4); - } - } - // display hp + score - snprintf(hpBuffer, sizeof(hpBuffer), "%u", plugin_state->player.hp); - canvas_draw_str_aligned(canvas, 118, 62, AlignRight, AlignBottom, hpBuffer); - - snprintf(scoreBuffer, sizeof(scoreBuffer), "%u", plugin_state->score); - canvas_draw_str_aligned(canvas, 126, 10, AlignRight, AlignBottom, scoreBuffer); - } - // Game Over banner - if(plugin_state->game_state == GameStateGameOver) { - // Screen is 128x64 px - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 34, 20, 62, 24); - - canvas_set_color(canvas, ColorBlack); - canvas_draw_frame(canvas, 34, 20, 62, 24); - - canvas_set_font(canvas, FontPrimary); - canvas_draw_str(canvas, 37, 31, "Game Over"); - - canvas_set_font(canvas, FontSecondary); - snprintf(scoreBuffer, sizeof(scoreBuffer), "Score: %u", plugin_state->score); - canvas_draw_str_aligned(canvas, 64, 41, AlignCenter, AlignBottom, scoreBuffer); - } - - //char* info = (char*)malloc(16 * sizeof(char)); - //asprintf(&info, "%d, %d", plugin_state->x, plugin_state->y); - //canvas_draw_str_aligned(canvas, 32, 16, AlignLeft, AlignBottom, info); - //free(info); - - furi_mutex_release(plugin_state->mutex); -} - -static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) { - furi_assert(event_queue); - PluginEvent event = {.type = EventTypeKey, .input = *input_event}; - furi_message_queue_put(event_queue, &event, FuriWaitForever); -} - -static void tick(PluginState* const plugin_state) { - if(plugin_state->input_shoot && (plugin_state->projectiles_count < PROJECTILES_MAX)) { - Projectile* p = (Projectile*)malloc(sizeof(Projectile)); - p->position.x = plugin_state->player.position.x; - p->position.y = plugin_state->player.position.y; - - size_t idx = plugin_state->projectiles_count; - plugin_state->projectiles[idx] = p; - plugin_state->projectiles_count += 1; - } - - for(int i = 0; i < ZOMBIES_MAX; ++i) { - if(!plugin_state->zombies[i]) { - Zombie* z = (Zombie*)malloc(sizeof(Zombie)); - //z->hp = 20; - z->position.x = 126; - z->position.y = MIN_Y + (rand() % (MAX_Y - MIN_Y)); - - plugin_state->zombies[i] = z; - plugin_state->zombies_count += 1; - } - } - - for(int i = 0; i < PROJECTILES_MAX; ++i) { - Projectile* p = plugin_state->projectiles[i]; - if(p != NULL) { - p->position.x += 2; - - for(int i = 0; i < ZOMBIES_MAX; ++i) { - Zombie* z = plugin_state->zombies[i]; - if(z != NULL) { - if( // projectile close enough to zombie - (((z->position.x - p->position.x) <= 2) && - ((z->position.y - p->position.y) <= 4)) && - (((p->position.x - z->position.x) <= 2) && - ((p->position.y - z->position.y) <= 6))) { - //z->hp -= 5; - //if(z->hp <= 0) { - plugin_state->zombies_count -= 1; - free(z); - plugin_state->zombies[i] = NULL; - plugin_state->score++; - //if(plugin_state->score % 15 == 0) dolphin_deed(getRandomDeed()); - //} - } else if(z->position.x <= WALL_X && z->position.x > 0) { // zombie got to the wall - plugin_state->zombies_count -= 1; - free(z); - plugin_state->zombies[i] = NULL; - if(plugin_state->player.hp > 0) { - plugin_state->player.hp--; - } else { - plugin_state->game_state = GameStateGameOver; - } - } else { - if(furi_get_tick() % 2 == 0) z->position.x--; - } - } - } - - if(p->position.x >= 128) { - free(p); - plugin_state->projectiles[i] = NULL; - } - } - } - - plugin_state->input_shoot = false; -} - -static void timer_callback(void* ctx) { - furi_assert(ctx); - FuriMessageQueue* event_queue = ctx; - PluginEvent event = {.type = EventTypeTick}; - furi_message_queue_put(event_queue, &event, 0); -} - -static void zombiez_state_init(PluginState* const plugin_state) { - plugin_state->player.position.x = PLAYER_START_X; - plugin_state->player.position.y = PLAYER_START_Y; - plugin_state->player.hp = 20; - - plugin_state->projectiles_count = 0; - plugin_state->zombies_count = 0; - plugin_state->score = 0; - - for(int i = 0; i < PROJECTILES_MAX; i++) { - plugin_state->projectiles[i] = NULL; - } - - for(int i = 0; i < ZOMBIES_MAX; i++) { - plugin_state->zombies[i] = NULL; - } - - plugin_state->game_state = GameStatePlaying; - plugin_state->input_shoot = false; -} - -int32_t zombiez_game_app(void* p) { - UNUSED(p); - uint32_t return_code = 0; - FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent)); - - PluginState* plugin_state = malloc(sizeof(PluginState)); - zombiez_state_init(plugin_state); - - plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); - if(!plugin_state->mutex) { - FURI_LOG_E("Zombiez", "cannot create mutex\r\n"); - return_code = 255; - goto free_and_exit; - } - - // Set system callbacks - ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, render_callback, plugin_state); - view_port_input_callback_set(view_port, input_callback, event_queue); - - FuriTimer* timer = furi_timer_alloc(timer_callback, FuriTimerTypePeriodic, event_queue); - furi_timer_start(timer, furi_kernel_get_tick_frequency() / 22); - - // Open GUI and register view_port - Gui* gui = furi_record_open(RECORD_GUI); - gui_add_view_port(gui, view_port, GuiLayerFullscreen); - - // Call dolphin deed on game start - dolphin_deed(DolphinDeedPluginGameStart); - - PluginEvent event; - bool isRunning = true; - while(isRunning) { - FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); - if(event_status == FuriStatusOk) { - if(event.type == EventTypeKey) { - if(event.input.type == InputTypePress) { - switch(event.input.key) { - case InputKeyUp: - if(plugin_state->player.position.y > MIN_Y && - plugin_state->game_state == GameStatePlaying) { - plugin_state->player.position.y--; - } - break; - case InputKeyDown: - if(plugin_state->player.position.y < MAX_Y && - plugin_state->game_state == GameStatePlaying) { - plugin_state->player.position.y++; - } - break; - case InputKeyOk: - if(plugin_state->projectiles_count < PROJECTILES_MAX && - plugin_state->game_state == GameStatePlaying) { - plugin_state->input_shoot = true; - } - break; - case InputKeyBack: - break; - default: - break; - } - } else if( - event.input.type == InputTypeRepeat && - plugin_state->game_state == GameStatePlaying) { - switch(event.input.key) { - case InputKeyUp: - if(plugin_state->player.position.y > (MIN_Y + 1)) { - plugin_state->player.position.y -= 4; - } - break; - case InputKeyDown: - if(plugin_state->player.position.y < (MAX_Y - 1)) { - plugin_state->player.position.y += 4; - } - break; - default: - break; - } - } else if(event.input.type == InputTypeLong) { - if(event.input.key == InputKeyOk) { - if(plugin_state->game_state == GameStateGameOver) { - zombiez_state_init(plugin_state); - } else if(plugin_state->projectiles_count >= PROJECTILES_MAX) { - plugin_state->projectiles_count = 0; - plugin_state->player.hp++; - } - } else if(event.input.key == InputKeyBack) { - isRunning = false; - } - } - } else if(event.type == EventTypeTick) { - tick(plugin_state); - } - } - - view_port_update(view_port); - furi_mutex_release(plugin_state->mutex); - } - - furi_timer_free(timer); - view_port_enabled_set(view_port, false); - gui_remove_view_port(gui, view_port); - furi_record_close(RECORD_GUI); - view_port_free(view_port); - furi_mutex_free(plugin_state->mutex); - -free_and_exit: - free(plugin_state); - furi_message_queue_free(event_queue); - - return return_code; -} \ No newline at end of file diff --git a/applications/external/zombiez/zombiez.h b/applications/external/zombiez/zombiez.h deleted file mode 100644 index eea71d707..000000000 --- a/applications/external/zombiez/zombiez.h +++ /dev/null @@ -1,62 +0,0 @@ -#include - -uint8_t zombie_array[2][8][5] = { - { - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {1, 1, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 0, 0}, - {0, 0, 1, 0, 0}, - }, - { - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {1, 1, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 1, 1, 1}, - {0, 0, 0, 0, 1}, - {0, 0, 0, 0, 1}, - }, -}; - -uint8_t heart_array[5][5][5] = { - { - {0, 1, 0, 1, 0}, - {1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1}, - {0, 1, 1, 1, 0}, - {0, 0, 1, 0, 0}, - }, - { - {0, 0, 0, 0, 0}, - {1, 1, 1, 1, 1}, - {1, 1, 1, 1, 1}, - {0, 1, 1, 1, 0}, - {0, 0, 1, 0, 0}, - }, - { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {1, 1, 1, 1, 1}, - {0, 1, 1, 1, 0}, - {0, 0, 1, 0, 0}, - }, - { - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0}, - {0, 1, 1, 1, 0}, - {0, 0, 1, 0, 0}, - }, - { - {1, 0, 0, 0, 1}, - {0, 1, 0, 1, 0}, - {0, 0, 1, 0, 0}, - {0, 1, 0, 1, 0}, - {1, 0, 0, 0, 1}, - }, -}; \ No newline at end of file