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.

283 lines
7.4 KiB

  1. /*
  2. TERMINAL MODULE
  3. Copyright (C) 2016-2019 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if TERMINAL_SUPPORT
  6. #include <vector>
  7. #include "libs/EmbedisWrap.h"
  8. #include <Stream.h>
  9. #include "libs/StreamInjector.h"
  10. StreamInjector _serial = StreamInjector(TERMINAL_BUFFER_SIZE);
  11. EmbedisWrap embedis(_serial, TERMINAL_BUFFER_SIZE);
  12. #if SERIAL_RX_ENABLED
  13. char _serial_rx_buffer[TERMINAL_BUFFER_SIZE];
  14. static unsigned char _serial_rx_pointer = 0;
  15. #endif // SERIAL_RX_ENABLED
  16. // -----------------------------------------------------------------------------
  17. // Commands
  18. // -----------------------------------------------------------------------------
  19. void _terminalHelpCommand() {
  20. // Get sorted list of commands
  21. std::vector<String> commands;
  22. unsigned char size = embedis.getCommandCount();
  23. for (unsigned int i=0; i<size; i++) {
  24. String command = embedis.getCommandName(i);
  25. bool inserted = false;
  26. for (unsigned char j=0; j<commands.size(); j++) {
  27. // Check if we have to insert it before the current element
  28. if (commands[j].compareTo(command) > 0) {
  29. commands.insert(commands.begin() + j, command);
  30. inserted = true;
  31. break;
  32. }
  33. }
  34. // If we could not insert it, just push it at the end
  35. if (!inserted) commands.push_back(command);
  36. }
  37. // Output the list
  38. DEBUG_MSG_P(PSTR("Available commands:\n"));
  39. for (unsigned char i=0; i<commands.size(); i++) {
  40. DEBUG_MSG_P(PSTR("> %s\n"), (commands[i]).c_str());
  41. }
  42. }
  43. void _terminalKeysCommand() {
  44. // Get sorted list of keys
  45. std::vector<String> keys = _settingsKeys();
  46. // Write key-values
  47. DEBUG_MSG_P(PSTR("Current settings:\n"));
  48. for (unsigned int i=0; i<keys.size(); i++) {
  49. String value = getSetting(keys[i]);
  50. DEBUG_MSG_P(PSTR("> %s => \"%s\"\n"), (keys[i]).c_str(), value.c_str());
  51. }
  52. unsigned long freeEEPROM = SPI_FLASH_SEC_SIZE - settingsSize();
  53. DEBUG_MSG_P(PSTR("Number of keys: %d\n"), keys.size());
  54. DEBUG_MSG_P(PSTR("Current EEPROM sector: %u\n"), EEPROMr.current());
  55. DEBUG_MSG_P(PSTR("Free EEPROM: %d bytes (%d%%)\n"), freeEEPROM, 100 * freeEEPROM / SPI_FLASH_SEC_SIZE);
  56. }
  57. void _terminalInitCommand() {
  58. #if DEBUG_SUPPORT
  59. terminalRegisterCommand(F("CRASH"), [](Embedis* e) {
  60. crashDump();
  61. crashClear();
  62. terminalOK();
  63. });
  64. #endif
  65. terminalRegisterCommand(F("COMMANDS"), [](Embedis* e) {
  66. _terminalHelpCommand();
  67. terminalOK();
  68. });
  69. terminalRegisterCommand(F("ERASE.CONFIG"), [](Embedis* e) {
  70. terminalOK();
  71. resetReason(CUSTOM_RESET_TERMINAL);
  72. _eepromCommit();
  73. ESP.eraseConfig();
  74. *((int*) 0) = 0; // see https://github.com/esp8266/Arduino/issues/1494
  75. });
  76. terminalRegisterCommand(F("FACTORY.RESET"), [](Embedis* e) {
  77. resetSettings();
  78. terminalOK();
  79. });
  80. terminalRegisterCommand(F("GPIO"), [](Embedis* e) {
  81. if (e->argc < 2) {
  82. terminalError(F("Wrong arguments"));
  83. return;
  84. }
  85. int pin = String(e->argv[1]).toInt();
  86. //if (!gpioValid(pin)) {
  87. // terminalError(F("Invalid GPIO"));
  88. // return;
  89. //}
  90. if (e->argc > 2) {
  91. bool state = String(e->argv[2]).toInt() == 1;
  92. digitalWrite(pin, state);
  93. }
  94. DEBUG_MSG_P(PSTR("GPIO %d is %s\n"), pin, digitalRead(pin) == HIGH ? "HIGH" : "LOW");
  95. terminalOK();
  96. });
  97. terminalRegisterCommand(F("HEAP"), [](Embedis* e) {
  98. infoMemory("Heap", getInitialFreeHeap(), getFreeHeap());
  99. terminalOK();
  100. });
  101. terminalRegisterCommand(F("STACK"), [](Embedis* e) {
  102. infoMemory("Stack", 4096, getFreeStack());
  103. terminalOK();
  104. });
  105. terminalRegisterCommand(F("HELP"), [](Embedis* e) {
  106. _terminalHelpCommand();
  107. terminalOK();
  108. });
  109. terminalRegisterCommand(F("INFO"), [](Embedis* e) {
  110. info();
  111. terminalOK();
  112. });
  113. terminalRegisterCommand(F("KEYS"), [](Embedis* e) {
  114. _terminalKeysCommand();
  115. terminalOK();
  116. });
  117. terminalRegisterCommand(F("GET"), [](Embedis* e) {
  118. if (e->argc < 2) {
  119. terminalError(F("Wrong arguments"));
  120. return;
  121. }
  122. for (unsigned char i = 1; i < e->argc; i++) {
  123. String key = String(e->argv[i]);
  124. String value;
  125. if (!Embedis::get(key, value)) {
  126. DEBUG_MSG_P(PSTR("> %s =>\n"), key.c_str());
  127. continue;
  128. }
  129. DEBUG_MSG_P(PSTR("> %s => \"%s\"\n"), key.c_str(), value.c_str());
  130. }
  131. terminalOK();
  132. });
  133. terminalRegisterCommand(F("RELOAD"), [](Embedis* e) {
  134. espurnaReload();
  135. terminalOK();
  136. });
  137. terminalRegisterCommand(F("RESET"), [](Embedis* e) {
  138. terminalOK();
  139. deferredReset(100, CUSTOM_RESET_TERMINAL);
  140. });
  141. terminalRegisterCommand(F("RESET.SAFE"), [](Embedis* e) {
  142. EEPROMr.write(EEPROM_CRASH_COUNTER, SYSTEM_CHECK_MAX);
  143. terminalOK();
  144. deferredReset(100, CUSTOM_RESET_TERMINAL);
  145. });
  146. terminalRegisterCommand(F("UPTIME"), [](Embedis* e) {
  147. DEBUG_MSG_P(PSTR("Uptime: %d seconds\n"), getUptime());
  148. terminalOK();
  149. });
  150. terminalRegisterCommand(F("CONFIG"), [](Embedis* e) {
  151. DynamicJsonBuffer jsonBuffer;
  152. JsonObject& root = jsonBuffer.createObject();
  153. settingsGetJson(root);
  154. String output;
  155. root.printTo(output);
  156. DEBUG_MSG(output.c_str());
  157. });
  158. #if not SETTINGS_AUTOSAVE
  159. terminalRegisterCommand(F("SAVE"), [](Embedis* e) {
  160. eepromCommit();
  161. DEBUG_MSG_P(PSTR("\n+OK\n"));
  162. });
  163. #endif
  164. }
  165. void _terminalLoop() {
  166. #if DEBUG_SERIAL_SUPPORT
  167. while (DEBUG_PORT.available()) {
  168. _serial.inject(DEBUG_PORT.read());
  169. }
  170. #endif
  171. embedis.process();
  172. #if SERIAL_RX_ENABLED
  173. while (SERIAL_RX_PORT.available() > 0) {
  174. char rc = SERIAL_RX_PORT.read();
  175. _serial_rx_buffer[_serial_rx_pointer++] = rc;
  176. if ((_serial_rx_pointer == TERMINAL_BUFFER_SIZE) || (rc == 10)) {
  177. terminalInject(_serial_rx_buffer, (size_t) _serial_rx_pointer);
  178. _serial_rx_pointer = 0;
  179. }
  180. }
  181. #endif // SERIAL_RX_ENABLED
  182. }
  183. // -----------------------------------------------------------------------------
  184. // Pubic API
  185. // -----------------------------------------------------------------------------
  186. void terminalInject(void *data, size_t len) {
  187. _serial.inject((char *) data, len);
  188. }
  189. Stream & terminalSerial() {
  190. return (Stream &) _serial;
  191. }
  192. void terminalRegisterCommand(const String& name, void (*call)(Embedis*)) {
  193. Embedis::command(name, call);
  194. };
  195. void terminalOK() {
  196. DEBUG_MSG_P(PSTR("+OK\n"));
  197. }
  198. void terminalError(const String& error) {
  199. DEBUG_MSG_P(PSTR("-ERROR: %s\n"), error.c_str());
  200. }
  201. void terminalSetup() {
  202. _serial.callback([](uint8_t ch) {
  203. #if TELNET_SUPPORT
  204. telnetWrite(ch);
  205. #endif
  206. #if DEBUG_SERIAL_SUPPORT
  207. DEBUG_PORT.write(ch);
  208. #endif
  209. });
  210. _terminalInitCommand();
  211. #if SERIAL_RX_ENABLED
  212. SERIAL_RX_PORT.begin(SERIAL_RX_BAUDRATE);
  213. #endif // SERIAL_RX_ENABLED
  214. // Register loop
  215. espurnaRegisterLoop(_terminalLoop);
  216. }
  217. #endif // TERMINAL_SUPPORT