Furi,FuriHal: various improvements (#2819)

* 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>
This commit is contained in:
あく 2023-06-30 18:52:43 +09:00 committed by GitHub
parent 5d40193308
commit 6d9de25494
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 218 additions and 33 deletions

View file

@ -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",
)

View file

@ -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;
}

View file

@ -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);
@ -79,6 +88,13 @@ 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);
@ -86,9 +102,15 @@ void furi_hal_bt_init() {
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
@ -99,13 +121,13 @@ 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) {
@ -113,26 +135,26 @@ static bool furi_hal_bt_radio_stack_is_supported(const BleGlueC2Info* info) {
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);
@ -166,17 +188,17 @@ 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;
@ -184,7 +206,7 @@ bool furi_hal_bt_is_ble_gatt_gap_supported() {
}
bool furi_hal_bt_is_testing_supported() {
if(furi_hal_bt_stack == FuriHalBtStackFull) {
if(furi_hal_bt.stack == FuriHalBtStackFull) {
return true;
} else {
return false;

View file

@ -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();

View file

@ -13,6 +13,8 @@
*/
#pragma once
#include <m-core.h>
#ifdef __cplusplus
extern "C" {
#define FURI_NORETURN [[noreturn]]
@ -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

View file

@ -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) {