tty.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445
  1. #define BAUD_RATE 115200
  2. #include "tty.h"
  3. #include "config.h"
  4. #include "fw.h"
  5. #include "rom/crc.h"
  6. #include <USB.h>
  7. #include <HardwareSerial.h>
  8. #define SOH '\001'
  9. #define STX '\002'
  10. #define ETX '\003'
  11. #define EOT '\004'
  12. #define ENQ '\005'
  13. #define ACK '\006'
  14. #define XON '\021' // DC1
  15. #define WRST '\022' // DC2 - window = 0
  16. #define XOFF '\023' // DC3
  17. #define WGO '\024' // DC4 - window + 256 bytes
  18. #define NAK '\025'
  19. #define SYN '\026'
  20. #define ETB '\027' // Not in upload mode
  21. #define CAN '\030'
  22. #define EM '\031' // Packet offset too high
  23. #define FS '\034'
  24. #define GS '\035'
  25. #define RS '\036'
  26. #define US '\037'
  27. #define WGO_CHUNK 256
  28. #define STREAMBUF_SIZE 2048
  29. #define BUF_SLACK (STREAMBUF_SIZE >> 1)
  30. static char enq_str[] = "\026\035MAX80 v0\004\r\n";
  31. static const char fwupload_start[] =
  32. "\034\001: /// MAX80 FW UPLOAD ~@~ $\r\n\035";
  33. void TTY::reset()
  34. {
  35. rx.rlen = 0;
  36. rx.state = rx_state::normal;
  37. rx.b64_bits = 0;
  38. }
  39. static void null_flush(void)
  40. {
  41. }
  42. TTY::TTY(Stream &port)
  43. {
  44. _port = &port;
  45. rx_sbuf = true ? xStreamBufferCreate(STREAMBUF_SIZE, 1) : NULL;
  46. _flush = null_flush;
  47. reset();
  48. }
  49. TTY::~TTY()
  50. {
  51. if (rx_sbuf)
  52. vStreamBufferDelete(rx_sbuf);
  53. }
  54. int TTY::rxdata(void *buf, size_t len)
  55. {
  56. printf("[TTY] rxdata(%zu) ", len);
  57. if (!rx_sbuf)
  58. return 0;
  59. int rcv = 0;
  60. while (!rcv) {
  61. rcv = xStreamBufferReceive(rx_sbuf, buf, len, 0);
  62. if (rcv)
  63. break;
  64. uint32_t now = millis();
  65. if (now - last_rx > 500) {
  66. last_rx = now;
  67. tx_credits_reset = true;
  68. }
  69. if (tx_credits_reset) {
  70. // Drain input before WRST
  71. flush();
  72. if (port().write(WRST)) {
  73. printf("[UPLD] Resetting window, last_ack = %u\n", rx.last_ack);
  74. tx_credits_reset = false;
  75. tx_credits = STREAMBUF_SIZE - BUF_SLACK;
  76. } else {
  77. // Uhm... wait a tiny bit and then try again to sent WRST?
  78. static bool failed_once = false;
  79. if (!failed_once) {
  80. printf("[UPLD] Failed to reset window?!\n");
  81. failed_once = true;
  82. }
  83. rcv = xStreamBufferReceive(rx_sbuf, buf, len, 1);
  84. }
  85. } else {
  86. while (tx_credits >= WGO_CHUNK && port().write(WGO))
  87. tx_credits -= WGO_CHUNK;
  88. rcv = xStreamBufferReceive(rx_sbuf, buf, len, 1);
  89. tx_credits += rcv;
  90. }
  91. }
  92. printf("got %d\n", rcv);
  93. return rcv;
  94. }
  95. int TTY::rxdata(token_t me, void *buf, size_t len)
  96. {
  97. TTY *tty = (TTY *)me;
  98. return tty->rxdata(buf, len);
  99. }
  100. void TTY::_upload_begin()
  101. {
  102. printf("[TTY] _upload_begin\n");
  103. if (rx_sbuf)
  104. xStreamBufferReset(rx_sbuf);
  105. else
  106. rx_sbuf = xStreamBufferCreate(STREAMBUF_SIZE, 1);
  107. printf("[TTY] rx_sbuf = %p\n", rx_sbuf);
  108. if (!rx_sbuf)
  109. goto can;
  110. port().write(RS);
  111. tx_credits_reset = true;
  112. rx.state = rx_state::stxwait;
  113. rx.last_ack = 0;
  114. rx.rlen = 0;
  115. rx.b64_bits = 0;
  116. printf("[TTY] firmware_update_start()\n");
  117. if (firmware_update_start(TTY::rxdata, (token_t)this, true))
  118. goto can;
  119. return;
  120. can:
  121. port().write(CAN);
  122. rx.state = rx_state::normal;
  123. return;
  124. }
  125. void TTY::_onerr()
  126. {
  127. if (rx.state != rx_state::normal) {
  128. port().write(NAK);
  129. }
  130. }
  131. static int filter_echo(int byte)
  132. {
  133. if (byte >= ' ' && byte < 127)
  134. return byte;
  135. if (byte == '\t' || byte == '\r' || byte == '\n')
  136. return byte;
  137. return -1;
  138. }
  139. // Decode a base64 data byte (using simple offset-63)
  140. // Call with -1 or any invalid value to invalidate the input buffer
  141. int TTY::_decode_data(int input)
  142. {
  143. unsigned int buf = rx.b64_buf;
  144. unsigned int inval = input - '?';
  145. if (inval > 63) {
  146. rx.b64_bits = 0;
  147. return -2; // Invalid input
  148. }
  149. rx.b64_buf = buf = (buf << 6) + inval;
  150. rx.b64_bits += 6;
  151. if (rx.b64_bits >= 8) {
  152. rx.b64_bits -= 8;
  153. return (uint8_t)(buf >> rx.b64_bits);
  154. } else {
  155. return -1;
  156. }
  157. }
  158. // Change this to be a buffer...
  159. void TTY::_onrx()
  160. {
  161. int byte, data;
  162. while ((byte = port().read()) >= 0) {
  163. last_rx = millis();
  164. switch (rx.state) {
  165. case rx_state::normal:
  166. if (rx.rlen < sizeof fwupload_start &&
  167. byte == fwupload_start[rx.rlen]) {
  168. if (!fwupload_start[++rx.rlen]) {
  169. _upload_begin();
  170. byte = -1;
  171. }
  172. } else {
  173. rx.rlen = 0;
  174. switch (byte) {
  175. case ENQ:
  176. port().write(enq_str);
  177. byte = ETB;
  178. break;
  179. case ETX:
  180. case EOT:
  181. case CAN:
  182. byte = ETB; // Not in file upload state
  183. break;
  184. default:
  185. // Echo if printable
  186. byte = filter_echo(byte);
  187. break;
  188. }
  189. }
  190. break;
  191. case rx_state::stxwait:
  192. switch (byte) {
  193. case STX:
  194. rx.rlen = 0;
  195. rx.hdr_raw[rx.rlen++] = byte;
  196. rx.b64_bits = 0;
  197. rx.state = rx_state::hdr;
  198. byte = -1;
  199. break;
  200. case ETX:
  201. case CAN:
  202. printf("[UPLD] Received <%02X> waiting for STX\n", byte);
  203. reset();
  204. byte = CAN;
  205. break;
  206. case ENQ:
  207. rx.rlen = 0;
  208. byte = GS; // In upload wait for STX state
  209. break;
  210. case SYN:
  211. rx.rlen = 0;
  212. tx_credits_reset = true; // Request to resync credits
  213. byte = -1;
  214. break;
  215. case EOT:
  216. // Upload complete, no more data
  217. byte = ETB;
  218. break;
  219. default:
  220. byte = -1; // No echo
  221. break;
  222. }
  223. break;
  224. case rx_state::hdr:
  225. data = _decode_data(byte);
  226. byte = -1;
  227. if (data < -1) {
  228. rx.state = rx_state::stxwait;
  229. rx.rlen = 0;
  230. tx_credits_reset = true;
  231. byte = US; // Framing error
  232. } else if (data == -1) {
  233. // Nothing to do
  234. } else if (rx.rlen >= sizeof rx.hdr_raw) {
  235. // ERROR THIS SHOULD NEVER HAPPEN
  236. printf("[UPLD] Header buffer overrun!!!\n");
  237. reset();
  238. byte = CAN;
  239. } else {
  240. rx.hdr_raw[rx.rlen++] = data;
  241. if (rx.rlen == sizeof rx.hdr) {
  242. // Start of data packet
  243. printf("[UPLD] Start packet hdr %d length %d offset %d last_ack %d\n",
  244. rx.rlen, rx.hdr.len+1, rx.hdr.offs, rx.last_ack);
  245. rx.state = rx_state::data;
  246. rx.rlen = 0;
  247. }
  248. }
  249. break;
  250. case rx_state::data:
  251. data = _decode_data(byte);
  252. byte = -1;
  253. if (data < -1) {
  254. rx.state = rx_state::stxwait;
  255. rx.rlen = 0;
  256. tx_credits_reset = true;
  257. byte = US; // Framing error
  258. } else if (data == -1) {
  259. // Nothing to do
  260. } else if (rx.rlen >= sizeof rx_data) {
  261. // ERROR THIS SHOULD NEVER HAPPEN
  262. printf("[UPLD] Packet data buffer overrun!!!\n");
  263. reset();
  264. byte = CAN;
  265. } else {
  266. rx_data[rx.rlen++] = data;
  267. // rx.hdr.len = packet data len - 1
  268. if (rx.rlen > rx.hdr.len) {
  269. int have = rx.rlen;
  270. uint32_t crc;
  271. if (have != rx.hdr.len + 1) {
  272. printf("[UPLD] Invalid packet length (should not happen...)\n");
  273. byte = NAK;
  274. } else if ((crc = crc32_le(0, rx_data, have))
  275. != rx.hdr.crc) {
  276. printf("[UPLD] Packet CRC error hdr %08x data %08x\n", rx.hdr.crc, crc);
  277. printf("\"");
  278. for (int i = 0; i < have; i++)
  279. printf("\\x%02x", rx_data[i]);
  280. printf("\"\n");
  281. byte = NAK;
  282. } else if (rx.hdr.offs > rx.last_ack) {
  283. printf("[UPLD] Invalid packet offsets [%d..%d) at %d\n",
  284. rx.hdr.offs, rx.hdr.offs + have, rx.last_ack);
  285. byte = EM;
  286. } else if (rx.hdr.offs + have <= rx.last_ack) {
  287. // Ack and discard packet below current window (transmitter is catching up)
  288. byte = ACK;
  289. } else {
  290. int sent = 0;
  291. uint32_t skip = rx.last_ack - rx.hdr.offs;
  292. have -= skip;
  293. sent = xStreamBufferSend(rx_sbuf, rx_data+skip, have, 0);
  294. rx.last_ack += sent;
  295. if (sent != have) {
  296. printf("[UPLD] Packet underrun, got %d, expected %d\n", sent, have);
  297. byte = NAK;
  298. } else {
  299. printf("[UPLD] %d bytes received OK\n", sent);
  300. byte = ACK;
  301. }
  302. }
  303. if (byte != ACK)
  304. tx_credits_reset = true;
  305. rx.state = rx_state::stxwait;
  306. rx.rlen = 0;
  307. }
  308. }
  309. break;
  310. }
  311. if (byte >= 0)
  312. port().write(byte);
  313. }
  314. }
  315. void TTY::_onconnect()
  316. {
  317. port().write(XON);
  318. }
  319. void TTY::_onbreak()
  320. {
  321. reset();
  322. }
  323. void TTY::_ondisconnect()
  324. {
  325. reset();
  326. }
  327. static TTY *uart_tty, *usb_tty;
  328. void TTY::usb_onevent(void *arg, esp_event_base_t event_base,
  329. int32_t event_id, void *event_data)
  330. {
  331. switch (event_id) {
  332. case ARDUINO_USB_CDC_CONNECTED_EVENT:
  333. case ARDUINO_USB_CDC_LINE_STATE_EVENT:
  334. usb_tty->_onconnect();
  335. break;
  336. case ARDUINO_USB_CDC_DISCONNECTED_EVENT:
  337. usb_tty->_ondisconnect();
  338. break;
  339. case ARDUINO_USB_CDC_RX_EVENT:
  340. usb_tty->_onrx();
  341. break;
  342. case ARDUINO_USB_CDC_RX_OVERFLOW_EVENT:
  343. usb_tty->_onerr();
  344. break;
  345. default:
  346. // Do nothing
  347. break;
  348. }
  349. }
  350. void TTY::uart_onrx(void)
  351. {
  352. uart_tty->_onrx();
  353. }
  354. void TTY::uart_onerr(hardwareSerial_error_t err)
  355. {
  356. switch (err) {
  357. case UART_BREAK_ERROR:
  358. uart_tty->_onbreak();
  359. break;
  360. default:
  361. uart_tty->_onerr();
  362. break;
  363. }
  364. }
  365. static void uart_flush()
  366. {
  367. Serial0.flush(true);
  368. }
  369. static void usb_flush()
  370. {
  371. Serial.flush();
  372. }
  373. void TTY::init()
  374. {
  375. enq_str[sizeof(enq_str)-5] += max80_board_version;
  376. uart_tty = new TTY(Serial0);
  377. uart_tty->_flush = uart_flush;
  378. Serial0.begin(BAUD_RATE);
  379. Serial0.onReceive(uart_onrx, false);
  380. Serial0.onReceiveError(uart_onerr);
  381. usb_tty = new TTY(Serial);
  382. usb_tty->_flush = usb_flush;
  383. Serial.onEvent(usb_onevent);
  384. Serial.enableReboot(true);
  385. }
  386. void TTY::ping()
  387. {
  388. }