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 | ||||
| 
 | ||||
| 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; | ||||
|  | ||||
| @ -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(); | ||||
|  | ||||
| @ -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)                            \ | ||||
| #define __furi_check(__e, __m) \ | ||||
|     do {                       \ | ||||
|         if(!(__e)) {           \ | ||||
|             furi_crash(__FURI_CHECK_MESSAGE_FLAG); \ | ||||
|             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)                            \ | ||||
| #define __furi_assert(__e, __m) \ | ||||
|     do {                        \ | ||||
|         if(!(__e)) {            \ | ||||
|             furi_crash(__FURI_ASSERT_MESSAGE_FLAG); \ | ||||
|             furi_crash(__m);    \ | ||||
|         }                       \ | ||||
|     } while(0) | ||||
| #else | ||||
| #define furi_assert(__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,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) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく