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
	 あく
						あく