mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 04:34:43 +04:00
Merge remote-tracking branch 'OFW/dev' into dev
This commit is contained in:
@@ -244,3 +244,20 @@ App(
|
|||||||
entry_point="get_api",
|
entry_point="get_api",
|
||||||
requires=["unit_tests"],
|
requires=["unit_tests"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
App(
|
||||||
|
appid="test_args",
|
||||||
|
sources=["tests/common/*.c", "tests/args/*.c"],
|
||||||
|
apptype=FlipperAppType.PLUGIN,
|
||||||
|
entry_point="get_api",
|
||||||
|
requires=["unit_tests"],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
App(
|
||||||
|
appid="test_notification",
|
||||||
|
sources=["tests/common/*.c", "tests/notification/*.c"],
|
||||||
|
apptype=FlipperAppType.PLUGIN,
|
||||||
|
entry_point="get_api",
|
||||||
|
requires=["unit_tests"],
|
||||||
|
)
|
||||||
|
|||||||
211
applications/debug/unit_tests/tests/args/args_test.c
Normal file
211
applications/debug/unit_tests/tests/args/args_test.c
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
|
||||||
|
#include "../test.h" // IWYU pragma: keep
|
||||||
|
#include <toolbox/args.h>
|
||||||
|
|
||||||
|
const uint32_t one_ms = 1;
|
||||||
|
const uint32_t one_s = 1000 * one_ms;
|
||||||
|
const uint32_t one_m = 60 * one_s;
|
||||||
|
const uint32_t one_h = 60 * one_m;
|
||||||
|
|
||||||
|
MU_TEST(args_read_duration_default_values_test) {
|
||||||
|
FuriString* args_string;
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
// Check default == NULL (ms)
|
||||||
|
args_string = furi_string_alloc_set_str("1");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, one_ms);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
// Check default == ms
|
||||||
|
args_string = furi_string_alloc_set_str("1");
|
||||||
|
mu_check(args_read_duration(args_string, &value, "ms"));
|
||||||
|
mu_assert_int_eq(value, one_ms);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
// Check default == s
|
||||||
|
args_string = furi_string_alloc_set_str("1");
|
||||||
|
mu_check(args_read_duration(args_string, &value, "s"));
|
||||||
|
mu_assert_int_eq(value, one_s);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
// Check default == m
|
||||||
|
args_string = furi_string_alloc_set_str("1");
|
||||||
|
mu_check(args_read_duration(args_string, &value, "m"));
|
||||||
|
mu_assert_int_eq(value, one_m);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
// Check default == h
|
||||||
|
args_string = furi_string_alloc_set_str("1");
|
||||||
|
mu_check(args_read_duration(args_string, &value, "h"));
|
||||||
|
mu_assert_int_eq(value, one_h);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(args_read_duration_suffix_values_test) {
|
||||||
|
FuriString* args_string;
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
// Check ms
|
||||||
|
args_string = furi_string_alloc_set_str("1ms");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, one_ms);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
// Check s
|
||||||
|
args_string = furi_string_alloc_set_str("1s");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, one_s);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
// Check m
|
||||||
|
args_string = furi_string_alloc_set_str("1m");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, one_m);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
value = 0;
|
||||||
|
|
||||||
|
// Check h
|
||||||
|
args_string = furi_string_alloc_set_str("1h");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, one_h);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
value = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(args_read_duration_values_test) {
|
||||||
|
FuriString* args_string;
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
// Check for ms
|
||||||
|
args_string = furi_string_alloc_set_str("4294967295ms");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 4294967295U);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for s
|
||||||
|
args_string = furi_string_alloc_set_str("4294967s");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 4294967U * one_s);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for m
|
||||||
|
args_string = furi_string_alloc_set_str("71582m");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 71582U * one_m);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for h
|
||||||
|
args_string = furi_string_alloc_set_str("1193h");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 1193U * one_h);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for ms in float
|
||||||
|
args_string = furi_string_alloc_set_str("4.2ms");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 4);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for s in float
|
||||||
|
args_string = furi_string_alloc_set_str("1.5s");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, (uint32_t)(1.5 * one_s));
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for m in float
|
||||||
|
args_string = furi_string_alloc_set_str("1.5m");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, (uint32_t)(1.5 * one_m));
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for h in float
|
||||||
|
args_string = furi_string_alloc_set_str("1.5h");
|
||||||
|
mu_check(args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, (uint32_t)(1.5 * one_h));
|
||||||
|
furi_string_free(args_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(args_read_duration_errors_test) {
|
||||||
|
FuriString* args_string;
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
// Check wrong suffix
|
||||||
|
args_string = furi_string_alloc_set_str("1x");
|
||||||
|
mu_check(!args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 0);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check wrong suffix
|
||||||
|
args_string = furi_string_alloc_set_str("1xs");
|
||||||
|
mu_check(!args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 0);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check negative value
|
||||||
|
args_string = furi_string_alloc_set_str("-1s");
|
||||||
|
mu_check(!args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 0);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check wrong values
|
||||||
|
|
||||||
|
// Check only suffix
|
||||||
|
args_string = furi_string_alloc_set_str("s");
|
||||||
|
mu_check(!args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 0);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check doubled point
|
||||||
|
args_string = furi_string_alloc_set_str("0.1.1");
|
||||||
|
mu_check(!args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 0);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check overflow values
|
||||||
|
|
||||||
|
// Check for ms
|
||||||
|
args_string = furi_string_alloc_set_str("4294967296ms");
|
||||||
|
mu_check(!args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 0);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for s
|
||||||
|
args_string = furi_string_alloc_set_str("4294968s");
|
||||||
|
mu_check(!args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 0);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for m
|
||||||
|
args_string = furi_string_alloc_set_str("71583m");
|
||||||
|
mu_check(!args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 0);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
|
||||||
|
// Check for h
|
||||||
|
args_string = furi_string_alloc_set_str("1194h");
|
||||||
|
mu_check(!args_read_duration(args_string, &value, NULL));
|
||||||
|
mu_assert_int_eq(value, 0);
|
||||||
|
furi_string_free(args_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(toolbox_args_read_duration_suite) {
|
||||||
|
MU_RUN_TEST(args_read_duration_default_values_test);
|
||||||
|
MU_RUN_TEST(args_read_duration_suffix_values_test);
|
||||||
|
MU_RUN_TEST(args_read_duration_values_test);
|
||||||
|
MU_RUN_TEST(args_read_duration_errors_test);
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_minunit_test_toolbox_args(void) {
|
||||||
|
MU_RUN_SUITE(toolbox_args_read_duration_suite);
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_API_DEFINE(run_minunit_test_toolbox_args)
|
||||||
@@ -389,8 +389,8 @@ void minunit_printf_warning(const char* format, ...);
|
|||||||
__func__, \
|
__func__, \
|
||||||
__FILE__, \
|
__FILE__, \
|
||||||
__LINE__, \
|
__LINE__, \
|
||||||
minunit_tmp_e, \
|
|
||||||
minunit_tmp_r, \
|
minunit_tmp_r, \
|
||||||
|
minunit_tmp_e, \
|
||||||
minunit_tmp_m); \
|
minunit_tmp_m); \
|
||||||
minunit_status = 1; \
|
minunit_status = 1; \
|
||||||
return; \
|
return; \
|
||||||
|
|||||||
@@ -268,9 +268,9 @@ static void mf_ultralight_reader_test(const char* path) {
|
|||||||
nfc_listener_stop(mfu_listener);
|
nfc_listener_stop(mfu_listener);
|
||||||
nfc_listener_free(mfu_listener);
|
nfc_listener_free(mfu_listener);
|
||||||
|
|
||||||
mu_assert(
|
MfUltralightData* mfu_other_data =
|
||||||
mf_ultralight_is_equal(mfu_data, nfc_device_get_data(nfc_device, NfcProtocolMfUltralight)),
|
(MfUltralightData*)nfc_device_get_data(nfc_device, NfcProtocolMfUltralight);
|
||||||
"Data not matches");
|
mu_assert(mf_ultralight_is_equal(mfu_data, mfu_other_data), "Data mismatch");
|
||||||
|
|
||||||
mf_ultralight_free(mfu_data);
|
mf_ultralight_free(mfu_data);
|
||||||
nfc_device_free(nfc_device);
|
nfc_device_free(nfc_device);
|
||||||
|
|||||||
165
applications/debug/unit_tests/tests/notification/notes_test.c
Normal file
165
applications/debug/unit_tests/tests/notification/notes_test.c
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
#include "../test.h" // IWYU pragma: keep
|
||||||
|
#include <float_tools.h>
|
||||||
|
#include <notification/notification_messages_notes.h>
|
||||||
|
|
||||||
|
void frequency_assert(const char* note_name, const NotificationMessage* message) {
|
||||||
|
double a = notification_messages_notes_frequency_from_name(note_name);
|
||||||
|
double b = message->data.sound.frequency;
|
||||||
|
const double epsilon = message->data.sound.frequency > 5000 ? 0.02f : 0.01f;
|
||||||
|
mu_assert_double_between(b - epsilon, b + epsilon, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST(notification_messages_notes_frequency_from_name_test) {
|
||||||
|
// Upper case
|
||||||
|
mu_check(float_is_equal(
|
||||||
|
notification_messages_notes_frequency_from_name("C0"),
|
||||||
|
notification_messages_notes_frequency_from_name("c0")));
|
||||||
|
|
||||||
|
// Mixed case
|
||||||
|
mu_check(float_is_equal(
|
||||||
|
notification_messages_notes_frequency_from_name("Cs0"),
|
||||||
|
notification_messages_notes_frequency_from_name("cs0")));
|
||||||
|
|
||||||
|
// Check errors
|
||||||
|
mu_check(
|
||||||
|
float_is_equal(notification_messages_notes_frequency_from_name("0"), 0.0)); // Without note
|
||||||
|
mu_check(float_is_equal(
|
||||||
|
notification_messages_notes_frequency_from_name("C"), 0.0)); // Without octave
|
||||||
|
mu_check(float_is_equal(
|
||||||
|
notification_messages_notes_frequency_from_name("C9"), 0.0)); // Unsupported octave
|
||||||
|
mu_check(float_is_equal(
|
||||||
|
notification_messages_notes_frequency_from_name("C10"), 0.0)); // Unsupported octave
|
||||||
|
mu_check(float_is_equal(
|
||||||
|
notification_messages_notes_frequency_from_name("X0"), 0.0)); // Unknown note
|
||||||
|
mu_check(float_is_equal(
|
||||||
|
notification_messages_notes_frequency_from_name("CCC0"), 0.0)); // Note name overflow
|
||||||
|
|
||||||
|
// Notes and structures
|
||||||
|
frequency_assert("c0", &message_note_c0);
|
||||||
|
frequency_assert("cs0", &message_note_cs0);
|
||||||
|
frequency_assert("d0", &message_note_d0);
|
||||||
|
frequency_assert("ds0", &message_note_ds0);
|
||||||
|
frequency_assert("e0", &message_note_e0);
|
||||||
|
frequency_assert("f0", &message_note_f0);
|
||||||
|
frequency_assert("fs0", &message_note_fs0);
|
||||||
|
frequency_assert("g0", &message_note_g0);
|
||||||
|
frequency_assert("gs0", &message_note_gs0);
|
||||||
|
frequency_assert("a0", &message_note_a0);
|
||||||
|
frequency_assert("as0", &message_note_as0);
|
||||||
|
frequency_assert("b0", &message_note_b0);
|
||||||
|
|
||||||
|
frequency_assert("c1", &message_note_c1);
|
||||||
|
frequency_assert("cs1", &message_note_cs1);
|
||||||
|
frequency_assert("d1", &message_note_d1);
|
||||||
|
frequency_assert("ds1", &message_note_ds1);
|
||||||
|
frequency_assert("e1", &message_note_e1);
|
||||||
|
frequency_assert("f1", &message_note_f1);
|
||||||
|
frequency_assert("fs1", &message_note_fs1);
|
||||||
|
frequency_assert("g1", &message_note_g1);
|
||||||
|
frequency_assert("gs1", &message_note_gs1);
|
||||||
|
frequency_assert("a1", &message_note_a1);
|
||||||
|
frequency_assert("as1", &message_note_as1);
|
||||||
|
frequency_assert("b1", &message_note_b1);
|
||||||
|
|
||||||
|
frequency_assert("c2", &message_note_c2);
|
||||||
|
frequency_assert("cs2", &message_note_cs2);
|
||||||
|
frequency_assert("d2", &message_note_d2);
|
||||||
|
frequency_assert("ds2", &message_note_ds2);
|
||||||
|
frequency_assert("e2", &message_note_e2);
|
||||||
|
frequency_assert("f2", &message_note_f2);
|
||||||
|
frequency_assert("fs2", &message_note_fs2);
|
||||||
|
frequency_assert("g2", &message_note_g2);
|
||||||
|
frequency_assert("gs2", &message_note_gs2);
|
||||||
|
frequency_assert("a2", &message_note_a2);
|
||||||
|
frequency_assert("as2", &message_note_as2);
|
||||||
|
frequency_assert("b2", &message_note_b2);
|
||||||
|
|
||||||
|
frequency_assert("c3", &message_note_c3);
|
||||||
|
frequency_assert("cs3", &message_note_cs3);
|
||||||
|
frequency_assert("d3", &message_note_d3);
|
||||||
|
frequency_assert("ds3", &message_note_ds3);
|
||||||
|
frequency_assert("e3", &message_note_e3);
|
||||||
|
frequency_assert("f3", &message_note_f3);
|
||||||
|
frequency_assert("fs3", &message_note_fs3);
|
||||||
|
frequency_assert("g3", &message_note_g3);
|
||||||
|
frequency_assert("gs3", &message_note_gs3);
|
||||||
|
frequency_assert("a3", &message_note_a3);
|
||||||
|
frequency_assert("as3", &message_note_as3);
|
||||||
|
frequency_assert("b3", &message_note_b3);
|
||||||
|
|
||||||
|
frequency_assert("c4", &message_note_c4);
|
||||||
|
frequency_assert("cs4", &message_note_cs4);
|
||||||
|
frequency_assert("d4", &message_note_d4);
|
||||||
|
frequency_assert("ds4", &message_note_ds4);
|
||||||
|
frequency_assert("e4", &message_note_e4);
|
||||||
|
frequency_assert("f4", &message_note_f4);
|
||||||
|
frequency_assert("fs4", &message_note_fs4);
|
||||||
|
frequency_assert("g4", &message_note_g4);
|
||||||
|
frequency_assert("gs4", &message_note_gs4);
|
||||||
|
frequency_assert("a4", &message_note_a4);
|
||||||
|
frequency_assert("as4", &message_note_as4);
|
||||||
|
frequency_assert("b4", &message_note_b4);
|
||||||
|
|
||||||
|
frequency_assert("c5", &message_note_c5);
|
||||||
|
frequency_assert("cs5", &message_note_cs5);
|
||||||
|
frequency_assert("d5", &message_note_d5);
|
||||||
|
frequency_assert("ds5", &message_note_ds5);
|
||||||
|
frequency_assert("e5", &message_note_e5);
|
||||||
|
frequency_assert("f5", &message_note_f5);
|
||||||
|
frequency_assert("fs5", &message_note_fs5);
|
||||||
|
frequency_assert("g5", &message_note_g5);
|
||||||
|
frequency_assert("gs5", &message_note_gs5);
|
||||||
|
frequency_assert("a5", &message_note_a5);
|
||||||
|
frequency_assert("as5", &message_note_as5);
|
||||||
|
frequency_assert("b5", &message_note_b5);
|
||||||
|
|
||||||
|
frequency_assert("c6", &message_note_c6);
|
||||||
|
frequency_assert("cs6", &message_note_cs6);
|
||||||
|
frequency_assert("d6", &message_note_d6);
|
||||||
|
frequency_assert("ds6", &message_note_ds6);
|
||||||
|
frequency_assert("e6", &message_note_e6);
|
||||||
|
frequency_assert("f6", &message_note_f6);
|
||||||
|
frequency_assert("fs6", &message_note_fs6);
|
||||||
|
frequency_assert("g6", &message_note_g6);
|
||||||
|
frequency_assert("gs6", &message_note_gs6);
|
||||||
|
frequency_assert("a6", &message_note_a6);
|
||||||
|
frequency_assert("as6", &message_note_as6);
|
||||||
|
frequency_assert("b6", &message_note_b6);
|
||||||
|
|
||||||
|
frequency_assert("c7", &message_note_c7);
|
||||||
|
frequency_assert("cs7", &message_note_cs7);
|
||||||
|
frequency_assert("d7", &message_note_d7);
|
||||||
|
frequency_assert("ds7", &message_note_ds7);
|
||||||
|
frequency_assert("e7", &message_note_e7);
|
||||||
|
frequency_assert("f7", &message_note_f7);
|
||||||
|
frequency_assert("fs7", &message_note_fs7);
|
||||||
|
frequency_assert("g7", &message_note_g7);
|
||||||
|
frequency_assert("gs7", &message_note_gs7);
|
||||||
|
frequency_assert("a7", &message_note_a7);
|
||||||
|
frequency_assert("as7", &message_note_as7);
|
||||||
|
frequency_assert("b7", &message_note_b7);
|
||||||
|
|
||||||
|
frequency_assert("c8", &message_note_c8);
|
||||||
|
frequency_assert("cs8", &message_note_cs8);
|
||||||
|
frequency_assert("d8", &message_note_d8);
|
||||||
|
frequency_assert("ds8", &message_note_ds8);
|
||||||
|
frequency_assert("e8", &message_note_e8);
|
||||||
|
frequency_assert("f8", &message_note_f8);
|
||||||
|
frequency_assert("fs8", &message_note_fs8);
|
||||||
|
frequency_assert("g8", &message_note_g8);
|
||||||
|
frequency_assert("gs8", &message_note_gs8);
|
||||||
|
frequency_assert("a8", &message_note_a8);
|
||||||
|
frequency_assert("as8", &message_note_as8);
|
||||||
|
frequency_assert("b8", &message_note_b8);
|
||||||
|
}
|
||||||
|
|
||||||
|
MU_TEST_SUITE(notes_suite) {
|
||||||
|
MU_RUN_TEST(notification_messages_notes_frequency_from_name_test);
|
||||||
|
}
|
||||||
|
|
||||||
|
int run_minunit_test_notes(void) {
|
||||||
|
MU_RUN_SUITE(notes_suite);
|
||||||
|
return MU_EXIT_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_API_DEFINE(run_minunit_test_notes)
|
||||||
@@ -39,7 +39,7 @@ bool nfc_scene_mf_classic_keys_add_on_event(void* context, SceneManagerEvent eve
|
|||||||
instance->scene_manager, NfcSceneMfClassicKeysWarnDuplicate);
|
instance->scene_manager, NfcSceneMfClassicKeysWarnDuplicate);
|
||||||
} else if(keys_dict_add_key(dict, key.data, sizeof(MfClassicKey))) {
|
} else if(keys_dict_add_key(dict, key.data, sizeof(MfClassicKey))) {
|
||||||
scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess);
|
scene_manager_next_scene(instance->scene_manager, NfcSceneSaveSuccess);
|
||||||
dolphin_deed(DolphinDeedNfcMfcAdd);
|
dolphin_deed(DolphinDeedNfcKeyAdd);
|
||||||
} else {
|
} else {
|
||||||
scene_manager_previous_scene(instance->scene_manager);
|
scene_manager_previous_scene(instance->scene_manager);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,3 +49,11 @@ App(
|
|||||||
requires=["cli"],
|
requires=["cli"],
|
||||||
sources=["commands/subshell_demo.c"],
|
sources=["commands/subshell_demo.c"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
App(
|
||||||
|
appid="cli_buzzer",
|
||||||
|
apptype=FlipperAppType.PLUGIN,
|
||||||
|
entry_point="cli_buzzer_ep",
|
||||||
|
requires=["cli"],
|
||||||
|
sources=["commands/buzzer.c"],
|
||||||
|
)
|
||||||
|
|||||||
@@ -356,11 +356,13 @@ void cli_command_led(PipeSide* pipe, FuriString* args, void* context) {
|
|||||||
static void cli_command_top(PipeSide* pipe, FuriString* args, void* context) {
|
static void cli_command_top(PipeSide* pipe, FuriString* args, void* context) {
|
||||||
UNUSED(context);
|
UNUSED(context);
|
||||||
|
|
||||||
int interval = 1000;
|
uint32_t interval;
|
||||||
args_read_int_and_trim(args, &interval);
|
if(!args_read_duration(args, &interval, NULL)) {
|
||||||
|
interval = 1000;
|
||||||
|
}
|
||||||
|
|
||||||
FuriThreadList* thread_list = furi_thread_list_alloc();
|
FuriThreadList* thread_list = furi_thread_list_alloc();
|
||||||
while(!cli_is_pipe_broken_or_is_etx_next_char(pipe)) {
|
do {
|
||||||
uint32_t tick = furi_get_tick();
|
uint32_t tick = furi_get_tick();
|
||||||
furi_thread_enumerate(thread_list);
|
furi_thread_enumerate(thread_list);
|
||||||
|
|
||||||
@@ -416,12 +418,8 @@ static void cli_command_top(PipeSide* pipe, FuriString* args, void* context) {
|
|||||||
printf(ANSI_ERASE_DISPLAY(ANSI_ERASE_FROM_CURSOR_TO_END));
|
printf(ANSI_ERASE_DISPLAY(ANSI_ERASE_FROM_CURSOR_TO_END));
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
if(interval > 0) {
|
} while(interval > 0 && cli_sleep(pipe, interval));
|
||||||
furi_delay_ms(interval);
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
furi_thread_list_free(thread_list);
|
furi_thread_list_free(thread_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -491,6 +489,37 @@ void cli_command_echo(PipeSide* pipe, FuriString* args, void* context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pause for a specified duration or until Ctrl+C is pressed or the
|
||||||
|
* session is terminated.
|
||||||
|
*
|
||||||
|
* The duration can be specified in various units such as milliseconds (ms),
|
||||||
|
* seconds (s), minutes (m), or hours (h). If the unit is not specified, the
|
||||||
|
* second is used by default.
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
* sleep 5s
|
||||||
|
*/
|
||||||
|
void cli_command_sleep(PipeSide* pipe, FuriString* args, void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
FuriString* duration_string;
|
||||||
|
duration_string = furi_string_alloc();
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint32_t duration_in_ms = 0;
|
||||||
|
if(!args_read_string_and_trim(args, duration_string) ||
|
||||||
|
!args_read_duration(duration_string, &duration_in_ms, "s")) {
|
||||||
|
cli_print_usage("sleep", "[<0-...>[<ms|s|m|h>]]", furi_string_get_cstr(args));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli_sleep(pipe, duration_in_ms);
|
||||||
|
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
furi_string_free(duration_string);
|
||||||
|
}
|
||||||
|
|
||||||
void cli_main_commands_init(CliRegistry* registry) {
|
void cli_main_commands_init(CliRegistry* registry) {
|
||||||
cli_registry_add_command(
|
cli_registry_add_command(
|
||||||
registry, "!", CliCommandFlagParallelSafe, cli_command_info, (void*)true);
|
registry, "!", CliCommandFlagParallelSafe, cli_command_info, (void*)true);
|
||||||
@@ -508,6 +537,8 @@ void cli_main_commands_init(CliRegistry* registry) {
|
|||||||
cli_registry_add_command(
|
cli_registry_add_command(
|
||||||
registry, "free_blocks", CliCommandFlagParallelSafe, cli_command_free_blocks, NULL);
|
registry, "free_blocks", CliCommandFlagParallelSafe, cli_command_free_blocks, NULL);
|
||||||
cli_registry_add_command(registry, "echo", CliCommandFlagParallelSafe, cli_command_echo, NULL);
|
cli_registry_add_command(registry, "echo", CliCommandFlagParallelSafe, cli_command_echo, NULL);
|
||||||
|
cli_registry_add_command(
|
||||||
|
registry, "sleep", CliCommandFlagParallelSafe, cli_command_sleep, NULL);
|
||||||
|
|
||||||
cli_registry_add_command(registry, "vibro", CliCommandFlagDefault, cli_command_vibro, NULL);
|
cli_registry_add_command(registry, "vibro", CliCommandFlagDefault, cli_command_vibro, NULL);
|
||||||
cli_registry_add_command(registry, "led", CliCommandFlagDefault, cli_command_led, NULL);
|
cli_registry_add_command(registry, "led", CliCommandFlagDefault, cli_command_led, NULL);
|
||||||
|
|||||||
135
applications/services/cli/commands/buzzer.c
Normal file
135
applications/services/cli/commands/buzzer.c
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
#include "../cli_main_commands.h"
|
||||||
|
#include <notification/notification_app.h>
|
||||||
|
#include <toolbox/args.h>
|
||||||
|
#include <toolbox/cli/cli_command.h>
|
||||||
|
|
||||||
|
void cli_command_buzzer_print_usage(bool is_freq_subcommand, FuriString* args) {
|
||||||
|
if(is_freq_subcommand) {
|
||||||
|
cli_print_usage(
|
||||||
|
"buzzer freq", "<freq_hz> [<0-...>[<ms|s|m|h>]]", furi_string_get_cstr(args));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
cli_print_usage("buzzer note", "<note> [<0-...>[<ms|s|m|h>]]", furi_string_get_cstr(args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float cli_command_buzzer_read_frequency(bool is_freq_subcommand, FuriString* args) {
|
||||||
|
float frequency = 0.0f;
|
||||||
|
|
||||||
|
if(is_freq_subcommand) {
|
||||||
|
args_read_float_and_trim(args, &frequency);
|
||||||
|
return frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract note frequency from name
|
||||||
|
|
||||||
|
FuriString* note_name_string;
|
||||||
|
note_name_string = furi_string_alloc();
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!args_read_string_and_trim(args, note_name_string)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const char* note_name = furi_string_get_cstr(note_name_string);
|
||||||
|
frequency = notification_messages_notes_frequency_from_name(note_name);
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
furi_string_free(note_name_string);
|
||||||
|
|
||||||
|
return frequency;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cli_command_buzzer_play(
|
||||||
|
PipeSide* pipe,
|
||||||
|
NotificationApp* notification,
|
||||||
|
bool is_freq_subcommand,
|
||||||
|
FuriString* args) {
|
||||||
|
FuriString* duration_string;
|
||||||
|
duration_string = furi_string_alloc();
|
||||||
|
|
||||||
|
do {
|
||||||
|
float frequency = cli_command_buzzer_read_frequency(is_freq_subcommand, args);
|
||||||
|
if(frequency <= 0.0f) {
|
||||||
|
cli_command_buzzer_print_usage(is_freq_subcommand, args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NotificationMessage notification_buzzer_message = {
|
||||||
|
.type = NotificationMessageTypeSoundOn,
|
||||||
|
.data.sound.frequency = frequency,
|
||||||
|
.data.sound.volume = 1.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Optional duration
|
||||||
|
uint32_t duration_ms = 100;
|
||||||
|
if(args_read_string_and_trim(args, duration_string)) {
|
||||||
|
if(!args_read_duration(duration_string, &duration_ms, NULL)) {
|
||||||
|
cli_command_buzzer_print_usage(is_freq_subcommand, args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const NotificationSequence sound_on_sequence = {
|
||||||
|
¬ification_buzzer_message,
|
||||||
|
&message_do_not_reset,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Play sound
|
||||||
|
notification_message_block(notification, &sound_on_sequence);
|
||||||
|
|
||||||
|
cli_sleep(pipe, duration_ms);
|
||||||
|
|
||||||
|
// Stop sound
|
||||||
|
const NotificationSequence sound_off_sequence = {
|
||||||
|
&message_sound_off,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
notification_message_block(notification, &sound_off_sequence);
|
||||||
|
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
furi_string_free(duration_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
void execute(PipeSide* pipe, FuriString* args, void* context) {
|
||||||
|
UNUSED(context);
|
||||||
|
|
||||||
|
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||||
|
|
||||||
|
FuriString* command_string;
|
||||||
|
command_string = furi_string_alloc();
|
||||||
|
|
||||||
|
do {
|
||||||
|
if(!args_read_string_and_trim(args, command_string)) {
|
||||||
|
cli_print_usage("buzzer", "<freq|note>", furi_string_get_cstr(args));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check volume
|
||||||
|
if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagStealthMode)) {
|
||||||
|
printf("Flipper is in stealth mode. Unmute the device to control buzzer.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(notification->settings.speaker_volume == 0.0f) {
|
||||||
|
printf("Sound is disabled in settings. Increase volume to control buzzer.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(furi_string_cmp(command_string, "freq") == 0) {
|
||||||
|
cli_command_buzzer_play(pipe, notification, true, args);
|
||||||
|
break;
|
||||||
|
} else if(furi_string_cmp(command_string, "note") == 0) {
|
||||||
|
cli_command_buzzer_play(pipe, notification, false, args);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
cli_print_usage("buzzer", "<freq|note>", furi_string_get_cstr(args));
|
||||||
|
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
furi_string_free(command_string);
|
||||||
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI_COMMAND_INTERFACE(buzzer, execute, CliCommandFlagDefault, 2048, CLI_APPID);
|
||||||
@@ -20,7 +20,7 @@ static const DolphinDeedWeight dolphin_deed_weights[] = {
|
|||||||
{3, DolphinAppNfc}, // DolphinDeedNfcSave
|
{3, DolphinAppNfc}, // DolphinDeedNfcSave
|
||||||
{1, DolphinAppNfc}, // DolphinDeedNfcDetectReader
|
{1, DolphinAppNfc}, // DolphinDeedNfcDetectReader
|
||||||
{2, DolphinAppNfc}, // DolphinDeedNfcEmulate
|
{2, DolphinAppNfc}, // DolphinDeedNfcEmulate
|
||||||
{2, DolphinAppNfc}, // DolphinDeedNfcMfcAdd
|
{2, DolphinAppNfc}, // DolphinDeedNfcKeyAdd
|
||||||
{1, DolphinAppNfc}, // DolphinDeedNfcAddSave
|
{1, DolphinAppNfc}, // DolphinDeedNfcAddSave
|
||||||
{1, DolphinAppNfc}, // DolphinDeedNfcAddEmulate
|
{1, DolphinAppNfc}, // DolphinDeedNfcAddEmulate
|
||||||
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ typedef enum {
|
|||||||
DolphinDeedNfcSave,
|
DolphinDeedNfcSave,
|
||||||
DolphinDeedNfcDetectReader,
|
DolphinDeedNfcDetectReader,
|
||||||
DolphinDeedNfcEmulate,
|
DolphinDeedNfcEmulate,
|
||||||
DolphinDeedNfcMfcAdd,
|
DolphinDeedNfcKeyAdd,
|
||||||
DolphinDeedNfcAddSave,
|
DolphinDeedNfcAddSave,
|
||||||
DolphinDeedNfcAddEmulate,
|
DolphinDeedNfcAddEmulate,
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "notification.h"
|
#include "notification.h"
|
||||||
|
#include <toolbox/strint.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Python script for note messages generation
|
Python script for note messages generation
|
||||||
@@ -571,3 +572,35 @@ const NotificationMessage message_note_b8 = {
|
|||||||
.data.sound.frequency = 7902.13f,
|
.data.sound.frequency = 7902.13f,
|
||||||
.data.sound.volume = 1.0f,
|
.data.sound.volume = 1.0f,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
float notification_messages_notes_frequency_from_name(const char* note_name) {
|
||||||
|
const float base_note = 16.3515979f; // C0
|
||||||
|
|
||||||
|
const char* note_names[] = {"c", "cs", "d", "ds", "e", "f", "fs", "g", "gs", "a", "as", "b"};
|
||||||
|
const size_t notes_count = COUNT_OF(note_names);
|
||||||
|
|
||||||
|
char note_wo_octave[3] = {0};
|
||||||
|
for(size_t i = 0; i < sizeof(note_wo_octave) - 1; i++) {
|
||||||
|
char in = *note_name;
|
||||||
|
if(!in) break;
|
||||||
|
if(!isalpha(in)) break;
|
||||||
|
note_wo_octave[i] = in;
|
||||||
|
note_name++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int note_index = -1;
|
||||||
|
for(size_t i = 0; i < notes_count; i++) {
|
||||||
|
if(strcasecmp(note_wo_octave, note_names[i]) == 0) note_index = i;
|
||||||
|
}
|
||||||
|
if(note_index < 0) return 0.0;
|
||||||
|
|
||||||
|
uint16_t octave;
|
||||||
|
StrintParseError error = strint_to_uint16(note_name, NULL, &octave, 10);
|
||||||
|
if(error != StrintParseNoError) return 0.0;
|
||||||
|
if(octave > 8) return 0.0;
|
||||||
|
|
||||||
|
int semitone_index = octave * notes_count + note_index;
|
||||||
|
float frequency = base_note * powf(2.0f, semitone_index / 12.0f);
|
||||||
|
|
||||||
|
return roundf(frequency * 100) / 100.0f;
|
||||||
|
}
|
||||||
|
|||||||
@@ -115,6 +115,17 @@ extern const NotificationMessage message_note_a8;
|
|||||||
extern const NotificationMessage message_note_as8;
|
extern const NotificationMessage message_note_as8;
|
||||||
extern const NotificationMessage message_note_b8;
|
extern const NotificationMessage message_note_b8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the frequency of the given note
|
||||||
|
*
|
||||||
|
* This function calculates and returns the frequency (in Hz) of the specified note.
|
||||||
|
* If the input note name is invalid, the function returns 0.0.
|
||||||
|
*
|
||||||
|
* @param [in] note_name The name of the note (e.g., "A4", cs5")
|
||||||
|
* @return The frequency of the note in Hz, or 0.0 if the note name is invalid
|
||||||
|
*/
|
||||||
|
extern float notification_messages_notes_frequency_from_name(const char* note_name);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -303,6 +303,26 @@ None, there are no versions yet.
|
|||||||
|
|
||||||
This file contains a list of Mifare Classic keys. Each key is represented as a hex string. Lines starting with '#' are ignored as comments. Blank lines are ignored as well.
|
This file contains a list of Mifare Classic keys. Each key is represented as a hex string. Lines starting with '#' are ignored as comments. Blank lines are ignored as well.
|
||||||
|
|
||||||
|
## Mifare Ultralight C Dictionary
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
# Hexadecimal-Reversed Sample Key
|
||||||
|
12E4143455F495649454D4B414542524
|
||||||
|
# Byte-Reversed Sample Key (!NACUOYFIEMKAERB)
|
||||||
|
214E4143554F594649454D4B41455242
|
||||||
|
# Sample Key (BREAKMEIFYOUCAN!)
|
||||||
|
425245414B4D454946594F5543414E21
|
||||||
|
# Semnox Key (IEMKAERB!NACUOY )
|
||||||
|
49454D4B41455242214E4143554F5900
|
||||||
|
# Modified Semnox Key (IEMKAERB!NACUOYF)
|
||||||
|
49454D4B41455242214E4143554F5946
|
||||||
|
...
|
||||||
|
|
||||||
|
### Description
|
||||||
|
|
||||||
|
This file contains a list of Mifare Ultralight C keys. Each key is represented as a hex string. Lines starting with '#' are ignored as comments. Blank lines are ignored as well.
|
||||||
|
|
||||||
## EMV resources
|
## EMV resources
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "hex.h"
|
#include "hex.h"
|
||||||
#include "strint.h"
|
#include "strint.h"
|
||||||
#include "m-core.h"
|
#include "m-core.h"
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
size_t args_get_first_word_length(FuriString* args) {
|
size_t args_get_first_word_length(FuriString* args) {
|
||||||
size_t ws = furi_string_search_char(args, ' ');
|
size_t ws = furi_string_search_char(args, ' ');
|
||||||
@@ -34,6 +35,24 @@ bool args_read_int_and_trim(FuriString* args, int* value) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool args_read_float_and_trim(FuriString* args, float* value) {
|
||||||
|
size_t cmd_length = args_get_first_word_length(args);
|
||||||
|
if(cmd_length == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* end_ptr;
|
||||||
|
float temp = strtof(furi_string_get_cstr(args), &end_ptr);
|
||||||
|
if(end_ptr == furi_string_get_cstr(args)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*value = temp;
|
||||||
|
furi_string_right(args, cmd_length);
|
||||||
|
furi_string_trim(args);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool args_read_string_and_trim(FuriString* args, FuriString* word) {
|
bool args_read_string_and_trim(FuriString* args, FuriString* word) {
|
||||||
size_t cmd_length = args_get_first_word_length(args);
|
size_t cmd_length = args_get_first_word_length(args);
|
||||||
|
|
||||||
@@ -97,3 +116,38 @@ bool args_read_hex_bytes(FuriString* args, uint8_t* bytes, size_t bytes_count) {
|
|||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool args_read_duration(FuriString* args, uint32_t* value, const char* default_unit) {
|
||||||
|
const char* args_cstr = furi_string_get_cstr(args);
|
||||||
|
|
||||||
|
const char* unit;
|
||||||
|
errno = 0;
|
||||||
|
double duration_ms = strtod(args_cstr, (char**)&unit);
|
||||||
|
if(errno) return false;
|
||||||
|
if(duration_ms < 0) return false;
|
||||||
|
if(unit == args_cstr) return false;
|
||||||
|
|
||||||
|
if(strcmp(unit, "") == 0) {
|
||||||
|
unit = default_unit;
|
||||||
|
if(!unit) unit = "ms";
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t multiplier;
|
||||||
|
if(strcasecmp(unit, "ms") == 0) {
|
||||||
|
multiplier = 1;
|
||||||
|
} else if(strcasecmp(unit, "s") == 0) {
|
||||||
|
multiplier = 1000;
|
||||||
|
} else if(strcasecmp(unit, "m") == 0) {
|
||||||
|
multiplier = 60 * 1000;
|
||||||
|
} else if(strcasecmp(unit, "h") == 0) {
|
||||||
|
multiplier = 60 * 60 * 1000;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t max_pre_multiplication = UINT32_MAX / multiplier;
|
||||||
|
if(duration_ms > max_pre_multiplication) return false;
|
||||||
|
|
||||||
|
*value = round(duration_ms * multiplier);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|||||||
@@ -11,12 +11,21 @@ extern "C" {
|
|||||||
/** Extract int value and trim arguments string
|
/** Extract int value and trim arguments string
|
||||||
*
|
*
|
||||||
* @param args - arguments string
|
* @param args - arguments string
|
||||||
* @param word first argument, output
|
* @param value first argument, output
|
||||||
* @return true - success
|
* @return true - success
|
||||||
* @return false - arguments string does not contain int
|
* @return false - arguments string does not contain int
|
||||||
*/
|
*/
|
||||||
bool args_read_int_and_trim(FuriString* args, int* value);
|
bool args_read_int_and_trim(FuriString* args, int* value);
|
||||||
|
|
||||||
|
/** Extract float value and trim arguments string
|
||||||
|
*
|
||||||
|
* @param [in, out] args arguments string
|
||||||
|
* @param [out] value first argument
|
||||||
|
* @return true - success
|
||||||
|
* @return false - arguments string does not contain float
|
||||||
|
*/
|
||||||
|
bool args_read_float_and_trim(FuriString* args, float* value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Extract first argument from arguments string and trim arguments string
|
* @brief Extract first argument from arguments string and trim arguments string
|
||||||
*
|
*
|
||||||
@@ -48,6 +57,18 @@ bool args_read_probably_quoted_string_and_trim(FuriString* args, FuriString* wor
|
|||||||
*/
|
*/
|
||||||
bool args_read_hex_bytes(FuriString* args, uint8_t* bytes, size_t bytes_count);
|
bool args_read_hex_bytes(FuriString* args, uint8_t* bytes, size_t bytes_count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Parses a duration value from a given string and converts it to milliseconds
|
||||||
|
*
|
||||||
|
* @param [in] args the input string containing the duration value. The string may include units (e.g., "10s", "0.5m").
|
||||||
|
* @param [out] value pointer to store the parsed value in milliseconds
|
||||||
|
* @param [in] default_unit A default unit to be used if the input string does not contain a valid suffix.
|
||||||
|
* Supported units: `"ms"`, `"s"`, `"m"`, `"h"`
|
||||||
|
* If NULL, the function will assume milliseconds by default.
|
||||||
|
* @return `true` if the parsing and conversion succeeded, `false` otherwise.
|
||||||
|
*/
|
||||||
|
bool args_read_duration(FuriString* args, uint32_t* value, const char* default_unit);
|
||||||
|
|
||||||
/************************************ HELPERS ***************************************/
|
/************************************ HELPERS ***************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,3 +15,18 @@ void cli_print_usage(const char* cmd, const char* usage, const char* arg) {
|
|||||||
|
|
||||||
printf("%s: illegal option -- %s\r\nusage: %s %s", cmd, arg, cmd, usage);
|
printf("%s: illegal option -- %s\r\nusage: %s %s", cmd, arg, cmd, usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool cli_sleep(PipeSide* side, uint32_t duration_in_ms) {
|
||||||
|
uint32_t passed_time = 0;
|
||||||
|
bool is_interrupted = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint32_t left_time = duration_in_ms - passed_time;
|
||||||
|
uint32_t check_interval = left_time >= 100 ? 100 : left_time;
|
||||||
|
furi_delay_ms(check_interval);
|
||||||
|
passed_time += check_interval;
|
||||||
|
is_interrupted = cli_is_pipe_broken_or_is_etx_next_char(side);
|
||||||
|
} while(!is_interrupted && passed_time < duration_in_ms);
|
||||||
|
|
||||||
|
return !is_interrupted;
|
||||||
|
}
|
||||||
|
|||||||
@@ -80,6 +80,21 @@ bool cli_is_pipe_broken_or_is_etx_next_char(PipeSide* side);
|
|||||||
*/
|
*/
|
||||||
void cli_print_usage(const char* cmd, const char* usage, const char* arg);
|
void cli_print_usage(const char* cmd, const char* usage, const char* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pause for a specified duration or until Ctrl+C is pressed or the
|
||||||
|
* session is terminated.
|
||||||
|
*
|
||||||
|
* @param [in] side Pointer to pipe side given to the command thread.
|
||||||
|
* @param [in] duration_in_ms Duration of sleep in milliseconds.
|
||||||
|
* @return `true` if the sleep completed without interruption.
|
||||||
|
* @return `false` if interrupted.
|
||||||
|
*
|
||||||
|
* @warning This function also assumes that the pipe is installed as the
|
||||||
|
* thread's stdio.
|
||||||
|
* @warning This function will consume 0 or 1 bytes from the pipe.
|
||||||
|
*/
|
||||||
|
bool cli_sleep(PipeSide* side, uint32_t duration_in_ms);
|
||||||
|
|
||||||
#define CLI_COMMAND_INTERFACE(name, execute_callback, flags, stack_depth, app_id) \
|
#define CLI_COMMAND_INTERFACE(name, execute_callback, flags, stack_depth, app_id) \
|
||||||
static const CliCommandDescriptor cli_##name##_desc = { \
|
static const CliCommandDescriptor cli_##name##_desc = { \
|
||||||
#name, \
|
#name, \
|
||||||
|
|||||||
@@ -546,6 +546,8 @@ Function,-,arc4random_uniform,__uint32_t,__uint32_t
|
|||||||
Function,+,args_char_to_hex,_Bool,"char, char, uint8_t*"
|
Function,+,args_char_to_hex,_Bool,"char, char, uint8_t*"
|
||||||
Function,+,args_get_first_word_length,size_t,FuriString*
|
Function,+,args_get_first_word_length,size_t,FuriString*
|
||||||
Function,+,args_length,size_t,FuriString*
|
Function,+,args_length,size_t,FuriString*
|
||||||
|
Function,+,args_read_duration,_Bool,"FuriString*, uint32_t*, const char*"
|
||||||
|
Function,+,args_read_float_and_trim,_Bool,"FuriString*, float*"
|
||||||
Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t"
|
Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t"
|
||||||
Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*"
|
Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*"
|
||||||
Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*"
|
Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*"
|
||||||
@@ -802,6 +804,7 @@ Function,+,cli_shell_free,void,CliShell*
|
|||||||
Function,+,cli_shell_join,void,CliShell*
|
Function,+,cli_shell_join,void,CliShell*
|
||||||
Function,+,cli_shell_set_prompt,void,"CliShell*, const char*"
|
Function,+,cli_shell_set_prompt,void,"CliShell*, const char*"
|
||||||
Function,+,cli_shell_start,void,CliShell*
|
Function,+,cli_shell_start,void,CliShell*
|
||||||
|
Function,+,cli_sleep,_Bool,"PipeSide*, uint32_t"
|
||||||
Function,+,cli_vcp_disable,void,CliVcp*
|
Function,+,cli_vcp_disable,void,CliVcp*
|
||||||
Function,+,cli_vcp_enable,void,CliVcp*
|
Function,+,cli_vcp_enable,void,CliVcp*
|
||||||
Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiInterface*"
|
Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiInterface*"
|
||||||
@@ -2269,6 +2272,7 @@ Function,+,notification_internal_message,void,"NotificationApp*, const Notificat
|
|||||||
Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*"
|
Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*"
|
||||||
Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*"
|
Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*"
|
||||||
Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*"
|
Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*"
|
||||||
|
Function,+,notification_messages_notes_frequency_from_name,float,const char*
|
||||||
Function,-,nrand48,long,unsigned short[3]
|
Function,-,nrand48,long,unsigned short[3]
|
||||||
Function,+,number_input_alloc,NumberInput*,
|
Function,+,number_input_alloc,NumberInput*,
|
||||||
Function,+,number_input_free,void,NumberInput*
|
Function,+,number_input_free,void,NumberInput*
|
||||||
|
|||||||
|
@@ -636,6 +636,8 @@ Function,-,arc4random_uniform,__uint32_t,__uint32_t
|
|||||||
Function,+,args_char_to_hex,_Bool,"char, char, uint8_t*"
|
Function,+,args_char_to_hex,_Bool,"char, char, uint8_t*"
|
||||||
Function,+,args_get_first_word_length,size_t,FuriString*
|
Function,+,args_get_first_word_length,size_t,FuriString*
|
||||||
Function,+,args_length,size_t,FuriString*
|
Function,+,args_length,size_t,FuriString*
|
||||||
|
Function,+,args_read_float_and_trim,_Bool,"FuriString*, float*"
|
||||||
|
Function,+,args_read_duration,_Bool,"FuriString*, uint32_t*, const char*"
|
||||||
Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t"
|
Function,+,args_read_hex_bytes,_Bool,"FuriString*, uint8_t*, size_t"
|
||||||
Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*"
|
Function,+,args_read_int_and_trim,_Bool,"FuriString*, int*"
|
||||||
Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*"
|
Function,+,args_read_probably_quoted_string_and_trim,_Bool,"FuriString*, FuriString*"
|
||||||
@@ -895,6 +897,7 @@ Function,+,cli_shell_free,void,CliShell*
|
|||||||
Function,+,cli_shell_join,void,CliShell*
|
Function,+,cli_shell_join,void,CliShell*
|
||||||
Function,+,cli_shell_set_prompt,void,"CliShell*, const char*"
|
Function,+,cli_shell_set_prompt,void,"CliShell*, const char*"
|
||||||
Function,+,cli_shell_start,void,CliShell*
|
Function,+,cli_shell_start,void,CliShell*
|
||||||
|
Function,+,cli_sleep,_Bool,"PipeSide*, uint32_t"
|
||||||
Function,+,cli_vcp_disable,void,CliVcp*
|
Function,+,cli_vcp_disable,void,CliVcp*
|
||||||
Function,+,cli_vcp_enable,void,CliVcp*
|
Function,+,cli_vcp_enable,void,CliVcp*
|
||||||
Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiInterface*"
|
Function,+,composite_api_resolver_add,void,"CompositeApiResolver*, const ElfApiInterface*"
|
||||||
@@ -2983,6 +2986,7 @@ Function,+,notification_internal_message,void,"NotificationApp*, const Notificat
|
|||||||
Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*"
|
Function,+,notification_internal_message_block,void,"NotificationApp*, const NotificationSequence*"
|
||||||
Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*"
|
Function,+,notification_message,void,"NotificationApp*, const NotificationSequence*"
|
||||||
Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*"
|
Function,+,notification_message_block,void,"NotificationApp*, const NotificationSequence*"
|
||||||
|
Function,+,notification_messages_notes_frequency_from_name,float,const char*
|
||||||
Function,-,nrand48,long,unsigned short[3]
|
Function,-,nrand48,long,unsigned short[3]
|
||||||
Function,+,ntag4xx_alloc,Ntag4xxData*,
|
Function,+,ntag4xx_alloc,Ntag4xxData*,
|
||||||
Function,+,ntag4xx_copy,void,"Ntag4xxData*, const Ntag4xxData*"
|
Function,+,ntag4xx_copy,void,"Ntag4xxData*, const Ntag4xxData*"
|
||||||
|
|||||||
|
Reference in New Issue
Block a user