ZuluSCSI_log.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. /**
  2. * ZuluSCSI™ - Copyright (c) 2022-2024 Rabbit Hole Computing™
  3. * Copyright (c) 2023 joshua stein <jcs@jcs.org>
  4. * Copyright (c) 2024 Eric Helgeson <erichelgeson@gmail.com>
  5. *
  6. * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
  7. *
  8. * https://www.gnu.org/licenses/gpl-3.0.html
  9. * ----
  10. * This program is free software: you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version. 
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18. * GNU General Public License for more details. 
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  22. **/
  23. #include "ZuluSCSI_log.h"
  24. #include "ZuluSCSI_config.h"
  25. #include "ZuluSCSI_platform.h"
  26. #include <stdio.h>
  27. #include <stdarg.h>
  28. const char *g_log_firmwareversion = ZULU_FW_VERSION " " __DATE__ " " __TIME__;
  29. bool g_log_debug = false;
  30. bool g_log_ignore_busy_free = false;
  31. uint8_t g_scsi_log_mask = 0xFF;
  32. // This memory buffer can be read by debugger and is also saved to zululog.txt
  33. #define LOGBUFMASK (LOGBUFSIZE - 1)
  34. // The log buffer is in special uninitialized RAM section so that it is not reset
  35. // when soft rebooting or jumping from bootloader.
  36. uint32_t g_log_magic;
  37. char g_logbuffer[LOGBUFSIZE + 1];
  38. uint32_t g_logpos;
  39. void log_raw(const char *str)
  40. {
  41. // Keep log from reboot / bootloader if magic matches expected value
  42. if (g_log_magic != 0xAA55AA55)
  43. {
  44. g_log_magic = 0xAA55AA55;
  45. g_logpos = 0;
  46. }
  47. const char *p = str;
  48. while (*p)
  49. {
  50. g_logbuffer[g_logpos & LOGBUFMASK] = *p++;
  51. g_logpos++;
  52. }
  53. // Keep buffer null-terminated
  54. g_logbuffer[g_logpos & LOGBUFMASK] = '\0';
  55. platform_log(str);
  56. }
  57. // Log byte as hex
  58. void log_raw(uint8_t value)
  59. {
  60. const char *nibble = "0123456789ABCDEF";
  61. char hexbuf[5] = {
  62. '0', 'x',
  63. nibble[(value >> 4) & 0xF], nibble[(value >> 0) & 0xF],
  64. 0
  65. };
  66. log_raw(hexbuf);
  67. }
  68. // Log integer as hex
  69. void log_raw(uint32_t value)
  70. {
  71. const char *nibble = "0123456789ABCDEF";
  72. char hexbuf[11] = {
  73. '0', 'x',
  74. nibble[(value >> 28) & 0xF], nibble[(value >> 24) & 0xF],
  75. nibble[(value >> 20) & 0xF], nibble[(value >> 16) & 0xF],
  76. nibble[(value >> 12) & 0xF], nibble[(value >> 8) & 0xF],
  77. nibble[(value >> 4) & 0xF], nibble[(value >> 0) & 0xF],
  78. 0
  79. };
  80. log_raw(hexbuf);
  81. }
  82. // Log integer as hex
  83. void log_raw(uint64_t value)
  84. {
  85. const char *nibble = "0123456789ABCDEF";
  86. char hexbuf[19] = {
  87. '0', 'x',
  88. nibble[(value >> 60) & 0xF], nibble[(value >> 56) & 0xF],
  89. nibble[(value >> 52) & 0xF], nibble[(value >> 48) & 0xF],
  90. nibble[(value >> 44) & 0xF], nibble[(value >> 40) & 0xF],
  91. nibble[(value >> 36) & 0xF], nibble[(value >> 32) & 0xF],
  92. nibble[(value >> 28) & 0xF], nibble[(value >> 24) & 0xF],
  93. nibble[(value >> 20) & 0xF], nibble[(value >> 16) & 0xF],
  94. nibble[(value >> 12) & 0xF], nibble[(value >> 8) & 0xF],
  95. nibble[(value >> 4) & 0xF], nibble[(value >> 0) & 0xF],
  96. 0
  97. };
  98. log_raw(hexbuf);
  99. }
  100. // Log integer as decimal
  101. void log_raw(int value)
  102. {
  103. char decbuf[16] = {0};
  104. char *p = &decbuf[14];
  105. int remainder = (value < 0) ? -value : value;
  106. do
  107. {
  108. *--p = '0' + (remainder % 10);
  109. remainder /= 10;
  110. } while (remainder > 0);
  111. if (value < 0)
  112. {
  113. *--p = '-';
  114. }
  115. log_raw(p);
  116. }
  117. void log_raw(bytearray array)
  118. {
  119. for (size_t i = 0; i < array.len; i++)
  120. {
  121. log_raw(array.data[i]);
  122. log_raw(" ");
  123. if (i > 32)
  124. {
  125. log_raw("... (total ", (int)array.len, ")");
  126. break;
  127. }
  128. }
  129. }
  130. uint32_t log_get_buffer_len()
  131. {
  132. return g_logpos;
  133. }
  134. const char *log_get_buffer(uint32_t *startpos, uint32_t *available)
  135. {
  136. uint32_t default_pos = 0;
  137. if (startpos == NULL)
  138. {
  139. startpos = &default_pos;
  140. }
  141. // Check oldest data available in buffer
  142. uint32_t lag = (g_logpos - *startpos);
  143. if (lag >= LOGBUFSIZE)
  144. {
  145. // If we lose data, skip 512 bytes forward to give us time to transmit
  146. // pending data before new log messages arrive. Also skip to next line
  147. // break to keep formatting consistent.
  148. uint32_t oldest = g_logpos - LOGBUFSIZE + 512;
  149. while (oldest < g_logpos)
  150. {
  151. char c = g_logbuffer[oldest & LOGBUFMASK];
  152. if (c == '\r' || c == '\n') break;
  153. oldest++;
  154. }
  155. if (oldest > g_logpos)
  156. {
  157. oldest = g_logpos;
  158. }
  159. *startpos = oldest;
  160. }
  161. const char *result = &g_logbuffer[*startpos & LOGBUFMASK];
  162. // Calculate number of bytes available
  163. uint32_t len;
  164. if ((g_logpos & LOGBUFMASK) >= (*startpos & LOGBUFMASK))
  165. {
  166. // Can read directly to g_logpos
  167. len = g_logpos - *startpos;
  168. }
  169. else
  170. {
  171. // Buffer wraps, read to end of buffer now and start from beginning on next call.
  172. len = LOGBUFSIZE - (*startpos & LOGBUFMASK);
  173. }
  174. if (available) { *available = len; }
  175. *startpos += len;
  176. return result;
  177. }
  178. #ifdef NETWORK_DEBUG_LOGGING
  179. // TODO write directly global log buffer to save some memory
  180. static char shared_log_buf[1500 * 3];
  181. // core method for variadic printf like logging
  182. static void log_va(bool debug, const char *format, va_list ap)
  183. {
  184. vsnprintf(shared_log_buf, sizeof(shared_log_buf), format, ap);
  185. if (debug)
  186. {
  187. dbgmsg(shared_log_buf);
  188. }
  189. else
  190. {
  191. logmsg(shared_log_buf);
  192. }
  193. }
  194. void logmsg_f(const char *format, ...)
  195. {
  196. va_list ap;
  197. va_start(ap, format);
  198. log_va(false, format, ap);
  199. va_end(ap);
  200. }
  201. void dbgmsg_f(const char *format, ...)
  202. {
  203. if (!g_log_debug)
  204. return;
  205. va_list ap;
  206. va_start(ap, format);
  207. log_va(true, format, ap);
  208. va_end(ap);
  209. }
  210. // core method for logging a data buffer into a hex string
  211. void log_hex_buf(const unsigned char *buf, unsigned long size, bool debug)
  212. {
  213. static char hex[] = "0123456789abcdef";
  214. int o = 0;
  215. for (int j = 0; j < size; j++) {
  216. if (o + 3 >= sizeof(shared_log_buf))
  217. break;
  218. if (j != 0)
  219. shared_log_buf[o++] = ' ';
  220. shared_log_buf[o++] = hex[(buf[j] >> 4) & 0xf];
  221. shared_log_buf[o++] = hex[buf[j] & 0xf];
  222. shared_log_buf[o] = 0;
  223. }
  224. if (debug)
  225. dbgmsg(shared_log_buf);
  226. else
  227. logmsg(shared_log_buf);
  228. }
  229. void logmsg_buf(const unsigned char *buf, unsigned long size)
  230. {
  231. log_hex_buf(buf, size, false);
  232. }
  233. void dbgmsg_buf(const unsigned char *buf, unsigned long size)
  234. {
  235. if (!g_log_debug)
  236. return;
  237. log_hex_buf(buf, size, true);
  238. }
  239. #endif // NETWORK_DEBUG_LOGGING