Error handling/logging implementation and tests

pull/6983/head
Senthil Ramakrishnan 2018-05-07 17:24:42 -05:00
parent eb9435b52e
commit 9041b475c6
19 changed files with 1908 additions and 220 deletions

View File

@ -0,0 +1,411 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 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 "greentea-client/test_env.h"
#include "utest/utest.h"
#include "unity/unity.h"
#include "mbed.h"
using utest::v1::Case;
/** Test logging of system errors
* and ensure the status/erro code is correct
*/
void test_system_errors()
{
MbedErrorStatus error = MAKE_ERROR(ENTITY_APPLICATION, ERROR_CODE_UNKNOWN);
SET_ERROR(error, "Error Unknown", 0xAABBCCDD );
MbedErrorStatus lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(error, lastError);
error = MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_CREATE_FAILED);
SET_ERROR(error, "Error Platform", 0xABCDABCD );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(error, lastError);
error = MAKE_ERROR(ENTITY_DRIVER_SERIAL, ERROR_CODE_OUT_OF_RESOURCES);
SET_ERROR(error, "Error Serial driver", 0xAA );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(error, lastError);
error = MAKE_ERROR(ENTITY_UNKNOWN, ERROR_CODE_OUT_OF_MEMORY);
SET_ERROR(error, "Error Out of resources", 0x11223344 );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(error, lastError);
}
/** Test logging of custom errors
* and ensure the status/erro code is correct
*/
void test_custom_errors()
{
MbedErrorStatus error = MAKE_CUSTOM_ERROR(ENTITY_APPLICATION, ERROR_CODE_UNKNOWN);
SET_ERROR(error, "Custom Error Unknown", 0x1234 );
MbedErrorStatus lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(error, lastError);
error = MAKE_CUSTOM_ERROR(ENTITY_PLATFORM, ERROR_CODE_CREATE_FAILED);
SET_ERROR(error, "Custom Error Platform", 0x5555 );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(error, lastError);
error = MAKE_CUSTOM_ERROR(ENTITY_HAL, ERROR_CODE_OUT_OF_MEMORY);
SET_ERROR(error, "Custom Error Unknown", 0x33445566 );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(error, lastError);
}
/** Test logging of posix errors
* and ensure the status/erro code is correct
*/
void test_posix_errors()
{
SET_ERROR(ERROR_EPERM, "Posix Error Eperm", 0x1234 );
MbedErrorStatus lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(ERROR_EPERM, lastError);
SET_ERROR(ERROR_EBADF, "Posix Error, bad file descriptor", 0x5555 );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(ERROR_EBADF, lastError);
SET_ERROR(ERROR_ENOENT, "Posix error, no file or dir", 0x33445566 );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(ERROR_ENOENT, lastError);
}
/** Test first and last error capture
*/
void test_first_and_last_error_capture()
{
//clear the errors and error count to 0
clear_all_errors();
SET_ERROR(ERROR_OUT_OF_RESOURCES, "System type error", 0x1100 );
SET_ERROR(ERROR_OUT_OF_MEMORY, "Out of memory", 0x2233);
SET_ERROR(ERROR_SEMAPHORE_LOCK_FAILED, "Sem lock failed", 0x3344 );
SET_ERROR(ERROR_MUTEX_LOCK_FAILED, "Mutex lock failed", 0x4455 );
SET_ERROR(ERROR_CREATE_FAILED, "Create failed", 0x5566 );
SET_ERROR(ERROR_TIMEOUT, "Time out error", 0x7788 );
SET_ERROR(ERROR_MUTEX_UNLOCK_FAILED, "Mutex unlock failed", 0x99AA );
SET_ERROR(ERROR_SEMAPHORE_UNLOCK_FAILED, "Semaphore unlock failed", 0xBBCC );
MbedErrorStatus error = get_last_error();
printf("\nlastError = 0x%08X", error );
TEST_ASSERT_EQUAL_UINT(ERROR_SEMAPHORE_UNLOCK_FAILED, error);
error = get_first_error();
printf("\nfirstError = 0x%08X", error );
TEST_ASSERT_EQUAL_UINT(ERROR_OUT_OF_RESOURCES, error);
}
/** Test error count and reset functionality
*/
void test_error_count_and_reset()
{
int count = 7;
//Log multiple errors and get the error count and make sure its 15
for(int i=0; i<count; i++) {
SET_ERROR(ERROR_OUT_OF_MEMORY, "Out of memory", i);
}
TEST_ASSERT_EQUAL_INT(count, get_error_count());
//clear the errors and error count to 0
clear_all_errors();
//Now the error count should be 0
TEST_ASSERT_EQUAL_INT(0, get_error_count());
}
/** Test error type encoding
*/
void test_error_encoding()
{
SET_ERROR(ERROR_OUT_OF_RESOURCES, "System type error", 0x1100 );
MbedErrorStatus lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(ERROR_TYPE_SYSTEM, GET_MBED_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(ENTITY_UNKNOWN, GET_MBED_ERROR_ENTITY(lastError));
TEST_ASSERT_EQUAL_UINT(ERROR_CODE_OUT_OF_RESOURCES, GET_MBED_ERROR_CODE(lastError));
MbedErrorStatus error = MAKE_CUSTOM_ERROR(ENTITY_PLATFORM, ERROR_CODE_CREATE_FAILED);
SET_ERROR(error, "Custom Error Type", 0x2233);
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(ERROR_TYPE_CUSTOM, GET_MBED_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(ENTITY_PLATFORM, GET_MBED_ERROR_ENTITY(lastError));
TEST_ASSERT_EQUAL_UINT(ERROR_CODE_CREATE_FAILED, GET_MBED_ERROR_CODE(lastError));
SET_ERROR(ERROR_EACCES, "Posix Error 1", 0x3344 );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(ERROR_TYPE_POSIX, GET_MBED_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(ENTITY_UNKNOWN, GET_MBED_ERROR_ENTITY(lastError));
TEST_ASSERT_EQUAL_UINT(ERROR_CODE_EACCES, GET_MBED_ERROR_CODE(lastError));
SET_ERROR(ERROR_ERANGE, "Posix Error 2", 0x3355 );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(ERROR_TYPE_POSIX, GET_MBED_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(ENTITY_UNKNOWN, GET_MBED_ERROR_ENTITY(lastError));
TEST_ASSERT_EQUAL_UINT(ERROR_CODE_ERANGE, GET_MBED_ERROR_CODE(lastError));
error = MAKE_ERROR(ENTITY_HAL, ERROR_CODE_UNKNOWN);
SET_ERROR(error, "HAL Entity error", 0x5566 );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(ERROR_TYPE_SYSTEM, GET_MBED_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(ENTITY_HAL, GET_MBED_ERROR_ENTITY(lastError));
TEST_ASSERT_EQUAL_UINT(ERROR_CODE_UNKNOWN, GET_MBED_ERROR_CODE(lastError));
SET_ERROR(ERROR_UNKNOWN, "Unknown Entity error", 7788 );
lastError = get_last_error();
printf("\nlastError = 0x%08X", lastError );
TEST_ASSERT_EQUAL_UINT(ERROR_TYPE_SYSTEM, GET_MBED_ERROR_TYPE(lastError));
TEST_ASSERT_EQUAL_UINT(ENTITY_UNKNOWN, GET_MBED_ERROR_ENTITY(lastError));
TEST_ASSERT_EQUAL_UINT(ERROR_CODE_UNKNOWN, GET_MBED_ERROR_CODE(lastError));
}
/** Test error value
*/
void test_error_value()
{
uint32_t error_value = 0xAA11BB22;
mbed_error_ctx error_ctx = {0};
SET_ERROR(ERROR_OUT_OF_RESOURCES, "System type error", error_value );
MbedErrorStatus status = get_last_error_log_info( &error_ctx );
TEST_ASSERT(status == ERROR_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
MbedErrorStatus error = MAKE_CUSTOM_ERROR(ENTITY_PLATFORM, ERROR_CODE_CREATE_FAILED);
error_value = 0xABCD;
SET_ERROR(error, "Custom Error Type", error_value);
status = get_last_error_log_info( &error_ctx );
TEST_ASSERT(status == ERROR_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
error_value = 0x11223344;
SET_ERROR(ERROR_EACCES, "Posix Error 1", error_value );
status = get_last_error_log_info( &error_ctx );
TEST_ASSERT(status == ERROR_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
}
/** Test error context capture
*/
void test_error_context_capture()
{
uint32_t error_value = 0xABCD;
mbed_error_ctx error_ctx = {0};
SET_ERROR(ERROR_INVALID_ARGUMENT, "System type error", error_value );
MbedErrorStatus status = get_last_error_log_info( &error_ctx );
TEST_ASSERT(status == ERROR_SUCCESS);
TEST_ASSERT_EQUAL_UINT(error_value, error_ctx.error_value);
TEST_ASSERT_EQUAL_UINT(osThreadGetId(), error_ctx.thread_id);
//Capture thread info and compare
osRtxThread_t *current_thread = osRtxInfo.thread.run.curr;
TEST_ASSERT_EQUAL_UINT((uint32_t)current_thread->thread_addr, error_ctx.thread_entry_address);
TEST_ASSERT_EQUAL_UINT((uint32_t)current_thread->stack_size, error_ctx.thread_stack_size);
TEST_ASSERT_EQUAL_UINT((uint32_t)current_thread->stack_mem, error_ctx.thread_stack_mem);
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
TEST_ASSERT_EQUAL_STRING(MBED_FILENAME, error_ctx.error_filename);
#endif
}
#ifndef MBED_CONF_ERROR_LOG_DISABLED
/** Test error logging functionality
*/
void test_error_logging()
{
mbed_error_ctx error_ctx = {0};
//clear the current errors first
clear_all_errors();
//log 3 errors and retrieve them to ensure they are correct
SET_ERROR(ERROR_INVALID_ARGUMENT, "Invalid argument error", 1 );
SET_ERROR(ERROR_INVALID_SIZE, "Invalid size error", 2 );
SET_ERROR(ERROR_INVALID_FORMAT, "Invalid format error", 3 );
MbedErrorStatus status = get_error_log_info( 0, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_INVALID_ARGUMENT, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(1, error_ctx.error_value);
status = get_error_log_info( 1, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_INVALID_SIZE, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(2, error_ctx.error_value);
status = get_error_log_info( 2, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_INVALID_FORMAT, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(3, error_ctx.error_value);
//log 2 more errors to fill the log and then read them out to ensure that its correct
SET_ERROR(ERROR_INVALID_DATA, "Invalid data", 4 );
SET_ERROR(ERROR_INVALID_OPERATION, "Invalid operation", 5 );
status = get_error_log_info( 3, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_INVALID_DATA, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(4, error_ctx.error_value);
status = get_error_log_info( 4, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_INVALID_OPERATION, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(5, error_ctx.error_value);
//Log a bunch of errors to overflow the error log and retrieve them
SET_ERROR(ERROR_INVALID_ARGUMENT, "Invalid argument error", 6 );
SET_ERROR(ERROR_INVALID_SIZE, "Invalid size error", 7 );
SET_ERROR(ERROR_INVALID_FORMAT, "Invalid format error", 8 );
SET_ERROR(ERROR_NOT_READY, "Not ready error", 9 );
//Last 5 entries
SET_ERROR(ERROR_TIMEOUT, "Timeout error", 10 );
SET_ERROR(ERROR_ALREADY_IN_USE, "Already in use error", 11 );
SET_ERROR(ERROR_NOT_SUPPORTED, "Not supported error", 12 );
SET_ERROR(ERROR_ACCESS_DENIED, "Access denied error", 13 );
SET_ERROR(ERROR_NOT_FOUND, "Not found error", 14 );
status = get_error_log_info( 0, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_TIMEOUT, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(10, error_ctx.error_value);
status = get_error_log_info( 1, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_ALREADY_IN_USE, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(11, error_ctx.error_value);
status = get_error_log_info( 2, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_NOT_SUPPORTED, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(12, error_ctx.error_value);
status = get_error_log_info( 3, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_ACCESS_DENIED, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(13, error_ctx.error_value);
status = get_error_log_info( 4, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_NOT_FOUND, error_ctx.error_status);
TEST_ASSERT_EQUAL_UINT(14, error_ctx.error_value);
//Try an index which is invalid, we should get ERROR_INVALID_ARGUMENT back
status = get_error_log_info( 99, &error_ctx );
TEST_ASSERT_EQUAL_UINT(ERROR_INVALID_ARGUMENT, status);
}
#define NUM_TEST_THREADS 15
//Error logger threads
void err_thread_func(MbedErrorStatus *error_status)
{
printf("\nError Status = 0x%08X\n",*error_status);
SET_ERROR(*error_status, "Error from Multi-Threaded error logging test", *error_status );
}
/** Test error logging multithreaded
*/
void test_error_logging_multithread()
{
mbed_error_ctx error_ctx = {0};
int i=0;
Thread errThread[NUM_TEST_THREADS];
MbedErrorStatus error_status[NUM_TEST_THREADS] = {
ERROR_INVALID_ARGUMENT, ERROR_INVALID_DATA, ERROR_INVALID_FORMAT, ERROR_INVALID_SIZE, ERROR_INVALID_OPERATION,
ERROR_NOT_FOUND, ERROR_ACCESS_DENIED, ERROR_FAILED_OPERATION, ERROR_OPERATION_PROHIBITED, ERROR_OPERATION_ABORTED,
ERROR_NO_RESPONSE, ERROR_SEMAPHORE_LOCK_FAILED, ERROR_MUTEX_LOCK_FAILED, ERROR_OPEN_FAILED, ERROR_CLOSE_FAILED
};
for(; i<NUM_TEST_THREADS; i++) {
errThread[i].start(callback(err_thread_func, &error_status[i]));
}
wait(2.0);
for(i=0; i<NUM_TEST_THREADS; i++) {
errThread[i].join();
}
i = get_error_log_count()-1;
printf("\nError log count = %d\n", i+1);
for(;i>=0;--i) {
MbedErrorStatus status = get_error_log_info( i, &error_ctx );
printf("\nError Status[%d] = 0x%08X Value = 0x%08X\n", i, error_ctx.error_status, error_ctx.error_value);
TEST_ASSERT_EQUAL_UINT((unsigned int)error_ctx.error_value, (unsigned int)error_ctx.error_status);
}
}
#endif
static Semaphore callback_sem;
void MyErrorHook(const mbed_error_ctx *error_ctx)
{
callback_sem.release();
}
/** Test error hook
*/
void test_error_hook()
{
if( ERROR_SUCCESS != set_error_hook(MyErrorHook)) {
TEST_FAIL();
}
SET_ERROR(ERROR_INVALID_ARGUMENT, "Test for error hook", 1234);
int32_t sem_status = callback_sem.wait(5000);
TEST_ASSERT(sem_status > 0);
}
utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(100, "default_auto");
return utest::v1::verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("Test error counting and reset", test_error_count_and_reset),
Case("Test system errors", test_system_errors),
Case("Test custom errors", test_custom_errors),
Case("Test posix errors", test_posix_errors),
Case("Test first and last error capture", test_first_and_last_error_capture),
Case("Test error encoding", test_error_encoding),
Case("Test error value", test_error_value),
Case("Test error context capture", test_error_context_capture),
Case("Test error hook", test_error_hook),
#ifndef MBED_CONF_ERROR_LOG_DISABLED
Case("Test error logging", test_error_logging),
Case("Test error handling multi-threaded", test_error_logging_multithread),
#endif
};
utest::v1::Specification specification(test_setup, cases);
int main()
{
return !utest::v1::Harness::run(specification);
}

View File

@ -123,7 +123,7 @@ u32_t sys_now(void) {
*---------------------------------------------------------------------------*/
err_t sys_mbox_new(sys_mbox_t *mbox, int queue_sz) {
if (queue_sz > MB_SIZE)
error("sys_mbox_new size error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_INVALID_SIZE), "sys_mbox_new size error\n", queue_sz);
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->id = osEventFlagsNew(&mbox->attr);
if (mbox->id == NULL)
error("sys_mbox_new create error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_CREATE_FAILED), "sys_mbox_new create error\n", mbox->id);
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) {
if (mbox->post_idx != mbox->fetch_idx)
error("sys_mbox_free error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_FREE_FAILED), "sys_mbox_free error\n", mbox->post_idx);
}
/*---------------------------------------------------------------------------*
@ -309,7 +309,7 @@ err_t sys_sem_new(sys_sem_t *sem, u8_t count) {
sem->attr.cb_size = sizeof(sem->data);
sem->id = osSemaphoreNew(UINT16_MAX, count, &sem->attr);
if (sem->id == NULL)
error("sys_sem_new create error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_CREATE_FAILED), "sys_sem_new create error\n", sem->id);
return ERR_OK;
}
@ -388,14 +388,14 @@ err_t sys_mutex_new(sys_mutex_t *mutex) {
* @param mutex the mutex to lock */
void sys_mutex_lock(sys_mutex_t *mutex) {
if (osMutexAcquire(mutex->id, osWaitForever) != osOK)
error("sys_mutex_lock error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_MUTEX_LOCK_FAILED), "sys_mutex_lock error\n", mutex->id);
}
/** Unlock a mutex
* @param mutex the mutex to unlock */
void sys_mutex_unlock(sys_mutex_t *mutex) {
if (osMutexRelease(mutex->id) != osOK)
error("sys_mutex_unlock error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_MUTEX_UNLOCK_FAILED), "sys_mutex_unlock error\n", mutex->id);
}
/** 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 = osMutexNew(&lwip_sys_mutex_attr);
if (lwip_sys_mutex == NULL)
error("sys_init error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_INITIALIZATION_FAILED), "sys_init error\n", lwip_sys_mutex);
}
/*---------------------------------------------------------------------------*
@ -452,7 +452,7 @@ u32_t sys_jiffies(void) {
*---------------------------------------------------------------------------*/
sys_prot_t sys_arch_protect(void) {
if (osMutexAcquire(lwip_sys_mutex, osWaitForever) != osOK)
error("sys_arch_protect error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_MUTEX_LOCK_FAILED), "sys_arch_protect error\n", lwip_sys_mutex);
return (sys_prot_t) 1;
}
@ -469,7 +469,7 @@ sys_prot_t sys_arch_protect(void) {
*---------------------------------------------------------------------------*/
void sys_arch_unprotect(sys_prot_t p) {
if (osMutexRelease(lwip_sys_mutex) != osOK)
error("sys_arch_unprotect error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_MUTEX_LOCK_FAILED), "sys_arch_unprotect error\n", lwip_sys_mutex);
}
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));
if (thread_pool_index >= SYS_THREAD_POOL_N)
error("sys_thread_new number error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_THREAD_CREATE_FAILED), "sys_thread_new number error\n", thread_pool_index);
sys_thread_t t = (sys_thread_t)&thread_pool[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_mem = malloc(stacksize);
if (t->attr.stack_mem == NULL) {
error("Error allocating the stack memory");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_OUT_OF_MEMORY), "Error allocating the stack memory", t);
}
t->id = osThreadNew((osThreadFunc_t)thread, arg, &t->attr);
if (t->id == NULL)
error("sys_thread_new create error\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_NETWORK_STACK, ERROR_CODE_THREAD_CREATE_FAILED), "sys_thread_new create error\n", t->id);
return t;
}

View File

@ -57,14 +57,14 @@ int ReadOnlyBlockDevice::read(void *buffer, bd_addr_t addr, bd_size_t size)
int ReadOnlyBlockDevice::program(const void *buffer, bd_addr_t addr, bd_size_t size)
{
error("ReadOnlyBlockDevice::program() not allowed");
return 0;
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_BLOCK_DEVICE, ERROR_CODE_WRITE_PROTECTED), "ReadOnlyBlockDevice::program() not allowed", addr);
return ERROR_WRITE_PROTECTED;
}
int ReadOnlyBlockDevice::erase(bd_addr_t addr, bd_size_t size)
{
error("ReadOnlyBlockDevice::erase() not allowed");
return 0;
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_BLOCK_DEVICE, ERROR_CODE_WRITE_PROTECTED), "ReadOnlyBlockDevice::erase() not allowed", addr);
return ERROR_WRITE_PROTECTED;
}
bd_size_t ReadOnlyBlockDevice::get_read_size() const

View File

@ -29,7 +29,7 @@ void pinmap_pinout(PinName pin, const PinMap *map) {
}
map++;
}
error("could not pinout");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_PINMAP_INVALID), "could not pinout", pin);
}
uint32_t pinmap_merge(uint32_t a, uint32_t b) {
@ -44,7 +44,7 @@ uint32_t pinmap_merge(uint32_t a, uint32_t b) {
return a;
// mis-match error case
error("pinmap mis-match");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_PINMAP_INVALID), "pinmap mis-match", a);
return (uint32_t)NC;
}
@ -64,7 +64,7 @@ uint32_t pinmap_peripheral(PinName pin, const PinMap* map) {
return (uint32_t)NC;
peripheral = pinmap_find_peripheral(pin, map);
if ((uint32_t)NC == peripheral) // no mapping available
error("pinmap not found for peripheral");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_PINMAP_INVALID), "pinmap not found for peripheral", peripheral);
return peripheral;
}
@ -84,6 +84,6 @@ uint32_t pinmap_function(PinName pin, const PinMap* map) {
return (uint32_t)NC;
function = pinmap_find_function(pin, map);
if ((uint32_t)NC == function) // no mapping available
error("pinmap not found for function");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_PINMAP_INVALID), "pinmap not found for function", function);
return function;
}

View File

@ -161,7 +161,7 @@ void sleep_manager_lock_deep_sleep_internal(void)
core_util_critical_section_enter();
if (deep_sleep_lock == USHRT_MAX) {
core_util_critical_section_exit();
error("Deep sleep lock would overflow (> USHRT_MAX)");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_HAL, ERROR_CODE_OVERFLOW), "DeepSleepLock overflow (> USHRT_MAX)", deep_sleep_lock);
}
core_util_atomic_incr_u16(&deep_sleep_lock, 1);
core_util_critical_section_exit();
@ -172,7 +172,7 @@ void sleep_manager_unlock_deep_sleep_internal(void)
core_util_critical_section_enter();
if (deep_sleep_lock == 0) {
core_util_critical_section_exit();
error("Deep sleep lock would underflow (< 0)");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_HAL, ERROR_CODE_UNDERFLOW), "DeepSleepLock underflow (< 0)", deep_sleep_lock);
}
core_util_atomic_decr_u16(&deep_sleep_lock, 1);
core_util_critical_section_exit();

View File

@ -69,7 +69,7 @@ public:
sleep_manager_lock_deep_sleep();
}
if (0 == count) {
error("DeepSleepLock overflow (> USHRT_MAX)");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_OVERFLOW), "DeepSleepLock overflow (> USHRT_MAX)", count);
}
}
@ -83,7 +83,7 @@ public:
}
if (count == USHRT_MAX) {
core_util_critical_section_exit();
error("DeepSleepLock underflow (< 0)");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_UNDERFLOW), "DeepSleepLock underflow (< 0)", count);
}
}
};

View File

@ -29,7 +29,7 @@ Stream::Stream(const char *name) : FileLike(name), _file(NULL) {
if (_file) {
mbed_set_unbuffered_stream(_file);
} else {
error("Stream obj failure, errno=%d\r\n", errno);
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_OPEN_FAILED), "Stream obj failure", _file);
}
}

View File

@ -15,15 +15,55 @@
*/
#include <stdlib.h>
#include <stdarg.h>
#include "rtx_os.h"
#include "mbed_rtx.h"
#include "device.h"
#include "platform/mbed_toolchain.h"
#include "platform/mbed_critical.h"
#include "platform/mbed_error.h"
#include "platform/mbed_error_log.h"
#include "platform/mbed_error_report.h"
#include "platform/mbed_interface.h"
#if DEVICE_STDIO_MESSAGES
#include <stdio.h>
#endif
static uint8_t error_in_progress = 0;
static int error_count = 0;
static mbed_error_ctx first_error_ctx = {0};
static mbed_error_ctx current_error_ctx = {0};
static MbedErrorHook error_hook = NULL;
//Helper function to get the current SP
static unsigned int get_current_sp()
{
//If in Handler mode we are always using MSP
if( __get_IPSR() != 0U ) {
return __get_MSP();
} else {
//Look into CONTROL.SPSEL value
if ((__get_CONTROL() & 2U) == 0U) {
return __get_PSP();//Read PSP
} else {
return __get_MSP();//Read MSP
}
}
}
//Helper function to halt the system
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 (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
for(;;) {
__WFI();
}
} else {
//exit eventually calls mbed_die
exit(1);
}
}
WEAK void error(const char* format, ...) {
@ -41,3 +81,190 @@ WEAK void error(const char* format, ...) {
#endif
exit(1);
}
//Set an error status with the error handling system
MbedErrorStatus set_error(MbedErrorStatus error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
{
//Error status should always be < 0
if(error_status >= 0) {
return ERROR_INVALID_ARGUMENT;
}
//Use critsect here, as we don't want processing more than one error at the same time
core_util_critical_section_enter();
//Increment error count
error_count++;
//Clear the context capturing buffer
memset(&current_error_ctx, sizeof(mbed_error_ctx), 0);
//Capture error information
current_error_ctx.error_status = error_status;
current_error_ctx.error_address = (uint32_t)MBED_CALLER_ADDR();
current_error_ctx.error_value = error_value;
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
//Capture filename/linenumber if provided
//Index for tracking error_filename
int idx = 0;
if(NULL != filename) {
while(idx < MBED_CONF_MAX_ERROR_FILENAME_LEN && (filename[idx] != '\0')) {
current_error_ctx.error_filename[idx] = filename[idx];
idx++;
}
current_error_ctx.error_line_number = line_number;
}
#endif
//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;
current_error_ctx.thread_current_sp = get_current_sp();
//Call the error hook if available
if(error_hook != NULL) {
error_hook(&current_error_ctx);
}
#ifndef MBED_CONF_ERROR_LOG_DISABLED
//Log the error with error log
mbed_log_put_error(&current_error_ctx);
#endif
//Report the error
mbed_report_error(&current_error_ctx, (char *)error_msg);
//Capture the fist system error and store it
if(error_count == 1) { //first error
memcpy(&first_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx));
}
//Use critsect here, as we don't want processing more than one error at the same time
core_util_critical_section_exit();
return ERROR_SUCCESS;
}
//Return the first error
MbedErrorStatus get_first_error(void)
{
//return the first error recorded
return first_error_ctx.error_status;
}
//Return the last error
MbedErrorStatus get_last_error(void)
{
//return the last error recorded
return current_error_ctx.error_status;
}
//Gets the current error count
int get_error_count(void)
{
//return the current error count
return error_count;
}
//Sets a fatal error
MbedErrorStatus set_error_fatal(MbedErrorStatus error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
{
//set the error reported and then halt the system
if( ERROR_SUCCESS != set_error(error_status, error_msg, error_value, filename, line_number) )
return ERROR_FAILED_OPERATION;
mbed_halt_system();
return ERROR_FAILED_OPERATION;
}
//Register an application defined callback with error handling
MbedErrorStatus set_error_hook(MbedErrorHook error_hook_in)
{
//register the new hook/callback
if( error_hook_in != NULL ) {
error_hook = error_hook_in;
return ERROR_SUCCESS;
}
return ERROR_INVALID_ARGUMENT;
}
//Retrieve the first error context from error log
MbedErrorStatus get_first_error_log_info (mbed_error_ctx *error_info)
{
memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx));
return ERROR_SUCCESS;
}
//Retrieve the last error context from error log
MbedErrorStatus get_last_error_log_info (mbed_error_ctx *error_info)
{
memcpy(error_info, &current_error_ctx, sizeof(mbed_error_ctx));
return ERROR_SUCCESS;
}
//Makes an MbedErrorStatus value
MbedErrorStatus make_mbed_error(MbedErrorType error_type, MbedEntityType entity, MbedErrorCode error_code)
{
switch(error_type)
{
case ERROR_TYPE_POSIX:
if(error_code >= MBED_POSIX_ERROR_BASE && error_code <= MBED_SYSTEM_ERROR_BASE)
return -error_code;
break;
case ERROR_TYPE_SYSTEM:
if(error_code >= MBED_SYSTEM_ERROR_BASE && error_code <= MBED_CUSTOM_ERROR_BASE)
return MAKE_MBED_ERROR(ERROR_TYPE_SYSTEM, entity, error_code);
break;
case ERROR_TYPE_CUSTOM:
if(error_code >= MBED_CUSTOM_ERROR_BASE)
return MAKE_MBED_ERROR(ERROR_TYPE_CUSTOM, entity, error_code);
break;
default:
break;
}
//If we are passed incorrect values return a generic system error
return MAKE_MBED_ERROR(ERROR_TYPE_SYSTEM, ENTITY_UNKNOWN, ERROR_CODE_UNKNOWN);
}
/**
* Clears all the last error, error count and all entries in the error log.
* @return 0 or ERROR_SUCCESS on success.
*
*/
MbedErrorStatus clear_all_errors(void)
{
MbedErrorStatus status = ERROR_SUCCESS;
//Clear the error and context capturing buffer
memset(&current_error_ctx, sizeof(mbed_error_ctx), 0);
//reset error count to 0
error_count = 0;
#ifndef MBED_CONF_ERROR_LOG_DISABLED
status = mbed_log_reset();
#endif
return status;
}
#ifndef MBED_CONF_ERROR_LOG_DISABLED
//Retrieve the error context from error log at the specified index
MbedErrorStatus get_error_log_info (int index, mbed_error_ctx *error_info)
{
return mbed_log_get_error(index, error_info);
}
//Retrieve the error log count
int get_error_log_count(void)
{
return mbed_log_get_error_log_count();
}
#endif

View File

@ -1,4 +1,3 @@
/** \addtogroup platform */
/** @{*/
/**
@ -23,13 +22,522 @@
#ifndef MBED_ERROR_H
#define MBED_ERROR_H
#include "platform/mbed_retarget.h"
#include "platform/mbed_toolchain.h"
#ifdef __cplusplus
extern "C" {
#endif
//Define this macro to include filenames in error context, this can save memory. For release builds, do not include filename
//#define MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED 1
//Define this macro to disable error logging, note that the first and last error capture will still be active by default
//#define MBED_CONF_ERROR_LOG_DISABLED 1
#ifndef MBED_CONF_MAX_ERROR_FILENAME_LEN
#define MBED_CONF_MAX_ERROR_FILENAME_LEN 16
#endif
#define MBED_ERROR_STATUS_CODE_MASK (0x0000FFFF)
#define MBED_ERROR_STATUS_CODE_POS (0)
#define MBED_ERROR_STATUS_CODE_FIELD_SIZE (16)
#define MBED_ERROR_STATUS_ENTITY_MASK (0x00FF0000)
#define MBED_ERROR_STATUS_ENTITY_POS (16)
#define MBED_ERROR_STATUS_ENTITY_FIELD_SIZE (8)
#define MBED_ERROR_STATUS_TYPE_MASK (0x60000000)
#define MBED_ERROR_STATUS_TYPE_POS (29)
#define MBED_ERROR_STATUS_TYPE_FIELD_SIZE (2)
/* MbedErrorStatus Status Encoding */
//|31(1 bit) Always Negative|30-29(2 bits) |28-24 | 23-16(8 bits) | 15-0(16 bits) |
//|-1 |TYPE |(unused/reserved) | ENTITY TYPE | ERROR CODE |
#define MAKE_MBED_ERROR(type, entity, error_code) (MbedErrorStatus) \
((0x80000000) | \
(MBED_ERROR_STATUS_CODE_MASK & (error_code << MBED_ERROR_STATUS_CODE_POS)) | \
(MBED_ERROR_STATUS_ENTITY_MASK & (entity << MBED_ERROR_STATUS_ENTITY_POS)) | \
(MBED_ERROR_STATUS_TYPE_MASK & (type << MBED_ERROR_STATUS_TYPE_POS)))
#define GET_MBED_ERROR_TYPE( error_status ) ((error_status & MBED_ERROR_STATUS_TYPE_MASK) >> MBED_ERROR_STATUS_TYPE_POS)
#define GET_MBED_ERROR_ENTITY( error_status ) ((error_status & MBED_ERROR_STATUS_ENTITY_MASK) >> MBED_ERROR_STATUS_ENTITY_POS)
#define GET_MBED_ERROR_CODE( error_status ) (int)((GET_MBED_ERROR_TYPE( error_status ) == ERROR_TYPE_POSIX)?(-error_status):((error_status & MBED_ERROR_STATUS_CODE_MASK) >> MBED_ERROR_STATUS_CODE_POS))
/** MbedErrorStatus description
*
* MbedErrorStatus type represents the error status values under MbedOS. MbedErrorStatus values are signed integers and always be negative.\n
* Internally its encoded as below with bit-fields representing error type, entity and error code:\n\n
* MbedErrorStatus Status Encoding:\n
*
\verbatim
| 31 Always Negative | 30-29(2 bits) | 28-24 | 23-16(8 bits) | 15-0(16 bits) |
| -1 | TYPE | (unused/reserved) | ENTITY TYPE | ERROR CODE |
\endverbatim
*
* The error status value range for each error type is as follows:\n
* Posix Error Status-es - 0xFFFFFFFF to 0xFFFFFF01(-1 -255) - This corresponds to Posix error codes represented as negative.\n
* System Error Status-es - 0x80XX0100 to 0x80XX0FFF - This corresponds to System error codes range(all values are negative). Bits 23-16 will be entity type(marked with XX)\n
* Custom Error Status-es - 0xA0XX1000 to 0xA0XXFFFF - This corresponds to Custom error codes range(all values are negative). Bits 23-16 will be entity type(marked with XX)\n\n
*
* The ERROR CODE(values encoded into ERROR CODE bit-field in MbedErrorStatus) value range for each error type is also seperated as below:\n
* Posix Error Codes - 1 to 255.\n
* System Error Codes - 256 to 4095.\n
* Custom Error Codes - 4096 to 65535.\n
*
* @note Posix error codes are always encoded as negative of their actual value. For example, EPERM is encoded as -EPERM.
* And, the ENTITY TYPE for Posix error codes are always encoded as ENTITY_UNKNOWN.\n
* This is to enable easy injection of Posix error codes into MbedOS error handling system without altering the actual Posix error values.\n
* Accordingly, Posix error codes are represented as -1 to -255 under MbedOS error status representation.
*/
typedef int MbedErrorStatus;
/**
* Macro for defining a Posix error status. This macro is mainly used to define Posix error values in MbedErrorCode enumeration.
* @param error_name Name of the error without the ERROR_ prefix
* @param error_code Error code value to be used, must be between 1 and 255(inclusive).
*
*/
#define DEFINE_POSIX_ERROR( error_name, error_code ) \
ERROR_CODE_##error_name = error_code, \
ERROR_##error_name = -(MBED_POSIX_ERROR_BASE + error_code)
/**
* Macro for defining a System error status. This macro is used to define System error values in MbedErrorCode enumeration.
* @param error_name Name of the error without the ERROR_ prefix
* @param error_code Error code value to be used, must be between 256 and 4096(inclusive).
*
*/
#define DEFINE_SYSTEM_ERROR( error_name, error_code ) \
ERROR_CODE_##error_name = MBED_SYSTEM_ERROR_BASE + error_code, \
ERROR_##error_name = MAKE_MBED_ERROR(ERROR_TYPE_SYSTEM, ENTITY_UNKNOWN, ERROR_CODE_##error_name)
/**
* Macro for defining a Custom error status. This macro is used to define custom error values in MbedErrorCode enumeration.
* @param error_name Name of the error without the ERROR_ prefix
* @param error_code Error code value to be used, must be between 4097 and 65535(inclusive).
*
*/
#define DEFINE_CUSTOM_ERROR( error_name, error_code ) \
ERROR_CODE_##error_name = MBED_CUSTOM_ERROR_BASE + error_code, \
ERROR_##error_name = MAKE_MBED_ERROR(ERROR_TYPE_CUSTOM, ENTITY_UNKNOWN, ERROR_CODE_##error_name)
/**
* Macro for setting a system error. This macro will log the error, prints the error report and return to the caller. Its a wrapper for calling set_error API.
* @param error_status MbedErrorStatus status to be set(See MbedErrorStatus enum above for available error status values).
* @param error_msg The error message to be printed out to STDIO/Serial.
* @param error_value Value associated with the error status. This would depend on error code/error scenario.
*
* @code
*
* SET_ERROR( ERROR_INVALID_SIZE, "MyDriver: Invalid size in read", size_val )
*
* @endcode
* @note The macro calls set_error API with filename and line number info without caller explicitly passing them.
* Since this macro is a wrapper for set_error API callers should process the return value from this macro which is the return value from calling set_error API.
*
*/
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
#define SET_ERROR( error_status, error_msg, error_value ) set_error( error_status, (const char *)error_msg, (uint32_t)error_value, (const char *)MBED_FILENAME, __LINE__ )
#else
#define SET_ERROR( error_status, error_msg, error_value ) set_error( error_status, (const char *)error_msg, (uint32_t)error_value, NULL, 0 )
#endif
/**
* Macro for setting a fatal system error. This macro will log the error, prints the error report and halts the system. Its a wrapper for calling set_error_fatal API
* @param error_status MbedErrorStatus status to be set(See MbedErrorStatus enum above for available error status values).
* @param error_msg The error message to be printed out to STDIO/Serial.
* @param error_value Value associated with the error status. This would depend on error code/error scenario.
* @return 0 or ERROR_SUCCESS.
* ERROR_INVALID_ARGUMENT if called with invalid error status/codes
*
* @code
*
* SET_ERROR_FATAL( ERROR_MUTEX_LOCK_FAILED, "MyDriver: Can't lock driver Mutex", &my_mutex )
*
* @endcode
* @note The macro calls set_error_fatal API with filename and line number info without caller explicitly passing them.
* Since this macro is a wrapper for set_error_fatal API callers should process the return value from this macro which is the return value from calling set_error_fatal API.
*
*/
#define SET_ERROR_FATAL( error_status, error_msg, error_value ) set_error_fatal( error_status, (const char *)error_msg, (uint32_t)error_value, (const char *)MBED_FILENAME, __LINE__ )
//Error Type definition
/** MbedErrorType definition
* @note
* This enumeration defines the Error types supported. The value of these enum values will be encoded into MbedErrorStatus TYPE field.\n
* See MbedErrorStatus description for more info.\n
* ERROR_TYPE_SYSTEM - Used to indicate that the error status is of System defined Error type.\n
* ERROR_TYPE_CUSTOM - Used to indicate that the error status is of Custom defined Error type.\n
* ERROR_TYPE_POSIX - Used to indicate that the error status is of Posix error type.\n
*
*/
typedef enum _MbedErrorType
{
ERROR_TYPE_SYSTEM = 0,
ERROR_TYPE_CUSTOM = 1,
//2 is reserved
//Use 3 for POSIX because we are mapping -1 to -255 to POSIX error codes
//and thus we must use 3 to match the type bits in error status representation which are from 0xFFFFFFFF to 0xFFFFFF00
ERROR_TYPE_POSIX = 3
} MbedErrorType;
//Entity type/id definitions
/** MbedEntityType definition
* @note
* This enumeration defines the Entity types. The value of these enum values will be encoded into MbedErrorStatus ENTITY field.\n\n
* See MbedErrorStatus description for more info.\n
* ENTITY_UNKNOWN - This entity type can be used if caller of the set_error/set_error_fatal doesn't know who is the actual originator of the error.\n
* Other entity values can be used to provide more info on who/where the error originated from.\n\n
* For example, if I2C driver is the component originating the error you can use ENTITY_DRIVER_I2C to provide more info.\n
* Its used in call to MAKE_ERROR/MAKE_SYSTEM_ERROR/MAKE_CUSTOM_ERROR macros.\n
* @code
* MbedErrorStatus i2c_driver_error = MAKE_ERROR( ENTITY_DRIVER_I2C, ERROR_CONFIG_UNSUPPORTED );
* @endcode
*/
typedef enum _MbedEntityType
{
ENTITY_APPLICATION = 0,
ENTITY_PLATFORM,
ENTITY_KERNEL,
ENTITY_NETWORK_STACK,
ENTITY_HAL,
ENTITY_MEMORY_SUBSYSTEM,
ENTITY_FILESYSTEM,
ENTITY_BLOCK_DEVICE,
ENTITY_DRIVER,
ENTITY_DRIVER_SERIAL,
ENTITY_DRIVER_RTC,
ENTITY_DRIVER_I2C,
ENTITY_DRIVER_SPI,
ENTITY_DRIVER_GPIO,
ENTITY_DRIVER_ANALOG,
ENTITY_DRIVER_DIGITAL,
ENTITY_DRIVER_CAN,
ENTITY_DRIVER_ETHERNET,
ENTITY_DRIVER_CRC,
ENTITY_DRIVER_PWM,
ENTITY_DRIVER_QSPI,
ENTITY_DRIVER_USB,
ENTITY_TARGET_SDK,
/* Add More entities here as required */
ENTITY_UNKNOWN = 255,
ENTITY_MAX = ENTITY_UNKNOWN
} MbedEntityType;
//Use ERROR_SUCCESS(=0) or any postive number for successful returns
#define ERROR_SUCCESS 0
#define MBED_POSIX_ERROR_BASE 0
#define MBED_SYSTEM_ERROR_BASE 256
#define MBED_CUSTOM_ERROR_BASE 4096
//Error Code definitions
/** MbedErrorCode definition
*
* MbedErrorCode enumeration defines the Error codes and Error status values for ENTITY_UNKNOWN.\n
* It defines all of Posix Error Codes/Statuses and Mbed System Error Codes/Statuses.\n\n
*
* @note
* Posix Error codes are defined using the macro DEFINE_POSIX_ERROR\n
* For example DEFINE_POSIX_ERROR( EPERM, EPERM ). This effectively defines the following values:\n
* ERROR_CODE_EPERM = EPERM\n
* ERROR_EPERM = -EPERM\n
*
* Posix Error codes are defined using the macro DEFINE_POSIX_ERROR\n
* For example DEFINE_POSIX_ERROR( EPERM, EPERM ). This macro defines the following values:\n
* ERROR_CODE_EPERM = MBED_POSIX_ERROR_BASE+EPERM\n
* ERROR_EPERM = -(MBED_POSIX_ERROR_BASE+EPERM)\n
* Its effectively equivalent to:\n
* ERROR_CODE_EPERM = 1\n
* ERROR_EPERM = -1\n
* All Posix error codes currently supported by MbedOS(defined in mbed_retarget.h) are defined using the DEFINE_POSIX_ERROR macro.\n\n
*
* MbedOS System Error codes are defined using the macro DEFINE_SYSTEM_ERROR\n
* For example DEFINE_SYSTEM_ERROR( INVALID_ARGUMENT ,1 ) macro defines the following values:\n
* ERROR_CODE_INVALID_ARGUMENT = MBED_SYSTEM_ERROR_BASE+1\n
* ERROR_INVALID_ARGUMENT = MAKE_MBED_ERROR(ERROR_TYPE_SYSTEM, ENTITY_UNKNOWN, ERROR_CODE_INVALID_ARGUMENT)\n
* Its effectively equivalent to:\n
* ERROR_CODE_INVALID_ARGUMENT = 1\n
* ERROR_INVALID_ARGUMENT = 0x80FF0001\n (Note that ENTITY field is set to ENTITY_UNKNOWN)
* New System Error codes should be defined using DEFINE_SYSTEM_ERROR macro and must have an unique error code value\n
* passed as the second argument in the DEFINE_SYSTEM_ERROR macro.\n\n
*
* Custom Error codes can be defined using the macro DEFINE_CUSTOM_ERROR\n
* This is mainly meant to capture non-generic error codes specific to a device.
* For example DEFINE_CUSTOM_ERROR( MY_CUSTOM_ERROR ,1 ) macro defines the following values:\n
* ERROR_CODE_MY_CUSTOM_ERROR = MBED_CUSTOM_ERROR_BASE+1\n
* ERROR_MY_CUSTOM_ERROR = MAKE_MBED_ERROR(ERROR_TYPE_CUSTOM, ENTITY_UNKNOWN, ERROR_CODE_MY_CUSTOM_ERROR)\n
* Its effectively equivalent to:\n
* ERROR_CODE_MY_CUSTOM_ERROR = 4097\n
* ERROR_MY_CUSTOM_ERROR = 0xA0FF1001\n (Note that ENTITY field is set to ENTITY_UNKNOWN)
*
*/
typedef enum _MbedErrorCode
{
//Below are POSIX ERROR CODE definitions, which starts at MBED_POSIX_ERROR_BASE(=0)
//POSIX ERROR CODE definitions starts at offset 0(MBED_POSIX_ERROR_BASE) to align them with actual Posix Error Code
//defintions in mbed_retarget.h
// Error Name Error Code
DEFINE_POSIX_ERROR( EPERM ,EPERM ), /* 1 Operation not permitted */
DEFINE_POSIX_ERROR( ENOENT ,ENOENT ), /* 2 No such file or directory */
DEFINE_POSIX_ERROR( ESRCH ,ESRCH ), /* 3 No such process */
DEFINE_POSIX_ERROR( EINTR ,EINTR ), /* 4 Interrupted system call */
DEFINE_POSIX_ERROR( EIO ,EIO ), /* 5 I/O error */
DEFINE_POSIX_ERROR( ENXIO ,ENXIO ), /* 6 No such device or address */
DEFINE_POSIX_ERROR( E2BIG ,E2BIG ), /* 7 Argument list too long */
DEFINE_POSIX_ERROR( ENOEXEC ,ENOEXEC ), /* 8 Exec format error */
DEFINE_POSIX_ERROR( EBADF ,EBADF ), /* 9 Bad file number */
DEFINE_POSIX_ERROR( ECHILD ,ECHILD ), /* 10 No child processes */
DEFINE_POSIX_ERROR( EAGAIN ,EAGAIN ), /* 11 Try again */
DEFINE_POSIX_ERROR( ENOMEM ,ENOMEM ), /* 12 Out of memory */
DEFINE_POSIX_ERROR( EACCES ,EACCES ), /* 13 Permission denied */
DEFINE_POSIX_ERROR( EFAULT ,EFAULT ), /* 14 Bad address */
DEFINE_POSIX_ERROR( ENOTBLK ,ENOTBLK ), /* 15 Block device required */
DEFINE_POSIX_ERROR( EBUSY ,EBUSY ), /* 16 Device or resource busy */
DEFINE_POSIX_ERROR( EEXIST ,EEXIST ), /* 17 File exists */
DEFINE_POSIX_ERROR( EXDEV ,EXDEV ), /* 18 Cross-device link */
DEFINE_POSIX_ERROR( ENODEV ,ENODEV ), /* 19 No such device */
DEFINE_POSIX_ERROR( ENOTDIR ,ENOTDIR ), /* 20 Not a directory */
DEFINE_POSIX_ERROR( EISDIR ,EISDIR ), /* 21 Is a directory */
DEFINE_POSIX_ERROR( EINVAL ,EINVAL ), /* 22 Invalid argument */
DEFINE_POSIX_ERROR( ENFILE ,ENFILE ), /* 23 File table overflow */
DEFINE_POSIX_ERROR( EMFILE ,EMFILE ), /* 24 Too many open files */
DEFINE_POSIX_ERROR( ENOTTY ,ENOTTY ), /* 25 Not a typewriter */
DEFINE_POSIX_ERROR( ETXTBSY ,ETXTBSY ), /* 26 Text file busy */
DEFINE_POSIX_ERROR( EFBIG ,EFBIG ), /* 27 File too large */
DEFINE_POSIX_ERROR( ENOSPC ,ENOSPC ), /* 28 No space left on device */
DEFINE_POSIX_ERROR( ESPIPE ,ESPIPE ), /* 29 Illegal seek */
DEFINE_POSIX_ERROR( EROFS ,EROFS ), /* 30 Read-only file system */
DEFINE_POSIX_ERROR( EMLINK ,EMLINK ), /* 31 Too many links */
DEFINE_POSIX_ERROR( EPIPE ,EPIPE ), /* 32 Broken pipe */
DEFINE_POSIX_ERROR( EDOM ,EDOM ), /* 33 Math argument out of domain of func */
DEFINE_POSIX_ERROR( ERANGE ,ERANGE ), /* 34 Math result not representable */
DEFINE_POSIX_ERROR( EDEADLK ,EDEADLK ), /* 35 Resource deadlock would occur */
DEFINE_POSIX_ERROR( ENAMETOOLONG ,ENAMETOOLONG ), /* 36 File name too long */
DEFINE_POSIX_ERROR( ENOLCK ,ENOLCK ), /* 37 No record locks available */
DEFINE_POSIX_ERROR( ENOSYS ,ENOSYS ), /* 38 Function not implemented */
DEFINE_POSIX_ERROR( ENOTEMPTY ,ENOTEMPTY ), /* 39 Directory not empty */
DEFINE_POSIX_ERROR( ELOOP ,ELOOP ), /* 40 Too many symbolic links encountered */
DEFINE_POSIX_ERROR( EWOULDBLOCK ,EAGAIN ), /* EAGAIN Operation would block */
DEFINE_POSIX_ERROR( ENOMSG ,ENOMSG ), /* 42 No message of desired type */
DEFINE_POSIX_ERROR( EIDRM ,EIDRM ), /* 43 Identifier removed */
DEFINE_POSIX_ERROR( ECHRNG ,ECHRNG ), /* 44 Channel number out of range */
DEFINE_POSIX_ERROR( EL2NSYNC ,EL2NSYNC ), /* 45 Level 2 not synchronized */
DEFINE_POSIX_ERROR( EL3HLT ,EL3HLT ), /* 46 Level 3 halted */
DEFINE_POSIX_ERROR( EL3RST ,EL3RST ), /* 47 Level 3 reset */
DEFINE_POSIX_ERROR( ELNRNG ,ELNRNG ), /* 48 Link number out of range */
DEFINE_POSIX_ERROR( EUNATCH ,EUNATCH ), /* 49 Protocol driver not attached */
DEFINE_POSIX_ERROR( ENOCSI ,ENOCSI ), /* 50 No CSI structure available */
DEFINE_POSIX_ERROR( EL2HLT ,EL2HLT ), /* 51 Level 2 halted */
DEFINE_POSIX_ERROR( EBADE ,EBADE ), /* 52 Invalid exchange */
DEFINE_POSIX_ERROR( EBADR ,EBADR ), /* 53 Invalid request descriptor */
DEFINE_POSIX_ERROR( EXFULL ,EXFULL ), /* 54 Exchange full */
DEFINE_POSIX_ERROR( ENOANO ,ENOANO ), /* 55 No anode */
DEFINE_POSIX_ERROR( EBADRQC ,EBADRQC ), /* 56 Invalid request code */
DEFINE_POSIX_ERROR( EBADSLT ,EBADSLT ), /* 57 Invalid slot */
DEFINE_POSIX_ERROR( EDEADLOCK ,EDEADLK ), /* EDEADLK Resource deadlock would occur */
DEFINE_POSIX_ERROR( EBFONT ,EBFONT ), /* 59 Bad font file format */
DEFINE_POSIX_ERROR( ENOSTR ,ENOSTR ), /* 60 Device not a stream */
DEFINE_POSIX_ERROR( ENODATA ,ENODATA ), /* 61 No data available */
DEFINE_POSIX_ERROR( ETIME ,ETIME ), /* 62 Timer expired */
DEFINE_POSIX_ERROR( ENOSR ,ENOSR ), /* 63 Out of streams resources */
DEFINE_POSIX_ERROR( ENONET ,ENONET ), /* 64 Machine is not on the network */
DEFINE_POSIX_ERROR( ENOPKG ,ENOPKG ), /* 65 Package not installed */
DEFINE_POSIX_ERROR( EREMOTE ,EREMOTE ), /* 66 Object is remote */
DEFINE_POSIX_ERROR( ENOLINK ,ENOLINK ), /* 67 Link has been severed */
DEFINE_POSIX_ERROR( EADV ,EADV ), /* 68 Advertise error */
DEFINE_POSIX_ERROR( ESRMNT ,ESRMNT ), /* 69 Srmount error */
DEFINE_POSIX_ERROR( ECOMM ,ECOMM ), /* 70 Communication error on send */
DEFINE_POSIX_ERROR( EPROTO ,EPROTO ), /* 71 Protocol error */
DEFINE_POSIX_ERROR( EMULTIHOP ,EMULTIHOP ), /* 72 Multihop attempted */
DEFINE_POSIX_ERROR( EDOTDOT ,EDOTDOT ), /* 73 RFS specific error */
DEFINE_POSIX_ERROR( EBADMSG ,EBADMSG ), /* 74 Not a data message */
DEFINE_POSIX_ERROR( EOVERFLOW ,EOVERFLOW ), /* 75 Value too large for defined data type */
DEFINE_POSIX_ERROR( ENOTUNIQ ,ENOTUNIQ ), /* 76 Name not unique on network */
DEFINE_POSIX_ERROR( EBADFD ,EBADFD ), /* 77 File descriptor in bad state */
DEFINE_POSIX_ERROR( EREMCHG ,EREMCHG ), /* 78 Remote address changed */
DEFINE_POSIX_ERROR( ELIBACC ,ELIBACC ), /* 79 Can not access a needed shared library */
DEFINE_POSIX_ERROR( ELIBBAD ,ELIBBAD ), /* 80 Accessing a corrupted shared library */
DEFINE_POSIX_ERROR( ELIBSCN ,ELIBSCN ), /* 81 .lib section in a.out corrupted */
DEFINE_POSIX_ERROR( ELIBMAX ,ELIBMAX ), /* 82 Attempting to link in too many shared libraries */
DEFINE_POSIX_ERROR( ELIBEXEC ,ELIBEXEC ), /* 83 Cannot exec a shared library directly */
DEFINE_POSIX_ERROR( EILSEQ ,EILSEQ ), /* 84 Illegal byte sequence */
DEFINE_POSIX_ERROR( ERESTART ,ERESTART ), /* 85 Interrupted system call should be restarted */
DEFINE_POSIX_ERROR( ESTRPIPE ,ESTRPIPE ), /* 86 Streams pipe error */
DEFINE_POSIX_ERROR( EUSERS ,EUSERS ), /* 87 Too many users */
DEFINE_POSIX_ERROR( ENOTSOCK ,ENOTSOCK ), /* 88 Socket operation on non-socket */
DEFINE_POSIX_ERROR( EDESTADDRREQ ,EDESTADDRREQ ), /* 89 Destination address required */
DEFINE_POSIX_ERROR( EMSGSIZE ,EMSGSIZE ), /* 90 Message too long */
DEFINE_POSIX_ERROR( EPROTOTYPE ,EPROTOTYPE ), /* 91 Protocol wrong type for socket */
DEFINE_POSIX_ERROR( ENOPROTOOPT ,ENOPROTOOPT ), /* 92 Protocol not available */
DEFINE_POSIX_ERROR( EPROTONOSUPPORT ,EPROTONOSUPPORT ), /* 93 Protocol not supported */
DEFINE_POSIX_ERROR( ESOCKTNOSUPPORT ,ESOCKTNOSUPPORT ), /* 94 Socket type not supported */
DEFINE_POSIX_ERROR( EOPNOTSUPP ,EOPNOTSUPP ), /* 95 Operation not supported on transport endpoint */
DEFINE_POSIX_ERROR( EPFNOSUPPORT ,EPFNOSUPPORT ), /* 96 Protocol family not supported */
DEFINE_POSIX_ERROR( EAFNOSUPPORT ,EAFNOSUPPORT ), /* 97 Address family not supported by protocol */
DEFINE_POSIX_ERROR( EADDRINUSE ,EADDRINUSE ), /* 98 Address already in use */
DEFINE_POSIX_ERROR( EADDRNOTAVAIL ,EADDRNOTAVAIL ), /* 99 Cannot assign requested address */
DEFINE_POSIX_ERROR( ENETDOWN ,ENETDOWN ), /* 100 Network is down */
DEFINE_POSIX_ERROR( ENETUNREACH ,ENETUNREACH ), /* 101 Network is unreachable */
DEFINE_POSIX_ERROR( ENETRESET ,ENETRESET ), /* 102 Network dropped connection because of reset */
DEFINE_POSIX_ERROR( ECONNABORTED ,ECONNABORTED ), /* 103 Software caused connection abort */
DEFINE_POSIX_ERROR( ECONNRESET ,ECONNRESET ), /* 104 Connection reset by peer */
DEFINE_POSIX_ERROR( ENOBUFS ,ENOBUFS ), /* 105 No buffer space available */
DEFINE_POSIX_ERROR( EISCONN ,EISCONN ), /* 106 Transport endpoint is already connected */
DEFINE_POSIX_ERROR( ENOTCONN ,ENOTCONN ), /* 107 Transport endpoint is not connected */
DEFINE_POSIX_ERROR( ESHUTDOWN ,ESHUTDOWN ), /* 108 Cannot send after transport endpoint shutdown */
DEFINE_POSIX_ERROR( ETOOMANYREFS ,ETOOMANYREFS ), /* 109 Too many references: cannot splice */
DEFINE_POSIX_ERROR( ETIMEDOUT ,ETIMEDOUT ), /* 110 Connection timed out */
DEFINE_POSIX_ERROR( ECONNREFUSED ,ECONNREFUSED ), /* 111 Connection refused */
DEFINE_POSIX_ERROR( EHOSTDOWN ,EHOSTDOWN ), /* 112 Host is down */
DEFINE_POSIX_ERROR( EHOSTUNREACH ,EHOSTUNREACH ), /* 113 No route to host */
DEFINE_POSIX_ERROR( EALREADY ,EALREADY ), /* 114 Operation already in progress */
DEFINE_POSIX_ERROR( EINPROGRESS ,EINPROGRESS ), /* 115 Operation now in progress */
DEFINE_POSIX_ERROR( ESTALE ,ESTALE ), /* 116 Stale NFS file handle */
DEFINE_POSIX_ERROR( EUCLEAN ,EUCLEAN ), /* 117 Structure needs cleaning */
DEFINE_POSIX_ERROR( ENOTNAM ,ENOTNAM ), /* 118 Not a XENIX named type file */
DEFINE_POSIX_ERROR( ENAVAIL ,ENAVAIL ), /* 119 No XENIX semaphores available */
DEFINE_POSIX_ERROR( EISNAM ,EISNAM ), /* 120 Is a named type file */
DEFINE_POSIX_ERROR( EREMOTEIO ,EREMOTEIO ), /* 121 Remote I/O error */
DEFINE_POSIX_ERROR( EDQUOT ,EDQUOT ), /* 122 Quota exceeded */
DEFINE_POSIX_ERROR( ENOMEDIUM ,ENOMEDIUM ), /* 123 No medium found */
DEFINE_POSIX_ERROR( EMEDIUMTYPE ,EMEDIUMTYPE ), /* 124 Wrong medium type */
DEFINE_POSIX_ERROR( ECANCELED ,ECANCELED ), /* 125 Operation Canceled */
DEFINE_POSIX_ERROR( ENOKEY ,ENOKEY ), /* 126 Required key not available */
DEFINE_POSIX_ERROR( EKEYEXPIRED ,EKEYEXPIRED ), /* 127 Key has expired */
DEFINE_POSIX_ERROR( EKEYREVOKED ,EKEYREVOKED ), /* 128 Key has been revoked */
DEFINE_POSIX_ERROR( EKEYREJECTED ,EKEYREJECTED ), /* 129 Key was rejected by service */
DEFINE_POSIX_ERROR( EOWNERDEAD ,EOWNERDEAD ), /* 130 Owner died */
DEFINE_POSIX_ERROR( ENOTRECOVERABLE ,ENOTRECOVERABLE ), /* 131 State not recoverable */
//Below are MBED SYSTEM ERROR CODE definitions
//MBED SYSTEM ERROR CODE definitions starts at offset MBED_SYSTEM_ERROR_BASE, see above.
// Error Name Error Code
DEFINE_SYSTEM_ERROR( UNKNOWN ,0 ),
DEFINE_SYSTEM_ERROR( INVALID_ARGUMENT ,1 ),
DEFINE_SYSTEM_ERROR( INVALID_DATA ,2 ),
DEFINE_SYSTEM_ERROR( INVALID_FORMAT ,3 ),
DEFINE_SYSTEM_ERROR( INVALID_INDEX ,4 ),
DEFINE_SYSTEM_ERROR( INVALID_SIZE ,5 ),
DEFINE_SYSTEM_ERROR( INVALID_OPERATION ,6 ),
DEFINE_SYSTEM_ERROR( NOT_FOUND ,7 ),
DEFINE_SYSTEM_ERROR( ACCESS_DENIED ,8 ),
DEFINE_SYSTEM_ERROR( NOT_SUPPORTED ,9 ),
DEFINE_SYSTEM_ERROR( BUFFER_FULL ,10 ),
DEFINE_SYSTEM_ERROR( MEDIA_FULL ,11 ),
DEFINE_SYSTEM_ERROR( ALREADY_IN_USE ,12 ),
DEFINE_SYSTEM_ERROR( TIMEOUT ,13 ),
DEFINE_SYSTEM_ERROR( NOT_READY ,14 ),
DEFINE_SYSTEM_ERROR( FAILED_OPERATION ,15 ),
DEFINE_SYSTEM_ERROR( OPERATION_PROHIBITED ,16 ),
DEFINE_SYSTEM_ERROR( OPERATION_ABORTED ,17 ),
DEFINE_SYSTEM_ERROR( WRITE_PROTECTED ,18 ),
DEFINE_SYSTEM_ERROR( NO_RESPONSE ,19 ),
DEFINE_SYSTEM_ERROR( SEMAPHORE_LOCK_FAILED ,20 ),
DEFINE_SYSTEM_ERROR( MUTEX_LOCK_FAILED ,21 ),
DEFINE_SYSTEM_ERROR( SEMAPHORE_UNLOCK_FAILED ,22 ),
DEFINE_SYSTEM_ERROR( MUTEX_UNLOCK_FAILED ,23 ),
DEFINE_SYSTEM_ERROR( CRC_ERROR ,24 ),
DEFINE_SYSTEM_ERROR( OPEN_FAILED ,25 ),
DEFINE_SYSTEM_ERROR( CLOSE_FAILED ,26 ),
DEFINE_SYSTEM_ERROR( READ_FAILED ,27 ),
DEFINE_SYSTEM_ERROR( WRITE_FAILED ,28 ),
DEFINE_SYSTEM_ERROR( INITIALIZATION_FAILED ,29 ),
DEFINE_SYSTEM_ERROR( BOOT_FAILURE ,30 ),
DEFINE_SYSTEM_ERROR( OUT_OF_MEMORY ,31 ),
DEFINE_SYSTEM_ERROR( OUT_OF_RESOURCES ,32 ),
DEFINE_SYSTEM_ERROR( ALLOC_FAILED ,33 ),
DEFINE_SYSTEM_ERROR( FREE_FAILED ,34 ),
DEFINE_SYSTEM_ERROR( OVERFLOW ,35 ),
DEFINE_SYSTEM_ERROR( UNDERFLOW ,36 ),
DEFINE_SYSTEM_ERROR( STACK_OVERFLOW ,37 ),
DEFINE_SYSTEM_ERROR( ISR_QUEUE_OVERFLOW ,38 ),
DEFINE_SYSTEM_ERROR( TIMER_QUEUE_OVERFLOW ,39 ),
DEFINE_SYSTEM_ERROR( CLIB_SPACE_UNAVAILABLE ,40 ),
DEFINE_SYSTEM_ERROR( CLIB_EXCEPTION ,41 ),
DEFINE_SYSTEM_ERROR( CLIB_MUTEX_INIT_FAILURE ,42 ),
DEFINE_SYSTEM_ERROR( CREATE_FAILED ,43 ),
DEFINE_SYSTEM_ERROR( DELETE_FAILED ,44 ),
DEFINE_SYSTEM_ERROR( THREAD_CREATE_FAILED ,45 ),
DEFINE_SYSTEM_ERROR( THREAD_DELETE_FAILED ,46 ),
DEFINE_SYSTEM_ERROR( PROHIBITED_IN_ISR_CONTEXT ,47 ),
DEFINE_SYSTEM_ERROR( PINMAP_INVALID ,48 ),
DEFINE_SYSTEM_ERROR( RTOS_EVENT ,49 ),
DEFINE_SYSTEM_ERROR( RTOS_THREAD_EVENT ,50 ),
DEFINE_SYSTEM_ERROR( RTOS_MUTEX_EVENT ,51 ),
DEFINE_SYSTEM_ERROR( RTOS_SEMAPHORE_EVENT ,52 ),
DEFINE_SYSTEM_ERROR( RTOS_MEMORY_POOL_EVENT ,53 ),
DEFINE_SYSTEM_ERROR( RTOS_TIMER_EVENT ,54 ),
DEFINE_SYSTEM_ERROR( RTOS_EVENT_FLAGS_EVENT ,55 ),
DEFINE_SYSTEM_ERROR( RTOS_MESSAGE_QUEUE_EVENT ,56 ),
DEFINE_SYSTEM_ERROR( DEVICE_BUSY ,57 ),
DEFINE_SYSTEM_ERROR( CONFIG_UNSUPPORTED ,58 ),
DEFINE_SYSTEM_ERROR( CONFIG_MISMATCH ,59 ),
DEFINE_SYSTEM_ERROR( ALREADY_INITIALIZED ,60 ),
DEFINE_SYSTEM_ERROR( HARDFAULT_EXCEPTION ,61 ),
DEFINE_SYSTEM_ERROR( MEMMANAGE_EXCEPTION ,62 ),
DEFINE_SYSTEM_ERROR( BUSFAULT_EXCEPTION ,63 ),
DEFINE_SYSTEM_ERROR( USAGEFAULT_EXCEPTION ,64 ),
//Everytime you add a new system error code, you must update
//Error documentation under Handbook to capture the info on
//the new error status/codes
//MBED CUSTOM ERROR CODE definitions starts at offset MBED_CUSTOM_ERROR_BASE, see above.
/* Add More/Custom Error Codes here, See example below */
//DEFINE_CUSTOM_ERROR( MY_CUSTOM_ERROR , 1 ),
} MbedErrorCode;
/** mbed_error_ctx struct
*
* This struct captures the context information at the time of error.\n
* It primarily contains information about the thread where the error originated,\n
* filename/line number of the source file where the error occurred, a context specific error value(error_value)\n
* and the address where the error originated.\n
*
* @note
* Below are the members of mbed_error_ctx struct\n
* error_status MbedErrorStatus value for this error\n
* error_function_address Address where the error occurred\n
* thread_id ID of the thread which generated the error\n
* thread_entry_address Entry function of the thread which generated the error\n
* thread_stack_size Stack Size of the thread which generated the error\n
* thread_stack_mem Stack Top of the thread which generated the error\n
* thread_current_sp Current Stack Pointer of the thread which generated the error\n
* error_value A context/error specific value associated with this error\n
* error_filename Filename where the error originated\n
* error_line_number Line number in error_filename where the error originated\n
*/
typedef struct _mbed_error_ctx {
MbedErrorStatus error_status;
uint32_t error_address;
uint32_t error_value;
uint32_t thread_id;
uint32_t thread_entry_address;
uint32_t thread_stack_size;
uint32_t thread_stack_mem;
uint32_t thread_current_sp;
#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED
char error_filename[MBED_CONF_MAX_ERROR_FILENAME_LEN];
uint32_t error_line_number;
#endif
} mbed_error_ctx;
/** To generate a fatal compile-time error, you can use the pre-processor #error directive.
*
* @param format C string that contains data stream to be printed.
* Code snippets below show valid format.
*
* @deprecated
* This function has been deprecated, please use one of SET_ERROR/SET_ERROR_FATAL macros
* or one of set_error/set_error_fatal functions.
*
* @code
* #error "That shouldn't have happened!"
* @endcode
@ -66,12 +574,207 @@
*
*
*/
MBED_DEPRECATED_SINCE("mbed-os-5.9", "This function has been deprecated, please use one of SET_ERROR/SET_ERROR_FATAL macros or one of set_error/set_error_fatal functions" )
#ifdef __cplusplus
extern "C" {
#endif
void error(const char* format, ...);
/**
* Call this Macro to generate a MbedErrorStatus value for a System error
* @param entity Entity generating the error code. If its unknown, pass ENTITY_UNKNOWN. See MbedEntityType for entity types.
* @param error_code The MbedErrorCode code to be used in generating the MbedErrorStatus. See MbedErrorCode for error codes.
*
* @code
*
* MbedErrorStatus driver_error = MAKE_SYSTEM_ERROR( ENTITY_DRIVER_USB, ERROR_CODE_INITIALIZATION_FAILED )
*
* @endcode
* @note This macro generate MbedErrorStatus-es with error type set to ERROR_TYPE_SYSTEM
*
*/
#define MAKE_SYSTEM_ERROR(entity, error_code) MAKE_MBED_ERROR(ERROR_TYPE_SYSTEM, entity, error_code)
/**
* Call this Macro to generate a MbedErrorStatus value for a Custom error
* @param entity Entity generating the error code. If its unknown, pass ENTITY_UNKNOWN. See MbedEntityType for entity types.
* @param error_code The MbedErrorCode code to be used in generating the MbedErrorStatus. See MbedErrorCode for error codes.
*
* @code
*
* MbedErrorStatus custom_error = MAKE_CUSTOM_ERROR( ENTITY_APPLICATION, 0xDEAD//16-bit custom error code )
*
* @endcode
* @note This macro generate MbedErrorStatus-es with error type set to ERROR_TYPE_CUSTOM
*
*/
#define MAKE_CUSTOM_ERROR(entity, error_code) MAKE_MBED_ERROR(ERROR_TYPE_CUSTOM, entity, error_code)
/**
* Call this Macro to generate a MbedErrorStatus value for a System error
* @param entity Entity generating the error code. If its unknown, pass ENTITY_UNKNOWN. See MbedEntityType for entity types.
* @param error_code The MbedErrorCode code to be used in generating the MbedErrorStatus. See MbedErrorCode for error codes.
*
* @code
*
* MbedErrorStatus new_error = MAKE_ERROR( ENTITY_DRIVER_USB, ERROR_INITIALIZATION_FAILED )
*
* @endcode
* @note This macro generate MbedErrorStatus-es with error type set to ERROR_TYPE_SYSTEM
*
*/
#define MAKE_ERROR(entity, error_code) MAKE_SYSTEM_ERROR(entity, error_code)
/**
* Callback/Error hook function prototype. Applications needing a callback when an error is reported can use set_error_hook function
* to register a callback/error hook function using the following prototype. When an error happens in the system error handling
* implementation will invoke this callback with the MbedErrorStatus reported and the error context at the time of error.
* @param error_status MbedErrorStatus status being reported.
* @param error_ctx Error context structure associated with this error.
* @return void
*
*/
typedef void (*MbedErrorHook)(const mbed_error_ctx *error_ctx);
/**
* Call this function to set a system error. This function will log the error status with the context info, prints the error report and return to caller.
*
* @param error_status MbedErrorStatus status to be set(See MbedErrorStatus enum above for available error status values).
* @param error_msg The error message to be printed out to STDIO/Serial.
* @param error_value Value associated with the error status. This would depend on error code/error scenario.
* @param filename Name of the source file originating the error( Most callers can pass __FILE__ here ).
* @param line_number The line number of the source file originating the error( Most callers can pass __LINE__ here ) .
* @return 0 or ERROR_SUCCESS.
* ERROR_INVALID_ARGUMENT if called with invalid error status/codes
*
* @code
*
* set_error( ERROR_OUT_OF_MEMORY, "Out of memory error", 0, __FILE__, __LINE__ )
*
* @endcode
*
* @note See SET_ERROR/SET_ERROR_FATAL macros which provides a wrapper on this API
*/
MbedErrorStatus set_error(MbedErrorStatus error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number);
/**
* Returns the first system error reported.
* @return MbedErrorStatus code logged for the first error or ERROR_SUCCESS if no errors are logged.
*
*/
MbedErrorStatus get_first_error(void);
/**
* Returns the most recent system error reported.
* @return MbedErrorStatus code logged for the last error or ERROR_SUCCESS if no errors are logged.
*
*/
MbedErrorStatus get_last_error(void);
/**
* Returns the number of system errors reported after boot.
* @return int Number of errors reported.
*
*/
int 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.
*
* @param error_status MbedErrorStatus status to be set(See MbedErrorStatus enum above for available error status values).
* @param error_msg The error message to be printed out to STDIO/Serial.
* @param error_value Value associated with the error status. This would depend on error code/error scenario.
* @param filename Name of the source file originating the error( Most callers can pass __FILE__ here ).
* @param line_number The line number of the source file originating the error( Most callers can pass __LINE__ here ) .
* @return 0 or ERROR_SUCCESS.
* ERROR_INVALID_ARGUMENT if called with invalid error status/codes
*
* @code
*
* set_error_fatal( ERROR_PROHIBITED_OPERATION, "Prohibited operation tried", 0, __FILE__, __LINE__ )
*
* @endcode
*
* @note See SET_ERROR/SET_ERROR_FATAL macros which provides a wrapper on this API
*/
MbedErrorStatus set_error_fatal(MbedErrorStatus error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number);
/**
* Registers an application defined error callback with the error handling system.
* This function will be called with error context info whenever system handles a set_error/set_error_fatal call
* @param custom_error_hook MbedErrorStatus status to be set(See MbedErrorStatus enum above for available error status values).
* @return 0 or ERROR_SUCCESS on success.
* ERROR_INVALID_ARGUMENT in case of NULL for custom_error_hook
*
* @code
*
* MbedErrorStatus my_custom_error_hook(MbedErrorStatus error_status, const mbed_error_ctx *error_ctx) {
* //Do something with the error_status or error_ctx
* }
*
* set_error_hook( my_custom_error_hook )
*
* @endcode
*
*/
MbedErrorStatus set_error_hook(MbedErrorHook custom_error_hook);
/**
* Reads the first error context information logged.
* @param error_info This is the mbed_error_context info captured as part of the first set_error call. The caller should pass a pointer to mbed_error_context struct allocated by the caller.
* @return 0 or ERROR_SUCCESS on success.
* ERROR_INVALID_ARGUMENT in case of invalid index
*
*/
MbedErrorStatus get_first_error_log_info(mbed_error_ctx *error_info);
/**
* Reads the last error context information logged.
* @param error_info This is the mbed_error_context info captured as part of the last set_error call. The caller should pass a pointer to mbed_error_context struct allocated by the caller.
* @return 0 or ERROR_SUCCESS on success.
* ERROR_INVALID_ARGUMENT in case of invalid index
*
*/
MbedErrorStatus get_last_error_log_info(mbed_error_ctx *error_info);
/**
* Clears all the last error, error count and all entries in the error log.
* @return 0 or ERROR_SUCCESS on success.
*
*/
MbedErrorStatus clear_all_errors(void);
/**
* Generates a MbedErrorStatus value based on passed in values for type, entity and error code.
* @param error_type Error type based on MbedErrorType enum.
* @param entity Entity type based on MbedEntityType enum.
* @param error_code Error codes defined by MbedErrorCode enum
* @return 0 or ERROR_SUCCESS on success.
*
*/
MbedErrorStatus make_mbed_error(MbedErrorType error_type, MbedEntityType entity, MbedErrorCode error_code);
#ifndef MBED_CONF_ERROR_LOG_DISABLED
/**
* Returns the current number of entries in the error log, if there has been more than max number of errors logged the number returned will be max depth of error log.
* @return Current number of entries in the error log.
*
*/
int get_error_log_count(void);
/**
* Reads the error context information for a specific error log specified by the index.
*
* @param index index of the error context entry in the log to be retrieved.\n
* The number of entries in the error log depth is configured during build and the max index depends on max depth of error log.\n
* index = 0 points to the oldest entry in the log, and index = (max log depth - 1) points to the latest entry in the error log.\n
* @param error_info This is the mbed_error_context info captured as part of the log. The caller should pass a pointer to mbed_error_context struct allocated by the caller.
* @return 0 or ERROR_SUCCESS on success.
* ERROR_INVALID_ARGUMENT in case of invalid index
*
*/
MbedErrorStatus get_error_log_info(int index, mbed_error_ctx *error_info);
#endif
#ifdef __cplusplus
}
#endif
@ -80,3 +783,5 @@ void error(const char* format, ...);
/** @}*/
/** @}*/

148
platform/mbed_error_log.c Normal file
View File

@ -0,0 +1,148 @@
/* 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 "device.h"
#include "platform/mbed_error.h"
#include "platform/mbed_toolchain.h"
#include "platform/mbed_critical.h"
#include "platform/mbed_interface.h"
#ifndef MBED_CONF_ERROR_LOG_DISABLED
#include "platform/mbed_error_log.h"
static mbed_error_ctx mbed_error_ctx_log[MBED_CONF_ERROR_LOG_SIZE] = {0};
static int error_log_count = -1;
static void mbed_log_lock()
{
core_util_critical_section_enter();
}
static void mbed_log_unlock()
{
core_util_critical_section_exit();
}
MbedErrorStatus mbed_log_put_error(mbed_error_ctx *error_ctx)
{
//Return error if error_ctx is NULL
if(NULL == error_ctx) {
return ERROR_INVALID_ARGUMENT;
}
mbed_log_lock();
error_log_count++;
memcpy(&mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_LOG_SIZE], error_ctx, sizeof(mbed_error_ctx) );
mbed_log_unlock();
return ERROR_SUCCESS;
}
MbedErrorStatus mbed_log_get_error(int index, mbed_error_ctx *error_ctx)
{
//Return error if index is more than max log size
if(index >= MBED_CONF_ERROR_LOG_SIZE) {
return ERROR_INVALID_ARGUMENT;
}
mbed_log_lock();
//calculate the index where we want to pick the ctx
if(error_log_count >= MBED_CONF_ERROR_LOG_SIZE) {
index = (error_log_count + index + 1) % MBED_CONF_ERROR_LOG_SIZE;
}
mbed_log_unlock();
memcpy(error_ctx, &mbed_error_ctx_log[index % MBED_CONF_ERROR_LOG_SIZE], sizeof(mbed_error_ctx) );
return ERROR_SUCCESS;
}
mbed_error_ctx *mbed_log_get_entry(void)
{
mbed_log_lock();
error_log_count++;
mbed_error_ctx *ctx = &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_LOG_SIZE];
mbed_log_unlock();
return ctx;
}
MbedErrorStatus mbed_log_get_last_error(mbed_error_ctx *error_ctx)
{
if(-1 == error_log_count) {
return ERROR_NOT_FOUND;
}
mbed_log_lock();
memcpy(error_ctx, &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_LOG_SIZE], sizeof(mbed_error_ctx) );
mbed_log_unlock();
return ERROR_SUCCESS;
}
int mbed_log_get_error_log_count()
{
return (error_log_count >= MBED_CONF_ERROR_LOG_SIZE? MBED_CONF_ERROR_LOG_SIZE:error_log_count+1);
}
MbedErrorStatus mbed_log_reset()
{
mbed_log_lock();
error_log_count = -1;
mbed_log_unlock();
return ERROR_SUCCESS;
}
#if DEVICE_LOCALFILESYSTEM
MbedErrorStatus mbed_log_save_error_log(const char *path)
{
MbedErrorStatus ret = ERROR_SUCCESS;
mbed_error_ctx ctx = {0};
int log_count = mbed_log_get_error_log_count();
FILE *error_log_file = NULL;
//Open the file for saving the error log info
if((error_log_file = fopen( path, "w" ) ) == NULL){
ret = MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_OPEN_FAILED);
goto exit;
}
//first line of file will be error log count
if(fprintf(error_log_file, "\nError Log Count = %d\n", log_count)){
ret = MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_WRITE_FAILED);
goto exit;
}
//Update with error log info
while(log_count >= 0) {
mbed_log_get_error(log_count, &ctx);
//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 File:%s+%d\n", log_count, ctx.error_status, ctx.thread_id, ctx.error_address)) {
ret = MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_WRITE_FAILED);
goto exit;
}
log_count--;
}
ret = 0;
exit:
fclose(error_log_file);
return ret;
}
#endif
#endif

44
platform/mbed_error_log.h Normal file
View File

@ -0,0 +1,44 @@
/* 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_LOG_H
#define MBED_ERROR_LOG_H
#ifndef MBED_CONF_ERROR_LOG_SIZE
#define MBED_CONF_ERROR_LOG_SIZE 5
#else
#if MBED_CONF_ERROR_LOG_SIZE == 0
#define MBED_CONF_ERROR_LOG_SIZE 1
#endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
MbedErrorStatus mbed_log_put_error(mbed_error_ctx *error_ctx);
MbedErrorStatus mbed_log_get_error(int index, mbed_error_ctx *error_ctx);
mbed_error_ctx *mbed_log_get_entry(void);
MbedErrorStatus mbed_log_get_last_error(mbed_error_ctx *error_ctx);
int mbed_log_get_error_log_count(void);
MbedErrorStatus mbed_log_reset(void);
MbedErrorStatus mbed_save_error_log(const char *path);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,187 @@
/* 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 "rtx_os.h"
#include "mbed_rtx.h"
#include "hal/serial_api.h"
#include "platform/mbed_error.h"
#include "platform/mbed_error_report.h"
#if DEVICE_SERIAL
extern int stdio_uart_inited;
extern serial_t stdio_uart;
#endif
/* 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)];
}
}
/* 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
int i = 0;
int idx = 0;
int vidx = 0;
char hex_str[9]={0};
char *str=NULL;
/* Initializes std uart if not init-ed yet */
if (!stdio_uart_inited) {
serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
}
while(fmtstr[i] != '\0') {
if(fmtstr[i]=='%') {
i++;
if(fmtstr[i]=='x') {
//print the number in hex format
value_to_hex_str(values[vidx++],hex_str);
for(idx=7; idx>=0; idx--) {
serial_putc(&stdio_uart, hex_str[idx]);
}
}
else if(fmtstr[i]=='s') {
//print the string
str = (char *)((uint32_t)values[vidx++]);
while(*str != '\0') {
serial_putc(&stdio_uart, *str);
str++;
}
str = NULL;
} else {
//print the % and char without formatting and keep going
serial_putc(&stdio_uart, '%');
serial_putc(&stdio_uart, fmtstr[i]);
}
} else {
serial_putc(&stdio_uart, fmtstr[i]);
}
i++;
}
#endif
}
/* 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 EntryFn: 0x%x Stack Size: 0x%x Mem: 0x%x SP: 0x%x", data);
}
void mbed_report_error(const mbed_error_ctx *error_ctx, char *error_msg)
{
int error_code = GET_MBED_ERROR_CODE(error_ctx->error_status);
mbed_error_print("\n\n++ MbedOS Error Info ++\nError Status: 0x%x", (uint32_t *)&error_ctx->error_status);
mbed_error_print("\nError Message: ", NULL);
//Report error info based on error code, some errors require different info
if(error_code == ERROR_CODE_HARDFAULT_EXCEPTION ||
error_code == ERROR_CODE_MEMMANAGE_EXCEPTION ||
error_code == ERROR_CODE_BUSFAULT_EXCEPTION ||
error_code == ERROR_CODE_USAGEFAULT_EXCEPTION ) {
mbed_error_print(error_msg, NULL);
mbed_error_print("\nError Location: 0x%x\n", (uint32_t *)&error_ctx->error_value);
} else {
switch (error_code) {
//These are errors reported by kernel handled from mbed_rtx_handlers
case ERROR_CODE_RTOS_EVENT:
mbed_error_print("Kernel Error: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case ERROR_CODE_RTOS_THREAD_EVENT:
mbed_error_print("Thread Error: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case ERROR_CODE_RTOS_MUTEX_EVENT:
mbed_error_print("Mutex Error: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case ERROR_CODE_RTOS_SEMAPHORE_EVENT:
mbed_error_print("Semaphore Error: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case ERROR_CODE_RTOS_MEMORY_POOL_EVENT:
mbed_error_print("MemoryPool Error: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case ERROR_CODE_RTOS_EVENT_FLAGS_EVENT:
mbed_error_print("EventFlags Error: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case ERROR_CODE_RTOS_TIMER_EVENT:
mbed_error_print("Timer Error: 0x%x, ", (uint32_t *)&error_ctx->error_value);
break;
case ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT:
mbed_error_print("MessageQueue Error: 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("\nError Location: 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
//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 EntryFn: 0x%x StackSize: 0x%x StackMem: 0x%x SP: 0x%x ",
(uint32_t *)&error_ctx->error_value);
}
mbed_error_print("\n-- MbedOS Error Info --", NULL);
}

View File

@ -0,0 +1,50 @@
/** \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
/* routine to report the error */
void mbed_report_error(const mbed_error_ctx *error_ctx, char *error_msg);
/* Prints thread info from a list */
void print_threads_info(osRtxThread_t *threads);
/* Prints info of a thread(using osRtxThread_t struct)*/
void print_thread(osRtxThread_t *thread);
/* 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);
#ifdef __cplusplus
}
#endif
#endif
/** @}*/

View File

@ -126,6 +126,7 @@ void remove_filehandle(FileHandle *file) {
#if DEVICE_SERIAL
extern int stdio_uart_inited;
extern serial_t stdio_uart;
#endif
/* Private FileHandle to implement backwards-compatible functionality of
* direct HAL serial access for default stdin/stdout/stderr.
@ -192,7 +193,6 @@ short DirectSerial::poll(short events) const {
}
return revents;
}
#endif
class Sink : public FileHandle {
public:
@ -538,7 +538,7 @@ extern "C" int PREFIX(_write)(FILEHANDLE fh, const unsigned char *buffer, unsign
#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
error("Error - writing to a file in an ISR or critical section\r\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_PROHIBITED_IN_ISR_CONTEXT), "Error - writing to a file in an ISR or critical section\r\n", fh);
}
#endif
@ -646,7 +646,7 @@ extern "C" int PREFIX(_read)(FILEHANDLE fh, unsigned char *buffer, unsigned int
#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED && defined(MBED_CONF_RTOS_PRESENT)
if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
error("Error - reading from a file in an ISR or critical section\r\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_PROHIBITED_IN_ISR_CONTEXT), "Error - reading from a file in an ISR or critical section\r\n", fh);
}
#endif
@ -1088,7 +1088,7 @@ extern "C" int statvfs(const char *path, struct statvfs *buf) {
#include "mbed_error.h"
namespace __gnu_cxx {
void __verbose_terminate_handler() {
error("Exception");
SET_ERROR_FATAL(MAKE_ERROR( ENTITY_PLATFORM, ERROR_CODE_CLIB_EXCEPTION),"Exception", 0);
}
}
extern "C" WEAK void __cxa_pure_virtual(void);
@ -1374,7 +1374,7 @@ extern "C" void __cxa_guard_abort(int *guard_object_p)
#endif
#if defined(MBED_MEM_TRACING_ENABLED) && (defined(__CC_ARM) || defined(__ICCARM__) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)))
#if defined(MBED_MEM_TRACING_ENABLED) && (defined(__CC_ARM) || defined(__ICCARM__))
// If the memory tracing is enabled, the wrappers in mbed_alloc_wrappers.cpp
// provide the implementation for these. Note: this needs to use the wrappers
@ -1471,7 +1471,7 @@ void *operator new(std::size_t count)
{
void *buffer = malloc(count);
if (NULL == buffer) {
error("Operator new out of memory\r\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_OUT_OF_MEMORY), "Operator new out of memory\r\n", count);
}
return buffer;
}
@ -1480,7 +1480,7 @@ void *operator new[](std::size_t count)
{
void *buffer = malloc(count);
if (NULL == buffer) {
error("Operator new[] out of memory\r\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_OUT_OF_MEMORY), "Operator new[] out of memory\r\n", count);
}
return buffer;
}

View File

@ -15,104 +15,107 @@
*/
#include "rtx_os.h"
#include "device.h"
#include "mbed_rtx.h"
#include "mbed_rtx_fault_handler.h"
#include "hal/serial_api.h"
#include "platform/mbed_error.h"
#include "platform/mbed_error_report.h"
#ifndef MBED_FAULT_HANDLER_DISABLED
#include "mbed_rtx_fault_handler.h"
//Functions Prototypes
void print_context_info(void);
//Global for populating the context in exception handler
mbed_fault_context_t mbed_fault_context;
//Structure to capture the context
void fault_print_init(void);
void fault_print_str(char *fmtstr, uint32_t *values);
void hex_to_str(uint32_t value, char *hex_star);
void print_context_info(void);
void print_threads_info(osRtxThread_t *);
void print_thread(osRtxThread_t *thread);
void print_register(char *regtag, uint32_t regval);
#if DEVICE_SERIAL
extern int stdio_uart_inited;
extern serial_t stdio_uart;
#endif
//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.
__NO_RETURN void mbed_fault_handler (uint32_t fault_type, void *mbed_fault_context_in, void *osRtxInfoIn)
{
fault_print_init();
fault_print_str("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL);
MbedErrorStatus faultStatus = ERROR_SUCCESS;
mbed_error_print("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL);
switch( fault_type ) {
case HARD_FAULT_EXCEPTION:
fault_print_str("HardFault",NULL);
mbed_error_print("HardFault",NULL);
faultStatus = ERROR_HARDFAULT_EXCEPTION;
break;
case MEMMANAGE_FAULT_EXCEPTION:
fault_print_str("MemManageFault",NULL);
mbed_error_print("MemManageFault",NULL);
faultStatus = ERROR_MEMMANAGE_EXCEPTION;
break;
case BUS_FAULT_EXCEPTION:
fault_print_str("BusFault",NULL);
mbed_error_print("BusFault",NULL);
faultStatus = ERROR_BUSFAULT_EXCEPTION;
break;
case USAGE_FAULT_EXCEPTION:
fault_print_str("UsageFault",NULL);
mbed_error_print("UsageFault",NULL);
faultStatus = ERROR_USAGEFAULT_EXCEPTION;
break;
default:
fault_print_str("Unknown Fault",NULL);
mbed_error_print("Unknown Fault",NULL);
faultStatus = ERROR_UNKNOWN;
break;
}
fault_print_str("\n\nContext:",NULL);
mbed_error_print("\n\nContext:",NULL);
print_context_info();
fault_print_str("\n\nThread Info:\nCurrent:",NULL);
mbed_error_print("\n\nThread Info:\nCurrent:",NULL);
print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.curr);
fault_print_str("\nNext:",NULL);
mbed_error_print("\nNext:",NULL);
print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.next);
fault_print_str("\nWait Threads:",NULL);
mbed_error_print("\nWait Threads:",NULL);
osRtxThread_t *threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.wait_list;
print_threads_info(threads);
fault_print_str("\nDelay Threads:",NULL);
mbed_error_print("\nDelay Threads:",NULL);
threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.delay_list;
print_threads_info(threads);
fault_print_str("\nIdle Thread:",NULL);
mbed_error_print("\nIdle Thread:",NULL);
threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.idle;
print_threads_info(threads);
fault_print_str("\n\n-- MbedOS Fault Handler --\n\n",NULL);
/* Just spin here, we have already crashed */
for (;;) {}
mbed_error_print("\n\n-- MbedOS Fault Handler --\n\n",NULL);
//Now call set_error_fatal, to log the error and halt the system
set_error_fatal( MAKE_ERROR( ENTITY_UNKNOWN, faultStatus ), "System encountered an unrecoverable fault excaption, halting system.", mbed_fault_context.PC, NULL, 0 );
/* In case we return, just spin here, we have already crashed */
for (;;) {
__WFI();
}
}
void print_context_info()
void print_context_info(void)
{
//Context Regs
fault_print_str( "\nR0 : %"
"\nR1 : %"
"\nR2 : %"
"\nR3 : %"
"\nR4 : %"
"\nR5 : %"
"\nR6 : %"
"\nR7 : %"
"\nR8 : %"
"\nR9 : %"
"\nR10 : %"
"\nR11 : %"
"\nR12 : %"
"\nSP : %"
"\nLR : %"
"\nPC : %"
"\nxPSR : %"
"\nPSP : %"
"\nMSP : %", (uint32_t *)&mbed_fault_context);
mbed_error_print("\nR0 : %x"
"\nR1 : %x"
"\nR2 : %x"
"\nR3 : %x"
"\nR4 : %x"
"\nR5 : %x"
"\nR6 : %x"
"\nR7 : %x"
"\nR8 : %x"
"\nR9 : %x"
"\nR10 : %x"
"\nR11 : %x"
"\nR12 : %x"
"\nSP : %x"
"\nLR : %x"
"\nPC : %x"
"\nxPSR : %x"
"\nPSP : %x"
"\nMSP : %x", (uint32_t *)&mbed_fault_context);
//Capture CPUID to get core/cpu info
fault_print_str("\nCPUID: %",(uint32_t *)&SCB->CPUID);
mbed_error_print("\nCPUID: %x",(uint32_t *)&SCB->CPUID);
#if !defined(TARGET_M0) && !defined(TARGET_M0P)
//Capture fault information registers to infer the cause of exception
@ -126,121 +129,43 @@ void print_context_info()
FSR[4] = SCB->DFSR;
FSR[5] = SCB->AFSR;
FSR[6] = SCB->SHCSR;
fault_print_str("\nHFSR : %"
"\nMMFSR: %"
"\nBFSR : %"
"\nUFSR : %"
"\nDFSR : %"
"\nAFSR : %"
"\nSHCSR: %",FSR);
mbed_error_print("\nHFSR : %x"
"\nMMFSR: %x"
"\nBFSR : %x"
"\nUFSR : %x"
"\nDFSR : %x"
"\nAFSR : %x"
"\nSHCSR: %x",FSR);
//Print MMFAR only if its valid as indicated by MMFSR
if(FSR[1] & 0x80) {
fault_print_str("\nMMFAR: %",(uint32_t *)&SCB->MMFAR);
mbed_error_print("\nMMFAR: %x",(uint32_t *)&SCB->MMFAR);
}
//Print BFAR only if its valid as indicated by BFSR
if(FSR[2] & 0x80) {
fault_print_str("\nBFAR : %",(uint32_t *)&SCB->BFAR);
mbed_error_print("\nBFAR : %x",(uint32_t *)&SCB->BFAR);
}
#endif
//Print Mode
if(mbed_fault_context.EXC_RETURN & 0x8) {
fault_print_str("\nMode : Thread", NULL);
mbed_error_print("\nMode : Thread", NULL);
//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
//thread mode eventhough we are in Handler mode by the time we capture it.
if(mbed_fault_context.CONTROL & 0x1) {
fault_print_str("\nPriv : User", NULL);
mbed_error_print("\nPriv : User", NULL);
} else {
fault_print_str("\nPriv : Privileged", NULL);
mbed_error_print("\nPriv : Privileged", NULL);
}
} else {
fault_print_str("\nMode : Handler", NULL);
fault_print_str("\nPriv : Privileged", NULL);
mbed_error_print("\nMode : Handler", NULL);
mbed_error_print("\nPriv : Privileged", NULL);
}
//Print Return Stack
if(mbed_fault_context.EXC_RETURN & 0x4) {
fault_print_str("\nStack: PSP", NULL);
mbed_error_print("\nStack: PSP", NULL);
} else {
fault_print_str("\nStack: MSP", NULL);
}
}
/* 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;
fault_print_str("\nState: % EntryFn: % Stack Size: % Mem: % SP: %", data);
}
/* Initializes std uart for spitting the info out */
void fault_print_init()
{
#if DEVICE_SERIAL
if (!stdio_uart_inited) {
serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
}
#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 fault_print_str(char *fmtstr, uint32_t *values)
{
#if DEVICE_SERIAL
int i = 0;
int idx = 0;
int vidx = 0;
char hex_str[9]={0};
while(fmtstr[i] != '\0') {
if(fmtstr[i]=='%') {
hex_to_str(values[vidx++],hex_str);
for(idx=7; idx>=0; idx--) {
serial_putc(&stdio_uart, hex_str[idx]);
}
} else {
if (fmtstr[i] == '\n') {
serial_putc(&stdio_uart, '\r');
}
serial_putc(&stdio_uart, fmtstr[i]);
}
i++;
}
#endif
}
/* Converts a uint32 to hex char string */
void hex_to_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)];
mbed_error_print("\nStack: MSP", NULL);
}
}

View File

@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_RTX_FAULT_HANDLER_H
#define MBED_RTX_FAULT_HANDLER_H
//Fault context struct
//WARNING: DO NOT CHANGE THIS STRUCT WITHOUT MAKING CORRESPONDING CHANGES in except.S files.
@ -52,3 +55,4 @@ typedef struct {
//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);
#endif

View File

@ -323,7 +323,7 @@ void mbed_start_main(void)
_main_thread_attr.name = "main_thread";
osThreadId_t result = osThreadNew((osThreadFunc_t)pre_main, NULL, &_main_thread_attr);
if ((void *)result == NULL) {
error("Pre main thread not created");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_INITIALIZATION_FAILED), "Pre main thread not created", &_main_thread_attr);
}
osKernelStart();

View File

@ -19,6 +19,7 @@
#include "rtx_evr.h"
#include "mbed_rtx.h"
#include "mbed_error.h"
#include "mbed_interface.h"
#include "RTX_Config.h"
#ifdef RTE_Compiler_EventRecorder
@ -46,31 +47,27 @@ __NO_RETURN uint32_t osRtxErrorNotify (uint32_t code, void *object_id)
case osRtxErrorStackUnderflow:
// Stack underflow detected for thread (thread_id=object_id)
// Note: "overflow" is printed instead of "underflow" due to end user familiarity with overflow errors
error("CMSIS-RTOS error: Stack overflow (status: 0x%X, task ID: 0x%X, task name: %s)\n\r",
code, object_id, osThreadGetName(object_id));
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_KERNEL, ERROR_CODE_STACK_OVERFLOW), "CMSIS-RTOS error: Stack overflow", code);
break;
case osRtxErrorISRQueueOverflow:
// ISR Queue overflow detected when inserting object (object_id)
error("CMSIS-RTOS error: ISR Queue overflow (status: 0x%X, task ID: 0x%X, object ID: 0x%X)\n\r",
code, tid, object_id);
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_KERNEL, ERROR_CODE_ISR_QUEUE_OVERFLOW), "CMSIS-RTOS error: ISR Queue overflow", code);
break;
case osRtxErrorTimerQueueOverflow:
// User Timer Callback Queue overflow detected for timer (timer_id=object_id)
error("CMSIS-RTOS error: User Timer Callback Queue overflow (status: 0x%X, task ID: 0x%X, timer ID: 0x%X)\n\r",
code, tid, object_id);
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_KERNEL, ERROR_CODE_TIMER_QUEUE_OVERFLOW), "CMSIS-RTOS error: User Timer Callback Queue overflow", code);
break;
case osRtxErrorClibSpace:
// Standard C/C++ library libspace not available: increase OS_THREAD_LIBSPACE_NUM
error("CMSIS-RTOS error: STD C/C++ library libspace not available (status: 0x%X, task ID: 0x%X)\n\r",
code, tid);
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_KERNEL, ERROR_CODE_CLIB_SPACE_UNAVAILABLE), "CMSIS-RTOS error: STD C/C++ library libspace not available", code);
break;
case osRtxErrorClibMutex:
// Standard C/C++ library mutex initialization failed
error("CMSIS-RTOS error: STD C/C++ library mutex initialization failed (status: 0x%X, task ID: 0x%X)\n\r",
code, tid);
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_KERNEL, ERROR_CODE_CLIB_MUTEX_INIT_FAILURE), "CMSIS-RTOS error: STD C/C++ library mutex initialization failed", code);
break;
default:
error("CMSIS-RTOS error: Unknown (status: 0x%X, task ID: 0x%X)\n\r", code, tid);
//Unknown error flagged from kernel
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_KERNEL, ERROR_CODE_UNKNOWN), "CMSIS-RTOS error: Unknown", code);
break;
}
@ -102,27 +99,27 @@ static const char* error_msg(int32_t status)
void EvrRtxKernelError (int32_t status)
{
error("Kernel error %i: %s\r\n", status, error_msg(status));
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_RTOS_EVENT), error_msg(status), status);
}
void EvrRtxThreadError (osThreadId_t thread_id, int32_t status)
{
error("Thread %p error %i: %s\r\n", thread_id, status, error_msg(status));
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_RTOS_THREAD_EVENT), error_msg(status), thread_id);
}
void EvrRtxTimerError (osTimerId_t timer_id, int32_t status)
{
error("Timer %p error %i: %s\r\n", timer_id, status, error_msg(status));
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_RTOS_TIMER_EVENT), error_msg(status), timer_id);
}
void EvrRtxEventFlagsError (osEventFlagsId_t ef_id, int32_t status)
{
error("Event %p error %i: %s\r\n", ef_id, status, error_msg(status));
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_RTOS_EVENT_FLAGS_EVENT), error_msg(status), ef_id);
}
void EvrRtxMutexError (osMutexId_t mutex_id, int32_t status)
{
error("Mutex %p error %i: %s\r\n", mutex_id, status, error_msg(status));
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_RTOS_MUTEX_EVENT), error_msg(status), mutex_id);
}
void EvrRtxSemaphoreError (osSemaphoreId_t semaphore_id, int32_t status)
@ -132,17 +129,17 @@ void EvrRtxSemaphoreError (osSemaphoreId_t semaphore_id, int32_t status)
return;
}
error("Semaphore %p error %i\r\n", semaphore_id, status);
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_RTOS_SEMAPHORE_EVENT), error_msg(status), semaphore_id);
}
void EvrRtxMemoryPoolError (osMemoryPoolId_t mp_id, int32_t status)
{
error("Memory Pool %p error %i\r\n", mp_id, status);
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_RTOS_MEMORY_POOL_EVENT), error_msg(status), mp_id);
}
void EvrRtxMessageQueueError (osMessageQueueId_t mq_id, int32_t status)
{
error("Message Queue %p error %i\r\n", mq_id, status);
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT), error_msg(status), mq_id);
}
#endif

View File

@ -43,11 +43,7 @@ extern "C" void thread_terminate_hook(osThreadId_t id)
namespace rtos {
#ifndef MBED_TZ_DEFAULT_ACCESS
#define MBED_TZ_DEFAULT_ACCESS 0
#endif
void Thread::constructor(uint32_t tz_module, osPriority priority,
void Thread::constructor(osPriority priority,
uint32_t stack_size, unsigned char *stack_mem, const char *name) {
const uintptr_t unaligned_mem = reinterpret_cast<uintptr_t>(stack_mem);
@ -64,27 +60,21 @@ void Thread::constructor(uint32_t tz_module, osPriority priority,
_attr.stack_size = aligned_size;
_attr.name = name ? name : "application_unnamed_thread";
_attr.stack_mem = reinterpret_cast<uint32_t*>(aligned_mem);
_attr.tz_module = tz_module;
}
void Thread::constructor(osPriority priority,
uint32_t stack_size, unsigned char *stack_mem, const char *name) {
constructor(MBED_TZ_DEFAULT_ACCESS, priority, stack_size, stack_mem, name);
}
void Thread::constructor(Callback<void()> task,
osPriority priority, uint32_t stack_size, unsigned char *stack_mem, const char *name) {
constructor(MBED_TZ_DEFAULT_ACCESS, priority, stack_size, stack_mem, name);
constructor(priority, stack_size, stack_mem, name);
switch (start(task)) {
case osErrorResource:
error("OS ran out of threads!\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_OUT_OF_RESOURCES), "OS ran out of threads!\n", task);
break;
case osErrorParameter:
error("Thread already running!\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_ALREADY_IN_USE), "Thread already running!\n", task);
break;
case osErrorNoMemory:
error("Error allocating the stack memory\n");
SET_ERROR_FATAL(MAKE_ERROR(ENTITY_PLATFORM, ERROR_CODE_OUT_OF_MEMORY), "Error allocating the stack memory\n", task);
default:
break;
}