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.

300 lines
8.1 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. #if defined(DEBUG_ESP_PORT)
  177. #if not defined(NDEBUG)
  178. constexpr const bool debug_sdk = true;
  179. #endif // !defined(NDEBUG)
  180. #else
  181. constexpr const bool debug_sdk = false;
  182. #endif // defined(DEBUG_ESP_PORT)
  183. DEBUG_PORT.setDebugOutput(getSetting("dbgSDK", debug_sdk));
  184. #if DEBUG_LOG_BUFFER_SUPPORT
  185. {
  186. const auto enabled = getSetting("dbgBufEnabled", 1 == DEBUG_LOG_BUFFER_ENABLED);
  187. const auto size = getSetting("dbgBufSize", DEBUG_LOG_BUFFER_SIZE);
  188. if (enabled) {
  189. _debug_log_buffer_enabled = true;
  190. _debug_log_buffer.reserve(size);
  191. }
  192. }
  193. #if TERMINAL_SUPPORT
  194. terminalRegisterCommand(F("DEBUG.BUFFER"), [](Embedis* e) {
  195. _debug_log_buffer_enabled = false;
  196. if (!_debug_log_buffer.size()) {
  197. DEBUG_MSG_P(PSTR("[DEBUG] Buffer is empty\n"));
  198. return;
  199. }
  200. DEBUG_MSG_P(PSTR("[DEBUG] Buffer size: %u / %u bytes\n"),
  201. _debug_log_buffer.size(),
  202. _debug_log_buffer.capacity()
  203. );
  204. size_t index = 0;
  205. do {
  206. if (index >= _debug_log_buffer.size()) {
  207. break;
  208. }
  209. size_t len = _debug_log_buffer[index] << 8;
  210. len = len | _debug_log_buffer[index + 1];
  211. index += 2;
  212. auto value = _debug_log_buffer[index + len];
  213. _debug_log_buffer[index + len] = '\0';
  214. _debugSendInternal(_debug_log_buffer.data() + index, false);
  215. _debug_log_buffer[index + len] = value;
  216. index += len;
  217. } while (true);
  218. _debug_log_buffer.clear();
  219. _debug_log_buffer.shrink_to_fit();
  220. });
  221. #endif // TERMINAL_SUPPORT
  222. #endif // DEBUG_LOG_BUFFER
  223. }
  224. #endif // DEBUG_SUPPORT