Basic debug library
Dependents: modem_ref_helper_for_v5_3_217 modem_ref_helper
WizziDebug.cpp@9:87d9cc850af1, 2019-08-01 (annotated)
- Committer:
- Jeej
- Date:
- Thu Aug 01 08:32:35 2019 +0000
- Revision:
- 9:87d9cc850af1
- Parent:
- 8:87a867b8a129
- Child:
- 10:0e6e54fb08c0
Updated for mbed-os 5.13
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Jeej | 0:1d3ed1850649 | 1 | #include "mbed.h" |
Jeej | 0:1d3ed1850649 | 2 | #include "rtos.h" |
Jeej | 0:1d3ed1850649 | 3 | #include "WizziDebug.h" |
Jeej | 0:1d3ed1850649 | 4 | #include "CBuffer.h" |
Jeej | 0:1d3ed1850649 | 5 | #include <stdio.h> |
Jeej | 0:1d3ed1850649 | 6 | #include <string.h> |
Jeej | 0:1d3ed1850649 | 7 | #include <stdarg.h> |
Jeej | 0:1d3ed1850649 | 8 | |
Jeej | 5:63ef3a21e932 | 9 | #define DBG_MAX_STRING_SIZE (512) |
Jeej | 0:1d3ed1850649 | 10 | |
Jeej | 0:1d3ed1850649 | 11 | static CBuffer<uint8_t, 2048> g_dbg_buf; |
Jeej | 0:1d3ed1850649 | 12 | static char g_dbg_msg[DBG_MAX_STRING_SIZE]; |
Jeej | 9:87d9cc850af1 | 13 | static Thread g_dbg_thread(osPriorityLow, 512); |
Jeej | 0:1d3ed1850649 | 14 | static RawSerial* g_dbg_serial; |
Jeej | 0:1d3ed1850649 | 15 | static Mutex g_dbg_ressource; |
Jeej | 0:1d3ed1850649 | 16 | static Semaphore g_dbg_print(0); |
Jeej | 0:1d3ed1850649 | 17 | static uint32_t g_dbg_nb_mallocs; |
Jeej | 6:70e985e34364 | 18 | static PinName __attribute__((unused)) g_dbg_led; |
Jeej | 0:1d3ed1850649 | 19 | static uint32_t g_dbg_missing; |
Jeej | 7:8e75991f65e5 | 20 | static void (*g_dbg_rx_callback)(char c) = NULL; |
Jeej | 0:1d3ed1850649 | 21 | |
Jeej | 0:1d3ed1850649 | 22 | void dbg_print_thread(); |
Jeej | 0:1d3ed1850649 | 23 | |
Jeej | 7:8e75991f65e5 | 24 | static void dbg_serial_rx_isr(void) |
Jeej | 7:8e75991f65e5 | 25 | { |
Jeej | 7:8e75991f65e5 | 26 | if (!g_dbg_rx_callback) |
Jeej | 7:8e75991f65e5 | 27 | { |
Jeej | 7:8e75991f65e5 | 28 | PRINT("%c", g_dbg_serial->getc()); |
Jeej | 7:8e75991f65e5 | 29 | return; |
Jeej | 7:8e75991f65e5 | 30 | } |
Jeej | 7:8e75991f65e5 | 31 | |
Jeej | 7:8e75991f65e5 | 32 | // Loop just in case more than one character is in UART's receive FIFO buffer |
Jeej | 7:8e75991f65e5 | 33 | while (g_dbg_serial->readable()) |
Jeej | 7:8e75991f65e5 | 34 | { |
Jeej | 7:8e75991f65e5 | 35 | g_dbg_rx_callback(g_dbg_serial->getc()); |
Jeej | 7:8e75991f65e5 | 36 | } |
Jeej | 7:8e75991f65e5 | 37 | } |
Jeej | 7:8e75991f65e5 | 38 | |
Jeej | 0:1d3ed1850649 | 39 | // Redefine mbed error function |
Jeej | 0:1d3ed1850649 | 40 | void error(const char* format, ...) |
Jeej | 0:1d3ed1850649 | 41 | { |
Jeej | 0:1d3ed1850649 | 42 | char buf[DBG_MAX_STRING_SIZE]; |
Jeej | 0:1d3ed1850649 | 43 | |
Jeej | 0:1d3ed1850649 | 44 | va_list args; |
Jeej | 0:1d3ed1850649 | 45 | va_start(args, format); |
Jeej | 0:1d3ed1850649 | 46 | vsprintf(buf, format, args); |
Jeej | 0:1d3ed1850649 | 47 | va_end(args); |
Jeej | 0:1d3ed1850649 | 48 | |
Jeej | 0:1d3ed1850649 | 49 | ASSERT(false, buf); |
Jeej | 0:1d3ed1850649 | 50 | } |
Jeej | 0:1d3ed1850649 | 51 | |
Jeej | 0:1d3ed1850649 | 52 | void dbg_open(PinName led, PinName tx, PinName rx) |
Jeej | 0:1d3ed1850649 | 53 | { |
Jeej | 0:1d3ed1850649 | 54 | //FPRINT("\r\n"); |
Jeej | 0:1d3ed1850649 | 55 | |
Jeej | 0:1d3ed1850649 | 56 | g_dbg_nb_mallocs = 0; |
Jeej | 0:1d3ed1850649 | 57 | g_dbg_led = led; |
Jeej | 0:1d3ed1850649 | 58 | g_dbg_missing = 0; |
Jeej | 0:1d3ed1850649 | 59 | |
Jeej | 0:1d3ed1850649 | 60 | g_dbg_serial = new RawSerial(tx, rx, 115200); |
Jeej | 0:1d3ed1850649 | 61 | g_dbg_serial->format(8, SerialBase::None, 1); |
Jeej | 7:8e75991f65e5 | 62 | g_dbg_serial->attach(callback(&dbg_serial_rx_isr), Serial::RxIrq); |
Jeej | 0:1d3ed1850649 | 63 | |
Jeej | 0:1d3ed1850649 | 64 | g_dbg_thread.start(dbg_print_thread); |
Jeej | 0:1d3ed1850649 | 65 | } |
Jeej | 0:1d3ed1850649 | 66 | |
Jeej | 0:1d3ed1850649 | 67 | // Destructor |
Jeej | 0:1d3ed1850649 | 68 | void dbg_close( void ) |
Jeej | 0:1d3ed1850649 | 69 | { |
Jeej | 0:1d3ed1850649 | 70 | FPRINT("\r\n"); |
Jeej | 0:1d3ed1850649 | 71 | g_dbg_thread.terminate(); |
Jeej | 0:1d3ed1850649 | 72 | delete g_dbg_serial; |
Jeej | 0:1d3ed1850649 | 73 | } |
Jeej | 0:1d3ed1850649 | 74 | |
Jeej | 0:1d3ed1850649 | 75 | void dbg_set_led(PinName led, PinName dummy1, PinName dummy2) |
Jeej | 0:1d3ed1850649 | 76 | { |
Jeej | 0:1d3ed1850649 | 77 | FPRINT("\r\n"); |
Jeej | 0:1d3ed1850649 | 78 | g_dbg_led = led; |
Jeej | 0:1d3ed1850649 | 79 | } |
Jeej | 0:1d3ed1850649 | 80 | |
Jeej | 0:1d3ed1850649 | 81 | static void dbg_add_to_buf(char* msg, int size) |
Jeej | 0:1d3ed1850649 | 82 | { |
Jeej | 2:9e2ab0547cd0 | 83 | #ifdef __FORCE_FLUSH__ |
Jeej | 2:9e2ab0547cd0 | 84 | for (int i = 0; i < size; i++) |
Jeej | 2:9e2ab0547cd0 | 85 | { |
Jeej | 2:9e2ab0547cd0 | 86 | g_dbg_serial->putc(msg[i]); |
Jeej | 2:9e2ab0547cd0 | 87 | } |
Jeej | 2:9e2ab0547cd0 | 88 | #else |
Jeej | 0:1d3ed1850649 | 89 | if(size > 0) |
Jeej | 0:1d3ed1850649 | 90 | { |
Jeej | 0:1d3ed1850649 | 91 | if (g_dbg_buf.remaining_space() < size) |
Jeej | 0:1d3ed1850649 | 92 | { |
Jeej | 2:9e2ab0547cd0 | 93 | #ifdef __FLUSH_IF_FULL__ |
Jeej | 0:1d3ed1850649 | 94 | // Flush just what is needed |
Jeej | 0:1d3ed1850649 | 95 | do { |
Jeej | 0:1d3ed1850649 | 96 | g_dbg_serial->putc(g_dbg_buf.pop()); |
Jeej | 0:1d3ed1850649 | 97 | } while (g_dbg_buf.remaining_space() < size); |
Jeej | 0:1d3ed1850649 | 98 | |
Jeej | 0:1d3ed1850649 | 99 | g_dbg_buf.add((uint8_t*)msg, size); |
Jeej | 2:9e2ab0547cd0 | 100 | #else |
Jeej | 0:1d3ed1850649 | 101 | // Discard |
Jeej | 0:1d3ed1850649 | 102 | g_dbg_missing++; |
Jeej | 2:9e2ab0547cd0 | 103 | #endif |
Jeej | 0:1d3ed1850649 | 104 | } |
Jeej | 0:1d3ed1850649 | 105 | else |
Jeej | 0:1d3ed1850649 | 106 | { |
Jeej | 0:1d3ed1850649 | 107 | // add |
Jeej | 0:1d3ed1850649 | 108 | g_dbg_buf.add((uint8_t*)msg, size); |
Jeej | 0:1d3ed1850649 | 109 | } |
Jeej | 0:1d3ed1850649 | 110 | |
Jeej | 0:1d3ed1850649 | 111 | // Allow printing |
Jeej | 0:1d3ed1850649 | 112 | g_dbg_print.release(); |
Jeej | 0:1d3ed1850649 | 113 | } |
Jeej | 2:9e2ab0547cd0 | 114 | #endif |
Jeej | 0:1d3ed1850649 | 115 | } |
Jeej | 0:1d3ed1850649 | 116 | |
Jeej | 0:1d3ed1850649 | 117 | // Asserts and trap processor. |
Jeej | 0:1d3ed1850649 | 118 | void dbg_assert(bool test, const char* format, ...) |
Jeej | 0:1d3ed1850649 | 119 | { |
Jeej | 0:1d3ed1850649 | 120 | if (test) return; |
Jeej | 0:1d3ed1850649 | 121 | |
Jeej | 0:1d3ed1850649 | 122 | int assert_size; |
Jeej | 0:1d3ed1850649 | 123 | |
Jeej | 8:87a867b8a129 | 124 | assert_size = sprintf(g_dbg_msg, "ASSERT "); |
Jeej | 0:1d3ed1850649 | 125 | |
Jeej | 0:1d3ed1850649 | 126 | // expand assert string |
Jeej | 0:1d3ed1850649 | 127 | va_list args; |
Jeej | 0:1d3ed1850649 | 128 | va_start(args, format); |
Jeej | 4:31e1101e6999 | 129 | vsprintf(g_dbg_msg+assert_size, format, args); |
Jeej | 0:1d3ed1850649 | 130 | va_end(args); |
Jeej | 0:1d3ed1850649 | 131 | |
Jeej | 0:1d3ed1850649 | 132 | dbg_flush(); |
Jeej | 0:1d3ed1850649 | 133 | |
Jeej | 0:1d3ed1850649 | 134 | g_dbg_serial->printf(g_dbg_msg); |
Jeej | 0:1d3ed1850649 | 135 | |
Jeej | 0:1d3ed1850649 | 136 | #ifdef __REBOOT_ON_ASSERT__ |
Jeej | 8:87a867b8a129 | 137 | ThisThread::sleep_for(1000); |
Jeej | 0:1d3ed1850649 | 138 | NVIC_SystemReset(); |
Jeej | 0:1d3ed1850649 | 139 | #else |
Jeej | 0:1d3ed1850649 | 140 | DigitalOut* dbg_led = NULL; |
Jeej | 0:1d3ed1850649 | 141 | if (g_dbg_led != NC) |
Jeej | 0:1d3ed1850649 | 142 | { |
Jeej | 0:1d3ed1850649 | 143 | dbg_led = new DigitalOut(g_dbg_led); |
Jeej | 0:1d3ed1850649 | 144 | } |
Jeej | 0:1d3ed1850649 | 145 | |
Jeej | 0:1d3ed1850649 | 146 | // Die... |
Jeej | 0:1d3ed1850649 | 147 | while(1) |
Jeej | 0:1d3ed1850649 | 148 | { |
Jeej | 0:1d3ed1850649 | 149 | if (dbg_led != NULL) |
Jeej | 0:1d3ed1850649 | 150 | { |
Jeej | 0:1d3ed1850649 | 151 | *(dbg_led) = !(*(dbg_led)); |
Jeej | 0:1d3ed1850649 | 152 | } |
Jeej | 8:87a867b8a129 | 153 | ThisThread::sleep_for(30); |
Jeej | 0:1d3ed1850649 | 154 | //wait_ms(30); |
Jeej | 0:1d3ed1850649 | 155 | } |
Jeej | 0:1d3ed1850649 | 156 | #endif |
Jeej | 0:1d3ed1850649 | 157 | } |
Jeej | 0:1d3ed1850649 | 158 | |
Jeej | 0:1d3ed1850649 | 159 | // Prints a message to the debug port. |
Jeej | 0:1d3ed1850649 | 160 | void dbg_print(const char* format, ...) |
Jeej | 0:1d3ed1850649 | 161 | { |
Jeej | 0:1d3ed1850649 | 162 | int size; |
Jeej | 0:1d3ed1850649 | 163 | |
Jeej | 0:1d3ed1850649 | 164 | va_list args; |
Jeej | 0:1d3ed1850649 | 165 | va_start(args, format); |
Jeej | 0:1d3ed1850649 | 166 | size = vsprintf(g_dbg_msg, format, args); |
Jeej | 0:1d3ed1850649 | 167 | va_end(args); |
Jeej | 0:1d3ed1850649 | 168 | |
Jeej | 0:1d3ed1850649 | 169 | dbg_add_to_buf(g_dbg_msg, size); |
Jeej | 0:1d3ed1850649 | 170 | } |
Jeej | 0:1d3ed1850649 | 171 | |
Jeej | 0:1d3ed1850649 | 172 | // Flush the pending debug messages. |
Jeej | 0:1d3ed1850649 | 173 | void dbg_flush( void ) |
Jeej | 0:1d3ed1850649 | 174 | { |
Jeej | 0:1d3ed1850649 | 175 | g_dbg_ressource.lock(); |
Jeej | 0:1d3ed1850649 | 176 | while(!g_dbg_buf.empty()) |
Jeej | 0:1d3ed1850649 | 177 | { |
Jeej | 0:1d3ed1850649 | 178 | g_dbg_serial->putc(g_dbg_buf.pop()); |
Jeej | 0:1d3ed1850649 | 179 | } |
Jeej | 0:1d3ed1850649 | 180 | g_dbg_ressource.unlock(); |
Jeej | 0:1d3ed1850649 | 181 | } |
Jeej | 0:1d3ed1850649 | 182 | |
Jeej | 0:1d3ed1850649 | 183 | // Prints malloc parameters. |
Jeej | 0:1d3ed1850649 | 184 | void* dbg_malloc(size_t size, const char* f, uint32_t l) |
Jeej | 0:1d3ed1850649 | 185 | { |
Jeej | 0:1d3ed1850649 | 186 | void* a; |
Jeej | 0:1d3ed1850649 | 187 | a = malloc(size); |
Jeej | 0:1d3ed1850649 | 188 | g_dbg_nb_mallocs++; |
Jeej | 0:1d3ed1850649 | 189 | dbg_print("M @%08x %dB %s:%d (%d)\r\n", (uint32_t)a, size, f, l, g_dbg_nb_mallocs); |
Jeej | 0:1d3ed1850649 | 190 | return a; |
Jeej | 0:1d3ed1850649 | 191 | } |
Jeej | 0:1d3ed1850649 | 192 | |
Jeej | 0:1d3ed1850649 | 193 | // Prints realloc parameters. |
Jeej | 0:1d3ed1850649 | 194 | void* dbg_realloc(void* p, size_t size, const char* f, uint32_t l) |
Jeej | 0:1d3ed1850649 | 195 | { |
Jeej | 0:1d3ed1850649 | 196 | void* a; |
Jeej | 0:1d3ed1850649 | 197 | dbg_assert(((uint32_t)p >= RAM_START_ADDRESS) && ((uint32_t)p < RAM_END_ADDRESS), "Trying to realloc illegal address @08x\r\n", (uint32_t)p); |
Jeej | 0:1d3ed1850649 | 198 | a = realloc(p, size); |
Jeej | 0:1d3ed1850649 | 199 | dbg_print("R @%08x->@%08x %dB %s:%d\r\n", (uint32_t)p, (uint32_t)a, size, f, l); |
Jeej | 0:1d3ed1850649 | 200 | return a; |
Jeej | 0:1d3ed1850649 | 201 | } |
Jeej | 0:1d3ed1850649 | 202 | |
Jeej | 0:1d3ed1850649 | 203 | // Prints free parameters. |
Jeej | 0:1d3ed1850649 | 204 | void dbg_free(void* p, const char* f, uint32_t l) |
Jeej | 0:1d3ed1850649 | 205 | { |
Jeej | 0:1d3ed1850649 | 206 | g_dbg_nb_mallocs--; |
Jeej | 0:1d3ed1850649 | 207 | dbg_print("F @%08x %s:%d (%d)\r\n", (uint32_t)p, f, l, g_dbg_nb_mallocs); |
Jeej | 0:1d3ed1850649 | 208 | dbg_assert(((uint32_t)p >= RAM_START_ADDRESS) && ((uint32_t)p < RAM_END_ADDRESS), "Trying to free illegal address @08x\r\n", (uint32_t)p); |
Jeej | 0:1d3ed1850649 | 209 | free(p); |
Jeej | 0:1d3ed1850649 | 210 | } |
Jeej | 0:1d3ed1850649 | 211 | |
Jeej | 0:1d3ed1850649 | 212 | void dbg_print_data(const char* before, const char* format, uint8_t* data, uint8_t length, const char* after) |
Jeej | 0:1d3ed1850649 | 213 | { |
Jeej | 0:1d3ed1850649 | 214 | uint32_t total_len = 0; |
Jeej | 0:1d3ed1850649 | 215 | |
Jeej | 0:1d3ed1850649 | 216 | total_len += sprintf(g_dbg_msg, before); |
Jeej | 0:1d3ed1850649 | 217 | |
Jeej | 0:1d3ed1850649 | 218 | for (uint8_t i=0 ; i<length ; i++) |
Jeej | 0:1d3ed1850649 | 219 | { |
Jeej | 0:1d3ed1850649 | 220 | total_len += sprintf(&g_dbg_msg[total_len], format, data[i]); |
Jeej | 0:1d3ed1850649 | 221 | dbg_assert(total_len < DBG_MAX_STRING_SIZE, "Print data too long.\r\n"); |
Jeej | 0:1d3ed1850649 | 222 | } |
Jeej | 0:1d3ed1850649 | 223 | |
Jeej | 0:1d3ed1850649 | 224 | total_len += sprintf(&g_dbg_msg[total_len], after); |
Jeej | 0:1d3ed1850649 | 225 | |
Jeej | 0:1d3ed1850649 | 226 | dbg_add_to_buf(g_dbg_msg, total_len); |
Jeej | 0:1d3ed1850649 | 227 | } |
Jeej | 0:1d3ed1850649 | 228 | |
Jeej | 0:1d3ed1850649 | 229 | |
Jeej | 0:1d3ed1850649 | 230 | // Thread for printing debug messages. |
Jeej | 0:1d3ed1850649 | 231 | void dbg_print_thread() |
Jeej | 0:1d3ed1850649 | 232 | { |
Jeej | 0:1d3ed1850649 | 233 | FPRINT("(id:0x%08x)\r\n", osThreadGetId()); |
Jeej | 0:1d3ed1850649 | 234 | |
Jeej | 0:1d3ed1850649 | 235 | while (true) |
Jeej | 0:1d3ed1850649 | 236 | { |
Jeej | 9:87d9cc850af1 | 237 | g_dbg_print.acquire(); |
Jeej | 0:1d3ed1850649 | 238 | |
Jeej | 0:1d3ed1850649 | 239 | if (g_dbg_missing) |
Jeej | 0:1d3ed1850649 | 240 | { |
Jeej | 0:1d3ed1850649 | 241 | g_dbg_serial->printf("Missing %d traces!!!\r\n", g_dbg_missing); |
Jeej | 0:1d3ed1850649 | 242 | g_dbg_missing = 0; |
Jeej | 0:1d3ed1850649 | 243 | } |
Jeej | 0:1d3ed1850649 | 244 | |
Jeej | 0:1d3ed1850649 | 245 | while(!g_dbg_buf.empty()) |
Jeej | 0:1d3ed1850649 | 246 | { |
Jeej | 0:1d3ed1850649 | 247 | g_dbg_ressource.lock(); |
Jeej | 0:1d3ed1850649 | 248 | |
Jeej | 0:1d3ed1850649 | 249 | #ifdef __FORCE_LINE_INTEGRITY__ |
Jeej | 0:1d3ed1850649 | 250 | // Flush until EOL |
Jeej | 0:1d3ed1850649 | 251 | uint8_t byte; |
Jeej | 0:1d3ed1850649 | 252 | do { |
Jeej | 0:1d3ed1850649 | 253 | byte = g_dbg_buf.pop(); |
Jeej | 0:1d3ed1850649 | 254 | g_dbg_serial->putc(byte); |
Jeej | 9:87d9cc850af1 | 255 | } while (byte != '\n' && !g_dbg_buf.empty()); |
Jeej | 0:1d3ed1850649 | 256 | #else |
Jeej | 0:1d3ed1850649 | 257 | // Flush characters one by one |
Jeej | 0:1d3ed1850649 | 258 | g_dbg_serial->putc(g_dbg_buf.pop()); |
Jeej | 0:1d3ed1850649 | 259 | #endif |
Jeej | 0:1d3ed1850649 | 260 | |
Jeej | 0:1d3ed1850649 | 261 | g_dbg_ressource.unlock(); |
Jeej | 8:87a867b8a129 | 262 | ThisThread::yield(); |
Jeej | 0:1d3ed1850649 | 263 | } |
Jeej | 0:1d3ed1850649 | 264 | } |
Jeej | 0:1d3ed1850649 | 265 | } |
Jeej | 0:1d3ed1850649 | 266 | |
Jeej | 7:8e75991f65e5 | 267 | void dbg_set_rx_callback(void (*rx_isr)(char c)) |
Jeej | 7:8e75991f65e5 | 268 | { |
Jeej | 7:8e75991f65e5 | 269 | g_dbg_rx_callback = rx_isr; |
Jeej | 7:8e75991f65e5 | 270 | } |