2
0

tty.cpp 9.3 KB

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