Teensy 4.1 core updated for C++20
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.

734 lines
16KB

  1. /* USB API for Teensy USB Development Board
  2. * http://www.pjrc.com/teensy/teensyduino.html
  3. * Copyright (c) 2012 PJRC.COM, LLC
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. * THE SOFTWARE.
  22. */
  23. #include <avr/io.h>
  24. #include <avr/pgmspace.h>
  25. #include <stdint.h>
  26. #include "usb_common.h"
  27. #include "usb_private.h"
  28. #include "usb_api.h"
  29. #include "wiring.h"
  30. FlightSimCommand * FlightSimCommand::first = NULL;
  31. FlightSimCommand * FlightSimCommand::last = NULL;
  32. FlightSimInteger * FlightSimInteger::first = NULL;
  33. FlightSimInteger * FlightSimInteger::last = NULL;
  34. FlightSimFloat * FlightSimFloat::first = NULL;
  35. FlightSimFloat * FlightSimFloat::last = NULL;
  36. uint8_t FlightSimClass::enabled = 0;
  37. uint8_t FlightSimClass::request_id_messages = 0;
  38. unsigned long FlightSimClass::frameCount = 0;
  39. elapsedMillis FlightSimClass::enableTimeout;
  40. static unsigned int unassigned_id = 1; // TODO: move into FlightSimClass
  41. FlightSimCommand::FlightSimCommand()
  42. {
  43. id = unassigned_id++;
  44. if (!first) {
  45. first = this;
  46. } else {
  47. last->next = this;
  48. }
  49. last = this;
  50. name = NULL;
  51. next = NULL;
  52. FlightSimClass::request_id_messages = 1;
  53. }
  54. void FlightSimCommand::identify(void)
  55. {
  56. uint8_t len, buf[6];
  57. if (!FlightSim.enabled || !name) return;
  58. len = strlen_P((const char *)name);
  59. buf[0] = len + 6;
  60. buf[1] = 1;
  61. buf[2] = id;
  62. buf[3] = id >> 8;
  63. buf[4] = 0;
  64. buf[5] = 0;
  65. FlightSimClass::xmit(buf, 6, name, len);
  66. }
  67. void FlightSimCommand::sendcmd(uint8_t n)
  68. {
  69. uint8_t buf[4];
  70. if (!FlightSim.enabled || !name) return;
  71. buf[0] = 4;
  72. buf[1] = n;
  73. buf[2] = id;
  74. buf[3] = id >> 8;
  75. FlightSimClass::xmit(buf, 4);
  76. }
  77. FlightSimInteger::FlightSimInteger()
  78. {
  79. id = unassigned_id++;
  80. if (!first) {
  81. first = this;
  82. } else {
  83. last->next = this;
  84. }
  85. last = this;
  86. name = NULL;
  87. next = NULL;
  88. value = 0;
  89. change_callback = NULL;
  90. FlightSimClass::request_id_messages = 1;
  91. }
  92. void FlightSimInteger::identify(void)
  93. {
  94. uint8_t len, buf[6];
  95. if (!FlightSim.enabled || !name) return;
  96. len = strlen_P((const char *)name);
  97. buf[0] = len + 6;
  98. buf[1] = 1;
  99. buf[2] = id;
  100. buf[3] = id >> 8;
  101. buf[4] = 1;
  102. buf[5] = 0;
  103. FlightSimClass::xmit(buf, 6, name, len);
  104. }
  105. void FlightSimInteger::write(long val)
  106. {
  107. uint8_t buf[6];
  108. value = val;
  109. if (!FlightSim.enabled || !name) return; // TODO: mark as dirty
  110. buf[0] = 10;
  111. buf[1] = 2;
  112. buf[2] = id;
  113. buf[3] = id >> 8;
  114. buf[4] = 1;
  115. buf[5] = 0;
  116. FlightSimClass::xmit(buf, 6, (uint8_t *)&value, 4);
  117. }
  118. void FlightSimInteger::update(long val)
  119. {
  120. value = val;
  121. if (change_callback) (*change_callback)(val);
  122. }
  123. FlightSimInteger * FlightSimInteger::find(unsigned int n)
  124. {
  125. for (FlightSimInteger *p = first; p; p = p->next) {
  126. if (p->id == n) return p;
  127. }
  128. return NULL;
  129. }
  130. FlightSimFloat::FlightSimFloat()
  131. {
  132. id = unassigned_id++;
  133. if (!first) {
  134. first = this;
  135. } else {
  136. last->next = this;
  137. }
  138. last = this;
  139. name = NULL;
  140. next = NULL;
  141. value = 0;
  142. change_callback = NULL;
  143. FlightSimClass::request_id_messages = 1;
  144. }
  145. void FlightSimFloat::identify(void)
  146. {
  147. uint8_t len, buf[6];
  148. if (!FlightSim.enabled || !name) return;
  149. len = strlen_P((const char *)name);
  150. buf[0] = len + 6;
  151. buf[1] = 1;
  152. buf[2] = id;
  153. buf[3] = id >> 8;
  154. buf[4] = 2;
  155. buf[5] = 0;
  156. FlightSimClass::xmit(buf, 6, name, len);
  157. }
  158. void FlightSimFloat::write(float val)
  159. {
  160. uint8_t buf[6];
  161. value = val;
  162. if (!FlightSim.enabled || !name) return; // TODO: mark as dirty
  163. buf[0] = 10;
  164. buf[1] = 2;
  165. buf[2] = id;
  166. buf[3] = id >> 8;
  167. buf[4] = 2;
  168. buf[5] = 0;
  169. FlightSimClass::xmit(buf, 6, (uint8_t *)&value, 4);
  170. }
  171. void FlightSimFloat::update(float val)
  172. {
  173. value = val;
  174. if (change_callback) (*change_callback)(val);
  175. }
  176. FlightSimFloat * FlightSimFloat::find(unsigned int n)
  177. {
  178. for (FlightSimFloat *p = first; p; p = p->next) {
  179. if (p->id == n) return p;
  180. }
  181. return NULL;
  182. }
  183. FlightSimClass::FlightSimClass()
  184. {
  185. }
  186. void FlightSimClass::update(void)
  187. {
  188. uint8_t len, maxlen, type, buf[64], *p;
  189. uint16_t id;
  190. while (recv(buf)) {
  191. p = buf;
  192. maxlen = 64;
  193. do {
  194. len = p[0];
  195. if (len < 2 || len > maxlen) break;
  196. switch (p[1]) {
  197. case 0x02: // write data
  198. if (len < 10) break;
  199. id = p[2] | (p[3] << 8);
  200. type = p[4];
  201. if (type == 1) {
  202. FlightSimInteger *item = FlightSimInteger::find(id);
  203. if (!item) break;
  204. item->update(*(long *)(p + 6));
  205. } else if (type == 2) {
  206. FlightSimFloat *item = FlightSimFloat::find(id);
  207. if (!item) break;
  208. item->update(*(float *)(p + 6));
  209. }
  210. break;
  211. case 0x03: // enable/disable
  212. if (len < 4) break;
  213. switch (p[2]) {
  214. case 1:
  215. request_id_messages = 1;
  216. case 2:
  217. enable();
  218. frameCount++;
  219. break;
  220. case 3:
  221. disable();
  222. }
  223. }
  224. p += len;
  225. maxlen -= len;
  226. } while (p < buf + 64);
  227. }
  228. if (enabled && request_id_messages) {
  229. request_id_messages = 0;
  230. for (FlightSimCommand *p = FlightSimCommand::first; p; p = p->next) {
  231. p->identify();
  232. }
  233. for (FlightSimInteger *p = FlightSimInteger::first; p; p = p->next) {
  234. p->identify();
  235. // TODO: send any dirty data
  236. }
  237. for (FlightSimFloat *p = FlightSimFloat::first; p; p = p->next) {
  238. p->identify();
  239. // TODO: send any dirty data
  240. }
  241. }
  242. }
  243. bool FlightSimClass::isEnabled(void)
  244. {
  245. if (!usb_configuration) return false;
  246. if (!enabled) return false;
  247. if (enableTimeout > 1500) return false;
  248. return true;
  249. }
  250. // receive a packet
  251. uint8_t FlightSimClass::recv(uint8_t *buffer)
  252. {
  253. uint8_t intr_state;
  254. // if we're not online (enumerated and configured), error
  255. if (!usb_configuration) return 0;
  256. intr_state = SREG;
  257. cli();
  258. UENUM = FLIGHTSIM_RX_ENDPOINT;
  259. if (!(UEINTX & (1<<RWAL))) {
  260. SREG = intr_state;
  261. return 0;
  262. }
  263. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  264. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  265. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  266. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  267. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  268. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  269. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  270. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  271. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  272. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  273. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  274. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  275. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  276. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  277. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  278. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  279. UEINTX = 0x6B;
  280. SREG = intr_state;
  281. return 1;
  282. }
  283. void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1)
  284. {
  285. uint8_t intr_state, avail;
  286. if (n1 > FLIGHTSIM_TX_SIZE) return;
  287. if (!enabled || !usb_configuration) return;
  288. intr_state = SREG;
  289. cli();
  290. UENUM = FLIGHTSIM_TX_ENDPOINT;
  291. avail = FLIGHTSIM_TX_SIZE - UEBCLX;
  292. if ((UEINTX & (1<<RWAL)) && (avail >= n1)) {
  293. goto send;
  294. } else {
  295. while (avail) {
  296. UEDATX = 0;
  297. avail--;
  298. }
  299. UEINTX = 0x3A;
  300. while (1) {
  301. if (UEINTX & (1<<RWAL)) break;
  302. SREG = intr_state;
  303. if (!enabled || !usb_configuration) return;
  304. intr_state = SREG;
  305. cli();
  306. UENUM = FLIGHTSIM_TX_ENDPOINT;
  307. }
  308. }
  309. send:
  310. do {
  311. UEDATX = *p1++;
  312. } while (--n1 > 0);
  313. if (UEBCLX == FLIGHTSIM_TX_SIZE) UEINTX = 0x3A;
  314. SREG = intr_state;
  315. }
  316. void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1, const uint8_t *p2, uint8_t n2)
  317. {
  318. uint8_t intr_state, total, avail;
  319. total = n1 + n2;
  320. if (total > FLIGHTSIM_TX_SIZE) return;
  321. if (!enabled || !usb_configuration) return;
  322. intr_state = SREG;
  323. cli();
  324. UENUM = FLIGHTSIM_TX_ENDPOINT;
  325. avail = FLIGHTSIM_TX_SIZE - UEBCLX;
  326. if ((UEINTX & (1<<RWAL)) && (avail >= total)) {
  327. goto send;
  328. } else {
  329. while (avail) {
  330. UEDATX = 0;
  331. avail--;
  332. }
  333. UEINTX = 0x3A;
  334. while (1) {
  335. if (UEINTX & (1<<RWAL)) break;
  336. SREG = intr_state;
  337. if (!enabled || !usb_configuration) return;
  338. intr_state = SREG;
  339. cli();
  340. UENUM = FLIGHTSIM_TX_ENDPOINT;
  341. }
  342. }
  343. send:
  344. do {
  345. UEDATX = *p1++;
  346. } while (--n1 > 0);
  347. do {
  348. UEDATX = *p2++;
  349. } while (--n2 > 0);
  350. if (UEBCLX == FLIGHTSIM_TX_SIZE) UEINTX = 0x3A;
  351. SREG = intr_state;
  352. }
  353. void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint8_t n2)
  354. {
  355. uint8_t intr_state, total, avail;
  356. const char *s2 = (const char *)p2;
  357. total = n1 + n2;
  358. if (total > FLIGHTSIM_TX_SIZE) return;
  359. if (!enabled || !usb_configuration) return;
  360. intr_state = SREG;
  361. cli();
  362. UENUM = FLIGHTSIM_TX_ENDPOINT;
  363. avail = FLIGHTSIM_TX_SIZE - UEBCLX;
  364. if ((UEINTX & (1<<RWAL)) && (avail >= total)) {
  365. goto send;
  366. } else {
  367. while (avail) {
  368. UEDATX = 0;
  369. avail--;
  370. }
  371. UEINTX = 0x3A;
  372. while (1) {
  373. if (UEINTX & (1<<RWAL)) break;
  374. SREG = intr_state;
  375. if (!enabled || !usb_configuration) return;
  376. intr_state = SREG;
  377. cli();
  378. UENUM = FLIGHTSIM_TX_ENDPOINT;
  379. }
  380. }
  381. send:
  382. do {
  383. UEDATX = *p1++;
  384. } while (--n1 > 0);
  385. do {
  386. pgm_read_byte_postinc(UEDATX, s2);
  387. } while (--n2 > 0);
  388. if (UEBCLX == FLIGHTSIM_TX_SIZE) UEINTX = 0x3A;
  389. SREG = intr_state;
  390. }
  391. FlightSimClass FlightSim;
  392. static volatile uint8_t prev_byte=0;
  393. void usb_serial_class::begin(long speed)
  394. {
  395. // make sure USB is initialized
  396. usb_init();
  397. uint16_t begin_wait = (uint16_t)millis();
  398. while (1) {
  399. if (usb_configuration) {
  400. delay(200); // a little time for host to load a driver
  401. return;
  402. }
  403. if (usb_suspended) {
  404. uint16_t begin_suspend = (uint16_t)millis();
  405. while (usb_suspended) {
  406. // must remain suspended for a while, because
  407. // normal USB enumeration causes brief suspend
  408. // states, typically under 0.1 second
  409. if ((uint16_t)millis() - begin_suspend > 250) {
  410. return;
  411. }
  412. }
  413. }
  414. // ... or a timout (powered by a USB power adaptor that
  415. // wiggles the data lines to keep a USB device charging)
  416. if ((uint16_t)millis() - begin_wait > 2500) return;
  417. }
  418. prev_byte = 0;
  419. }
  420. void usb_serial_class::end()
  421. {
  422. usb_shutdown();
  423. delay(25);
  424. }
  425. // number of bytes available in the receive buffer
  426. int usb_serial_class::available()
  427. {
  428. uint8_t c;
  429. c = prev_byte; // assume 1 byte static volatile access is atomic
  430. if (c) return 1;
  431. c = readnext();
  432. if (c) {
  433. prev_byte = c;
  434. return 1;
  435. }
  436. return 0;
  437. }
  438. // get the next character, or -1 if nothing received
  439. int usb_serial_class::read()
  440. {
  441. uint8_t c;
  442. c = prev_byte;
  443. if (c) {
  444. prev_byte = 0;
  445. return c;
  446. }
  447. c = readnext();
  448. if (c) return c;
  449. return -1;
  450. }
  451. int usb_serial_class::peek()
  452. {
  453. uint8_t c;
  454. c = prev_byte;
  455. if (c) return c;
  456. c = readnext();
  457. if (c) {
  458. prev_byte = c;
  459. return c;
  460. }
  461. return -1;
  462. }
  463. // get the next character, or 0 if nothing
  464. uint8_t usb_serial_class::readnext(void)
  465. {
  466. uint8_t c, intr_state;
  467. // interrupts are disabled so these functions can be
  468. // used from the main program or interrupt context,
  469. // even both in the same program!
  470. intr_state = SREG;
  471. cli();
  472. if (!usb_configuration) {
  473. SREG = intr_state;
  474. return 0;
  475. }
  476. UENUM = DEBUG_RX_ENDPOINT;
  477. try_again:
  478. if (!(UEINTX & (1<<RWAL))) {
  479. // no packet in buffer
  480. SREG = intr_state;
  481. return 0;
  482. }
  483. // take one byte out of the buffer
  484. c = UEDATX;
  485. if (c == 0) {
  486. // if we see a zero, discard it and
  487. // discard the rest of this packet
  488. UEINTX = 0x6B;
  489. goto try_again;
  490. }
  491. // if this drained the buffer, release it
  492. if (!(UEINTX & (1<<RWAL))) UEINTX = 0x6B;
  493. SREG = intr_state;
  494. return c;
  495. }
  496. // discard any buffered input
  497. void usb_serial_class::flush()
  498. {
  499. uint8_t intr_state;
  500. if (usb_configuration) {
  501. intr_state = SREG;
  502. cli();
  503. UENUM = DEBUG_RX_ENDPOINT;
  504. while ((UEINTX & (1<<RWAL))) {
  505. UEINTX = 0x6B;
  506. }
  507. SREG = intr_state;
  508. }
  509. prev_byte = 0;
  510. }
  511. // transmit a character.
  512. #if ARDUINO >= 100
  513. size_t usb_serial_class::write(uint8_t c)
  514. #else
  515. void usb_serial_class::write(uint8_t c)
  516. #endif
  517. {
  518. //static uint8_t previous_timeout=0;
  519. uint8_t timeout, intr_state;
  520. // if we're not online (enumerated and configured), error
  521. if (!usb_configuration) goto error;
  522. // interrupts are disabled so these functions can be
  523. // used from the main program or interrupt context,
  524. // even both in the same program!
  525. intr_state = SREG;
  526. cli();
  527. UENUM = DEBUG_TX_ENDPOINT;
  528. // if we gave up due to timeout before, don't wait again
  529. #if 0
  530. // this seems to be causig a lockup... why????
  531. if (previous_timeout) {
  532. if (!(UEINTX & (1<<RWAL))) {
  533. SREG = intr_state;
  534. return;
  535. }
  536. previous_timeout = 0;
  537. }
  538. #endif
  539. // wait for the FIFO to be ready to accept data
  540. timeout = UDFNUML + TRANSMIT_TIMEOUT;
  541. while (1) {
  542. // are we ready to transmit?
  543. if (UEINTX & (1<<RWAL)) break;
  544. SREG = intr_state;
  545. // have we waited too long? This happens if the user
  546. // is not running an application that is listening
  547. if (UDFNUML == timeout) {
  548. //previous_timeout = 1;
  549. goto error;
  550. }
  551. // has the USB gone offline?
  552. if (!usb_configuration) goto error;
  553. // get ready to try checking again
  554. intr_state = SREG;
  555. cli();
  556. UENUM = DEBUG_TX_ENDPOINT;
  557. }
  558. // actually write the byte into the FIFO
  559. UEDATX = c;
  560. // if this completed a packet, transmit it now!
  561. if (!(UEINTX & (1<<RWAL))) {
  562. UEINTX = 0x3A;
  563. debug_flush_timer = 0;
  564. } else {
  565. debug_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
  566. }
  567. SREG = intr_state;
  568. #if ARDUINO >= 100
  569. return 1;
  570. #endif
  571. error:
  572. #if ARDUINO >= 100
  573. setWriteError();
  574. return 0;
  575. #else
  576. return;
  577. #endif
  578. }
  579. // These are Teensy-specific extensions to the Serial object
  580. // immediately transmit any buffered output.
  581. // This doesn't actually transmit the data - that is impossible!
  582. // USB devices only transmit when the host allows, so the best
  583. // we can do is release the FIFO buffer for when the host wants it
  584. void usb_serial_class::send_now(void)
  585. {
  586. uint8_t intr_state;
  587. intr_state = SREG;
  588. cli();
  589. if (debug_flush_timer) {
  590. UENUM = DEBUG_TX_ENDPOINT;
  591. while ((UEINTX & (1<<RWAL))) {
  592. UEDATX = 0;
  593. }
  594. UEINTX = 0x3A;
  595. debug_flush_timer = 0;
  596. }
  597. SREG = intr_state;
  598. }
  599. uint32_t usb_serial_class::baud(void)
  600. {
  601. return ((uint32_t)DEBUG_TX_SIZE * 10000 / DEBUG_TX_INTERVAL);
  602. }
  603. uint8_t usb_serial_class::stopbits(void)
  604. {
  605. return 1;
  606. }
  607. uint8_t usb_serial_class::paritytype(void)
  608. {
  609. return 0;
  610. }
  611. uint8_t usb_serial_class::numbits(void)
  612. {
  613. return 8;
  614. }
  615. uint8_t usb_serial_class::dtr(void)
  616. {
  617. return 1;
  618. }
  619. uint8_t usb_serial_class::rts(void)
  620. {
  621. return 1;
  622. }
  623. usb_serial_class::operator bool()
  624. {
  625. if (usb_configuration) return true;
  626. return false;
  627. }
  628. // Preinstantiate Objects //////////////////////////////////////////////////////
  629. usb_serial_class Serial = usb_serial_class();