Merge branch 'dev-upstream' into shutdown_idle

This commit is contained in:
SHxKenzuto
2022-12-09 17:18:28 +01:00
415 changed files with 7882 additions and 2423 deletions
+7 -2
View File
@@ -18,7 +18,7 @@
/applications/main/gpio/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/main/ibutton/ @skotopes @DrZlo13 @hedger @gsurkov
/applications/main/infrared/ @skotopes @DrZlo13 @hedger @gsurkov
/applications/main/nfc/ @skotopes @DrZlo13 @hedger @gornekich
/applications/main/nfc/ @skotopes @DrZlo13 @hedger @gornekich @Astrrra
/applications/main/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
/applications/main/u2f/ @skotopes @DrZlo13 @hedger @nminaylov
@@ -40,6 +40,8 @@
/applications/system/storage_move_to_sd/ @skotopes @DrZlo13 @hedger @nminaylov
/applications/debug/unit_tests/ @skotopes @DrZlo13 @hedger @nminaylov @gornekich @Astrrra @gsurkov @Skorpionm
# Documentation
/documentation/ @skotopes @DrZlo13 @hedger @drunkbatya
/scripts/toolchain/ @skotopes @DrZlo13 @hedger @drunkbatya
@@ -54,6 +56,9 @@
/lib/mbedtls/ @skotopes @DrZlo13 @hedger @nminaylov
/lib/micro-ecc/ @skotopes @DrZlo13 @hedger @nminaylov
/lib/nanopb/ @skotopes @DrZlo13 @hedger @nminaylov
/lib/nfc/ @skotopes @DrZlo13 @hedger @gornekich
/lib/nfc/ @skotopes @DrZlo13 @hedger @gornekich @Astrrra
/lib/one_wire/ @skotopes @DrZlo13 @hedger @gsurkov
/lib/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
# CI/CD
/.github/workflows/ @skotopes @DrZlo13 @hedger @drunkbatya
+1 -1
View File
@@ -91,7 +91,7 @@ jobs:
export RODATA_SIZE="$(get_size ".rodata")"
export DATA_SIZE="$(get_size ".data")"
export FREE_FLASH_SIZE="$(get_size ".free_flash")"
python3 -m pip install mariadb
python3 -m pip install mariadb==1.1.4
python3 scripts/amap_mariadb_insert.py \
${{ secrets.AMAP_MARIADB_USER }} \
${{ secrets.AMAP_MARIADB_PASSWORD }} \
+1 -1
View File
@@ -57,7 +57,7 @@ jobs:
- name: 'Generate compile_comands.json'
run: |
FBT_TOOLCHAIN_PATH=/runner/_work ./fbt COMPACT=1 version_json proto_ver icons firmware_cdb dolphin_internal dolphin_blocking
FBT_TOOLCHAIN_PATH=/runner/_work ./fbt COMPACT=1 version_json proto_ver icons firmware_cdb dolphin_internal dolphin_blocking _fap_icons
- name: 'Static code analysis'
run: |
+2
View File
@@ -54,3 +54,5 @@ openocd.log
# PVS Studio temporary files
.PVS-Studio/
PVS-Studio.log
.gdbinit
+1
View File
@@ -5,6 +5,7 @@
//-V:BPTREE_DEF2:779,1086,557,773,512
//-V:DICT_DEF2:779,524,776,760,1044,1001,729,590,568,747,685
//-V:ALGO_DEF:1048,747,1044
//-V:TUPLE_DEF2:524,590,1001,760
# Non-severe malloc/null pointer deref warnings
//-V::522:2,3
+4
View File
@@ -38,6 +38,7 @@
"postAttachCommands": [
// "compare-sections",
"source debug/flipperapps.py",
"fap-set-debug-elf-root build/latest/.extapps",
// "source debug/FreeRTOS/FreeRTOS.py",
// "svd_load debug/STM32WB55_CM4.svd"
]
@@ -59,6 +60,7 @@
"set confirm off",
"set mem inaccessible-by-default off",
"source debug/flipperapps.py",
"fap-set-debug-elf-root build/latest/.extapps",
// "compare-sections",
]
// "showDevDebugOutput": "raw",
@@ -76,6 +78,7 @@
"rtos": "FreeRTOS",
"postAttachCommands": [
"source debug/flipperapps.py",
"fap-set-debug-elf-root build/latest/.extapps",
]
// "showDevDebugOutput": "raw",
},
@@ -95,6 +98,7 @@
],
"postAttachCommands": [
"source debug/flipperapps.py",
"fap-set-debug-elf-root build/latest/.extapps",
],
// "showDevDebugOutput": "raw",
},
+3 -3
View File
@@ -2,7 +2,7 @@
Thank you for investing your time in contributing to our project!
Read our [Code of Coduct](CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
Read our [Code of Conduct](CODE_OF_CONDUCT.md) to keep our community approachable and respectable.
In this guide you will get an overview of the contribution workflow from opening an issue, creating a PR, reviewing, and merging the PR.
@@ -17,12 +17,12 @@ See the [ReadMe](ReadMe.md) to get an overview of the project. Here are some hel
## Getting started
Before writing code and creating PR make sure that it aligns with our mission and guidlines:
Before writing code and creating PR make sure that it aligns with our mission and guidelines:
- All our devices are intended for research and education.
- PR that contains code intended to commit crimes is not going to be accepted.
- Your PR must comply with our [Coding Style](CODING_STYLE.md)
- Your PR must contain code compatiable with project [LICENSE](LICENSE).
- Your PR must contain code compatible with project [LICENSE](LICENSE).
- PR will only be merged if it pass CI/CD.
- PR will only be merged if it pass review by code owner.
+23 -12
View File
@@ -7,6 +7,7 @@
# construction of certain targets behind command-line options.
import os
from fbt.util import path_as_posix
DefaultEnvironment(tools=[])
@@ -43,6 +44,7 @@ distenv = coreenv.Clone(
"jflash",
],
ENV=os.environ,
UPDATE_BUNDLE_DIR="dist/${DIST_DIR}/f${TARGET_HW}-update-${DIST_SUFFIX}",
)
firmware_env = distenv.AddFwProject(
@@ -140,21 +142,28 @@ distenv.Default(basic_dist)
dist_dir = distenv.GetProjetDirName()
fap_dist = [
distenv.Install(
f"#/dist/{dist_dir}/apps/debug_elf",
firmware_env["FW_EXTAPPS"]["debug"].values(),
distenv.Dir(f"#/dist/{dist_dir}/apps/debug_elf"),
list(
app_artifact.debug
for app_artifact in firmware_env["FW_EXTAPPS"].applications.values()
),
),
*(
distenv.Install(f"#/dist/{dist_dir}/apps/{dist_entry[0]}", dist_entry[1])
for dist_entry in firmware_env["FW_EXTAPPS"]["dist"].values()
distenv.Install(
f"#/dist/{dist_dir}/apps",
"#/assets/resources/apps",
),
]
Depends(fap_dist, firmware_env["FW_EXTAPPS"]["validators"].values())
Depends(
fap_dist,
list(
app_artifact.validator
for app_artifact in firmware_env["FW_EXTAPPS"].applications.values()
),
)
Alias("fap_dist", fap_dist)
# distenv.Default(fap_dist)
distenv.Depends(
firmware_env["FW_RESOURCES"], firmware_env["FW_EXTAPPS"]["resources_dist"]
)
distenv.Depends(firmware_env["FW_RESOURCES"], firmware_env["FW_EXTAPPS"].resources_dist)
# Target for bundling core2 package for qFlipper
@@ -192,6 +201,7 @@ firmware_debug = distenv.PhonyTarget(
source=firmware_env["FW_ELF"],
GDBOPTS="${GDBOPTS_BASE}",
GDBREMOTE="${OPENOCD_GDB_PIPE}",
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
)
distenv.Depends(firmware_debug, firmware_flash)
@@ -201,6 +211,7 @@ distenv.PhonyTarget(
source=firmware_env["FW_ELF"],
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
GDBREMOTE="${BLACKMAGIC_ADDR}",
FBT_FAP_DEBUG_ELF_ROOT=path_as_posix(firmware_env.subst("$FBT_FAP_DEBUG_ELF_ROOT")),
)
# Debug alien elf
@@ -209,7 +220,7 @@ distenv.PhonyTarget(
"${GDBPYCOM}",
GDBOPTS="${GDBOPTS_BASE}",
GDBREMOTE="${OPENOCD_GDB_PIPE}",
GDBPYOPTS='-ex "source debug/PyCortexMDebug/PyCortexMDebug.py" ',
GDBPYOPTS='-ex "source ${FBT_DEBUG_DIR}/PyCortexMDebug/PyCortexMDebug.py" ',
)
distenv.PhonyTarget(
@@ -230,13 +241,13 @@ distenv.PhonyTarget(
distenv.PhonyTarget(
"lint",
"${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py check ${LINT_SOURCES}",
LINT_SOURCES=firmware_env["LINT_SOURCES"],
LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]],
)
distenv.PhonyTarget(
"format",
"${PYTHON3} ${FBT_SCRIPT_DIR}/lint.py format ${LINT_SOURCES}",
LINT_SOURCES=firmware_env["LINT_SOURCES"],
LINT_SOURCES=[n.srcnode() for n in firmware_env["LINT_SOURCES"]],
)
# PY_LINT_SOURCES contains recursively-built modules' SConscript files + application manifests
@@ -71,7 +71,7 @@ void WIEGAND::end() {
}
void WIEGAND::ReadD0() {
_bitCount++; // Increament bit count for Interrupt connected to D0
_bitCount++; // Increment bit count for Interrupt connected to D0
if(_bitCount > 31) // If bit count more than 31, process high bits
{
_cardTempHigh |= ((0x80000000 & _cardTemp) >> 31); // shift value to high bits
@@ -98,7 +98,7 @@ void bt_debug_app_free(BtDebugApp* app) {
int32_t bt_debug_app(void* p) {
UNUSED(p);
if(!furi_hal_bt_is_testing_supported()) {
FURI_LOG_E(TAG, "Incorrect radio stack: radio testing fetures are absent.");
FURI_LOG_E(TAG, "Incorrect radio stack: radio testing features are absent.");
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
dialog_message_show_storage_error(dialogs, "Incorrect\nRadioStack");
return 255;
@@ -145,7 +145,7 @@ DisplayTest* display_test_alloc() {
view_set_previous_callback(view, display_test_previous_callback);
view_dispatcher_add_view(instance->view_dispatcher, DisplayTestViewConfigure, view);
// Configurtion items
// Configuration items
VariableItem* item;
instance->config_bias = false;
instance->config_contrast = 32;
@@ -48,7 +48,7 @@ FileBrowserApp* file_browser_app_alloc(char* arg) {
app->file_path = furi_string_alloc();
app->file_browser = file_browser_alloc(app->file_path);
file_browser_configure(app->file_browser, "*", true, &I_badusb_10px, true);
file_browser_configure(app->file_browser, "*", NULL, true, &I_badusb_10px, true);
view_dispatcher_add_view(
app->view_dispatcher, FileBrowserAppViewStart, widget_get_view(app->widget));
@@ -0,0 +1,10 @@
App(
appid="rpc_debug",
name="RPC Debug",
apptype=FlipperAppType.DEBUG,
entry_point="rpc_debug_app",
requires=["gui", "rpc_start", "notification"],
stack_size=2 * 1024,
order=10,
fap_category="Debug",
)
@@ -0,0 +1,138 @@
#include "rpc_debug_app.h"
#include <core/log.h>
#include <string.h>
static bool rpc_debug_app_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
RpcDebugApp* app = context;
return scene_manager_handle_custom_event(app->scene_manager, event);
}
static bool rpc_debug_app_back_event_callback(void* context) {
furi_assert(context);
RpcDebugApp* app = context;
return scene_manager_handle_back_event(app->scene_manager);
}
static void rpc_debug_app_tick_event_callback(void* context) {
furi_assert(context);
RpcDebugApp* app = context;
scene_manager_handle_tick_event(app->scene_manager);
}
static void rpc_debug_app_rpc_command_callback(RpcAppSystemEvent event, void* context) {
furi_assert(context);
RpcDebugApp* app = context;
furi_assert(app->rpc);
if(event == RpcAppEventSessionClose) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
rpc_system_app_set_callback(app->rpc, NULL, NULL);
app->rpc = NULL;
} else if(event == RpcAppEventAppExit) {
scene_manager_stop(app->scene_manager);
view_dispatcher_stop(app->view_dispatcher);
rpc_system_app_confirm(app->rpc, RpcAppEventAppExit, true);
} else {
rpc_system_app_confirm(app->rpc, event, false);
}
}
static bool rpc_debug_app_rpc_init_rpc(RpcDebugApp* app, const char* args) {
bool ret = false;
if(args && strlen(args)) {
uint32_t rpc = 0;
if(sscanf(args, "RPC %lX", &rpc) == 1) {
app->rpc = (RpcAppSystem*)rpc;
rpc_system_app_set_callback(app->rpc, rpc_debug_app_rpc_command_callback, app);
rpc_system_app_send_started(app->rpc);
ret = true;
}
}
return ret;
}
static RpcDebugApp* rpc_debug_app_alloc() {
RpcDebugApp* app = malloc(sizeof(RpcDebugApp));
app->gui = furi_record_open(RECORD_GUI);
app->notifications = furi_record_open(RECORD_NOTIFICATION);
app->scene_manager = scene_manager_alloc(&rpc_debug_app_scene_handlers, app);
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
view_dispatcher_set_custom_event_callback(
app->view_dispatcher, rpc_debug_app_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
app->view_dispatcher, rpc_debug_app_back_event_callback);
view_dispatcher_set_tick_event_callback(
app->view_dispatcher, rpc_debug_app_tick_event_callback, 100);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
view_dispatcher_enable_queue(app->view_dispatcher);
app->widget = widget_alloc();
view_dispatcher_add_view(
app->view_dispatcher, RpcDebugAppViewWidget, widget_get_view(app->widget));
app->submenu = submenu_alloc();
view_dispatcher_add_view(
app->view_dispatcher, RpcDebugAppViewSubmenu, submenu_get_view(app->submenu));
app->text_box = text_box_alloc();
view_dispatcher_add_view(
app->view_dispatcher, RpcDebugAppViewTextBox, text_box_get_view(app->text_box));
app->text_input = text_input_alloc();
view_dispatcher_add_view(
app->view_dispatcher, RpcDebugAppViewTextInput, text_input_get_view(app->text_input));
app->byte_input = byte_input_alloc();
view_dispatcher_add_view(
app->view_dispatcher, RpcDebugAppViewByteInput, byte_input_get_view(app->byte_input));
return app;
}
static void rpc_debug_app_free(RpcDebugApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewByteInput);
view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewTextInput);
view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewTextBox);
view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewSubmenu);
view_dispatcher_remove_view(app->view_dispatcher, RpcDebugAppViewWidget);
free(app->byte_input);
free(app->text_input);
free(app->text_box);
free(app->submenu);
free(app->widget);
free(app->scene_manager);
free(app->view_dispatcher);
furi_record_close(RECORD_NOTIFICATION);
app->notifications = NULL;
furi_record_close(RECORD_GUI);
app->gui = NULL;
if(app->rpc) {
rpc_system_app_set_callback(app->rpc, NULL, NULL);
rpc_system_app_send_exited(app->rpc);
app->rpc = NULL;
}
free(app);
}
int32_t rpc_debug_app(void* args) {
RpcDebugApp* app = rpc_debug_app_alloc();
if(rpc_debug_app_rpc_init_rpc(app, args)) {
notification_message(app->notifications, &sequence_display_backlight_on);
scene_manager_next_scene(app->scene_manager, RpcDebugAppSceneStart);
} else {
scene_manager_next_scene(app->scene_manager, RpcDebugAppSceneStartDummy);
}
view_dispatcher_run(app->view_dispatcher);
rpc_debug_app_free(app);
return 0;
}
@@ -0,0 +1,54 @@
#pragma once
#include <furi.h>
#include <gui/gui.h>
#include <gui/view.h>
#include <gui/scene_manager.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/widget.h>
#include <gui/modules/submenu.h>
#include <gui/modules/text_box.h>
#include <gui/modules/text_input.h>
#include <gui/modules/byte_input.h>
#include <rpc/rpc_app.h>
#include <notification/notification_messages.h>
#include "scenes/rpc_debug_app_scene.h"
#define DATA_STORE_SIZE 64U
#define TEXT_STORE_SIZE 64U
typedef struct {
Gui* gui;
RpcAppSystem* rpc;
SceneManager* scene_manager;
ViewDispatcher* view_dispatcher;
NotificationApp* notifications;
Widget* widget;
Submenu* submenu;
TextBox* text_box;
TextInput* text_input;
ByteInput* byte_input;
char text_store[TEXT_STORE_SIZE];
uint8_t data_store[DATA_STORE_SIZE];
} RpcDebugApp;
typedef enum {
RpcDebugAppViewWidget,
RpcDebugAppViewSubmenu,
RpcDebugAppViewTextBox,
RpcDebugAppViewTextInput,
RpcDebugAppViewByteInput,
} RpcDebugAppView;
typedef enum {
// Reserve first 100 events for button types and indexes, starting from 0
RpcDebugAppCustomEventInputErrorCode = 100,
RpcDebugAppCustomEventInputErrorText,
RpcDebugAppCustomEventInputDataExchange,
RpcDebugAppCustomEventRpcDataExchange,
} RpcDebugAppCustomEvent;
@@ -0,0 +1,30 @@
#include "rpc_debug_app_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const rpc_debug_app_on_enter_handlers[])(void*) = {
#include "rpc_debug_app_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 rpc_debug_app_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "rpc_debug_app_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 rpc_debug_app_on_exit_handlers[])(void* context) = {
#include "rpc_debug_app_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers rpc_debug_app_scene_handlers = {
.on_enter_handlers = rpc_debug_app_on_enter_handlers,
.on_event_handlers = rpc_debug_app_on_event_handlers,
.on_exit_handlers = rpc_debug_app_on_exit_handlers,
.scene_num = RpcDebugAppSceneNum,
};
@@ -0,0 +1,29 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) RpcDebugAppScene##id,
typedef enum {
#include "rpc_debug_app_scene_config.h"
RpcDebugAppSceneNum,
} RpcDebugAppScene;
#undef ADD_SCENE
extern const SceneManagerHandlers rpc_debug_app_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "rpc_debug_app_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 "rpc_debug_app_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 "rpc_debug_app_scene_config.h"
#undef ADD_SCENE
@@ -0,0 +1,8 @@
ADD_SCENE(rpc_debug_app, start, Start)
ADD_SCENE(rpc_debug_app, start_dummy, StartDummy)
ADD_SCENE(rpc_debug_app, test_app_error, TestAppError)
ADD_SCENE(rpc_debug_app, test_data_exchange, TestDataExchange)
ADD_SCENE(rpc_debug_app, input_error_code, InputErrorCode)
ADD_SCENE(rpc_debug_app, input_error_text, InputErrorText)
ADD_SCENE(rpc_debug_app, input_data_exchange, InputDataExchange)
ADD_SCENE(rpc_debug_app, receive_data_exchange, ReceiveDataExchange)
@@ -0,0 +1,40 @@
#include "../rpc_debug_app.h"
static void rpc_debug_app_scene_input_data_exchange_result_callback(void* context) {
RpcDebugApp* app = context;
view_dispatcher_send_custom_event(
app->view_dispatcher, RpcDebugAppCustomEventInputDataExchange);
}
void rpc_debug_app_scene_input_data_exchange_on_enter(void* context) {
RpcDebugApp* app = context;
byte_input_set_header_text(app->byte_input, "Enter data to exchange");
byte_input_set_result_callback(
app->byte_input,
rpc_debug_app_scene_input_data_exchange_result_callback,
NULL,
app,
app->data_store,
DATA_STORE_SIZE);
view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewByteInput);
}
bool rpc_debug_app_scene_input_data_exchange_on_event(void* context, SceneManagerEvent event) {
RpcDebugApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == RpcDebugAppCustomEventInputDataExchange) {
rpc_system_app_exchange_data(app->rpc, app->data_store, DATA_STORE_SIZE);
scene_manager_previous_scene(app->scene_manager);
consumed = true;
}
}
return consumed;
}
void rpc_debug_app_scene_input_data_exchange_on_exit(void* context) {
RpcDebugApp* app = context;
UNUSED(app);
}
@@ -0,0 +1,60 @@
#include "../rpc_debug_app.h"
static bool rpc_debug_app_scene_input_error_code_validator_callback(
const char* text,
FuriString* error,
void* context) {
UNUSED(context);
for(; *text; ++text) {
const char c = *text;
if(c < '0' || c > '9') {
furi_string_printf(error, "%s", "Please enter\na number!");
return false;
}
}
return true;
}
static void rpc_debug_app_scene_input_error_code_result_callback(void* context) {
RpcDebugApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, RpcDebugAppCustomEventInputErrorCode);
}
void rpc_debug_app_scene_input_error_code_on_enter(void* context) {
RpcDebugApp* app = context;
strncpy(app->text_store, "666", TEXT_STORE_SIZE);
text_input_set_header_text(app->text_input, "Enter error code");
text_input_set_validator(
app->text_input, rpc_debug_app_scene_input_error_code_validator_callback, NULL);
text_input_set_result_callback(
app->text_input,
rpc_debug_app_scene_input_error_code_result_callback,
app,
app->text_store,
TEXT_STORE_SIZE,
true);
view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewTextInput);
}
bool rpc_debug_app_scene_input_error_code_on_event(void* context, SceneManagerEvent event) {
RpcDebugApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == RpcDebugAppCustomEventInputErrorCode) {
rpc_system_app_set_error_code(app->rpc, (uint32_t)atol(app->text_store));
scene_manager_previous_scene(app->scene_manager);
consumed = true;
}
}
return consumed;
}
void rpc_debug_app_scene_input_error_code_on_exit(void* context) {
RpcDebugApp* app = context;
text_input_reset(app->text_input);
text_input_set_validator(app->text_input, NULL, NULL);
}
@@ -0,0 +1,40 @@
#include "../rpc_debug_app.h"
static void rpc_debug_app_scene_input_error_text_result_callback(void* context) {
RpcDebugApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, RpcDebugAppCustomEventInputErrorText);
}
void rpc_debug_app_scene_input_error_text_on_enter(void* context) {
RpcDebugApp* app = context;
strncpy(app->text_store, "I'm a scary error message!", TEXT_STORE_SIZE);
text_input_set_header_text(app->text_input, "Enter error text");
text_input_set_result_callback(
app->text_input,
rpc_debug_app_scene_input_error_text_result_callback,
app,
app->text_store,
TEXT_STORE_SIZE,
true);
view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewTextInput);
}
bool rpc_debug_app_scene_input_error_text_on_event(void* context, SceneManagerEvent event) {
RpcDebugApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == RpcDebugAppCustomEventInputErrorText) {
rpc_system_app_set_error_text(app->rpc, app->text_store);
scene_manager_previous_scene(app->scene_manager);
consumed = true;
}
}
return consumed;
}
void rpc_debug_app_scene_input_error_text_on_exit(void* context) {
RpcDebugApp* app = context;
text_input_reset(app->text_input);
}
@@ -0,0 +1,70 @@
#include "../rpc_debug_app.h"
static void rpc_debug_app_scene_start_format_hex(
const uint8_t* data,
size_t data_size,
char* buf,
size_t buf_size) {
furi_assert(data);
furi_assert(buf);
const size_t byte_width = 3;
const size_t line_width = 7;
data_size = MIN(data_size, buf_size / (byte_width + 1));
for(size_t i = 0; i < data_size; ++i) {
char* p = buf + (i * byte_width);
char sep = !((i + 1) % line_width) ? '\n' : ' ';
snprintf(p, byte_width + 1, "%02X%c", data[i], sep);
}
buf[buf_size - 1] = '\0';
}
static void rpc_debug_app_scene_receive_data_exchange_callback(
const uint8_t* data,
size_t data_size,
void* context) {
RpcDebugApp* app = context;
if(data) {
rpc_debug_app_scene_start_format_hex(data, data_size, app->text_store, TEXT_STORE_SIZE);
} else {
strncpy(app->text_store, "<Data empty>", TEXT_STORE_SIZE);
}
view_dispatcher_send_custom_event(app->view_dispatcher, RpcDebugAppCustomEventRpcDataExchange);
}
void rpc_debug_app_scene_receive_data_exchange_on_enter(void* context) {
RpcDebugApp* app = context;
strncpy(app->text_store, "Received data will appear here...", TEXT_STORE_SIZE);
text_box_set_text(app->text_box, app->text_store);
text_box_set_font(app->text_box, TextBoxFontHex);
rpc_system_app_set_data_exchange_callback(
app->rpc, rpc_debug_app_scene_receive_data_exchange_callback, app);
view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewTextBox);
}
bool rpc_debug_app_scene_receive_data_exchange_on_event(void* context, SceneManagerEvent event) {
RpcDebugApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == RpcDebugAppCustomEventRpcDataExchange) {
notification_message(app->notifications, &sequence_blink_cyan_100);
notification_message(app->notifications, &sequence_display_backlight_on);
text_box_set_text(app->text_box, app->text_store);
consumed = true;
}
}
return consumed;
}
void rpc_debug_app_scene_receive_data_exchange_on_exit(void* context) {
RpcDebugApp* app = context;
text_box_reset(app->text_box);
rpc_system_app_set_data_exchange_callback(app->rpc, NULL, NULL);
}
@@ -0,0 +1,57 @@
#include "../rpc_debug_app.h"
enum SubmenuIndex {
SubmenuIndexTestAppError,
SubmenuIndexTestDataExchange,
};
static void rpc_debug_app_scene_start_submenu_callback(void* context, uint32_t index) {
RpcDebugApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void rpc_debug_app_scene_start_on_enter(void* context) {
RpcDebugApp* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu,
"Test App Error",
SubmenuIndexTestAppError,
rpc_debug_app_scene_start_submenu_callback,
app);
submenu_add_item(
submenu,
"Test Data Exchange",
SubmenuIndexTestDataExchange,
rpc_debug_app_scene_start_submenu_callback,
app);
submenu_set_selected_item(submenu, SubmenuIndexTestAppError);
view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewSubmenu);
}
bool rpc_debug_app_scene_start_on_event(void* context, SceneManagerEvent event) {
RpcDebugApp* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
const uint32_t submenu_index = event.event;
if(submenu_index == SubmenuIndexTestAppError) {
scene_manager_next_scene(scene_manager, RpcDebugAppSceneTestAppError);
consumed = true;
} else if(submenu_index == SubmenuIndexTestDataExchange) {
scene_manager_next_scene(scene_manager, RpcDebugAppSceneTestDataExchange);
consumed = true;
}
}
return consumed;
}
void rpc_debug_app_scene_start_on_exit(void* context) {
RpcDebugApp* app = context;
submenu_reset(app->submenu);
}
@@ -0,0 +1,30 @@
#include "../rpc_debug_app.h"
void rpc_debug_app_scene_start_dummy_on_enter(void* context) {
RpcDebugApp* app = context;
widget_add_text_box_element(
app->widget,
0,
0,
128,
64,
AlignCenter,
AlignCenter,
"This application\nis meant to be run\nin \e#RPC\e# mode.",
false);
view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewWidget);
}
bool rpc_debug_app_scene_start_dummy_on_event(void* context, SceneManagerEvent event) {
RpcDebugApp* app = context;
UNUSED(app);
UNUSED(event);
bool consumed = false;
return consumed;
}
void rpc_debug_app_scene_start_dummy_on_exit(void* context) {
RpcDebugApp* app = context;
widget_reset(app->widget);
}
@@ -0,0 +1,57 @@
#include "../rpc_debug_app.h"
typedef enum {
SubmenuIndexSetErrorCode,
SubmenuIndexSetErrorText,
} SubmenuIndex;
static void rpc_debug_app_scene_test_app_error_submenu_callback(void* context, uint32_t index) {
RpcDebugApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void rpc_debug_app_scene_test_app_error_on_enter(void* context) {
RpcDebugApp* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu,
"Set Error Code",
SubmenuIndexSetErrorCode,
rpc_debug_app_scene_test_app_error_submenu_callback,
app);
submenu_add_item(
submenu,
"Set Error Text",
SubmenuIndexSetErrorText,
rpc_debug_app_scene_test_app_error_submenu_callback,
app);
submenu_set_selected_item(submenu, SubmenuIndexSetErrorCode);
view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewSubmenu);
}
bool rpc_debug_app_scene_test_app_error_on_event(void* context, SceneManagerEvent event) {
RpcDebugApp* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
const uint32_t submenu_index = event.event;
if(submenu_index == SubmenuIndexSetErrorCode) {
scene_manager_next_scene(scene_manager, RpcDebugAppSceneInputErrorCode);
consumed = true;
} else if(submenu_index == SubmenuIndexSetErrorText) {
scene_manager_next_scene(scene_manager, RpcDebugAppSceneInputErrorText);
consumed = true;
}
}
return consumed;
}
void rpc_debug_app_scene_test_app_error_on_exit(void* context) {
RpcDebugApp* app = context;
submenu_reset(app->submenu);
}
@@ -0,0 +1,58 @@
#include "../rpc_debug_app.h"
typedef enum {
SubmenuIndexSendData,
SubmenuIndexReceiveData,
} SubmenuIndex;
static void
rpc_debug_app_scene_test_data_exchange_submenu_callback(void* context, uint32_t index) {
RpcDebugApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, index);
}
void rpc_debug_app_scene_test_data_exchange_on_enter(void* context) {
RpcDebugApp* app = context;
Submenu* submenu = app->submenu;
submenu_add_item(
submenu,
"Send Data",
SubmenuIndexSendData,
rpc_debug_app_scene_test_data_exchange_submenu_callback,
app);
submenu_add_item(
submenu,
"Receive Data",
SubmenuIndexReceiveData,
rpc_debug_app_scene_test_data_exchange_submenu_callback,
app);
submenu_set_selected_item(submenu, SubmenuIndexSendData);
view_dispatcher_switch_to_view(app->view_dispatcher, RpcDebugAppViewSubmenu);
}
bool rpc_debug_app_scene_test_data_exchange_on_event(void* context, SceneManagerEvent event) {
RpcDebugApp* app = context;
SceneManager* scene_manager = app->scene_manager;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
const uint32_t submenu_index = event.event;
if(submenu_index == SubmenuIndexSendData) {
scene_manager_next_scene(scene_manager, RpcDebugAppSceneInputDataExchange);
consumed = true;
} else if(submenu_index == SubmenuIndexReceiveData) {
scene_manager_next_scene(scene_manager, RpcDebugAppSceneReceiveDataExchange);
consumed = true;
}
}
return consumed;
}
void rpc_debug_app_scene_test_data_exchange_on_exit(void* context) {
RpcDebugApp* app = context;
submenu_reset(app->submenu);
}
+5 -9
View File
@@ -215,30 +215,26 @@ static UartEchoApp* uart_echo_app_alloc() {
view_dispatcher_add_view(app->view_dispatcher, 0, app->view);
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
app->worker_thread = furi_thread_alloc_ex("UsbUartWorker", 1024, uart_echo_worker, app);
furi_thread_start(app->worker_thread);
// Enable uart listener
furi_hal_console_disable();
furi_hal_uart_set_br(FuriHalUartIdUSART1, 115200);
furi_hal_uart_set_irq_cb(FuriHalUartIdUSART1, uart_echo_on_irq_cb, app);
app->worker_thread = furi_thread_alloc();
furi_thread_set_name(app->worker_thread, "UsbUartWorker");
furi_thread_set_stack_size(app->worker_thread, 1024);
furi_thread_set_context(app->worker_thread, app);
furi_thread_set_callback(app->worker_thread, uart_echo_worker);
furi_thread_start(app->worker_thread);
return app;
}
static void uart_echo_app_free(UartEchoApp* app) {
furi_assert(app);
furi_hal_console_enable(); // this will also clear IRQ callback so thread is no longer referenced
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), WorkerEventStop);
furi_thread_join(app->worker_thread);
furi_thread_free(app->worker_thread);
furi_hal_console_enable();
// Free views
view_dispatcher_remove_view(app->view_dispatcher, 0);
@@ -11,7 +11,7 @@
extern size_t memmgr_get_free_heap(void);
extern size_t memmgr_get_minimum_free_heap(void);
// current heap managment realization consume:
// current heap management realization consume:
// X bytes after allocate and 0 bytes after allocate and free,
// where X = sizeof(void*) + sizeof(size_t), look to BlockLink_t
const size_t heap_overhead_max_size = sizeof(void*) + sizeof(size_t);
@@ -21,7 +21,7 @@ bool heap_equal(size_t heap_size, size_t heap_size_old) {
const size_t heap_low = heap_size_old - heap_overhead_max_size;
const size_t heap_high = heap_size_old + heap_overhead_max_size;
// not extact, so we must test it against bigger numbers than "overhead size"
// not exact, so we must test it against bigger numbers than "overhead size"
const bool result = ((heap_size >= heap_low) && (heap_size <= heap_high));
// debug allocation info
@@ -0,0 +1,116 @@
#include <stdio.h>
#include <furi.h>
#include <furi_hal.h>
#include <lp5562_reg.h>
#include "../minunit.h"
#define DATA_SIZE 4
static void furi_hal_i2c_int_setup() {
furi_hal_i2c_acquire(&furi_hal_i2c_handle_power);
}
static void furi_hal_i2c_int_teardown() {
furi_hal_i2c_release(&furi_hal_i2c_handle_power);
}
MU_TEST(furi_hal_i2c_int_1b) {
bool ret = false;
uint8_t data_one = 0;
// 1 byte: read, write, read
ret = furi_hal_i2c_read_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
&data_one,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "0 read_reg_8 failed");
mu_assert(data_one != 0, "0 invalid data");
ret = furi_hal_i2c_write_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
data_one,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "1 write_reg_8 failed");
ret = furi_hal_i2c_read_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
&data_one,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "2 read_reg_8 failed");
mu_assert(data_one != 0, "2 invalid data");
}
MU_TEST(furi_hal_i2c_int_3b) {
bool ret = false;
uint8_t data_many[DATA_SIZE] = {0};
// 3 byte: read, write, read
data_many[0] = LP5562_CHANNEL_BLUE_CURRENT_REGISTER;
ret = furi_hal_i2c_tx(
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, 1, LP5562_I2C_TIMEOUT);
mu_assert(ret, "3 tx failed");
ret = furi_hal_i2c_rx(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
data_many + 1,
DATA_SIZE - 1,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "4 rx failed");
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "4 invalid data_many");
ret = furi_hal_i2c_tx(
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, DATA_SIZE, LP5562_I2C_TIMEOUT);
mu_assert(ret, "5 tx failed");
ret = furi_hal_i2c_tx(
&furi_hal_i2c_handle_power, LP5562_ADDRESS, data_many, 1, LP5562_I2C_TIMEOUT);
mu_assert(ret, "6 tx failed");
ret = furi_hal_i2c_rx(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
data_many + 1,
DATA_SIZE - 1,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "7 rx failed");
for(size_t i = 0; i < DATA_SIZE; i++) mu_assert(data_many[i] != 0, "7 invalid data_many");
}
MU_TEST(furi_hal_i2c_int_1b_fail) {
bool ret = false;
uint8_t data_one = 0;
// 1 byte: fail, read, fail, write, fail, read
data_one = 0;
ret = furi_hal_i2c_read_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS + 0x10,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
&data_one,
LP5562_I2C_TIMEOUT);
mu_assert(!ret, "8 read_reg_8 failed");
mu_assert(data_one == 0, "8 invalid data");
ret = furi_hal_i2c_read_reg_8(
&furi_hal_i2c_handle_power,
LP5562_ADDRESS,
LP5562_CHANNEL_BLUE_CURRENT_REGISTER,
&data_one,
LP5562_I2C_TIMEOUT);
mu_assert(ret, "9 read_reg_8 failed");
mu_assert(data_one != 0, "9 invalid data");
}
MU_TEST_SUITE(furi_hal_i2c_int_suite) {
MU_SUITE_CONFIGURE(&furi_hal_i2c_int_setup, &furi_hal_i2c_int_teardown);
MU_RUN_TEST(furi_hal_i2c_int_1b);
MU_RUN_TEST(furi_hal_i2c_int_3b);
MU_RUN_TEST(furi_hal_i2c_int_1b_fail);
}
int run_minunit_test_furi_hal() {
MU_RUN_SUITE(furi_hal_i2c_int_suite);
return MU_EXIT_CODE;
}
@@ -424,6 +424,7 @@ MU_TEST(infrared_test_decoder_mixed) {
infrared_test_run_decoder(InfraredProtocolRC5, 5);
infrared_test_run_decoder(InfraredProtocolSamsung32, 1);
infrared_test_run_decoder(InfraredProtocolSIRC, 3);
infrared_test_run_decoder(InfraredProtocolKaseikyo, 1);
}
MU_TEST(infrared_test_decoder_nec) {
@@ -489,6 +490,15 @@ MU_TEST(infrared_test_encoder_rc6) {
infrared_test_run_encoder(InfraredProtocolRC6, 1);
}
MU_TEST(infrared_test_decoder_kaseikyo) {
infrared_test_run_decoder(InfraredProtocolKaseikyo, 1);
infrared_test_run_decoder(InfraredProtocolKaseikyo, 2);
infrared_test_run_decoder(InfraredProtocolKaseikyo, 3);
infrared_test_run_decoder(InfraredProtocolKaseikyo, 4);
infrared_test_run_decoder(InfraredProtocolKaseikyo, 5);
infrared_test_run_decoder(InfraredProtocolKaseikyo, 6);
}
MU_TEST(infrared_test_encoder_decoder_all) {
infrared_test_run_encoder_decoder(InfraredProtocolNEC, 1);
infrared_test_run_encoder_decoder(InfraredProtocolNECext, 1);
@@ -498,6 +508,7 @@ MU_TEST(infrared_test_encoder_decoder_all) {
infrared_test_run_encoder_decoder(InfraredProtocolRC6, 1);
infrared_test_run_encoder_decoder(InfraredProtocolRC5, 1);
infrared_test_run_encoder_decoder(InfraredProtocolSIRC, 1);
infrared_test_run_encoder_decoder(InfraredProtocolKaseikyo, 1);
}
MU_TEST_SUITE(infrared_test) {
@@ -515,6 +526,7 @@ MU_TEST_SUITE(infrared_test) {
MU_RUN_TEST(infrared_test_decoder_nec);
MU_RUN_TEST(infrared_test_decoder_samsung32);
MU_RUN_TEST(infrared_test_decoder_necext1);
MU_RUN_TEST(infrared_test_decoder_kaseikyo);
MU_RUN_TEST(infrared_test_decoder_mixed);
MU_RUN_TEST(infrared_test_encoder_decoder_all);
}
+1 -1
View File
@@ -316,7 +316,7 @@ void minunit_print_fail(const char* error);
MU__SAFE_BLOCK( \
double minunit_tmp_e; double minunit_tmp_r; minunit_assert++; minunit_tmp_e = (expected); \
minunit_tmp_r = (result); \
if(fabs(minunit_tmp_e - minunit_tmp_r) > MINUNIT_EPSILON) { \
if(fabs(minunit_tmp_e - minunit_tmp_r) > (double)MINUNIT_EPSILON) { \
int minunit_significant_figures = 1 - log10(MINUNIT_EPSILON); \
snprintf( \
minunit_last_message, \
+198 -1
View File
@@ -5,6 +5,8 @@
#include <lib/nfc/protocols/nfca.h>
#include <lib/nfc/helpers/mf_classic_dict.h>
#include <lib/digital_signal/digital_signal.h>
#include <lib/nfc/nfc_device.h>
#include <applications/main/nfc/helpers/nfc_generators.h>
#include <lib/flipper_format/flipper_format_i.h>
#include <lib/toolbox/stream/file_stream.h>
@@ -17,6 +19,7 @@
#define NFC_TEST_SIGNAL_SHORT_FILE "nfc_nfca_signal_short.nfc"
#define NFC_TEST_SIGNAL_LONG_FILE "nfc_nfca_signal_long.nfc"
#define NFC_TEST_DICT_PATH EXT_PATH("unit_tests/mf_classic_dict.nfc")
#define NFC_TEST_NFC_DEV_PATH EXT_PATH("unit_tests/nfc/nfc_dev_test.nfc")
static const char* nfc_test_file_type = "Flipper NFC test";
static const uint32_t nfc_test_file_version = 1;
@@ -133,7 +136,7 @@ static bool nfc_test_digital_signal_test_encode(
ref_timings_sum += ref[i];
if(timings_diff > timing_tolerance) {
FURI_LOG_E(
TAG, "Too big differece in %d timings. Ref: %ld, DUT: %ld", i, ref[i], dut[i]);
TAG, "Too big difference in %d timings. Ref: %ld, DUT: %ld", i, ref[i], dut[i]);
timing_check_success = false;
break;
}
@@ -287,9 +290,203 @@ MU_TEST(mf_classic_dict_load_test) {
furi_record_close(RECORD_STORAGE);
}
MU_TEST(nfca_file_test) {
NfcDevice* nfc = nfc_device_alloc();
mu_assert(nfc != NULL, "nfc_device_data != NULL assert failed\r\n");
nfc->format = NfcDeviceSaveFormatUid;
// Fill the UID, sak, ATQA and type
uint8_t uid[7] = {0x04, 0x01, 0x23, 0x45, 0x67, 0x89, 0x00};
memcpy(nfc->dev_data.nfc_data.uid, uid, 7);
nfc->dev_data.nfc_data.uid_len = 7;
nfc->dev_data.nfc_data.sak = 0x08;
nfc->dev_data.nfc_data.atqa[0] = 0x00;
nfc->dev_data.nfc_data.atqa[1] = 0x04;
nfc->dev_data.nfc_data.type = FuriHalNfcTypeA;
// Save the NFC device data to the file
mu_assert(
nfc_device_save(nfc, NFC_TEST_NFC_DEV_PATH), "nfc_device_save == true assert failed\r\n");
nfc_device_free(nfc);
// Load the NFC device data from the file
NfcDevice* nfc_validate = nfc_device_alloc();
mu_assert(
nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, true),
"nfc_device_load == true assert failed\r\n");
// Check the UID, sak, ATQA and type
mu_assert(memcmp(nfc_validate->dev_data.nfc_data.uid, uid, 7) == 0, "uid assert failed\r\n");
mu_assert(nfc_validate->dev_data.nfc_data.sak == 0x08, "sak == 0x08 assert failed\r\n");
mu_assert(
nfc_validate->dev_data.nfc_data.atqa[0] == 0x00, "atqa[0] == 0x00 assert failed\r\n");
mu_assert(
nfc_validate->dev_data.nfc_data.atqa[1] == 0x04, "atqa[1] == 0x04 assert failed\r\n");
mu_assert(
nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA,
"type == FuriHalNfcTypeA assert failed\r\n");
nfc_device_free(nfc_validate);
}
static void mf_classic_generator_test(uint8_t uid_len, MfClassicType type) {
NfcDevice* nfc_dev = nfc_device_alloc();
mu_assert(nfc_dev != NULL, "nfc_device_data != NULL assert failed\r\n");
nfc_dev->format = NfcDeviceSaveFormatMifareClassic;
// Create a test file
nfc_generate_mf_classic(&nfc_dev->dev_data, uid_len, type);
// Get the uid from generated MFC
uint8_t uid[7] = {0};
memcpy(uid, nfc_dev->dev_data.nfc_data.uid, uid_len);
uint8_t sak = nfc_dev->dev_data.nfc_data.sak;
uint8_t atqa[2] = {};
memcpy(atqa, nfc_dev->dev_data.nfc_data.atqa, 2);
MfClassicData* mf_data = &nfc_dev->dev_data.mf_classic_data;
// Check the manufacturer block (should be uid[uid_len] + 0xFF[rest])
uint8_t manufacturer_block[16] = {0};
memcpy(manufacturer_block, nfc_dev->dev_data.mf_classic_data.block[0].value, 16);
mu_assert(
memcmp(manufacturer_block, uid, uid_len) == 0,
"manufacturer_block uid doesn't match the file\r\n");
for(uint8_t i = uid_len; i < 16; i++) {
mu_assert(
manufacturer_block[i] == 0xFF, "manufacturer_block[i] == 0xFF assert failed\r\n");
}
// Reference sector trailers (should be 0xFF[6] + 0xFF + 0x07 + 0x80 + 0x69 + 0xFF[6])
uint8_t sector_trailer[16] = {
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0x07,
0x80,
0x69,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF,
0xFF};
// Reference block data
uint8_t block_data[16] = {};
memset(block_data, 0xff, sizeof(block_data));
uint16_t total_blocks = mf_classic_get_total_block_num(type);
for(size_t i = 1; i < total_blocks; i++) {
if(mf_classic_is_sector_trailer(i)) {
mu_assert(
memcmp(mf_data->block[i].value, sector_trailer, 16) == 0,
"Failed sector trailer compare");
} else {
mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare");
}
}
// Save the NFC device data to the file
mu_assert(
nfc_device_save(nfc_dev, NFC_TEST_NFC_DEV_PATH),
"nfc_device_save == true assert failed\r\n");
// Verify that key cache is saved
FuriString* key_cache_name = furi_string_alloc();
furi_string_set_str(key_cache_name, "/ext/nfc/.cache/");
for(size_t i = 0; i < uid_len; i++) {
furi_string_cat_printf(key_cache_name, "%02X", uid[i]);
}
furi_string_cat_printf(key_cache_name, ".keys");
mu_assert(
storage_common_stat(nfc_dev->storage, furi_string_get_cstr(key_cache_name), NULL) ==
FSE_OK,
"Key cache file save failed");
nfc_device_free(nfc_dev);
// Load the NFC device data from the file
NfcDevice* nfc_validate = nfc_device_alloc();
mu_assert(nfc_validate, "Nfc device alloc assert");
mu_assert(
nfc_device_load(nfc_validate, NFC_TEST_NFC_DEV_PATH, false),
"nfc_device_load == true assert failed\r\n");
// Check the UID, sak, ATQA and type
mu_assert(
memcmp(nfc_validate->dev_data.nfc_data.uid, uid, uid_len) == 0,
"uid compare assert failed\r\n");
mu_assert(nfc_validate->dev_data.nfc_data.sak == sak, "sak compare assert failed\r\n");
mu_assert(
memcmp(nfc_validate->dev_data.nfc_data.atqa, atqa, 2) == 0,
"atqa compare assert failed\r\n");
mu_assert(
nfc_validate->dev_data.nfc_data.type == FuriHalNfcTypeA,
"type == FuriHalNfcTypeA assert failed\r\n");
// Check the manufacturer block
mu_assert(
memcmp(nfc_validate->dev_data.mf_classic_data.block[0].value, manufacturer_block, 16) == 0,
"manufacturer_block assert failed\r\n");
// Check other blocks
for(size_t i = 1; i < total_blocks; i++) {
if(mf_classic_is_sector_trailer(i)) {
mu_assert(
memcmp(mf_data->block[i].value, sector_trailer, 16) == 0,
"Failed sector trailer compare");
} else {
mu_assert(memcmp(mf_data->block[i].value, block_data, 16) == 0, "Failed data compare");
}
}
nfc_device_free(nfc_validate);
// Check saved key cache
NfcDevice* nfc_keys = nfc_device_alloc();
mu_assert(nfc_validate, "Nfc device alloc assert");
nfc_keys->dev_data.nfc_data.uid_len = uid_len;
memcpy(nfc_keys->dev_data.nfc_data.uid, uid, uid_len);
mu_assert(nfc_device_load_key_cache(nfc_keys), "Failed to load key cache");
uint8_t total_sec = mf_classic_get_total_sectors_num(type);
uint8_t default_key[6] = {};
memset(default_key, 0xff, 6);
for(size_t i = 0; i < total_sec; i++) {
MfClassicSectorTrailer* sec_tr =
mf_classic_get_sector_trailer_by_sector(&nfc_keys->dev_data.mf_classic_data, i);
mu_assert(memcmp(sec_tr->key_a, default_key, 6) == 0, "Failed key compare");
mu_assert(memcmp(sec_tr->key_b, default_key, 6) == 0, "Failed key compare");
}
// Delete key cache file
mu_assert(
storage_common_remove(nfc_keys->storage, furi_string_get_cstr(key_cache_name)) == FSE_OK,
"Failed to remove key cache file");
furi_string_free(key_cache_name);
nfc_device_free(nfc_keys);
}
MU_TEST(mf_classic_1k_4b_file_test) {
mf_classic_generator_test(4, MfClassicType1k);
}
MU_TEST(mf_classic_4k_4b_file_test) {
mf_classic_generator_test(4, MfClassicType4k);
}
MU_TEST(mf_classic_1k_7b_file_test) {
mf_classic_generator_test(7, MfClassicType1k);
}
MU_TEST(mf_classic_4k_7b_file_test) {
mf_classic_generator_test(7, MfClassicType4k);
}
MU_TEST_SUITE(nfc) {
nfc_test_alloc();
MU_RUN_TEST(nfca_file_test);
MU_RUN_TEST(mf_classic_1k_4b_file_test);
MU_RUN_TEST(mf_classic_4k_4b_file_test);
MU_RUN_TEST(mf_classic_1k_7b_file_test);
MU_RUN_TEST(mf_classic_4k_7b_file_test);
MU_RUN_TEST(nfc_digital_signal_test);
MU_RUN_TEST(mf_classic_dict_test);
MU_RUN_TEST(mf_classic_dict_load_test);
@@ -0,0 +1,62 @@
#include <furi.h>
#include <furi_hal.h>
#include "../minunit.h"
static void power_test_deinit(void) {
// Try to reset to default charging voltage
furi_hal_power_set_battery_charging_voltage(4.208f);
}
MU_TEST(test_power_charge_voltage_exact) {
// Power of 16mV charge voltages get applied exactly
// (bq25896 charge controller works in 16mV increments)
//
// This test may need adapted if other charge controllers are used in the future.
for(uint16_t charge_mv = 3840; charge_mv <= 4208; charge_mv += 16) {
float charge_volt = (float)charge_mv / 1000.0f;
furi_hal_power_set_battery_charging_voltage(charge_volt);
mu_assert_double_eq(charge_volt, furi_hal_power_get_battery_charging_voltage());
}
}
MU_TEST(test_power_charge_voltage_floating_imprecision) {
// 4.016f should act as 4.016 V, even with floating point imprecision
furi_hal_power_set_battery_charging_voltage(4.016f);
mu_assert_double_eq(4.016f, furi_hal_power_get_battery_charging_voltage());
}
MU_TEST(test_power_charge_voltage_inexact) {
// Charge voltages that are not power of 16mV get truncated down
furi_hal_power_set_battery_charging_voltage(3.841f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
furi_hal_power_set_battery_charging_voltage(3.900f);
mu_assert_double_eq(3.888, furi_hal_power_get_battery_charging_voltage());
furi_hal_power_set_battery_charging_voltage(4.200f);
mu_assert_double_eq(4.192, furi_hal_power_get_battery_charging_voltage());
}
MU_TEST(test_power_charge_voltage_invalid_clamped) {
// Out-of-range charge voltages get clamped to 3.840 V and 4.208 V
furi_hal_power_set_battery_charging_voltage(3.808f);
mu_assert_double_eq(3.840, furi_hal_power_get_battery_charging_voltage());
// NOTE: Intentionally picking a small increment above 4.208 V to reduce the risk of an
// unhappy battery if this fails.
furi_hal_power_set_battery_charging_voltage(4.240f);
mu_assert_double_eq(4.208, furi_hal_power_get_battery_charging_voltage());
}
MU_TEST_SUITE(test_power_suite) {
MU_RUN_TEST(test_power_charge_voltage_exact);
MU_RUN_TEST(test_power_charge_voltage_floating_imprecision);
MU_RUN_TEST(test_power_charge_voltage_inexact);
MU_RUN_TEST(test_power_charge_voltage_invalid_clamped);
power_test_deinit();
}
int run_minunit_test_power() {
MU_RUN_SUITE(test_power_suite);
return MU_EXIT_CODE;
}
@@ -43,11 +43,8 @@ MU_TEST(storage_file_open_lock) {
File* file = storage_file_alloc(storage);
// file_locker thread start
FuriThread* locker_thread = furi_thread_alloc();
furi_thread_set_name(locker_thread, "StorageFileLocker");
furi_thread_set_stack_size(locker_thread, 2048);
furi_thread_set_context(locker_thread, semaphore);
furi_thread_set_callback(locker_thread, storage_file_locker);
FuriThread* locker_thread =
furi_thread_alloc_ex("StorageFileLocker", 2048, storage_file_locker, semaphore);
furi_thread_start(locker_thread);
// wait for file lock
@@ -133,11 +130,8 @@ MU_TEST(storage_dir_open_lock) {
File* file = storage_file_alloc(storage);
// file_locker thread start
FuriThread* locker_thread = furi_thread_alloc();
furi_thread_set_name(locker_thread, "StorageDirLocker");
furi_thread_set_stack_size(locker_thread, 2048);
furi_thread_set_context(locker_thread, semaphore);
furi_thread_set_callback(locker_thread, storage_dir_locker);
FuriThread* locker_thread =
furi_thread_alloc_ex("StorageDirLocker", 2048, storage_dir_locker, semaphore);
furi_thread_start(locker_thread);
// wait for dir lock
@@ -219,21 +219,21 @@ MU_TEST_1(stream_composite_subtest, Stream* stream) {
mu_check(stream_eof(stream));
mu_assert_int_eq(0, stream_tell(stream));
// insert formated string at the end of stream
// insert formatted string at the end of stream
// "" -> "dio666"
mu_check(stream_insert_format(stream, "%s%d", "dio", 666));
mu_assert_int_eq(6, stream_size(stream));
mu_check(stream_eof(stream));
mu_assert_int_eq(6, stream_tell(stream));
// insert formated string at the end of stream
// insert formatted string at the end of stream
// "dio666" -> "dio666zlo555"
mu_check(stream_insert_format(stream, "%s%d", "zlo", 555));
mu_assert_int_eq(12, stream_size(stream));
mu_check(stream_eof(stream));
mu_assert_int_eq(12, stream_tell(stream));
// insert formated string at the 6 pos
// insert formatted string at the 6 pos
// "dio666" -> "dio666baba13zlo555"
mu_check(stream_seek(stream, 6, StreamOffsetFromStart));
mu_check(stream_insert_format(stream, "%s%d", "baba", 13));
@@ -13,7 +13,7 @@
#define CAME_ATOMO_DIR_NAME EXT_PATH("subghz/assets/came_atomo")
#define NICE_FLOR_S_DIR_NAME EXT_PATH("subghz/assets/nice_flor_s")
#define TEST_RANDOM_DIR_NAME EXT_PATH("unit_tests/subghz/test_random_raw.sub")
#define TEST_RANDOM_COUNT_PARSE 232
#define TEST_RANDOM_COUNT_PARSE 244
#define TEST_TIMEOUT 10000
static SubGhzEnvironment* environment_handler;
@@ -209,6 +209,149 @@ MU_TEST(subghz_keystore_test) {
"Test keystore error");
}
typedef enum {
SubGhzHalAsyncTxTestTypeNormal,
SubGhzHalAsyncTxTestTypeInvalidStart,
SubGhzHalAsyncTxTestTypeInvalidMid,
SubGhzHalAsyncTxTestTypeInvalidEnd,
SubGhzHalAsyncTxTestTypeResetStart,
SubGhzHalAsyncTxTestTypeResetMid,
SubGhzHalAsyncTxTestTypeResetEnd,
} SubGhzHalAsyncTxTestType;
typedef struct {
SubGhzHalAsyncTxTestType type;
size_t pos;
} SubGhzHalAsyncTxTest;
#define SUBGHZ_HAL_TEST_DURATION 1
static LevelDuration subghz_hal_async_tx_test_yield(void* context) {
SubGhzHalAsyncTxTest* test = context;
bool is_odd = test->pos % 2;
if(test->type == SubGhzHalAsyncTxTestTypeNormal) {
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidStart) {
if(test->pos == 0) {
test->pos++;
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidMid) {
if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
test->pos++;
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeInvalidEnd) {
if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
test->pos++;
return level_duration_make(!is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL * 8) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeResetStart) {
if(test->pos == 0) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeResetMid) {
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_HALF / 2) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else if(test->type == SubGhzHalAsyncTxTestTypeResetEnd) {
if(test->pos < API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
test->pos++;
return level_duration_make(is_odd, SUBGHZ_HAL_TEST_DURATION);
} else if(test->pos == API_HAL_SUBGHZ_ASYNC_TX_BUFFER_FULL - 1) {
test->pos++;
return level_duration_reset();
} else {
furi_crash("Yield after reset");
}
} else {
furi_crash("Programming error");
}
}
bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
SubGhzHalAsyncTxTest test = {0};
test.type = type;
furi_hal_subghz_reset();
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
furi_hal_subghz_set_frequency_and_path(433920000);
furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test);
while(!furi_hal_subghz_is_async_tx_complete()) {
furi_delay_ms(10);
}
furi_hal_subghz_stop_async_tx();
furi_hal_subghz_sleep();
return true;
}
MU_TEST(subghz_hal_async_tx_test) {
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeNormal),
"Test furi_hal_async_tx normal");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeInvalidStart),
"Test furi_hal_async_tx invalid start");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeInvalidMid),
"Test furi_hal_async_tx invalid mid");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeInvalidEnd),
"Test furi_hal_async_tx invalid end");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeResetStart),
"Test furi_hal_async_tx reset start");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeResetMid),
"Test furi_hal_async_tx reset mid");
mu_assert(
subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestTypeResetEnd),
"Test furi_hal_async_tx reset end");
}
//test decoders
MU_TEST(subghz_decoder_came_atomo_test) {
mu_assert(
@@ -437,6 +580,13 @@ MU_TEST(subghz_decoder_clemsa_test) {
"Test decoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n");
}
MU_TEST(subghz_decoder_ansonic_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/ansonic_raw.sub"), SUBGHZ_PROTOCOL_ANSONIC_NAME),
"Test decoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n");
}
//test encoders
MU_TEST(subghz_encoder_princeton_test) {
mu_assert(
@@ -558,6 +708,12 @@ MU_TEST(subghz_encoder_clemsa_test) {
"Test encoder " SUBGHZ_PROTOCOL_CLEMSA_NAME " error\r\n");
}
MU_TEST(subghz_encoder_ansonic_test) {
mu_assert(
subghz_encoder_test(EXT_PATH("unit_tests/subghz/ansonic.sub")),
"Test encoder " SUBGHZ_PROTOCOL_ANSONIC_NAME " error\r\n");
}
MU_TEST(subghz_random_test) {
mu_assert(subghz_decode_random_test(TEST_RANDOM_DIR_NAME), "Random test error\r\n");
}
@@ -566,6 +722,8 @@ MU_TEST_SUITE(subghz) {
subghz_test_init();
MU_RUN_TEST(subghz_keystore_test);
MU_RUN_TEST(subghz_hal_async_tx_test);
MU_RUN_TEST(subghz_decoder_came_atomo_test);
MU_RUN_TEST(subghz_decoder_came_test);
MU_RUN_TEST(subghz_decoder_came_twee_test);
@@ -598,6 +756,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_decoder_magellan_test);
MU_RUN_TEST(subghz_decoder_intertechno_v3_test);
MU_RUN_TEST(subghz_decoder_clemsa_test);
MU_RUN_TEST(subghz_decoder_ansonic_test);
MU_RUN_TEST(subghz_encoder_princeton_test);
MU_RUN_TEST(subghz_encoder_came_test);
@@ -619,6 +778,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_encoder_magellan_test);
MU_RUN_TEST(subghz_encoder_intertechno_v3_test);
MU_RUN_TEST(subghz_encoder_clemsa_test);
MU_RUN_TEST(subghz_encoder_ansonic_test);
MU_RUN_TEST(subghz_random_test);
subghz_test_deinit();
@@ -9,6 +9,7 @@
#define TAG "UnitTests"
int run_minunit_test_furi();
int run_minunit_test_furi_hal();
int run_minunit_test_furi_string();
int run_minunit_test_infrared();
int run_minunit_test_rpc();
@@ -18,6 +19,7 @@ int run_minunit_test_stream();
int run_minunit_test_storage();
int run_minunit_test_subghz();
int run_minunit_test_dirwalk();
int run_minunit_test_power();
int run_minunit_test_protocol_dict();
int run_minunit_test_lfrfid_protocols();
int run_minunit_test_nfc();
@@ -32,6 +34,7 @@ typedef struct {
const UnitTest unit_tests[] = {
{.name = "furi", .entry = run_minunit_test_furi},
{.name = "furi_hal", .entry = run_minunit_test_furi_hal},
{.name = "furi_string", .entry = run_minunit_test_furi_string},
{.name = "storage", .entry = run_minunit_test_storage},
{.name = "stream", .entry = run_minunit_test_stream},
@@ -42,6 +45,7 @@ const UnitTest unit_tests[] = {
{.name = "subghz", .entry = run_minunit_test_subghz},
{.name = "infrared", .entry = run_minunit_test_infrared},
{.name = "nfc", .entry = run_minunit_test_nfc},
{.name = "power", .entry = run_minunit_test_power},
{.name = "protocol_dict", .entry = run_minunit_test_protocol_dict},
{.name = "lfrfid", .entry = run_minunit_test_lfrfid_protocols},
{.name = "bit_lib", .entry = run_minunit_test_bit_lib},
@@ -80,10 +80,12 @@ static void archive_file_browser_set_path(
ArchiveBrowserView* browser,
FuriString* path,
const char* filter_ext,
bool skip_assets) {
bool skip_assets,
bool hide_dot_files) {
furi_assert(browser);
if(!browser->worker_running) {
browser->worker = file_browser_worker_alloc(path, filter_ext, skip_assets);
browser->worker =
file_browser_worker_alloc(path, NULL, filter_ext, skip_assets, hide_dot_files);
file_browser_worker_set_callback_context(browser->worker, browser);
file_browser_worker_set_folder_callback(browser->worker, archive_folder_open_cb);
file_browser_worker_set_list_callback(browser->worker, archive_list_load_cb);
@@ -92,7 +94,8 @@ static void archive_file_browser_set_path(
browser->worker_running = true;
} else {
furi_assert(browser->worker);
file_browser_worker_set_config(browser->worker, path, filter_ext, skip_assets);
file_browser_worker_set_config(
browser->worker, path, filter_ext, skip_assets, hide_dot_files);
}
}
@@ -265,8 +268,7 @@ void archive_file_array_load(ArchiveBrowserView* browser, int8_t dir) {
offset_new = model->item_idx - FILE_LIST_BUF_LEN / 4 * 1;
}
if(offset_new > 0) {
offset_new =
CLAMP(offset_new, (int32_t)model->item_cnt - FILE_LIST_BUF_LEN, 0);
offset_new = CLAMP(offset_new, (int32_t)model->item_cnt, 0);
} else {
offset_new = 0;
}
@@ -473,8 +475,10 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
tab = archive_get_tab(browser);
if(archive_is_dir_exists(browser->path)) {
bool skip_assets = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
// Hide dot files everywhere except Browser
bool hide_dot_files = (strcmp(archive_get_tab_ext(tab), "*") == 0) ? false : true;
archive_file_browser_set_path(
browser, browser->path, archive_get_tab_ext(tab), skip_assets);
browser, browser->path, archive_get_tab_ext(tab), skip_assets, hide_dot_files);
tab_empty = false; // Empty check will be performed later
}
}
@@ -3,9 +3,9 @@
#include "../archive_i.h"
#include <storage/storage.h>
#define TAB_RIGHT InputKeyRight // Default tab swith direction
#define TAB_RIGHT InputKeyRight // Default tab switch direction
#define TAB_DEFAULT ArchiveTabFavorites // Start tab
#define FILE_LIST_BUF_LEN 100
#define FILE_LIST_BUF_LEN 50
static const char* tab_default_paths[] = {
[ArchiveTabFavorites] = "/app:favorites",
@@ -133,7 +133,7 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
case ArchiveBrowserEventFileMenuRename:
if(favorites) {
browser->callback(ArchiveBrowserEventEnterFavMove, browser->context);
} else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) {
} else if(selected->is_app == false) {
archive_show_file_menu(browser, false);
scene_manager_set_scene_state(
archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH);
@@ -57,9 +57,11 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
ArchiveFile_t* file = archive_get_current_file(archive->browser);
FuriString* path_dst;
path_dst = furi_string_alloc();
path_extract_dirname(path_src, path_dst);
furi_string_cat_printf(path_dst, "/%s%s", archive->text_store, known_ext[file->type]);
furi_string_cat_printf(
path_dst, "/%s%s", archive->text_store, archive->file_extension);
storage_common_rename(fs_api, path_src, furi_string_get_cstr(path_dst));
furi_record_close(RECORD_STORAGE);
@@ -65,7 +65,6 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
if(!archive_is_known_app(selected->type)) {
furi_string_set(menu[0], "---");
furi_string_set(menu[1], "---");
furi_string_set(menu[2], "---");
} else {
if(model->tab_idx == ArchiveTabFavorites) {
furi_string_set(menu[2], "Move");
@@ -11,4 +11,5 @@ App(
stack_size=2 * 1024,
icon="A_BadUsb_14",
order=70,
fap_libs=["assets"],
)
+8 -19
View File
@@ -237,12 +237,8 @@ static int32_t
const char* line_tmp = furi_string_get_cstr(line);
bool state = false;
for(uint32_t i = 0; i < line_len; i++) {
if((line_tmp[i] != ' ') && (line_tmp[i] != '\t') && (line_tmp[i] != '\n')) {
line_tmp = &line_tmp[i];
break; // Skip spaces and tabs
}
if(i == line_len - 1) return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
if(line_len == 0) {
return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
}
FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
@@ -338,10 +334,6 @@ static int32_t
furi_hal_hid_kb_release(key);
return (0);
}
if(error != NULL) {
strncpy(error, "Unknown error", error_len);
}
return SCRIPT_STATE_ERROR;
}
static bool ducky_set_usb_id(BadUsbScript* bad_usb, const char* line) {
@@ -454,10 +446,12 @@ static int32_t ducky_script_execute_next(BadUsbScript* bad_usb, File* script_fil
bad_usb->st.line_cur++;
bad_usb->buf_len = bad_usb->buf_len + bad_usb->buf_start - (i + 1);
bad_usb->buf_start = i + 1;
furi_string_trim(bad_usb->line);
delay_val = ducky_parse_line(
bad_usb, bad_usb->line, bad_usb->st.error, sizeof(bad_usb->st.error));
if(delay_val < 0) {
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
return 0;
} else if(delay_val < 0) {
bad_usb->st.error_line = bad_usb->st.line_cur;
FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_usb->st.line_cur);
return SCRIPT_STATE_ERROR;
@@ -656,19 +650,14 @@ static int32_t bad_usb_worker(void* context) {
BadUsbScript* bad_usb_script_open(FuriString* file_path) {
furi_assert(file_path);
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript));
BadUsbScript* bad_usb = malloc(sizeof(BadUsbScript)); //-V773
bad_usb->file_path = furi_string_alloc();
furi_string_set(bad_usb->file_path, file_path);
bad_usb->st.state = BadUsbStateInit;
bad_usb->st.error[0] = '\0';
bad_usb->thread = furi_thread_alloc();
furi_thread_set_name(bad_usb->thread, "BadUsbWorker");
furi_thread_set_stack_size(bad_usb->thread, 2048);
furi_thread_set_context(bad_usb->thread, bad_usb);
furi_thread_set_callback(bad_usb->thread, bad_usb_worker);
bad_usb->thread = furi_thread_alloc_ex("BadUsbWorker", 2048, bad_usb_worker, bad_usb);
furi_thread_start(bad_usb->thread);
return bad_usb;
}
@@ -1,12 +1,14 @@
#include "../bad_usb_app_i.h"
#include "furi_hal_power.h"
#include "furi_hal_usb.h"
#include <storage/storage.h>
static bool bad_usb_file_select(BadUsbApp* bad_usb) {
furi_assert(bad_usb);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, BAD_USB_APP_EXTENSION, &I_badusb_10px);
browser_options.base_path = BAD_USB_APP_PATH_FOLDER;
// Input events and views are managed by file_browser
bool res = dialog_file_browser_show(
@@ -31,7 +31,7 @@ bool elf_resolve_from_hashtable(const char* name, Elf32_Addr* address) {
auto find_res = std::lower_bound(elf_api_table.cbegin(), elf_api_table.cend(), key);
if((find_res == elf_api_table.cend() || (find_res->hash != gnu_sym_hash))) {
FURI_LOG_W(TAG, "Cant find symbol '%s' (hash %lx)!", name, gnu_sym_hash);
FURI_LOG_W(TAG, "Can't find symbol '%s' (hash %lx)!", name, gnu_sym_hash);
result = false;
} else {
result = true;
@@ -148,6 +148,7 @@ static bool fap_loader_select_app(FapLoader* loader) {
.hide_ext = true,
.item_loader_callback = fap_loader_item_callback,
.item_loader_context = loader,
.base_path = EXT_PATH("apps"),
};
return dialog_file_browser_show(
@@ -155,7 +156,7 @@ static bool fap_loader_select_app(FapLoader* loader) {
}
static FapLoader* fap_loader_alloc(const char* path) {
FapLoader* loader = malloc(sizeof(FapLoader));
FapLoader* loader = malloc(sizeof(FapLoader)); //-V773
loader->fap_path = furi_string_alloc_set(path);
loader->storage = furi_record_open(RECORD_STORAGE);
loader->dialogs = furi_record_open(RECORD_DIALOGS);
+1
View File
@@ -8,4 +8,5 @@ App(
stack_size=1 * 1024,
icon="A_GPIO_14",
order=50,
fap_libs=["assets"],
)
+1
View File
@@ -29,6 +29,7 @@ struct GpioApp {
GpioTest* gpio_test;
GpioUsbUart* gpio_usb_uart;
UsbUartBridge* usb_uart_bridge;
UsbUartConfig* usb_uart_cfg;
};
typedef enum {
@@ -9,4 +9,5 @@ typedef enum {
GpioCustomEventErrorBack,
GpioUsbUartEventConfig,
GpioUsbUartEventConfigSet,
} GpioCustomEvent;
@@ -9,8 +9,6 @@ typedef enum {
UsbUartLineIndexFlow,
} LineIndex;
static UsbUartConfig* cfg_set;
static const char* vcp_ch[] = {"0 (CLI)", "1"};
static const char* uart_ch[] = {"13,14", "15,16"};
static const char* flow_pins[] = {"None", "2,3", "6,7", "16,15"};
@@ -28,8 +26,14 @@ static const uint32_t baudrate_list[] = {
};
bool gpio_scene_usb_uart_cfg_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
GpioApp* app = context;
furi_assert(app);
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GpioUsbUartEventConfigSet) {
usb_uart_set_config(app->usb_uart_bridge, app->usb_uart_cfg);
return true;
}
}
return false;
}
@@ -38,55 +42,59 @@ void line_ensure_flow_invariant(GpioApp* app) {
// selected. This function enforces that invariant by resetting flow_pins
// to None if it is configured to 16,15 when LPUART is selected.
uint8_t available_flow_pins = cfg_set->uart_ch == FuriHalUartIdLPUART1 ? 3 : 4;
uint8_t available_flow_pins = app->usb_uart_cfg->uart_ch == FuriHalUartIdLPUART1 ? 3 : 4;
VariableItem* item = app->var_item_flow;
variable_item_set_values_count(item, available_flow_pins);
if(cfg_set->flow_pins >= available_flow_pins) {
cfg_set->flow_pins = 0;
usb_uart_set_config(app->usb_uart_bridge, cfg_set);
if(app->usb_uart_cfg->flow_pins >= available_flow_pins) {
app->usb_uart_cfg->flow_pins = 0;
variable_item_set_current_value_index(item, cfg_set->flow_pins);
variable_item_set_current_value_text(item, flow_pins[cfg_set->flow_pins]);
variable_item_set_current_value_index(item, app->usb_uart_cfg->flow_pins);
variable_item_set_current_value_text(item, flow_pins[app->usb_uart_cfg->flow_pins]);
}
}
static void line_vcp_cb(VariableItem* item) {
GpioApp* app = variable_item_get_context(item);
furi_assert(app);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, vcp_ch[index]);
cfg_set->vcp_ch = index;
usb_uart_set_config(app->usb_uart_bridge, cfg_set);
app->usb_uart_cfg->vcp_ch = index;
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
}
static void line_port_cb(VariableItem* item) {
GpioApp* app = variable_item_get_context(item);
furi_assert(app);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, uart_ch[index]);
if(index == 0)
cfg_set->uart_ch = FuriHalUartIdUSART1;
app->usb_uart_cfg->uart_ch = FuriHalUartIdUSART1;
else if(index == 1)
cfg_set->uart_ch = FuriHalUartIdLPUART1;
usb_uart_set_config(app->usb_uart_bridge, cfg_set);
app->usb_uart_cfg->uart_ch = FuriHalUartIdLPUART1;
line_ensure_flow_invariant(app);
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
}
static void line_flow_cb(VariableItem* item) {
GpioApp* app = variable_item_get_context(item);
furi_assert(app);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, flow_pins[index]);
cfg_set->flow_pins = index;
usb_uart_set_config(app->usb_uart_bridge, cfg_set);
app->usb_uart_cfg->flow_pins = index;
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
}
static void line_baudrate_cb(VariableItem* item) {
GpioApp* app = variable_item_get_context(item);
furi_assert(app);
uint8_t index = variable_item_get_current_value_index(item);
char br_text[8];
@@ -94,28 +102,29 @@ static void line_baudrate_cb(VariableItem* item) {
if(index > 0) {
snprintf(br_text, 7, "%lu", baudrate_list[index - 1]);
variable_item_set_current_value_text(item, br_text);
cfg_set->baudrate = baudrate_list[index - 1];
app->usb_uart_cfg->baudrate = baudrate_list[index - 1];
} else {
variable_item_set_current_value_text(item, baudrate_mode[index]);
cfg_set->baudrate = 0;
app->usb_uart_cfg->baudrate = 0;
}
cfg_set->baudrate_mode = index;
usb_uart_set_config(app->usb_uart_bridge, cfg_set);
app->usb_uart_cfg->baudrate_mode = index;
view_dispatcher_send_custom_event(app->view_dispatcher, GpioUsbUartEventConfigSet);
}
void gpio_scene_usb_uart_cfg_on_enter(void* context) {
GpioApp* app = context;
furi_assert(app);
VariableItemList* var_item_list = app->var_item_list;
cfg_set = malloc(sizeof(UsbUartConfig));
usb_uart_get_config(app->usb_uart_bridge, cfg_set);
app->usb_uart_cfg = malloc(sizeof(UsbUartConfig));
usb_uart_get_config(app->usb_uart_bridge, app->usb_uart_cfg);
VariableItem* item;
char br_text[8];
item = variable_item_list_add(var_item_list, "USB Channel", 2, line_vcp_cb, app);
variable_item_set_current_value_index(item, cfg_set->vcp_ch);
variable_item_set_current_value_text(item, vcp_ch[cfg_set->vcp_ch]);
variable_item_set_current_value_index(item, app->usb_uart_cfg->vcp_ch);
variable_item_set_current_value_text(item, vcp_ch[app->usb_uart_cfg->vcp_ch]);
item = variable_item_list_add(
var_item_list,
@@ -123,22 +132,23 @@ void gpio_scene_usb_uart_cfg_on_enter(void* context) {
sizeof(baudrate_list) / sizeof(baudrate_list[0]) + 1,
line_baudrate_cb,
app);
variable_item_set_current_value_index(item, cfg_set->baudrate_mode);
if(cfg_set->baudrate_mode > 0) {
snprintf(br_text, 7, "%lu", baudrate_list[cfg_set->baudrate_mode - 1]);
variable_item_set_current_value_index(item, app->usb_uart_cfg->baudrate_mode);
if(app->usb_uart_cfg->baudrate_mode > 0) {
snprintf(br_text, 7, "%lu", baudrate_list[app->usb_uart_cfg->baudrate_mode - 1]);
variable_item_set_current_value_text(item, br_text);
} else {
variable_item_set_current_value_text(item, baudrate_mode[cfg_set->baudrate_mode]);
variable_item_set_current_value_text(
item, baudrate_mode[app->usb_uart_cfg->baudrate_mode]);
}
item = variable_item_list_add(var_item_list, "UART Pins", 2, line_port_cb, app);
variable_item_set_current_value_index(item, cfg_set->uart_ch);
variable_item_set_current_value_text(item, uart_ch[cfg_set->uart_ch]);
variable_item_set_current_value_index(item, app->usb_uart_cfg->uart_ch);
variable_item_set_current_value_text(item, uart_ch[app->usb_uart_cfg->uart_ch]);
item = variable_item_list_add(
var_item_list, "RTS/DTR Pins", COUNT_OF(flow_pins), line_flow_cb, app);
variable_item_set_current_value_index(item, cfg_set->flow_pins);
variable_item_set_current_value_text(item, flow_pins[cfg_set->flow_pins]);
variable_item_set_current_value_index(item, app->usb_uart_cfg->flow_pins);
variable_item_set_current_value_text(item, flow_pins[app->usb_uart_cfg->flow_pins]);
app->var_item_flow = item;
line_ensure_flow_invariant(app);
@@ -155,5 +165,5 @@ void gpio_scene_usb_uart_cfg_on_exit(void* context) {
GpioAppViewUsbUartCfg,
variable_item_list_get_selected_item_index(app->var_item_list));
variable_item_list_reset(app->var_item_list);
free(cfg_set);
free(app->usb_uart_cfg);
}
+11 -12
View File
@@ -3,6 +3,7 @@
#include <furi_hal_usb_cdc.h>
#include "usb_cdc.h"
#include "cli/cli_vcp.h"
#include <toolbox/api_lock.h>
#include "cli/cli.h"
#define USB_CDC_PKT_LEN CDC_DATA_SZ
@@ -51,6 +52,8 @@ struct UsbUartBridge {
UsbUartState st;
FuriApiLock cfg_lock;
uint8_t rx_buf[USB_CDC_PKT_LEN];
};
@@ -159,11 +162,8 @@ static int32_t usb_uart_worker(void* context) {
usb_uart->tx_sem = furi_semaphore_alloc(1, 1);
usb_uart->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal);
usb_uart->tx_thread = furi_thread_alloc();
furi_thread_set_name(usb_uart->tx_thread, "UsbUartTxWorker");
furi_thread_set_stack_size(usb_uart->tx_thread, 512);
furi_thread_set_context(usb_uart->tx_thread, usb_uart);
furi_thread_set_callback(usb_uart->tx_thread, usb_uart_tx_thread);
usb_uart->tx_thread =
furi_thread_alloc_ex("UsbUartTxWorker", 512, usb_uart_tx_thread, usb_uart);
usb_uart_vcp_init(usb_uart, usb_uart->cfg.vcp_ch);
usb_uart_serial_init(usb_uart, usb_uart->cfg.uart_ch);
@@ -184,7 +184,7 @@ static int32_t usb_uart_worker(void* context) {
while(1) {
uint32_t events =
furi_thread_flags_wait(WORKER_ALL_RX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
furi_check((events & FuriFlagError) == 0);
furi_check(!(events & FuriFlagError));
if(events & WorkerEvtStop) break;
if(events & WorkerEvtRxDone) {
size_t len = furi_stream_buffer_receive(
@@ -247,6 +247,7 @@ static int32_t usb_uart_worker(void* context) {
usb_uart->cfg.flow_pins = usb_uart->cfg_new.flow_pins;
events |= WorkerEvtCtrlLineSet;
}
api_lock_unlock(usb_uart->cfg_lock);
}
if(events & WorkerEvtLineCfgSet) {
if(usb_uart->cfg.baudrate == 0)
@@ -288,7 +289,7 @@ static int32_t usb_uart_tx_thread(void* context) {
while(1) {
uint32_t events =
furi_thread_flags_wait(WORKER_ALL_TX_EVENTS, FuriFlagWaitAny, FuriWaitForever);
furi_check((events & FuriFlagError) == 0);
furi_check(!(events & FuriFlagError));
if(events & WorkerEvtTxStop) break;
if(events & WorkerEvtCdcRx) {
furi_check(furi_mutex_acquire(usb_uart->usb_mutex, FuriWaitForever) == FuriStatusOk);
@@ -338,11 +339,7 @@ UsbUartBridge* usb_uart_enable(UsbUartConfig* cfg) {
memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig));
usb_uart->thread = furi_thread_alloc();
furi_thread_set_name(usb_uart->thread, "UsbUartWorker");
furi_thread_set_stack_size(usb_uart->thread, 1024);
furi_thread_set_context(usb_uart->thread, usb_uart);
furi_thread_set_callback(usb_uart->thread, usb_uart_worker);
usb_uart->thread = furi_thread_alloc_ex("UsbUartWorker", 1024, usb_uart_worker, usb_uart);
furi_thread_start(usb_uart->thread);
return usb_uart;
@@ -359,8 +356,10 @@ void usb_uart_disable(UsbUartBridge* usb_uart) {
void usb_uart_set_config(UsbUartBridge* usb_uart, UsbUartConfig* cfg) {
furi_assert(usb_uart);
furi_assert(cfg);
usb_uart->cfg_lock = api_lock_alloc_locked();
memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig));
furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCfgChange);
api_lock_wait_unlock_and_free(usb_uart->cfg_lock);
}
void usb_uart_get_config(UsbUartBridge* usb_uart, UsbUartConfig* cfg) {
@@ -12,6 +12,7 @@ App(
icon="A_iButton_14",
stack_size=2 * 1024,
order=60,
fap_libs=["assets"],
)
App(
+1
View File
@@ -218,6 +218,7 @@ void ibutton_free(iButton* ibutton) {
bool ibutton_file_select(iButton* ibutton) {
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, IBUTTON_APP_EXTENSION, &I_ibutt_10px);
browser_options.base_path = IBUTTON_APP_FOLDER;
bool success = dialog_file_browser_show(
ibutton->dialogs, ibutton->file_path, ibutton->file_path, &browser_options);
@@ -39,10 +39,5 @@ void ibutton_scene_delete_success_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_disable_timeout(popup);
popup_set_context(popup, NULL);
popup_set_callback(popup, NULL);
popup_reset(popup);
}
@@ -39,10 +39,5 @@ void ibutton_scene_save_success_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_disable_timeout(popup);
popup_set_context(popup, NULL);
popup_set_callback(popup, NULL);
popup_reset(popup);
}
@@ -43,10 +43,5 @@ void ibutton_scene_write_success_on_exit(void* context) {
iButton* ibutton = context;
Popup* popup = ibutton->popup;
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_disable_timeout(popup);
popup_set_context(popup, NULL);
popup_set_callback(popup, NULL);
popup_reset(popup);
}
@@ -12,6 +12,7 @@ App(
icon="A_Infrared_14",
stack_size=3 * 1024,
order=40,
fap_libs=["assets"],
)
App(
@@ -7,6 +7,7 @@ void infrared_scene_remote_list_on_enter(void* context) {
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, INFRARED_APP_EXTENSION, &I_ir_10px);
browser_options.base_path = INFRARED_APP_FOLDER;
bool success = dialog_file_browser_show(
infrared->dialogs, infrared->file_path, infrared->file_path, &browser_options);
@@ -24,7 +24,7 @@ void infrared_scene_universal_tv_on_enter(void* context) {
&I_Power_hvr_25x27,
infrared_scene_universal_common_item_callback,
context);
infrared_brute_force_add_record(brute_force, i++, "POWER");
infrared_brute_force_add_record(brute_force, i++, "Power");
button_panel_add_item(
button_panel,
i,
@@ -36,7 +36,7 @@ void infrared_scene_universal_tv_on_enter(void* context) {
&I_Mute_hvr_25x27,
infrared_scene_universal_common_item_callback,
context);
infrared_brute_force_add_record(brute_force, i++, "MUTE");
infrared_brute_force_add_record(brute_force, i++, "Mute");
button_panel_add_item(
button_panel,
i,
@@ -48,7 +48,7 @@ void infrared_scene_universal_tv_on_enter(void* context) {
&I_Vol_up_hvr_25x27,
infrared_scene_universal_common_item_callback,
context);
infrared_brute_force_add_record(brute_force, i++, "VOL+");
infrared_brute_force_add_record(brute_force, i++, "Vol_up");
button_panel_add_item(
button_panel,
i,
@@ -60,7 +60,7 @@ void infrared_scene_universal_tv_on_enter(void* context) {
&I_Up_hvr_25x27,
infrared_scene_universal_common_item_callback,
context);
infrared_brute_force_add_record(brute_force, i++, "CH+");
infrared_brute_force_add_record(brute_force, i++, "Ch_next");
button_panel_add_item(
button_panel,
i,
@@ -72,7 +72,7 @@ void infrared_scene_universal_tv_on_enter(void* context) {
&I_Vol_down_hvr_25x27,
infrared_scene_universal_common_item_callback,
context);
infrared_brute_force_add_record(brute_force, i++, "VOL-");
infrared_brute_force_add_record(brute_force, i++, "Vol_dn");
button_panel_add_item(
button_panel,
i,
@@ -84,7 +84,7 @@ void infrared_scene_universal_tv_on_enter(void* context) {
&I_Down_hvr_25x27,
infrared_scene_universal_common_item_callback,
context);
infrared_brute_force_add_record(brute_force, i++, "CH-");
infrared_brute_force_add_record(brute_force, i++, "Ch_prev");
button_panel_add_label(button_panel, 6, 11, FontPrimary, "TV remote");
button_panel_add_label(button_panel, 9, 64, FontSecondary, "Vol");
+1
View File
@@ -14,6 +14,7 @@ App(
icon="A_125khz_14",
stack_size=2 * 1024,
order=20,
fap_libs=["assets"],
)
App(
+2 -1
View File
@@ -32,7 +32,7 @@ static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
}
static LfRfid* lfrfid_alloc() {
LfRfid* lfrfid = malloc(sizeof(LfRfid));
LfRfid* lfrfid = malloc(sizeof(LfRfid)); //-V773
lfrfid->storage = furi_record_open(RECORD_STORAGE);
lfrfid->dialogs = furi_record_open(RECORD_DIALOGS);
@@ -230,6 +230,7 @@ bool lfrfid_load_key_from_file_select(LfRfid* app) {
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, LFRFID_APP_EXTENSION, &I_125_10px);
browser_options.base_path = LFRFID_APP_FOLDER;
// Input events and views are managed by file_browser
bool result =
@@ -314,7 +314,7 @@ static void nfc_generate_ntag_i2c_plus_2k(NfcDeviceData* data) {
mful->version.storage_size = 0x15;
}
static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type) {
nfc_generate_common_start(data);
nfc_generate_mf_classic_common(data, uid_len, type);
@@ -337,6 +337,9 @@ static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClas
}
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
}
// Set SAK to 18
data->nfc_data.sak = 0x18;
} else if(type == MfClassicType1k) {
// Set every block to 0xFF
for(uint16_t i = 1; i < MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; i += 1) {
@@ -347,6 +350,8 @@ static void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClas
}
mf_classic_set_block_read(mfc, i, &mfc->block[i]);
}
// Set SAK to 08
data->nfc_data.sak = 0x08;
}
mfc->type = type;
@@ -11,3 +11,5 @@ struct NfcGenerator {
};
extern const NfcGenerator* const nfc_generators[];
void nfc_generate_mf_classic(NfcDeviceData* data, uint8_t uid_len, MfClassicType type);
+10 -1
View File
@@ -116,7 +116,9 @@ void nfc_free(Nfc* nfc) {
// Stop worker
nfc_worker_stop(nfc->worker);
// Save data in shadow file
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
if(furi_string_size(nfc->dev->load_path)) {
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
}
}
if(nfc->rpc_ctx) {
rpc_system_app_send_exited(nfc->rpc_ctx);
@@ -218,6 +220,13 @@ void nfc_blink_stop(Nfc* nfc) {
notification_message(nfc->notifications, &sequence_blink_stop);
}
bool nfc_save_file(Nfc* nfc) {
furi_string_printf(
nfc->dev->load_path, "%s/%s%s", NFC_APP_FOLDER, nfc->dev->dev_name, NFC_APP_EXTENSION);
bool file_saved = nfc_device_save(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
return file_saved;
}
void nfc_show_loading_popup(void* context, bool show) {
Nfc* nfc = context;
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
+2
View File
@@ -114,4 +114,6 @@ void nfc_blink_detect_start(Nfc* nfc);
void nfc_blink_stop(Nfc* nfc);
bool nfc_save_file(Nfc* nfc);
void nfc_show_loading_popup(void* context, bool show);
@@ -21,6 +21,7 @@ ADD_SCENE(nfc, mf_ultralight_emulate, MfUltralightEmulate)
ADD_SCENE(nfc, mf_ultralight_read_auth, MfUltralightReadAuth)
ADD_SCENE(nfc, mf_ultralight_read_auth_result, MfUltralightReadAuthResult)
ADD_SCENE(nfc, mf_ultralight_key_input, MfUltralightKeyInput)
ADD_SCENE(nfc, mf_ultralight_unlock_auto, MfUltralightUnlockAuto)
ADD_SCENE(nfc, mf_ultralight_unlock_menu, MfUltralightUnlockMenu)
ADD_SCENE(nfc, mf_ultralight_unlock_warn, MfUltralightUnlockWarn)
ADD_SCENE(nfc, mf_desfire_read_success, MfDesfireReadSuccess)
@@ -60,3 +61,4 @@ ADD_SCENE(nfc, detect_reader, DetectReader)
ADD_SCENE(nfc, mfkey_nonces_info, MfkeyNoncesInfo)
ADD_SCENE(nfc, mfkey_complete, MfkeyComplete)
ADD_SCENE(nfc, nfc_data_info, NfcDataInfo)
ADD_SCENE(nfc, read_card_type, ReadCardType)
@@ -37,8 +37,8 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
FuriString* info_str;
info_str = furi_string_alloc();
widget_add_icon_element(widget, 0, 3, &I_RFIDDolphinSend_97x61);
widget_add_string_element(widget, 89, 32, AlignCenter, AlignTop, FontPrimary, "Emulating UID");
widget_add_icon_element(widget, 0, 3, &I_NFC_dolphin_emulation_47x61);
widget_add_string_element(widget, 57, 13, AlignLeft, AlignTop, FontPrimary, "Emulating UID");
if(strcmp(nfc->dev->dev_name, "")) {
furi_string_printf(info_str, "%s", nfc->dev->dev_name);
} else {
@@ -48,7 +48,7 @@ static void nfc_scene_emulate_uid_widget_config(Nfc* nfc, bool data_received) {
}
furi_string_trim(info_str);
widget_add_text_box_element(
widget, 56, 43, 70, 21, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true);
widget, 57, 28, 67, 25, AlignCenter, AlignTop, furi_string_get_cstr(info_str), true);
furi_string_free(info_str);
if(data_received) {
widget_add_button_element(
@@ -29,8 +29,13 @@ bool nfc_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
if(event.event == DialogExResultRight) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
} else if(event.event == DialogExResultLeft) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneReadCardType)) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneReadCardType);
} else {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneStart);
}
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = true;
@@ -1,6 +1,7 @@
#include "../nfc_i.h"
enum SubmenuIndex {
SubmenuIndexReadCardType,
SubmenuIndexMfClassicKeys,
SubmenuIndexMfUltralightUnlock,
};
@@ -15,6 +16,12 @@ void nfc_scene_extra_actions_on_enter(void* context) {
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
submenu_add_item(
submenu,
"Read Specific Card Type",
SubmenuIndexReadCardType,
nfc_scene_extra_actions_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Mifare Classic Keys",
@@ -44,9 +51,15 @@ bool nfc_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
consumed = true;
} else if(event.event == SubmenuIndexMfUltralightUnlock) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
consumed = true;
} else if(event.event == SubmenuIndexReadCardType) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, 0);
scene_manager_next_scene(nfc->scene_manager, NfcSceneReadCardType);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
}
return consumed;
}
@@ -5,6 +5,9 @@ void nfc_scene_file_select_on_enter(void* context) {
Nfc* nfc = context;
// Process file_select return
nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc);
if(!furi_string_size(nfc->dev->load_path)) {
furi_string_set_str(nfc->dev->load_path, NFC_APP_FOLDER);
}
if(nfc_file_select(nfc->dev)) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, 0);
scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
@@ -17,13 +17,14 @@ void nfc_scene_mf_classic_emulate_on_enter(void* context) {
// Setup view
Popup* popup = nfc->popup;
popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop);
if(strcmp(nfc->dev->dev_name, "")) {
nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name);
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
} else {
nfc_text_store_set(nfc, "Emulating\nMf Classic", nfc->dev->dev_name);
nfc_text_store_set(nfc, "MIFARE\nClassic");
}
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop);
popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61);
popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop);
// Setup and start worker
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
@@ -48,7 +49,10 @@ bool nfc_scene_mf_classic_emulate_on_event(void* context, SceneManagerEvent even
NFC_MF_CLASSIC_DATA_CHANGED) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicEmulate, NFC_MF_CLASSIC_DATA_NOT_CHANGED);
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
// Save shadow file
if(furi_string_size(nfc->dev->load_path)) {
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
}
}
consumed = false;
}
@@ -4,6 +4,7 @@
enum SubmenuIndex {
SubmenuIndexSave,
SubmenuIndexEmulate,
SubmenuIndexDetectReader,
SubmenuIndexInfo,
};
@@ -21,6 +22,14 @@ void nfc_scene_mf_classic_menu_on_enter(void* context) {
submenu, "Save", SubmenuIndexSave, nfc_scene_mf_classic_menu_submenu_callback, nfc);
submenu_add_item(
submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_mf_classic_menu_submenu_callback, nfc);
if(!mf_classic_is_card_read(&nfc->dev->dev_data.mf_classic_data)) {
submenu_add_item(
submenu,
"Detect reader",
SubmenuIndexDetectReader,
nfc_scene_mf_classic_menu_submenu_callback,
nfc);
}
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, nfc_scene_mf_classic_menu_submenu_callback, nfc);
@@ -35,17 +44,14 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event)
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfClassicMenu, event.event);
if(event.event == SubmenuIndexSave) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexSave);
nfc->dev->format = NfcDeviceSaveFormatMifareClassic;
// Clear device name
nfc_device_set_name(nfc->dev, "");
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
consumed = true;
} else if(event.event == SubmenuIndexEmulate) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexEmulate);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicEmulate);
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetType)) {
DOLPHIN_DEED(DolphinDeedNfcAddEmulate);
@@ -53,9 +59,11 @@ bool nfc_scene_mf_classic_menu_on_event(void* context, SceneManagerEvent event)
DOLPHIN_DEED(DolphinDeedNfcEmulate);
}
consumed = true;
} else if(event.event == SubmenuIndexDetectReader) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
DOLPHIN_DEED(DolphinDeedNfcDetectReader);
consumed = true;
} else if(event.event == SubmenuIndexInfo) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfClassicMenu, SubmenuIndexInfo);
scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcDataInfo);
consumed = true;
}
@@ -24,7 +24,7 @@ void nfc_scene_mf_classic_read_success_on_enter(void* context) {
widget_add_button_element(
widget, GuiButtonTypeRight, "More", nfc_scene_mf_classic_read_success_widget_callback, nfc);
FuriString* temp_str;
FuriString* temp_str = NULL;
if(furi_string_size(nfc->dev->dev_data.parsed_data)) {
temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data);
} else {
@@ -57,7 +57,7 @@ bool nfc_scene_mf_classic_update_on_event(void* context, SceneManagerEvent event
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == NfcWorkerEventSuccess) {
nfc_worker_stop(nfc->worker);
if(nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name)) {
if(nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path))) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicUpdateSuccess);
} else {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrongCard);
@@ -16,14 +16,20 @@ void nfc_scene_mf_ultralight_emulate_on_enter(void* context) {
Nfc* nfc = context;
// Setup view
MfUltralightType type = nfc->dev->dev_data.mf_ul_data.type;
bool is_ultralight = (type == MfUltralightTypeUL11) || (type == MfUltralightTypeUL21) ||
(type == MfUltralightTypeUnknown);
Popup* popup = nfc->popup;
popup_set_header(popup, "Emulating", 67, 13, AlignLeft, AlignTop);
if(strcmp(nfc->dev->dev_name, "")) {
nfc_text_store_set(nfc, "Emulating\n%s", nfc->dev->dev_name);
nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
} else if(is_ultralight) {
nfc_text_store_set(nfc, "MIFARE\nUltralight");
} else {
nfc_text_store_set(nfc, "Emulating\nMf Ultralight", nfc->dev->dev_name);
nfc_text_store_set(nfc, "MIFARE\nNTAG");
}
popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
popup_set_header(popup, nfc->text_store, 56, 31, AlignLeft, AlignTop);
popup_set_icon(popup, 0, 3, &I_NFC_dolphin_emulation_47x61);
popup_set_text(popup, nfc->text_store, 90, 28, AlignCenter, AlignTop);
// Setup and start worker
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
@@ -48,7 +54,10 @@ bool nfc_scene_mf_ultralight_emulate_on_event(void* context, SceneManagerEvent e
NFC_MF_UL_DATA_CHANGED) {
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightEmulate, NFC_MF_UL_DATA_NOT_CHANGED);
nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
// Save shadow file
if(furi_string_size(nfc->dev->load_path)) {
nfc_device_save_shadow(nfc->dev, furi_string_get_cstr(nfc->dev->load_path));
}
}
consumed = false;
}
@@ -19,10 +19,10 @@ void nfc_scene_mf_ultralight_menu_on_enter(void* context) {
Submenu* submenu = nfc->submenu;
MfUltralightData* data = &nfc->dev->dev_data.mf_ul_data;
if(data->data_read != data->data_size) {
if(!mf_ul_is_full_capture(data)) {
submenu_add_item(
submenu,
"Unlock With Password",
"Unlock",
SubmenuIndexUnlock,
nfc_scene_mf_ultralight_menu_submenu_callback,
nfc);
@@ -24,25 +24,29 @@ void nfc_scene_mf_ultralight_read_auth_set_state(Nfc* nfc, NfcSceneMfUlReadState
if(curr_state != state) {
if(state == NfcSceneMfUlReadStateDetecting) {
popup_reset(nfc->popup);
popup_set_text(
nfc->popup, "Apply card to\nFlipper's back", 97, 24, AlignCenter, AlignTop);
popup_set_text(nfc->popup, "Apply the\ntarget card", 97, 24, AlignCenter, AlignTop);
popup_set_icon(nfc->popup, 0, 8, &I_NFC_manual_60x50);
nfc_blink_read_start(nfc);
} else if(state == NfcSceneMfUlReadStateReading) {
popup_reset(nfc->popup);
popup_set_header(
nfc->popup, "Reading card\nDon't move...", 85, 24, AlignCenter, AlignTop);
popup_set_icon(nfc->popup, 12, 23, &A_Loading_24);
nfc_blink_detect_start(nfc);
} else if(state == NfcSceneMfUlReadStateNotSupportedCard) {
popup_reset(nfc->popup);
popup_set_header(nfc->popup, "Wrong type of card!", 64, 3, AlignCenter, AlignTop);
popup_set_text(
nfc->popup,
"Only MIFARE\nUltralight & NTAG\n are supported",
"Only MIFARE\nUltralight & NTAG\nare supported",
4,
22,
AlignLeft,
AlignTop);
popup_set_icon(nfc->popup, 73, 20, &I_DolphinCommon_56x48);
nfc_blink_stop(nfc);
notification_message(nfc->notifications, &sequence_error);
notification_message(nfc->notifications, &sequence_set_red_255);
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneMfUltralightReadAuth, state);
}
@@ -62,8 +66,6 @@ void nfc_scene_mf_ultralight_read_auth_on_enter(void* context) {
&nfc->dev->dev_data,
nfc_scene_mf_ultralight_read_auth_worker_callback,
nfc);
nfc_blink_read_start(nfc);
}
bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent event) {
@@ -86,8 +88,17 @@ bool nfc_scene_mf_ultralight_read_auth_on_event(void* context, SceneManagerEvent
nfc, NfcSceneMfUlReadStateNotSupportedCard);
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
NfcScene next_scene;
if(mf_ul_data->auth_method == MfUltralightAuthMethodManual) {
next_scene = NfcSceneMfUltralightKeyInput;
} else if(mf_ul_data->auth_method == MfUltralightAuthMethodAuto) {
next_scene = NfcSceneMfUltralightUnlockAuto;
} else {
next_scene = NfcSceneMfUltralightUnlockMenu;
}
consumed =
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, next_scene);
}
return consumed;
}
@@ -19,16 +19,20 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) {
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(mf_ul_data);
Widget* widget = nfc->widget;
const char* title;
FuriString* temp_str;
temp_str = furi_string_alloc();
if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) {
widget_add_string_element(
widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "All pages are unlocked!");
if(mf_ul_data->auth_success) {
title = "All pages are unlocked!";
} else {
title = "All unlocked but failed auth!";
}
} else {
widget_add_string_element(
widget, 64, 0, AlignCenter, AlignTop, FontPrimary, "Not all pages unlocked!");
title = "Not all pages unlocked!";
}
widget_add_string_element(widget, 64, 0, AlignCenter, AlignTop, FontPrimary, title);
furi_string_set(temp_str, "UID:");
for(size_t i = 0; i < nfc_data->uid_len; i++) {
furi_string_cat_printf(temp_str, " %02X", nfc_data->uid[i]);
@@ -65,6 +69,7 @@ void nfc_scene_mf_ultralight_read_auth_result_on_enter(void* context) {
nfc);
furi_string_free(temp_str);
notification_message(nfc->notifications, &sequence_set_green_255);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
}
@@ -81,8 +86,21 @@ bool nfc_scene_mf_ultralight_read_auth_result_on_event(void* context, SceneManag
consumed = true;
}
} else if(event.type == SceneManagerEventTypeBack) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
MfUltralightData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
if(mf_ul_data->auth_method == MfUltralightAuthMethodManual ||
mf_ul_data->auth_method == MfUltralightAuthMethodAuto) {
consumed = scene_manager_previous_scene(nfc->scene_manager);
} else {
NfcScene next_scene;
if((mf_ul_data->data_read == mf_ul_data->data_size) && (mf_ul_data->data_read > 0)) {
next_scene = NfcSceneMfUltralightMenu;
} else {
next_scene = NfcSceneMfUltralightUnlockMenu;
}
consumed =
scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, next_scene);
}
}
return consumed;
@@ -93,4 +111,6 @@ void nfc_scene_mf_ultralight_read_auth_result_on_exit(void* context) {
// Clean views
widget_reset(nfc->widget);
notification_message_block(nfc->notifications, &sequence_reset_green);
}
@@ -31,7 +31,7 @@ void nfc_scene_mf_ultralight_read_success_on_enter(void* context) {
nfc_scene_mf_ultralight_read_success_widget_callback,
nfc);
FuriString* temp_str;
FuriString* temp_str = NULL;
if(furi_string_size(nfc->dev->dev_data.parsed_data)) {
temp_str = furi_string_alloc_set(nfc->dev->dev_data.parsed_data);
} else {
@@ -0,0 +1,64 @@
#include "../nfc_i.h"
bool nfc_scene_mf_ultralight_unlock_auto_worker_callback(NfcWorkerEvent event, void* context) {
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, event);
return true;
}
void nfc_scene_mf_ultralight_unlock_auto_on_enter(void* context) {
Nfc* nfc = context;
// Setup view
widget_add_string_multiline_element(
nfc->widget,
54,
30,
AlignLeft,
AlignCenter,
FontPrimary,
"Touch the\nreader to get\npassword...");
widget_add_icon_element(nfc->widget, 0, 15, &I_Modern_reader_18x34);
widget_add_icon_element(nfc->widget, 20, 12, &I_Move_flipper_26x39);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
// Start worker
nfc_worker_start(
nfc->worker,
NfcWorkerStateMfUltralightEmulate,
&nfc->dev->dev_data,
nfc_scene_mf_ultralight_unlock_auto_worker_callback,
nfc);
nfc_blink_read_start(nfc);
}
bool nfc_scene_mf_ultralight_unlock_auto_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if((event.event == NfcWorkerEventMfUltralightPwdAuth)) {
MfUltralightAuth* auth = &nfc->dev->dev_data.mf_ul_auth;
memcpy(nfc->byte_input_store, auth->pwd.raw, sizeof(auth->pwd.raw));
nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodAuto;
nfc_worker_stop(nfc->worker);
notification_message(nfc->notifications, &sequence_success);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn);
consumed = true;
}
}
return consumed;
}
void nfc_scene_mf_ultralight_unlock_auto_on_exit(void* context) {
Nfc* nfc = context;
// Stop worker
nfc_worker_stop(nfc->worker);
// Clear view
widget_reset(nfc->widget);
nfc_blink_stop(nfc);
}
@@ -1,9 +1,10 @@
#include "../nfc_i.h"
enum SubmenuIndex {
SubmenuIndexMfUlUnlockMenuManual,
SubmenuIndexMfUlUnlockMenuAuto,
SubmenuIndexMfUlUnlockMenuAmeebo,
SubmenuIndexMfUlUnlockMenuXiaomi,
SubmenuIndexMfUlUnlockMenuManual,
};
void nfc_scene_mf_ultralight_unlock_menu_submenu_callback(void* context, uint32_t index) {
@@ -18,12 +19,14 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) {
uint32_t state =
scene_manager_get_scene_state(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
submenu_add_item(
submenu,
"Enter Password Manually",
SubmenuIndexMfUlUnlockMenuManual,
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
nfc);
if(nfc->dev->dev_data.protocol == NfcDeviceProtocolMifareUl) {
submenu_add_item(
submenu,
"Unlock With Reader",
SubmenuIndexMfUlUnlockMenuAuto,
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
nfc);
}
submenu_add_item(
submenu,
"Auth As Ameebo",
@@ -32,10 +35,16 @@ void nfc_scene_mf_ultralight_unlock_menu_on_enter(void* context) {
nfc);
submenu_add_item(
submenu,
"Auth As Xiaomi",
"Auth As Xiaomi Air Purifier",
SubmenuIndexMfUlUnlockMenuXiaomi,
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Enter Password Manually",
SubmenuIndexMfUlUnlockMenuManual,
nfc_scene_mf_ultralight_unlock_menu_submenu_callback,
nfc);
submenu_set_selected_item(submenu, state);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
@@ -57,8 +66,12 @@ bool nfc_scene_mf_ultralight_unlock_menu_on_event(void* context, SceneManagerEve
nfc->dev->dev_data.mf_ul_data.auth_method = MfUltralightAuthMethodXiaomi;
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockWarn);
consumed = true;
} else if(event.event == SubmenuIndexMfUlUnlockMenuAuto) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockAuto);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneExtraActions, event.event);
scene_manager_set_scene_state(
nfc->scene_manager, NfcSceneMfUltralightUnlockMenu, event.event);
}
return consumed;
}
@@ -10,15 +10,43 @@ void nfc_scene_mf_ultralight_unlock_warn_dialog_callback(DialogExResult result,
void nfc_scene_mf_ultralight_unlock_warn_on_enter(void* context) {
Nfc* nfc = context;
DialogEx* dialog_ex = nfc->dialog_ex;
MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method;
dialog_ex_set_context(dialog_ex, nfc);
dialog_ex_set_result_callback(dialog_ex, nfc_scene_mf_ultralight_unlock_warn_dialog_callback);
dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop);
dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48);
dialog_ex_set_center_button_text(dialog_ex, "OK");
if(auth_method == MfUltralightAuthMethodManual || auth_method == MfUltralightAuthMethodAuto) {
// Build dialog text
MfUltralightAuth* auth = &nfc->dev->dev_data.mf_ul_auth;
FuriString* password_str =
furi_string_alloc_set_str("Try to unlock the card with\npassword: ");
for(size_t i = 0; i < sizeof(auth->pwd.raw); ++i) {
furi_string_cat_printf(password_str, "%02X ", nfc->byte_input_store[i]);
}
furi_string_cat_str(password_str, "?\nCaution, a wrong password\ncan block the card!");
nfc_text_store_set(nfc, furi_string_get_cstr(password_str));
furi_string_free(password_str);
dialog_ex_set_header(
dialog_ex,
auth_method == MfUltralightAuthMethodAuto ? "Password captured!" : "Risky function!",
64,
0,
AlignCenter,
AlignTop);
dialog_ex_set_text(dialog_ex, nfc->text_store, 64, 12, AlignCenter, AlignTop);
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
dialog_ex_set_right_button_text(dialog_ex, "Continue");
if(auth_method == MfUltralightAuthMethodAuto)
notification_message(nfc->notifications, &sequence_set_green_255);
} else {
dialog_ex_set_header(dialog_ex, "Risky function!", 64, 4, AlignCenter, AlignTop);
dialog_ex_set_text(
dialog_ex, "Wrong password\ncan block your\ncard.", 4, 18, AlignLeft, AlignTop);
dialog_ex_set_icon(dialog_ex, 73, 20, &I_DolphinCommon_56x48);
dialog_ex_set_center_button_text(dialog_ex, "OK");
}
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
}
@@ -28,12 +56,33 @@ bool nfc_scene_mf_ultralight_unlock_warn_on_event(void* context, SceneManagerEve
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultCenter) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
DOLPHIN_DEED(DolphinDeedNfcRead);
MfUltralightAuthMethod auth_method = nfc->dev->dev_data.mf_ul_data.auth_method;
if(auth_method == MfUltralightAuthMethodManual || auth_method == MfUltralightAuthMethodAuto) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultRight) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
DOLPHIN_DEED(DolphinDeedNfcRead);
consumed = true;
} else if(event.event == DialogExResultLeft) {
if(auth_method == MfUltralightAuthMethodAuto) {
consumed = scene_manager_search_and_switch_to_previous_scene(
nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
} else {
consumed = scene_manager_previous_scene(nfc->scene_manager);
}
}
} else if(event.type == SceneManagerEventTypeBack) {
// Cannot press back
consumed = true;
}
} else {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == DialogExResultCenter) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadAuth);
DOLPHIN_DEED(DolphinDeedNfcRead);
consumed = true;
}
}
}
return consumed;
@@ -43,5 +92,7 @@ void nfc_scene_mf_ultralight_unlock_warn_on_exit(void* context) {
Nfc* nfc = context;
dialog_ex_reset(nfc->dialog_ex);
submenu_reset(nfc->submenu);
nfc_text_store_clear(nfc);
notification_message_block(nfc->notifications, &sequence_reset_green);
}
@@ -87,6 +87,22 @@ void nfc_scene_nfc_data_info_on_enter(void* context) {
temp_str, "\nPages Read %d/%d", data->data_read / 4, data->data_size / 4);
if(data->data_size > data->data_read) {
furi_string_cat_printf(temp_str, "\nPassword-protected");
} else if(data->auth_success) {
MfUltralightConfigPages* config_pages = mf_ultralight_get_config_pages(data);
if(config_pages) {
furi_string_cat_printf(
temp_str,
"\nPassword: %02X %02X %02X %02X",
config_pages->auth_data.pwd.raw[0],
config_pages->auth_data.pwd.raw[1],
config_pages->auth_data.pwd.raw[2],
config_pages->auth_data.pwd.raw[3]);
furi_string_cat_printf(
temp_str,
"\nPACK: %02X %02X",
config_pages->auth_data.pack.raw[0],
config_pages->auth_data.pack.raw[1]);
}
}
} else if(protocol == NfcDeviceProtocolMifareClassic) {
MfClassicData* data = &dev_data->mf_classic_data;
@@ -115,7 +131,7 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == GuiButtonTypeRight) {
if(protocol == NfcDeviceProtocolMifareDesfire) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireApp);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfDesfireData);
consumed = true;
} else if(protocol == NfcDeviceProtocolMifareUl) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightData);
@@ -70,6 +70,8 @@ bool nfc_scene_read_on_event(void* context, SceneManagerEvent event) {
consumed = true;
} else if(event.event == NfcWorkerEventReadMfUltralight) {
notification_message(nfc->notifications, &sequence_success);
// Set unlock password input to 0xFFFFFFFF only on fresh read
memset(nfc->byte_input_store, 0xFF, 4);
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightReadSuccess);
DOLPHIN_DEED(DolphinDeedNfcReadSuccess);
consumed = true;
@@ -0,0 +1,97 @@
#include "../nfc_i.h"
#include "nfc_worker_i.h"
enum SubmenuIndex {
SubmenuIndexReadMifareClassic,
SubmenuIndexReadMifareDesfire,
SubmenuIndexReadMfUltralight,
SubmenuIndexReadEMV,
SubmenuIndexReadNFCA,
};
void nfc_scene_read_card_type_submenu_callback(void* context, uint32_t index) {
Nfc* nfc = context;
view_dispatcher_send_custom_event(nfc->view_dispatcher, index);
}
void nfc_scene_read_card_type_on_enter(void* context) {
Nfc* nfc = context;
Submenu* submenu = nfc->submenu;
submenu_add_item(
submenu,
"Read Mifare Classic",
SubmenuIndexReadMifareClassic,
nfc_scene_read_card_type_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Read Mifare DESFire",
SubmenuIndexReadMifareDesfire,
nfc_scene_read_card_type_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Read NTAG/Ultralight",
SubmenuIndexReadMfUltralight,
nfc_scene_read_card_type_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Read EMV card",
SubmenuIndexReadEMV,
nfc_scene_read_card_type_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Read NFC-A data",
SubmenuIndexReadNFCA,
nfc_scene_read_card_type_submenu_callback,
nfc);
uint32_t state = scene_manager_get_scene_state(nfc->scene_manager, NfcSceneReadCardType);
submenu_set_selected_item(submenu, state);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
}
bool nfc_scene_read_card_type_on_event(void* context, SceneManagerEvent event) {
Nfc* nfc = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexReadMifareClassic) {
nfc->dev->dev_data.read_mode = NfcReadModeMfClassic;
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
consumed = true;
}
if(event.event == SubmenuIndexReadMifareDesfire) {
nfc->dev->dev_data.read_mode = NfcReadModeMfDesfire;
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
consumed = true;
}
if(event.event == SubmenuIndexReadMfUltralight) {
nfc->dev->dev_data.read_mode = NfcReadModeMfUltralight;
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
consumed = true;
}
if(event.event == SubmenuIndexReadEMV) {
nfc->dev->dev_data.read_mode = NfcReadModeEMV;
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
consumed = true;
}
if(event.event == SubmenuIndexReadNFCA) {
nfc->dev->dev_data.read_mode = NfcReadModeNFCA;
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
consumed = true;
}
scene_manager_set_scene_state(nfc->scene_manager, NfcSceneReadCardType, event.event);
}
return consumed;
}
void nfc_scene_read_card_type_on_exit(void* context) {
Nfc* nfc = context;
submenu_reset(nfc->submenu);
}
+1 -1
View File
@@ -7,7 +7,7 @@ void nfc_scene_rpc_on_enter(void* context) {
popup_set_header(popup, "NFC", 89, 42, AlignCenter, AlignBottom);
popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
popup_set_icon(popup, 0, 12, &I_NFC_dolphin_emulation_47x61);
view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
@@ -62,7 +62,7 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
}
strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
if(nfc_device_save(nfc->dev, nfc->text_store)) {
if(nfc_save_file(nfc)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
if(!scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
// Nothing, do not count editing as saving
@@ -11,6 +11,8 @@ enum SubmenuIndex {
SubmenuIndexDelete,
SubmenuIndexInfo,
SubmenuIndexRestoreOriginal,
SubmenuIndexMfUlUnlockByReader,
SubmenuIndexMfUlUnlockByPassword,
};
void nfc_scene_saved_menu_submenu_callback(void* context, uint32_t index) {
@@ -69,6 +71,21 @@ void nfc_scene_saved_menu_on_enter(void* context) {
}
submenu_add_item(
submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc);
if(nfc->dev->format == NfcDeviceSaveFormatMifareUl &&
!mf_ul_is_full_capture(&nfc->dev->dev_data.mf_ul_data)) {
submenu_add_item(
submenu,
"Unlock With Reader",
SubmenuIndexMfUlUnlockByReader,
nfc_scene_saved_menu_submenu_callback,
nfc);
submenu_add_item(
submenu,
"Unlock With Password",
SubmenuIndexMfUlUnlockByPassword,
nfc_scene_saved_menu_submenu_callback,
nfc);
}
if(nfc->dev->shadow_file_exist) {
submenu_add_item(
submenu,
@@ -106,6 +123,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
consumed = true;
} else if(event.event == SubmenuIndexDetectReader) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneDetectReader);
DOLPHIN_DEED(DolphinDeedNfcDetectReader);
consumed = true;
} else if(event.event == SubmenuIndexWrite) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicWrite);
@@ -141,6 +159,12 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
} else if(event.event == SubmenuIndexRestoreOriginal) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneRestoreOriginalConfirm);
consumed = true;
} else if(event.event == SubmenuIndexMfUlUnlockByReader) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockAuto);
consumed = true;
} else if(event.event == SubmenuIndexMfUlUnlockByPassword) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneMfUltralightUnlockMenu);
consumed = true;
}
}
@@ -31,7 +31,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
if(event.event == NfcCustomEventByteInputDone) {
if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSavedMenu)) {
nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
if(nfc_device_save(nfc->dev, nfc->dev->dev_name)) {
if(nfc_save_file(nfc)) {
scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
consumed = true;
}
@@ -41,6 +41,7 @@ bool nfc_scene_set_uid_on_event(void* context, SceneManagerEvent event) {
}
}
}
return consumed;
}
@@ -1,4 +1,5 @@
#include "../nfc_i.h"
#include "nfc_worker_i.h"
#include <dolphin/dolphin.h>
enum SubmenuIndex {
@@ -47,6 +48,7 @@ bool nfc_scene_start_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexRead) {
nfc->dev->dev_data.read_mode = NfcReadModeAuto;
scene_manager_next_scene(nfc->scene_manager, NfcSceneRead);
DOLPHIN_DEED(DolphinDeedNfcRead);
consumed = true;
@@ -59,11 +59,8 @@ SubGhzChatWorker* subghz_chat_worker_alloc(Cli* cli) {
instance->cli = cli;
instance->thread = furi_thread_alloc();
furi_thread_set_name(instance->thread, "SubGhzChat");
furi_thread_set_stack_size(instance->thread, 2048);
furi_thread_set_context(instance->thread, instance);
furi_thread_set_callback(instance->thread, subghz_chat_worker_thread);
instance->thread =
furi_thread_alloc_ex("SubGhzChat", 2048, subghz_chat_worker_thread, instance);
instance->subghz_txrx = subghz_tx_rx_worker_alloc();
instance->event_queue = furi_message_queue_alloc(80, sizeof(SubGhzChatEvent));
return instance;
@@ -0,0 +1,13 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
/** SubGhzErrorType */
typedef enum {
SubGhzErrorTypeNoError = 0, /** There are no errors */
SubGhzErrorTypeParseFile =
1, /** File parsing error, or wrong file structure, or missing required parameters. more accurate data can be obtained through the debug port */
SubGhzErrorTypeOnlyRX =
2, /** Transmission on this frequency is blocked by regional settings */
} SubGhzErrorType;
@@ -25,7 +25,7 @@ TUPLE_DEF2(
(frequency, uint32_t),
(count, uint8_t),
(rssi_max, uint8_t))
/* Register globaly the oplist */
/* Register globally the oplist */
#define M_OPL_SubGhzFrequencyAnalyzerLogItem_t() \
TUPLE_OPLIST(SubGhzFrequencyAnalyzerLogItem, M_POD_OPLIST, M_DEFAULT_OPLIST, M_DEFAULT_OPLIST)
@@ -5,8 +5,6 @@
#define TAG "SubghzFrequencyAnalyzerWorker"
#define SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD -95.0f
static const uint8_t subghz_preset_ook_58khz[][2] = {
{CC1101_MDMCFG4, 0b11110111}, // Rx BW filter is 58.035714kHz
/* End */
@@ -71,7 +69,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
.frequency_coarse = 0, .rssi_coarse = 0, .frequency_fine = 0, .rssi_fine = 0};
float rssi = 0;
uint32_t frequency = 0;
float rssi_temp = 0;
float rssi_temp = -127.0f;
uint32_t frequency_temp = 0;
CC1101Status status;
@@ -196,7 +194,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
TAG, "=:%lu:%f", frequency_rssi.frequency_fine, (double)frequency_rssi.rssi_fine);
instance->sample_hold_counter = 20;
rssi_temp = frequency_rssi.rssi_fine;
rssi_temp = (rssi_temp + frequency_rssi.rssi_fine) / 2;
frequency_temp = frequency_rssi.frequency_fine;
if(instance->filVal) {
@@ -207,10 +205,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
// Deliver callback
if(instance->pair_callback) {
instance->pair_callback(
instance->context,
frequency_rssi.frequency_fine,
frequency_rssi.rssi_fine,
true);
instance->context, frequency_rssi.frequency_fine, rssi_temp, true);
}
} else if( // Deliver results coarse
(frequency_rssi.rssi_coarse > SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD) &&
@@ -222,7 +217,7 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
(double)frequency_rssi.rssi_coarse);
instance->sample_hold_counter = 20;
rssi_temp = frequency_rssi.rssi_coarse;
rssi_temp = (rssi_temp + frequency_rssi.rssi_coarse) / 2;
frequency_temp = frequency_rssi.frequency_coarse;
if(instance->filVal) {
frequency_rssi.frequency_coarse =
@@ -232,15 +227,12 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
// Deliver callback
if(instance->pair_callback) {
instance->pair_callback(
instance->context,
frequency_rssi.frequency_coarse,
frequency_rssi.rssi_coarse,
true);
instance->context, frequency_rssi.frequency_coarse, rssi_temp, true);
}
} else {
if(instance->sample_hold_counter > 0) {
instance->sample_hold_counter--;
if(instance->sample_hold_counter == 18) {
if(instance->sample_hold_counter == 15) {
if(instance->pair_callback) {
instance->pair_callback(
instance->context, frequency_temp, rssi_temp, false);
@@ -248,8 +240,8 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) {
}
} else {
instance->filVal = 0;
if(instance->pair_callback)
instance->pair_callback(instance->context, 0, 0, false);
rssi_temp = -127.0f;
instance->pair_callback(instance->context, 0, 0, false);
}
}
}
@@ -265,12 +257,8 @@ SubGhzFrequencyAnalyzerWorker* subghz_frequency_analyzer_worker_alloc(void* cont
furi_assert(context);
SubGhzFrequencyAnalyzerWorker* instance = malloc(sizeof(SubGhzFrequencyAnalyzerWorker));
instance->thread = furi_thread_alloc();
furi_thread_set_name(instance->thread, "SubGhzFAWorker");
furi_thread_set_stack_size(instance->thread, 2048);
furi_thread_set_context(instance->thread, instance);
furi_thread_set_callback(instance->thread, subghz_frequency_analyzer_worker_thread);
instance->thread = furi_thread_alloc_ex(
"SubGhzFAWorker", 2048, subghz_frequency_analyzer_worker_thread, instance);
SubGhz* subghz = context;
instance->setting = subghz->setting;
return instance;
@@ -3,6 +3,8 @@
#include <furi_hal.h>
#include "../subghz_i.h"
#define SUBGHZ_FREQUENCY_ANALYZER_THRESHOLD -93.0f
typedef struct SubGhzFrequencyAnalyzerWorker SubGhzFrequencyAnalyzerWorker;
typedef void (*SubGhzFrequencyAnalyzerWorkerPairCallback)(
@@ -44,14 +44,7 @@ bool subghz_scene_delete_success_on_event(void* context, SceneManagerEvent event
void subghz_scene_delete_success_on_exit(void* context) {
SubGhz* subghz = context;
// Clear view
Popup* popup = subghz->popup;
popup_set_header(popup, NULL, 0, 0, AlignCenter, AlignBottom);
popup_set_text(popup, NULL, 0, 0, AlignCenter, AlignTop);
popup_set_icon(popup, 0, 0, NULL);
popup_set_callback(popup, NULL);
popup_set_context(popup, NULL);
popup_set_timeout(popup, 0);
popup_disable_timeout(popup);
popup_reset(popup);
}
@@ -38,18 +38,34 @@ bool subghz_scene_more_raw_on_event(void* context, SceneManagerEvent event) {
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexDelete) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW);
return true;
if(subghz_file_available(subghz)) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerNoSet);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexDelete);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneDeleteRAW);
return true;
} else {
if(!scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart)) {
scene_manager_stop(subghz->scene_manager);
view_dispatcher_stop(subghz->view_dispatcher);
}
}
} else if(event.event == SubmenuIndexEdit) {
furi_string_reset(subghz->file_path_tmp);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
return true;
if(subghz_file_available(subghz)) {
furi_string_reset(subghz->file_path_tmp);
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneMoreRAW, SubmenuIndexEdit);
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
return true;
} else {
if(!scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart)) {
scene_manager_stop(subghz->scene_manager);
view_dispatcher_stop(subghz->view_dispatcher);
}
}
}
}
return false;
@@ -198,20 +198,28 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
break;
case SubGhzCustomEventViewReadRAWMore:
if(subghz_scene_read_raw_update_filename(subghz)) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
consumed = true;
if(subghz_file_available(subghz)) {
if(subghz_scene_read_raw_update_filename(subghz)) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSet);
subghz->txrx->rx_key_state = SubGhzRxKeyStateRAWLoad;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneMoreRAW);
consumed = true;
} else {
furi_crash("SubGhz: RAW file name update error.");
}
} else {
furi_crash("SubGhz: RAW file name update error.");
if(!scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart)) {
scene_manager_stop(subghz->scene_manager);
view_dispatcher_stop(subghz->view_dispatcher);
}
}
break;
case SubGhzCustomEventViewReadRAWSendStart:
if(subghz_scene_read_raw_update_filename(subghz)) {
if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
//start send
subghz->state_notifications = SubGhzNotificationStateIDLE;
if(subghz->txrx->txrx_state == SubGhzTxRxStateRx) {
@@ -238,6 +246,12 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
subghz->state_notifications = SubGhzNotificationStateTx;
}
}
} else {
if(!scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart)) {
scene_manager_stop(subghz->scene_manager);
view_dispatcher_stop(subghz->view_dispatcher);
}
}
consumed = true;
break;
@@ -314,11 +328,17 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) {
break;
case SubGhzCustomEventViewReadRAWSave:
if(subghz_scene_read_raw_update_filename(subghz)) {
if(subghz_file_available(subghz) && subghz_scene_read_raw_update_filename(subghz)) {
scene_manager_set_scene_state(
subghz->scene_manager, SubGhzSceneReadRAW, SubGhzCustomEventManagerSetRAW);
subghz->txrx->rx_key_state = SubGhzRxKeyStateBack;
scene_manager_next_scene(subghz->scene_manager, SubGhzSceneSaveName);
} else {
if(!scene_manager_search_and_switch_to_previous_scene(
subghz->scene_manager, SubGhzSceneStart)) {
scene_manager_stop(subghz->scene_manager);
view_dispatcher_stop(subghz->view_dispatcher);
}
}
consumed = true;
break;
@@ -43,6 +43,12 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
result = subghz_tx_start(subghz, subghz->txrx->fff_data);
if(result) subghz_blink_start(subghz);
}
if(!result) {
rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeOnlyRX);
rpc_system_app_set_error_text(
subghz->rpc_ctx,
"Transmission on this frequency is restricted in your region");
}
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventButtonPress, result);
} else if(event.event == SubGhzCustomEventSceneRpcButtonRelease) {
bool result = false;
@@ -74,6 +80,9 @@ bool subghz_scene_rpc_on_event(void* context, SceneManagerEvent event) {
popup_set_text(popup, subghz->file_name_tmp, 89, 44, AlignCenter, AlignTop);
furi_string_free(file_name);
} else {
rpc_system_app_set_error_code(subghz->rpc_ctx, SubGhzErrorTypeParseFile);
rpc_system_app_set_error_text(subghz->rpc_ctx, "Cannot parse file");
}
}
rpc_system_app_confirm(subghz->rpc_ctx, RpcAppEventLoadFile, result);

Some files were not shown because too many files have changed in this diff Show More