BlueSCSI_log.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // Copyright (c) 2022 Rabbit Hole Computing™
  2. // Copyright (c) 2023 Eric Helgeson
  3. #include "BlueSCSI_log.h"
  4. #include "BlueSCSI_config.h"
  5. #include "BlueSCSI_platform.h"
  6. const char *g_log_firmwareversion = BLUESCSI_FW_VERSION " " __DATE__ " " __TIME__;
  7. bool g_log_debug = false;
  8. uint8_t g_scsi_log_mask = 0;
  9. bool g_test_mode = false;
  10. // This memory buffer can be read by debugger and is also saved to log.txt
  11. #define LOGBUFMASK (LOGBUFSIZE - 1)
  12. // The log buffer is in special uninitialized RAM section so that it is not reset
  13. // when soft rebooting or jumping from bootloader.
  14. uint32_t g_log_magic;
  15. char g_logbuffer[LOGBUFSIZE + 1];
  16. uint32_t g_logpos;
  17. void log_raw(const char *str)
  18. {
  19. // Keep log from reboot / bootloader if magic matches expected value
  20. if (g_log_magic != 0xAA55AA55)
  21. {
  22. g_log_magic = 0xAA55AA55;
  23. g_logpos = 0;
  24. }
  25. const char *p = str;
  26. while (*p)
  27. {
  28. g_logbuffer[g_logpos & LOGBUFMASK] = *p++;
  29. g_logpos++;
  30. }
  31. // Keep buffer null-terminated
  32. g_logbuffer[g_logpos & LOGBUFMASK] = '\0';
  33. platform_log(str);
  34. }
  35. // Log byte as hex
  36. void log_raw(uint8_t value)
  37. {
  38. const char *nibble = "0123456789ABCDEF";
  39. char hexbuf[5] = {
  40. '0', 'x',
  41. nibble[(value >> 4) & 0xF], nibble[(value >> 0) & 0xF],
  42. 0
  43. };
  44. log_raw(hexbuf);
  45. }
  46. // Log integer as hex
  47. void log_raw(uint32_t value)
  48. {
  49. const char *nibble = "0123456789ABCDEF";
  50. char hexbuf[11] = {
  51. '0', 'x',
  52. nibble[(value >> 28) & 0xF], nibble[(value >> 24) & 0xF],
  53. nibble[(value >> 20) & 0xF], nibble[(value >> 16) & 0xF],
  54. nibble[(value >> 12) & 0xF], nibble[(value >> 8) & 0xF],
  55. nibble[(value >> 4) & 0xF], nibble[(value >> 0) & 0xF],
  56. 0
  57. };
  58. log_raw(hexbuf);
  59. }
  60. // Log integer as hex
  61. void log_raw(uint64_t value)
  62. {
  63. const char *nibble = "0123456789ABCDEF";
  64. char hexbuf[19] = {
  65. '0', 'x',
  66. nibble[(value >> 60) & 0xF], nibble[(value >> 56) & 0xF],
  67. nibble[(value >> 52) & 0xF], nibble[(value >> 48) & 0xF],
  68. nibble[(value >> 44) & 0xF], nibble[(value >> 40) & 0xF],
  69. nibble[(value >> 36) & 0xF], nibble[(value >> 32) & 0xF],
  70. nibble[(value >> 28) & 0xF], nibble[(value >> 24) & 0xF],
  71. nibble[(value >> 20) & 0xF], nibble[(value >> 16) & 0xF],
  72. nibble[(value >> 12) & 0xF], nibble[(value >> 8) & 0xF],
  73. nibble[(value >> 4) & 0xF], nibble[(value >> 0) & 0xF],
  74. 0
  75. };
  76. log_raw(hexbuf);
  77. }
  78. // Log integer as decimal
  79. void log_raw(int value)
  80. {
  81. char decbuf[16] = {0};
  82. char *p = &decbuf[14];
  83. int remainder = (value < 0) ? -value : value;
  84. do
  85. {
  86. *--p = '0' + (remainder % 10);
  87. remainder /= 10;
  88. } while (remainder > 0);
  89. if (value < 0)
  90. {
  91. *--p = '-';
  92. }
  93. log_raw(p);
  94. }
  95. void log_raw(bytearray array)
  96. {
  97. for (size_t i = 0; i < array.len; i++)
  98. {
  99. log_raw(array.data[i]);
  100. log_raw(" ");
  101. if (i > 32)
  102. {
  103. log_raw("... (total ", (int)array.len, ")");
  104. break;
  105. }
  106. }
  107. }
  108. void log_raw(double value)
  109. {
  110. char buffer[6];
  111. snprintf(buffer, sizeof buffer, "%0.3f", value);
  112. log_raw(buffer);
  113. }
  114. void log_raw(bool value)
  115. {
  116. if(value) log_raw("true");
  117. else log_raw("false");
  118. }
  119. void log_f(const char *format, ...)
  120. {
  121. static char out[2048];
  122. va_list ap;
  123. va_start(ap, format);
  124. vsnprintf(out, sizeof(out), format, ap);
  125. va_end(ap);
  126. log(out);
  127. }
  128. void log_buf(const unsigned char *buf, unsigned long size)
  129. {
  130. static char tmp[1500 * 3];
  131. static char hex[] = "0123456789abcdef";
  132. int o = 0;
  133. for (int j = 0; j < size; j++) {
  134. if (o + 3 >= sizeof(tmp))
  135. break;
  136. if (j != 0)
  137. tmp[o++] = ' ';
  138. tmp[o++] = hex[(buf[j] >> 4) & 0xf];
  139. tmp[o++] = hex[buf[j] & 0xf];
  140. tmp[o] = 0;
  141. }
  142. log_f("%s", tmp);
  143. }
  144. uint32_t log_get_buffer_len()
  145. {
  146. return g_logpos;
  147. }
  148. const char *log_get_buffer(uint32_t *startpos, uint32_t *available)
  149. {
  150. uint32_t default_pos = 0;
  151. if (startpos == NULL)
  152. {
  153. startpos = &default_pos;
  154. }
  155. // Check oldest data available in buffer
  156. uint32_t lag = (g_logpos - *startpos);
  157. if (lag >= LOGBUFSIZE)
  158. {
  159. // If we lose data, skip 512 bytes forward to give us time to transmit
  160. // pending data before new log messages arrive. Also skip to next line
  161. // break to keep formatting consistent.
  162. uint32_t oldest = g_logpos - LOGBUFSIZE + 512;
  163. while (oldest < g_logpos)
  164. {
  165. char c = g_logbuffer[oldest & LOGBUFMASK];
  166. if (c == '\r' || c == '\n') break;
  167. oldest++;
  168. }
  169. if (oldest > g_logpos)
  170. {
  171. oldest = g_logpos;
  172. }
  173. *startpos = oldest;
  174. }
  175. const char *result = &g_logbuffer[*startpos & LOGBUFMASK];
  176. // Calculate number of bytes available
  177. uint32_t len;
  178. if ((g_logpos & LOGBUFMASK) >= (*startpos & LOGBUFMASK))
  179. {
  180. // Can read directly to g_logpos
  181. len = g_logpos - *startpos;
  182. }
  183. else
  184. {
  185. // Buffer wraps, read to end of buffer now and start from beginning on next call.
  186. len = LOGBUFSIZE - (*startpos & LOGBUFMASK);
  187. }
  188. if (available) { *available = len; }
  189. *startpos += len;
  190. return result;
  191. }
  192. // TODO write directly global log buffer to save some memory
  193. static char shared_log_buf[1500 * 3];
  194. // core method for variadic printf like logging
  195. static void log_va(bool debug, const char *format, va_list ap)
  196. {
  197. vsnprintf(shared_log_buf, sizeof(shared_log_buf), format, ap);
  198. if (debug)
  199. {
  200. debuglog(shared_log_buf);
  201. }
  202. else
  203. {
  204. log(shared_log_buf);
  205. }
  206. }
  207. void logmsg_f(const char *format, ...)
  208. {
  209. va_list ap;
  210. va_start(ap, format);
  211. log_va(false, format, ap);
  212. va_end(ap);
  213. }
  214. void dbgmsg_f(const char *format, ...)
  215. {
  216. if (!g_log_debug)
  217. return;
  218. va_list ap;
  219. va_start(ap, format);
  220. log_va(true, format, ap);
  221. va_end(ap);
  222. }
  223. // core method for logging a data buffer into a hex string
  224. void log_hex_buf(const unsigned char *buf, unsigned long size, bool debug)
  225. {
  226. static char hex[] = "0123456789abcdef";
  227. int o = 0;
  228. for (int j = 0; j < size; j++) {
  229. if (o + 3 >= sizeof(shared_log_buf))
  230. break;
  231. if (j != 0)
  232. shared_log_buf[o++] = ' ';
  233. shared_log_buf[o++] = hex[(buf[j] >> 4) & 0xf];
  234. shared_log_buf[o++] = hex[buf[j] & 0xf];
  235. shared_log_buf[o] = 0;
  236. }
  237. if (debug)
  238. debuglog(shared_log_buf);
  239. else
  240. log(shared_log_buf);
  241. }
  242. void logmsg_buf(const unsigned char *buf, unsigned long size)
  243. {
  244. log_hex_buf(buf, size, false);
  245. }
  246. void dbgmsg_buf(const unsigned char *buf, unsigned long size)
  247. {
  248. if (!g_log_debug)
  249. return;
  250. log_hex_buf(buf, size, true);
  251. }