00001
00020
00021
00022
00023
00024 #include <stdarg.h>
00025
00026 #include "rwnx_config.h"
00027 #include "dbg_assert.h"
00028 #include "co_math.h"
00029
00030 #include "dbg.h"
00031
00032 #if NX_PRINT == NX_PRINT_IPC
00033 #include "ipc_emb.h"
00034 #elif NX_PRINT == NX_PRINT_PRINTF
00035 #include <stdio.h>
00036 #elif NX_PRINT == NX_PRINT_PRINTK
00037 #include <linux/kernel.h>
00038 #endif
00039
00041 #define FLAG_SHORT_SUPPORTED
00042
00044 enum
00045 {
00046 S_COPY,
00047 S_PERCENT,
00048 S_FLAGS,
00049 S_WIDTH,
00050 S_DOT,
00051 S_PRECIS,
00052 S_SIZE,
00053 S_TYPE,
00054 S_MAX
00055 };
00056
00058 enum
00059 {
00060 C_OTHER,
00061 C_PERCENT,
00062 C_DOT,
00063 C_ZERO,
00064 C_DIGIT,
00065 C_FLAG,
00066 C_SIZE,
00067 C_TYPE,
00068 C_MAX
00069 };
00070
00071
00073 enum
00074 {
00075 FLAG_SHORT = (1 << 0),
00076 FLAG_LONG = (1 << 1),
00077 FLAG_SIGNED = (1 << 2),
00078 FLAG_SIGN = (1 << 3),
00079 FLAG_SIGN_SPACE = (1 << 4),
00080 FLAG_LEFT = (1 << 5),
00081 FLAG_LEAD_ZERO = (1 << 6),
00082 FLAG_NEGATIVE = (1 << 7),
00083 };
00084
00085
00087 static const uint8_t transition_table[S_MAX][C_MAX] =
00088 {
00089 { S_COPY, S_PERCENT, S_COPY, S_COPY, S_COPY, S_COPY, S_COPY, S_COPY },
00090 { S_COPY, S_COPY, S_DOT, S_FLAGS , S_WIDTH, S_FLAGS , S_SIZE, S_TYPE },
00091 { S_COPY, S_COPY, S_DOT, S_FLAGS, S_WIDTH, S_FLAGS, S_SIZE, S_TYPE },
00092 { S_COPY, S_COPY, S_DOT, S_WIDTH, S_WIDTH, S_COPY, S_SIZE, S_TYPE },
00093 { S_COPY, S_COPY, S_COPY, S_PRECIS, S_PRECIS, S_COPY, S_SIZE, S_TYPE },
00094 { S_COPY, S_COPY, S_COPY, S_PRECIS, S_PRECIS, S_COPY, S_SIZE, S_TYPE },
00095 { S_COPY, S_COPY, S_COPY, S_COPY, S_COPY, S_COPY, S_COPY, S_TYPE },
00096 { S_COPY, S_PERCENT, S_COPY, S_COPY, S_COPY, S_COPY, S_COPY, S_COPY },
00097 };
00098
00099
00101 static const char hex_upper_table[] = "0123456789ABCDEF";
00102 #ifdef SUPPORT_LOWER_CASE_HEX
00104 static const char hex_lower_table[] = "0123456789abcdef";
00105 #endif
00106
00107
00108
00120 static uint32_t type_get(char c)
00121 {
00122 uint32_t res;
00123
00124 switch(c)
00125 {
00126 case '%':
00127 res = C_PERCENT;
00128 break;
00129
00130 case '.':
00131 res = C_DOT;
00132 break;
00133
00134 case '0':
00135 res = C_ZERO;
00136 break;
00137
00138 case ' ':
00139 case '+':
00140 case '-':
00141 res = C_FLAG;
00142 break;
00143
00144 case 'h':
00145 case 'l':
00146 res = C_SIZE;
00147 break;
00148
00149 case 'x':
00150 case 'X':
00151 case 'd':
00152 case 'b':
00153 case 'i':
00154 case 'c':
00155 case 'u':
00156 case 's':
00157 case 'm':
00158 case 'M':
00159 case 'a':
00160 case 'A':
00161 res = C_TYPE;
00162 break;
00163
00164 case '*':
00165 res = C_DIGIT;
00166 break;
00167
00168 default:
00169 if(('1' <= c) && (c <= '9'))
00170 {
00171 res = C_DIGIT;
00172 }
00173 else
00174 {
00175 res = C_OTHER;
00176 }
00177 break;
00178 }
00179
00180 return res;
00181 }
00182
00201 uint32_t dbg_vsnprintf_offset(char *buffer, uint32_t size, uint32_t offset, const char *fmt, va_list args)
00202 {
00203 uint32_t state_current = S_COPY;
00204 char c;
00205
00206 char *fmt_field_ptr = NULL;
00207 int fmt_field_size = 0;
00208
00209 char buffer_tmp[64];
00210
00211 int field_width = 0;
00212 char field_flags = 0;
00213 int field_precision = 0;
00214 int field_padding = 0;
00215
00216 int32_t value;
00217 char *tmp_ptr = NULL;
00218
00219 uint32_t res = 0, remain;
00220
00221 #define WRITE_CHAR(_c) if (remain && res >= offset) {*buffer++ = (_c); remain--;} res++
00222
00223
00224 if (buffer == NULL)
00225 size = 0;
00226
00227 remain = size;
00228
00229
00230 while ((c = *fmt++) != 0)
00231 {
00232 state_current = transition_table[state_current][type_get(c)];
00233
00234 switch (state_current)
00235 {
00236 case S_COPY :
00237 WRITE_CHAR(c);
00238 break;
00239
00240 case S_PERCENT:
00241
00242 field_width = 0;
00243 field_flags = 0;
00244 field_precision = -1;
00245 break;
00246
00247 case S_FLAGS:
00248
00249 switch(c)
00250 {
00251 case '-':
00252
00253 field_flags |= FLAG_LEFT;
00254 break;
00255 case '+':
00256
00257 field_flags |= FLAG_SIGN;
00258 break;
00259 case ' ':
00260
00261 field_flags |= FLAG_SIGN_SPACE;
00262 break;
00263 case '0':
00264
00265 field_flags |= FLAG_LEAD_ZERO;
00266 break;
00267 default:
00268 ASSERT_ERR(0);
00269 break;
00270 }
00271 break;
00272
00273 case S_WIDTH:
00274 if (c != '*')
00275 {
00276
00277 field_width = field_width * 10 + (c - '0');
00278 }
00279 else
00280 {
00281 field_width = (int)va_arg(args, int);
00282 }
00283 break;
00284
00285 case S_DOT:
00286
00287 field_precision = 0;
00288 break;
00289
00290 case S_PRECIS:
00291 if (c != '*')
00292 {
00293
00294 field_precision = field_precision * 10 + (c - '0');
00295 }
00296 else
00297 {
00298 field_precision = (int)va_arg(args, int);
00299 }
00300 break;
00301
00302 case S_SIZE:
00303
00304 switch (c)
00305 {
00306 case 'l':
00307
00308 field_flags |= FLAG_LONG;
00309 break;
00310
00311 #ifdef FLAG_SHORT_SUPPORTED
00312 case 'h':
00313
00314 field_flags |= FLAG_SHORT;
00315 break;
00316 #endif // FLAG_SHORT_SUPPORTED
00317
00318 default:
00319 ASSERT_ERR(0);
00320 break;
00321 }
00322 break;
00323
00324 case S_TYPE:
00325
00326
00327 switch (c)
00328 {
00329
00330 case 'c':
00331
00332 buffer_tmp[0] = (char)va_arg(args, int);
00333 fmt_field_ptr = buffer_tmp;
00334 fmt_field_size = 1;
00335 break;
00336
00337
00338
00339 case 's':
00340
00341 fmt_field_ptr = va_arg(args, char *);
00342 fmt_field_size = 0;
00343 if (fmt_field_ptr != NULL)
00344 {
00345
00346
00347 tmp_ptr = fmt_field_ptr;
00348 while (*tmp_ptr != '\0')
00349 {
00350 if (field_precision == 0)
00351 break;
00352 if (field_precision > 0)
00353 field_precision --;
00354 tmp_ptr++;
00355 fmt_field_size++;
00356 }
00357 }
00358 break;
00359
00360
00361 case 'm':
00362 case 'M':
00363 {
00364 int i;
00365 fmt_field_ptr = buffer_tmp;
00366 tmp_ptr = va_arg(args, char *);
00367 fmt_field_size = 17;
00368 for(i = 5;;)
00369 {
00370 value = (unsigned char) *tmp_ptr++;
00371 *fmt_field_ptr++ = hex_upper_table[value >> 4];
00372 *fmt_field_ptr++ = hex_upper_table[value & 0xF];
00373 if (i-- == 0) break;
00374 *fmt_field_ptr++ = ':';
00375 }
00376 fmt_field_ptr = buffer_tmp;
00377 break;
00378 }
00379
00380 case 'a':
00381 case 'A':
00382 fmt_field_ptr = buffer_tmp;
00383 tmp_ptr = va_arg(args, char *);
00384
00385 field_width = co_min(field_width, sizeof(buffer_tmp)/3);
00386
00387 if (!field_width) field_width = 16;
00388 fmt_field_size = field_width * 3 - 1 ;
00389 for(;;)
00390 {
00391 value = (unsigned char) *tmp_ptr++;
00392 *fmt_field_ptr++ = hex_upper_table[value >> 4];
00393 *fmt_field_ptr++ = hex_upper_table[value & 0xF];
00394 if (--field_width == 0) break;
00395
00396 if (3 & (uint32_t) tmp_ptr) *fmt_field_ptr++ = '.';
00397 else *fmt_field_ptr++ = ':';
00398 }
00399 fmt_field_ptr = buffer_tmp;
00400 break;
00401
00402 case 'i':
00403 c = 'd';
00404 case 'd':
00405 case 'u':
00406 case 'X':
00407 case 'x':
00408 case 'b':
00409
00410
00411 fmt_field_ptr = buffer_tmp + sizeof(buffer_tmp);
00412 fmt_field_size = 0;
00413
00414
00415 if (field_flags & FLAG_LONG)
00416 {
00417
00418 value = va_arg(args, uint32_t);
00419 }
00420 #ifdef FLAG_SHORT_SUPPORTED
00421 else if(field_flags & FLAG_SHORT)
00422 {
00423 if (c == 'd')
00424 {
00425
00426 value = (int16_t) va_arg(args, int);
00427 }
00428 else
00429 {
00430 value = (uint16_t) va_arg(args, int);
00431 }
00432 }
00433 #endif // FLAG_SHORT_SUPPORTED
00434 else
00435 {
00436
00437
00438 value = va_arg(args, int);
00439 }
00440
00441 switch (c)
00442 {
00443 case 'd':
00444
00445 if (value < 0)
00446 {
00447 value = (uint32_t)(-value);
00448
00449 field_flags |= FLAG_NEGATIVE;
00450 }
00451
00452 case 'u':
00453 do
00454 {
00455
00456 fmt_field_ptr--;
00457 *fmt_field_ptr = ('0'+ ((char) (value % 10)));
00458 value = value / 10;
00459 fmt_field_size++;
00460 }
00461 while (value != 0);
00462
00463
00464 if (field_flags & FLAG_NEGATIVE)
00465 {
00466
00467 fmt_field_ptr--;
00468
00469 *fmt_field_ptr = '-';
00470 fmt_field_size++;
00471 }
00472 else if (field_flags & FLAG_SIGN)
00473 {
00474
00475 fmt_field_ptr--;
00476 *fmt_field_ptr = '+';
00477 fmt_field_size++;
00478 }
00479 else if (field_flags & FLAG_SIGN_SPACE)
00480 {
00481
00482 fmt_field_ptr--;
00483 *fmt_field_ptr = ' ';
00484 fmt_field_size++;
00485 }
00486 break;
00487
00488 case 'x':
00489 #ifdef SUPPORT_LOWER_CASE_HEX
00490 do
00491 {
00492
00493 fmt_field_ptr--;
00494 *fmt_field_ptr = hex_lower_table[value & 0XFUL];
00495 value = ((uint32_t) value) >> 4;
00496 fmt_field_size++;
00497 }
00498 while (value != 0);
00499 break;
00500 #endif
00501
00502 case 'X':
00503 do
00504 {
00505
00506 fmt_field_ptr--;
00507 *fmt_field_ptr = hex_upper_table[value & 0XFUL];
00508 value = ((uint32_t) value) >> 4;
00509 fmt_field_size++;
00510 }
00511 while (value != 0);
00512 break;
00513
00514 case 'b':
00515 do
00516 {
00517
00518 fmt_field_ptr--;
00519 *fmt_field_ptr = '0' + ((char) (value & 0x01UL));
00520 value = ((uint32_t) value) >> 1;
00521 fmt_field_size++;
00522 }
00523 while (value != 0);
00524 break;
00525 default:
00526
00527 break;
00528 }
00529
00530 default:
00531
00532 break;
00533 }
00534
00535
00536
00537 field_padding = field_width - fmt_field_size;
00538
00539
00540 if (field_flags & FLAG_LEAD_ZERO)
00541 {
00542
00543 while (field_padding > 0)
00544 {
00545 WRITE_CHAR('0');
00546 field_padding--;
00547 }
00548 }
00549 else if (!(field_flags & FLAG_LEFT))
00550 {
00551 while (field_padding > 0)
00552 {
00553 WRITE_CHAR(' ');
00554 field_padding--;
00555 }
00556 }
00557
00558
00559 while (fmt_field_size > 0)
00560 {
00561 WRITE_CHAR(*fmt_field_ptr);
00562 fmt_field_ptr++;
00563 fmt_field_size--;
00564 }
00565
00566
00567 while ((field_padding > 0))
00568 {
00569 WRITE_CHAR(' ');
00570 field_padding--;
00571 }
00572 break;
00573
00574 default:
00575 ASSERT_ERR(0);
00576 }
00577 }
00578
00579 #undef WRITE_CHAR
00580
00581 if (remain)
00582 {
00583 *buffer = '\0';
00584 }
00585 else if (size)
00586 {
00587 buffer[-1] = '\0';
00588 }
00589
00590 return res;
00591 }
00592
00593 #if NX_PRINT == NX_PRINT_IPC
00594
00604 static void dbg_emb_vprintf(bool force, const char *fmt_usr, va_list args)
00605 {
00606 int mutex;
00607 GLOBAL_INT_DISABLE();
00608 mutex = dbg_env.print_mutex;
00609 mutex++;
00610 dbg_env.print_mutex = mutex;
00611 GLOBAL_INT_RESTORE();
00612
00613 if (mutex == 1)
00614 {
00615 unsigned int len = dbg_vsnprintf(dbg_env.print_buffer, sizeof(dbg_env.print_buffer),
00616 fmt_usr, args);
00617
00618 if (len < sizeof(dbg_env.print_buffer))
00619 len ++;
00620 else
00621 len = sizeof(dbg_env.print_buffer);
00622
00623 ipc_emb_print_fwd(force, len, dbg_env.print_buffer);
00624
00625
00626
00627 while (mutex != dbg_env.print_mutex)
00628 {
00629 mutex = dbg_env.print_mutex;
00630
00631
00632 }
00633 dbg_env.print_mutex = 0;
00634 }
00635 }
00636 #endif
00637
00638
00647 void dbg_test_print(const char *fmt, ...)
00648 {
00649 const char *fmt_usr = (const char*) fmt;
00650 uint32_t severity = 0;
00651
00652
00653
00654 if (dbg_env.filter_severity == 0) return;
00655
00656 do
00657 {
00658
00659 unsigned char prefix = ((unsigned char)*fmt_usr) & 0xFF;
00660
00661
00662 if (prefix < DBG_MOD_MIN) break;
00663
00664 if (prefix < DBG_MOD_MAX)
00665 {
00666
00667 if (~dbg_env.filter_module & CO_BIT(prefix - DBG_MOD_MIN)) return;
00668 }
00669 else
00670 {
00671
00672 ASSERT_ERR(DBG_SEV_MIN <= prefix && prefix < DBG_SEV_MAX);
00673 severity = (uint32_t)(prefix - DBG_SEV_MIN);
00674
00675
00676 if (dbg_env.filter_severity <= severity) return;
00677 }
00678
00679
00680 fmt_usr++;
00681 }
00682 while (fmt_usr != fmt + 2);
00683
00684
00685 va_list args;
00686 va_start(args, fmt);
00687
00688 #if NX_PRINT == NX_PRINT_IPC
00689 dbg_emb_vprintf(severity<=DBG_SEV_IDX_ERR, fmt_usr, args);
00690
00691 #elif NX_PRINT == NX_PRINT_PRINTK
00692 vprintk(fmt_usr, args);
00693
00694 #elif NX_PRINT == NX_PRINT_PRINTF
00695 vprintf(fmt_usr, args);
00696
00697 #endif
00698
00699 va_end(args);
00700 }
00701
00718 uint32_t dbg_snprintf(char *buffer, uint32_t size, const char *fmt, ...)
00719 {
00720 uint32_t ret;
00721 const char *fmt_usr = (const char*) fmt;
00722
00723
00724 va_list args;
00725 va_start(args, fmt);
00726
00727 ret = dbg_vsnprintf(buffer, size, fmt_usr, args);
00728
00729 va_end(args);
00730
00731 return ret;
00732 }
00733