From 3f56ade85fe76bd1500ab3e8df6a872199fa686c Mon Sep 17 00:00:00 2001 From: armink Date: Thu, 25 Jun 2015 14:28:18 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E3=80=90=E5=A2=9E=E5=8A=A0=E3=80=91?= =?UTF-8?q?=E5=BC=80=E5=90=AF/=E5=85=B3=E9=97=AD=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E9=94=81=E5=8A=9F=E8=83=BD=EF=BC=8C=E4=BF=9D=E8=AF=81=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E6=88=96=E7=A1=AC=E4=BB=B6=E5=9C=A8=E5=87=BA=E7=8E=B0?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E6=97=B6=EF=BC=8CEasyLogger=E4=BE=9D?= =?UTF-8?q?=E7=84=B6=E6=AD=A3=E5=B8=B8=E5=8F=AF=E4=BB=A5=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: armink --- demo/os/rt-thread/stm32f10x/README.md | 6 +- .../RT-Thread-1.2.2/include/rtdebug.h | 9 ++- .../RT-Thread-1.2.2/include/rtthread.h | 5 ++ .../stm32f10x/RT-Thread-1.2.2/src/kservice.c | 13 ++++ .../os/rt-thread/stm32f10x/app/src/app_task.c | 45 ++++++++++++ easylogger/inc/elog.h | 3 +- easylogger/inc/elog_flash.h | 3 +- easylogger/src/elog.c | 59 +++++++++++++-- easylogger/src/elog_flash.c | 71 ++++++++++++++++--- 9 files changed, 195 insertions(+), 19 deletions(-) diff --git a/demo/os/rt-thread/stm32f10x/README.md b/demo/os/rt-thread/stm32f10x/README.md index 8240b29..f0909e1 100644 --- a/demo/os/rt-thread/stm32f10x/README.md +++ b/demo/os/rt-thread/stm32f10x/README.md @@ -21,4 +21,8 @@ `RVMDK` 下为Keil工程文件 -`EWARM` 下为IAR工程文件 \ No newline at end of file +`EWARM` 下为IAR工程文件 + +## 3、其他功能 + +- 1、新增 RTT断言及硬件异常的钩子的方法,使得系统在出现异常时,错误日志依然可以被输出或保存。参考 `app\src\app_task.c` 中的 `assert_hook` 及 `exception_hook` 方法。 \ No newline at end of file diff --git a/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/include/rtdebug.h b/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/include/rtdebug.h index 8fd07b5..a324a29 100644 --- a/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/include/rtdebug.h +++ b/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/include/rtdebug.h @@ -84,8 +84,13 @@ while (0) if (!(EX)) \ { \ volatile char dummy = 0; \ - rt_kprintf("(%s) assert failed at %s:%d \n", #EX, __FUNCTION__, __LINE__);\ - while (dummy == 0); \ + if (rt_assert_hook == RT_NULL) \ + { \ + rt_kprintf("(%s) assert failed at %s:%d \n", #EX, __FUNCTION__, __LINE__);\ + while (dummy == 0); \ + } else { \ + rt_assert_hook(#EX, __FUNCTION__, __LINE__); \ + } \ } /* Macro to check current context */ diff --git a/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/include/rtthread.h b/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/include/rtthread.h index edd207b..c2bedc8 100644 --- a/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/include/rtthread.h +++ b/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/include/rtthread.h @@ -510,6 +510,11 @@ rt_uint32_t rt_strcasecmp(const char *a, const char *b); void rt_show_version(void); +#ifdef RT_DEBUG +extern void (*rt_assert_hook)(const char* ex, const char* func, rt_size_t line); +void rt_assert_set_hook(void (*hook)(const char* ex, const char* func, rt_size_t line)); +#endif /* RT_DEBUG */ + /*@}*/ #ifdef __cplusplus diff --git a/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/src/kservice.c b/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/src/kservice.c index 0f06806..a027e08 100644 --- a/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/src/kservice.c +++ b/demo/os/rt-thread/stm32f10x/RT-Thread-1.2.2/src/kservice.c @@ -1249,6 +1249,19 @@ int __rt_ffs(int value) } #endif +#ifdef RT_DEBUG +/* RT_ASSERT(EX)'s hook */ +void (*rt_assert_hook)(const char* ex, const char* func, rt_size_t line); +/** + * This function will set a hook function to RT_ASSERT(EX). It will run when the expression is false. + * + * @param hook the hook function + */ +void rt_assert_set_hook(void (*hook)(const char* ex, const char* func, rt_size_t line)) { + rt_assert_hook = hook; +} +#endif /* RT_DEBUG */ + #if !defined (RT_USING_NEWLIB) && defined (RT_USING_MINILIBC) && defined (__GNUC__) #include void *memcpy(void *dest, const void *src, size_t n) __attribute__((weak, alias("rt_memcpy"))); diff --git a/demo/os/rt-thread/stm32f10x/app/src/app_task.c b/demo/os/rt-thread/stm32f10x/app/src/app_task.c index 74d0c2c..ca16dd2 100644 --- a/demo/os/rt-thread/stm32f10x/app/src/app_task.c +++ b/demo/os/rt-thread/stm32f10x/app/src/app_task.c @@ -32,6 +32,8 @@ static rt_uint8_t thread_sys_monitor_stack[512]; struct rt_thread thread_sys_monitor; static void test_elog(void); +static void assert_hook(const char* ex, const char* func, rt_size_t line); +static rt_err_t exception_hook(void *context); /** * System monitor thread. @@ -90,6 +92,10 @@ void sys_init_thread(void* parameter){ /* set enabled format */ elog_set_fmt(ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME /*| ELOG_FMT_P_INFO*/ | ELOG_FMT_T_INFO | ELOG_FMT_DIR /*| ELOG_FMT_FUNC*/ | ELOG_FMT_LINE); + /* set hardware exception hook */ + rt_hw_exception_install(exception_hook); + /* set RT-Thread assert hook */ + rt_assert_set_hook(assert_hook); /* initialize OK and switch to running status */ set_system_status(SYSTEM_STATUS_RUN); } else { @@ -100,6 +106,45 @@ void sys_init_thread(void* parameter){ rt_thread_delete(rt_thread_self()); } +static void assert_hook(const char* ex, const char* func, rt_size_t line) { + elog_output_lock_enabled(false); + //elog_flash_lock_enabled(false); + elog_a("assert", "(%s) has assert failed at %s:%ld.\n", ex, func, line); + //elog_flash_flush(); + while(1); +} + +static rt_err_t exception_hook(void *context) { + struct exception_stack_frame { + rt_uint32_t r0; + rt_uint32_t r1; + rt_uint32_t r2; + rt_uint32_t r3; + rt_uint32_t r12; + rt_uint32_t lr; + rt_uint32_t pc; + rt_uint32_t psr; + }; + struct exception_stack_frame *exception_stack = (struct exception_stack_frame *) context; + + elog_output_lock_enabled(false); + //elog_flash_lock_enabled(false); + + elog_e("hw_fault", "psr: 0x%08x", exception_stack->psr); + elog_e("hw_fault", " pc: 0x%08x", exception_stack->pc); + elog_e("hw_fault", " lr: 0x%08x", exception_stack->lr); + elog_e("hw_fault", "r12: 0x%08x", exception_stack->r12); + elog_e("hw_fault", "r03: 0x%08x", exception_stack->r3); + elog_e("hw_fault", "r02: 0x%08x", exception_stack->r2); + elog_e("hw_fault", "r01: 0x%08x", exception_stack->r1); + elog_e("hw_fault", "r00: 0x%08x", exception_stack->r0); + elog_e("hw_fault", "hard fault on thread: %s", rt_thread_self()->name); + + //elog_flash_flush(); + + return RT_EOK; +} + int rt_application_init(void) { rt_thread_t init_thread = NULL; diff --git a/easylogger/inc/elog.h b/easylogger/inc/elog.h index c5cfac2..ea4256f 100644 --- a/easylogger/inc/elog.h +++ b/easylogger/inc/elog.h @@ -61,7 +61,7 @@ extern "C" { /* output newline sign */ #define ELOG_NEWLINE_SIGN "\r\n" /* EasyLogger software version number */ -#define ELOG_SW_VERSION "0.06.24" +#define ELOG_SW_VERSION "0.06.25" /* EasyLogger assert for developer. */ #define ELOG_ASSERT(EXPR) \ @@ -115,6 +115,7 @@ void elog_set_filter_kw(const char *keyword); void elog_raw(const char *format, ...); void elog_output(uint8_t level, const char *tag, const char *file, const char *func, const long line, const char *format, ...); +void elog_output_lock_enabled(bool enabled); #ifndef ELOG_OUTPUT_ENABLE diff --git a/easylogger/inc/elog_flash.h b/easylogger/inc/elog_flash.h index 5037854..176533c 100644 --- a/easylogger/inc/elog_flash.h +++ b/easylogger/inc/elog_flash.h @@ -40,7 +40,7 @@ extern "C" { /* EasyLogger flash save plugin's RAM buffer size */ #define ELOG_FLASH_BUF_SIZE 1024 /* EasyLogger flash save plugin's software version number */ -#define ELOG_FLASH_SW_VERSION "0.06.10" +#define ELOG_FLASH_SW_VERSION "0.06.25" /* elog_flash.c */ ElogErrCode elog_flash_init(void); @@ -50,6 +50,7 @@ void elog_flash_outout_recent(size_t size); void elog_flash_set_filter(uint8_t level,const char *tag,const char *keyword); void elog_flash_write(const char *log, size_t size); void elog_flash_clean(void); +void elog_flash_lock_enabled(bool enabled); #ifdef ELOG_FLASH_USING_BUF_MODE void elog_flash_flush(void); diff --git a/easylogger/src/elog.c b/easylogger/src/elog.c index bfae4a5..811260e 100644 --- a/easylogger/src/elog.c +++ b/easylogger/src/elog.c @@ -46,6 +46,14 @@ static const char *level_output_info[] = { "D/", "V/", }; +/* the output lock enable or disable. default is enable */ +static bool output_lock_enabled = true; +/* the output is locked before enable. */ +static bool output_is_locked_before_enable = false; +/* the output is locked before disable. */ +static bool output_is_locked_before_disable = false; +static void output_lock(void); +static void output_unlock(void); static bool get_fmt_enabled(size_t set); /** @@ -166,7 +174,7 @@ void elog_raw(const char *format, ...) { va_start(args, format); /* lock output */ - elog_port_output_lock(); + output_lock(); /* package log data to buffer */ fmt_result = vsnprintf(log_buf, ELOG_BUF_SIZE, format, args); @@ -225,7 +233,7 @@ void elog_output(uint8_t level, const char *tag, const char *file, const char *f va_start(args, format); /* lock output */ - elog_port_output_lock(); + output_lock(); /* package level info */ if (get_fmt_enabled(ELOG_FMT_LVL)) { log_len += elog_strcpy(log_len, log_buf + log_len, level_output_info[level]); @@ -307,7 +315,7 @@ void elog_output(uint8_t level, const char *tag, const char *file, const char *f if (!strstr(log_buf, elog.filter.keyword)) { //TODO 可以考虑采用KMP及朴素模式匹配字符串,提升性能 /* unlock output */ - elog_port_output_unlock(); + output_unlock(); return; } @@ -325,7 +333,7 @@ void elog_output(uint8_t level, const char *tag, const char *file, const char *f elog_port_output(log_buf, log_len); /* unlock output */ - elog_port_output_unlock(); + output_unlock(); } /** @@ -342,3 +350,46 @@ static bool get_fmt_enabled(size_t set) { return false; } } + +/** + * enable or disable logger output lock + * @note disable this lock is not recommended except you want output system exception log + * + * @param enabled true: enable false: disable + */ +void elog_output_lock_enabled(bool enabled) { + output_lock_enabled = enabled; + /* it will re-lock or re-unlock before output lock enable */ + if (output_lock_enabled) { + if (!output_is_locked_before_disable && output_is_locked_before_enable) { + /* the output lock is unlocked before disable, and the lock will unlocking after enable */ + elog_port_output_lock(); + } else if (output_is_locked_before_disable && !output_is_locked_before_enable) { + /* the output lock is locked before disable, and the lock will locking after enable */ + elog_port_output_unlock(); + } + } +} + +/** + * lock output + */ +static void output_lock(void) { + if (output_lock_enabled) { + elog_port_output_lock(); + output_is_locked_before_disable = true; + } else { + output_is_locked_before_enable = true; + } +} +/** + * unlock output + */ +static void output_unlock(void) { + if (output_lock_enabled) { + elog_port_output_unlock(); + output_is_locked_before_disable = false; + } else { + output_is_locked_before_enable = false; + } +} diff --git a/easylogger/src/elog_flash.c b/easylogger/src/elog_flash.c index 070eecc..9edc462 100644 --- a/easylogger/src/elog_flash.c +++ b/easylogger/src/elog_flash.c @@ -48,6 +48,14 @@ static size_t cur_buf_size = 0; /* initialize OK flag */ static bool init_ok = false; +/* the flash log buffer lock enable or disable. default is enable */ +static bool log_buf_lock_enabled = true; +/* the flash log buffer is locked before enable. */ +static bool log_buf_is_locked_before_enable = false; +/* the flash log buffer is locked before disable. */ +static bool log_buf_is_locked_before_disable = false; +static void log_buf_lock(void); +static void log_buf_unlock(void); /** * EasyLogger flash save plugin initialize. @@ -94,7 +102,7 @@ void elog_flash_outout(size_t index, size_t size) { /* must be call this function after initialize OK */ ELOG_ASSERT(init_ok); /* lock flash log buffer */ - elog_flash_port_lock(); + log_buf_lock(); /* Output all flash saved log. It will use filter */ while (true) { if (index + read_size + buf_szie < log_total_size) { @@ -118,7 +126,7 @@ void elog_flash_outout(size_t index, size_t size) { } } /* unlock flash log buffer */ - elog_flash_port_unlock(); + log_buf_unlock(); } /** @@ -163,7 +171,7 @@ void elog_flash_write(const char *log, size_t size) { ELOG_ASSERT(init_ok); /* lock flash log buffer */ - elog_flash_port_lock(); + log_buf_lock(); #ifdef ELOG_FLASH_USING_BUF_MODE while (true) { @@ -174,11 +182,11 @@ void elog_flash_write(const char *log, size_t size) { size -= write_size; cur_buf_size += write_size; /* unlock flash log buffer */ - elog_flash_port_unlock(); + log_buf_unlock(); /* write all buffered log to flash, cur_buf_size will reset */ elog_flash_flush(); /* lock flash log buffer */ - elog_flash_port_lock(); + log_buf_lock(); } else { memcpy(log_buf + cur_buf_size, log + write_index, size); cur_buf_size += size; @@ -198,7 +206,7 @@ void elog_flash_write(const char *log, size_t size) { #endif /* unlock flash log buffer */ - elog_flash_port_unlock(); + log_buf_unlock(); } #ifdef ELOG_FLASH_USING_BUF_MODE @@ -211,7 +219,7 @@ void elog_flash_flush(void) { /* must be call this function after initialize OK */ ELOG_ASSERT(init_ok); /* lock flash log buffer */ - elog_flash_port_lock(); + log_buf_lock(); /* flash write is word alignment */ if (cur_buf_size % 4 != 0) { write_overage_size = 4 - (cur_buf_size % 4); @@ -223,7 +231,7 @@ void elog_flash_flush(void) { /* reset position */ cur_buf_size = 0; /* unlock flash log buffer */ - elog_flash_port_unlock(); + log_buf_unlock(); } #endif @@ -236,7 +244,7 @@ void elog_flash_clean(void) { /* must be call this function after initialize OK */ ELOG_ASSERT(init_ok); /* lock flash log buffer */ - elog_flash_port_lock(); + log_buf_lock(); /* clean all log which in flash */ clean_result = flash_log_clean(); @@ -246,7 +254,7 @@ void elog_flash_clean(void) { #endif /* unlock flash log buffer */ - elog_flash_port_unlock(); + log_buf_unlock(); if(clean_result == FLASH_NO_ERR) { log_i("All logs which in flash is clean OK."); @@ -254,3 +262,46 @@ void elog_flash_clean(void) { log_e("Clean logs which in flash has an error!"); } } + +/** + * enable or disable flash plugin lock + * @note disable this lock is not recommended except you want output system exception log + * + * @param enabled true: enable false: disable + */ +void elog_flash_lock_enabled(bool enabled) { + log_buf_lock_enabled = enabled; + /* it will re-lock or re-unlock before log buffer lock enable */ + if (log_buf_lock_enabled) { + if (!log_buf_is_locked_before_disable && log_buf_is_locked_before_enable) { + /* the log buffer lock is unlocked before disable, and the lock will unlocking after enable */ + elog_flash_port_lock(); + } else if (log_buf_is_locked_before_disable && !log_buf_is_locked_before_enable) { + /* the log buffer lock is locked before disable, and the lock will locking after enable */ + elog_flash_port_unlock(); + } + } +} + +/** + * lock flash log buffer + */ +static void log_buf_lock(void) { + if (log_buf_lock_enabled) { + elog_flash_port_lock(); + log_buf_is_locked_before_disable = true; + } else { + log_buf_is_locked_before_enable = true; + } +} +/** + * unlock flash log buffer + */ +static void log_buf_unlock(void) { + if (log_buf_lock_enabled) { + elog_flash_port_unlock(); + log_buf_is_locked_before_disable = false; + } else { + log_buf_is_locked_before_enable = false; + } +}