Merge remote-tracking branch 'origin/release-candidate' into release
9
.github/workflows/build.yml
vendored
@ -14,8 +14,11 @@ jobs:
|
|||||||
|
|
||||||
- name: 'Decontaminate previous build leftovers'
|
- name: 'Decontaminate previous build leftovers'
|
||||||
run: |
|
run: |
|
||||||
git submodule status \
|
if [ -d .git ]
|
||||||
|| git checkout `git rev-list --max-parents=0 HEAD | tail -n 1`
|
then
|
||||||
|
git submodule status \
|
||||||
|
|| git checkout `git rev-list --max-parents=0 HEAD | tail -n 1`
|
||||||
|
fi
|
||||||
|
|
||||||
- name: 'Checkout code'
|
- name: 'Checkout code'
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@ -44,7 +47,7 @@ jobs:
|
|||||||
|
|
||||||
- name: 'Generate branch suffix'
|
- name: 'Generate branch suffix'
|
||||||
if: startsWith(github.ref, 'refs/tags/') != true
|
if: startsWith(github.ref, 'refs/tags/') != true
|
||||||
run: echo "SUFFIX=$(date +'%Y-%m-%d')-$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
run: echo "SUFFIX=$(git rev-parse --abbrev-ref HEAD)-$(date +'%d%m%Y')-$(git rev-parse --short HEAD)" >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: 'Build bootloader in docker'
|
- name: 'Build bootloader in docker'
|
||||||
uses: ./.github/actions/docker
|
uses: ./.github/actions/docker
|
||||||
|
|||||||
15
.github/workflows/lint_c.yml
vendored
@ -12,16 +12,19 @@ jobs:
|
|||||||
- name: 'Cleanup workspace'
|
- name: 'Cleanup workspace'
|
||||||
uses: AutoModality/action-clean@v1
|
uses: AutoModality/action-clean@v1
|
||||||
|
|
||||||
|
- name: 'Decontaminate previous build leftovers'
|
||||||
|
run: |
|
||||||
|
if [ -d .git ]
|
||||||
|
then
|
||||||
|
git submodule status \
|
||||||
|
|| git checkout `git rev-list --max-parents=0 HEAD | tail -n 1`
|
||||||
|
fi
|
||||||
|
|
||||||
- name: 'Checkout code'
|
- name: 'Checkout code'
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
submodules: true
|
||||||
- name: 'Checkout submodules: update'
|
|
||||||
run: git submodule update --init --recursive
|
|
||||||
|
|
||||||
- name: 'Checkout submodules: sync'
|
|
||||||
run: git submodule sync
|
|
||||||
|
|
||||||
- name: 'Docker cache'
|
- name: 'Docker cache'
|
||||||
uses: satackey/action-docker-layer-caching@v0.0.11
|
uses: satackey/action-docker-layer-caching@v0.0.11
|
||||||
|
|||||||
24
.github/workflows/lint_python.yml
vendored
@ -10,6 +10,24 @@ jobs:
|
|||||||
lint_python:
|
lint_python:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: 'Cleanup workspace'
|
||||||
- uses: actions/setup-python@v2
|
uses: AutoModality/action-clean@v1
|
||||||
- uses: psf/black@20.8b1
|
|
||||||
|
- name: 'Decontaminate previous build leftovers'
|
||||||
|
run: |
|
||||||
|
if [ -d .git ]
|
||||||
|
then
|
||||||
|
git submodule status \
|
||||||
|
|| git checkout `git rev-list --max-parents=0 HEAD | tail -n 1`
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: 'Checkout code'
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: 'Setup python'
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
|
||||||
|
- name: 'Check python code with black'
|
||||||
|
uses: psf/black@20.8b1
|
||||||
|
|||||||
@ -39,6 +39,7 @@ int32_t lfrfid_debug_app(void* p);
|
|||||||
int32_t storage_app(void* p);
|
int32_t storage_app(void* p);
|
||||||
int32_t storage_app_test(void* p);
|
int32_t storage_app_test(void* p);
|
||||||
int32_t dialogs_app(void* p);
|
int32_t dialogs_app(void* p);
|
||||||
|
int32_t power_observer(void* p);
|
||||||
|
|
||||||
// On system start hooks declaration
|
// On system start hooks declaration
|
||||||
void irda_cli_init();
|
void irda_cli_init();
|
||||||
@ -91,6 +92,10 @@ const FlipperApplication FLIPPER_SERVICES[] = {
|
|||||||
{.app = power_task, .name = "power_task", .stack_size = 1024, .icon = &A_Plugins_14},
|
{.app = power_task, .name = "power_task", .stack_size = 1024, .icon = &A_Plugins_14},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SRV_POWER_OBSERVER
|
||||||
|
{.app = power_observer, .name = "power_observer", .stack_size = 1024, .icon = &A_Plugins_14},
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SRV_BT
|
#ifdef SRV_BT
|
||||||
{.app = bt_task, .name = "bt_task", .stack_size = 1024, .icon = &A_Plugins_14},
|
{.app = bt_task, .name = "bt_task", .stack_size = 1024, .icon = &A_Plugins_14},
|
||||||
#endif
|
#endif
|
||||||
@ -139,7 +144,7 @@ const FlipperApplication FLIPPER_SERVICES[] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SRV_KEYPAD_TEST
|
#ifdef SRV_KEYPAD_TEST
|
||||||
{.app = keypad_test, .name = "keypad_test", .icon = &A_Plugins_14},
|
{.app = keypad_test, .name = "keypad_test", .stack_size = 1024, .icon = &A_Plugins_14},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SRV_ACCESSOR
|
#ifdef SRV_ACCESSOR
|
||||||
@ -268,7 +273,7 @@ const FlipperApplication FLIPPER_DEBUG_APPS[] = {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef APP_KEYPAD_TEST
|
#ifdef APP_KEYPAD_TEST
|
||||||
{.app = keypad_test, .name = "keypad_test", .icon = &A_Plugins_14},
|
{.app = keypad_test, .name = "keypad_test", .stack_size = 1024, .icon = &A_Plugins_14},
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef APP_ACCESSOR
|
#ifdef APP_ACCESSOR
|
||||||
|
|||||||
@ -20,6 +20,7 @@ SRV_DOLPHIN = 1
|
|||||||
SRV_NOTIFICATION = 1
|
SRV_NOTIFICATION = 1
|
||||||
SRV_STORAGE = 1
|
SRV_STORAGE = 1
|
||||||
SRV_DIALOGS = 1
|
SRV_DIALOGS = 1
|
||||||
|
SRV_POWER_OBSERVER = 1
|
||||||
|
|
||||||
# Main Apps
|
# Main Apps
|
||||||
APP_IRDA = 1
|
APP_IRDA = 1
|
||||||
@ -59,6 +60,12 @@ SRV_CLI = 1
|
|||||||
CFLAGS += -DSRV_POWER
|
CFLAGS += -DSRV_POWER
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
SRV_POWER_OBSERVER ?= 0
|
||||||
|
ifeq ($(SRV_POWER_OBSERVER), 1)
|
||||||
|
SRV_POWER = 1
|
||||||
|
CFLAGS += -DSRV_POWER_OBSERVER
|
||||||
|
endif
|
||||||
|
|
||||||
SRV_BT ?= 0
|
SRV_BT ?= 0
|
||||||
ifeq ($(SRV_BT), 1)
|
ifeq ($(SRV_BT), 1)
|
||||||
SRV_CLI = 1
|
SRV_CLI = 1
|
||||||
|
|||||||
@ -297,7 +297,8 @@ static void archive_enter_text_input(ArchiveApp* archive) {
|
|||||||
archive_text_input_callback,
|
archive_text_input_callback,
|
||||||
archive,
|
archive,
|
||||||
archive->browser.text_input_buffer,
|
archive->browser.text_input_buffer,
|
||||||
MAX_NAME_LEN);
|
MAX_NAME_LEN,
|
||||||
|
false);
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput);
|
view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#include "cli_i.h"
|
#include "cli_i.h"
|
||||||
#include "cli_commands.h"
|
#include "cli_commands.h"
|
||||||
|
|
||||||
#include <version.h>
|
|
||||||
#include <api-hal-version.h>
|
#include <api-hal-version.h>
|
||||||
#include <loader/loader.h>
|
#include <loader/loader.h>
|
||||||
|
|
||||||
|
|||||||
@ -94,23 +94,30 @@ void cli_command_help(Cli* cli, string_t args, void* context) {
|
|||||||
(void)args;
|
(void)args;
|
||||||
printf("Commands we have:");
|
printf("Commands we have:");
|
||||||
|
|
||||||
// Get the middle element
|
// Command count
|
||||||
CliCommandTree_it_t it_mid;
|
const size_t commands_count = CliCommandTree_size(cli->commands);
|
||||||
uint8_t cmd_num = CliCommandTree_size(cli->commands);
|
const size_t commands_count_mid = commands_count / 2 + commands_count % 2;
|
||||||
uint8_t i = cmd_num / 2 + cmd_num % 2;
|
|
||||||
for(CliCommandTree_it(it_mid, cli->commands); i; --i, CliCommandTree_next(it_mid))
|
|
||||||
;
|
|
||||||
// Use 2 iterators from start and middle to show 2 columns
|
// Use 2 iterators from start and middle to show 2 columns
|
||||||
CliCommandTree_it_t it_i;
|
CliCommandTree_it_t it_left;
|
||||||
CliCommandTree_it_t it_j;
|
CliCommandTree_it(it_left, cli->commands);
|
||||||
for(CliCommandTree_it(it_i, cli->commands), CliCommandTree_it_set(it_j, it_mid);
|
CliCommandTree_it_t it_right;
|
||||||
!CliCommandTree_it_equal_p(it_i, it_mid);
|
CliCommandTree_it(it_right, cli->commands);
|
||||||
CliCommandTree_next(it_i), CliCommandTree_next(it_j)) {
|
for(size_t i = 0; i < commands_count_mid; i++) CliCommandTree_next(it_right);
|
||||||
CliCommandTree_itref_t* ref = CliCommandTree_ref(it_i);
|
|
||||||
|
// Iterate throw tree
|
||||||
|
for(size_t i = 0; i < commands_count_mid; i++) {
|
||||||
printf("\r\n");
|
printf("\r\n");
|
||||||
printf("%-30s", string_get_cstr(ref->key_ptr[0]));
|
// Left Column
|
||||||
ref = CliCommandTree_ref(it_j);
|
if(!CliCommandTree_end_p(it_left)) {
|
||||||
printf(string_get_cstr(ref->key_ptr[0]));
|
printf("%-30s", string_get_cstr(*CliCommandTree_ref(it_left)->key_ptr));
|
||||||
|
CliCommandTree_next(it_left);
|
||||||
|
}
|
||||||
|
// Right Column
|
||||||
|
if(!CliCommandTree_end_p(it_right)) {
|
||||||
|
printf(string_get_cstr(*CliCommandTree_ref(it_right)->key_ptr));
|
||||||
|
CliCommandTree_next(it_right);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if(string_size(args) > 0) {
|
if(string_size(args) > 0) {
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
#include <api-hal.h>
|
#include <api-hal.h>
|
||||||
#include <version.h>
|
|
||||||
#include <api-hal-version.h>
|
#include <api-hal-version.h>
|
||||||
|
|
||||||
static char* Lockmenu_Items[3] = {"Lock", "Set PIN", "DUMB mode"};
|
static char* Lockmenu_Items[3] = {"Lock", "Set PIN", "DUMB mode"};
|
||||||
@ -40,7 +39,7 @@ void dolphin_view_first_start_draw(Canvas* canvas, void* model) {
|
|||||||
"I am",
|
"I am",
|
||||||
my_name ? my_name : "Unknown",
|
my_name ? my_name : "Unknown",
|
||||||
",\ncyberdolphin\nliving in your\npocket >");
|
",\ncyberdolphin\nliving in your\npocket >");
|
||||||
canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart5_45x53);
|
canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart5_54x49);
|
||||||
elements_multiline_text_framed(canvas, 60, 17, buf);
|
elements_multiline_text_framed(canvas, 60, 17, buf);
|
||||||
} else if(m->page == 6) {
|
} else if(m->page == 6) {
|
||||||
canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart6_58x54);
|
canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart6_58x54);
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
static const char* emotes_list[] = {
|
// temp
|
||||||
"(O_o)", "(!_?)", "(^_^)", "(*__*)", "(@_@)", "(X_x)", "(>_<)", "(^ ^)", "(^_^)",
|
const char* console_emotes[] = {
|
||||||
"(-_-)", "(~_~)", "(#^.^#)", "(^ ^)", "(^.^)", "(-.-)", "zZzZ", "(^_-)", "(^_-)",
|
"Run it, m8",
|
||||||
"(+_+)", "(+o+)", "(' ')", "('-')", "('.')", "('_')", "(* > *)", "(o o)", "(^_^)",
|
"Lets GOOOO",
|
||||||
"(^O^)", "(^o^)", "(^o^)", "(._.)", "(_^_)", "('_')", "('_;)", "(T_T)", "(;_;)",
|
"Click it, buddy",
|
||||||
"(ー_ー)", "(-.-)", "(^o^)", "(-_-)", "(=_=)", "(=^ ^=)", "(. .)", "(._.)", "( ^m^)",
|
"I wanna play",
|
||||||
"(?_?)", "(*^_^*)", "(^<^)", "(^.^)", "(^·^)", "(^.^)", "(^_^.)", "(^_^)", "(^^)",
|
"Wtf is this?",
|
||||||
"(^J^)", "(*^.^*)", "(#^.^#)", "(~o~)", "(^o^)", "(-o-)", "(^. ^)", "(^o^)", "(*^0^*)",
|
"Just do it",
|
||||||
"(*_*)", "(~ o ~)", "(~_~)", "(p_-)", "d[-_-]b", "(^0_0^)", "- ^ -"};
|
"JUST DO IT!",
|
||||||
|
|
||||||
static const char* dialogues_list[] = {
|
|
||||||
"Let's hack!\n\nbla bla bla\nbla bla..",
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,49 +1,38 @@
|
|||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
#include "applications.h"
|
#include "applications.h"
|
||||||
#include "items_i.h"
|
#include "items_i.h"
|
||||||
|
#include "emotes.h"
|
||||||
|
#include <gui/icon_i.h>
|
||||||
|
|
||||||
const Item TV = {
|
const Item Food = {
|
||||||
.layer = 7,
|
|
||||||
.timeout = 10,
|
|
||||||
.x = 160,
|
|
||||||
.y = 34,
|
|
||||||
.icon = &I_TV_20x24,
|
|
||||||
.action_name = "Use",
|
|
||||||
.draw = draw_tv,
|
|
||||||
.callback = smash_tv};
|
|
||||||
|
|
||||||
const Item Painting = {
|
|
||||||
.layer = 3,
|
|
||||||
.timeout = 20,
|
|
||||||
.x = 160,
|
|
||||||
.y = 10,
|
|
||||||
.icon = &I_Home_painting_17x20,
|
|
||||||
.action_name = "Inspect",
|
|
||||||
.draw = NULL,
|
|
||||||
.callback = inspect_painting};
|
|
||||||
|
|
||||||
const Item Sofa = {
|
|
||||||
.layer = 4,
|
.layer = 4,
|
||||||
.timeout = 100,
|
.timeout = 100,
|
||||||
.x = 250,
|
.pos =
|
||||||
.y = 34,
|
{
|
||||||
.icon = &I_Sofa_40x13,
|
.x = 0,
|
||||||
.action_name = "Sit",
|
.y = 90,
|
||||||
.draw = NULL,
|
},
|
||||||
.callback = sofa_sit};
|
.width = 60,
|
||||||
|
.height = 50,
|
||||||
|
.draw = food_redraw,
|
||||||
|
.callback = food_callback};
|
||||||
|
|
||||||
const Item PC = {
|
const Item Console = {
|
||||||
.layer = 4,
|
.layer = 4,
|
||||||
.timeout = 100,
|
.timeout = 100,
|
||||||
.x = 400,
|
.pos =
|
||||||
.y = 10,
|
{
|
||||||
.icon = &I_PC_22x29,
|
.x = 357,
|
||||||
.action_name = "Use",
|
.y = 190,
|
||||||
.draw = NULL,
|
},
|
||||||
.callback = pc_callback};
|
.width = 40,
|
||||||
|
.height = 20,
|
||||||
|
.draw = console_redraw,
|
||||||
|
.callback = console_callback};
|
||||||
|
|
||||||
const Item* Home[ITEMS_NUM] = {&TV, &Sofa, &Painting, &PC};
|
const Item* Home[] = {&Food, &Console};
|
||||||
const Item** Scenes[1] = {*&Home};
|
|
||||||
|
const Item** Scenes[] = {Home};
|
||||||
|
|
||||||
const Item** get_scene(SceneState* state) {
|
const Item** get_scene(SceneState* state) {
|
||||||
return Scenes[state->scene_id];
|
return Scenes[state->scene_id];
|
||||||
@ -64,6 +53,37 @@ static void dolphin_scene_start_app(SceneState* state, const FlipperApplication*
|
|||||||
furi_thread_start(state->scene_app_thread);
|
furi_thread_start(state->scene_app_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint16_t roll_new(uint16_t prev, uint16_t max) {
|
||||||
|
uint16_t val = 999;
|
||||||
|
while(val != prev) {
|
||||||
|
val = random() % max;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dolphin_scene_type_text(
|
||||||
|
Canvas* canvas,
|
||||||
|
SceneState* state,
|
||||||
|
uint8_t x,
|
||||||
|
uint8_t y,
|
||||||
|
const char* text) {
|
||||||
|
char dialog_str[64];
|
||||||
|
char buf[64];
|
||||||
|
|
||||||
|
strcpy(dialog_str, (char*)text);
|
||||||
|
|
||||||
|
if(state->dialog_progress <= strlen(dialog_str)) {
|
||||||
|
if(HAL_GetTick() / 10 % 2 == 0) state->dialog_progress++;
|
||||||
|
dialog_str[state->dialog_progress] = '\0';
|
||||||
|
snprintf(buf, state->dialog_progress, dialog_str);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, 64, dialog_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas_draw_str_aligned(canvas, x, y, AlignCenter, AlignCenter, buf);
|
||||||
|
}
|
||||||
|
|
||||||
const void scene_activate_item_callback(SceneState* state, Canvas* canvas) {
|
const void scene_activate_item_callback(SceneState* state, Canvas* canvas) {
|
||||||
furi_assert(state);
|
furi_assert(state);
|
||||||
furi_assert(canvas);
|
furi_assert(canvas);
|
||||||
@ -78,16 +98,32 @@ const void scene_activate_item_callback(SceneState* state, Canvas* canvas) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Vec2 item_get_pos(SceneState* state, ItemsEnum item) {
|
||||||
|
const Item** current = get_scene(state);
|
||||||
|
Vec2 rel_pos = {0, 0};
|
||||||
|
|
||||||
|
rel_pos.x = DOLPHIN_WIDTH / 2 + (current[item]->pos.x * PARALLAX(current[item]->layer));
|
||||||
|
rel_pos.y = DOLPHIN_WIDTH / 4 + (current[item]->pos.y * PARALLAX(current[item]->layer));
|
||||||
|
|
||||||
|
return rel_pos;
|
||||||
|
}
|
||||||
|
|
||||||
const Item* is_nearby(SceneState* state) {
|
const Item* is_nearby(SceneState* state) {
|
||||||
furi_assert(state);
|
furi_assert(state);
|
||||||
uint8_t item = 0;
|
uint8_t item = 0;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
const Item** current = get_scene(state);
|
const Item** current = get_scene(state);
|
||||||
while(item < ITEMS_NUM) {
|
while(item < ItemsEnumTotal) {
|
||||||
int32_t rel =
|
int32_t rel_x =
|
||||||
(DOLPHIN_CENTER + DOLPHIN_WIDTH / 2 -
|
(DOLPHIN_CENTER + DOLPHIN_WIDTH / 2 -
|
||||||
(current[item]->x - state->player_global.x) * PARALLAX(current[item]->layer));
|
(current[item]->pos.x - state->player_global.x) * PARALLAX(current[item]->layer));
|
||||||
if(abs(rel) <= DOLPHIN_WIDTH / 2) {
|
|
||||||
|
uint8_t item_height = current[item]->height;
|
||||||
|
uint8_t item_width = current[item]->width;
|
||||||
|
|
||||||
|
int32_t rel_y = current[item]->pos.y - state->player_global.y;
|
||||||
|
|
||||||
|
if(abs(rel_x) <= item_width && abs(rel_y) <= item_height) {
|
||||||
found = !found;
|
found = !found;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -96,50 +132,102 @@ const Item* is_nearby(SceneState* state) {
|
|||||||
return found ? current[item] : NULL;
|
return found ? current[item] : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw_tv(Canvas* canvas, void* state) {
|
void food_redraw(Canvas* canvas, void* s) {
|
||||||
furi_assert(state);
|
furi_assert(s);
|
||||||
SceneState* s = state;
|
SceneState* state = s;
|
||||||
canvas_set_color(canvas, ColorWhite);
|
|
||||||
canvas_draw_box(
|
const Icon* food_frames[] = {
|
||||||
canvas, (TV.x + 3 - s->player_global.x) * PARALLAX(TV.layer), TV.y + 4, 16, 20);
|
&I_food1_61x98,
|
||||||
canvas_set_color(canvas, ColorBlack);
|
&I_food2_61x98,
|
||||||
canvas_set_bitmap_mode(canvas, true);
|
&I_food3_61x98,
|
||||||
}
|
&I_food4_61x98,
|
||||||
|
&I_food5_61x98,
|
||||||
|
&I_food6_61x98,
|
||||||
|
&I_food7_61x98,
|
||||||
|
&I_food8_61x98,
|
||||||
|
&I_food9_61x98,
|
||||||
|
&I_food10_61x98,
|
||||||
|
&I_food11_61x98,
|
||||||
|
&I_food12_61x98,
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t frame = ((HAL_GetTick() / 200) % SIZEOF_ARRAY(food_frames));
|
||||||
|
|
||||||
|
if(is_nearby(state) && (state->player_global.y > Food.pos.y)) {
|
||||||
|
dolphin_scene_type_text(
|
||||||
|
canvas,
|
||||||
|
state,
|
||||||
|
(Food.pos.x - state->player_global.x) * PARALLAX(Food.layer) + 90,
|
||||||
|
state->screen.y + 8,
|
||||||
|
console_emotes[state->emote_id]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
state->dialog_progress = 0;
|
||||||
|
state->emote_id = roll_new(state->previous_emote, SIZEOF_ARRAY(console_emotes));
|
||||||
|
}
|
||||||
|
|
||||||
void smash_tv(Canvas* canvas, void* state) {
|
|
||||||
furi_assert(state);
|
|
||||||
SceneState* s = state;
|
|
||||||
s->player_flipped = true;
|
|
||||||
canvas_set_bitmap_mode(canvas, true);
|
|
||||||
canvas_draw_icon(
|
canvas_draw_icon(
|
||||||
canvas, ((TV.x - 5) - s->player_global.x) * PARALLAX(TV.layer), TV.y - 2, &I_FX_Bang_32x6);
|
canvas,
|
||||||
canvas_set_bitmap_mode(canvas, false);
|
(Food.pos.x - state->player_global.x) * PARALLAX(Food.layer),
|
||||||
if(s->action_timeout < TV.timeout - 2) {
|
Food.pos.y - state->player_global.y,
|
||||||
elements_multiline_text_framed(canvas, 80, 24, "Bang!");
|
food_frames[frame]);
|
||||||
|
|
||||||
|
canvas_set_bitmap_mode(canvas, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void food_callback(Canvas* canvas, void* s) {
|
||||||
|
furi_assert(s);
|
||||||
|
SceneState* state = s;
|
||||||
|
if(state->use_pending) {
|
||||||
|
dolphin_scene_start_app(state, &FLIPPER_SCENE_APPS[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sofa_sit(Canvas* canvas, void* state) {
|
void console_redraw(Canvas* canvas, void* s) {
|
||||||
furi_assert(state);
|
furi_assert(s);
|
||||||
SceneState* s = state;
|
SceneState* state = s;
|
||||||
// temp fix pos
|
|
||||||
s->player_global.x = 154;
|
|
||||||
s->dolphin_gfx = &A_FX_Sitting_40x27;
|
|
||||||
s->dolphin_gfx_b = &I_FX_SittingB_40x27;
|
|
||||||
}
|
|
||||||
|
|
||||||
void inspect_painting(Canvas* canvas, void* state) {
|
const Icon* console[] = {
|
||||||
furi_assert(state);
|
&I_Console_74x67_0,
|
||||||
SceneState* s = state;
|
&I_Console_74x67_1,
|
||||||
if(s->use_pending) {
|
&I_Console_74x67_2,
|
||||||
dolphin_scene_start_app(s, &FLIPPER_SCENE_APPS[0]);
|
&I_Console_74x67_3,
|
||||||
|
&I_Console_74x67_4,
|
||||||
|
&I_Console_74x67_5,
|
||||||
|
&I_Console_74x67_6,
|
||||||
|
&I_Console_74x67_7,
|
||||||
|
&I_Console_74x67_8,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t frame = ((HAL_GetTick() / 100) % SIZEOF_ARRAY(console));
|
||||||
|
|
||||||
|
canvas_draw_icon(
|
||||||
|
canvas,
|
||||||
|
(Console.pos.x - state->player_global.x) * PARALLAX(Console.layer),
|
||||||
|
Console.pos.y - state->player_global.y,
|
||||||
|
console[frame]);
|
||||||
|
|
||||||
|
canvas_set_bitmap_mode(canvas, true);
|
||||||
|
|
||||||
|
if(is_nearby(state)) {
|
||||||
|
dolphin_scene_type_text(
|
||||||
|
canvas,
|
||||||
|
state,
|
||||||
|
(Console.pos.x - state->player_global.x) * PARALLAX(Console.layer) - 25,
|
||||||
|
Console.pos.y - state->player_global.y + 14,
|
||||||
|
console_emotes[state->emote_id]);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
state->dialog_progress = 0;
|
||||||
|
state->emote_id = roll_new(state->previous_emote, SIZEOF_ARRAY(console_emotes));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pc_callback(Canvas* canvas, void* state) {
|
void console_callback(Canvas* canvas, void* s) {
|
||||||
furi_assert(state);
|
furi_assert(s);
|
||||||
SceneState* s = state;
|
SceneState* state = s;
|
||||||
if(s->use_pending) {
|
if(state->use_pending) {
|
||||||
dolphin_scene_start_app(s, &FLIPPER_SCENE_APPS[1]);
|
dolphin_scene_start_app(state, &FLIPPER_SCENE_APPS[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,8 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "dolphin/scenes/scene.h"
|
#include "dolphin/scenes/scene.h"
|
||||||
|
|
||||||
#define ITEMS_NUM 4
|
typedef enum {
|
||||||
|
ItemsFood,
|
||||||
|
ItemsConsole,
|
||||||
|
ItemsEnumTotal,
|
||||||
|
} ItemsEnum;
|
||||||
|
|
||||||
|
uint16_t roll_new(uint16_t prev, uint16_t max);
|
||||||
|
const Vec2 item_get_pos(SceneState* state, ItemsEnum item);
|
||||||
const Item* is_nearby(SceneState* state);
|
const Item* is_nearby(SceneState* state);
|
||||||
const Item** get_scene(SceneState* state);
|
const Item** get_scene(SceneState* state);
|
||||||
const void scene_activate_item_callback(SceneState* state, Canvas* canvas);
|
const void scene_activate_item_callback(SceneState* state, Canvas* canvas);
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "items.h"
|
#include "items.h"
|
||||||
|
|
||||||
void smash_tv(Canvas* canvas, void* state);
|
void food_redraw(Canvas* canvas, void* state);
|
||||||
void draw_tv(Canvas* canvas, void* state);
|
void food_callback(Canvas* canvas, void* state);
|
||||||
void sofa_sit(Canvas* canvas, void* state);
|
|
||||||
void inspect_painting(Canvas* canvas, void* state);
|
void console_redraw(Canvas* canvas, void* state);
|
||||||
void pc_callback(Canvas* canvas, void* state);
|
void console_callback(Canvas* canvas, void* state);
|
||||||
|
|||||||
276
applications/dolphin/scenes/assets/meta.h
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "dolphin/scenes/scene.h"
|
||||||
|
|
||||||
|
const DolphinFrame up = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_up1_73x61,
|
||||||
|
.b = &I_black_up1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_up2_73x61,
|
||||||
|
.b = &I_black_up2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame up_down = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_updown1_73x61,
|
||||||
|
.b = &I_black_updown1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_updown2_73x61,
|
||||||
|
.b = &I_black_updown2_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_updown3_73x61,
|
||||||
|
.b = &I_black_updown3_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame up_right = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_upright1_73x61,
|
||||||
|
.b = &I_black_upright1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_upright2_73x61,
|
||||||
|
.b = &I_black_upright2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame up_left = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_upleft1_73x61,
|
||||||
|
.b = &I_black_upleft1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_upleft2_73x61,
|
||||||
|
.b = &I_black_upleft2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame right = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_right1_73x61,
|
||||||
|
.b = &I_black_right1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_right2_73x61,
|
||||||
|
.b = &I_black_right2_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_right3_73x61,
|
||||||
|
.b = &I_black_right3_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame right_up = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_rightup1_73x61,
|
||||||
|
.b = &I_black_rightup1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_rightup2_73x61,
|
||||||
|
.b = &I_black_rightup2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame right_down = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_rightdown1_73x61,
|
||||||
|
.b = &I_black_rightdown1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_rightdown2_73x61,
|
||||||
|
.b = &I_black_rightdown2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame right_left = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_rightleft1_73x61,
|
||||||
|
.b = &I_black_rightleft1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_rightleft2_73x61,
|
||||||
|
.b = &I_black_rightleft2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame down = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_down1_73x61,
|
||||||
|
.b = &I_black_down1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_down2_73x61,
|
||||||
|
.b = &I_black_down2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame down_up = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_downup1_73x61,
|
||||||
|
.b = &I_black_downup1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_downup2_73x61,
|
||||||
|
.b = &I_black_downup2_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_downup3_73x61,
|
||||||
|
.b = &I_black_downup3_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame down_left = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_downleft1_73x61,
|
||||||
|
.b = &I_black_downleft1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_downleft2_73x61,
|
||||||
|
.b = &I_black_downleft2_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_downleft3_73x61,
|
||||||
|
.b = &I_black_downleft3_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame down_right = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_downright1_73x61,
|
||||||
|
.b = &I_black_downright1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_downright2_73x61,
|
||||||
|
.b = &I_black_downright2_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_downright3_73x61,
|
||||||
|
.b = &I_black_downright3_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame left = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_left1_73x61,
|
||||||
|
.b = &I_black_left1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_left2_73x61,
|
||||||
|
.b = &I_black_left2_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_left3_73x61,
|
||||||
|
.b = &I_black_left3_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame left_up = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_leftup1_73x61,
|
||||||
|
.b = &I_black_leftup1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_leftup2_73x61,
|
||||||
|
.b = &I_black_leftup2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame left_down = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_leftdown1_73x61,
|
||||||
|
.b = &I_black_leftdown1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_leftdown2_73x61,
|
||||||
|
.b = &I_black_leftdown2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame left_right = {
|
||||||
|
.frames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.f = &I_rightleft1_73x61,
|
||||||
|
.b = &I_black_rightleft1_73x61,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.f = &I_rightleft2_73x61,
|
||||||
|
.b = &I_black_rightleft2_73x61,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.total = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
const DolphinFrame* frames[4][4] = {
|
||||||
|
[DirUp] = {[DirUp] = &up, [DirRight] = &up_right, [DirDown] = &up_down, [DirLeft] = &up_left},
|
||||||
|
[DirRight] =
|
||||||
|
{[DirUp] = &right_up, [DirRight] = &right, [DirDown] = &right_down, [DirLeft] = &right_left},
|
||||||
|
[DirDown] =
|
||||||
|
{[DirUp] = &down_up, [DirRight] = &down_right, [DirDown] = &down, [DirLeft] = &down_left},
|
||||||
|
[DirLeft] =
|
||||||
|
{[DirUp] = &left_up, [DirRight] = &left_right, [DirDown] = &left_down, [DirLeft] = &left},
|
||||||
|
};
|
||||||
@ -52,7 +52,7 @@ void scene_alloc() {
|
|||||||
|
|
||||||
// SceneAppGui
|
// SceneAppGui
|
||||||
scene_app_gui = furi_alloc(sizeof(SceneAppGui));
|
scene_app_gui = furi_alloc(sizeof(SceneAppGui));
|
||||||
scene_app_gui->mqueue = osMessageQueueNew(2, sizeof(AppEvent), NULL);
|
scene_app_gui->mqueue = osMessageQueueNew(8, sizeof(AppEvent), NULL);
|
||||||
scene_app_gui->gui = furi_record_open("gui");
|
scene_app_gui->gui = furi_record_open("gui");
|
||||||
scene_app_gui->view_port = view_port_alloc();
|
scene_app_gui->view_port = view_port_alloc();
|
||||||
scene_app_gui->timer =
|
scene_app_gui->timer =
|
||||||
@ -62,10 +62,18 @@ void scene_alloc() {
|
|||||||
SceneState* scene_state = furi_alloc(sizeof(SceneState));
|
SceneState* scene_state = furi_alloc(sizeof(SceneState));
|
||||||
scene_state->player.y = DOLPHIN_DEFAULT_Y;
|
scene_state->player.y = DOLPHIN_DEFAULT_Y;
|
||||||
scene_state->player.x = DOLPHIN_CENTER;
|
scene_state->player.x = DOLPHIN_CENTER;
|
||||||
scene_state->player_global.x = random() % WORLD_WIDTH / 4;
|
|
||||||
|
scene_state->player_global.x = 160;
|
||||||
|
scene_state->player_global.y = WORLD_HEIGHT;
|
||||||
|
|
||||||
|
scene_state->frame_group = DirRight;
|
||||||
|
scene_state->frame_type = DirRight;
|
||||||
|
scene_state->frame_pending = DirRight;
|
||||||
|
scene_state->last_group = DirRight;
|
||||||
|
|
||||||
scene_state->screen.x = scene_state->player.x;
|
scene_state->screen.x = scene_state->player.x;
|
||||||
scene_state->screen.y = scene_state->player.y;
|
scene_state->screen.y = scene_state->player.y;
|
||||||
|
// scene_state->debug = true;
|
||||||
scene_state_mutex = furi_alloc(sizeof(ValueMutex));
|
scene_state_mutex = furi_alloc(sizeof(ValueMutex));
|
||||||
furi_check(init_mutex(scene_state_mutex, scene_state, sizeof(SceneState)));
|
furi_check(init_mutex(scene_state_mutex, scene_state, sizeof(SceneState)));
|
||||||
|
|
||||||
@ -73,7 +81,7 @@ void scene_alloc() {
|
|||||||
view_port_draw_callback_set(scene_app_gui->view_port, dolphin_scene_redraw, scene_state_mutex);
|
view_port_draw_callback_set(scene_app_gui->view_port, dolphin_scene_redraw, scene_state_mutex);
|
||||||
view_port_input_callback_set(
|
view_port_input_callback_set(
|
||||||
scene_app_gui->view_port, scene_engine_input_callback, scene_app_gui->mqueue);
|
scene_app_gui->view_port, scene_engine_input_callback, scene_app_gui->mqueue);
|
||||||
gui_add_view_port(scene_app_gui->gui, scene_app_gui->view_port, GuiLayerMain);
|
gui_add_view_port(scene_app_gui->gui, scene_app_gui->view_port, GuiLayerFullscreen);
|
||||||
view_port_enabled_set(scene_app_gui->view_port, true);
|
view_port_enabled_set(scene_app_gui->view_port, true);
|
||||||
printf("scene_alloc: complete\r\n");
|
printf("scene_alloc: complete\r\n");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,26 +16,28 @@
|
|||||||
// player
|
// player
|
||||||
#define DOLPHIN_WIDTH 32
|
#define DOLPHIN_WIDTH 32
|
||||||
#define DOLPHIN_HEIGHT 32
|
#define DOLPHIN_HEIGHT 32
|
||||||
#define DOLPHIN_CENTER (SCREEN_WIDTH / 2 - DOLPHIN_WIDTH / 2)
|
#define DOLPHIN_CENTER (SCREEN_WIDTH / 2 - DOLPHIN_WIDTH)
|
||||||
#define SPEED_X 2
|
#define SPEED_X 4
|
||||||
#define ACTIONS_NUM 5
|
#define SPEED_Y 4
|
||||||
#define DOLPHIN_DEFAULT_Y 20
|
#define ACTIONS_NUM 4
|
||||||
|
#define DOLPHIN_DEFAULT_Y 2
|
||||||
|
#define MAX_FRAMES 3
|
||||||
|
|
||||||
// world
|
// world
|
||||||
#define WORLD_WIDTH 2048
|
#define WORLD_WIDTH 256
|
||||||
#define WORLD_HEIGHT 64
|
#define WORLD_HEIGHT 192
|
||||||
|
|
||||||
#define LAYERS 8
|
#define LAYERS 8
|
||||||
#define SCENE_ZOOM 9
|
|
||||||
#define DOLPHIN_LAYER 6
|
#define DOLPHIN_LAYER 6
|
||||||
#define PARALLAX_MOD 7
|
#define PARALLAX_MOD 7
|
||||||
#define PARALLAX(layer) layer / PARALLAX_MOD - layer
|
#define PARALLAX(layer) layer / PARALLAX_MOD - layer
|
||||||
|
|
||||||
#define DIALOG_PROGRESS 250
|
#define DIALOG_PROGRESS 250
|
||||||
|
|
||||||
enum Actions { SLEEP = 0, IDLE, WALK, EMOTE, INTERACT, MINDCONTROL };
|
enum Actions { IDLE = 0, EMOTE, INTERACT, MINDCONTROL };
|
||||||
|
|
||||||
static const uint16_t default_timeout[] =
|
static const uint16_t default_timeout[] =
|
||||||
{[SLEEP] = 300, [IDLE] = 100, [WALK] = 100, [EMOTE] = 50, [INTERACT] = 10, [MINDCONTROL] = 50};
|
{[IDLE] = 100, [EMOTE] = 50, [INTERACT] = 10, [MINDCONTROL] = 50};
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
EventTypeTick,
|
EventTypeTick,
|
||||||
@ -64,47 +66,60 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t layer;
|
uint8_t layer;
|
||||||
uint16_t timeout;
|
uint16_t timeout;
|
||||||
int32_t x;
|
Vec2 pos;
|
||||||
int32_t y;
|
|
||||||
const Icon* icon;
|
uint8_t width;
|
||||||
char action_name[16];
|
uint8_t height;
|
||||||
|
|
||||||
void (*draw)(Canvas* canvas, void* model);
|
void (*draw)(Canvas* canvas, void* model);
|
||||||
void (*callback)(Canvas* canvas, void* model);
|
void (*callback)(Canvas* canvas, void* model);
|
||||||
} Item;
|
} Item;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DirUp = 0,
|
||||||
|
DirRight,
|
||||||
|
DirDown,
|
||||||
|
DirLeft,
|
||||||
|
} FrameDirectionEnum;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const Icon* f;
|
||||||
|
const Icon* b;
|
||||||
|
} DolphinGfxAsset;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const DolphinGfxAsset frames[MAX_FRAMES];
|
||||||
|
const uint8_t total;
|
||||||
|
} DolphinFrame;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
///
|
|
||||||
Vec2 player;
|
Vec2 player;
|
||||||
Vec2 player_global;
|
Vec2 player_global;
|
||||||
Vec2 player_v;
|
Vec2 player_v;
|
||||||
Vec2 screen;
|
Vec2 screen;
|
||||||
|
|
||||||
const Icon* dolphin_gfx;
|
FrameDirectionEnum frame_group;
|
||||||
const Icon* dolphin_gfx_b; // temp
|
FrameDirectionEnum last_group;
|
||||||
|
FrameDirectionEnum frame_pending;
|
||||||
|
FrameDirectionEnum frame_type;
|
||||||
|
|
||||||
bool player_flipped;
|
const DolphinFrame* current_frame;
|
||||||
|
|
||||||
|
bool transition;
|
||||||
|
bool transition_pending;
|
||||||
bool use_pending;
|
bool use_pending;
|
||||||
// dolphin_scene_debug
|
|
||||||
bool debug;
|
bool debug;
|
||||||
|
|
||||||
uint8_t player_anim;
|
uint8_t player_anim;
|
||||||
uint8_t scene_id;
|
uint8_t frame_idx;
|
||||||
|
|
||||||
|
uint8_t scene_id;
|
||||||
uint8_t emote_id;
|
uint8_t emote_id;
|
||||||
uint8_t previous_emote;
|
uint8_t previous_emote;
|
||||||
|
|
||||||
uint8_t dialogue_id;
|
|
||||||
uint8_t previous_dialogue;
|
|
||||||
|
|
||||||
uint32_t action_timeout;
|
|
||||||
uint8_t poi;
|
|
||||||
|
|
||||||
uint8_t action;
|
uint8_t action;
|
||||||
uint8_t next_action;
|
|
||||||
uint8_t prev_action;
|
uint8_t prev_action;
|
||||||
|
uint8_t action_timeout;
|
||||||
int8_t zoom_v;
|
|
||||||
uint8_t scene_zoom;
|
|
||||||
uint8_t dialog_progress;
|
uint8_t dialog_progress;
|
||||||
|
|
||||||
FuriThread* scene_app_thread;
|
FuriThread* scene_app_thread;
|
||||||
|
|||||||
@ -6,43 +6,31 @@ void dolphin_scene_handle_user_input(SceneState* state, InputEvent* input) {
|
|||||||
furi_assert(state);
|
furi_assert(state);
|
||||||
furi_assert(input);
|
furi_assert(input);
|
||||||
|
|
||||||
// dolphin_scene_debug
|
state->last_group = state->frame_group;
|
||||||
if(input->type == InputTypeShort) {
|
|
||||||
if(input->key == InputKeyUp) {
|
|
||||||
state->debug = !state->debug;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// toggle mind control on any user interaction
|
|
||||||
if(input->type == InputTypePress) {
|
if(input->type == InputTypePress) {
|
||||||
if(input->key == InputKeyLeft || input->key == InputKeyRight || input->key == InputKeyOk) {
|
state->action = MINDCONTROL;
|
||||||
state->action = MINDCONTROL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// zoom poc for tests
|
|
||||||
if(input->type == InputTypePress) {
|
|
||||||
if(input->key == InputKeyDown) {
|
|
||||||
state->zoom_v = SPEED_X;
|
|
||||||
}
|
|
||||||
} else if(input->type == InputTypeRelease) {
|
|
||||||
if(input->key == InputKeyDown) {
|
|
||||||
state->zoom_v = -SPEED_X * 2;
|
|
||||||
state->dialog_progress = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// mind control
|
|
||||||
if(state->action == MINDCONTROL) {
|
if(state->action == MINDCONTROL) {
|
||||||
if(input->type == InputTypePress) {
|
if(input->type == InputTypePress) {
|
||||||
if(input->key == InputKeyRight) {
|
if(input->key == InputKeyRight) {
|
||||||
state->player_flipped = false;
|
state->player_v.y = 0;
|
||||||
state->player_v.x = SPEED_X;
|
state->player_v.x = SPEED_X;
|
||||||
} else if(input->key == InputKeyLeft) {
|
} else if(input->key == InputKeyLeft) {
|
||||||
state->player_flipped = true;
|
state->player_v.y = 0;
|
||||||
state->player_v.x = -SPEED_X;
|
state->player_v.x = -SPEED_X;
|
||||||
}
|
} else if(input->key == InputKeyUp) {
|
||||||
} else if(input->type == InputTypeRelease) {
|
|
||||||
if(input->key == InputKeyRight || input->key == InputKeyLeft) {
|
|
||||||
state->player_v.x = 0;
|
state->player_v.x = 0;
|
||||||
|
state->player_v.y = -SPEED_Y;
|
||||||
|
} else if(input->key == InputKeyDown) {
|
||||||
|
state->player_v.x = 0;
|
||||||
|
state->player_v.y = SPEED_Y;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(input->type == InputTypeRelease) {
|
||||||
|
state->player_v.x = 0;
|
||||||
|
state->player_v.y = 0;
|
||||||
} else if(input->type == InputTypeShort) {
|
} else if(input->type == InputTypeShort) {
|
||||||
if(input->key == InputKeyOk) {
|
if(input->key == InputKeyOk) {
|
||||||
state->prev_action = MINDCONTROL;
|
state->prev_action = MINDCONTROL;
|
||||||
@ -59,13 +47,14 @@ void dolphin_scene_coordinates(SceneState* state, uint32_t dt) {
|
|||||||
|
|
||||||
// global pos
|
// global pos
|
||||||
state->player_global.x = CLAMP(state->player_global.x + state->player_v.x, WORLD_WIDTH, 0);
|
state->player_global.x = CLAMP(state->player_global.x + state->player_v.x, WORLD_WIDTH, 0);
|
||||||
|
state->player_global.y = CLAMP(state->player_global.y + state->player_v.y, WORLD_HEIGHT, 0);
|
||||||
|
|
||||||
// zoom handlers
|
// nudge camera postition
|
||||||
state->scene_zoom = CLAMP(state->scene_zoom + state->zoom_v, SCENE_ZOOM, 0);
|
if(state->player_global.x > 170) {
|
||||||
state->player.x = CLAMP(state->player.x - (state->zoom_v * (SPEED_X * 2)), DOLPHIN_CENTER, 0);
|
state->player.x =
|
||||||
state->player.y = CLAMP(state->player.y - (state->zoom_v * SPEED_X / 2), DOLPHIN_DEFAULT_Y, 3);
|
CLAMP(state->player.x - state->player_v.x / 2, DOLPHIN_CENTER, -DOLPHIN_WIDTH / 2);
|
||||||
|
} else if(state->player_global.x < 70) {
|
||||||
//center screen
|
state->player.x =
|
||||||
state->screen.x = state->player_global.x - state->player.x;
|
CLAMP(state->player.x - state->player_v.x / 2, DOLPHIN_WIDTH * 2, DOLPHIN_CENTER);
|
||||||
state->player_anim = (state->player_global.x / 10) % 2;
|
}
|
||||||
}
|
}
|
||||||
@ -1,74 +1,32 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include "scene.h"
|
#include "scene.h"
|
||||||
#include "assets/emotes.h"
|
#include "assets/items.h"
|
||||||
|
|
||||||
static uint16_t roll_new(uint16_t prev, uint16_t max) {
|
|
||||||
uint16_t val = 999;
|
|
||||||
while(val != prev) {
|
|
||||||
val = random() % max;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scene_proceed_action(SceneState* state) {
|
static void scene_proceed_action(SceneState* state) {
|
||||||
furi_assert(state);
|
furi_assert(state);
|
||||||
|
|
||||||
state->prev_action = state->action;
|
state->prev_action = state->action;
|
||||||
state->action = (state->prev_action != state->next_action) ?
|
state->action = roll_new(state->prev_action, ACTIONS_NUM);
|
||||||
state->next_action :
|
|
||||||
roll_new(state->next_action, ACTIONS_NUM);
|
|
||||||
state->action_timeout = default_timeout[state->action];
|
state->action_timeout = default_timeout[state->action];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scene_dolphin_go_to_poi(SceneState* state) {
|
|
||||||
furi_assert(state);
|
|
||||||
if(state->player_global.x < state->poi) {
|
|
||||||
state->player_flipped = false;
|
|
||||||
state->player_v.x = SPEED_X / 2;
|
|
||||||
} else if(state->player_global.x > state->poi) {
|
|
||||||
state->player_flipped = true;
|
|
||||||
state->player_v.x = -SPEED_X / 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scene_action_handler(SceneState* state) {
|
static void scene_action_handler(SceneState* state) {
|
||||||
furi_assert(state);
|
furi_assert(state);
|
||||||
if(state->action == MINDCONTROL && state->player_v.x != 0) {
|
if(state->action == MINDCONTROL) {
|
||||||
state->action_timeout = default_timeout[state->action];
|
if(state->player_v.x != 0 || state->player_v.y != 0) {
|
||||||
|
state->action_timeout = default_timeout[state->action];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(state->action_timeout > 0) {
|
if(state->action_timeout > 0) {
|
||||||
state->action_timeout--;
|
state->action_timeout--;
|
||||||
} else {
|
|
||||||
if(random() % 1000 > 500) {
|
|
||||||
state->next_action = roll_new(state->prev_action, ACTIONS_NUM);
|
|
||||||
state->poi = roll_new(state->player_global.x, WORLD_WIDTH / 4);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dolphin_scene_update_state(SceneState* state, uint32_t t, uint32_t dt) {
|
void dolphin_scene_update_state(SceneState* state, uint32_t t, uint32_t dt) {
|
||||||
furi_assert(state);
|
furi_assert(state);
|
||||||
scene_action_handler(state);
|
scene_action_handler(state);
|
||||||
UNUSED(dialogues_list);
|
|
||||||
|
|
||||||
switch(state->action) {
|
switch(state->action) {
|
||||||
case WALK:
|
|
||||||
if(state->player_global.x == state->poi) {
|
|
||||||
state->player_v.x = 0;
|
|
||||||
scene_proceed_action(state);
|
|
||||||
} else {
|
|
||||||
scene_dolphin_go_to_poi(state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case EMOTE:
|
|
||||||
state->player_flipped = false;
|
|
||||||
if(state->action_timeout == 0) {
|
|
||||||
scene_proceed_action(state);
|
|
||||||
state->emote_id = roll_new(state->previous_emote, SIZEOF_ARRAY(emotes_list));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case INTERACT:
|
case INTERACT:
|
||||||
if(state->action_timeout == 0) {
|
if(state->action_timeout == 0) {
|
||||||
if(state->prev_action == MINDCONTROL) {
|
if(state->prev_action == MINDCONTROL) {
|
||||||
@ -78,20 +36,9 @@ void dolphin_scene_update_state(SceneState* state, uint32_t t, uint32_t dt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SLEEP:
|
|
||||||
if(state->poi != 154) { // temp
|
|
||||||
state->poi = 154;
|
|
||||||
} else if(state->player_global.x != state->poi) {
|
|
||||||
scene_dolphin_go_to_poi(state);
|
|
||||||
} else {
|
|
||||||
state->player_v.x = 0;
|
|
||||||
if(state->action_timeout == 0) {
|
|
||||||
state->poi = roll_new(state->player_global.x, WORLD_WIDTH / 4);
|
|
||||||
scene_proceed_action(state);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
|
|
||||||
if(state->action_timeout == 0) {
|
if(state->action_timeout == 0) {
|
||||||
scene_proceed_action(state);
|
scene_proceed_action(state);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,101 +1,46 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include "scene.h"
|
#include "scene.h"
|
||||||
#include "assets/emotes.h"
|
|
||||||
#include "assets/items.h"
|
#include "assets/items.h"
|
||||||
|
#include "assets/meta.h"
|
||||||
#include <gui/elements.h>
|
#include <gui/elements.h>
|
||||||
|
|
||||||
const char* action_str[] = {"Sleep", "Idle", "Walk", "Emote", "Use", "MC"};
|
void dolphin_scene_transition_handler(SceneState* state) {
|
||||||
|
uint8_t speed_mod = (state->player_v.x || state->player_v.y || state->transition) ? 6 : 10;
|
||||||
|
|
||||||
static void scene_draw_hint(SceneState* state, Canvas* canvas, bool glitching) {
|
if(state->player_v.x < 0) {
|
||||||
furi_assert(state);
|
state->frame_pending = DirLeft;
|
||||||
furi_assert(canvas);
|
} else if(state->player_v.x > 0) {
|
||||||
char buf[32];
|
state->frame_pending = DirRight;
|
||||||
|
} else if(state->player_v.y < 0) {
|
||||||
const Item* near = is_nearby(state);
|
state->frame_pending = DirUp;
|
||||||
if(near) {
|
} else if(state->player_v.y > 0) {
|
||||||
int32_t hint_pos_x = (near->x - state->player_global.x) * PARALLAX(near->layer) + 25;
|
state->frame_pending = DirDown;
|
||||||
int8_t hint_pos_y = near->y < 15 ? near->y + 4 : near->y - 16;
|
|
||||||
|
|
||||||
strcpy(buf, near->action_name);
|
|
||||||
if(glitching) {
|
|
||||||
for(size_t g = 0; g != state->action_timeout; g++) {
|
|
||||||
buf[(g * 23) % strlen(buf)] = ' ' + (random() % g * 17) % ('z' - ' ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_draw_str(canvas, hint_pos_x, hint_pos_y, buf);
|
|
||||||
}
|
}
|
||||||
}
|
state->transition_pending = state->frame_group != state->frame_pending;
|
||||||
|
|
||||||
static void scene_draw_current_emote(SceneState* state, Canvas* canvas) {
|
if(*&frames[state->frame_group][state->frame_type]->frames[state->frame_idx].f) {
|
||||||
furi_assert(state);
|
state->current_frame = *&frames[state->frame_group][state->frame_type];
|
||||||
furi_assert(canvas);
|
}
|
||||||
elements_multiline_text_framed(canvas, 80, 20, (char*)emotes_list[state->emote_id]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scene_draw_sleep_emote(SceneState* state, Canvas* canvas) {
|
uint8_t total = state->current_frame->frames[2].f == NULL ? 2 : 3;
|
||||||
furi_assert(state);
|
|
||||||
furi_assert(canvas);
|
|
||||||
|
|
||||||
char dialog_str[] = "zZzZ..";
|
if(state->transition_pending && !state->frame_idx) {
|
||||||
// 2do - sofa x pos getter
|
state->transition_pending = false;
|
||||||
if(state->player_global.x == 154 && state->action_timeout % 100 < 50) {
|
state->transition = true;
|
||||||
if(state->dialog_progress < strlen(dialog_str)) {
|
}
|
||||||
if(state->action_timeout % 10 == 0) state->dialog_progress++;
|
|
||||||
|
|
||||||
dialog_str[state->dialog_progress + 1] = '\0';
|
|
||||||
canvas_draw_str(canvas, 80, 20, dialog_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if(state->transition) {
|
||||||
|
state->frame_type = state->frame_pending;
|
||||||
|
state->frame_group = state->last_group;
|
||||||
|
state->transition = !(state->frame_idx == total - 1);
|
||||||
} else {
|
} else {
|
||||||
state->dialog_progress = 0;
|
state->frame_group = state->frame_type;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void scene_draw_dialog(SceneState* state, Canvas* canvas) {
|
|
||||||
furi_assert(state);
|
|
||||||
furi_assert(canvas);
|
|
||||||
|
|
||||||
char dialog_str[64];
|
|
||||||
char buf[64];
|
|
||||||
|
|
||||||
strcpy(dialog_str, (char*)dialogues_list[state->dialogue_id]);
|
|
||||||
|
|
||||||
if(state->dialog_progress <= strlen(dialog_str)) {
|
|
||||||
if(state->action_timeout % 2 == 0) state->dialog_progress++;
|
|
||||||
dialog_str[state->dialog_progress] = '\0';
|
|
||||||
snprintf(buf, state->dialog_progress, dialog_str);
|
|
||||||
} else {
|
|
||||||
snprintf(buf, 64, dialog_str);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
elements_multiline_text_framed(canvas, 68, 16, buf);
|
state->player_anim++;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
if(!(state->player_anim % speed_mod)) {
|
||||||
static void draw_idle_emote(SceneState* state, Canvas* canvas){
|
state->frame_idx = (state->frame_idx + 1) % total;
|
||||||
if(state->action_timeout % 50 < 40 && state->prev_action == MINDCONTROL){
|
|
||||||
elements_multiline_text_framed(canvas, 68, 16, "WUT?!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static void draw_idle_emote(SceneState* state, Canvas* canvas) {
|
|
||||||
furi_assert(state);
|
|
||||||
furi_assert(canvas);
|
|
||||||
|
|
||||||
char dialog_str[] = "...";
|
|
||||||
|
|
||||||
if(state->action_timeout % 100 < 50) {
|
|
||||||
if(state->dialog_progress < strlen(dialog_str)) {
|
|
||||||
if(state->action_timeout % 10 == 0) state->dialog_progress++;
|
|
||||||
|
|
||||||
dialog_str[state->dialog_progress + 1] = '\0';
|
|
||||||
canvas_draw_str(canvas, 70, 15, dialog_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
state->dialog_progress = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,44 +48,24 @@ void dolphin_scene_render_dolphin(SceneState* state, Canvas* canvas) {
|
|||||||
furi_assert(state);
|
furi_assert(state);
|
||||||
furi_assert(canvas);
|
furi_assert(canvas);
|
||||||
|
|
||||||
if(state->scene_zoom == SCENE_ZOOM) {
|
dolphin_scene_transition_handler(state);
|
||||||
state->dolphin_gfx = &I_DolphinExcited_64x63;
|
|
||||||
} else if(state->action == SLEEP && state->player_global.x == 154) { // 2do - sofa x pos getter
|
|
||||||
state->dolphin_gfx = &A_FX_Sitting_40x27;
|
|
||||||
state->dolphin_gfx_b = &I_FX_SittingB_40x27;
|
|
||||||
} else if(state->action != INTERACT) {
|
|
||||||
if(state->player_v.x < 0 || state->player_flipped) {
|
|
||||||
if(state->player_anim == 0) {
|
|
||||||
state->dolphin_gfx = &I_WalkL1_32x32;
|
|
||||||
state->dolphin_gfx_b = &I_WalkLB1_32x32;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
state->dolphin_gfx = &I_WalkL2_32x32;
|
|
||||||
state->dolphin_gfx_b = &I_WalkLB2_32x32;
|
|
||||||
}
|
|
||||||
} else if(state->player_v.x > 0 || !state->player_flipped) {
|
|
||||||
if(state->player_anim == 0) {
|
|
||||||
state->dolphin_gfx = &I_WalkR1_32x32;
|
|
||||||
state->dolphin_gfx_b = &I_WalkRB1_32x32;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
state->dolphin_gfx = &I_WalkR2_32x32;
|
|
||||||
state->dolphin_gfx_b = &I_WalkRB2_32x32;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_set_bitmap_mode(canvas, true);
|
canvas_set_bitmap_mode(canvas, true);
|
||||||
canvas_set_color(canvas, ColorWhite);
|
canvas_set_color(canvas, ColorWhite);
|
||||||
canvas_draw_icon(canvas, state->player.x, state->player.y, state->dolphin_gfx_b);
|
canvas_draw_icon(
|
||||||
|
canvas, state->player.x, state->player.y, state->current_frame->frames[state->frame_idx].b);
|
||||||
canvas_set_color(canvas, ColorBlack);
|
canvas_set_color(canvas, ColorBlack);
|
||||||
canvas_draw_icon(canvas, state->player.x, state->player.y, state->dolphin_gfx);
|
canvas_draw_icon(
|
||||||
|
canvas, state->player.x, state->player.y, state->current_frame->frames[state->frame_idx].f);
|
||||||
canvas_set_bitmap_mode(canvas, false);
|
canvas_set_bitmap_mode(canvas, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool item_screen_bounds(int32_t pos) {
|
static bool item_screen_bounds_x(int32_t pos) {
|
||||||
return pos > -SCREEN_WIDTH && pos < (SCREEN_WIDTH * 2);
|
return pos > -SCREEN_WIDTH && pos < (SCREEN_WIDTH * 2);
|
||||||
}
|
}
|
||||||
|
static bool item_screen_bounds_y(int32_t pos) {
|
||||||
|
return pos > -SCREEN_HEIGHT * 2 && pos < (SCREEN_HEIGHT * 2);
|
||||||
|
}
|
||||||
|
|
||||||
void dolphin_scene_render(SceneState* state, Canvas* canvas, uint32_t t) {
|
void dolphin_scene_render(SceneState* state, Canvas* canvas, uint32_t t) {
|
||||||
furi_assert(state);
|
furi_assert(state);
|
||||||
@ -151,24 +76,17 @@ void dolphin_scene_render(SceneState* state, Canvas* canvas, uint32_t t) {
|
|||||||
const Item** current_scene = get_scene(state);
|
const Item** current_scene = get_scene(state);
|
||||||
|
|
||||||
for(uint8_t l = 0; l < LAYERS; l++) {
|
for(uint8_t l = 0; l < LAYERS; l++) {
|
||||||
if(state->scene_zoom < SCENE_ZOOM) {
|
for(uint8_t i = 0; i < ItemsEnumTotal; i++) {
|
||||||
for(uint8_t i = 0; i < ITEMS_NUM; i++) {
|
int32_t item_pos_X = (current_scene[i]->pos.x - state->player_global.x);
|
||||||
int32_t item_pos = (current_scene[i]->x - state->player_global.x);
|
int32_t item_pos_Y = (current_scene[i]->pos.y - state->player_global.y);
|
||||||
if(item_screen_bounds(item_pos)) {
|
|
||||||
if(current_scene[i]->draw) current_scene[i]->draw(canvas, state);
|
|
||||||
|
|
||||||
if(l == current_scene[i]->layer) {
|
if(item_screen_bounds_x(item_pos_X) && item_screen_bounds_y(item_pos_Y)) {
|
||||||
canvas_draw_icon(
|
if(l == current_scene[i]->layer) {
|
||||||
canvas,
|
if(current_scene[i]->draw) {
|
||||||
item_pos * PARALLAX(l),
|
current_scene[i]->draw(canvas, state);
|
||||||
current_scene[i]->y,
|
|
||||||
current_scene[i]->icon);
|
|
||||||
canvas_set_bitmap_mode(canvas, false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(l == 0) canvas_draw_line(canvas, 0, 42, 128, 42);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(l == DOLPHIN_LAYER) dolphin_scene_render_dolphin(state, canvas);
|
if(l == DOLPHIN_LAYER) dolphin_scene_render_dolphin(state, canvas);
|
||||||
@ -188,24 +106,16 @@ void dolphin_scene_render_state(SceneState* state, Canvas* canvas) {
|
|||||||
if(state->debug) {
|
if(state->debug) {
|
||||||
sprintf(
|
sprintf(
|
||||||
buf,
|
buf,
|
||||||
"x:%ld>%d %ld %s",
|
"%d:%d %d/%dP%dL%d T%d-%d",
|
||||||
state->player_global.x,
|
state->frame_idx,
|
||||||
state->poi,
|
state->current_frame->frames[2].f == NULL ? 2 : 3,
|
||||||
state->action_timeout,
|
state->frame_group,
|
||||||
action_str[state->action]);
|
state->frame_type,
|
||||||
|
state->frame_pending,
|
||||||
|
state->last_group,
|
||||||
|
state->transition_pending,
|
||||||
|
state->transition);
|
||||||
canvas_draw_str(canvas, 0, 13, buf);
|
canvas_draw_str(canvas, 0, 13, buf);
|
||||||
}
|
}
|
||||||
|
if(state->action == INTERACT) scene_activate_item_callback(state, canvas);
|
||||||
if(state->scene_zoom == SCENE_ZOOM)
|
|
||||||
scene_draw_dialog(state, canvas);
|
|
||||||
else if(state->action == EMOTE)
|
|
||||||
scene_draw_current_emote(state, canvas);
|
|
||||||
else if(state->action == MINDCONTROL)
|
|
||||||
scene_draw_hint(state, canvas, state->action_timeout > 45);
|
|
||||||
else if(state->action == INTERACT)
|
|
||||||
scene_activate_item_callback(state, canvas);
|
|
||||||
else if(state->action == SLEEP)
|
|
||||||
scene_draw_sleep_emote(state, canvas);
|
|
||||||
else if(state->action == IDLE)
|
|
||||||
draw_idle_emote(state, canvas);
|
|
||||||
}
|
}
|
||||||
@ -192,7 +192,8 @@ int32_t gui_test(void* param) {
|
|||||||
text_input_callback,
|
text_input_callback,
|
||||||
gui_tester,
|
gui_tester,
|
||||||
text_input_text,
|
text_input_text,
|
||||||
text_input_text_len);
|
text_input_text_len,
|
||||||
|
false);
|
||||||
text_input_set_header_text(gui_tester->text_input, "Name the key");
|
text_input_set_header_text(gui_tester->text_input, "Name the key");
|
||||||
|
|
||||||
const uint8_t byte_input_bytes_len = 16;
|
const uint8_t byte_input_bytes_len = 16;
|
||||||
|
|||||||
23
applications/gui/modules/text_input.c
Normal file → Executable file
@ -16,6 +16,7 @@ typedef struct {
|
|||||||
const char* header;
|
const char* header;
|
||||||
char* text_buffer;
|
char* text_buffer;
|
||||||
size_t text_buffer_size;
|
size_t text_buffer_size;
|
||||||
|
bool clear_default_text;
|
||||||
|
|
||||||
TextInputCallback callback;
|
TextInputCallback callback;
|
||||||
void* callback_context;
|
void* callback_context;
|
||||||
@ -128,7 +129,7 @@ static const char char_to_uppercase(const char letter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void text_input_backspace_cb(TextInputModel* model) {
|
static void text_input_backspace_cb(TextInputModel* model) {
|
||||||
uint8_t text_length = strlen(model->text_buffer);
|
uint8_t text_length = model->clear_default_text ? 1 : strlen(model->text_buffer);
|
||||||
if(text_length > 0) {
|
if(text_length > 0) {
|
||||||
model->text_buffer[text_length - 1] = 0;
|
model->text_buffer[text_length - 1] = 0;
|
||||||
}
|
}
|
||||||
@ -158,11 +159,16 @@ static void text_input_view_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
text++;
|
text++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(model->clear_default_text) {
|
||||||
|
elements_slightly_rounded_box(
|
||||||
|
canvas, start_pos - 1, 14, canvas_string_width(canvas, text) + 2, 10);
|
||||||
|
canvas_set_color(canvas, ColorWhite);
|
||||||
|
} else {
|
||||||
|
canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 1, 22, "|");
|
||||||
|
canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 2, 22, "|");
|
||||||
|
}
|
||||||
canvas_draw_str(canvas, start_pos, 22, text);
|
canvas_draw_str(canvas, start_pos, 22, text);
|
||||||
|
|
||||||
canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 1, 22, "|");
|
|
||||||
canvas_draw_str(canvas, start_pos + canvas_string_width(canvas, text) + 2, 22, "|");
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontKeyboard);
|
canvas_set_font(canvas, FontKeyboard);
|
||||||
|
|
||||||
for(uint8_t row = 0; row <= keyboard_row_count; row++) {
|
for(uint8_t row = 0; row <= keyboard_row_count; row++) {
|
||||||
@ -295,12 +301,16 @@ static void text_input_handle_ok(TextInput* text_input) {
|
|||||||
} else if(selected == BACKSPACE_KEY) {
|
} else if(selected == BACKSPACE_KEY) {
|
||||||
text_input_backspace_cb(model);
|
text_input_backspace_cb(model);
|
||||||
} else if(text_length < (model->text_buffer_size - 1)) {
|
} else if(text_length < (model->text_buffer_size - 1)) {
|
||||||
|
if(model->clear_default_text) {
|
||||||
|
text_length = 0;
|
||||||
|
}
|
||||||
if(text_length == 0 && char_is_lowercase(selected)) {
|
if(text_length == 0 && char_is_lowercase(selected)) {
|
||||||
selected = char_to_uppercase(selected);
|
selected = char_to_uppercase(selected);
|
||||||
}
|
}
|
||||||
model->text_buffer[text_length] = selected;
|
model->text_buffer[text_length] = selected;
|
||||||
model->text_buffer[text_length + 1] = 0;
|
model->text_buffer[text_length + 1] = 0;
|
||||||
}
|
}
|
||||||
|
model->clear_default_text = false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -365,6 +375,7 @@ TextInput* text_input_alloc() {
|
|||||||
model->header = "";
|
model->header = "";
|
||||||
model->selected_row = 0;
|
model->selected_row = 0;
|
||||||
model->selected_column = 0;
|
model->selected_column = 0;
|
||||||
|
model->clear_default_text = false;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -387,13 +398,15 @@ void text_input_set_result_callback(
|
|||||||
TextInputCallback callback,
|
TextInputCallback callback,
|
||||||
void* callback_context,
|
void* callback_context,
|
||||||
char* text_buffer,
|
char* text_buffer,
|
||||||
size_t text_buffer_size) {
|
size_t text_buffer_size,
|
||||||
|
bool clear_default_text) {
|
||||||
with_view_model(
|
with_view_model(
|
||||||
text_input->view, (TextInputModel * model) {
|
text_input->view, (TextInputModel * model) {
|
||||||
model->callback = callback;
|
model->callback = callback;
|
||||||
model->callback_context = callback_context;
|
model->callback_context = callback_context;
|
||||||
model->text_buffer = text_buffer;
|
model->text_buffer = text_buffer;
|
||||||
model->text_buffer_size = text_buffer_size;
|
model->text_buffer_size = text_buffer_size;
|
||||||
|
model->clear_default_text = clear_default_text;
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,13 +39,15 @@ View* text_input_get_view(TextInput* text_input);
|
|||||||
* @param callback_context - callback context
|
* @param callback_context - callback context
|
||||||
* @param text_buffer - pointer to YOUR text buffer, that we going to modify
|
* @param text_buffer - pointer to YOUR text buffer, that we going to modify
|
||||||
* @param text_buffer_size - YOUR text buffer size in bytes. Max string length will be text_buffer_size - 1.
|
* @param text_buffer_size - YOUR text buffer size in bytes. Max string length will be text_buffer_size - 1.
|
||||||
|
* @param clear_default_text - clear text from text_buffer on first OK event
|
||||||
*/
|
*/
|
||||||
void text_input_set_result_callback(
|
void text_input_set_result_callback(
|
||||||
TextInput* text_input,
|
TextInput* text_input,
|
||||||
TextInputCallback callback,
|
TextInputCallback callback,
|
||||||
void* callback_context,
|
void* callback_context,
|
||||||
char* text_buffer,
|
char* text_buffer,
|
||||||
size_t text_buffer_size);
|
size_t text_buffer_size,
|
||||||
|
bool clear_default_text);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set text input header text
|
* @brief Set text input header text
|
||||||
|
|||||||
@ -53,11 +53,11 @@ bool scene_manager_handle_custom_event(SceneManager* scene_manager, uint32_t cus
|
|||||||
scene_manager->context, event);
|
scene_manager->context, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool scene_manager_handle_navigation_event(SceneManager* scene_manager) {
|
bool scene_manager_handle_back_event(SceneManager* scene_manager) {
|
||||||
furi_assert(scene_manager);
|
furi_assert(scene_manager);
|
||||||
|
|
||||||
SceneManagerEvent event = {
|
SceneManagerEvent event = {
|
||||||
.type = SceneManagerEventTypeNavigation,
|
.type = SceneManagerEventTypeBack,
|
||||||
};
|
};
|
||||||
uint32_t scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
|
uint32_t scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
|
||||||
bool consumed =
|
bool consumed =
|
||||||
@ -109,7 +109,9 @@ bool scene_manager_previous_scene(SceneManager* scene_manager) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool scene_manager_search_previous_scene(SceneManager* scene_manager, uint32_t scene_id) {
|
bool scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
SceneManager* scene_manager,
|
||||||
|
uint32_t scene_id) {
|
||||||
furi_assert(scene_manager);
|
furi_assert(scene_manager);
|
||||||
|
|
||||||
uint32_t prev_scene_id = 0;
|
uint32_t prev_scene_id = 0;
|
||||||
@ -137,3 +139,45 @@ bool scene_manager_search_previous_scene(SceneManager* scene_manager, uint32_t s
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool scene_manager_has_previous_scene(SceneManager* scene_manager, uint32_t scene_id) {
|
||||||
|
furi_assert(scene_manager);
|
||||||
|
bool scene_found = false;
|
||||||
|
uint32_t prev_scene_id;
|
||||||
|
SceneManagerIdStack_it_t scene_it;
|
||||||
|
SceneManagerIdStack_it_last(scene_it, scene_manager->scene_id_stack);
|
||||||
|
|
||||||
|
// Perform search in scene stack
|
||||||
|
while(!scene_found) {
|
||||||
|
SceneManagerIdStack_previous(scene_it);
|
||||||
|
if(SceneManagerIdStack_end_p(scene_it)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
prev_scene_id = *SceneManagerIdStack_ref(scene_it);
|
||||||
|
if(prev_scene_id == scene_id) {
|
||||||
|
scene_found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scene_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool scene_manager_search_and_switch_to_another_scene(
|
||||||
|
SceneManager* scene_manager,
|
||||||
|
uint32_t scene_id) {
|
||||||
|
furi_assert(scene_manager);
|
||||||
|
furi_assert(scene_id < scene_manager->scene_handlers->scene_num);
|
||||||
|
|
||||||
|
uint32_t cur_scene_id = *SceneManagerIdStack_back(scene_manager->scene_id_stack);
|
||||||
|
SceneManagerIdStack_it_t scene_it;
|
||||||
|
SceneManagerIdStack_it(scene_it, scene_manager->scene_id_stack);
|
||||||
|
SceneManagerIdStack_next(scene_it);
|
||||||
|
// Remove all scene id from navigation stack until first scene
|
||||||
|
SceneManagerIdStack_pop_until(scene_manager->scene_id_stack, scene_it);
|
||||||
|
// Add next scene
|
||||||
|
SceneManagerIdStack_push_back(scene_manager->scene_id_stack, scene_id);
|
||||||
|
|
||||||
|
scene_manager->scene_handlers->on_exit_handlers[cur_scene_id](scene_manager->context);
|
||||||
|
scene_manager->scene_handlers->on_enter_handlers[scene_id](scene_manager->context);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ extern "C" {
|
|||||||
*/
|
*/
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SceneManagerEventTypeCustom,
|
SceneManagerEventTypeCustom,
|
||||||
SceneManagerEventTypeNavigation,
|
SceneManagerEventTypeBack,
|
||||||
SceneManagerEventTypeTick,
|
SceneManagerEventTypeTick,
|
||||||
} SceneManagerEventType;
|
} SceneManagerEventType;
|
||||||
|
|
||||||
@ -78,12 +78,12 @@ void scene_manager_free(SceneManager* scene_manager);
|
|||||||
*/
|
*/
|
||||||
bool scene_manager_handle_custom_event(SceneManager* scene_manager, uint32_t custom_event);
|
bool scene_manager_handle_custom_event(SceneManager* scene_manager, uint32_t custom_event);
|
||||||
|
|
||||||
/** Navigation event handler
|
/** Back event handler
|
||||||
* Calls Scene event handler with Navigation event parameter
|
* Calls Scene event handler with Back event parameter
|
||||||
* @param scene_manager SceneManager instance
|
* @param scene_manager SceneManager instance
|
||||||
* @return true if event was consumed, false otherwise
|
* @return true if event was consumed, false otherwise
|
||||||
*/
|
*/
|
||||||
bool scene_manager_handle_navigation_event(SceneManager* scene_manager);
|
bool scene_manager_handle_back_event(SceneManager* scene_manager);
|
||||||
|
|
||||||
/** Tick event handler
|
/** Tick event handler
|
||||||
* Calls Scene event handler with Tick event parameter
|
* Calls Scene event handler with Tick event parameter
|
||||||
@ -104,12 +104,30 @@ void scene_manager_next_scene(SceneManager* scene_manager, uint32_t next_scene_i
|
|||||||
*/
|
*/
|
||||||
bool scene_manager_previous_scene(SceneManager* scene_manager);
|
bool scene_manager_previous_scene(SceneManager* scene_manager);
|
||||||
|
|
||||||
/** Search previous Scene by ID
|
/** Search previous Scene
|
||||||
* @param scene_manager SceneManager instance
|
* @param scene_manager SceneManager instance
|
||||||
* @param scene_id Scene ID
|
* @param scene_id Scene ID
|
||||||
* @return true if previous scene was found, false otherwise
|
* @return true if previous scene was found, false otherwise
|
||||||
*/
|
*/
|
||||||
bool scene_manager_search_previous_scene(SceneManager* scene_manager, uint32_t scene_id);
|
bool scene_manager_has_previous_scene(SceneManager* scene_manager, uint32_t scene_id);
|
||||||
|
|
||||||
|
/** Search and switch to previous Scene
|
||||||
|
* @param scene_manager SceneManager instance
|
||||||
|
* @param scene_id Scene ID
|
||||||
|
* @return true if previous scene was found, false otherwise
|
||||||
|
*/
|
||||||
|
bool scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
SceneManager* scene_manager,
|
||||||
|
uint32_t scene_id);
|
||||||
|
|
||||||
|
/** Clear Scene stack and switch to another Scene
|
||||||
|
* @param scene_manager SceneManager instance
|
||||||
|
* @param scene_id Scene ID
|
||||||
|
* @return true if previous scene was found, false otherwise
|
||||||
|
*/
|
||||||
|
bool scene_manager_search_and_switch_to_another_scene(
|
||||||
|
SceneManager* scene_manager,
|
||||||
|
uint32_t scene_id);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
#include <callback-connector.h>
|
#include <callback-connector.h>
|
||||||
#include <m-string.h>
|
#include <m-string.h>
|
||||||
#include <file-worker-cpp.h>
|
#include <file-worker-cpp.h>
|
||||||
#include <path.h>
|
#include <lib/toolbox/path.h>
|
||||||
|
|
||||||
const char* iButtonApp::app_folder = "/any/ibutton";
|
const char* iButtonApp::app_folder = "/any/ibutton";
|
||||||
const char* iButtonApp::app_extension = ".ibtn";
|
const char* iButtonApp::app_extension = ".ibtn";
|
||||||
@ -40,9 +40,6 @@ iButtonApp::iButtonApp()
|
|||||||
: notification{"notification"} {
|
: notification{"notification"} {
|
||||||
api_hal_power_insomnia_enter();
|
api_hal_power_insomnia_enter();
|
||||||
key_worker = new KeyWorker(&ibutton_gpio);
|
key_worker = new KeyWorker(&ibutton_gpio);
|
||||||
|
|
||||||
// we need random
|
|
||||||
srand(DWT->CYCCNT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iButtonApp::~iButtonApp() {
|
iButtonApp::~iButtonApp() {
|
||||||
@ -186,38 +183,6 @@ uint8_t iButtonApp::get_text_store_size() {
|
|||||||
return text_store_size;
|
return text_store_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void iButtonApp::generate_random_name(char* name, uint8_t max_name_size) {
|
|
||||||
const uint8_t prefix_size = 9;
|
|
||||||
const char* prefix[prefix_size] = {
|
|
||||||
"ancient",
|
|
||||||
"hollow",
|
|
||||||
"strange",
|
|
||||||
"disappeared",
|
|
||||||
"unknown",
|
|
||||||
"unthinkable",
|
|
||||||
"unnamable",
|
|
||||||
"nameless",
|
|
||||||
"my",
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t suffix_size = 8;
|
|
||||||
const char* suffix[suffix_size] = {
|
|
||||||
"door",
|
|
||||||
"entrance",
|
|
||||||
"doorway",
|
|
||||||
"entry",
|
|
||||||
"portal",
|
|
||||||
"entree",
|
|
||||||
"opening",
|
|
||||||
"crack",
|
|
||||||
};
|
|
||||||
|
|
||||||
sniprintf(
|
|
||||||
name, max_name_size, "%s_%s", prefix[rand() % prefix_size], suffix[rand() % suffix_size]);
|
|
||||||
// to upper
|
|
||||||
name[0] = name[0] - 0x20;
|
|
||||||
}
|
|
||||||
|
|
||||||
// file managment
|
// file managment
|
||||||
bool iButtonApp::save_key(const char* key_name) {
|
bool iButtonApp::save_key(const char* key_name) {
|
||||||
// Create ibutton directory if necessary
|
// Create ibutton directory if necessary
|
||||||
|
|||||||
@ -90,8 +90,6 @@ public:
|
|||||||
char* get_file_name();
|
char* get_file_name();
|
||||||
uint8_t get_file_name_size();
|
uint8_t get_file_name_size();
|
||||||
|
|
||||||
void generate_random_name(char* name, uint8_t max_name_size);
|
|
||||||
|
|
||||||
bool save_key(const char* key_name);
|
bool save_key(const char* key_name);
|
||||||
bool load_key();
|
bool load_key();
|
||||||
bool load_key(const char* key_name);
|
bool load_key(const char* key_name);
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#include <api-hal.h>
|
#include <api-hal.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <cli/cli.h>
|
#include <cli/cli.h>
|
||||||
#include <args.h>
|
#include <lib/toolbox/args.h>
|
||||||
|
|
||||||
#include "helpers/key-info.h"
|
#include "helpers/key-info.h"
|
||||||
#include "helpers/key-worker.h"
|
#include "helpers/key-worker.h"
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "../ibutton-event.h"
|
#include "../ibutton-event.h"
|
||||||
#include "../ibutton-key.h"
|
#include "../ibutton-key.h"
|
||||||
#include <callback-connector.h>
|
#include <callback-connector.h>
|
||||||
|
#include <lib/toolbox/random_name.h>
|
||||||
|
|
||||||
void iButtonSceneSaveName::on_enter(iButtonApp* app) {
|
void iButtonSceneSaveName::on_enter(iButtonApp* app) {
|
||||||
iButtonAppViewManager* view_manager = app->get_view_manager();
|
iButtonAppViewManager* view_manager = app->get_view_manager();
|
||||||
@ -12,16 +13,17 @@ void iButtonSceneSaveName::on_enter(iButtonApp* app) {
|
|||||||
|
|
||||||
iButtonKey* key = app->get_key();
|
iButtonKey* key = app->get_key();
|
||||||
const char* key_name = key->get_name();
|
const char* key_name = key->get_name();
|
||||||
|
bool key_name_empty = !strcmp(key_name, "");
|
||||||
|
|
||||||
if(strcmp(key_name, "") == 0) {
|
if(key_name_empty) {
|
||||||
app->generate_random_name(app->get_text_store(), app->get_text_store_size());
|
set_random_name(app->get_text_store(), app->get_text_store_size());
|
||||||
} else {
|
} else {
|
||||||
app->set_text_store("%s", key_name);
|
app->set_text_store("%s", key_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
text_input_set_header_text(text_input, "Name the key");
|
text_input_set_header_text(text_input, "Name the key");
|
||||||
text_input_set_result_callback(
|
text_input_set_result_callback(
|
||||||
text_input, callback, app, app->get_text_store(), IBUTTON_KEY_NAME_SIZE);
|
text_input, callback, app, app->get_text_store(), IBUTTON_KEY_NAME_SIZE, key_name_empty);
|
||||||
|
|
||||||
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewTextInput);
|
view_manager->switch_to(iButtonAppViewManager::Type::iButtonAppViewTextInput);
|
||||||
}
|
}
|
||||||
@ -47,7 +49,7 @@ bool iButtonSceneSaveName::on_event(iButtonApp* app, iButtonEvent* event) {
|
|||||||
void iButtonSceneSaveName::on_exit(iButtonApp* app) {
|
void iButtonSceneSaveName::on_exit(iButtonApp* app) {
|
||||||
TextInput* text_input = app->get_view_manager()->get_text_input();
|
TextInput* text_input = app->get_view_manager()->get_text_input();
|
||||||
text_input_set_header_text(text_input, "");
|
text_input_set_header_text(text_input, "");
|
||||||
text_input_set_result_callback(text_input, NULL, NULL, NULL, 0);
|
text_input_set_result_callback(text_input, NULL, NULL, NULL, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void iButtonSceneSaveName::text_input_callback(void* context) {
|
void iButtonSceneSaveName::text_input_callback(void* context) {
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <m-string.h>
|
#include <m-string.h>
|
||||||
#include <irda_transmit.h>
|
#include <irda_transmit.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) {
|
static void signal_received_callback(void* context, IrdaWorkerSignal* received_signal) {
|
||||||
furi_assert(received_signal);
|
furi_assert(received_signal);
|
||||||
@ -47,7 +48,7 @@ static void signal_received_callback(void* context, IrdaWorkerSignal* received_s
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void irda_cli_start_ir_rx(Cli* cli, string_t args, void* context) {
|
static void irda_cli_start_ir_rx(Cli* cli, string_t args, void* context) {
|
||||||
if(api_hal_irda_rx_irq_is_busy()) {
|
if(api_hal_irda_is_busy()) {
|
||||||
printf("IRDA is busy. Exit.");
|
printf("IRDA is busy. Exit.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -105,7 +106,7 @@ static bool parse_signal_raw(
|
|||||||
uint32_t* timings,
|
uint32_t* timings,
|
||||||
uint32_t* timings_cnt,
|
uint32_t* timings_cnt,
|
||||||
float* duty_cycle,
|
float* duty_cycle,
|
||||||
float* frequency) {
|
uint32_t* frequency) {
|
||||||
char frequency_str[10];
|
char frequency_str[10];
|
||||||
char duty_cycle_str[10];
|
char duty_cycle_str[10];
|
||||||
int parsed = sscanf(str, "RAW F:%9s DC:%9s", frequency_str, duty_cycle_str);
|
int parsed = sscanf(str, "RAW F:%9s DC:%9s", frequency_str, duty_cycle_str);
|
||||||
@ -141,14 +142,14 @@ static bool parse_signal_raw(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) {
|
static void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) {
|
||||||
if(api_hal_irda_rx_irq_is_busy()) {
|
if(api_hal_irda_is_busy()) {
|
||||||
printf("IRDA is busy. Exit.");
|
printf("IRDA is busy. Exit.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
IrdaMessage message;
|
IrdaMessage message;
|
||||||
const char* str = string_get_cstr(args);
|
const char* str = string_get_cstr(args);
|
||||||
float frequency;
|
uint32_t frequency;
|
||||||
float duty_cycle;
|
float duty_cycle;
|
||||||
uint32_t* timings = (uint32_t*)furi_alloc(sizeof(uint32_t) * 1000);
|
uint32_t* timings = (uint32_t*)furi_alloc(sizeof(uint32_t) * 1000);
|
||||||
uint32_t timings_cnt = 1000;
|
uint32_t timings_cnt = 1000;
|
||||||
@ -156,7 +157,7 @@ static void irda_cli_start_ir_tx(Cli* cli, string_t args, void* context) {
|
|||||||
if(parse_message(str, &message)) {
|
if(parse_message(str, &message)) {
|
||||||
irda_send(&message, 1);
|
irda_send(&message, 1);
|
||||||
} else if(parse_signal_raw(str, timings, &timings_cnt, &duty_cycle, &frequency)) {
|
} else if(parse_signal_raw(str, timings, &timings_cnt, &duty_cycle, &frequency)) {
|
||||||
irda_send_raw_ext(timings, timings_cnt, true, duty_cycle, frequency);
|
irda_send_raw_ext(timings, timings_cnt, true, frequency, duty_cycle);
|
||||||
} else {
|
} else {
|
||||||
printf("Wrong arguments.\r\n");
|
printf("Wrong arguments.\r\n");
|
||||||
irda_cli_print_usage();
|
irda_cli_print_usage();
|
||||||
|
|||||||
@ -20,7 +20,8 @@ void IrdaAppSceneEditRename::on_enter(IrdaApp* app) {
|
|||||||
IrdaApp::text_input_callback,
|
IrdaApp::text_input_callback,
|
||||||
app,
|
app,
|
||||||
app->get_text_store(0),
|
app->get_text_store(0),
|
||||||
app->get_text_store_size());
|
app->get_text_store_size(),
|
||||||
|
false);
|
||||||
|
|
||||||
view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput);
|
view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,8 @@ void IrdaAppSceneLearnEnterName::on_enter(IrdaApp* app) {
|
|||||||
IrdaApp::text_input_callback,
|
IrdaApp::text_input_callback,
|
||||||
app,
|
app,
|
||||||
app->get_text_store(0),
|
app->get_text_store(0),
|
||||||
app->get_text_store_size());
|
app->get_text_store_size(),
|
||||||
|
false);
|
||||||
|
|
||||||
view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput);
|
view_manager->switch_to(IrdaAppViewManager::ViewType::TextInput);
|
||||||
}
|
}
|
||||||
|
|||||||
15
applications/lfrfid/helpers/decoder-gpio-out.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "decoder-gpio-out.h"
|
||||||
|
#include <furi.h>
|
||||||
|
#include <api-hal.h>
|
||||||
|
|
||||||
|
void DecoderGpioOut::process_front(bool polarity, uint32_t time) {
|
||||||
|
hal_gpio_write(&gpio_ext_pa7, polarity);
|
||||||
|
}
|
||||||
|
|
||||||
|
DecoderGpioOut::DecoderGpioOut() {
|
||||||
|
hal_gpio_init_simple(&gpio_ext_pa7, GpioModeOutputPushPull);
|
||||||
|
}
|
||||||
|
|
||||||
|
DecoderGpioOut::~DecoderGpioOut() {
|
||||||
|
hal_gpio_init_simple(&gpio_ext_pa7, GpioModeAnalog);
|
||||||
|
}
|
||||||
14
applications/lfrfid/helpers/decoder-gpio-out.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
class DecoderGpioOut {
|
||||||
|
public:
|
||||||
|
void process_front(bool polarity, uint32_t time);
|
||||||
|
|
||||||
|
DecoderGpioOut();
|
||||||
|
~DecoderGpioOut();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reset_state();
|
||||||
|
};
|
||||||
@ -2,18 +2,24 @@
|
|||||||
#include <api-hal.h>
|
#include <api-hal.h>
|
||||||
|
|
||||||
constexpr uint32_t clocks_in_us = 64;
|
constexpr uint32_t clocks_in_us = 64;
|
||||||
|
constexpr uint32_t us_per_bit = 255;
|
||||||
constexpr uint32_t min_time_us = 25 * clocks_in_us;
|
|
||||||
constexpr uint32_t mid_time_us = 45 * clocks_in_us;
|
|
||||||
constexpr uint32_t max_time_us = 90 * clocks_in_us;
|
|
||||||
|
|
||||||
bool DecoderIndala::read(uint8_t* data, uint8_t data_size) {
|
bool DecoderIndala::read(uint8_t* data, uint8_t data_size) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if(ready) {
|
if(ready) {
|
||||||
result = true;
|
result = true;
|
||||||
printf("IND %02X %02X %02X\r\n", facility, (uint8_t)(number >> 8), (uint8_t)number);
|
if(cursed_data_valid) {
|
||||||
ready = false;
|
indala.decode(
|
||||||
|
reinterpret_cast<const uint8_t*>(&cursed_raw_data),
|
||||||
|
sizeof(uint64_t),
|
||||||
|
data,
|
||||||
|
data_size);
|
||||||
|
} else {
|
||||||
|
indala.decode(
|
||||||
|
reinterpret_cast<const uint8_t*>(&raw_data), sizeof(uint64_t), data, data_size);
|
||||||
|
}
|
||||||
|
reset_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -22,149 +28,49 @@ bool DecoderIndala::read(uint8_t* data, uint8_t data_size) {
|
|||||||
void DecoderIndala::process_front(bool polarity, uint32_t time) {
|
void DecoderIndala::process_front(bool polarity, uint32_t time) {
|
||||||
if(ready) return;
|
if(ready) return;
|
||||||
|
|
||||||
if(polarity == false) {
|
process_internal(polarity, time, &raw_data);
|
||||||
last_pulse_time = time;
|
if(ready) return;
|
||||||
} else {
|
|
||||||
last_pulse_time += time;
|
|
||||||
pulse_count++;
|
|
||||||
|
|
||||||
if(last_pulse_time > min_time_us && last_pulse_time < max_time_us) {
|
if(polarity) {
|
||||||
if(last_pulse_time > mid_time_us) {
|
time = time + 110;
|
||||||
bool last_data = !(readed_data & 1);
|
} else {
|
||||||
pulse_count = 0;
|
time = time - 110;
|
||||||
readed_data = (readed_data << 1) | last_data;
|
}
|
||||||
verify();
|
|
||||||
} else if((pulse_count % 16) == 0) {
|
process_internal(!polarity, time, &cursed_raw_data);
|
||||||
bool last_data = readed_data & 1;
|
if(ready) {
|
||||||
pulse_count = 0;
|
cursed_data_valid = true;
|
||||||
readed_data = (readed_data << 1) | last_data;
|
}
|
||||||
verify();
|
}
|
||||||
|
|
||||||
|
void DecoderIndala::process_internal(bool polarity, uint32_t time, uint64_t* data) {
|
||||||
|
time /= clocks_in_us;
|
||||||
|
time += (us_per_bit / 2);
|
||||||
|
|
||||||
|
uint32_t bit_count = (time / us_per_bit);
|
||||||
|
|
||||||
|
if(bit_count < 64) {
|
||||||
|
for(uint32_t i = 0; i < bit_count; i++) {
|
||||||
|
*data = (*data << 1) | polarity;
|
||||||
|
|
||||||
|
if((*data >> 32) == 0xa0000000ULL) {
|
||||||
|
if(indala.can_be_decoded(
|
||||||
|
reinterpret_cast<const uint8_t*>(data), sizeof(uint64_t))) {
|
||||||
|
ready = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DecoderIndala::DecoderIndala() {
|
DecoderIndala::DecoderIndala() {
|
||||||
|
reset_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecoderIndala::reset_state() {
|
void DecoderIndala::reset_state() {
|
||||||
}
|
raw_data = 0;
|
||||||
|
cursed_raw_data = 0;
|
||||||
void DecoderIndala::verify() {
|
ready = false;
|
||||||
// verify inverse
|
cursed_data_valid = false;
|
||||||
readed_data = ~readed_data;
|
}
|
||||||
verify_inner();
|
|
||||||
|
|
||||||
// verify normal
|
|
||||||
readed_data = ~readed_data;
|
|
||||||
verify_inner();
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
uint64_t raw;
|
|
||||||
struct __attribute__((packed)) {
|
|
||||||
uint8_t static0 : 3;
|
|
||||||
uint8_t checksum : 2;
|
|
||||||
uint8_t static1 : 2;
|
|
||||||
uint8_t y14 : 1;
|
|
||||||
|
|
||||||
uint8_t x8 : 1;
|
|
||||||
uint8_t x1 : 1;
|
|
||||||
uint8_t y13 : 1;
|
|
||||||
uint8_t static2 : 1;
|
|
||||||
uint8_t y12 : 1;
|
|
||||||
uint8_t x6 : 1;
|
|
||||||
uint8_t y5 : 1;
|
|
||||||
uint8_t y8 : 1;
|
|
||||||
|
|
||||||
uint8_t y15 : 1;
|
|
||||||
uint8_t x2 : 1;
|
|
||||||
uint8_t x5 : 1;
|
|
||||||
uint8_t x4 : 1;
|
|
||||||
uint8_t y9 : 1;
|
|
||||||
uint8_t y2 : 1;
|
|
||||||
uint8_t x3 : 1;
|
|
||||||
uint8_t y3 : 1;
|
|
||||||
|
|
||||||
uint8_t y1 : 1;
|
|
||||||
uint8_t y16 : 1;
|
|
||||||
uint8_t y4 : 1;
|
|
||||||
uint8_t x7 : 1;
|
|
||||||
uint8_t p2 : 1;
|
|
||||||
uint8_t y11 : 1;
|
|
||||||
uint8_t y6 : 1;
|
|
||||||
uint8_t y7 : 1;
|
|
||||||
|
|
||||||
uint8_t p1 : 1;
|
|
||||||
uint8_t y10 : 1;
|
|
||||||
uint32_t preamble : 30;
|
|
||||||
};
|
|
||||||
} IndalaFormat;
|
|
||||||
|
|
||||||
void DecoderIndala::verify_inner() {
|
|
||||||
IndalaFormat id;
|
|
||||||
id.raw = readed_data;
|
|
||||||
|
|
||||||
// preamble
|
|
||||||
//if((data >> 34) != 0b000000000000000000000000000001) return;
|
|
||||||
if(id.preamble != 1) return;
|
|
||||||
|
|
||||||
// static data bits
|
|
||||||
//if((data & 0b100001100111) != 0b101) return;
|
|
||||||
if(id.static2 != 0 && id.static1 != 0 && id.static0 != 0b101) return;
|
|
||||||
|
|
||||||
// Indala checksum
|
|
||||||
uint8_t sum_to_check = id.y2 + id.y4 + id.y7 + id.y8 + id.y10 + id.y11 + id.y14 + id.y16;
|
|
||||||
|
|
||||||
if(sum_to_check % 2 == 0) {
|
|
||||||
if(id.checksum != 0b10) return;
|
|
||||||
} else {
|
|
||||||
if(id.checksum != 0b01) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read facility number
|
|
||||||
facility = (id.x1 << 7) + (id.x2 << 6) + (id.x3 << 5) + (id.x4 << 4) + (id.x5 << 3) +
|
|
||||||
(id.x6 << 2) + (id.x7 << 1) + (id.x8 << 0);
|
|
||||||
|
|
||||||
// read serial number
|
|
||||||
number = (id.y1 << 15) + (id.y2 << 14) + (id.y3 << 13) + (id.y4 << 12) + (id.y5 << 11) +
|
|
||||||
(id.y6 << 10) + (id.y7 << 9) + (id.y8 << 8) + (id.y9 << 7) + (id.y10 << 6) +
|
|
||||||
(id.y11 << 5) + (id.y12 << 4) + (id.y13 << 3) + (id.y14 << 2) + (id.y15 << 1) +
|
|
||||||
(id.y16 << 0);
|
|
||||||
|
|
||||||
// Wiegand checksum left
|
|
||||||
sum_to_check = 0;
|
|
||||||
for(int8_t i = 0; i < 8; i--) {
|
|
||||||
if((facility >> i) & 1) {
|
|
||||||
sum_to_check += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int8_t i = 0; i < 4; i--) {
|
|
||||||
if((number >> i) & 1) {
|
|
||||||
sum_to_check += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(id.p1) {
|
|
||||||
sum_to_check += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((sum_to_check % 2) == 1) return;
|
|
||||||
|
|
||||||
// Wiegand checksum right
|
|
||||||
sum_to_check = 0;
|
|
||||||
for(int8_t i = 0; i < 12; i--) {
|
|
||||||
if((number >> (i + 4)) & 1) {
|
|
||||||
sum_to_check += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(id.p2) {
|
|
||||||
sum_to_check += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((sum_to_check % 2) != 1) return;
|
|
||||||
|
|
||||||
ready = true;
|
|
||||||
}
|
|
||||||
@ -2,27 +2,24 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include "protocols/protocol-indala-40134.h"
|
||||||
|
|
||||||
class DecoderIndala {
|
class DecoderIndala {
|
||||||
public:
|
public:
|
||||||
bool read(uint8_t* data, uint8_t data_size);
|
bool read(uint8_t* data, uint8_t data_size);
|
||||||
void process_front(bool polarity, uint32_t time);
|
void process_front(bool polarity, uint32_t time);
|
||||||
|
|
||||||
|
void process_internal(bool polarity, uint32_t time, uint64_t* data);
|
||||||
|
|
||||||
DecoderIndala();
|
DecoderIndala();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void reset_state();
|
void reset_state();
|
||||||
|
|
||||||
void verify();
|
uint64_t raw_data;
|
||||||
void verify_inner();
|
uint64_t cursed_raw_data;
|
||||||
|
|
||||||
uint32_t last_pulse_time = 0;
|
|
||||||
uint32_t pulse_count = 0;
|
|
||||||
uint32_t overall_pulse_count = 0;
|
|
||||||
|
|
||||||
uint64_t readed_data = 0;
|
|
||||||
|
|
||||||
std::atomic<bool> ready;
|
std::atomic<bool> ready;
|
||||||
uint8_t facility = 0;
|
std::atomic<bool> cursed_data_valid;
|
||||||
uint16_t number = 0;
|
ProtocolIndala40134 indala;
|
||||||
};
|
};
|
||||||
@ -7,7 +7,6 @@ void EncoderHID_H10301::init(const uint8_t* data, const uint8_t data_size) {
|
|||||||
hid.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 3);
|
hid.encode(data, data_size, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 3);
|
||||||
|
|
||||||
card_data_index = 0;
|
card_data_index = 0;
|
||||||
bit_index = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncoderHID_H10301::write_bit(bool bit, uint8_t position) {
|
void EncoderHID_H10301::write_bit(bool bit, uint8_t position) {
|
||||||
@ -24,39 +23,24 @@ void EncoderHID_H10301::write_raw_bit(bool bit, uint8_t position) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void EncoderHID_H10301::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) {
|
void EncoderHID_H10301::get_next(bool* polarity, uint16_t* period, uint16_t* pulse) {
|
||||||
// hid 0 is 6 cycles by 8 clocks
|
uint8_t bit = (card_data[card_data_index / 32] >> (31 - (card_data_index % 32))) & 1;
|
||||||
const uint8_t hid_0_period = 8;
|
|
||||||
const uint8_t hid_0_count = 6;
|
|
||||||
// hid 1 is 5 cycles by 10 clocks
|
|
||||||
const uint8_t hid_1_period = 10;
|
|
||||||
const uint8_t hid_1_count = 5;
|
|
||||||
|
|
||||||
bool bit = (card_data[card_data_index / 32] >> (31 - (card_data_index % 32))) & 1;
|
bool advance = fsk->next(bit, period);
|
||||||
|
if(advance) {
|
||||||
*polarity = true;
|
card_data_index++;
|
||||||
if(bit) {
|
if(card_data_index >= (32 * card_data_max)) {
|
||||||
*period = hid_1_period;
|
card_data_index = 0;
|
||||||
*pulse = hid_1_period / 2;
|
|
||||||
|
|
||||||
bit_index++;
|
|
||||||
if(bit_index >= hid_1_count) {
|
|
||||||
bit_index = 0;
|
|
||||||
card_data_index++;
|
|
||||||
if(card_data_index >= (32 * card_data_max)) {
|
|
||||||
card_data_index = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*period = hid_0_period;
|
|
||||||
*pulse = hid_0_period / 2;
|
|
||||||
|
|
||||||
bit_index++;
|
|
||||||
if(bit_index >= hid_0_count) {
|
|
||||||
bit_index = 0;
|
|
||||||
card_data_index++;
|
|
||||||
if(card_data_index >= (32 * card_data_max)) {
|
|
||||||
card_data_index = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*polarity = true;
|
||||||
|
*pulse = *period / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
EncoderHID_H10301::EncoderHID_H10301() {
|
||||||
|
fsk = new OscFSK(8, 10, 50);
|
||||||
|
}
|
||||||
|
|
||||||
|
EncoderHID_H10301::~EncoderHID_H10301() {
|
||||||
|
delete fsk;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "encoder-generic.h"
|
#include "encoder-generic.h"
|
||||||
|
#include "osc-fsk.h"
|
||||||
|
|
||||||
class EncoderHID_H10301 : public EncoderGeneric {
|
class EncoderHID_H10301 : public EncoderGeneric {
|
||||||
public:
|
public:
|
||||||
@ -10,15 +11,16 @@ public:
|
|||||||
* @param data_size must be 3
|
* @param data_size must be 3
|
||||||
*/
|
*/
|
||||||
void init(const uint8_t* data, const uint8_t data_size) final;
|
void init(const uint8_t* data, const uint8_t data_size) final;
|
||||||
|
|
||||||
void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final;
|
void get_next(bool* polarity, uint16_t* period, uint16_t* pulse) final;
|
||||||
|
EncoderHID_H10301();
|
||||||
|
~EncoderHID_H10301();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const uint8_t card_data_max = 3;
|
static const uint8_t card_data_max = 3;
|
||||||
uint32_t card_data[card_data_max];
|
uint32_t card_data[card_data_max];
|
||||||
uint8_t card_data_index;
|
uint8_t card_data_index;
|
||||||
uint8_t bit_index;
|
|
||||||
|
|
||||||
void write_bit(bool bit, uint8_t position);
|
void write_bit(bool bit, uint8_t position);
|
||||||
void write_raw_bit(bool bit, uint8_t position);
|
void write_raw_bit(bool bit, uint8_t position);
|
||||||
|
|
||||||
|
OscFSK* fsk;
|
||||||
};
|
};
|
||||||
20
applications/lfrfid/helpers/osc-fsk.cpp
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#include "osc-fsk.h"
|
||||||
|
|
||||||
|
OscFSK::OscFSK(uint16_t _freq_low, uint16_t _freq_hi, uint16_t _osc_phase_max)
|
||||||
|
: freq{_freq_low, _freq_hi}
|
||||||
|
, osc_phase_max(_osc_phase_max) {
|
||||||
|
osc_phase_current = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OscFSK::next(bool bit, uint16_t* period) {
|
||||||
|
bool advance = false;
|
||||||
|
*period = freq[bit];
|
||||||
|
osc_phase_current += *period;
|
||||||
|
|
||||||
|
if(osc_phase_current > osc_phase_max) {
|
||||||
|
advance = true;
|
||||||
|
osc_phase_current -= osc_phase_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return advance;
|
||||||
|
}
|
||||||
30
applications/lfrfid/helpers/osc-fsk.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This code tries to fit the periods into a given number of cycles (phases) by taking cycles from the next cycle of periods.
|
||||||
|
*/
|
||||||
|
class OscFSK {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Get next period
|
||||||
|
* @param bit bit value
|
||||||
|
* @param period return period
|
||||||
|
* @return bool whether to advance to the next bit
|
||||||
|
*/
|
||||||
|
bool next(bool bit, uint16_t* period);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FSK ocillator constructor
|
||||||
|
*
|
||||||
|
* @param freq_low bit 0 freq
|
||||||
|
* @param freq_hi bit 1 freq
|
||||||
|
* @param osc_phase_max max oscillator phase
|
||||||
|
*/
|
||||||
|
OscFSK(uint16_t freq_low, uint16_t freq_hi, uint16_t osc_phase_max);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint16_t freq[2];
|
||||||
|
const uint16_t osc_phase_max;
|
||||||
|
int32_t osc_phase_current;
|
||||||
|
};
|
||||||
@ -12,6 +12,11 @@ static void set_bit(bool bit, uint8_t position, Indala40134CardData* card_data)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool get_bit(uint8_t position, const Indala40134CardData* card_data) {
|
||||||
|
position = (sizeof(Indala40134CardData) * 8) - 1 - position;
|
||||||
|
return (*card_data >> position) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t ProtocolIndala40134::get_encoded_data_size() {
|
uint8_t ProtocolIndala40134::get_encoded_data_size() {
|
||||||
return sizeof(Indala40134CardData);
|
return sizeof(Indala40134CardData);
|
||||||
}
|
}
|
||||||
@ -110,6 +115,46 @@ void ProtocolIndala40134::encode(
|
|||||||
memcpy(encoded_data, &card_data, get_encoded_data_size());
|
memcpy(encoded_data, &card_data, get_encoded_data_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// factory code
|
||||||
|
static uint8_t get_fc(const Indala40134CardData* card_data) {
|
||||||
|
uint8_t fc = 0;
|
||||||
|
|
||||||
|
fc = fc << 1 | get_bit(57, card_data);
|
||||||
|
fc = fc << 1 | get_bit(49, card_data);
|
||||||
|
fc = fc << 1 | get_bit(44, card_data);
|
||||||
|
fc = fc << 1 | get_bit(47, card_data);
|
||||||
|
fc = fc << 1 | get_bit(48, card_data);
|
||||||
|
fc = fc << 1 | get_bit(53, card_data);
|
||||||
|
fc = fc << 1 | get_bit(39, card_data);
|
||||||
|
fc = fc << 1 | get_bit(58, card_data);
|
||||||
|
|
||||||
|
return fc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// card number
|
||||||
|
static uint16_t get_cn(const Indala40134CardData* card_data) {
|
||||||
|
uint16_t cn = 0;
|
||||||
|
|
||||||
|
cn = cn << 1 | get_bit(42, card_data);
|
||||||
|
cn = cn << 1 | get_bit(45, card_data);
|
||||||
|
cn = cn << 1 | get_bit(43, card_data);
|
||||||
|
cn = cn << 1 | get_bit(40, card_data);
|
||||||
|
cn = cn << 1 | get_bit(52, card_data);
|
||||||
|
cn = cn << 1 | get_bit(36, card_data);
|
||||||
|
cn = cn << 1 | get_bit(35, card_data);
|
||||||
|
cn = cn << 1 | get_bit(51, card_data);
|
||||||
|
cn = cn << 1 | get_bit(46, card_data);
|
||||||
|
cn = cn << 1 | get_bit(33, card_data);
|
||||||
|
cn = cn << 1 | get_bit(37, card_data);
|
||||||
|
cn = cn << 1 | get_bit(54, card_data);
|
||||||
|
cn = cn << 1 | get_bit(56, card_data);
|
||||||
|
cn = cn << 1 | get_bit(59, card_data);
|
||||||
|
cn = cn << 1 | get_bit(50, card_data);
|
||||||
|
cn = cn << 1 | get_bit(41, card_data);
|
||||||
|
|
||||||
|
return cn;
|
||||||
|
}
|
||||||
|
|
||||||
void ProtocolIndala40134::decode(
|
void ProtocolIndala40134::decode(
|
||||||
const uint8_t* encoded_data,
|
const uint8_t* encoded_data,
|
||||||
const uint8_t encoded_data_size,
|
const uint8_t encoded_data_size,
|
||||||
@ -117,15 +162,76 @@ void ProtocolIndala40134::decode(
|
|||||||
const uint8_t decoded_data_size) {
|
const uint8_t decoded_data_size) {
|
||||||
furi_check(decoded_data_size >= get_decoded_data_size());
|
furi_check(decoded_data_size >= get_decoded_data_size());
|
||||||
furi_check(encoded_data_size >= get_encoded_data_size());
|
furi_check(encoded_data_size >= get_encoded_data_size());
|
||||||
// TODO implement decoding
|
|
||||||
furi_check(0);
|
const Indala40134CardData* card_data =
|
||||||
|
reinterpret_cast<const Indala40134CardData*>(encoded_data);
|
||||||
|
|
||||||
|
uint8_t fc = get_fc(card_data);
|
||||||
|
uint16_t card = get_cn(card_data);
|
||||||
|
|
||||||
|
decoded_data[0] = fc;
|
||||||
|
decoded_data[1] = card >> 8;
|
||||||
|
decoded_data[2] = card;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProtocolIndala40134::can_be_decoded(
|
bool ProtocolIndala40134::can_be_decoded(
|
||||||
const uint8_t* encoded_data,
|
const uint8_t* encoded_data,
|
||||||
const uint8_t encoded_data_size) {
|
const uint8_t encoded_data_size) {
|
||||||
furi_check(encoded_data_size >= get_encoded_data_size());
|
furi_check(encoded_data_size >= get_encoded_data_size());
|
||||||
// TODO implement decoding
|
bool can_be_decoded = false;
|
||||||
furi_check(0);
|
|
||||||
return false;
|
const Indala40134CardData* card_data =
|
||||||
|
reinterpret_cast<const Indala40134CardData*>(encoded_data);
|
||||||
|
|
||||||
|
do {
|
||||||
|
// preambula
|
||||||
|
if((*card_data >> 32) != 0xa0000000UL) break;
|
||||||
|
|
||||||
|
// data
|
||||||
|
const uint32_t fc_and_card = get_fc(card_data) << 16 | get_cn(card_data);
|
||||||
|
|
||||||
|
// checksum
|
||||||
|
const uint8_t checksum = get_bit(62, card_data) << 1 | get_bit(63, card_data);
|
||||||
|
uint8_t checksum_sum = 0;
|
||||||
|
checksum_sum += ((fc_and_card >> 14) & 1);
|
||||||
|
checksum_sum += ((fc_and_card >> 12) & 1);
|
||||||
|
checksum_sum += ((fc_and_card >> 9) & 1);
|
||||||
|
checksum_sum += ((fc_and_card >> 8) & 1);
|
||||||
|
checksum_sum += ((fc_and_card >> 6) & 1);
|
||||||
|
checksum_sum += ((fc_and_card >> 5) & 1);
|
||||||
|
checksum_sum += ((fc_and_card >> 2) & 1);
|
||||||
|
checksum_sum += ((fc_and_card >> 0) & 1);
|
||||||
|
checksum_sum = checksum_sum & 0b1;
|
||||||
|
|
||||||
|
if(checksum_sum == 1 && checksum == 0b01) {
|
||||||
|
} else if(checksum_sum == 0 && checksum == 0b10) {
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// wiegand parity bits
|
||||||
|
// even parity sum calculation (high 12 bits of data)
|
||||||
|
const bool even_parity = get_bit(34, card_data);
|
||||||
|
uint8_t even_parity_sum = 0;
|
||||||
|
for(int8_t i = 12; i < 24; i++) {
|
||||||
|
if(((fc_and_card >> i) & 1) == 1) {
|
||||||
|
even_parity_sum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(even_parity_sum % 2 != even_parity) break;
|
||||||
|
|
||||||
|
// odd parity sum calculation (low 12 bits of data)
|
||||||
|
const bool odd_parity = get_bit(38, card_data);
|
||||||
|
uint8_t odd_parity_sum = 1;
|
||||||
|
for(int8_t i = 0; i < 12; i++) {
|
||||||
|
if(((fc_and_card >> i) & 1) == 1) {
|
||||||
|
odd_parity_sum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(odd_parity_sum % 2 != odd_parity) break;
|
||||||
|
|
||||||
|
can_be_decoded = true;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return can_be_decoded;
|
||||||
}
|
}
|
||||||
@ -1,35 +0,0 @@
|
|||||||
#include "rfid-name-generator.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
void rfid_generate_random_name(char* name, uint8_t max_name_size) {
|
|
||||||
const uint8_t prefix_size = 9;
|
|
||||||
const char* prefix[prefix_size] = {
|
|
||||||
"good",
|
|
||||||
"nice",
|
|
||||||
"best",
|
|
||||||
"some",
|
|
||||||
"strange",
|
|
||||||
"working",
|
|
||||||
"that",
|
|
||||||
"forgettable",
|
|
||||||
"easy",
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t suffix_size = 7;
|
|
||||||
const char* suffix[suffix_size] = {
|
|
||||||
"pass",
|
|
||||||
"card",
|
|
||||||
"key",
|
|
||||||
"fob",
|
|
||||||
"permit",
|
|
||||||
"pass",
|
|
||||||
"one",
|
|
||||||
};
|
|
||||||
|
|
||||||
sniprintf(
|
|
||||||
name, max_name_size, "%s_%s", prefix[rand() % prefix_size], suffix[rand() % suffix_size]);
|
|
||||||
|
|
||||||
// to upper
|
|
||||||
name[0] = name[0] - ('a' - 'A');
|
|
||||||
}
|
|
||||||
@ -1,4 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "stdint.h"
|
|
||||||
|
|
||||||
void rfid_generate_random_name(char* name, uint8_t max_name_size);
|
|
||||||
@ -17,19 +17,47 @@ struct RfidReaderAccessor {
|
|||||||
|
|
||||||
void RfidReader::decode(bool polarity) {
|
void RfidReader::decode(bool polarity) {
|
||||||
uint32_t current_dwt_value = DWT->CYCCNT;
|
uint32_t current_dwt_value = DWT->CYCCNT;
|
||||||
|
uint32_t period = current_dwt_value - last_dwt_value;
|
||||||
|
last_dwt_value = current_dwt_value;
|
||||||
|
|
||||||
|
//decoder_gpio_out.process_front(polarity, period);
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::Normal:
|
case Type::Normal:
|
||||||
decoder_em.process_front(polarity, current_dwt_value - last_dwt_value);
|
decoder_em.process_front(polarity, period);
|
||||||
decoder_hid26.process_front(polarity, current_dwt_value - last_dwt_value);
|
decoder_hid26.process_front(polarity, period);
|
||||||
//decoder_indala.process_front(polarity, current_dwt_value - last_dwt_value);
|
|
||||||
//decoder_analyzer.process_front(polarity, current_dwt_value - last_dwt_value);
|
|
||||||
|
|
||||||
last_dwt_value = current_dwt_value;
|
|
||||||
break;
|
break;
|
||||||
case Type::Indala:
|
case Type::Indala:
|
||||||
|
decoder_em.process_front(polarity, period);
|
||||||
|
decoder_hid26.process_front(polarity, period);
|
||||||
|
decoder_indala.process_front(polarity, period);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
detect_ticks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RfidReader::switch_timer_elapsed() {
|
||||||
|
const uint32_t seconds_to_switch = osKernelGetTickFreq() * 2.0f;
|
||||||
|
return (osKernelGetTickCount() - switch_os_tick_last) > seconds_to_switch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RfidReader::switch_timer_reset() {
|
||||||
|
switch_os_tick_last = osKernelGetTickCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RfidReader::switch_mode() {
|
||||||
|
switch(type) {
|
||||||
|
case Type::Normal:
|
||||||
|
type = Type::Indala;
|
||||||
|
api_hal_rfid_change_read_config(62500.0f, 0.25f);
|
||||||
|
break;
|
||||||
|
case Type::Indala:
|
||||||
|
type = Type::Normal;
|
||||||
|
api_hal_rfid_change_read_config(125000.0f, 0.5f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_timer_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void comparator_trigger_callback(void* hcomp, void* comp_ctx) {
|
static void comparator_trigger_callback(void* hcomp, void* comp_ctx) {
|
||||||
@ -45,47 +73,103 @@ static void comparator_trigger_callback(void* hcomp, void* comp_ctx) {
|
|||||||
RfidReader::RfidReader() {
|
RfidReader::RfidReader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RfidReader::start(Type _type) {
|
void RfidReader::start() {
|
||||||
type = _type;
|
type = Type::Normal;
|
||||||
|
|
||||||
start_gpio();
|
api_hal_rfid_pins_read();
|
||||||
|
api_hal_rfid_tim_read(125000, 0.5);
|
||||||
|
api_hal_rfid_tim_read_start();
|
||||||
|
start_comparator();
|
||||||
|
|
||||||
|
switch_timer_reset();
|
||||||
|
last_readed_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RfidReader::start_forced(RfidReader::Type _type) {
|
||||||
|
type = _type;
|
||||||
switch(type) {
|
switch(type) {
|
||||||
case Type::Normal:
|
case Type::Normal:
|
||||||
start_timer();
|
start();
|
||||||
break;
|
break;
|
||||||
case Type::Indala:
|
case Type::Indala:
|
||||||
start_timer_indala();
|
api_hal_rfid_pins_read();
|
||||||
|
api_hal_rfid_tim_read(62500.0f, 0.25f);
|
||||||
|
api_hal_rfid_tim_read_start();
|
||||||
|
start_comparator();
|
||||||
|
|
||||||
|
switch_timer_reset();
|
||||||
|
last_readed_count = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
start_comparator();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RfidReader::stop() {
|
void RfidReader::stop() {
|
||||||
stop_gpio();
|
api_hal_rfid_pins_reset();
|
||||||
stop_timer();
|
api_hal_rfid_tim_read_stop();
|
||||||
|
api_hal_rfid_tim_reset();
|
||||||
stop_comparator();
|
stop_comparator();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RfidReader::read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size) {
|
bool RfidReader::read(LfrfidKeyType* _type, uint8_t* data, uint8_t data_size) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
bool something_readed = false;
|
||||||
|
|
||||||
|
// reading
|
||||||
if(decoder_em.read(data, data_size)) {
|
if(decoder_em.read(data, data_size)) {
|
||||||
*type = LfrfidKeyType::KeyEM4100;
|
*_type = LfrfidKeyType::KeyEM4100;
|
||||||
result = true;
|
something_readed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(decoder_hid26.read(data, data_size)) {
|
if(decoder_hid26.read(data, data_size)) {
|
||||||
*type = LfrfidKeyType::KeyH10301;
|
*_type = LfrfidKeyType::KeyH10301;
|
||||||
result = true;
|
something_readed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//decoder_indala.read(NULL, 0);
|
if(decoder_indala.read(data, data_size)) {
|
||||||
//decoder_analyzer.read(NULL, 0);
|
*_type = LfrfidKeyType::KeyI40134;
|
||||||
|
something_readed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validation
|
||||||
|
if(something_readed) {
|
||||||
|
switch_timer_reset();
|
||||||
|
|
||||||
|
if(last_readed_type == *_type && memcmp(last_readed_data, data, data_size) == 0) {
|
||||||
|
last_readed_count = last_readed_count + 1;
|
||||||
|
|
||||||
|
if(last_readed_count > 2) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
last_readed_type = *_type;
|
||||||
|
memcpy(last_readed_data, data, data_size);
|
||||||
|
last_readed_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// mode switching
|
||||||
|
if(switch_timer_elapsed()) {
|
||||||
|
switch_mode();
|
||||||
|
last_readed_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RfidReader::detect() {
|
||||||
|
bool detected = false;
|
||||||
|
if(detect_ticks > 10) {
|
||||||
|
detected = true;
|
||||||
|
}
|
||||||
|
detect_ticks = 0;
|
||||||
|
|
||||||
|
return detected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RfidReader::any_read() {
|
||||||
|
return last_readed_count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
void RfidReader::start_comparator(void) {
|
void RfidReader::start_comparator(void) {
|
||||||
api_interrupt_add(comparator_trigger_callback, InterruptTypeComparatorTrigger, this);
|
api_interrupt_add(comparator_trigger_callback, InterruptTypeComparatorTrigger, this);
|
||||||
last_dwt_value = DWT->CYCCNT;
|
last_dwt_value = DWT->CYCCNT;
|
||||||
@ -93,7 +177,7 @@ void RfidReader::start_comparator(void) {
|
|||||||
hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_2VREFINT;
|
hcomp1.Init.InputMinus = COMP_INPUT_MINUS_1_2VREFINT;
|
||||||
hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1;
|
hcomp1.Init.InputPlus = COMP_INPUT_PLUS_IO1;
|
||||||
hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED;
|
hcomp1.Init.OutputPol = COMP_OUTPUTPOL_NONINVERTED;
|
||||||
hcomp1.Init.Hysteresis = COMP_HYSTERESIS_LOW;
|
hcomp1.Init.Hysteresis = COMP_HYSTERESIS_HIGH;
|
||||||
hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE;
|
hcomp1.Init.BlankingSrce = COMP_BLANKINGSRC_NONE;
|
||||||
hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED;
|
hcomp1.Init.Mode = COMP_POWERMODE_MEDIUMSPEED;
|
||||||
hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE;
|
hcomp1.Init.WindowMode = COMP_WINDOWMODE_DISABLE;
|
||||||
@ -105,30 +189,7 @@ void RfidReader::start_comparator(void) {
|
|||||||
HAL_COMP_Start(&hcomp1);
|
HAL_COMP_Start(&hcomp1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RfidReader::start_timer(void) {
|
|
||||||
api_hal_rfid_tim_read(125000, 0.5);
|
|
||||||
api_hal_rfid_tim_read_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RfidReader::start_timer_indala(void) {
|
|
||||||
api_hal_rfid_tim_read(62500, 0.25);
|
|
||||||
api_hal_rfid_tim_read_start();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RfidReader::start_gpio(void) {
|
|
||||||
api_hal_rfid_pins_read();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RfidReader::stop_comparator(void) {
|
void RfidReader::stop_comparator(void) {
|
||||||
HAL_COMP_Stop(&hcomp1);
|
HAL_COMP_Stop(&hcomp1);
|
||||||
api_interrupt_remove(comparator_trigger_callback, InterruptTypeComparatorTrigger);
|
api_interrupt_remove(comparator_trigger_callback, InterruptTypeComparatorTrigger);
|
||||||
}
|
|
||||||
|
|
||||||
void RfidReader::stop_timer(void) {
|
|
||||||
api_hal_rfid_tim_read_stop();
|
|
||||||
api_hal_rfid_tim_reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RfidReader::stop_gpio(void) {
|
|
||||||
api_hal_rfid_pins_reset();
|
|
||||||
}
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "decoder-analyzer.h"
|
//#include "decoder-analyzer.h"
|
||||||
|
#include "decoder-gpio-out.h"
|
||||||
#include "decoder-emmarine.h"
|
#include "decoder-emmarine.h"
|
||||||
#include "decoder-hid26.h"
|
#include "decoder-hid26.h"
|
||||||
#include "decoder-indala.h"
|
#include "decoder-indala.h"
|
||||||
@ -13,14 +14,19 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
RfidReader();
|
RfidReader();
|
||||||
void start(Type type);
|
void start();
|
||||||
|
void start_forced(RfidReader::Type type);
|
||||||
void stop();
|
void stop();
|
||||||
bool read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size);
|
bool read(LfrfidKeyType* type, uint8_t* data, uint8_t data_size);
|
||||||
|
|
||||||
|
bool detect();
|
||||||
|
bool any_read();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct RfidReaderAccessor;
|
friend struct RfidReaderAccessor;
|
||||||
|
|
||||||
//DecoderAnalyzer decoder_analyzer;
|
//DecoderAnalyzer decoder_analyzer;
|
||||||
|
//DecoderGpioOut decoder_gpio_out;
|
||||||
DecoderEMMarine decoder_em;
|
DecoderEMMarine decoder_em;
|
||||||
DecoderHID26 decoder_hid26;
|
DecoderHID26 decoder_hid26;
|
||||||
DecoderIndala decoder_indala;
|
DecoderIndala decoder_indala;
|
||||||
@ -28,14 +34,20 @@ private:
|
|||||||
uint32_t last_dwt_value;
|
uint32_t last_dwt_value;
|
||||||
|
|
||||||
void start_comparator(void);
|
void start_comparator(void);
|
||||||
void start_timer(void);
|
|
||||||
void start_timer_indala(void);
|
|
||||||
void start_gpio(void);
|
|
||||||
void stop_comparator(void);
|
void stop_comparator(void);
|
||||||
void stop_timer(void);
|
|
||||||
void stop_gpio(void);
|
|
||||||
|
|
||||||
void decode(bool polarity);
|
void decode(bool polarity);
|
||||||
|
|
||||||
|
uint32_t detect_ticks;
|
||||||
|
|
||||||
|
uint32_t switch_os_tick_last;
|
||||||
|
bool switch_timer_elapsed();
|
||||||
|
void switch_timer_reset();
|
||||||
|
void switch_mode();
|
||||||
|
|
||||||
|
LfrfidKeyType last_readed_type;
|
||||||
|
uint8_t last_readed_data[LFRFID_KEY_SIZE];
|
||||||
|
uint8_t last_readed_count;
|
||||||
|
|
||||||
Type type = Type::Normal;
|
Type type = Type::Normal;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,7 +7,7 @@ RfidWorker::~RfidWorker() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RfidWorker::start_read() {
|
void RfidWorker::start_read() {
|
||||||
reader.start(RfidReader::Type::Normal);
|
reader.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RfidWorker::read() {
|
bool RfidWorker::read() {
|
||||||
@ -25,6 +25,14 @@ bool RfidWorker::read() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RfidWorker::detect() {
|
||||||
|
return reader.detect();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RfidWorker::any_read() {
|
||||||
|
return reader.any_read();
|
||||||
|
}
|
||||||
|
|
||||||
void RfidWorker::stop_read() {
|
void RfidWorker::stop_read() {
|
||||||
reader.stop();
|
reader.stop();
|
||||||
}
|
}
|
||||||
@ -36,7 +44,7 @@ void RfidWorker::start_write() {
|
|||||||
|
|
||||||
write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write, this));
|
write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write, this));
|
||||||
write_sequence->do_after_tick(2, std::bind(&RfidWorker::sq_write_start_validate, this));
|
write_sequence->do_after_tick(2, std::bind(&RfidWorker::sq_write_start_validate, this));
|
||||||
write_sequence->do_after_tick(15, std::bind(&RfidWorker::sq_write_validate, this));
|
write_sequence->do_every_tick(30, std::bind(&RfidWorker::sq_write_validate, this));
|
||||||
write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write_stop_validate, this));
|
write_sequence->do_every_tick(1, std::bind(&RfidWorker::sq_write_stop_validate, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,26 +67,37 @@ void RfidWorker::stop_emulate() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RfidWorker::sq_write() {
|
void RfidWorker::sq_write() {
|
||||||
// TODO expand this
|
for(size_t i = 0; i < 5; i++) {
|
||||||
switch(key.get_type()) {
|
switch(key.get_type()) {
|
||||||
case LfrfidKeyType::KeyEM4100:
|
case LfrfidKeyType::KeyEM4100:
|
||||||
writer.start();
|
writer.start();
|
||||||
writer.write_em(key.get_data());
|
writer.write_em(key.get_data());
|
||||||
writer.stop();
|
writer.stop();
|
||||||
break;
|
break;
|
||||||
case LfrfidKeyType::KeyH10301:
|
case LfrfidKeyType::KeyH10301:
|
||||||
writer.start();
|
writer.start();
|
||||||
writer.write_hid(key.get_data());
|
writer.write_hid(key.get_data());
|
||||||
writer.stop();
|
writer.stop();
|
||||||
break;
|
break;
|
||||||
|
case LfrfidKeyType::KeyI40134:
|
||||||
default:
|
writer.start();
|
||||||
break;
|
writer.write_indala(key.get_data());
|
||||||
|
writer.stop();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RfidWorker::sq_write_start_validate() {
|
void RfidWorker::sq_write_start_validate() {
|
||||||
reader.start(RfidReader::Type::Normal);
|
switch(key.get_type()) {
|
||||||
|
case LfrfidKeyType::KeyEM4100:
|
||||||
|
case LfrfidKeyType::KeyH10301:
|
||||||
|
reader.start_forced(RfidReader::Type::Normal);
|
||||||
|
break;
|
||||||
|
case LfrfidKeyType::KeyI40134:
|
||||||
|
reader.start_forced(RfidReader::Type::Indala);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RfidWorker::sq_write_validate() {
|
void RfidWorker::sq_write_validate() {
|
||||||
@ -88,7 +107,11 @@ void RfidWorker::sq_write_validate() {
|
|||||||
|
|
||||||
bool result = reader.read(&type, data, data_size);
|
bool result = reader.read(&type, data, data_size);
|
||||||
|
|
||||||
if(result) {
|
if(result && (write_result != WriteResult::Ok)) {
|
||||||
|
if(validate_counts > (5 * 60)) {
|
||||||
|
write_result = WriteResult::NotWritable;
|
||||||
|
}
|
||||||
|
|
||||||
if(type == key.get_type()) {
|
if(type == key.get_type()) {
|
||||||
if(memcmp(data, key.get_data(), key.get_type_data_count()) == 0) {
|
if(memcmp(data, key.get_data(), key.get_type_data_count()) == 0) {
|
||||||
write_result = WriteResult::Ok;
|
write_result = WriteResult::Ok;
|
||||||
@ -99,10 +122,6 @@ void RfidWorker::sq_write_validate() {
|
|||||||
} else {
|
} else {
|
||||||
validate_counts++;
|
validate_counts++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(validate_counts > 5) {
|
|
||||||
write_result = WriteResult::NotWritable;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,8 @@ public:
|
|||||||
|
|
||||||
void start_read();
|
void start_read();
|
||||||
bool read();
|
bool read();
|
||||||
|
bool detect();
|
||||||
|
bool any_read();
|
||||||
void stop_read();
|
void stop_read();
|
||||||
|
|
||||||
enum class WriteResult : uint8_t {
|
enum class WriteResult : uint8_t {
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#include <api-hal.h>
|
#include <api-hal.h>
|
||||||
#include "protocols/protocol-emmarin.h"
|
#include "protocols/protocol-emmarin.h"
|
||||||
#include "protocols/protocol-hid-h10301.h"
|
#include "protocols/protocol-hid-h10301.h"
|
||||||
|
#include "protocols/protocol-indala-40134.h"
|
||||||
|
|
||||||
extern COMP_HandleTypeDef hcomp1;
|
extern COMP_HandleTypeDef hcomp1;
|
||||||
|
|
||||||
@ -115,7 +116,7 @@ void RfidWriter::write_em(const uint8_t em_data[5]) {
|
|||||||
ProtocolEMMarin em_card;
|
ProtocolEMMarin em_card;
|
||||||
uint64_t em_encoded_data;
|
uint64_t em_encoded_data;
|
||||||
em_card.encode(em_data, 5, reinterpret_cast<uint8_t*>(&em_encoded_data), sizeof(uint64_t));
|
em_card.encode(em_data, 5, reinterpret_cast<uint8_t*>(&em_encoded_data), sizeof(uint64_t));
|
||||||
const uint32_t em_config_block_data = 0b01100000000101001000000001000000;
|
const uint32_t em_config_block_data = 0b00000000000101001000000001000000;
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
write_block(0, 0, false, em_config_block_data);
|
write_block(0, 0, false, em_config_block_data);
|
||||||
@ -140,3 +141,19 @@ void RfidWriter::write_hid(const uint8_t hid_data[3]) {
|
|||||||
write_reset();
|
write_reset();
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RfidWriter::write_indala(const uint8_t indala_data[3]) {
|
||||||
|
ProtocolIndala40134 indala_card;
|
||||||
|
uint32_t card_data[2];
|
||||||
|
indala_card.encode(
|
||||||
|
indala_data, 3, reinterpret_cast<uint8_t*>(&card_data), sizeof(card_data) * 2);
|
||||||
|
|
||||||
|
const uint32_t indala_config_block_data = 0b00000000000010000001000001000000;
|
||||||
|
|
||||||
|
__disable_irq();
|
||||||
|
write_block(0, 0, false, indala_config_block_data);
|
||||||
|
write_block(0, 1, false, card_data[0]);
|
||||||
|
write_block(0, 2, false, card_data[1]);
|
||||||
|
write_reset();
|
||||||
|
__enable_irq();
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ public:
|
|||||||
void stop();
|
void stop();
|
||||||
void write_em(const uint8_t em_data[5]);
|
void write_em(const uint8_t em_data[5]);
|
||||||
void write_hid(const uint8_t hid_data[3]);
|
void write_hid(const uint8_t hid_data[3]);
|
||||||
|
void write_indala(const uint8_t indala_data[3]);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void write_gap(uint32_t gap_time);
|
void write_gap(uint32_t gap_time);
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
#include "scene/lfrfid-app-scene-delete-success.h"
|
#include "scene/lfrfid-app-scene-delete-success.h"
|
||||||
|
|
||||||
#include <file-worker-cpp.h>
|
#include <file-worker-cpp.h>
|
||||||
#include <path.h>
|
#include <lib/toolbox/path.h>
|
||||||
|
|
||||||
const char* LfRfidApp::app_folder = "/any/lfrfid";
|
const char* LfRfidApp::app_folder = "/any/lfrfid";
|
||||||
const char* LfRfidApp::app_extension = ".rfid";
|
const char* LfRfidApp::app_extension = ".rfid";
|
||||||
@ -27,9 +27,6 @@ LfRfidApp::LfRfidApp()
|
|||||||
, notification{"notification"}
|
, notification{"notification"}
|
||||||
, text_store(40) {
|
, text_store(40) {
|
||||||
api_hal_power_insomnia_enter();
|
api_hal_power_insomnia_enter();
|
||||||
|
|
||||||
// we need random
|
|
||||||
srand(DWT->CYCCNT);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
LfRfidApp::~LfRfidApp() {
|
LfRfidApp::~LfRfidApp() {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#include <api-hal.h>
|
#include <api-hal.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <cli/cli.h>
|
#include <cli/cli.h>
|
||||||
#include <args.h>
|
#include <lib/toolbox/args.h>
|
||||||
|
|
||||||
#include "helpers/rfid-reader.h"
|
#include "helpers/rfid-reader.h"
|
||||||
#include "helpers/rfid-timer-emulator.h"
|
#include "helpers/rfid-timer-emulator.h"
|
||||||
@ -46,7 +46,7 @@ bool lfrfid_cli_get_key_type(string_t data, LfrfidKeyType* type) {
|
|||||||
|
|
||||||
void lfrfid_cli_read(Cli* cli) {
|
void lfrfid_cli_read(Cli* cli) {
|
||||||
RfidReader reader;
|
RfidReader reader;
|
||||||
reader.start(RfidReader::Type::Normal);
|
reader.start();
|
||||||
|
|
||||||
static const uint8_t data_size = LFRFID_KEY_SIZE;
|
static const uint8_t data_size = LFRFID_KEY_SIZE;
|
||||||
uint8_t data[data_size] = {0};
|
uint8_t data[data_size] = {0};
|
||||||
|
|||||||
@ -55,6 +55,7 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) {
|
|||||||
string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary);
|
string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary);
|
||||||
break;
|
break;
|
||||||
case LfrfidKeyType::KeyH10301:
|
case LfrfidKeyType::KeyH10301:
|
||||||
|
case LfrfidKeyType::KeyI40134:
|
||||||
line_1_text->set_text("HEX:", 65, 23, AlignRight, AlignBottom, FontSecondary);
|
line_1_text->set_text("HEX:", 65, 23, AlignRight, AlignBottom, FontSecondary);
|
||||||
line_2_text->set_text("FC:", 65, 35, AlignRight, AlignBottom, FontSecondary);
|
line_2_text->set_text("FC:", 65, 35, AlignRight, AlignBottom, FontSecondary);
|
||||||
line_3_text->set_text("Card:", 65, 47, AlignRight, AlignBottom, FontSecondary);
|
line_3_text->set_text("Card:", 65, 47, AlignRight, AlignBottom, FontSecondary);
|
||||||
@ -73,9 +74,6 @@ void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool need_restore) {
|
|||||||
line_3_value->set_text(
|
line_3_value->set_text(
|
||||||
string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary);
|
string_get_cstr(string[2]), 68, 47, AlignLeft, AlignBottom, FontSecondary);
|
||||||
break;
|
break;
|
||||||
case LfrfidKeyType::KeyI40134:
|
|
||||||
//TODO implement when we can read Indala
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app->view_controller.switch_to<ContainerVM>();
|
app->view_controller.switch_to<ContainerVM>();
|
||||||
|
|||||||
@ -18,7 +18,13 @@ bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
|
|||||||
notification_message(app->notification, &sequence_success);
|
notification_message(app->notification, &sequence_success);
|
||||||
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess);
|
app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess);
|
||||||
} else {
|
} else {
|
||||||
notification_message(app->notification, &sequence_blink_red_10);
|
if(app->worker.any_read()) {
|
||||||
|
notification_message(app->notification, &sequence_blink_green_10);
|
||||||
|
} else if(app->worker.detect()) {
|
||||||
|
notification_message(app->notification, &sequence_blink_blue_10);
|
||||||
|
} else {
|
||||||
|
notification_message(app->notification, &sequence_blink_red_10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
applications/lfrfid/scene/lfrfid-app-scene-save-name.cpp
Normal file → Executable file
@ -1,11 +1,12 @@
|
|||||||
#include "lfrfid-app-scene-save-name.h"
|
#include "lfrfid-app-scene-save-name.h"
|
||||||
#include "../helpers/rfid-name-generator.h"
|
#include <lib/toolbox/random_name.h>
|
||||||
|
|
||||||
void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool need_restore) {
|
void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool need_restore) {
|
||||||
const char* key_name = app->worker.key.get_name();
|
const char* key_name = app->worker.key.get_name();
|
||||||
|
|
||||||
if(strcmp(key_name, "") == 0) {
|
bool key_name_empty = !strcmp(key_name, "");
|
||||||
rfid_generate_random_name(app->text_store.text, app->text_store.text_size);
|
if(key_name_empty) {
|
||||||
|
set_random_name(app->text_store.text, app->text_store.text_size);
|
||||||
} else {
|
} else {
|
||||||
app->text_store.set("%s", key_name);
|
app->text_store.set("%s", key_name);
|
||||||
}
|
}
|
||||||
@ -14,7 +15,11 @@ void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool need_restore) {
|
|||||||
text_input->set_header_text("Name the card");
|
text_input->set_header_text("Name the card");
|
||||||
|
|
||||||
text_input->set_result_callback(
|
text_input->set_result_callback(
|
||||||
save_callback, app, app->text_store.text, app->worker.key.get_name_length());
|
save_callback,
|
||||||
|
app,
|
||||||
|
app->text_store.text,
|
||||||
|
app->worker.key.get_name_length(),
|
||||||
|
key_name_empty);
|
||||||
|
|
||||||
app->view_controller.switch_to<TextInputVM>();
|
app->view_controller.switch_to<TextInputVM>();
|
||||||
}
|
}
|
||||||
|
|||||||
7
applications/nfc/nfc.c
Normal file → Executable file
@ -7,10 +7,10 @@ bool nfc_custom_event_callback(void* context, uint32_t event) {
|
|||||||
return scene_manager_handle_custom_event(nfc->scene_manager, event);
|
return scene_manager_handle_custom_event(nfc->scene_manager, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool nfc_navigation_event_callback(void* context) {
|
bool nfc_back_event_callback(void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = (Nfc*)context;
|
||||||
return scene_manager_handle_navigation_event(nfc->scene_manager);
|
return scene_manager_handle_back_event(nfc->scene_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_tick_event_callback(void* context) {
|
void nfc_tick_event_callback(void* context) {
|
||||||
@ -28,8 +28,7 @@ Nfc* nfc_alloc() {
|
|||||||
view_dispatcher_enable_queue(nfc->view_dispatcher);
|
view_dispatcher_enable_queue(nfc->view_dispatcher);
|
||||||
view_dispatcher_set_event_callback_context(nfc->view_dispatcher, nfc);
|
view_dispatcher_set_event_callback_context(nfc->view_dispatcher, nfc);
|
||||||
view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback);
|
view_dispatcher_set_custom_event_callback(nfc->view_dispatcher, nfc_custom_event_callback);
|
||||||
view_dispatcher_set_navigation_event_callback(
|
view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback);
|
||||||
nfc->view_dispatcher, nfc_navigation_event_callback);
|
|
||||||
view_dispatcher_set_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100);
|
view_dispatcher_set_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100);
|
||||||
|
|
||||||
// Open GUI record
|
// Open GUI record
|
||||||
|
|||||||
@ -19,7 +19,6 @@ void nfc_cli_detect(Cli* cli, string_t args, void* context) {
|
|||||||
rfalNfcDevice* dev_list;
|
rfalNfcDevice* dev_list;
|
||||||
uint8_t dev_cnt = 0;
|
uint8_t dev_cnt = 0;
|
||||||
bool cmd_exit = false;
|
bool cmd_exit = false;
|
||||||
api_hal_nfc_init();
|
|
||||||
api_hal_nfc_exit_sleep();
|
api_hal_nfc_exit_sleep();
|
||||||
printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n");
|
printf("Detecting nfc...\r\nPress Ctrl+C to abort\r\n");
|
||||||
while(!cmd_exit) {
|
while(!cmd_exit) {
|
||||||
@ -51,7 +50,6 @@ void nfc_cli_emulate(Cli* cli, string_t args, void* context) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
api_hal_nfc_init();
|
|
||||||
api_hal_nfc_exit_sleep();
|
api_hal_nfc_exit_sleep();
|
||||||
printf("Emulating NFC-A Type: T2T UID: CF72D440 SAK: 20 ATQA: 00/04\r\n");
|
printf("Emulating NFC-A Type: T2T UID: CF72D440 SAK: 20 ATQA: 00/04\r\n");
|
||||||
printf("Press Ctrl+C to abort\r\n");
|
printf("Press Ctrl+C to abort\r\n");
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
#include "nfc_device_i.h"
|
#include "nfc_device_i.h"
|
||||||
|
|
||||||
#include <file-worker.h>
|
#include <file-worker.h>
|
||||||
#include <path.h>
|
#include <lib/toolbox/path.h>
|
||||||
#include <hex.h>
|
#include <lib/toolbox/hex.h>
|
||||||
|
|
||||||
#define NFC_DEVICE_MAX_DATA_LEN 14
|
#define NFC_DEVICE_MAX_DATA_LEN 14
|
||||||
|
|
||||||
@ -203,6 +203,10 @@ uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_
|
|||||||
for(uint8_t i = 0; i < sizeof(data->number); i++) {
|
for(uint8_t i = 0; i < sizeof(data->number); i++) {
|
||||||
string_cat_printf(bank_card_string, " %02X", data->number[i]);
|
string_cat_printf(bank_card_string, " %02X", data->number[i]);
|
||||||
}
|
}
|
||||||
|
if(data->exp_mon) {
|
||||||
|
string_cat_printf(
|
||||||
|
bank_card_string, "\nExp date: %02X/%02X", data->exp_mon, data->exp_year);
|
||||||
|
}
|
||||||
return string_size(bank_card_string);
|
return string_size(bank_card_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +240,14 @@ bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
parsed = true;
|
parsed = true;
|
||||||
|
// Check expiration date presence
|
||||||
|
ws = string_search_str(bank_card_string, "Exp date: ");
|
||||||
|
if(ws != STRING_FAILURE) {
|
||||||
|
// strlen("Exp date: ") = 10
|
||||||
|
string_right(bank_card_string, 10);
|
||||||
|
nfc_device_read_hex(bank_card_string, &data->exp_mon, 1);
|
||||||
|
nfc_device_read_hex(bank_card_string, &data->exp_year, 1);
|
||||||
|
}
|
||||||
} while(0);
|
} while(0);
|
||||||
|
|
||||||
return parsed;
|
return parsed;
|
||||||
|
|||||||
@ -42,7 +42,7 @@ typedef struct {
|
|||||||
uint16_t aid_len;
|
uint16_t aid_len;
|
||||||
uint8_t number[8];
|
uint8_t number[8];
|
||||||
uint8_t exp_mon;
|
uint8_t exp_mon;
|
||||||
uint16_t exp_year;
|
uint8_t exp_year;
|
||||||
char cardholder[32];
|
char cardholder[32];
|
||||||
} NfcEmvData;
|
} NfcEmvData;
|
||||||
|
|
||||||
|
|||||||
@ -15,9 +15,7 @@ NfcWorker* nfc_worker_alloc() {
|
|||||||
nfc_worker->callback = NULL;
|
nfc_worker->callback = NULL;
|
||||||
nfc_worker->context = NULL;
|
nfc_worker->context = NULL;
|
||||||
// Initialize rfal
|
// Initialize rfal
|
||||||
nfc_worker->error = api_hal_nfc_init();
|
if(!api_hal_nfc_is_busy()) {
|
||||||
if(nfc_worker->error == ERR_NONE) {
|
|
||||||
api_hal_nfc_start_sleep();
|
|
||||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
nfc_worker_change_state(nfc_worker, NfcWorkerStateReady);
|
||||||
} else {
|
} else {
|
||||||
nfc_worker_change_state(nfc_worker, NfcWorkerStateBroken);
|
nfc_worker_change_state(nfc_worker, NfcWorkerStateBroken);
|
||||||
@ -35,10 +33,6 @@ NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker) {
|
|||||||
return nfc_worker->state;
|
return nfc_worker->state;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnCode nfc_worker_get_error(NfcWorker* nfc_worker) {
|
|
||||||
return nfc_worker->error;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nfc_worker_start(
|
void nfc_worker_start(
|
||||||
NfcWorker* nfc_worker,
|
NfcWorker* nfc_worker,
|
||||||
NfcWorkerState state,
|
NfcWorkerState state,
|
||||||
@ -87,8 +81,8 @@ void nfc_worker_task(void* context) {
|
|||||||
nfc_worker_read_emv_app(nfc_worker);
|
nfc_worker_read_emv_app(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadEMV) {
|
} else if(nfc_worker->state == NfcWorkerStateReadEMV) {
|
||||||
nfc_worker_read_emv(nfc_worker);
|
nfc_worker_read_emv(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateEmulateEMV) {
|
} else if(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
||||||
nfc_worker_emulate_emv(nfc_worker);
|
nfc_worker_emulate_apdu(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateReadMifareUl) {
|
} else if(nfc_worker->state == NfcWorkerStateReadMifareUl) {
|
||||||
nfc_worker_read_mifare_ul(nfc_worker);
|
nfc_worker_read_mifare_ul(nfc_worker);
|
||||||
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
|
} else if(nfc_worker->state == NfcWorkerStateEmulateMifareUl) {
|
||||||
@ -330,6 +324,10 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
|||||||
result->emv_data.number,
|
result->emv_data.number,
|
||||||
emv_app.card_number,
|
emv_app.card_number,
|
||||||
sizeof(emv_app.card_number));
|
sizeof(emv_app.card_number));
|
||||||
|
if(emv_app.exp_month) {
|
||||||
|
result->emv_data.exp_mon = emv_app.exp_month;
|
||||||
|
result->emv_data.exp_year = emv_app.exp_year;
|
||||||
|
}
|
||||||
// Notify caller and exit
|
// Notify caller and exit
|
||||||
if(nfc_worker->callback) {
|
if(nfc_worker->callback) {
|
||||||
nfc_worker->callback(nfc_worker->context);
|
nfc_worker->callback(nfc_worker->context);
|
||||||
@ -354,7 +352,7 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nfc_worker_emulate_emv(NfcWorker* nfc_worker) {
|
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker) {
|
||||||
ReturnCode err;
|
ReturnCode err;
|
||||||
uint8_t tx_buff[255] = {};
|
uint8_t tx_buff[255] = {};
|
||||||
uint16_t tx_len = 0;
|
uint16_t tx_len = 0;
|
||||||
@ -368,9 +366,47 @@ void nfc_worker_emulate_emv(NfcWorker* nfc_worker) {
|
|||||||
.device = NfcDeviceNfca,
|
.device = NfcDeviceNfca,
|
||||||
.protocol = NfcDeviceProtocolEMV,
|
.protocol = NfcDeviceProtocolEMV,
|
||||||
};
|
};
|
||||||
|
// Test RX data
|
||||||
|
const uint8_t debug_rx[] = {
|
||||||
|
0xba, 0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca,
|
||||||
|
0xca, 0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
|
||||||
|
0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba,
|
||||||
|
0x0b, 0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca,
|
||||||
|
0xfe, 0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
|
||||||
|
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b,
|
||||||
|
0xba, 0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe,
|
||||||
|
0xfa, 0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
|
||||||
|
0xbb, 0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba,
|
||||||
|
0xba, 0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa,
|
||||||
|
0xce, 0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
|
||||||
|
0xcc, 0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba,
|
||||||
|
0x20, 0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce,
|
||||||
|
0x14, 0x88, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
|
||||||
|
0xdd, 0xee, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0xba, 0x0b, 0xba, 0xba, 0x20,
|
||||||
|
0x00, 0x02, 0x28, 0xde, 0xad, 0xbe, 0xef, 0x00, 0xca, 0xca, 0xca, 0xfe, 0xfa, 0xce, 0x14,
|
||||||
|
0x88, 0x00};
|
||||||
|
// Test TX data
|
||||||
|
const uint8_t debug_tx[] = {
|
||||||
|
0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32,
|
||||||
|
0x10, 0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad,
|
||||||
|
0xbe, 0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12,
|
||||||
|
0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,
|
||||||
|
0x14, 0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe,
|
||||||
|
0xef, 0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34,
|
||||||
|
0x56, 0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14,
|
||||||
|
0x88, 0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef,
|
||||||
|
0xce, 0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56,
|
||||||
|
0x78, 0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88,
|
||||||
|
0x02, 0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce,
|
||||||
|
0xee, 0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78,
|
||||||
|
0x9a, 0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02,
|
||||||
|
0x28, 0x00, 0x00, 0xca, 0xca, 0x00, 0xc0, 0xc0, 0x00, 0xde, 0xad, 0xbe, 0xef, 0xce, 0xee,
|
||||||
|
0xec, 0xca, 0xfe, 0xba, 0xba, 0xb0, 0xb0, 0xac, 0xdc, 0x11, 0x12, 0x34, 0x56, 0x78, 0x9a,
|
||||||
|
0xbc, 0xde, 0xff, 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x14, 0x88, 0x02, 0x28,
|
||||||
|
0x00, 0x00};
|
||||||
|
|
||||||
while(nfc_worker->state == NfcWorkerStateEmulateEMV) {
|
while(nfc_worker->state == NfcWorkerStateEmulateApdu) {
|
||||||
if(api_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 100)) {
|
if(api_hal_nfc_listen(params.uid, params.uid_len, params.atqa, params.sak, 300)) {
|
||||||
FURI_LOG_I(NFC_WORKER_TAG, "POS terminal detected");
|
FURI_LOG_I(NFC_WORKER_TAG, "POS terminal detected");
|
||||||
// Read data from POS terminal
|
// Read data from POS terminal
|
||||||
err = api_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false);
|
err = api_hal_nfc_data_exchange(NULL, 0, &rx_buff, &rx_len, false);
|
||||||
@ -407,7 +443,23 @@ void nfc_worker_emulate_emv(NfcWorker* nfc_worker) {
|
|||||||
tx_len = emv_get_proc_opt_ans(tx_buff);
|
tx_len = emv_get_proc_opt_ans(tx_buff);
|
||||||
err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
err = api_hal_nfc_data_exchange(tx_buff, tx_len, &rx_buff, &rx_len, false);
|
||||||
if(err == ERR_NONE) {
|
if(err == ERR_NONE) {
|
||||||
FURI_LOG_I(NFC_WORKER_TAG, "Received PDOL");
|
FURI_LOG_I(NFC_WORKER_TAG, "Transive PDOL ANS");
|
||||||
|
} else {
|
||||||
|
FURI_LOG_E(NFC_WORKER_TAG, "Error in 4rd data exchange: Transive PDOL ANS");
|
||||||
|
api_hal_nfc_deactivate();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(*rx_len != sizeof(debug_rx) || memcmp(rx_buff, debug_rx, sizeof(debug_rx))) {
|
||||||
|
FURI_LOG_E(NFC_WORKER_TAG, "Failed long message test");
|
||||||
|
} else {
|
||||||
|
FURI_LOG_I(NFC_WORKER_TAG, "Correct debug message received");
|
||||||
|
tx_len = sizeof(debug_tx);
|
||||||
|
err = api_hal_nfc_data_exchange(
|
||||||
|
(uint8_t*)debug_tx, tx_len, &rx_buff, &rx_len, false);
|
||||||
|
if(err == ERR_NONE) {
|
||||||
|
FURI_LOG_I(NFC_WORKER_TAG, "Transive Debug message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
api_hal_nfc_deactivate();
|
api_hal_nfc_deactivate();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -14,7 +14,7 @@ typedef enum {
|
|||||||
NfcWorkerStateEmulate,
|
NfcWorkerStateEmulate,
|
||||||
NfcWorkerStateReadEMVApp,
|
NfcWorkerStateReadEMVApp,
|
||||||
NfcWorkerStateReadEMV,
|
NfcWorkerStateReadEMV,
|
||||||
NfcWorkerStateEmulateEMV,
|
NfcWorkerStateEmulateApdu,
|
||||||
NfcWorkerStateField,
|
NfcWorkerStateField,
|
||||||
NfcWorkerStateReadMifareUl,
|
NfcWorkerStateReadMifareUl,
|
||||||
NfcWorkerStateEmulateMifareUl,
|
NfcWorkerStateEmulateMifareUl,
|
||||||
@ -28,8 +28,6 @@ NfcWorker* nfc_worker_alloc();
|
|||||||
|
|
||||||
NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker);
|
NfcWorkerState nfc_worker_get_state(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
ReturnCode nfc_worker_get_error(NfcWorker* nfc_worker);
|
|
||||||
|
|
||||||
void nfc_worker_free(NfcWorker* nfc_worker);
|
void nfc_worker_free(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
void nfc_worker_start(
|
void nfc_worker_start(
|
||||||
|
|||||||
@ -26,7 +26,6 @@ struct NfcWorker {
|
|||||||
void* context;
|
void* context;
|
||||||
|
|
||||||
NfcWorkerState state;
|
NfcWorkerState state;
|
||||||
ReturnCode error;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);
|
void nfc_worker_change_state(NfcWorker* nfc_worker, NfcWorkerState state);
|
||||||
@ -37,7 +36,7 @@ void nfc_worker_read_emv_app(NfcWorker* nfc_worker);
|
|||||||
|
|
||||||
void nfc_worker_read_emv(NfcWorker* nfc_worker);
|
void nfc_worker_read_emv(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
void nfc_worker_emulate_emv(NfcWorker* nfc_worker);
|
void nfc_worker_emulate_apdu(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
void nfc_worker_detect(NfcWorker* nfc_worker);
|
void nfc_worker_detect(NfcWorker* nfc_worker);
|
||||||
|
|
||||||
|
|||||||
@ -70,8 +70,9 @@ const bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event)
|
|||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeNavigation) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
return scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart);
|
return scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -25,3 +25,4 @@ ADD_SCENE(nfc, delete_success, DeleteSuccess)
|
|||||||
ADD_SCENE(nfc, run_emv_app_confirm, RunEmvAppConfirm)
|
ADD_SCENE(nfc, run_emv_app_confirm, RunEmvAppConfirm)
|
||||||
ADD_SCENE(nfc, read_emv_data, ReadEmvData)
|
ADD_SCENE(nfc, read_emv_data, ReadEmvData)
|
||||||
ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess)
|
ADD_SCENE(nfc, read_emv_data_success, ReadEmvDataSuccess)
|
||||||
|
ADD_SCENE(nfc, emulate_apdu_sequence, EmulateApduSequence)
|
||||||
|
|||||||
3
applications/nfc/scenes/nfc_scene_delete.c
Normal file → Executable file
@ -75,7 +75,8 @@ const bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
|
|||||||
if(nfc_device_delete(&nfc->dev)) {
|
if(nfc_device_delete(&nfc->dev)) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart);
|
scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
3
applications/nfc/scenes/nfc_scene_delete_success.c
Normal file → Executable file
@ -26,7 +26,8 @@ const bool nfc_scene_delete_success_on_event(void* context, SceneManagerEvent ev
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
|
if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
|
||||||
return scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart);
|
return scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
38
applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#include "../nfc_i.h"
|
||||||
|
|
||||||
|
const void nfc_scene_emulate_apdu_sequence_on_enter(void* context) {
|
||||||
|
Nfc* nfc = (Nfc*)context;
|
||||||
|
|
||||||
|
// Setup view
|
||||||
|
Popup* popup = nfc->popup;
|
||||||
|
|
||||||
|
popup_set_header(popup, "Run APDU reader", 64, 31, AlignCenter, AlignTop);
|
||||||
|
|
||||||
|
// Setup and start worker
|
||||||
|
|
||||||
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
|
||||||
|
nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev.dev_data, NULL, nfc);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) {
|
||||||
|
Nfc* nfc = (Nfc*)context;
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeTick) {
|
||||||
|
notification_message(nfc->notifications, &sequence_blink_blue_10);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void nfc_scene_emulate_apdu_sequence_on_exit(void* context) {
|
||||||
|
Nfc* nfc = (Nfc*)context;
|
||||||
|
|
||||||
|
// Stop worker
|
||||||
|
nfc_worker_stop(nfc->worker);
|
||||||
|
|
||||||
|
// Clear view
|
||||||
|
Popup* popup = nfc->popup;
|
||||||
|
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
|
||||||
|
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
|
||||||
|
popup_set_icon(popup, 0, 0, NULL);
|
||||||
|
}
|
||||||
@ -6,7 +6,7 @@ const void nfc_scene_file_select_on_enter(void* context) {
|
|||||||
if(nfc_file_select(&nfc->dev)) {
|
if(nfc_file_select(&nfc->dev)) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart);
|
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
5
applications/nfc/scenes/nfc_scene_mifare_ul_menu.c
Normal file → Executable file
@ -41,8 +41,9 @@ const bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent ev
|
|||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneNotImplemented);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeNavigation) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
return scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart);
|
return scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -59,6 +59,12 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
|
|||||||
char sak_str[16];
|
char sak_str[16];
|
||||||
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak);
|
snprintf(sak_str, sizeof(sak_str), "SAK: %02X", nfc_data->sak);
|
||||||
widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str);
|
widget_add_string_element(nfc->widget, 121, 42, AlignRight, AlignTop, FontSecondary, sak_str);
|
||||||
|
if(emv_data->exp_mon) {
|
||||||
|
char exp_str[16];
|
||||||
|
snprintf(
|
||||||
|
exp_str, sizeof(exp_str), "Exp: %02X/%02X", emv_data->exp_mon, emv_data->exp_year);
|
||||||
|
widget_add_string_element(nfc->widget, 7, 32, AlignLeft, AlignTop, FontSecondary, exp_str);
|
||||||
|
}
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
|
||||||
}
|
}
|
||||||
@ -68,15 +74,16 @@ const bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerE
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == GuiButtonTypeLeft) {
|
if(event.event == GuiButtonTypeLeft) {
|
||||||
return scene_manager_search_previous_scene(
|
return scene_manager_search_and_switch_to_previous_scene(
|
||||||
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
||||||
} else if(event.event == GuiButtonTypeRight) {
|
} else if(event.event == GuiButtonTypeRight) {
|
||||||
nfc->dev.format = NfcDeviceSaveFormatBankCard;
|
nfc->dev.format = NfcDeviceSaveFormatBankCard;
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeNavigation) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
return scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
return scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneReadEmvAppSuccess);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
#include "../nfc_i.h"
|
#include "../nfc_i.h"
|
||||||
|
#include <lib/toolbox/random_name.h>
|
||||||
|
|
||||||
#define SCENE_SAVE_NAME_CUSTOM_EVENT (0UL)
|
#define SCENE_SAVE_NAME_CUSTOM_EVENT (0UL)
|
||||||
|
|
||||||
@ -13,17 +14,21 @@ const void nfc_scene_save_name_on_enter(void* context) {
|
|||||||
|
|
||||||
// Setup view
|
// Setup view
|
||||||
TextInput* text_input = nfc->text_input;
|
TextInput* text_input = nfc->text_input;
|
||||||
if(nfc->dev.dev_name) {
|
bool dev_name_empty = false;
|
||||||
nfc_device_delete(&nfc->dev);
|
if(!strcmp(nfc->dev.dev_name, "")) {
|
||||||
|
set_random_name(nfc->text_store, sizeof(nfc->text_store));
|
||||||
|
dev_name_empty = true;
|
||||||
|
} else {
|
||||||
|
nfc_text_store_set(nfc, nfc->dev.dev_name);
|
||||||
}
|
}
|
||||||
nfc_text_store_set(nfc, nfc->dev.dev_name);
|
|
||||||
text_input_set_header_text(text_input, "Name the card");
|
text_input_set_header_text(text_input, "Name the card");
|
||||||
text_input_set_result_callback(
|
text_input_set_result_callback(
|
||||||
text_input,
|
text_input,
|
||||||
nfc_scene_save_name_text_input_callback,
|
nfc_scene_save_name_text_input_callback,
|
||||||
nfc,
|
nfc,
|
||||||
nfc->text_store,
|
nfc->text_store,
|
||||||
sizeof(nfc->text_store));
|
NFC_DEV_NAME_MAX_LEN,
|
||||||
|
dev_name_empty);
|
||||||
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput);
|
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,12 +37,16 @@ const bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event)
|
|||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) {
|
if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) {
|
||||||
|
if(nfc->dev.dev_name) {
|
||||||
|
nfc_device_delete(&nfc->dev);
|
||||||
|
}
|
||||||
memcpy(&nfc->dev.dev_name, nfc->text_store, strlen(nfc->text_store));
|
memcpy(&nfc->dev.dev_name, nfc->text_store, strlen(nfc->text_store));
|
||||||
if(nfc_device_save(&nfc->dev, nfc->text_store)) {
|
if(nfc_device_save(&nfc->dev, nfc->text_store)) {
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart);
|
return scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneStart);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,4 +58,5 @@ const void nfc_scene_save_name_on_exit(void* context) {
|
|||||||
|
|
||||||
// Clear view
|
// Clear view
|
||||||
text_input_set_header_text(nfc->text_input, NULL);
|
text_input_set_header_text(nfc->text_input, NULL);
|
||||||
|
text_input_set_result_callback(nfc->text_input, NULL, NULL, NULL, 0, false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -23,13 +23,23 @@ const void nfc_scene_save_success_on_enter(void* context) {
|
|||||||
|
|
||||||
const bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
const bool nfc_scene_save_success_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = (Nfc*)context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
|
if(event.event == SCENE_SAVE_SUCCESS_CUSTOM_EVENT) {
|
||||||
return scene_manager_search_previous_scene(nfc->scene_manager, NfcSceneStart);
|
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneCardMenu)) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneCardMenu);
|
||||||
|
} else if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
|
||||||
|
consumed = scene_manager_search_and_switch_to_another_scene(
|
||||||
|
nfc->scene_manager, NfcSceneFileSelect);
|
||||||
|
} else {
|
||||||
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
nfc->scene_manager, NfcSceneStart);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void nfc_scene_save_success_on_exit(void* context) {
|
const void nfc_scene_save_success_on_exit(void* context) {
|
||||||
|
|||||||
@ -5,6 +5,7 @@ enum SubmenuIndex {
|
|||||||
SubmenuIndexRunScript,
|
SubmenuIndexRunScript,
|
||||||
SubmenuIndexSaved,
|
SubmenuIndexSaved,
|
||||||
SubmenuIndexAddManualy,
|
SubmenuIndexAddManualy,
|
||||||
|
SubmenuIndexDebug,
|
||||||
};
|
};
|
||||||
|
|
||||||
void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
|
void nfc_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||||
@ -29,6 +30,7 @@ const void nfc_scene_start_on_enter(void* context) {
|
|||||||
submenu, "Saved cards", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc);
|
submenu, "Saved cards", SubmenuIndexSaved, nfc_scene_start_submenu_callback, nfc);
|
||||||
submenu_add_item(
|
submenu_add_item(
|
||||||
submenu, "Add manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc);
|
submenu, "Add manually", SubmenuIndexAddManualy, nfc_scene_start_submenu_callback, nfc);
|
||||||
|
submenu_add_item(submenu, "Debug", SubmenuIndexDebug, nfc_scene_start_submenu_callback, nfc);
|
||||||
submenu_set_selected_item(
|
submenu_set_selected_item(
|
||||||
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart));
|
submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart));
|
||||||
|
|
||||||
@ -38,29 +40,34 @@ const void nfc_scene_start_on_enter(void* context) {
|
|||||||
|
|
||||||
const bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
const bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||||
Nfc* nfc = (Nfc*)context;
|
Nfc* nfc = (Nfc*)context;
|
||||||
|
bool consumed = false;
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
if(event.event == SubmenuIndexRead) {
|
if(event.event == SubmenuIndexRead) {
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexRead);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCard);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCard);
|
||||||
return true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexRunScript) {
|
} else if(event.event == SubmenuIndexRunScript) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneStart, SubmenuIndexRunScript);
|
nfc->scene_manager, NfcSceneStart, SubmenuIndexRunScript);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneScriptsMenu);
|
||||||
return true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexSaved) {
|
} else if(event.event == SubmenuIndexSaved) {
|
||||||
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexSaved);
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexSaved);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneFileSelect);
|
||||||
return true;
|
consumed = true;
|
||||||
} else if(event.event == SubmenuIndexAddManualy) {
|
} else if(event.event == SubmenuIndexAddManualy) {
|
||||||
scene_manager_set_scene_state(
|
scene_manager_set_scene_state(
|
||||||
nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManualy);
|
nfc->scene_manager, NfcSceneStart, SubmenuIndexAddManualy);
|
||||||
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneSetType);
|
||||||
return true;
|
consumed = true;
|
||||||
|
} else if(event.event == SubmenuIndexDebug) {
|
||||||
|
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneStart, SubmenuIndexDebug);
|
||||||
|
scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateApduSequence);
|
||||||
|
consumed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return consumed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void nfc_scene_start_on_exit(void* context) {
|
const void nfc_scene_start_on_exit(void* context) {
|
||||||
|
|||||||
@ -49,10 +49,10 @@ void bank_card_set_number(BankCard* bank_card, uint8_t* number) {
|
|||||||
string_clear(num_str);
|
string_clear(num_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint16_t year) {
|
void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) {
|
||||||
furi_assert(bank_card);
|
furi_assert(bank_card);
|
||||||
char exp_date_str[16];
|
char exp_date_str[16];
|
||||||
snprintf(exp_date_str, sizeof(exp_date_str), "Exp: %02d/%02d", mon, year % 100);
|
snprintf(exp_date_str, sizeof(exp_date_str), "Exp: %02X/%02X", mon, year);
|
||||||
widget_add_string_element(
|
widget_add_string_element(
|
||||||
bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str);
|
bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,6 @@ void bank_card_set_name(BankCard* bank_card, char* name);
|
|||||||
|
|
||||||
void bank_card_set_number(BankCard* bank_card, uint8_t* number);
|
void bank_card_set_number(BankCard* bank_card, uint8_t* number);
|
||||||
|
|
||||||
void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint16_t year);
|
void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year);
|
||||||
|
|
||||||
void bank_card_set_cardholder_name(BankCard* bank_card, char* name);
|
void bank_card_set_cardholder_name(BankCard* bank_card, char* name);
|
||||||
|
|||||||
@ -74,7 +74,7 @@ uint8_t float_value_index(const float value, const float values[], uint8_t value
|
|||||||
const float epsilon = 0.01f;
|
const float epsilon = 0.01f;
|
||||||
float last_value = values[0];
|
float last_value = values[0];
|
||||||
uint8_t index = 0;
|
uint8_t index = 0;
|
||||||
for(uint8_t i = 1; i < values_count; i++) {
|
for(uint8_t i = 0; i < values_count; i++) {
|
||||||
if((value >= last_value - epsilon) && (value <= values[i] + epsilon)) {
|
if((value >= last_value - epsilon) && (value <= values[i] + epsilon)) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
@ -85,9 +85,9 @@ uint8_t float_value_index(const float value, const float values[], uint8_t value
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t uint32_value_index(const uint32_t value, const uint32_t values[], uint8_t values_count) {
|
uint8_t uint32_value_index(const uint32_t value, const uint32_t values[], uint8_t values_count) {
|
||||||
float last_value = values[0];
|
int64_t last_value = INT64_MIN;
|
||||||
uint8_t index = 0;
|
uint8_t index = 0;
|
||||||
for(uint8_t i = 1; i < values_count; i++) {
|
for(uint8_t i = 0; i < values_count; i++) {
|
||||||
if((value >= last_value) && (value <= values[i])) {
|
if((value >= last_value) && (value <= values[i])) {
|
||||||
index = i;
|
index = i;
|
||||||
break;
|
break;
|
||||||
|
|||||||
33
applications/power-observer/power-observer.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#include <furi.h>
|
||||||
|
#include <api-hal.h>
|
||||||
|
#include <notification/notification-messages.h>
|
||||||
|
|
||||||
|
const NotificationMessage message_green_110 = {
|
||||||
|
.type = NotificationMessageTypeLedGreen,
|
||||||
|
.data.led.value = 110,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const NotificationSequence sequence_overconsumption = {
|
||||||
|
&message_green_110,
|
||||||
|
&message_red_255,
|
||||||
|
&message_delay_100,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
int32_t power_observer(void* p) {
|
||||||
|
NotificationApp* notifications = furi_record_open("notification");
|
||||||
|
|
||||||
|
const float overconsumption_limit = 0.03f;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
float current = -api_hal_power_get_battery_current(ApiHalPowerICFuelGauge);
|
||||||
|
|
||||||
|
if(current >= overconsumption_limit) {
|
||||||
|
notification_message_block(notifications, &sequence_overconsumption);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@ -43,6 +43,16 @@ void power_cli_otg(Cli* cli, string_t args, void* context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void power_cli_ext(Cli* cli, string_t args, void* context) {
|
||||||
|
if(!string_cmp(args, "0")) {
|
||||||
|
api_hal_power_disable_external_3_3v();
|
||||||
|
} else if(!string_cmp(args, "1")) {
|
||||||
|
api_hal_power_enable_external_3_3v();
|
||||||
|
} else {
|
||||||
|
cli_print_usage("power_ext", "<1|0>", string_get_cstr(args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void power_cli_init(Cli* cli, Power* power) {
|
void power_cli_init(Cli* cli, Power* power) {
|
||||||
cli_add_command(cli, "poweroff", CliCommandFlagParallelSafe, power_cli_poweroff, power);
|
cli_add_command(cli, "poweroff", CliCommandFlagParallelSafe, power_cli_poweroff, power);
|
||||||
cli_add_command(cli, "reboot", CliCommandFlagParallelSafe, power_cli_reboot, power);
|
cli_add_command(cli, "reboot", CliCommandFlagParallelSafe, power_cli_reboot, power);
|
||||||
@ -51,4 +61,5 @@ void power_cli_init(Cli* cli, Power* power) {
|
|||||||
cli_add_command(cli, "dfu", CliCommandFlagParallelSafe, power_cli_dfu, power);
|
cli_add_command(cli, "dfu", CliCommandFlagParallelSafe, power_cli_dfu, power);
|
||||||
cli_add_command(cli, "power_info", CliCommandFlagParallelSafe, power_cli_info, power);
|
cli_add_command(cli, "power_info", CliCommandFlagParallelSafe, power_cli_info, power);
|
||||||
cli_add_command(cli, "power_otg", CliCommandFlagParallelSafe, power_cli_otg, power);
|
cli_add_command(cli, "power_otg", CliCommandFlagParallelSafe, power_cli_otg, power);
|
||||||
|
cli_add_command(cli, "power_ext", CliCommandFlagParallelSafe, power_cli_ext, power);
|
||||||
}
|
}
|
||||||
|
|||||||
9
applications/storage-settings/scenes/storage-settings-scene-ejected.c
Normal file → Executable file
@ -40,12 +40,13 @@ bool storage_settings_scene_unmounted_on_event(void* context, SceneManagerEvent
|
|||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
switch(event.event) {
|
switch(event.event) {
|
||||||
case DialogExResultLeft:
|
case DialogExResultLeft:
|
||||||
consumed =
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
scene_manager_search_previous_scene(app->scene_manager, StorageSettingsStart);
|
app->scene_manager, StorageSettingsStart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeNavigation) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
consumed = scene_manager_search_previous_scene(app->scene_manager, StorageSettingsStart);
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
app->scene_manager, StorageSettingsStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
|
|||||||
9
applications/storage-settings/scenes/storage-settings-scene-formatting.c
Normal file → Executable file
@ -60,12 +60,13 @@ bool storage_settings_scene_formatting_on_event(void* context, SceneManagerEvent
|
|||||||
if(event.type == SceneManagerEventTypeCustom) {
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
switch(event.event) {
|
switch(event.event) {
|
||||||
case DialogExResultLeft:
|
case DialogExResultLeft:
|
||||||
consumed =
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
scene_manager_search_previous_scene(app->scene_manager, StorageSettingsStart);
|
app->scene_manager, StorageSettingsStart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if(event.type == SceneManagerEventTypeNavigation) {
|
} else if(event.type == SceneManagerEventTypeBack) {
|
||||||
consumed = scene_manager_search_previous_scene(app->scene_manager, StorageSettingsStart);
|
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||||
|
app->scene_manager, StorageSettingsStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
return consumed;
|
return consumed;
|
||||||
|
|||||||
@ -6,10 +6,10 @@ static bool storage_settings_custom_event_callback(void* context, uint32_t event
|
|||||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool storage_settings_navigation_event_callback(void* context) {
|
static bool storage_settings_back_event_callback(void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
StorageSettings* app = context;
|
StorageSettings* app = context;
|
||||||
return scene_manager_handle_navigation_event(app->scene_manager);
|
return scene_manager_handle_back_event(app->scene_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
static StorageSettings* storage_settings_alloc() {
|
static StorageSettings* storage_settings_alloc() {
|
||||||
@ -29,7 +29,7 @@ static StorageSettings* storage_settings_alloc() {
|
|||||||
view_dispatcher_set_custom_event_callback(
|
view_dispatcher_set_custom_event_callback(
|
||||||
app->view_dispatcher, storage_settings_custom_event_callback);
|
app->view_dispatcher, storage_settings_custom_event_callback);
|
||||||
view_dispatcher_set_navigation_event_callback(
|
view_dispatcher_set_navigation_event_callback(
|
||||||
app->view_dispatcher, storage_settings_navigation_event_callback);
|
app->view_dispatcher, storage_settings_back_event_callback);
|
||||||
|
|
||||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <cli/cli.h>
|
#include <cli/cli.h>
|
||||||
#include <args.h>
|
#include <lib/toolbox/args.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
#include <storage/storage-sd-api.h>
|
#include <storage/storage-sd-api.h>
|
||||||
#include <api-hal-version.h>
|
#include <api-hal-version.h>
|
||||||
@ -30,6 +30,7 @@ void storage_cli_print_usage() {
|
|||||||
"\twrite\t - read data from cli and append it to file, <args> should contain how many bytes you want to write\r\n");
|
"\twrite\t - read data from cli and append it to file, <args> should contain how many bytes you want to write\r\n");
|
||||||
printf("\tcopy\t - copy file to new file, <args> must contain new path\r\n");
|
printf("\tcopy\t - copy file to new file, <args> must contain new path\r\n");
|
||||||
printf("\trename\t - move file to new file, <args> must contain new path\r\n");
|
printf("\trename\t - move file to new file, <args> must contain new path\r\n");
|
||||||
|
printf("\tmkdir\t - creates a new directory\r\n");
|
||||||
};
|
};
|
||||||
|
|
||||||
void storage_cli_print_error(FS_Error error) {
|
void storage_cli_print_error(FS_Error error) {
|
||||||
@ -285,6 +286,17 @@ void storage_cli_rename(Cli* cli, string_t old_path, string_t args) {
|
|||||||
furi_record_close("storage");
|
furi_record_close("storage");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void storage_cli_mkdir(Cli* cli, string_t path) {
|
||||||
|
Storage* api = furi_record_open("storage");
|
||||||
|
FS_Error error = storage_common_mkdir(api, string_get_cstr(path));
|
||||||
|
|
||||||
|
if(error != FSE_OK) {
|
||||||
|
storage_cli_print_error(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_record_close("storage");
|
||||||
|
}
|
||||||
|
|
||||||
void storage_cli(Cli* cli, string_t args, void* context) {
|
void storage_cli(Cli* cli, string_t args, void* context) {
|
||||||
string_t cmd;
|
string_t cmd;
|
||||||
string_t path;
|
string_t path;
|
||||||
@ -342,6 +354,11 @@ void storage_cli(Cli* cli, string_t args, void* context) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(string_cmp_str(cmd, "mkdir") == 0) {
|
||||||
|
storage_cli_mkdir(cli, path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
storage_cli_print_usage();
|
storage_cli_print_usage();
|
||||||
} while(false);
|
} while(false);
|
||||||
|
|
||||||
|
|||||||
@ -10,67 +10,67 @@ extern const Icon A_MDWRB_32x32;
|
|||||||
extern const Icon A_MDWR_32x32;
|
extern const Icon A_MDWR_32x32;
|
||||||
extern const Icon A_WatchingTV_128x64;
|
extern const Icon A_WatchingTV_128x64;
|
||||||
extern const Icon A_Wink_128x64;
|
extern const Icon A_Wink_128x64;
|
||||||
extern const Icon I_125_10px;
|
|
||||||
extern const Icon I_ble_10px;
|
|
||||||
extern const Icon I_dir_10px;
|
extern const Icon I_dir_10px;
|
||||||
extern const Icon I_ibutt_10px;
|
|
||||||
extern const Icon I_ir_10px;
|
|
||||||
extern const Icon I_Nfc_10px;
|
extern const Icon I_Nfc_10px;
|
||||||
extern const Icon I_sub1_10px;
|
extern const Icon I_sub1_10px;
|
||||||
|
extern const Icon I_ir_10px;
|
||||||
|
extern const Icon I_ibutt_10px;
|
||||||
extern const Icon I_unknown_10px;
|
extern const Icon I_unknown_10px;
|
||||||
extern const Icon I_ButtonCenter_7x7;
|
extern const Icon I_ble_10px;
|
||||||
extern const Icon I_ButtonLeftSmall_3x5;
|
extern const Icon I_125_10px;
|
||||||
extern const Icon I_ButtonLeft_4x7;
|
|
||||||
extern const Icon I_ButtonRightSmall_3x5;
|
extern const Icon I_ButtonRightSmall_3x5;
|
||||||
|
extern const Icon I_ButtonLeft_4x7;
|
||||||
|
extern const Icon I_ButtonLeftSmall_3x5;
|
||||||
extern const Icon I_ButtonRight_4x7;
|
extern const Icon I_ButtonRight_4x7;
|
||||||
extern const Icon I_BigBurger_24x24;
|
extern const Icon I_ButtonCenter_7x7;
|
||||||
|
extern const Icon I_FX_SittingB_40x27;
|
||||||
extern const Icon I_BigGames_24x24;
|
extern const Icon I_BigGames_24x24;
|
||||||
extern const Icon I_BigProfile_24x24;
|
extern const Icon I_BigProfile_24x24;
|
||||||
extern const Icon I_DolphinFirstStart0_70x53;
|
|
||||||
extern const Icon I_DolphinFirstStart1_59x53;
|
|
||||||
extern const Icon I_DolphinFirstStart2_59x51;
|
|
||||||
extern const Icon I_DolphinFirstStart3_57x48;
|
|
||||||
extern const Icon I_DolphinFirstStart4_67x53;
|
|
||||||
extern const Icon I_DolphinFirstStart5_45x53;
|
|
||||||
extern const Icon I_DolphinFirstStart6_58x54;
|
|
||||||
extern const Icon I_DolphinFirstStart7_61x51;
|
|
||||||
extern const Icon I_DolphinFirstStart8_56x51;
|
|
||||||
extern const Icon I_DolphinOkay_41x43;
|
extern const Icon I_DolphinOkay_41x43;
|
||||||
|
extern const Icon I_DolphinFirstStart4_67x53;
|
||||||
|
extern const Icon I_DolphinFirstStart2_59x51;
|
||||||
|
extern const Icon I_DolphinFirstStart5_54x49;
|
||||||
|
extern const Icon I_DolphinFirstStart0_70x53;
|
||||||
|
extern const Icon I_DolphinFirstStart6_58x54;
|
||||||
|
extern const Icon I_DolphinFirstStart1_59x53;
|
||||||
|
extern const Icon I_DolphinFirstStart8_56x51;
|
||||||
|
extern const Icon I_DolphinFirstStart7_61x51;
|
||||||
extern const Icon I_Flipper_young_80x60;
|
extern const Icon I_Flipper_young_80x60;
|
||||||
|
extern const Icon I_BigBurger_24x24;
|
||||||
extern const Icon I_FX_Bang_32x6;
|
extern const Icon I_FX_Bang_32x6;
|
||||||
extern const Icon I_FX_SittingB_40x27;
|
extern const Icon I_DolphinFirstStart3_57x48;
|
||||||
extern const Icon I_DoorLeft_70x55;
|
extern const Icon I_PassportBottom_128x17;
|
||||||
extern const Icon I_DoorLeft_8x56;
|
extern const Icon I_DoorLeft_8x56;
|
||||||
extern const Icon I_DoorLocked_10x56;
|
extern const Icon I_DoorLocked_10x56;
|
||||||
extern const Icon I_DoorRight_70x55;
|
|
||||||
extern const Icon I_DoorRight_8x56;
|
extern const Icon I_DoorRight_8x56;
|
||||||
extern const Icon I_LockPopup_100x49;
|
extern const Icon I_DoorLeft_70x55;
|
||||||
extern const Icon I_PassportBottom_128x17;
|
|
||||||
extern const Icon I_PassportLeft_6x47;
|
extern const Icon I_PassportLeft_6x47;
|
||||||
extern const Icon I_Back_15x10;
|
extern const Icon I_DoorRight_70x55;
|
||||||
|
extern const Icon I_LockPopup_100x49;
|
||||||
|
extern const Icon I_Mute_25x27;
|
||||||
|
extern const Icon I_IrdaArrowUp_4x8;
|
||||||
|
extern const Icon I_Up_hvr_25x27;
|
||||||
|
extern const Icon I_Mute_hvr_25x27;
|
||||||
|
extern const Icon I_Vol_down_25x27;
|
||||||
extern const Icon I_Down_25x27;
|
extern const Icon I_Down_25x27;
|
||||||
|
extern const Icon I_Power_hvr_25x27;
|
||||||
|
extern const Icon I_IrdaLearnShort_128x31;
|
||||||
|
extern const Icon I_IrdaArrowDown_4x8;
|
||||||
|
extern const Icon I_Vol_down_hvr_25x27;
|
||||||
|
extern const Icon I_IrdaLearn_128x64;
|
||||||
extern const Icon I_Down_hvr_25x27;
|
extern const Icon I_Down_hvr_25x27;
|
||||||
extern const Icon I_Fill_marker_7x7;
|
extern const Icon I_Fill_marker_7x7;
|
||||||
extern const Icon I_IrdaArrowDown_4x8;
|
|
||||||
extern const Icon I_IrdaArrowUp_4x8;
|
|
||||||
extern const Icon I_IrdaLearnShort_128x31;
|
|
||||||
extern const Icon I_IrdaLearn_128x64;
|
|
||||||
extern const Icon I_IrdaSendShort_128x34;
|
|
||||||
extern const Icon I_IrdaSend_128x64;
|
|
||||||
extern const Icon I_Mute_25x27;
|
|
||||||
extern const Icon I_Mute_hvr_25x27;
|
|
||||||
extern const Icon I_Power_25x27;
|
extern const Icon I_Power_25x27;
|
||||||
extern const Icon I_Power_hvr_25x27;
|
|
||||||
extern const Icon I_Up_25x27;
|
|
||||||
extern const Icon I_Up_hvr_25x27;
|
|
||||||
extern const Icon I_Vol_down_25x27;
|
|
||||||
extern const Icon I_Vol_down_hvr_25x27;
|
|
||||||
extern const Icon I_Vol_up_25x27;
|
extern const Icon I_Vol_up_25x27;
|
||||||
|
extern const Icon I_Up_25x27;
|
||||||
|
extern const Icon I_Back_15x10;
|
||||||
|
extern const Icon I_IrdaSend_128x64;
|
||||||
|
extern const Icon I_IrdaSendShort_128x34;
|
||||||
extern const Icon I_Vol_up_hvr_25x27;
|
extern const Icon I_Vol_up_hvr_25x27;
|
||||||
extern const Icon I_KeyBackspaceSelected_16x9;
|
|
||||||
extern const Icon I_KeyBackspace_16x9;
|
|
||||||
extern const Icon I_KeySaveSelected_24x11;
|
|
||||||
extern const Icon I_KeySave_24x11;
|
extern const Icon I_KeySave_24x11;
|
||||||
|
extern const Icon I_KeyBackspaceSelected_16x9;
|
||||||
|
extern const Icon I_KeySaveSelected_24x11;
|
||||||
|
extern const Icon I_KeyBackspace_16x9;
|
||||||
extern const Icon A_125khz_14;
|
extern const Icon A_125khz_14;
|
||||||
extern const Icon A_Bluetooth_14;
|
extern const Icon A_Bluetooth_14;
|
||||||
extern const Icon A_FileManager_14;
|
extern const Icon A_FileManager_14;
|
||||||
@ -86,61 +86,141 @@ extern const Icon A_Sub1ghz_14;
|
|||||||
extern const Icon A_Tamagotchi_14;
|
extern const Icon A_Tamagotchi_14;
|
||||||
extern const Icon A_U2F_14;
|
extern const Icon A_U2F_14;
|
||||||
extern const Icon A_iButton_14;
|
extern const Icon A_iButton_14;
|
||||||
extern const Icon I_EMV_Chip_14x11;
|
|
||||||
extern const Icon I_Medium_chip_22x21;
|
extern const Icon I_Medium_chip_22x21;
|
||||||
extern const Icon I_passport_bad1_43x45;
|
extern const Icon I_EMV_Chip_14x11;
|
||||||
extern const Icon I_passport_bad2_43x45;
|
|
||||||
extern const Icon I_passport_bad3_43x45;
|
|
||||||
extern const Icon I_passport_happy1_43x45;
|
extern const Icon I_passport_happy1_43x45;
|
||||||
extern const Icon I_passport_happy2_43x45;
|
extern const Icon I_passport_bad3_43x45;
|
||||||
extern const Icon I_passport_happy3_43x45;
|
|
||||||
extern const Icon I_passport_okay1_43x45;
|
|
||||||
extern const Icon I_passport_okay2_43x45;
|
extern const Icon I_passport_okay2_43x45;
|
||||||
|
extern const Icon I_passport_bad2_43x45;
|
||||||
extern const Icon I_passport_okay3_43x45;
|
extern const Icon I_passport_okay3_43x45;
|
||||||
extern const Icon I_BatteryBody_52x28;
|
extern const Icon I_passport_bad1_43x45;
|
||||||
extern const Icon I_Battery_16x16;
|
extern const Icon I_passport_happy3_43x45;
|
||||||
|
extern const Icon I_passport_happy2_43x45;
|
||||||
|
extern const Icon I_passport_okay1_43x45;
|
||||||
|
extern const Icon I_Health_16x16;
|
||||||
extern const Icon I_FaceCharging_29x14;
|
extern const Icon I_FaceCharging_29x14;
|
||||||
extern const Icon I_FaceConfused_29x14;
|
extern const Icon I_BatteryBody_52x28;
|
||||||
|
extern const Icon I_Voltage_16x16;
|
||||||
|
extern const Icon I_Temperature_16x16;
|
||||||
extern const Icon I_FaceNopower_29x14;
|
extern const Icon I_FaceNopower_29x14;
|
||||||
extern const Icon I_FaceNormal_29x14;
|
extern const Icon I_FaceNormal_29x14;
|
||||||
extern const Icon I_Health_16x16;
|
extern const Icon I_Battery_16x16;
|
||||||
extern const Icon I_Temperature_16x16;
|
extern const Icon I_FaceConfused_29x14;
|
||||||
extern const Icon I_Voltage_16x16;
|
|
||||||
extern const Icon I_RFIDBigChip_37x36;
|
|
||||||
extern const Icon I_RFIDDolphinReceive_97x61;
|
|
||||||
extern const Icon I_RFIDDolphinSend_97x61;
|
|
||||||
extern const Icon I_RFIDDolphinSuccess_108x57;
|
extern const Icon I_RFIDDolphinSuccess_108x57;
|
||||||
extern const Icon I_SDError_43x35;
|
extern const Icon I_RFIDBigChip_37x36;
|
||||||
|
extern const Icon I_RFIDDolphinSend_97x61;
|
||||||
|
extern const Icon I_RFIDDolphinReceive_97x61;
|
||||||
extern const Icon I_SDQuestion_35x43;
|
extern const Icon I_SDQuestion_35x43;
|
||||||
extern const Icon I_Home_painting_17x20;
|
extern const Icon I_SDError_43x35;
|
||||||
extern const Icon I_PC_22x29;
|
extern const Icon I_Console_74x67_4;
|
||||||
extern const Icon I_Sofa_40x13;
|
extern const Icon I_Console_74x67_5;
|
||||||
extern const Icon I_TV_20x20;
|
extern const Icon I_Console_74x67_7;
|
||||||
extern const Icon I_TV_20x24;
|
extern const Icon I_Console_74x67_6;
|
||||||
extern const Icon I_WalkL1_32x32;
|
extern const Icon I_Console_74x67_2;
|
||||||
extern const Icon I_WalkL2_32x32;
|
extern const Icon I_Console_74x67_3;
|
||||||
extern const Icon I_WalkLB1_32x32;
|
extern const Icon I_Console_74x67_1;
|
||||||
extern const Icon I_WalkLB2_32x32;
|
extern const Icon I_Console_74x67_0;
|
||||||
extern const Icon I_WalkR1_32x32;
|
extern const Icon I_Console_74x67_8;
|
||||||
extern const Icon I_WalkR2_32x32;
|
extern const Icon I_food8_61x98;
|
||||||
extern const Icon I_WalkRB1_32x32;
|
extern const Icon I_food5_61x98;
|
||||||
extern const Icon I_WalkRB2_32x32;
|
extern const Icon I_food3_61x98;
|
||||||
extern const Icon I_Background_128x11;
|
extern const Icon I_food9_61x98;
|
||||||
extern const Icon I_Background_128x8;
|
extern const Icon I_food12_61x98;
|
||||||
|
extern const Icon I_food4_61x98;
|
||||||
|
extern const Icon I_food2_61x98;
|
||||||
|
extern const Icon I_food7_61x98;
|
||||||
|
extern const Icon I_food11_61x98;
|
||||||
|
extern const Icon I_food1_61x98;
|
||||||
|
extern const Icon I_food6_61x98;
|
||||||
|
extern const Icon I_food10_61x98;
|
||||||
|
extern const Icon I_rightdown2_73x61;
|
||||||
|
extern const Icon I_black_upright2_73x61;
|
||||||
|
extern const Icon I_black_leftup1_73x61;
|
||||||
|
extern const Icon I_black_upleft1_73x61;
|
||||||
|
extern const Icon I_black_down2_73x61;
|
||||||
|
extern const Icon I_downleft3_73x61;
|
||||||
|
extern const Icon I_down2_73x61;
|
||||||
|
extern const Icon I_black_downright2_73x61;
|
||||||
|
extern const Icon I_black_downleft2_73x61;
|
||||||
|
extern const Icon I_up2_73x61;
|
||||||
|
extern const Icon I_right1_73x61;
|
||||||
|
extern const Icon I_black_up1_73x61;
|
||||||
|
extern const Icon I_upright1_73x61;
|
||||||
|
extern const Icon I_black_rightleft2_73x61;
|
||||||
|
extern const Icon I_black_right3_73x61;
|
||||||
|
extern const Icon I_upleft2_73x61;
|
||||||
|
extern const Icon I_black_downup3_73x61;
|
||||||
|
extern const Icon I_black_updown3_73x61;
|
||||||
|
extern const Icon I_leftup2_73x61;
|
||||||
|
extern const Icon I_leftdown2_73x61;
|
||||||
|
extern const Icon I_downup1_73x61;
|
||||||
|
extern const Icon I_updown1_73x61;
|
||||||
|
extern const Icon I_rightup1_73x61;
|
||||||
|
extern const Icon I_black_rightdown1_73x61;
|
||||||
|
extern const Icon I_downleft2_73x61;
|
||||||
|
extern const Icon I_downright1_73x61;
|
||||||
|
extern const Icon I_black_downright3_73x61;
|
||||||
|
extern const Icon I_black_downleft3_73x61;
|
||||||
|
extern const Icon I_rightleft1_73x61;
|
||||||
|
extern const Icon I_black_right2_73x61;
|
||||||
|
extern const Icon I_black_rightup2_73x61;
|
||||||
|
extern const Icon I_black_downup2_73x61;
|
||||||
|
extern const Icon I_black_updown2_73x61;
|
||||||
|
extern const Icon I_black_left1_73x61;
|
||||||
|
extern const Icon I_black_leftdown2_73x61;
|
||||||
|
extern const Icon I_left1_73x61;
|
||||||
|
extern const Icon I_rightup2_73x61;
|
||||||
|
extern const Icon I_black_rightdown2_73x61;
|
||||||
|
extern const Icon I_downup2_73x61;
|
||||||
|
extern const Icon I_updown2_73x61;
|
||||||
|
extern const Icon I_right3_73x61;
|
||||||
|
extern const Icon I_downright2_73x61;
|
||||||
|
extern const Icon I_downleft1_73x61;
|
||||||
|
extern const Icon I_black_rightup1_73x61;
|
||||||
|
extern const Icon I_black_right1_73x61;
|
||||||
|
extern const Icon I_rightleft2_73x61;
|
||||||
|
extern const Icon I_left2_73x61;
|
||||||
|
extern const Icon I_black_left2_73x61;
|
||||||
|
extern const Icon I_black_downup1_73x61;
|
||||||
|
extern const Icon I_black_updown1_73x61;
|
||||||
|
extern const Icon I_black_leftdown1_73x61;
|
||||||
|
extern const Icon I_downup3_73x61;
|
||||||
|
extern const Icon I_updown3_73x61;
|
||||||
|
extern const Icon I_black_leftup2_73x61;
|
||||||
|
extern const Icon I_black_upright1_73x61;
|
||||||
|
extern const Icon I_rightdown1_73x61;
|
||||||
|
extern const Icon I_right2_73x61;
|
||||||
|
extern const Icon I_black_downleft1_73x61;
|
||||||
|
extern const Icon I_down1_73x61;
|
||||||
|
extern const Icon I_black_downright1_73x61;
|
||||||
|
extern const Icon I_up1_73x61;
|
||||||
|
extern const Icon I_downright3_73x61;
|
||||||
|
extern const Icon I_black_down1_73x61;
|
||||||
|
extern const Icon I_black_upleft2_73x61;
|
||||||
|
extern const Icon I_upleft1_73x61;
|
||||||
|
extern const Icon I_black_rightleft1_73x61;
|
||||||
|
extern const Icon I_black_up2_73x61;
|
||||||
|
extern const Icon I_upright2_73x61;
|
||||||
|
extern const Icon I_leftdown1_73x61;
|
||||||
|
extern const Icon I_left3_73x61;
|
||||||
|
extern const Icon I_leftup1_73x61;
|
||||||
|
extern const Icon I_black_left3_73x61;
|
||||||
extern const Icon I_BadUsb_9x8;
|
extern const Icon I_BadUsb_9x8;
|
||||||
extern const Icon I_Battery_19x8;
|
|
||||||
extern const Icon I_Battery_26x8;
|
|
||||||
extern const Icon I_Bluetooth_5x8;
|
|
||||||
extern const Icon I_Lock_8x8;
|
|
||||||
extern const Icon I_PlaceholderL_11x13;
|
|
||||||
extern const Icon I_PlaceholderR_30x13;
|
extern const Icon I_PlaceholderR_30x13;
|
||||||
extern const Icon I_SDcardFail_11x8;
|
extern const Icon I_Background_128x8;
|
||||||
|
extern const Icon I_Lock_8x8;
|
||||||
|
extern const Icon I_Battery_26x8;
|
||||||
|
extern const Icon I_PlaceholderL_11x13;
|
||||||
|
extern const Icon I_Battery_19x8;
|
||||||
extern const Icon I_SDcardMounted_11x8;
|
extern const Icon I_SDcardMounted_11x8;
|
||||||
|
extern const Icon I_SDcardFail_11x8;
|
||||||
extern const Icon I_USBConnected_15x8;
|
extern const Icon I_USBConnected_15x8;
|
||||||
extern const Icon I_DolphinExcited_64x63;
|
extern const Icon I_Bluetooth_5x8;
|
||||||
|
extern const Icon I_Background_128x11;
|
||||||
extern const Icon I_DolphinMafia_115x62;
|
extern const Icon I_DolphinMafia_115x62;
|
||||||
extern const Icon I_DolphinNice_96x59;
|
extern const Icon I_DolphinExcited_64x63;
|
||||||
extern const Icon I_DolphinWait_61x59;
|
|
||||||
extern const Icon I_iButtonDolphinSuccess_109x60;
|
extern const Icon I_iButtonDolphinSuccess_109x60;
|
||||||
extern const Icon I_iButtonDolphinVerySuccess_108x52;
|
extern const Icon I_iButtonDolphinVerySuccess_108x52;
|
||||||
extern const Icon I_iButtonKey_49x44;
|
extern const Icon I_iButtonKey_49x44;
|
||||||
|
extern const Icon I_DolphinNice_96x59;
|
||||||
|
extern const Icon I_DolphinWait_61x59;
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 522 B |
BIN
assets/icons/Dolphin/DolphinFirstStart5_54x49.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 1.3 KiB |
BIN
assets/icons/Scenes/Console_74x67/Console_74x67_0.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/Scenes/Console_74x67/Console_74x67_1.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/Scenes/Console_74x67/Console_74x67_2.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/Scenes/Console_74x67/Console_74x67_3.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/Scenes/Console_74x67/Console_74x67_4.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/Scenes/Console_74x67/Console_74x67_5.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/Scenes/Console_74x67/Console_74x67_6.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/Scenes/Console_74x67/Console_74x67_7.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/Scenes/Console_74x67/Console_74x67_8.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
assets/icons/Scenes/Food/food10_61x98.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/icons/Scenes/Food/food11_61x98.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/icons/Scenes/Food/food12_61x98.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/icons/Scenes/Food/food1_61x98.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/icons/Scenes/Food/food2_61x98.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/icons/Scenes/Food/food3_61x98.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |