Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

296 lines
8.0 KiB

7 years ago
6 years ago
6 years ago
7 years ago
7 years ago
6 years ago
7 years ago
  1. /*
  2. DEBUG MODULE
  3. Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if DEBUG_SUPPORT
  6. #include <limits>
  7. #include <vector>
  8. #include "debug.h"
  9. #if DEBUG_UDP_SUPPORT
  10. #include <WiFiUdp.h>
  11. WiFiUDP _udp_debug;
  12. #if DEBUG_UDP_PORT == 514
  13. char _udp_syslog_header[40] = {0};
  14. #endif
  15. #endif
  16. // -----------------------------------------------------------------------------
  17. // printf-like debug methods
  18. // -----------------------------------------------------------------------------
  19. constexpr const int DEBUG_SEND_STRING_BUFFER_SIZE = 128;
  20. void _debugSendInternal(const char * message, bool add_timestamp = DEBUG_ADD_TIMESTAMP);
  21. // TODO: switch to newlib vsnprintf for latest Cores to support PROGMEM args
  22. void _debugSend(const char * format, va_list args) {
  23. char temp[DEBUG_SEND_STRING_BUFFER_SIZE];
  24. int len = ets_vsnprintf(temp, sizeof(temp), format, args);
  25. // strlen(...) + '\0' already in temp buffer, avoid using malloc when possible
  26. if (len < DEBUG_SEND_STRING_BUFFER_SIZE) {
  27. _debugSendInternal(temp);
  28. return;
  29. }
  30. len += 1;
  31. auto* buffer = static_cast<char*>(malloc(len));
  32. if (!buffer) {
  33. return;
  34. }
  35. ets_vsnprintf(buffer, len, format, args);
  36. _debugSendInternal(buffer);
  37. free(buffer);
  38. }
  39. void debugSend(const char* format, ...) {
  40. va_list args;
  41. va_start(args, format);
  42. _debugSend(format, args);
  43. va_end(args);
  44. }
  45. void debugSend_P(PGM_P format_P, ...) {
  46. char format[strlen_P(format_P) + 1];
  47. memcpy_P(format, format_P, sizeof(format));
  48. va_list args;
  49. va_start(args, format_P);
  50. _debugSend(format, args);
  51. va_end(args);
  52. }
  53. // -----------------------------------------------------------------------------
  54. // specific debug targets
  55. // -----------------------------------------------------------------------------
  56. #if DEBUG_SERIAL_SUPPORT
  57. void _debugSendSerial(const char* prefix, const char* data) {
  58. if (prefix && (prefix[0] != '\0')) {
  59. DEBUG_PORT.print(prefix);
  60. }
  61. DEBUG_PORT.print(data);
  62. }
  63. #endif // DEBUG_SERIAL_SUPPORT
  64. #if DEBUG_TELNET_SUPPORT
  65. void _debugSendTelnet(const char* prefix, const char* data) {
  66. if (prefix && (prefix[0] != '\0')) {
  67. _telnetWrite(prefix);
  68. }
  69. _telnetWrite(data);
  70. }
  71. #endif // DEBUG_TELNET_SUPPORT
  72. #if DEBUG_LOG_BUFFER_SUPPORT
  73. std::vector<char> _debug_log_buffer;
  74. bool _debug_log_buffer_enabled = false;
  75. void _debugLogBuffer(const char* prefix, const char* data) {
  76. if (!_debug_log_buffer_enabled) return;
  77. const auto prefix_len = strlen(prefix);
  78. const auto data_len = strlen(data);
  79. const auto total_len = prefix_len + data_len;
  80. if (total_len >= std::numeric_limits<uint16_t>::max()) {
  81. return;
  82. }
  83. if ((_debug_log_buffer.capacity() - _debug_log_buffer.size()) <= (total_len + 3)) {
  84. _debug_log_buffer_enabled = false;
  85. return;
  86. }
  87. _debug_log_buffer.push_back(total_len >> 8);
  88. _debug_log_buffer.push_back(total_len & 0xff);
  89. if (prefix && (prefix[0] != '\0')) {
  90. _debug_log_buffer.insert(_debug_log_buffer.end(), prefix, prefix + prefix_len);
  91. }
  92. _debug_log_buffer.insert(_debug_log_buffer.end(), data, data + data_len);
  93. }
  94. bool debugLogBuffer() {
  95. return _debug_log_buffer_enabled;
  96. }
  97. #endif // DEBUG_LOG_BUFFER_SUPPORT
  98. // -----------------------------------------------------------------------------
  99. void _debugSendInternal(const char * message, bool add_timestamp) {
  100. const size_t msg_len = strlen(message);
  101. bool pause = false;
  102. char timestamp[10] = {0};
  103. #if DEBUG_ADD_TIMESTAMP
  104. static bool continue_timestamp = true;
  105. if (add_timestamp && continue_timestamp) {
  106. snprintf(timestamp, sizeof(timestamp), "[%06lu] ", millis() % 1000000);
  107. }
  108. continue_timestamp = add_timestamp || (message[msg_len - 1] == 10) || (message[msg_len - 1] == 13);
  109. #endif
  110. #if DEBUG_SERIAL_SUPPORT
  111. _debugSendSerial(timestamp, message);
  112. #endif
  113. #if DEBUG_UDP_SUPPORT
  114. #if SYSTEM_CHECK_ENABLED
  115. if (systemCheck()) {
  116. #endif
  117. _udp_debug.beginPacket(DEBUG_UDP_IP, DEBUG_UDP_PORT);
  118. #if DEBUG_UDP_PORT == 514
  119. _udp_debug.write(_udp_syslog_header);
  120. #endif
  121. _udp_debug.write(message);
  122. _udp_debug.endPacket();
  123. pause = true;
  124. #if SYSTEM_CHECK_ENABLED
  125. }
  126. #endif
  127. #endif
  128. #if DEBUG_TELNET_SUPPORT
  129. _debugSendTelnet(timestamp, message);
  130. pause = true;
  131. #endif
  132. #if DEBUG_WEB_SUPPORT
  133. wsDebugSend(timestamp, message);
  134. pause = true;
  135. #endif
  136. #if DEBUG_LOG_BUFFER_SUPPORT
  137. _debugLogBuffer(timestamp, message);
  138. #endif
  139. if (pause) optimistic_yield(100);
  140. }
  141. // -----------------------------------------------------------------------------
  142. #if DEBUG_WEB_SUPPORT
  143. void _debugWebSocketOnAction(uint32_t client_id, const char * action, JsonObject& data) {
  144. #if TERMINAL_SUPPORT
  145. if (strcmp(action, "dbgcmd") == 0) {
  146. if (!data.containsKey("command") || !data["command"].is<const char*>()) return;
  147. const char* command = data["command"];
  148. if (command && strlen(command)) {
  149. auto command = data.get<const char*>("command");
  150. terminalInject((void*) command, strlen(command));
  151. terminalInject('\n');
  152. }
  153. }
  154. #endif
  155. }
  156. void debugWebSetup() {
  157. wsRegister()
  158. .onVisible([](JsonObject& root) { root["dbgVisible"] = 1; })
  159. .onAction(_debugWebSocketOnAction);
  160. // TODO: if hostname string changes, need to update header too
  161. #if DEBUG_UDP_SUPPORT
  162. #if DEBUG_UDP_PORT == 514
  163. snprintf_P(_udp_syslog_header, sizeof(_udp_syslog_header), PSTR("<%u>%s ESPurna[0]: "), DEBUG_UDP_FAC_PRI, getSetting("hostname").c_str());
  164. #endif
  165. #endif
  166. }
  167. #endif // DEBUG_WEB_SUPPORT
  168. // -----------------------------------------------------------------------------
  169. void debugSetup() {
  170. #if DEBUG_SERIAL_SUPPORT
  171. DEBUG_PORT.begin(SERIAL_BAUDRATE);
  172. #endif
  173. // HardwareSerial::begin() will automatically enable this when
  174. // `#if defined(DEBUG_ESP_PORT) && !defined(NDEBUG)`
  175. // Core debugging also depends on various DEBUG_ESP_... being defined
  176. #define DEBUG_SERIAL_SDK (int)(defined(DEBUG_ESP_PORT) && !defined(NDEBUG))
  177. if (getSetting("dbgSDK", DEBUG_SERIAL_SDK).toInt() == 1) {
  178. DEBUG_PORT.setDebugOutput(true);
  179. }
  180. #undef DEBUG_SERIAL_SDK
  181. #if DEBUG_LOG_BUFFER_SUPPORT
  182. {
  183. auto enabled = getSetting("dbgBufEnabled", DEBUG_LOG_BUFFER_ENABLED).toInt() == 1;
  184. auto size = getSetting("dbgBufSize", DEBUG_LOG_BUFFER_SIZE).toInt();
  185. if (enabled) {
  186. _debug_log_buffer_enabled = true;
  187. _debug_log_buffer.reserve(size);
  188. }
  189. }
  190. #if TERMINAL_SUPPORT
  191. terminalRegisterCommand(F("DEBUG.BUFFER"), [](Embedis* e) {
  192. _debug_log_buffer_enabled = false;
  193. if (!_debug_log_buffer.size()) {
  194. DEBUG_MSG_P(PSTR("[DEBUG] Buffer is empty\n"));
  195. return;
  196. }
  197. DEBUG_MSG_P(PSTR("[DEBUG] Buffer size: %u / %u bytes\n"),
  198. _debug_log_buffer.size(),
  199. _debug_log_buffer.capacity()
  200. );
  201. size_t index = 0;
  202. do {
  203. if (index >= _debug_log_buffer.size()) {
  204. break;
  205. }
  206. size_t len = _debug_log_buffer[index] << 8;
  207. len = len | _debug_log_buffer[index + 1];
  208. index += 2;
  209. auto value = _debug_log_buffer[index + len];
  210. _debug_log_buffer[index + len] = '\0';
  211. _debugSendInternal(_debug_log_buffer.data() + index, false);
  212. _debug_log_buffer[index + len] = value;
  213. index += len;
  214. } while (true);
  215. _debug_log_buffer.clear();
  216. _debug_log_buffer.shrink_to_fit();
  217. });
  218. #endif // TERMINAL_SUPPORT
  219. #endif // DEBUG_LOG_BUFFER
  220. }
  221. #endif // DEBUG_SUPPORT