-
Notifications
You must be signed in to change notification settings - Fork 0
A C header file with commonly-used debug macros
License
hkchai/c_common
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
This is a collection of macros for zone-based printing of debug messages, targetting console applications. PROBLEM STATEMENT: During software development, it is often desirable to control the amount of messages generated. The put-and-forget solution: putting in debug statements and if necessary, removing them later. As shown in the following 'put_and_forget' function. The disadvantage of this method is waste of resources. Chance is high that we may need the debug aids later and the process of adding/removing the statements is error-prone and inefficient. On the other hand it is usual not desirable to see so many debug messages during normal operation of the software. Therefore this solution is not practical. #define MEM_SIZE (1024) int put_and_forget() { printf("Entering %s\n", __func__); do_board_setup(); printf("Before dma setup\n"); do_dma_setup(); printf("After dma setup\n"); memBlock = (char *) malloc(MEM_SIZE); if(memBlock == NULL) { printf("Cannot allocate memory!\n"); return -1; } return 0; }/* put_and_forget */ With DBG switch: By adding the #ifdef DBG preprocessor guards, the debug statements could be enabled and disabled at the flip of the switch. This is a vast improvement over the previous solution because we can decide when we want to debug statements. However this approach still has its downsides. First, We still don't have a fine control on exactly which messages we want to see, and the display tends to be garbled up by unwanted messages from other modules. Besides that, the function will be cluttered with a lot of #if...#endif's which make the code very messy. Obviously a better approach is needed. #define DBG // Comment out when not in use #define MEM_SIZE (1024) int with_debug_statement() { char *memBlock = NULL; #ifdef DBG printf("Entering %s\n", __func__); #endif do_board_setup(); #ifdef DBG printf("Before dma setup\n"); #endif do_dma_setup(); #ifdef DBG printf("After dma setup\n"); #endif memBlock = (char *) malloc(MEM_SIZE); if(memBlock == NULL) { #ifdef DBG printf("Cannot allocate memory!\n"); #endif return -1; } return 0; }/* with_debug_statement */ MY SOLUTION: Zone-based control: Due to the constraint of the solution based on DBG switch, we figured it is necessary to have a fine-grained control on what messages will be shown. To start off, we declare a static unsigned integer as a variable to control the verbosity of the debug messages on a per-file basis. Next, we classify messages into different categories, each represented by a bit of the unsigned integer. Examples of the categories include: fatal (e.g. cannot allocate memory), important (e.g. ethernet interface is up), warning (e.g. configuration not found), and user-defined zones (e.g. debug_zone_1 for all calculations on the SNR), etc. For the complete list, please refer to the header file directly. In other words, we have a very fine-grained control of the set of messages we want to print simply by flipping the corresponding bits. The following example may help to clarify things. // // For reading convenience I have reproduced the macro definitions below. In actual // use, the user only needs to include "common.h" // #define VPRINT(level, F, args...)\ do{\ if(level & global_verbose_level)\ {\ printf("\n\r%s: " F, __func__, ##args);\ }\ }while(0) #define V_MAX (1<<31) #define V_ENTER_EXIT (1<<30) // // Unused bits for future development // #define V_DEBUG_3 (1<<14) #define V_DEBUG_2 (1<<13) #define V_DEBUG_1 (1<<12) #define V_DEBUG (1<<11) #define V_INFO (1<<10) #define V_WARNING (1<<8) #define V_ERROR (1<<6) #define V_IMPORTANT (1<<5) #define V_FATAL (1<<4) #define V_CRITICAL (1<<2) #define V_SILENT (1<<1) #define V_MIN (0) // // We declare this variable static so that its scope is only limited to this file // V_IMPORTANT_S is a shorthand for (V_IMPORTANT | V_FATAL | V_CRITICAL) // static unsigned int global_verbose_level = V_IMPORTANT_S; #define MEM_SIZE (1024) int zone_based() { VPRINT(V_INFO, "Entering %s\n", __func__); do_board_setup(); VPRINT(V_DEBUG_1, "Before dma setup\n"); do_dma_setup(); VPRINT(V_DEBUG_1, "After dma setup\n"); memBlock = (char *) malloc(MEM_SIZE); if(memBlock != NULL); { /* V_FATAL will still show up because it is included by V_IMPORTANT_S */ VPRINT(V_FATAL, "Cannot allocate memory\n"); return -1; } return 0; }/* zone_based */
About
A C header file with commonly-used debug macros
Resources
License
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published