[FL-3289] Various Furi/FuriHal bug fixes and improvements (#2637)
* Furi: properly handle thread free before TCB scrapping, add furi_free - more invasive version of free to memmgr. FuriHal: add DWT comparator api to cortex. Updater, RPC: refactor various thread shanenigans. Code cleanup. * Rollback free macros and related changes
This commit is contained in:
		
							parent
							
								
									a7d1ec03e8
								
							
						
					
					
						commit
						914129a0d9
					
				| @ -248,6 +248,7 @@ static void loader_do_app_closed(Loader* loader) { | |||||||
|     free(loader->app.name); |     free(loader->app.name); | ||||||
|     loader->app.name = NULL; |     loader->app.name = NULL; | ||||||
| 
 | 
 | ||||||
|  |     furi_thread_join(loader->app.thread); | ||||||
|     furi_thread_free(loader->app.thread); |     furi_thread_free(loader->app.thread); | ||||||
|     loader->app.thread = NULL; |     loader->app.thread = NULL; | ||||||
| } | } | ||||||
|  | |||||||
| @ -326,31 +326,35 @@ static int32_t rpc_session_worker(void* context) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void rpc_session_free_callback(FuriThreadState thread_state, void* context) { | static void rpc_session_thread_pending_callback(void* context, uint32_t arg) { | ||||||
|     furi_assert(context); |     UNUSED(arg); | ||||||
| 
 |  | ||||||
|     RpcSession* session = (RpcSession*)context; |     RpcSession* session = (RpcSession*)context; | ||||||
| 
 | 
 | ||||||
|  |     for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { | ||||||
|  |         if(rpc_systems[i].free) { | ||||||
|  |             (rpc_systems[i].free)(session->system_contexts[i]); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     free(session->system_contexts); | ||||||
|  |     free(session->decoded_message); | ||||||
|  |     RpcHandlerDict_clear(session->handlers); | ||||||
|  |     furi_stream_buffer_free(session->stream); | ||||||
|  | 
 | ||||||
|  |     furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); | ||||||
|  |     if(session->terminated_callback) { | ||||||
|  |         session->terminated_callback(session->context); | ||||||
|  |     } | ||||||
|  |     furi_mutex_release(session->callbacks_mutex); | ||||||
|  | 
 | ||||||
|  |     furi_mutex_free(session->callbacks_mutex); | ||||||
|  |     furi_thread_join(session->thread); | ||||||
|  |     furi_thread_free(session->thread); | ||||||
|  |     free(session); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void rpc_session_thread_state_callback(FuriThreadState thread_state, void* context) { | ||||||
|     if(thread_state == FuriThreadStateStopped) { |     if(thread_state == FuriThreadStateStopped) { | ||||||
|         for(size_t i = 0; i < COUNT_OF(rpc_systems); ++i) { |         furi_timer_pending_callback(rpc_session_thread_pending_callback, context, 0); | ||||||
|             if(rpc_systems[i].free) { |  | ||||||
|                 rpc_systems[i].free(session->system_contexts[i]); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         free(session->system_contexts); |  | ||||||
|         free(session->decoded_message); |  | ||||||
|         RpcHandlerDict_clear(session->handlers); |  | ||||||
|         furi_stream_buffer_free(session->stream); |  | ||||||
| 
 |  | ||||||
|         furi_mutex_acquire(session->callbacks_mutex, FuriWaitForever); |  | ||||||
|         if(session->terminated_callback) { |  | ||||||
|             session->terminated_callback(session->context); |  | ||||||
|         } |  | ||||||
|         furi_mutex_release(session->callbacks_mutex); |  | ||||||
| 
 |  | ||||||
|         furi_mutex_free(session->callbacks_mutex); |  | ||||||
|         furi_thread_free(session->thread); |  | ||||||
|         free(session); |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -385,7 +389,7 @@ RpcSession* rpc_session_open(Rpc* rpc, RpcOwner owner) { | |||||||
|     session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); |     session->thread = furi_thread_alloc_ex("RpcSessionWorker", 3072, rpc_session_worker, session); | ||||||
| 
 | 
 | ||||||
|     furi_thread_set_state_context(session->thread, session); |     furi_thread_set_state_context(session->thread, session); | ||||||
|     furi_thread_set_state_callback(session->thread, rpc_session_free_callback); |     furi_thread_set_state_callback(session->thread, rpc_session_thread_state_callback); | ||||||
| 
 | 
 | ||||||
|     furi_thread_start(session->thread); |     furi_thread_start(session->thread); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -803,6 +803,7 @@ void storage_file_free(File* file) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FuriPubSub* storage_get_pubsub(Storage* storage) { | FuriPubSub* storage_get_pubsub(Storage* storage) { | ||||||
|  |     furi_assert(storage); | ||||||
|     return storage->pubsub; |     return storage->pubsub; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -337,6 +337,7 @@ static bool storage_ext_file_close(void* ctx, File* file) { | |||||||
|     file->internal_error_id = f_close(file_data); |     file->internal_error_id = f_close(file_data); | ||||||
|     file->error_id = storage_ext_parse_error(file->internal_error_id); |     file->error_id = storage_ext_parse_error(file->internal_error_id); | ||||||
|     free(file_data); |     free(file_data); | ||||||
|  |     storage_set_storage_file_data(file, NULL, storage); | ||||||
|     return (file->error_id == FSE_OK); |     return (file->error_id == FSE_OK); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -53,7 +53,9 @@ static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) { | |||||||
|             (uint32_t)(data->vbus_voltage), |             (uint32_t)(data->vbus_voltage), | ||||||
|             (uint32_t)(data->vbus_voltage * 10) % 10, |             (uint32_t)(data->vbus_voltage * 10) % 10, | ||||||
|             current); |             current); | ||||||
|     } else if(current < 0) { |     } else if(current < -5) { | ||||||
|  |         // Often gauge reports anything in the range 1~5ma as 5ma
 | ||||||
|  |         // That brings confusion, so we'll treat it as Napping
 | ||||||
|         snprintf( |         snprintf( | ||||||
|             emote, |             emote, | ||||||
|             sizeof(emote), |             sizeof(emote), | ||||||
|  | |||||||
| @ -85,22 +85,10 @@ static void updater_cli_ep(Cli* cli, FuriString* args, void* context) { | |||||||
|     updater_cli_help(args); |     updater_cli_help(args); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int32_t updater_spawner_thread_worker(void* arg) { | static void updater_start_app(void* context, uint32_t arg) { | ||||||
|  |     UNUSED(context); | ||||||
|     UNUSED(arg); |     UNUSED(arg); | ||||||
|     Loader* loader = furi_record_open(RECORD_LOADER); |  | ||||||
|     loader_start(loader, "UpdaterApp", NULL); |  | ||||||
|     furi_record_close(RECORD_LOADER); |  | ||||||
|     return 0; |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| static void updater_spawner_thread_cleanup(FuriThreadState state, void* context) { |  | ||||||
|     FuriThread* thread = context; |  | ||||||
|     if(state == FuriThreadStateStopped) { |  | ||||||
|         furi_thread_free(thread); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void updater_start_app() { |  | ||||||
|     FuriHalRtcBootMode mode = furi_hal_rtc_get_boot_mode(); |     FuriHalRtcBootMode mode = furi_hal_rtc_get_boot_mode(); | ||||||
|     if((mode != FuriHalRtcBootModePreUpdate) && (mode != FuriHalRtcBootModePostUpdate)) { |     if((mode != FuriHalRtcBootModePreUpdate) && (mode != FuriHalRtcBootModePostUpdate)) { | ||||||
|         return; |         return; | ||||||
| @ -110,11 +98,9 @@ static void updater_start_app() { | |||||||
|      * inside loader process, at startup.  |      * inside loader process, at startup.  | ||||||
|      * So, accessing its record would cause a deadlock  |      * So, accessing its record would cause a deadlock  | ||||||
|      */ |      */ | ||||||
|     FuriThread* thread = |     Loader* loader = furi_record_open(RECORD_LOADER); | ||||||
|         furi_thread_alloc_ex("UpdateAppSpawner", 768, updater_spawner_thread_worker, NULL); |     loader_start(loader, "UpdaterApp", NULL); | ||||||
|     furi_thread_set_state_callback(thread, updater_spawner_thread_cleanup); |     furi_record_close(RECORD_LOADER); | ||||||
|     furi_thread_set_state_context(thread, thread); |  | ||||||
|     furi_thread_start(thread); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void updater_on_system_start() { | void updater_on_system_start() { | ||||||
| @ -126,7 +112,7 @@ void updater_on_system_start() { | |||||||
|     UNUSED(updater_cli_ep); |     UNUSED(updater_cli_ep); | ||||||
| #endif | #endif | ||||||
| #ifndef FURI_RAM_EXEC | #ifndef FURI_RAM_EXEC | ||||||
|     updater_start_app(); |     furi_timer_pending_callback(updater_start_app, NULL, 0); | ||||||
| #else | #else | ||||||
|     UNUSED(updater_start_app); |     UNUSED(updater_start_app); | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -346,7 +346,11 @@ int32_t update_task_worker_flash_writer(void* context) { | |||||||
|         furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); |         furi_hal_rtc_set_boot_mode(FuriHalRtcBootModePostUpdate); | ||||||
|         // Format LFS before restoring backup on next boot
 |         // Format LFS before restoring backup on next boot
 | ||||||
|         furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); |         furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset); | ||||||
| 
 | #ifdef FURI_NDEBUG | ||||||
|  |         // Production
 | ||||||
|  |         furi_hal_rtc_set_log_level(FuriLogLevelDefault); | ||||||
|  |         furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug); | ||||||
|  | #endif | ||||||
|         update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); |         update_task_set_progress(update_task, UpdateTaskStageCompleted, 100); | ||||||
|         success = true; |         success = true; | ||||||
|     } while(false); |     } while(false); | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,24.0,, | Version,+,26.0,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.h,, | Header,+,applications/services/cli/cli_vcp.h,, | ||||||
| @ -892,6 +892,8 @@ Function,+,furi_hal_console_puts,void,const char* | |||||||
| Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" | Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" | ||||||
| Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" | Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" | ||||||
| Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" | Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" | ||||||
|  | Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" | ||||||
|  | Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp | ||||||
| Function,+,furi_hal_cortex_delay_us,void,uint32_t | Function,+,furi_hal_cortex_delay_us,void,uint32_t | ||||||
| Function,-,furi_hal_cortex_init_early,void, | Function,-,furi_hal_cortex_init_early,void, | ||||||
| Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, | Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, | ||||||
| @ -1278,7 +1280,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" | |||||||
| Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" | Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" | ||||||
| Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" | Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" | ||||||
| Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" | Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" | ||||||
| Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback | Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback | ||||||
| Function,+,furi_thread_start,void,FuriThread* | Function,+,furi_thread_start,void,FuriThread* | ||||||
| Function,+,furi_thread_stdout_flush,int32_t, | Function,+,furi_thread_stdout_flush,int32_t, | ||||||
| Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" | Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" | ||||||
| @ -1287,6 +1289,7 @@ Function,+,furi_thread_yield,void, | |||||||
| Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" | Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" | ||||||
| Function,+,furi_timer_free,void,FuriTimer* | Function,+,furi_timer_free,void,FuriTimer* | ||||||
| Function,+,furi_timer_is_running,uint32_t,FuriTimer* | Function,+,furi_timer_is_running,uint32_t,FuriTimer* | ||||||
|  | Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" | ||||||
| Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" | Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" | ||||||
| Function,+,furi_timer_stop,FuriStatus,FuriTimer* | Function,+,furi_timer_stop,FuriStatus,FuriTimer* | ||||||
| Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" | Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" | ||||||
|  | |||||||
| 
 | 
| @ -1,5 +1,5 @@ | |||||||
| entry,status,name,type,params | entry,status,name,type,params | ||||||
| Version,+,24.0,, | Version,+,26.0,, | ||||||
| Header,+,applications/services/bt/bt_service/bt.h,, | Header,+,applications/services/bt/bt_service/bt.h,, | ||||||
| Header,+,applications/services/cli/cli.h,, | Header,+,applications/services/cli/cli.h,, | ||||||
| Header,+,applications/services/cli/cli_vcp.h,, | Header,+,applications/services/cli/cli_vcp.h,, | ||||||
| @ -1073,6 +1073,8 @@ Function,+,furi_hal_console_puts,void,const char* | |||||||
| Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" | Function,+,furi_hal_console_set_tx_callback,void,"FuriHalConsoleTxCallback, void*" | ||||||
| Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" | Function,+,furi_hal_console_tx,void,"const uint8_t*, size_t" | ||||||
| Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" | Function,+,furi_hal_console_tx_with_new_line,void,"const uint8_t*, size_t" | ||||||
|  | Function,+,furi_hal_cortex_comp_enable,void,"FuriHalCortexComp, FuriHalCortexCompFunction, uint32_t, uint32_t, FuriHalCortexCompSize" | ||||||
|  | Function,+,furi_hal_cortex_comp_reset,void,FuriHalCortexComp | ||||||
| Function,+,furi_hal_cortex_delay_us,void,uint32_t | Function,+,furi_hal_cortex_delay_us,void,uint32_t | ||||||
| Function,-,furi_hal_cortex_init_early,void, | Function,-,furi_hal_cortex_init_early,void, | ||||||
| Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, | Function,+,furi_hal_cortex_instructions_per_microsecond,uint32_t, | ||||||
| @ -1562,7 +1564,7 @@ Function,+,furi_thread_set_priority,void,"FuriThread*, FuriThreadPriority" | |||||||
| Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" | Function,+,furi_thread_set_stack_size,void,"FuriThread*, size_t" | ||||||
| Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" | Function,+,furi_thread_set_state_callback,void,"FuriThread*, FuriThreadStateCallback" | ||||||
| Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" | Function,+,furi_thread_set_state_context,void,"FuriThread*, void*" | ||||||
| Function,+,furi_thread_set_stdout_callback,_Bool,FuriThreadStdoutWriteCallback | Function,+,furi_thread_set_stdout_callback,void,FuriThreadStdoutWriteCallback | ||||||
| Function,+,furi_thread_start,void,FuriThread* | Function,+,furi_thread_start,void,FuriThread* | ||||||
| Function,+,furi_thread_stdout_flush,int32_t, | Function,+,furi_thread_stdout_flush,int32_t, | ||||||
| Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" | Function,+,furi_thread_stdout_write,size_t,"const char*, size_t" | ||||||
| @ -1571,6 +1573,7 @@ Function,+,furi_thread_yield,void, | |||||||
| Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" | Function,+,furi_timer_alloc,FuriTimer*,"FuriTimerCallback, FuriTimerType, void*" | ||||||
| Function,+,furi_timer_free,void,FuriTimer* | Function,+,furi_timer_free,void,FuriTimer* | ||||||
| Function,+,furi_timer_is_running,uint32_t,FuriTimer* | Function,+,furi_timer_is_running,uint32_t,FuriTimer* | ||||||
|  | Function,+,furi_timer_pending_callback,void,"FuriTimerPendigCallback, void*, uint32_t" | ||||||
| Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" | Function,+,furi_timer_start,FuriStatus,"FuriTimer*, uint32_t" | ||||||
| Function,+,furi_timer_stop,FuriStatus,FuriTimer* | Function,+,furi_timer_stop,FuriStatus,FuriTimer* | ||||||
| Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" | Function,-,fwrite,size_t,"const void*, size_t, size_t, FILE*" | ||||||
|  | |||||||
| 
 | 
| @ -1,11 +1,12 @@ | |||||||
| #include <furi_hal_cortex.h> | #include <furi_hal_cortex.h> | ||||||
|  | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #include <stm32wbxx.h> | #include <stm32wbxx.h> | ||||||
| 
 | 
 | ||||||
| #define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000) | #define FURI_HAL_CORTEX_INSTRUCTIONS_PER_MICROSECOND (SystemCoreClock / 1000000) | ||||||
| 
 | 
 | ||||||
| void furi_hal_cortex_init_early() { | void furi_hal_cortex_init_early() { | ||||||
|     CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; |     CoreDebug->DEMCR |= (CoreDebug_DEMCR_TRCENA_Msk | CoreDebug_DEMCR_MON_EN_Msk); | ||||||
|     DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; |     DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; | ||||||
|     DWT->CYCCNT = 0U; |     DWT->CYCCNT = 0U; | ||||||
| 
 | 
 | ||||||
| @ -39,3 +40,70 @@ void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer) { | |||||||
|     while(!furi_hal_cortex_timer_is_expired(cortex_timer)) |     while(!furi_hal_cortex_timer_is_expired(cortex_timer)) | ||||||
|         ; |         ; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | // Duck ST
 | ||||||
|  | #undef COMP0 | ||||||
|  | #undef COMP1 | ||||||
|  | #undef COMP2 | ||||||
|  | #undef COMP3 | ||||||
|  | 
 | ||||||
|  | void furi_hal_cortex_comp_enable( | ||||||
|  |     FuriHalCortexComp comp, | ||||||
|  |     FuriHalCortexCompFunction function, | ||||||
|  |     uint32_t value, | ||||||
|  |     uint32_t mask, | ||||||
|  |     FuriHalCortexCompSize size) { | ||||||
|  |     uint32_t function_reg = (uint32_t)function | ((uint32_t)size << 10); | ||||||
|  | 
 | ||||||
|  |     switch(comp) { | ||||||
|  |     case FuriHalCortexComp0: | ||||||
|  |         (DWT->COMP0) = value; | ||||||
|  |         (DWT->MASK0) = mask; | ||||||
|  |         (DWT->FUNCTION0) = function_reg; | ||||||
|  |         break; | ||||||
|  |     case FuriHalCortexComp1: | ||||||
|  |         (DWT->COMP1) = value; | ||||||
|  |         (DWT->MASK1) = mask; | ||||||
|  |         (DWT->FUNCTION1) = function_reg; | ||||||
|  |         break; | ||||||
|  |     case FuriHalCortexComp2: | ||||||
|  |         (DWT->COMP2) = value; | ||||||
|  |         (DWT->MASK2) = mask; | ||||||
|  |         (DWT->FUNCTION2) = function_reg; | ||||||
|  |         break; | ||||||
|  |     case FuriHalCortexComp3: | ||||||
|  |         (DWT->COMP3) = value; | ||||||
|  |         (DWT->MASK3) = mask; | ||||||
|  |         (DWT->FUNCTION3) = function_reg; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         furi_crash("Invalid parameter"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_cortex_comp_reset(FuriHalCortexComp comp) { | ||||||
|  |     switch(comp) { | ||||||
|  |     case FuriHalCortexComp0: | ||||||
|  |         (DWT->COMP0) = 0; | ||||||
|  |         (DWT->MASK0) = 0; | ||||||
|  |         (DWT->FUNCTION0) = 0; | ||||||
|  |         break; | ||||||
|  |     case FuriHalCortexComp1: | ||||||
|  |         (DWT->COMP1) = 0; | ||||||
|  |         (DWT->MASK1) = 0; | ||||||
|  |         (DWT->FUNCTION1) = 0; | ||||||
|  |         break; | ||||||
|  |     case FuriHalCortexComp2: | ||||||
|  |         (DWT->COMP2) = 0; | ||||||
|  |         (DWT->MASK2) = 0; | ||||||
|  |         (DWT->FUNCTION2) = 0; | ||||||
|  |         break; | ||||||
|  |     case FuriHalCortexComp3: | ||||||
|  |         (DWT->COMP3) = 0; | ||||||
|  |         (DWT->MASK3) = 0; | ||||||
|  |         (DWT->FUNCTION3) = 0; | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         furi_crash("Invalid parameter"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | |||||||
| @ -56,6 +56,53 @@ bool furi_hal_cortex_timer_is_expired(FuriHalCortexTimer cortex_timer); | |||||||
|  */ |  */ | ||||||
| void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer); | void furi_hal_cortex_timer_wait(FuriHalCortexTimer cortex_timer); | ||||||
| 
 | 
 | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalCortexComp0, | ||||||
|  |     FuriHalCortexComp1, | ||||||
|  |     FuriHalCortexComp2, | ||||||
|  |     FuriHalCortexComp3, | ||||||
|  | } FuriHalCortexComp; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalCortexCompSizeWord = 0b10, | ||||||
|  |     FuriHalCortexCompSizeHalfWord = 0b01, | ||||||
|  |     FuriHalCortexCompSizeByte = 0b00, | ||||||
|  | } FuriHalCortexCompSize; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalCortexCompFunctionPC = 0b100, | ||||||
|  |     FuriHalCortexCompFunctionRead = 0b101, | ||||||
|  |     FuriHalCortexCompFunctionWrite = 0b110, | ||||||
|  |     FuriHalCortexCompFunctionReadWrite = 0b110, | ||||||
|  | } FuriHalCortexCompFunction; | ||||||
|  | 
 | ||||||
|  | /** Enable DWT comparator
 | ||||||
|  |  *  | ||||||
|  |  * Allows to programmatically set instruction/data breakpoints. | ||||||
|  |  *  | ||||||
|  |  * More details on how it works can be found in armv7m official documentation: | ||||||
|  |  * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/The-DWT-comparators
 | ||||||
|  |  * https://developer.arm.com/documentation/ddi0403/d/Debug-Architecture/ARMv7-M-Debug/The-Data-Watchpoint-and-Trace-unit/Comparator-Function-registers--DWT-FUNCTIONn
 | ||||||
|  |  * | ||||||
|  |  * @param[in]  comp      The Comparator | ||||||
|  |  * @param[in]  function  The Comparator Function to use | ||||||
|  |  * @param[in]  value     The value | ||||||
|  |  * @param[in]  mask      The mask | ||||||
|  |  * @param[in]  size      The size | ||||||
|  |  */ | ||||||
|  | void furi_hal_cortex_comp_enable( | ||||||
|  |     FuriHalCortexComp comp, | ||||||
|  |     FuriHalCortexCompFunction function, | ||||||
|  |     uint32_t value, | ||||||
|  |     uint32_t mask, | ||||||
|  |     FuriHalCortexCompSize size); | ||||||
|  | 
 | ||||||
|  | /** Reset DWT comparator
 | ||||||
|  |  * | ||||||
|  |  * @param[in]  comp  The Comparator | ||||||
|  |  */ | ||||||
|  | void furi_hal_cortex_comp_reset(FuriHalCortexComp comp); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -164,10 +164,13 @@ FuriThread* furi_thread_alloc_ex( | |||||||
| 
 | 
 | ||||||
| void furi_thread_free(FuriThread* thread) { | void furi_thread_free(FuriThread* thread) { | ||||||
|     furi_assert(thread); |     furi_assert(thread); | ||||||
|     furi_assert(thread->state == FuriThreadStateStopped); |  | ||||||
| 
 | 
 | ||||||
|     if(thread->name) free((void*)thread->name); |     // Ensure that use join before free
 | ||||||
|     if(thread->appid) free((void*)thread->appid); |     furi_assert(thread->state == FuriThreadStateStopped); | ||||||
|  |     furi_assert(thread->task_handle == NULL); | ||||||
|  | 
 | ||||||
|  |     if(thread->name) free(thread->name); | ||||||
|  |     if(thread->appid) free(thread->appid); | ||||||
|     furi_string_free(thread->output.buffer); |     furi_string_free(thread->output.buffer); | ||||||
| 
 | 
 | ||||||
|     free(thread); |     free(thread); | ||||||
| @ -176,14 +179,14 @@ void furi_thread_free(FuriThread* thread) { | |||||||
| void furi_thread_set_name(FuriThread* thread, const char* name) { | void furi_thread_set_name(FuriThread* thread, const char* name) { | ||||||
|     furi_assert(thread); |     furi_assert(thread); | ||||||
|     furi_assert(thread->state == FuriThreadStateStopped); |     furi_assert(thread->state == FuriThreadStateStopped); | ||||||
|     if(thread->name) free((void*)thread->name); |     if(thread->name) free(thread->name); | ||||||
|     thread->name = name ? strdup(name) : NULL; |     thread->name = name ? strdup(name) : NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_thread_set_appid(FuriThread* thread, const char* appid) { | void furi_thread_set_appid(FuriThread* thread, const char* appid) { | ||||||
|     furi_assert(thread); |     furi_assert(thread); | ||||||
|     furi_assert(thread->state == FuriThreadStateStopped); |     furi_assert(thread->state == FuriThreadStateStopped); | ||||||
|     if(thread->appid) free((void*)thread->appid); |     if(thread->appid) free(thread->appid); | ||||||
|     thread->appid = appid ? strdup(appid) : NULL; |     thread->appid = appid ? strdup(appid) : NULL; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -276,7 +279,7 @@ void furi_thread_cleanup_tcb_event(TaskHandle_t task) { | |||||||
|     if(thread) { |     if(thread) { | ||||||
|         // clear thread local storage
 |         // clear thread local storage
 | ||||||
|         vTaskSetThreadLocalStoragePointer(task, 0, NULL); |         vTaskSetThreadLocalStoragePointer(task, 0, NULL); | ||||||
| 
 |         furi_assert(thread->task_handle == task); | ||||||
|         thread->task_handle = NULL; |         thread->task_handle = NULL; | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -332,7 +335,6 @@ FuriThreadId furi_thread_get_current_id() { | |||||||
| 
 | 
 | ||||||
| FuriThread* furi_thread_get_current() { | FuriThread* furi_thread_get_current() { | ||||||
|     FuriThread* thread = pvTaskGetThreadLocalStoragePointer(NULL, 0); |     FuriThread* thread = pvTaskGetThreadLocalStoragePointer(NULL, 0); | ||||||
|     furi_assert(thread != NULL); |  | ||||||
|     return thread; |     return thread; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -579,24 +581,22 @@ static int32_t __furi_thread_stdout_flush(FuriThread* thread) { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { | void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback) { | ||||||
|     FuriThread* thread = furi_thread_get_current(); |     FuriThread* thread = furi_thread_get_current(); | ||||||
| 
 |     furi_assert(thread); | ||||||
|     __furi_thread_stdout_flush(thread); |     __furi_thread_stdout_flush(thread); | ||||||
|     thread->output.write_callback = callback; |     thread->output.write_callback = callback; | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() { | FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback() { | ||||||
|     FuriThread* thread = furi_thread_get_current(); |     FuriThread* thread = furi_thread_get_current(); | ||||||
| 
 |     furi_assert(thread); | ||||||
|     return thread->output.write_callback; |     return thread->output.write_callback; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| size_t furi_thread_stdout_write(const char* data, size_t size) { | size_t furi_thread_stdout_write(const char* data, size_t size) { | ||||||
|     FuriThread* thread = furi_thread_get_current(); |     FuriThread* thread = furi_thread_get_current(); | ||||||
| 
 |     furi_assert(thread); | ||||||
|     if(size == 0 || data == NULL) { |     if(size == 0 || data == NULL) { | ||||||
|         return __furi_thread_stdout_flush(thread); |         return __furi_thread_stdout_flush(thread); | ||||||
|     } else { |     } else { | ||||||
| @ -619,7 +619,9 @@ size_t furi_thread_stdout_write(const char* data, size_t size) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t furi_thread_stdout_flush() { | int32_t furi_thread_stdout_flush() { | ||||||
|     return __furi_thread_stdout_flush(furi_thread_get_current()); |     FuriThread* thread = furi_thread_get_current(); | ||||||
|  |     furi_assert(thread); | ||||||
|  |     return __furi_thread_stdout_flush(thread); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_thread_suspend(FuriThreadId thread_id) { | void furi_thread_suspend(FuriThreadId thread_id) { | ||||||
|  | |||||||
| @ -233,7 +233,7 @@ FuriThreadId furi_thread_get_current_id(); | |||||||
| 
 | 
 | ||||||
| /** Get FuriThread instance for current thread
 | /** Get FuriThread instance for current thread
 | ||||||
|  *  |  *  | ||||||
|  * @return FuriThread*  |  * @return pointer to FuriThread or NULL if this thread doesn't belongs to Furi | ||||||
|  */ |  */ | ||||||
| FuriThread* furi_thread_get_current(); | FuriThread* furi_thread_get_current(); | ||||||
| 
 | 
 | ||||||
| @ -290,10 +290,8 @@ FuriThreadStdoutWriteCallback furi_thread_get_stdout_callback(); | |||||||
| /** Set STDOUT callback for thread
 | /** Set STDOUT callback for thread
 | ||||||
|  * |  * | ||||||
|  * @param      callback  callback or NULL to clear |  * @param      callback  callback or NULL to clear | ||||||
|  *  |  | ||||||
|  * @return     true on success, otherwise fail |  | ||||||
|  */ |  */ | ||||||
| bool furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); | void furi_thread_set_stdout_callback(FuriThreadStdoutWriteCallback callback); | ||||||
| 
 | 
 | ||||||
| /** Write data to buffered STDOUT
 | /** Write data to buffered STDOUT
 | ||||||
|  *  |  *  | ||||||
|  | |||||||
| @ -124,3 +124,13 @@ uint32_t furi_timer_is_running(FuriTimer* instance) { | |||||||
|     /* Return 0: not running, 1: running */ |     /* Return 0: not running, 1: running */ | ||||||
|     return (uint32_t)xTimerIsTimerActive(hTimer); |     return (uint32_t)xTimerIsTimerActive(hTimer); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg) { | ||||||
|  |     BaseType_t ret = pdFAIL; | ||||||
|  |     if(furi_kernel_is_irq_or_masked()) { | ||||||
|  |         ret = xTimerPendFunctionCallFromISR(callback, context, arg, NULL); | ||||||
|  |     } else { | ||||||
|  |         ret = xTimerPendFunctionCall(callback, context, arg, FuriWaitForever); | ||||||
|  |     } | ||||||
|  |     furi_check(ret == pdPASS); | ||||||
|  | } | ||||||
| @ -56,6 +56,10 @@ FuriStatus furi_timer_stop(FuriTimer* instance); | |||||||
|  */ |  */ | ||||||
| uint32_t furi_timer_is_running(FuriTimer* instance); | uint32_t furi_timer_is_running(FuriTimer* instance); | ||||||
| 
 | 
 | ||||||
|  | typedef void (*FuriTimerPendigCallback)(void* context, uint32_t arg); | ||||||
|  | 
 | ||||||
|  | void furi_timer_pending_callback(FuriTimerPendigCallback callback, void* context, uint32_t arg); | ||||||
|  | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく