mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-22 20:43:07 +00:00
Merge branch 'ofw-dev' into dev
This commit is contained in:
commit
b0988e4d86
65 changed files with 1473 additions and 130 deletions
|
@ -48,7 +48,7 @@ Almost everything in flipper firmware is built around this concept.
|
|||
# C coding style
|
||||
|
||||
- Tab is 4 spaces
|
||||
- Use `fbt format` to reformat source code and check style guide before commit
|
||||
- Use `./fbt format` to reformat source code and check style guide before commit
|
||||
|
||||
## Naming
|
||||
|
||||
|
|
|
@ -6,6 +6,11 @@ static void comparator_trigger_callback(bool level, void* comp_ctx) {
|
|||
furi_hal_gpio_write(&gpio_ext_pa7, !level);
|
||||
}
|
||||
|
||||
void lfrfid_debug_view_tune_callback(void* context) {
|
||||
LfRfidDebug* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, 0xBA);
|
||||
}
|
||||
|
||||
void lfrfid_debug_scene_tune_on_enter(void* context) {
|
||||
LfRfidDebug* app = context;
|
||||
|
||||
|
@ -16,6 +21,8 @@ void lfrfid_debug_scene_tune_on_enter(void* context) {
|
|||
|
||||
furi_hal_rfid_tim_read_start(125000, 0.5);
|
||||
|
||||
lfrfid_debug_view_tune_set_callback(app->tune_view, lfrfid_debug_view_tune_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidDebugViewTune);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ typedef struct {
|
|||
uint32_t ARR;
|
||||
uint32_t CCR;
|
||||
int pos;
|
||||
void (*update_callback)(void* context);
|
||||
void* update_context;
|
||||
} LfRfidTuneViewModel;
|
||||
|
||||
static void lfrfid_debug_view_tune_draw_callback(Canvas* canvas, void* _model) {
|
||||
|
@ -151,6 +153,18 @@ static bool lfrfid_debug_view_tune_input_callback(InputEvent* event, void* conte
|
|||
consumed = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if(event->key == InputKeyLeft || event->key == InputKeyRight) {
|
||||
with_view_model(
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
if(model->update_callback) {
|
||||
model->update_callback(model->update_context);
|
||||
}
|
||||
},
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
|
@ -161,19 +175,7 @@ LfRfidTuneView* lfrfid_debug_view_tune_alloc() {
|
|||
tune_view->view = view_alloc();
|
||||
view_set_context(tune_view->view, tune_view);
|
||||
view_allocate_model(tune_view->view, ViewModelTypeLocking, sizeof(LfRfidTuneViewModel));
|
||||
|
||||
with_view_model(
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
model->dirty = true;
|
||||
model->fine = false;
|
||||
model->ARR = 511;
|
||||
model->CCR = 255;
|
||||
model->pos = 0;
|
||||
},
|
||||
true);
|
||||
|
||||
lfrfid_debug_view_tune_clean(tune_view);
|
||||
view_set_draw_callback(tune_view->view, lfrfid_debug_view_tune_draw_callback);
|
||||
view_set_input_callback(tune_view->view, lfrfid_debug_view_tune_input_callback);
|
||||
|
||||
|
@ -199,6 +201,8 @@ void lfrfid_debug_view_tune_clean(LfRfidTuneView* tune_view) {
|
|||
model->ARR = 511;
|
||||
model->CCR = 255;
|
||||
model->pos = 0;
|
||||
model->update_callback = NULL;
|
||||
model->update_context = NULL;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
@ -232,3 +236,17 @@ uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view) {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
void lfrfid_debug_view_tune_set_callback(
|
||||
LfRfidTuneView* tune_view,
|
||||
void (*callback)(void* context),
|
||||
void* context) {
|
||||
with_view_model(
|
||||
tune_view->view,
|
||||
LfRfidTuneViewModel * model,
|
||||
{
|
||||
model->update_callback = callback;
|
||||
model->update_context = context;
|
||||
},
|
||||
false);
|
||||
}
|
||||
|
|
|
@ -16,3 +16,8 @@ bool lfrfid_debug_view_tune_is_dirty(LfRfidTuneView* tune_view);
|
|||
uint32_t lfrfid_debug_view_tune_get_arr(LfRfidTuneView* tune_view);
|
||||
|
||||
uint32_t lfrfid_debug_view_tune_get_ccr(LfRfidTuneView* tune_view);
|
||||
|
||||
void lfrfid_debug_view_tune_set_callback(
|
||||
LfRfidTuneView* tune_view,
|
||||
void (*callback)(void* context),
|
||||
void* context);
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
#include <dialogs/dialogs.h>
|
||||
|
||||
#include "../minunit.h"
|
||||
|
||||
MU_TEST(test_dialog_file_browser_set_basic_options_should_init_all_fields) {
|
||||
mu_assert(
|
||||
sizeof(DialogsFileBrowserOptions) == 28,
|
||||
"Changes to `DialogsFileBrowserOptions` should also be reflected in `dialog_file_browser_set_basic_options`");
|
||||
|
||||
DialogsFileBrowserOptions options;
|
||||
dialog_file_browser_set_basic_options(&options, ".fap", NULL);
|
||||
// note: this assertions can safely be changed, their primary purpose is to remind the maintainer
|
||||
// to update `dialog_file_browser_set_basic_options` by including all structure fields in it
|
||||
mu_assert_string_eq(".fap", options.extension);
|
||||
mu_assert_null(options.base_path);
|
||||
mu_assert(options.skip_assets, "`skip_assets` should default to `true");
|
||||
mu_assert(options.hide_dot_files, "`hide_dot_files` should default to `true");
|
||||
mu_assert_null(options.icon);
|
||||
mu_assert(options.hide_ext, "`hide_ext` should default to `true");
|
||||
mu_assert_null(options.item_loader_callback);
|
||||
mu_assert_null(options.item_loader_context);
|
||||
}
|
||||
|
||||
MU_TEST_SUITE(dialogs_file_browser_options) {
|
||||
MU_RUN_TEST(test_dialog_file_browser_set_basic_options_should_init_all_fields);
|
||||
}
|
||||
|
||||
int run_minunit_test_dialogs_file_browser_options() {
|
||||
MU_RUN_SUITE(dialogs_file_browser_options);
|
||||
|
||||
return MU_EXIT_CODE;
|
||||
}
|
|
@ -27,6 +27,7 @@ int run_minunit_test_nfc();
|
|||
int run_minunit_test_bit_lib();
|
||||
int run_minunit_test_float_tools();
|
||||
int run_minunit_test_bt();
|
||||
int run_minunit_test_dialogs_file_browser_options();
|
||||
|
||||
typedef int (*UnitTestEntry)();
|
||||
|
||||
|
@ -55,6 +56,8 @@ const UnitTest unit_tests[] = {
|
|||
{.name = "bit_lib", .entry = run_minunit_test_bit_lib},
|
||||
{.name = "float_tools", .entry = run_minunit_test_float_tools},
|
||||
{.name = "bt", .entry = run_minunit_test_bt},
|
||||
{.name = "dialogs_file_browser_options",
|
||||
.entry = run_minunit_test_dialogs_file_browser_options},
|
||||
};
|
||||
|
||||
void minunit_print_progress() {
|
||||
|
|
13
applications/external/nfc_rfid_detector/application.fam
vendored
Normal file
13
applications/external/nfc_rfid_detector/application.fam
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
App(
|
||||
appid="nfc_rfid_detector",
|
||||
name="NFC/RFID detector",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
targets=["f7"],
|
||||
entry_point="nfc_rfid_detector_app",
|
||||
requires=["gui"],
|
||||
stack_size=4 * 1024,
|
||||
order=50,
|
||||
fap_icon="nfc_rfid_detector_10px.png",
|
||||
fap_category="Tools",
|
||||
fap_icon_assets="images",
|
||||
)
|
7
applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_event.h
vendored
Normal file
7
applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_event.h
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
typedef enum {
|
||||
//NfcRfidDetectorCustomEvent
|
||||
NfcRfidDetectorCustomEventStartId = 100,
|
||||
|
||||
} NfcRfidDetectorCustomEvent;
|
15
applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_types.h
vendored
Normal file
15
applications/external/nfc_rfid_detector/helpers/nfc_rfid_detector_types.h
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define NFC_RFID_DETECTOR_VERSION_APP "0.1"
|
||||
#define NFC_RFID_DETECTOR_DEVELOPED "SkorP"
|
||||
#define NFC_RFID_DETECTOR_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
|
||||
|
||||
typedef enum {
|
||||
NfcRfidDetectorViewVariableItemList,
|
||||
NfcRfidDetectorViewSubmenu,
|
||||
NfcRfidDetectorViewFieldPresence,
|
||||
NfcRfidDetectorViewWidget,
|
||||
} NfcRfidDetectorView;
|
BIN
applications/external/nfc_rfid_detector/images/Modern_reader_18x34.png
vendored
Normal file
BIN
applications/external/nfc_rfid_detector/images/Modern_reader_18x34.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
applications/external/nfc_rfid_detector/images/Move_flipper_26x39.png
vendored
Normal file
BIN
applications/external/nfc_rfid_detector/images/Move_flipper_26x39.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
applications/external/nfc_rfid_detector/images/NFC_detect_45x30.png
vendored
Normal file
BIN
applications/external/nfc_rfid_detector/images/NFC_detect_45x30.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 168 B |
BIN
applications/external/nfc_rfid_detector/images/Rfid_detect_45x30.png
vendored
Normal file
BIN
applications/external/nfc_rfid_detector/images/Rfid_detect_45x30.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 158 B |
BIN
applications/external/nfc_rfid_detector/nfc_rfid_detector_10px.png
vendored
Normal file
BIN
applications/external/nfc_rfid_detector/nfc_rfid_detector_10px.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 124 B |
108
applications/external/nfc_rfid_detector/nfc_rfid_detector_app.c
vendored
Normal file
108
applications/external/nfc_rfid_detector/nfc_rfid_detector_app.c
vendored
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "nfc_rfid_detector_app_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
static bool nfc_rfid_detector_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool nfc_rfid_detector_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void nfc_rfid_detector_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
NfcRfidDetectorApp* nfc_rfid_detector_app_alloc() {
|
||||
NfcRfidDetectorApp* app = malloc(sizeof(NfcRfidDetectorApp));
|
||||
|
||||
// GUI
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
// View Dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&nfc_rfid_detector_scene_handlers, app);
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, nfc_rfid_detector_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, nfc_rfid_detector_app_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, nfc_rfid_detector_app_tick_event_callback, 100);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// Open Notification record
|
||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
// SubMenu
|
||||
app->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, NfcRfidDetectorViewSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
// Widget
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, NfcRfidDetectorViewWidget, widget_get_view(app->widget));
|
||||
|
||||
// Field Presence
|
||||
app->nfc_rfid_detector_field_presence = nfc_rfid_detector_view_field_presence_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
NfcRfidDetectorViewFieldPresence,
|
||||
nfc_rfid_detector_view_field_presence_get_view(app->nfc_rfid_detector_field_presence));
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, NfcRfidDetectorSceneStart);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_app_free(NfcRfidDetectorApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// Submenu
|
||||
view_dispatcher_remove_view(app->view_dispatcher, NfcRfidDetectorViewSubmenu);
|
||||
submenu_free(app->submenu);
|
||||
|
||||
// Widget
|
||||
view_dispatcher_remove_view(app->view_dispatcher, NfcRfidDetectorViewWidget);
|
||||
widget_free(app->widget);
|
||||
|
||||
// Field Presence
|
||||
view_dispatcher_remove_view(app->view_dispatcher, NfcRfidDetectorViewFieldPresence);
|
||||
nfc_rfid_detector_view_field_presence_free(app->nfc_rfid_detector_field_presence);
|
||||
|
||||
// View dispatcher
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
// Notifications
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
app->notifications = NULL;
|
||||
|
||||
// Close records
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t nfc_rfid_detector_app(void* p) {
|
||||
UNUSED(p);
|
||||
NfcRfidDetectorApp* nfc_rfid_detector_app = nfc_rfid_detector_app_alloc();
|
||||
|
||||
view_dispatcher_run(nfc_rfid_detector_app->view_dispatcher);
|
||||
|
||||
nfc_rfid_detector_app_free(nfc_rfid_detector_app);
|
||||
|
||||
return 0;
|
||||
}
|
40
applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.c
vendored
Normal file
40
applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.c
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
#include "nfc_rfid_detector_app_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
|
||||
#define TAG "NfcRfidDetector"
|
||||
|
||||
void nfc_rfid_detector_app_field_presence_start(NfcRfidDetectorApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// start the field presence rfid detection
|
||||
furi_hal_rfid_field_detect_start();
|
||||
|
||||
// start the field presence nfc detection
|
||||
furi_hal_nfc_exit_sleep();
|
||||
furi_hal_nfc_field_detect_start();
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_app_field_presence_stop(NfcRfidDetectorApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// stop the field presence rfid detection
|
||||
furi_hal_rfid_field_detect_stop();
|
||||
|
||||
// stop the field presence nfc detection
|
||||
furi_hal_nfc_start_sleep();
|
||||
}
|
||||
|
||||
bool nfc_rfid_detector_app_field_presence_is_nfc(NfcRfidDetectorApp* app) {
|
||||
furi_assert(app);
|
||||
|
||||
// check if the field presence is nfc
|
||||
return furi_hal_nfc_field_is_present();
|
||||
}
|
||||
|
||||
bool nfc_rfid_detector_app_field_presence_is_rfid(NfcRfidDetectorApp* app, uint32_t* frequency) {
|
||||
furi_assert(app);
|
||||
|
||||
// check if the field presence is rfid
|
||||
return furi_hal_rfid_field_is_present(frequency);
|
||||
}
|
30
applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.h
vendored
Normal file
30
applications/external/nfc_rfid_detector/nfc_rfid_detector_app_i.h
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "helpers/nfc_rfid_detector_types.h"
|
||||
#include "helpers/nfc_rfid_detector_event.h"
|
||||
|
||||
#include "scenes/nfc_rfid_detector_scene.h"
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include "views/nfc_rfid_detector_view_field_presence.h"
|
||||
|
||||
typedef struct NfcRfidDetectorApp NfcRfidDetectorApp;
|
||||
|
||||
struct NfcRfidDetectorApp {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
NotificationApp* notifications;
|
||||
Submenu* submenu;
|
||||
Widget* widget;
|
||||
NfcRfidDetectorFieldPresence* nfc_rfid_detector_field_presence;
|
||||
};
|
||||
|
||||
void nfc_rfid_detector_app_field_presence_start(NfcRfidDetectorApp* app);
|
||||
void nfc_rfid_detector_app_field_presence_stop(NfcRfidDetectorApp* app);
|
||||
bool nfc_rfid_detector_app_field_presence_is_nfc(NfcRfidDetectorApp* app);
|
||||
bool nfc_rfid_detector_app_field_presence_is_rfid(NfcRfidDetectorApp* app, uint32_t* frequency);
|
31
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.c
vendored
Normal file
31
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.c
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "../nfc_rfid_detector_app_i.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const nfc_rfid_detector_scene_on_enter_handlers[])(void*) = {
|
||||
#include "nfc_rfid_detector_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const nfc_rfid_detector_scene_on_event_handlers[])(void* context, SceneManagerEvent event) =
|
||||
{
|
||||
#include "nfc_rfid_detector_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const nfc_rfid_detector_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "nfc_rfid_detector_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers nfc_rfid_detector_scene_handlers = {
|
||||
.on_enter_handlers = nfc_rfid_detector_scene_on_enter_handlers,
|
||||
.on_event_handlers = nfc_rfid_detector_scene_on_event_handlers,
|
||||
.on_exit_handlers = nfc_rfid_detector_scene_on_exit_handlers,
|
||||
.scene_num = NfcRfidDetectorSceneNum,
|
||||
};
|
29
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.h
vendored
Normal file
29
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene.h
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) NfcRfidDetectorScene##id,
|
||||
typedef enum {
|
||||
#include "nfc_rfid_detector_scene_config.h"
|
||||
NfcRfidDetectorSceneNum,
|
||||
} NfcRfidDetectorScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers nfc_rfid_detector_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "nfc_rfid_detector_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "nfc_rfid_detector_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "nfc_rfid_detector_scene_config.h"
|
||||
#undef ADD_SCENE
|
69
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_about.c
vendored
Normal file
69
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_about.c
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
#include "../nfc_rfid_detector_app_i.h"
|
||||
|
||||
void nfc_rfid_detector_scene_about_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
NfcRfidDetectorApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_scene_about_on_enter(void* context) {
|
||||
NfcRfidDetectorApp* app = context;
|
||||
|
||||
FuriString* temp_str;
|
||||
temp_str = furi_string_alloc();
|
||||
furi_string_printf(temp_str, "\e#%s\n", "Information");
|
||||
|
||||
furi_string_cat_printf(temp_str, "Version: %s\n", NFC_RFID_DETECTOR_VERSION_APP);
|
||||
furi_string_cat_printf(temp_str, "Developed by: %s\n", NFC_RFID_DETECTOR_DEVELOPED);
|
||||
furi_string_cat_printf(temp_str, "Github: %s\n\n", NFC_RFID_DETECTOR_GITHUB);
|
||||
|
||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
|
||||
furi_string_cat_printf(
|
||||
temp_str,
|
||||
"This application allows\nyou to determine what\ntype of electromagnetic\nfield the reader is using.\nFor LF RFID you can also\nsee the carrier frequency\n\n");
|
||||
|
||||
widget_add_text_box_element(
|
||||
app->widget,
|
||||
0,
|
||||
0,
|
||||
128,
|
||||
14,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
"\e#\e! \e!\n",
|
||||
false);
|
||||
widget_add_text_box_element(
|
||||
app->widget,
|
||||
0,
|
||||
2,
|
||||
128,
|
||||
14,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
"\e#\e! NFC/RFID detector \e!\n",
|
||||
false);
|
||||
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
|
||||
furi_string_free(temp_str);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, NfcRfidDetectorViewWidget);
|
||||
}
|
||||
|
||||
bool nfc_rfid_detector_scene_about_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcRfidDetectorApp* app = context;
|
||||
bool consumed = false;
|
||||
UNUSED(app);
|
||||
UNUSED(event);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_scene_about_on_exit(void* context) {
|
||||
NfcRfidDetectorApp* app = context;
|
||||
|
||||
// Clear views
|
||||
widget_reset(app->widget);
|
||||
}
|
3
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_config.h
vendored
Normal file
3
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_config.h
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
ADD_SCENE(nfc_rfid_detector, start, Start)
|
||||
ADD_SCENE(nfc_rfid_detector, about, About)
|
||||
ADD_SCENE(nfc_rfid_detector, field_presence, FieldPresence)
|
60
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_field_presence.c
vendored
Normal file
60
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_field_presence.c
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "../nfc_rfid_detector_app_i.h"
|
||||
#include "../views/nfc_rfid_detector_view_field_presence.h"
|
||||
|
||||
void nfc_rfid_detector_scene_field_presence_callback(
|
||||
NfcRfidDetectorCustomEvent event,
|
||||
void* context) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
static const NotificationSequence notification_app_display_on = {
|
||||
|
||||
&message_display_backlight_on,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void nfc_rfid_detector_scene_field_presence_update(void* context) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorApp* app = context;
|
||||
|
||||
uint32_t frequency = 0;
|
||||
bool nfc_field = nfc_rfid_detector_app_field_presence_is_nfc(app);
|
||||
bool rfid_field = nfc_rfid_detector_app_field_presence_is_rfid(app, &frequency);
|
||||
|
||||
if(nfc_field || rfid_field)
|
||||
notification_message(app->notifications, ¬ification_app_display_on);
|
||||
|
||||
nfc_rfid_detector_view_field_presence_update(
|
||||
app->nfc_rfid_detector_field_presence, nfc_field, rfid_field, frequency);
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_scene_field_presence_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorApp* app = context;
|
||||
|
||||
// Start detection of field presence
|
||||
nfc_rfid_detector_app_field_presence_start(app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, NfcRfidDetectorViewFieldPresence);
|
||||
}
|
||||
|
||||
bool nfc_rfid_detector_scene_field_presence_on_event(void* context, SceneManagerEvent event) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
nfc_rfid_detector_scene_field_presence_update(app);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_scene_field_presence_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorApp* app = context;
|
||||
// Stop detection of field presence
|
||||
nfc_rfid_detector_app_field_presence_stop(app);
|
||||
}
|
58
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_start.c
vendored
Normal file
58
applications/external/nfc_rfid_detector/scenes/nfc_rfid_detector_scene_start.c
vendored
Normal file
|
@ -0,0 +1,58 @@
|
|||
#include "../nfc_rfid_detector_app_i.h"
|
||||
|
||||
typedef enum {
|
||||
SubmenuIndexNfcRfidDetectorFieldPresence,
|
||||
SubmenuIndexNfcRfidDetectorAbout,
|
||||
} SubmenuIndex;
|
||||
|
||||
void nfc_rfid_detector_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
NfcRfidDetectorApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_scene_start_on_enter(void* context) {
|
||||
UNUSED(context);
|
||||
NfcRfidDetectorApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Detect field type",
|
||||
SubmenuIndexNfcRfidDetectorFieldPresence,
|
||||
nfc_rfid_detector_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"About",
|
||||
SubmenuIndexNfcRfidDetectorAbout,
|
||||
nfc_rfid_detector_scene_start_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, NfcRfidDetectorSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, NfcRfidDetectorViewSubmenu);
|
||||
}
|
||||
|
||||
bool nfc_rfid_detector_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
NfcRfidDetectorApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == SubmenuIndexNfcRfidDetectorAbout) {
|
||||
scene_manager_next_scene(app->scene_manager, NfcRfidDetectorSceneAbout);
|
||||
consumed = true;
|
||||
} else if(event.event == SubmenuIndexNfcRfidDetectorFieldPresence) {
|
||||
scene_manager_next_scene(app->scene_manager, NfcRfidDetectorSceneFieldPresence);
|
||||
consumed = true;
|
||||
}
|
||||
scene_manager_set_scene_state(app->scene_manager, NfcRfidDetectorSceneStart, event.event);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_scene_start_on_exit(void* context) {
|
||||
NfcRfidDetectorApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
164
applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.c
vendored
Normal file
164
applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.c
vendored
Normal file
|
@ -0,0 +1,164 @@
|
|||
#include "nfc_rfid_detector_view_field_presence.h"
|
||||
#include "../nfc_rfid_detector_app_i.h"
|
||||
#include <nfc_rfid_detector_icons.h>
|
||||
|
||||
#include <input/input.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
#define FIELD_FOUND_WEIGHT 5
|
||||
|
||||
typedef enum {
|
||||
NfcRfidDetectorTypeFieldPresenceNfc,
|
||||
NfcRfidDetectorTypeFieldPresenceRfid,
|
||||
} NfcRfidDetectorTypeFieldPresence;
|
||||
|
||||
static const Icon* NfcRfidDetectorFieldPresenceIcons[] = {
|
||||
[NfcRfidDetectorTypeFieldPresenceNfc] = &I_NFC_detect_45x30,
|
||||
[NfcRfidDetectorTypeFieldPresenceRfid] = &I_Rfid_detect_45x30,
|
||||
};
|
||||
|
||||
struct NfcRfidDetectorFieldPresence {
|
||||
View* view;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t nfc_field;
|
||||
uint8_t rfid_field;
|
||||
uint32_t rfid_frequency;
|
||||
} NfcRfidDetectorFieldPresenceModel;
|
||||
|
||||
void nfc_rfid_detector_view_field_presence_update(
|
||||
NfcRfidDetectorFieldPresence* instance,
|
||||
bool nfc_field,
|
||||
bool rfid_field,
|
||||
uint32_t rfid_frequency) {
|
||||
furi_assert(instance);
|
||||
with_view_model(
|
||||
instance->view,
|
||||
NfcRfidDetectorFieldPresenceModel * model,
|
||||
{
|
||||
if(nfc_field) {
|
||||
model->nfc_field = FIELD_FOUND_WEIGHT;
|
||||
} else if(model->nfc_field) {
|
||||
model->nfc_field--;
|
||||
}
|
||||
if(rfid_field) {
|
||||
model->rfid_field = FIELD_FOUND_WEIGHT;
|
||||
model->rfid_frequency = rfid_frequency;
|
||||
} else if(model->rfid_field) {
|
||||
model->rfid_field--;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_view_field_presence_draw(
|
||||
Canvas* canvas,
|
||||
NfcRfidDetectorFieldPresenceModel* model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
if(!model->nfc_field && !model->rfid_field) {
|
||||
canvas_draw_icon(canvas, 0, 16, &I_Modern_reader_18x34);
|
||||
canvas_draw_icon(canvas, 22, 12, &I_Move_flipper_26x39);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 56, 36, "Touch the reader");
|
||||
} else {
|
||||
if(model->nfc_field) {
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 21, 10, "NFC");
|
||||
canvas_draw_icon(
|
||||
canvas,
|
||||
9,
|
||||
17,
|
||||
NfcRfidDetectorFieldPresenceIcons[NfcRfidDetectorTypeFieldPresenceNfc]);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 9, 62, "13,56 MHz");
|
||||
}
|
||||
|
||||
if(model->rfid_field) {
|
||||
char str[16];
|
||||
snprintf(str, sizeof(str), "%.02f KHz", (double)model->rfid_frequency / 1000);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str(canvas, 76, 10, "LF RFID");
|
||||
canvas_draw_icon(
|
||||
canvas,
|
||||
71,
|
||||
17,
|
||||
NfcRfidDetectorFieldPresenceIcons[NfcRfidDetectorTypeFieldPresenceRfid]);
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
canvas_draw_str(canvas, 69, 62, str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool nfc_rfid_detector_view_field_presence_input(InputEvent* event, void* context) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorFieldPresence* instance = context;
|
||||
UNUSED(instance);
|
||||
|
||||
if(event->key == InputKeyBack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_view_field_presence_enter(void* context) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorFieldPresence* instance = context;
|
||||
with_view_model(
|
||||
instance->view,
|
||||
NfcRfidDetectorFieldPresenceModel * model,
|
||||
{
|
||||
model->nfc_field = 0;
|
||||
model->rfid_field = 0;
|
||||
model->rfid_frequency = 0;
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_view_field_presence_exit(void* context) {
|
||||
furi_assert(context);
|
||||
NfcRfidDetectorFieldPresence* instance = context;
|
||||
UNUSED(instance);
|
||||
}
|
||||
|
||||
NfcRfidDetectorFieldPresence* nfc_rfid_detector_view_field_presence_alloc() {
|
||||
NfcRfidDetectorFieldPresence* instance = malloc(sizeof(NfcRfidDetectorFieldPresence));
|
||||
|
||||
// View allocation and configuration
|
||||
instance->view = view_alloc();
|
||||
|
||||
view_allocate_model(
|
||||
instance->view, ViewModelTypeLocking, sizeof(NfcRfidDetectorFieldPresenceModel));
|
||||
view_set_context(instance->view, instance);
|
||||
view_set_draw_callback(
|
||||
instance->view, (ViewDrawCallback)nfc_rfid_detector_view_field_presence_draw);
|
||||
view_set_input_callback(instance->view, nfc_rfid_detector_view_field_presence_input);
|
||||
view_set_enter_callback(instance->view, nfc_rfid_detector_view_field_presence_enter);
|
||||
view_set_exit_callback(instance->view, nfc_rfid_detector_view_field_presence_exit);
|
||||
|
||||
with_view_model(
|
||||
instance->view,
|
||||
NfcRfidDetectorFieldPresenceModel * model,
|
||||
{
|
||||
model->nfc_field = 0;
|
||||
model->rfid_field = 0;
|
||||
model->rfid_frequency = 0;
|
||||
},
|
||||
true);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void nfc_rfid_detector_view_field_presence_free(NfcRfidDetectorFieldPresence* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* nfc_rfid_detector_view_field_presence_get_view(NfcRfidDetectorFieldPresence* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->view;
|
||||
}
|
19
applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.h
vendored
Normal file
19
applications/external/nfc_rfid_detector/views/nfc_rfid_detector_view_field_presence.h
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../helpers/nfc_rfid_detector_types.h"
|
||||
#include "../helpers/nfc_rfid_detector_event.h"
|
||||
|
||||
typedef struct NfcRfidDetectorFieldPresence NfcRfidDetectorFieldPresence;
|
||||
|
||||
void nfc_rfid_detector_view_field_presence_update(
|
||||
NfcRfidDetectorFieldPresence* instance,
|
||||
bool nfc_field,
|
||||
bool rfid_field,
|
||||
uint32_t rfid_frequency);
|
||||
|
||||
NfcRfidDetectorFieldPresence* nfc_rfid_detector_view_field_presence_alloc();
|
||||
|
||||
void nfc_rfid_detector_view_field_presence_free(NfcRfidDetectorFieldPresence* instance);
|
||||
|
||||
View* nfc_rfid_detector_view_field_presence_get_view(NfcRfidDetectorFieldPresence* instance);
|
|
@ -464,9 +464,24 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
|||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{
|
||||
int32_t scroll_speed = 1;
|
||||
if(model->button_held_for_ticks > 5) {
|
||||
if(model->button_held_for_ticks % 2) {
|
||||
scroll_speed = 0;
|
||||
} else {
|
||||
scroll_speed = model->button_held_for_ticks > 9 ? 4 : 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(event->key == InputKeyUp) {
|
||||
if(model->item_idx < scroll_speed) {
|
||||
model->button_held_for_ticks = 0;
|
||||
model->item_idx = model->item_cnt - 1;
|
||||
} else {
|
||||
model->item_idx =
|
||||
((model->item_idx - 1) + model->item_cnt) % model->item_cnt;
|
||||
((model->item_idx - scroll_speed) + model->item_cnt) %
|
||||
model->item_cnt;
|
||||
}
|
||||
if(is_file_list_load_required(model)) {
|
||||
model->list_loading = true;
|
||||
browser->callback(ArchiveBrowserEventLoadPrevItems, browser->context);
|
||||
|
@ -475,8 +490,15 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
|||
browser->callback(ArchiveBrowserEventFavMoveUp, browser->context);
|
||||
}
|
||||
model->scroll_counter = 0;
|
||||
model->button_held_for_ticks += 1;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->item_idx = (model->item_idx + 1) % model->item_cnt;
|
||||
int32_t count = model->item_cnt;
|
||||
if(model->item_idx + scroll_speed >= count) {
|
||||
model->button_held_for_ticks = 0;
|
||||
model->item_idx = 0;
|
||||
} else {
|
||||
model->item_idx = (model->item_idx + scroll_speed) % model->item_cnt;
|
||||
}
|
||||
if(is_file_list_load_required(model)) {
|
||||
model->list_loading = true;
|
||||
browser->callback(ArchiveBrowserEventLoadNextItems, browser->context);
|
||||
|
@ -485,6 +507,7 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
|||
browser->callback(ArchiveBrowserEventFavMoveDown, browser->context);
|
||||
}
|
||||
model->scroll_counter = 0;
|
||||
model->button_held_for_ticks += 1;
|
||||
}
|
||||
},
|
||||
false);
|
||||
|
@ -521,6 +544,14 @@ static bool archive_view_input(InputEvent* event, void* context) {
|
|||
}
|
||||
}
|
||||
|
||||
if(event->type == InputTypeRelease) {
|
||||
with_view_model(
|
||||
browser->view,
|
||||
ArchiveBrowserViewModel * model,
|
||||
{ model->button_held_for_ticks = 0; },
|
||||
true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,8 @@ typedef struct {
|
|||
int32_t array_offset;
|
||||
int32_t list_offset;
|
||||
size_t scroll_counter;
|
||||
|
||||
uint32_t button_held_for_ticks;
|
||||
} ArchiveBrowserViewModel;
|
||||
|
||||
void archive_browser_set_callback(
|
||||
|
|
|
@ -16,7 +16,8 @@ typedef struct DialogsApp DialogsApp;
|
|||
/****************** FILE BROWSER ******************/
|
||||
|
||||
/**
|
||||
* File browser dialog extra options
|
||||
* File browser dialog extra options.
|
||||
* This can be default-initialized using {@link dialog_file_browser_set_basic_options}.
|
||||
* @param extension file extension to be offered for selection
|
||||
* @param base_path root folder path for navigation with back key
|
||||
* @param skip_assets true - do not show assets folders
|
||||
|
@ -38,8 +39,10 @@ typedef struct {
|
|||
} DialogsFileBrowserOptions;
|
||||
|
||||
/**
|
||||
* Initialize file browser dialog options
|
||||
* and set default values
|
||||
* Initialize file browser dialog options and set default values.
|
||||
* This is guaranteed to initialize all fields
|
||||
* so it is safe to pass pointer to uninitialized {@code options}
|
||||
* and assume that the data behind it becomes fully initialized after the call.
|
||||
* @param options pointer to options structure
|
||||
* @param extension file extension to filter
|
||||
* @param icon file icon pointer, NULL for default icon
|
||||
|
|
|
@ -146,6 +146,8 @@ typedef struct {
|
|||
const Icon* file_icon;
|
||||
bool hide_ext;
|
||||
size_t scroll_counter;
|
||||
|
||||
uint32_t button_held_for_ticks;
|
||||
} FileBrowserModel;
|
||||
|
||||
static const Icon* BrowserItemIcons[] = {
|
||||
|
@ -659,9 +661,24 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
|
|||
browser->view,
|
||||
FileBrowserModel * model,
|
||||
{
|
||||
int32_t scroll_speed = 1;
|
||||
if(model->button_held_for_ticks > 5) {
|
||||
if(model->button_held_for_ticks % 2) {
|
||||
scroll_speed = 0;
|
||||
} else {
|
||||
scroll_speed = model->button_held_for_ticks > 9 ? 5 : 3;
|
||||
}
|
||||
}
|
||||
|
||||
if(event->key == InputKeyUp) {
|
||||
if(model->item_idx < scroll_speed) {
|
||||
model->button_held_for_ticks = 0;
|
||||
model->item_idx = model->item_cnt - 1;
|
||||
} else {
|
||||
model->item_idx =
|
||||
((model->item_idx - 1) + model->item_cnt) % model->item_cnt;
|
||||
((model->item_idx - scroll_speed) + model->item_cnt) %
|
||||
model->item_cnt;
|
||||
}
|
||||
if(browser_is_list_load_required(model)) {
|
||||
model->list_loading = true;
|
||||
int32_t load_offset = CLAMP(
|
||||
|
@ -672,8 +689,16 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
|
|||
browser->worker, load_offset, ITEM_LIST_LEN_MAX);
|
||||
}
|
||||
model->scroll_counter = 0;
|
||||
|
||||
model->button_held_for_ticks += 1;
|
||||
} else if(event->key == InputKeyDown) {
|
||||
model->item_idx = (model->item_idx + 1) % model->item_cnt;
|
||||
int32_t count = model->item_cnt;
|
||||
if(model->item_idx + scroll_speed >= count) {
|
||||
model->button_held_for_ticks = 0;
|
||||
model->item_idx = 0;
|
||||
} else {
|
||||
model->item_idx = (model->item_idx + scroll_speed) % model->item_cnt;
|
||||
}
|
||||
if(browser_is_list_load_required(model)) {
|
||||
model->list_loading = true;
|
||||
int32_t load_offset = CLAMP(
|
||||
|
@ -684,11 +709,19 @@ static bool file_browser_view_input_callback(InputEvent* event, void* context) {
|
|||
browser->worker, load_offset, ITEM_LIST_LEN_MAX);
|
||||
}
|
||||
model->scroll_counter = 0;
|
||||
|
||||
model->button_held_for_ticks += 1;
|
||||
}
|
||||
},
|
||||
false);
|
||||
browser_update_offset(browser);
|
||||
consumed = true;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
with_view_model(
|
||||
browser->view,
|
||||
FileBrowserModel * model,
|
||||
{ model->button_held_for_ticks = 0; },
|
||||
true);
|
||||
}
|
||||
} else if(event->key == InputKeyOk) {
|
||||
if(event->type == InputTypeShort) {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
struct TextBox {
|
||||
View* view;
|
||||
|
||||
uint16_t button_held_for_ticks;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
@ -19,28 +21,39 @@ typedef struct {
|
|||
bool formatted;
|
||||
} TextBoxModel;
|
||||
|
||||
static void text_box_process_down(TextBox* text_box) {
|
||||
static void text_box_process_down(TextBox* text_box, uint8_t lines) {
|
||||
with_view_model(
|
||||
text_box->view,
|
||||
TextBoxModel * model,
|
||||
{
|
||||
if(model->scroll_pos < model->scroll_num - 1) {
|
||||
model->scroll_pos++;
|
||||
if(model->scroll_pos < model->scroll_num - lines) {
|
||||
model->scroll_pos += lines;
|
||||
for(uint8_t i = 0; i < lines; i++) {
|
||||
// Search next line start
|
||||
while(*model->text_pos++ != '\n')
|
||||
;
|
||||
}
|
||||
} else if(lines > 1) {
|
||||
lines = model->scroll_num - model->scroll_pos - 1;
|
||||
model->scroll_pos = model->scroll_num - 1;
|
||||
for(uint8_t i = 0; i < lines; i++) {
|
||||
// Search next line start
|
||||
while(*model->text_pos++ != '\n')
|
||||
;
|
||||
}
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
static void text_box_process_up(TextBox* text_box) {
|
||||
static void text_box_process_up(TextBox* text_box, uint8_t lines) {
|
||||
with_view_model(
|
||||
text_box->view,
|
||||
TextBoxModel * model,
|
||||
{
|
||||
if(model->scroll_pos > 0) {
|
||||
model->scroll_pos--;
|
||||
if(model->scroll_pos > lines - 1) {
|
||||
model->scroll_pos -= lines;
|
||||
for(uint8_t i = 0; i < lines; i++) {
|
||||
// Reach last symbol of previous line
|
||||
model->text_pos--;
|
||||
// Search previous line start
|
||||
|
@ -50,6 +63,11 @@ static void text_box_process_up(TextBox* text_box) {
|
|||
model->text_pos++;
|
||||
}
|
||||
}
|
||||
} else if(lines > 1) {
|
||||
lines = model->scroll_pos;
|
||||
model->scroll_pos = 0;
|
||||
model->text_pos = (char*)model->text;
|
||||
}
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
@ -120,14 +138,28 @@ static bool text_box_view_input_callback(InputEvent* event, void* context) {
|
|||
|
||||
TextBox* text_box = context;
|
||||
bool consumed = false;
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
|
||||
int32_t scroll_speed = 1;
|
||||
if(text_box->button_held_for_ticks > 5) {
|
||||
if(text_box->button_held_for_ticks % 2) {
|
||||
scroll_speed = 0;
|
||||
} else {
|
||||
scroll_speed = text_box->button_held_for_ticks > 9 ? 5 : 3;
|
||||
}
|
||||
}
|
||||
|
||||
if(event->key == InputKeyDown) {
|
||||
text_box_process_down(text_box);
|
||||
text_box_process_down(text_box, scroll_speed);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyUp) {
|
||||
text_box_process_up(text_box);
|
||||
text_box_process_up(text_box, scroll_speed);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
text_box->button_held_for_ticks++;
|
||||
} else if(event->type == InputTypeRelease) {
|
||||
text_box->button_held_for_ticks = 0;
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
|
Binary file not shown.
|
@ -618,3 +618,40 @@ type: raw
|
|||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3165 1578 549 1037 549 1037 550 342 485 343 484 343 513 1034 551 340 487 340 487 1035 551 1035 550 340 486 1037 548 341 485 341 485 1041 545 1041 545 341 486 1042 544 1042 544 340 487 341 486 1042 544 341 486 340 488 1042 544 341 487 341 486 341 486 341 461 343 509 341 487 341 461 343 484 343 510 341 486 341 461 343 484 343 509 341 462 343 509 341 462 343 484 1068 518 343 510 341 461 1068 518 343 484 343 484 343 484 1068 518 343 484 343 484 343 484 343 484 342 485 343 485 1068 518 1068 518 1068 518 343 485 343 484 343 485 343 484 343 484 343 484 343 484 343 484 1068 518 1068 518 1068 518 343 484 343 484 343 485 343 484 343 484 343 484 343 484 343 484 343 484 342 485 343 485 343 484 343 484 343 484 343 484 343 484 343 484 343 485 343 484 343 484 343 484 343 484 343 484 343 485 343 484 343 484 343 484 343 484 343 484 1070 516 343 484 343 484 343 484 1071 515 343 484 1094 492 343 484 343 484 343 485 344 483 343 484 343 484
|
||||
#
|
||||
# Model: Mitsubishi MSZ-AP25VGK
|
||||
name: Off
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3531 1667 500 1225 499 1225 499 376 499 377 498 377 498 1224 500 377 498 377 498 1224 500 1225 499 377 527 1195 557 318 556 318 555 1167 530 1194 529 374 499 1224 499 1225 497 377 497 378 497 1228 496 379 496 380 495 1229 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 496 380 495 380 495 380 495 380 495 9028 3526 1672 495 1229 495 1229 495 380 495 380 495 380 495 1230 494 380 495 380 495 1229 495 1229 495 380 495 1229 495 380 495 380 495 1229 495 1229 495 380 495 1229 495 1229 495 380 495 380 495 1229 495 380 495 380 495 1229 495 380 495 381 494 381 494 380 495 380 495 380 495 380 495 381 494 380 495 381 494 381 494 381 494 381 494 381 494 380 495 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 1230 494 1230 494 381 494 381 494 381 494 381 494 381 494 381 494 1230 494 381 494 381 494 381 494 381 494 381 494 1230 494 1230 494 381 494 1230 494 1230 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 1230 494 381 494 1230 494 381 494 381 494 1230 494 381 494 1230 494 1230 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 381 494 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 1231 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 382 493 1231 493 382 493 1231 493 382 493 1231 493 382 493 383 492 382 493
|
||||
#
|
||||
name: Dh
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3561 1666 500 1195 529 1193 531 374 501 375 500 375 500 1196 529 374 501 375 500 1223 501 1223 501 375 529 1194 558 318 557 318 555 1168 530 1193 530 345 529 1194 529 1196 527 348 526 350 525 1200 524 352 522 353 522 1228 496 379 496 379 496 379 496 379 496 379 496 379 497 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 9028 3529 1670 496 1228 496 1228 496 379 496 379 496 379 496 1228 496 379 496 379 496 1228 496 1228 496 379 496 1228 496 379 496 379 496 1228 496 1228 496 379 496 1228 496 1228 496 379 496 379 496 1228 496 379 496 379 496 1228 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 379 496 380 495 379 496 379 496 379 496 379 496 380 495 379 496 380 495 379 496 1229 495 380 495 380 495 379 496 380 495 380 495 380 495 1229 495 380 495 380 495 380 495 380 495 380 495 380 495 1229 495 380 495 380 495 380 495 380 495 380 495 1229 495 380 495 380 495 1229 495 1229 495 380 495 380 495 380 495 380 495 380 496 380 495 380 495 380 495 1229 495 380 495 1229 495 380 495 380 495 1229 495 380 495 1229 495 1229 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 380 495 381 494 380 495 380 495 380 495 380 495 1230 494 380 495 381 494 381 494 380 495 380 495 380 495 380 495 381 494 381 495 380 495 381 494 381 495 380 495 381 494 381 495 380 495 381 494 381 494 381 494 381 494 381 494 381 494 381 494 1230 494 381 494 381 494 1230 494 381 494 1230 494 381 494 381 494
|
||||
#
|
||||
name: Cool_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3534 1637 530 1192 533 1195 529 375 500 375 500 375 500 1195 530 375 501 375 500 1224 500 1224 501 376 528 1195 557 319 556 318 555 1168 530 1193 530 345 530 1194 529 1196 527 348 526 350 525 1201 523 353 522 378 497 1228 496 379 497 379 496 379 497 379 496 379 497 379 497 379 497 379 496 379 496 379 496 379 496 379 497 379 497 379 496 379 496 9030 3530 1671 496 1229 496 1229 495 379 496 379 496 379 497 1229 496 379 496 379 497 1229 496 1229 495 380 496 1229 495 379 497 379 496 1229 496 1229 495 379 497 1229 495 1228 497 379 496 380 496 1229 496 379 497 379 496 1229 496 379 496 380 496 380 495 380 496 379 496 380 496 380 495 380 496 380 496 380 496 379 496 380 496 380 495 380 496 380 495 380 496 380 495 380 496 380 495 380 495 1229 496 380 495 380 495 380 495 380 496 380 495 1229 496 1229 496 380 495 380 496 380 495 380 496 380 496 380 495 380 495 380 496 380 496 380 495 380 496 380 495 1229 495 1230 495 380 495 1229 496 1229 496 380 495 381 495 380 495 380 495 380 496 380 496 380 495 380 496 1229 496 380 495 1230 495 380 495 380 495 1230 495 380 495 1230 495 1230 495 380 495 380 496 380 495 380 495 380 495 380 496 380 496 380 495 380 496 380 495 380 495 380 496 380 495 381 495 380 495 380 495 380 495 381 495 380 495 381 495 380 495 381 494 381 495 381 495 380 495 1230 495 381 495 380 495 381 494 381 495 381 494 381 495 381 494 381 495 381 495 381 494 381 495 381 494 381 495 381 495 381 494 381 495 381 494 381 494 381 495 381 494 381 494 381 494 381 495 1230 495 381 495 1230 495 1230 495 381 494 1230 494 381 495 381 494
|
||||
#
|
||||
name: Cool_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3534 1667 500 1224 501 1224 501 376 500 375 500 376 500 1224 501 376 500 376 499 1224 501 1225 500 376 500 1225 556 320 556 318 555 1167 530 1194 530 345 530 1195 529 1196 528 348 527 377 498 1227 498 378 497 379 496 1229 496 379 496 379 497 379 497 379 497 379 497 380 496 379 497 379 496 379 497 380 496 380 496 380 496 380 496 379 497 379 497 9033 3530 1672 496 1229 496 1229 496 380 496 380 496 380 496 1229 496 380 496 380 496 1229 496 1229 496 380 496 1229 496 380 496 380 496 1229 496 1229 496 380 496 1230 495 1229 496 380 495 380 496 1229 496 380 496 380 496 1229 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 496 380 495 380 496 380 496 380 496 380 496 380 496 380 496 380 496 1230 495 380 496 380 495 380 496 381 495 380 495 1230 495 1230 495 380 496 380 496 380 496 1230 495 1230 495 1230 495 380 496 380 496 380 496 380 496 380 496 381 495 1230 495 1230 495 381 495 1230 495 1230 495 380 495 381 495 381 495 381 495 381 495 381 495 380 496 381 495 1230 495 381 495 1230 495 381 495 380 496 1230 495 381 495 1230 495 1230 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 380 496 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 1231 494 381 495 381 495 381 495 381 495 381 495 381 494 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 381 495 382 494 382 494 1231 494 381 495 1231 494 1231 494 381 495 382 494
|
||||
#
|
||||
name: Heat_hi
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3539 1670 501 1226 502 1226 501 376 501 377 500 376 501 1226 501 376 499 378 500 1226 501 1226 501 377 528 1199 557 320 557 318 529 1197 531 1195 531 346 530 1196 530 1198 528 349 527 352 524 1229 498 379 498 379 498 1230 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 9045 3536 1674 496 1231 497 1231 497 380 497 380 497 380 497 1231 496 380 497 380 497 1231 497 1231 496 380 497 1231 496 380 497 380 497 1231 496 1231 497 380 497 1231 496 1231 496 380 497 380 497 1231 496 381 496 380 497 1231 497 381 496 380 497 380 497 380 497 380 497 381 496 381 496 381 496 380 497 380 497 381 496 381 496 381 496 381 496 380 497 381 496 381 496 381 496 381 496 380 497 1231 496 381 496 381 496 380 497 381 496 381 496 1232 495 381 496 381 496 381 496 381 496 1232 495 1232 495 1232 496 1232 495 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 1232 496 1232 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 1232 496 381 496 1232 495 381 496 1232 495 381 496 1232 495 1232 495 381 496 381 496 382 495 381 496 381 496 381 496 381 496 382 495 381 496 381 496 381 496 381 496 381 496 382 495 381 496 381 496 381 496 381 496 382 495 382 495 382 495 382 495 382 495 382 495 382 495 1232 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 1233 495 1233 494 1233 495 382 495 382 495 1233 495 1233 494 382 495
|
||||
#
|
||||
name: Heat_lo
|
||||
type: raw
|
||||
frequency: 38000
|
||||
duty_cycle: 0.330000
|
||||
data: 3539 1637 533 1225 502 1193 534 375 501 376 501 376 500 1226 501 376 501 376 500 1226 500 1227 501 376 529 1197 558 320 557 319 555 1169 531 1195 531 346 529 1196 530 1198 528 349 526 352 524 1229 497 379 497 379 497 1230 497 380 497 380 497 379 498 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 9042 3535 1674 496 1230 497 1230 497 380 497 380 497 380 497 1230 497 380 497 380 496 1230 497 1230 497 380 497 1230 497 380 497 380 497 1231 496 1230 497 380 497 1231 496 1231 496 380 496 380 497 1231 496 380 497 380 496 1231 496 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 497 380 496 380 497 380 497 380 497 380 497 380 496 381 496 380 497 380 497 380 497 381 496 1231 496 381 496 380 497 380 497 381 496 381 496 1231 496 381 496 381 496 380 497 381 495 1231 496 1231 496 1231 496 380 497 381 496 381 496 380 496 381 496 381 496 381 496 381 496 381 496 1231 496 1231 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 1231 496 381 496 381 496 1232 495 381 495 1232 495 381 496 1231 496 1231 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 496 381 495 381 496 381 496 381 496 381 496 1232 495 381 496 381 496 381 496 381 496 381 495 381 496 381 495 382 495 381 496 382 495 381 495 382 495 381 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 382 495 381 495 1232 495 1232 495 1232 495 1232 495 1232 495 382 495 382 495 382 495
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
entry,status,name,type,params
|
||||
Version,+,31.0,,
|
||||
Version,+,31.2,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
|
@ -679,7 +679,8 @@ Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_
|
|||
Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
|
||||
Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, uint8_t"
|
||||
Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool"
|
||||
Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, const char*, Elf32_Addr*"
|
||||
Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*"
|
||||
Function,+,elf_symbolname_hash,uint32_t,const char*
|
||||
Function,+,empty_screen_alloc,EmptyScreen*,
|
||||
Function,+,empty_screen_free,void,EmptyScreen*
|
||||
Function,+,empty_screen_get_view,View*,EmptyScreen*
|
||||
|
@ -1060,6 +1061,7 @@ Function,+,furi_hal_power_sleep,void,
|
|||
Function,+,furi_hal_power_sleep_available,_Bool,
|
||||
Function,+,furi_hal_power_suppress_charge_enter,void,
|
||||
Function,+,furi_hal_power_suppress_charge_exit,void,
|
||||
Function,+,furi_hal_pwm_is_running,_Bool,FuriHalPwmOutputId
|
||||
Function,+,furi_hal_pwm_set_params,void,"FuriHalPwmOutputId, uint32_t, uint8_t"
|
||||
Function,+,furi_hal_pwm_start,void,"FuriHalPwmOutputId, uint32_t, uint8_t"
|
||||
Function,+,furi_hal_pwm_stop,void,FuriHalPwmOutputId
|
||||
|
|
|
|
@ -1,5 +1,5 @@
|
|||
entry,status,name,type,params
|
||||
Version,+,31.0,,
|
||||
Version,+,31.2,,
|
||||
Header,+,applications/services/bt/bt_service/bt.h,,
|
||||
Header,+,applications/services/cli/cli.h,,
|
||||
Header,+,applications/services/cli/cli_vcp.h,,
|
||||
|
@ -821,7 +821,8 @@ Function,+,elements_slightly_rounded_box,void,"Canvas*, uint8_t, uint8_t, uint8_
|
|||
Function,+,elements_slightly_rounded_frame,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t"
|
||||
Function,+,elements_string_fit_width,void,"Canvas*, FuriString*, uint8_t"
|
||||
Function,+,elements_text_box,void,"Canvas*, uint8_t, uint8_t, uint8_t, uint8_t, Align, Align, const char*, _Bool"
|
||||
Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, const char*, Elf32_Addr*"
|
||||
Function,+,elf_resolve_from_hashtable,_Bool,"const ElfApiInterface*, uint32_t, Elf32_Addr*"
|
||||
Function,+,elf_symbolname_hash,uint32_t,const char*
|
||||
Function,+,empty_screen_alloc,EmptyScreen*,
|
||||
Function,+,empty_screen_free,void,EmptyScreen*
|
||||
Function,+,empty_screen_get_view,View*,EmptyScreen*
|
||||
|
@ -1243,6 +1244,8 @@ Function,+,furi_hal_mpu_protect_disable,void,FuriHalMpuRegion
|
|||
Function,+,furi_hal_mpu_protect_no_access,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize"
|
||||
Function,+,furi_hal_mpu_protect_read_only,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize"
|
||||
Function,+,furi_hal_nfc_activate_nfca,_Bool,"uint32_t, uint32_t*"
|
||||
Function,+,furi_hal_nfc_field_is_present,_Bool,
|
||||
Function,+,furi_hal_nfc_field_detect_start,void,
|
||||
Function,+,furi_hal_nfc_deinit,void,
|
||||
Function,+,furi_hal_nfc_detect,_Bool,"FuriHalNfcDevData*, uint32_t"
|
||||
Function,+,furi_hal_nfc_emulate_nfca,_Bool,"uint8_t*, uint8_t, uint8_t*, uint8_t, FuriHalNfcEmulateCallback, void*, uint32_t"
|
||||
|
@ -1327,6 +1330,9 @@ Function,-,furi_hal_resources_init_early,void,
|
|||
Function,+,furi_hal_rfid_comp_set_callback,void,"FuriHalRfidCompCallback, void*"
|
||||
Function,+,furi_hal_rfid_comp_start,void,
|
||||
Function,+,furi_hal_rfid_comp_stop,void,
|
||||
Function,+,furi_hal_rfid_field_is_present,_Bool,uint32_t*
|
||||
Function,+,furi_hal_rfid_field_detect_start,void,
|
||||
Function,+,furi_hal_rfid_field_detect_stop,void,
|
||||
Function,-,furi_hal_rfid_init,void,
|
||||
Function,+,furi_hal_rfid_pin_pull_pulldown,void,
|
||||
Function,+,furi_hal_rfid_pin_pull_release,void,
|
||||
|
|
|
|
@ -819,3 +819,17 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits(
|
|||
void furi_hal_nfc_ll_poll() {
|
||||
rfalWorker();
|
||||
}
|
||||
|
||||
void furi_hal_nfc_field_detect_start() {
|
||||
st25r3916WriteRegister(
|
||||
ST25R3916_REG_OP_CONTROL,
|
||||
ST25R3916_REG_OP_CONTROL_en | ST25R3916_REG_OP_CONTROL_en_fd_mask);
|
||||
st25r3916WriteRegister(ST25R3916_REG_MODE, ST25R3916_REG_MODE_targ | ST25R3916_REG_MODE_om0);
|
||||
}
|
||||
|
||||
bool furi_hal_nfc_field_is_present() {
|
||||
return st25r3916CheckReg(
|
||||
ST25R3916_REG_AUX_DISPLAY,
|
||||
ST25R3916_REG_AUX_DISPLAY_efd_o,
|
||||
ST25R3916_REG_AUX_DISPLAY_efd_o);
|
||||
}
|
|
@ -423,6 +423,10 @@ FuriHalNfcReturn furi_hal_nfc_ll_txrx_bits(
|
|||
|
||||
void furi_hal_nfc_ll_poll();
|
||||
|
||||
void furi_hal_nfc_field_detect_start();
|
||||
|
||||
bool furi_hal_nfc_field_is_present();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -25,6 +25,19 @@
|
|||
#define RFID_CAPTURE_IND_CH LL_TIM_CHANNEL_CH3
|
||||
#define RFID_CAPTURE_DIR_CH LL_TIM_CHANNEL_CH4
|
||||
|
||||
// Field presence detection
|
||||
#define FURI_HAL_RFID_FIELD_FREQUENCY_MIN 80000
|
||||
#define FURI_HAL_RFID_FIELD_FREQUENCY_MAX 200000
|
||||
|
||||
#define FURI_HAL_RFID_FIELD_COUNTER_TIMER TIM2
|
||||
#define FURI_HAL_RFID_FIELD_COUNTER_TIMER_BUS FuriHalBusTIM2
|
||||
#define FURI_HAL_RFID_FIELD_COUNTER_TIMER_CHANNEL LL_TIM_CHANNEL_CH3
|
||||
|
||||
#define FURI_HAL_RFID_FIELD_TIMEOUT_TIMER TIM1
|
||||
#define FURI_HAL_RFID_FIELD_TIMEOUT_TIMER_BUS FuriHalBusTIM1
|
||||
|
||||
#define FURI_HAL_RFID_FIELD_DMAMUX_DMA LL_DMAMUX_REQ_TIM1_UP
|
||||
|
||||
/* DMA Channels definition */
|
||||
#define RFID_DMA DMA2
|
||||
#define RFID_DMA_CH1_CHANNEL LL_DMA_CHANNEL_1
|
||||
|
@ -33,10 +46,16 @@
|
|||
#define RFID_DMA_CH1_DEF RFID_DMA, RFID_DMA_CH1_CHANNEL
|
||||
#define RFID_DMA_CH2_DEF RFID_DMA, RFID_DMA_CH2_CHANNEL
|
||||
|
||||
typedef struct {
|
||||
uint32_t counter;
|
||||
uint32_t set_tim_counter_cnt;
|
||||
} FuriHalRfidField;
|
||||
|
||||
typedef struct {
|
||||
FuriHalRfidDMACallback dma_callback;
|
||||
FuriHalRfidReadCaptureCallback read_capture_callback;
|
||||
void* context;
|
||||
FuriHalRfidField field;
|
||||
} FuriHalRfid;
|
||||
|
||||
FuriHalRfid* furi_hal_rfid = NULL;
|
||||
|
@ -51,6 +70,8 @@ FuriHalRfid* furi_hal_rfid = NULL;
|
|||
void furi_hal_rfid_init() {
|
||||
furi_assert(furi_hal_rfid == NULL);
|
||||
furi_hal_rfid = malloc(sizeof(FuriHalRfid));
|
||||
furi_hal_rfid->field.counter = 0;
|
||||
furi_hal_rfid->field.set_tim_counter_cnt = 0;
|
||||
|
||||
furi_hal_rfid_pins_reset();
|
||||
|
||||
|
@ -133,6 +154,23 @@ static void furi_hal_rfid_pins_read() {
|
|||
furi_hal_gpio_init(&gpio_rfid_data_in, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
||||
}
|
||||
|
||||
static void furi_hal_rfid_pins_field() {
|
||||
// ibutton low
|
||||
furi_hal_ibutton_pin_configure();
|
||||
furi_hal_ibutton_pin_write(false);
|
||||
|
||||
// pull pin to timer out
|
||||
furi_hal_gpio_init(&gpio_nfc_irq_rfid_pull, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, false);
|
||||
|
||||
// pull rfid antenna from carrier side
|
||||
furi_hal_gpio_init(&gpio_rfid_carrier_out, GpioModeOutputPushPull, GpioPullNo, GpioSpeedLow);
|
||||
furi_hal_gpio_write(&gpio_rfid_carrier_out, false);
|
||||
|
||||
furi_hal_gpio_init_ex(
|
||||
&gpio_rfid_carrier, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedLow, GpioAltFn2TIM2);
|
||||
}
|
||||
|
||||
void furi_hal_rfid_pin_pull_release() {
|
||||
furi_hal_gpio_write(&gpio_nfc_irq_rfid_pull, true);
|
||||
}
|
||||
|
@ -427,3 +465,124 @@ void COMP_IRQHandler() {
|
|||
furi_hal_rfid_comp_callback_context);
|
||||
}
|
||||
}
|
||||
|
||||
static void furi_hal_rfid_field_tim_setup() {
|
||||
// setup timer counter
|
||||
furi_hal_bus_enable(FURI_HAL_RFID_FIELD_COUNTER_TIMER_BUS);
|
||||
|
||||
LL_TIM_SetPrescaler(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0);
|
||||
LL_TIM_SetCounterMode(FURI_HAL_RFID_FIELD_COUNTER_TIMER, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetAutoReload(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0xFFFFFFFF);
|
||||
LL_TIM_DisableARRPreload(FURI_HAL_RFID_FIELD_COUNTER_TIMER);
|
||||
LL_TIM_SetRepetitionCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0);
|
||||
|
||||
LL_TIM_SetClockDivision(FURI_HAL_RFID_FIELD_COUNTER_TIMER, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetClockSource(FURI_HAL_RFID_FIELD_COUNTER_TIMER, LL_TIM_CLOCKSOURCE_EXT_MODE2);
|
||||
LL_TIM_ConfigETR(
|
||||
FURI_HAL_RFID_FIELD_COUNTER_TIMER,
|
||||
LL_TIM_ETR_POLARITY_INVERTED,
|
||||
LL_TIM_ETR_PRESCALER_DIV1,
|
||||
LL_TIM_ETR_FILTER_FDIV1);
|
||||
|
||||
LL_TIM_OC_InitTypeDef TIM_OC_InitStruct = {0};
|
||||
TIM_OC_InitStruct.OCMode = LL_TIM_OCMODE_PWM1;
|
||||
TIM_OC_InitStruct.OCState = LL_TIM_OCSTATE_ENABLE;
|
||||
TIM_OC_InitStruct.CompareValue = 1;
|
||||
LL_TIM_OC_Init(
|
||||
FURI_HAL_RFID_FIELD_COUNTER_TIMER,
|
||||
FURI_HAL_RFID_FIELD_COUNTER_TIMER_CHANNEL,
|
||||
&TIM_OC_InitStruct);
|
||||
|
||||
LL_TIM_GenerateEvent_UPDATE(FURI_HAL_RFID_FIELD_COUNTER_TIMER);
|
||||
LL_TIM_OC_SetPolarity(
|
||||
FURI_HAL_RFID_FIELD_COUNTER_TIMER,
|
||||
FURI_HAL_RFID_FIELD_COUNTER_TIMER_CHANNEL,
|
||||
LL_TIM_OCPOLARITY_HIGH);
|
||||
LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_FIELD_COUNTER_TIMER);
|
||||
|
||||
// setup timer timeouts dma
|
||||
furi_hal_bus_enable(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER_BUS);
|
||||
|
||||
LL_TIM_SetPrescaler(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, 64000 - 1);
|
||||
LL_TIM_SetCounterMode(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, LL_TIM_COUNTERMODE_UP);
|
||||
LL_TIM_SetAutoReload(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, 100 - 1); // 100 ms
|
||||
LL_TIM_SetClockDivision(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, LL_TIM_CLOCKDIVISION_DIV1);
|
||||
LL_TIM_SetClockSource(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, LL_TIM_CLOCKSOURCE_INTERNAL);
|
||||
|
||||
LL_TIM_DisableARRPreload(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER);
|
||||
|
||||
LL_TIM_EnableDMAReq_UPDATE(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER);
|
||||
LL_TIM_GenerateEvent_UPDATE(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER);
|
||||
}
|
||||
|
||||
void furi_hal_rfid_field_detect_start(void) {
|
||||
// setup pins
|
||||
furi_hal_rfid_pins_field();
|
||||
|
||||
// configure timer
|
||||
furi_hal_rfid_field_tim_setup();
|
||||
|
||||
// configure DMA "TIM_COUNTER_CNT -> counter"
|
||||
LL_DMA_SetMemoryAddress(RFID_DMA_CH1_DEF, (uint32_t) & (furi_hal_rfid->field.counter));
|
||||
LL_DMA_SetPeriphAddress(
|
||||
RFID_DMA_CH1_DEF, (uint32_t) & (FURI_HAL_RFID_FIELD_COUNTER_TIMER->CNT));
|
||||
LL_DMA_ConfigTransfer(
|
||||
RFID_DMA_CH1_DEF,
|
||||
LL_DMA_DIRECTION_PERIPH_TO_MEMORY | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
|
||||
LL_DMA_MEMORY_NOINCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
|
||||
LL_DMA_PRIORITY_MEDIUM);
|
||||
LL_DMA_SetDataLength(RFID_DMA_CH1_DEF, 1);
|
||||
LL_DMA_SetPeriphRequest(RFID_DMA_CH1_DEF, FURI_HAL_RFID_FIELD_DMAMUX_DMA);
|
||||
LL_DMA_EnableChannel(RFID_DMA_CH1_DEF);
|
||||
|
||||
// configure DMA "mem -> TIM_COUNTER_CNT"
|
||||
LL_DMA_SetMemoryAddress(
|
||||
RFID_DMA_CH2_DEF, (uint32_t) & (furi_hal_rfid->field.set_tim_counter_cnt));
|
||||
LL_DMA_SetPeriphAddress(
|
||||
RFID_DMA_CH2_DEF, (uint32_t) & (FURI_HAL_RFID_FIELD_COUNTER_TIMER->CNT));
|
||||
LL_DMA_ConfigTransfer(
|
||||
RFID_DMA_CH2_DEF,
|
||||
LL_DMA_DIRECTION_MEMORY_TO_PERIPH | LL_DMA_MODE_CIRCULAR | LL_DMA_PERIPH_NOINCREMENT |
|
||||
LL_DMA_MEMORY_NOINCREMENT | LL_DMA_PDATAALIGN_WORD | LL_DMA_MDATAALIGN_WORD |
|
||||
LL_DMA_PRIORITY_LOW);
|
||||
LL_DMA_SetDataLength(RFID_DMA_CH2_DEF, 1);
|
||||
LL_DMA_SetPeriphRequest(RFID_DMA_CH2_DEF, FURI_HAL_RFID_FIELD_DMAMUX_DMA);
|
||||
LL_DMA_EnableChannel(RFID_DMA_CH2_DEF);
|
||||
|
||||
// start tim counter
|
||||
LL_TIM_EnableAllOutputs(FURI_HAL_RFID_FIELD_COUNTER_TIMER);
|
||||
|
||||
LL_TIM_SetCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER, 0);
|
||||
LL_TIM_EnableCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER);
|
||||
|
||||
// start tim timeout
|
||||
LL_TIM_SetCounter(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER, 0);
|
||||
LL_TIM_EnableCounter(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER);
|
||||
LL_TIM_EnableIT_UPDATE(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER);
|
||||
}
|
||||
|
||||
void furi_hal_rfid_field_detect_stop(void) {
|
||||
LL_TIM_DisableCounter(FURI_HAL_RFID_FIELD_COUNTER_TIMER);
|
||||
LL_TIM_DisableAllOutputs(FURI_HAL_RFID_FIELD_COUNTER_TIMER);
|
||||
|
||||
LL_TIM_DisableCounter(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER);
|
||||
|
||||
FURI_CRITICAL_ENTER();
|
||||
|
||||
LL_DMA_DeInit(RFID_DMA_CH1_DEF);
|
||||
LL_DMA_DeInit(RFID_DMA_CH2_DEF);
|
||||
|
||||
furi_hal_bus_disable(FURI_HAL_RFID_FIELD_COUNTER_TIMER_BUS);
|
||||
furi_hal_bus_disable(FURI_HAL_RFID_FIELD_TIMEOUT_TIMER_BUS);
|
||||
|
||||
furi_hal_rfid_pins_reset();
|
||||
|
||||
FURI_CRITICAL_EXIT();
|
||||
}
|
||||
|
||||
bool furi_hal_rfid_field_is_present(uint32_t* frequency) {
|
||||
*frequency = furi_hal_rfid->field.counter * 10;
|
||||
return (
|
||||
(*frequency >= FURI_HAL_RFID_FIELD_FREQUENCY_MIN) &&
|
||||
(*frequency <= FURI_HAL_RFID_FIELD_FREQUENCY_MAX));
|
||||
}
|
|
@ -87,6 +87,20 @@ typedef void (*FuriHalRfidCompCallback)(bool level, void* context);
|
|||
/** Set comparator callback */
|
||||
void furi_hal_rfid_comp_set_callback(FuriHalRfidCompCallback callback, void* context);
|
||||
|
||||
/** Start/Enable Field Presence detect */
|
||||
void furi_hal_rfid_field_detect_start();
|
||||
|
||||
/** Stop/Disable Field Presence detect */
|
||||
void furi_hal_rfid_field_detect_stop();
|
||||
|
||||
/** Check Field Presence
|
||||
*
|
||||
* @param[out] frequency pointer to frequency value to be set if filed detected
|
||||
*
|
||||
* @return true if field is present, false if not
|
||||
*/
|
||||
bool furi_hal_rfid_field_is_present(uint32_t* frequency);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -296,7 +296,9 @@ static FuriStringUTF8State state_to_furi_state(m_str1ng_utf8_state_e state) {
|
|||
}
|
||||
|
||||
void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnicodeValue* unicode) {
|
||||
string_unicode_t m_u = *unicode;
|
||||
m_str1ng_utf8_state_e m_state = furi_state_to_state(*state);
|
||||
m_str1ng_utf8_decode(c, &m_state, unicode);
|
||||
m_str1ng_utf8_decode(c, &m_state, &m_u);
|
||||
*state = state_to_furi_state(m_state);
|
||||
*unicode = m_u;
|
||||
}
|
||||
|
|
|
@ -633,20 +633,17 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico
|
|||
* @brief Search for a string (or C string) in a string
|
||||
* (string, [c]string[, start=0])
|
||||
*/
|
||||
#define furi_string_search(v, ...) \
|
||||
#define furi_string_search(...) \
|
||||
M_APPLY( \
|
||||
FURI_STRING_SELECT3, \
|
||||
furi_string_search, \
|
||||
furi_string_search_str, \
|
||||
v, \
|
||||
M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
|
||||
M_DEFAULT_ARGS(3, (0), __VA_ARGS__))
|
||||
/**
|
||||
* @brief Search for a C string in a string
|
||||
* (string, cstring[, start=0])
|
||||
*/
|
||||
#define furi_string_search_str(v, ...) \
|
||||
M_APPLY(furi_string_search_str, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
#define furi_string_search_str(...) furi_string_search_str(M_DEFAULT_ARGS(3, (0), __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Test if the string starts with the given string (or C string).
|
||||
|
@ -672,41 +669,36 @@ void furi_string_utf8_decode(char c, FuriStringUTF8State* state, FuriStringUnico
|
|||
* @brief Trim a string from the given set of characters (default is " \n\r\t").
|
||||
* (string[, set=" \n\r\t"])
|
||||
*/
|
||||
#define furi_string_trim(...) M_APPLY(furi_string_trim, M_IF_DEFAULT1(" \n\r\t", __VA_ARGS__))
|
||||
#define furi_string_trim(...) furi_string_trim(M_DEFAULT_ARGS(2, (" \n\r\t"), __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Search for a character in a string.
|
||||
* (string, character[, start=0])
|
||||
*/
|
||||
#define furi_string_search_char(v, ...) \
|
||||
M_APPLY(furi_string_search_char, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
#define furi_string_search_char(...) furi_string_search_char(M_DEFAULT_ARGS(3, (0), __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Reverse Search for a character in a string.
|
||||
* (string, character[, start=0])
|
||||
*/
|
||||
#define furi_string_search_rchar(v, ...) \
|
||||
M_APPLY(furi_string_search_rchar, v, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
#define furi_string_search_rchar(...) furi_string_search_rchar(M_DEFAULT_ARGS(3, (0), __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Replace a string to another string (or C string to another C string) in a string.
|
||||
* (string, [c]string, [c]string[, start=0])
|
||||
*/
|
||||
#define furi_string_replace(a, b, ...) \
|
||||
#define furi_string_replace(...) \
|
||||
M_APPLY( \
|
||||
FURI_STRING_SELECT4, \
|
||||
furi_string_replace, \
|
||||
furi_string_replace_str, \
|
||||
a, \
|
||||
b, \
|
||||
M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
M_DEFAULT_ARGS(4, (0), __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief Replace a C string to another C string in a string.
|
||||
* (string, cstring, cstring[, start=0])
|
||||
*/
|
||||
#define furi_string_replace_str(a, b, ...) \
|
||||
M_APPLY(furi_string_replace_str, a, b, M_IF_DEFAULT1(0, __VA_ARGS__))
|
||||
#define furi_string_replace_str(...) furi_string_replace_str(M_DEFAULT_ARGS(4, (0), __VA_ARGS__))
|
||||
|
||||
/**
|
||||
* @brief INIT OPLIST for FuriString.
|
||||
|
|
|
@ -7,27 +7,22 @@
|
|||
|
||||
bool elf_resolve_from_hashtable(
|
||||
const ElfApiInterface* interface,
|
||||
const char* name,
|
||||
uint32_t hash,
|
||||
Elf32_Addr* address) {
|
||||
bool result = false;
|
||||
const HashtableApiInterface* hashtable_interface =
|
||||
static_cast<const HashtableApiInterface*>(interface);
|
||||
bool result = false;
|
||||
uint32_t gnu_sym_hash = elf_gnu_hash(name);
|
||||
|
||||
sym_entry key = {
|
||||
.hash = gnu_sym_hash,
|
||||
.hash = hash,
|
||||
.address = 0,
|
||||
};
|
||||
|
||||
auto find_res =
|
||||
std::lower_bound(hashtable_interface->table_cbegin, hashtable_interface->table_cend, key);
|
||||
if((find_res == hashtable_interface->table_cend || (find_res->hash != gnu_sym_hash))) {
|
||||
if((find_res == hashtable_interface->table_cend || (find_res->hash != hash))) {
|
||||
FURI_LOG_W(
|
||||
TAG,
|
||||
"Can't find symbol '%s' (hash %lx) @ %p!",
|
||||
name,
|
||||
gnu_sym_hash,
|
||||
hashtable_interface->table_cbegin);
|
||||
TAG, "Can't find symbol with hash %lx @ %p!", hash, hashtable_interface->table_cbegin);
|
||||
result = false;
|
||||
} else {
|
||||
result = true;
|
||||
|
@ -36,3 +31,7 @@ bool elf_resolve_from_hashtable(
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t elf_symbolname_hash(const char* s) {
|
||||
return elf_gnu_hash(s);
|
||||
}
|
|
@ -19,15 +19,17 @@ struct sym_entry {
|
|||
/**
|
||||
* @brief Resolver for API entries using a pre-sorted table with hashes
|
||||
* @param interface pointer to HashtableApiInterface
|
||||
* @param name function name
|
||||
* @param hash gnu hash of function name
|
||||
* @param address output for function address
|
||||
* @return true if the table contains a function
|
||||
*/
|
||||
bool elf_resolve_from_hashtable(
|
||||
const ElfApiInterface* interface,
|
||||
const char* name,
|
||||
uint32_t hash,
|
||||
Elf32_Addr* address);
|
||||
|
||||
uint32_t elf_symbolname_hash(const char* s);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
|
@ -49,7 +51,9 @@ struct HashtableApiInterface : public ElfApiInterface {
|
|||
}
|
||||
|
||||
#define API_VARIABLE(x, var_type) \
|
||||
sym_entry { .hash = elf_gnu_hash(#x), .address = (uint32_t)(&(x)), }
|
||||
sym_entry { \
|
||||
.hash = elf_gnu_hash(#x), .address = (uint32_t)(&(x)), \
|
||||
}
|
||||
|
||||
constexpr bool operator<(const sym_entry& k1, const sym_entry& k2) {
|
||||
return k1.hash < k2.hash;
|
||||
|
|
|
@ -11,6 +11,6 @@ typedef struct ElfApiInterface {
|
|||
uint16_t api_version_minor;
|
||||
bool (*resolver_callback)(
|
||||
const struct ElfApiInterface* interface,
|
||||
const char* name,
|
||||
uint32_t hash,
|
||||
Elf32_Addr* address);
|
||||
} ElfApiInterface;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "elf_file.h"
|
||||
#include "elf_file_i.h"
|
||||
#include "elf_api_interface.h"
|
||||
#include "../api_hashtable/api_hashtable.h"
|
||||
|
||||
#define TAG "elf"
|
||||
|
||||
|
@ -9,6 +10,7 @@
|
|||
#define SECTION_OFFSET(e, n) ((e)->section_table + (n) * sizeof(Elf32_Shdr))
|
||||
#define IS_FLAGS_SET(v, m) (((v) & (m)) == (m))
|
||||
#define RESOLVER_THREAD_YIELD_STEP 30
|
||||
#define FAST_RELOCATION_VERSION 1
|
||||
|
||||
// #define ELF_DEBUG_LOG 1
|
||||
|
||||
|
@ -71,6 +73,7 @@ static ELFSection* elf_file_get_or_put_section(ELFFile* elf, const char* name) {
|
|||
.size = 0,
|
||||
.rel_count = 0,
|
||||
.rel_offset = 0,
|
||||
.fast_rel = NULL,
|
||||
});
|
||||
section_p = elf_file_get_section(elf, name);
|
||||
}
|
||||
|
@ -168,7 +171,8 @@ static ELFSection* elf_section_of(ELFFile* elf, int index) {
|
|||
static Elf32_Addr elf_address_of(ELFFile* elf, Elf32_Sym* sym, const char* sName) {
|
||||
if(sym->st_shndx == SHN_UNDEF) {
|
||||
Elf32_Addr addr = 0;
|
||||
if(elf->api_interface->resolver_callback(elf->api_interface, sName, &addr)) {
|
||||
uint32_t hash = elf_symbolname_hash(sName);
|
||||
if(elf->api_interface->resolver_callback(elf->api_interface, hash, &addr)) {
|
||||
return addr;
|
||||
}
|
||||
} else {
|
||||
|
@ -424,6 +428,7 @@ typedef enum {
|
|||
SectionTypeSymTab = 1 << 3,
|
||||
SectionTypeStrTab = 1 << 4,
|
||||
SectionTypeDebugLink = 1 << 5,
|
||||
SectionTypeFastRelData = 1 << 6,
|
||||
|
||||
SectionTypeValid = SectionTypeSymTab | SectionTypeStrTab,
|
||||
} SectionType;
|
||||
|
@ -505,7 +510,8 @@ static SectionType elf_preload_section(
|
|||
// TODO: how to do it not by name?
|
||||
// .ARM: type 0x70000001, flags SHF_ALLOC | SHF_LINK_ORDER
|
||||
// .rel.ARM: type 0x9, flags SHT_REL
|
||||
if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.")) {
|
||||
if(str_prefix(name, ".ARM.") || str_prefix(name, ".rel.ARM.") ||
|
||||
str_prefix(name, ".fast.rel.ARM.")) {
|
||||
FURI_LOG_D(TAG, "Ignoring ARM section");
|
||||
return SectionTypeUnused;
|
||||
}
|
||||
|
@ -536,11 +542,31 @@ static SectionType elf_preload_section(
|
|||
|
||||
// Load link info section
|
||||
if(section_header->sh_flags & SHF_INFO_LINK) {
|
||||
if(str_prefix(name, ".rel")) {
|
||||
name = name + strlen(".rel");
|
||||
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
|
||||
section_p->rel_count = section_header->sh_size / sizeof(Elf32_Rel);
|
||||
section_p->rel_offset = section_header->sh_offset;
|
||||
return SectionTypeRelData;
|
||||
} else {
|
||||
FURI_LOG_E(TAG, "Unknown link info section '%s'", name);
|
||||
return SectionTypeERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Load fast rel section
|
||||
if(str_prefix(name, ".fast.rel")) {
|
||||
name = name + strlen(".fast.rel");
|
||||
ELFSection* section_p = elf_file_get_or_put_section(elf, name);
|
||||
section_p->fast_rel = malloc(sizeof(ELFSection));
|
||||
|
||||
if(!elf_load_section_data(elf, section_p->fast_rel, section_header)) {
|
||||
FURI_LOG_E(TAG, "Error loading section '%s'", name);
|
||||
return SectionTypeERROR;
|
||||
}
|
||||
|
||||
FURI_LOG_D(TAG, "Loaded fast rel section for '%s'", name);
|
||||
return SectionTypeFastRelData;
|
||||
}
|
||||
|
||||
// Load symbol table
|
||||
|
@ -571,8 +597,90 @@ static SectionType elf_preload_section(
|
|||
return SectionTypeUnused;
|
||||
}
|
||||
|
||||
static Elf32_Addr elf_address_of_by_hash(ELFFile* elf, uint32_t hash) {
|
||||
Elf32_Addr addr = 0;
|
||||
if(elf->api_interface->resolver_callback(elf->api_interface, hash, &addr)) {
|
||||
return addr;
|
||||
}
|
||||
return ELF_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
static bool elf_relocate_fast(ELFFile* elf, ELFSection* s) {
|
||||
UNUSED(elf);
|
||||
const uint8_t* start = s->fast_rel->data;
|
||||
const uint8_t version = *start;
|
||||
|
||||
if(version != FAST_RELOCATION_VERSION) {
|
||||
FURI_LOG_E(TAG, "Unsupported fast relocation version %d", version);
|
||||
return false;
|
||||
}
|
||||
start += 1;
|
||||
|
||||
const uint32_t records_count = *((uint32_t*)start);
|
||||
start += 4;
|
||||
FURI_LOG_D(TAG, "Fast relocation records count: %ld", records_count);
|
||||
|
||||
for(uint32_t i = 0; i < records_count; i++) {
|
||||
bool is_section = (*start & (0x1 << 7)) ? true : false;
|
||||
uint8_t type = *start & 0x7F;
|
||||
start += 1;
|
||||
uint32_t hash_or_section_index = *((uint32_t*)start);
|
||||
start += 4;
|
||||
|
||||
uint32_t section_value = ELF_INVALID_ADDRESS;
|
||||
if(is_section) {
|
||||
section_value = *((uint32_t*)start);
|
||||
start += 4;
|
||||
}
|
||||
|
||||
const uint32_t offsets_count = *((uint32_t*)start);
|
||||
start += 4;
|
||||
|
||||
FURI_LOG_D(
|
||||
TAG,
|
||||
"Fast relocation record %ld: is_section=%d, type=%d, hash_or_section_index=%lX, offsets_count=%ld",
|
||||
i,
|
||||
is_section,
|
||||
type,
|
||||
hash_or_section_index,
|
||||
offsets_count);
|
||||
|
||||
Elf32_Addr address = 0;
|
||||
if(is_section) {
|
||||
ELFSection* symSec = elf_section_of(elf, hash_or_section_index);
|
||||
if(symSec) {
|
||||
address = ((Elf32_Addr)symSec->data) + section_value;
|
||||
}
|
||||
} else {
|
||||
address = elf_address_of_by_hash(elf, hash_or_section_index);
|
||||
}
|
||||
|
||||
if(address == ELF_INVALID_ADDRESS) {
|
||||
FURI_LOG_E(TAG, "Failed to resolve address for hash %lX", hash_or_section_index);
|
||||
return false;
|
||||
}
|
||||
|
||||
for(uint32_t j = 0; j < offsets_count; j++) {
|
||||
uint32_t offset = *((uint32_t*)start) & 0x00FFFFFF;
|
||||
start += 3;
|
||||
// FURI_LOG_I(TAG, " Fast relocation offset %ld: %ld", j, offset);
|
||||
Elf32_Addr relAddr = ((Elf32_Addr)s->data) + offset;
|
||||
elf_relocate_symbol(elf, relAddr, type, address);
|
||||
}
|
||||
}
|
||||
|
||||
aligned_free(s->fast_rel->data);
|
||||
free(s->fast_rel);
|
||||
s->fast_rel = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool elf_relocate_section(ELFFile* elf, ELFSection* section) {
|
||||
if(section->rel_count) {
|
||||
if(section->fast_rel) {
|
||||
FURI_LOG_D(TAG, "Fast relocating section");
|
||||
return elf_relocate_fast(elf, section);
|
||||
} else if(section->rel_count) {
|
||||
FURI_LOG_D(TAG, "Relocating section");
|
||||
return elf_relocate(elf, section);
|
||||
} else {
|
||||
|
@ -630,6 +738,10 @@ void elf_file_free(ELFFile* elf) {
|
|||
if(itref->value.data) {
|
||||
aligned_free(itref->value.data);
|
||||
}
|
||||
if(itref->value.fast_rel) {
|
||||
aligned_free(itref->value.fast_rel->data);
|
||||
free(itref->value.fast_rel);
|
||||
}
|
||||
free((void*)itref->key);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,14 +13,18 @@ DICT_DEF2(AddressCache, int, M_DEFAULT_OPLIST, Elf32_Addr, M_DEFAULT_OPLIST)
|
|||
*/
|
||||
typedef int32_t(entry_t)(void*);
|
||||
|
||||
typedef struct {
|
||||
typedef struct ELFSection ELFSection;
|
||||
|
||||
struct ELFSection {
|
||||
void* data;
|
||||
uint16_t sec_idx;
|
||||
Elf32_Word size;
|
||||
|
||||
size_t rel_count;
|
||||
Elf32_Off rel_offset;
|
||||
} ELFSection;
|
||||
ELFSection* fast_rel;
|
||||
|
||||
uint16_t sec_idx;
|
||||
};
|
||||
|
||||
DICT_DEF2(ELFSectionDict, const char*, M_CSTR_OPLIST, ELFSection, M_POD_OPLIST)
|
||||
|
||||
|
|
|
@ -13,12 +13,12 @@ struct CompositeApiResolver {
|
|||
|
||||
static bool composite_api_resolver_callback(
|
||||
const ElfApiInterface* interface,
|
||||
const char* name,
|
||||
uint32_t hash,
|
||||
Elf32_Addr* address) {
|
||||
CompositeApiResolver* resolver = (CompositeApiResolver*)interface;
|
||||
for
|
||||
M_EACH(interface, resolver->interfaces, ElfApiInterfaceList_t) {
|
||||
if((*interface)->resolver_callback(*interface, name, address)) {
|
||||
if((*interface)->resolver_callback(*interface, hash, address)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ ReturnCode slix2_read_nxp_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_da
|
|||
}
|
||||
}
|
||||
|
||||
if(ret != ERR_NONE || received != 8) {
|
||||
if(ret != ERR_NONE || received != 8) { //-V560
|
||||
FURI_LOG_D(TAG, "Failed: %d, %d", ret, received);
|
||||
return ret;
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ ReturnCode slix2_read_signature(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data
|
|||
}
|
||||
}
|
||||
|
||||
if(ret != ERR_NONE || received != 33) {
|
||||
if(ret != ERR_NONE || received != 33) { //-V560
|
||||
FURI_LOG_D(TAG, "Failed: %d, %d", ret, received);
|
||||
return ret;
|
||||
}
|
||||
|
@ -649,7 +649,7 @@ bool slix2_protocol_filter( // -V524
|
|||
ctr_new = (ctr_old & 0xFFFF0000) | ((ctr_old + 1) & 0xFFFF);
|
||||
|
||||
/* protection flag set? */
|
||||
if(ctr_old & 0x01000000) {
|
||||
if(ctr_old & 0x01000000) { //-V1051
|
||||
allowed = nfcv_data->sub_data.slix.flags &
|
||||
NfcVSlixDataFlagsValidKeyRead;
|
||||
}
|
||||
|
@ -659,7 +659,10 @@ bool slix2_protocol_filter( // -V524
|
|||
}
|
||||
|
||||
if(allowed) {
|
||||
memcpy(&nfcv_data->data[nfcv_data->block_size * block_num], &ctr_new, 4);
|
||||
memcpy( //-V1086
|
||||
&nfcv_data->data[nfcv_data->block_size * block_num],
|
||||
&ctr_new,
|
||||
4);
|
||||
} else {
|
||||
/* incorrect read or write password */
|
||||
ctx->response_buffer[0] = NFCV_RES_FLAG_ERROR;
|
||||
|
|
|
@ -2,12 +2,13 @@
|
|||
#include <m-core.h>
|
||||
|
||||
#define M_INIT_DUP(a) ((a) = strdup(""))
|
||||
#define M_SET_DUP(a, b) (M_CHECK_DEFAULT_TYPE(a), free((void*)a), (a) = strdup(b))
|
||||
#define M_INIT_SET_DUP(a, b) ((a) = strdup(b))
|
||||
#define M_SET_DUP(a, b) (free((void*)a), (a) = strdup(b))
|
||||
#define M_CLEAR_DUP(a) (free((void*)a))
|
||||
|
||||
#define M_CSTR_DUP_OPLIST \
|
||||
(INIT(M_INIT_DUP), \
|
||||
INIT_SET(M_SET_DUP), \
|
||||
INIT_SET(M_INIT_SET_DUP), \
|
||||
SET(M_SET_DUP), \
|
||||
CLEAR(M_CLEAR_DUP), \
|
||||
HASH(m_core_cstr_hash), \
|
||||
|
|
0
scripts/distfap.py
Normal file → Executable file
0
scripts/distfap.py
Normal file → Executable file
169
scripts/fastfap.py
Executable file
169
scripts/fastfap.py
Executable file
|
@ -0,0 +1,169 @@
|
|||
#!/usr/bin/env python3
|
||||
import hashlib
|
||||
import os
|
||||
import struct
|
||||
import subprocess
|
||||
import tempfile
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
|
||||
from elftools.elf.elffile import ELFFile
|
||||
from elftools.elf.relocation import RelocationSection
|
||||
from elftools.elf.sections import SymbolTableSection
|
||||
from fbt.sdk.hashes import gnu_sym_hash
|
||||
from flipper.app import App
|
||||
|
||||
VERSION = 1
|
||||
|
||||
|
||||
@dataclass
|
||||
class RelData:
|
||||
section: int
|
||||
section_value: int
|
||||
type: int
|
||||
offset: int
|
||||
name: str
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class UniqueRelData:
|
||||
section: int
|
||||
section_value: int
|
||||
type: int
|
||||
name: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class RelSection:
|
||||
name: str
|
||||
oringinal_name: str
|
||||
data: dict[UniqueRelData, list[int]]
|
||||
|
||||
|
||||
def serialize_relsection_data(data: dict[UniqueRelData, list[int]]) -> bytes:
|
||||
result = struct.pack("<B", VERSION)
|
||||
result += struct.pack("<I", len(data))
|
||||
for unique, values in data.items():
|
||||
if unique.section > 0:
|
||||
result += struct.pack("<B", (1 << 7) | unique.type & 0x7F)
|
||||
result += struct.pack("<I", unique.section)
|
||||
result += struct.pack("<I", unique.section_value)
|
||||
else:
|
||||
result += struct.pack("<B", (0 << 7) | unique.type & 0x7F)
|
||||
result += struct.pack("<I", gnu_sym_hash(unique.name))
|
||||
|
||||
result += struct.pack("<I", len(values))
|
||||
for offset in values:
|
||||
result += struct.pack(
|
||||
"<BBB", offset & 0xFF, (offset >> 8) & 0xFF, (offset >> 16) & 0xFF
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class Main(App):
|
||||
def init(self):
|
||||
self.parser.add_argument("fap_src_path", help="App file to upload")
|
||||
self.parser.add_argument("objcopy_path", help="Objcopy path")
|
||||
self.parser.set_defaults(func=self.process)
|
||||
|
||||
def process(self):
|
||||
fap_path = self.args.fap_src_path
|
||||
objcopy_path = self.args.objcopy_path
|
||||
|
||||
sections: list[RelSection] = []
|
||||
|
||||
with open(fap_path, "rb") as f:
|
||||
elf_file = ELFFile(f)
|
||||
|
||||
relocation_sections: list[RelocationSection] = []
|
||||
symtab_section: SymbolTableSection | None = None
|
||||
|
||||
for section in elf_file.iter_sections():
|
||||
if isinstance(section, RelocationSection):
|
||||
relocation_sections.append(section)
|
||||
|
||||
if isinstance(section, SymbolTableSection):
|
||||
symtab_section = section
|
||||
|
||||
if not symtab_section:
|
||||
self.logger.error("No symbol table found")
|
||||
return 1
|
||||
|
||||
if not relocation_sections:
|
||||
self.logger.info("No relocation sections found")
|
||||
return 0
|
||||
|
||||
for section in relocation_sections:
|
||||
section_relocations: list[RelData] = []
|
||||
|
||||
for relocation in section.iter_relocations():
|
||||
symbol_id: int = relocation.entry["r_info_sym"]
|
||||
offset: int = relocation.entry["r_offset"]
|
||||
type: int = relocation.entry["r_info_type"]
|
||||
symbol = symtab_section.get_symbol(symbol_id)
|
||||
section_index: int = symbol["st_shndx"]
|
||||
section_value: int = symbol["st_value"]
|
||||
if section_index == "SHN_UNDEF":
|
||||
section_index = 0
|
||||
|
||||
section_relocations.append(
|
||||
RelData(section_index, section_value, type, offset, symbol.name)
|
||||
)
|
||||
|
||||
unique_relocations: dict[UniqueRelData, list[int]] = defaultdict(list)
|
||||
for relocation in section_relocations:
|
||||
unique = UniqueRelData(
|
||||
relocation.section,
|
||||
relocation.section_value,
|
||||
relocation.type,
|
||||
relocation.name,
|
||||
)
|
||||
|
||||
unique_relocations[unique].append(relocation.offset)
|
||||
|
||||
section_name = section.name
|
||||
if section_name.startswith(".rel"):
|
||||
section_name = ".fast.rel" + section_name[4:]
|
||||
else:
|
||||
self.logger.error(
|
||||
"Unknown relocation section name: %s", section_name
|
||||
)
|
||||
return 1
|
||||
|
||||
sections.append(
|
||||
RelSection(section_name, section.name, unique_relocations)
|
||||
)
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
for section in sections:
|
||||
data = serialize_relsection_data(section.data)
|
||||
hash_name = hashlib.md5(section.name.encode()).hexdigest()
|
||||
filename = f"{temp_dir}/{hash_name}.bin"
|
||||
|
||||
if os.path.isfile(filename):
|
||||
self.logger.error(f"File {filename} already exists")
|
||||
return 1
|
||||
|
||||
with open(filename, "wb") as f:
|
||||
f.write(data)
|
||||
|
||||
exit_code = subprocess.run(
|
||||
[
|
||||
objcopy_path,
|
||||
"--add-section",
|
||||
f"{section.name}={filename}",
|
||||
fap_path,
|
||||
],
|
||||
check=True,
|
||||
)
|
||||
|
||||
if exit_code.returncode != 0:
|
||||
self.logger.error("objcopy failed")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
Main()()
|
|
@ -1,4 +1,5 @@
|
|||
from typing import List
|
||||
from .hashes import gnu_sym_hash
|
||||
|
||||
from cxxheaderparser.parser import CxxParser
|
||||
from . import (
|
||||
|
@ -72,13 +73,6 @@ class SymbolManager:
|
|||
self.api.headers.add(ApiHeader(header))
|
||||
|
||||
|
||||
def gnu_sym_hash(name: str):
|
||||
h = 0x1505
|
||||
for c in name:
|
||||
h = (h << 5) + h + ord(c)
|
||||
return str(hex(h))[-8:]
|
||||
|
||||
|
||||
class SdkCollector:
|
||||
def __init__(self):
|
||||
self.symbol_manager = SymbolManager()
|
||||
|
|
5
scripts/fbt/sdk/hashes.py
Normal file
5
scripts/fbt/sdk/hashes.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
def gnu_sym_hash(name: str) -> int:
|
||||
h = 0x1505
|
||||
for c in name:
|
||||
h = ((h << 5) + h + ord(c)) & 0xFFFFFFFF
|
||||
return h
|
|
@ -384,10 +384,16 @@ def generate_embed_app_metadata_actions(source, target, env, for_signature):
|
|||
"${SOURCES} ${TARGET}"
|
||||
)
|
||||
|
||||
actions.append(
|
||||
actions.extend(
|
||||
(
|
||||
Action(
|
||||
objcopy_str,
|
||||
"$APPMETAEMBED_COMSTR",
|
||||
),
|
||||
Action(
|
||||
"${PYTHON3} ${FBT_SCRIPT_DIR}/fastfap.py ${TARGET} ${OBJCOPY}",
|
||||
"$FASTFAP_COMSTR",
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -450,6 +456,7 @@ def generate(env, **kw):
|
|||
APPMETA_COMSTR="\tAPPMETA\t${TARGET}",
|
||||
APPFILE_COMSTR="\tAPPFILE\t${TARGET}",
|
||||
APPMETAEMBED_COMSTR="\tFAP\t${TARGET}",
|
||||
FASTFAP_COMSTR="\tFASTFAP\t${TARGET}",
|
||||
APPCHECK_COMSTR="\tAPPCHK\t${SOURCE}",
|
||||
)
|
||||
|
||||
|
|
0
scripts/fwsize.py
Normal file → Executable file
0
scripts/fwsize.py
Normal file → Executable file
0
scripts/get_env.py
Normal file → Executable file
0
scripts/get_env.py
Normal file → Executable file
0
scripts/runfap.py
Normal file → Executable file
0
scripts/runfap.py
Normal file → Executable file
0
scripts/sconsdist.py
Normal file → Executable file
0
scripts/sconsdist.py
Normal file → Executable file
0
scripts/selfupdate.py
Normal file → Executable file
0
scripts/selfupdate.py
Normal file → Executable file
0
scripts/slideshow.py
Normal file → Executable file
0
scripts/slideshow.py
Normal file → Executable file
|
@ -8,6 +8,7 @@ import time
|
|||
def flp_serial_by_name(flp_name):
|
||||
if sys.platform == "darwin": # MacOS
|
||||
flp_serial = "/dev/cu.usbmodemflip_" + flp_name + "1"
|
||||
logging.info(f"Darwin, looking for {flp_serial}")
|
||||
elif sys.platform == "linux": # Linux
|
||||
flp_serial = (
|
||||
"/dev/serial/by-id/usb-Flipper_Devices_Inc._Flipper_"
|
||||
|
@ -16,10 +17,12 @@ def flp_serial_by_name(flp_name):
|
|||
+ flp_name
|
||||
+ "-if00"
|
||||
)
|
||||
logging.info(f"linux, looking for {flp_serial}")
|
||||
|
||||
if os.path.exists(flp_serial):
|
||||
return flp_serial
|
||||
else:
|
||||
logging.info(f"Couldn't find {logging.info} on this attempt.")
|
||||
if os.path.exists(flp_name):
|
||||
return flp_name
|
||||
else:
|
||||
|
@ -38,7 +41,7 @@ def main():
|
|||
level=logging.INFO,
|
||||
datefmt="%Y-%m-%d %H:%M:%S",
|
||||
)
|
||||
logging.info("Waiting for Flipper to be ready...")
|
||||
logging.info(f"Waiting for Flipper {flipper_name} to be ready...")
|
||||
|
||||
while flipper == "" and elapsed < UPDATE_TIMEOUT:
|
||||
elapsed += 1
|
||||
|
|
|
@ -20,13 +20,13 @@ def main():
|
|||
logging.error("Flipper not found!")
|
||||
sys.exit(1)
|
||||
|
||||
with serial.Serial(flp_serial, timeout=1) as flipper:
|
||||
with serial.Serial(flp_serial, timeout=10) as flipper:
|
||||
logging.info(f"Found Flipper at {flp_serial}")
|
||||
flipper.baudrate = 230400
|
||||
flipper.flushOutput()
|
||||
flipper.flushInput()
|
||||
|
||||
flipper.timeout = 180
|
||||
flipper.timeout = 300
|
||||
|
||||
flipper.read_until(b">: ").decode("utf-8")
|
||||
flipper.write(b"unit_tests\r")
|
||||
|
|
|
@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] (
|
|||
exit /b 0
|
||||
)
|
||||
|
||||
set "FLIPPER_TOOLCHAIN_VERSION=21"
|
||||
set "FLIPPER_TOOLCHAIN_VERSION=22"
|
||||
|
||||
if ["%FBT_TOOLCHAIN_PATH%"] == [""] (
|
||||
set "FBT_TOOLCHAIN_PATH=%FBT_ROOT%"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
# public variables
|
||||
DEFAULT_SCRIPT_PATH="$(pwd -P)";
|
||||
FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"21"}";
|
||||
FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"22"}";
|
||||
|
||||
if [ -z ${FBT_TOOLCHAIN_PATH+x} ] ; then
|
||||
FBT_TOOLCHAIN_PATH_WAS_SET=0;
|
||||
|
|
0
scripts/version.py
Normal file → Executable file
0
scripts/version.py
Normal file → Executable file
Loading…
Reference in a new issue