diff --git a/TESTS/mbed_platform/error_handling/main.cpp b/TESTS/mbed_platform/error_handling/main.cpp new file mode 100644 index 0000000000..008033c3da --- /dev/null +++ b/TESTS/mbed_platform/error_handling/main.cpp @@ -0,0 +1,365 @@ +/* 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" +#include +#include "HeapBlockDevice.h" + +using utest::v1::Case; + +/** 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; ithread_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_HIST_DISABLED +/** Test error logging functionality + */ +void test_error_logging() +{ + mbed_error_ctx error_ctx = {0}; + + //clear the current errors first + mbed_clear_all_errors(); + + //log 3 errors and retrieve them to ensure they are correct + MBED_WARNING1(MBED_ERROR_INVALID_ARGUMENT, "Invalid argument", 1 ); + MBED_WARNING1(MBED_ERROR_INVALID_SIZE, "Invalid size", 2 ); + MBED_WARNING1(MBED_ERROR_INVALID_FORMAT, "Invalid format", 3 ); + + mbed_error_status_t status = mbed_get_error_hist_info( 0, &error_ctx ); + TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, error_ctx.error_status); + TEST_ASSERT_EQUAL_UINT(1, error_ctx.error_value); + + status = mbed_get_error_hist_info( 1, &error_ctx ); + TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_SIZE, error_ctx.error_status); + TEST_ASSERT_EQUAL_UINT(2, error_ctx.error_value); + + status = mbed_get_error_hist_info( 2, &error_ctx ); + TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_FORMAT, error_ctx.error_status); + TEST_ASSERT_EQUAL_UINT(3, error_ctx.error_value); + + //Log a bunch of errors to overflow the error log and retrieve them + MBED_WARNING1(MBED_ERROR_INVALID_ARGUMENT, "Invalid argument", 6 ); + MBED_WARNING1(MBED_ERROR_INVALID_SIZE, "Invalid size", 7 ); + MBED_WARNING1(MBED_ERROR_INVALID_FORMAT, "Invalid format", 8 ); + MBED_WARNING1(MBED_ERROR_NOT_READY, "Not ready error", 9 ); + + //Last 4 entries + MBED_WARNING1(MBED_ERROR_TIME_OUT, "Timeout error", 10 ); + MBED_WARNING1(MBED_ERROR_ALREADY_IN_USE, "Already in use error", 11 ); + MBED_WARNING1(MBED_ERROR_UNSUPPORTED, "Not supported", 12 ); + MBED_WARNING1(MBED_ERROR_ACCESS_DENIED, "Access denied", 13 ); + + status = mbed_get_error_hist_info( 0, &error_ctx ); + TEST_ASSERT_EQUAL_UINT(MBED_ERROR_TIME_OUT, error_ctx.error_status); + TEST_ASSERT_EQUAL_UINT(10, error_ctx.error_value); + + status = mbed_get_error_hist_info( 1, &error_ctx ); + TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ALREADY_IN_USE, error_ctx.error_status); + TEST_ASSERT_EQUAL_UINT(11, error_ctx.error_value); + + status = mbed_get_error_hist_info( 2, &error_ctx ); + TEST_ASSERT_EQUAL_UINT(MBED_ERROR_UNSUPPORTED, error_ctx.error_status); + TEST_ASSERT_EQUAL_UINT(12, error_ctx.error_value); + + status = mbed_get_error_hist_info( 3, &error_ctx ); + TEST_ASSERT_EQUAL_UINT(MBED_ERROR_ACCESS_DENIED, error_ctx.error_status); + TEST_ASSERT_EQUAL_UINT(13, error_ctx.error_value); + + //Try an index which is invalid, we should get ERROR_INVALID_ARGUMENT back + status = mbed_get_error_hist_info( 99, &error_ctx ); + TEST_ASSERT_EQUAL_UINT(MBED_ERROR_INVALID_ARGUMENT, status); + +} + +#define NUM_TEST_THREADS 5 + +//Error logger threads +void err_thread_func(mbed_error_status_t *error_status) +{ + MBED_WARNING1(*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]; + mbed_error_status_t error_status[NUM_TEST_THREADS] = { + MBED_ERROR_INVALID_ARGUMENT, MBED_ERROR_INVALID_DATA_DETECTED, MBED_ERROR_INVALID_FORMAT, MBED_ERROR_INVALID_SIZE, MBED_ERROR_INVALID_OPERATION + }; + + + for(; istart(callback(err_thread_func, &error_status[i])); + } + wait(2.0); + for(i=0; ijoin(); + } + + i = mbed_get_error_hist_count()-1; + + for(;i>=0;--i) { + mbed_error_status_t status = mbed_get_error_hist_info( i, &error_ctx ); + if(status != MBED_SUCCESS) { + TEST_FAIL(); + } + + 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( MBED_SUCCESS != mbed_set_error_hook(MyErrorHook)) { + TEST_FAIL(); + } + + MBED_WARNING1(MBED_ERROR_INVALID_ARGUMENT, "Test for error hook", 1234); + int32_t sem_status = callback_sem.wait(5000); + + TEST_ASSERT(sem_status > 0); +} + +#ifdef MBED_TEST_SIM_BLOCKDEVICE + +// test configuration +#ifndef MBED_TEST_FILESYSTEM +#define MBED_TEST_FILESYSTEM LittleFileSystem +#endif + +#ifndef MBED_TEST_FILESYSTEM_DECL +#define MBED_TEST_FILESYSTEM_DECL MBED_TEST_FILESYSTEM fs("fs") +#endif + +#ifndef MBED_TEST_BLOCK_COUNT +#define MBED_TEST_BLOCK_COUNT 64 +#endif + +#ifndef MBED_TEST_SIM_BLOCKDEVICE_DECL +#define MBED_TEST_SIM_BLOCKDEVICE_DECL MBED_TEST_SIM_BLOCKDEVICE fd(MBED_TEST_BLOCK_COUNT*512, 1, 1, 512) +#endif + +// declarations +#define STRINGIZE(x) STRINGIZE2(x) +#define STRINGIZE2(x) #x +#define INCLUDE(x) STRINGIZE(x.h) + +#include INCLUDE(MBED_TEST_FILESYSTEM) +#include INCLUDE(MBED_TEST_SIM_BLOCKDEVICE) + +MBED_TEST_FILESYSTEM_DECL; +MBED_TEST_SIM_BLOCKDEVICE_DECL; + +/** Test save error log + */ +void test_save_error_log() +{ + //Log some errors + MBED_WARNING1(MBED_ERROR_TIME_OUT, "Timeout error", 1 ); + MBED_WARNING1(MBED_ERROR_ALREADY_IN_USE, "Already in use error", 2 ); + MBED_WARNING1(MBED_ERROR_UNSUPPORTED, "Not supported error", 3 ); + MBED_WARNING1(MBED_ERROR_ACCESS_DENIED, "Access denied error", 4 ); + MBED_WARNING1(MBED_ERROR_ITEM_NOT_FOUND, "Not found error", 5 ); + + int error = 0; + + error = MBED_TEST_FILESYSTEM::format(&fd); + if(error < 0) { + TEST_FAIL_MESSAGE("Failed formatting"); + } + + error = fs.mount(&fd); + if(error < 0) { + TEST_FAIL_MESSAGE("Failed mounting fs"); + } + + if(MBED_SUCCESS != mbed_save_error_hist("/fs/errors.log")) { + TEST_FAIL_MESSAGE("Failed saving error log"); + } + + FILE *error_file = fopen("/fs/errors.log", "r"); + if(error_file == NULL) { + TEST_FAIL_MESSAGE("Unable to find error log in fs"); + } + + char buff[64] = {0}; + while (!feof(error_file)){ + int size = fread(&buff[0], 1, 15, error_file); + fwrite(&buff[0], 1, size, stdout); + } + fclose(error_file); + + error = fs.unmount(); + if(error < 0) { + TEST_FAIL_MESSAGE("Failed unmounting fs"); + } +} + +#endif + +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(120, "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 error encoding, value capture, first and last errors", test_error_capturing), + Case("Test error context capture", test_error_context_capture), + Case("Test error hook", test_error_hook), +#ifndef MBED_CONF_ERROR_HIST_DISABLED + Case("Test error logging", test_error_logging), + Case("Test error handling multi-threaded", test_error_logging_multithread), +#ifdef MBED_TEST_SIM_BLOCKDEVICE + Case("Test error save log", test_save_error_log), +#endif +#endif +}; + +utest::v1::Specification specification(test_setup, cases); + +int main() +{ + return !utest::v1::Harness::run(specification); +} diff --git a/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp b/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp index 7753a4521d..4ec343bf33 100644 --- a/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp +++ b/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp @@ -51,6 +51,12 @@ Semaphore sync_sem(0, 1); void error(const char* format, ...) { (void) format; } + +//Override the set_error function to trap the errors +mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) +{ + return MBED_SUCCESS; +} #endif template diff --git a/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp b/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp index 694ea04bf3..6ec123a112 100644 --- a/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp +++ b/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp @@ -85,6 +85,11 @@ void error(const char* format, ...) { (void) format; } + +mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) +{ + return MBED_SUCCESS; +} #endif /** Test one-shot not restarted when elapsed diff --git a/TESTS/mbedmicro-rtos-mbed/signals/main.cpp b/TESTS/mbedmicro-rtos-mbed/signals/main.cpp index 0809b14f17..324329397b 100644 --- a/TESTS/mbedmicro-rtos-mbed/signals/main.cpp +++ b/TESTS/mbedmicro-rtos-mbed/signals/main.cpp @@ -55,6 +55,11 @@ struct Sync { void error(const char* format, ...) { (void) format; } + +mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) +{ + return MBED_SUCCESS; +} #endif diff --git a/features/filesystem/bd/ReadOnlyBlockDevice.cpp b/features/filesystem/bd/ReadOnlyBlockDevice.cpp index 0b23694fa1..fe6e40c93d 100644 --- a/features/filesystem/bd/ReadOnlyBlockDevice.cpp +++ b/features/filesystem/bd/ReadOnlyBlockDevice.cpp @@ -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; + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_BLOCK_DEVICE, MBED_ERROR_CODE_WRITE_PROTECTED), "ReadOnlyBlockDevice::program() not allowed", addr); + return MBED_ERROR_WRITE_PROTECTED; } int ReadOnlyBlockDevice::erase(bd_addr_t addr, bd_size_t size) { - error("ReadOnlyBlockDevice::erase() not allowed"); - return 0; + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_BLOCK_DEVICE, MBED_ERROR_CODE_WRITE_PROTECTED), "ReadOnlyBlockDevice::erase() not allowed", addr); + return MBED_ERROR_WRITE_PROTECTED; } bd_size_t ReadOnlyBlockDevice::get_read_size() const diff --git a/hal/mbed_pinmap_common.c b/hal/mbed_pinmap_common.c index 93658b2793..1cb369f7e7 100644 --- a/hal/mbed_pinmap_common.c +++ b/hal/mbed_pinmap_common.c @@ -29,7 +29,7 @@ void pinmap_pinout(PinName pin, const PinMap *map) { } map++; } - error("could not pinout"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_PINMAP_INVALID), "pinmap not found for function", function); return function; } diff --git a/hal/mbed_sleep_manager.c b/hal/mbed_sleep_manager.c index 8e33acfcb9..6704ca542f 100644 --- a/hal/mbed_sleep_manager.c +++ b/hal/mbed_sleep_manager.c @@ -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)"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_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)"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNDERFLOW), "DeepSleepLock underflow (< 0)", deep_sleep_lock); } core_util_atomic_decr_u16(&deep_sleep_lock, 1); core_util_critical_section_exit(); diff --git a/platform/DeepSleepLock.h b/platform/DeepSleepLock.h index 78fa962732..b383770b9a 100644 --- a/platform/DeepSleepLock.h +++ b/platform/DeepSleepLock.h @@ -69,7 +69,7 @@ public: sleep_manager_lock_deep_sleep(); } if (0 == count) { - error("DeepSleepLock overflow (> USHRT_MAX)"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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)"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_UNDERFLOW), "DeepSleepLock underflow (< 0)", count); } } }; diff --git a/platform/Stream.cpp b/platform/Stream.cpp index 61054d65bc..63d83c5a4e 100644 --- a/platform/Stream.cpp +++ b/platform/Stream.cpp @@ -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); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OPEN_FAILED), "Stream obj failure", _file); } } diff --git a/platform/mbed_error.c b/platform/mbed_error.c index 37422033c0..712a1e8d25 100644 --- a/platform/mbed_error.c +++ b/platform/mbed_error.c @@ -16,14 +16,55 @@ #include #include #include "device.h" -#include "platform/mbed_toolchain.h" +#include "platform/mbed_critical.h" #include "platform/mbed_error.h" +#include "platform/mbed_error_hist.h" #include "platform/mbed_interface.h" +#ifdef MBED_CONF_RTOS_PRESENT +#include "rtx_os.h" +#endif + #if DEVICE_STDIO_MESSAGES #include #endif +//Helper macro to get the current SP +#define GET_CURRENT_SP(sp) \ + { \ + /*If in Handler mode we are always using MSP*/ \ + if( __get_IPSR() != 0U ) { \ + sp = __get_MSP(); \ + } else { \ + /*Look into CONTROL.SPSEL value*/ \ + if ((__get_CONTROL() & 2U) == 0U) { \ + sp = __get_MSP();/*Read MSP*/ \ + } else { \ + sp = __get_PSP();/*Read PSP*/ \ + } \ + } \ + } + + static uint8_t error_in_progress = 0; +static int error_count = 0; +static mbed_error_ctx first_error_ctx = {0}; +static mbed_error_ctx last_error_ctx = {0}; +static mbed_error_hook_t error_hook = NULL; +static void print_error_report(mbed_error_ctx *ctx, const char *); + +//Helper function to halt the system +static void mbed_halt_system(void) +{ + //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, ...) { @@ -37,7 +78,360 @@ WEAK void error(const char* format, ...) { va_list arg; va_start(arg, format); mbed_error_vfprintf(format, arg); + MBED_ERROR(MBED_ERROR_UNKNOWN, "Fatal Run-time Error"); va_end(arg); #endif exit(1); } + +//Set an error status with the error handling system +mbed_error_status_t handle_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) +{ + mbed_error_ctx current_error_ctx; + + //Error status should always be < 0 + if(error_status >= 0) { + //This is a weird situation, someone called mbed_error with invalid error code. + //We will still handle the situation but change the error code to ERROR_INVALID_ARGUMENT, atleast the context will have info on who called it + error_status = MBED_ERROR_INVALID_ARGUMENT; + } + + //Prevent corruption by holding out other callers + //and we also need this until we remove the "error" call completely + while (error_in_progress == 1); + + //Use critsect here, as we don't want inadvertant modification of this global variable + core_util_critical_section_enter(); + error_in_progress = 1; + core_util_critical_section_exit(); + + //Increment error count + error_count++; + + //Clear the context capturing buffer + memset(¤t_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_RTOS_PRESENT + //Capture thread info + osRtxThread_t *current_thread = osRtxInfo.thread.run.curr; + current_error_ctx.thread_id = (uint32_t)current_thread; + current_error_ctx.thread_entry_address = (uint32_t)current_thread->thread_addr; + current_error_ctx.thread_stack_size = current_thread->stack_size; + current_error_ctx.thread_stack_mem = (uint32_t)current_thread->stack_mem; +#ifdef TARGET_CORTEX_M + GET_CURRENT_SP(current_error_ctx.thread_current_sp); +#endif //TARGET_CORTEX_M + +#endif //MBED_CONF_RTOS_PRESENT + +#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED + //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 the fist system error and store it + if(error_count == 1) { //first error + memcpy(&first_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx)); + } + + //copy this error to last error + memcpy(&last_error_ctx, ¤t_error_ctx, sizeof(mbed_error_ctx)); + +#ifndef MBED_CONF_ERROR_HIST_DISABLED + //Log the error with error log + mbed_error_hist_put(¤t_error_ctx); +#endif + + //Call the error hook if available + if(error_hook != NULL) { + error_hook(&last_error_ctx); + } + + error_in_progress = 0; + + return MBED_SUCCESS; +} + +//Return the first error +mbed_error_status_t mbed_get_first_error(void) +{ + //return the first error recorded + return first_error_ctx.error_status; +} + +//Return the last error +mbed_error_status_t mbed_get_last_error(void) +{ + //return the last error recorded + return last_error_ctx.error_status; +} + +//Gets the current error count +int mbed_get_error_count(void) +{ + //return the current error count + return error_count; +} + +//Sets a fatal error +mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) +{ + return handle_error(error_status, error_msg, error_value, filename, line_number); +} + +//Sets a fatal error +WEAK mbed_error_status_t mbed_error(mbed_error_status_t 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( MBED_SUCCESS != handle_error(error_status, error_msg, error_value, filename, line_number) ) + return MBED_ERROR_FAILED_OPERATION; + + //On fatal errors print the error context/report + print_error_report(&last_error_ctx, error_msg); + mbed_halt_system(); + + return MBED_ERROR_FAILED_OPERATION; +} + +//Register an application defined callback with error handling +mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in) +{ + //register the new hook/callback + if( error_hook_in != NULL ) { + error_hook = error_hook_in; + return MBED_SUCCESS; + } + + return MBED_ERROR_INVALID_ARGUMENT; +} + +//Retrieve the first error context from error log +mbed_error_status_t mbed_get_first_error_info (mbed_error_ctx *error_info) +{ + memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx)); + return MBED_SUCCESS; +} + +//Retrieve the last error context from error log +mbed_error_status_t mbed_get_last_error_info (mbed_error_ctx *error_info) +{ + memcpy(error_info, &last_error_ctx, sizeof(mbed_error_ctx)); + return MBED_SUCCESS; +} + +//Makes an mbed_error_status_t value +mbed_error_status_t mbed_make_error(mbed_error_type_t error_type, mbed_module_type_t entity, mbed_error_code_t error_code) +{ + switch(error_type) + { + case MBED_ERROR_TYPE_POSIX: + if(error_code >= MBED_POSIX_ERROR_BASE && error_code <= MBED_SYSTEM_ERROR_BASE) + return -error_code; + break; + + case MBED_ERROR_TYPE_SYSTEM: + if(error_code >= MBED_SYSTEM_ERROR_BASE && error_code <= MBED_CUSTOM_ERROR_BASE) + return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, entity, error_code); + break; + + case MBED_ERROR_TYPE_CUSTOM: + if(error_code >= MBED_CUSTOM_ERROR_BASE) + return MAKE_MBED_ERROR(MBED_ERROR_TYPE_CUSTOM, entity, error_code); + break; + + default: + break; + } + + //If we are passed incorrect values return a generic system error + return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, MBED_MODULE_UNKNOWN, MBED_ERROR_CODE_UNKNOWN); +} + +/** + * Clears all the last error, error count and all entries in the error log. + * @return 0 or MBED_SUCCESS on success. + * + */ +mbed_error_status_t mbed_clear_all_errors(void) +{ + mbed_error_status_t status = MBED_SUCCESS; + + //Make sure we dont multiple clients resetting + core_util_critical_section_enter(); + //Clear the error and context capturing buffer + memset(&last_error_ctx, sizeof(mbed_error_ctx), 0); + //reset error count to 0 + error_count = 0; +#ifndef MBED_CONF_ERROR_HIST_DISABLED + status = mbed_error_hist_reset(); +#endif + core_util_critical_section_exit(); + + return status; +} + +#ifndef MBED_CONF_ERROR_HIST_DISABLED +//Retrieve the error context from error log at the specified index +mbed_error_status_t mbed_get_error_hist_info (int index, mbed_error_ctx *error_info) +{ + return mbed_error_hist_get(index, error_info); +} + +//Retrieve the error log count +int mbed_get_error_hist_count(void) +{ + return mbed_error_hist_get_count(); +} + +mbed_error_status_t mbed_save_error_hist(const char *path) +{ + mbed_error_status_t ret = MBED_SUCCESS; + mbed_error_ctx ctx = {0}; + int log_count = mbed_error_hist_get_count(); + FILE *error_log_file = NULL; + + //Ensure path is valid + if(path==NULL) { + ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT); + goto exit; + } + + //Open the file for saving the error log info + if((error_log_file = fopen( path, "w" ) ) == NULL){ + ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OPEN_FAILED); + goto exit; + } + + //First store the first and last errors + if(fprintf(error_log_file, "\nFirst Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n", + (unsigned int)first_error_ctx.error_status, + (unsigned int)first_error_ctx.thread_id, + (unsigned int)first_error_ctx.error_address, + (unsigned int)first_error_ctx.error_value) <= 0) { + ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED); + goto exit; + } + + if(fprintf(error_log_file, "\nLast Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n", + (unsigned int)last_error_ctx.error_status, + (unsigned int)last_error_ctx.thread_id, + (unsigned int)last_error_ctx.error_address, + (unsigned int)last_error_ctx.error_value) <= 0) { + ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED); + goto exit; + } + + //Update with error log info + while(--log_count >= 0) { + mbed_error_hist_get(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 Value:0x%x\n", + log_count, + (unsigned int)ctx.error_status, + (unsigned int)ctx.thread_id, + (unsigned int)ctx.error_address, + (unsigned int)ctx.error_value) <= 0) { + ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED); + goto exit; + } + } + +exit: + fclose(error_log_file); + + return ret; +} + +static void print_error_report(mbed_error_ctx *ctx, const char *error_msg) +{ + uint32_t error_code = MBED_GET_ERROR_CODE(ctx->error_status); + uint32_t error_module = MBED_GET_ERROR_MODULE(ctx->error_status); + + mbed_error_printf("\n\n++ MbedOS Error Info ++\nError Status: 0x%x Code: %d Entity: %d\nError Message: ", ctx->error_status, error_code, error_module); + + //Report error info based on error code, some errors require different + //error_vals[1] contains the error code + if(error_code == MBED_ERROR_CODE_HARDFAULT_EXCEPTION || + error_code == MBED_ERROR_CODE_MEMMANAGE_EXCEPTION || + error_code == MBED_ERROR_CODE_BUSFAULT_EXCEPTION || + error_code == MBED_ERROR_CODE_USAGEFAULT_EXCEPTION ) { + mbed_error_printf(error_msg); + mbed_error_printf("\nLocation: 0x%x\n", ctx->error_value); + } else { + switch (error_code) { + //These are errors reported by kernel handled from mbed_rtx_handlers + case MBED_ERROR_CODE_RTOS_EVENT: + mbed_error_printf("Kernel Error: 0x%x, ", ctx->error_value); + break; + + case MBED_ERROR_CODE_RTOS_THREAD_EVENT: + mbed_error_printf("Thread: 0x%x, ", ctx->error_value); + break; + + case MBED_ERROR_CODE_RTOS_MUTEX_EVENT: + mbed_error_printf("Mutex: 0x%x, ", ctx->error_value); + break; + + case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT: + mbed_error_printf("Semaphore: 0x%x, ", ctx->error_value); + break; + + case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT: + mbed_error_printf("MemoryPool: 0x%x, ", ctx->error_value); + break; + + case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT: + mbed_error_printf("EventFlags: 0x%x, ", ctx->error_value); + break; + + case MBED_ERROR_CODE_RTOS_TIMER_EVENT: + mbed_error_printf("Timer: 0x%x, ", ctx->error_value); + break; + + case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT: + mbed_error_printf("MessageQueue: 0x%x, ", ctx->error_value); + break; + + default: + //Nothing to do here, just print the error info down + break; + } + mbed_error_printf(error_msg, NULL); + mbed_error_printf("\nLocation: 0x%x", ctx->error_address); +#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED + if(NULL != error_ctx->error_filename) { + //for string, we must pass address of a ptr which has the address of the string + uint32_t *file_name = (uint32_t *)&error_ctx->error_filename[0]; + mbed_error_printf("\nFile:%s", &file_name); + mbed_error_printf("+0x%x", ctx->error_line_number); + } +#endif + +#ifdef TARGET_CORTEX_M + mbed_error_printf("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x SP: 0x%x ", + ctx->error_value, ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem, ctx->thread_current_sp); +#else + //For Cortex-A targets we dont have support to capture the current SP + mbed_error_printf("\nError Value: 0x%x\nCurrent Thread: Id: 0x%x Entry: 0x%x StackSize: 0x%x StackMem: 0x%x ", + ctx->error_value, ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem); +#endif //TARGET_CORTEX_M + } + + mbed_error_printf("\n-- MbedOS Error Info --"); +} + + +#endif + diff --git a/platform/mbed_error.h b/platform/mbed_error.h index 8f5cd9baff..203c89b14c 100644 --- a/platform/mbed_error.h +++ b/platform/mbed_error.h @@ -1,4 +1,3 @@ - /** \addtogroup platform */ /** @{*/ /** @@ -23,7 +22,791 @@ #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. For release builds, do not include filename to save memory. + * MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED + */ + +/** Define this macro to disable error logging, note that the first and last error capture will still be active by default. + * MBED_CONF_ERROR_HIST_DISABLED + */ + +#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_MODULE_MASK (0x00FF0000) +#define MBED_ERROR_STATUS_MODULE_POS (16) +#define MBED_ERROR_STATUS_MODULE_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) + +/* mbed_error_status_t 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) | MODULE TYPE | ERROR CODE | + +#define MAKE_MBED_ERROR(type, module, error_code) (mbed_error_status_t) \ + ((0x80000000) | \ + (MBED_ERROR_STATUS_CODE_MASK & (error_code << MBED_ERROR_STATUS_CODE_POS)) | \ + (MBED_ERROR_STATUS_MODULE_MASK & (module << MBED_ERROR_STATUS_MODULE_POS)) | \ + (MBED_ERROR_STATUS_TYPE_MASK & (type << MBED_ERROR_STATUS_TYPE_POS))) + +#define MBED_GET_ERROR_TYPE( error_status ) ((error_status & MBED_ERROR_STATUS_TYPE_MASK) >> MBED_ERROR_STATUS_TYPE_POS) +#define MBED_GET_ERROR_MODULE( error_status ) ((error_status & MBED_ERROR_STATUS_MODULE_MASK) >> MBED_ERROR_STATUS_MODULE_POS) +#define MBED_GET_ERROR_CODE( error_status ) (int)((MBED_GET_ERROR_TYPE( error_status ) == MBED_ERROR_TYPE_POSIX)?(-error_status):((error_status & MBED_ERROR_STATUS_CODE_MASK) >> MBED_ERROR_STATUS_CODE_POS)) + +/** mbed_error_status_t description + * + * mbed_error_status_t type represents the error status values under MbedOS. mbed_error_status_t values are signed integers and always be negative.\n + * Internally its encoded as below with bit-fields representing error type, module and error code:\n\n + * mbed_error_status_t 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) | MODULE 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 module 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 module type(marked with XX)\n\n + * + * The ERROR CODE(values encoded into ERROR CODE bit-field in mbed_error_status_t) 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 MODULE TYPE for Posix error codes are always encoded as MBED_MODULE_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 mbed_error_status_t; + +/** + * Macro for defining a Posix error status. This macro is mainly used to define Posix error values in mbed_error_code_t 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 MBED_DEFINE_POSIX_ERROR( error_name, error_code ) \ + MBED_ERROR_CODE_##error_name = error_code, \ + MBED_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 mbed_error_code_t 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 MBED_DEFINE_SYSTEM_ERROR( error_name, error_code ) \ + MBED_ERROR_CODE_##error_name = MBED_SYSTEM_ERROR_BASE + error_code, \ + MBED_ERROR_##error_name = MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, MBED_MODULE_UNKNOWN, MBED_ERROR_CODE_##error_name) + +/** + * Macro for defining a Custom error status. This macro is used to define custom error values in mbed_error_code_t 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 MBED_DEFINE_CUSTOM_ERROR( error_name, error_code ) \ + MBED_ERROR_CODE_##error_name = MBED_CUSTOM_ERROR_BASE + error_code, \ + MBED_ERROR_##error_name = MAKE_MBED_ERROR(MBED_ERROR_TYPE_CUSTOM, MBED_MODULE_UNKNOWN, MBED_ERROR_CODE_##error_name) + + +/** + * Macros for setting a system warning. These macros will log the error, Its a wrapper for calling mbed_warning API. + * There are 2 versions of this macro. MBED_WARNING takes status and message. MBED_WARNING1 takes an additional context specific argument + * @param error_status mbed_error_status_t status to be set(See mbed_error_status_t 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 + * + * MBED_WARNING( ERROR_INVALID_SIZE, "MyDriver: Invalid size in read" ) + * MBED_WARNING1( ERROR_INVALID_SIZE, "MyDriver: Invalid size in read", size_val ) + * + * @endcode + * @note The macro calls mbed_warning API with filename and line number info without caller explicitly passing them. + * Since this macro is a wrapper for mbed_warning API callers should process the return value from this macro which is the return value from calling mbed_error API. + * + */ +#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED + #define MBED_WARNING1( error_status, error_msg, error_value ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)error_value, (const char *)MBED_FILENAME, __LINE__ ) + #define MBED_WARNING( error_status, error_msg ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)0 , (const char *)MBED_FILENAME, __LINE__ ) +#else + #define MBED_WARNING1( error_status, error_msg, error_value ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)error_value, NULL, 0 ) + #define MBED_WARNING( error_status, error_msg ) mbed_warning( error_status, (const char *)error_msg, (uint32_t)0, NULL, 0 ) +#endif + +/** + * Macros for setting a fatal system error. These macros will log the error, prints the error report and halts the system. Its a wrapper for calling mbed_error API. + * There are 2 versions of this macro. MBED_ERROR takes status and message. MBED_ERROR1 takes an additional context specific argument + * @param error_status mbed_error_status_t status to be set(See mbed_error_status_t 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. Only available with MBED_ERROR1 + * @return 0 or MBED_SUCCESS. + * MBED_ERROR_INVALID_ARGUMENT if called with invalid error status/codes + * + * @code + * + * MBED_ERROR( MBED_ERROR_MUTEX_LOCK_FAILED, "MyDriver: Can't lock driver Mutex" ) + * MBED_ERROR1( MBED_ERROR_MUTEX_LOCK_FAILED, "MyDriver: Can't lock driver Mutex", &my_mutex ) + * + * @endcode + * @note The macro calls mbed_error API with filename and line number info without caller explicitly passing them. + * Since this macro is a wrapper for mbed_error API callers should process the return value from this macro which is the return value from calling mbed_error API. + * + */ +#ifdef MBED_CONF_ERROR_FILENAME_CAPTURE_ENABLED + #define MBED_ERROR1( error_status, error_msg, error_value ) mbed_error( error_status, (const char *)error_msg, (uint32_t)error_value, (const char *)MBED_FILENAME, __LINE__ ) + #define MBED_ERROR( error_status, error_msg ) mbed_error( error_status, (const char *)error_msg, (uint32_t)0 , (const char *)MBED_FILENAME, __LINE__ ) +#else + #define MBED_ERROR1( error_status, error_msg, error_value ) mbed_error( error_status, (const char *)error_msg, (uint32_t)error_value, NULL, 0 ) + #define MBED_ERROR( error_status, error_msg ) mbed_error( error_status, (const char *)error_msg, (uint32_t)0 , NULL, 0 ) +#endif + +//Error Type definition +/** mbed_error_type_t definition + * @note + * This enumeration defines the Error types supported. The value of these enum values will be encoded into mbed_error_status_t TYPE field.\n + * See mbed_error_status_t description for more info.\n + * MBED_ERROR_TYPE_SYSTEM - Used to indicate that the error status is of System defined Error type.\n + * MBED_ERROR_TYPE_CUSTOM - Used to indicate that the error status is of Custom defined Error type.\n + * MBED_ERROR_TYPE_POSIX - Used to indicate that the error status is of Posix error type.\n + * + */ +typedef enum _mbed_error_type_t +{ + MBED_ERROR_TYPE_SYSTEM = 0, + MBED_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 + MBED_ERROR_TYPE_POSIX = 3 +} mbed_error_type_t; + +//Module type/id definitions +/** mbed_module_type_t definition + * @note + * This enumeration defines the module types. The value of these enum values will be encoded into mbed_error_status_t MODULE field.\n\n + * See mbed_error_status_t description for more info.\n + * MBED_MODULE_UNKNOWN - This module type can be used if caller of the mbed_error/mbed_warning doesn't know who is the actual originator of the error.\n + * Other module 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 MBED_MODULE_DRIVER_I2C to provide more info.\n + * Its used in call to MBED_MAKE_ERROR/MBED_MAKE_SYSTEM_ERROR/MBED_MAKE_CUSTOM_ERROR macros.\n + * + * @code + * Example: mbed_error_status_t i2c_driver_error = MBED_MAKE_ERROR( MBED_MODULE_DRIVER_I2C, MBED_ERROR_CONFIG_UNSUPPORTED ); + * @endcode + * + * @note + * \n Below are the module code mappings:\n + \verbatim + MBED_MODULE_APPLICATION 0 Application + MBED_MODULE_PLATFORM 1 Platform + MODULE_KERNEL 2 RTX Kernel + MBED_MODULE_NETWORK_STACK 3 Network stack + MBED_MODULE_HAL 4 HAL - Hardware Abstraction Layer + MBED_MODULE_NETWORK_STACKMODULE_MEMORY_SUBSYSTEM 5 Memory Subsystem + MBED_MODULE_FILESYSTEM 6 Filesystem + MBED_MODULE_BLOCK_DEVICE 7 Block device + MBED_MODULE_DRIVER 8 Driver + MBED_MODULE_DRIVER_SERIAL 9 Serial Driver + MBED_MODULE_DRIVER_RTC 10 RTC Driver + MBED_MODULE_DRIVER_I2C 11 I2C Driver + MODULE_DRIVER_SPI 12 SPI Driver + MODULE_DRIVER_GPIO 13 GPIO Driver + MODULE_DRIVER_ANALOG 14 Analog Driver + MODULE_DRIVER_DIGITAL 15 DigitalIO Driver + MODULE_DRIVER_CAN 16 CAN Driver + MODULE_DRIVER_ETHERNET 17 Ethernet Driver + MODULE_DRIVER_CRC 18 CRC Module + MODULE_DRIVER_PWM 19 PWM Driver + MODULE_DRIVER_QSPI 20 QSPI Driver + MODULE_DRIVER_USB 21 USB Driver + MODULE_TARGET_SDK 22 SDK + + MBED_MODULE_UNKNOWN 255 Unknown module + \endverbatim + * + */ +typedef enum _mbed_module_type +{ + MBED_MODULE_APPLICATION = 0, + MBED_MODULE_PLATFORM, + MBED_MODULE_KERNEL, + MBED_MODULE_NETWORK_STACK, + MBED_MODULE_HAL, + MBED_MODULE_NETWORK_STACKMODULE_MEMORY_SUBSYSTEM, + MBED_MODULE_FILESYSTEM, + MBED_MODULE_BLOCK_DEVICE, + MBED_MODULE_DRIVER, + MBED_MODULE_DRIVER_SERIAL, + MBED_MODULE_DRIVER_RTC, + MBED_MODULE_DRIVER_I2C, + MBED_MODULE_DRIVER_SPI, + MBED_MODULE_DRIVER_GPIO, + MBED_MODULE_DRIVER_ANALOG, + MBED_MODULE_DRIVER_DIGITAL, + MBED_MODULE_DRIVER_CAN, + MBED_MODULE_DRIVER_ETHERNET, + MBED_MODULE_DRIVER_CRC, + MBED_MODULE_DRIVER_PWM, + MBED_MODULE_DRIVER_QSPI, + MBED_MODULE_DRIVER_USB, + MBED_MODULE_TARGET_SDK, + /* Add More entities here as required */ + + MBED_MODULE_UNKNOWN = 255, + MBED_MODULE_MAX = MBED_MODULE_UNKNOWN +} mbed_module_type_t; + +//Use MBED_SUCCESS(=0) or any postive number for successful returns +#define MBED_SUCCESS 0 + +#define MBED_POSIX_ERROR_BASE 0 +#define MBED_SYSTEM_ERROR_BASE 256 +#define MBED_CUSTOM_ERROR_BASE 4096 + +//Error Code definitions +/** mbed_error_code_t definition + * + * mbed_error_code_t enumeration defines the Error codes and Error status values for MBED_MODULE_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 MBED_DEFINE_POSIX_ERROR\n + * For example MBED_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 MBED_DEFINE_POSIX_ERROR\n + * For example MBED_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 MBED_DEFINE_POSIX_ERROR macro.\n\n + * Below are the Posic error codes and the description:\n + * \verbatim + EPERM 1 Operation not permitted + ENOENT 2 No such file or directory + ESRCH 3 No such process + EINTR 4 Interrupted system call + EIO 5 I/O error + ENXIO 6 No such device or address + E2BIG 7 Argument list too long + ENOEXEC 8 Exec format error + EBADF 9 Bad file number + ECHILD 10 No child processes + EAGAIN 11 Try again + ENOMEM 12 Out of memory + EACCES 13 Permission denied + EFAULT 14 Bad address + ENOTBLK 15 Block device required + EBUSY 16 Device or resource busy + EEXIST 17 File exists + EXDEV 18 Cross-device link + ENODEV 19 No such device + ENOTDIR 20 Not a directory + EISDIR 21 Is a directory + EINVAL 22 Invalid argument + ENFILE 23 File table overflow + EMFILE 24 Too many open files + ENOTTY 25 Not a typewriter + ETXTBSY 26 Text file busy + EFBIG 27 File too large + ENOSPC 28 No space left on device + ESPIPE 29 Illegal seek + EROFS 30 Read-only file system + EMLINK 31 Too many links + EPIPE 32 Broken pipe + EDOM 33 Math argument out of domain of func + ERANGE 34 Math result not representable + EDEADLK 35 Resource deadlock would occur + ENAMETOOLONG 36 File name too long + ENOLCK 37 No record locks available + ENOSYS 38 Function not implemented + ENOTEMPTY 39 Directory not empty + ELOOP 40 Too many symbolic links encountered + EWOULDBLOCK EAGAIN Operation would block + ENOMSG 42 No message of desired type + EIDRM 43 Identifier removed + ECHRNG 44 Channel number out of range + EL2NSYNC 45 Level 2 not synchronized + EL3HLT 46 Level 3 halted + EL3RST 47 Level 3 reset + ELNRNG 48 Link number out of range + EUNATCH 49 Protocol driver not attached + ENOCSI 50 No CSI structure available + EL2HLT 51 Level 2 halted + EBADE 52 Invalid exchange + EBADR 53 Invalid request descriptor + EXFULL 54 Exchange full + ENOANO 55 No anode + EBADRQC 56 Invalid request code + EBADSLT 57 Invalid slot + EDEADLOCK EDEADLK Resource deadlock would occur + EBFONT 59 Bad font file format + ENOSTR 60 Device not a stream + ENODATA 61 No data available + ETIME 62 Timer expired + ENOSR 63 Out of streams resources + ENONET 64 Machine is not on the network + ENOPKG 65 Package not installed + EREMOTE 66 Object is remote + ENOLINK 67 Link has been severed + EADV 68 Advertise error + ESRMNT 69 Srmount error + ECOMM 70 Communication error on send + EPROTO 71 Protocol error + EMULTIHOP 72 Multihop attempted + EDOTDOT 73 RFS specific error + EBADMSG 74 Not a data message + EOVERFLOW 75 Value too large for defined data type + ENOTUNIQ 76 Name not unique on network + EBADFD 77 File descriptor in bad state + EREMCHG 78 Remote address changed + ELIBACC 79 Can not access a needed shared library + ELIBBAD 80 Accessing a corrupted shared library + ELIBSCN 81 .lib section in a.out corrupted + ELIBMAX 82 Attempting to link in too many shared libraries + ELIBEXEC 83 Cannot exec a shared library directly + EILSEQ 84 Illegal byte sequence + ERESTART 85 Interrupted system call should be restarted + ESTRPIPE 86 Streams pipe error + EUSERS 87 Too many users + ENOTSOCK 88 Socket operation on non-socket + EDESTADDRREQ 89 Destination address required + EMSGSIZE 90 Message too long + EPROTOTYPE 91 Protocol wrong type for socket + ENOPROTOOPT 92 Protocol not available + EPROTONOSUPPORT 93 Protocol not supported + ESOCKTNOSUPPORT 94 Socket type not supported + EOPNOTSUPP 95 Operation not supported on transport endpoint + EPFNOSUPPORT 96 Protocol family not supported + EAFNOSUPPORT 97 Address family not supported by protocol + EADDRINUSE 98 Address already in use + EADDRNOTAVAIL 99 Cannot assign requested address + ENETDOWN 100 Network is down + ENETUNREACH 101 Network is unreachable + ENETRESET 102 Network dropped connection because of reset + ECONNABORTED 103 Software caused connection abort + ECONNRESET 104 Connection reset by peer + ENOBUFS 105 No buffer space available + EISCONN 106 Transport endpoint is already connected + ENOTCONN 107 Transport endpoint is not connected + ESHUTDOWN 108 Cannot send after transport endpoint shutdown + ETOOMANYREFS 109 Too many references: cannot splice + ETIMEDOUT 110 Connection timed out + ECONNREFUSED 111 Connection refused + EHOSTDOWN 112 Host is down + EHOSTUNREACH 113 No route to host + EALREADY 114 Operation already in progress + EINPROGRESS 115 Operation now in progress + ESTALE 116 Stale NFS file handle + EUCLEAN 117 Structure needs cleaning + ENOTNAM 118 Not a XENIX named type file + ENAVAIL 119 No XENIX semaphores available + EISNAM 120 Is a named type file + EREMOTEIO 121 Remote I/O error + EDQUOT 122 Quota exceeded + ENOMEDIUM 123 No medium found + EMEDIUMTYPE 124 Wrong medium type + ECANCELED 125 Operation Canceled + ENOKEY 126 Required key not available + EKEYEXPIRED 127 Key has expired + EKEYREVOKED 128 Key has been revoked + EKEYREJECTED 129 Key was rejected by service + EOWNERDEAD 130 Owner died + ENOTRECOVERABLE 131 State not recoverable + \endverbatim + * + * @note + * MbedOS System Error codes are defined using the macro MBED_DEFINE_SYSTEM_ERROR\n + * For example MBED_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, MBED_MODULE_UNKNOWN, ERROR_CODE_INVALID_ARGUMENT)\n + * Its effectively equivalent to:\n + * ERROR_CODE_INVALID_ARGUMENT = 1\n + * ERROR_INVALID_ARGUMENT = 0x80FF0001\n (Note that MODULE field is set to MBED_MODULE_UNKNOWN) + * New System Error codes should be defined using MBED_DEFINE_SYSTEM_ERROR macro and must have an unique error code value\n + * passed as the second argument in the MBED_DEFINE_SYSTEM_ERROR macro.\n\n + * Below are the Mbed System error codes and the description: + * \verbatim + UNKNOWN 256 Unknown error + INVALID_ARGUMENT 257 Invalid Argument + INVALID_DATA 258 Invalid data + INVALID_FORMAT 259 Invalid format + INVALID_INDEX 260 Invalid Index + INVALID_SIZE 261 Inavlid Size + INVALID_OPERATION 262 Invalid Operation + NOT_FOUND 263 Not Found + ACCESS_DENIED 264 Access Denied + NOT_SUPPORTED 265 Not supported + BUFFER_FULL 266 Buffer Full + MEDIA_FULL 267 Media/Disk Full + ALREADY_IN_USE 268 Already in use + TIMEOUT 269 Timeout error + NOT_READY 270 Not Ready + FAILED_OPERATION 271 Requested Operation failed + OPERATION_PROHIBITED 272 Operation prohibited + OPERATION_ABORTED 273 Operation failed + WRITE_PROTECTED 274 Attempt to write to write-protected resource + NO_RESPONSE 275 No response + SEMAPHORE_LOCK_FAILED 276 Sempahore lock failed + MUTEX_LOCK_FAILED 277 Mutex lock failed + SEMAPHORE_UNLOCK_FAILED 278 Sempahore unlock failed + MUTEX_UNLOCK_FAILED 279 Mutex unlock failed + CRC_ERROR 280 CRC error or mismatch + OPEN_FAILED 281 Open failed + CLOSE_FAILED 282 Close failed + READ_FAILED 283 Read failed + WRITE_FAILED 284 Write failed + INITIALIZATION_FAILED 285 Initialization failed + BOOT_FAILURE 286 Boot failure + OUT_OF_MEMORY 287 Out of memory + OUT_OF_RESOURCES 288 Out of resources + ALLOC_FAILED 289 Alloc failed + FREE_FAILED 290 Free failed + OVERFLOW 291 Overflow error + UNDERFLOW 292 Underflow error + STACK_OVERFLOW 293 Stack overflow error + ISR_QUEUE_OVERFLOW 294 ISR queue overflow + TIMER_QUEUE_OVERFLOW 295 Timer Queue overflow + CLIB_SPACE_UNAVAILABLE 296 Standard library error - Space unavailable + CLIB_EXCEPTION 297 Standard library error - Exception + CLIB_MUTEX_INIT_FAILURE 298 Standard library error - Mutex Init failure + CREATE_FAILED 299 Create failed + DELETE_FAILED 300 Delete failed + THREAD_CREATE_FAILED 301 Thread Create failed + THREAD_DELETE_FAILED 302 Thread Delete failed + PROHIBITED_IN_ISR_CONTEXT 303 Operation Prohibited in ISR context + PINMAP_INVALID 304 Pinmap Invalid + RTOS_EVENT 305 Unknown Rtos Error + RTOS_THREAD_EVENT 306 Rtos Thread Error + RTOS_MUTEX_EVENT 307 Rtos Mutex Error + RTOS_SEMAPHORE_EVENT 308 Rtos Semaphore Error + RTOS_MEMORY_POOL_EVENT 309 Rtos Memory Pool Error + RTOS_TIMER_EVENT 310 Rtos Timer Error + RTOS_EVENT_FLAGS_EVENT 311 Rtos Event flags Error + RTOS_MESSAGE_QUEUE_EVENT 312 Rtos Message queue Error + DEVICE_BUSY 313 Device Busy + CONFIG_UNSUPPORTED 314 Configuration not supported + CONFIG_MISMATCH 315 Configuration mismatch + ALREADY_INITIALIZED 316 Already initialzied + HARDFAULT_EXCEPTION 317 HardFault exception + MEMMANAGE_EXCEPTION 318 MemManage exception + BUSFAULT_EXCEPTION 319 BusFault exception + USAGEFAULT_EXCEPTION 320 UsageFault exception + \endverbatim + * + * @note + * 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, MBED_MODULE_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 MODULE field is set to MBED_MODULE_UNKNOWN) \n\n + * + * @note + * **Using error codes:** \n + * Posix error codes may be used in modules/functions currently using Posix error codes and switching them to Mbed-OS error codes + * may cause interoperability issues. For example, some of the filesystem, network stack implementations may need to use + * Posix error codes in order to keep them compatible with other modules interfacing with them, and may continue to use Posix error codes. + * + * In all other cases, like for any native development of Mbed-OS modules Mbed-OS error codes should be used. + * This makes it easy to use Mbed-OS error reporting/logging infrastructure and makes debugging error scenarios + * much more efficient. + * + * @note + * **Searching for error codes in mbed-os source tree:** \n + * If you get an error report as below which you want to search for in mbed-os source tree, first take note of "Error Code" number. \n + * For example, the below error report has an error code of \b 259. Find the error name associated with the error code and in this case its \b INVALID_FORMAT. \n + * Use that error name(\b INVALID_FORMAT) to search the source tree for code locations setting that specific error code. \n + * If the Error module reported is not 255(which indicates unknown module), you can also use that to narrow down to the specific component reporting the error. + * See mbed_module_type_t enum above for module mapping. \n + * + * \verbatim + ++ MbedOS Error Info ++ + Error Status: 0x80040103 + Error Code: 259 + Error Module: 04 + Error Message: HAL Module error + Error Location: 0x000067C7 + Error Value: 0x00005566 + Current Thread: Id: 0x200024A8 EntryFn: 0x0000FB0D StackSize: 0x00001000 StackMem: 0x200014A8 SP: 0x2002FFD8 + -- MbedOS Error Info -- + \endverbatim + */ + +typedef enum _mbed_error_code +{ + //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 + MBED_DEFINE_POSIX_ERROR( EPERM ,EPERM ), /* 1 Operation not permitted */ + MBED_DEFINE_POSIX_ERROR( ENOENT ,ENOENT ), /* 2 No such file or directory */ + MBED_DEFINE_POSIX_ERROR( ESRCH ,ESRCH ), /* 3 No such process */ + MBED_DEFINE_POSIX_ERROR( EINTR ,EINTR ), /* 4 Interrupted system call */ + MBED_DEFINE_POSIX_ERROR( EIO ,EIO ), /* 5 I/O error */ + MBED_DEFINE_POSIX_ERROR( ENXIO ,ENXIO ), /* 6 No such device or address */ + MBED_DEFINE_POSIX_ERROR( E2BIG ,E2BIG ), /* 7 Argument list too long */ + MBED_DEFINE_POSIX_ERROR( ENOEXEC ,ENOEXEC ), /* 8 Exec format error */ + MBED_DEFINE_POSIX_ERROR( EBADF ,EBADF ), /* 9 Bad file number */ + MBED_DEFINE_POSIX_ERROR( ECHILD ,ECHILD ), /* 10 No child processes */ + MBED_DEFINE_POSIX_ERROR( EAGAIN ,EAGAIN ), /* 11 Try again */ + MBED_DEFINE_POSIX_ERROR( ENOMEM ,ENOMEM ), /* 12 Out of memory */ + MBED_DEFINE_POSIX_ERROR( EACCES ,EACCES ), /* 13 Permission denied */ + MBED_DEFINE_POSIX_ERROR( EFAULT ,EFAULT ), /* 14 Bad address */ + MBED_DEFINE_POSIX_ERROR( ENOTBLK ,ENOTBLK ), /* 15 Block device required */ + MBED_DEFINE_POSIX_ERROR( EBUSY ,EBUSY ), /* 16 Device or resource busy */ + MBED_DEFINE_POSIX_ERROR( EEXIST ,EEXIST ), /* 17 File exists */ + MBED_DEFINE_POSIX_ERROR( EXDEV ,EXDEV ), /* 18 Cross-device link */ + MBED_DEFINE_POSIX_ERROR( ENODEV ,ENODEV ), /* 19 No such device */ + MBED_DEFINE_POSIX_ERROR( ENOTDIR ,ENOTDIR ), /* 20 Not a directory */ + MBED_DEFINE_POSIX_ERROR( EISDIR ,EISDIR ), /* 21 Is a directory */ + MBED_DEFINE_POSIX_ERROR( EINVAL ,EINVAL ), /* 22 Invalid argument */ + MBED_DEFINE_POSIX_ERROR( ENFILE ,ENFILE ), /* 23 File table overflow */ + MBED_DEFINE_POSIX_ERROR( EMFILE ,EMFILE ), /* 24 Too many open files */ + MBED_DEFINE_POSIX_ERROR( ENOTTY ,ENOTTY ), /* 25 Not a typewriter */ + MBED_DEFINE_POSIX_ERROR( ETXTBSY ,ETXTBSY ), /* 26 Text file busy */ + MBED_DEFINE_POSIX_ERROR( EFBIG ,EFBIG ), /* 27 File too large */ + MBED_DEFINE_POSIX_ERROR( ENOSPC ,ENOSPC ), /* 28 No space left on device */ + MBED_DEFINE_POSIX_ERROR( ESPIPE ,ESPIPE ), /* 29 Illegal seek */ + MBED_DEFINE_POSIX_ERROR( EROFS ,EROFS ), /* 30 Read-only file system */ + MBED_DEFINE_POSIX_ERROR( EMLINK ,EMLINK ), /* 31 Too many links */ + MBED_DEFINE_POSIX_ERROR( EPIPE ,EPIPE ), /* 32 Broken pipe */ + MBED_DEFINE_POSIX_ERROR( EDOM ,EDOM ), /* 33 Math argument out of domain of func */ + MBED_DEFINE_POSIX_ERROR( ERANGE ,ERANGE ), /* 34 Math result not representable */ + MBED_DEFINE_POSIX_ERROR( EDEADLK ,EDEADLK ), /* 35 Resource deadlock would occur */ + MBED_DEFINE_POSIX_ERROR( ENAMETOOLONG ,ENAMETOOLONG ), /* 36 File name too long */ + MBED_DEFINE_POSIX_ERROR( ENOLCK ,ENOLCK ), /* 37 No record locks available */ + MBED_DEFINE_POSIX_ERROR( ENOSYS ,ENOSYS ), /* 38 Function not implemented */ + MBED_DEFINE_POSIX_ERROR( ENOTEMPTY ,ENOTEMPTY ), /* 39 Directory not empty */ + MBED_DEFINE_POSIX_ERROR( ELOOP ,ELOOP ), /* 40 Too many symbolic links encountered */ + MBED_DEFINE_POSIX_ERROR( EWOULDBLOCK ,EAGAIN ), /* EAGAIN Operation would block */ + MBED_DEFINE_POSIX_ERROR( ENOMSG ,ENOMSG ), /* 42 No message of desired type */ + MBED_DEFINE_POSIX_ERROR( EIDRM ,EIDRM ), /* 43 Identifier removed */ + MBED_DEFINE_POSIX_ERROR( ECHRNG ,ECHRNG ), /* 44 Channel number out of range */ + MBED_DEFINE_POSIX_ERROR( EL2NSYNC ,EL2NSYNC ), /* 45 Level 2 not synchronized */ + MBED_DEFINE_POSIX_ERROR( EL3HLT ,EL3HLT ), /* 46 Level 3 halted */ + MBED_DEFINE_POSIX_ERROR( EL3RST ,EL3RST ), /* 47 Level 3 reset */ + MBED_DEFINE_POSIX_ERROR( ELNRNG ,ELNRNG ), /* 48 Link number out of range */ + MBED_DEFINE_POSIX_ERROR( EUNATCH ,EUNATCH ), /* 49 Protocol driver not attached */ + MBED_DEFINE_POSIX_ERROR( ENOCSI ,ENOCSI ), /* 50 No CSI structure available */ + MBED_DEFINE_POSIX_ERROR( EL2HLT ,EL2HLT ), /* 51 Level 2 halted */ + MBED_DEFINE_POSIX_ERROR( EBADE ,EBADE ), /* 52 Invalid exchange */ + MBED_DEFINE_POSIX_ERROR( EBADR ,EBADR ), /* 53 Invalid request descriptor */ + MBED_DEFINE_POSIX_ERROR( EXFULL ,EXFULL ), /* 54 Exchange full */ + MBED_DEFINE_POSIX_ERROR( ENOANO ,ENOANO ), /* 55 No anode */ + MBED_DEFINE_POSIX_ERROR( EBADRQC ,EBADRQC ), /* 56 Invalid request code */ + MBED_DEFINE_POSIX_ERROR( EBADSLT ,EBADSLT ), /* 57 Invalid slot */ + MBED_DEFINE_POSIX_ERROR( EDEADLOCK ,EDEADLK ), /* EDEADLK Resource deadlock would occur */ + MBED_DEFINE_POSIX_ERROR( EBFONT ,EBFONT ), /* 59 Bad font file format */ + MBED_DEFINE_POSIX_ERROR( ENOSTR ,ENOSTR ), /* 60 Device not a stream */ + MBED_DEFINE_POSIX_ERROR( ENODATA ,ENODATA ), /* 61 No data available */ + MBED_DEFINE_POSIX_ERROR( ETIME ,ETIME ), /* 62 Timer expired */ + MBED_DEFINE_POSIX_ERROR( ENOSR ,ENOSR ), /* 63 Out of streams resources */ + MBED_DEFINE_POSIX_ERROR( ENONET ,ENONET ), /* 64 Machine is not on the network */ + MBED_DEFINE_POSIX_ERROR( ENOPKG ,ENOPKG ), /* 65 Package not installed */ + MBED_DEFINE_POSIX_ERROR( EREMOTE ,EREMOTE ), /* 66 Object is remote */ + MBED_DEFINE_POSIX_ERROR( ENOLINK ,ENOLINK ), /* 67 Link has been severed */ + MBED_DEFINE_POSIX_ERROR( EADV ,EADV ), /* 68 Advertise error */ + MBED_DEFINE_POSIX_ERROR( ESRMNT ,ESRMNT ), /* 69 Srmount error */ + MBED_DEFINE_POSIX_ERROR( ECOMM ,ECOMM ), /* 70 Communication error on send */ + MBED_DEFINE_POSIX_ERROR( EPROTO ,EPROTO ), /* 71 Protocol error */ + MBED_DEFINE_POSIX_ERROR( EMULTIHOP ,EMULTIHOP ), /* 72 Multihop attempted */ + MBED_DEFINE_POSIX_ERROR( EDOTDOT ,EDOTDOT ), /* 73 RFS specific error */ + MBED_DEFINE_POSIX_ERROR( EBADMSG ,EBADMSG ), /* 74 Not a data message */ + MBED_DEFINE_POSIX_ERROR( EOVERFLOW ,EOVERFLOW ), /* 75 Value too large for defined data type */ + MBED_DEFINE_POSIX_ERROR( ENOTUNIQ ,ENOTUNIQ ), /* 76 Name not unique on network */ + MBED_DEFINE_POSIX_ERROR( EBADFD ,EBADFD ), /* 77 File descriptor in bad state */ + MBED_DEFINE_POSIX_ERROR( EREMCHG ,EREMCHG ), /* 78 Remote address changed */ + MBED_DEFINE_POSIX_ERROR( ELIBACC ,ELIBACC ), /* 79 Can not access a needed shared library */ + MBED_DEFINE_POSIX_ERROR( ELIBBAD ,ELIBBAD ), /* 80 Accessing a corrupted shared library */ + MBED_DEFINE_POSIX_ERROR( ELIBSCN ,ELIBSCN ), /* 81 .lib section in a.out corrupted */ + MBED_DEFINE_POSIX_ERROR( ELIBMAX ,ELIBMAX ), /* 82 Attempting to link in too many shared libraries */ + MBED_DEFINE_POSIX_ERROR( ELIBEXEC ,ELIBEXEC ), /* 83 Cannot exec a shared library directly */ + MBED_DEFINE_POSIX_ERROR( EILSEQ ,EILSEQ ), /* 84 Illegal byte sequence */ + MBED_DEFINE_POSIX_ERROR( ERESTART ,ERESTART ), /* 85 Interrupted system call should be restarted */ + MBED_DEFINE_POSIX_ERROR( ESTRPIPE ,ESTRPIPE ), /* 86 Streams pipe error */ + MBED_DEFINE_POSIX_ERROR( EUSERS ,EUSERS ), /* 87 Too many users */ + MBED_DEFINE_POSIX_ERROR( ENOTSOCK ,ENOTSOCK ), /* 88 Socket operation on non-socket */ + MBED_DEFINE_POSIX_ERROR( EDESTADDRREQ ,EDESTADDRREQ ), /* 89 Destination address required */ + MBED_DEFINE_POSIX_ERROR( EMSGSIZE ,EMSGSIZE ), /* 90 Message too long */ + MBED_DEFINE_POSIX_ERROR( EPROTOTYPE ,EPROTOTYPE ), /* 91 Protocol wrong type for socket */ + MBED_DEFINE_POSIX_ERROR( ENOPROTOOPT ,ENOPROTOOPT ), /* 92 Protocol not available */ + MBED_DEFINE_POSIX_ERROR( EPROTONOSUPPORT ,EPROTONOSUPPORT ), /* 93 Protocol not supported */ + MBED_DEFINE_POSIX_ERROR( ESOCKTNOSUPPORT ,ESOCKTNOSUPPORT ), /* 94 Socket type not supported */ + MBED_DEFINE_POSIX_ERROR( EOPNOTSUPP ,EOPNOTSUPP ), /* 95 Operation not supported on transport endpoint */ + MBED_DEFINE_POSIX_ERROR( EPFNOSUPPORT ,EPFNOSUPPORT ), /* 96 Protocol family not supported */ + MBED_DEFINE_POSIX_ERROR( EAFNOSUPPORT ,EAFNOSUPPORT ), /* 97 Address family not supported by protocol */ + MBED_DEFINE_POSIX_ERROR( EADDRINUSE ,EADDRINUSE ), /* 98 Address already in use */ + MBED_DEFINE_POSIX_ERROR( EADDRNOTAVAIL ,EADDRNOTAVAIL ), /* 99 Cannot assign requested address */ + MBED_DEFINE_POSIX_ERROR( ENETDOWN ,ENETDOWN ), /* 100 Network is down */ + MBED_DEFINE_POSIX_ERROR( ENETUNREACH ,ENETUNREACH ), /* 101 Network is unreachable */ + MBED_DEFINE_POSIX_ERROR( ENETRESET ,ENETRESET ), /* 102 Network dropped connection because of reset */ + MBED_DEFINE_POSIX_ERROR( ECONNABORTED ,ECONNABORTED ), /* 103 Software caused connection abort */ + MBED_DEFINE_POSIX_ERROR( ECONNRESET ,ECONNRESET ), /* 104 Connection reset by peer */ + MBED_DEFINE_POSIX_ERROR( ENOBUFS ,ENOBUFS ), /* 105 No buffer space available */ + MBED_DEFINE_POSIX_ERROR( EISCONN ,EISCONN ), /* 106 Transport endpoint is already connected */ + MBED_DEFINE_POSIX_ERROR( ENOTCONN ,ENOTCONN ), /* 107 Transport endpoint is not connected */ + MBED_DEFINE_POSIX_ERROR( ESHUTDOWN ,ESHUTDOWN ), /* 108 Cannot send after transport endpoint shutdown */ + MBED_DEFINE_POSIX_ERROR( ETOOMANYREFS ,ETOOMANYREFS ), /* 109 Too many references: cannot splice */ + MBED_DEFINE_POSIX_ERROR( ETIMEDOUT ,ETIMEDOUT ), /* 110 Connection timed out */ + MBED_DEFINE_POSIX_ERROR( ECONNREFUSED ,ECONNREFUSED ), /* 111 Connection refused */ + MBED_DEFINE_POSIX_ERROR( EHOSTDOWN ,EHOSTDOWN ), /* 112 Host is down */ + MBED_DEFINE_POSIX_ERROR( EHOSTUNREACH ,EHOSTUNREACH ), /* 113 No route to host */ + MBED_DEFINE_POSIX_ERROR( EALREADY ,EALREADY ), /* 114 Operation already in progress */ + MBED_DEFINE_POSIX_ERROR( EINPROGRESS ,EINPROGRESS ), /* 115 Operation now in progress */ + MBED_DEFINE_POSIX_ERROR( ESTALE ,ESTALE ), /* 116 Stale NFS file handle */ + MBED_DEFINE_POSIX_ERROR( EUCLEAN ,EUCLEAN ), /* 117 Structure needs cleaning */ + MBED_DEFINE_POSIX_ERROR( ENOTNAM ,ENOTNAM ), /* 118 Not a XENIX named type file */ + MBED_DEFINE_POSIX_ERROR( ENAVAIL ,ENAVAIL ), /* 119 No XENIX semaphores available */ + MBED_DEFINE_POSIX_ERROR( EISNAM ,EISNAM ), /* 120 Is a named type file */ + MBED_DEFINE_POSIX_ERROR( EREMOTEIO ,EREMOTEIO ), /* 121 Remote I/O error */ + MBED_DEFINE_POSIX_ERROR( EDQUOT ,EDQUOT ), /* 122 Quota exceeded */ + MBED_DEFINE_POSIX_ERROR( ENOMEDIUM ,ENOMEDIUM ), /* 123 No medium found */ + MBED_DEFINE_POSIX_ERROR( EMEDIUMTYPE ,EMEDIUMTYPE ), /* 124 Wrong medium type */ + MBED_DEFINE_POSIX_ERROR( ECANCELED ,ECANCELED ), /* 125 Operation Canceled */ + MBED_DEFINE_POSIX_ERROR( ENOKEY ,ENOKEY ), /* 126 Required key not available */ + MBED_DEFINE_POSIX_ERROR( EKEYEXPIRED ,EKEYEXPIRED ), /* 127 Key has expired */ + MBED_DEFINE_POSIX_ERROR( EKEYREVOKED ,EKEYREVOKED ), /* 128 Key has been revoked */ + MBED_DEFINE_POSIX_ERROR( EKEYREJECTED ,EKEYREJECTED ), /* 129 Key was rejected by service */ + MBED_DEFINE_POSIX_ERROR( EOWNERDEAD ,EOWNERDEAD ), /* 130 Owner died */ + MBED_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 Offset Error Code + MBED_DEFINE_SYSTEM_ERROR( UNKNOWN ,0 ), /* 256 Unknown error */ + MBED_DEFINE_SYSTEM_ERROR( INVALID_ARGUMENT ,1 ), /* 257 Invalid Argument */ + MBED_DEFINE_SYSTEM_ERROR( INVALID_DATA_DETECTED ,2 ), /* 258 Invalid data detected */ + MBED_DEFINE_SYSTEM_ERROR( INVALID_FORMAT ,3 ), /* 259 Invalid format */ + MBED_DEFINE_SYSTEM_ERROR( INVALID_INDEX ,4 ), /* 260 Invalid Index */ + MBED_DEFINE_SYSTEM_ERROR( INVALID_SIZE ,5 ), /* 261 Inavlid Size */ + MBED_DEFINE_SYSTEM_ERROR( INVALID_OPERATION ,6 ), /* 262 Invalid Operation */ + MBED_DEFINE_SYSTEM_ERROR( ITEM_NOT_FOUND ,7 ), /* 263 Item Not Found */ + MBED_DEFINE_SYSTEM_ERROR( ACCESS_DENIED ,8 ), /* 264 Access Denied */ + MBED_DEFINE_SYSTEM_ERROR( UNSUPPORTED ,9 ), /* 265 Unsupported */ + MBED_DEFINE_SYSTEM_ERROR( BUFFER_FULL ,10 ), /* 266 Buffer Full */ + MBED_DEFINE_SYSTEM_ERROR( MEDIA_FULL ,11 ), /* 267 Media/Disk Full */ + MBED_DEFINE_SYSTEM_ERROR( ALREADY_IN_USE ,12 ), /* 268 Already in use */ + MBED_DEFINE_SYSTEM_ERROR( TIME_OUT ,13 ), /* 269 Timeout error */ + MBED_DEFINE_SYSTEM_ERROR( NOT_READY ,14 ), /* 270 Not Ready */ + MBED_DEFINE_SYSTEM_ERROR( FAILED_OPERATION ,15 ), /* 271 Requested Operation failed */ + MBED_DEFINE_SYSTEM_ERROR( OPERATION_PROHIBITED ,16 ), /* 272 Operation prohibited */ + MBED_DEFINE_SYSTEM_ERROR( OPERATION_ABORTED ,17 ), /* 273 Operation failed */ + MBED_DEFINE_SYSTEM_ERROR( WRITE_PROTECTED ,18 ), /* 274 Attempt to write to write-protected resource */ + MBED_DEFINE_SYSTEM_ERROR( NO_RESPONSE ,19 ), /* 275 No response */ + MBED_DEFINE_SYSTEM_ERROR( SEMAPHORE_LOCK_FAILED ,20 ), /* 276 Sempahore lock failed */ + MBED_DEFINE_SYSTEM_ERROR( MUTEX_LOCK_FAILED ,21 ), /* 277 Mutex lock failed */ + MBED_DEFINE_SYSTEM_ERROR( SEMAPHORE_UNLOCK_FAILED ,22 ), /* 278 Sempahore unlock failed */ + MBED_DEFINE_SYSTEM_ERROR( MUTEX_UNLOCK_FAILED ,23 ), /* 279 Mutex unlock failed */ + MBED_DEFINE_SYSTEM_ERROR( CRC_ERROR ,24 ), /* 280 CRC error or mismatch */ + MBED_DEFINE_SYSTEM_ERROR( OPEN_FAILED ,25 ), /* 281 Open failed */ + MBED_DEFINE_SYSTEM_ERROR( CLOSE_FAILED ,26 ), /* 282 Close failed */ + MBED_DEFINE_SYSTEM_ERROR( READ_FAILED ,27 ), /* 283 Read failed */ + MBED_DEFINE_SYSTEM_ERROR( WRITE_FAILED ,28 ), /* 284 Write failed */ + MBED_DEFINE_SYSTEM_ERROR( INITIALIZATION_FAILED ,29 ), /* 285 Initialization failed */ + MBED_DEFINE_SYSTEM_ERROR( BOOT_FAILURE ,30 ), /* 286 Boot failure */ + MBED_DEFINE_SYSTEM_ERROR( OUT_OF_MEMORY ,31 ), /* 287 Out of memory */ + MBED_DEFINE_SYSTEM_ERROR( OUT_OF_RESOURCES ,32 ), /* 288 Out of resources */ + MBED_DEFINE_SYSTEM_ERROR( ALLOC_FAILED ,33 ), /* 289 Alloc failed */ + MBED_DEFINE_SYSTEM_ERROR( FREE_FAILED ,34 ), /* 290 Free failed */ + MBED_DEFINE_SYSTEM_ERROR( OVERFLOW ,35 ), /* 291 Overflow error */ + MBED_DEFINE_SYSTEM_ERROR( UNDERFLOW ,36 ), /* 292 Underflow error */ + MBED_DEFINE_SYSTEM_ERROR( STACK_OVERFLOW ,37 ), /* 293 Stack overflow error */ + MBED_DEFINE_SYSTEM_ERROR( ISR_QUEUE_OVERFLOW ,38 ), /* 294 ISR queue overflow */ + MBED_DEFINE_SYSTEM_ERROR( TIMER_QUEUE_OVERFLOW ,39 ), /* 295 Timer Queue overflow */ + MBED_DEFINE_SYSTEM_ERROR( CLIB_SPACE_UNAVAILABLE ,40 ), /* 296 Standard library error - Space unavailable */ + MBED_DEFINE_SYSTEM_ERROR( CLIB_EXCEPTION ,41 ), /* 297 Standard library error - Exception */ + MBED_DEFINE_SYSTEM_ERROR( CLIB_MUTEX_INIT_FAILURE ,42 ), /* 298 Standard library error - Mutex Init failure */ + MBED_DEFINE_SYSTEM_ERROR( CREATE_FAILED ,43 ), /* 299 Create failed */ + MBED_DEFINE_SYSTEM_ERROR( DELETE_FAILED ,44 ), /* 300 Delete failed */ + MBED_DEFINE_SYSTEM_ERROR( THREAD_CREATE_FAILED ,45 ), /* 301 Thread Create failed */ + MBED_DEFINE_SYSTEM_ERROR( THREAD_DELETE_FAILED ,46 ), /* 302 Thread Delete failed */ + MBED_DEFINE_SYSTEM_ERROR( PROHIBITED_IN_ISR_CONTEXT ,47 ), /* 303 Operation Prohibited in ISR context */ + MBED_DEFINE_SYSTEM_ERROR( PINMAP_INVALID ,48 ), /* 304 Pinmap Invalid */ + MBED_DEFINE_SYSTEM_ERROR( RTOS_EVENT ,49 ), /* 305 Unknown Rtos Error */ + MBED_DEFINE_SYSTEM_ERROR( RTOS_THREAD_EVENT ,50 ), /* 306 Rtos Thread Error */ + MBED_DEFINE_SYSTEM_ERROR( RTOS_MUTEX_EVENT ,51 ), /* 307 Rtos Mutex Error */ + MBED_DEFINE_SYSTEM_ERROR( RTOS_SEMAPHORE_EVENT ,52 ), /* 308 Rtos Semaphore Error */ + MBED_DEFINE_SYSTEM_ERROR( RTOS_MEMORY_POOL_EVENT ,53 ), /* 309 Rtos Memory Pool Error */ + MBED_DEFINE_SYSTEM_ERROR( RTOS_TIMER_EVENT ,54 ), /* 310 Rtos Timer Error */ + MBED_DEFINE_SYSTEM_ERROR( RTOS_EVENT_FLAGS_EVENT ,55 ), /* 311 Rtos Event flags Error */ + MBED_DEFINE_SYSTEM_ERROR( RTOS_MESSAGE_QUEUE_EVENT ,56 ), /* 312 Rtos Message queue Error */ + MBED_DEFINE_SYSTEM_ERROR( DEVICE_BUSY ,57 ), /* 313 Device Busy */ + MBED_DEFINE_SYSTEM_ERROR( CONFIG_UNSUPPORTED ,58 ), /* 314 Configuration not supported */ + MBED_DEFINE_SYSTEM_ERROR( CONFIG_MISMATCH ,59 ), /* 315 Configuration mismatch */ + MBED_DEFINE_SYSTEM_ERROR( ALREADY_INITIALIZED ,60 ), /* 316 Already initialzied */ + MBED_DEFINE_SYSTEM_ERROR( HARDFAULT_EXCEPTION ,61 ), /* 317 HardFault exception */ + MBED_DEFINE_SYSTEM_ERROR( MEMMANAGE_EXCEPTION ,62 ), /* 318 MemManage exception */ + MBED_DEFINE_SYSTEM_ERROR( BUSFAULT_EXCEPTION ,63 ), /* 319 BusFault exception */ + MBED_DEFINE_SYSTEM_ERROR( USAGEFAULT_EXCEPTION ,64 ), /* 320 UsageFault exception*/ + + //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 ), + +} mbed_error_code_t; + +/** 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 mbed_error_status_t 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 { + mbed_error_status_t 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. * @@ -66,12 +849,218 @@ * * */ - -#ifdef __cplusplus -extern "C" { -#endif + void error(const char* format, ...); +/** + * Call this Macro to generate a mbed_error_status_t value for a System error + * @param module Module generating the error code. If its unknown, pass MBED_MODULE_UNKNOWN. See mbed_module_type_t for module types. + * @param error_code The mbed_error_code_t code to be used in generating the mbed_error_status_t. See mbed_error_code_t for error codes. + * + * @code + * + * mbed_error_status_t driver_error = MBED_MAKE_SYSTEM_ERROR( MODULE_DRIVER_USB, MBED_ERROR_CODE_INITIALIZATION_FAILED ) + * + * @endcode + * @note This macro generate mbed_error_status_t-es with error type set to MBED_ERROR_TYPE_SYSTEM + * + */ +#define MBED_MAKE_SYSTEM_ERROR(module, error_code) MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, module, error_code) + +/** + * Call this Macro to generate a mbed_error_status_t value for a Custom error + * @param module Module generating the error code. If its unknown, pass MBED_MODULE_UNKNOWN. See mbed_module_type_t for module types. + * @param error_code The mbed_error_code_t code to be used in generating the mbed_error_status_t. See mbed_error_code_t for error codes. + * + * @code + * + * mbed_error_status_t custom_error = MBED_MAKE_CUSTOM_ERROR( MBED_MODULE_APPLICATION, 0xDEAD//16-bit custom error code ) + * + * @endcode + * @note This macro generate mbed_error_status_t-es with error type set to MBED_ERROR_TYPE_CUSTOM + * + */ +#define MBED_MAKE_CUSTOM_ERROR(module, error_code) MAKE_MBED_ERROR(MBED_ERROR_TYPE_CUSTOM, module, error_code) + +/** + * Call this Macro to generate a mbed_error_status_t value for a System error + * @param module Module generating the error code. If its unknown, pass MBED_MODULE_UNKNOWN. See mbed_module_type_t for module types. + * @param error_code The mbed_error_code_t code to be used in generating the mbed_error_status_t. See mbed_error_code_t for error codes. + * + * @code + * + * mbed_error_status_t new_error = MBED_MAKE_ERROR( MODULE_DRIVER_USB, MBED_ERROR_INITIALIZATION_FAILED ) + * + * @endcode + * @note This macro generate mbed_error_status_t-es with error type set to MBED_ERROR_TYPE_SYSTEM + * + */ +#define MBED_MAKE_ERROR(module, error_code) MBED_MAKE_SYSTEM_ERROR(module, error_code) + +/** + * Callback/Error hook function prototype. Applications needing a callback when an error is reported can use mbed_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 mbed_error_status_t reported and the error context at the time of error. + * @param error_status mbed_error_status_t status being reported. + * @param error_ctx Error context structure associated with this error. + * @return void + * + */ +typedef void (*mbed_error_hook_t)(const mbed_error_ctx *error_ctx); + +/** + * Call this function to set a system error/warning. This function will log the error status with the context info and return to caller. + * + * @param error_status mbed_error_status_t status to be set(See mbed_error_status_t 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 MBED_SUCCESS. + * MBED_ERROR_INVALID_ARGUMENT if called with invalid error status/codes + * + * @code + * + * mbed_error( ERROR_OUT_OF_MEMORY, "Out of memory error", 0, __FILE__, __LINE__ ) + * + * @endcode + * + * @note See MBED_WARNING/MBED_ERROR macros which provides a wrapper on this API + */ +mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number); + +/** + * Returns the first system error reported. + * @return mbed_error_status_t code logged for the first error or MBED_SUCCESS if no errors are logged. + * + */ +mbed_error_status_t mbed_get_first_error(void); + +/** + * Returns the most recent system error reported. + * @return mbed_error_status_t code logged for the last error or MBED_SUCCESS if no errors are logged. + * + */ +mbed_error_status_t mbed_get_last_error(void); + +/** + * Returns the number of system errors reported after boot. + * @return int Number of errors reported. + * + */ +int mbed_get_error_count(void); + +/** + * Call this function to set a fatal system error and halt the system. This function will log the fatal error with the context info and prints the error report and halts the system. + * + * @param error_status mbed_error_status_t status to be set(See mbed_error_status_t 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 MBED_SUCCESS. + * MBED_ERROR_INVALID_ARGUMENT if called with invalid error status/codes + * + * @code + * + * mbed_error( MBED_ERROR_PROHIBITED_OPERATION, "Prohibited operation tried", 0, __FILE__, __LINE__ ) + * + * @endcode + * + * @note See MBED_WARNING/MBED_ERROR macros which provides a wrapper on this API + */ +mbed_error_status_t mbed_error(mbed_error_status_t 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 mbed_error/mbed_warning call + * NOTE: This function should be implemented for re-entrancy as multiple threads may invoke mbed_error which may cause error hook to be called. + * @param custom_error_hook mbed_error_status_t status to be set(See mbed_error_status_t enum above for available error status values). + * @return 0 or MBED_SUCCESS on success. + * MBED_ERROR_INVALID_ARGUMENT in case of NULL for custom_error_hook + * + * @code + * + * mbed_error_status_t my_custom_error_hook(mbed_error_status_t error_status, const mbed_error_ctx *error_ctx) { + * //Do something with the error_status or error_ctx + * } + * + * mbed_set_error_hook( my_custom_error_hook ) + * + * @endcode + * @note The erro hook function implementation should be re-entrant. + * + */ +mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t custom_error_hook); + +/** + * Reads the first error context information captured. + * @param error_info This is the mbed_error_context info captured as part of the first mbed_error call. The caller should pass a pointer to mbed_error_context struct allocated by the caller. + * @return 0 or MBED_SUCCESS on success. + * MBED_ERROR_INVALID_ARGUMENT in case of invalid index + * + */ +mbed_error_status_t mbed_get_first_error_info(mbed_error_ctx *error_info); + +/** + * Reads the last error context information captured. + * @param error_info This is the mbed_error_context info captured as part of the last mbed_error call. The caller should pass a pointer to mbed_error_context struct allocated by the caller. + * @return 0 or MBED_ERROR_SUCCESS on success. + * MBED_ERROR_INVALID_ARGUMENT in case of invalid index + * + */ +mbed_error_status_t mbed_get_last_error_info(mbed_error_ctx *error_info); + +/** + * Clears the last error, first error, error count and all entries in the error history. + * @return 0 or MBED_SUCCESS on success. + * + */ +mbed_error_status_t mbed_clear_all_errors(void); + +/** + * Generates a mbed_error_status_t value based on passed in values for type, module and error code. + * @param error_type Error type based on mbed_error_type_t enum. + * @param module Module type based on mbed_module_type_t enum. + * @param error_code Error codes defined by mbed_error_code_t enum + * @return 0 or MBED_ERROR_SUCCESS on success. + * + */ +mbed_error_status_t mbed_make_error(mbed_error_type_t error_type, mbed_module_type_t module, mbed_error_code_t error_code); + +/** + * Returns the current number of entries in the error history, if there has been more than max number of errors logged the number returned will be max depth of error history. + * @return Current number of entries in the error history. + * + */ +int mbed_get_error_hist_count(void); + +/** + * Reads the error context information for a specific error from error history, specified by the index. + * + * @param index index of the error context entry in the history to be retrieved.\n + * The number of entries in the error history is configured during build and the max index depends on max depth of error history.\n + * index = 0 points to the oldest entry in the history, and index = (max history depth - 1) points to the latest entry in the error history.\n + * @param error_info This is the mbed_error_context info captured as part of the error history. The caller should pass a pointer to mbed_error_context struct allocated by the caller. + * @return 0 or MBED_SUCCESS on success. + * MBED_ERROR_INVALID_ARGUMENT in case of invalid index + * + */ +mbed_error_status_t mbed_get_error_hist_info(int index, mbed_error_ctx *error_info); + +/** + * Saves the error history information to a file + * + * @param path path to the file in the filesystem + * @return 0 or MBED_ERROR_SUCCESS on success. + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid + * + * @note Filesystem support is required in order for this function to work. + * + */ +mbed_error_status_t mbed_save_error_hist(const char *path); + #ifdef __cplusplus } #endif @@ -80,3 +1069,5 @@ void error(const char* format, ...); /** @}*/ /** @}*/ + + diff --git a/platform/mbed_error_hist.c b/platform/mbed_error_hist.c new file mode 100644 index 0000000000..3420a78553 --- /dev/null +++ b/platform/mbed_error_hist.c @@ -0,0 +1,99 @@ +/* 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 +#include +#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_HIST_DISABLED +#include "platform/mbed_error_hist.h" + +static mbed_error_ctx mbed_error_ctx_log[MBED_CONF_ERROR_HIST_SIZE] = {0}; +static int error_log_count = -1; + +mbed_error_status_t mbed_error_hist_put(mbed_error_ctx *error_ctx) +{ + //Return error if error_ctx is NULL + if(NULL == error_ctx) { + return MBED_ERROR_INVALID_ARGUMENT; + } + + core_util_critical_section_enter(); + error_log_count++; + memcpy(&mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE], error_ctx, sizeof(mbed_error_ctx) ); + core_util_critical_section_exit(); + + return MBED_SUCCESS; +} + +mbed_error_status_t mbed_error_hist_get(int index, mbed_error_ctx *error_ctx) +{ + //Return error if index is more than max log size + if(index >= MBED_CONF_ERROR_HIST_SIZE) { + return MBED_ERROR_INVALID_ARGUMENT; + } + + core_util_critical_section_enter(); + //calculate the index where we want to pick the ctx + if(error_log_count >= MBED_CONF_ERROR_HIST_SIZE) { + index = (error_log_count + index + 1) % MBED_CONF_ERROR_HIST_SIZE; + } + core_util_critical_section_exit(); + memcpy(error_ctx, &mbed_error_ctx_log[index % MBED_CONF_ERROR_HIST_SIZE], sizeof(mbed_error_ctx) ); + + return MBED_SUCCESS; +} + +mbed_error_ctx *mbed_error_hist_get_entry(void) +{ + core_util_critical_section_enter(); + error_log_count++; + mbed_error_ctx *ctx = &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE]; + core_util_critical_section_exit(); + + return ctx; +} + +mbed_error_status_t mbed_error_hist_get_last_error(mbed_error_ctx *error_ctx) +{ + if(-1 == error_log_count) { + return MBED_ERROR_ITEM_NOT_FOUND; + } + core_util_critical_section_enter(); + memcpy(error_ctx, &mbed_error_ctx_log[error_log_count % MBED_CONF_ERROR_HIST_SIZE], sizeof(mbed_error_ctx) ); + core_util_critical_section_exit(); + + return MBED_SUCCESS; +} + +int mbed_error_hist_get_count() +{ + return (error_log_count >= MBED_CONF_ERROR_HIST_SIZE? MBED_CONF_ERROR_HIST_SIZE:error_log_count+1); +} + +mbed_error_status_t mbed_error_hist_reset() +{ + core_util_critical_section_enter(); + error_log_count = -1; + core_util_critical_section_exit(); + + return MBED_SUCCESS; +} + +#endif diff --git a/platform/mbed_error_hist.h b/platform/mbed_error_hist.h new file mode 100644 index 0000000000..b4380237e4 --- /dev/null +++ b/platform/mbed_error_hist.h @@ -0,0 +1,116 @@ +/* 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_HIST_H +#define MBED_ERROR_HIST_H + +#ifndef MBED_CONF_ERROR_HIST_SIZE + #define MBED_CONF_ERROR_HIST_SIZE 4 +#else + #if MBED_CONF_ERROR_HIST_SIZE == 0 + #define MBED_CONF_ERROR_HIST_SIZE 1 + #endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif +/* + * Puts/Adds an error entry into the error history list + * + * @param error_ctx pointer to the mbed_error_ctx struct with the error context + * @return 0 or MBED_SUCCESS on success. + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid + * + * + */ +mbed_error_status_t mbed_error_hist_put(mbed_error_ctx *error_ctx); + +/* + * Reads the error entry from the error list with the specified index + * + * @param index Index of the error context to be retrieved. It starts from 0 and 0 is the oldest. + * @param error_ctx pointer to the mbed_error_ctx struct where the error context will be filled, this should be allocated by the caller + * @return 0 or MBED_SUCCESS on success. + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid + * + * + */ +mbed_error_status_t mbed_error_hist_get(int index, mbed_error_ctx *error_ctx); + +/* + * Gets a reference to the next error entry in the error log where in the error ctx can be filled in. + * Its like reserving the next error entry to fill in the error info + * + * @return Returns the pointer to the next error ctx entry + * + * + */ +mbed_error_ctx *mbed_error_hist_get_entry(void); + +/* + * Reads the last(latest) error entry from the error history + * + * @param error_ctx pointer to the mbed_error_ctx struct where the error context will be filled, this should be allocated by the caller + * @return 0 or MBED_SUCCESS on success. + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid + * + * + */ +mbed_error_status_t mbed_error_hist_get_last_error(mbed_error_ctx *error_ctx); + +/* + * Returns the number of error entries in the error history list + * + * @return Number of entries in the history list + * + * + */ +int mbed_error_hist_get_count(void); + +/* + * Resets the error log by resetting the number of errors to 0 and clears all previous errors in the history list + * + * @return 0 or MBED_SUCCESS on success. + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid + * + * + */ +mbed_error_status_t mbed_error_hist_reset(void); + +/* + * Saves the error log information to a file + * + * @param path path to the file in the filesystem + * @return 0 or MBED_SUCCESS on success. + * MBED_ERROR_WRITE_FAILED if writing to file failed + * MBED_ERROR_INVALID_ARGUMENT if path is not valid + * + * @note Filesystem support is required in order for this function to work. + * + */ +mbed_error_status_t mbed_save_error_hist(const char *path); + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/platform/mbed_retarget.cpp b/platform/mbed_retarget.cpp index bd110cff00..81cae4da56 100644 --- a/platform/mbed_retarget.cpp +++ b/platform/mbed_retarget.cpp @@ -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"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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 @@ -1387,7 +1387,7 @@ void *operator new(std::size_t count) { void *buffer = malloc_wrapper(count, MBED_CALLER_ADDR()); if (NULL == buffer) { - error("Operator new out of memory\r\n"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Operator new out of memory\r\n", count); } return buffer; } @@ -1431,7 +1431,7 @@ void *operator new(std::size_t count) { void *buffer = malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); if (NULL == buffer) { - error("Operator new out of memory\r\n"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Operator new out of memory\r\n", count); } return buffer; } @@ -1440,7 +1440,7 @@ void *operator new[](std::size_t count) { void *buffer = malloc_wrapper(_REENT, count, MBED_CALLER_ADDR()); if (NULL == buffer) { - error("Operator new[] out of memory\r\n"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Operator new out of memory\r\n", count); } return buffer; } @@ -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"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Operator new[] out of memory\r\n", count); } return buffer; } diff --git a/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.c b/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.c index f8ec70efee..89482ad908 100644 --- a/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.c +++ b/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.c @@ -15,104 +15,230 @@ */ #include "rtx_os.h" -#include "mbed_rtx.h" -#include "mbed_rtx_fault_handler.h" +#include "device.h" +#include "platform/mbed_error.h" #include "hal/serial_api.h" +#include "hal/itm_api.h" #ifndef MBED_FAULT_HANDLER_DISABLED +#include "mbed_rtx_fault_handler.h" + +#ifdef DEVICE_SERIAL +extern int stdio_uart_inited; +extern serial_t stdio_uart; +#endif + +//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); +/* Converts a uint32 to hex char string */ +static void value_to_hex_str(uint32_t value, char *hex_str) +{ + char hex_char_map[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + int i = 0; + + //Return without converting if hex_str is not provided + if(hex_str == NULL) return; + + for(i=7; i>=0; i--) { + hex_str[i] = hex_char_map[(value & (0xf << (i * 4))) >> (i * 4)]; + } +} +static void fault_print_init(void) +{ #if DEVICE_SERIAL -extern int stdio_uart_inited; -extern serial_t stdio_uart; + /* Initializes std uart if not init-ed yet */ + if (!stdio_uart_inited) { + serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX); + } +#endif + +#if DEVICE_ITM + /*Initialize ITM interfaces*/ + mbed_itm_init(); +#endif +} + +static void fault_putc(char ch) +{ +#if DEVICE_SERIAL + serial_putc(&stdio_uart, ch); +#endif + +#if DEVICE_ITM + /*Initialize ITM interfaces*/ + mbed_itm_send(ITM_PORT_SWO, ch); +#endif +} + +/* Limited print functionality which prints the string out to +stdout/uart without using stdlib by directly calling serial-api +and also uses less resources +The fmtstr contains the format string for printing and for every % +found in that it fetches a uint32 value from values buffer +and prints it in hex format. +*/ +static void fault_print(char *fmtstr, uint32_t *values) +{ +#if DEVICE_SERIAL || DEVICE_ITM + int i = 0; + int idx = 0; + int vidx = 0; + char num_str[9]={0}; + char *str=NULL; + + //Init error reporting interfaces + fault_print_init(); + + while(fmtstr[i] != '\0') { + if(fmtstr[i]=='%') { + i++; + if(fmtstr[i]=='x') { + //print the number in hex format + value_to_hex_str(values[vidx++],num_str); + for(idx=7; idx>=0; idx--) { + fault_putc(num_str[idx]); + } + } + else if(fmtstr[i]=='s') { + //print the string + str = (char *)((uint32_t)values[vidx++]); + while(*str != '\0') { + fault_putc(*str); + str++; + } + str = NULL; + } else { + //Do not handle any other % formatting and keep going + } + } else { + //handle carriage returns + if (fmtstr[i] == '\n') { + fault_putc('\r'); + } + fault_putc(fmtstr[i]); + } + i++; + } +#endif +} + +#ifdef MBED_CONF_RTOS_PRESENT +/* Prints info of a thread(using osRtxThread_t struct)*/ +static void print_thread(osRtxThread_t *thread) +{ + uint32_t data[5]; + + data[0]=thread->state; + data[1]=thread->thread_addr; + data[2]=thread->stack_size; + data[3]=(uint32_t)thread->stack_mem; + data[4]=thread->sp; + fault_print("\nState: 0x%x Entry: 0x%x Stack Size: 0x%x Mem: 0x%x SP: 0x%x", data); +} + +/* Prints thread info from a list */ +static void print_threads_info(osRtxThread_t *threads) +{ + while(threads != NULL) { + print_thread( threads ); + threads = threads->thread_next; + } +} + #endif //This is a handler function called from Fault handler to print the error information out. //This 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); + mbed_error_status_t faultStatus = MBED_SUCCESS; + + fault_print("\n++ MbedOS Fault Handler ++\n\nFaultType: ",NULL); switch( fault_type ) { case HARD_FAULT_EXCEPTION: - fault_print_str("HardFault",NULL); + fault_print("HardFault",NULL); + faultStatus = MBED_ERROR_HARDFAULT_EXCEPTION; break; case MEMMANAGE_FAULT_EXCEPTION: - fault_print_str("MemManageFault",NULL); + fault_print("MemManageFault",NULL); + faultStatus = MBED_ERROR_MEMMANAGE_EXCEPTION; break; case BUS_FAULT_EXCEPTION: - fault_print_str("BusFault",NULL); + fault_print("BusFault",NULL); + faultStatus = MBED_ERROR_BUSFAULT_EXCEPTION; break; case USAGE_FAULT_EXCEPTION: - fault_print_str("UsageFault",NULL); + fault_print("UsageFault",NULL); + faultStatus = MBED_ERROR_USAGEFAULT_EXCEPTION; break; default: - fault_print_str("Unknown Fault",NULL); + fault_print("Unknown Fault",NULL); + faultStatus = MBED_ERROR_UNKNOWN; break; } - fault_print_str("\n\nContext:",NULL); + fault_print("\n\nContext:",NULL); print_context_info(); - fault_print_str("\n\nThread Info:\nCurrent:",NULL); + fault_print("\n\nThreads Info:\nCurrent:",NULL); print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.curr); - fault_print_str("\nNext:",NULL); + fault_print("\nNext:",NULL); print_thread(((osRtxInfo_t *)osRtxInfoIn)->thread.run.next); - fault_print_str("\nWait Threads:",NULL); + fault_print("\nWait:",NULL); osRtxThread_t *threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.wait_list; print_threads_info(threads); - fault_print_str("\nDelay Threads:",NULL); + fault_print("\nDelay:",NULL); threads = ((osRtxInfo_t *)osRtxInfoIn)->thread.delay_list; print_threads_info(threads); - fault_print_str("\nIdle Thread:",NULL); + fault_print("\nIdle:",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 (;;) {} + fault_print("\n\n-- MbedOS Fault Handler --\n\n",NULL); + + //Now call mbed_error, to log the error and halt the system + mbed_error( MBED_MAKE_ERROR( MBED_MODULE_UNKNOWN, faultStatus ), "System encountered an unrecoverable fault excaption, halting system.", mbed_fault_context.PC_reg, NULL, 0 ); + + /* 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); + fault_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); + fault_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 +252,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); + fault_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); + fault_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); + fault_print("\nBFAR : %x",(uint32_t *)&SCB->BFAR); } #endif //Print Mode if(mbed_fault_context.EXC_RETURN & 0x8) { - fault_print_str("\nMode : Thread", NULL); + fault_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); + fault_print("\nPriv : User", NULL); } else { - fault_print_str("\nPriv : Privileged", NULL); + fault_print("\nPriv : Privileged", NULL); } } else { - fault_print_str("\nMode : Handler", NULL); - fault_print_str("\nPriv : Privileged", NULL); + fault_print("\nMode : Handler", NULL); + fault_print("\nPriv : Privileged", NULL); } //Print Return Stack if(mbed_fault_context.EXC_RETURN & 0x4) { - fault_print_str("\nStack: PSP", NULL); + fault_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)]; + fault_print("\nStack: MSP", NULL); } } diff --git a/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.h b/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.h index 54c85c736f..37a0514442 100644 --- a/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.h +++ b/rtos/TARGET_CORTEX/TARGET_CORTEX_M/mbed_rtx_fault_handler.h @@ -13,27 +13,30 @@ * 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. //Offset of these registers are used by fault handler in except.S typedef struct { - uint32_t R0; - uint32_t R1; - uint32_t R2; - uint32_t R3; - uint32_t R4; - uint32_t R5; - uint32_t R6; - uint32_t R7; - uint32_t R8; - uint32_t R9; - uint32_t R10; - uint32_t R11; - uint32_t R12; - uint32_t SP; - uint32_t LR; - uint32_t PC; + uint32_t R0_reg; + uint32_t R1_reg; + uint32_t R2_reg; + uint32_t R3_reg; + uint32_t R4_reg; + uint32_t R5_reg; + uint32_t R6_reg; + uint32_t R7_reg; + uint32_t R8_reg; + uint32_t R9_reg; + uint32_t R10_reg; + uint32_t R11_reg; + uint32_t R12_reg; + uint32_t SP_reg; + uint32_t LR_reg; + uint32_t PC_reg; uint32_t xPSR; uint32_t PSP; uint32_t MSP; @@ -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 diff --git a/rtos/TARGET_CORTEX/mbed_boot.c b/rtos/TARGET_CORTEX/mbed_boot.c index 4198b53225..cb4f1b4e35 100644 --- a/rtos/TARGET_CORTEX/mbed_boot.c +++ b/rtos/TARGET_CORTEX/mbed_boot.c @@ -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"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INITIALIZATION_FAILED), "Pre main thread not created", &_main_thread_attr); } osKernelStart(); diff --git a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c index ebbd3979e3..223874e4e5 100644 --- a/rtos/TARGET_CORTEX/mbed_rtx_handlers.c +++ b/rtos/TARGET_CORTEX/mbed_rtx_handlers.c @@ -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)); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_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); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_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); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_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); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_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); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_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 + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_KERNEL, MBED_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)); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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)); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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)); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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)); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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)); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_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); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT), error_msg(status), mq_id); } #endif diff --git a/rtos/Thread.cpp b/rtos/Thread.cpp index f43d39e3ec..cc8fcda1bf 100644 --- a/rtos/Thread.cpp +++ b/rtos/Thread.cpp @@ -78,13 +78,13 @@ void Thread::constructor(Callback task, switch (start(task)) { case osErrorResource: - error("OS ran out of threads!\n"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_RESOURCES), "OS ran out of threads!\n", task); break; case osErrorParameter: - error("Thread already running!\n"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_ALREADY_IN_USE), "Thread already running!\n", task); break; case osErrorNoMemory: - error("Error allocating the stack memory\n"); + MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OUT_OF_MEMORY), "Error allocating the stack memory\n", task); default: break; }