@@ -501,7 +501,23 @@ rt_weak rt_size_t ulog_hex_formater(char *log_buf, const char *tag, const rt_uin
501501 return ulog_tail_formater (log_buf , log_len , RT_TRUE , LOG_LVL_DBG );
502502}
503503
504- static void ulog_output_to_all_backend (rt_uint32_t level , const char * tag , rt_bool_t is_raw , const char * log , rt_size_t len )
504+ /**
505+ * @brief Internal helper to broadcast a log to backends.
506+ *
507+ * @details This is the core broadcasting function. It iterates through all
508+ * registered backends and outputs the log message. It can operate
509+ * in two modes.
510+ *
511+ * @param emergency_only If RT_TRUE, it will only output to backends marked as
512+ * `is_emergency_backend`. If RT_FALSE, it will output to
513+ * all backends that match the filter criteria.
514+ * @param level The log level.
515+ * @param tag The log tag.
516+ * @param is_raw Whether the log is raw data.
517+ * @param log The log message buffer.
518+ * @param len The length of the log message.
519+ */
520+ static void _ulog_output_to_backends (rt_bool_t emergency_only , rt_uint32_t level , const char * tag , rt_bool_t is_raw , const char * log , rt_size_t len )
505521{
506522 rt_slist_t * node ;
507523 ulog_backend_t backend ;
@@ -520,6 +536,13 @@ static void ulog_output_to_all_backend(rt_uint32_t level, const char *tag, rt_bo
520536 for (node = rt_slist_first (& ulog .backend_list ); node ; node = rt_slist_next (node ))
521537 {
522538 backend = rt_slist_entry (node , struct ulog_backend , list );
539+
540+ if (emergency_only && !backend -> is_emergency_backend )
541+ {
542+ /* In emergency mode, skip any backend not marked as emergency-safe. */
543+ continue ;
544+ }
545+
523546 if (backend -> out_level < level )
524547 {
525548 continue ;
@@ -558,6 +581,11 @@ static void ulog_output_to_all_backend(rt_uint32_t level, const char *tag, rt_bo
558581 }
559582}
560583
584+ static void ulog_output_to_all_backend (rt_uint32_t level , const char * tag , rt_bool_t is_raw , const char * log , rt_size_t len )
585+ {
586+ _ulog_output_to_backends (RT_FALSE , level , tag , is_raw , log , len );
587+ }
588+
561589static void do_output (rt_uint32_t level , const char * tag , rt_bool_t is_raw , const char * log_buf , rt_size_t log_len )
562590{
563591#ifdef ULOG_USING_ASYNC_OUTPUT
@@ -1297,6 +1325,7 @@ rt_err_t ulog_backend_register(ulog_backend_t backend, const char *name, rt_bool
12971325 backend -> support_color = support_color ;
12981326 backend -> out_level = LOG_FILTER_LVL_ALL ;
12991327 rt_strncpy (backend -> name , name , RT_NAME_MAX - 1 );
1328+ backend -> is_emergency_backend = RT_FALSE ;
13001329
13011330 level = rt_spin_lock_irqsave (& _spinlock );
13021331 rt_slist_append (& ulog .backend_list , & backend -> list );
@@ -1366,13 +1395,54 @@ ulog_backend_t ulog_backend_find(const char *name)
13661395 return RT_NULL ;
13671396}
13681397
1398+ /**
1399+ * @brief Sets the emergency-safe status for a specific backend at runtime.
1400+ *
1401+ * @details This function allows an application to dynamically mark a backend
1402+ * as safe or unsafe for use in emergency contexts (e.g., fault handlers).
1403+ * Only backends marked as safe will be used by `ulog_emergency_flush`.
1404+ *
1405+ * @param[in] name The name of the target backend.
1406+ * @param[in] is_emergency RT_TRUE to mark the backend as safe for emergency calls,
1407+ * RT_FALSE otherwise.
1408+ *
1409+ * @return rt_err_t RT_EOK on success, -RT_ERROR if the backend with the given name
1410+ * is not found, or -RT_EINVAL if the name is invalid.
1411+ */
1412+ rt_err_t ulog_backend_set_emergency (const char * name , rt_bool_t is_emergency )
1413+ {
1414+ ulog_backend_t backend ;
1415+ rt_err_t result = - RT_ERROR ;
1416+
1417+ if (name == RT_NULL )
1418+ {
1419+ return - RT_EINVAL ;
1420+ }
1421+
1422+ rt_mutex_take (& ulog .output_locker , RT_WAITING_FOREVER );
1423+
1424+ backend = ulog_backend_find (name );
1425+ if (backend != RT_NULL )
1426+ {
1427+ backend -> is_emergency_backend = is_emergency ;
1428+ result = RT_EOK ;
1429+ }
1430+
1431+ rt_mutex_release (& ulog .output_locker );
1432+
1433+ return result ;
1434+ }
1435+
13691436#ifdef ULOG_USING_ASYNC_OUTPUT
13701437/**
13711438 * asynchronous output logs to all backends
13721439 *
1440+ * @param[in] emergency_mode A flag to select the operational mode. RT_FALSE for
1441+ * normal operation, RT_TRUE for emergency fault context.
1442+ *
13731443 * @note you must call this function when ULOG_ASYNC_OUTPUT_BY_THREAD is disable
13741444 */
1375- void ulog_async_output (void )
1445+ void ulog_async_output (rt_bool_t emergency_mode )
13761446{
13771447 rt_rbb_blk_t log_blk ;
13781448 ulog_frame_t log_frame ;
@@ -1387,14 +1457,12 @@ void ulog_async_output(void)
13871457 log_frame = (ulog_frame_t ) log_blk -> buf ;
13881458 if (log_frame -> magic == ULOG_FRAME_MAGIC )
13891459 {
1390- /* output to all backends */
1391- ulog_output_to_all_backend (log_frame -> level , log_frame -> tag , log_frame -> is_raw , log_frame -> log ,
1392- log_frame -> log_len );
1460+ _ulog_output_to_backends (emergency_mode , log_frame -> level , log_frame -> tag , log_frame -> is_raw , log_frame -> log , log_frame -> log_len );
13931461 }
13941462 rt_rbb_blk_free (ulog .async_rbb , log_blk );
13951463 }
13961464 /* output the log_raw format log */
1397- if (ulog .async_rb )
1465+ if (ulog .async_rb && ! emergency_mode )
13981466 {
13991467 rt_size_t log_len = rt_ringbuffer_data_len (ulog .async_rb );
14001468 char * log = rt_malloc (log_len + 1 );
@@ -1434,14 +1502,14 @@ rt_err_t ulog_async_waiting_log(rt_int32_t time)
14341502
14351503static void async_output_thread_entry (void * param )
14361504{
1437- ulog_async_output ();
1505+ ulog_async_output (RT_FALSE );
14381506
14391507 while (1 )
14401508 {
14411509 ulog_async_waiting_log (RT_WAITING_FOREVER );
14421510 while (1 )
14431511 {
1444- ulog_async_output ();
1512+ ulog_async_output (RT_FALSE );
14451513 /* If there is no log output for a certain period of time,
14461514 * refresh the log buffer
14471515 */
@@ -1471,7 +1539,7 @@ void ulog_flush(void)
14711539 return ;
14721540
14731541#ifdef ULOG_USING_ASYNC_OUTPUT
1474- ulog_async_output ();
1542+ ulog_async_output (RT_FALSE );
14751543#endif
14761544
14771545 /* flush all backends */
@@ -1485,6 +1553,36 @@ void ulog_flush(void)
14851553 }
14861554}
14871555
1556+ /**
1557+ * @brief Flushes pending logs and outputs to emergency-safe backends.
1558+ */
1559+ void ulog_emergency_flush (void )
1560+ {
1561+ rt_slist_t * node ;
1562+ ulog_backend_t backend ;
1563+ rt_base_t irq_flag ;
1564+
1565+ if (!ulog .init_ok )
1566+ return ;
1567+
1568+ irq_flag = rt_hw_interrupt_disable ();
1569+
1570+ #ifdef ULOG_USING_ASYNC_OUTPUT
1571+ ulog_async_output (RT_TRUE );
1572+ #endif
1573+
1574+ rt_slist_for_each (node , & ulog .backend_list )
1575+ {
1576+ backend = rt_slist_entry (node , struct ulog_backend , list );
1577+ if (backend -> is_emergency_backend && backend -> flush )
1578+ {
1579+ backend -> flush (backend );
1580+ }
1581+ }
1582+
1583+ rt_hw_interrupt_enable (irq_flag );
1584+ }
1585+
14881586/**
14891587 * @brief ulog initialization
14901588 *
0 commit comments