mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-11 23:38:11 -07:00
Merge branch 'dev' into dev
This commit is contained in:
+7
-2
@@ -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
|
||||
|
||||
@@ -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 }} \
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -54,3 +54,5 @@ openocd.log
|
||||
# PVS Studio temporary files
|
||||
.PVS-Studio/
|
||||
PVS-Studio.log
|
||||
|
||||
.gdbinit
|
||||
|
||||
@@ -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
|
||||
|
||||
Vendored
+4
@@ -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
@@ -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"],
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -8,4 +8,5 @@ App(
|
||||
stack_size=1 * 1024,
|
||||
icon="A_GPIO_14",
|
||||
order=50,
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -14,6 +14,7 @@ App(
|
||||
icon="A_125khz_14",
|
||||
stack_size=2 * 1024,
|
||||
order=20,
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
App(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -11,4 +11,5 @@ App(
|
||||
stack_size=2 * 1024,
|
||||
icon="A_U2F_14",
|
||||
order=80,
|
||||
fap_libs=["assets"],
|
||||
)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/html
|
||||
/latex
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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"),
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
@@ -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 {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user