Move plugins to external folder
@@ -1,68 +0,0 @@
|
||||
# Doom Flipper Zero edition
|
||||
|
||||
<div style="text-align:center"><img src="assets/logo_inv.png"/></div>
|
||||
|
||||
## Will it run Doom?
|
||||
As tradition goes, Doom is being ported to almost every possible embedded electronic device. Therefore I did an attempt to come up with something close to Doom and still compatible on the Flipper Zero's hardware.<br> This is not the actual Doom game but a port made from yet another Doom port to the Arduino Nano (https://github.com/daveruiz/doom-nano/). This port is basically a raycasting engine, using Doom sprites.<br>
|
||||
This version is very basic and might be improved over time.
|
||||
|
||||
## How to install on Flipper Zero
|
||||
During the porting process, minor changes were made to the workings (and build options) of the current firmware. These changes are documented here and are necessary in order to get a working firmware build that contains this Doom port.
|
||||
### Modifying the firmware & build options
|
||||
* In the `sites/cc.scons` add the following values to the `CCFLAGS` section:
|
||||
```
|
||||
...
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-type-limits",
|
||||
"-Wno-unused-variable",
|
||||
...
|
||||
```
|
||||
* In `applications/gui/canvas_i.h` comment out the following line:<br>
|
||||
`uint8_t* canvas_get_buffer(Canvas* canvas);` --> `//uint8_t* canvas_get_buffer(Canvas* canvas);`
|
||||
|
||||
* In `applications/gui/canvas.h` add the following lines:
|
||||
```
|
||||
uint8_t* canvas_get_buffer(Canvas* canvas);
|
||||
void canvas_draw_icon_bitmap(Canvas* canvas, uint8_t x, uint8_t y, int16_t w, int16_t h, const Icon* icon);
|
||||
```
|
||||
* In `applications/gui/canvas.c` add the following function:
|
||||
```
|
||||
void canvas_draw_icon_bitmap(Canvas* canvas, uint8_t x, uint8_t y, int16_t w, int16_t h, const Icon* icon){
|
||||
furi_assert(canvas);
|
||||
furi_assert(icon);
|
||||
|
||||
x += canvas->offset_x;
|
||||
y += canvas->offset_y;
|
||||
uint8_t* icon_data = NULL;
|
||||
furi_hal_compress_icon_decode(icon_get_data(icon), &icon_data);
|
||||
u8g2_DrawXBM(&canvas->fb, x, y, w, h, icon_data);
|
||||
}
|
||||
```
|
||||
|
||||
### Installing the plugin in the firmware
|
||||
* Make a folder called Doom in the applications folder. Add all the source files (also the compiled folder and it's files) in the Doom folder.
|
||||
* Make the `applications/meta/application.fam` look like the following:
|
||||
```
|
||||
App(
|
||||
appid="basic_plugins",
|
||||
name="Basic applications for plug-in menu",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
...
|
||||
"doom_game",
|
||||
...
|
||||
|
||||
],
|
||||
)
|
||||
```
|
||||
|
||||
If all went well the only thing left to do is building the firmware and installing it to the Flipper.
|
||||
|
||||
## Screenshots
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
@@ -1,15 +0,0 @@
|
||||
App(
|
||||
appid="DOOM",
|
||||
name="DOOM",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="doom_app",
|
||||
cdefines=["APP_DOOM_GAME"],
|
||||
requires=[
|
||||
"gui",
|
||||
"music_player",
|
||||
],
|
||||
stack_size=4 * 1024,
|
||||
order=75,
|
||||
fap_icon="doom_10px.png",
|
||||
fap_category="Games",
|
||||
)
|
||||
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 583 B |
|
Before Width: | Height: | Size: 418 B |
|
Before Width: | Height: | Size: 388 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 847 B |
|
Before Width: | Height: | Size: 903 B |
|
Before Width: | Height: | Size: 958 B |
|
Before Width: | Height: | Size: 417 B |
|
Before Width: | Height: | Size: 383 B |
|
Before Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 2.1 MiB |
|
Before Width: | Height: | Size: 2.3 MiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
@@ -1,405 +0,0 @@
|
||||
#include "assets_icons.h"
|
||||
|
||||
#include <gui/icon_i.h>
|
||||
|
||||
// Inverted icons
|
||||
|
||||
const uint8_t _I_fire_inv_0[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x30, 0x00, 0x40, 0xee, 0x00, 0x80, 0xe6, 0x00,
|
||||
0x80, 0xa7, 0x01, 0x80, 0xc7, 0x03, 0x40, 0x45, 0x03, 0xe0, 0x41, 0x07, 0xf8, 0x82, 0x9f, 0xb9,
|
||||
0x01, 0x3e, 0x7c, 0x00, 0x7a, 0x6e, 0x00, 0x56, 0x1c, 0x00, 0x6c, 0xf4, 0x01, 0x3a, 0x6c, 0x00,
|
||||
0x7e, 0xfc, 0x00, 0x1a, 0x08, 0x00, 0x3c, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
};
|
||||
const uint8_t* const _I_fire_inv[] = {_I_fire_inv_0};
|
||||
|
||||
const uint8_t _I_gun_inv_0[] = {
|
||||
0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x80, 0x23, 0x00, 0x00, 0x40,
|
||||
0x20, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x40, 0x57, 0x00, 0x00, 0x20, 0x8b, 0x00, 0x00,
|
||||
0x90, 0x11, 0x01, 0x00, 0x98, 0x00, 0x00, 0x00, 0xb0, 0x43, 0x01, 0x00, 0x94, 0x81, 0x03,
|
||||
0x00, 0xd0, 0x45, 0x04, 0x00, 0x8c, 0x02, 0x02, 0x00, 0xc4, 0x00, 0x03, 0x00, 0xc8, 0x00,
|
||||
0x02, 0x00, 0x4e, 0x40, 0x00, 0x00, 0x92, 0x00, 0x02, 0x80, 0x07, 0x15, 0x04, 0xe0, 0x8f,
|
||||
0x00, 0x0c, 0xd0, 0x9d, 0x07, 0x17, 0xe0, 0x3a, 0xc0, 0x3f, 0xe0, 0xf7, 0xff, 0x77, 0xe0,
|
||||
0xae, 0xfe, 0x4b, 0xd8, 0xdd, 0xff, 0x4d, 0x88, 0xea, 0xbe, 0x26, 0x4c, 0xf5, 0xff, 0x17,
|
||||
0xc8, 0xfa, 0xae, 0x0b, 0xcc, 0xff, 0xdf, 0x19, 0xe8, 0xeb, 0xa7, 0x00, 0xd8, 0xf1, 0x4d,
|
||||
0x0c, 0xc0, 0xbe, 0x1a, 0x08, 0xf6, 0xfd, 0x37, 0x04,
|
||||
};
|
||||
const uint8_t* const _I_gun_inv[] = {_I_gun_inv_0};
|
||||
|
||||
const uint8_t _I_gun_mask_inv_0[] = {
|
||||
0x01, 0x00, 0x53, 0x00, 0x00, 0x0c, 0x38, 0x04, 0x38, 0x09, 0xf8, 0x0c, 0x78, 0x17, 0xf0,
|
||||
0x18, 0xf8, 0x00, 0x67, 0xff, 0x01, 0xaf, 0xc3, 0xff, 0x01, 0x80, 0x7e, 0x3f, 0xf0, 0x38,
|
||||
0x07, 0xf0, 0x0e, 0x40, 0x31, 0x03, 0x8f, 0xfb, 0xff, 0x07, 0x01, 0x94, 0x3c, 0x0e, 0xc0,
|
||||
0x35, 0xff, 0x85, 0xc8, 0x06, 0x30, 0x7e, 0x00, 0x0c, 0x61, 0xe2, 0xe1, 0xff, 0xc7, 0xc5,
|
||||
0xc3, 0xff, 0x9f, 0x80, 0xca, 0xfe, 0x03, 0x2f, 0xf8, 0x0c, 0xc6, 0xc2, 0x03, 0x4b, 0xf8,
|
||||
0xa8, 0x42, 0xe2, 0x03, 0x28, 0xf8, 0x1e, 0x80, 0x68, 0x1e, 0x28, 0x78,
|
||||
};
|
||||
const uint8_t* const _I_gun_mask_inv[] = {_I_gun_mask_inv_0};
|
||||
|
||||
const uint8_t _I_logo_inv_0[] = {
|
||||
0x01, 0x00, 0x92, 0x01, 0x00, 0x78, 0x03, 0xc0, 0x03, 0xfc, 0xff, 0xff, 0xfc, 0x1f, 0xf9, 0xff,
|
||||
0xe3, 0xff, 0x0f, 0x8f, 0xfc, 0x2f, 0xe0, 0xf3, 0xdc, 0x6e, 0xf7, 0x7b, 0x1d, 0xdd, 0xef, 0x79,
|
||||
0xbb, 0xcd, 0xce, 0xf7, 0x13, 0xb0, 0x79, 0xfc, 0x03, 0xe3, 0xfb, 0x01, 0x0f, 0xfb, 0xff, 0xbf,
|
||||
0x11, 0x8c, 0x7c, 0x1e, 0x7e, 0x0f, 0x77, 0xbb, 0xd4, 0x02, 0x10, 0x00, 0xeb, 0xad, 0xde, 0xc8,
|
||||
0x70, 0x3c, 0xf8, 0x01, 0xf7, 0xbf, 0xff, 0x20, 0xe0, 0xf3, 0xc0, 0x6e, 0x80, 0x0d, 0x7a, 0xde,
|
||||
0x40, 0x83, 0xf8, 0x03, 0x10, 0xfa, 0x70, 0x07, 0xee, 0x02, 0x18, 0x30, 0x3d, 0x0a, 0xe3, 0xfb,
|
||||
0x83, 0x86, 0xc7, 0x82, 0x1f, 0x1f, 0xf8, 0xfd, 0x61, 0x5a, 0x0d, 0x54, 0x0b, 0x55, 0xaa, 0xc0,
|
||||
0x00, 0x84, 0x0c, 0x21, 0xf4, 0x8f, 0xf4, 0x3b, 0x70, 0x3e, 0xf7, 0x7b, 0x01, 0x9f, 0xef, 0xf7,
|
||||
0xc3, 0xfe, 0x1f, 0x6f, 0x87, 0xee, 0x07, 0xfe, 0xff, 0x60, 0x07, 0xfe, 0x1f, 0x88, 0xef, 0xc3,
|
||||
0xf3, 0x01, 0xfe, 0x7f, 0x30, 0x1b, 0xdf, 0xef, 0xf6, 0x0a, 0x1f, 0xf0, 0x79, 0xd0, 0x22, 0xf7,
|
||||
0x0b, 0x9c, 0x0e, 0xed, 0x76, 0x80, 0x4d, 0xee, 0xf7, 0x71, 0xff, 0x87, 0xd6, 0x2b, 0x50, 0xa8,
|
||||
0xc0, 0x6a, 0x95, 0x48, 0x04, 0x56, 0xab, 0x55, 0x1f, 0xf8, 0xff, 0xc7, 0xfe, 0x3f, 0xaa, 0xe4,
|
||||
0x02, 0x3b, 0x55, 0xae, 0x8f, 0xfc, 0xbf, 0xe1, 0xff, 0x0f, 0xf8, 0x7d, 0x61, 0x18, 0x0c, 0x44,
|
||||
0x03, 0x11, 0x88, 0x02, 0x0e, 0x23, 0x04, 0x0e, 0x30, 0xfa, 0x41, 0x43, 0xe2, 0x06, 0x18, 0xa8,
|
||||
0x18, 0x43, 0xe9, 0x02, 0xd0, 0x68, 0xa1, 0x5a, 0x2d, 0x51, 0x10, 0x70, 0x5a, 0x21, 0xfc, 0x45,
|
||||
0x43, 0xe3, 0x50, 0x0f, 0xc4, 0x20, 0x72, 0x20, 0x22, 0x02, 0x16, 0x00, 0x7e, 0xd5, 0x4a, 0x8d,
|
||||
0x54, 0x3e, 0x35, 0x40, 0xfb, 0x80, 0x3c, 0x3e, 0x35, 0x5a, 0x09, 0xe8, 0x6a, 0x87, 0xc1, 0x23,
|
||||
0x88, 0xfd, 0x40, 0x0c, 0x09, 0x20, 0xfa, 0x87, 0x06, 0x00, 0x1f, 0x38, 0x0c, 0x50, 0x3e, 0xa0,
|
||||
0x0f, 0x0f, 0x8c, 0x56, 0x00, 0x5c, 0x1a, 0x80, 0x90, 0x62, 0x03, 0xf6, 0x80, 0x42, 0x17, 0xc2,
|
||||
0x7b, 0x10, 0x20, 0x87, 0xde, 0xa9, 0x04, 0x80, 0x54, 0x20, 0x94, 0x08, 0xa0, 0x24, 0x47, 0xf5,
|
||||
0x01, 0x20, 0x54, 0x44, 0x18, 0x80, 0x42, 0x88, 0x17, 0xfc, 0x7e, 0xb4, 0x40, 0x4c, 0x12, 0x04,
|
||||
0x01, 0xe3, 0xf4, 0x2a, 0xf8, 0x03, 0xc0, 0x1f, 0xe0, 0xbc, 0xcf, 0xb8, 0xf8, 0x1e, 0xbf, 0xcc,
|
||||
0x5b, 0x12, 0x0c, 0x56, 0x0a, 0x51, 0x82, 0xa8, 0x28, 0x08, 0x1f, 0x32, 0x0c, 0x00, 0x3e, 0x85,
|
||||
0xe3, 0x1e, 0x17, 0x8f, 0x4f, 0xe6, 0x1f, 0x99, 0x44, 0x0a, 0x10, 0x2f, 0x13, 0xb4, 0xc8, 0x29,
|
||||
0x03, 0xf3, 0x89, 0x03, 0xe7, 0x10, 0x5f, 0x2a, 0x87, 0xd1, 0x1b, 0xe0, 0x0f, 0x00, 0x78, 0x03,
|
||||
0xc0, 0x1e, 0x00, 0xf0, 0x02, 0x00,
|
||||
};
|
||||
const uint8_t* const _I_logo_inv[] = {_I_logo_inv_0};
|
||||
|
||||
const Icon I_fire_inv =
|
||||
{.width = 24, .height = 20, .frame_count = 1, .frame_rate = 0, .frames = _I_fire_inv};
|
||||
const Icon I_gun_inv =
|
||||
{.width = 32, .height = 32, .frame_count = 1, .frame_rate = 0, .frames = _I_gun_inv};
|
||||
const Icon I_gun_mask_inv =
|
||||
{.width = 32, .height = 32, .frame_count = 1, .frame_rate = 0, .frames = _I_gun_mask_inv};
|
||||
const Icon I_logo_inv =
|
||||
{.width = 128, .height = 64, .frame_count = 1, .frame_rate = 0, .frames = _I_logo_inv};
|
||||
|
||||
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};
|
||||
@@ -1,114 +0,0 @@
|
||||
#pragma once
|
||||
#include <gui/icon.h>
|
||||
|
||||
#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
|
||||
|
||||
// Inverted icons
|
||||
extern const Icon I_fire_inv;
|
||||
extern const Icon I_gun_inv;
|
||||
extern const Icon I_gun_mask_inv;
|
||||
extern const Icon I_logo_inv;
|
||||
|
||||
// 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
|
||||
@@ -1,91 +0,0 @@
|
||||
#ifndef _constants_h
|
||||
#define _constants_h
|
||||
#define PB_CONSTEXPR constexpr
|
||||
|
||||
#define PI 3.14159265358979323846
|
||||
|
||||
// Key pinout
|
||||
#define USE_INPUT_PULLUP
|
||||
#define K_LEFT 6
|
||||
#define K_RIGHT 7
|
||||
#define K_UP 8
|
||||
#define K_DOWN 3
|
||||
#define K_FIRE 10
|
||||
|
||||
// SNES Controller
|
||||
// uncomment following line to enable snes controller support
|
||||
// #define SNES_CONTROLLER
|
||||
const uint8_t DATA_CLOCK = 11;
|
||||
const uint8_t DATA_LATCH = 12;
|
||||
const uint8_t DATA_SERIAL = 13;
|
||||
|
||||
// Sound
|
||||
const uint8_t SOUND_PIN = 9; // do not change, belongs to used timer
|
||||
|
||||
// GFX settings
|
||||
#define OPTIMIZE_SSD1306 // Optimizations for SSD1366 displays
|
||||
|
||||
#define FRAME_TIME 66.666666 // Desired time per frame in ms (66.666666 is ~15 fps)
|
||||
#define RES_DIVIDER 2
|
||||
|
||||
/* Higher values will result in lower horizontal resolution when rasterize and lower process and memory usage
|
||||
Lower will require more process and memory, but looks nicer
|
||||
*/
|
||||
#define Z_RES_DIVIDER 2 // Zbuffer resolution divider. We sacrifice resolution to save memory
|
||||
#define DISTANCE_MULTIPLIER 20
|
||||
|
||||
/* Distances are stored as uint8_t, multiplying the distance we can obtain more precision taking care
|
||||
of keep numbers inside the type range. Max is 256 / MAX_RENDER_DEPTH
|
||||
*/
|
||||
|
||||
#define MAX_RENDER_DEPTH 12
|
||||
#define MAX_SPRITE_DEPTH 8
|
||||
|
||||
#define ZBUFFER_SIZE SCREEN_WIDTH / Z_RES_DIVIDER
|
||||
|
||||
// Level
|
||||
#define LEVEL_WIDTH_BASE 6
|
||||
#define LEVEL_WIDTH (1 << LEVEL_WIDTH_BASE)
|
||||
#define LEVEL_HEIGHT 57
|
||||
#define LEVEL_SIZE LEVEL_WIDTH / 2 * LEVEL_HEIGHT
|
||||
|
||||
// scenes
|
||||
#define INTRO 0
|
||||
#define GAME_PLAY 1
|
||||
|
||||
// Game
|
||||
#define GUN_TARGET_POS 18
|
||||
#define GUN_SHOT_POS GUN_TARGET_POS + 4
|
||||
|
||||
#define ROT_SPEED .12
|
||||
#define MOV_SPEED .2
|
||||
#define MOV_SPEED_INV 5 // 1 / MOV_SPEED
|
||||
|
||||
#define JOGGING_SPEED .005
|
||||
#define ENEMY_SPEED .02
|
||||
#define FIREBALL_SPEED .2
|
||||
#define FIREBALL_ANGLES 45 // Num of angles per PI
|
||||
|
||||
#define MAX_ENTITIES 10 // Max num of active entities
|
||||
#define MAX_STATIC_ENTITIES 28 // Max num of entities in sleep mode
|
||||
|
||||
#define MAX_ENTITY_DISTANCE 200 // * DISTANCE_MULTIPLIER
|
||||
#define MAX_ENEMY_VIEW 80 // * DISTANCE_MULTIPLIER
|
||||
#define ITEM_COLLIDER_DIST 6 // * DISTANCE_MULTIPLIER
|
||||
#define ENEMY_COLLIDER_DIST 4 // * DISTANCE_MULTIPLIER
|
||||
#define FIREBALL_COLLIDER_DIST 2 // * DISTANCE_MULTIPLIER
|
||||
#define ENEMY_MELEE_DIST 6 // * DISTANCE_MULTIPLIER
|
||||
#define WALL_COLLIDER_DIST .2
|
||||
|
||||
#define ENEMY_MELEE_DAMAGE 8
|
||||
#define ENEMY_FIREBALL_DAMAGE 20
|
||||
#define GUN_MAX_DAMAGE 20
|
||||
|
||||
// display
|
||||
const uint8_t SCREEN_WIDTH = 128;
|
||||
const uint8_t SCREEN_HEIGHT = 64;
|
||||
const uint8_t HALF_WIDTH = SCREEN_WIDTH / 2;
|
||||
const uint8_t RENDER_HEIGHT = 56; // raycaster working height (the rest is for the hud)
|
||||
const uint8_t HALF_HEIGHT = SCREEN_HEIGHT / 2;
|
||||
|
||||
#endif
|
||||
@@ -1,282 +0,0 @@
|
||||
#include <gui/gui.h>
|
||||
#include <gui/canvas_i.h>
|
||||
#include <furi_hal.h>
|
||||
#include <u8g2_glue.h>
|
||||
#include "constants.h"
|
||||
#include "compiled/assets_icons.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();
|
||||
void setupDisplay(Canvas* canvas);
|
||||
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
|
||||
uint8_t* display_buf = NULL;
|
||||
|
||||
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 setupDisplay(Canvas* canvas) {
|
||||
memset(zbuffer, 0xff, 128);
|
||||
display_buf = (uint8_t*)canvas_get_buffer(canvas);
|
||||
//display_buf = u8g2_GetBufferPtr(&canvas->fb);
|
||||
}
|
||||
|
||||
void drawBitmap(
|
||||
int16_t x,
|
||||
int16_t y,
|
||||
const Icon* i,
|
||||
int16_t w,
|
||||
int16_t h,
|
||||
uint16_t color,
|
||||
Canvas* const canvas) {
|
||||
UNUSED(color);
|
||||
canvas_draw_icon_bitmap(canvas, x, y, w, h, i);
|
||||
}
|
||||
|
||||
void drawText(uint8_t x, uint8_t y, uint8_t num, Canvas* const canvas) {
|
||||
char buf[4];
|
||||
itoa(num, buf, 10);
|
||||
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;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,504 +0,0 @@
|
||||
#include "doom_music_player_worker.h"
|
||||
|
||||
#include <furi_hal.h>
|
||||
#include <furi.h>
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <lib/flipper_format/flipper_format.h>
|
||||
|
||||
#include <m-array.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
#ifndef _entities_h
|
||||
#define _entities_h
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#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
|
||||
@@ -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
|
||||
@@ -1,34 +0,0 @@
|
||||
#ifndef sound_h
|
||||
#define sound_h
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <stdint.h>
|
||||
#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
|
||||
@@ -1,33 +0,0 @@
|
||||
#include "types.h"
|
||||
|
||||
/*template <class T>
|
||||
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;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#ifndef _types_h
|
||||
#define _types_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
//#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
|
||||
@@ -1,674 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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://www.gnu.org/licenses/>.
|
||||
|
||||
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:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
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
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||
@@ -1,18 +0,0 @@
|
||||

|
||||
|
||||
[Original Link](https://github.com/litui/dtmf_dolphin)
|
||||
|
||||
## DTMF Dolphin
|
||||
|
||||
DTMF (Dual-Tone Multi-Frequency) dialer, Bluebox, and Redbox.
|
||||
|
||||
Now in a release-ready state for both Dialer, Bluebox, and Redbox (US/UK) functionality!
|
||||
|
||||
Please note that using the current tone output method, the 2600 tone is scaled about 33 Hz higher than it should be. This is a limitation of the current sample rate.
|
||||
|
||||
### Educational Links:
|
||||
|
||||
* http://www.phrack.org/issues/25/7.html#article
|
||||
* https://en.wikipedia.org/wiki/Dual-tone_multi-frequency_signaling
|
||||
* https://en.wikipedia.org/wiki/Blue_box
|
||||
* https://en.wikipedia.org/wiki/Red_box_(phreaking)
|
||||
@@ -1,16 +0,0 @@
|
||||
App(
|
||||
appid="dtmf_dolphin",
|
||||
name="DTMF Dolphin",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="dtmf_dolphin_app",
|
||||
cdefines=["DTMF_DOLPHIN"],
|
||||
requires=[
|
||||
"storage",
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
fap_icon="phone.png",
|
||||
stack_size=8 * 1024,
|
||||
order=20,
|
||||
fap_category="Tools",
|
||||
)
|
||||
@@ -1,89 +0,0 @@
|
||||
#include "dtmf_dolphin_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
static bool dtmf_dolphin_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
DTMFDolphinApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool dtmf_dolphin_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
DTMFDolphinApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void dtmf_dolphin_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
DTMFDolphinApp* app = context;
|
||||
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static DTMFDolphinApp* app_alloc() {
|
||||
DTMFDolphinApp* app = malloc(sizeof(DTMFDolphinApp));
|
||||
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&dtmf_dolphin_scene_handlers, app);
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, dtmf_dolphin_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, dtmf_dolphin_app_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, dtmf_dolphin_app_tick_event_callback, 100);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
app->main_menu_list = variable_item_list_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DTMFDolphinViewMainMenu,
|
||||
variable_item_list_get_view(app->main_menu_list));
|
||||
|
||||
app->dtmf_dolphin_dialer = dtmf_dolphin_dialer_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DTMFDolphinViewDialer,
|
||||
dtmf_dolphin_dialer_get_view(app->dtmf_dolphin_dialer));
|
||||
|
||||
app->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message(app->notification, &sequence_display_backlight_enforce_on);
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneStart);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void app_free(DTMFDolphinApp* app) {
|
||||
furi_assert(app);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DTMFDolphinViewMainMenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DTMFDolphinViewDialer);
|
||||
variable_item_list_free(app->main_menu_list);
|
||||
|
||||
dtmf_dolphin_dialer_free(app->dtmf_dolphin_dialer);
|
||||
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
notification_message(app->notification, &sequence_display_backlight_enforce_auto);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t dtmf_dolphin_app(void* p) {
|
||||
UNUSED(p);
|
||||
DTMFDolphinApp* app = app_alloc();
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
app_free(app);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,270 +0,0 @@
|
||||
#include "dtmf_dolphin_audio.h"
|
||||
|
||||
DTMFDolphinAudio* current_player;
|
||||
|
||||
static void dtmf_dolphin_audio_dma_isr(void* ctx) {
|
||||
FuriMessageQueue* event_queue = ctx;
|
||||
|
||||
if(LL_DMA_IsActiveFlag_HT1(DMA1)) {
|
||||
LL_DMA_ClearFlag_HT1(DMA1);
|
||||
|
||||
DTMFDolphinCustomEvent event = {.type = DTMFDolphinEventDMAHalfTransfer};
|
||||
furi_message_queue_put(event_queue, &event, 0);
|
||||
}
|
||||
|
||||
if(LL_DMA_IsActiveFlag_TC1(DMA1)) {
|
||||
LL_DMA_ClearFlag_TC1(DMA1);
|
||||
|
||||
DTMFDolphinCustomEvent event = {.type = DTMFDolphinEventDMAFullTransfer};
|
||||
furi_message_queue_put(event_queue, &event, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void dtmf_dolphin_audio_clear_samples(DTMFDolphinAudio* player) {
|
||||
for(size_t i = 0; i < player->buffer_length; i++) {
|
||||
player->sample_buffer[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
DTMFDolphinOsc* dtmf_dolphin_osc_alloc() {
|
||||
DTMFDolphinOsc* osc = malloc(sizeof(DTMFDolphinOsc));
|
||||
osc->cached_freq = 0;
|
||||
osc->offset = 0;
|
||||
osc->period = 0;
|
||||
osc->lookup_table = NULL;
|
||||
return osc;
|
||||
}
|
||||
|
||||
DTMFDolphinPulseFilter* dtmf_dolphin_pulse_filter_alloc() {
|
||||
DTMFDolphinPulseFilter* pf = malloc(sizeof(DTMFDolphinPulseFilter));
|
||||
pf->duration = 0;
|
||||
pf->period = 0;
|
||||
pf->offset = 0;
|
||||
pf->lookup_table = NULL;
|
||||
return pf;
|
||||
}
|
||||
|
||||
DTMFDolphinAudio* dtmf_dolphin_audio_alloc() {
|
||||
DTMFDolphinAudio* player = malloc(sizeof(DTMFDolphinAudio));
|
||||
player->buffer_length = SAMPLE_BUFFER_LENGTH;
|
||||
player->half_buffer_length = SAMPLE_BUFFER_LENGTH / 2;
|
||||
player->sample_buffer = malloc(sizeof(uint16_t) * player->buffer_length);
|
||||
player->osc1 = dtmf_dolphin_osc_alloc();
|
||||
player->osc2 = dtmf_dolphin_osc_alloc();
|
||||
player->volume = 1.0f;
|
||||
player->queue = furi_message_queue_alloc(10, sizeof(DTMFDolphinCustomEvent));
|
||||
player->filter = dtmf_dolphin_pulse_filter_alloc();
|
||||
player->playing = false;
|
||||
dtmf_dolphin_audio_clear_samples(player);
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
size_t calc_waveform_period(float freq) {
|
||||
if(!freq) {
|
||||
return 0;
|
||||
}
|
||||
// DMA Rate calculation, thanks to Dr_Zlo
|
||||
float dma_rate = CPU_CLOCK_FREQ / 2 / DTMF_DOLPHIN_HAL_DMA_PRESCALER /
|
||||
(DTMF_DOLPHIN_HAL_DMA_AUTORELOAD + 1);
|
||||
|
||||
// Using a constant scaling modifier, which likely represents
|
||||
// the combined system overhead and isr latency.
|
||||
return (uint16_t)dma_rate * 2 / freq * 0.801923;
|
||||
}
|
||||
|
||||
void osc_generate_lookup_table(DTMFDolphinOsc* osc, float freq) {
|
||||
if(osc->lookup_table != NULL) {
|
||||
free(osc->lookup_table);
|
||||
}
|
||||
osc->offset = 0;
|
||||
osc->cached_freq = freq;
|
||||
osc->period = calc_waveform_period(freq);
|
||||
if(!osc->period) {
|
||||
osc->lookup_table = NULL;
|
||||
return;
|
||||
}
|
||||
osc->lookup_table = malloc(sizeof(float) * osc->period);
|
||||
|
||||
for(size_t i = 0; i < osc->period; i++) {
|
||||
osc->lookup_table[i] = sin(i * PERIOD_2_PI / osc->period) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void filter_generate_lookup_table(
|
||||
DTMFDolphinPulseFilter* pf,
|
||||
uint16_t pulses,
|
||||
uint16_t pulse_ms,
|
||||
uint16_t gap_ms) {
|
||||
if(pf->lookup_table != NULL) {
|
||||
free(pf->lookup_table);
|
||||
}
|
||||
pf->offset = 0;
|
||||
|
||||
uint16_t gap_period = calc_waveform_period(1000 / (float)gap_ms);
|
||||
uint16_t pulse_period = calc_waveform_period(1000 / (float)pulse_ms);
|
||||
pf->period = pulse_period + gap_period;
|
||||
|
||||
if(!pf->period) {
|
||||
pf->lookup_table = NULL;
|
||||
return;
|
||||
}
|
||||
pf->duration = pf->period * pulses;
|
||||
pf->lookup_table = malloc(sizeof(bool) * pf->duration);
|
||||
|
||||
for(size_t i = 0; i < pf->duration; i++) {
|
||||
pf->lookup_table[i] = i % pf->period < pulse_period;
|
||||
}
|
||||
}
|
||||
|
||||
float sample_frame(DTMFDolphinOsc* osc) {
|
||||
float frame = 0.0;
|
||||
|
||||
if(osc->period) {
|
||||
frame = osc->lookup_table[osc->offset];
|
||||
osc->offset = (osc->offset + 1) % osc->period;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
bool sample_filter(DTMFDolphinPulseFilter* pf) {
|
||||
bool frame = true;
|
||||
|
||||
if(pf->duration) {
|
||||
if(pf->offset < pf->duration) {
|
||||
frame = pf->lookup_table[pf->offset];
|
||||
pf->offset = pf->offset + 1;
|
||||
} else {
|
||||
frame = false;
|
||||
}
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc) {
|
||||
if(osc->lookup_table != NULL) {
|
||||
free(osc->lookup_table);
|
||||
}
|
||||
free(osc);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_filter_free(DTMFDolphinPulseFilter* pf) {
|
||||
if(pf->lookup_table != NULL) {
|
||||
free(pf->lookup_table);
|
||||
}
|
||||
free(pf);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_audio_free(DTMFDolphinAudio* player) {
|
||||
furi_message_queue_free(player->queue);
|
||||
dtmf_dolphin_osc_free(player->osc1);
|
||||
dtmf_dolphin_osc_free(player->osc2);
|
||||
dtmf_dolphin_filter_free(player->filter);
|
||||
free(player->sample_buffer);
|
||||
free(player);
|
||||
current_player = NULL;
|
||||
}
|
||||
|
||||
bool generate_waveform(DTMFDolphinAudio* player, uint16_t buffer_index) {
|
||||
uint16_t* sample_buffer_start = &player->sample_buffer[buffer_index];
|
||||
|
||||
for(size_t i = 0; i < player->half_buffer_length; i++) {
|
||||
float data = 0;
|
||||
if(player->osc2->period) {
|
||||
data = (sample_frame(player->osc1) / 2) + (sample_frame(player->osc2) / 2);
|
||||
} else {
|
||||
data = (sample_frame(player->osc1));
|
||||
}
|
||||
data *= sample_filter(player->filter) ? player->volume : 0.0;
|
||||
data *= UINT8_MAX / 2; // scale -128..127
|
||||
data += UINT8_MAX / 2; // to unsigned
|
||||
|
||||
if(data < 0) {
|
||||
data = 0;
|
||||
}
|
||||
|
||||
if(data > 255) {
|
||||
data = 255;
|
||||
}
|
||||
|
||||
sample_buffer_start[i] = data;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_audio_play_tones(
|
||||
float freq1,
|
||||
float freq2,
|
||||
uint16_t pulses,
|
||||
uint16_t pulse_ms,
|
||||
uint16_t gap_ms) {
|
||||
if(current_player != NULL && current_player->playing) {
|
||||
// Cannot start playing while still playing something else
|
||||
return false;
|
||||
}
|
||||
current_player = dtmf_dolphin_audio_alloc();
|
||||
|
||||
osc_generate_lookup_table(current_player->osc1, freq1);
|
||||
osc_generate_lookup_table(current_player->osc2, freq2);
|
||||
filter_generate_lookup_table(current_player->filter, pulses, pulse_ms, gap_ms);
|
||||
|
||||
generate_waveform(current_player, 0);
|
||||
generate_waveform(current_player, current_player->half_buffer_length);
|
||||
|
||||
dtmf_dolphin_speaker_init();
|
||||
dtmf_dolphin_dma_init((uint32_t)current_player->sample_buffer, current_player->buffer_length);
|
||||
|
||||
furi_hal_interrupt_set_isr(
|
||||
FuriHalInterruptIdDma1Ch1, dtmf_dolphin_audio_dma_isr, current_player->queue);
|
||||
if(furi_hal_speaker_acquire(1000)) {
|
||||
dtmf_dolphin_dma_start();
|
||||
dtmf_dolphin_speaker_start();
|
||||
current_player->playing = true;
|
||||
return true;
|
||||
} else {
|
||||
current_player->playing = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_audio_stop_tones() {
|
||||
if(current_player != NULL && !current_player->playing) {
|
||||
// Can't stop a player that isn't playing.
|
||||
return false;
|
||||
}
|
||||
while(current_player->filter->offset > 0 &&
|
||||
current_player->filter->offset < current_player->filter->duration) {
|
||||
// run remaining ticks if needed to complete filter sequence
|
||||
dtmf_dolphin_audio_handle_tick();
|
||||
}
|
||||
dtmf_dolphin_speaker_stop();
|
||||
dtmf_dolphin_dma_stop();
|
||||
furi_hal_speaker_release();
|
||||
|
||||
furi_hal_interrupt_set_isr(FuriHalInterruptIdDma1Ch1, NULL, NULL);
|
||||
|
||||
dtmf_dolphin_audio_free(current_player);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_audio_handle_tick() {
|
||||
bool handled = false;
|
||||
|
||||
if(current_player) {
|
||||
DTMFDolphinCustomEvent event;
|
||||
if(furi_message_queue_get(current_player->queue, &event, 250) == FuriStatusOk) {
|
||||
if(event.type == DTMFDolphinEventDMAHalfTransfer) {
|
||||
generate_waveform(current_player, 0);
|
||||
handled = true;
|
||||
} else if(event.type == DTMFDolphinEventDMAFullTransfer) {
|
||||
generate_waveform(current_player, current_player->half_buffer_length);
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return handled;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#pragma once
|
||||
// #include "dtmf_dolphin_i.h"
|
||||
#include "dtmf_dolphin_event.h"
|
||||
#include "dtmf_dolphin_hal.h"
|
||||
|
||||
#define SAMPLE_BUFFER_LENGTH 8192
|
||||
#define PERIOD_2_PI 6.2832
|
||||
#define CPU_CLOCK_FREQ 64000000
|
||||
|
||||
typedef struct {
|
||||
float cached_freq;
|
||||
size_t period;
|
||||
float* lookup_table;
|
||||
uint16_t offset;
|
||||
} DTMFDolphinOsc;
|
||||
|
||||
typedef struct {
|
||||
float duration;
|
||||
size_t period;
|
||||
bool* lookup_table;
|
||||
uint16_t offset;
|
||||
} DTMFDolphinPulseFilter;
|
||||
|
||||
typedef struct {
|
||||
size_t buffer_length;
|
||||
size_t half_buffer_length;
|
||||
uint8_t* buffer_buffer;
|
||||
uint16_t* sample_buffer;
|
||||
float volume;
|
||||
FuriMessageQueue* queue;
|
||||
DTMFDolphinOsc* osc1;
|
||||
DTMFDolphinOsc* osc2;
|
||||
DTMFDolphinPulseFilter* filter;
|
||||
bool playing;
|
||||
} DTMFDolphinAudio;
|
||||
|
||||
DTMFDolphinOsc* dtmf_dolphin_osc_alloc();
|
||||
|
||||
DTMFDolphinAudio* dtmf_dolphin_audio_alloc();
|
||||
|
||||
void dtmf_dolphin_audio_free(DTMFDolphinAudio* player);
|
||||
|
||||
void dtmf_dolphin_osc_free(DTMFDolphinOsc* osc);
|
||||
|
||||
bool dtmf_dolphin_audio_play_tones(
|
||||
float freq1,
|
||||
float freq2,
|
||||
uint16_t pulses,
|
||||
uint16_t pulse_ms,
|
||||
uint16_t gap_ms);
|
||||
|
||||
bool dtmf_dolphin_audio_stop_tones();
|
||||
|
||||
bool dtmf_dolphin_audio_handle_tick();
|
||||
@@ -1,220 +0,0 @@
|
||||
#include "dtmf_dolphin_data.h"
|
||||
|
||||
typedef struct {
|
||||
const uint8_t row;
|
||||
const uint8_t col;
|
||||
const uint8_t span;
|
||||
} DTMFDolphinTonePos;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const float frequency_1;
|
||||
const float frequency_2;
|
||||
const DTMFDolphinTonePos pos;
|
||||
const uint16_t pulses; // for Redbox
|
||||
const uint16_t pulse_ms; // for Redbox
|
||||
const uint16_t gap_duration; // for Redbox
|
||||
} DTMFDolphinTones;
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
DTMFDolphinToneSection block;
|
||||
uint8_t tone_count;
|
||||
DTMFDolphinTones tones[DTMF_DOLPHIN_MAX_TONE_COUNT];
|
||||
} DTMFDolphinSceneData;
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataDialer = {
|
||||
.name = "Dialer",
|
||||
.block = DTMF_DOLPHIN_TONE_BLOCK_DIALER,
|
||||
.tone_count = 16,
|
||||
.tones = {
|
||||
{"1", 697.0, 1209.0, {0, 0, 1}, 0, 0, 0},
|
||||
{"2", 697.0, 1336.0, {0, 1, 1}, 0, 0, 0},
|
||||
{"3", 697.0, 1477.0, {0, 2, 1}, 0, 0, 0},
|
||||
{"A", 697.0, 1633.0, {0, 3, 1}, 0, 0, 0},
|
||||
{"4", 770.0, 1209.0, {1, 0, 1}, 0, 0, 0},
|
||||
{"5", 770.0, 1336.0, {1, 1, 1}, 0, 0, 0},
|
||||
{"6", 770.0, 1477.0, {1, 2, 1}, 0, 0, 0},
|
||||
{"B", 770.0, 1633.0, {1, 3, 1}, 0, 0, 0},
|
||||
{"7", 852.0, 1209.0, {2, 0, 1}, 0, 0, 0},
|
||||
{"8", 852.0, 1336.0, {2, 1, 1}, 0, 0, 0},
|
||||
{"9", 852.0, 1477.0, {2, 2, 1}, 0, 0, 0},
|
||||
{"C", 852.0, 1633.0, {2, 3, 1}, 0, 0, 0},
|
||||
{"*", 941.0, 1209.0, {3, 0, 1}, 0, 0, 0},
|
||||
{"0", 941.0, 1336.0, {3, 1, 1}, 0, 0, 0},
|
||||
{"#", 941.0, 1477.0, {3, 2, 1}, 0, 0, 0},
|
||||
{"D", 941.0, 1633.0, {3, 3, 1}, 0, 0, 0},
|
||||
}};
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataBluebox = {
|
||||
.name = "Bluebox",
|
||||
.block = DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX,
|
||||
.tone_count = 13,
|
||||
.tones = {
|
||||
{"1", 700.0, 900.0, {0, 0, 1}, 0, 0, 0},
|
||||
{"2", 700.0, 1100.0, {0, 1, 1}, 0, 0, 0},
|
||||
{"3", 900.0, 1100.0, {0, 2, 1}, 0, 0, 0},
|
||||
{"4", 700.0, 1300.0, {1, 0, 1}, 0, 0, 0},
|
||||
{"5", 900.0, 1300.0, {1, 1, 1}, 0, 0, 0},
|
||||
{"6", 1100.0, 1300.0, {1, 2, 1}, 0, 0, 0},
|
||||
{"7", 700.0, 1500.0, {2, 0, 1}, 0, 0, 0},
|
||||
{"8", 900.0, 1500.0, {2, 1, 1}, 0, 0, 0},
|
||||
{"9", 1100.0, 1500.0, {2, 2, 1}, 0, 0, 0},
|
||||
{"0", 1300.0, 1500.0, {3, 1, 1}, 0, 0, 0},
|
||||
{"KP", 1100.0, 1700.0, {0, 3, 2}, 0, 0, 0},
|
||||
{"ST", 1500.0, 1700.0, {1, 3, 2}, 0, 0, 0},
|
||||
{"2600", 2600.0, 0.0, {3, 2, 3}, 0, 0, 0},
|
||||
}};
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUS = {
|
||||
.name = "Redbox (US)",
|
||||
.block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US,
|
||||
.tone_count = 4,
|
||||
.tones = {
|
||||
{"Nickel", 1700.0, 2200.0, {0, 0, 5}, 1, 66, 0},
|
||||
{"Dime", 1700.0, 2200.0, {1, 0, 5}, 2, 66, 66},
|
||||
{"Quarter", 1700.0, 2200.0, {2, 0, 5}, 5, 33, 33},
|
||||
{"Dollar", 1700.0, 2200.0, {3, 0, 5}, 1, 650, 0},
|
||||
}};
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataRedboxCA = {
|
||||
.name = "Redbox (CA)",
|
||||
.block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_CA,
|
||||
.tone_count = 3,
|
||||
.tones = {
|
||||
{"Nickel", 2200.0, 0.0, {0, 0, 5}, 1, 66, 0},
|
||||
{"Dime", 2200.0, 0.0, {1, 0, 5}, 2, 66, 66},
|
||||
{"Quarter", 2200.0, 0.0, {2, 0, 5}, 5, 33, 33},
|
||||
}};
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataRedboxUK = {
|
||||
.name = "Redbox (UK)",
|
||||
.block = DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK,
|
||||
.tone_count = 2,
|
||||
.tones = {
|
||||
{"10p", 1000.0, 0.0, {0, 0, 5}, 1, 200, 0},
|
||||
{"50p", 1000.0, 0.0, {1, 0, 5}, 1, 350, 0},
|
||||
}};
|
||||
|
||||
DTMFDolphinSceneData DTMFDolphinSceneDataMisc = {
|
||||
.name = "Misc",
|
||||
.block = DTMF_DOLPHIN_TONE_BLOCK_MISC,
|
||||
.tone_count = 3,
|
||||
.tones = {
|
||||
{"CCITT 11", 700.0, 1700.0, {0, 0, 5}, 0, 0, 0},
|
||||
{"CCITT 12", 900.0, 1700.0, {1, 0, 5}, 0, 0, 0},
|
||||
{"CCITT KP2", 1300.0, 1700.0, {2, 0, 5}, 0, 0, 0},
|
||||
}};
|
||||
|
||||
DTMFDolphinToneSection current_section;
|
||||
DTMFDolphinSceneData* current_scene_data;
|
||||
|
||||
void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section) {
|
||||
current_section = section;
|
||||
|
||||
switch(current_section) {
|
||||
case DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX:
|
||||
current_scene_data = &DTMFDolphinSceneDataBluebox;
|
||||
break;
|
||||
case DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US:
|
||||
current_scene_data = &DTMFDolphinSceneDataRedboxUS;
|
||||
break;
|
||||
case DTMF_DOLPHIN_TONE_BLOCK_REDBOX_CA:
|
||||
current_scene_data = &DTMFDolphinSceneDataRedboxCA;
|
||||
break;
|
||||
case DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK:
|
||||
current_scene_data = &DTMFDolphinSceneDataRedboxUK;
|
||||
break;
|
||||
case DTMF_DOLPHIN_TONE_BLOCK_MISC:
|
||||
current_scene_data = &DTMFDolphinSceneDataMisc;
|
||||
break;
|
||||
default: // DTMF_DOLPHIN_TONE_BLOCK_DIALER:
|
||||
current_scene_data = &DTMFDolphinSceneDataDialer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DTMFDolphinToneSection dtmf_dolphin_data_get_current_section() {
|
||||
return current_section;
|
||||
}
|
||||
|
||||
DTMFDolphinSceneData* dtmf_dolphin_data_get_current_scene_data() {
|
||||
return current_scene_data;
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_data_get_tone_frequencies(float* freq1, float* freq2, uint8_t row, uint8_t col) {
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if(tones.pos.row == row && tones.pos.col == col) {
|
||||
freq1[0] = tones.frequency_1;
|
||||
freq2[0] = tones.frequency_2;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_data_get_filter_data(
|
||||
uint16_t* pulses,
|
||||
uint16_t* pulse_ms,
|
||||
uint16_t* gap_ms,
|
||||
uint8_t row,
|
||||
uint8_t col) {
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if(tones.pos.row == row && tones.pos.col == col) {
|
||||
pulses[0] = tones.pulses;
|
||||
pulse_ms[0] = tones.pulse_ms;
|
||||
gap_ms[0] = tones.gap_duration;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* dtmf_dolphin_data_get_tone_name(uint8_t row, uint8_t col) {
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if(tones.pos.row == row && tones.pos.col == col) {
|
||||
return tones.name;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* dtmf_dolphin_data_get_current_section_name() {
|
||||
if(current_scene_data) {
|
||||
return current_scene_data->name;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void dtmf_dolphin_tone_get_max_pos(uint8_t* max_rows, uint8_t* max_cols, uint8_t* max_span) {
|
||||
max_rows[0] = 0;
|
||||
max_cols[0] = 0;
|
||||
max_span[0] = 0;
|
||||
uint8_t tmp_rowspan[5] = {0, 0, 0, 0, 0};
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if(tones.pos.row > max_rows[0]) {
|
||||
max_rows[0] = tones.pos.row;
|
||||
}
|
||||
if(tones.pos.col > max_cols[0]) {
|
||||
max_cols[0] = tones.pos.col;
|
||||
}
|
||||
tmp_rowspan[tones.pos.row] += tones.pos.span;
|
||||
if(tmp_rowspan[tones.pos.row] > max_span[0]) max_span[0] = tmp_rowspan[tones.pos.row];
|
||||
}
|
||||
max_rows[0]++;
|
||||
max_cols[0]++;
|
||||
}
|
||||
|
||||
uint8_t dtmf_dolphin_get_tone_span(uint8_t row, uint8_t col) {
|
||||
for(size_t i = 0; i < current_scene_data->tone_count; i++) {
|
||||
DTMFDolphinTones tones = current_scene_data->tones[i];
|
||||
if(tones.pos.row == row && tones.pos.col == col) {
|
||||
return tones.pos.span;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define DTMF_DOLPHIN_MAX_TONE_COUNT 16
|
||||
|
||||
typedef enum {
|
||||
DTMF_DOLPHIN_TONE_BLOCK_DIALER,
|
||||
DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX,
|
||||
DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US,
|
||||
DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK,
|
||||
DTMF_DOLPHIN_TONE_BLOCK_REDBOX_CA,
|
||||
DTMF_DOLPHIN_TONE_BLOCK_MISC,
|
||||
} DTMFDolphinToneSection;
|
||||
|
||||
void dtmf_dolphin_data_set_current_section(DTMFDolphinToneSection section);
|
||||
|
||||
DTMFDolphinToneSection dtmf_dolphin_data_get_current_section();
|
||||
|
||||
bool dtmf_dolphin_data_get_tone_frequencies(float* freq1, float* freq2, uint8_t row, uint8_t col);
|
||||
|
||||
bool dtmf_dolphin_data_get_filter_data(
|
||||
uint16_t* pulses,
|
||||
uint16_t* pulse_ms,
|
||||
uint16_t* gap_ms,
|
||||
uint8_t row,
|
||||
uint8_t col);
|
||||
|
||||
const char* dtmf_dolphin_data_get_tone_name(uint8_t row, uint8_t col);
|
||||
|
||||
const char* dtmf_dolphin_data_get_current_section_name();
|
||||
|
||||
void dtmf_dolphin_tone_get_max_pos(uint8_t* max_rows, uint8_t* max_cols, uint8_t* max_span);
|
||||
|
||||
uint8_t dtmf_dolphin_get_tone_span(uint8_t row, uint8_t col);
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
DTMFDolphinEventVolumeUp = 0,
|
||||
DTMFDolphinEventVolumeDown,
|
||||
DTMFDolphinDialerOkCB,
|
||||
DTMFDolphinEventStartDialer,
|
||||
DTMFDolphinEventStartBluebox,
|
||||
DTMFDolphinEventStartRedboxUS,
|
||||
DTMFDolphinEventStartRedboxUK,
|
||||
DTMFDolphinEventStartRedboxCA,
|
||||
DTMFDolphinEventStartMisc,
|
||||
DTMFDolphinEventPlayTones,
|
||||
DTMFDolphinEventStopTones,
|
||||
DTMFDolphinEventDMAHalfTransfer,
|
||||
DTMFDolphinEventDMAFullTransfer,
|
||||
} DTMFDolphinEvent;
|
||||
|
||||
typedef struct {
|
||||
DTMFDolphinEvent type;
|
||||
} DTMFDolphinCustomEvent;
|
||||
@@ -1,52 +0,0 @@
|
||||
#include "dtmf_dolphin_hal.h"
|
||||
|
||||
void dtmf_dolphin_speaker_init() {
|
||||
LL_TIM_InitTypeDef TIM_InitStruct = {0};
|
||||
TIM_InitStruct.Prescaler = DTMF_DOLPHIN_HAL_DMA_PRESCALER;
|
||||
TIM_InitStruct.Autoreload = DTMF_DOLPHIN_HAL_DMA_AUTORELOAD;
|
||||
LL_TIM_Init(FURI_HAL_SPEAKER_TIMER, &TIM_InitStruct);
|
||||
|
||||
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
|
||||
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
|
||||
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE;
|
||||
TIM_OC_InitStruct.CompareValue = 127;
|
||||
LL_TIM_OC_Init(FURI_HAL_SPEAKER_TIMER, FURI_HAL_SPEAKER_CHANNEL, &TIM_OC_InitStruct);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_speaker_start() {
|
||||
LL_TIM_EnableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_EnableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_speaker_stop() {
|
||||
LL_TIM_DisableAllOutputs(FURI_HAL_SPEAKER_TIMER);
|
||||
LL_TIM_DisableCounter(FURI_HAL_SPEAKER_TIMER);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_dma_init(uint32_t address, size_t size) {
|
||||
uint32_t dma_dst = (uint32_t) & (FURI_HAL_SPEAKER_TIMER->CCR1);
|
||||
|
||||
LL_DMA_ConfigAddresses(DMA_INSTANCE, address, dma_dst, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
||||
LL_DMA_SetDataLength(DMA_INSTANCE, size);
|
||||
|
||||
LL_DMA_SetPeriphRequest(DMA_INSTANCE, LL_DMAMUX_REQ_TIM16_UP);
|
||||
LL_DMA_SetDataTransferDirection(DMA_INSTANCE, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
|
||||
LL_DMA_SetChannelPriorityLevel(DMA_INSTANCE, LL_DMA_PRIORITY_VERYHIGH);
|
||||
LL_DMA_SetMode(DMA_INSTANCE, LL_DMA_MODE_CIRCULAR);
|
||||
LL_DMA_SetPeriphIncMode(DMA_INSTANCE, LL_DMA_PERIPH_NOINCREMENT);
|
||||
LL_DMA_SetMemoryIncMode(DMA_INSTANCE, LL_DMA_MEMORY_INCREMENT);
|
||||
LL_DMA_SetPeriphSize(DMA_INSTANCE, LL_DMA_PDATAALIGN_HALFWORD);
|
||||
LL_DMA_SetMemorySize(DMA_INSTANCE, LL_DMA_MDATAALIGN_HALFWORD);
|
||||
|
||||
LL_DMA_EnableIT_TC(DMA_INSTANCE);
|
||||
LL_DMA_EnableIT_HT(DMA_INSTANCE);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_dma_start() {
|
||||
LL_DMA_EnableChannel(DMA_INSTANCE);
|
||||
LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_SPEAKER_TIMER);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_dma_stop() {
|
||||
LL_DMA_DisableChannel(DMA_INSTANCE);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <stm32wb55xx.h>
|
||||
#include <stm32wbxx_ll_tim.h>
|
||||
#include <stm32wbxx_ll_dma.h>
|
||||
|
||||
#define FURI_HAL_SPEAKER_TIMER TIM16
|
||||
#define FURI_HAL_SPEAKER_CHANNEL LL_TIM_CHANNEL_CH1
|
||||
#define DMA_INSTANCE DMA1, LL_DMA_CHANNEL_1
|
||||
|
||||
#define DTMF_DOLPHIN_HAL_DMA_PRESCALER 4
|
||||
#define DTMF_DOLPHIN_HAL_DMA_AUTORELOAD 255
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void dtmf_dolphin_speaker_init();
|
||||
|
||||
void dtmf_dolphin_speaker_start();
|
||||
|
||||
void dtmf_dolphin_speaker_stop();
|
||||
|
||||
void dtmf_dolphin_dma_init(uint32_t address, size_t size);
|
||||
|
||||
void dtmf_dolphin_dma_start();
|
||||
|
||||
void dtmf_dolphin_dma_stop();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "scenes/dtmf_dolphin_scene.h"
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
// #include <gui/modules/submenu.h>
|
||||
// #include <gui/modules/widget.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <input/input.h>
|
||||
|
||||
#include "dtmf_dolphin_event.h"
|
||||
|
||||
#include "views/dtmf_dolphin_dialer.h"
|
||||
|
||||
#define TAG "DTMFDolphin"
|
||||
|
||||
enum DTMFDolphinSceneState {
|
||||
DTMFDolphinSceneStateDialer,
|
||||
DTMFDolphinSceneStateBluebox,
|
||||
DTMFDolphinSceneStateRedboxUS,
|
||||
DTMFDolphinSceneStateRedboxUK,
|
||||
DTMFDolphinSceneStateRedboxCA,
|
||||
DTMFDolphinSceneStateMisc,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
VariableItemList* main_menu_list;
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer;
|
||||
|
||||
Gui* gui;
|
||||
// ButtonPanel* dialer_button_panel;
|
||||
// ButtonPanel* bluebox_button_panel;
|
||||
// ButtonPanel* redbox_button_panel;
|
||||
NotificationApp* notification;
|
||||
} DTMFDolphinApp;
|
||||
|
||||
typedef enum { DTMFDolphinViewMainMenu, DTMFDolphinViewDialer } DTMFDolphinView;
|
||||
|
Before Width: | Height: | Size: 306 B |
|
Before Width: | Height: | Size: 1.9 MiB |
@@ -1,30 +0,0 @@
|
||||
#include "dtmf_dolphin_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const dtmf_dolphin_scene_on_enter_handlers[])(void*) = {
|
||||
#include "dtmf_dolphin_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const dtmf_dolphin_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "dtmf_dolphin_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const dtmf_dolphin_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "dtmf_dolphin_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers dtmf_dolphin_scene_handlers = {
|
||||
.on_enter_handlers = dtmf_dolphin_scene_on_enter_handlers,
|
||||
.on_event_handlers = dtmf_dolphin_scene_on_event_handlers,
|
||||
.on_exit_handlers = dtmf_dolphin_scene_on_exit_handlers,
|
||||
.scene_num = DTMFDolphinSceneNum,
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) DTMFDolphinScene##id,
|
||||
typedef enum {
|
||||
#include "dtmf_dolphin_scene_config.h"
|
||||
DTMFDolphinSceneNum,
|
||||
} DTMFDolphinScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers dtmf_dolphin_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "dtmf_dolphin_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "dtmf_dolphin_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "dtmf_dolphin_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -1,2 +0,0 @@
|
||||
ADD_SCENE(dtmf_dolphin, start, Start)
|
||||
ADD_SCENE(dtmf_dolphin, dialer, Dialer)
|
||||
@@ -1,49 +0,0 @@
|
||||
#include "../dtmf_dolphin_i.h"
|
||||
// #include "../dtmf_dolphin_data.h"
|
||||
// #include "../dtmf_dolphin_audio.h"
|
||||
|
||||
void dtmf_dolphin_scene_dialer_on_enter(void* context) {
|
||||
DTMFDolphinApp* app = context;
|
||||
DTMFDolphinScene scene_id = DTMFDolphinSceneDialer;
|
||||
enum DTMFDolphinSceneState state = scene_manager_get_scene_state(app->scene_manager, scene_id);
|
||||
|
||||
switch(state) {
|
||||
case DTMFDolphinSceneStateBluebox:
|
||||
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_BLUEBOX);
|
||||
break;
|
||||
case DTMFDolphinSceneStateRedboxUS:
|
||||
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_US);
|
||||
break;
|
||||
case DTMFDolphinSceneStateRedboxUK:
|
||||
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_UK);
|
||||
break;
|
||||
case DTMFDolphinSceneStateRedboxCA:
|
||||
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_REDBOX_CA);
|
||||
break;
|
||||
case DTMFDolphinSceneStateMisc:
|
||||
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_MISC);
|
||||
break;
|
||||
default:
|
||||
dtmf_dolphin_data_set_current_section(DTMF_DOLPHIN_TONE_BLOCK_DIALER);
|
||||
break;
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DTMFDolphinViewDialer);
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_scene_dialer_on_event(void* context, SceneManagerEvent event) {
|
||||
DTMFDolphinApp* app = context;
|
||||
UNUSED(app);
|
||||
UNUSED(event);
|
||||
bool consumed = false;
|
||||
|
||||
// if(event.type == SceneManagerEventTypeTick) {
|
||||
// consumed = true;
|
||||
// }
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void dtmf_dolphin_scene_dialer_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
#include "../dtmf_dolphin_i.h"
|
||||
|
||||
static void dtmf_dolphin_scene_start_main_menu_enter_callback(void* context, uint32_t index) {
|
||||
DTMFDolphinApp* app = context;
|
||||
uint8_t cust_event = 255;
|
||||
switch(index) {
|
||||
case 0:
|
||||
cust_event = DTMFDolphinEventStartDialer;
|
||||
break;
|
||||
case 1:
|
||||
cust_event = DTMFDolphinEventStartBluebox;
|
||||
break;
|
||||
case 2:
|
||||
cust_event = DTMFDolphinEventStartRedboxUS;
|
||||
break;
|
||||
case 3:
|
||||
cust_event = DTMFDolphinEventStartRedboxUK;
|
||||
break;
|
||||
case 4:
|
||||
cust_event = DTMFDolphinEventStartRedboxCA;
|
||||
break;
|
||||
case 5:
|
||||
cust_event = DTMFDolphinEventStartMisc;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, cust_event);
|
||||
}
|
||||
|
||||
void dtmf_dolphin_scene_start_on_enter(void* context) {
|
||||
DTMFDolphinApp* app = context;
|
||||
VariableItemList* var_item_list = app->main_menu_list;
|
||||
|
||||
// VariableItem* item;
|
||||
variable_item_list_set_enter_callback(
|
||||
var_item_list, dtmf_dolphin_scene_start_main_menu_enter_callback, app);
|
||||
|
||||
variable_item_list_add(var_item_list, "Dialer", 0, NULL, context);
|
||||
variable_item_list_add(var_item_list, "Bluebox", 0, NULL, context);
|
||||
variable_item_list_add(var_item_list, "Redbox (US)", 0, NULL, context);
|
||||
variable_item_list_add(var_item_list, "Redbox (UK)", 0, NULL, context);
|
||||
variable_item_list_add(var_item_list, "Redbox (CA)", 0, NULL, context);
|
||||
variable_item_list_add(var_item_list, "Misc", 0, NULL, context);
|
||||
|
||||
variable_item_list_set_selected_item(
|
||||
var_item_list, scene_manager_get_scene_state(app->scene_manager, DTMFDolphinSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DTMFDolphinViewMainMenu);
|
||||
}
|
||||
|
||||
bool dtmf_dolphin_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
DTMFDolphinApp* app = context;
|
||||
UNUSED(app);
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
uint8_t sc_state;
|
||||
|
||||
switch(event.event) {
|
||||
case DTMFDolphinEventStartDialer:
|
||||
sc_state = DTMFDolphinSceneStateDialer;
|
||||
break;
|
||||
case DTMFDolphinEventStartBluebox:
|
||||
sc_state = DTMFDolphinSceneStateBluebox;
|
||||
break;
|
||||
case DTMFDolphinEventStartRedboxUS:
|
||||
sc_state = DTMFDolphinSceneStateRedboxUS;
|
||||
break;
|
||||
case DTMFDolphinEventStartRedboxUK:
|
||||
sc_state = DTMFDolphinSceneStateRedboxUK;
|
||||
break;
|
||||
case DTMFDolphinEventStartRedboxCA:
|
||||
sc_state = DTMFDolphinSceneStateRedboxCA;
|
||||
break;
|
||||
case DTMFDolphinEventStartMisc:
|
||||
sc_state = DTMFDolphinSceneStateMisc;
|
||||
break;
|
||||
default:
|
||||
return consumed;
|
||||
}
|
||||
scene_manager_set_scene_state(app->scene_manager, DTMFDolphinSceneDialer, sc_state);
|
||||
scene_manager_next_scene(app->scene_manager, DTMFDolphinSceneDialer);
|
||||
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void dtmf_dolphin_scene_start_on_exit(void* context) {
|
||||
DTMFDolphinApp* app = context;
|
||||
variable_item_list_reset(app->main_menu_list);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
#include "../dtmf_dolphin_event.h"
|
||||
#include "../dtmf_dolphin_data.h"
|
||||
#include "../dtmf_dolphin_audio.h"
|
||||
|
||||
#define DTMF_DOLPHIN_NUMPAD_X 1
|
||||
#define DTMF_DOLPHIN_NUMPAD_Y 14
|
||||
#define DTMF_DOLPHIN_BUTTON_WIDTH 13
|
||||
#define DTMF_DOLPHIN_BUTTON_HEIGHT 13
|
||||
#define DTMF_DOLPHIN_BUTTON_PADDING 1 // all sides
|
||||
@@ -1,350 +0,0 @@
|
||||
#include "dtmf_dolphin_dialer.h"
|
||||
|
||||
#include <gui/elements.h>
|
||||
|
||||
typedef struct DTMFDolphinDialer {
|
||||
View* view;
|
||||
DTMFDolphinDialerOkCallback callback;
|
||||
void* context;
|
||||
} DTMFDolphinDialer;
|
||||
|
||||
typedef struct {
|
||||
DTMFDolphinToneSection section;
|
||||
uint8_t row;
|
||||
uint8_t col;
|
||||
float freq1;
|
||||
float freq2;
|
||||
bool playing;
|
||||
uint16_t pulses;
|
||||
uint16_t pulse_ms;
|
||||
uint16_t gap_ms;
|
||||
} DTMFDolphinDialerModel;
|
||||
|
||||
static bool dtmf_dolphin_dialer_process_up(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
static bool dtmf_dolphin_dialer_process_down(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
static bool dtmf_dolphin_dialer_process_left(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
static bool
|
||||
dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event);
|
||||
|
||||
void draw_button(Canvas* canvas, uint8_t row, uint8_t col, bool invert) {
|
||||
uint8_t left = DTMF_DOLPHIN_NUMPAD_X + // ((col + 1) * DTMF_DOLPHIN_BUTTON_PADDING) +
|
||||
(col * DTMF_DOLPHIN_BUTTON_WIDTH);
|
||||
// (col * DTMF_DOLPHIN_BUTTON_PADDING);
|
||||
uint8_t top = DTMF_DOLPHIN_NUMPAD_Y + // ((row + 1) * DTMF_DOLPHIN_BUTTON_PADDING) +
|
||||
(row * DTMF_DOLPHIN_BUTTON_HEIGHT);
|
||||
// (row * DTMF_DOLPHIN_BUTTON_PADDING);
|
||||
|
||||
uint8_t span = dtmf_dolphin_get_tone_span(row, col);
|
||||
|
||||
if(span == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(invert)
|
||||
canvas_draw_rbox(
|
||||
canvas,
|
||||
left,
|
||||
top,
|
||||
(DTMF_DOLPHIN_BUTTON_WIDTH * span) - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
|
||||
DTMF_DOLPHIN_BUTTON_HEIGHT - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
|
||||
2);
|
||||
else
|
||||
canvas_draw_rframe(
|
||||
canvas,
|
||||
left,
|
||||
top,
|
||||
(DTMF_DOLPHIN_BUTTON_WIDTH * span) - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
|
||||
DTMF_DOLPHIN_BUTTON_HEIGHT - (DTMF_DOLPHIN_BUTTON_PADDING * 2),
|
||||
2);
|
||||
|
||||
if(invert) canvas_invert_color(canvas);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
// canvas_set_color(canvas, invert ? ColorWhite : ColorBlack);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
left - 1 + (int)((DTMF_DOLPHIN_BUTTON_WIDTH * span) / 2),
|
||||
top + (int)(DTMF_DOLPHIN_BUTTON_HEIGHT / 2),
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
dtmf_dolphin_data_get_tone_name(row, col));
|
||||
|
||||
if(invert) canvas_invert_color(canvas);
|
||||
}
|
||||
|
||||
void draw_dialer(Canvas* canvas, void* _model) {
|
||||
DTMFDolphinDialerModel* model = _model;
|
||||
uint8_t max_rows;
|
||||
uint8_t max_cols;
|
||||
uint8_t max_span;
|
||||
dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
for(int r = 0; r < max_rows; r++) {
|
||||
for(int c = 0; c < max_cols; c++) {
|
||||
if(model->row == r && model->col == c)
|
||||
draw_button(canvas, r, c, true);
|
||||
else
|
||||
draw_button(canvas, r, c, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void update_frequencies(DTMFDolphinDialerModel* model) {
|
||||
dtmf_dolphin_data_get_tone_frequencies(&model->freq1, &model->freq2, model->row, model->col);
|
||||
dtmf_dolphin_data_get_filter_data(
|
||||
&model->pulses, &model->pulse_ms, &model->gap_ms, model->row, model->col);
|
||||
}
|
||||
|
||||
static void dtmf_dolphin_dialer_draw_callback(Canvas* canvas, void* _model) {
|
||||
DTMFDolphinDialerModel* model = _model;
|
||||
if(model->playing) {
|
||||
// Leverage the prioritized draw callback to handle
|
||||
// the DMA so that it doesn't skip.
|
||||
dtmf_dolphin_audio_handle_tick();
|
||||
// Don't do any drawing if audio is playing.
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas,
|
||||
canvas_width(canvas) / 2,
|
||||
canvas_height(canvas) / 2,
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
"Playing Tones");
|
||||
return;
|
||||
}
|
||||
update_frequencies(model);
|
||||
uint8_t max_rows = 0;
|
||||
uint8_t max_cols = 0;
|
||||
uint8_t max_span = 0;
|
||||
dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span);
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text(canvas, 2, 10, dtmf_dolphin_data_get_current_section_name());
|
||||
canvas_draw_line(
|
||||
canvas,
|
||||
(max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1,
|
||||
0,
|
||||
(max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 1,
|
||||
canvas_height(canvas));
|
||||
elements_multiline_text(canvas, (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 4, 10, "Detail");
|
||||
canvas_draw_line(
|
||||
canvas, 0, DTMF_DOLPHIN_NUMPAD_Y - 3, canvas_width(canvas), DTMF_DOLPHIN_NUMPAD_Y - 3);
|
||||
// elements_multiline_text_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Dialer Mode");
|
||||
|
||||
draw_dialer(canvas, model);
|
||||
|
||||
FuriString* output = furi_string_alloc();
|
||||
|
||||
if(model->freq1 && model->freq2) {
|
||||
furi_string_cat_printf(
|
||||
output,
|
||||
"Dual Tone\nF1: %u Hz\nF2: %u Hz\n",
|
||||
(unsigned int)model->freq1,
|
||||
(unsigned int)model->freq2);
|
||||
} else if(model->freq1) {
|
||||
furi_string_cat_printf(output, "Single Tone\nF: %u Hz\n", (unsigned int)model->freq1);
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
if(model->pulse_ms) {
|
||||
furi_string_cat_printf(output, "P: %u * %u ms\n", model->pulses, model->pulse_ms);
|
||||
}
|
||||
if(model->gap_ms) {
|
||||
furi_string_cat_printf(output, "Gaps: %u ms\n", model->gap_ms);
|
||||
}
|
||||
elements_multiline_text(
|
||||
canvas, (max_span * DTMF_DOLPHIN_BUTTON_WIDTH) + 4, 21, furi_string_get_cstr(output));
|
||||
|
||||
furi_string_free(output);
|
||||
}
|
||||
|
||||
static bool dtmf_dolphin_dialer_input_callback(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyRight) {
|
||||
consumed = dtmf_dolphin_dialer_process_right(dtmf_dolphin_dialer);
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
consumed = dtmf_dolphin_dialer_process_left(dtmf_dolphin_dialer);
|
||||
} else if(event->key == InputKeyUp) {
|
||||
consumed = dtmf_dolphin_dialer_process_up(dtmf_dolphin_dialer);
|
||||
} else if(event->key == InputKeyDown) {
|
||||
consumed = dtmf_dolphin_dialer_process_down(dtmf_dolphin_dialer);
|
||||
}
|
||||
|
||||
} else if(event->key == InputKeyOk) {
|
||||
consumed = dtmf_dolphin_dialer_process_ok(dtmf_dolphin_dialer, event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static bool dtmf_dolphin_dialer_process_up(DTMFDolphinDialer* dtmf_dolphin_dialer) {
|
||||
with_view_model(
|
||||
dtmf_dolphin_dialer->view,
|
||||
DTMFDolphinDialerModel * model,
|
||||
{
|
||||
uint8_t span = 0;
|
||||
uint8_t cursor = model->row;
|
||||
while(span == 0 && cursor > 0) {
|
||||
cursor--;
|
||||
span = dtmf_dolphin_get_tone_span(cursor, model->col);
|
||||
}
|
||||
if(span != 0) {
|
||||
model->row = cursor;
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool dtmf_dolphin_dialer_process_down(DTMFDolphinDialer* dtmf_dolphin_dialer) {
|
||||
uint8_t max_rows = 0;
|
||||
uint8_t max_cols = 0;
|
||||
uint8_t max_span = 0;
|
||||
dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span);
|
||||
|
||||
with_view_model(
|
||||
dtmf_dolphin_dialer->view,
|
||||
DTMFDolphinDialerModel * model,
|
||||
{
|
||||
uint8_t span = 0;
|
||||
uint8_t cursor = model->row;
|
||||
while(span == 0 && cursor < max_rows - 1) {
|
||||
cursor++;
|
||||
span = dtmf_dolphin_get_tone_span(cursor, model->col);
|
||||
}
|
||||
if(span != 0) {
|
||||
model->row = cursor;
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool dtmf_dolphin_dialer_process_left(DTMFDolphinDialer* dtmf_dolphin_dialer) {
|
||||
with_view_model(
|
||||
dtmf_dolphin_dialer->view,
|
||||
DTMFDolphinDialerModel * model,
|
||||
{
|
||||
uint8_t span = 0;
|
||||
uint8_t cursor = model->col;
|
||||
while(span == 0 && cursor > 0) {
|
||||
cursor--;
|
||||
span = dtmf_dolphin_get_tone_span(model->row, cursor);
|
||||
}
|
||||
if(span != 0) {
|
||||
model->col = cursor;
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool dtmf_dolphin_dialer_process_right(DTMFDolphinDialer* dtmf_dolphin_dialer) {
|
||||
uint8_t max_rows = 0;
|
||||
uint8_t max_cols = 0;
|
||||
uint8_t max_span = 0;
|
||||
dtmf_dolphin_tone_get_max_pos(&max_rows, &max_cols, &max_span);
|
||||
|
||||
with_view_model(
|
||||
dtmf_dolphin_dialer->view,
|
||||
DTMFDolphinDialerModel * model,
|
||||
{
|
||||
uint8_t span = 0;
|
||||
uint8_t cursor = model->col;
|
||||
while(span == 0 && cursor < max_cols - 1) {
|
||||
cursor++;
|
||||
span = dtmf_dolphin_get_tone_span(model->row, cursor);
|
||||
}
|
||||
if(span != 0) {
|
||||
model->col = cursor;
|
||||
}
|
||||
},
|
||||
true);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
dtmf_dolphin_dialer_process_ok(DTMFDolphinDialer* dtmf_dolphin_dialer, InputEvent* event) {
|
||||
bool consumed = false;
|
||||
|
||||
with_view_model(
|
||||
dtmf_dolphin_dialer->view,
|
||||
DTMFDolphinDialerModel * model,
|
||||
{
|
||||
if(event->type == InputTypePress) {
|
||||
model->playing = dtmf_dolphin_audio_play_tones(
|
||||
model->freq1, model->freq2, model->pulses, model->pulse_ms, model->gap_ms);
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
model->playing = !dtmf_dolphin_audio_stop_tones();
|
||||
}
|
||||
},
|
||||
true);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static void dtmf_dolphin_dialer_enter_callback(void* context) {
|
||||
furi_assert(context);
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer = context;
|
||||
|
||||
with_view_model(
|
||||
dtmf_dolphin_dialer->view,
|
||||
DTMFDolphinDialerModel * model,
|
||||
{
|
||||
model->col = 0;
|
||||
model->row = 0;
|
||||
model->section = 0;
|
||||
model->freq1 = 0.0;
|
||||
model->freq2 = 0.0;
|
||||
model->playing = false;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer_alloc() {
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer = malloc(sizeof(DTMFDolphinDialer));
|
||||
|
||||
dtmf_dolphin_dialer->view = view_alloc();
|
||||
view_allocate_model(
|
||||
dtmf_dolphin_dialer->view, ViewModelTypeLocking, sizeof(DTMFDolphinDialerModel));
|
||||
|
||||
with_view_model(
|
||||
dtmf_dolphin_dialer->view,
|
||||
DTMFDolphinDialerModel * model,
|
||||
{
|
||||
model->col = 0;
|
||||
model->row = 0;
|
||||
model->section = 0;
|
||||
model->freq1 = 0.0;
|
||||
model->freq2 = 0.0;
|
||||
model->playing = false;
|
||||
},
|
||||
true);
|
||||
|
||||
view_set_context(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer);
|
||||
view_set_draw_callback(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer_draw_callback);
|
||||
view_set_input_callback(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer_input_callback);
|
||||
view_set_enter_callback(dtmf_dolphin_dialer->view, dtmf_dolphin_dialer_enter_callback);
|
||||
return dtmf_dolphin_dialer;
|
||||
}
|
||||
|
||||
void dtmf_dolphin_dialer_free(DTMFDolphinDialer* dtmf_dolphin_dialer) {
|
||||
furi_assert(dtmf_dolphin_dialer);
|
||||
view_free(dtmf_dolphin_dialer->view);
|
||||
free(dtmf_dolphin_dialer);
|
||||
}
|
||||
|
||||
View* dtmf_dolphin_dialer_get_view(DTMFDolphinDialer* dtmf_dolphin_dialer) {
|
||||
furi_assert(dtmf_dolphin_dialer);
|
||||
return dtmf_dolphin_dialer->view;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "dtmf_dolphin_common.h"
|
||||
|
||||
typedef struct DTMFDolphinDialer DTMFDolphinDialer;
|
||||
typedef void (*DTMFDolphinDialerOkCallback)(InputType type, void* context);
|
||||
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer_alloc();
|
||||
|
||||
void dtmf_dolphin_dialer_free(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
|
||||
View* dtmf_dolphin_dialer_get_view(DTMFDolphinDialer* dtmf_dolphin_dialer);
|
||||
|
||||
void dtmf_dolphin_dialer_set_ok_callback(
|
||||
DTMFDolphinDialer* dtmf_dolphin_dialer,
|
||||
DTMFDolphinDialerOkCallback callback,
|
||||
void* context);
|
||||
@@ -1,7 +0,0 @@
|
||||
#define WIFI_MODULE_INIT_VERSION "WFDM_0.1"
|
||||
|
||||
#define MODULE_CONTEXT_INITIALIZATION WIFI_MODULE_INIT_VERSION
|
||||
|
||||
#define FLIPPERZERO_SERIAL_BAUD 230400
|
||||
|
||||
#define NA 0
|
||||
@@ -1,12 +0,0 @@
|
||||
App(
|
||||
appid="ESP8266_Deauther",
|
||||
name="[ESP8266] Deauther",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="esp8266_deauth_app",
|
||||
cdefines=["APP_ESP8266_deauth"],
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
order=100,
|
||||
fap_icon="wifi_10px.png",
|
||||
fap_category="GPIO",
|
||||
)
|
||||
@@ -1,540 +0,0 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal_console.h>
|
||||
#include <furi_hal_gpio.h>
|
||||
#include <furi_hal_power.h>
|
||||
#include <furi_hal_uart.h>
|
||||
#include <gui/canvas_i.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
//#include <math.h>
|
||||
//#include <notification/notification.h>
|
||||
//#include <notification/notification_messages.h>
|
||||
//#include <stdlib.h>
|
||||
|
||||
#include <u8g2.h>
|
||||
|
||||
#include "FlipperZeroWiFiDeauthModuleDefines.h"
|
||||
|
||||
#define DEAUTH_APP_DEBUG 0
|
||||
|
||||
#if DEAUTH_APP_DEBUG
|
||||
#define APP_NAME_TAG "WiFi_Deauther"
|
||||
#define DEAUTH_APP_LOG_I(format, ...) FURI_LOG_I(APP_NAME_TAG, format, ##__VA_ARGS__)
|
||||
#define DEAUTH_APP_LOG_D(format, ...) FURI_LOG_D(APP_NAME_TAG, format, ##__VA_ARGS__)
|
||||
#define DEAUTH_APP_LOG_E(format, ...) FURI_LOG_E(APP_NAME_TAG, format, ##__VA_ARGS__)
|
||||
#else
|
||||
#define DEAUTH_APP_LOG_I(format, ...)
|
||||
#define DEAUTH_APP_LOG_D(format, ...)
|
||||
#define DEAUTH_APP_LOG_E(format, ...)
|
||||
#endif // WIFI_APP_DEBUG
|
||||
|
||||
#define DISABLE_CONSOLE !DEAUTH_APP_DEBUG
|
||||
#define ENABLE_MODULE_POWER 1
|
||||
#define ENABLE_MODULE_DETECTION 1
|
||||
|
||||
typedef enum EEventType // app internally defined event types
|
||||
{ EventTypeKey // flipper input.h type
|
||||
} EEventType;
|
||||
|
||||
typedef struct SPluginEvent {
|
||||
EEventType m_type;
|
||||
InputEvent m_input;
|
||||
} SPluginEvent;
|
||||
|
||||
typedef enum EAppContext {
|
||||
Undefined,
|
||||
WaitingForModule,
|
||||
Initializing,
|
||||
ModuleActive,
|
||||
} EAppContext;
|
||||
|
||||
typedef enum EWorkerEventFlags {
|
||||
WorkerEventReserved = (1 << 0), // Reserved for StreamBuffer internal event
|
||||
WorkerEventStop = (1 << 1),
|
||||
WorkerEventRx = (1 << 2),
|
||||
} EWorkerEventFlags;
|
||||
|
||||
typedef struct SGpioButtons {
|
||||
GpioPin const* pinButtonUp;
|
||||
GpioPin const* pinButtonDown;
|
||||
GpioPin const* pinButtonOK;
|
||||
GpioPin const* pinButtonBack;
|
||||
} SGpioButtons;
|
||||
|
||||
typedef struct SWiFiDeauthApp {
|
||||
FuriMutex* mutex;
|
||||
Gui* m_gui;
|
||||
FuriThread* m_worker_thread;
|
||||
//NotificationApp* m_notification;
|
||||
FuriStreamBuffer* m_rx_stream;
|
||||
SGpioButtons m_GpioButtons;
|
||||
|
||||
bool m_wifiDeauthModuleInitialized;
|
||||
bool m_wifiDeauthModuleAttached;
|
||||
|
||||
EAppContext m_context;
|
||||
|
||||
uint8_t m_backBuffer[128 * 8 * 8];
|
||||
//uint8_t m_renderBuffer[128 * 8 * 8];
|
||||
|
||||
uint8_t* m_backBufferPtr;
|
||||
//uint8_t* m_m_renderBufferPtr;
|
||||
|
||||
//uint8_t* m_originalBuffer;
|
||||
//uint8_t** m_originalBufferLocation;
|
||||
size_t m_canvasSize;
|
||||
|
||||
bool m_needUpdateGUI;
|
||||
} SWiFiDeauthApp;
|
||||
|
||||
/////// INIT STATE ///////
|
||||
static void esp8266_deauth_app_init(SWiFiDeauthApp* const app) {
|
||||
app->m_context = Undefined;
|
||||
|
||||
app->m_canvasSize = 128 * 8 * 8;
|
||||
memset(app->m_backBuffer, DEAUTH_APP_DEBUG ? 0xFF : 0x00, app->m_canvasSize);
|
||||
//memset(app->m_renderBuffer, DEAUTH_APP_DEBUG ? 0xFF : 0x00, app->m_canvasSize);
|
||||
|
||||
//app->m_originalBuffer = NULL;
|
||||
//app->m_originalBufferLocation = NULL;
|
||||
|
||||
//app->m_m_renderBufferPtr = app->m_renderBuffer;
|
||||
app->m_backBufferPtr = app->m_backBuffer;
|
||||
|
||||
app->m_GpioButtons.pinButtonUp = &gpio_ext_pc3;
|
||||
app->m_GpioButtons.pinButtonDown = &gpio_ext_pb2;
|
||||
app->m_GpioButtons.pinButtonOK = &gpio_ext_pb3;
|
||||
app->m_GpioButtons.pinButtonBack = &gpio_ext_pa4;
|
||||
|
||||
app->m_needUpdateGUI = false;
|
||||
|
||||
#if ENABLE_MODULE_POWER
|
||||
app->m_wifiDeauthModuleInitialized = false;
|
||||
#else
|
||||
app->m_wifiDeauthModuleInitialized = true;
|
||||
#endif // ENABLE_MODULE_POWER
|
||||
|
||||
#if ENABLE_MODULE_DETECTION
|
||||
app->m_wifiDeauthModuleAttached = false;
|
||||
#else
|
||||
app->m_wifiDeauthModuleAttached = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void esp8266_deauth_module_render_callback(Canvas* const canvas, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
SWiFiDeauthApp* app = ctx;
|
||||
furi_mutex_acquire(app->mutex, FuriWaitForever);
|
||||
|
||||
//if(app->m_needUpdateGUI)
|
||||
//{
|
||||
// app->m_needUpdateGUI = false;
|
||||
|
||||
// //app->m_canvasSize = canvas_get_buffer_size(canvas);
|
||||
// //app->m_originalBuffer = canvas_get_buffer(canvas);
|
||||
// //app->m_originalBufferLocation = &u8g2_GetBufferPtr(&canvas->fb);
|
||||
// //u8g2_GetBufferPtr(&canvas->fb) = app->m_m_renderBufferPtr;
|
||||
//}
|
||||
|
||||
//uint8_t* exchangeBuffers = app->m_m_renderBufferPtr;
|
||||
//app->m_m_renderBufferPtr = app->m_backBufferPtr;
|
||||
//app->m_backBufferPtr = exchangeBuffers;
|
||||
|
||||
//if(app->m_needUpdateGUI)
|
||||
//{
|
||||
// //memcpy(app->m_renderBuffer, app->m_backBuffer, app->m_canvasSize);
|
||||
// app->m_needUpdateGUI = false;
|
||||
//}
|
||||
|
||||
switch(app->m_context) {
|
||||
case Undefined: {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
const char* strInitializing = "Something wrong";
|
||||
canvas_draw_str(
|
||||
canvas,
|
||||
(u8g2_GetDisplayWidth(&canvas->fb) / 2) -
|
||||
(canvas_string_width(canvas, strInitializing) / 2),
|
||||
(u8g2_GetDisplayHeight(&canvas->fb) /
|
||||
2) /* - (u8g2_GetMaxCharHeight(&canvas->fb) / 2)*/,
|
||||
strInitializing);
|
||||
} break;
|
||||
case WaitingForModule:
|
||||
#if ENABLE_MODULE_DETECTION
|
||||
furi_assert(!app->m_wifiDeauthModuleAttached);
|
||||
if(!app->m_wifiDeauthModuleAttached) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
const char* strInitializing = "Attach WiFi Deauther module";
|
||||
canvas_draw_str(
|
||||
canvas,
|
||||
(u8g2_GetDisplayWidth(&canvas->fb) / 2) -
|
||||
(canvas_string_width(canvas, strInitializing) / 2),
|
||||
(u8g2_GetDisplayHeight(&canvas->fb) /
|
||||
2) /* - (u8g2_GetMaxCharHeight(&canvas->fb) / 2)*/,
|
||||
strInitializing);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case Initializing:
|
||||
#if ENABLE_MODULE_POWER
|
||||
{
|
||||
furi_assert(!app->m_wifiDeauthModuleInitialized);
|
||||
if(!app->m_wifiDeauthModuleInitialized) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
|
||||
const char* strInitializing = "Initializing...";
|
||||
canvas_draw_str(
|
||||
canvas,
|
||||
(u8g2_GetDisplayWidth(&canvas->fb) / 2) -
|
||||
(canvas_string_width(canvas, strInitializing) / 2),
|
||||
(u8g2_GetDisplayHeight(&canvas->fb) / 2) -
|
||||
(u8g2_GetMaxCharHeight(&canvas->fb) / 2),
|
||||
strInitializing);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_MODULE_POWER
|
||||
break;
|
||||
case ModuleActive: {
|
||||
uint8_t* buffer = canvas_get_buffer(canvas);
|
||||
app->m_canvasSize = canvas_get_buffer_size(canvas);
|
||||
memcpy(buffer, app->m_backBuffer, app->m_canvasSize);
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
furi_mutex_release(app->mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
esp8266_deauth_module_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
SPluginEvent event = {.m_type = EventTypeKey, .m_input = *input_event};
|
||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
||||
}
|
||||
|
||||
static void uart_on_irq_cb(UartIrqEvent ev, uint8_t data, void* context) {
|
||||
furi_assert(context);
|
||||
|
||||
SWiFiDeauthApp* app = context;
|
||||
|
||||
DEAUTH_APP_LOG_I("uart_echo_on_irq_cb");
|
||||
|
||||
if(ev == UartIrqEventRXNE) {
|
||||
DEAUTH_APP_LOG_I("ev == UartIrqEventRXNE");
|
||||
furi_stream_buffer_send(app->m_rx_stream, &data, 1, 0);
|
||||
furi_thread_flags_set(furi_thread_get_id(app->m_worker_thread), WorkerEventRx);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t uart_worker(void* context) {
|
||||
furi_assert(context);
|
||||
DEAUTH_APP_LOG_I("[UART] Worker thread init");
|
||||
|
||||
SWiFiDeauthApp* app = context;
|
||||
furi_mutex_acquire(app->mutex, FuriWaitForever);
|
||||
if(app == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
FuriStreamBuffer* rx_stream = app->m_rx_stream;
|
||||
|
||||
furi_mutex_release(app->mutex);
|
||||
|
||||
#if ENABLE_MODULE_POWER
|
||||
bool initialized = false;
|
||||
|
||||
FuriString* receivedString;
|
||||
receivedString = furi_string_alloc();
|
||||
#endif // ENABLE_MODULE_POWER
|
||||
|
||||
while(true) {
|
||||
uint32_t events = furi_thread_flags_wait(
|
||||
WorkerEventStop | WorkerEventRx, FuriFlagWaitAny, FuriWaitForever);
|
||||
furi_check((events & FuriFlagError) == 0);
|
||||
|
||||
if(events & WorkerEventStop) break;
|
||||
if(events & WorkerEventRx) {
|
||||
DEAUTH_APP_LOG_I("[UART] Received data");
|
||||
SWiFiDeauthApp* app = context;
|
||||
furi_mutex_acquire(app->mutex, FuriWaitForever);
|
||||
if(app == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t dataReceivedLength = 0;
|
||||
int index = 0;
|
||||
do {
|
||||
const uint8_t dataBufferSize = 64;
|
||||
uint8_t dataBuffer[dataBufferSize];
|
||||
dataReceivedLength =
|
||||
furi_stream_buffer_receive(rx_stream, dataBuffer, dataBufferSize, 25);
|
||||
if(dataReceivedLength > 0) {
|
||||
#if ENABLE_MODULE_POWER
|
||||
if(!initialized) {
|
||||
if(!(dataReceivedLength > strlen(MODULE_CONTEXT_INITIALIZATION))) {
|
||||
DEAUTH_APP_LOG_I("[UART] Found possible init candidate");
|
||||
for(uint16_t i = 0; i < dataReceivedLength; i++) {
|
||||
furi_string_push_back(receivedString, dataBuffer[i]);
|
||||
}
|
||||
}
|
||||
} else
|
||||
#endif // ENABLE_MODULE_POWER
|
||||
{
|
||||
DEAUTH_APP_LOG_I("[UART] Data copied to backbuffer");
|
||||
memcpy(app->m_backBuffer + index, dataBuffer, dataReceivedLength);
|
||||
index += dataReceivedLength;
|
||||
app->m_needUpdateGUI = true;
|
||||
}
|
||||
}
|
||||
|
||||
} while(dataReceivedLength > 0);
|
||||
|
||||
#if ENABLE_MODULE_POWER
|
||||
if(!app->m_wifiDeauthModuleInitialized) {
|
||||
if(furi_string_cmp_str(receivedString, MODULE_CONTEXT_INITIALIZATION) == 0) {
|
||||
DEAUTH_APP_LOG_I("[UART] Initialized");
|
||||
initialized = true;
|
||||
app->m_wifiDeauthModuleInitialized = true;
|
||||
app->m_context = ModuleActive;
|
||||
furi_string_free(receivedString);
|
||||
} else {
|
||||
DEAUTH_APP_LOG_I("[UART] Not an initialization command");
|
||||
furi_string_reset(receivedString);
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_MODULE_POWER
|
||||
|
||||
furi_mutex_release(app->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t esp8266_deauth_app(void* p) {
|
||||
UNUSED(p);
|
||||
|
||||
DEAUTH_APP_LOG_I("Init");
|
||||
|
||||
// FuriTimer* timer = furi_timer_alloc(blink_test_update, FuriTimerTypePeriodic, event_queue);
|
||||
// furi_timer_start(timer, furi_kernel_get_tick_frequency());
|
||||
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SPluginEvent));
|
||||
|
||||
SWiFiDeauthApp* app = malloc(sizeof(SWiFiDeauthApp));
|
||||
|
||||
esp8266_deauth_app_init(app);
|
||||
|
||||
furi_hal_gpio_init_simple(app->m_GpioButtons.pinButtonUp, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(app->m_GpioButtons.pinButtonDown, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(app->m_GpioButtons.pinButtonOK, GpioModeOutputPushPull);
|
||||
furi_hal_gpio_init_simple(app->m_GpioButtons.pinButtonBack, GpioModeOutputPushPull);
|
||||
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonUp, true);
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonDown, true);
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonOK, true);
|
||||
furi_hal_gpio_write(
|
||||
app->m_GpioButtons.pinButtonBack, false); // GPIO15 - Boot fails if pulled HIGH
|
||||
|
||||
#if ENABLE_MODULE_DETECTION
|
||||
furi_hal_gpio_init(
|
||||
&gpio_ext_pc0,
|
||||
GpioModeInput,
|
||||
GpioPullUp,
|
||||
GpioSpeedLow); // Connect to the Flipper's ground just to be sure
|
||||
//furi_hal_gpio_add_int_callback(pinD0, input_isr_d0, this);
|
||||
app->m_context = WaitingForModule;
|
||||
#else
|
||||
#if ENABLE_MODULE_POWER
|
||||
app->m_context = Initializing;
|
||||
furi_hal_power_enable_otg();
|
||||
#else
|
||||
app->m_context = ModuleActive;
|
||||
#endif
|
||||
#endif // ENABLE_MODULE_DETECTION
|
||||
|
||||
app->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(!app->mutex) {
|
||||
DEAUTH_APP_LOG_E("cannot create mutex\r\n");
|
||||
free(app);
|
||||
return 255;
|
||||
}
|
||||
|
||||
DEAUTH_APP_LOG_I("Mutex created");
|
||||
|
||||
//app->m_notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, esp8266_deauth_module_render_callback, app);
|
||||
view_port_input_callback_set(view_port, esp8266_deauth_module_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);
|
||||
|
||||
//notification_message(app->notification, &sequence_set_only_blue_255);
|
||||
|
||||
app->m_rx_stream = furi_stream_buffer_alloc(1 * 1024, 1);
|
||||
|
||||
app->m_worker_thread = furi_thread_alloc();
|
||||
furi_thread_set_name(app->m_worker_thread, "WiFiDeauthModuleUARTWorker");
|
||||
furi_thread_set_stack_size(app->m_worker_thread, 1 * 1024);
|
||||
furi_thread_set_context(app->m_worker_thread, app);
|
||||
furi_thread_set_callback(app->m_worker_thread, uart_worker);
|
||||
furi_thread_start(app->m_worker_thread);
|
||||
DEAUTH_APP_LOG_I("UART thread allocated");
|
||||
|
||||
// Enable uart listener
|
||||
#if DISABLE_CONSOLE
|
||||
furi_hal_console_disable();
|
||||
#endif
|
||||
furi_hal_uart_set_br(FuriHalUartIdUSART1, FLIPPERZERO_SERIAL_BAUD);
|
||||
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_on_irq_cb, app);
|
||||
DEAUTH_APP_LOG_I("UART Listener created");
|
||||
|
||||
SPluginEvent event;
|
||||
for(bool processing = true; processing;) {
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
||||
furi_mutex_acquire(app->mutex, FuriWaitForever);
|
||||
|
||||
#if ENABLE_MODULE_DETECTION
|
||||
if(!app->m_wifiDeauthModuleAttached) {
|
||||
if(furi_hal_gpio_read(&gpio_ext_pc0) == false) {
|
||||
DEAUTH_APP_LOG_I("Module Attached");
|
||||
app->m_wifiDeauthModuleAttached = true;
|
||||
#if ENABLE_MODULE_POWER
|
||||
app->m_context = Initializing;
|
||||
furi_hal_power_enable_otg();
|
||||
#else
|
||||
app->m_context = ModuleActive;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif // ENABLE_MODULE_DETECTION
|
||||
|
||||
if(event_status == FuriStatusOk) {
|
||||
if(event.m_type == EventTypeKey) {
|
||||
if(app->m_wifiDeauthModuleInitialized) {
|
||||
if(app->m_context == ModuleActive) {
|
||||
switch(event.m_input.key) {
|
||||
case InputKeyUp:
|
||||
if(event.m_input.type == InputTypePress) {
|
||||
DEAUTH_APP_LOG_I("Up Press");
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonUp, false);
|
||||
} else if(event.m_input.type == InputTypeRelease) {
|
||||
DEAUTH_APP_LOG_I("Up Release");
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonUp, true);
|
||||
}
|
||||
break;
|
||||
case InputKeyDown:
|
||||
if(event.m_input.type == InputTypePress) {
|
||||
DEAUTH_APP_LOG_I("Down Press");
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonDown, false);
|
||||
} else if(event.m_input.type == InputTypeRelease) {
|
||||
DEAUTH_APP_LOG_I("Down Release");
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonDown, true);
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
if(event.m_input.type == InputTypePress) {
|
||||
DEAUTH_APP_LOG_I("OK Press");
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonOK, false);
|
||||
} else if(event.m_input.type == InputTypeRelease) {
|
||||
DEAUTH_APP_LOG_I("OK Release");
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonOK, true);
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
if(event.m_input.type == InputTypePress) {
|
||||
DEAUTH_APP_LOG_I("Back Press");
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonBack, false);
|
||||
} else if(event.m_input.type == InputTypeRelease) {
|
||||
DEAUTH_APP_LOG_I("Back Release");
|
||||
furi_hal_gpio_write(app->m_GpioButtons.pinButtonBack, true);
|
||||
} else if(event.m_input.type == InputTypeLong) {
|
||||
DEAUTH_APP_LOG_I("Back Long");
|
||||
processing = false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(event.m_input.key == InputKeyBack) {
|
||||
if(event.m_input.type == InputTypeShort ||
|
||||
event.m_input.type == InputTypeLong) {
|
||||
processing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if ENABLE_MODULE_DETECTION
|
||||
if(app->m_wifiDeauthModuleAttached && furi_hal_gpio_read(&gpio_ext_pc0) == true) {
|
||||
DEAUTH_APP_LOG_D("Module Disconnected - Exit");
|
||||
processing = false;
|
||||
app->m_wifiDeauthModuleAttached = false;
|
||||
app->m_wifiDeauthModuleInitialized = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
view_port_update(view_port);
|
||||
furi_mutex_release(app->mutex);
|
||||
}
|
||||
|
||||
DEAUTH_APP_LOG_I("Start exit app");
|
||||
|
||||
furi_thread_flags_set(furi_thread_get_id(app->m_worker_thread), WorkerEventStop);
|
||||
furi_thread_join(app->m_worker_thread);
|
||||
furi_thread_free(app->m_worker_thread);
|
||||
|
||||
DEAUTH_APP_LOG_I("Thread Deleted");
|
||||
|
||||
// Reset GPIO pins to default state
|
||||
furi_hal_gpio_init(&gpio_ext_pc0, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pc3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pb2, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pb3, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(&gpio_ext_pa4, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
|
||||
#if DISABLE_CONSOLE
|
||||
furi_hal_console_enable();
|
||||
#endif
|
||||
|
||||
//*app->m_originalBufferLocation = app->m_originalBuffer;
|
||||
|
||||
view_port_enabled_set(view_port, false);
|
||||
|
||||
gui_remove_view_port(gui, view_port);
|
||||
|
||||
// Close gui record
|
||||
furi_record_close(RECORD_GUI);
|
||||
//furi_record_close(RECORD_NOTIFICATION);
|
||||
app->m_gui = NULL;
|
||||
|
||||
view_port_free(view_port);
|
||||
|
||||
furi_message_queue_free(event_queue);
|
||||
|
||||
furi_stream_buffer_free(app->m_rx_stream);
|
||||
|
||||
furi_mutex_free(app->mutex);
|
||||
|
||||
// Free rest
|
||||
free(app);
|
||||
|
||||
DEAUTH_APP_LOG_I("App freed");
|
||||
|
||||
#if ENABLE_MODULE_POWER
|
||||
furi_hal_power_disable_otg();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,13 +0,0 @@
|
||||
App(
|
||||
appid="FlappyBird",
|
||||
name="Flappy Bird",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="flappy_game_app",
|
||||
cdefines=["APP_FLAPPY_GAME"],
|
||||
requires=["gui"],
|
||||
stack_size=4 * 1024,
|
||||
order=100,
|
||||
fap_icon="flappy_10px.png",
|
||||
fap_category="Games",
|
||||
fap_icon_assets="assets",
|
||||
)
|
||||
|
Before Width: | Height: | Size: 113 B |
|
Before Width: | Height: | Size: 116 B |
|
Before Width: | Height: | Size: 116 B |
@@ -1 +0,0 @@
|
||||
3
|
||||
|
Before Width: | Height: | Size: 1.7 KiB |
@@ -1,374 +0,0 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <FlappyBird_icons.h>
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/icon_animation_i.h>
|
||||
#include <input/input.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#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 struct {
|
||||
int x;
|
||||
int y;
|
||||
} POINT;
|
||||
|
||||
typedef struct {
|
||||
float gravity;
|
||||
POINT point;
|
||||
IconAnimation* sprite;
|
||||
} 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;
|
||||
bird.sprite = icon_animation_alloc(&A_bird);
|
||||
|
||||
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) {
|
||||
icon_animation_free(game_state->bird.sprite);
|
||||
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
|
||||
game_state->bird.sprite->frame = 1;
|
||||
if(game_state->bird.gravity < -0.5)
|
||||
game_state->bird.sprite->frame = 0;
|
||||
else if(game_state->bird.gravity > 0.5)
|
||||
game_state->bird.sprite->frame = 2;
|
||||
|
||||
canvas_draw_icon_animation(
|
||||
canvas, game_state->bird.point.x, game_state->bird.point.y, game_state->bird.sprite);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* @G4N4P4T1 wrote this file. As long as you retain this notice you
|
||||
* can do whatever you want with this stuff. If we meet some day, and you think
|
||||
* this stuff is worth it, you can buy me a beer in return.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1,35 +0,0 @@
|
||||
# Flipfrid
|
||||
|
||||
Basic EM4100 and HIDProx Fuzzer.
|
||||
|
||||
## Why
|
||||
|
||||
Flipfrid is a simple Rfid fuzzer using EM4100 protocol (125khz).
|
||||
Objective is to provide a simple to use fuzzer to test readers by emulating various cards.
|
||||
|
||||
- EM4100 cards use a 1 byte customer id and 4 bytes card id.
|
||||
- HIDProx cards use a 2 byte customer id and 3 byte card id.
|
||||
|
||||
## How
|
||||
|
||||
1) Select the Protocol with the left and right arrows
|
||||
2) Select the Mode with the up and down arrows
|
||||
|
||||
### Info
|
||||
|
||||
There are 2 Protocols:
|
||||
- EM4100
|
||||
- HIDProx
|
||||
|
||||
There are 4 modes:
|
||||
- Default Values: Try factory/default keys and emulate one after the other.
|
||||
- BF customer id: An iteration from 0X00 to 0XFF on the first byte.
|
||||
- Load Dump file: Load an existing dump (.rfid) generated by Flipperzero, select an index and bruteforce from 0X00 to 0XFF;
|
||||
- Uids list: Iterate over an input text file (one uid per line) and emulate one after the other.
|
||||
|
||||
|
||||
|
||||
|
||||
TODO :
|
||||
- blank screen on back press
|
||||
- Add second byte test to `BF customer id`
|
||||
@@ -1,13 +0,0 @@
|
||||
App(
|
||||
appid="RFID_Fuzzer",
|
||||
name="RFID Fuzzer",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="flipfrid_start",
|
||||
cdefines=["APP_FLIP_FRID"],
|
||||
requires=["gui", "storage", "dialogs", "input", "notification"],
|
||||
stack_size=1 * 1024,
|
||||
order=15,
|
||||
fap_icon="rfid_10px.png",
|
||||
fap_category="Tools",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
@@ -1,261 +0,0 @@
|
||||
#include "flipfrid.h"
|
||||
|
||||
#include "scene/flipfrid_scene_entrypoint.h"
|
||||
#include "scene/flipfrid_scene_load_file.h"
|
||||
#include "scene/flipfrid_scene_select_field.h"
|
||||
#include "scene/flipfrid_scene_run_attack.h"
|
||||
#include "scene/flipfrid_scene_load_custom_uids.h"
|
||||
|
||||
#define RFIDFUZZER_APP_FOLDER "/ext/rfidfuzzer"
|
||||
|
||||
static void flipfrid_draw_callback(Canvas* const canvas, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
FlipFridState* flipfrid_state = ctx;
|
||||
furi_mutex_acquire(flipfrid_state->mutex, FuriWaitForever);
|
||||
|
||||
// Draw correct Canvas
|
||||
switch(flipfrid_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_draw(canvas, flipfrid_state);
|
||||
break;
|
||||
}
|
||||
|
||||
furi_mutex_release(flipfrid_state->mutex);
|
||||
}
|
||||
|
||||
void flipfrid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
|
||||
FlipFridEvent event = {
|
||||
.evt_type = EventTypeKey, .key = input_event->key, .input_type = input_event->type};
|
||||
furi_message_queue_put(event_queue, &event, 25);
|
||||
}
|
||||
|
||||
static void flipfrid_timer_callback(FuriMessageQueue* event_queue) {
|
||||
furi_assert(event_queue);
|
||||
FlipFridEvent event = {
|
||||
.evt_type = EventTypeTick, .key = InputKeyUp, .input_type = InputTypeRelease};
|
||||
furi_message_queue_put(event_queue, &event, 25);
|
||||
}
|
||||
|
||||
FlipFridState* flipfrid_alloc() {
|
||||
FlipFridState* flipfrid = malloc(sizeof(FlipFridState));
|
||||
flipfrid->notification_msg = furi_string_alloc();
|
||||
flipfrid->attack_name = furi_string_alloc();
|
||||
flipfrid->proto_name = furi_string_alloc();
|
||||
flipfrid->data_str = furi_string_alloc();
|
||||
|
||||
flipfrid->previous_scene = NoneScene;
|
||||
flipfrid->current_scene = SceneEntryPoint;
|
||||
flipfrid->is_running = true;
|
||||
flipfrid->is_attacking = false;
|
||||
flipfrid->key_index = 0;
|
||||
flipfrid->menu_index = 0;
|
||||
flipfrid->menu_proto_index = 0;
|
||||
|
||||
flipfrid->attack = FlipFridAttackDefaultValues;
|
||||
flipfrid->notify = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
flipfrid->data[0] = 0x00;
|
||||
flipfrid->data[1] = 0x00;
|
||||
flipfrid->data[2] = 0x00;
|
||||
flipfrid->data[3] = 0x00;
|
||||
flipfrid->data[4] = 0x00;
|
||||
flipfrid->data[5] = 0x00;
|
||||
|
||||
flipfrid->payload[0] = 0x00;
|
||||
flipfrid->payload[1] = 0x00;
|
||||
flipfrid->payload[2] = 0x00;
|
||||
flipfrid->payload[3] = 0x00;
|
||||
flipfrid->payload[4] = 0x00;
|
||||
flipfrid->payload[5] = 0x00;
|
||||
|
||||
//Dialog
|
||||
flipfrid->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
|
||||
return flipfrid;
|
||||
}
|
||||
|
||||
void flipfrid_free(FlipFridState* flipfrid) {
|
||||
//Dialog
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
notification_message(flipfrid->notify, &sequence_blink_stop);
|
||||
|
||||
// Strings
|
||||
furi_string_free(flipfrid->notification_msg);
|
||||
furi_string_free(flipfrid->attack_name);
|
||||
furi_string_free(flipfrid->proto_name);
|
||||
furi_string_free(flipfrid->data_str);
|
||||
|
||||
free(flipfrid->data);
|
||||
free(flipfrid->payload);
|
||||
|
||||
// The rest
|
||||
free(flipfrid);
|
||||
}
|
||||
|
||||
// ENTRYPOINT
|
||||
int32_t flipfrid_start(void* p) {
|
||||
UNUSED(p);
|
||||
// Input
|
||||
FURI_LOG_I(TAG, "Initializing input");
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(FlipFridEvent));
|
||||
FlipFridState* flipfrid_state = flipfrid_alloc();
|
||||
|
||||
flipfrid_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(!flipfrid_state->mutex) {
|
||||
FURI_LOG_E(TAG, "cannot create mutex\r\n");
|
||||
furi_message_queue_free(event_queue);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
flipfrid_free(flipfrid_state);
|
||||
return 255;
|
||||
}
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
if(!storage_simply_mkdir(storage, RFIDFUZZER_APP_FOLDER)) {
|
||||
FURI_LOG_E(TAG, "Could not create folder %s", RFIDFUZZER_APP_FOLDER);
|
||||
}
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
// Configure view port
|
||||
FURI_LOG_I(TAG, "Initializing viewport");
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(view_port, flipfrid_draw_callback, flipfrid_state);
|
||||
view_port_input_callback_set(view_port, flipfrid_input_callback, event_queue);
|
||||
|
||||
// Configure timer
|
||||
FURI_LOG_I(TAG, "Initializing timer");
|
||||
FuriTimer* timer =
|
||||
furi_timer_alloc(flipfrid_timer_callback, FuriTimerTypePeriodic, event_queue);
|
||||
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 10); // 10 times per second
|
||||
|
||||
// Register view port in GUI
|
||||
FURI_LOG_I(TAG, "Initializing gui");
|
||||
Gui* gui = (Gui*)furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
|
||||
// Init values
|
||||
FlipFridEvent event;
|
||||
while(flipfrid_state->is_running) {
|
||||
// Get next event
|
||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 25);
|
||||
if(event_status == FuriStatusOk) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
//Handle event key
|
||||
switch(flipfrid_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_event(event, flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_event(event, flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_event(event, flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_event(event, flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_event(event, flipfrid_state);
|
||||
break;
|
||||
}
|
||||
|
||||
} else if(event.evt_type == EventTypeTick) {
|
||||
//Handle event tick
|
||||
if(flipfrid_state->current_scene != flipfrid_state->previous_scene) {
|
||||
// Trigger Exit Scene
|
||||
switch(flipfrid_state->previous_scene) {
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_exit(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_exit(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_exit(flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_exit(flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_exit(flipfrid_state);
|
||||
break;
|
||||
case NoneScene:
|
||||
break;
|
||||
}
|
||||
|
||||
// Trigger Entry Scene
|
||||
switch(flipfrid_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_enter(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_enter(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_enter(flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_enter(flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_enter(flipfrid_state);
|
||||
break;
|
||||
}
|
||||
flipfrid_state->previous_scene = flipfrid_state->current_scene;
|
||||
}
|
||||
|
||||
// Trigger Tick Scene
|
||||
switch(flipfrid_state->current_scene) {
|
||||
case NoneScene:
|
||||
case SceneEntryPoint:
|
||||
flipfrid_scene_entrypoint_on_tick(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectFile:
|
||||
flipfrid_scene_load_file_on_tick(flipfrid_state);
|
||||
break;
|
||||
case SceneSelectField:
|
||||
flipfrid_scene_select_field_on_tick(flipfrid_state);
|
||||
break;
|
||||
case SceneAttack:
|
||||
flipfrid_scene_run_attack_on_tick(flipfrid_state);
|
||||
break;
|
||||
case SceneLoadCustomUids:
|
||||
flipfrid_scene_load_custom_uids_on_tick(flipfrid_state);
|
||||
break;
|
||||
}
|
||||
view_port_update(view_port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
furi_timer_stop(timer);
|
||||
furi_timer_free(timer);
|
||||
|
||||
FURI_LOG_I(TAG, "Cleaning up");
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_mutex_free(flipfrid_state->mutex);
|
||||
flipfrid_free(flipfrid_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <input/input.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <toolbox/stream/stream.h>
|
||||
#include <flipper_format/flipper_format_i.h>
|
||||
|
||||
#include <toolbox/stream/stream.h>
|
||||
#include <toolbox/stream/string_stream.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include <toolbox/stream/buffered_file_stream.h>
|
||||
|
||||
#include <RFID_Fuzzer_icons.h>
|
||||
|
||||
#include <lib/lfrfid/lfrfid_worker.h>
|
||||
#include <lfrfid/protocols/lfrfid_protocols.h>
|
||||
|
||||
#define TAG "FlipFrid"
|
||||
|
||||
typedef enum {
|
||||
FlipFridAttackDefaultValues,
|
||||
FlipFridAttackBfCustomerId,
|
||||
FlipFridAttackLoadFile,
|
||||
FlipFridAttackLoadFileCustomUids,
|
||||
} FlipFridAttacks;
|
||||
|
||||
typedef enum {
|
||||
EM4100,
|
||||
HIDProx,
|
||||
PAC,
|
||||
H10301,
|
||||
} FlipFridProtos;
|
||||
|
||||
typedef enum {
|
||||
NoneScene,
|
||||
SceneEntryPoint,
|
||||
SceneSelectFile,
|
||||
SceneSelectField,
|
||||
SceneAttack,
|
||||
SceneLoadCustomUids,
|
||||
} FlipFridScene;
|
||||
|
||||
typedef enum {
|
||||
EventTypeTick,
|
||||
EventTypeKey,
|
||||
} EventType;
|
||||
|
||||
typedef struct {
|
||||
EventType evt_type;
|
||||
InputKey key;
|
||||
InputType input_type;
|
||||
} FlipFridEvent;
|
||||
|
||||
// STRUCTS
|
||||
typedef struct {
|
||||
FuriMutex* mutex;
|
||||
bool is_running;
|
||||
bool is_attacking;
|
||||
FlipFridScene current_scene;
|
||||
FlipFridScene previous_scene;
|
||||
NotificationApp* notify;
|
||||
u_int8_t menu_index;
|
||||
u_int8_t menu_proto_index;
|
||||
|
||||
FuriString* data_str;
|
||||
uint8_t data[6];
|
||||
uint8_t payload[6];
|
||||
uint8_t attack_step;
|
||||
FlipFridAttacks attack;
|
||||
FlipFridProtos proto;
|
||||
FuriString* attack_name;
|
||||
FuriString* proto_name;
|
||||
|
||||
DialogsApp* dialogs;
|
||||
FuriString* notification_msg;
|
||||
uint8_t key_index;
|
||||
LFRFIDWorker* worker;
|
||||
ProtocolDict* dict;
|
||||
ProtocolId protocol;
|
||||
bool workr_rund;
|
||||
bool attack_stop_called;
|
||||
|
||||
uint8_t time_between_cards;
|
||||
|
||||
// Used for custom dictionnary
|
||||
Stream* uids_stream;
|
||||
} FlipFridState;
|
||||
|
Before Width: | Height: | Size: 308 B |
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,217 +0,0 @@
|
||||
#include "flipfrid_scene_entrypoint.h"
|
||||
|
||||
FuriString* main_menu_items[4];
|
||||
FuriString* main_menu_proto_items[4];
|
||||
|
||||
void flipfrid_scene_entrypoint_menu_callback(
|
||||
FlipFridState* context,
|
||||
uint32_t index,
|
||||
uint32_t proto_index) {
|
||||
switch(index) {
|
||||
case FlipFridAttackDefaultValues:
|
||||
context->attack = FlipFridAttackDefaultValues;
|
||||
context->current_scene = SceneAttack;
|
||||
furi_string_set(context->attack_name, "Default Values");
|
||||
break;
|
||||
case FlipFridAttackBfCustomerId:
|
||||
context->attack = FlipFridAttackBfCustomerId;
|
||||
context->current_scene = SceneAttack;
|
||||
furi_string_set(context->attack_name, "Bad Customer ID");
|
||||
break;
|
||||
case FlipFridAttackLoadFile:
|
||||
context->attack = FlipFridAttackLoadFile;
|
||||
context->current_scene = SceneSelectFile;
|
||||
furi_string_set(context->attack_name, "Load File");
|
||||
break;
|
||||
case FlipFridAttackLoadFileCustomUids:
|
||||
context->attack = FlipFridAttackLoadFileCustomUids;
|
||||
context->current_scene = SceneLoadCustomUids;
|
||||
furi_string_set(context->attack_name, "Load Custom UIDs");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch(proto_index) {
|
||||
case EM4100:
|
||||
context->proto = EM4100;
|
||||
furi_string_set(context->proto_name, "EM4100");
|
||||
break;
|
||||
case HIDProx:
|
||||
context->proto = HIDProx;
|
||||
furi_string_set(context->proto_name, "HIDProx");
|
||||
break;
|
||||
case PAC:
|
||||
context->proto = PAC;
|
||||
furi_string_set(context->proto_name, "PAC/Stanley");
|
||||
break;
|
||||
case H10301:
|
||||
context->proto = H10301;
|
||||
furi_string_set(context->proto_name, "H10301");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_enter(FlipFridState* context) {
|
||||
// Clear the previous payload
|
||||
context->payload[0] = 0x00;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
context->payload[5] = 0x00;
|
||||
|
||||
context->menu_index = 0;
|
||||
/*for(uint32_t i = 0; i < 4; i++) {
|
||||
menu_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
|
||||
main_menu_items[0] = furi_string_alloc_set("Default Values");
|
||||
main_menu_items[1] = furi_string_alloc_set("BF Customer ID");
|
||||
main_menu_items[2] = furi_string_alloc_set("Load File");
|
||||
main_menu_items[3] = furi_string_alloc_set("Load UIDs from file");
|
||||
|
||||
context->menu_proto_index = 0;
|
||||
/*for(uint32_t i = 0; i < 4; i++) {
|
||||
menu_proto_items[i] = furi_string_alloc();
|
||||
}*/
|
||||
|
||||
main_menu_proto_items[0] = furi_string_alloc_set("EM4100");
|
||||
main_menu_proto_items[1] = furi_string_alloc_set("HIDProx");
|
||||
main_menu_proto_items[2] = furi_string_alloc_set("PAC/Stanley");
|
||||
main_menu_proto_items[3] = furi_string_alloc_set("H10301");
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
furi_string_free(main_menu_items[i]);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < 4; i++) {
|
||||
furi_string_free(main_menu_proto_items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
|
||||
context->menu_index++;
|
||||
}
|
||||
break;
|
||||
case InputKeyUp:
|
||||
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||
context->menu_index--;
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(context->menu_proto_index > EM4100) {
|
||||
context->menu_proto_index--;
|
||||
} else if(context->menu_proto_index == EM4100) {
|
||||
context->menu_proto_index = H10301;
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(context->menu_proto_index < H10301) {
|
||||
context->menu_proto_index++;
|
||||
} else if(context->menu_proto_index == H10301) {
|
||||
context->menu_proto_index = EM4100;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
flipfrid_scene_entrypoint_menu_callback(
|
||||
context, context->menu_index, context->menu_proto_index);
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->is_running = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(main_menu_items[context->menu_index] != NULL) {
|
||||
if(context->menu_index > FlipFridAttackDefaultValues) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_items[context->menu_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
36,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_items[context->menu_index]));
|
||||
|
||||
if(context->menu_index < FlipFridAttackLoadFileCustomUids) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
48,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_items[context->menu_index + 1]));
|
||||
}
|
||||
|
||||
if(context->menu_proto_index > EM4100) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index - 1]));
|
||||
}
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 27, 4, AlignCenter, AlignTop, "<");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
4,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index]));
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(canvas, 101, 4, AlignCenter, AlignTop, ">");
|
||||
|
||||
if(context->menu_proto_index < H10301) {
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas,
|
||||
64,
|
||||
-12,
|
||||
AlignCenter,
|
||||
AlignTop,
|
||||
furi_string_get_cstr(main_menu_proto_items[context->menu_proto_index + 1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_entrypoint_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_entrypoint_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_entrypoint_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_entrypoint_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_entrypoint_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
@@ -1,85 +0,0 @@
|
||||
#include "flipfrid_scene_load_custom_uids.h"
|
||||
#include "flipfrid_scene_run_attack.h"
|
||||
#include "flipfrid_scene_entrypoint.h"
|
||||
|
||||
#define LFRFID_UIDS_EXTENSION ".txt"
|
||||
#define RFIDFUZZER_APP_PATH_FOLDER "/ext/rfidfuzzer"
|
||||
|
||||
bool flipfrid_load_uids(FlipFridState* context, const char* file_path) {
|
||||
bool result = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
context->uids_stream = buffered_file_stream_alloc(storage);
|
||||
result =
|
||||
buffered_file_stream_open(context->uids_stream, file_path, FSAM_READ, FSOM_OPEN_EXISTING);
|
||||
// Close if loading fails
|
||||
if(!result) {
|
||||
buffered_file_stream_close(context->uids_stream);
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool flipfrid_load_custom_uids_from_file(FlipFridState* context) {
|
||||
// Input events and views are managed by file_select
|
||||
FuriString* uid_path;
|
||||
uid_path = furi_string_alloc();
|
||||
furi_string_set(uid_path, RFIDFUZZER_APP_PATH_FOLDER);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, LFRFID_UIDS_EXTENSION, &I_125_10px);
|
||||
browser_options.base_path = RFIDFUZZER_APP_PATH_FOLDER;
|
||||
browser_options.hide_ext = false;
|
||||
|
||||
bool res = dialog_file_browser_show(context->dialogs, uid_path, uid_path, &browser_options);
|
||||
|
||||
if(res) {
|
||||
res = flipfrid_load_uids(context, furi_string_get_cstr(uid_path));
|
||||
}
|
||||
|
||||
furi_string_free(uid_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context) {
|
||||
if(flipfrid_load_custom_uids_from_file(context)) {
|
||||
// Force context loading
|
||||
flipfrid_scene_run_attack_on_enter(context);
|
||||
context->current_scene = SceneAttack;
|
||||
} else {
|
||||
flipfrid_scene_entrypoint_on_enter(context);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
case InputKeyUp:
|
||||
case InputKeyLeft:
|
||||
case InputKeyRight:
|
||||
case InputKeyOk:
|
||||
case InputKeyBack:
|
||||
context->current_scene = SceneEntryPoint;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
UNUSED(canvas);
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_load_custom_uids_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_load_custom_uids_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_load_custom_uids_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_load_custom_uids_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_load_custom_uids_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
bool flipfrid_load_custom_uids_from_file(FlipFridState* context);
|
||||
@@ -1,193 +0,0 @@
|
||||
#include "flipfrid_scene_load_file.h"
|
||||
#include "flipfrid_scene_entrypoint.h"
|
||||
|
||||
#define LFRFID_APP_EXTENSION ".rfid"
|
||||
#define LFRFID_APP_PATH_FOLDER "/ext/lfrfid"
|
||||
|
||||
bool flipfrid_load(FlipFridState* context, const char* file_path) {
|
||||
bool result = false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FlipperFormat* fff_data_file = flipper_format_file_alloc(storage);
|
||||
FuriString* temp_str;
|
||||
temp_str = furi_string_alloc();
|
||||
do {
|
||||
if(!flipper_format_file_open_existing(fff_data_file, file_path)) {
|
||||
FURI_LOG_E(TAG, "Error open file %s", file_path);
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Error open file");
|
||||
break;
|
||||
}
|
||||
|
||||
// FileType
|
||||
if(!flipper_format_read_string(fff_data_file, "Filetype", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Filetype");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Filetypes");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Filetype: %s", furi_string_get_cstr(temp_str));
|
||||
}
|
||||
|
||||
// Key type
|
||||
if(!flipper_format_read_string(fff_data_file, "Key type", temp_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Key type");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key type: %s", furi_string_get_cstr(temp_str));
|
||||
|
||||
if(context->proto == EM4100) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "EM4100") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == PAC) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "PAC/Stanley") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == H10301) {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "H10301") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(strcmp(furi_string_get_cstr(temp_str), "HIDProx") != 0) {
|
||||
FURI_LOG_E(TAG, "Unsupported Key type");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Unsupported Key type");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Data
|
||||
if(!flipper_format_read_string(fff_data_file, "Data", context->data_str)) {
|
||||
FURI_LOG_E(TAG, "Missing or incorrect Data");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Missing or incorrect Key");
|
||||
break;
|
||||
} else {
|
||||
FURI_LOG_I(TAG, "Key: %s", furi_string_get_cstr(context->data_str));
|
||||
|
||||
if(context->proto == EM4100) {
|
||||
if(furi_string_size(context->data_str) != 14) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == PAC) {
|
||||
if(furi_string_size(context->data_str) != 11) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
} else if(context->proto == H10301) {
|
||||
if(furi_string_size(context->data_str) != 8) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if(furi_string_size(context->data_str) != 17) {
|
||||
FURI_LOG_E(TAG, "Incorrect Key length");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Incorrect Key length");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// String to uint8_t
|
||||
for(uint8_t i = 0; i < 6; i++) {
|
||||
char temp_str2[3];
|
||||
temp_str2[0] = furi_string_get_cstr(context->data_str)[i * 3];
|
||||
temp_str2[1] = furi_string_get_cstr(context->data_str)[i * 3 + 1];
|
||||
temp_str2[2] = '\0';
|
||||
context->data[i] = (uint8_t)strtol(temp_str2, NULL, 16);
|
||||
}
|
||||
}
|
||||
|
||||
result = true;
|
||||
} while(0);
|
||||
furi_string_free(temp_str);
|
||||
flipper_format_free(fff_data_file);
|
||||
if(result) {
|
||||
FURI_LOG_I(TAG, "Loaded successfully");
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, "Source loaded.");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_enter(FlipFridState* context) {
|
||||
if(flipfrid_load_protocol_from_file(context)) {
|
||||
context->current_scene = SceneSelectField;
|
||||
} else {
|
||||
flipfrid_scene_entrypoint_on_enter(context);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_tick(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
case InputKeyUp:
|
||||
case InputKeyLeft:
|
||||
case InputKeyRight:
|
||||
case InputKeyOk:
|
||||
case InputKeyBack:
|
||||
context->current_scene = SceneEntryPoint;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
UNUSED(canvas);
|
||||
}
|
||||
|
||||
bool flipfrid_load_protocol_from_file(FlipFridState* context) {
|
||||
FuriString* user_file_path;
|
||||
user_file_path = furi_string_alloc();
|
||||
furi_string_set(user_file_path, LFRFID_APP_PATH_FOLDER);
|
||||
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, LFRFID_APP_EXTENSION, &I_125_10px);
|
||||
browser_options.base_path = LFRFID_APP_PATH_FOLDER;
|
||||
|
||||
// Input events and views are managed by file_select
|
||||
bool res = dialog_file_browser_show(
|
||||
context->dialogs, user_file_path, user_file_path, &browser_options);
|
||||
|
||||
if(res) {
|
||||
res = flipfrid_load(context, furi_string_get_cstr(user_file_path));
|
||||
}
|
||||
|
||||
furi_string_free(user_file_path);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_load_file_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_load_file_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_load_file_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_load_file_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_load_file_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
bool flipfrid_load_protocol_from_file(FlipFridState* context);
|
||||
@@ -1,666 +0,0 @@
|
||||
#include "flipfrid_scene_run_attack.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
uint8_t counter = 0;
|
||||
|
||||
uint8_t id_list[17][5] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78, 0x9A}, // Incremental UID
|
||||
{0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0x04, 0xd0, 0x9b, 0x0d, 0x6a}, // From arha
|
||||
{0x34, 0x00, 0x29, 0x3d, 0x9e}, // From arha
|
||||
{0x04, 0xdf, 0x00, 0x00, 0x01}, // From arha
|
||||
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
uint8_t id_list_hid[14][6] = {
|
||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC}, // Incremental UID
|
||||
{0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0xCA, 0xCA, 0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
uint8_t id_list_pac[17][4] = {
|
||||
{0x00, 0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56, 0x78}, // Incremental UID
|
||||
{0x9A, 0x78, 0x56, 0x34}, // Decremental UID
|
||||
{0x04, 0xd0, 0x9b, 0x0d}, // From arha
|
||||
{0x34, 0x00, 0x29, 0x3d}, // From arha
|
||||
{0x04, 0xdf, 0x00, 0x00}, // From arha
|
||||
{0xCA, 0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
uint8_t id_list_h[14][3] = {
|
||||
{0x00, 0x00, 0x00}, // Null bytes
|
||||
{0xFF, 0xFF, 0xFF}, // Only FF
|
||||
{0x11, 0x11, 0x11}, // Only 11
|
||||
{0x22, 0x22, 0x22}, // Only 22
|
||||
{0x33, 0x33, 0x33}, // Only 33
|
||||
{0x44, 0x44, 0x44}, // Only 44
|
||||
{0x55, 0x55, 0x55}, // Only 55
|
||||
{0x66, 0x66, 0x66}, // Only 66
|
||||
{0x77, 0x77, 0x77}, // Only 77
|
||||
{0x88, 0x88, 0x88}, // Only 88
|
||||
{0x99, 0x99, 0x99}, // Only 99
|
||||
{0x12, 0x34, 0x56}, // Incremental UID
|
||||
{0x56, 0x34, 0x12}, // Decremental UID
|
||||
{0xCA, 0xCA, 0xCA}, // From arha
|
||||
};
|
||||
|
||||
void flipfrid_scene_run_attack_on_enter(FlipFridState* context) {
|
||||
context->time_between_cards = 10;
|
||||
context->attack_step = 0;
|
||||
context->attack_stop_called = false;
|
||||
context->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
|
||||
context->worker = lfrfid_worker_alloc(context->dict);
|
||||
if(context->proto == HIDProx) {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "HIDProx");
|
||||
} else if(context->proto == PAC) {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "PAC/Stanley");
|
||||
} else if(context->proto == H10301) {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "H10301");
|
||||
} else {
|
||||
context->protocol = protocol_dict_get_protocol_by_name(context->dict, "EM4100");
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_exit(FlipFridState* context) {
|
||||
if(context->workr_rund) {
|
||||
lfrfid_worker_stop(context->worker);
|
||||
lfrfid_worker_stop_thread(context->worker);
|
||||
context->workr_rund = false;
|
||||
}
|
||||
lfrfid_worker_free(context->worker);
|
||||
protocol_dict_free(context->dict);
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_tick(FlipFridState* context) {
|
||||
if(context->is_attacking) {
|
||||
if(1 == counter) {
|
||||
protocol_dict_set_data(context->dict, context->protocol, context->payload, 6);
|
||||
lfrfid_worker_free(context->worker);
|
||||
context->worker = lfrfid_worker_alloc(context->dict);
|
||||
lfrfid_worker_start_thread(context->worker);
|
||||
lfrfid_worker_emulate_start(context->worker, context->protocol);
|
||||
context->workr_rund = true;
|
||||
} else if(0 == counter) {
|
||||
if(context->workr_rund) {
|
||||
lfrfid_worker_stop(context->worker);
|
||||
lfrfid_worker_stop_thread(context->worker);
|
||||
context->workr_rund = false;
|
||||
furi_delay_ms(200);
|
||||
}
|
||||
switch(context->attack) {
|
||||
case FlipFridAttackDefaultValues:
|
||||
if(context->proto == EM4100) {
|
||||
context->payload[0] = id_list[context->attack_step][0];
|
||||
context->payload[1] = id_list[context->attack_step][1];
|
||||
context->payload[2] = id_list[context->attack_step][2];
|
||||
context->payload[3] = id_list[context->attack_step][3];
|
||||
context->payload[4] = id_list[context->attack_step][4];
|
||||
|
||||
if(context->attack_step == 16) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == PAC) {
|
||||
context->payload[0] = id_list_pac[context->attack_step][0];
|
||||
context->payload[1] = id_list_pac[context->attack_step][1];
|
||||
context->payload[2] = id_list_pac[context->attack_step][2];
|
||||
context->payload[3] = id_list_pac[context->attack_step][3];
|
||||
|
||||
if(context->attack_step == 16) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == H10301) {
|
||||
context->payload[0] = id_list_h[context->attack_step][0];
|
||||
context->payload[1] = id_list_h[context->attack_step][1];
|
||||
context->payload[2] = id_list_h[context->attack_step][2];
|
||||
|
||||
if(context->attack_step == 13) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = id_list_hid[context->attack_step][0];
|
||||
context->payload[1] = id_list_hid[context->attack_step][1];
|
||||
context->payload[2] = id_list_hid[context->attack_step][2];
|
||||
context->payload[3] = id_list_hid[context->attack_step][3];
|
||||
context->payload[4] = id_list_hid[context->attack_step][4];
|
||||
context->payload[5] = id_list_hid[context->attack_step][5];
|
||||
|
||||
if(context->attack_step == 13) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FlipFridAttackBfCustomerId:
|
||||
if(context->proto == EM4100) {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == PAC) {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == H10301) {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = context->attack_step;
|
||||
context->payload[1] = 0x00;
|
||||
context->payload[2] = 0x00;
|
||||
context->payload[3] = 0x00;
|
||||
context->payload[4] = 0x00;
|
||||
context->payload[5] = 0x00;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FlipFridAttackLoadFile:
|
||||
if(context->proto == EM4100) {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
context->payload[4] = context->data[4];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == PAC) {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == H10301) {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
context->payload[0] = context->data[0];
|
||||
context->payload[1] = context->data[1];
|
||||
context->payload[2] = context->data[2];
|
||||
context->payload[3] = context->data[3];
|
||||
context->payload[4] = context->data[4];
|
||||
context->payload[5] = context->data[5];
|
||||
|
||||
context->payload[context->key_index] = context->attack_step;
|
||||
|
||||
if(context->attack_step == 255) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
break;
|
||||
} else {
|
||||
context->attack_step++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case FlipFridAttackLoadFileCustomUids:
|
||||
if(context->proto == EM4100) {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 11) break;
|
||||
break;
|
||||
}
|
||||
if(end_of_list) break;
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(furi_string_size(context->data_str) != 11) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == PAC) {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 9) break;
|
||||
break;
|
||||
}
|
||||
if(end_of_list) break;
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(furi_string_size(context->data_str) != 9) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
} else if(context->proto == H10301) {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 7) break;
|
||||
break;
|
||||
}
|
||||
if(end_of_list) break;
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(furi_string_size(context->data_str) != 7) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 3; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
bool end_of_list = false;
|
||||
while(true) {
|
||||
furi_string_reset(context->data_str);
|
||||
if(!stream_read_line(context->uids_stream, context->data_str)) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
stream_rewind(context->uids_stream);
|
||||
end_of_list = true;
|
||||
break;
|
||||
};
|
||||
if(furi_string_get_char(context->data_str, 0) == '#') continue;
|
||||
if(furi_string_size(context->data_str) != 13) break;
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, furi_string_get_cstr(context->data_str));
|
||||
if(end_of_list) break;
|
||||
if(furi_string_size(context->data_str) != 13) {
|
||||
context->attack_step = 0;
|
||||
counter = 0;
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_error);
|
||||
break;
|
||||
};
|
||||
|
||||
// string is valid, parse it in context->payload
|
||||
for(uint8_t i = 0; i < 6; i++) {
|
||||
char temp_str[3];
|
||||
temp_str[0] = furi_string_get_cstr(context->data_str)[i * 2];
|
||||
temp_str[1] = furi_string_get_cstr(context->data_str)[i * 2 + 1];
|
||||
temp_str[2] = '\0';
|
||||
context->payload[i] = (uint8_t)strtol(temp_str, NULL, 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(counter > context->time_between_cards) {
|
||||
counter = 0;
|
||||
} else {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
break;
|
||||
case InputKeyUp:
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards > 5) {
|
||||
context->time_between_cards--;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards < 70) {
|
||||
context->time_between_cards++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
counter = 0;
|
||||
if(!context->is_attacking) {
|
||||
notification_message(context->notify, &sequence_blink_start_blue);
|
||||
context->is_attacking = true;
|
||||
} else {
|
||||
context->is_attacking = false;
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
notification_message(context->notify, &sequence_single_vibro);
|
||||
}
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->is_attacking = false;
|
||||
counter = 0;
|
||||
|
||||
notification_message(context->notify, &sequence_blink_stop);
|
||||
if(context->attack_stop_called) {
|
||||
context->attack_stop_called = false;
|
||||
context->attack_step = 0;
|
||||
if(context->attack == FlipFridAttackLoadFileCustomUids) {
|
||||
furi_string_reset(context->data_str);
|
||||
stream_rewind(context->uids_stream);
|
||||
buffered_file_stream_close(context->uids_stream);
|
||||
}
|
||||
|
||||
furi_string_reset(context->notification_msg);
|
||||
context->current_scene = SceneEntryPoint;
|
||||
}
|
||||
|
||||
context->attack_stop_called = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(event.input_type == InputTypeLong) {
|
||||
switch(event.key) {
|
||||
case InputKeyLeft:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards > 0) {
|
||||
if((context->time_between_cards - 10) > 5) {
|
||||
context->time_between_cards -= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(!context->is_attacking) {
|
||||
if(context->time_between_cards < 70) {
|
||||
context->time_between_cards += 10;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Frame
|
||||
//canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
// Title
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 2, AlignCenter, AlignTop, furi_string_get_cstr(context->attack_name));
|
||||
|
||||
char uid[18];
|
||||
char speed[16];
|
||||
if(context->proto == HIDProx) {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3],
|
||||
context->payload[4],
|
||||
context->payload[5]);
|
||||
} else if(context->proto == PAC) {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3]);
|
||||
} else if(context->proto == H10301) {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2]);
|
||||
} else {
|
||||
snprintf(
|
||||
uid,
|
||||
sizeof(uid),
|
||||
"%02X:%02X:%02X:%02X:%02X",
|
||||
context->payload[0],
|
||||
context->payload[1],
|
||||
context->payload[2],
|
||||
context->payload[3],
|
||||
context->payload[4]);
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(canvas, 64, 38, AlignCenter, AlignTop, uid);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 26, AlignCenter, AlignTop, furi_string_get_cstr(context->proto_name));
|
||||
|
||||
snprintf(speed, sizeof(speed), "Time delay: %d", context->time_between_cards);
|
||||
|
||||
//canvas_draw_str_aligned(canvas, 0, 22, AlignLeft, AlignTop, "Speed:");
|
||||
canvas_draw_str_aligned(canvas, 64, 14, AlignCenter, AlignTop, speed);
|
||||
//char start_stop_msg[20];
|
||||
if(context->is_attacking) {
|
||||
elements_button_center(canvas, "Stop");
|
||||
//snprintf(start_stop_msg, sizeof(start_stop_msg), " Press OK to stop ");
|
||||
} else {
|
||||
elements_button_center(canvas, "Start");
|
||||
elements_button_left(canvas, "TD -");
|
||||
elements_button_right(canvas, "+ TD");
|
||||
}
|
||||
//canvas_draw_str_aligned(canvas, 64, 44, AlignCenter, AlignTop, start_stop_msg);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_run_attack_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_run_attack_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_run_attack_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_run_attack_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_run_attack_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
@@ -1,160 +0,0 @@
|
||||
#include "flipfrid_scene_select_field.h"
|
||||
|
||||
void flipfrid_center_displayed_key(FlipFridState* context, uint8_t index) {
|
||||
char key_cstr[18];
|
||||
uint8_t key_len = 18;
|
||||
uint8_t str_index = (index * 3);
|
||||
int data_len = sizeof(context->data) / sizeof(context->data[0]);
|
||||
int key_index = 0;
|
||||
|
||||
if(context->proto == EM4100) {
|
||||
key_len = 16;
|
||||
}
|
||||
if(context->proto == PAC) {
|
||||
key_len = 13;
|
||||
}
|
||||
if(context->proto == H10301) {
|
||||
key_len = 10;
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < data_len; i++) {
|
||||
if(context->data[i] < 9) {
|
||||
key_index +=
|
||||
snprintf(&key_cstr[key_index], key_len - key_index, "0%X ", context->data[i]);
|
||||
} else {
|
||||
key_index +=
|
||||
snprintf(&key_cstr[key_index], key_len - key_index, "%X ", context->data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
char display_menu[17] = {
|
||||
'X', 'X', ' ', 'X', 'X', ' ', '<', 'X', 'X', '>', ' ', 'X', 'X', ' ', 'X', 'X', '\0'};
|
||||
|
||||
if(index > 1) {
|
||||
display_menu[0] = key_cstr[str_index - 6];
|
||||
display_menu[1] = key_cstr[str_index - 5];
|
||||
} else {
|
||||
display_menu[0] = ' ';
|
||||
display_menu[1] = ' ';
|
||||
}
|
||||
|
||||
if(index > 0) {
|
||||
display_menu[3] = key_cstr[str_index - 3];
|
||||
display_menu[4] = key_cstr[str_index - 2];
|
||||
} else {
|
||||
display_menu[3] = ' ';
|
||||
display_menu[4] = ' ';
|
||||
}
|
||||
|
||||
display_menu[7] = key_cstr[str_index];
|
||||
display_menu[8] = key_cstr[str_index + 1];
|
||||
|
||||
if((str_index + 4) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[11] = key_cstr[str_index + 3];
|
||||
display_menu[12] = key_cstr[str_index + 4];
|
||||
} else {
|
||||
display_menu[11] = ' ';
|
||||
display_menu[12] = ' ';
|
||||
}
|
||||
|
||||
if((str_index + 8) <= (uint8_t)strlen(key_cstr)) {
|
||||
display_menu[14] = key_cstr[str_index + 6];
|
||||
display_menu[15] = key_cstr[str_index + 7];
|
||||
} else {
|
||||
display_menu[14] = ' ';
|
||||
display_menu[15] = ' ';
|
||||
}
|
||||
|
||||
furi_string_reset(context->notification_msg);
|
||||
furi_string_set(context->notification_msg, display_menu);
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_enter(FlipFridState* context) {
|
||||
furi_string_reset(context->notification_msg);
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_exit(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_tick(FlipFridState* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context) {
|
||||
if(event.evt_type == EventTypeKey) {
|
||||
if(event.input_type == InputTypeShort) {
|
||||
const char* key_cstr = furi_string_get_cstr(context->data_str);
|
||||
int data_len = sizeof(context->data) / sizeof(context->data[0]);
|
||||
|
||||
// don't look, it's ugly but I'm a python dev so...
|
||||
uint8_t nb_bytes = 0;
|
||||
for(uint8_t i = 0; i < strlen(key_cstr); i++) {
|
||||
if(' ' == key_cstr[i]) {
|
||||
nb_bytes++;
|
||||
}
|
||||
}
|
||||
|
||||
switch(event.key) {
|
||||
case InputKeyDown:
|
||||
for(uint8_t i = 0; i < data_len; i++) {
|
||||
if(context->key_index == i) {
|
||||
context->data[i] = (context->data[i] - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyUp:
|
||||
for(uint8_t i = 0; i < data_len; i++) {
|
||||
if(context->key_index == i) {
|
||||
context->data[i] = (context->data[i] + 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InputKeyLeft:
|
||||
if(context->key_index > 0) {
|
||||
context->key_index = context->key_index - 1;
|
||||
}
|
||||
break;
|
||||
case InputKeyRight:
|
||||
if(context->key_index < nb_bytes) {
|
||||
context->key_index = context->key_index + 1;
|
||||
}
|
||||
break;
|
||||
case InputKeyOk:
|
||||
furi_string_reset(context->notification_msg);
|
||||
context->current_scene = SceneAttack;
|
||||
break;
|
||||
case InputKeyBack:
|
||||
context->key_index = 0;
|
||||
furi_string_reset(context->notification_msg);
|
||||
context->current_scene = SceneSelectFile;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
FURI_LOG_D(TAG, "Position: %d/%d", context->key_index, nb_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
// Frame
|
||||
//canvas_draw_frame(canvas, 0, 0, 128, 64);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(canvas, 12, 5, AlignLeft, AlignTop, "Left and right: select byte");
|
||||
canvas_draw_str_aligned(canvas, 12, 15, AlignLeft, AlignTop, "Up and down: adjust byte");
|
||||
|
||||
char msg_index[18];
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
snprintf(msg_index, sizeof(msg_index), "Field index : %d", context->key_index);
|
||||
canvas_draw_str_aligned(canvas, 64, 30, AlignCenter, AlignTop, msg_index);
|
||||
|
||||
flipfrid_center_displayed_key(context, context->key_index);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 45, AlignCenter, AlignTop, furi_string_get_cstr(context->notification_msg));
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
#include "../flipfrid.h"
|
||||
|
||||
void flipfrid_scene_select_field_on_enter(FlipFridState* context);
|
||||
void flipfrid_scene_select_field_on_exit(FlipFridState* context);
|
||||
void flipfrid_scene_select_field_on_tick(FlipFridState* context);
|
||||
void flipfrid_scene_select_field_on_event(FlipFridEvent event, FlipFridState* context);
|
||||
void flipfrid_scene_select_field_on_draw(Canvas* canvas, FlipFridState* context);
|
||||
void center_displayed_key(FlipFridState* context, uint8_t index);
|
||||
@@ -1,44 +0,0 @@
|
||||
# flipperzero-i2ctools
|
||||
|
||||
[Original link](https://github.com/NaejEL/flipperzero-i2ctools)
|
||||
Set of i2c tools for Flipper Zero
|
||||
|
||||

|
||||
|
||||
## Wiring
|
||||
|
||||
C0 -> SCL
|
||||
|
||||
C1 -> SDA
|
||||
|
||||
GND -> GND
|
||||
|
||||
>/!\ Target must use 3v3 logic levels. If you not sure use an i2c isolator like ISO1541
|
||||
|
||||
## Tools
|
||||
|
||||
### Scanner
|
||||
|
||||
Look for i2c peripherals adresses
|
||||
|
||||
### Sniffer
|
||||
|
||||
Spy i2c traffic
|
||||
|
||||
### Sender
|
||||
|
||||
Send command to i2c peripherals and read result
|
||||
|
||||
## TODO
|
||||
|
||||
- [ ] Read more than 2 bytes in sender mode
|
||||
- [ ] Add 10-bits adresses support
|
||||
- [ ] Test with rate > 100khz
|
||||
- [ ] Save records
|
||||
- [ ] Play from files
|
||||
- [ ] Kicad module
|
||||
- [ ] Improve UI
|
||||
- [ ] Refactor Event Management Code
|
||||
- [ ] Add Documentation
|
||||
- [ ] Remove max data size
|
||||
- [ ] Remove max frames read size
|
||||
@@ -1,13 +0,0 @@
|
||||
App(
|
||||
appid="i2cTools",
|
||||
name="[GPIO] i2c Tools",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="i2ctools_app",
|
||||
cdefines=["APP_I2CTOOLS"],
|
||||
requires=["gui"],
|
||||
stack_size=2 * 1024,
|
||||
order=175,
|
||||
fap_icon="i2ctools.png",
|
||||
fap_category="GPIO",
|
||||
fap_icon_assets="images",
|
||||
)
|
||||
@@ -1,35 +0,0 @@
|
||||
#include "i2cscanner.h"
|
||||
|
||||
void scan_i2c_bus(i2cScanner* i2c_scanner) {
|
||||
i2c_scanner->nb_found = 0;
|
||||
i2c_scanner->scanned = true;
|
||||
// Get the bus
|
||||
furi_hal_i2c_acquire(I2C_BUS);
|
||||
// scan
|
||||
for(uint8_t addr = 0x01; addr <= MAX_I2C_ADDR << 1; addr++) {
|
||||
// Check for peripherals
|
||||
if(furi_hal_i2c_is_device_ready(I2C_BUS, addr, I2C_TIMEOUT)) {
|
||||
// skip even 8-bit addr
|
||||
if(addr % 2 != 0) {
|
||||
continue;
|
||||
}
|
||||
// convert addr to 7-bits
|
||||
i2c_scanner->addresses[i2c_scanner->nb_found] = addr >> 1;
|
||||
i2c_scanner->nb_found++;
|
||||
}
|
||||
}
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
}
|
||||
|
||||
i2cScanner* i2c_scanner_alloc() {
|
||||
i2cScanner* i2c_scanner = malloc(sizeof(i2cScanner));
|
||||
i2c_scanner->nb_found = 0;
|
||||
i2c_scanner->menu_index = 0;
|
||||
i2c_scanner->scanned = false;
|
||||
return i2c_scanner;
|
||||
}
|
||||
|
||||
void i2c_scanner_free(i2cScanner* i2c_scanner) {
|
||||
furi_assert(i2c_scanner);
|
||||
free(i2c_scanner);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
// I2C BUS
|
||||
#define I2C_BUS &furi_hal_i2c_handle_external
|
||||
#define I2C_TIMEOUT 3
|
||||
|
||||
// 7 bits addresses
|
||||
#define MAX_I2C_ADDR 0x7F
|
||||
|
||||
typedef struct {
|
||||
uint8_t addresses[MAX_I2C_ADDR + 1];
|
||||
uint8_t nb_found;
|
||||
uint8_t menu_index;
|
||||
bool scanned;
|
||||
} i2cScanner;
|
||||
|
||||
void scan_i2c_bus(i2cScanner* i2c_scanner);
|
||||
|
||||
i2cScanner* i2c_scanner_alloc();
|
||||
void i2c_scanner_free(i2cScanner* i2c_scanner);
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "i2csender.h"
|
||||
|
||||
void i2c_send(i2cSender* i2c_sender) {
|
||||
furi_hal_i2c_acquire(I2C_BUS);
|
||||
uint8_t adress = i2c_sender->scanner->addresses[i2c_sender->address_idx] << 1;
|
||||
i2c_sender->error = furi_hal_i2c_trx(
|
||||
I2C_BUS,
|
||||
adress,
|
||||
&i2c_sender->value,
|
||||
sizeof(i2c_sender->value),
|
||||
i2c_sender->recv,
|
||||
sizeof(i2c_sender->recv),
|
||||
I2C_TIMEOUT);
|
||||
furi_hal_i2c_release(I2C_BUS);
|
||||
i2c_sender->must_send = false;
|
||||
i2c_sender->sended = true;
|
||||
}
|
||||
|
||||
i2cSender* i2c_sender_alloc() {
|
||||
i2cSender* i2c_sender = malloc(sizeof(i2cSender));
|
||||
i2c_sender->must_send = false;
|
||||
i2c_sender->sended = false;
|
||||
return i2c_sender;
|
||||
}
|
||||
|
||||
void i2c_sender_free(i2cSender* i2c_sender) {
|
||||
furi_assert(i2c_sender);
|
||||
free(i2c_sender);
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include "i2cscanner.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t address_idx;
|
||||
uint8_t value;
|
||||
uint8_t recv[2];
|
||||
bool must_send;
|
||||
bool sended;
|
||||
bool error;
|
||||
|
||||
i2cScanner* scanner;
|
||||
} i2cSender;
|
||||
|
||||
void i2c_send();
|
||||
|
||||
i2cSender* i2c_sender_alloc();
|
||||
void i2c_sender_free(i2cSender* i2c_sender);
|
||||
@@ -1,101 +0,0 @@
|
||||
#include "i2csniffer.h"
|
||||
|
||||
void clear_sniffer_buffers(i2cSniffer* i2c_sniffer) {
|
||||
furi_assert(i2c_sniffer);
|
||||
for(uint8_t i = 0; i < MAX_RECORDS; i++) {
|
||||
for(uint8_t j = 0; j < MAX_MESSAGE_SIZE; j++) {
|
||||
i2c_sniffer->frames[i].ack[j] = false;
|
||||
i2c_sniffer->frames[i].data[j] = 0;
|
||||
}
|
||||
i2c_sniffer->frames[i].bit_index = 0;
|
||||
i2c_sniffer->frames[i].data_index = 0;
|
||||
}
|
||||
i2c_sniffer->frame_index = 0;
|
||||
i2c_sniffer->state = I2C_BUS_FREE;
|
||||
i2c_sniffer->first = true;
|
||||
}
|
||||
|
||||
void start_interrupts(i2cSniffer* i2c_sniffer) {
|
||||
furi_assert(i2c_sniffer);
|
||||
furi_hal_gpio_init(pinSCL, GpioModeInterruptRise, GpioPullNo, GpioSpeedHigh);
|
||||
furi_hal_gpio_add_int_callback(pinSCL, SCLcallback, i2c_sniffer);
|
||||
|
||||
// Add Rise and Fall Interrupt on SDA pin
|
||||
furi_hal_gpio_init(pinSDA, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedHigh);
|
||||
furi_hal_gpio_add_int_callback(pinSDA, SDAcallback, i2c_sniffer);
|
||||
}
|
||||
|
||||
void stop_interrupts() {
|
||||
furi_hal_gpio_remove_int_callback(pinSCL);
|
||||
furi_hal_gpio_remove_int_callback(pinSDA);
|
||||
// Reset GPIO pins to default state
|
||||
furi_hal_gpio_init(pinSCL, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_init(pinSDA, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
// Called on Fallin/Rising SDA
|
||||
// Used to monitor i2c bus state
|
||||
void SDAcallback(void* _i2c_sniffer) {
|
||||
i2cSniffer* i2c_sniffer = _i2c_sniffer;
|
||||
// SCL is low maybe cclock strecching
|
||||
if(furi_hal_gpio_read(pinSCL) == false) {
|
||||
return;
|
||||
}
|
||||
// Check for stop condition: SDA rising while SCL is High
|
||||
if(i2c_sniffer->state == I2C_BUS_STARTED) {
|
||||
if(furi_hal_gpio_read(pinSDA) == true) {
|
||||
i2c_sniffer->state = I2C_BUS_FREE;
|
||||
}
|
||||
}
|
||||
// Check for start condition: SDA falling while SCL is high
|
||||
else if(furi_hal_gpio_read(pinSDA) == false) {
|
||||
i2c_sniffer->state = I2C_BUS_STARTED;
|
||||
if(i2c_sniffer->first) {
|
||||
i2c_sniffer->first = false;
|
||||
return;
|
||||
}
|
||||
i2c_sniffer->frame_index++;
|
||||
if(i2c_sniffer->frame_index >= MAX_RECORDS) {
|
||||
clear_sniffer_buffers(i2c_sniffer);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Called on Rising SCL
|
||||
// Used to read bus datas
|
||||
void SCLcallback(void* _i2c_sniffer) {
|
||||
i2cSniffer* i2c_sniffer = _i2c_sniffer;
|
||||
if(i2c_sniffer->state == I2C_BUS_FREE) {
|
||||
return;
|
||||
}
|
||||
uint8_t frame = i2c_sniffer->frame_index;
|
||||
uint8_t bit = i2c_sniffer->frames[frame].bit_index;
|
||||
uint8_t data_idx = i2c_sniffer->frames[frame].data_index;
|
||||
if(bit < 8) {
|
||||
i2c_sniffer->frames[frame].data[data_idx] <<= 1;
|
||||
i2c_sniffer->frames[frame].data[data_idx] |= (int)furi_hal_gpio_read(pinSDA);
|
||||
i2c_sniffer->frames[frame].bit_index++;
|
||||
} else {
|
||||
i2c_sniffer->frames[frame].ack[data_idx] = !furi_hal_gpio_read(pinSDA);
|
||||
i2c_sniffer->frames[frame].data_index++;
|
||||
i2c_sniffer->frames[frame].bit_index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
i2cSniffer* i2c_sniffer_alloc() {
|
||||
i2cSniffer* i2c_sniffer = malloc(sizeof(i2cSniffer));
|
||||
i2c_sniffer->started = false;
|
||||
i2c_sniffer->row_index = 0;
|
||||
i2c_sniffer->menu_index = 0;
|
||||
clear_sniffer_buffers(i2c_sniffer);
|
||||
return i2c_sniffer;
|
||||
}
|
||||
|
||||
void i2c_sniffer_free(i2cSniffer* i2c_sniffer) {
|
||||
furi_assert(i2c_sniffer);
|
||||
if(i2c_sniffer->started) {
|
||||
stop_interrupts();
|
||||
}
|
||||
free(i2c_sniffer);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
// I2C Pins
|
||||
#define pinSCL &gpio_ext_pc0
|
||||
#define pinSDA &gpio_ext_pc1
|
||||
|
||||
// Bus States
|
||||
typedef enum { I2C_BUS_FREE, I2C_BUS_STARTED } i2cBusStates;
|
||||
|
||||
// Max read size of i2c frame by message
|
||||
// Arbitraly defined
|
||||
// They're not real limit to maximum frames send
|
||||
#define MAX_MESSAGE_SIZE 128
|
||||
|
||||
// Nb of records
|
||||
#define MAX_RECORDS 128
|
||||
|
||||
/// @brief Struct used to store our reads
|
||||
typedef struct {
|
||||
uint8_t data[MAX_MESSAGE_SIZE];
|
||||
bool ack[MAX_MESSAGE_SIZE];
|
||||
uint8_t bit_index;
|
||||
uint8_t data_index;
|
||||
} i2cFrame;
|
||||
|
||||
typedef struct {
|
||||
bool started;
|
||||
bool first;
|
||||
i2cBusStates state;
|
||||
i2cFrame frames[MAX_RECORDS];
|
||||
uint8_t frame_index;
|
||||
uint8_t menu_index;
|
||||
uint8_t row_index;
|
||||
} i2cSniffer;
|
||||
|
||||
void clear_sniffer_buffers(i2cSniffer* i2c_sniffer);
|
||||
void start_interrupts(i2cSniffer* i2c_sniffer);
|
||||
void stop_interrupts();
|
||||
void SDAcallback(void* _i2c_sniffer);
|
||||
void SCLcallback(void* _i2c_sniffer);
|
||||
|
||||
i2cSniffer* i2c_sniffer_alloc();
|
||||
void i2c_sniffer_free(i2cSniffer* i2c_sniffer);
|
||||
@@ -1,225 +0,0 @@
|
||||
#include "i2ctools_i.h"
|
||||
|
||||
void i2ctools_draw_callback(Canvas* canvas, void* ctx) {
|
||||
furi_assert(ctx);
|
||||
i2cTools* i2ctools = ctx;
|
||||
furi_mutex_acquire(i2ctools->mutex, FuriWaitForever);
|
||||
|
||||
switch(i2ctools->main_view->current_view) {
|
||||
case MAIN_VIEW:
|
||||
draw_main_view(canvas, i2ctools->main_view);
|
||||
break;
|
||||
|
||||
case SCAN_VIEW:
|
||||
draw_scanner_view(canvas, i2ctools->scanner);
|
||||
break;
|
||||
|
||||
case SNIFF_VIEW:
|
||||
draw_sniffer_view(canvas, i2ctools->sniffer);
|
||||
break;
|
||||
|
||||
case SEND_VIEW:
|
||||
draw_sender_view(canvas, i2ctools->sender);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
furi_mutex_release(i2ctools->mutex);
|
||||
}
|
||||
|
||||
void i2ctools_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 i2ctools_app(void* p) {
|
||||
UNUSED(p);
|
||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
|
||||
|
||||
// Alloc i2ctools
|
||||
i2cTools* i2ctools = malloc(sizeof(i2cTools));
|
||||
i2ctools->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||
if(!i2ctools->mutex) {
|
||||
FURI_LOG_E(APP_NAME, "cannot create mutex\r\n");
|
||||
free(i2ctools);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Alloc viewport
|
||||
i2ctools->view_port = view_port_alloc();
|
||||
view_port_draw_callback_set(i2ctools->view_port, i2ctools_draw_callback, i2ctools);
|
||||
view_port_input_callback_set(i2ctools->view_port, i2ctools_input_callback, event_queue);
|
||||
|
||||
// Register view port in GUI
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, i2ctools->view_port, GuiLayerFullscreen);
|
||||
|
||||
InputEvent event;
|
||||
|
||||
i2ctools->main_view = i2c_main_view_alloc();
|
||||
|
||||
i2ctools->sniffer = i2c_sniffer_alloc();
|
||||
i2ctools->sniffer->menu_index = 0;
|
||||
|
||||
i2ctools->scanner = i2c_scanner_alloc();
|
||||
|
||||
i2ctools->sender = i2c_sender_alloc();
|
||||
// Share scanner with sender
|
||||
i2ctools->sender->scanner = i2ctools->scanner;
|
||||
|
||||
while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) {
|
||||
// Back
|
||||
if(event.key == InputKeyBack && event.type == InputTypeRelease) {
|
||||
if(i2ctools->main_view->current_view == MAIN_VIEW) {
|
||||
break;
|
||||
} else {
|
||||
if(i2ctools->main_view->current_view == SNIFF_VIEW) {
|
||||
stop_interrupts();
|
||||
i2ctools->sniffer->started = false;
|
||||
i2ctools->sniffer->state = I2C_BUS_FREE;
|
||||
}
|
||||
i2ctools->main_view->current_view = MAIN_VIEW;
|
||||
}
|
||||
}
|
||||
// Up
|
||||
else if(event.key == InputKeyUp && event.type == InputTypeRelease) {
|
||||
if(i2ctools->main_view->current_view == MAIN_VIEW) {
|
||||
if((i2ctools->main_view->menu_index > SCAN_VIEW)) {
|
||||
i2ctools->main_view->menu_index--;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SCAN_VIEW) {
|
||||
if(i2ctools->scanner->menu_index > 0) {
|
||||
i2ctools->scanner->menu_index--;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SNIFF_VIEW) {
|
||||
if(i2ctools->sniffer->row_index > 0) {
|
||||
i2ctools->sniffer->row_index--;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SEND_VIEW) {
|
||||
if(i2ctools->sender->value < 0xFF) {
|
||||
i2ctools->sender->value++;
|
||||
i2ctools->sender->sended = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Long Up
|
||||
else if(
|
||||
event.key == InputKeyUp &&
|
||||
(event.type == InputTypeLong || event.type == InputTypeRepeat)) {
|
||||
if(i2ctools->main_view->current_view == SCAN_VIEW) {
|
||||
if(i2ctools->scanner->menu_index > 5) {
|
||||
i2ctools->scanner->menu_index -= 5;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SEND_VIEW) {
|
||||
if(i2ctools->sender->value < 0xF9) {
|
||||
i2ctools->sender->value += 5;
|
||||
i2ctools->sender->sended = false;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SNIFF_VIEW) {
|
||||
if(i2ctools->sniffer->row_index > 5) {
|
||||
i2ctools->sniffer->row_index -= 5;
|
||||
} else {
|
||||
i2ctools->sniffer->row_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Down
|
||||
else if(event.key == InputKeyDown && event.type == InputTypeRelease) {
|
||||
if(i2ctools->main_view->current_view == MAIN_VIEW) {
|
||||
if(i2ctools->main_view->menu_index < MENU_SIZE - 1) {
|
||||
i2ctools->main_view->menu_index++;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SCAN_VIEW) {
|
||||
if(i2ctools->scanner->menu_index < ((int)i2ctools->scanner->nb_found / 3)) {
|
||||
i2ctools->scanner->menu_index++;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SNIFF_VIEW) {
|
||||
if((i2ctools->sniffer->row_index + 3) <
|
||||
(int)i2ctools->sniffer->frames[i2ctools->sniffer->menu_index].data_index) {
|
||||
i2ctools->sniffer->row_index++;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SEND_VIEW) {
|
||||
if(i2ctools->sender->value > 0x00) {
|
||||
i2ctools->sender->value--;
|
||||
i2ctools->sender->sended = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Long Down
|
||||
else if(
|
||||
event.key == InputKeyDown &&
|
||||
(event.type == InputTypeLong || event.type == InputTypeRepeat)) {
|
||||
if(i2ctools->main_view->current_view == SEND_VIEW) {
|
||||
if(i2ctools->sender->value > 0x05) {
|
||||
i2ctools->sender->value -= 5;
|
||||
i2ctools->sender->sended = false;
|
||||
} else {
|
||||
i2ctools->sender->value = 0;
|
||||
i2ctools->sender->sended = false;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SNIFF_VIEW) {
|
||||
if((i2ctools->sniffer->row_index + 8) <
|
||||
(int)i2ctools->sniffer->frames[i2ctools->sniffer->menu_index].data_index) {
|
||||
i2ctools->sniffer->row_index += 5;
|
||||
}
|
||||
}
|
||||
|
||||
} else if(event.key == InputKeyOk && event.type == InputTypeRelease) {
|
||||
if(i2ctools->main_view->current_view == MAIN_VIEW) {
|
||||
i2ctools->main_view->current_view = i2ctools->main_view->menu_index;
|
||||
} else if(i2ctools->main_view->current_view == SCAN_VIEW) {
|
||||
scan_i2c_bus(i2ctools->scanner);
|
||||
} else if(i2ctools->main_view->current_view == SEND_VIEW) {
|
||||
i2ctools->sender->must_send = true;
|
||||
} else if(i2ctools->main_view->current_view == SNIFF_VIEW) {
|
||||
if(i2ctools->sniffer->started) {
|
||||
stop_interrupts();
|
||||
i2ctools->sniffer->started = false;
|
||||
i2ctools->sniffer->state = I2C_BUS_FREE;
|
||||
} else {
|
||||
start_interrupts(i2ctools->sniffer);
|
||||
i2ctools->sniffer->started = true;
|
||||
i2ctools->sniffer->state = I2C_BUS_FREE;
|
||||
}
|
||||
}
|
||||
} else if(event.key == InputKeyRight && event.type == InputTypeRelease) {
|
||||
if(i2ctools->main_view->current_view == SEND_VIEW) {
|
||||
if(i2ctools->sender->address_idx < (i2ctools->scanner->nb_found - 1)) {
|
||||
i2ctools->sender->address_idx++;
|
||||
i2ctools->sender->sended = false;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SNIFF_VIEW) {
|
||||
if(i2ctools->sniffer->menu_index < i2ctools->sniffer->frame_index) {
|
||||
i2ctools->sniffer->menu_index++;
|
||||
i2ctools->sniffer->row_index = 0;
|
||||
}
|
||||
}
|
||||
} else if(event.key == InputKeyLeft && event.type == InputTypeRelease) {
|
||||
if(i2ctools->main_view->current_view == SEND_VIEW) {
|
||||
if(i2ctools->sender->address_idx > 0) {
|
||||
i2ctools->sender->address_idx--;
|
||||
i2ctools->sender->sended = false;
|
||||
}
|
||||
} else if(i2ctools->main_view->current_view == SNIFF_VIEW) {
|
||||
if(i2ctools->sniffer->menu_index > 0) {
|
||||
i2ctools->sniffer->menu_index--;
|
||||
i2ctools->sniffer->row_index = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
view_port_update(i2ctools->view_port);
|
||||
}
|
||||
gui_remove_view_port(gui, i2ctools->view_port);
|
||||
view_port_free(i2ctools->view_port);
|
||||
furi_message_queue_free(event_queue);
|
||||
i2c_sniffer_free(i2ctools->sniffer);
|
||||
i2c_scanner_free(i2ctools->scanner);
|
||||
i2c_sender_free(i2ctools->sender);
|
||||
i2c_main_view_free(i2ctools->main_view);
|
||||
furi_mutex_free(i2ctools->mutex);
|
||||
free(i2ctools);
|
||||
furi_record_close(RECORD_GUI);
|
||||
return 0;
|
||||
}
|
||||
|
Before Width: | Height: | Size: 2.5 MiB |
|
Before Width: | Height: | Size: 8.2 KiB |
@@ -1,23 +0,0 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
|
||||
#include "i2csniffer.h"
|
||||
#include "i2cscanner.h"
|
||||
#include "i2csender.h"
|
||||
#include "views/main_view.h"
|
||||
#include "views/sniffer_view.h"
|
||||
#include "views/scanner_view.h"
|
||||
#include "views/sender_view.h"
|
||||
|
||||
// App datas
|
||||
typedef struct {
|
||||
FuriMutex* mutex;
|
||||
ViewPort* view_port;
|
||||
i2cMainView* main_view;
|
||||
|
||||
i2cScanner* scanner;
|
||||
i2cSniffer* sniffer;
|
||||
i2cSender* sender;
|
||||
} i2cTools;
|
||||
|
Before Width: | Height: | Size: 102 B |