Refactor error reporting

pull/6983/head
Senthil Ramakrishnan 2018-05-22 19:25:46 -05:00
parent d4fe75731d
commit 693a6c40bb
9 changed files with 385 additions and 526 deletions

View File

@ -33,13 +33,13 @@ void test_error_count_and_reset()
MBED_WARNING(MBED_ERROR_OUT_OF_MEMORY, "Out of memory", i); MBED_WARNING(MBED_ERROR_OUT_OF_MEMORY, "Out of memory", i);
} }
TEST_ASSERT_EQUAL_INT(count, get_error_count()); TEST_ASSERT_EQUAL_INT(count, mbed_get_error_count());
//clear the errors and error count to 0 //clear the errors and error count to 0
mbed_clear_all_errors(); mbed_clear_all_errors();
//Now the error count should be 0 //Now the error count should be 0
TEST_ASSERT_EQUAL_INT(0, get_error_count()); TEST_ASSERT_EQUAL_INT(0, mbed_get_error_count());
} }
@ -54,61 +54,61 @@ void test_error_capturing()
//first clear all errors and start afresh //first clear all errors and start afresh
MBED_WARNING(MBED_ERROR_OUT_OF_RESOURCES, "System type error", 0x1100 ); MBED_WARNING(MBED_ERROR_OUT_OF_RESOURCES, "System type error", 0x1100 );
mbed_error_status_t lastError = get_last_error(); mbed_error_status_t lastError = mbed_get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_MODULE_UNKNOWN, MBED_GET_ERROR_MODULE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_MODULE_UNKNOWN, MBED_GET_ERROR_MODULE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_OUT_OF_RESOURCES, MBED_GET_ERROR_CODE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_OUT_OF_RESOURCES, MBED_GET_ERROR_CODE(lastError));
mbed_error_status_t error = MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SERIAL, MBED_ERROR_CODE_OUT_OF_RESOURCES); mbed_error_status_t error = MBED_MAKE_ERROR(MBED_MODULE_DRIVER_SERIAL, MBED_ERROR_CODE_OUT_OF_RESOURCES);
MBED_WARNING(error, "Error Serial", 0xAA ); MBED_WARNING(error, "Error Serial", 0xAA );
lastError = get_last_error(); lastError = mbed_get_last_error();
TEST_ASSERT_EQUAL_UINT(error, lastError); TEST_ASSERT_EQUAL_UINT(error, lastError);
error = MBED_MAKE_CUSTOM_ERROR(MBED_MODULE_APPLICATION, MBED_ERROR_CODE_UNKNOWN); error = MBED_MAKE_CUSTOM_ERROR(MBED_MODULE_APPLICATION, MBED_ERROR_CODE_UNKNOWN);
MBED_WARNING(error, "Custom Error Unknown", 0x1234 ); MBED_WARNING(error, "Custom Error Unknown", 0x1234 );
lastError = get_last_error(); lastError = mbed_get_last_error();
TEST_ASSERT_EQUAL_UINT(error, lastError); TEST_ASSERT_EQUAL_UINT(error, lastError);
MBED_WARNING(MBED_ERROR_EPERM, "Posix Error Eperm", 0x1234 ); MBED_WARNING(MBED_ERROR_EPERM, "Posix Error Eperm", 0x1234 );
lastError = get_last_error(); lastError = mbed_get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_EPERM, lastError); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_EPERM, lastError);
error = MBED_MAKE_CUSTOM_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_CREATE_FAILED); error = MBED_MAKE_CUSTOM_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_CREATE_FAILED);
MBED_WARNING(error, "Custom Error Type", error_value); MBED_WARNING(error, "Custom Error Type", error_value);
lastError = get_last_error(); lastError = mbed_get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_CUSTOM, MBED_GET_ERROR_TYPE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_CUSTOM, MBED_GET_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_MODULE_PLATFORM, MBED_GET_ERROR_MODULE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_MODULE_PLATFORM, MBED_GET_ERROR_MODULE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_CREATE_FAILED, MBED_GET_ERROR_CODE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_CREATE_FAILED, MBED_GET_ERROR_CODE(lastError));
mbed_error_status_t status = mbed_get_last_error_log_info( &error_ctx ); mbed_error_status_t status = mbed_get_last_error_info( &error_ctx );
TEST_ASSERT(status == MBED_SUCCESS); TEST_ASSERT(status == MBED_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
error_value = 0xAABBCC; error_value = 0xAABBCC;
MBED_WARNING(MBED_ERROR_EACCES, "Posix Error", error_value ); MBED_WARNING(MBED_ERROR_EACCES, "Posix Error", error_value );
lastError = get_last_error(); lastError = mbed_get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_POSIX, MBED_GET_ERROR_TYPE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_POSIX, MBED_GET_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_MODULE_UNKNOWN, MBED_GET_ERROR_MODULE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_MODULE_UNKNOWN, MBED_GET_ERROR_MODULE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_EACCES, MBED_GET_ERROR_CODE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_EACCES, MBED_GET_ERROR_CODE(lastError));
status = mbed_get_last_error_log_info( &error_ctx ); status = mbed_get_last_error_info( &error_ctx );
TEST_ASSERT(status == MBED_SUCCESS); TEST_ASSERT(status == MBED_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
error_value = 0; error_value = 0;
error = MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNKNOWN); error = MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNKNOWN);
MBED_WARNING(error, "HAL Entity error", error_value ); MBED_WARNING(error, "HAL Entity error", error_value );
lastError = get_last_error(); lastError = mbed_get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TYPE_SYSTEM, MBED_GET_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_MODULE_HAL, MBED_GET_ERROR_MODULE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_MODULE_HAL, MBED_GET_ERROR_MODULE(lastError));
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_UNKNOWN, MBED_GET_ERROR_CODE(lastError)); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_CODE_UNKNOWN, MBED_GET_ERROR_CODE(lastError));
status = mbed_get_last_error_log_info( &error_ctx ); status = mbed_get_last_error_info( &error_ctx );
TEST_ASSERT(status == MBED_SUCCESS); TEST_ASSERT(status == MBED_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
MBED_WARNING(MBED_ERROR_MUTEX_LOCK_FAILED, "Mutex lock failed", 0x4455 ); MBED_WARNING(MBED_ERROR_MUTEX_LOCK_FAILED, "Mutex lock failed", 0x4455 );
error = get_last_error(); error = mbed_get_last_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_MUTEX_LOCK_FAILED, error); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_MUTEX_LOCK_FAILED, error);
error = get_first_error(); error = mbed_get_first_error();
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_OUT_OF_RESOURCES, error); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_OUT_OF_RESOURCES, error);
} }
@ -121,7 +121,7 @@ void test_error_context_capture()
mbed_error_ctx error_ctx = {0}; mbed_error_ctx error_ctx = {0};
MBED_WARNING(MBED_ERROR_INVALID_ARGUMENT, "System type error", error_value ); MBED_WARNING(MBED_ERROR_INVALID_ARGUMENT, "System type error", error_value );
mbed_error_status_t status = mbed_get_last_error_log_info( &error_ctx ); mbed_error_status_t status = mbed_get_last_error_info( &error_ctx );
TEST_ASSERT(status == MBED_SUCCESS); TEST_ASSERT(status == MBED_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
TEST_ASSERT_EQUAL_UINT(osThreadGetId(), error_ctx.thread_id); TEST_ASSERT_EQUAL_UINT(osThreadGetId(), error_ctx.thread_id);
@ -136,7 +136,7 @@ void test_error_context_capture()
#endif #endif
} }
#ifndef MBED_CONF_ERROR_LOG_DISABLED #ifndef MBED_CONF_ERROR_HIST_DISABLED
/** Test error logging functionality /** Test error logging functionality
*/ */
void test_error_logging() void test_error_logging()
@ -151,15 +151,15 @@ void test_error_logging()
MBED_WARNING(MBED_ERROR_INVALID_SIZE, "Invalid size", 2 ); MBED_WARNING(MBED_ERROR_INVALID_SIZE, "Invalid size", 2 );
MBED_WARNING(MBED_ERROR_INVALID_FORMAT, "Invalid format", 3 ); MBED_WARNING(MBED_ERROR_INVALID_FORMAT, "Invalid format", 3 );
mbed_error_status_t status = mbed_get_error_log_info( 0, &error_ctx ); mbed_error_status_t status = mbed_get_error_hist_info( 0, &error_ctx );
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(1, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(1, error_ctx.error_value);
status = mbed_get_error_log_info( 1, &error_ctx ); status = mbed_get_error_hist_info( 1, &error_ctx );
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_SIZE, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_SIZE, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(2, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(2, error_ctx.error_value);
status = mbed_get_error_log_info( 2, &error_ctx ); status = mbed_get_error_hist_info( 2, &error_ctx );
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_FORMAT, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_FORMAT, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(3, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(3, error_ctx.error_value);
@ -175,24 +175,24 @@ void test_error_logging()
MBED_WARNING(MBED_ERROR_UNSUPPORTED, "Not supported", 12 ); MBED_WARNING(MBED_ERROR_UNSUPPORTED, "Not supported", 12 );
MBED_WARNING(MBED_ERROR_ACCESS_DENIED, "Access denied", 13 ); MBED_WARNING(MBED_ERROR_ACCESS_DENIED, "Access denied", 13 );
status = mbed_get_error_log_info( 0, &error_ctx ); status = mbed_get_error_hist_info( 0, &error_ctx );
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TIME_OUT, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TIME_OUT, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(10, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(10, error_ctx.error_value);
status = mbed_get_error_log_info( 1, &error_ctx ); status = mbed_get_error_hist_info( 1, &error_ctx );
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ALREADY_IN_USE, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ALREADY_IN_USE, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(11, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(11, error_ctx.error_value);
status = mbed_get_error_log_info( 2, &error_ctx ); status = mbed_get_error_hist_info( 2, &error_ctx );
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_UNSUPPORTED, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_UNSUPPORTED, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(12, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(12, error_ctx.error_value);
status = mbed_get_error_log_info( 3, &error_ctx ); status = mbed_get_error_hist_info( 3, &error_ctx );
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ACCESS_DENIED, error_ctx.error_status); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ACCESS_DENIED, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(13, error_ctx.error_value); TEST_ASSERT_EQUAL_UINT(13, error_ctx.error_value);
//Try an index which is invalid, we should get ERROR_INVALID_ARGUMENT back //Try an index which is invalid, we should get ERROR_INVALID_ARGUMENT back
status = mbed_get_error_log_info( 99, &error_ctx ); status = mbed_get_error_hist_info( 99, &error_ctx );
TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, status); TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, status);
} }
@ -202,7 +202,6 @@ void test_error_logging()
//Error logger threads //Error logger threads
void err_thread_func(mbed_error_status_t *error_status) void err_thread_func(mbed_error_status_t *error_status)
{ {
//printf("\nError Status = 0x%08X\n",*error_status);
MBED_WARNING(*error_status, "Error from Multi-Threaded error logging test", *error_status ); MBED_WARNING(*error_status, "Error from Multi-Threaded error logging test", *error_status );
} }
@ -228,15 +227,14 @@ void test_error_logging_multithread()
errThread[i]->join(); errThread[i]->join();
} }
i = mbed_get_error_log_count()-1; i = mbed_get_error_hist_count()-1;
//printf("\nError log count = %d\n", i+1);
for(;i>=0;--i) { for(;i>=0;--i) {
mbed_error_status_t status = mbed_get_error_log_info( i, &error_ctx ); mbed_error_status_t status = mbed_get_error_hist_info( i, &error_ctx );
if(status != MBED_SUCCESS) { if(status != MBED_SUCCESS) {
TEST_FAIL(); TEST_FAIL();
} }
//printf("\nError Status[%d] = 0x%08X Value = 0x%08X\n", i, (unsigned int)error_ctx.error_status, (unsigned int)error_ctx.error_value);
TEST_ASSERT_EQUAL_UINT((unsigned int)error_ctx.error_value, (unsigned int)error_ctx.error_status); TEST_ASSERT_EQUAL_UINT((unsigned int)error_ctx.error_value, (unsigned int)error_ctx.error_status);
} }
} }
@ -307,25 +305,21 @@ void test_save_error_log()
error = MBED_TEST_FILESYSTEM::format(&fd); error = MBED_TEST_FILESYSTEM::format(&fd);
if(error < 0) { if(error < 0) {
printf("Failed formatting"); TEST_FAIL_MESSAGE("Failed formatting");
TEST_FAIL();
} }
error = fs.mount(&fd); error = fs.mount(&fd);
if(error < 0) { if(error < 0) {
printf("Failed mounting fs"); TEST_FAIL_MESSAGE("Failed mounting fs");
TEST_FAIL();
} }
if(MBED_SUCCESS != mbed_save_error_log("/fs/errors.log")) { if(MBED_SUCCESS != mbed_save_error_hist("/fs/errors.log")) {
printf("Failed saving error log"); TEST_FAIL_MESSAGE("Failed saving error log");
TEST_FAIL();
} }
FILE *error_file = fopen("/fs/errors.log", "r"); FILE *error_file = fopen("/fs/errors.log", "r");
if(error_file == NULL) { if(error_file == NULL) {
printf("Unable to find error log in fs"); TEST_FAIL_MESSAGE("Unable to find error log in fs");
TEST_FAIL();
} }
char buff[64] = {0}; char buff[64] = {0};
@ -333,13 +327,11 @@ void test_save_error_log()
int size = fread(&buff[0], 1, 15, error_file); int size = fread(&buff[0], 1, 15, error_file);
fwrite(&buff[0], 1, size, stdout); fwrite(&buff[0], 1, size, stdout);
} }
printf("\r\n");
fclose(error_file); fclose(error_file);
error = fs.unmount(); error = fs.unmount();
if(error < 0) { if(error < 0) {
printf("Failed unmounting fs"); TEST_FAIL_MESSAGE("Failed unmounting fs");
TEST_FAIL();
} }
} }
@ -347,7 +339,7 @@ void test_save_error_log()
utest::v1::status_t test_setup(const size_t number_of_cases) utest::v1::status_t test_setup(const size_t number_of_cases)
{ {
GREENTEA_SETUP(300, "default_auto"); GREENTEA_SETUP(120, "default_auto");
return utest::v1::verbose_test_setup_handler(number_of_cases); return utest::v1::verbose_test_setup_handler(number_of_cases);
} }
@ -356,7 +348,7 @@ Case cases[] = {
Case("Test error encoding, value capture, first and last errors", test_error_capturing), Case("Test error encoding, value capture, first and last errors", test_error_capturing),
Case("Test error context capture", test_error_context_capture), Case("Test error context capture", test_error_context_capture),
Case("Test error hook", test_error_hook), Case("Test error hook", test_error_hook),
#ifndef MBED_CONF_ERROR_LOG_DISABLED #ifndef MBED_CONF_ERROR_HIST_DISABLED
Case("Test error logging", test_error_logging), Case("Test error logging", test_error_logging),
Case("Test error handling multi-threaded", test_error_logging_multithread), Case("Test error handling multi-threaded", test_error_logging_multithread),
#ifdef MBED_TEST_SIM_BLOCKDEVICE #ifdef MBED_TEST_SIM_BLOCKDEVICE

View File

@ -123,7 +123,7 @@ u32_t sys_now(void) {
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) { err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) {
if (queue_sz > MB_SIZE) if (queue_sz > MB_SIZE)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_INVALID_SIZE), "sys_mbox_new size error\n", queue_sz); error("sys_mbox_new size error\n");
memset(mbox, 0, sizeof(*mbox)); memset(mbox, 0, sizeof(*mbox));
@ -131,7 +131,7 @@ err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) {
mbox->attr.cb_size = sizeof(mbox->data); mbox->attr.cb_size = sizeof(mbox->data);
mbox->id = osEventFlagsNew(&mbox->attr); mbox->id = osEventFlagsNew(&mbox->attr);
if (mbox->id == NULL) if (mbox->id == NULL)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_CREATE_FAILED), "sys_mbox_new create error\n", mbox->id); error("sys_mbox_new create error\n");
osEventFlagsSet(mbox->id, SYS_MBOX_POST_EVENT); osEventFlagsSet(mbox->id, SYS_MBOX_POST_EVENT);
@ -150,7 +150,7 @@ err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) {
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
void sys_mbox_free(sys_mbox_t *mbox) { void sys_mbox_free(sys_mbox_t *mbox) {
if (mbox->post_idx != mbox->fetch_idx) if (mbox->post_idx != mbox->fetch_idx)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_FREE_FAILED), "sys_mbox_free error\n", mbox->post_idx); error("sys_mbox_free error\n");
} }
/*---------------------------------------------------------------------------* /*---------------------------------------------------------------------------*
@ -309,7 +309,7 @@ err_t sys_sem_new(sys_sem_t *sem, u8_t count) {
sem->attr.cb_size = sizeof(sem->data); sem->attr.cb_size = sizeof(sem->data);
sem->id = osSemaphoreNew(UINT16_MAX, count, &sem->attr); sem->id = osSemaphoreNew(UINT16_MAX, count, &sem->attr);
if (sem->id == NULL) if (sem->id == NULL)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_CREATE_FAILED), "sys_sem_new create error\n", sem->id); error("sys_sem_new create error\n");
return ERR_OK; return ERR_OK;
} }
@ -388,14 +388,14 @@ err_t sys_mutex_new(sys_mutex_t *mutex) {
* @param mutex the mutex to lock */ * @param mutex the mutex to lock */
void sys_mutex_lock(sys_mutex_t *mutex) { void sys_mutex_lock(sys_mutex_t *mutex) {
if (osMutexAcquire(mutex->id, osWaitForever) != osOK) if (osMutexAcquire(mutex->id, osWaitForever) != osOK)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "sys_mutex_lock error\n", mutex->id); error("sys_mutex_lock error\n");
} }
/** Unlock a mutex /** Unlock a mutex
* @param mutex the mutex to unlock */ * @param mutex the mutex to unlock */
void sys_mutex_unlock(sys_mutex_t *mutex) { void sys_mutex_unlock(sys_mutex_t *mutex) {
if (osMutexRelease(mutex->id) != osOK) if (osMutexRelease(mutex->id) != osOK)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_MUTEX_UNLOCK_FAILED), "sys_mutex_unlock error\n", mutex->id); error("sys_mutex_unlock error\n");
} }
/** Delete a mutex /** Delete a mutex
@ -418,7 +418,7 @@ void sys_init(void) {
lwip_sys_mutex_attr.cb_size = sizeof(lwip_sys_mutex_data); lwip_sys_mutex_attr.cb_size = sizeof(lwip_sys_mutex_data);
lwip_sys_mutex = osMutexNew(&lwip_sys_mutex_attr); lwip_sys_mutex = osMutexNew(&lwip_sys_mutex_attr);
if (lwip_sys_mutex == NULL) if (lwip_sys_mutex == NULL)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_INITIALIZATION_FAILED), "sys_init error\n", lwip_sys_mutex); error("sys_init error\n");
} }
/*---------------------------------------------------------------------------* /*---------------------------------------------------------------------------*
@ -452,7 +452,7 @@ u32_t sys_jiffies(void) {
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
sys_prot_t sys_arch_protect(void) { sys_prot_t sys_arch_protect(void) {
if (osMutexAcquire(lwip_sys_mutex, osWaitForever) != osOK) if (osMutexAcquire(lwip_sys_mutex, osWaitForever) != osOK)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "sys_arch_protect error\n", lwip_sys_mutex); error("sys_arch_protect error\n");
return (sys_prot_t) 1; return (sys_prot_t) 1;
} }
@ -469,7 +469,7 @@ sys_prot_t sys_arch_protect(void) {
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
void sys_arch_unprotect(sys_prot_t p) { void sys_arch_unprotect(sys_prot_t p) {
if (osMutexRelease(lwip_sys_mutex) != osOK) if (osMutexRelease(lwip_sys_mutex) != osOK)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_MUTEX_LOCK_FAILED), "sys_arch_unprotect error\n", lwip_sys_mutex); error("sys_arch_unprotect error\n");
} }
u32_t sys_now(void) { u32_t sys_now(void) {
@ -508,7 +508,7 @@ sys_thread_t sys_thread_new(const char *pcName,
LWIP_DEBUGF(SYS_DEBUG, ("New Thread: %s\n", pcName)); LWIP_DEBUGF(SYS_DEBUG, ("New Thread: %s\n", pcName));
if (thread_pool_index >= SYS_THREAD_POOL_N) if (thread_pool_index >= SYS_THREAD_POOL_N)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_THREAD_CREATE_FAILED), "sys_thread_new number error\n", thread_pool_index); error("sys_thread_new number error\n");
sys_thread_t t = (sys_thread_t)&thread_pool[thread_pool_index]; sys_thread_t t = (sys_thread_t)&thread_pool[thread_pool_index];
thread_pool_index++; thread_pool_index++;
@ -520,11 +520,11 @@ sys_thread_t sys_thread_new(const char *pcName,
t->attr.stack_size = stacksize; t->attr.stack_size = stacksize;
t->attr.stack_mem = malloc(stacksize); t->attr.stack_mem = malloc(stacksize);
if (t->attr.stack_mem == NULL) { if (t->attr.stack_mem == NULL) {
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_OUT_OF_MEMORY), "Error allocating the stack memory", t); error("Error allocating the stack memory");
} }
t->id = osThreadNew((osThreadFunc_t)thread, arg, &t->attr); t->id = osThreadNew((osThreadFunc_t)thread, arg, &t->attr);
if (t->id == NULL) if (t->id == NULL)
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_NETWORK_STACK, MBED_ERROR_CODE_THREAD_CREATE_FAILED), "sys_thread_new create error\n", t->id); error("sys_thread_new create error\n");
return t; return t;
} }

View File

@ -18,25 +18,43 @@
#include "device.h" #include "device.h"
#include "platform/mbed_critical.h" #include "platform/mbed_critical.h"
#include "platform/mbed_error.h" #include "platform/mbed_error.h"
#include "platform/mbed_error_log.h" #include "platform/mbed_error_hist.h"
#include "platform/mbed_error_report.h"
#include "platform/mbed_interface.h" #include "platform/mbed_interface.h"
#ifdef MBED_CONF_RTOS_PRESENT
#include "rtx_os.h"
#endif
#if DEVICE_STDIO_MESSAGES #if DEVICE_STDIO_MESSAGES
#include <stdio.h> #include <stdio.h>
#endif #endif
//Helper macro to get the current SP
#define GET_CURRENT_SP(sp) \
{ \
/*If in Handler mode we are always using MSP*/ \
if( __get_IPSR() != 0U ) { \
sp = __get_MSP(); \
} else { \
/*Look into CONTROL.SPSEL value*/ \
if ((__get_CONTROL() & 2U) == 0U) { \
sp = __get_MSP();/*Read MSP*/ \
} else { \
sp = __get_PSP();/*Read PSP*/ \
} \
} \
}
static uint8_t error_in_progress = 0; static uint8_t error_in_progress = 0;
static int error_count = 0; static int error_count = 0;
static mbed_error_ctx first_error_ctx = {0}; static mbed_error_ctx first_error_ctx = {0};
static mbed_error_ctx last_error_ctx = {0}; static mbed_error_ctx last_error_ctx = {0};
static mbed_error_hook_t error_hook = NULL; static mbed_error_hook_t error_hook = NULL;
static void print_error_report(mbed_error_ctx *ctx, const char *);
//Helper function to halt the system //Helper function to halt the system
static void mbed_halt_system(void) static void mbed_halt_system(void)
{ {
mbed_error_print("\nFATAL ERROR: Halting System...\n", NULL);
//If not in ISR context exit, otherwise spin on WFI //If not in ISR context exit, otherwise spin on WFI
if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) { if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
for(;;) { for(;;) {
@ -60,6 +78,7 @@ WEAK void error(const char* format, ...) {
va_list arg; va_list arg;
va_start(arg, format); va_start(arg, format);
mbed_error_vfprintf(format, arg); mbed_error_vfprintf(format, arg);
MBED_ERROR(MBED_ERROR_UNKNOWN, "Fatal Run-time Error", 0);
va_end(arg); va_end(arg);
#endif #endif
exit(1); exit(1);
@ -78,7 +97,7 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e
} }
//Prevent corruption by holding out other callers //Prevent corruption by holding out other callers
//and we also need this until we remove the error call completely //and we also need this until we remove the "error" call completely
while (error_in_progress == 1); while (error_in_progress == 1);
//Use critsect here, as we don't want inadvertant modification of this global variable //Use critsect here, as we don't want inadvertant modification of this global variable
@ -95,6 +114,18 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e
current_error_ctx.error_status = error_status; current_error_ctx.error_status = error_status;
current_error_ctx.error_address = (uint32_t)MBED_CALLER_ADDR(); current_error_ctx.error_address = (uint32_t)MBED_CALLER_ADDR();
current_error_ctx.error_value = error_value; current_error_ctx.error_value = error_value;
#ifdef MBED_CONF_RTOS_PRESENT
//Capture thread info
osRtxThread_t *current_thread = osRtxInfo.thread.run.curr;
current_error_ctx.thread_id = (uint32_t)current_thread;
current_error_ctx.thread_entry_address = (uint32_t)current_thread->thread_addr;
current_error_ctx.thread_stack_size = current_thread->stack_size;
current_error_ctx.thread_stack_mem = (uint32_t)current_thread->stack_mem;
#ifdef TARGET_CORTEX_M
GET_CURRENT_SP(current_error_ctx.thread_current_sp);
#endif //TARGET_CORTEX_M
#endif //MBED_CONF_RTOS_PRESENT
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED #ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
//Capture filename/linenumber if provided //Capture filename/linenumber if provided
@ -110,9 +141,6 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e
} }
#endif #endif
//Report the error
mbed_report_error(&current_error_ctx, (char *)error_msg);
//Capture the fist system error and store it //Capture the fist system error and store it
if(error_count == 1) { //first error if(error_count == 1) { //first error
memcpy(&first_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx)); memcpy(&first_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx));
@ -121,9 +149,9 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e
//copy this error to last error //copy this error to last error
memcpy(&last_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx)); memcpy(&last_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx));
#ifndef MBED_CONF_ERROR_LOG_DISABLED #ifndef MBED_CONF_ERROR_HIST_DISABLED
//Log the error with error log //Log the error with error log
mbed_log_put_error(&current_error_ctx); mbed_error_hist_put(&current_error_ctx);
#endif #endif
//Call the error hook if available //Call the error hook if available
@ -137,21 +165,21 @@ mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *e
} }
//Return the first error //Return the first error
mbed_error_status_t get_first_error(void) mbed_error_status_t mbed_get_first_error(void)
{ {
//return the first error recorded //return the first error recorded
return first_error_ctx.error_status; return first_error_ctx.error_status;
} }
//Return the last error //Return the last error
mbed_error_status_t get_last_error(void) mbed_error_status_t mbed_get_last_error(void)
{ {
//return the last error recorded //return the last error recorded
return last_error_ctx.error_status; return last_error_ctx.error_status;
} }
//Gets the current error count //Gets the current error count
int get_error_count(void) int mbed_get_error_count(void)
{ {
//return the current error count //return the current error count
return error_count; return error_count;
@ -169,6 +197,9 @@ WEAK mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char
//set the error reported and then halt the system //set the error reported and then halt the system
if( MBED_SUCCESS != handle_error(error_status, error_msg, error_value, filename, line_number) ) if( MBED_SUCCESS != handle_error(error_status, error_msg, error_value, filename, line_number) )
return MBED_ERROR_FAILED_OPERATION; return MBED_ERROR_FAILED_OPERATION;
//On fatal errors print the error context/report
print_error_report(&last_error_ctx, error_msg);
mbed_halt_system(); mbed_halt_system();
return MBED_ERROR_FAILED_OPERATION; return MBED_ERROR_FAILED_OPERATION;
@ -187,14 +218,14 @@ mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in)
} }
//Retrieve the first error context from error log //Retrieve the first error context from error log
mbed_error_status_t mbed_get_first_error_log_info (mbed_error_ctx *error_info) mbed_error_status_t mbed_get_first_error_info (mbed_error_ctx *error_info)
{ {
memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx)); memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx));
return MBED_SUCCESS; return MBED_SUCCESS;
} }
//Retrieve the last error context from error log //Retrieve the last error context from error log
mbed_error_status_t mbed_get_last_error_log_info (mbed_error_ctx *error_info) mbed_error_status_t mbed_get_last_error_info (mbed_error_ctx *error_info)
{ {
memcpy(error_info, &last_error_ctx, sizeof(mbed_error_ctx)); memcpy(error_info, &last_error_ctx, sizeof(mbed_error_ctx));
return MBED_SUCCESS; return MBED_SUCCESS;
@ -243,32 +274,32 @@ mbed_error_status_t mbed_clear_all_errors(void)
memset(&last_error_ctx, sizeof(mbed_error_ctx), 0); memset(&last_error_ctx, sizeof(mbed_error_ctx), 0);
//reset error count to 0 //reset error count to 0
error_count = 0; error_count = 0;
#ifndef MBED_CONF_ERROR_LOG_DISABLED #ifndef MBED_CONF_ERROR_HIST_DISABLED
status = mbed_log_reset(); status = mbed_error_hist_reset();
#endif #endif
core_util_critical_section_exit(); core_util_critical_section_exit();
return status; return status;
} }
#ifndef MBED_CONF_ERROR_LOG_DISABLED #ifndef MBED_CONF_ERROR_HIST_DISABLED
//Retrieve the error context from error log at the specified index //Retrieve the error context from error log at the specified index
mbed_error_status_t mbed_get_error_log_info (int index, mbed_error_ctx *error_info) mbed_error_status_t mbed_get_error_hist_info (int index, mbed_error_ctx *error_info)
{ {
return mbed_log_get_error(index, error_info); return mbed_error_hist_get(index, error_info);
} }
//Retrieve the error log count //Retrieve the error log count
int mbed_get_error_log_count(void) int mbed_get_error_hist_count(void)
{ {
return mbed_log_get_error_log_count(); return mbed_error_hist_get_count();
} }
mbed_error_status_t mbed_save_error_log(const char *path) mbed_error_status_t mbed_save_error_hist(const char *path)
{ {
mbed_error_status_t ret = MBED_SUCCESS; mbed_error_status_t ret = MBED_SUCCESS;
mbed_error_ctx ctx = {0}; mbed_error_ctx ctx = {0};
int log_count = mbed_log_get_error_log_count(); int log_count = mbed_error_hist_get_count();
FILE *error_log_file = NULL; FILE *error_log_file = NULL;
//Ensure path is valid //Ensure path is valid
@ -304,7 +335,7 @@ mbed_error_status_t mbed_save_error_log(const char *path)
//Update with error log info //Update with error log info
while(--log_count >= 0) { while(--log_count >= 0) {
mbed_log_get_error(log_count, &ctx); mbed_error_hist_get(log_count, &ctx);
//first line of file will be error log count //first line of file will be error log count
if(fprintf(error_log_file, "\n%d: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n", if(fprintf(error_log_file, "\n%d: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
log_count, log_count,
@ -323,6 +354,84 @@ exit:
return ret; return ret;
} }
static void print_error_report(mbed_error_ctx *ctx, const char *error_msg)
{
uint32_t error_code = MBED_GET_ERROR_CODE(ctx->error_status);
uint32_t error_module = MBED_GET_ERROR_MODULE(ctx->error_status);
mbed_error_printf("\n\n++ MbedOS Error Info ++\nError Status: 0x%x Code: %d Entity: %d\nError Message: ", ctx->error_status, error_code, error_module);
//Report error info based on error code, some errors require different
//error_vals[1] contains the error code
if(error_code == MBED_ERROR_CODE_HARDFAULT_EXCEPTION ||
error_code == MBED_ERROR_CODE_MEMMANAGE_EXCEPTION ||
error_code == MBED_ERROR_CODE_BUSFAULT_EXCEPTION ||
error_code == MBED_ERROR_CODE_USAGEFAULT_EXCEPTION ) {
mbed_error_printf(error_msg);
mbed_error_printf("\nLocation: 0x%x\n", ctx->error_value);
} else {
switch (error_code) {
//These are errors reported by kernel handled from mbed_rtx_handlers
case MBED_ERROR_CODE_RTOS_EVENT:
mbed_error_printf("Kernel Error: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_THREAD_EVENT:
mbed_error_printf("Thread: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MUTEX_EVENT:
mbed_error_printf("Mutex: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT:
mbed_error_printf("Semaphore: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT:
mbed_error_printf("MemoryPool: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT:
mbed_error_printf("EventFlags: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_TIMER_EVENT:
mbed_error_printf("Timer: 0x%x, ", ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT:
mbed_error_printf("MessageQueue: 0x%x, ", ctx->error_value);
break;
default:
//Nothing to do here, just print the error info down
break;
}
mbed_error_printf(error_msg, NULL);
mbed_error_printf("\nLocation: 0x%x", ctx->error_address);
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
if(NULL != error_ctx->error_filename) {
//for string, we must pass address of a ptr which has the address of the string
uint32_t *file_name = (uint32_t *)&error_ctx->error_filename[0];
mbed_error_printf("\nFile:%s", &file_name);
mbed_error_printf("+0x%x", ctx->error_line_number);
}
#endif
#ifdef TARGET_CORTEX_M
mbed_error_printf("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x SP: 0x%x ",
ctx->error_value, ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem, ctx->thread_current_sp);
#else
//For Cortex-A targets we dont have support to capture the current SP
mbed_error_printf("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x ",
ctx->error_value, ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem);
#endif //TARGET_CORTEX_M
}
mbed_error_printf("\n-- MbedOS Error Info --");
}
#endif #endif

View File

@ -34,7 +34,7 @@ extern "C" {
*/ */
/** Define this macro to disable error logging, note that the first and last error capture will still be active by default. /** Define this macro to disable error logging, note that the first and last error capture will still be active by default.
* MBED_CONF_ERROR_LOG_DISABLED * MBED_CONF_ERROR_HIST_DISABLED
*/ */
#ifndef MBED_CONF_MAX_ERROR_FILENAME_LEN #ifndef MBED_CONF_MAX_ERROR_FILENAME_LEN
@ -805,10 +805,6 @@ typedef struct _mbed_error_ctx {
* @param format C string that contains data stream to be printed. * @param format C string that contains data stream to be printed.
* Code snippets below show valid format. * Code snippets below show valid format.
* *
* @deprecated
* This function has been deprecated, please use one of MBED_WARNING/MBED_ERROR macros
* or one of mbed_error/mbed_warning functions.
*
* @code * @code
* #error "That shouldn't have happened!" * #error "That shouldn't have happened!"
* @endcode * @endcode
@ -846,8 +842,6 @@ typedef struct _mbed_error_ctx {
* *
*/ */
MBED_DEPRECATED_SINCE("mbed-os-5.9", "This function has been deprecated, please use one of MBED_WARNING/MBED_ERROR macros or one of mbed_warning/mbed_error functions" )
void error(const char* format, ...); void error(const char* format, ...);
/** /**
@ -932,21 +926,21 @@ mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *e
* @return mbed_error_status_t code logged for the first error or MBED_SUCCESS if no errors are logged. * @return mbed_error_status_t code logged for the first error or MBED_SUCCESS if no errors are logged.
* *
*/ */
mbed_error_status_t get_first_error(void); mbed_error_status_t mbed_get_first_error(void);
/** /**
* Returns the most recent system error reported. * Returns the most recent system error reported.
* @return mbed_error_status_t code logged for the last error or MBED_SUCCESS if no errors are logged. * @return mbed_error_status_t code logged for the last error or MBED_SUCCESS if no errors are logged.
* *
*/ */
mbed_error_status_t get_last_error(void); mbed_error_status_t mbed_get_last_error(void);
/** /**
* Returns the number of system errors reported after boot. * Returns the number of system errors reported after boot.
* @return int Number of errors reported. * @return int Number of errors reported.
* *
*/ */
int get_error_count(void); int mbed_get_error_count(void);
/** /**
* Call this function to set a fatal system error and halt the system. This function will log the fatal error with the context info and prints the error report. * Call this function to set a fatal system error and halt the system. This function will log the fatal error with the context info and prints the error report.
@ -998,7 +992,7 @@ mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t custom_error_hook);
* MBED_ERROR_INVALID_ARGUMENT in case of invalid index * MBED_ERROR_INVALID_ARGUMENT in case of invalid index
* *
*/ */
mbed_error_status_t mbed_get_first_error_log_info(mbed_error_ctx *error_info); mbed_error_status_t mbed_get_first_error_info(mbed_error_ctx *error_info);
/** /**
* Reads the last error context information logged. * Reads the last error context information logged.
@ -1007,7 +1001,7 @@ mbed_error_status_t mbed_get_first_error_log_info(mbed_error_ctx *error_info);
* MBED_ERROR_INVALID_ARGUMENT in case of invalid index * MBED_ERROR_INVALID_ARGUMENT in case of invalid index
* *
*/ */
mbed_error_status_t mbed_get_last_error_log_info(mbed_error_ctx *error_info); mbed_error_status_t mbed_get_last_error_info(mbed_error_ctx *error_info);
/** /**
* Clears all the last error, error count and all entries in the error log. * Clears all the last error, error count and all entries in the error log.
@ -1031,7 +1025,7 @@ mbed_error_status_t mbed_make_error(mbed_error_type_t error_type, mbed_module_ty
* @return Current number of entries in the error log. * @return Current number of entries in the error log.
* *
*/ */
int mbed_get_error_log_count(void); int mbed_get_error_hist_count(void);
/** /**
* Reads the error context information for a specific error log specified by the index. * Reads the error context information for a specific error log specified by the index.
@ -1044,7 +1038,7 @@ int mbed_get_error_log_count(void);
* MBED_ERROR_INVALID_ARGUMENT in case of invalid index * MBED_ERROR_INVALID_ARGUMENT in case of invalid index
* *
*/ */
mbed_error_status_t mbed_get_error_log_info(int index, mbed_error_ctx *error_info); mbed_error_status_t mbed_get_error_hist_info(int index, mbed_error_ctx *error_info);
/** /**
* Saves the error log information to a file * Saves the error log information to a file
@ -1057,7 +1051,7 @@ mbed_error_status_t mbed_get_error_log_info(int index, mbed_error_ctx *error_inf
* @note Filesystem support is required in order for this function to work. * @note Filesystem support is required in order for this function to work.
* *
*/ */
mbed_error_status_t mbed_save_error_log(const char *path); mbed_error_status_t mbed_save_error_hist(const char *path);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -21,13 +21,13 @@
#include "platform/mbed_critical.h" #include "platform/mbed_critical.h"
#include "platform/mbed_interface.h" #include "platform/mbed_interface.h"
#ifndef MBED_CONF_ERROR_LOG_DISABLED #ifndef MBED_CONF_ERROR_HIST_DISABLED
#include "platform/mbed_error_log.h" #include "platform/mbed_error_hist.h"
static mbed_error_ctx mbed_error_ctx_log[MBED_CONF_ERROR_LOG_SIZE] = {0}; static mbed_error_ctx mbed_error_ctx_log[MBED_CONF_ERROR_HIST_SIZE] = {0};
static int error_log_count = -1; static int error_log_count = -1;
mbed_error_status_t mbed_log_put_error(mbed_error_ctx *error_ctx) mbed_error_status_t mbed_error_hist_put(mbed_error_ctx *error_ctx)
{ {
//Return error if error_ctx is NULL //Return error if error_ctx is NULL
if(NULL == error_ctx) { if(NULL == error_ctx) {
@ -36,58 +36,58 @@ mbed_error_status_t mbed_log_put_error(mbed_error_ctx *error_ctx)
core_util_critical_section_enter(); core_util_critical_section_enter();
error_log_count++; error_log_count++;
memcpy(&mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_LOG_SIZE], error_ctx, sizeof(mbed_error_ctx) ); memcpy(&mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE], error_ctx, sizeof(mbed_error_ctx) );
core_util_critical_section_exit(); core_util_critical_section_exit();
return MBED_SUCCESS; return MBED_SUCCESS;
} }
mbed_error_status_t mbed_log_get_error(int index, mbed_error_ctx *error_ctx) mbed_error_status_t mbed_error_hist_get(int index, mbed_error_ctx *error_ctx)
{ {
//Return error if index is more than max log size //Return error if index is more than max log size
if(index >= MBED_CONF_ERROR_LOG_SIZE) { if(index >= MBED_CONF_ERROR_HIST_SIZE) {
return MBED_ERROR_INVALID_ARGUMENT; return MBED_ERROR_INVALID_ARGUMENT;
} }
core_util_critical_section_enter(); core_util_critical_section_enter();
//calculate the index where we want to pick the ctx //calculate the index where we want to pick the ctx
if(error_log_count >= MBED_CONF_ERROR_LOG_SIZE) { if(error_log_count >= MBED_CONF_ERROR_HIST_SIZE) {
index = (error_log_count + index + 1) % MBED_CONF_ERROR_LOG_SIZE; index = (error_log_count + index + 1) % MBED_CONF_ERROR_HIST_SIZE;
} }
core_util_critical_section_exit(); core_util_critical_section_exit();
memcpy(error_ctx, &mbed_error_ctx_log[index % MBED_CONF_ERROR_LOG_SIZE], sizeof(mbed_error_ctx) ); memcpy(error_ctx, &mbed_error_ctx_log[index % MBED_CONF_ERROR_HIST_SIZE], sizeof(mbed_error_ctx) );
return MBED_SUCCESS; return MBED_SUCCESS;
} }
mbed_error_ctx *mbed_log_get_entry(void) mbed_error_ctx *mbed_error_hist_get_entry(void)
{ {
core_util_critical_section_enter(); core_util_critical_section_enter();
error_log_count++; error_log_count++;
mbed_error_ctx *ctx = &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_LOG_SIZE]; mbed_error_ctx *ctx = &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE];
core_util_critical_section_exit(); core_util_critical_section_exit();
return ctx; return ctx;
} }
mbed_error_status_t mbed_log_get_last_error(mbed_error_ctx *error_ctx) mbed_error_status_t mbed_error_hist_get_last_error(mbed_error_ctx *error_ctx)
{ {
if(-1 == error_log_count) { if(-1 == error_log_count) {
return MBED_ERROR_ITEM_NOT_FOUND; return MBED_ERROR_ITEM_NOT_FOUND;
} }
core_util_critical_section_enter(); core_util_critical_section_enter();
memcpy(error_ctx, &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_LOG_SIZE], sizeof(mbed_error_ctx) ); memcpy(error_ctx, &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE], sizeof(mbed_error_ctx) );
core_util_critical_section_exit(); core_util_critical_section_exit();
return MBED_SUCCESS; return MBED_SUCCESS;
} }
int mbed_log_get_error_log_count() int mbed_error_hist_get_count()
{ {
return (error_log_count >= MBED_CONF_ERROR_LOG_SIZE? MBED_CONF_ERROR_LOG_SIZE:error_log_count+1); return (error_log_count >= MBED_CONF_ERROR_HIST_SIZE? MBED_CONF_ERROR_HIST_SIZE:error_log_count+1);
} }
mbed_error_status_t mbed_log_reset() mbed_error_status_t mbed_error_hist_reset()
{ {
core_util_critical_section_enter(); core_util_critical_section_enter();
error_log_count = -1; error_log_count = -1;

View File

@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
#ifndef MBED_ERROR_LOG_H #ifndef MBED_ERROR_HIST_H
#define MBED_ERROR_LOG_H #define MBED_ERROR_HIST_H
#ifndef MBED_CONF_ERROR_LOG_SIZE #ifndef MBED_CONF_ERROR_HIST_SIZE
#define MBED_CONF_ERROR_LOG_SIZE 4 #define MBED_CONF_ERROR_HIST_SIZE 4
#else #else
#if MBED_CONF_ERROR_LOG_SIZE == 0 #if MBED_CONF_ERROR_HIST_SIZE == 0
#define MBED_CONF_ERROR_LOG_SIZE 1 #define MBED_CONF_ERROR_HIST_SIZE 1
#endif #endif
#endif #endif
@ -28,16 +28,16 @@
extern "C" { extern "C" {
#endif #endif
/* /*
* Puts/Adds an error entry into the error list * Puts/Adds an error entry into the error history list
* *
* @param error_ctx pointer to the mbed_error_ctx struct with the error context * @param error_ctx pointer to the mbed_error_ctx struct with the error context
* @return 0 or MBED_SUCCESS on success. * @return 0 or MBED_SUCCESS on success.
* ERROR_WRITE_FAILED if writing to file failed * MBED_ERROR_WRITE_FAILED if writing to file failed
* ERROR_INVALID_ARGUMENT if path is not valid * MBED_ERROR_INVALID_ARGUMENT if path is not valid
* *
* *
*/ */
mbed_error_status_t mbed_log_put_error(mbed_error_ctx *error_ctx); mbed_error_status_t mbed_error_hist_put(mbed_error_ctx *error_ctx);
/* /*
* Reads the error entry from the error list with the specified index * Reads the error entry from the error list with the specified index
@ -45,12 +45,12 @@ mbed_error_status_t mbed_log_put_error(mbed_error_ctx *error_ctx);
* @param index Index of the error context to be retrieved. It starts from 0 and 0 is the oldest. * @param index Index of the error context to be retrieved. It starts from 0 and 0 is the oldest.
* @param error_ctx pointer to the mbed_error_ctx struct where the error context will be filled, this should be allocated by the caller * @param error_ctx pointer to the mbed_error_ctx struct where the error context will be filled, this should be allocated by the caller
* @return 0 or MBED_SUCCESS on success. * @return 0 or MBED_SUCCESS on success.
* ERROR_WRITE_FAILED if writing to file failed * MBED_ERROR_WRITE_FAILED if writing to file failed
* ERROR_INVALID_ARGUMENT if path is not valid * MBED_ERROR_INVALID_ARGUMENT if path is not valid
* *
* *
*/ */
mbed_error_status_t mbed_log_get_error(int index, mbed_error_ctx *error_ctx); mbed_error_status_t mbed_error_hist_get(int index, mbed_error_ctx *error_ctx);
/* /*
* Gets a reference to the next error entry in the error log where in the error ctx can be filled in. * Gets a reference to the next error entry in the error log where in the error ctx can be filled in.
@ -60,52 +60,52 @@ mbed_error_status_t mbed_log_get_error(int index, mbed_error_ctx *error_ctx);
* *
* *
*/ */
mbed_error_ctx *mbed_log_get_entry(void); mbed_error_ctx *mbed_error_hist_get_entry(void);
/* /*
* Reads the last(latest) error entry from the error list * Reads the last(latest) error entry from the error history
* *
* @param error_ctx pointer to the mbed_error_ctx struct where the error context will be filled, this should be allocated by the caller * @param error_ctx pointer to the mbed_error_ctx struct where the error context will be filled, this should be allocated by the caller
* @return 0 or MBED_SUCCESS on success. * @return 0 or MBED_SUCCESS on success.
* ERROR_WRITE_FAILED if writing to file failed * MBED_ERROR_WRITE_FAILED if writing to file failed
* ERROR_INVALID_ARGUMENT if path is not valid * MBED_ERROR_INVALID_ARGUMENT if path is not valid
* *
* *
*/ */
mbed_error_status_t mbed_log_get_last_error(mbed_error_ctx *error_ctx); mbed_error_status_t mbed_error_hist_get_last_error(mbed_error_ctx *error_ctx);
/* /*
* Returns the number of error entries in the error list * Returns the number of error entries in the error history list
* *
* @return Number of entries in the list * @return Number of entries in the history list
* *
* *
*/ */
int mbed_log_get_error_log_count(void); int mbed_error_hist_get_count(void);
/* /*
* Resets the error log by resetting the number of errors to 0 and clears all previous errors in the log * Resets the error log by resetting the number of errors to 0 and clears all previous errors in the history list
* *
* @return 0 or MBED_SUCCESS on success. * @return 0 or MBED_SUCCESS on success.
* ERROR_WRITE_FAILED if writing to file failed * MBED_ERROR_WRITE_FAILED if writing to file failed
* ERROR_INVALID_ARGUMENT if path is not valid * MBED_ERROR_INVALID_ARGUMENT if path is not valid
* *
* *
*/ */
mbed_error_status_t mbed_log_reset(void); mbed_error_status_t mbed_error_hist_reset(void);
/* /*
* Saves the error log information to a file * Saves the error log information to a file
* *
* @param path path to the file in the filesystem * @param path path to the file in the filesystem
* @return 0 or MBED_SUCCESS on success. * @return 0 or MBED_SUCCESS on success.
* ERROR_WRITE_FAILED if writing to file failed * MBED_ERROR_WRITE_FAILED if writing to file failed
* ERROR_INVALID_ARGUMENT if path is not valid * MBED_ERROR_INVALID_ARGUMENT if path is not valid
* *
* @note Filesystem support is required in order for this function to work. * @note Filesystem support is required in order for this function to work.
* *
*/ */
mbed_error_status_t mbed_save_error_log(const char *path); mbed_error_status_t mbed_save_error_hist(const char *path);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,278 +0,0 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdarg.h>
#include "hal/serial_api.h"
#include "hal/itm_api.h"
#include "platform/mbed_error.h"
#include "platform/mbed_error_report.h"
#ifdef DEVICE_SERIAL
extern int stdio_uart_inited;
extern serial_t stdio_uart;
#endif
//Helper macro to get the current SP
#define GET_CURRENT_SP(sp) \
{ \
/*If in Handler mode we are always using MSP*/ \
if( __get_IPSR() != 0U ) { \
sp = __get_MSP(); \
} else { \
/*Look into CONTROL.SPSEL value*/ \
if ((__get_CONTROL() & 2U) == 0U) { \
sp = __get_MSP();/*Read MSP*/ \
} else { \
sp = __get_PSP();/*Read PSP*/ \
} \
} \
}
/* Converts a uint32 to hex char string */
static void value_to_hex_str(uint32_t value, char *hex_str)
{
char hex_char_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
int i = 0;
//Return without converting if hex_str is not provided
if(hex_str == NULL) return;
for(i=7; i>=0; i--) {
hex_str[i] = hex_char_map[(value & (0xf << (i * 4))) >> (i * 4)];
}
}
/* Converts a uint32 to dec char string */
static void value_to_dec_str(uint32_t value, char *dec_str)
{
char dec_char_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
int i = 0;
//Return without converting if hex_str is not provided
if(dec_str == NULL) return;
while(value > 0) {
dec_str[i++] = dec_char_map[value % 10];
value = value / 10;
}
}
void mbed_error_init(void)
{
#if DEVICE_SERIAL && (MBED_CONF_ERROR_REPORT_INTERFACE==DEVICE_SERIAL)
/* Initializes std uart if not init-ed yet */
if (!stdio_uart_inited) {
serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
}
#endif
#if DEVICE_ITM && (MBED_CONF_ERROR_REPORT_INTERFACE==DEVICE_ITM)
/*Initialize ITM interfaces*/
mbed_itm_init();
#endif
}
void mbed_error_putc(char ch)
{
#if DEVICE_SERIAL && (MBED_CONF_ERROR_REPORT_INTERFACE==DEVICE_SERIAL)
serial_putc(&stdio_uart, ch);
#endif
#if DEVICE_ITM && (MBED_CONF_ERROR_REPORT_INTERFACE==DEVICE_ITM)
/*Initialize ITM interfaces*/
mbed_itm_send(ITM_PORT_SWO, ch);
#endif
}
/* Limited print functionality which prints the string out to
stdout/uart without using stdlib by directly calling serial-api
and also uses less resources
The fmtstr contains the format string for printing and for every %
found in that it fetches a uint32 value from values buffer
and prints it in hex format.
*/
void mbed_error_print(char *fmtstr, uint32_t *values)
{
#if DEVICE_SERIAL || DEVICE_ITM
int i = 0;
int idx = 0;
int vidx = 0;
char num_str[9]={0};
char *str=NULL;
//Init error reporting interfaces
mbed_error_init();
while(fmtstr[i] != '\0') {
if(fmtstr[i]=='%') {
i++;
if(fmtstr[i]=='x') {
//print the number in hex format
value_to_hex_str(values[vidx++],num_str);
for(idx=7; idx>=0; idx--) {
mbed_error_putc(num_str[idx]);
}
}
else if(fmtstr[i]=='d') {
memset(num_str, '0', sizeof(num_str));
//print the number in dec format
value_to_dec_str(values[vidx++],num_str);
idx=5;//Start from 5 as we dont have big decimal numbers
while(num_str[idx--]=='0' && idx > 0);//Dont print zeros at front
for(idx++;idx>=0; idx--) {
mbed_error_putc(num_str[idx]);
}
}
else if(fmtstr[i]=='s') {
//print the string
str = (char *)((uint32_t)values[vidx++]);
while(*str != '\0') {
mbed_error_putc(*str);
str++;
}
str = NULL;
} else {
//Do not handle any other % formatting and keep going
}
} else {
//handle carriage returns
if (fmtstr[i] == '\n') {
mbed_error_putc('\r');
}
mbed_error_putc(fmtstr[i]);
}
i++;
}
#endif
}
#ifdef MBED_CONF_RTOS_PRESENT
/* Prints thread info from a list */
void print_threads_info(osRtxThread_t *threads)
{
while(threads != NULL) {
print_thread( threads );
threads = threads->thread_next;
}
}
/* Prints info of a thread(using osRtxThread_t struct)*/
void print_thread(osRtxThread_t *thread)
{
uint32_t data[5];
data[0]=thread->state;
data[1]=thread->thread_addr;
data[2]=thread->stack_size;
data[3]=(uint32_t)thread->stack_mem;
data[4]=thread->sp;
mbed_error_print("\nState: 0x%x Entry: 0x%x Stack Size: 0x%x Mem: 0x%x SP: 0x%x", data);
}
#endif
/* Prints the error information */
void mbed_report_error(mbed_error_ctx *error_ctx, char *error_msg)
{
uint32_t error_vals[3] = {0};
error_vals[0] = error_ctx->error_status;
error_vals[1] = MBED_GET_ERROR_CODE(error_ctx->error_status);
error_vals[2] = MBED_GET_ERROR_MODULE(error_ctx->error_status);
mbed_error_print("\n\n++ MbedOS Error Info ++\nError Status: 0x%x Code: %d Entity: %d\nError Message: ", error_vals);
//Report error info based on error code, some errors require different
//error_vals[1] contains the error code
if(error_vals[1] == MBED_ERROR_CODE_HARDFAULT_EXCEPTION ||
error_vals[1] == MBED_ERROR_CODE_MEMMANAGE_EXCEPTION ||
error_vals[1] == MBED_ERROR_CODE_BUSFAULT_EXCEPTION ||
error_vals[1] == MBED_ERROR_CODE_USAGEFAULT_EXCEPTION ) {
mbed_error_print(error_msg, NULL);
mbed_error_print("\nLocation: 0x%x\n", (uint32_t *)&error_ctx->error_value);
} else {
switch (error_vals[1]) {
//These are errors reported by kernel handled from mbed_rtx_handlers
case MBED_ERROR_CODE_RTOS_EVENT:
mbed_error_print("Kernel Error: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_THREAD_EVENT:
mbed_error_print("Thread: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MUTEX_EVENT:
mbed_error_print("Mutex: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT:
mbed_error_print("Semaphore: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT:
mbed_error_print("MemoryPool: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT:
mbed_error_print("EventFlags: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_TIMER_EVENT:
mbed_error_print("Timer: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT:
mbed_error_print("MessageQueue: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
default:
//Nothing to do here, just print the error info down
break;
}
mbed_error_print(error_msg, NULL);
mbed_error_print("\nLocation: 0x%x", (uint32_t *)&error_ctx->error_address);
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
if(NULL != error_ctx->error_filename) {
//for string, we must pass address of a ptr which has the address of the string
uint32_t *file_name = (uint32_t *)&error_ctx->error_filename[0];
mbed_error_print("\nFile:%s", &file_name);
mbed_error_print("+0x%x", (uint32_t *)&error_ctx->error_line_number);
}
#endif
#ifdef MBED_CONF_RTOS_PRESENT
//Capture thread info
osRtxThread_t *current_thread = osRtxInfo.thread.run.curr;
error_ctx->thread_id = (uint32_t)current_thread;
error_ctx->thread_entry_address = (uint32_t)current_thread->thread_addr;
error_ctx->thread_stack_size = current_thread->stack_size;
error_ctx->thread_stack_mem = (uint32_t)current_thread->stack_mem;
#ifdef TARGET_CORTEX_M
GET_CURRENT_SP(error_ctx->thread_current_sp);
//Take advantage of the fact that the thread info in context struct is consecutively placed
mbed_error_print("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x SP: 0x%x ",
(uint32_t *)&error_ctx->error_value);
#else
//For Cortex-A targets we dont have support to capture the current SP
//Take advantage of the fact that the thread info in context struct is consecutively placed
mbed_error_print("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x ",
(uint32_t *)&error_ctx->error_value);
#endif //TARGET_CORTEX_M
#endif //MBED_CONF_RTOS_PRESENT
}
mbed_error_print("\n-- MbedOS Error Info --", NULL);
}

View File

@ -1,82 +0,0 @@
/** \addtogroup platform */
/** @{*/
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_ERROR_REPORT_H
#define MBED_ERROR_REPORT_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MBED_CONF_ERROR_REPORT_INTERFACE
#define MBED_CONF_ERROR_REPORT_INTERFACE DEVICE_SERIAL
#endif
#ifdef MBED_CONF_RTOS_PRESENT
#include "rtx_os.h"
/* Prints thread info from a list
* @param threads Pointer to the list of osRtxThread_t structs for which the thread info will be printed
*
*/
void print_threads_info(osRtxThread_t *threads);
/* Prints info of a thread(using osRtxThread_t struct)
* @param thread Pointer to the osRtxThread_t struct for which the thread info will be printed
*
*/
void print_thread(osRtxThread_t *thread);
#endif
/* Routine to report the error
* @param error_ctx This is the error context struct containing the error info
* @param error_msg Error message to be used when reporting the error
*
*/
void mbed_report_error(mbed_error_ctx *error_ctx, char *error_msg);
/* Limited print functionality which prints the string out to
stdout/uart without using stdlib by directly calling serial-api
and also uses less resources
The fmtstr contains the format string for printing and for every %
found in that it fetches a uint32 value from values buffer
and prints it in hex format.
* @param fmstr format string to be used, currently we support %x(hex) %d(decimal) %s(string) formatters only.
* @param values This should be a pointer to array of values used for printing corresponding to the format specifiers(%x,%d,%s)) mentioned
*
*/
void mbed_error_print(char *fmtstr, uint32_t *values);
/* Initializes the data structures and interfaces for printing the error output
*
*/
void mbed_error_init(void);
/* Routine which putc into serial/itm interface
* @param ch character to print
*
*/
void mbed_error_putc(char ch);
#ifdef __cplusplus
}
#endif
#endif
/** @}*/

View File

@ -17,69 +17,193 @@
#include "rtx_os.h" #include "rtx_os.h"
#include "device.h" #include "device.h"
#include "platform/mbed_error.h" #include "platform/mbed_error.h"
#include "platform/mbed_error_report.h" #include "hal/serial_api.h"
#include "hal/itm_api.h"
#ifndef MBED_FAULT_HANDLER_DISABLED #ifndef MBED_FAULT_HANDLER_DISABLED
#include "mbed_rtx_fault_handler.h" #include "mbed_rtx_fault_handler.h"
#ifdef DEVICE_SERIAL
extern int stdio_uart_inited;
extern serial_t stdio_uart;
#endif
//Functions Prototypes //Functions Prototypes
void print_context_info(void); void print_context_info(void);
//Global for populating the context in exception handler //Global for populating the context in exception handler
mbed_fault_context_t mbed_fault_context; mbed_fault_context_t mbed_fault_context;
/* Converts a uint32 to hex char string */
static void value_to_hex_str(uint32_t value, char *hex_str)
{
char hex_char_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
int i = 0;
//Return without converting if hex_str is not provided
if(hex_str == NULL) return;
for(i=7; i>=0; i--) {
hex_str[i] = hex_char_map[(value & (0xf << (i * 4))) >> (i * 4)];
}
}
static void fault_print_init(void)
{
#if DEVICE_SERIAL
/* Initializes std uart if not init-ed yet */
if (!stdio_uart_inited) {
serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
}
#endif
#if DEVICE_ITM
/*Initialize ITM interfaces*/
mbed_itm_init();
#endif
}
static void fault_putc(char ch)
{
#if DEVICE_SERIAL
serial_putc(&stdio_uart, ch);
#endif
#if DEVICE_ITM
/*Initialize ITM interfaces*/
mbed_itm_send(ITM_PORT_SWO, ch);
#endif
}
/* Limited print functionality which prints the string out to
stdout/uart without using stdlib by directly calling serial-api
and also uses less resources
The fmtstr contains the format string for printing and for every %
found in that it fetches a uint32 value from values buffer
and prints it in hex format.
*/
static void fault_print(char *fmtstr, uint32_t *values)
{
#if DEVICE_SERIAL || DEVICE_ITM
int i = 0;
int idx = 0;
int vidx = 0;
char num_str[9]={0};
char *str=NULL;
//Init error reporting interfaces
fault_print_init();
while(fmtstr[i] != '\0') {
if(fmtstr[i]=='%') {
i++;
if(fmtstr[i]=='x') {
//print the number in hex format
value_to_hex_str(values[vidx++],num_str);
for(idx=7; idx>=0; idx--) {
fault_putc(num_str[idx]);
}
}
else if(fmtstr[i]=='s') {
//print the string
str = (char *)((uint32_t)values[vidx++]);
while(*str != '\0') {
fault_putc(*str);
str++;
}
str = NULL;
} else {
//Do not handle any other % formatting and keep going
}
} else {
//handle carriage returns
if (fmtstr[i] == '\n') {
fault_putc('\r');
}
fault_putc(fmtstr[i]);
}
i++;
}
#endif
}
#ifdef MBED_CONF_RTOS_PRESENT
/* Prints info of a thread(using osRtxThread_t struct)*/
static void print_thread(osRtxThread_t *thread)
{
uint32_t data[5];
data[0]=thread->state;
data[1]=thread->thread_addr;
data[2]=thread->stack_size;
data[3]=(uint32_t)thread->stack_mem;
data[4]=thread->sp;
fault_print("\nState: 0x%x Entry: 0x%x Stack Size: 0x%x Mem: 0x%x SP: 0x%x", data);
}
/* Prints thread info from a list */
static void print_threads_info(osRtxThread_t *threads)
{
while(threads != NULL) {
print_thread( threads );
threads = threads->thread_next;
}
}
#endif
//This is a handler function called from Fault handler to print the error information out. //This is a handler function called from Fault handler to print the error information out.
//This runs in fault context and uses special functions(defined in mbed_rtx_fault_handler.c) to print the information without using C-lib support. //This runs in fault context and uses special functions(defined in mbed_rtx_fault_handler.c) to print the information without using C-lib support.
__NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn) __NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn)
{ {
mbed_error_status_t faultStatus = MBED_SUCCESS; mbed_error_status_t faultStatus = MBED_SUCCESS;
mbed_error_print("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL); fault_print("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL);
switch( fault_type ) { switch( fault_type ) {
case HARD_FAULT_EXCEPTION: case HARD_FAULT_EXCEPTION:
mbed_error_print("HardFault",NULL); fault_print("HardFault",NULL);
faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION; faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION;
break; break;
case MEMMANAGE_FAULT_EXCEPTION: case MEMMANAGE_FAULT_EXCEPTION:
mbed_error_print("MemManageFault",NULL); fault_print("MemManageFault",NULL);
faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION; faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION;
break; break;
case BUS_FAULT_EXCEPTION: case BUS_FAULT_EXCEPTION:
mbed_error_print("BusFault",NULL); fault_print("BusFault",NULL);
faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION; faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION;
break; break;
case USAGE_FAULT_EXCEPTION: case USAGE_FAULT_EXCEPTION:
mbed_error_print("UsageFault",NULL); fault_print("UsageFault",NULL);
faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION; faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION;
break; break;
default: default:
mbed_error_print("Unknown Fault",NULL); fault_print("Unknown Fault",NULL);
faultStatus = MBED_ERROR_UNKNOWN; faultStatus = MBED_ERROR_UNKNOWN;
break; break;
} }
mbed_error_print("\n\nContext:",NULL); fault_print("\n\nContext:",NULL);
print_context_info(); print_context_info();
mbed_error_print("\n\nThreads Info:\nCurrent:",NULL); fault_print("\n\nThreads Info:\nCurrent:",NULL);
print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.curr); print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.curr);
mbed_error_print("\nNext:",NULL); fault_print("\nNext:",NULL);
print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.next); print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.next);
mbed_error_print("\nWait:",NULL); fault_print("\nWait:",NULL);
osRtxThread_t *threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.wait_list; osRtxThread_t *threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.wait_list;
print_threads_info(threads); print_threads_info(threads);
mbed_error_print("\nDelay:",NULL); fault_print("\nDelay:",NULL);
threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.delay_list; threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.delay_list;
print_threads_info(threads); print_threads_info(threads);
mbed_error_print("\nIdle:",NULL); fault_print("\nIdle:",NULL);
threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.idle; threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.idle;
print_threads_info(threads); print_threads_info(threads);
mbed_error_print("\n\n-- MbedOS Fault Handler --\n\n",NULL); fault_print("\n\n-- MbedOS Fault Handler --\n\n",NULL);
//Now call mbed_error, to log the error and halt the system //Now call mbed_error, to log the error and halt the system
mbed_error( MBED_MAKE_ERROR( MBED_MODULE_UNKNOWN, faultStatus ), "System encountered an unrecoverable fault excaption, halting system.", mbed_fault_context.PC_reg, NULL, 0 ); mbed_error( MBED_MAKE_ERROR( MBED_MODULE_UNKNOWN, faultStatus ), "System encountered an unrecoverable fault excaption, halting system.", mbed_fault_context.PC_reg, NULL, 0 );
@ -93,7 +217,7 @@ __NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_conte
void print_context_info(void) void print_context_info(void)
{ {
//Context Regs //Context Regs
mbed_error_print("\nR0 : %x" fault_print("\nR0 : %x"
"\nR1 : %x" "\nR1 : %x"
"\nR2 : %x" "\nR2 : %x"
"\nR3 : %x" "\nR3 : %x"
@ -114,7 +238,7 @@ void print_context_info(void)
"\nMSP : %x", (uint32_t *)&mbed_fault_context); "\nMSP : %x", (uint32_t *)&mbed_fault_context);
//Capture CPUID to get core/cpu info //Capture CPUID to get core/cpu info
mbed_error_print("\nCPUID: %x",(uint32_t *)&SCB->CPUID); fault_print("\nCPUID: %x",(uint32_t *)&SCB->CPUID);
#if !defined(TARGET_M0) && !defined(TARGET_M0P) #if !defined(TARGET_M0) && !defined(TARGET_M0P)
//Capture fault information registers to infer the cause of exception //Capture fault information registers to infer the cause of exception
@ -128,7 +252,7 @@ void print_context_info(void)
FSR[4] = SCB->DFSR; FSR[4] = SCB->DFSR;
FSR[5] = SCB->AFSR; FSR[5] = SCB->AFSR;
FSR[6] = SCB->SHCSR; FSR[6] = SCB->SHCSR;
mbed_error_print("\nHFSR : %x" fault_print("\nHFSR : %x"
"\nMMFSR: %x" "\nMMFSR: %x"
"\nBFSR : %x" "\nBFSR : %x"
"\nUFSR : %x" "\nUFSR : %x"
@ -138,33 +262,33 @@ void print_context_info(void)
//Print MMFAR only if its valid as indicated by MMFSR //Print MMFAR only if its valid as indicated by MMFSR
if(FSR[1] & 0x80) { if(FSR[1] & 0x80) {
mbed_error_print("\nMMFAR: %x",(uint32_t *)&SCB->MMFAR); fault_print("\nMMFAR: %x",(uint32_t *)&SCB->MMFAR);
} }
//Print BFAR only if its valid as indicated by BFSR //Print BFAR only if its valid as indicated by BFSR
if(FSR[2] & 0x80) { if(FSR[2] & 0x80) {
mbed_error_print("\nBFAR : %x",(uint32_t *)&SCB->BFAR); fault_print("\nBFAR : %x",(uint32_t *)&SCB->BFAR);
} }
#endif #endif
//Print Mode //Print Mode
if(mbed_fault_context.EXC_RETURN & 0x8) { if(mbed_fault_context.EXC_RETURN & 0x8) {
mbed_error_print("\nMode : Thread", NULL); fault_print("\nMode : Thread", NULL);
//Print Priv level in Thread mode - We capture CONTROL reg which reflects the privilege. //Print Priv level in Thread mode - We capture CONTROL reg which reflects the privilege.
//Note that the CONTROL register captured still reflects the privilege status of the //Note that the CONTROL register captured still reflects the privilege status of the
//thread mode eventhough we are in Handler mode by the time we capture it. //thread mode eventhough we are in Handler mode by the time we capture it.
if(mbed_fault_context.CONTROL & 0x1) { if(mbed_fault_context.CONTROL & 0x1) {
mbed_error_print("\nPriv : User", NULL); fault_print("\nPriv : User", NULL);
} else { } else {
mbed_error_print("\nPriv : Privileged", NULL); fault_print("\nPriv : Privileged", NULL);
} }
} else { } else {
mbed_error_print("\nMode : Handler", NULL); fault_print("\nMode : Handler", NULL);
mbed_error_print("\nPriv : Privileged", NULL); fault_print("\nPriv : Privileged", NULL);
} }
//Print Return Stack //Print Return Stack
if(mbed_fault_context.EXC_RETURN & 0x4) { if(mbed_fault_context.EXC_RETURN & 0x4) {
mbed_error_print("\nStack: PSP", NULL); fault_print("\nStack: PSP", NULL);
} else { } else {
mbed_error_print("\nStack: MSP", NULL); fault_print("\nStack: MSP", NULL);
} }
} }