Merge branch 'dev' into dev

This commit is contained in:
JuanJakobo
2022-11-16 08:36:53 +01:00
committed by GitHub
152 changed files with 2211 additions and 495 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",
},
+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
@@ -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);
}
@@ -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;
@@ -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);
@@ -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"],
)
+7 -13
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,7 +650,7 @@ 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);
@@ -155,7 +155,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"],
)
+2 -2
View File
@@ -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(
@@ -288,7 +288,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);
@@ -12,6 +12,7 @@ App(
icon="A_iButton_14",
stack_size=2 * 1024,
order=60,
fap_libs=["assets"],
)
App(
@@ -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(
+1
View File
@@ -14,6 +14,7 @@ App(
icon="A_125khz_14",
stack_size=2 * 1024,
order=20,
fap_libs=["assets"],
)
App(
+1 -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);
@@ -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);
@@ -60,3 +60,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)
@@ -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);
@@ -48,7 +48,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;
}
@@ -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);
@@ -48,7 +48,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;
}
@@ -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,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);
}
@@ -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
@@ -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;
@@ -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;
@@ -44,14 +44,7 @@ bool subghz_scene_save_success_on_event(void* context, SceneManagerEvent event)
void subghz_scene_save_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);
}
@@ -36,16 +36,10 @@ bool subghz_scene_show_error_sub_on_event(void* context, SceneManagerEvent event
void subghz_scene_show_error_sub_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);
furi_string_reset(subghz->error_str);
notification_message(subghz->notifications, &sequence_reset_rgb);
@@ -43,14 +43,7 @@ bool subghz_scene_show_only_rx_on_event(void* context, SceneManagerEvent event)
void subghz_scene_show_only_rx_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);
}
+17 -6
View File
@@ -490,6 +490,23 @@ bool subghz_rename_file(SubGhz* subghz) {
return ret;
}
bool subghz_file_available(SubGhz* subghz) {
furi_assert(subghz);
bool ret = true;
Storage* storage = furi_record_open(RECORD_STORAGE);
FS_Error fs_result =
storage_common_stat(storage, furi_string_get_cstr(subghz->file_path), NULL);
if(fs_result != FSE_OK) {
dialog_message_show_storage_error(subghz->dialogs, "File not available\n file/directory");
ret = false;
}
furi_record_close(RECORD_STORAGE);
return ret;
}
bool subghz_delete_file(SubGhz* subghz) {
furi_assert(subghz);
@@ -513,12 +530,6 @@ bool subghz_path_is_file(FuriString* path) {
}
uint32_t subghz_random_serial(void) {
static bool rand_generator_inited = false;
if(!rand_generator_inited) {
srand(DWT->CYCCNT);
rand_generator_inited = true;
}
return (uint32_t)rand();
}
+1
View File
@@ -124,6 +124,7 @@ bool subghz_save_protocol_to_file(
const char* dev_file_name);
bool subghz_load_protocol_from_file(SubGhz* subghz);
bool subghz_rename_file(SubGhz* subghz);
bool subghz_file_available(SubGhz* subghz);
bool subghz_delete_file(SubGhz* subghz);
void subghz_file_name_clear(SubGhz* subghz);
bool subghz_path_is_file(FuriString* path);
+1
View File
@@ -11,4 +11,5 @@ App(
stack_size=2 * 1024,
icon="A_U2F_14",
order=80,
fap_libs=["assets"],
)
+1 -1
View File
@@ -203,7 +203,7 @@ static int32_t u2f_hid_worker(void* context) {
WorkerEvtStop | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtRequest,
FuriFlagWaitAny,
FuriWaitForever);
furi_check((flags & FuriFlagError) == 0);
furi_check(!(flags & FuriFlagError));
if(flags & WorkerEvtStop) break;
if(flags & WorkerEvtConnect) {
u2f_set_state(u2f_hid->u2f_instance, 1);
+20
View File
@@ -13,6 +13,8 @@
#include "dap_config.h"
#include "gui/dap_gui.h"
#include "usb/dap_v2_usb.h"
#include <dialogs/dialogs.h>
#include "dap_link_icons.h"
/***************************************************************************/
/****************************** DAP COMMON *********************************/
@@ -495,6 +497,24 @@ DapConfig* dap_app_get_config(DapApp* app) {
int32_t dap_link_app(void* p) {
UNUSED(p);
if(furi_hal_usb_is_locked()) {
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
DialogMessage* message = dialog_message_alloc();
dialog_message_set_header(message, "Connection\nis active!", 3, 2, AlignLeft, AlignTop);
dialog_message_set_text(
message,
"Disconnect from\nPC or phone to\nuse this function.",
3,
30,
AlignLeft,
AlignTop);
dialog_message_set_icon(message, &I_ActiveConnection_50x64, 78, 0);
dialog_message_show(dialogs, message);
dialog_message_free(message);
furi_record_close(RECORD_DIALOGS);
return -1;
}
// alloc app
DapApp* app = dap_app_alloc();
app_handle = app;
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

@@ -210,5 +210,5 @@ bool magic_wipe() {
void magic_deactivate() {
furi_hal_nfc_ll_txrx_off();
furi_hal_nfc_start_sleep();
furi_hal_nfc_sleep();
}
@@ -167,7 +167,6 @@ void nfc_magic_worker_wipe(NfcMagicWorker* nfc_magic_worker) {
if(!magic_data_access_cmd()) continue;
if(!magic_write_blk(0, &block)) continue;
nfc_magic_worker->callback(NfcMagicWorkerEventSuccess, nfc_magic_worker->context);
magic_deactivate();
break;
}
magic_deactivate();
@@ -286,7 +286,6 @@ static void
int32_t snake_game_app(void* p) {
UNUSED(p);
srand(DWT->CYCCNT);
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(SnakeEvent));
@@ -293,7 +293,7 @@ void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* ou
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%d.%d C Hum:%d%%",
"Temp:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
@@ -301,7 +301,6 @@ void ws_protocol_decoder_acurite_592txr_get_string(void* context, FuriString* ou
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(int16_t)instance->generic.temp,
abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))),
(double)instance->generic.temp,
instance->generic.humidity);
}
@@ -234,7 +234,7 @@ void ws_protocol_decoder_acurite_606tx_get_string(void* context, FuriString* out
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%d.%d C Hum:%d%%",
"Temp:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
@@ -242,7 +242,6 @@ void ws_protocol_decoder_acurite_606tx_get_string(void* context, FuriString* out
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(int16_t)instance->generic.temp,
abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))),
(double)instance->generic.temp,
instance->generic.humidity);
}
@@ -0,0 +1,247 @@
#include "acurite_609txc.h"
#define TAG "WSProtocolAcurite_609TXC"
/*
* Help
* https://github.com/merbanan/rtl_433/blob/5bef4e43133ac4c0e2d18d36f87c52b4f9458453/src/devices/acurite.c#L216
*
* 0000 1111 | 0011 0000 | 0101 1100 | 0000 0000 | 1110 0111
* iiii iiii | buuu tttt | tttt tttt | hhhh hhhh | cccc cccc
* - i: identification; changes on battery switch
* - c: checksum (sum of previous by bytes)
* - u: unknown
* - b: battery low; flag to indicate low battery voltage
* - t: temperature; in °C * 10, 12 bit with complement
* - h: humidity
*
*/
static const SubGhzBlockConst ws_protocol_acurite_609txc_const = {
.te_short = 500,
.te_long = 1000,
.te_delta = 150,
.min_count_bit_for_found = 40,
};
struct WSProtocolDecoderAcurite_609TXC {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
WSBlockGeneric generic;
};
struct WSProtocolEncoderAcurite_609TXC {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
WSBlockGeneric generic;
};
typedef enum {
Acurite_609TXCDecoderStepReset = 0,
Acurite_609TXCDecoderStepSaveDuration,
Acurite_609TXCDecoderStepCheckDuration,
} Acurite_609TXCDecoderStep;
const SubGhzProtocolDecoder ws_protocol_acurite_609txc_decoder = {
.alloc = ws_protocol_decoder_acurite_609txc_alloc,
.free = ws_protocol_decoder_acurite_609txc_free,
.feed = ws_protocol_decoder_acurite_609txc_feed,
.reset = ws_protocol_decoder_acurite_609txc_reset,
.get_hash_data = ws_protocol_decoder_acurite_609txc_get_hash_data,
.serialize = ws_protocol_decoder_acurite_609txc_serialize,
.deserialize = ws_protocol_decoder_acurite_609txc_deserialize,
.get_string = ws_protocol_decoder_acurite_609txc_get_string,
};
const SubGhzProtocolEncoder ws_protocol_acurite_609txc_encoder = {
.alloc = NULL,
.free = NULL,
.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};
const SubGhzProtocol ws_protocol_acurite_609txc = {
.name = WS_PROTOCOL_ACURITE_609TXC_NAME,
.type = SubGhzProtocolWeatherStation,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
.decoder = &ws_protocol_acurite_609txc_decoder,
.encoder = &ws_protocol_acurite_609txc_encoder,
};
void* ws_protocol_decoder_acurite_609txc_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
WSProtocolDecoderAcurite_609TXC* instance = malloc(sizeof(WSProtocolDecoderAcurite_609TXC));
instance->base.protocol = &ws_protocol_acurite_609txc;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void ws_protocol_decoder_acurite_609txc_free(void* context) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
free(instance);
}
void ws_protocol_decoder_acurite_609txc_reset(void* context) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
static bool ws_protocol_acurite_609txc_check(WSProtocolDecoderAcurite_609TXC* instance) {
if(!instance->decoder.decode_data) return false;
uint8_t crc = (uint8_t)(instance->decoder.decode_data >> 32) +
(uint8_t)(instance->decoder.decode_data >> 24) +
(uint8_t)(instance->decoder.decode_data >> 16) +
(uint8_t)(instance->decoder.decode_data >> 8);
return (crc == (instance->decoder.decode_data & 0xFF));
}
/**
* Analysis of received data
* @param instance Pointer to a WSBlockGeneric* instance
*/
static void ws_protocol_acurite_609txc_remote_controller(WSBlockGeneric* instance) {
instance->id = (instance->data >> 32) & 0xFF;
instance->battery_low = (instance->data >> 31) & 1;
instance->channel = WS_NO_CHANNEL;
// Temperature in Celsius is encoded as a 12 bit integer value
// multiplied by 10 using the 4th - 6th nybbles (bytes 1 & 2)
// negative values are recovered by sign extend from int16_t.
int16_t temp_raw =
(int16_t)(((instance->data >> 12) & 0xf000) | ((instance->data >> 16) << 4));
instance->temp = (temp_raw >> 4) * 0.1f;
instance->humidity = (instance->data >> 8) & 0xff;
instance->btn = WS_NO_BTN;
}
void ws_protocol_decoder_acurite_609txc_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
switch(instance->decoder.parser_step) {
case Acurite_609TXCDecoderStepReset:
if((!level) && (DURATION_DIFF(duration, ws_protocol_acurite_609txc_const.te_short * 17) <
ws_protocol_acurite_609txc_const.te_delta * 8)) {
//Found syncPrefix
instance->decoder.parser_step = Acurite_609TXCDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
}
break;
case Acurite_609TXCDecoderStepSaveDuration:
if(level) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = Acurite_609TXCDecoderStepCheckDuration;
} else {
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
break;
case Acurite_609TXCDecoderStepCheckDuration:
if(!level) {
if(DURATION_DIFF(instance->decoder.te_last, ws_protocol_acurite_609txc_const.te_short) <
ws_protocol_acurite_609txc_const.te_delta) {
if((DURATION_DIFF(duration, ws_protocol_acurite_609txc_const.te_short) <
ws_protocol_acurite_609txc_const.te_delta) ||
(duration > ws_protocol_acurite_609txc_const.te_long * 3)) {
//Found syncPostfix
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
if((instance->decoder.decode_count_bit ==
ws_protocol_acurite_609txc_const.min_count_bit_for_found) &&
ws_protocol_acurite_609txc_check(instance)) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
ws_protocol_acurite_609txc_remote_controller(&instance->generic);
if(instance->base.callback)
instance->base.callback(&instance->base, instance->base.context);
}
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else if(
DURATION_DIFF(duration, ws_protocol_acurite_609txc_const.te_long) <
ws_protocol_acurite_609txc_const.te_delta * 2) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = Acurite_609TXCDecoderStepSaveDuration;
} else if(
DURATION_DIFF(duration, ws_protocol_acurite_609txc_const.te_long * 2) <
ws_protocol_acurite_609txc_const.te_delta * 4) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = Acurite_609TXCDecoderStepSaveDuration;
} else {
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
} else {
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
} else {
instance->decoder.parser_step = Acurite_609TXCDecoderStepReset;
}
break;
}
}
uint8_t ws_protocol_decoder_acurite_609txc_get_hash_data(void* context) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
return subghz_protocol_blocks_get_hash_data(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}
bool ws_protocol_decoder_acurite_609txc_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
}
bool ws_protocol_decoder_acurite_609txc_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
bool ret = false;
do {
if(!ws_block_generic_deserialize(&instance->generic, flipper_format)) {
break;
}
if(instance->generic.data_count_bit !=
ws_protocol_acurite_609txc_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
break;
}
ret = true;
} while(false);
return ret;
}
void ws_protocol_decoder_acurite_609txc_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderAcurite_609TXC* instance = context;
furi_string_printf(
output,
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 40),
(uint32_t)(instance->generic.data),
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(double)instance->generic.temp,
instance->generic.humidity);
}
@@ -0,0 +1,79 @@
#pragma once
#include <lib/subghz/protocols/base.h>
#include <lib/subghz/blocks/const.h>
#include <lib/subghz/blocks/decoder.h>
#include <lib/subghz/blocks/encoder.h>
#include "ws_generic.h"
#include <lib/subghz/blocks/math.h>
#define WS_PROTOCOL_ACURITE_609TXC_NAME "Acurite-609TXC"
typedef struct WSProtocolDecoderAcurite_609TXC WSProtocolDecoderAcurite_609TXC;
typedef struct WSProtocolEncoderAcurite_609TXC WSProtocolEncoderAcurite_609TXC;
extern const SubGhzProtocolDecoder ws_protocol_acurite_609txc_decoder;
extern const SubGhzProtocolEncoder ws_protocol_acurite_609txc_encoder;
extern const SubGhzProtocol ws_protocol_acurite_609txc;
/**
* Allocate WSProtocolDecoderAcurite_609TXC.
* @param environment Pointer to a SubGhzEnvironment instance
* @return WSProtocolDecoderAcurite_609TXC* pointer to a WSProtocolDecoderAcurite_609TXC instance
*/
void* ws_protocol_decoder_acurite_609txc_alloc(SubGhzEnvironment* environment);
/**
* Free WSProtocolDecoderAcurite_609TXC.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
*/
void ws_protocol_decoder_acurite_609txc_free(void* context);
/**
* Reset decoder WSProtocolDecoderAcurite_609TXC.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
*/
void ws_protocol_decoder_acurite_609txc_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void ws_protocol_decoder_acurite_609txc_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @return hash Hash sum
*/
uint8_t ws_protocol_decoder_acurite_609txc_get_hash_data(void* context);
/**
* Serialize data WSProtocolDecoderAcurite_609TXC.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return true On success
*/
bool ws_protocol_decoder_acurite_609txc_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data WSProtocolDecoderAcurite_609TXC.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return true On success
*/
bool ws_protocol_decoder_acurite_609txc_deserialize(void* context, FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a WSProtocolDecoderAcurite_609TXC instance
* @param output Resulting text
*/
void ws_protocol_decoder_acurite_609txc_get_string(void* context, FuriString* output);
@@ -200,7 +200,6 @@ void ws_protocol_decoder_ambient_weather_feed(void* context, bool level, uint32_
((instance->decoder.decode_data & AMBIENT_WEATHER_PACKET_HEADER_MASK) ==
AMBIENT_WEATHER_PACKET_HEADER_2)) {
if(ws_protocol_ambient_weather_check_crc(instance)) {
instance->decoder.decode_data = instance->decoder.decode_data;
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit =
ws_protocol_ambient_weather_const.min_count_bit_for_found;
@@ -264,7 +263,7 @@ void ws_protocol_decoder_ambient_weather_get_string(void* context, FuriString* o
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%d.%d C Hum:%d%%",
"Temp:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
@@ -272,7 +271,6 @@ void ws_protocol_decoder_ambient_weather_get_string(void* context, FuriString* o
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(int16_t)instance->generic.temp,
abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))),
(double)instance->generic.temp,
instance->generic.humidity);
}
@@ -327,7 +327,7 @@ void ws_protocol_decoder_gt_wt_03_get_string(void* context, FuriString* output)
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%d.%d C Hum:%d%%",
"Temp:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
@@ -335,7 +335,6 @@ void ws_protocol_decoder_gt_wt_03_get_string(void* context, FuriString* output)
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(int16_t)instance->generic.temp,
abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))),
(double)instance->generic.temp,
instance->generic.humidity);
}
@@ -283,7 +283,7 @@ void ws_protocol_decoder_infactory_get_string(void* context, FuriString* output)
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%d.%d C Hum:%d%%",
"Temp:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
@@ -291,7 +291,6 @@ void ws_protocol_decoder_infactory_get_string(void* context, FuriString* output)
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(int16_t)instance->generic.temp,
abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))),
(double)instance->generic.temp,
instance->generic.humidity);
}
@@ -284,7 +284,7 @@ void ws_protocol_decoder_lacrosse_tx141thbv2_get_string(void* context, FuriStrin
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%d.%d C Hum:%d%%",
"Temp:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
@@ -292,7 +292,6 @@ void ws_protocol_decoder_lacrosse_tx141thbv2_get_string(void* context, FuriStrin
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(int16_t)instance->generic.temp,
abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))),
(double)instance->generic.temp,
instance->generic.humidity);
}
@@ -247,7 +247,7 @@ void ws_protocol_decoder_nexus_th_get_string(void* context, FuriString* output)
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%d.%d C Hum:%d%%",
"Temp:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
@@ -255,7 +255,6 @@ void ws_protocol_decoder_nexus_th_get_string(void* context, FuriString* output)
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(int16_t)instance->generic.temp,
abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))),
(double)instance->generic.temp,
instance->generic.humidity);
}
@@ -6,6 +6,7 @@ const SubGhzProtocol* weather_station_protocol_registry_items[] = {
&ws_protocol_nexus_th,
&ws_protocol_gt_wt_03,
&ws_protocol_acurite_606tx,
&ws_protocol_acurite_609txc,
&ws_protocol_lacrosse_tx141thbv2,
&ws_protocol_oregon2,
&ws_protocol_acurite_592txr,
@@ -6,6 +6,7 @@
#include "nexus_th.h"
#include "gt_wt_03.h"
#include "acurite_606tx.h"
#include "acurite_609txc.h"
#include "lacrosse_tx141thbv2.h"
#include "oregon2.h"
#include "acurite_592txr.h"
@@ -246,7 +246,7 @@ void ws_protocol_decoder_thermopro_tx4_get_string(void* context, FuriString* out
"%s %dbit\r\n"
"Key:0x%lX%08lX\r\n"
"Sn:0x%lX Ch:%d Bat:%d\r\n"
"Temp:%d.%d C Hum:%d%%",
"Temp:%3.1f C Hum:%d%%",
instance->generic.protocol_name,
instance->generic.data_count_bit,
(uint32_t)(instance->generic.data >> 32),
@@ -254,7 +254,6 @@ void ws_protocol_decoder_thermopro_tx4_get_string(void* context, FuriString* out
instance->generic.id,
instance->generic.channel,
instance->generic.battery_low,
(int16_t)instance->generic.temp,
abs(((int16_t)(instance->generic.temp * 10) - (((int16_t)instance->generic.temp) * 10))),
(double)instance->generic.temp,
instance->generic.humidity);
}
@@ -75,12 +75,7 @@ void ws_view_receiver_info_draw(Canvas* canvas, WSReceiverInfoModel* model) {
if(model->generic->temp != WS_NO_TEMPERATURE) {
canvas_draw_icon(canvas, 18, 42, &I_Therm_7x16);
snprintf(
buffer,
sizeof(buffer),
"%3.2d.%d C",
(int16_t)model->generic->temp,
abs(((int16_t)(model->generic->temp * 10) - (((int16_t)model->generic->temp) * 10))));
snprintf(buffer, sizeof(buffer), "%3.1f C", (double)model->generic->temp);
canvas_draw_str_aligned(canvas, 63, 46, AlignRight, AlignTop, buffer);
canvas_draw_circle(canvas, 55, 45, 1);
}
+19 -14
View File
@@ -61,15 +61,20 @@ static void gpio_print_pins(void) {
}
}
typedef enum { OK, ERR_CMD_SYNTAX, ERR_PIN, ERR_VALUE } GpioParseError;
typedef enum {
GpioParseReturnOk,
GpioParseReturnCmdSyntaxError,
GpioParseReturnPinError,
GpioParseReturnValueError
} GpioParseReturn;
static GpioParseError gpio_command_parse(FuriString* args, size_t* pin_num, uint8_t* value) {
static GpioParseReturn gpio_command_parse(FuriString* args, size_t* pin_num, uint8_t* value) {
FuriString* pin_name;
pin_name = furi_string_alloc();
size_t ws = furi_string_search_char(args, ' ');
if(ws == FURI_STRING_FAILURE) {
return ERR_CMD_SYNTAX;
return GpioParseReturnCmdSyntaxError;
}
furi_string_set_n(pin_name, args, 0, ws);
@@ -78,7 +83,7 @@ static GpioParseError gpio_command_parse(FuriString* args, size_t* pin_num, uint
if(!pin_name_to_int(pin_name, pin_num)) {
furi_string_free(pin_name);
return ERR_PIN;
return GpioParseReturnPinError;
}
furi_string_free(pin_name);
@@ -88,10 +93,10 @@ static GpioParseError gpio_command_parse(FuriString* args, size_t* pin_num, uint
} else if(!furi_string_cmp(args, "1")) {
*value = 1;
} else {
return ERR_VALUE;
return GpioParseReturnValueError;
}
return OK;
return GpioParseReturnOk;
}
void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
@@ -101,15 +106,15 @@ void cli_command_gpio_mode(Cli* cli, FuriString* args, void* context) {
size_t num = 0;
uint8_t value = 255;
GpioParseError err = gpio_command_parse(args, &num, &value);
GpioParseReturn err = gpio_command_parse(args, &num, &value);
if(ERR_CMD_SYNTAX == err) {
if(err == GpioParseReturnCmdSyntaxError) {
cli_print_usage("gpio mode", "<pin_name> <0|1>", furi_string_get_cstr(args));
return;
} else if(ERR_PIN == err) {
} else if(err == GpioParseReturnPinError) {
gpio_print_pins();
return;
} else if(ERR_VALUE == err) {
} else if(err == GpioParseReturnValueError) {
printf("Value is invalid. Enter 1 for input or 0 for output");
return;
}
@@ -161,15 +166,15 @@ void cli_command_gpio_set(Cli* cli, FuriString* args, void* context) {
size_t num = 0;
uint8_t value = 0;
GpioParseError err = gpio_command_parse(args, &num, &value);
GpioParseReturn err = gpio_command_parse(args, &num, &value);
if(ERR_CMD_SYNTAX == err) {
if(err == GpioParseReturnCmdSyntaxError) {
cli_print_usage("gpio set", "<pin_name> <0|1>", furi_string_get_cstr(args));
return;
} else if(ERR_PIN == err) {
} else if(err == GpioParseReturnPinError) {
gpio_print_pins();
return;
} else if(ERR_VALUE == err) {
} else if(err == GpioParseReturnValueError) {
printf("Value is invalid. Enter 1 for high or 0 for low");
return;
}
+79 -17
View File
@@ -7,6 +7,7 @@
#include <time.h>
#include <notification/notification_messages.h>
#include <loader/loader.h>
#include <lib/toolbox/args.h>
// Close to ISO, `date +'%Y-%m-%d %H:%M:%S %u'`
#define CLI_DATE_FORMAT "%.4d-%.2d-%.2d %.2d:%.2d:%.2d %d"
@@ -192,6 +193,83 @@ void cli_command_log(Cli* cli, FuriString* args, void* context) {
furi_stream_buffer_free(ring);
}
void cli_command_sysctl_debug(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
UNUSED(context);
if(!furi_string_cmp(args, "0")) {
furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
loader_update_menu();
printf("Debug disabled.");
} else if(!furi_string_cmp(args, "1")) {
furi_hal_rtc_set_flag(FuriHalRtcFlagDebug);
loader_update_menu();
printf("Debug enabled.");
} else {
cli_print_usage("sysctl debug", "<1|0>", furi_string_get_cstr(args));
}
}
void cli_command_sysctl_heap_track(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
UNUSED(context);
if(!furi_string_cmp(args, "none")) {
furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeNone);
printf("Heap tracking disabled");
} else if(!furi_string_cmp(args, "main")) {
furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeMain);
printf("Heap tracking enabled for application main thread");
#if FURI_DEBUG
} else if(!furi_string_cmp(args, "tree")) {
furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeTree);
printf("Heap tracking enabled for application main and child threads");
} else if(!furi_string_cmp(args, "all")) {
furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackModeAll);
printf("Heap tracking enabled for all threads");
#endif
} else {
cli_print_usage("sysctl heap_track", "<none|main|tree|all>", furi_string_get_cstr(args));
}
}
void cli_command_sysctl_print_usage() {
printf("Usage:\r\n");
printf("sysctl <cmd> <args>\r\n");
printf("Cmd list:\r\n");
printf("\tdebug <0|1>\t - Enable or disable system debug\r\n");
#if FURI_DEBUG
printf("\theap_track <none|main|tree|all>\t - Set heap allocation tracking mode\r\n");
#else
printf("\theap_track <none|main>\t - Set heap allocation tracking mode\r\n");
#endif
}
void cli_command_sysctl(Cli* cli, FuriString* args, void* context) {
FuriString* cmd;
cmd = furi_string_alloc();
do {
if(!args_read_string_and_trim(args, cmd)) {
cli_command_sysctl_print_usage();
break;
}
if(furi_string_cmp_str(cmd, "debug") == 0) {
cli_command_sysctl_debug(cli, args, context);
break;
}
if(furi_string_cmp_str(cmd, "heap_track") == 0) {
cli_command_sysctl_heap_track(cli, args, context);
break;
}
cli_command_sysctl_print_usage();
} while(false);
furi_string_free(cmd);
}
void cli_command_vibro(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
UNUSED(context);
@@ -208,22 +286,6 @@ void cli_command_vibro(Cli* cli, FuriString* args, void* context) {
}
}
void cli_command_debug(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
UNUSED(context);
if(!furi_string_cmp(args, "0")) {
furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
loader_update_menu();
printf("Debug disabled.");
} else if(!furi_string_cmp(args, "1")) {
furi_hal_rtc_set_flag(FuriHalRtcFlagDebug);
loader_update_menu();
printf("Debug enabled.");
} else {
cli_print_usage("debug", "<1|0>", furi_string_get_cstr(args));
}
}
void cli_command_led(Cli* cli, FuriString* args, void* context) {
UNUSED(cli);
UNUSED(context);
@@ -356,7 +418,7 @@ void cli_commands_init(Cli* cli) {
cli_add_command(cli, "date", CliCommandFlagParallelSafe, cli_command_date, NULL);
cli_add_command(cli, "log", CliCommandFlagParallelSafe, cli_command_log, NULL);
cli_add_command(cli, "debug", CliCommandFlagDefault, cli_command_debug, NULL);
cli_add_command(cli, "sysctl", CliCommandFlagDefault, cli_command_sysctl, NULL);
cli_add_command(cli, "ps", CliCommandFlagParallelSafe, cli_command_ps, NULL);
cli_add_command(cli, "free", CliCommandFlagParallelSafe, cli_command_free, NULL);
cli_add_command(cli, "free_blocks", CliCommandFlagParallelSafe, cli_command_free_blocks, NULL);
+2 -2
View File
@@ -103,7 +103,7 @@ static int32_t vcp_worker(void* context) {
while(1) {
uint32_t flags =
furi_thread_flags_wait(VCP_THREAD_FLAG_ALL, FuriFlagWaitAny, FuriWaitForever);
furi_assert((flags & FuriFlagError) == 0);
furi_assert(!(flags & FuriFlagError));
// VCP session opened
if(flags & VcpEvtConnect) {
@@ -303,7 +303,7 @@ static void vcp_on_cdc_control_line(void* context, uint8_t state) {
static void vcp_on_cdc_rx(void* context) {
UNUSED(context);
uint32_t ret = furi_thread_flags_set(furi_thread_get_id(vcp->thread), VcpEvtRx);
furi_check((ret & FuriFlagError) == 0);
furi_check(!(ret & FuriFlagError));
}
static void vcp_on_cdc_tx_complete(void* context) {
+2 -2
View File
@@ -167,7 +167,7 @@ void crypto_cli_decrypt(Cli* cli, FuriString* args) {
void crypto_cli_has_key(Cli* cli, FuriString* args) {
UNUSED(cli);
int key_slot = 0;
uint8_t iv[16];
uint8_t iv[16] = {0};
do {
if(!args_read_int_and_trim(args, &key_slot) || !(key_slot > 0 && key_slot <= 100)) {
@@ -249,7 +249,7 @@ void crypto_cli_store_key(Cli* cli, FuriString* args) {
}
if(key_slot > 0) {
uint8_t iv[16];
uint8_t iv[16] = {0};
if(key_slot > 1) {
if(!furi_hal_crypto_store_load_key(key_slot - 1, iv)) {
printf(
@@ -45,6 +45,13 @@ static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* fl
return;
}
FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode();
if(mode > FuriHalRtcHeapTrackModeNone) {
furi_thread_enable_heap_trace(desktop->scene_thread);
} else {
furi_thread_disable_heap_trace(desktop->scene_thread);
}
furi_thread_set_name(desktop->scene_thread, flipper_app->name);
furi_thread_set_stack_size(desktop->scene_thread, flipper_app->stack_size);
furi_thread_set_callback(desktop->scene_thread, flipper_app->app);
+1 -1
View File
@@ -436,7 +436,7 @@ void gui_add_framebuffer_callback(Gui* gui, GuiCanvasCommitCallback callback, vo
const CanvasCallbackPair p = {callback, context};
gui_lock(gui);
furi_assert(CanvasCallbackPairArray_count(gui->canvas_callback_pair, p) == 0);
furi_assert(!CanvasCallbackPairArray_count(gui->canvas_callback_pair, p));
CanvasCallbackPairArray_push_back(gui->canvas_callback_pair, p);
gui_unlock(gui);
@@ -359,7 +359,7 @@ static int32_t browser_worker(void* context) {
BrowserWorker*
file_browser_worker_alloc(FuriString* path, const char* filter_ext, bool skip_assets) {
BrowserWorker* browser = malloc(sizeof(BrowserWorker));
BrowserWorker* browser = malloc(sizeof(BrowserWorker)); //-V773
idx_last_array_init(browser->idx_last);
@@ -60,7 +60,7 @@ WidgetElement* widget_element_button_create(
ButtonCallback callback,
void* context) {
// Allocate and init model
GuiButtonModel* model = malloc(sizeof(GuiButtonModel));
GuiButtonModel* model = malloc(sizeof(GuiButtonModel)); //-V773
model->button_type = button_type;
model->callback = callback;
model->context = context;
+2 -2
View File
@@ -23,7 +23,7 @@ void view_dispatcher_free(ViewDispatcher* view_dispatcher) {
gui_remove_view_port(view_dispatcher->gui, view_dispatcher->view_port);
}
// Crash if not all views were freed
furi_assert(ViewDict_size(view_dispatcher->views) == 0);
furi_assert(!ViewDict_size(view_dispatcher->views));
ViewDict_clear(view_dispatcher->views);
// Free ViewPort
@@ -157,7 +157,7 @@ void view_dispatcher_remove_view(ViewDispatcher* view_dispatcher, uint32_t view_
view_dispatcher->ongoing_input_view = NULL;
}
// Remove view
ViewDict_erase(view_dispatcher->views, view_id);
furi_check(ViewDict_erase(view_dispatcher->views, view_id));
view_set_update_callback(view, NULL);
view_set_update_callback_context(view, NULL);
+19 -1
View File
@@ -1,5 +1,7 @@
#include "input_i.h"
// #define INPUT_DEBUG
#define GPIO_Read(input_pin) (furi_hal_gpio_read(input_pin.pin->gpio) ^ (input_pin.pin->inverted))
static Input* input = NULL;
@@ -72,6 +74,10 @@ int32_t input_srv(void* p) {
input->event_pubsub = furi_pubsub_alloc();
furi_record_create(RECORD_INPUT_EVENTS, input->event_pubsub);
#if INPUT_DEBUG
furi_hal_gpio_init_simple(&gpio_ext_pa4, GpioModeOutputPushPull);
#endif
#ifdef SRV_CLI
input->cli = furi_record_open(RECORD_CLI);
if(input->cli) {
@@ -95,10 +101,16 @@ int32_t input_srv(void* p) {
bool is_changing = false;
for(size_t i = 0; i < input_pins_count; i++) {
bool state = GPIO_Read(input->pin_states[i]);
if(state) {
if(input->pin_states[i].debounce < INPUT_DEBOUNCE_TICKS)
input->pin_states[i].debounce += 1;
} else {
if(input->pin_states[i].debounce > 0) input->pin_states[i].debounce -= 1;
}
if(input->pin_states[i].debounce > 0 &&
input->pin_states[i].debounce < INPUT_DEBOUNCE_TICKS) {
is_changing = true;
input->pin_states[i].debounce += (state ? 1 : -1);
} else if(input->pin_states[i].state != state) {
input->pin_states[i].state = state;
@@ -129,8 +141,14 @@ int32_t input_srv(void* p) {
}
if(is_changing) {
#if INPUT_DEBUG
furi_hal_gpio_write(&gpio_ext_pa4, 1);
#endif
furi_delay_tick(1);
} else {
#if INPUT_DEBUG
furi_hal_gpio_write(&gpio_ext_pa4, 0);
#endif
furi_thread_flags_wait(INPUT_THREAD_FLAG_ISR, FuriFlagWaitAny, FuriWaitForever);
}
}
+11 -8
View File
@@ -21,6 +21,13 @@ static bool
FURI_LOG_I(TAG, "Starting: %s", loader_instance->application->name);
FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode();
if(mode > FuriHalRtcHeapTrackModeNone) {
furi_thread_enable_heap_trace(loader_instance->application_thread);
} else {
furi_thread_disable_heap_trace(loader_instance->application_thread);
}
furi_thread_set_name(loader_instance->application_thread, loader_instance->application->name);
furi_thread_set_stack_size(
loader_instance->application_thread, loader_instance->application->stack_size);
@@ -269,22 +276,18 @@ static void loader_thread_state_callback(FuriThreadState thread_state, void* con
event.type = LoaderEventTypeApplicationStarted;
furi_pubsub_publish(loader_instance->pubsub, &event);
if(!loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe) {
if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) {
furi_hal_power_insomnia_enter();
}
} else if(thread_state == FuriThreadStateStopped) {
FURI_LOG_I(
TAG,
"Application thread stopped. Free heap: %d. Thread allocation balance: %d.",
memmgr_get_free_heap(),
furi_thread_get_heap_size(instance->application_thread));
FURI_LOG_I(TAG, "Application stopped. Free heap: %d", memmgr_get_free_heap());
if(loader_instance->application_arguments) {
free(loader_instance->application_arguments);
loader_instance->application_arguments = NULL;
}
if(!loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe) {
if(!(loader_instance->application->flags & FlipperApplicationFlagInsomniaSafe)) {
furi_hal_power_insomnia_exit();
}
loader_unlock(instance);
@@ -310,7 +313,7 @@ static Loader* loader_alloc() {
Loader* instance = malloc(sizeof(Loader));
instance->application_thread = furi_thread_alloc();
furi_thread_enable_heap_trace(instance->application_thread);
furi_thread_set_state_context(instance->application_thread, instance);
furi_thread_set_state_callback(instance->application_thread, loader_thread_state_callback);
+1 -1
View File
@@ -372,7 +372,7 @@ RpcSession* rpc_session_open(Rpc* rpc) {
session->thread = furi_thread_alloc();
furi_thread_set_name(session->thread, "RpcSessionWorker");
furi_thread_set_stack_size(session->thread, 2048);
furi_thread_set_stack_size(session->thread, 3072);
furi_thread_set_context(session->thread, session);
furi_thread_set_callback(session->thread, rpc_session_worker);
+2 -2
View File
@@ -275,7 +275,7 @@ static void storage_cli_read_chunks(Cli* cli, FuriString* path, FuriString* args
uint32_t buffer_size;
int parsed_count = sscanf(furi_string_get_cstr(args), "%lu", &buffer_size);
if(parsed_count == EOF || parsed_count != 1) {
if(parsed_count != 1) {
storage_cli_print_usage();
} else if(storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
uint64_t file_size = storage_file_size(file);
@@ -315,7 +315,7 @@ static void storage_cli_write_chunk(Cli* cli, FuriString* path, FuriString* args
uint32_t buffer_size;
int parsed_count = sscanf(furi_string_get_cstr(args), "%lu", &buffer_size);
if(parsed_count == EOF || parsed_count != 1) {
if(parsed_count != 1) {
storage_cli_print_usage();
} else {
if(storage_file_open(file, furi_string_get_cstr(path), FSAM_WRITE, FSOM_OPEN_APPEND)) {
@@ -545,8 +545,8 @@ static FS_Error
FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path) {
FS_Error error;
const char* new_path_tmp;
FuriString* new_path_next;
const char* new_path_tmp = NULL;
FuriString* new_path_next = NULL;
new_path_next = furi_string_alloc();
FileInfo fileinfo;
@@ -45,6 +45,31 @@ static void debug_changed(VariableItem* item) {
loader_update_menu();
}
const char* const heap_trace_mode_text[] = {
"None",
"Main",
#if FURI_DEBUG
"Tree",
"All",
#endif
};
const uint32_t heap_trace_mode_value[] = {
FuriHalRtcHeapTrackModeNone,
FuriHalRtcHeapTrackModeMain,
#if FURI_DEBUG
FuriHalRtcHeapTrackModeTree,
FuriHalRtcHeapTrackModeAll,
#endif
};
static void heap_trace_mode_changed(VariableItem* item) {
// SystemSettings* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, heap_trace_mode_text[index]);
furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[index]);
}
static uint32_t system_settings_exit(void* context) {
UNUSED(context);
return VIEW_NONE;
@@ -79,6 +104,18 @@ SystemSettings* system_settings_alloc() {
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, debug_text[value_index]);
item = variable_item_list_add(
app->var_item_list,
"Heap Trace",
COUNT_OF(heap_trace_mode_text),
heap_trace_mode_changed,
app);
value_index = value_index_uint32(
furi_hal_rtc_get_heap_track_mode(), heap_trace_mode_value, COUNT_OF(heap_trace_mode_text));
furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[value_index]);
variable_item_set_current_value_index(item, value_index);
variable_item_set_current_value_text(item, heap_trace_mode_text[value_index]);
view_set_previous_callback(
variable_item_list_get_view(app->var_item_list), system_settings_exit);
view_dispatcher_add_view(
@@ -0,0 +1,105 @@
Filetype: IR tests file
Version: 1
#
name: decoder_input1
type: raw
data: 1000000 3363 1685 407 436 411 432 415 1240 434 410 437 1245 439 404 433 1249 435 408 439 431 406 1249 435 435 412 405 442 1241 433 1249 435 408 439 405 442 428 409 434 413 430 407 411 436 433 414 429 408 1248 436 407 440 1243 441 428 409 434 413 431 406 1249 435 1248 436 406 441 1242 442 1240 434 409 438 431 416 428 409 408 439 430 407 411 436 407 440 429 408 436 411 432 415 402 435 1247 437 1245 439 1243 441 1238 436
#
name: decoder_expected1
type: parsed_array
count: 1
#
protocol: Kaseikyo
address: 41 54 32 00
command: 1B 00 00 00
repeat: false
#
name: decoder_input2
type: raw
data: 1000000 3365 1683 409 434 413 431 406 1276 408 435 412 1270 414 429 408 1248 436 434 413 430 407 1275 409 434 413 431 406 1276 408 1248 436 433 414 430 407 437 410 433 414 429 408 436 411 432 415 428 409 1246 438 432 415 1267 407 437 410 433 414 429 408 436 411 432 415 1266 408 1250 434 1248 436 432 415 429 408 435 412 432 415 428 409 434 413 430 407 437 410 433 414 429 408 436 411 432 415 428 409 435 412 1240 434
#
name: decoder_expected2
type: parsed_array
count: 1
#
protocol: Kaseikyo
address: 41 54 32 00
command: 1C 00 00 00
repeat: false
#
name: decoder_input3
type: raw
data: 1000000 3361 1661 442 427 410 434 413 1243 441 428 409 1247 437 432 415 1241 433 410 437 407 440 1242 432 437 410 407 440 1242 442 1241 433 436 411 407 440 430 407 436 411 406 441 402 435 435 412 431 416 1240 434 410 437 1245 439 404 433 411 436 407 440 403 434 436 411 432 415 429 408 1249 435 1247 437 1245 439 430 407 1250 434 434 413 404 433 438 409 434 413 1243 441 1241 433 410 437 1245 439 430 407 1250 434 432 415
#
name: decoder_expected3
type: parsed_array
count: 1
#
protocol: Kaseikyo
address: 41 54 32 00
command: 70 01 00 00
repeat: false
#
name: decoder_input4
type: raw
data: 1000000 3365 1656 436 406 441 402 435 1248 436 406 441 1242 432 410 437 1246 438 404 433 410 437 1246 438 404 433 437 410 1245 491 1190 442 401 436 435 412 431 416 427 410 433 414 429 408 435 412 431 416 1240 434 435 412 1244 440 1241 433 436 411 433 414 402 435 409 438 405 442 402 435 1247 437 1244 440 1241 433 437 410 1245 439 430 407 410 437 406 441 402 435 409 438 1243 441 402 435 1247 437 406 441 1240 434 433 414
#
name: decoder_expected4
type: parsed_array
count: 1
#
protocol: Kaseikyo
address: 43 54 32 00
command: 70 01 00 00
repeat: false
#
name: decoder_input5
type: raw
data: 1000000 3357 1665 438 431 416 428 409 1247 437 432 415 1241 433 436 411 1245 439 430 407 436 411 1245 439 430 407 437 410 1246 438 1243 441 428 409 436 411 432 415 428 409 435 412 431 416 427 410 434 413 1243 441 427 410 1247 437 1245 439 430 407 437 410 1246 438 1244 440 429 408 1250 434 1248 488 355 440 429 408 436 411 432 415 428 408 435 412 431 416 428 409 1247 437 432 415 428 409 1248 436 1246 490 1191 441 1240 434
#
name: decoder_expected5
type: parsed_array
count: 1
#
protocol: Kaseikyo
address: 43 54 32 00
command: 1B 00 00 00
repeat: false
#
name: decoder_input6
type: raw
data: 1000000 3358 1664 439 430 407 437 410 1245 439 430 407 1250 434 434 413 1243 441 428 409 435 412 1244 440 428 409 435 412 1244 440 1242 432 437 410 434 413 430 407 436 411 432 415 428 409 435 412 431 416 1240 434 435 412 1244 440 1242 442 427 410 434 413 1243 441 427 409 1247 437 433 414 429 408 436 411 432 415 428 409 435 412 431 416 427 410 434 413 1243 441 1240 486 357 438 432 415 1240 434 436 411 432 415 425 412
#
name: decoder_expected6
type: parsed_array
count: 1
#
protocol: Kaseikyo
address: 43 54 32 00
command: 05 00 00 00
repeat: false
#
name: encoder_decoder_input1
type: parsed_array
count: 4
#
protocol: Kaseikyo
address: 41 54 32 00
command: 1B 00 00 00
repeat: false
#
protocol: Kaseikyo
address: 41 54 32 00
command: 70 01 00 00
repeat: false
#
protocol: Kaseikyo
address: 43 54 32 00
command: 05 00 00 00
repeat: false
#
protocol: Kaseikyo
address: 43 54 32 00
command: 1B 00 00 00
repeat: false
#
+35 -11
View File
@@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import Tuple, Dict
from typing import Optional, Tuple, Dict, ClassVar
import struct
import posixpath
import os
@@ -22,14 +22,18 @@ class AppState:
debug_link_elf: str = ""
debug_link_crc: int = 0
DEBUG_ELF_ROOT: ClassVar[Optional[str]] = None
def __post_init__(self):
if self.other_sections is None:
self.other_sections = {}
def get_original_elf_path(self, elf_path="build/latest/.extapps") -> str:
def get_original_elf_path(self) -> str:
if self.DEBUG_ELF_ROOT is None:
raise ValueError("DEBUG_ELF_ROOT not set; call fap-set-debug-elf-root")
return (
posixpath.join(elf_path, self.debug_link_elf)
if elf_path
posixpath.join(self.DEBUG_ELF_ROOT, self.debug_link_elf)
if self.DEBUG_ELF_ROOT
else self.debug_link_elf
)
@@ -84,7 +88,9 @@ class AppState:
if debug_link_size := int(app_state["debug_link_info"]["debug_link_size"]):
debug_link_data = (
gdb.selected_inferior()
.read_memory(int(app_state["debug_link_info"]["debug_link"]), debug_link_size)
.read_memory(
int(app_state["debug_link_info"]["debug_link"]), debug_link_size
)
.tobytes()
)
state.debug_link_elf, state.debug_link_crc = AppState.parse_debug_link_data(
@@ -103,6 +109,29 @@ class AppState:
return state
class SetFapDebugElfRoot(gdb.Command):
"""Set path to original ELF files for debug info"""
def __init__(self):
super().__init__(
"fap-set-debug-elf-root", gdb.COMMAND_FILES, gdb.COMPLETE_FILENAME
)
self.dont_repeat()
def invoke(self, arg, from_tty):
AppState.DEBUG_ELF_ROOT = arg
try:
global helper
print(f"Set '{arg}' as debug info lookup path for Flipper external apps")
helper.attach_fw()
gdb.events.stop.connect(helper.handle_stop)
except gdb.error as e:
print(f"Support for Flipper external apps debug is not available: {e}")
SetFapDebugElfRoot()
class FlipperAppDebugHelper:
def __init__(self):
self.app_ptr = None
@@ -149,9 +178,4 @@ class FlipperAppDebugHelper:
helper = FlipperAppDebugHelper()
try:
helper.attach_fw()
print("Support for Flipper external apps debug is enabled")
gdb.events.stop.connect(helper.handle_stop)
except gdb.error as e:
print(f"Support for Flipper external apps debug is not available: {e}")
print("Support for Flipper external apps debug is loaded")
+2
View File
@@ -0,0 +1,2 @@
/html
/latex
+1
View File
@@ -40,6 +40,7 @@ Only 2 parameters are mandatory: ***appid*** and ***apptype***, others are optio
* **icon**: Animated icon name from built-in assets to be used when building app as a part of firmware.
* **order**: Order of an application within its group when sorting entries in it. The lower the order is, the closer to the start of the list the item is placed. *Used for ordering startup hooks and menu entries.*
* **sdk_headers**: List of C header files from this app's code to include in API definitions for external applications.
* **targets**: list of strings, target names, which this application is compatible with. If not specified, application is built for all targets. Default value is `["all"]`.
#### Parameters for external applications
+15 -7
View File
@@ -872,12 +872,9 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched.
INPUT = applications \
core \
lib/infrared \
lib/subghz \
lib/toolbox \
lib/onewire \
firmware/targets/furi_hal_include
lib \
firmware \
furi
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@@ -930,7 +927,18 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE =
EXCLUDE = \
lib/mlib \
lib/STM32CubeWB \
lib/littlefs \
lib/nanopb \
assets/protobuf \
lib/libusb_stm32 \
lib/FreeRTOS-Kernel \
lib/microtar \
lib/mbedtls \
lib/cxxheaderparser \
applications/plugins/dap_link/lib/free-dap
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
+11 -11
View File
@@ -1,7 +1,7 @@
# Key Combos
There are times when your flipper feels blue and don't respond to your commands.
In that case you may find this guide useful.
There are times when your flipper feels blue and doesn't respond to your commands.
In that case, you may find this guide useful.
## Basic Combos
@@ -9,7 +9,7 @@ In that case you may find this guide useful.
### Hardware Reset
- Press `LEFT` and `BACK` and hold for couple seconds
- Press `LEFT` and `BACK` and hold for a couple of seconds
- Release `LEFT` and `BACK`
This combo performs hardware reset by pulling MCU reset line down.
@@ -29,7 +29,7 @@ There is 1 case when it's not working:
- If you have not disconnected USB, then disconnect USB and repeat previous step
- Release `BACK` key
This combo performs reset by switching SYS power line off and then on.
This combo performs a reset by switching SYS power line off and then on.
Main components involved: Keys -> DD6(bq25896, charger)
There is 1 case when it's not working:
@@ -60,13 +60,13 @@ There is 1 case when it's not working:
### Hardware Reset + Software DFU
- Press `LEFT` and `BACK` and hold for couple seconds
- Press `LEFT` and `BACK` and hold for a couple of seconds
- Release `BACK`
- Device will enter DFU with indication (Blue LED + DFU Screen)
- Release `LEFT`
This combo performs hardware reset by pulling MCU reset line down.
Then `LEFT` key indicates to boot-loader that DFU mode requested.
Then `LEFT` key indicates to boot-loader that DFU mode is requested.
There are 2 cases when it's not working:
@@ -76,7 +76,7 @@ There are 2 cases when it's not working:
### Hardware Reset + Hardware DFU
- Press `LEFT` and `BACK` and `OK` and hold for couple seconds
- Press `LEFT` and `BACK` and `OK` and hold for a couple of seconds
- Release `BACK` and `LEFT`
- Device will enter DFU without indication
@@ -127,8 +127,8 @@ There are 2 cases when it's not working:
If none of the described methods were useful:
- Ensure battery charged
- Disconnect battery and connect again (Requires disassembly)
- Try to Flash device with ST-Link or other programmer that support SWD
- Ensure the battery charged
- Disconnect the battery and connect again (Requires disassembly)
- Try to Flash device with ST-Link or other programmer that supports SWD
If you still here and your device is not working: it's not software issue.
If you still here and your device is not working: it's not a software issue.
+49
View File
@@ -0,0 +1,49 @@
# Unit tests
## Intro
Unit tests are special pieces of code that apply known inputs to the feature code and check the results to see if they were correct.
They are crucial for writing robust, bug-free code.
Flipper Zero firmware includes a separate application called [unit_tests](/applications/debug/unit_tests).
It is run directly on the Flipper Zero in order to employ its hardware features and to rule out any platform-related differences.
When contributing code to the Flipper Zero firmware, it is highly desirable to supply unit tests along with the proposed features.
Running existing unit tests is useful to ensure that the new code doesn't introduce any regressions.
## Running unit tests
In order to run the unit tests, follow these steps:
1. Compile the firmware with the tests enabled: `./fbt FIRMWARE_APP_SET=unit_tests`.
2. Flash the firmware using your preferred method.
3. Copy the [assets/unit_tests](assets/unit_tests) folder to the root your Flipper Zero's SD card.
4. Launch the CLI session and run the `unit_tests` command.
**NOTE:** To run a particular test (and skip all others), specify its name as the command argument.
See [test_index.c](applications/debug/unit_tests/test_index.c) for the complete list of test names.
## Adding unit tests
### General
#### Entry point
The common entry point for all tests it the [unit_tests](applications/debug/unit_tests) application. Test-specific code is placed into an arbitrarily named subdirectory and is then called from the [test_index.c](applications/debug/unit_tests/test_index.c) source file.
#### Test assets
Some unit tests require external data in order to function. These files (commonly called assets) reside in the [assets/unit_tests](/assets/unit_tests) directory in their respective subdirectories. Asset files can be of any type (plain text, FlipperFormat(FFF), binary etc).
### Application-specific
#### Infrared
Each infrared protocol has a corresponding set of unit tests, so it makes sense to implement one when adding support for a new protocol.
In order to add unit tests for your protocol, follow these steps:
1. Create a file named `test_<your_protocol_name>.irtest` in the [assets](assets/unit_tests/infrared) directory.
2. Fill it with the test data (more on it below).
3. Add the test code to [infrared_test.c](applications/debug/unit_tests/infrared/infrared_test.c).
4. Update the [assets](assets/unit_tests/infrared) on your Flipper Zero and run the tests to see if they pass.
##### Test data format
Each unit test has 3 sections:
1. `decoder` - takes in raw signal and outputs decoded messages.
2. `encoder` - takes in decoded messages and outputs raw signal.
3. `encoder_decoder` - takes in decoded messages, turns them into raw signal and then decodes again.
Infrared test asset files have an `.irtest` extension and are regular `.ir` files with a few additions.
Decoder input data has signal names `decoder_input_N`, where N is a test sequence number. Expected data goes under the name `decoder_expected_N`. When testing the encoder these two are switched.
Decoded data is represented in arrays (since a single raw signal may decode to several messages). If there is only one signal, then it has to be an array of size 1. Use the existing files as syntax examples.
##### Getting raw signals
Recording raw IR signals is possible using Flipper Zero. Launch the CLI session, run `ir rx raw`, then point the remote towards Flipper's receiver and send the signals. The raw signal data will be printed to the console in a convenient format.
+3 -2
View File
@@ -49,12 +49,12 @@ OPENOCD_OPTS = [
"-c",
"transport select hla_swd",
"-f",
"debug/stm32wbx.cfg",
"${FBT_DEBUG_DIR}/stm32wbx.cfg",
"-c",
"stm32wbx.cpu configure -rtos auto",
]
SVD_FILE = "debug/STM32WB55_CM4.svd"
SVD_FILE = "${FBT_DEBUG_DIR}/STM32WB55_CM4.svd"
# Look for blackmagic probe on serial ports and local network
BLACKMAGIC = "auto"
@@ -81,6 +81,7 @@ FIRMWARE_APPS = {
"basic_services",
"updater_app",
"unit_tests",
"nfc",
],
}
+14 -10
View File
@@ -20,10 +20,9 @@ env = ENV.Clone(
BUILD_DIR=fw_build_meta["build_dir"],
IS_BASE_FIRMWARE=fw_build_meta["type"] == "firmware",
FW_FLAVOR=fw_build_meta["flavor"],
PLUGIN_ELF_DIR="${BUILD_DIR}",
LIB_DIST_DIR="${BUILD_DIR}/lib",
LIB_DIST_DIR=fw_build_meta["build_dir"].Dir("lib"),
LINT_SOURCES=[
"applications",
Dir("applications"),
],
LIBPATH=[
"${LIB_DIST_DIR}",
@@ -41,11 +40,11 @@ env = ENV.Clone(
FW_LIB_OPTS={
"Default": {
"CCFLAGS": [
"-Os",
"-Og" if ENV["LIB_DEBUG"] else "-Os",
],
"CPPDEFINES": [
"NDEBUG",
"FURI_NDEBUG",
"FURI_DEBUG" if ENV["LIB_DEBUG"] else "FURI_NDEBUG",
],
# You can add other entries named after libraries
# If they are present, they have precedence over Default
@@ -142,12 +141,14 @@ for app_dir, _ in env["APPDIRS"]:
fwenv.PrepareApplicationsBuild()
# Build external apps
# Build external apps + configure SDK
if env["IS_BASE_FIRMWARE"]:
extapps = fwenv["FW_EXTAPPS"] = SConscript(
"site_scons/extapps.scons", exports={"ENV": fwenv}
fwenv.SetDefault(FBT_FAP_DEBUG_ELF_ROOT="${BUILD_DIR}/.extapps")
fwenv["FW_EXTAPPS"] = SConscript(
"site_scons/extapps.scons",
exports={"ENV": fwenv},
)
fw_artifacts.append(extapps["sdk_tree"])
fw_artifacts.append(fwenv["FW_EXTAPPS"].sdk_tree)
# Add preprocessor definitions for current set of apps
@@ -263,7 +264,10 @@ fw_artifacts.extend(
fwcdb = fwenv.CompilationDatabase()
# without filtering, both updater & firmware commands would be generated in same file
fwenv.Replace(COMPILATIONDB_PATH_FILTER=fwenv.subst("*${FW_FLAVOR}*"))
fwenv.Replace(
COMPILATIONDB_PATH_FILTER=fwenv.subst("*${FW_FLAVOR}*"),
COMPILATIONDB_SRCPATH_FILTER="*.c*",
)
AlwaysBuild(fwcdb)
Precious(fwcdb)
NoClean(fwcdb)
+1 -1
View File
@@ -1,7 +1,7 @@
Import("env")
env.Append(
LINT_SOURCES=["firmware"],
LINT_SOURCES=[Dir(".")],
SDK_HEADERS=[
*env.GlobRecursive("*.h", "targets/furi_hal_include", "*_i.h"),
*env.GlobRecursive("*.h", "targets/f${TARGET_HW}/furi_hal", "*_i.h"),
+4 -1
View File
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,7.3,,
Version,+,7.5,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
@@ -1260,6 +1260,7 @@ Function,+,furi_hal_rtc_deinit_early,void,
Function,+,furi_hal_rtc_get_boot_mode,FuriHalRtcBootMode,
Function,+,furi_hal_rtc_get_datetime,void,FuriHalRtcDateTime*
Function,+,furi_hal_rtc_get_fault_data,uint32_t,
Function,+,furi_hal_rtc_get_heap_track_mode,FuriHalRtcHeapTrackMode,
Function,+,furi_hal_rtc_get_log_level,uint8_t,
Function,+,furi_hal_rtc_get_pin_fails,uint32_t,
Function,+,furi_hal_rtc_get_register,uint32_t,FuriHalRtcRegister
@@ -1272,6 +1273,7 @@ Function,+,furi_hal_rtc_set_boot_mode,void,FuriHalRtcBootMode
Function,+,furi_hal_rtc_set_datetime,void,FuriHalRtcDateTime*
Function,+,furi_hal_rtc_set_fault_data,void,uint32_t
Function,+,furi_hal_rtc_set_flag,void,FuriHalRtcFlag
Function,+,furi_hal_rtc_set_heap_track_mode,void,FuriHalRtcHeapTrackMode
Function,+,furi_hal_rtc_set_log_level,void,uint8_t
Function,+,furi_hal_rtc_set_pin_fails,void,uint32_t
Function,+,furi_hal_rtc_set_register,void,"FuriHalRtcRegister, uint32_t"
@@ -1844,6 +1846,7 @@ Function,-,mf_classic_get_read_sectors_and_keys,void,"MfClassicData*, uint8_t*,
Function,-,mf_classic_get_sector_by_block,uint8_t,uint8_t
Function,-,mf_classic_get_sector_trailer_block_num_by_sector,uint8_t,uint8_t
Function,-,mf_classic_get_sector_trailer_by_sector,MfClassicSectorTrailer*,"MfClassicData*, uint8_t"
Function,-,mf_classic_get_total_block_num,uint16_t,MfClassicType
Function,-,mf_classic_get_total_sectors_num,uint8_t,MfClassicType
Function,-,mf_classic_get_type_str,const char*,MfClassicType
Function,-,mf_classic_is_allowed_access_data_block,_Bool,"MfClassicData*, uint8_t, MfClassicKey, MfClassicAction"
1 entry status name type params
2 Version + 7.3 7.5
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
1260 Function + furi_hal_rtc_get_boot_mode FuriHalRtcBootMode
1261 Function + furi_hal_rtc_get_datetime void FuriHalRtcDateTime*
1262 Function + furi_hal_rtc_get_fault_data uint32_t
1263 Function + furi_hal_rtc_get_heap_track_mode FuriHalRtcHeapTrackMode
1264 Function + furi_hal_rtc_get_log_level uint8_t
1265 Function + furi_hal_rtc_get_pin_fails uint32_t
1266 Function + furi_hal_rtc_get_register uint32_t FuriHalRtcRegister
1273 Function + furi_hal_rtc_set_datetime void FuriHalRtcDateTime*
1274 Function + furi_hal_rtc_set_fault_data void uint32_t
1275 Function + furi_hal_rtc_set_flag void FuriHalRtcFlag
1276 Function + furi_hal_rtc_set_heap_track_mode void FuriHalRtcHeapTrackMode
1277 Function + furi_hal_rtc_set_log_level void uint8_t
1278 Function + furi_hal_rtc_set_pin_fails void uint32_t
1279 Function + furi_hal_rtc_set_register void FuriHalRtcRegister, uint32_t
1846 Function - mf_classic_get_sector_by_block uint8_t uint8_t
1847 Function - mf_classic_get_sector_trailer_block_num_by_sector uint8_t uint8_t
1848 Function - mf_classic_get_sector_trailer_by_sector MfClassicSectorTrailer* MfClassicData*, uint8_t
1849 Function - mf_classic_get_total_block_num uint16_t MfClassicType
1850 Function - mf_classic_get_total_sectors_num uint8_t MfClassicType
1851 Function - mf_classic_get_type_str const char* MfClassicType
1852 Function - mf_classic_is_allowed_access_data_block _Bool MfClassicData*, uint8_t, MfClassicKey, MfClassicAction
+1 -2
View File
@@ -179,7 +179,7 @@ SVCCTL_UserEvtFlowStatus_t SVCCTL_App_Notification(void* pckt) {
case EVT_BLUE_GAP_PASS_KEY_REQUEST: {
// Generate random PIN code
uint32_t pin = rand() % 999999;
uint32_t pin = rand() % 999999; //-V1064
aci_gap_pass_key_resp(gap->service.connection_handle, pin);
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) {
FURI_LOG_I(TAG, "Pass key request event. Pin: ******");
@@ -478,7 +478,6 @@ bool gap_init(GapConfig* config, GapEventCallback on_event_cb, void* context) {
gap = malloc(sizeof(Gap));
gap->config = config;
srand(DWT->CYCCNT);
// Create advertising timer
gap->advertise_timer = furi_timer_alloc(gap_advetise_timer_callback, FuriTimerTypeOnce, NULL);
// Initialization of GATT & GAP layer
@@ -91,7 +91,7 @@ bool furi_hal_crypto_verify_key(uint8_t key_slot) {
uint8_t keys_nb = 0;
uint8_t valid_keys_nb = 0;
uint8_t last_valid_slot = ENCLAVE_FACTORY_KEY_SLOTS;
uint8_t empty_iv[16];
uint8_t empty_iv[16] = {0};
furi_hal_crypto_verify_enclave(&keys_nb, &valid_keys_nb);
if(key_slot <= ENCLAVE_FACTORY_KEY_SLOTS) { // It's a factory key
if(key_slot > keys_nb) return false;
@@ -10,7 +10,7 @@ extern "C" {
#endif
/* Input Related Constants */
#define INPUT_DEBOUNCE_TICKS 30
#define INPUT_DEBOUNCE_TICKS 4
/* Input Keys */
typedef enum {
+15 -1
View File
@@ -30,7 +30,8 @@ typedef struct {
uint8_t log_reserved : 4;
uint8_t flags;
uint8_t boot_mode : 4;
uint16_t reserved : 12;
uint8_t heap_track_mode : 2;
uint16_t reserved : 10;
} DeveloperReg;
_Static_assert(sizeof(DeveloperReg) == 4, "DeveloperReg size mismatch");
@@ -224,6 +225,19 @@ FuriHalRtcBootMode furi_hal_rtc_get_boot_mode() {
return (FuriHalRtcBootMode)data->boot_mode;
}
void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode) {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
data->heap_track_mode = mode;
furi_hal_rtc_set_register(FuriHalRtcRegisterSystem, data_reg);
}
FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode() {
uint32_t data_reg = furi_hal_rtc_get_register(FuriHalRtcRegisterSystem);
DeveloperReg* data = (DeveloperReg*)&data_reg;
return (FuriHalRtcHeapTrackMode)data->heap_track_mode;
}
void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime) {
furi_assert(datetime);
@@ -39,6 +39,13 @@ typedef enum {
FuriHalRtcBootModePostUpdate, /**< Boot to Update, post update */
} FuriHalRtcBootMode;
typedef enum {
FuriHalRtcHeapTrackModeNone = 0, /**< Disable allocation tracking */
FuriHalRtcHeapTrackModeMain, /**< Enable allocation tracking for main application thread */
FuriHalRtcHeapTrackModeTree, /**< Enable allocation tracking for main and children application threads */
FuriHalRtcHeapTrackModeAll, /**< Enable allocation tracking for all threads */
} FuriHalRtcHeapTrackMode;
typedef enum {
FuriHalRtcRegisterHeader, /**< RTC structure header */
FuriHalRtcRegisterSystem, /**< Various system bits */
@@ -79,6 +86,10 @@ void furi_hal_rtc_set_boot_mode(FuriHalRtcBootMode mode);
FuriHalRtcBootMode furi_hal_rtc_get_boot_mode();
void furi_hal_rtc_set_heap_track_mode(FuriHalRtcHeapTrackMode mode);
FuriHalRtcHeapTrackMode furi_hal_rtc_get_heap_track_mode();
void furi_hal_rtc_set_datetime(FuriHalRtcDateTime* datetime);
void furi_hal_rtc_get_datetime(FuriHalRtcDateTime* datetime);

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