Skip to content

Commit 13bf659

Browse files
authored
Merge branch 'dev' into loader-warn-sd-card
2 parents 65bfc98 + 4fd7652 commit 13bf659

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+693
-241
lines changed

SConstruct

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,14 +234,15 @@ firmware_debug = distenv.PhonyTarget(
234234
)
235235
distenv.Depends(firmware_debug, firmware_flash)
236236

237-
distenv.PhonyTarget(
237+
firmware_blackmagic = distenv.PhonyTarget(
238238
"blackmagic",
239239
"${GDBPYCOM}",
240240
source=firmware_env["FW_ELF"],
241241
GDBOPTS="${GDBOPTS_BASE} ${GDBOPTS_BLACKMAGIC}",
242242
GDBREMOTE="${BLACKMAGIC_ADDR}",
243243
FBT_FAP_DEBUG_ELF_ROOT=firmware_env["FBT_FAP_DEBUG_ELF_ROOT"],
244244
)
245+
distenv.Depends(firmware_blackmagic, firmware_flash)
245246

246247
# Debug alien elf
247248
debug_other_opts = [

applications/debug/rpc_debug_app/scenes/rpc_debug_app_scene_input_error_code.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "../rpc_debug_app.h"
22

3+
#include <lib/toolbox/strint.h>
4+
35
static bool rpc_debug_app_scene_input_error_code_validator_callback(
46
const char* text,
57
FuriString* error,
@@ -44,9 +46,8 @@ bool rpc_debug_app_scene_input_error_code_on_event(void* context, SceneManagerEv
4446

4547
if(event.type == SceneManagerEventTypeCustom) {
4648
if(event.event == RpcDebugAppCustomEventInputErrorCode) {
47-
char* end;
48-
int error_code = strtol(app->text_store, &end, 10);
49-
if(!*end) {
49+
uint32_t error_code;
50+
if(strint_to_uint32(app->text_store, NULL, &error_code, 10) == StrintParseNoError) {
5051
rpc_system_app_set_error_code(app->rpc, error_code);
5152
}
5253
scene_manager_previous_scene(app->scene_manager);

applications/debug/uart_echo/uart_echo.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
#include <gui/view_dispatcher.h>
77
#include <gui/modules/dialog_ex.h>
88

9+
#include <lib/toolbox/strint.h>
10+
911
#include <notification/notification.h>
1012
#include <notification/notification_messages.h>
1113

@@ -320,7 +322,7 @@ int32_t uart_echo_app(void* p) {
320322
uint32_t baudrate = DEFAULT_BAUD_RATE;
321323
if(p) {
322324
const char* baudrate_str = p;
323-
if(sscanf(baudrate_str, "%lu", &baudrate) != 1) {
325+
if(strint_to_uint32(baudrate_str, NULL, &baudrate, 10) != StrintParseNoError) {
324326
FURI_LOG_E(TAG, "Invalid baudrate: %s", baudrate_str);
325327
baudrate = DEFAULT_BAUD_RATE;
326328
}

applications/debug/unit_tests/application.fam

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,3 +220,11 @@ App(
220220
entry_point="get_api",
221221
requires=["unit_tests"],
222222
)
223+
224+
App(
225+
appid="test_strint",
226+
sources=["tests/common/*.c", "tests/strint/*.c"],
227+
apptype=FlipperAppType.PLUGIN,
228+
entry_point="get_api",
229+
requires=["unit_tests"],
230+
)
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
#include <furi.h>
2+
#include <furi_hal.h>
3+
4+
#include "../test.h" // IWYU pragma: keep
5+
6+
#include <toolbox/strint.h>
7+
8+
MU_TEST(strint_test_basic) {
9+
uint32_t result = 0;
10+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123456", NULL, &result, 10));
11+
mu_assert_int_eq(123456, result);
12+
}
13+
14+
MU_TEST(strint_test_junk) {
15+
uint32_t result = 0;
16+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32(" 123456 ", NULL, &result, 10));
17+
mu_assert_int_eq(123456, result);
18+
mu_assert_int_eq(
19+
StrintParseNoError, strint_to_uint32(" \r\n\r\n 123456 ", NULL, &result, 10));
20+
mu_assert_int_eq(123456, result);
21+
}
22+
23+
MU_TEST(strint_test_tail) {
24+
uint32_t result = 0;
25+
char* tail;
26+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123456tail", &tail, &result, 10));
27+
mu_assert_int_eq(123456, result);
28+
mu_assert_string_eq("tail", tail);
29+
mu_assert_int_eq(
30+
StrintParseNoError, strint_to_uint32(" \r\n 123456tail", &tail, &result, 10));
31+
mu_assert_int_eq(123456, result);
32+
mu_assert_string_eq("tail", tail);
33+
}
34+
35+
MU_TEST(strint_test_errors) {
36+
uint32_t result = 123;
37+
mu_assert_int_eq(StrintParseAbsentError, strint_to_uint32("", NULL, &result, 10));
38+
mu_assert_int_eq(123, result);
39+
mu_assert_int_eq(StrintParseAbsentError, strint_to_uint32(" asd\r\n", NULL, &result, 10));
40+
mu_assert_int_eq(123, result);
41+
mu_assert_int_eq(StrintParseSignError, strint_to_uint32("+++123456", NULL, &result, 10));
42+
mu_assert_int_eq(123, result);
43+
mu_assert_int_eq(StrintParseSignError, strint_to_uint32("-1", NULL, &result, 10));
44+
mu_assert_int_eq(123, result);
45+
mu_assert_int_eq(
46+
StrintParseOverflowError,
47+
strint_to_uint32("0xAAAAAAAAAAAAAAAADEADBEEF!!!!!!", NULL, &result, 0));
48+
mu_assert_int_eq(123, result);
49+
mu_assert_int_eq(StrintParseOverflowError, strint_to_uint32("4294967296", NULL, &result, 0));
50+
mu_assert_int_eq(123, result);
51+
52+
int32_t result_i32 = 123;
53+
mu_assert_int_eq(
54+
StrintParseOverflowError, strint_to_int32("-2147483649", NULL, &result_i32, 0));
55+
mu_assert_int_eq(123, result_i32);
56+
}
57+
58+
MU_TEST(strint_test_bases) {
59+
uint32_t result = 0;
60+
61+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0x123", NULL, &result, 0));
62+
mu_assert_int_eq(0x123, result);
63+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0X123", NULL, &result, 0));
64+
mu_assert_int_eq(0x123, result);
65+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0xDEADBEEF", NULL, &result, 0));
66+
mu_assert_int_eq(0xDEADBEEF, result);
67+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0xDEADBEEF", NULL, &result, 16));
68+
mu_assert_int_eq(0xDEADBEEF, result);
69+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123", NULL, &result, 16));
70+
mu_assert_int_eq(0x123, result);
71+
72+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123", NULL, &result, 0));
73+
mu_assert_int_eq(123, result);
74+
75+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0123", NULL, &result, 0));
76+
mu_assert_int_eq(0123, result);
77+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0123", NULL, &result, 8));
78+
mu_assert_int_eq(0123, result);
79+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("123", NULL, &result, 8));
80+
mu_assert_int_eq(0123, result);
81+
82+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0b101", NULL, &result, 0));
83+
mu_assert_int_eq(0b101, result);
84+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0b101", NULL, &result, 2));
85+
mu_assert_int_eq(0b101, result);
86+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("0B101", NULL, &result, 0));
87+
mu_assert_int_eq(0b101, result);
88+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("101", NULL, &result, 2));
89+
mu_assert_int_eq(0b101, result);
90+
}
91+
92+
MU_TEST_SUITE(strint_test_limits) {
93+
uint64_t result_u64 = 0;
94+
mu_assert_int_eq(
95+
StrintParseNoError, strint_to_uint64("18446744073709551615", NULL, &result_u64, 0));
96+
// `mu_assert_int_eq' does not support longs :(
97+
mu_assert(UINT64_MAX == result_u64, "result does not equal UINT64_MAX");
98+
99+
int64_t result_i64 = 0;
100+
mu_assert_int_eq(
101+
StrintParseNoError, strint_to_int64("9223372036854775807", NULL, &result_i64, 0));
102+
mu_assert(INT64_MAX == result_i64, "result does not equal INT64_MAX");
103+
mu_assert_int_eq(
104+
StrintParseNoError, strint_to_int64("-9223372036854775808", NULL, &result_i64, 0));
105+
mu_assert(INT64_MIN == result_i64, "result does not equal INT64_MIN");
106+
107+
uint32_t result_u32 = 0;
108+
mu_assert_int_eq(StrintParseNoError, strint_to_uint32("4294967295", NULL, &result_u32, 0));
109+
mu_assert_int_eq(UINT32_MAX, result_u32);
110+
111+
int32_t result_i32 = 0;
112+
mu_assert_int_eq(StrintParseNoError, strint_to_int32("2147483647", NULL, &result_i32, 0));
113+
mu_assert_int_eq(INT32_MAX, result_i32);
114+
mu_assert_int_eq(StrintParseNoError, strint_to_int32("-2147483648", NULL, &result_i32, 0));
115+
mu_assert_int_eq(INT32_MIN, result_i32);
116+
117+
uint16_t result_u16 = 0;
118+
mu_assert_int_eq(StrintParseNoError, strint_to_uint16("65535", NULL, &result_u16, 0));
119+
mu_assert_int_eq(UINT16_MAX, result_u16);
120+
121+
int16_t result_i16 = 0;
122+
mu_assert_int_eq(StrintParseNoError, strint_to_int16("32767", NULL, &result_i16, 0));
123+
mu_assert_int_eq(INT16_MAX, result_i16);
124+
mu_assert_int_eq(StrintParseNoError, strint_to_int16("-32768", NULL, &result_i16, 0));
125+
mu_assert_int_eq(INT16_MIN, result_i16);
126+
}
127+
128+
MU_TEST_SUITE(test_strint_suite) {
129+
MU_RUN_TEST(strint_test_basic);
130+
MU_RUN_TEST(strint_test_junk);
131+
MU_RUN_TEST(strint_test_tail);
132+
MU_RUN_TEST(strint_test_errors);
133+
MU_RUN_TEST(strint_test_bases);
134+
MU_RUN_TEST(strint_test_limits);
135+
}
136+
137+
int run_minunit_test_strint(void) {
138+
MU_RUN_SUITE(test_strint_suite);
139+
return MU_EXIT_CODE;
140+
}
141+
142+
TEST_API_DEFINE(run_minunit_test_strint)

applications/main/bad_usb/helpers/ducky_script.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <gui/gui.h>
44
#include <input/input.h>
55
#include <lib/toolbox/args.h>
6+
#include <lib/toolbox/strint.h>
67
#include <storage/storage.h>
78
#include "ducky_script.h"
89
#include "ducky_script_i.h"
@@ -64,7 +65,7 @@ uint16_t ducky_get_keycode(BadUsbScript* bad_usb, const char* param, bool accept
6465

6566
bool ducky_get_number(const char* param, uint32_t* val) {
6667
uint32_t value = 0;
67-
if(sscanf(param, "%lu", &value) == 1) {
68+
if(strint_to_uint32(param, NULL, &value, 10) == StrintParseNoError) {
6869
*val = value;
6970
return true;
7071
}

applications/main/ibutton/scenes/ibutton_scene_rpc.c

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
#include "../ibutton_i.h"
22

33
void ibutton_scene_rpc_on_enter(void* context) {
4-
iButton* ibutton = context;
4+
UNUSED(context);
5+
}
6+
7+
static void ibutton_rpc_start_emulation(iButton* ibutton) {
58
Popup* popup = ibutton->popup;
69

710
popup_set_header(popup, "iButton", 82, 28, AlignCenter, AlignBottom);
8-
popup_set_text(popup, "RPC mode", 82, 32, AlignCenter, AlignTop);
9-
11+
popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop);
1012
popup_set_icon(popup, 2, 14, &I_iButtonKey_49x44);
1113

1214
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
1315

16+
ibutton_worker_emulate_start(ibutton->worker, ibutton->key);
17+
18+
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
1419
notification_message(ibutton->notifications, &sequence_display_backlight_on);
1520
}
1621

1722
bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
1823
iButton* ibutton = context;
19-
Popup* popup = ibutton->popup;
2024

2125
bool consumed = false;
2226

@@ -27,17 +31,13 @@ bool ibutton_scene_rpc_on_event(void* context, SceneManagerEvent event) {
2731
bool result = false;
2832

2933
if(ibutton_load_key(ibutton, false)) {
30-
popup_set_text(popup, ibutton->key_name, 82, 32, AlignCenter, AlignTop);
31-
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewPopup);
32-
33-
ibutton_notification_message(ibutton, iButtonNotificationMessageEmulateStart);
34-
ibutton_worker_emulate_start(ibutton->worker, ibutton->key);
35-
34+
ibutton_rpc_start_emulation(ibutton);
3635
result = true;
36+
} else {
37+
rpc_system_app_set_error_code(ibutton->rpc, RpcAppSystemErrorCodeParseFile);
38+
rpc_system_app_set_error_text(ibutton->rpc, "Cannot load key file");
3739
}
38-
3940
rpc_system_app_confirm(ibutton->rpc, result);
40-
4141
} else if(event.event == iButtonCustomEventRpcExit) {
4242
rpc_system_app_confirm(ibutton->rpc, true);
4343
scene_manager_stop(ibutton->scene_manager);

applications/main/infrared/infrared_app.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -382,17 +382,15 @@ void infrared_tx_start(InfraredApp* infrared) {
382382
infrared->app_state.is_transmitting = true;
383383
}
384384

385-
void infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index) {
385+
bool infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index) {
386386
furi_assert(button_index < infrared_remote_get_signal_count(infrared->remote));
387387

388-
if(infrared_remote_load_signal(infrared->remote, infrared->current_signal, button_index)) {
388+
bool result =
389+
infrared_remote_load_signal(infrared->remote, infrared->current_signal, button_index);
390+
if(result) {
389391
infrared_tx_start(infrared);
390-
} else {
391-
infrared_show_error_message(
392-
infrared,
393-
"Failed to load\n\"%s\"",
394-
infrared_remote_get_signal_name(infrared->remote, button_index));
395392
}
393+
return result;
396394
}
397395

398396
void infrared_tx_stop(InfraredApp* infrared) {

applications/main/infrared/infrared_app_i.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ void infrared_tx_start(InfraredApp* infrared);
208208
* @param[in] button_index index of the signal to be loaded.
209209
* @returns true if the signal could be loaded, false otherwise.
210210
*/
211-
void infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index);
211+
bool infrared_tx_start_button_index(InfraredApp* infrared, size_t button_index);
212212

213213
/**
214214
* @brief Stop transmission of the currently loaded signal.

applications/main/infrared/infrared_cli.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <furi_hal_infrared.h>
66
#include <flipper_format.h>
77
#include <toolbox/args.h>
8+
#include <toolbox/strint.h>
89
#include <m-dict.h>
910

1011
#include "infrared_signal.h"
@@ -176,25 +177,28 @@ static bool infrared_cli_parse_raw(const char* str, InfraredSignal* signal) {
176177
return false;
177178
}
178179

179-
uint32_t* timings = malloc(sizeof(uint32_t) * MAX_TIMINGS_AMOUNT);
180-
uint32_t frequency = atoi(frequency_str);
181-
float duty_cycle = (float)atoi(duty_cycle_str) / 100;
180+
uint32_t frequency;
181+
uint32_t duty_cycle_u32;
182+
if(strint_to_uint32(frequency_str, NULL, &frequency, 10) != StrintParseNoError ||
183+
strint_to_uint32(duty_cycle_str, NULL, &duty_cycle_u32, 10) != StrintParseNoError)
184+
return false;
185+
float duty_cycle = duty_cycle_u32 / 100.0f;
182186

183187
str += strlen(frequency_str) + strlen(duty_cycle_str) + INFRARED_CLI_BUF_SIZE;
184188

189+
uint32_t* timings = malloc(sizeof(uint32_t) * MAX_TIMINGS_AMOUNT);
185190
size_t timings_size = 0;
186191
while(1) {
187192
while(*str == ' ') {
188193
++str;
189194
}
190195

191-
char timing_str[INFRARED_CLI_BUF_SIZE];
192-
if(sscanf(str, "%9s", timing_str) != 1) {
196+
uint32_t timing;
197+
char* next_token;
198+
if(strint_to_uint32(str, &next_token, &timing, 10) != StrintParseNoError) {
193199
break;
194200
}
195-
196-
str += strlen(timing_str);
197-
uint32_t timing = atoi(timing_str);
201+
str = next_token;
198202

199203
if((timing <= 0) || (timings_size >= MAX_TIMINGS_AMOUNT)) {
200204
break;

0 commit comments

Comments
 (0)