Skip to content

Commit

Permalink
Furi,FuriHal: various improvements (#2819)
Browse files Browse the repository at this point in the history
* Lib: adjust default contrast for ERC displays

* Furi: various improvements in check module

* Format Sources

* FurHal: ble early hardfault detection

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
  • Loading branch information
skotopes and hedger authored Jun 30, 2023
1 parent 5d40193 commit 6d9de25
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 33 deletions.
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

0 comments on commit 6d9de25

Please sign in to comment.