Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions applications/debug/crash_test/application.fam
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
App(
appid="crash_test",
name="Crash Test",
apptype=FlipperAppType.DEBUG,
entry_point="crash_test_app",
cdefines=["APP_CRASH_TEST"],
requires=["gui"],
stack_size=1 * 1024,
fap_category="Debug",
)
128 changes: 128 additions & 0 deletions applications/debug/crash_test/crash_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include <furi_hal.h>
#include <furi.h>

#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/submenu.h>

#define TAG "CrashTest"

typedef struct {
Gui* gui;
ViewDispatcher* view_dispatcher;
Submenu* submenu;
} CrashTest;

typedef enum {
CrashTestViewSubmenu,
} CrashTestView;

typedef enum {
CrashTestSubmenuCheck,
CrashTestSubmenuCheckMessage,
CrashTestSubmenuAssert,
CrashTestSubmenuAssertMessage,
CrashTestSubmenuCrash,
CrashTestSubmenuHalt,
} CrashTestSubmenu;

static void crash_test_submenu_callback(void* context, uint32_t index) {
CrashTest* instance = (CrashTest*)context;
UNUSED(instance);

switch(index) {
case CrashTestSubmenuCheck:
furi_check(false);
break;
case CrashTestSubmenuCheckMessage:
furi_check(false, "Crash test: furi_check with message");
break;
case CrashTestSubmenuAssert:
furi_assert(false);
break;
case CrashTestSubmenuAssertMessage:
furi_assert(false, "Crash test: furi_assert with message");
break;
case CrashTestSubmenuCrash:
furi_crash("Crash test: furi_crash");
break;
case CrashTestSubmenuHalt:
furi_halt("Crash test: furi_halt");
break;
default:
furi_crash("Programming error");
}
}

static uint32_t crash_test_exit_callback(void* context) {
UNUSED(context);
return VIEW_NONE;
}

CrashTest* crash_test_alloc() {
CrashTest* instance = malloc(sizeof(CrashTest));

View* view = NULL;

instance->gui = furi_record_open(RECORD_GUI);
instance->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(instance->view_dispatcher);
view_dispatcher_attach_to_gui(
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);

// Menu
instance->submenu = submenu_alloc();
view = submenu_get_view(instance->submenu);
view_set_previous_callback(view, crash_test_exit_callback);
view_dispatcher_add_view(instance->view_dispatcher, CrashTestViewSubmenu, view);
submenu_add_item(
instance->submenu, "Check", CrashTestSubmenuCheck, crash_test_submenu_callback, instance);
submenu_add_item(
instance->submenu,
"Check with message",
CrashTestSubmenuCheckMessage,
crash_test_submenu_callback,
instance);
submenu_add_item(
instance->submenu, "Assert", CrashTestSubmenuAssert, crash_test_submenu_callback, instance);
submenu_add_item(
instance->submenu,
"Assert with message",
CrashTestSubmenuAssertMessage,
crash_test_submenu_callback,
instance);
submenu_add_item(
instance->submenu, "Crash", CrashTestSubmenuCrash, crash_test_submenu_callback, instance);
submenu_add_item(
instance->submenu, "Halt", CrashTestSubmenuHalt, crash_test_submenu_callback, instance);

return instance;
}

void crash_test_free(CrashTest* instance) {
view_dispatcher_remove_view(instance->view_dispatcher, CrashTestViewSubmenu);
submenu_free(instance->submenu);

view_dispatcher_free(instance->view_dispatcher);
furi_record_close(RECORD_GUI);

free(instance);
}

int32_t crash_test_run(CrashTest* instance) {
view_dispatcher_switch_to_view(instance->view_dispatcher, CrashTestViewSubmenu);
view_dispatcher_run(instance->view_dispatcher);
return 0;
}

int32_t crash_test_app(void* p) {
UNUSED(p);

CrashTest* instance = crash_test_alloc();

int32_t ret = crash_test_run(instance);

crash_test_free(instance);

return ret;
}
58 changes: 40 additions & 18 deletions firmware/targets/f7/furi_hal/furi_hal_bt.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,17 @@

#define FURI_HAL_BT_HARDFAULT_INFO_MAGIC 0x1170FD0F

FuriMutex* furi_hal_bt_core2_mtx = NULL;
static FuriHalBtStack furi_hal_bt_stack = FuriHalBtStackUnknown;
typedef struct {
FuriMutex* core2_mtx;
FuriTimer* hardfault_check_timer;
FuriHalBtStack stack;
} FuriHalBt;

static FuriHalBt furi_hal_bt = {
.core2_mtx = NULL,
.hardfault_check_timer = NULL,
.stack = FuriHalBtStackUnknown,
};

typedef void (*FuriHalBtProfileStart)(void);
typedef void (*FuriHalBtProfileStop)(void);
Expand Down Expand Up @@ -79,16 +88,29 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = {
};
FuriHalBtProfileConfig* current_profile = NULL;

static void furi_hal_bt_hardfault_check(void* context) {
UNUSED(context);
if(furi_hal_bt_get_hardfault_info()) {
furi_crash("ST(R) Copro(R) HardFault");
}
}

void furi_hal_bt_init() {
furi_hal_bus_enable(FuriHalBusHSEM);
furi_hal_bus_enable(FuriHalBusIPCC);
furi_hal_bus_enable(FuriHalBusAES2);
furi_hal_bus_enable(FuriHalBusPKA);
furi_hal_bus_enable(FuriHalBusCRC);

if(!furi_hal_bt_core2_mtx) {
furi_hal_bt_core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
furi_assert(furi_hal_bt_core2_mtx);
if(!furi_hal_bt.core2_mtx) {
furi_hal_bt.core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
furi_assert(furi_hal_bt.core2_mtx);
}

if(!furi_hal_bt.hardfault_check_timer) {
furi_hal_bt.hardfault_check_timer =
furi_timer_alloc(furi_hal_bt_hardfault_check, FuriTimerTypePeriodic, NULL);
furi_timer_start(furi_hal_bt.hardfault_check_timer, 5000);
}

// Explicitly tell that we are in charge of CLK48 domain
Expand All @@ -99,40 +121,40 @@ void furi_hal_bt_init() {
}

void furi_hal_bt_lock_core2() {
furi_assert(furi_hal_bt_core2_mtx);
furi_check(furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever) == FuriStatusOk);
furi_assert(furi_hal_bt.core2_mtx);
furi_check(furi_mutex_acquire(furi_hal_bt.core2_mtx, FuriWaitForever) == FuriStatusOk);
}

void furi_hal_bt_unlock_core2() {
furi_assert(furi_hal_bt_core2_mtx);
furi_check(furi_mutex_release(furi_hal_bt_core2_mtx) == FuriStatusOk);
furi_assert(furi_hal_bt.core2_mtx);
furi_check(furi_mutex_release(furi_hal_bt.core2_mtx) == FuriStatusOk);
}

static bool furi_hal_bt_radio_stack_is_supported(const BleGlueC2Info* info) {
bool supported = false;
if(info->StackType == INFO_STACK_TYPE_BLE_LIGHT) {
if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR &&
info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) {
furi_hal_bt_stack = FuriHalBtStackLight;
furi_hal_bt.stack = FuriHalBtStackLight;
supported = true;
}
} else if(info->StackType == INFO_STACK_TYPE_BLE_FULL) {
if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR &&
info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) {
furi_hal_bt_stack = FuriHalBtStackFull;
furi_hal_bt.stack = FuriHalBtStackFull;
supported = true;
}
} else {
furi_hal_bt_stack = FuriHalBtStackUnknown;
furi_hal_bt.stack = FuriHalBtStackUnknown;
}
return supported;
}

bool furi_hal_bt_start_radio_stack() {
bool res = false;
furi_assert(furi_hal_bt_core2_mtx);
furi_assert(furi_hal_bt.core2_mtx);

furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever);
furi_mutex_acquire(furi_hal_bt.core2_mtx, FuriWaitForever);

// Explicitly tell that we are in charge of CLK48 domain
furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0);
Expand Down Expand Up @@ -166,25 +188,25 @@ bool furi_hal_bt_start_radio_stack() {
}
res = true;
} while(false);
furi_mutex_release(furi_hal_bt_core2_mtx);
furi_mutex_release(furi_hal_bt.core2_mtx);

return res;
}

FuriHalBtStack furi_hal_bt_get_radio_stack() {
return furi_hal_bt_stack;
return furi_hal_bt.stack;
}

bool furi_hal_bt_is_ble_gatt_gap_supported() {
if(furi_hal_bt_stack == FuriHalBtStackLight || furi_hal_bt_stack == FuriHalBtStackFull) {
if(furi_hal_bt.stack == FuriHalBtStackLight || furi_hal_bt.stack == FuriHalBtStackFull) {
return true;
} else {
return false;
}
}

bool furi_hal_bt_is_testing_supported() {
if(furi_hal_bt_stack == FuriHalBtStackFull) {
if(furi_hal_bt.stack == FuriHalBtStackFull) {
return true;
} else {
return false;
Expand Down
6 changes: 5 additions & 1 deletion furi/core/check.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,11 @@ FURI_NORETURN void __furi_crash() {
RESTORE_REGISTERS_AND_HALT_MCU(true);
#ifndef FURI_DEBUG
} else {
furi_hal_rtc_set_fault_data((uint32_t)__furi_check_message);
uint32_t ptr = (uint32_t)__furi_check_message;
if(ptr < FLASH_BASE || ptr > (FLASH_BASE + FLASH_SIZE)) {
ptr = (uint32_t) "Check serial logs";
}
furi_hal_rtc_set_fault_data(ptr);
furi_hal_console_puts("\r\nRebooting system.\r\n");
furi_hal_console_puts("\033[0m\r\n");
furi_hal_power_reset();
Expand Down
47 changes: 34 additions & 13 deletions furi/core/check.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
*/
#pragma once

#include <m-core.h>

#ifdef __cplusplus
extern "C" {
#define FURI_NORETURN [[noreturn]]
Expand Down Expand Up @@ -48,28 +50,47 @@ FURI_NORETURN void __furi_halt();
} while(0)

/** Check condition and crash if check failed */
#define furi_check(__e) \
do { \
if(!(__e)) { \
furi_crash(__FURI_CHECK_MESSAGE_FLAG); \
} \
#define __furi_check(__e, __m) \
do { \
if(!(__e)) { \
furi_crash(__m); \
} \
} while(0)

/** Check condition and crash if failed
*
* @param condition to check
* @param optional message
*/
#define furi_check(...) \
M_APPLY(__furi_check, M_DEFAULT_ARGS(2, (__FURI_CHECK_MESSAGE_FLAG), __VA_ARGS__))

/** Only in debug build: Assert condition and crash if assert failed */
#ifdef FURI_DEBUG
#define furi_assert(__e) \
do { \
if(!(__e)) { \
furi_crash(__FURI_ASSERT_MESSAGE_FLAG); \
} \
#define __furi_assert(__e, __m) \
do { \
if(!(__e)) { \
furi_crash(__m); \
} \
} while(0)
#else
#define furi_assert(__e) \
do { \
((void)(__e)); \
#define __furi_assert(__e, __m) \
do { \
((void)(__e)); \
((void)(__m)); \
} while(0)
#endif

/** Assert condition and crash if failed
*
* @warning only will do check if firmware compiled in debug mode
*
* @param condition to check
* @param optional message
*/
#define furi_assert(...) \
M_APPLY(__furi_assert, M_DEFAULT_ARGS(2, (__FURI_ASSERT_MESSAGE_FLAG), __VA_ARGS__))

#ifdef __cplusplus
}
#endif
2 changes: 1 addition & 1 deletion lib/u8g2/u8g2_glue.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

#include <furi_hal.h>

#define CONTRAST_ERC 32
#define CONTRAST_ERC 31
#define CONTRAST_MGG 31

uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
Expand Down