PlatformIO package of the Teensy core framework compatible with GCC 10 & 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.

797 lines
18KB

  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. uint16_t len;
  57. uint8_t buf[6];
  58. if (!FlightSim.enabled || !name) return;
  59. len = strlen_P((const char *)name);
  60. buf[0] = len + 6;
  61. buf[1] = 1;
  62. buf[2] = id;
  63. buf[3] = id >> 8;
  64. buf[4] = 0;
  65. buf[5] = 0;
  66. FlightSimClass::xmit(buf, 6, name, len);
  67. }
  68. void FlightSimCommand::sendcmd(uint8_t n)
  69. {
  70. uint8_t buf[4];
  71. if (!FlightSim.enabled || !name) return;
  72. buf[0] = 4;
  73. buf[1] = n;
  74. buf[2] = id;
  75. buf[3] = id >> 8;
  76. FlightSimClass::xmit(buf, 4);
  77. }
  78. FlightSimInteger::FlightSimInteger()
  79. {
  80. id = unassigned_id++;
  81. if (!first) {
  82. first = this;
  83. } else {
  84. last->next = this;
  85. }
  86. last = this;
  87. name = NULL;
  88. next = NULL;
  89. value = 0;
  90. change_callback = NULL;
  91. FlightSimClass::request_id_messages = 1;
  92. }
  93. void FlightSimInteger::identify(void)
  94. {
  95. uint16_t len;
  96. uint8_t buf[6];
  97. if (!FlightSim.enabled || !name) return;
  98. len = strlen_P((const char *)name);
  99. buf[0] = len + 6;
  100. buf[1] = 1;
  101. buf[2] = id;
  102. buf[3] = id >> 8;
  103. buf[4] = 1;
  104. buf[5] = 0;
  105. FlightSimClass::xmit(buf, 6, name, len);
  106. }
  107. void FlightSimInteger::write(long val)
  108. {
  109. uint8_t buf[6];
  110. value = val;
  111. if (!FlightSim.enabled || !name) return; // TODO: mark as dirty
  112. buf[0] = 10;
  113. buf[1] = 2;
  114. buf[2] = id;
  115. buf[3] = id >> 8;
  116. buf[4] = 1;
  117. buf[5] = 0;
  118. FlightSimClass::xmit(buf, 6, (uint8_t *)&value, 4);
  119. }
  120. void FlightSimInteger::update(long val)
  121. {
  122. value = val;
  123. if (change_callback) {
  124. if (!hasCallbackInfo) {
  125. (*change_callback)(val);
  126. } else {
  127. (*(void(*)(long,void*))change_callback)(val,callbackInfo);
  128. }
  129. }
  130. }
  131. FlightSimInteger * FlightSimInteger::find(unsigned int n)
  132. {
  133. for (FlightSimInteger *p = first; p; p = p->next) {
  134. if (p->id == n) return p;
  135. }
  136. return NULL;
  137. }
  138. FlightSimFloat::FlightSimFloat()
  139. {
  140. id = unassigned_id++;
  141. if (!first) {
  142. first = this;
  143. } else {
  144. last->next = this;
  145. }
  146. last = this;
  147. name = NULL;
  148. next = NULL;
  149. value = 0;
  150. change_callback = NULL;
  151. FlightSimClass::request_id_messages = 1;
  152. }
  153. void FlightSimFloat::identify(void)
  154. {
  155. uint16_t len;
  156. uint8_t buf[6];
  157. if (!FlightSim.enabled || !name) return;
  158. len = strlen_P((const char *)name);
  159. buf[0] = len + 6;
  160. buf[1] = 1;
  161. buf[2] = id;
  162. buf[3] = id >> 8;
  163. buf[4] = 2;
  164. buf[5] = 0;
  165. FlightSimClass::xmit(buf, 6, name, len);
  166. }
  167. void FlightSimFloat::write(float val)
  168. {
  169. uint8_t buf[6];
  170. value = val;
  171. if (!FlightSim.enabled || !name) return; // TODO: mark as dirty
  172. buf[0] = 10;
  173. buf[1] = 2;
  174. buf[2] = id;
  175. buf[3] = id >> 8;
  176. buf[4] = 2;
  177. buf[5] = 0;
  178. FlightSimClass::xmit(buf, 6, (uint8_t *)&value, 4);
  179. }
  180. void FlightSimFloat::update(float val)
  181. {
  182. value = val;
  183. if (change_callback) {
  184. if (!hasCallbackInfo) {
  185. (*change_callback)(val);
  186. } else {
  187. (*(void(*)(long,void*))change_callback)(val,callbackInfo);
  188. }
  189. }
  190. }
  191. FlightSimFloat * FlightSimFloat::find(unsigned int n)
  192. {
  193. for (FlightSimFloat *p = first; p; p = p->next) {
  194. if (p->id == n) return p;
  195. }
  196. return NULL;
  197. }
  198. FlightSimClass::FlightSimClass()
  199. {
  200. }
  201. void FlightSimClass::update(void)
  202. {
  203. uint8_t len, maxlen, type, buf[64], *p;
  204. uint16_t id;
  205. while (recv(buf)) {
  206. p = buf;
  207. maxlen = 64;
  208. do {
  209. len = p[0];
  210. if (len < 2 || len > maxlen) break;
  211. switch (p[1]) {
  212. case 0x02: // write data
  213. if (len < 10) break;
  214. id = p[2] | (p[3] << 8);
  215. type = p[4];
  216. if (type == 1) {
  217. FlightSimInteger *item = FlightSimInteger::find(id);
  218. if (!item) break;
  219. item->update(*(long *)(p + 6));
  220. } else if (type == 2) {
  221. FlightSimFloat *item = FlightSimFloat::find(id);
  222. if (!item) break;
  223. item->update(*(float *)(p + 6));
  224. }
  225. break;
  226. case 0x03: // enable/disable
  227. if (len < 4) break;
  228. switch (p[2]) {
  229. case 1:
  230. request_id_messages = 1;
  231. case 2:
  232. enable();
  233. frameCount++;
  234. break;
  235. case 3:
  236. disable();
  237. }
  238. }
  239. p += len;
  240. maxlen -= len;
  241. } while (p < buf + 64);
  242. }
  243. if (enabled && request_id_messages) {
  244. request_id_messages = 0;
  245. for (FlightSimCommand *p = FlightSimCommand::first; p; p = p->next) {
  246. p->identify();
  247. }
  248. for (FlightSimInteger *p = FlightSimInteger::first; p; p = p->next) {
  249. p->identify();
  250. // TODO: send any dirty data
  251. }
  252. for (FlightSimFloat *p = FlightSimFloat::first; p; p = p->next) {
  253. p->identify();
  254. // TODO: send any dirty data
  255. }
  256. }
  257. }
  258. bool FlightSimClass::isEnabled(void)
  259. {
  260. if (!usb_configuration) return false;
  261. if (!enabled) return false;
  262. if (enableTimeout > 1500) return false;
  263. return true;
  264. }
  265. // receive a packet
  266. uint8_t FlightSimClass::recv(uint8_t *buffer)
  267. {
  268. uint8_t intr_state;
  269. // if we're not online (enumerated and configured), error
  270. if (!usb_configuration) return 0;
  271. intr_state = SREG;
  272. cli();
  273. UENUM = FLIGHTSIM_RX_ENDPOINT;
  274. if (!(UEINTX & (1<<RWAL))) {
  275. SREG = intr_state;
  276. return 0;
  277. }
  278. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  279. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  280. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  281. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  282. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  283. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  284. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  285. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  286. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  287. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  288. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  289. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  290. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  291. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  292. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  293. *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX; *buffer++ = UEDATX;
  294. UEINTX = 0x6B;
  295. SREG = intr_state;
  296. return 1;
  297. }
  298. void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1)
  299. {
  300. uint8_t intr_state, avail;
  301. if (!enabled || !usb_configuration) return;
  302. intr_state = SREG;
  303. cli();
  304. UENUM = FLIGHTSIM_TX_ENDPOINT;
  305. avail = FLIGHTSIM_TX_SIZE - UEBCLX;
  306. if ((UEINTX & (1<<RWAL)) && (avail >= n1)) {
  307. goto send;
  308. } else {
  309. while (avail) {
  310. UEDATX = 0;
  311. avail--;
  312. }
  313. UEINTX = 0x3A;
  314. while (1) {
  315. if (UEINTX & (1<<RWAL)) break;
  316. SREG = intr_state;
  317. if (!enabled || !usb_configuration) return;
  318. intr_state = SREG;
  319. cli();
  320. UENUM = FLIGHTSIM_TX_ENDPOINT;
  321. }
  322. }
  323. send:
  324. do {
  325. UEDATX = *p1++;
  326. } while (--n1 > 0);
  327. if (UEBCLX == FLIGHTSIM_TX_SIZE) UEINTX = 0x3A;
  328. SREG = intr_state;
  329. }
  330. void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1, const uint8_t *p2, uint8_t n2)
  331. {
  332. uint8_t intr_state, total, avail;
  333. total = n1 + n2;
  334. if (!enabled || !usb_configuration) return;
  335. intr_state = SREG;
  336. cli();
  337. UENUM = FLIGHTSIM_TX_ENDPOINT;
  338. avail = FLIGHTSIM_TX_SIZE - UEBCLX;
  339. if ((UEINTX & (1<<RWAL)) && (avail >= total)) {
  340. goto send;
  341. } else {
  342. while (avail) {
  343. UEDATX = 0;
  344. avail--;
  345. }
  346. UEINTX = 0x3A;
  347. while (1) {
  348. if (UEINTX & (1<<RWAL)) break;
  349. SREG = intr_state;
  350. if (!enabled || !usb_configuration) return;
  351. intr_state = SREG;
  352. cli();
  353. UENUM = FLIGHTSIM_TX_ENDPOINT;
  354. }
  355. }
  356. send:
  357. do {
  358. UEDATX = *p1++;
  359. } while (--n1 > 0);
  360. do {
  361. UEDATX = *p2++;
  362. } while (--n2 > 0);
  363. if (UEBCLX == FLIGHTSIM_TX_SIZE) UEINTX = 0x3A;
  364. SREG = intr_state;
  365. }
  366. void FlightSimClass::xmit(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint16_t n2) {
  367. uint8_t intr_state, total, avail;
  368. const char * PROGMEM s2 = (const char *)p2;
  369. total = n1 + n2;
  370. if (total > FLIGHTSIM_TX_SIZE) {
  371. xmit_big_packet(p1, n1, p2, n2);
  372. return;
  373. }
  374. if (!enabled || !usb_configuration) return;
  375. intr_state = SREG;
  376. cli();
  377. UENUM = FLIGHTSIM_TX_ENDPOINT;
  378. avail = FLIGHTSIM_TX_SIZE - UEBCLX;
  379. if ((UEINTX & (1<<RWAL)) && (avail >= total)) {
  380. goto send;
  381. } else {
  382. while (avail) {
  383. UEDATX = 0;
  384. avail--;
  385. }
  386. UEINTX = 0x3A;
  387. while (1) {
  388. if (UEINTX & (1<<RWAL)) break;
  389. SREG = intr_state;
  390. if (!enabled || !usb_configuration) return;
  391. intr_state = SREG;
  392. cli();
  393. UENUM = FLIGHTSIM_TX_ENDPOINT;
  394. }
  395. }
  396. send:
  397. do {
  398. UEDATX = *p1++;
  399. } while (--n1 > 0);
  400. do {
  401. pgm_read_byte_postinc(UEDATX, s2);
  402. } while (--n2 > 0);
  403. if (UEBCLX == FLIGHTSIM_TX_SIZE) UEINTX = 0x3A;
  404. SREG = intr_state;
  405. }
  406. void FlightSimClass::xmit_big_packet(const uint8_t *p1, uint8_t n1, const _XpRefStr_ *p2, uint16_t n2) {
  407. uint8_t intr_state, avail;
  408. uint16_t total;
  409. bool part1 = true;
  410. const char * PROGMEM s2 = (const char *)p2;
  411. uint8_t packet_id = 1;
  412. total = n1 + n2;
  413. if (!enabled || !usb_configuration) return;
  414. intr_state = SREG;
  415. cli();
  416. UENUM = FLIGHTSIM_TX_ENDPOINT;
  417. avail = FLIGHTSIM_TX_SIZE - UEBCLX;
  418. while (total>0) {
  419. if (part1) {
  420. UEDATX = *p1++;
  421. part1 = (--n1 != 0);
  422. } else {
  423. pgm_read_byte_postinc(UEDATX, s2);
  424. n2--;
  425. }
  426. total--;
  427. if (!--avail) {
  428. // transmit packet
  429. UEINTX = 0x3A;
  430. while (1) {
  431. if (UEINTX & (1<<RWAL)) break;
  432. SREG = intr_state;
  433. if (!enabled || !usb_configuration) return;
  434. intr_state = SREG;
  435. cli();
  436. UENUM = FLIGHTSIM_TX_ENDPOINT;
  437. }
  438. // start new fragment with length and fragment ID
  439. UEDATX = (total<(FLIGHTSIM_TX_SIZE-3) ? total+3 : FLIGHTSIM_TX_SIZE); // length byte
  440. UEDATX = 0xff;
  441. UEDATX = packet_id++;
  442. avail = FLIGHTSIM_TX_SIZE - 3;
  443. }
  444. }
  445. if (UEBCLX == FLIGHTSIM_TX_SIZE) UEINTX = 0x3A;
  446. SREG = intr_state;
  447. }
  448. FlightSimClass FlightSim;
  449. static volatile uint8_t prev_byte=0;
  450. void usb_serial_class::begin(long speed)
  451. {
  452. // make sure USB is initialized
  453. usb_init();
  454. uint16_t begin_wait = (uint16_t)millis();
  455. while (1) {
  456. if (usb_configuration) {
  457. delay(200); // a little time for host to load a driver
  458. return;
  459. }
  460. if (usb_suspended) {
  461. uint16_t begin_suspend = (uint16_t)millis();
  462. while (usb_suspended) {
  463. // must remain suspended for a while, because
  464. // normal USB enumeration causes brief suspend
  465. // states, typically under 0.1 second
  466. if ((uint16_t)millis() - begin_suspend > 250) {
  467. return;
  468. }
  469. }
  470. }
  471. // ... or a timout (powered by a USB power adaptor that
  472. // wiggles the data lines to keep a USB device charging)
  473. if ((uint16_t)millis() - begin_wait > 2500) return;
  474. }
  475. prev_byte = 0;
  476. }
  477. void usb_serial_class::end()
  478. {
  479. usb_shutdown();
  480. delay(25);
  481. }
  482. // number of bytes available in the receive buffer
  483. int usb_serial_class::available()
  484. {
  485. uint8_t c;
  486. c = prev_byte; // assume 1 byte static volatile access is atomic
  487. if (c) return 1;
  488. c = readnext();
  489. if (c) {
  490. prev_byte = c;
  491. return 1;
  492. }
  493. return 0;
  494. }
  495. // get the next character, or -1 if nothing received
  496. int usb_serial_class::read()
  497. {
  498. uint8_t c;
  499. c = prev_byte;
  500. if (c) {
  501. prev_byte = 0;
  502. return c;
  503. }
  504. c = readnext();
  505. if (c) return c;
  506. return -1;
  507. }
  508. int usb_serial_class::peek()
  509. {
  510. uint8_t c;
  511. c = prev_byte;
  512. if (c) return c;
  513. c = readnext();
  514. if (c) {
  515. prev_byte = c;
  516. return c;
  517. }
  518. return -1;
  519. }
  520. // get the next character, or 0 if nothing
  521. uint8_t usb_serial_class::readnext(void)
  522. {
  523. uint8_t c, intr_state;
  524. // interrupts are disabled so these functions can be
  525. // used from the main program or interrupt context,
  526. // even both in the same program!
  527. intr_state = SREG;
  528. cli();
  529. if (!usb_configuration) {
  530. SREG = intr_state;
  531. return 0;
  532. }
  533. UENUM = DEBUG_RX_ENDPOINT;
  534. try_again:
  535. if (!(UEINTX & (1<<RWAL))) {
  536. // no packet in buffer
  537. SREG = intr_state;
  538. return 0;
  539. }
  540. // take one byte out of the buffer
  541. c = UEDATX;
  542. if (c == 0) {
  543. // if we see a zero, discard it and
  544. // discard the rest of this packet
  545. UEINTX = 0x6B;
  546. goto try_again;
  547. }
  548. // if this drained the buffer, release it
  549. if (!(UEINTX & (1<<RWAL))) UEINTX = 0x6B;
  550. SREG = intr_state;
  551. return c;
  552. }
  553. // discard any buffered input
  554. void usb_serial_class::flush()
  555. {
  556. uint8_t intr_state;
  557. if (usb_configuration) {
  558. intr_state = SREG;
  559. cli();
  560. UENUM = DEBUG_RX_ENDPOINT;
  561. while ((UEINTX & (1<<RWAL))) {
  562. UEINTX = 0x6B;
  563. }
  564. SREG = intr_state;
  565. }
  566. prev_byte = 0;
  567. }
  568. // transmit a character.
  569. #if ARDUINO >= 100
  570. size_t usb_serial_class::write(uint8_t c)
  571. #else
  572. void usb_serial_class::write(uint8_t c)
  573. #endif
  574. {
  575. //static uint8_t previous_timeout=0;
  576. uint8_t timeout, intr_state;
  577. // if we're not online (enumerated and configured), error
  578. if (!usb_configuration) goto error;
  579. // interrupts are disabled so these functions can be
  580. // used from the main program or interrupt context,
  581. // even both in the same program!
  582. intr_state = SREG;
  583. cli();
  584. UENUM = DEBUG_TX_ENDPOINT;
  585. // if we gave up due to timeout before, don't wait again
  586. #if 0
  587. // this seems to be causig a lockup... why????
  588. if (previous_timeout) {
  589. if (!(UEINTX & (1<<RWAL))) {
  590. SREG = intr_state;
  591. return;
  592. }
  593. previous_timeout = 0;
  594. }
  595. #endif
  596. // wait for the FIFO to be ready to accept data
  597. timeout = UDFNUML + TRANSMIT_TIMEOUT;
  598. while (1) {
  599. // are we ready to transmit?
  600. if (UEINTX & (1<<RWAL)) break;
  601. SREG = intr_state;
  602. // have we waited too long? This happens if the user
  603. // is not running an application that is listening
  604. if (UDFNUML == timeout) {
  605. //previous_timeout = 1;
  606. goto error;
  607. }
  608. // has the USB gone offline?
  609. if (!usb_configuration) goto error;
  610. // get ready to try checking again
  611. intr_state = SREG;
  612. cli();
  613. UENUM = DEBUG_TX_ENDPOINT;
  614. }
  615. // actually write the byte into the FIFO
  616. UEDATX = c;
  617. // if this completed a packet, transmit it now!
  618. if (!(UEINTX & (1<<RWAL))) {
  619. UEINTX = 0x3A;
  620. debug_flush_timer = 0;
  621. } else {
  622. debug_flush_timer = TRANSMIT_FLUSH_TIMEOUT;
  623. }
  624. SREG = intr_state;
  625. #if ARDUINO >= 100
  626. return 1;
  627. #endif
  628. error:
  629. #if ARDUINO >= 100
  630. setWriteError();
  631. return 0;
  632. #else
  633. return;
  634. #endif
  635. }
  636. // These are Teensy-specific extensions to the Serial object
  637. // immediately transmit any buffered output.
  638. // This doesn't actually transmit the data - that is impossible!
  639. // USB devices only transmit when the host allows, so the best
  640. // we can do is release the FIFO buffer for when the host wants it
  641. void usb_serial_class::send_now(void)
  642. {
  643. uint8_t intr_state;
  644. intr_state = SREG;
  645. cli();
  646. if (debug_flush_timer) {
  647. UENUM = DEBUG_TX_ENDPOINT;
  648. while ((UEINTX & (1<<RWAL))) {
  649. UEDATX = 0;
  650. }
  651. UEINTX = 0x3A;
  652. debug_flush_timer = 0;
  653. }
  654. SREG = intr_state;
  655. }
  656. uint32_t usb_serial_class::baud(void)
  657. {
  658. return ((uint32_t)DEBUG_TX_SIZE * 10000 / DEBUG_TX_INTERVAL);
  659. }
  660. uint8_t usb_serial_class::stopbits(void)
  661. {
  662. return 1;
  663. }
  664. uint8_t usb_serial_class::paritytype(void)
  665. {
  666. return 0;
  667. }
  668. uint8_t usb_serial_class::numbits(void)
  669. {
  670. return 8;
  671. }
  672. uint8_t usb_serial_class::dtr(void)
  673. {
  674. return 1;
  675. }
  676. uint8_t usb_serial_class::rts(void)
  677. {
  678. return 1;
  679. }
  680. usb_serial_class::operator bool()
  681. {
  682. if (usb_configuration) return true;
  683. return false;
  684. }
  685. // Preinstantiate Objects //////////////////////////////////////////////////////
  686. usb_serial_class Serial = usb_serial_class();