ZuluSCSI_log.cpp 5.8 KB

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