slip.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. // Copyright 2015 by Thorsten von Eicken, see LICENSE.txt
  2. #include "esp8266.h"
  3. #include "uart.h"
  4. #include "crc16.h"
  5. #include "serbridge.h"
  6. #include "console.h"
  7. #include "cmd.h"
  8. #ifdef SLIP_DBG
  9. #define DBG(format, ...) do { os_printf(format, ## __VA_ARGS__); } while(0)
  10. #else
  11. #define DBG(format, ...) do { } while(0)
  12. #endif
  13. extern void ICACHE_FLASH_ATTR console_process(char *buf, short len);
  14. // This SLIP parser tries to conform to RFC 1055 https://tools.ietf.org/html/rfc1055.
  15. // It accumulates each packet into a static buffer and calls cmd_parse() when the end
  16. // of a packet is reached. It expects cmd_parse() to copy anything it needs from the
  17. // buffer elsewhere as the buffer is immediately reused.
  18. // One special feature is that if the first two characters of a packet are both printable or
  19. // \n or \r then the parser assumes it's dealing with console debug output and calls
  20. // slip_console(c) for each character and does not accumulate chars in the buffer until the
  21. // next SLIP_END marker is seen. This allows random console debug output to come in between
  22. // packets as long as each packet starts *and* ends with SLIP_END (which is an official
  23. // variation on the SLIP protocol).
  24. static bool slip_escaped; // true when prev char received is escape
  25. static bool slip_inpkt; // true when we're after SLIP_START and before SLIP_END
  26. #define SLIP_MAX 1024 // max length of SLIP packet
  27. static char slip_buf[SLIP_MAX]; // buffer for current SLIP packet
  28. static short slip_len; // accumulated length in slip_buf
  29. // SLIP process a packet or a bunch of debug console chars
  30. static void ICACHE_FLASH_ATTR
  31. slip_process() {
  32. if (slip_len > 2) {
  33. // proper SLIP packet, invoke command processor after checking CRC
  34. //os_printf("SLIP: rcv %d\n", slip_len);
  35. uint16_t crc = crc16_data((uint8_t*)slip_buf, slip_len-2, 0);
  36. uint16_t rcv = ((uint16_t)slip_buf[slip_len-2]) | ((uint16_t)slip_buf[slip_len-1] << 8);
  37. if (crc == rcv) {
  38. cmdParsePacket((uint8_t*)slip_buf, slip_len-2);
  39. } else {
  40. os_printf("SLIP: bad CRC, crc=%04x rcv=%04x len=%d\n", crc, rcv, slip_len);
  41. for (short i=0; i<slip_len; i++) {
  42. if (slip_buf[i] >= ' ' && slip_buf[i] <= '~') {
  43. DBG("%c", slip_buf[i]);
  44. } else {
  45. DBG("\\%02X", slip_buf[i]);
  46. }
  47. }
  48. DBG("\n");
  49. }
  50. }
  51. }
  52. // determine whether a character is printable or not (or \r \n)
  53. static bool ICACHE_FLASH_ATTR
  54. slip_printable(char c) {
  55. return (c >= ' ' && c <= '~') || c == '\n' || c == '\r';
  56. }
  57. static void ICACHE_FLASH_ATTR
  58. slip_reset() {
  59. //os_printf("SLIP: reset\n");
  60. slip_inpkt = true;
  61. slip_escaped = false;
  62. slip_len = 0;
  63. }
  64. // SLIP parse a single character
  65. static void ICACHE_FLASH_ATTR
  66. slip_parse_char(char c) {
  67. if (c == SLIP_END) {
  68. // either start or end of packet, process whatever we may have accumulated
  69. DBG("SLIP: start or end len=%d inpkt=%d\n", slip_len, slip_inpkt);
  70. if (slip_len > 0) {
  71. if (slip_len > 2 && slip_inpkt) slip_process();
  72. else console_process(slip_buf, slip_len);
  73. }
  74. slip_reset();
  75. } else if (slip_escaped) {
  76. // prev char was SLIP_ESC
  77. if (c == SLIP_ESC_END) c = SLIP_END;
  78. if (c == SLIP_ESC_ESC) c = SLIP_ESC;
  79. if (slip_len < SLIP_MAX) slip_buf[slip_len++] = c;
  80. slip_escaped = false;
  81. } else if (slip_inpkt && c == SLIP_ESC) {
  82. slip_escaped = true;
  83. } else {
  84. if (slip_len == 1 && slip_printable(slip_buf[0]) && slip_printable(c)) {
  85. // start of packet and it's a printable character, we're gonna assume that this is console text
  86. slip_inpkt = false;
  87. }
  88. if (slip_len < SLIP_MAX) slip_buf[slip_len++] = c;
  89. }
  90. }
  91. // callback with a buffer of characters that have arrived on the uart
  92. void ICACHE_FLASH_ATTR
  93. slip_parse_buf(char *buf, short length) {
  94. // do SLIP parsing
  95. for (short i=0; i<length; i++)
  96. slip_parse_char(buf[i]);
  97. // if we're in-between packets (debug console) then print it now
  98. if (!slip_inpkt && length > 0) {
  99. console_process(slip_buf, slip_len);
  100. slip_len = 0;
  101. }
  102. }