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:
parent
5d40193308
commit
6d9de25494
10
applications/debug/crash_test/application.fam
Normal file
10
applications/debug/crash_test/application.fam
Normal 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",
|
||||||
|
)
|
||||||
128
applications/debug/crash_test/crash_test.c
Normal file
128
applications/debug/crash_test/crash_test.c
Normal 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;
|
||||||
|
}
|
||||||
@ -21,8 +21,17 @@
|
|||||||
|
|
||||||
#define FURI_HAL_BT_HARDFAULT_INFO_MAGIC 0x1170FD0F
|
#define FURI_HAL_BT_HARDFAULT_INFO_MAGIC 0x1170FD0F
|
||||||
|
|
||||||
FuriMutex* furi_hal_bt_core2_mtx = NULL;
|
typedef struct {
|
||||||
static FuriHalBtStack furi_hal_bt_stack = FuriHalBtStackUnknown;
|
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 (*FuriHalBtProfileStart)(void);
|
||||||
typedef void (*FuriHalBtProfileStop)(void);
|
typedef void (*FuriHalBtProfileStop)(void);
|
||||||
@ -79,6 +88,13 @@ FuriHalBtProfileConfig profile_config[FuriHalBtProfileNumber] = {
|
|||||||
};
|
};
|
||||||
FuriHalBtProfileConfig* current_profile = NULL;
|
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() {
|
void furi_hal_bt_init() {
|
||||||
furi_hal_bus_enable(FuriHalBusHSEM);
|
furi_hal_bus_enable(FuriHalBusHSEM);
|
||||||
furi_hal_bus_enable(FuriHalBusIPCC);
|
furi_hal_bus_enable(FuriHalBusIPCC);
|
||||||
@ -86,9 +102,15 @@ void furi_hal_bt_init() {
|
|||||||
furi_hal_bus_enable(FuriHalBusPKA);
|
furi_hal_bus_enable(FuriHalBusPKA);
|
||||||
furi_hal_bus_enable(FuriHalBusCRC);
|
furi_hal_bus_enable(FuriHalBusCRC);
|
||||||
|
|
||||||
if(!furi_hal_bt_core2_mtx) {
|
if(!furi_hal_bt.core2_mtx) {
|
||||||
furi_hal_bt_core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
|
furi_hal_bt.core2_mtx = furi_mutex_alloc(FuriMutexTypeNormal);
|
||||||
furi_assert(furi_hal_bt_core2_mtx);
|
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
|
// 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() {
|
void furi_hal_bt_lock_core2() {
|
||||||
furi_assert(furi_hal_bt_core2_mtx);
|
furi_assert(furi_hal_bt.core2_mtx);
|
||||||
furi_check(furi_mutex_acquire(furi_hal_bt_core2_mtx, FuriWaitForever) == FuriStatusOk);
|
furi_check(furi_mutex_acquire(furi_hal_bt.core2_mtx, FuriWaitForever) == FuriStatusOk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void furi_hal_bt_unlock_core2() {
|
void furi_hal_bt_unlock_core2() {
|
||||||
furi_assert(furi_hal_bt_core2_mtx);
|
furi_assert(furi_hal_bt.core2_mtx);
|
||||||
furi_check(furi_mutex_release(furi_hal_bt_core2_mtx) == FuriStatusOk);
|
furi_check(furi_mutex_release(furi_hal_bt.core2_mtx) == FuriStatusOk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool furi_hal_bt_radio_stack_is_supported(const BleGlueC2Info* info) {
|
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->StackType == INFO_STACK_TYPE_BLE_LIGHT) {
|
||||||
if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR &&
|
if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR &&
|
||||||
info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) {
|
info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) {
|
||||||
furi_hal_bt_stack = FuriHalBtStackLight;
|
furi_hal_bt.stack = FuriHalBtStackLight;
|
||||||
supported = true;
|
supported = true;
|
||||||
}
|
}
|
||||||
} else if(info->StackType == INFO_STACK_TYPE_BLE_FULL) {
|
} else if(info->StackType == INFO_STACK_TYPE_BLE_FULL) {
|
||||||
if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR &&
|
if(info->VersionMajor >= FURI_HAL_BT_STACK_VERSION_MAJOR &&
|
||||||
info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) {
|
info->VersionMinor >= FURI_HAL_BT_STACK_VERSION_MINOR) {
|
||||||
furi_hal_bt_stack = FuriHalBtStackFull;
|
furi_hal_bt.stack = FuriHalBtStackFull;
|
||||||
supported = true;
|
supported = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
furi_hal_bt_stack = FuriHalBtStackUnknown;
|
furi_hal_bt.stack = FuriHalBtStackUnknown;
|
||||||
}
|
}
|
||||||
return supported;
|
return supported;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_bt_start_radio_stack() {
|
bool furi_hal_bt_start_radio_stack() {
|
||||||
bool res = false;
|
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
|
// Explicitly tell that we are in charge of CLK48 domain
|
||||||
furi_check(LL_HSEM_1StepLock(HSEM, CFG_HW_CLK48_CONFIG_SEMID) == 0);
|
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;
|
res = true;
|
||||||
} while(false);
|
} while(false);
|
||||||
furi_mutex_release(furi_hal_bt_core2_mtx);
|
furi_mutex_release(furi_hal_bt.core2_mtx);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
FuriHalBtStack furi_hal_bt_get_radio_stack() {
|
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() {
|
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;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
@ -184,7 +206,7 @@ bool furi_hal_bt_is_ble_gatt_gap_supported() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool furi_hal_bt_is_testing_supported() {
|
bool furi_hal_bt_is_testing_supported() {
|
||||||
if(furi_hal_bt_stack == FuriHalBtStackFull) {
|
if(furi_hal_bt.stack == FuriHalBtStackFull) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@ -166,7 +166,11 @@ FURI_NORETURN void __furi_crash() {
|
|||||||
RESTORE_REGISTERS_AND_HALT_MCU(true);
|
RESTORE_REGISTERS_AND_HALT_MCU(true);
|
||||||
#ifndef FURI_DEBUG
|
#ifndef FURI_DEBUG
|
||||||
} else {
|
} 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("\r\nRebooting system.\r\n");
|
||||||
furi_hal_console_puts("\033[0m\r\n");
|
furi_hal_console_puts("\033[0m\r\n");
|
||||||
furi_hal_power_reset();
|
furi_hal_power_reset();
|
||||||
|
|||||||
@ -13,6 +13,8 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <m-core.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#define FURI_NORETURN [[noreturn]]
|
#define FURI_NORETURN [[noreturn]]
|
||||||
@ -48,28 +50,47 @@ FURI_NORETURN void __furi_halt();
|
|||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
/** Check condition and crash if check failed */
|
/** Check condition and crash if check failed */
|
||||||
#define furi_check(__e) \
|
#define __furi_check(__e, __m) \
|
||||||
do { \
|
do { \
|
||||||
if(!(__e)) { \
|
if(!(__e)) { \
|
||||||
furi_crash(__FURI_CHECK_MESSAGE_FLAG); \
|
furi_crash(__m); \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} 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 */
|
/** Only in debug build: Assert condition and crash if assert failed */
|
||||||
#ifdef FURI_DEBUG
|
#ifdef FURI_DEBUG
|
||||||
#define furi_assert(__e) \
|
#define __furi_assert(__e, __m) \
|
||||||
do { \
|
do { \
|
||||||
if(!(__e)) { \
|
if(!(__e)) { \
|
||||||
furi_crash(__FURI_ASSERT_MESSAGE_FLAG); \
|
furi_crash(__m); \
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
#else
|
#else
|
||||||
#define furi_assert(__e) \
|
#define __furi_assert(__e, __m) \
|
||||||
do { \
|
do { \
|
||||||
((void)(__e)); \
|
((void)(__e)); \
|
||||||
|
((void)(__m)); \
|
||||||
} while(0)
|
} while(0)
|
||||||
#endif
|
#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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <furi_hal.h>
|
#include <furi_hal.h>
|
||||||
|
|
||||||
#define CONTRAST_ERC 32
|
#define CONTRAST_ERC 31
|
||||||
#define CONTRAST_MGG 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) {
|
uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user