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.

преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
преди 11 години
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  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();