Teensy 4.1 core updated for C++20
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

usb_flightsim.cpp 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. /* Teensyduino Core Library
  2. * http://www.pjrc.com/teensy/
  3. * Copyright (c) 2013 PJRC.COM, LLC.
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining
  6. * a copy of this software and associated documentation files (the
  7. * "Software"), to deal in the Software without restriction, including
  8. * without limitation the rights to use, copy, modify, merge, publish,
  9. * distribute, sublicense, and/or sell copies of the Software, and to
  10. * permit persons to whom the Software is furnished to do so, subject to
  11. * the following conditions:
  12. *
  13. * 1. The above copyright notice and this permission notice shall be
  14. * included in all copies or substantial portions of the Software.
  15. *
  16. * 2. If the Software is incorporated into a build system that allows
  17. * selection among a list of target devices, then similar target
  18. * devices manufactured by PJRC.COM must be included in the list of
  19. * target devices and selectable in the same manner.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  25. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  26. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  27. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  28. * SOFTWARE.
  29. */
  30. extern "C" {
  31. #include "usb_dev.h"
  32. }
  33. #include "usb_flightsim.h"
  34. #include "debug/printf.h"
  35. #include "avr/pgmspace.h"
  36. #include "core_pins.h" // for yield(), millis()
  37. #include <string.h> // for memcpy()
  38. #ifdef FLIGHTSIM_INTERFACE // defined by usb_dev.h -> usb_desc.h
  39. #if F_CPU >= 20000000
  40. FlightSimCommand * FlightSimCommand::first = NULL;
  41. FlightSimCommand * FlightSimCommand::last = NULL;
  42. FlightSimInteger * FlightSimInteger::first = NULL;
  43. FlightSimInteger * FlightSimInteger::last = NULL;
  44. FlightSimFloat * FlightSimFloat::first = NULL;
  45. FlightSimFloat * FlightSimFloat::last = NULL;
  46. /// JB
  47. FlightSimEvent * FlightSimEvent::first = NULL;
  48. FlightSimEvent * FlightSimEvent::last = NULL;
  49. FlightSimData * FlightSimData::first = NULL;
  50. FlightSimData * FlightSimData::last = NULL;
  51. /// JB End
  52. uint8_t FlightSimClass::enabled = 0;
  53. uint8_t FlightSimClass::request_id_messages = 0;
  54. unsigned long FlightSimClass::frameCount = 0;
  55. elapsedMillis FlightSimClass::enableTimeout;
  56. static unsigned int unassigned_id = 1; // TODO: move into FlightSimClass
  57. static uint8_t tx_noautoflush=0;
  58. static uint8_t transmit_previous_timeout=0;
  59. #define TX_NUM 8
  60. static transfer_t tx_transfer[TX_NUM] __attribute__ ((used, aligned(32)));
  61. DMAMEM static uint8_t txbuffer[FLIGHTSIM_TX_SIZE * TX_NUM] __attribute__ ((aligned(32)));
  62. static uint8_t tx_head=0;
  63. static uint16_t tx_available=0;
  64. #define RX_NUM 6
  65. static transfer_t rx_transfer[RX_NUM] __attribute__ ((used, aligned(32)));
  66. DMAMEM static uint8_t rx_buffer[RX_NUM * FLIGHTSIM_RX_SIZE] __attribute__ ((aligned(32)));
  67. static volatile uint8_t rx_head;
  68. static volatile uint8_t rx_tail;
  69. static uint8_t rx_list[RX_NUM + 1];
  70. static volatile uint32_t rx_available;
  71. extern "C" {
  72. static void rx_queue_transfer(int i);
  73. static void rx_event(transfer_t *t);
  74. static void* usb_flightsim_get_packet();
  75. static void usb_flightsim_free_packet();
  76. static bool wait_for_tx_buf(transfer_t *xfer);
  77. static void send_packet(transfer_t *xfer);
  78. }
  79. // When the PC isn't listening, how long do we wait before discarding data?
  80. #define TX_TIMEOUT_MSEC 40
  81. extern volatile uint8_t usb_configuration;
  82. FlightSimCommand::FlightSimCommand()
  83. {
  84. id = unassigned_id++;
  85. if (!first) {
  86. first = this;
  87. } else {
  88. last->next = this;
  89. }
  90. last = this;
  91. name = NULL;
  92. next = NULL;
  93. FlightSimClass::request_id_messages = 1;
  94. }
  95. void FlightSimCommand::identify(void)
  96. {
  97. uint8_t len, buf[6];
  98. if (!FlightSim.enabled || !name) return;
  99. len = strlen((const char *)name);
  100. buf[0] = len + 6;
  101. buf[1] = 1;
  102. buf[2] = id;
  103. buf[3] = id >> 8;
  104. buf[4] = 0;
  105. buf[5] = 0;
  106. FlightSimClass::xmit(buf, 6, name, len);
  107. }
  108. void FlightSimCommand::sendcmd(uint8_t n)
  109. {
  110. uint8_t buf[4];
  111. if (!FlightSim.enabled || !name) return;
  112. buf[0] = 4;
  113. buf[1] = n;
  114. buf[2] = id;
  115. buf[3] = id >> 8;
  116. FlightSimClass::xmit(buf, 4, NULL, 0);
  117. }
  118. /// JB
  119. FlightSimEvent::FlightSimEvent()
  120. {
  121. id = unassigned_id++;
  122. if (!first) {
  123. first = this;
  124. } else {
  125. last->next = this;
  126. }
  127. last = this;
  128. name = NULL;
  129. next = NULL;
  130. occur_callback = NULL;
  131. occurredFlag = 0;
  132. callbackInfo = NULL;
  133. hasCallbackInfo = 0;
  134. value = 0;
  135. FlightSimClass::request_id_messages = 1;
  136. }
  137. void FlightSimEvent::identify(void)
  138. {
  139. uint8_t len, buf[6];
  140. if (!FlightSim.enabled || !name) return;
  141. len = strlen((const char *)name);
  142. buf[0] = len + 6;
  143. buf[1] = 1;
  144. buf[2] = id;
  145. buf[3] = id >> 8;
  146. buf[4] = 3;
  147. buf[5] = 0;
  148. FlightSimClass::xmit(buf, 6, name, len);
  149. }
  150. void FlightSimEvent::send(unsigned int data, unsigned int flags)
  151. {
  152. uint8_t buf[4];
  153. uint32_t txData[2];
  154. if (!FlightSim.enabled || !name) return;
  155. buf[0] = 12;
  156. buf[1] = 7;
  157. buf[2] = id;
  158. buf[3] = id >> 8;
  159. value = data;
  160. txData[0] = data;
  161. txData[1] = flags;
  162. FlightSimClass::xmit(buf, 4, (uint8_t *)&txData, 8);
  163. }
  164. void FlightSimEvent::update(long val)
  165. {
  166. value = (unsigned int) val;
  167. occurredFlag = true;
  168. if (occur_callback) {
  169. if (!hasCallbackInfo) {
  170. (*occur_callback)(val);
  171. } else {
  172. (*(void(*)(long,void*))occur_callback)(val,callbackInfo);
  173. }
  174. }
  175. }
  176. FlightSimEvent * FlightSimEvent::find(unsigned int n)
  177. {
  178. for (FlightSimEvent *p = first; p; p = p->next) {
  179. if (p->id == n) return p;
  180. }
  181. return NULL;
  182. }
  183. FlightSimData::FlightSimData()
  184. {
  185. id = unassigned_id++;
  186. if (!first) {
  187. first = this;
  188. } else {
  189. last->next = this;
  190. }
  191. last = this;
  192. name = NULL;
  193. next = NULL;
  194. valueLen = 0;
  195. hasCallbackInfo = 0;
  196. callbackWithObject = 0;
  197. callbackInfo = NULL;
  198. change_callback = NULL;
  199. FlightSimClass::request_id_messages = 1;
  200. }
  201. void FlightSimData::identify(void)
  202. {
  203. uint8_t len, buf[6];
  204. if (!FlightSim.enabled || !name) return;
  205. len = strlen((const char *)name);
  206. buf[0] = len + 6;
  207. buf[1] = 1;
  208. buf[2] = id;
  209. buf[3] = id >> 8;
  210. buf[4] = 4;
  211. buf[5] = 0;
  212. FlightSimClass::xmit(buf, 6, name, len);
  213. }
  214. void FlightSimData::update(char *val, size_t len)
  215. {
  216. valueLen = len;
  217. memcpy(value, val, len);
  218. if (len<FLIGHTSIM_DATA_MAXLEN) {
  219. memset(value+len,0,FLIGHTSIM_DATA_MAXLEN-len);
  220. }
  221. if (change_callback) {
  222. if (!callbackWithObject) {
  223. if (!hasCallbackInfo) {
  224. (*change_callback)(value);
  225. } else {
  226. (*(void(*)(char*,void*))change_callback)(value,callbackInfo);
  227. }
  228. } else {
  229. if (!hasCallbackInfo) {
  230. (*(void(*)(FlightSimData*))change_callback)(this);
  231. } else {
  232. (*(void(*)(FlightSimData*,void*))change_callback)(this,callbackInfo);
  233. }
  234. }
  235. }
  236. }
  237. FlightSimData * FlightSimData::find(unsigned int n)
  238. {
  239. for (FlightSimData *p = first; p; p = p->next) {
  240. if (p->id == n) return p;
  241. }
  242. return NULL;
  243. }
  244. /// JB End
  245. FlightSimInteger::FlightSimInteger()
  246. {
  247. id = unassigned_id++;
  248. if (!first) {
  249. first = this;
  250. } else {
  251. last->next = this;
  252. }
  253. last = this;
  254. name = NULL;
  255. next = NULL;
  256. value = 0;
  257. change_callback = NULL;
  258. callbackInfo = NULL;
  259. hasCallbackInfo = false;
  260. FlightSimClass::request_id_messages = 1;
  261. }
  262. void FlightSimInteger::identify(void)
  263. {
  264. uint8_t len, buf[6];
  265. if (!FlightSim.enabled || !name) return;
  266. len = strlen((const char *)name);
  267. buf[0] = len + 6;
  268. buf[1] = 1;
  269. buf[2] = id;
  270. buf[3] = id >> 8;
  271. buf[4] = 1;
  272. buf[5] = 0;
  273. FlightSimClass::xmit(buf, 6, name, len);
  274. }
  275. void FlightSimInteger::write(long val)
  276. {
  277. uint8_t buf[6];
  278. value = val;
  279. if (!FlightSim.enabled || !name) return; // TODO: mark as dirty
  280. buf[0] = 10;
  281. buf[1] = 2;
  282. buf[2] = id;
  283. buf[3] = id >> 8;
  284. buf[4] = 1;
  285. buf[5] = 0;
  286. FlightSimClass::xmit(buf, 6, (uint8_t *)&value, 4);
  287. }
  288. void FlightSimInteger::update(long val)
  289. {
  290. value = val;
  291. if (change_callback) {
  292. if (!hasCallbackInfo) {
  293. (*change_callback)(val);
  294. } else {
  295. (*(void(*)(long,void*))change_callback)(val,callbackInfo);
  296. }
  297. }
  298. }
  299. FlightSimInteger * FlightSimInteger::find(unsigned int n)
  300. {
  301. for (FlightSimInteger *p = first; p; p = p->next) {
  302. if (p->id == n) return p;
  303. }
  304. return NULL;
  305. }
  306. FlightSimFloat::FlightSimFloat()
  307. {
  308. id = unassigned_id++;
  309. if (!first) {
  310. first = this;
  311. } else {
  312. last->next = this;
  313. }
  314. last = this;
  315. name = NULL;
  316. next = NULL;
  317. value = 0;
  318. change_callback = NULL;
  319. hasCallbackInfo = false;
  320. callbackInfo = NULL;
  321. FlightSimClass::request_id_messages = 1;
  322. }
  323. void FlightSimFloat::identify(void)
  324. {
  325. uint8_t len, buf[6];
  326. if (!FlightSim.enabled || !name) return;
  327. len = strlen((const char *)name);
  328. buf[0] = len + 6;
  329. buf[1] = 1;
  330. buf[2] = id;
  331. buf[3] = id >> 8;
  332. buf[4] = 2;
  333. buf[5] = 0;
  334. FlightSimClass::xmit(buf, 6, name, len);
  335. }
  336. void FlightSimFloat::write(float val)
  337. {
  338. uint8_t buf[6];
  339. value = val;
  340. if (!FlightSim.enabled || !name) return; // TODO: mark as dirty
  341. buf[0] = 10;
  342. buf[1] = 2;
  343. buf[2] = id;
  344. buf[3] = id >> 8;
  345. buf[4] = 2;
  346. buf[5] = 0;
  347. FlightSimClass::xmit(buf, 6, (uint8_t *)&value, 4);
  348. }
  349. void FlightSimFloat::update(float val)
  350. {
  351. value = val;
  352. if (change_callback) { // add: JB
  353. if (!hasCallbackInfo) {
  354. (*change_callback)(val);
  355. } else {
  356. (*(void(*)(float,void*))change_callback)(val,callbackInfo);
  357. }
  358. }
  359. }
  360. FlightSimFloat * FlightSimFloat::find(unsigned int n)
  361. {
  362. for (FlightSimFloat *p = first; p; p = p->next) {
  363. if (p->id == n) return p;
  364. }
  365. return NULL;
  366. }
  367. FlightSimClass::FlightSimClass()
  368. {
  369. }
  370. void FlightSimClass::update(void)
  371. {
  372. uint8_t len, maxlen, type, *p, *end;
  373. union {
  374. uint8_t b[4];
  375. long l;
  376. float f;
  377. } data;
  378. void *rx_packet;
  379. uint16_t id;
  380. while (1) {
  381. if (!usb_configuration) break;
  382. rx_packet = usb_flightsim_get_packet();
  383. if (!rx_packet) break;
  384. p = (uint8_t*) rx_packet;
  385. end = p + FLIGHTSIM_RX_SIZE;
  386. maxlen = FLIGHTSIM_RX_SIZE;
  387. do {
  388. len = p[0];
  389. if (len < 2 || len > maxlen) break;
  390. switch (p[1]) {
  391. case 0x02: // write data
  392. if (len < 10) break;
  393. id = p[2] | (p[3] << 8);
  394. type = p[4];
  395. if (type == 1) {
  396. FlightSimInteger *item = FlightSimInteger::find(id);
  397. if (!item) break;
  398. data.b[0] = p[6];
  399. data.b[1] = p[7];
  400. data.b[2] = p[8];
  401. data.b[3] = p[9];
  402. item->update(data.l);
  403. } else if (type == 2) {
  404. FlightSimFloat *item = FlightSimFloat::find(id);
  405. if (!item) break;
  406. data.b[0] = p[6];
  407. data.b[1] = p[7];
  408. data.b[2] = p[8];
  409. data.b[3] = p[9];
  410. item->update(data.f);
  411. /// JB
  412. } else if (type == 3) {
  413. FlightSimEvent *item = FlightSimEvent::find(id);
  414. if (!item) break;
  415. data.b[0] = p[6];
  416. data.b[1] = p[7];
  417. data.b[2] = p[8];
  418. data.b[3] = p[9];
  419. item->update(data.f);
  420. } else if (type == 4) {
  421. FlightSimData *item = FlightSimData::find(id);
  422. if (!item) break;
  423. item->update(((char*)p)+6,len-6);
  424. /// JB End
  425. }
  426. break;
  427. case 0x03: // enable/disable
  428. if (len < 4) break;
  429. switch (p[2]) {
  430. case 1:
  431. request_id_messages = 1;
  432. /* no break */
  433. case 2:
  434. enable();
  435. frameCount++;
  436. break;
  437. case 3:
  438. disable();
  439. }
  440. }
  441. p += len;
  442. maxlen -= len;
  443. } while (p < end);
  444. usb_flightsim_free_packet();
  445. }
  446. if (enabled && request_id_messages) {
  447. request_id_messages = 0;
  448. for (FlightSimCommand *p = FlightSimCommand::first; p; p = p->next) {
  449. p->identify();
  450. }
  451. /// JB
  452. for (FlightSimEvent *p = FlightSimEvent::first; p; p = p->next) {
  453. p->identify();
  454. }
  455. for (FlightSimData *p = FlightSimData::first; p; p=p->next) {
  456. p->identify();
  457. }
  458. /// JB End
  459. for (FlightSimInteger *p = FlightSimInteger::first; p; p = p->next) {
  460. p->identify();
  461. // TODO: send any dirty data
  462. }
  463. for (FlightSimFloat *p = FlightSimFloat::first; p; p = p->next) {
  464. p->identify();
  465. // TODO: send any dirty data
  466. }
  467. }
  468. }
  469. bool FlightSimClass::isEnabled(void)
  470. {
  471. if (!usb_configuration) return false;
  472. if (!enabled) return false;
  473. if (enableTimeout > 1500) return false;
  474. return true;
  475. }
  476. void FlightSimClass::xmit(const void *p1, uint8_t n1, const void *p2, uint8_t n2)
  477. {
  478. if (!enabled || !usb_configuration) return;
  479. uint16_t total = n1 + n2;
  480. if (total > FLIGHTSIM_TX_SIZE) {
  481. xmit_big_packet(p1, n1, p2, n2);
  482. return;
  483. }
  484. // handle small packets
  485. tx_noautoflush = 1;
  486. transfer_t *xfer = tx_transfer + tx_head;
  487. if (!wait_for_tx_buf(xfer)) return;
  488. if (total > tx_available) {
  489. // send previous packet
  490. uint8_t *txdata = (uint8_t *)(txbuffer + (tx_head * FLIGHTSIM_TX_SIZE) + (FLIGHTSIM_TX_SIZE - tx_available));
  491. while (tx_available > 0) {
  492. // fill packet
  493. *txdata++ = 0;
  494. tx_available--;
  495. }
  496. send_packet(xfer);
  497. xfer = tx_transfer + tx_head;
  498. if (!wait_for_tx_buf(xfer)) return;
  499. }
  500. uint8_t *txdata = (uint8_t *)(txbuffer + (tx_head * FLIGHTSIM_TX_SIZE) + (FLIGHTSIM_TX_SIZE - tx_available));
  501. memcpy(txdata, p1, n1);
  502. tx_available -= n1;
  503. txdata += n1;
  504. if (n2 > 0) {
  505. memcpy(txdata, p2, n2);
  506. tx_available -= n2;
  507. }
  508. if (tx_available == 0) {
  509. // packet filled, send it
  510. send_packet(xfer);
  511. } else {
  512. // wait for send until next SOF
  513. usb_start_sof_interrupts(FLIGHTSIM_INTERFACE);
  514. }
  515. tx_noautoflush = 0;
  516. }
  517. void FlightSimClass::xmit_big_packet(const void *p1, uint8_t n1, const void *p2, uint8_t n2)
  518. {
  519. uint16_t remaining = n1 + n2;
  520. if (remaining > 255) {
  521. printf("Invalid flight sim packet length (>255)");
  522. return;
  523. }
  524. tx_noautoflush =1; // don't mess with my data, I'm working on it!
  525. transfer_t *xfer = tx_transfer + tx_head;
  526. if (!wait_for_tx_buf(xfer)) return; // after this, tx_available is guaranteed to be > 0
  527. bool part2 = false;
  528. uint8_t remainingPart1 = n1;
  529. const uint8_t *dataPtr = (const uint8_t*)p1;
  530. bool writeFragmentHeader = false;
  531. uint8_t fragmentCounter = 1;
  532. uint8_t *txdata = (uint8_t *)(txbuffer + (tx_head * FLIGHTSIM_TX_SIZE) + (FLIGHTSIM_TX_SIZE - tx_available));
  533. // fill first packet with whatever fits
  534. uint8_t partLen = tx_available > n1 ? n1 : tx_available;
  535. // copy first part, containing total packet length
  536. printf("%d bytes free, adding first %d bytes from p1, writing to %x\n", tx_available, partLen, txdata);
  537. memcpy(txdata, dataPtr, partLen);
  538. remainingPart1 -= partLen;
  539. txdata += partLen;
  540. tx_available -= partLen;
  541. if (remainingPart1) {
  542. // there still is data from the first part that
  543. // will go to the next packet. The boolean variable
  544. // part2 remains false
  545. remaining = remainingPart1+n2;
  546. dataPtr += partLen;
  547. } else {
  548. // maybe we have space for some data from the second part
  549. part2=true;
  550. // there is no need here to check whether tx_available is
  551. // bigger than n2. It's not. If it were, all the data
  552. // would have fit in a single packet and xmit_big_packet
  553. // would never have been called...
  554. printf("adding first %d bytes from p2, writing to %x\n", tx_available, txdata);
  555. remaining = n2;
  556. if (tx_available) {
  557. memcpy(txdata, p2, tx_available);
  558. remaining -= tx_available;
  559. }
  560. dataPtr = (const uint8_t*)p2 + tx_available;
  561. }
  562. // first packet filled, send it
  563. tx_available = 0;
  564. send_packet(xfer);
  565. xfer = tx_transfer + tx_head;
  566. writeFragmentHeader = true;
  567. printf("remaining bytes to send: %d\n", remaining);
  568. while (remaining >0) {
  569. if (!wait_for_tx_buf(xfer)) return;
  570. uint8_t *txdata = (uint8_t *)(txbuffer + (tx_head * FLIGHTSIM_TX_SIZE) + (FLIGHTSIM_TX_SIZE - tx_available));
  571. if (writeFragmentHeader) {
  572. printf("writing header of fragment %d to %x\n", fragmentCounter, txdata);
  573. *txdata++=(remaining+3 <= FLIGHTSIM_TX_SIZE) ? (uint8_t) remaining+3 : FLIGHTSIM_TX_SIZE;
  574. *txdata++=0xff;
  575. *txdata++=fragmentCounter++;
  576. tx_available -= 3;
  577. }
  578. if (!part2) {
  579. // we still need to send the first part
  580. uint8_t partLen = tx_available > remainingPart1 ? remainingPart1 : tx_available;
  581. printf("copying remaining %d bytes from first part to %x\n", partLen, txdata);
  582. memcpy(txdata, dataPtr, partLen);
  583. dataPtr += partLen;
  584. txdata += partLen;
  585. tx_available -= partLen;
  586. remaining -= partLen;
  587. remainingPart1 -= partLen;
  588. if (!remainingPart1) {
  589. part2=true;
  590. dataPtr = (const uint8_t*)p2;
  591. }
  592. }
  593. if (part2) {
  594. uint8_t partLen = tx_available > remaining ? remaining : tx_available;
  595. printf("copying %d bytes from second part to %x\n", partLen, txdata);
  596. if (partLen) {
  597. memcpy(txdata, dataPtr, partLen);
  598. remaining -= partLen;
  599. tx_available -= partLen;
  600. txdata += partLen;
  601. dataPtr += partLen;
  602. }
  603. }
  604. writeFragmentHeader = true;
  605. if (!tx_available) {
  606. // packet filled, send it
  607. send_packet(xfer);
  608. xfer = tx_transfer + tx_head;
  609. } else {
  610. // send on next SOF
  611. printf("tx_available: %d\n", tx_available);
  612. usb_start_sof_interrupts(FLIGHTSIM_INTERFACE);
  613. }
  614. }
  615. tx_noautoflush = 0; // data is ready to be transmitted on start of USB token
  616. }
  617. extern "C" {
  618. void usb_flightsim_configure() {
  619. printf("Flightsim_configure\n");
  620. memset(tx_transfer, 0, sizeof(tx_transfer));
  621. tx_head = 0;
  622. tx_available = 0;
  623. memset(rx_transfer, 0, sizeof(rx_transfer));
  624. printf("tx_transfer: %x\n", tx_transfer);
  625. printf("txbuffer: %x\n", txbuffer);
  626. printf("rx_transfer: %x\n", rx_transfer);
  627. printf("rxbuffer: %x\n", rx_buffer);
  628. rx_head = 0;
  629. rx_tail = 0;
  630. rx_available = 0;
  631. usb_config_rx(FLIGHTSIM_RX_ENDPOINT, FLIGHTSIM_RX_SIZE, 0, rx_event);
  632. usb_config_tx(FLIGHTSIM_TX_ENDPOINT, FLIGHTSIM_TX_SIZE, 0, NULL); // TODO: is ZLP needed?
  633. int i;
  634. for (i=0; i < RX_NUM; i++) rx_queue_transfer(i);
  635. tx_noautoflush = 0;
  636. transmit_previous_timeout = 0;
  637. }
  638. // This gets called from usb_isr when a USB start token arrives.
  639. // If we have a packet to transmit AND transmission isn't disabled
  640. // by tx_noautoflush, we fill it up with zeros and send it out
  641. // to USB
  642. void usb_flightsim_flush_output(void)
  643. {
  644. if (tx_noautoflush == 0 && tx_available > 0) {
  645. printf(" flush, %d %d\n", FLIGHTSIM_TX_SIZE, tx_available);
  646. uint32_t head = tx_head;
  647. transfer_t *xfer = tx_transfer + head;
  648. uint8_t *txbuf = txbuffer + (head * FLIGHTSIM_TX_SIZE);
  649. uint8_t *txPtr = txbuf + (FLIGHTSIM_TX_SIZE - tx_available);
  650. while (tx_available>0) {
  651. *txPtr++ = 0;
  652. tx_available--;
  653. }
  654. usb_prepare_transfer(xfer, txbuf, FLIGHTSIM_TX_SIZE, 0);
  655. arm_dcache_flush_delete(txbuf, FLIGHTSIM_TX_SIZE);
  656. usb_transmit(FLIGHTSIM_TX_ENDPOINT, xfer);
  657. if (++head >= TX_NUM) head = 0;
  658. tx_head = head;
  659. usb_stop_sof_interrupts(FLIGHTSIM_INTERFACE);
  660. }
  661. }
  662. static bool wait_for_tx_buf(transfer_t *xfer) {
  663. uint32_t wait_begin_at = systick_millis_count;
  664. while (!tx_available) {
  665. uint32_t status = usb_transfer_status(xfer);
  666. if (!(status & 0x80)) {
  667. if (status & 0x68) {
  668. // TODO: what if status has errors???
  669. }
  670. tx_available = FLIGHTSIM_TX_SIZE;
  671. transmit_previous_timeout = 0;
  672. break;
  673. }
  674. if (systick_millis_count - wait_begin_at > TX_TIMEOUT_MSEC) {
  675. transmit_previous_timeout = 1;
  676. }
  677. if (transmit_previous_timeout) {
  678. printf("Flight sim tx timeout");
  679. return false;
  680. }
  681. if (!usb_configuration) return false;
  682. yield();
  683. }
  684. return true;
  685. }
  686. static void send_packet(transfer_t *xfer) {
  687. uint32_t head = tx_head;
  688. uint8_t *txbuf = txbuffer + (tx_head * FLIGHTSIM_TX_SIZE);
  689. usb_prepare_transfer(xfer, txbuf, FLIGHTSIM_TX_SIZE, 0);
  690. arm_dcache_flush_delete(txbuf, FLIGHTSIM_TX_SIZE);
  691. usb_transmit(FLIGHTSIM_TX_ENDPOINT, xfer);
  692. if (++head >= TX_NUM) head = 0;
  693. tx_head = head;
  694. usb_stop_sof_interrupts(FLIGHTSIM_INTERFACE);
  695. }
  696. static void rx_queue_transfer(int i)
  697. {
  698. NVIC_DISABLE_IRQ(IRQ_USB1);
  699. void *buffer = rx_buffer + i * FLIGHTSIM_RX_SIZE;
  700. usb_prepare_transfer(rx_transfer + i, buffer, FLIGHTSIM_RX_SIZE, i);
  701. arm_dcache_delete(buffer, FLIGHTSIM_RX_SIZE);
  702. usb_receive(FLIGHTSIM_RX_ENDPOINT, rx_transfer + i);
  703. NVIC_ENABLE_IRQ(IRQ_USB1);
  704. }
  705. static void rx_event(transfer_t *t)
  706. {
  707. int len = FLIGHTSIM_RX_SIZE - ((t->status >> 16) & 0x7FFF);
  708. len &= 0xFFFC; // MIDI packets must be multiple of 4 bytes
  709. int i = t->callback_param;
  710. // printf("Flight sim rx event, len=%d, i=%d", len, i);
  711. if (len == FLIGHTSIM_RX_SIZE) {
  712. uint32_t head = rx_head;
  713. if (++head > RX_NUM) head = 0;
  714. rx_list[head] = i;
  715. rx_head = head;
  716. rx_available += len;
  717. } else {
  718. // received packet with invalid length
  719. rx_queue_transfer(i);
  720. }
  721. // printf(" ...done\n");
  722. }
  723. static void* usb_flightsim_get_packet(void)
  724. {
  725. void *result = NULL;
  726. NVIC_DISABLE_IRQ(IRQ_USB1);
  727. uint32_t tail = rx_tail;
  728. if (tail != rx_head) {
  729. if (++tail > RX_NUM) tail = 0;
  730. uint32_t i = rx_list[tail];
  731. result = rx_buffer + i * FLIGHTSIM_RX_SIZE;
  732. rx_available -= FLIGHTSIM_RX_SIZE;
  733. }
  734. NVIC_ENABLE_IRQ(IRQ_USB1);
  735. return result;
  736. }
  737. static void usb_flightsim_free_packet() {
  738. NVIC_DISABLE_IRQ(IRQ_USB1);
  739. uint32_t tail = rx_tail;
  740. if (tail != rx_head) {
  741. if (++tail > RX_NUM) tail = 0;
  742. uint32_t i = rx_list[tail];
  743. rx_tail = tail;
  744. rx_queue_transfer(i);
  745. }
  746. NVIC_ENABLE_IRQ(IRQ_USB1);
  747. }
  748. } // extern "C"
  749. #endif // F_CPU
  750. #endif // FLIGHTSIM_INTERFACE