Merge remote-tracking branch 'ofw/dev' into mntm-dev

This commit is contained in:
Willy-JL
2025-02-28 00:56:55 +00:00
81 changed files with 1521 additions and 1815 deletions

View File

@@ -2,6 +2,7 @@
#include <furi.h>
#include <furi_hal.h>
#include <stdarg.h>
#include <power/power_service/power.h>
void AccessorApp::run(void) {
AccessorEvent event;
@@ -35,16 +36,18 @@ AccessorApp::AccessorApp()
: text_store{0} {
notification = static_cast<NotificationApp*>(furi_record_open(RECORD_NOTIFICATION));
expansion = static_cast<Expansion*>(furi_record_open(RECORD_EXPANSION));
power = static_cast<Power*>(furi_record_open(RECORD_POWER));
onewire_host = onewire_host_alloc(&gpio_ibutton);
expansion_disable(expansion);
furi_hal_power_enable_otg();
power_enable_otg(power, true);
}
AccessorApp::~AccessorApp() {
furi_hal_power_disable_otg();
power_enable_otg(power, false);
expansion_enable(expansion);
furi_record_close(RECORD_EXPANSION);
furi_record_close(RECORD_NOTIFICATION);
furi_record_close(RECORD_POWER);
onewire_host_free(onewire_host);
}

View File

@@ -7,6 +7,7 @@
#include <one_wire/one_wire_host.h>
#include <notification/notification_messages.h>
#include <expansion/expansion.h>
#include <power/power_service/power.h>
class AccessorApp {
public:
@@ -53,4 +54,5 @@ private:
NotificationApp* notification;
Expansion* expansion;
Power* power;
};

View File

@@ -24,8 +24,49 @@ typedef enum {
CrashTestSubmenuAssertMessage,
CrashTestSubmenuCrash,
CrashTestSubmenuHalt,
CrashTestSubmenuHeapUnderflow,
CrashTestSubmenuHeapOverflow,
} CrashTestSubmenu;
static void crash_test_corrupt_heap_underflow(void) {
const size_t block_size = 1000;
const size_t underflow_size = 123;
uint8_t* block = malloc(block_size);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow" // that's what we want!
memset(block - underflow_size, 0xDD, underflow_size); // -V769
#pragma GCC diagnostic pop
free(block); // should crash here (if compiled with DEBUG=1)
// If we got here, the heap wasn't able to detect our corruption and crash
furi_crash("Test failed, should've crashed with \"FreeRTOS Assert\" error");
}
static void crash_test_corrupt_heap_overflow(void) {
const size_t block_size = 1000;
const size_t overflow_size = 123;
uint8_t* block1 = malloc(block_size);
uint8_t* block2 = malloc(block_size);
memset(block2, 12, 34); // simulate use to avoid optimization // -V597 // -V1086
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstringop-overflow" // that's what we want!
memset(block1 + block_size, 0xDD, overflow_size); // -V769 // -V512
#pragma GCC diagnostic pop
uint8_t* block3 = malloc(block_size);
memset(block3, 12, 34); // simulate use to avoid optimization // -V597 // -V1086
free(block3); // should crash here (if compiled with DEBUG=1)
free(block2);
free(block1);
// If we got here, the heap wasn't able to detect our corruption and crash
furi_crash("Test failed, should've crashed with \"FreeRTOS Assert\" error");
}
static void crash_test_submenu_callback(void* context, uint32_t index) {
CrashTest* instance = (CrashTest*)context;
UNUSED(instance);
@@ -49,6 +90,12 @@ static void crash_test_submenu_callback(void* context, uint32_t index) {
case CrashTestSubmenuHalt:
furi_halt("Crash test: furi_halt");
break;
case CrashTestSubmenuHeapUnderflow:
crash_test_corrupt_heap_underflow();
break;
case CrashTestSubmenuHeapOverflow:
crash_test_corrupt_heap_overflow();
break;
default:
furi_crash();
}
@@ -94,6 +141,18 @@ CrashTest* crash_test_alloc(void) {
instance->submenu, "Crash", CrashTestSubmenuCrash, crash_test_submenu_callback, instance);
submenu_add_item(
instance->submenu, "Halt", CrashTestSubmenuHalt, crash_test_submenu_callback, instance);
submenu_add_item(
instance->submenu,
"Heap underflow",
CrashTestSubmenuHeapUnderflow,
crash_test_submenu_callback,
instance);
submenu_add_item(
instance->submenu,
"Heap overflow",
CrashTestSubmenuHeapOverflow,
crash_test_submenu_callback,
instance);
return instance;
}

View File

@@ -16,6 +16,9 @@
#define LINES_ON_SCREEN 6
#define COLUMNS_ON_SCREEN 21
#define DEFAULT_BAUD_RATE 230400
#define DEFAULT_DATA_BITS FuriHalSerialDataBits8
#define DEFAULT_PARITY FuriHalSerialParityNone
#define DEFAULT_STOP_BITS FuriHalSerialStopBits1
typedef struct UartDumpModel UartDumpModel;
@@ -49,11 +52,12 @@ typedef enum {
WorkerEventRxOverrunError = (1 << 4),
WorkerEventRxFramingError = (1 << 5),
WorkerEventRxNoiseError = (1 << 6),
WorkerEventRxParityError = (1 << 7),
} WorkerEventFlags;
#define WORKER_EVENTS_MASK \
(WorkerEventStop | WorkerEventRxData | WorkerEventRxIdle | WorkerEventRxOverrunError | \
WorkerEventRxFramingError | WorkerEventRxNoiseError)
WorkerEventRxFramingError | WorkerEventRxNoiseError | WorkerEventRxParityError)
const NotificationSequence sequence_notification = {
&message_display_backlight_on,
@@ -62,6 +66,13 @@ const NotificationSequence sequence_notification = {
NULL,
};
const NotificationSequence sequence_error = {
&message_display_backlight_on,
&message_red_255,
&message_delay_10,
NULL,
};
static void uart_echo_view_draw_callback(Canvas* canvas, void* _model) {
UartDumpModel* model = _model;
@@ -133,6 +144,9 @@ static void
if(event & FuriHalSerialRxEventOverrunError) {
flag |= WorkerEventRxOverrunError;
}
if(event & FuriHalSerialRxEventParityError) {
flag |= WorkerEventRxParityError;
}
furi_thread_flags_set(furi_thread_get_id(app->worker_thread), flag);
}
@@ -227,13 +241,21 @@ static int32_t uart_echo_worker(void* context) {
if(events & WorkerEventRxNoiseError) {
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect NE\r\n", 13);
}
if(events & WorkerEventRxParityError) {
furi_hal_serial_tx(app->serial_handle, (uint8_t*)"\r\nDetect PE\r\n", 13);
}
notification_message(app->notification, &sequence_error);
}
}
return 0;
}
static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) {
static UartEchoApp* uart_echo_app_alloc(
uint32_t baudrate,
FuriHalSerialDataBits data_bits,
FuriHalSerialParity parity,
FuriHalSerialStopBits stop_bits) {
UartEchoApp* app = malloc(sizeof(UartEchoApp));
app->rx_stream = furi_stream_buffer_alloc(2048, 1);
@@ -275,6 +297,7 @@ static UartEchoApp* uart_echo_app_alloc(uint32_t baudrate) {
app->serial_handle = furi_hal_serial_control_acquire(FuriHalSerialIdUsart);
furi_check(app->serial_handle);
furi_hal_serial_init(app->serial_handle, baudrate);
furi_hal_serial_configure_framing(app->serial_handle, data_bits, parity, stop_bits);
furi_hal_serial_async_rx_start(app->serial_handle, uart_echo_on_irq_cb, app, true);
@@ -319,19 +342,76 @@ static void uart_echo_app_free(UartEchoApp* app) {
free(app);
}
// silences "same-assignment" false positives in the arg parser below
// -V::1048
int32_t uart_echo_app(void* p) {
uint32_t baudrate = DEFAULT_BAUD_RATE;
FuriHalSerialDataBits data_bits = DEFAULT_DATA_BITS;
FuriHalSerialParity parity = DEFAULT_PARITY;
FuriHalSerialStopBits stop_bits = DEFAULT_STOP_BITS;
if(p) {
const char* baudrate_str = p;
if(strint_to_uint32(baudrate_str, NULL, &baudrate, 10) != StrintParseNoError) {
FURI_LOG_E(TAG, "Invalid baudrate: %s", baudrate_str);
baudrate = DEFAULT_BAUD_RATE;
// parse argument
char* parse_ptr = p;
bool parse_success = false;
do {
if(strint_to_uint32(parse_ptr, &parse_ptr, &baudrate, 10) != StrintParseNoError) break;
if(*(parse_ptr++) != '_') break;
uint16_t data_bits_int;
if(strint_to_uint16(parse_ptr, &parse_ptr, &data_bits_int, 10) != StrintParseNoError)
break;
if(data_bits_int == 6)
data_bits = FuriHalSerialDataBits6;
else if(data_bits_int == 7)
data_bits = FuriHalSerialDataBits7;
else if(data_bits_int == 8)
data_bits = FuriHalSerialDataBits8;
else if(data_bits_int == 9)
data_bits = FuriHalSerialDataBits9;
else
break;
char parity_char = *(parse_ptr++);
if(parity_char == 'N')
parity = FuriHalSerialParityNone;
else if(parity_char == 'E')
parity = FuriHalSerialParityEven;
else if(parity_char == 'O')
parity = FuriHalSerialParityOdd;
else
break;
uint16_t stop_bits_int;
if(strint_to_uint16(parse_ptr, &parse_ptr, &stop_bits_int, 10) != StrintParseNoError)
break;
if(stop_bits_int == 5)
stop_bits = FuriHalSerialStopBits0_5;
else if(stop_bits_int == 1)
stop_bits = FuriHalSerialStopBits1;
else if(stop_bits_int == 15)
stop_bits = FuriHalSerialStopBits1_5;
else if(stop_bits_int == 2)
stop_bits = FuriHalSerialStopBits2;
else
break;
parse_success = true;
} while(0);
if(!parse_success) {
FURI_LOG_I(
TAG,
"Couldn't parse baud rate and framing (%s). Applying defaults (%d_8N1)",
(const char*)p,
DEFAULT_BAUD_RATE);
}
}
FURI_LOG_I(TAG, "Using baudrate: %lu", baudrate);
UartEchoApp* app = uart_echo_app_alloc(baudrate);
UartEchoApp* app = uart_echo_app_alloc(baudrate, data_bits, parity, stop_bits);
view_dispatcher_run(app->view_dispatcher);
uart_echo_app_free(app);
return 0;

View File

@@ -12,4 +12,4 @@ tests.assert_eq(false, doesSdkSupport(["abobus", "other-nonexistent-feature"]));
tests.assert_eq("momentum", flipper.firmwareVendor);
tests.assert_eq(0, flipper.jsSdkVersion[0]);
tests.assert_eq(2, flipper.jsSdkVersion[1]);
tests.assert_eq(3, flipper.jsSdkVersion[1]);

View File

@@ -30,7 +30,9 @@ static size_t mock_in_cb(char* buffer, size_t size, FuriWait wait, void* context
}
void test_stdin(void) {
FuriThreadStdinReadCallback in_cb = furi_thread_get_stdin_callback();
FuriThreadStdinReadCallback in_cb;
void* in_ctx;
furi_thread_get_stdin_callback(&in_cb, &in_ctx);
furi_thread_set_stdin_callback(mock_in_cb, CONTEXT_MAGIC);
char buf[256];
@@ -63,13 +65,14 @@ void test_stdin(void) {
fgets(buf, sizeof(buf), stdin);
mu_assert_string_eq(" World!\n", buf);
furi_thread_set_stdin_callback(in_cb, CONTEXT_MAGIC);
furi_thread_set_stdin_callback(in_cb, in_ctx);
}
// stdout
static FuriString* mock_out;
FuriThreadStdoutWriteCallback original_out_cb;
static FuriThreadStdoutWriteCallback original_out_cb;
static void* original_out_ctx;
static void mock_out_cb(const char* data, size_t size, void* context) {
furi_check(context == CONTEXT_MAGIC);
@@ -83,7 +86,7 @@ static void assert_and_clear_mock_out(const char* expected) {
// return the original stdout callback for the duration of the check
// if the check fails, we don't want the error to end up in our buffer,
// we want to be able to see it!
furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC);
furi_thread_set_stdout_callback(original_out_cb, original_out_ctx);
mu_assert_string_eq(expected, furi_string_get_cstr(mock_out));
furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC);
@@ -91,7 +94,7 @@ static void assert_and_clear_mock_out(const char* expected) {
}
void test_stdout(void) {
original_out_cb = furi_thread_get_stdout_callback();
furi_thread_get_stdout_callback(&original_out_cb, &original_out_ctx);
furi_thread_set_stdout_callback(mock_out_cb, CONTEXT_MAGIC);
mock_out = furi_string_alloc();
@@ -104,5 +107,5 @@ void test_stdout(void) {
assert_and_clear_mock_out("Hello!");
furi_string_free(mock_out);
furi_thread_set_stdout_callback(original_out_cb, CONTEXT_MAGIC);
furi_thread_set_stdout_callback(original_out_cb, original_out_ctx);
}