takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_error.c Source File

mbed_error.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include <stdlib.h>
00017 #include <stdarg.h>
00018 #include <string.h>
00019 #include "device.h"
00020 #include "platform/mbed_critical.h"
00021 #include "platform/mbed_error.h"
00022 #include "platform/mbed_error_hist.h"
00023 #include "platform/mbed_interface.h"
00024 #ifdef MBED_CONF_RTOS_PRESENT
00025 #include "rtx_os.h"
00026 #endif
00027 
00028 #if DEVICE_STDIO_MESSAGES
00029 #include <stdio.h>
00030 #endif
00031 
00032 //Helper macro to get the current SP
00033 #define GET_CURRENT_SP(sp)                                                          \
00034                         {                                                           \
00035                             /*If in Handler mode we are always using MSP*/          \
00036                             if ( __get_IPSR() != 0U ) {                             \
00037                                 sp = __get_MSP();                                   \
00038                             } else {                                                \
00039                                 /*Look into CONTROL.SPSEL value*/                   \
00040                                 if ((__get_CONTROL() & 2U) == 0U) {                 \
00041                                     sp = __get_MSP();/*Read MSP*/                   \
00042                                 } else {                                            \
00043                                     sp = __get_PSP();/*Read PSP*/                   \
00044                                 }                                                   \
00045                             }                                                       \
00046                         }
00047 
00048 #ifndef NDEBUG
00049 #define ERROR_REPORT(ctx, error_msg) print_error_report(ctx, error_msg)
00050 #else
00051 #define ERROR_REPORT(ctx, error_msg) ((void) 0)
00052 #endif
00053 
00054 static uint8_t error_in_progress = 0;
00055 static int error_count = 0;
00056 static mbed_error_ctx first_error_ctx = {0};
00057 static mbed_error_ctx last_error_ctx = {0};
00058 static mbed_error_hook_t error_hook = NULL;
00059 static void print_error_report(mbed_error_ctx *ctx, const char *);
00060 static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number, void *caller);
00061 
00062 //Helper function to halt the system
00063 static void mbed_halt_system(void)
00064 {
00065     //If not in ISR context exit, otherwise spin on WFI
00066     if (core_util_is_isr_active() || !core_util_are_interrupts_enabled()) {
00067         for (;;) {
00068             __WFI();
00069         }
00070     } else {
00071         //exit eventually calls mbed_die
00072         exit(1);
00073     }
00074 }
00075 
00076 WEAK void error(const char *format, ...)
00077 {
00078 
00079     // Prevent recursion if error is called again
00080     if (error_in_progress) {
00081         return;
00082     }
00083 
00084     //Call handle_error/print_error_report permanently setting error_in_progress flag
00085     handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR());
00086     ERROR_REPORT(&last_error_ctx, "Fatal Run-time error");
00087     error_in_progress = 1;
00088 
00089 #ifndef NDEBUG
00090     va_list arg;
00091     va_start(arg, format);
00092     mbed_error_vfprintf(format, arg);
00093     va_end(arg);
00094 #endif
00095     exit(1);
00096 }
00097 
00098 //Set an error status with the error handling system
00099 static mbed_error_status_t handle_error(mbed_error_status_t error_status, unsigned int error_value, const char *filename, int line_number, void *caller)
00100 {
00101     mbed_error_ctx current_error_ctx;
00102 
00103     //Error status should always be < 0
00104     if (error_status >= 0) {
00105         //This is a weird situation, someone called mbed_error with invalid error code.
00106         //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
00107         error_status = MBED_ERROR_INVALID_ARGUMENT;
00108     }
00109 
00110     //Prevent corruption by holding out other callers
00111     //and we also need this until we remove the "error" call completely
00112     while (error_in_progress == 1);
00113 
00114     //Use critsect here, as we don't want inadvertant modification of this global variable
00115     core_util_critical_section_enter();
00116     error_in_progress = 1;
00117     core_util_critical_section_exit();
00118 
00119     //Increment error count
00120     error_count++;
00121 
00122     //Clear the context capturing buffer
00123     memset(&current_error_ctx, 0, sizeof(mbed_error_ctx));
00124     //Capture error information
00125     current_error_ctx.error_status = error_status;
00126     current_error_ctx.error_address = (uint32_t)caller;
00127     current_error_ctx.error_value = error_value;
00128 #ifdef MBED_CONF_RTOS_PRESENT
00129     //Capture thread info
00130     osRtxThread_t *current_thread = osRtxInfo.thread.run.curr;
00131     current_error_ctx.thread_id = (uint32_t)current_thread;
00132     current_error_ctx.thread_entry_address = (uint32_t)current_thread->thread_addr;
00133     current_error_ctx.thread_stack_size = current_thread->stack_size;
00134     current_error_ctx.thread_stack_mem = (uint32_t)current_thread->stack_mem;
00135 #ifdef TARGET_CORTEX_M
00136     GET_CURRENT_SP(current_error_ctx.thread_current_sp);
00137 #endif //TARGET_CORTEX_M
00138 
00139 #endif //MBED_CONF_RTOS_PRESENT
00140 
00141 #if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED
00142     //Capture filename/linenumber if provided
00143     //Index for tracking error_filename
00144     memset(&current_error_ctx.error_filename, 0, MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN);
00145     strncpy(current_error_ctx.error_filename, filename, MBED_CONF_PLATFORM_MAX_ERROR_FILENAME_LEN);
00146     current_error_ctx.error_line_number = line_number;
00147 #endif
00148 
00149     //Capture the fist system error and store it
00150     if (error_count == 1) { //first error
00151         memcpy(&first_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx));
00152     }
00153 
00154     //copy this error to last error
00155     memcpy(&last_error_ctx, &current_error_ctx, sizeof(mbed_error_ctx));
00156 
00157 #if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
00158     //Log the error with error log
00159     mbed_error_hist_put(&current_error_ctx);
00160 #endif
00161 
00162     //Call the error hook if available
00163     if (error_hook != NULL) {
00164         error_hook(&last_error_ctx);
00165     }
00166 
00167     error_in_progress = 0;
00168 
00169     return MBED_SUCCESS;
00170 }
00171 
00172 //Return the first error
00173 mbed_error_status_t mbed_get_first_error(void)
00174 {
00175     //return the first error recorded
00176     return first_error_ctx.error_status;
00177 }
00178 
00179 //Return the last error
00180 mbed_error_status_t mbed_get_last_error(void)
00181 {
00182     //return the last error recorded
00183     return last_error_ctx.error_status;
00184 }
00185 
00186 //Gets the current error count
00187 int mbed_get_error_count(void)
00188 {
00189     //return the current error count
00190     return error_count;
00191 }
00192 
00193 //Sets a fatal error
00194 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)
00195 {
00196     return handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR());
00197 }
00198 
00199 //Sets a fatal error, this function is marked WEAK to be able to override this for some tests
00200 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)
00201 {
00202     //set the error reported and then halt the system
00203     if (MBED_SUCCESS != handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR())) {
00204         return MBED_ERROR_FAILED_OPERATION;
00205     }
00206 
00207     //On fatal errors print the error context/report
00208     ERROR_REPORT(&last_error_ctx, error_msg);
00209     mbed_halt_system();
00210 
00211     return MBED_ERROR_FAILED_OPERATION;
00212 }
00213 
00214 //Register an application defined callback with error handling
00215 mbed_error_status_t mbed_set_error_hook(mbed_error_hook_t error_hook_in)
00216 {
00217     //register the new hook/callback
00218     if (error_hook_in != NULL)  {
00219         error_hook = error_hook_in;
00220         return MBED_SUCCESS;
00221     }
00222 
00223     return MBED_ERROR_INVALID_ARGUMENT;
00224 }
00225 
00226 //Retrieve the first error context from error log
00227 mbed_error_status_t mbed_get_first_error_info(mbed_error_ctx *error_info)
00228 {
00229     memcpy(error_info, &first_error_ctx, sizeof(first_error_ctx));
00230     return MBED_SUCCESS;
00231 }
00232 
00233 //Retrieve the last error context from error log
00234 mbed_error_status_t mbed_get_last_error_info(mbed_error_ctx *error_info)
00235 {
00236     memcpy(error_info, &last_error_ctx, sizeof(mbed_error_ctx));
00237     return MBED_SUCCESS;
00238 }
00239 
00240 //Makes an mbed_error_status_t value
00241 mbed_error_status_t mbed_make_error(mbed_error_type_t error_type, mbed_module_type_t entity, mbed_error_code_t error_code)
00242 {
00243     switch (error_type) {
00244         case MBED_ERROR_TYPE_POSIX:
00245             if (error_code >= MBED_POSIX_ERROR_BASE && error_code <= MBED_SYSTEM_ERROR_BASE) {
00246                 return -error_code;
00247             }
00248             break;
00249 
00250         case MBED_ERROR_TYPE_SYSTEM:
00251             if (error_code >= MBED_SYSTEM_ERROR_BASE && error_code <= MBED_CUSTOM_ERROR_BASE) {
00252                 return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, entity, error_code);
00253             }
00254             break;
00255 
00256         case MBED_ERROR_TYPE_CUSTOM:
00257             if (error_code >= MBED_CUSTOM_ERROR_BASE) {
00258                 return MAKE_MBED_ERROR(MBED_ERROR_TYPE_CUSTOM, entity, error_code);
00259             }
00260             break;
00261 
00262         default:
00263             break;
00264     }
00265 
00266     //If we are passed incorrect values return a generic system error
00267     return MAKE_MBED_ERROR(MBED_ERROR_TYPE_SYSTEM, MBED_MODULE_UNKNOWN, MBED_ERROR_CODE_UNKNOWN);
00268 }
00269 
00270 /**
00271  * Clears all the last error, error count and all entries in the error log.
00272  * @return                      0 or MBED_SUCCESS on success.
00273  *
00274  */
00275 mbed_error_status_t mbed_clear_all_errors(void)
00276 {
00277     mbed_error_status_t status = MBED_SUCCESS;
00278 
00279     //Make sure we dont multiple clients resetting
00280     core_util_critical_section_enter();
00281     //Clear the error and context capturing buffer
00282     memset(&last_error_ctx, 0, sizeof(mbed_error_ctx));
00283     //reset error count to 0
00284     error_count = 0;
00285 #if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
00286     status = mbed_error_hist_reset();
00287 #endif
00288     core_util_critical_section_exit();
00289 
00290     return status;
00291 }
00292 
00293 #if MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO && defined(MBED_CONF_RTOS_PRESENT)
00294 /* Prints info of a thread(using osRtxThread_t struct)*/
00295 static void print_thread(osRtxThread_t *thread)
00296 {
00297     mbed_error_printf("\nState: 0x%08X Entry: 0x%08X Stack Size: 0x%08X Mem: 0x%08X SP: 0x%08X", thread->state, thread->thread_addr, thread->stack_size, (uint32_t)thread->stack_mem, thread->sp);
00298 }
00299 
00300 /* Prints thread info from a list */
00301 static void print_threads_info(osRtxThread_t *threads)
00302 {
00303     while (threads != NULL) {
00304         print_thread(threads);
00305         threads = threads->thread_next;
00306     }
00307 }
00308 #endif
00309 
00310 #ifndef NDEBUG
00311 static void print_error_report(mbed_error_ctx *ctx, const char *error_msg)
00312 {
00313     uint32_t error_code = MBED_GET_ERROR_CODE(ctx->error_status);
00314     uint32_t error_module = MBED_GET_ERROR_MODULE(ctx->error_status);
00315 
00316     mbed_error_printf("\n\n++ MbedOS Error Info ++\nError Status: 0x%X Code: %d Module: %d\nError Message: ", ctx->error_status, error_code, error_module);
00317 
00318     switch (error_code) {
00319         //These are errors reported by kernel handled from mbed_rtx_handlers
00320         case MBED_ERROR_CODE_RTOS_EVENT:
00321             mbed_error_printf("Kernel Error: 0x%X, ", ctx->error_value);
00322             break;
00323 
00324         case MBED_ERROR_CODE_RTOS_THREAD_EVENT:
00325             mbed_error_printf("Thread: 0x%X, ", ctx->error_value);
00326             break;
00327 
00328         case MBED_ERROR_CODE_RTOS_MUTEX_EVENT:
00329             mbed_error_printf("Mutex: 0x%X, ", ctx->error_value);
00330             break;
00331 
00332         case MBED_ERROR_CODE_RTOS_SEMAPHORE_EVENT:
00333             mbed_error_printf("Semaphore: 0x%X, ", ctx->error_value);
00334             break;
00335 
00336         case MBED_ERROR_CODE_RTOS_MEMORY_POOL_EVENT:
00337             mbed_error_printf("MemoryPool: 0x%X, ", ctx->error_value);
00338             break;
00339 
00340         case MBED_ERROR_CODE_RTOS_EVENT_FLAGS_EVENT:
00341             mbed_error_printf("EventFlags: 0x%X, ", ctx->error_value);
00342             break;
00343 
00344         case MBED_ERROR_CODE_RTOS_TIMER_EVENT:
00345             mbed_error_printf("Timer: 0x%X, ", ctx->error_value);
00346             break;
00347 
00348         case MBED_ERROR_CODE_RTOS_MESSAGE_QUEUE_EVENT:
00349             mbed_error_printf("MessageQueue: 0x%X, ", ctx->error_value);
00350             break;
00351 
00352         default:
00353             //Nothing to do here, just print the error info down
00354             break;
00355     }
00356     mbed_error_printf(error_msg);
00357     mbed_error_printf("\nLocation: 0x%X", ctx->error_address);
00358 
00359 #if MBED_CONF_PLATFORM_ERROR_FILENAME_CAPTURE_ENABLED && !defined(NDEBUG)
00360     if ((NULL != ctx->error_filename[0]) && (ctx->error_line_number != 0)) {
00361         //for string, we must pass address of a ptr which has the address of the string
00362         mbed_error_printf("\nFile:%s+%d", ctx->error_filename, ctx->error_line_number);
00363     }
00364 #endif
00365 
00366     mbed_error_printf("\nError Value: 0x%X", ctx->error_value);
00367 #ifdef TARGET_CORTEX_M
00368     mbed_error_printf("\nCurrent Thread: Id: 0x%X Entry: 0x%X StackSize: 0x%X StackMem: 0x%X SP: 0x%X ",
00369                       ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem, ctx->thread_current_sp);
00370 #else
00371     //For Cortex-A targets we dont have support to capture the current SP
00372     mbed_error_printf("\nCurrent Thread: Id: 0x%X Entry: 0x%X StackSize: 0x%X StackMem: 0x%X ",
00373                       ctx->thread_id, ctx->thread_entry_address, ctx->thread_stack_size, ctx->thread_stack_mem);
00374 #endif //TARGET_CORTEX_M
00375 
00376 #if MBED_CONF_PLATFORM_ERROR_ALL_THREADS_INFO && defined(MBED_CONF_RTOS_PRESENT)
00377     mbed_error_printf("\nNext:");
00378     print_thread(osRtxInfo.thread.run.next);
00379 
00380     mbed_error_printf("\nWait:");
00381     osRtxThread_t *threads = (osRtxThread_t *)&osRtxInfo.thread.wait_list;
00382     print_threads_info(threads);
00383 
00384     mbed_error_printf("\nDelay:");
00385     threads = (osRtxThread_t *)&osRtxInfo.thread.delay_list;
00386     print_threads_info(threads);
00387 
00388     mbed_error_printf("\nIdle:");
00389     threads = (osRtxThread_t *)&osRtxInfo.thread.idle;
00390     print_threads_info(threads);
00391 #endif
00392     mbed_error_printf(MBED_CONF_PLATFORM_ERROR_DECODE_HTTP_URL_STR, ctx->error_status);
00393     mbed_error_printf("\n-- MbedOS Error Info --\n");
00394 }
00395 #endif //ifndef NDEBUG
00396 
00397 #if MBED_CONF_PLATFORM_ERROR_HIST_ENABLED
00398 //Retrieve the error context from error log at the specified index
00399 mbed_error_status_t mbed_get_error_hist_info(int index, mbed_error_ctx *error_info)
00400 {
00401     return mbed_error_hist_get(index, error_info);
00402 }
00403 
00404 //Retrieve the error log count
00405 int mbed_get_error_hist_count(void)
00406 {
00407     return mbed_error_hist_get_count();
00408 }
00409 
00410 mbed_error_status_t mbed_save_error_hist(const char *path)
00411 {
00412     mbed_error_status_t ret = MBED_SUCCESS;
00413     mbed_error_ctx ctx = {0};
00414     int log_count = mbed_error_hist_get_count();
00415     FILE *error_log_file = NULL;
00416 
00417     //Ensure path is valid
00418     if (path == NULL) {
00419         ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_INVALID_ARGUMENT);
00420         goto exit;
00421     }
00422 
00423     //Open the file for saving the error log info
00424     if ((error_log_file = fopen(path, "w")) == NULL) {
00425         ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_OPEN_FAILED);
00426         goto exit;
00427     }
00428 
00429     //First store the first and last errors
00430     if (fprintf(error_log_file, "\nFirst Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
00431                 (unsigned int)first_error_ctx.error_status,
00432                 (unsigned int)first_error_ctx.thread_id,
00433                 (unsigned int)first_error_ctx.error_address,
00434                 (unsigned int)first_error_ctx.error_value) <= 0) {
00435         ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED);
00436         goto exit;
00437     }
00438 
00439     if (fprintf(error_log_file, "\nLast Error: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
00440                 (unsigned int)last_error_ctx.error_status,
00441                 (unsigned int)last_error_ctx.thread_id,
00442                 (unsigned int)last_error_ctx.error_address,
00443                 (unsigned int)last_error_ctx.error_value) <= 0) {
00444         ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED);
00445         goto exit;
00446     }
00447 
00448     //Update with error log info
00449     while (--log_count >= 0) {
00450         mbed_error_hist_get(log_count, &ctx);
00451         //first line of file will be error log count
00452         if (fprintf(error_log_file, "\n%d: Status:0x%x ThreadId:0x%x Address:0x%x Value:0x%x\n",
00453                     log_count,
00454                     (unsigned int)ctx.error_status,
00455                     (unsigned int)ctx.thread_id,
00456                     (unsigned int)ctx.error_address,
00457                     (unsigned int)ctx.error_value) <= 0) {
00458             ret = MBED_MAKE_ERROR(MBED_MODULE_PLATFORM, MBED_ERROR_CODE_WRITE_FAILED);
00459             goto exit;
00460         }
00461     }
00462 
00463 exit:
00464     fclose(error_log_file);
00465 
00466     return ret;
00467 }
00468 #endif
00469